diff --git a/reactos/drivers/filesystems/CMakeLists.txt b/reactos/drivers/filesystems/CMakeLists.txt index 1dd2bc7f115..a9ffab14a54 100644 --- a/reactos/drivers/filesystems/CMakeLists.txt +++ b/reactos/drivers/filesystems/CMakeLists.txt @@ -8,3 +8,7 @@ add_subdirectory(msfs) add_subdirectory(mup) add_subdirectory(npfs) add_subdirectory(ntfs) +if(MSVC) + # FIXME: Make sure this compiles with the *nix builder before enabling it + add_subdirectory(udfs) +endif() diff --git a/reactos/drivers/filesystems/udfs/CMakeLists.txt b/reactos/drivers/filesystems/udfs/CMakeLists.txt new file mode 100644 index 00000000000..db9ada319ce --- /dev/null +++ b/reactos/drivers/filesystems/udfs/CMakeLists.txt @@ -0,0 +1,55 @@ + +include_directories(include) + +set_cpp(WITH_RUNTIME) + +list(APPEND SOURCE + udf_info/alloc.cpp + udf_info/dirtree.cpp + udf_info/extent.cpp + udf_info/mount.cpp + udf_info/phys_eject.cpp + udf_info/physical.cpp + udf_info/remap.cpp + udf_info/udf_info.cpp + cleanup.cpp + close.cpp + create.cpp + devcntrl.cpp + dircntrl.cpp + env_spec.cpp + fastio.cpp + fileinfo.cpp + filter.cpp + flush.cpp + fscntrl.cpp + lockctrl.cpp + mem.cpp + misc.cpp + namesup.cpp + pnp.cpp + read.cpp + secursup.cpp + shutdown.cpp + sys_spec.cpp + udf_dbg.cpp + udfinit.cpp + unload.cpp + verfysup.cpp + volinfo.cpp + wcache.cpp + write.cpp) + +add_library(udfs SHARED ${SOURCE} udffs.rc) +if(MSVC) + # FIXME: Make sure we marked all what needs to be marked with stdcall before removing this. + add_target_compile_flags(udfs "/Gz") +else() + # FIXME: Tons of warnings. + replace_compile_flags("-Werror" " ") + add_target_compile_flags(udfs "-fpermissive") +endif() +set_module_type(udfs kernelmodedriver) +target_link_libraries(udfs ${PSEH_LIB}) +add_importlibs(udfs ntoskrnl hal) +add_cd_file(TARGET udfs DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtDecl.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtDecl.h new file mode 100644 index 00000000000..86f5d41ec2e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtDecl.h @@ -0,0 +1,58 @@ + +#ifdef CROSSNT_DECL +#undef CROSSNT_DECL +#undef CROSSNT_DECL_EX +#endif //CROSSNT_DECL + +/***************************/ +#ifdef CROSSNT_DECL_API + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ +typedef type (dspec *ptr##name) args; \ +extern "C" ptr##name CrNt##name; \ +type dspec CrNt##name##_impl args; + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ +typedef type (dspec *ptr##name) args; \ +extern "C" ptr##name CrNt##name; \ +type dspec CrNt##name##_impl args; + +#endif //CROSSNT_DECL_API + +/***************************/ +#ifdef CROSSNT_DECL_STUB + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ +extern "C" ptr##name CrNt##name = NULL; \ + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ +extern "C" ptr##name CrNt##name = NULL; \ + +#endif //CROSSNT_DECL_STUB + +/***************************/ +#ifdef CROSSNT_INIT_STUB + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ + KdPrint(("Init " #name " cur %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = (ptr##name)CrNtGetProcAddress(g_hNtosKrnl, #name); \ + KdPrint((" GetProcAddr(NTOSKRNL.EXE," #name ") = %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = CrNt##name##_impl; \ + } \ + KdPrint((" final %\n", CrNt##name)); \ + } + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ + KdPrint(("Init " mod "," #name " cur %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = (ptr##name)CrNtGetProcAddress(CrNtGetModuleBase(mod), #name); \ + KdPrint((" GetProcAddr(" mod "," #name ") = %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = CrNt##name##_impl; \ + } \ + KdPrint((" final %x\n", CrNt##name)); \ + } + +#endif //CROSSNT_INIT_STUB diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtStubs.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtStubs.h new file mode 100644 index 00000000000..adb48606b9d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrNtStubs.h @@ -0,0 +1,109 @@ + +CROSSNT_DECL( +HANDLE,__stdcall, +PsGetCurrentProcessId,(),()) + +CROSSNT_DECL( +HANDLE,__stdcall, +PsGetCurrentThreadId,(),()) + +CROSSNT_DECL( +BOOLEAN, +__fastcall, +KeTestSpinLock,( + IN PKSPIN_LOCK SpinLock + ), + ( + SpinLock + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedIncrement,( + IN OUT PLONG Addend + ), + ( + IN OUT PLONG Addend + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedDecrement,( + IN OUT PLONG Addend + ), + ( + IN OUT PLONG Addend + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedExchangeAdd,( + IN OUT PLONG Addend, + IN LONG Increment + ), + ( + IN OUT PLONG Addend, + IN LONG Increment + )) + +CROSSNT_DECL( +PVOID, +__fastcall, +InterlockedCompareExchange,( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + ), + ( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + )) + +CROSSNT_DECL_EX("HAL.DLL", +KIRQL,__stdcall, +KeRaiseIrqlToDpcLevel,(),()) + +CROSSNT_DECL_EX("HAL.DLL", +KIRQL,__stdcall, +KeRaiseIrqlToSynchLevel,(),()) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisInitializeReadWriteLock,( + IN PNDIS_RW_LOCK Lock + ), + ( + Lock + )) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisAcquireReadWriteLock,( + IN PNDIS_RW_LOCK Lock, + IN BOOLEAN fWrite, + IN PLOCK_STATE LockState + ), + ( + Lock, + fWrite, + LockState + )) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisReleaseReadWriteLock,( + IN PNDIS_RW_LOCK Lock, + IN PLOCK_STATE LockState + ), + ( + Lock, + LockState + )) + diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/CrossNt.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrossNt.h new file mode 100644 index 00000000000..5619834aa10 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/CrossNt.h @@ -0,0 +1,147 @@ +#ifndef __CROSS_VERSION_LIB_NT__H__ +#define __CROSS_VERSION_LIB_NT__H__ + +extern "C" { + +#pragma pack(push, 8) + +#if !defined(NT_INCLUDED) +#include // various NT definitions +#endif + +#include +#include +#include +#include +#include "ntddk_ex.h" + +#include "rwlock.h" + +#ifdef CROSS_NT_INTERNAL +#include "ilock.h" +#endif //CROSS_NT_INTERNAL + +#include "misc.h" +#include "tools.h" + +#pragma pack(pop) + +extern "C" +NTSTATUS +CrNtInit( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +extern "C" +ULONG +CrNtGetCPUGen(); + +extern "C" +PVOID +CrNtGetModuleBase( + IN PCHAR pModuleName + ); + +extern "C" +PVOID +CrNtFindModuleBaseByPtr( + IN PVOID ptrInSection, + IN PCHAR ptrExportedName + ); + +extern "C" +PVOID +CrNtGetProcAddress( + PVOID ModuleBase, + PCHAR pFunctionName + ); + +typedef BOOLEAN (__stdcall *ptrCrNtPsGetVersion)( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ); + +extern "C" +ptrCrNtPsGetVersion CrNtPsGetVersion; + +typedef NTSTATUS (__stdcall *ptrCrNtNtQuerySystemInformation)( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL + ); + +extern "C" +ptrCrNtNtQuerySystemInformation CrNtNtQuerySystemInformation; + +extern "C" +PVOID +CrNtSkipImportStub( + PVOID p + ); + +extern "C" { + +extern ULONG MajorVersion; +extern ULONG MinorVersion; +extern ULONG BuildNumber; +extern ULONG SPVersion; + +extern HANDLE g_hNtosKrnl; +extern HANDLE g_hHal; + +extern PCHAR g_KeNumberProcessors; + +}; + +#define WinVer_Is351 (MajorVersion==0x03) +#define WinVer_IsNT (MajorVersion==0x04) +#define WinVer_Is2k (MajorVersion==0x05 && MinorVersion==0x00) +#define WinVer_IsXP (MajorVersion==0x05 && MinorVersion==0x01) +#define WinVer_IsXPp (MajorVersion==0x05 && MinorVersion>=0x01) +#define WinVer_IsdNET (MajorVersion==0x05 && MinorVersion==0x02) +#define WinVer_IsdNETp ((MajorVersion==0x05 && MinorVersion>=0x02) || (MajorVersion>0x05)) +#define WinVer_IsVista (MajorVersion==0x06 && MinorVersion==0x00) + +#define WinVer_Id() ((MajorVersion << 8) | MinorVersion) + +#define WinVer_351 (0x0351) +#define WinVer_NT (0x0400) +#define WinVer_ROS (0x0401) +#define WinVer_2k (0x0500) +#define WinVer_XP (0x0501) +#define WinVer_dNET (0x0502) +#define WinVer_Vista (0x0600) + +#ifdef _DEBUG + +// NT3.51 doesn't export strlen() and strcmp() +// The same time, Release build doesn't depend no these functions since they are inlined + +size_t __cdecl CrNtstrlen ( + const char * str + ); + +int __cdecl CrNtstrcmp ( + const char * src, + const char * dst + ); + +#define strlen CrNtstrlen +#define strcmp CrNtstrcmp + +#endif //_DEBUG + +#define CROSSNT_DECL_API + +#include "CrNtDecl.h" +#include "CrNtStubs.h" + +#undef CROSSNT_DECL_API + +}; // end extern "C" + +#endif //__CROSS_VERSION_LIB_NT__H__ \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/ilock.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/ilock.h new file mode 100644 index 00000000000..4c1a7c4a68b --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/ilock.h @@ -0,0 +1,64 @@ +#ifndef __CROSS_NT_INTERLOCKED__H__ +#define __CROSS_NT_INTERLOCKED__H__ + +LONG +__fastcall +CrNtInterlockedIncrement_impl_i386_MP( + IN OUT PLONG Addend + ); + +LONG +__fastcall +CrNtInterlockedIncrement_impl_i386_UP( + IN OUT PLONG Addend + ); + +/********************************************************/ + +LONG +__fastcall +CrNtInterlockedDecrement_impl_i386_MP( + IN OUT PLONG Addend + ); + +LONG +__fastcall +CrNtInterlockedDecrement_impl_i386_UP( + IN OUT PLONG Addend + ); + +/********************************************************/ + +LONG +__fastcall +CrNtInterlockedExchangeAdd_impl_i386_MP( + IN OUT PLONG Addend, + IN LONG Increment + ); + +LONG +__fastcall +CrNtInterlockedExchangeAdd_impl_i386_UP( + IN OUT PLONG Addend, + IN LONG Increment + ); + +/********************************************************/ + +PVOID +__fastcall +CrNtInterlockedCompareExchange_impl_i386_MP( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + ); + +PVOID +__fastcall +CrNtInterlockedCompareExchange_impl_i386_UP( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + ); + +#endif __CROSS_NT_INTERLOCKED__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/misc.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/misc.h new file mode 100644 index 00000000000..5b0ac6f5c76 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/misc.h @@ -0,0 +1,148 @@ +#ifndef __CROSSNT_MISC__H__ +#define __CROSSNT_MISC__H__ + +#ifdef _X86_ + +typedef void +(__fastcall *ptrMOV_DD_SWP)( + void* a, // ECX + void* b // EDX + ); +extern "C" ptrMOV_DD_SWP _MOV_DD_SWP; + +extern "C" +void +__fastcall +_MOV_DD_SWP_i486( + void* a, // ECX + void* b // EDX + ); + +extern "C" +void +__fastcall +_MOV_DD_SWP_i386( + void* a, // ECX + void* b // EDX + ); +#define MOV_DD_SWP(a,b) _MOV_DD_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_DW_SWP( + void* a, // ECX + void* b // EDX + ); + +#define MOV_DW_SWP(a,b) _MOV_DW_SWP(&(a),&(b)) + +/********************/ + +typedef void +(__fastcall *ptrREVERSE_DD)( + void* a // ECX + ); +extern "C" ptrREVERSE_DD _REVERSE_DD; + +void +__fastcall +_REVERSE_DD_i486( + void* a // ECX + ); + +void +__fastcall +_REVERSE_DD_i386( + void* a // ECX + ); +#define REVERSE_DD(a) _REVERSE_DD(&(a)) + +/********************/ + +extern "C" +void +__fastcall +_REVERSE_DW( + void* a // ECX + ); + +#define REVERSE_DW(a) _REVERSE_DW(&(a)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_DW2DD_SWP( + void* a, // ECX + void* b // EDX + ); + +#define MOV_DW2DD_SWP(a,b) _MOV_DW2DD_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_SWP_DW2DD( + void* a, // ECX + void* b // EDX + ); + +#define MOV_SWP_DW2DD(a,b) _MOV_SWP_DW2DD(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_MSF( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF(a,b) _MOV_MSF(&(a),&(b)) + +/********************/ + +typedef void +(__fastcall *ptrMOV_MSF_SWP)( + void* a, // ECX + void* b // EDX + ); +extern "C" ptrMOV_MSF_SWP _MOV_MSF_SWP; + +extern "C" +void +__fastcall +_MOV_MSF_SWP_i486( + void* a, // ECX + void* b // EDX + ); + +extern "C" +void +__fastcall +_MOV_MSF_SWP_i386( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF_SWP(a,b) _MOV_MSF_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_XCHG_DD( + void* a, // ECX + void* b // EDX + ); +#define XCHG_DD(a,b) _XCHG_DD(&(a),&(b)) + +#endif //_X86_ + +#endif // __CROSSNT_MISC__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/CrossNt/rwlock.h b/reactos/drivers/filesystems/udfs/Include/CrossNt/rwlock.h new file mode 100644 index 00000000000..3f0bf2280bf --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/CrossNt/rwlock.h @@ -0,0 +1,39 @@ +#ifndef __CROSS_NT_RWLOCK__H__ +#define __CROSS_NT_RWLOCK__H__ + +#ifndef MAXIMUM_PROCESSORS +#define MAXIMUM_PROCESSORS 32 +#endif + +typedef union _NDIS_RW_LOCK_REFCOUNT { + unsigned int RefCount; + UCHAR cacheLine[16]; // One refCount per cache line +} NDIS_RW_LOCK_REFCOUNT; + +typedef struct _NDIS_RW_LOCK { + union { + struct { + KSPIN_LOCK SpinLock; + PVOID Context; + }; + UCHAR Reserved[16]; + }; + + NDIS_RW_LOCK_REFCOUNT RefCount[MAXIMUM_PROCESSORS]; +} NDIS_RW_LOCK, *PNDIS_RW_LOCK; + +typedef struct _LOCK_STATE { + USHORT LockState; + KIRQL OldIrql; +} LOCK_STATE, *PLOCK_STATE; + +#define RWLOCK_STATE_FREE 0 +#define RWLOCK_STATE_READ_ACQUIRED 1 +#define RWLOCK_STATE_WRITE_ACQUIRED 2 +#define RWLOCK_STATE_RECURSIVE 3 +#define RWLOCK_STATE_RELEASED 0xffff + +#define RWLOCK_FOR_WRITE TRUE +#define RWLOCK_FOR_READ FALSE + +#endif /* __CROSS_NT_RWLOCK__H__ */ diff --git a/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp b/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp new file mode 100644 index 00000000000..ed91fb0351e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp @@ -0,0 +1,1042 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Sys_Spec.cpp +* +* Module: UDF File System Driver +* (both User and Kernel mode execution) +* +* Description: +* Contains system-secific code +* +*************************************************************************/ + + +/* + This routine converts UDF timestamp to NT time + */ +LONGLONG +UDFTimeToNT( + IN PUDF_TIME_STAMP UdfTime + ) +{ + LONGLONG NtTime; + TIME_FIELDS TimeFields; + + TimeFields.Milliseconds = (USHORT)(UdfTime->centiseconds * 10 + UdfTime->hundredsOfMicroseconds / 100); + TimeFields.Second = (USHORT)(UdfTime->second); + TimeFields.Minute = (USHORT)(UdfTime->minute); + TimeFields.Hour = (USHORT)(UdfTime->hour); + TimeFields.Day = (USHORT)(UdfTime->day); + TimeFields.Month = (USHORT)(UdfTime->month); + TimeFields.Year = (USHORT)((UdfTime->year < 1601) ? 1601 : UdfTime->year); + + if (!RtlTimeFieldsToTime(&TimeFields, (PLARGE_INTEGER)&NtTime)) { + NtTime = 0; + } else { + ExLocalTimeToSystemTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&NtTime ); + } + + return NtTime; +} // end UDFTimeToNT() + + +/* + This routine converts NT time to UDF timestamp + */ +VOID +UDFTimeToUDF( + IN LONGLONG NtTime, + OUT PUDF_TIME_STAMP UdfTime + ) +{ + if(!NtTime) return; + LONGLONG LocalTime; + + TIME_FIELDS TimeFields; + + ExSystemTimeToLocalTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&LocalTime ); + RtlTimeToTimeFields( (PLARGE_INTEGER)&LocalTime, &TimeFields ); + + LocalTime /= 10; // microseconds + UdfTime->microseconds = (UCHAR)(NtTime % 100); + LocalTime /= 100; // hundreds of microseconds + UdfTime->hundredsOfMicroseconds = (UCHAR)(NtTime % 100); + LocalTime /= 100; // centiseconds + UdfTime->centiseconds = (UCHAR)(TimeFields.Milliseconds / 10); + UdfTime->second = (UCHAR)(TimeFields.Second); + UdfTime->minute = (UCHAR)(TimeFields.Minute); + UdfTime->hour = (UCHAR)(TimeFields.Hour); + UdfTime->day = (UCHAR)(TimeFields.Day); + UdfTime->month = (UCHAR)(TimeFields.Month); + UdfTime->year = (USHORT)(TimeFields.Year); + UdfTime->typeAndTimezone = (TIMESTAMP_TYPE_LOCAL << 14); +} // end UDFTimeToUDF() + +/* + */ +ULONG +UDFAttributesToNT( + IN PDIR_INDEX_ITEM FileDirNdx, + IN tag* FileEntry + ) +{ + ASSERT(FileDirNdx); + if( (FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) && + !(FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) + return FileDirNdx->SysAttr; + + ULONG NTAttr = 0; + ULONG attr = 0; //permissions + USHORT Flags = 0; + USHORT Type = 0; + UCHAR FCharact = 0; + + if(!FileEntry) { + if(!FileDirNdx->FileInfo) + return 0; + ValidateFileInfo(FileDirNdx->FileInfo); + FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; + } + if(FileEntry->tagIdent == TID_FILE_ENTRY) { + attr = ((PFILE_ENTRY)FileEntry)->permissions; + Flags = ((PFILE_ENTRY)FileEntry)->icbTag.flags; + Type = ((PFILE_ENTRY)FileEntry)->icbTag.fileType; + if(((PFILE_ENTRY)FileEntry)->fileLinkCount > 1) + FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + } else { + attr = ((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; + Flags = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; + Type = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; + if(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount > 1) + FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + } + FCharact = FileDirNdx->FileCharacteristics; + + if(Flags & ICB_FLAG_SYSTEM) NTAttr |= FILE_ATTRIBUTE_SYSTEM; + if(Flags & ICB_FLAG_ARCHIVE) NTAttr |= FILE_ATTRIBUTE_ARCHIVE; + if((Type == UDF_FILE_TYPE_DIRECTORY) || + (Type == UDF_FILE_TYPE_STREAMDIR) || + (FCharact & FILE_DIRECTORY)) { + NTAttr |= FILE_ATTRIBUTE_DIRECTORY; +#ifdef UDF_DBG + } else { + //NTAttr |= FILE_ATTRIBUTE_NORMAL; +#endif + } + if(FCharact & FILE_HIDDEN) NTAttr |= FILE_ATTRIBUTE_HIDDEN; + if( !(attr & PERM_O_WRITE) && + !(attr & PERM_G_WRITE) && + !(attr & PERM_U_WRITE) && + !(attr & PERM_O_DELETE) && + !(attr & PERM_G_DELETE) && + !(attr & PERM_U_DELETE) ) { + NTAttr |= FILE_ATTRIBUTE_READONLY; + } + FileDirNdx->SysAttr = NTAttr; + return NTAttr; +} // end UDFAttributesToNT() + +/* + */ +VOID +UDFAttributesToUDF( + IN PDIR_INDEX_ITEM FileDirNdx, + IN tag* FileEntry, + IN ULONG NTAttr + ) +{ + PULONG attr; //permissions + PUSHORT Flags; + PUCHAR Type; + PUCHAR FCharact; + + NTAttr &= UDF_VALID_FILE_ATTRIBUTES; + + if(!FileEntry) { + ASSERT(FileDirNdx); + if(!FileDirNdx->FileInfo) + return; + ValidateFileInfo(FileDirNdx->FileInfo); + FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; + FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } + if(FileEntry->tagIdent == TID_FILE_ENTRY) { + attr = &((PFILE_ENTRY)FileEntry)->permissions; + Flags = &((PFILE_ENTRY)FileEntry)->icbTag.flags; + Type = &((PFILE_ENTRY)FileEntry)->icbTag.fileType; + } else { + attr = &((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; + Flags = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; + Type = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; + } + FCharact = &(FileDirNdx->FileCharacteristics); + + if((*FCharact & FILE_DIRECTORY) || + (*Type == UDF_FILE_TYPE_STREAMDIR) || + (*Type == UDF_FILE_TYPE_DIRECTORY)) { + *FCharact |= FILE_DIRECTORY; + if(*Type != UDF_FILE_TYPE_STREAMDIR) + *Type = UDF_FILE_TYPE_DIRECTORY; + *attr |= (PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); + NTAttr |= FILE_ATTRIBUTE_DIRECTORY; + NTAttr &= ~FILE_ATTRIBUTE_NORMAL; + } else { + *FCharact &= ~FILE_DIRECTORY; + *Type = UDF_FILE_TYPE_REGULAR; + *attr &= ~(PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); + } + + if(NTAttr & FILE_ATTRIBUTE_SYSTEM) { + *Flags |= ICB_FLAG_SYSTEM; + } else { + *Flags &= ~ICB_FLAG_SYSTEM; + } + if(NTAttr & FILE_ATTRIBUTE_ARCHIVE) { + *Flags |= ICB_FLAG_ARCHIVE; + } else { + *Flags &= ~ICB_FLAG_ARCHIVE; + } + if(NTAttr & FILE_ATTRIBUTE_HIDDEN) { + *FCharact |= FILE_HIDDEN; + } else { + *FCharact &= ~FILE_HIDDEN; + } + *attr |= (PERM_O_READ | PERM_G_READ | PERM_U_READ); + if(!(NTAttr & FILE_ATTRIBUTE_READONLY)) { + *attr |= (PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | + PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | + PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); + } else { + *attr &= ~(PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | + PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | + PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); + } + FileDirNdx->SysAttr = NTAttr; + if(FileDirNdx->FileInfo) + FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + FileDirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + return; +} // end UDFAttributesToUDF() + +#ifndef _CONSOLE +/* + This routine fills PFILE_BOTH_DIR_INFORMATION structure (NT) + */ +NTSTATUS +UDFFileDirInfoToNT( + IN PVCB Vcb, + IN PDIR_INDEX_ITEM FileDirNdx, + OUT PFILE_BOTH_DIR_INFORMATION NTFileInfo + ) +{ + PFILE_ENTRY FileEntry; + UNICODE_STRING UdfName; + UNICODE_STRING DosName; + PEXTENDED_FILE_ENTRY ExFileEntry; + USHORT Ident; + BOOLEAN ReadSizes; + NTSTATUS status; + PtrUDFNTRequiredFCB NtReqFcb; + + KdPrint(("@=%#x, FileDirNdx %x\n", &Vcb, FileDirNdx)); + + ASSERT((ULONG)NTFileInfo > 0x1000); + RtlZeroMemory(NTFileInfo, sizeof(FILE_BOTH_DIR_INFORMATION)); + + DosName.Buffer = (PWCHAR)&(NTFileInfo->ShortName); + DosName.MaximumLength = sizeof(NTFileInfo->ShortName); // 12*sizeof(WCHAR) + + _SEH2_TRY { + KdPrint((" DirInfoToNT: %*.*S\n", FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + KdPrint((" DirInfoToNT: exception when printing file name\n")); + } _SEH2_END; + + if(FileDirNdx->FileInfo) { + KdPrint((" FileInfo\n")); + // validate FileInfo + ValidateFileInfo(FileDirNdx->FileInfo); + if(UDFGetFileLinkCount(FileDirNdx->FileInfo) > 1) + FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); + // read required sizes from Fcb (if any) if file is not linked + // otherwise we should read them from FileEntry + if(FileDirNdx->FileInfo->Fcb) { + KdPrint((" Fcb\n")); + NtReqFcb = FileDirNdx->FileInfo->Fcb->NTRequiredFCB; + NTFileInfo->CreationTime.QuadPart = NtReqFcb->CreationTime.QuadPart; + NTFileInfo->LastWriteTime.QuadPart = NtReqFcb->LastWriteTime.QuadPart; + NTFileInfo->LastAccessTime.QuadPart = NtReqFcb->LastAccessTime.QuadPart; + NTFileInfo->ChangeTime.QuadPart = NtReqFcb->ChangeTime.QuadPart; +// NTFileInfo->AllocationSize.QuadPart = NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; + NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; +/* FileDirNdx->FileSize = + NTFileInfo->EndOfFile.QuadPart = NtReqFcb->CommonFCBHeader.FileSize.QuadPart;*/ + NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; + if(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) { + KdPrint((" SYS_ATTR\n")); + NTFileInfo->FileAttributes = FileDirNdx->SysAttr; + goto get_name_only; + } + FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart; + FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart; + FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart; + FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart; + goto get_attr_only; + } + ASSERT(FileEntry); + } else if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || + (FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) { + LONG_AD feloc; + + KdPrint((" !SYS_ATTR\n")); + FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize); + if(!FileEntry) return STATUS_INSUFFICIENT_RESOURCES; + + feloc.extLength = Vcb->LBlockSize; + feloc.extLocation = FileDirNdx->FileEntryLoc; + + if(!NT_SUCCESS(status = UDFReadFileEntry(Vcb, &feloc, FileEntry, &Ident))) { + KdPrint((" !UDFReadFileEntry\n")); + MyFreePool__(FileEntry); + FileEntry = NULL; + goto get_name_only; + } + ReadSizes = TRUE; + } else { + KdPrint((" FileDirNdx\n")); + NTFileInfo->CreationTime.QuadPart = FileDirNdx->CreationTime; + NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->LastWriteTime; + NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->LastAccessTime; + NTFileInfo->ChangeTime.QuadPart = FileDirNdx->ChangeTime; + NTFileInfo->FileAttributes = FileDirNdx->SysAttr; + NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; + NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; + NTFileInfo->EaSize = 0; + FileEntry = NULL; + goto get_name_only; + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) + goto get_name_only; + + KdPrint((" direct\n")); + if(FileEntry->descTag.tagIdent == TID_FILE_ENTRY) { + KdPrint((" TID_FILE_ENTRY\n")); + if(ReadSizes) { + KdPrint((" ReadSizes\n")); + // Times + FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = + FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(FileEntry->modificationTime)); + FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(FileEntry->accessTime)); + FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(FileEntry->attrTime)); + // FileSize + FileDirNdx->FileSize = + NTFileInfo->EndOfFile.QuadPart = + FileEntry->informationLength; + KdPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", + FileEntry->informationLength, + FileEntry->lengthAllocDescs + )); + // AllocSize + FileDirNdx->AllocationSize = + NTFileInfo->AllocationSize.QuadPart = + (FileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); + } +// NTFileInfo->EaSize = 0;//FileEntry->lengthExtendedAttr; + } else if(FileEntry->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) { + ExFileEntry = (PEXTENDED_FILE_ENTRY)FileEntry; + KdPrint((" PEXTENDED_FILE_ENTRY\n")); + if(ReadSizes) { + KdPrint((" ReadSizes\n")); + // Times + FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = UDFTimeToNT(&(ExFileEntry->createTime)); + FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(ExFileEntry->modificationTime)); + FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(ExFileEntry->accessTime)); + FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(ExFileEntry->attrTime)); + // FileSize + FileDirNdx->FileSize = + NTFileInfo->EndOfFile.QuadPart = + ExFileEntry->informationLength; + KdPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", + FileEntry->informationLength, + FileEntry->lengthAllocDescs + )); + // AllocSize + FileDirNdx->AllocationSize = + NTFileInfo->AllocationSize.QuadPart = + (ExFileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); + } +// NTFileInfo->EaSize = 0;//ExFileEntry->lengthExtendedAttr; + } else { + KdPrint((" ???\n")); + goto get_name_only; + } + +get_attr_only: + + KdPrint((" get_attr")); + // do some substitutions + if(!FileDirNdx->CreationTime) { + FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = Vcb->VolCreationTime; + } + if(!FileDirNdx->LastAccessTime) { + FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->CreationTime; + } + if(!FileDirNdx->LastWriteTime) { + FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->CreationTime; + } + if(!FileDirNdx->ChangeTime) { + FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = FileDirNdx->CreationTime; + } + + FileDirNdx->SysAttr = + NTFileInfo->FileAttributes = UDFAttributesToNT(FileDirNdx, (tag*)FileEntry); + FileDirNdx->FI_Flags |= UDF_FI_FLAG_SYS_ATTR; + +get_name_only: + // get filename in standard Unicode format + UdfName = FileDirNdx->FName; + NTFileInfo->FileNameLength = UdfName.Length; + RtlCopyMemory((PCHAR)&(NTFileInfo->FileName), (PCHAR)(UdfName.Buffer), UdfName.MaximumLength); + if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_DOS)) { + KdPrint((" !UDF_FI_FLAG_DOS")); + UDFDOSName(Vcb, &DosName, &UdfName, + (FileDirNdx->FI_Flags & UDF_FI_FLAG_KEEP_NAME) ? TRUE : FALSE); + NTFileInfo->ShortNameLength = (UCHAR)DosName.Length; + } + // report zero EOF & AllocSize for Dirs + if(FileDirNdx->FileCharacteristics & FILE_DIRECTORY) { + KdPrint((" FILE_DIRECTORY")); + NTFileInfo->AllocationSize.QuadPart = + NTFileInfo->EndOfFile.QuadPart = 0; + } + KdPrint((" AllocationSize=%I64x, NTFileInfo->EndOfFile=%I64x", NTFileInfo->AllocationSize.QuadPart, NTFileInfo->EndOfFile.QuadPart)); + // free tmp buffer (if any) + KdPrint(("\n")); + if(FileEntry && !FileDirNdx->FileInfo) + MyFreePool__(FileEntry); + return STATUS_SUCCESS; +} // end UDFFileDirInfoToNT() + +#endif //_CONSOLE + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine changes xxxTime field(s) in (Ext)FileEntry + */ +VOID +UDFSetFileXTime( + IN PUDF_FILE_INFO FileInfo, + IN LONGLONG* CrtTime, + IN LONGLONG* AccTime, + IN LONGLONG* AttrTime, + IN LONGLONG* ChgTime + ) +{ + USHORT Ident; + PDIR_INDEX_ITEM DirNdx; + + ValidateFileInfo(FileInfo); + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); + Ident = FileInfo->Dloc->FileEntry->tagIdent; + + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + + if(AccTime) { + if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; + UDFTimeToUDF(*AccTime, &(fe->accessTime)); + } + if(AttrTime) { + if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; + UDFTimeToUDF(*AttrTime, &(fe->attrTime)); + } + if(ChgTime) { + if(DirNdx && *ChgTime) DirNdx->CreationTime = + DirNdx->LastWriteTime = *ChgTime; + UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); + } else + if(CrtTime) { + if(DirNdx && *CrtTime) DirNdx->CreationTime = + DirNdx->LastWriteTime = *CrtTime; + UDFTimeToUDF(*CrtTime, &(fe->modificationTime)); + } + + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + + if(AccTime) { + if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; + UDFTimeToUDF(*AccTime, &(fe->accessTime)); + } + if(AttrTime) { + if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; + UDFTimeToUDF(*AttrTime, &(fe->attrTime)); + } + if(ChgTime) { + if(DirNdx && *ChgTime) DirNdx->LastWriteTime = *ChgTime; + UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); + } + if(CrtTime) { + if(DirNdx && *CrtTime) DirNdx->CreationTime = *CrtTime; + UDFTimeToUDF(*CrtTime, &(fe->createTime)); + } + + } +} // end UDFSetFileXTime() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine gets xxxTime field(s) in (Ext)FileEntry + */ +VOID +UDFGetFileXTime( + IN PUDF_FILE_INFO FileInfo, + OUT LONGLONG* CrtTime, + OUT LONGLONG* AccTime, + OUT LONGLONG* AttrTime, + OUT LONGLONG* ChgTime + ) +{ + USHORT Ident; + + ValidateFileInfo(FileInfo); + + Ident = FileInfo->Dloc->FileEntry->tagIdent; + + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + + if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); + if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); + if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); + if(CrtTime) { + (*CrtTime) = *ChgTime; + } + + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + + if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); + if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); + if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); + if(CrtTime) *CrtTime = UDFTimeToNT(&(fe->createTime)); + + } + if(CrtTime) { + if(!(*CrtTime)) + KeQuerySystemTime((PLARGE_INTEGER)CrtTime); + if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; + if(AttrTime && !(*AttrTime)) (*AttrTime) = *CrtTime; + if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; + } +} // end UDFGetFileXTime() + +VOID +UDFNormalizeFileName( + IN PUNICODE_STRING FName, + IN USHORT valueCRC + ) +{ + PWCHAR buffer; + USHORT len; + + len = FName->Length/sizeof(WCHAR); + buffer = FName->Buffer; + + // check for '', '.' & '..' + if(!len) return; + if(!buffer[len-1]) { + FName->Length-=sizeof(WCHAR); + len--; + } + if(!len) return; + if(buffer[0] == UNICODE_PERIOD) { + if(len == 1) return; + if((buffer[1] == UNICODE_PERIOD) && (len == 2)) return; + } + + // check for trailing '.' + for(len--;len;len--) { + if( ((buffer[len] == UNICODE_PERIOD) || (buffer[len] == UNICODE_SPACE)) ) { + FName->Length-=sizeof(WCHAR); + buffer[len] = 0; + } else + break; + } +} // end UDFNormalizeFileName() + +#ifndef _CONSOLE + +void +__fastcall +UDFDOSNameOsNative( + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact + ) +{ + PWCHAR dosName = DosName->Buffer; + PWCHAR udfName = UdfName->Buffer; + uint32 udfLen = UdfName->Length / sizeof(WCHAR); + GENERATE_NAME_CONTEXT Ctx; + + if(KeepIntact && + (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { + if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) { + RtlCopyMemory(dosName, udfName, UdfName->Length); + DosName->Length = UdfName->Length; + return; + } + } + RtlZeroMemory(&Ctx, sizeof(GENERATE_NAME_CONTEXT)); + RtlGenerate8dot3Name(UdfName, FALSE, &Ctx, DosName); + +} // UDFDOSNameOsNative() + +#endif //_CONSOLE + +/*VOID +UDFNormalizeFileName( + IN PUNICODE_STRING FName, + IN USHORT valueCRC + ) +{ + WCHAR _newName[UDF_NAME_LEN+5]; + PWCHAR newName = (PWCHAR)(&_newName); + PWCHAR udfName = FName->Buffer; + LONG udfLen = FName->Length >> 1; + + LONG index, newIndex = 0, extIndex = 0, newExtIndex = 0, trailIndex = 0; + BOOLEAN needsCRC = FALSE, hasExt = FALSE; + WCHAR ext[UDF_EXT_SIZE], current; + + // handle CurrentDir ('.') and ParentDir ('..') cases + if((udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { + if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) + return; + } + + for (index = 0 ; index < udfLen ; index++) { + current = udfName[index]; + + // Look for illegal or unprintable characters. + if (UDFIsIllegalChar(current) || !UnicodeIsPrint(current)) { + needsCRC = TRUE; + current = ILLEGAL_CHAR_MARK; + // Skip Illegal characters(even spaces), + // but not periods. + while(index+1 < udfLen && + (UDFIsIllegalChar(udfName[index+1]) || + !UnicodeIsPrint(udfName[index+1])) && + udfName[index+1] != UNICODE_PERIOD) + index++; + } + + // Record position of extension, if one is found. + if ((current == UNICODE_PERIOD) && ((udfLen - index -1) <= UDF_EXT_SIZE)) { + if (udfLen == index + 1) { + // A trailing period is NOT an extension. + hasExt = FALSE; + } else { + hasExt = TRUE; + extIndex = index; + newExtIndex = newIndex; + } + } else if((current != UNICODE_PERIOD) && (current != UNICODE_SPACE)) { + trailIndex = index; + } + +// if (newIndex < MAXLEN) // tshi is always TRUE for WINNT + newName[newIndex] = current; + newIndex++; + + // For OS2, 95 & NT, truncate any trailing periods and\or spaces. + if (trailIndex != (newIndex - 1)) { + newIndex = trailIndex + 1; + needsCRC = TRUE; + hasExt = FALSE; //* Trailing period does not make an extension. + } + } + + if (needsCRC) { + int localExtIndex = 0; + if (hasExt) { + int maxFilenameLen; + //* Translate extension, and store it in ext. + for(index = 0; index maxFilenameLen) { + newIndex = maxFilenameLen; + } else { + newIndex = newExtIndex; + } + } else if (newIndex > UDF_NAME_LEN - 5) { + //If no extension, make sure to leave room for CRC. + newIndex = UDF_NAME_LEN - 5; + } + newName[newIndex++] = UNICODE_CRC_MARK; // Add mark for CRC. + //Calculate CRC from original filename from FileIdentifier. +// valueCRC = UDFUnicodeCksum(fidName, fidNameLen); +// / Convert 16-bits of CRC to hex characters. + newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; + newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; + newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; + newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; + // Place a translated extension at end, if found. + if (hasExt) { + newName[newIndex++] = UNICODE_PERIOD; + for (index = 0;index < localExtIndex ;index++ ) { + newName[newIndex++] = ext[index]; + } + } + } + + if(FName->Length == (USHORT)newIndex*sizeof(WCHAR)) { + RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); + return; + } + MyFreePool__(FName->Buffer); + FName->Buffer = (PWCHAR)MyAllocatePool__(UDF_FILENAME_MT, (newIndex+1)*sizeof(WCHAR)); + if(FName->Buffer) { + FName->Buffer[newIndex] = 0; + RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); + } + FName->Length = (USHORT)newIndex*sizeof(WCHAR); + FName->MaximumLength = (USHORT)(newIndex+1)*sizeof(WCHAR); +}*/ + +/*PUDF_FILE_INFO +UDFAllocFileInfo( + return ExAllocateFromZone(&(UDFGlobalData.FileInfoZoneHeader)); +)*/ + +#define STRING_BUFFER_ALIGNMENT (32) +#define STRING_BUFFER_ALIGN(sz) (((sz)+STRING_BUFFER_ALIGNMENT)&(~((ULONG)(STRING_BUFFER_ALIGNMENT-1)))) + +NTSTATUS +MyAppendUnicodeStringToString_( + IN PUNICODE_STRING Str1, + IN PUNICODE_STRING Str2 +#ifdef UDF_TRACK_UNICODE_STR + ,IN PCHAR Tag +#endif + ) +{ + PWCHAR tmp; + USHORT i; + +#ifdef UDF_TRACK_UNICODE_STR + #define UDF_UNC_STR_TAG Tag +#else + #define UDF_UNC_STR_TAG "AppUStr" +#endif + + tmp = Str1->Buffer; + i = Str1->Length + Str2->Length + sizeof(WCHAR); + ASSERT(Str1->MaximumLength); + if(i > Str1->MaximumLength) { + if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, + (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i)*2) ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + Str1->MaximumLength = i*2; + Str1->Buffer = tmp; + } + RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length); + +/* tmp = (PWCHAR)MyAllocatePoolTag__(NonPagedPool, i = Str1->Length + Str2->Length + sizeof(WCHAR), UDF_UNC_STR_TAG); + if(!tmp) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(tmp, Str1->Buffer, Str1->Length); + RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length);*/ + tmp[(i / sizeof(WCHAR)) - 1] = 0; + Str1->Length = i - sizeof(WCHAR); + //MyFreePool__(Str1->Buffer); +#ifdef UDF_DBG + if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { + ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); + } +#endif // UDF_DBG + return STATUS_SUCCESS; + +#undef UDF_UNC_STR_TAG + +} // end MyAppendUnicodeStringToString() + +NTSTATUS +MyAppendUnicodeToString_( + IN PUNICODE_STRING Str1, + IN PWSTR Str2 +#ifdef UDF_TRACK_UNICODE_STR + ,IN PCHAR Tag +#endif + ) +{ + PWCHAR tmp; + USHORT i; + +#ifdef UDF_TRACK_UNICODE_STR + #define UDF_UNC_STR_TAG Tag +#else + #define UDF_UNC_STR_TAG "AppStr" +#endif + +//#ifdef _X86_ +#ifdef _MSC_VER + + __asm push ebx + __asm push esi + + __asm xor ebx,ebx + __asm mov esi,Str2 +Scan_1: + __asm cmp [word ptr esi+ebx],0 + __asm je EO_Scan + __asm add ebx,2 + __asm jmp Scan_1 +EO_Scan: + __asm mov i,bx + + __asm pop esi + __asm pop ebx + +#else // NO X86 optimization, use generic C/C++ + + i=0; + while(Str2[i]) { + i++; + } + i *= sizeof(WCHAR); + +#endif // _X86_ + + tmp = Str1->Buffer; + ASSERT(Str1->MaximumLength); + if((Str1->Length+i+sizeof(WCHAR)) > Str1->MaximumLength) { + if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, + (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i + Str1->Length + sizeof(WCHAR))*2 ) ) { + return STATUS_INSUFFICIENT_RESOURCES; + } + Str1->MaximumLength = STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2; + Str1->Buffer = tmp; + } + RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2, i); + i+=Str1->Length; + tmp[(i / sizeof(WCHAR))] = 0; + Str1->Length = i; +#ifdef UDF_DBG +/* if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { + ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); + }*/ +#endif // UDF_DBG + return STATUS_SUCCESS; + +#undef UDF_UNC_STR_TAG + +} // end MyAppendUnicodeToString_() + +NTSTATUS +MyInitUnicodeString( + IN PUNICODE_STRING Str1, + IN PCWSTR Str2 + ) +{ + + USHORT i; + +//#ifdef _X86_ +#ifdef _MSC_VER + + __asm push ebx + __asm push esi + + __asm xor ebx,ebx + __asm mov esi,Str2 +Scan_1: + __asm cmp [word ptr esi+ebx],0 + __asm je EO_Scan + __asm add ebx,2 + __asm jmp Scan_1 +EO_Scan: + __asm mov i,bx + + __asm pop esi + __asm pop ebx + +#else // NO X86 optimization, use generic C/C++ + + i=0; + while(Str2[i]) { + i++; + } + i *= sizeof(WCHAR); + +#endif // _X86_ + + Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = i) + sizeof(WCHAR)); + Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); + if(!Str1->Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(Str1->Buffer, Str2, i); + Str1->Buffer[i/sizeof(WCHAR)] = 0; + return STATUS_SUCCESS; + +} // end MyInitUnicodeString() + +NTSTATUS +MyCloneUnicodeString( + IN PUNICODE_STRING Str1, + IN PUNICODE_STRING Str2 + ) +{ + Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = Str2->Length) + sizeof(WCHAR)); + Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); + if(!Str1->Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + ASSERT(Str2->Buffer); + RtlCopyMemory(Str1->Buffer, Str2->Buffer, Str2->Length); + Str1->Buffer[Str1->Length/sizeof(WCHAR)] = 0; + return STATUS_SUCCESS; + +} // end MyCloneUnicodeString() + +/* + This routine checks do we needn't read something from disk to + obtain Attributes & so on + */ +BOOLEAN +UDFIsDirInfoCached( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo + ) +{ + PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; + PDIR_INDEX_ITEM DirNdx; + for(uint_di i=2; DirNdx = UDFDirIndex(hDirNdx,i); i++) { + if(!(DirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || + (DirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) return FALSE; + } + return TRUE; +} // end UDFIsDirInfoCached() + +#ifndef UDF_READ_ONLY_BUILD +NTSTATUS +UDFDoesOSAllowFileToBeTargetForRename__( + IN PUDF_FILE_INFO FileInfo + ) +{ +#ifndef _CONSOLE + NTSTATUS RC; +#endif //_CONSOLE + + if(UDFIsADirectory(FileInfo)) + return STATUS_ACCESS_DENIED; + if(!FileInfo->ParentFile) + return STATUS_ACCESS_DENIED; + + if(UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index), + FileInfo->Dloc->FileEntry) & FILE_ATTRIBUTE_READONLY) + return STATUS_ACCESS_DENIED; + + if(!FileInfo->Fcb) + return STATUS_SUCCESS; +#ifndef _CONSOLE + RC = UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); + if(!NT_SUCCESS(RC)) + return RC; +#endif //_CONSOLE + if(!FileInfo->Fcb) + return STATUS_SUCCESS; +// RC = UDFMarkStreamsForDeletion(FileInfo->Fcb->Vcb, FileInfo->Fcb, TRUE); // Delete +/* RC = UDFSetDispositionInformation(FileInfo->Fcb, NULL, + FileInfo->Fcb->Vcb, NULL, TRUE); + if(NT_SUCCESS(RC)) { + FileInfo->Fcb->FCBFlags |= UDF_FCB_DELETED; + if(UDFGetFileLinkCount(FileInfo) <= 1) { + FileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; + } + } + return RC;*/ + return STATUS_ACCESS_DENIED; + +} // end UDFDoesOSAllowFileToBeTargetForRename__() + +NTSTATUS +UDFDoesOSAllowFileToBeUnlinked__( + IN PUDF_FILE_INFO FileInfo + ) +{ + PDIR_INDEX_HDR hCurDirNdx; + PDIR_INDEX_ITEM CurDirNdx; + uint_di i; +// IO_STATUS_BLOCK IoStatus; + + ASSERT(FileInfo->Dloc); + + if(!FileInfo->ParentFile) + return STATUS_CANNOT_DELETE; + if(FileInfo->Dloc->SDirInfo) + return STATUS_CANNOT_DELETE; + if(!UDFIsADirectory(FileInfo)) + return STATUS_SUCCESS; + +// UDFFlushAFile(FileInfo->Fcb, NULL, &IoStatus, 0); + hCurDirNdx = FileInfo->Dloc->DirIndex; + // check if we can delete all files + for(i=2; CurDirNdx = UDFDirIndex(hCurDirNdx,i); i++) { + // try to open Stream + if(CurDirNdx->FileInfo) + return STATUS_CANNOT_DELETE; + } +// return UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); + return STATUS_SUCCESS; +} // end UDFDoesOSAllowFileToBeUnlinked__() + +NTSTATUS +UDFDoesOSAllowFilePretendDeleted__( + IN PUDF_FILE_INFO FileInfo + ) +{ + PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); + if(!hDirNdx) return STATUS_CANNOT_DELETE; + PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); + if(!DirNdx) return STATUS_CANNOT_DELETE; + // we can't hide file that is not marked as deleted + if(!(DirNdx->FileCharacteristics & FILE_DELETED)) { + BrutePoint(); + +#ifndef _CONSOLE + if(!(FileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETED) )) +#endif //_CONSOLE + + return STATUS_CANNOT_DELETE; + } + return STATUS_SUCCESS; +} +#endif //UDF_READ_ONLY_BUILD + diff --git a/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.h b/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.h new file mode 100644 index 00000000000..19b03270b94 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.h @@ -0,0 +1,187 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: sys_spec_lib.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the UDF file system driver. +* +* Author: Alter +* +*************************************************************************/ + +#ifndef _UDF_SYS_SPEC_LIB__H_ +#define _UDF_SYS_SPEC_LIB__H_ + +typedef struct _UDF_PH_CALL_CONTEXT { + KEVENT event; + IO_STATUS_BLOCK IosbToUse; +} UDF_PH_CALL_CONTEXT, *PUDF_PH_CALL_CONTEXT; + +#ifdef _BROWSE_UDF_ + +// convert UDF timestamp to NT time +LONGLONG UDFTimeToNT(IN PUDF_TIME_STAMP UdfTime); +// translate UDF file attributes to NT ones +ULONG UDFAttributesToNT(IN PDIR_INDEX_ITEM FileDirNdx, + IN tag* FileEntry); +// translate NT file attributes to UDF ones +VOID UDFAttributesToUDF(IN PDIR_INDEX_ITEM FileDirNdx, + IN tag* FileEntry, + IN ULONG NTAttr); +// translate all file information to NT +NTSTATUS UDFFileDirInfoToNT(IN PVCB Vcb, + IN PDIR_INDEX_ITEM FileDirNdx, + OUT PFILE_BOTH_DIR_INFORMATION NTFileInfo); +// convert NT time to UDF timestamp +VOID UDFTimeToUDF(IN LONGLONG NtTime, + OUT PUDF_TIME_STAMP UdfTime); +// change xxxTime field(s) in (Ext)FileEntry +VOID UDFSetFileXTime(IN PUDF_FILE_INFO FileInfo, + IN LONGLONG* CrtTime, + IN LONGLONG* AccTime, + IN LONGLONG* AttrTime, + IN LONGLONG* ChgTime); +// get xxxTime field(s) in (Ext)FileEntry +VOID UDFGetFileXTime(IN PUDF_FILE_INFO FileInfo, + OUT LONGLONG* CrtTime, + OUT LONGLONG* AccTime, + OUT LONGLONG* AttrTime, + OUT LONGLONG* ChgTime); +// +#define UDFUpdateAccessTime(Vcb, FileInfo) \ +if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME) { \ + LONGLONG NtTime; \ + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); \ + UDFSetFileXTime(FileInfo, NULL, &NtTime, NULL, NULL); \ +} +// +#define UDFUpdateModifyTime(Vcb, FileInfo) \ +if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME) { \ + LONGLONG NtTime; \ + ULONG Attr; \ + PDIR_INDEX_ITEM DirNdx; \ + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); \ + UDFSetFileXTime(FileInfo, NULL, &NtTime, NULL, &NtTime); \ + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), (FileInfo)->Index); \ + Attr = UDFAttributesToNT(DirNdx, (FileInfo)->Dloc->FileEntry); \ + if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) \ + UDFAttributesToUDF(DirNdx, (FileInfo)->Dloc->FileEntry, Attr); \ +} +// +#define UDFUpdateAttrTime(Vcb, FileInfo) \ +if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) { \ + LONGLONG NtTime; \ + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); \ + UDFSetFileXTime(FileInfo, NULL, &NtTime, &NtTime, NULL); \ +} +// +#define UDFUpdateCreateTime(Vcb, FileInfo) \ +{ \ + LONGLONG NtTime; \ + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); \ + UDFSetFileXTime(FileInfo, &NtTime, &NtTime, &NtTime, &NtTime); \ +} + +void +__fastcall +UDFDOSNameOsNative( + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact + ); + +VOID UDFNormalizeFileName(IN PUNICODE_STRING FName, + IN USHORT valueCRC); + +NTSTATUS MyAppendUnicodeStringToString_(IN PUNICODE_STRING Str1, + IN PUNICODE_STRING Str2 +#ifdef UDF_TRACK_UNICODE_STR + ,IN PCHAR Tag +#endif + ); + +NTSTATUS MyAppendUnicodeToString_(IN PUNICODE_STRING Str1, + IN PWSTR Str2 +#ifdef UDF_TRACK_UNICODE_STR + ,IN PCHAR Tag +#endif + ); + +#ifdef UDF_TRACK_UNICODE_STR + #define MyAppendUnicodeStringToString(s1,s2) MyAppendUnicodeStringToString_(s1,s2,"AppUStr") + #define MyAppendUnicodeStringToStringTag(s1,s2,tag) MyAppendUnicodeStringToString_(s1,s2,tag) + #define MyAppendUnicodeToString(s1,s2) MyAppendUnicodeToString_(s1,s2,"AppStr") + #define MyAppendUnicodeToStringTag(s1,s2,tag) MyAppendUnicodeToString_(s1,s2,tag) +#else + #define MyAppendUnicodeStringToString(s1,s2) MyAppendUnicodeStringToString_(s1,s2) + #define MyAppendUnicodeStringToStringTag(s1,s2,tag) MyAppendUnicodeStringToString_(s1,s2) + #define MyAppendUnicodeToString(s1,s2) MyAppendUnicodeToString_(s1,s2) + #define MyAppendUnicodeToStringTag(s1,s2,tag) MyAppendUnicodeToString_(s1,s2) +#endif + +NTSTATUS MyInitUnicodeString(IN PUNICODE_STRING Str1, + IN PCWSTR Str2); + +NTSTATUS MyCloneUnicodeString(IN PUNICODE_STRING Str1, + IN PUNICODE_STRING Str2); + +/*ULONG MyCompareUnicodeString(PUNICODE_STRING s1, + PUNICODE_STRING s2, + BOOLEAN UpCase);*/ + +/* +#define UDFAllocFileInfo() \ + ExAllocateFromZone(&(UDFGlobalData.FileInfoZoneHeader)) +*/ + +#define UDFIsDataCached(Vcb,Lba,BCount) \ + ( WCacheIsInitialized__(&((Vcb)->FastCache)) && \ + (KeGetCurrentIrql() < DISPATCH_LEVEL) && \ + WCacheIsCached__(&((Vcb)->FastCache),Lba, BCount) ) + +BOOLEAN UDFIsDirInfoCached(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo); + +#define UDFGetNTFileId(Vcb, fi, fn) (((fi)->Dloc->FELoc.Mapping[0].extLocation - UDFPartStart(Vcb, -2)) + \ + ((ULONG)(UDFUnicodeCksum((fn)->Buffer, (fn)->Length/sizeof(WCHAR))) << 16) + \ + ((LONGLONG)Vcb<<32) ) + +#define UnicodeIsPrint(a) RtlIsValidOemCharacter(&(a)) + +#define UDFSysGetAllocSize(Vcb, Size) ((Size + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize - 1))) + +NTSTATUS UDFDoesOSAllowFileToBeTargetForRename__(IN PUDF_FILE_INFO FileInfo); +#define UDFDoesOSAllowFileToBeTargetForHLink__ UDFDoesOSAllowFileToBeTargetForRename__ +NTSTATUS UDFDoesOSAllowFileToBeUnlinked__(IN PUDF_FILE_INFO FileInfo); +#define UDFDoesOSAllowFileToBeMoved__ UDFDoesOSAllowFileToBeUnlinked__ +NTSTATUS UDFDoesOSAllowFilePretendDeleted__(IN PUDF_FILE_INFO FileInfo); +BOOLEAN UDFRemoveOSReferences__(IN PUDF_FILE_INFO FileInfo); + +#define UDFIsFSDevObj(DeviceObject) \ + (DeviceObject->DeviceExtension && \ + ( (((PVCB)(DeviceObject->DeviceExtension))->NodeIdentifier.NodeType == \ + UDF_NODE_TYPE_UDFFS_DEVOBJ) || \ + (((PVCB)(DeviceObject->DeviceExtension))->NodeIdentifier.NodeType == \ + UDF_NODE_TYPE_UDFFS_DRVOBJ) \ + ) \ + ) +/* +extern ULONG MajorVersion; +extern ULONG MinorVersion; +extern ULONG BuildNumber; + +#define WinVer_Is351 (MajorVersion==0x03 && MinorVersion==51) +#define WinVer_IsNT (MajorVersion==0x04) +#define WinVer_Is2k (MajorVersion==0x05 && MinorVersion==0x00) +#define WinVer_IsXP (MajorVersion==0x05 && MinorVersion==0x01) +#define WinVer_IsdNET (MajorVersion==0x05 && MinorVersion==0x02) +*/ +#endif //_BROWSE_UDF_ + +#endif // _UDF_SYS_SPEC_LIB__H_ diff --git a/reactos/drivers/filesystems/udfs/Include/check_env.h b/reactos/drivers/filesystems/udfs/Include/check_env.h new file mode 100644 index 00000000000..96c3b36b7ae --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/check_env.h @@ -0,0 +1,107 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __CHECK_EXECUTION_ENVIRONMENT__H__ +#define __CHECK_EXECUTION_ENVIRONMENT__H__ + +/* +// check mode +#ifdef NT_KERNEL_MODE + #ifdef NT_NATIVE_MODE + #error Error cannot combine Kernel and Natime + #endif // +#endif //NT_KERNEL_MODE +#ifdef NT_KERNEL_MODE + #if defined(NT_NATIVE_MODE) || defined(WIN_32_MODE) + #error !!!! Execution mode definition conflict !!!! + #endif // +#endif //NT_KERNEL_MODE +#ifdef NT_NATIVE_MODE + #if defined(WIN_32_MODE) + #error !!!! Execution mode definition conflict !!!! + #endif // +#endif //NT_NATIVE_MODE + +// include appropriate header(s) +#ifdef NT_KERNEL_MODE + + #ifdef NT_DEV_DRV_ENV + #include + #endif //NT_DEV_DRV_ENV + + #ifdef NT_FS_DRV_ENV + #include + #endif //NT_DEV_DRV_ENV + #include "Include/ntddk_ex.h" + + #ifdef WIN_32_ENV + #error Error: Win32 environment is not supported in Kernel Mode + #endif //WIN_32_ENV + +#endif //NT_KERNEL_MODE + +#ifdef NT_NATIVE_MODE + + #include "Include/nt_native.h" + #ifdef NT_DEV_DRV_ENV + #include "LibCdrw/env_spec_cdrw_w32.h" + #endif //NT_DEV_DRV_ENV + + #ifdef NT_FS_DRV_ENV + #error Error: FS Driver environment is not supported in Native Mode + #endif //NT_DEV_DRV_ENV + + #ifdef WIN_32_ENV + #endif //WIN_32_ENV + +#endif //NT_NATIVE_MODE + +#ifdef WIN_32_MODE + + #include "windows.h" + #ifdef NT_DEV_DRV_ENV + #include "LibCdrw/env_spec_cdrw_w32.h" + #endif //NT_DEV_DRV_ENV + + #ifdef NT_FS_DRV_ENV + #error Error: FS Driver environment is not supported in Win32 Mode + #endif //NT_DEV_DRV_ENV + + #ifdef WIN_32_ENV + #endif //WIN_32_ENV + +#endif //WIN_32_MODE +*/ + + +#ifdef NT_INCLUDED +#define NT_KERNEL_MODE +#endif //NT_INCLUDED + +#ifdef NT_NATIVE_MODE +//#define USER_MODE +#endif //NT_NATIVE_MODE + +// default to Win32 environment +#if (!defined(NT_KERNEL_MODE) && !defined(NT_NATIVE_MODE)) || defined(WIN_32_MODE) +//#warning !!!! Execution mode defaulted to WIN_32 !!!! +//#define USER_MODE +#define WIN_32_MODE +#endif + +// check mode +#ifdef NT_KERNEL_MODE + #if defined(NT_NATIVE_MODE) || defined(WIN_32_MODE) + #error !!!! Execution mode definition conflict !!!! + #endif // +#endif //NT_KERNEL_MODE +#ifdef NT_NATIVE_MODE + #if defined(WIN_32_MODE) + #error !!!! Execution mode definition conflict !!!! + #endif // +#endif //NT_NATIVE_MODE + + +#endif //__CHECK_EXECUTION_ENVIRONMENT__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/common.rc b/reactos/drivers/filesystems/udfs/Include/common.rc new file mode 100644 index 00000000000..39141920b6d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/common.rc @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: common.rc +// +//-------------------------------------------------------------------------- + +#include "version.h" + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR VER_STR_VENDOR_NAME +#define VER_FILEDESCRIPTION_STR_HDR "" +#define VER_LEGALCOPYRIGHT_YEARS "1999-2008" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 " VER_STR_VENDOR_NAME " " VER_LEGALCOPYRIGHT_YEARS +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR VER_STR_PRODUCT_NAME +#undef VER_LEGALTRADEMARKS_STR + +#define VER_LANGNEUTRAL + diff --git a/reactos/drivers/filesystems/udfs/Include/common_dwn.rc b/reactos/drivers/filesystems/udfs/Include/common_dwn.rc new file mode 100644 index 00000000000..39141920b6d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/common_dwn.rc @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: common.rc +// +//-------------------------------------------------------------------------- + +#include "version.h" + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR VER_STR_VENDOR_NAME +#define VER_FILEDESCRIPTION_STR_HDR "" +#define VER_LEGALCOPYRIGHT_YEARS "1999-2008" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 " VER_STR_VENDOR_NAME " " VER_LEGALCOPYRIGHT_YEARS +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR VER_STR_PRODUCT_NAME +#undef VER_LEGALTRADEMARKS_STR + +#define VER_LANGNEUTRAL + diff --git a/reactos/drivers/filesystems/udfs/Include/env_spec_nt.cpp b/reactos/drivers/filesystems/udfs/Include/env_spec_nt.cpp new file mode 100644 index 00000000000..310bed3bf82 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/env_spec_nt.cpp @@ -0,0 +1,595 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifdef NT_NATIVE_MODE + +#include "regtools.h" +#include + +/*typedef BOOLEAN (*PPsGetVersion) ( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ); + +//PPsGetVersion _PsGetVersion = PsGetVersion; + +/*NTSTATUS +KernelGetProcAddress( + PWCHAR DllName, + PUCHAR ProcName, + PVOID* ProcAddr + ) +{ + NTSTATUS RC; + HANDLE h; + UNICODE_STRING uname; + ANSI_STRING aname; + + RtlInitUnicodeString(&uname, DllName); + *ProcAddr = NULL; + + // RC = LdrGetDllHandle(NULL, NULL, &uname, &h); + if(!NT_SUCCESS(RC)) + return RC; + + RtlInitAnsiString(&aname, ProcName); + +// RC = LdrGetProcedureAddress(h, &aname, 0, ProcAddr); + return RC; +} */ + + +BOOLEAN +GetOsVersion( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ) +{ + WCHAR Str[32]; + ULONG mn=0, mj=0, bld=0; + +// if(_PsGetVersion) +// return _PsGetVersion(MajorVersion, MinorVersion, BuildNumber, CSDVersion); + + RtlZeroMemory(Str, sizeof(Str)); + if(RegTGetStringValue(NULL, L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + L"CurrentVersion", + &Str[0], sizeof(Str)-sizeof(WCHAR))) { + ULONG i=0; + WCHAR a; + while(a = Str[i]) { + if(a == '.') + break; + if(a < '0' || a > '9') + break; + mj = mj*16 + (a-'0'); + i++; + } + i++; + while(a = Str[i]) { + if(a == '.') + break; + if(a < '0' || a > '9') + break; + mn = mn*16 + (a-'0'); + i++; + } + } + + if(RegTGetStringValue(NULL, L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + L"CurrentBuildNumber", + &Str[0], sizeof(Str)-sizeof(WCHAR))) { + ULONG i=0; + WCHAR a; + while(a = Str[i]) { + if(a < '0' || a > '9') + break; + bld = bld*10 + (a-'0'); + i++; + } + } + if(MajorVersion) + *MajorVersion = mj; + if(MinorVersion) + *MinorVersion = mn; + if(BuildNumber) + *BuildNumber = bld; + return TRUE; +} + +BOOLEAN +MyDeviceIoControl( + HANDLE h, + DWORD dwIoControlCode, + PVOID lpInBuffer, + DWORD nInBufferSize, + PVOID lpOutBuffer, + DWORD nOutBufferSize, + DWORD* lpBytesReturned, + PVOID lpOverlapped + ) +{ + + NTSTATUS RC; + BOOLEAN DevIoCtl = TRUE; + IO_STATUS_BLOCK Iosb; + + if ( dwIoControlCode >> 16 == FILE_DEVICE_FILE_SYSTEM ) { + DevIoCtl = FALSE; + } else { + DevIoCtl = TRUE; + } + + if ( DevIoCtl ) { + RC = NtDeviceIoControlFile( + h, + NULL, + NULL, // APC routine + NULL, // APC Context + &Iosb, + dwIoControlCode, // IoControlCode + lpInBuffer, // Buffer for data to the FS + nInBufferSize, + lpOutBuffer, // OutputBuffer for data from the FS + nOutBufferSize // OutputBuffer Length + ); + } else { + RC = NtFsControlFile( + h, + NULL, + NULL, // APC routine + NULL, // APC Context + &Iosb, + dwIoControlCode, // IoControlCode + lpInBuffer, // Buffer for data to the FS + nInBufferSize, + lpOutBuffer, // OutputBuffer for data from the FS + nOutBufferSize // OutputBuffer Length + ); + } + + if ( RC == STATUS_PENDING) { + // Operation must complete before return & Iosb destroyed + RC = NtWaitForSingleObject( h, FALSE, NULL ); + if ( NT_SUCCESS(RC)) { + RC = Iosb.Status; + } + } + + if ( NT_SUCCESS(RC) ) { + *lpBytesReturned = Iosb.Information; + return TRUE; + } else { + // handle warning value STATUS_BUFFER_OVERFLOW somewhat correctly + if ( !NT_ERROR(RC) ) { + *lpBytesReturned = Iosb.Information; + } + return FALSE; + } +} + +VOID +Sleep( + ULONG t + ) +{ + LARGE_INTEGER delay = {0,0}; + delay.QuadPart = -10I64*1000*t; + NtDelayExecution(FALSE, &delay); +} + +HANDLE hGlobalHeap = NULL; + +extern "C" +PVOID +MyGlobalAlloc( + ULONG Size + ) +{ + if(!hGlobalHeap) { + // Initialize some heap + hGlobalHeap = RtlCreateHeap( HEAP_GROWABLE, // Flags + NULL, // HeapBase + 0, // ReserveSize + 0, // CommitSize + NULL, // Lock + NULL ); // Parameters + if(!hGlobalHeap || hGlobalHeap == (HANDLE)(-1)) { + hGlobalHeap = NULL; + return NULL; + } + } + return RtlAllocateHeap( hGlobalHeap, 0, Size ); +} + +extern "C" +VOID +MyGlobalFree( + PVOID Addr + ) +{ + if(!hGlobalHeap) { +// BrutePoint(); + return; + } + RtlFreeHeap( hGlobalHeap, 0, Addr ); + return; +} + +CHAR dbg_print_tmp_buff[2048]; +WCHAR dbg_stringBuffer[2048]; + +BOOLEAN was_enter = TRUE; + +extern "C" +VOID +PrintNtConsole( + PCHAR DebugMessage, + ... + ) +{ + int len; + UNICODE_STRING msgBuff; + va_list ap; + va_start(ap, DebugMessage); + + if(was_enter) { + strcpy(&dbg_print_tmp_buff[0], NT_DBG_PREFIX); + len = _vsnprintf(&dbg_print_tmp_buff[sizeof(NT_DBG_PREFIX)-1], 2047-sizeof(NT_DBG_PREFIX), DebugMessage, ap); + } else { + len = _vsnprintf(&dbg_print_tmp_buff[0], 2047, DebugMessage, ap); + } + dbg_print_tmp_buff[2047] = 0; + if(len > 0 && + (dbg_print_tmp_buff[len-1] == '\n' || + dbg_print_tmp_buff[len-1] == '\r') ) { + was_enter = TRUE; + } else { + was_enter = FALSE; + } + + len = swprintf( dbg_stringBuffer, L"%S", dbg_print_tmp_buff ); + msgBuff.Buffer = dbg_stringBuffer; + msgBuff.Length = len * sizeof(WCHAR); + msgBuff.MaximumLength = msgBuff.Length + sizeof(WCHAR); + NtDisplayString( &msgBuff ); + + va_end(ap); + +} // end PrintNtConsole() + +extern "C" +NTSTATUS +EnvFileOpenW( + PWCHAR Name, + HANDLE* ph + ) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + UNICODE_STRING fName; + + RtlInitUnicodeString(&fName, Name); + + InitializeObjectAttributes(&ObjectAttributes, &fName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtCreateFile(ph, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_COMPLETE_IF_OPLOCKED /*| FILE_WRITE_THROUGH*/, + NULL, + 0); + + return Status; +} // end EnvFileOpenW() + +extern "C" +NTSTATUS +EnvFileOpenA( + PCHAR Name, + HANDLE* ph + ) +{ + ULONG len; + PWCHAR NameW; + NTSTATUS Status; + + len = strlen(Name); + + NameW = (PWCHAR)MyAllocatePool__(NonPagedPool, (len+1)*sizeof(WCHAR)); + if(!NameW) + return STATUS_INSUFFICIENT_RESOURCES; + + swprintf(NameW, L"%S", Name); + + Status = EnvFileOpenW(NameW, ph); + + MyFreePool__(NameW); + + return Status; +} // end EnvFileOpenA() + +extern "C" +NTSTATUS +EnvFileClose( + HANDLE hFile + ) +{ + return NtClose(hFile); +} // end EnvFileClose() + +extern "C" +NTSTATUS +EnvFileGetSizeByHandle( + HANDLE hFile, + PLONGLONG lpFileSize + ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + FILE_STANDARD_INFORMATION StandardInfo; + + Status = NtQueryInformationFile( + hFile, + &IoStatusBlock, + &StandardInfo, + sizeof(StandardInfo), + FileStandardInformation + ); + if (NT_SUCCESS(Status)) { + *lpFileSize = StandardInfo.EndOfFile.QuadPart; + } + return Status; +} // end EnvFileGetSizeByHandle() + +extern "C" +NTSTATUS +EnvFileGetSizeA( + PCHAR Name, + PLONGLONG lpFileSize + ) +{ + NTSTATUS Status; + HANDLE hFile; + + (*lpFileSize) = -1I64; + + Status = EnvFileOpenA(Name, &hFile); + + if(!NT_SUCCESS(Status)) + return Status; + + Status = EnvFileGetSizeByHandle(hFile, lpFileSize); + + NtClose(hFile); + + return Status; +} // end EnvFileGetSizeA() + +extern "C" +NTSTATUS +EnvFileGetSizeW( + PWCHAR Name, + PLONGLONG lpFileSize + ) +{ + NTSTATUS Status; + HANDLE hFile; + + (*lpFileSize) = -1I64; + + Status = EnvFileOpenW(Name, &hFile); + + if(!NT_SUCCESS(Status)) + return Status; + + Status = EnvFileGetSizeByHandle(hFile, lpFileSize); + + NtClose(hFile); + + return Status; +} // end EnvFileGetSizeW() + +extern "C" +BOOLEAN +EnvFileExistsA(PCHAR Name) { + LONGLONG Size; + EnvFileGetSizeA(Name, &Size); + return Size != -1; +} + +extern "C" +BOOLEAN +EnvFileExistsW(PWCHAR Name) { + LONGLONG Size; + EnvFileGetSizeW(Name, &Size); + return Size != -1; +} + +extern "C" +NTSTATUS +EnvFileWrite( + HANDLE h, + PVOID ioBuffer, + ULONG Length, + PULONG bytesWritten + ) +{ + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + Status = NtWriteFile( + h, + NULL, // Event + NULL, // ApcRoutine + NULL, // ApcContext + &IoStatus, + ioBuffer, + Length, + NULL, // ByteOffset + NULL // Key + ); + (*bytesWritten) = IoStatus.Information; + + return Status; +} // end EnvFileWrite() + +extern "C" +NTSTATUS +EnvFileRead( + HANDLE h, + PVOID ioBuffer, + ULONG Length, + PULONG bytesRead + ) +{ + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + Status = NtReadFile( + h, + NULL, // Event + NULL, // ApcRoutine + NULL, // ApcContext + &IoStatus, + ioBuffer, + Length, + NULL, // ByteOffset + NULL // Key + ); + (*bytesRead) = IoStatus.Information; + + return Status; +} // end EnvFileRead() + +extern "C" +NTSTATUS +EnvFileSetPointer( + HANDLE hFile, + LONGLONG lDistanceToMove, + LONGLONG* lResultPointer, + DWORD dwMoveMethod + ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + FILE_POSITION_INFORMATION CurrentPosition; + FILE_STANDARD_INFORMATION FileInfo; + + switch (dwMoveMethod) { + case ENV_FILE_BEGIN : + CurrentPosition.CurrentByteOffset.QuadPart = lDistanceToMove; + break; + + case ENV_FILE_CURRENT : + + // Get the current position of the file pointer + Status = NtQueryInformationFile( + hFile, + &IoStatus, + &CurrentPosition, + sizeof(CurrentPosition), + FilePositionInformation + ); + if(!NT_SUCCESS(Status)) { + return Status; + } + CurrentPosition.CurrentByteOffset.QuadPart += lDistanceToMove; + break; + + case ENV_FILE_END : + Status = NtQueryInformationFile( + hFile, + &IoStatus, + &FileInfo, + sizeof(FileInfo), + FileStandardInformation + ); + if (!NT_SUCCESS(Status)) { + return Status; + } + CurrentPosition.CurrentByteOffset.QuadPart = + FileInfo.EndOfFile.QuadPart + lDistanceToMove; + break; + + default: + return STATUS_INVALID_PARAMETER; + } + + if ( CurrentPosition.CurrentByteOffset.QuadPart < 0 ) { + return Status; + } + + Status = NtSetInformationFile( + hFile, + &IoStatus, + &CurrentPosition, + sizeof(CurrentPosition), + FilePositionInformation + ); + + if(!NT_SUCCESS(Status)) { + return Status; + } + if(lResultPointer) { + *lResultPointer = CurrentPosition.CurrentByteOffset.QuadPart; + } + return STATUS_SUCCESS; +} // end EnvFileSetPointer() + +NTSTATUS EnvFileDeleteW(PWCHAR Name) { + + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + UNICODE_STRING fName; + HANDLE Handle; + FILE_DISPOSITION_INFORMATION Disposition; + + RtlInitUnicodeString(&fName, Name); + + InitializeObjectAttributes(&ObjectAttributes, &fName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtOpenFile( + &Handle, + (ACCESS_MASK)DELETE, + &ObjectAttributes, + &IoStatus, + FILE_SHARE_DELETE | + FILE_SHARE_READ | + FILE_SHARE_WRITE, + FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT + ); + + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + Disposition.DeleteFile = TRUE; + + Status = NtSetInformationFile( + Handle, + &IoStatus, + &Disposition, + sizeof(Disposition), + FileDispositionInformation + ); + + NtClose(Handle); + + return Status; +} +#endif //NT_NATIVE_MODE diff --git a/reactos/drivers/filesystems/udfs/Include/env_spec_nt.h b/reactos/drivers/filesystems/udfs/Include/env_spec_nt.h new file mode 100644 index 00000000000..c820f9da708 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/env_spec_nt.h @@ -0,0 +1,177 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __ENV_SPEC_NT_NATIVE__H__ +#define __ENV_SPEC_NT_NATIVE__H__ + +#ifdef NT_NATIVE_MODE + +#include "zw_2_nt.h" + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif //MAX_PATH + +BOOLEAN +GetOsVersion( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ); + +#define PsGetVersion(a,b,c,d) GetOsVersion(a,b,c,d) + +#define InterlockedIncrement(addr) \ + ((*addr)++) +#define InterlockedDecrement(addr) \ + ((*addr)--) +int +__inline +InterlockedExchangeAdd(PLONG addr, LONG i) { + LONG Old = (*addr); + (*addr) += i; + return Old; +} + +#define DeviceIoControl(h, ctlc, ib, is, ob, os, r, ov) MyDeviceIoControl(h, ctlc, ib, is, ob, os, r, ov) + +BOOLEAN +MyDeviceIoControl( + HANDLE hDevice, + DWORD dwIoControlCode, + PVOID lpInBuffer, + DWORD nInBufferSize, + PVOID lpOutBuffer, + DWORD nOutBufferSize, + DWORD* lpBytesReturned, + PVOID lpOverlapped + ); + +#define OemToCharW(ansi_s, uni_s) (swprintf(uni_s, L"%S", ansi_s)) +#define MultiByteToWideChar(cp, f, ansi_s, a_sz, uni_s, u_sz) (swprintf(uni_s, L"%S", ansi_s)) + +VOID +Sleep( + ULONG t + ); + +#define GlobalAlloc(foo, size) MyGlobalAlloc( size ); +#define GlobalFree(ptr) MyGlobalFree( ptr ); + +extern "C" +PVOID MyGlobalAlloc(ULONG Size); + +extern "C" +VOID MyGlobalFree(PVOID Addr); + +#define ExitProcess(Status) NtTerminateProcess( NtCurrentProcess(), Status ); + +extern "C" +VOID +PrintNtConsole( + PCHAR DebugMessage, + ... + ); + +extern "C" +NTSTATUS +EnvFileOpenW( + PWCHAR Name, + HANDLE* ph + ); + +extern "C" +NTSTATUS +EnvFileOpenA( + PCHAR Name, + HANDLE* ph + ); + +extern "C" +NTSTATUS +EnvFileClose( + HANDLE hFile + ); + +extern "C" +NTSTATUS +EnvFileGetSizeByHandle( + HANDLE hFile, + PLONGLONG lpFileSize + ); + +extern "C" +NTSTATUS +EnvFileGetSizeA( + PCHAR Name, + PLONGLONG lpFileSize + ); + +extern "C" +NTSTATUS +EnvFileGetSizeW( + PWCHAR Name, + PLONGLONG lpFileSize + ); + +extern "C" +BOOLEAN +EnvFileExistsA(PCHAR Name); + +extern "C" +BOOLEAN +EnvFileExistsW(PWCHAR Name); + +extern "C" +NTSTATUS +EnvFileWrite( + HANDLE h, + PVOID ioBuffer, + ULONG Length, + PULONG bytesWritten + ); + +extern "C" +NTSTATUS +EnvFileRead( + HANDLE h, + PVOID ioBuffer, + ULONG Length, + PULONG bytesRead + ); + +#define ENV_FILE_CURRENT 1 +#define ENV_FILE_END 2 +#define ENV_FILE_BEGIN 3 + +extern "C" +NTSTATUS +EnvFileSetPointer( + HANDLE hFile, + LONGLONG lDistanceToMove, + LONGLONG* lResultPointer, + DWORD dwMoveMethod + ); + +extern "C" +NTSTATUS +EnvFileDeleteW( + PWCHAR fName + ); + +#define PrintDbgConsole PrintNtConsole + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#endif //NT_NATIVE_MODE + +#endif //__ENV_SPEC_NT_NATIVE__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/env_spec_w32.cpp b/reactos/drivers/filesystems/udfs/Include/env_spec_w32.cpp new file mode 100644 index 00000000000..c24a894931a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/env_spec_w32.cpp @@ -0,0 +1,1149 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef UDF_FORMAT_MEDIA +ULONG LockMode = 0; +BOOLEAN opt_invalidate_volume = FALSE; +#endif //UDF_FORMAT_MEDIA + +#ifndef CDRW_W32 +#ifndef UDF_FORMAT_MEDIA +BOOLEAN open_as_device = FALSE; +#endif //UDF_FORMAT_MEDIA +#ifdef USE_SKIN_MODEL + +PSKIN_API SkinAPI = NULL; + +PSKIN_API +SkinLoad( + PWCHAR path, + HINSTANCE hInstance, // handle to current instance + HINSTANCE hPrevInstance, // handle to previous instance + int nCmdShow // show state + ) +{ + HMODULE hm; + PSKIN_API Skin; + PSKIN_API (__stdcall *SkinInit) (VOID); + + hm = LoadLibraryW(path); + if(!hm) + return NULL; + SkinInit = (PSKIN_API(__stdcall *)(void))GetProcAddress(hm, "SkinInit"); + if(!SkinInit) + return NULL; + Skin = SkinInit(); + if(!Skin) + return NULL; + Skin->Init(hInstance, hPrevInstance, nCmdShow); + return Skin; +} + + +#endif //USE_SKIN_MODEL + +#ifdef _BROWSE_UDF_ +#ifndef LIBUDF + +extern PVCB Vcb; + +#endif // LIBUDF +#endif //_BROWSE_UDF_ + +#ifdef LIBUDF +#define _lphUdf ((PUDF_VOL_HANDLE_I)(DeviceObject->lpContext)) +#endif //LIBUDF +#ifdef LIBUDFFMT +#define _lphUdf (DeviceObject->cbio) +#endif //LIBUDFFMT + +#ifndef CDRW_W32 + +NTSTATUS +UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PVOID Iosb OPTIONAL + ) +{ + ULONG real_read; +#if !defined(LIBUDF) && !defined(LIBUDFFMT) + ULONG ret; + + ULONG RC = DeviceIoControl(DeviceObject->h,IoControlCode, + InputBuffer,InputBufferLength, + OutputBuffer,OutputBufferLength, + &real_read,NULL); + + if (!RC) { + ret = GetLastError(); + } + return RC ? 1 : -1; + +#else // LIBUDF + + ULONG RC = _lphUdf->lpIOCtlFunc(_lphUdf->lpParameter,IoControlCode, + InputBuffer,InputBufferLength, + OutputBuffer,OutputBufferLength, + &real_read); + + return RC; + +#endif // LIBUDF + +} // end UDFPhSendIOCTL() + + +NTSTATUS +UDFPhReadSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG ReadBytes, + ULONG Flags + ) +{ + +#if !defined(LIBUDF) && !defined(LIBUDFFMT) + + NTSTATUS RC; +// KdPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0xb,Offset>>0xb)); + LONG HiOffs = (ULONG)(Offset >> 32); + + RC = SetFilePointer(DeviceObject->h,(ULONG)Offset,&HiOffs,FILE_BEGIN); + if(RC == INVALID_SET_FILE_POINTER) { + if(GetLastError() != NO_ERROR) { + KdPrint(("UDFPhReadSynchronous: error %x\n", GetLastError())); + return STATUS_END_OF_FILE; + } + } + RC = ReadFile(DeviceObject->h,Buffer,Length,ReadBytes,NULL); + if(NT_SUCCESS(RC) && + (!(*ReadBytes))) { + RC = GetLastError(); + return STATUS_END_OF_FILE; + } + return STATUS_SUCCESS; + +#else // LIBUDF + + return _lphUdf->lpReadFunc(_lphUdf->lpParameter, + Buffer, + Length, + Offset, + ReadBytes); + +#endif //defined LIBUDF || defined LIBUDFFMT + +} // end UDFPhReadSynchronous() + + +NTSTATUS +UDFPhWriteSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags + ) +{ +#if !defined(LIBUDF) && !defined(LIBUDFFMT) + + NTSTATUS RC = STATUS_SUCCESS; + LONG HiOffs = (ULONG)(Offset >> 32); + PVOID Buffer2 = NULL; + PVOID Buffer3 = NULL; + + RC = SetFilePointer(DeviceObject->h,(ULONG)Offset,&HiOffs,FILE_BEGIN); + if(RC == INVALID_SET_FILE_POINTER) { + if(GetLastError() != NO_ERROR) { + KdPrint(("UDFPhWriteSynchronous: error %x\n", GetLastError())); + return STATUS_END_OF_FILE; + } + } + + Buffer2 = ExAllocatePool(NonPagedPool, Length+0x10000); + Buffer3 = (PVOID)( ((ULONG)Buffer2 + 0xffff) & ~0xffff); + RtlCopyMemory(Buffer3, Buffer, Length); + + RC = WriteFile(DeviceObject->h,Buffer3,Length,WrittenBytes,NULL); + if(!RC || + !(*WrittenBytes)) { + RC = GetLastError(); + KdPrint(("UDFPhWriteSynchronous: EOF, error %x\n", RC)); + RC = STATUS_END_OF_FILE; + } else { + RC = STATUS_SUCCESS; + } + + if(Buffer2) ExFreePool(Buffer2); + + return RC; + +#else // LIBUDF + + return _lphUdf->lpWriteFunc(_lphUdf->lpParameter, + Buffer, + Length, + Offset, + WrittenBytes); + +#endif // LIBUDF + +} // end UDFPhWriteSynchronous() + +#if 0 +NTSTATUS +UDFPhWriteVerifySynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags + ) +{ + NTSTATUS RC; + PUCHAR v_buff = NULL; + ULONG ReadBytes; + + RC = UDFPhWriteSynchronous(DeviceObject, Buffer, Length, Offset, WrittenBytes, 0); + if(!Verify) + return RC; + v_buff = (PUCHAR)DbgAllocatePool(NonPagedPool, Length); + if(!v_buff) + return RC; + + RC = UDFPhSendIOCTL( IOCTL_CDRW_SYNC_CACHE, DeviceObject, + NULL,0, NULL,0, FALSE, NULL); + + RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, 0); + if(!NT_SUCCESS(RC)) { + BrutePoint(); + DbgFreePool(v_buff); + return RC; + } + if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) { + DbgFreePool(v_buff); + return RC; + } + BrutePoint(); + DbgFreePool(v_buff); + return STATUS_LOST_WRITEBEHIND_DATA; +} // end UDFPhWriteVerifySynchronous() +#endif + +VOID +set_image_size( + HANDLE h, +// ULONG LBA) + int64 len) +{ + LONG offh = (ULONG)(len >> 32); + //( (LONGLONG)LBA >> (32-Vcb->BlockSizeBits) ); + + SetFilePointer((HANDLE)h, (ULONG)(len /*(LBA << Vcb->BlockSizeBits)*/ ), &offh, FILE_BEGIN); + SetEndOfFile(h); + offh = 0; + SetFilePointer((HANDLE)h, 0, &offh, FILE_BEGIN); +} // end set_image_size() + +int64 +get_file_size( + HANDLE h + ) +{ + LONG hsz = 0; + LONG lsz; + + lsz = SetFilePointer(h, 0, &hsz, FILE_END); + return (((int64)hsz) << 32) | lsz; +} // end get_file_size() + +int64 +set_file_pointer( + HANDLE h, + int64 sz + ) +{ + ULONG hsz = (ULONG)(sz >> 32); + ULONG lsz = (ULONG)sz; + + lsz = SetFilePointer(h, lsz, (PLONG)&hsz, FILE_BEGIN); + return (((int64)hsz) << 32) | lsz; +} // end set_file_pointer() + +#endif //CDRW_W32 + +#ifndef LIBUDF + +#ifndef UDF_FORMAT_MEDIA + +ULONG +write( + PVCB Vcb, + HANDLE h, + PCHAR buff, + ULONG len) +{ + ULONG written; + LONG offh = 0; + ULONG offl = SetFilePointer((HANDLE)h, 0, &offh, FILE_CURRENT); +// ULONG Lba = (ULONG)((((LONGLONG)offh << 32) + offl) >> Vcb->BlockSizeBits); + + UDFWriteData(Vcb, FALSE, (((LONGLONG)offh)<<32)+offl, len, FALSE, buff, &written); + + SetFilePointer((HANDLE)h, offl, &offh, FILE_BEGIN); + offh = 0; + SetFilePointer((HANDLE)h, written, &offh, FILE_CURRENT); + + return written; +} // end write() +#endif //UDF_FORMAT_MEDIA + +#endif // LIBUDF + +#endif //CDRW_W32 + +#ifdef NT_NATIVE_MODE + +BOOL +Privilege( + LPTSTR pszPrivilege, + BOOL bEnable + ) +{ +#ifndef NT_NATIVE_MODE + HANDLE hToken; + TOKEN_PRIVILEGES tp; + + // obtain the token, first check the thread and then the process + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &hToken)) { + if (GetLastError() == ERROR_NO_TOKEN) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + return FALSE; + } + } else { + return FALSE; + } + } + + // get the luid for the privilege + if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid)) { + CloseHandle(hToken); + return FALSE; + } + + tp.PrivilegeCount = 1; + + if (bEnable) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // enable or disable the privilege + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0)) { + CloseHandle(hToken); + return FALSE; + } + + if (!CloseHandle(hToken)) + return FALSE; + +#endif //NT_NATIVE_MODE + + return TRUE; + +} // end Privilege() +#endif //NT_NATIVE_MODE + +#ifndef LIBUDF + +extern "C" +ULONG +MyLockVolume( + HANDLE h, + ULONG* pLockMode // OUT + ) +{ + ULONG RC; + ULONG returned; + + (*pLockMode) = -1; +#ifndef CDRW_W32 + RC = DeviceIoControl(h,IOCTL_UDF_LOCK_VOLUME_BY_PID,NULL,0,NULL,0,&returned,NULL); + if(RC) { + (*pLockMode) = IOCTL_UDF_LOCK_VOLUME_BY_PID; + return STATUS_SUCCESS; + } +#endif //CDRW_W32 + + RC = DeviceIoControl(h,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&returned,NULL); + if(RC) { + (*pLockMode) = FSCTL_LOCK_VOLUME; + return STATUS_SUCCESS; + } + return STATUS_UNSUCCESSFUL; +} // MyLockVolume() + +extern "C" +ULONG +MyUnlockVolume( + HANDLE h, + ULONG* pLockMode // IN + ) +{ + ULONG returned; + +#ifndef CDRW_W32 + if((*pLockMode) == IOCTL_UDF_LOCK_VOLUME_BY_PID) { + return DeviceIoControl(h,IOCTL_UDF_UNLOCK_VOLUME_BY_PID,NULL,0,NULL,0,&returned,NULL); + } +#endif //CDRW_W32 + + return DeviceIoControl(h,FSCTL_UNLOCK_VOLUME,NULL,0,NULL,0,&returned,NULL); + +} // MyUnlockVolume() + +void +my_retrieve_vol_type( +#ifndef CDRW_W32 + PVCB Vcb, +#endif + PWCHAR fn + ) +{ +#ifndef CDRW_W32 + if(wcslen(fn) == 2 && fn[1] == ':') { + ULONG DevType = GetDriveTypeW(fn); + KdPrint((" DevType %x\n", DevType)); + switch(DevType) { + case DRIVE_CDROM: + Vcb->PhDeviceType = FILE_DEVICE_CD_ROM; + break; + default: + Vcb->PhDeviceType = FILE_DEVICE_DISK; + break; + } + } + if(wcslen(fn) == 2 && fn[1] == ';') { + UserPrint(("Warrning: File name is similar to drive letter.\n" + " Don't you type semicolon ';' instead of colon ':' ?\n")); + } +#endif //CDRW_W32 +} // end my_retrieve_vol_type() + + +#ifdef NT_NATIVE_MODE +#define GetLastError() ((ULONG)(-1)) +#endif //NT_NATIVE_MODE + +#define MAX_INVALIDATE_VOLUME_RETRY 8 + +extern "C" +HANDLE +my_open( +#ifndef CDRW_W32 + PVCB Vcb, +#endif + PWCHAR fn + ) +{ + HANDLE h/*, h2*/; + WCHAR deviceNameBuffer[0x200]; + WCHAR FSNameBuffer[0x200]; +// CCHAR RealDeviceName[0x200]; +// WCHAR DeviceName[MAX_PATH+1]; + ULONG RC; + ULONG retry; + ULONG i; + BOOLEAN CantLock = FALSE; + PULONG pLockMode; +#ifdef NT_NATIVE_MODE + IO_STATUS_BLOCK ioStatus; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING uniFilename; +#endif //NT_NATIVE_MODE + ULONG returned; + +#ifndef CDRW_W32 +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; + fms-> +#endif + open_as_device = TRUE; +#endif //CDRW_W32 + + pLockMode = & +#ifdef UDF_FORMAT_MEDIA + fms-> +#endif + LockMode; + + // make several retries to workaround smart applications, + // those attempts to work with volume immediately after arrival + retry = 1 + +#ifdef UDF_FORMAT_MEDIA + fms-> +#endif + opt_invalidate_volume ? 0 : MAX_INVALIDATE_VOLUME_RETRY; + +#ifndef NT_NATIVE_MODE + swprintf(deviceNameBuffer, L"%ws\\", fn); + KdPrint(("my_open: %S\n", fn)); + i = sizeof(FSNameBuffer)/sizeof(FSNameBuffer[0]); + if(GetVolumeInformationW(deviceNameBuffer, NULL, 0, + &returned, &returned, &returned, FSNameBuffer, i)) { + KdPrint(("my_open: FS: %S\n", FSNameBuffer)); + if(!wcscmp(FSNameBuffer, L"Unknown")) { + retry++; + } + } else { + KdPrint(("my_open: FS: ???\n")); + } + KdPrint(("my_open: retry %d times\n", retry)); + +#endif //NT_NATIVE_MODE + + do { + // open as device +#ifndef NT_NATIVE_MODE + swprintf(deviceNameBuffer, L"\\\\.\\%ws", fn); + if(wcslen(fn) == 2 && fn[1] == ';') { + UserPrint(("Warrning: File name is similar to drive letter.\n" + " Don't you type semicolon ';' instead of colon ':' ?\n")); + } + h = (HANDLE)(-1); + for(i=0; i<4; i++) { + if(h == ((HANDLE)-1)) { + h = CreateFileW(deviceNameBuffer, GENERIC_READ | GENERIC_WRITE, + ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); + if(h != ((HANDLE)-1)) { + KdPrint((" opened i=%x\n", i)); + } + } + } +#else //NT_NATIVE_MODE + uniFilename.Length = swprintf(deviceNameBuffer, L"\\??\\%ws", fn); + uniFilename.Buffer = deviceNameBuffer; + uniFilename.Length *= sizeof(WCHAR); + uniFilename.MaximumLength = uniFilename.Length + sizeof(WCHAR); + + h = (HANDLE)(-1); + for(i=0; i<4; i++) { + InitializeObjectAttributes(&ObjectAttributes, &uniFilename, OBJ_CASE_INSENSITIVE, NULL, NULL); + if(h == ((HANDLE)-1)) { + RC = NtCreateFile(&h, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &ioStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE), + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_COMPLETE_IF_OPLOCKED | FILE_WRITE_THROUGH | FILE_NO_INTERMEDIATE_BUFFERING, + NULL, + 0); + if(!NT_SUCCESS(RC)) { + KdPrint((" opened i2=%x\n", i)); + h = ((HANDLE)-1); + } + } + } +#endif //NT_NATIVE_MODE + if(h != ((HANDLE)-1)) { +#ifndef CDRW_W32 +#ifdef UDF_FORMAT_MEDIA + if(fms->opt_flush || fms->opt_probe) { + return h; + } +#endif //UDF_FORMAT_MEDIA + my_retrieve_vol_type(Vcb, fn); +#else + my_retrieve_vol_type(fn); +#endif //CDRW_W32 + if(!NT_SUCCESS(MyLockVolume(h,pLockMode))) { +#ifndef CDRW_W32 + if(retry < MAX_INVALIDATE_VOLUME_RETRY) { + retry++; + if(!Privilege(SE_TCB_NAME, TRUE)) { + KdPrint(("SE_TCB privilege not held\n")); + } else + if(DeviceIoControl(h,FSCTL_INVALIDATE_VOLUMES,&h,sizeof(h),NULL,0,&returned,NULL) ) { + KdPrint((" FSCTL_INVALIDATE_VOLUMES ok, status %x\n", GetLastError())); + CloseHandle(h); + continue; + } else { +//#ifndef CDRW_W32 + KdPrint((" FSCTL_INVALIDATE_VOLUMES failed, error %x\n", GetLastError())); + RC = GetLastError(); + if(DeviceIoControl(h,IOCTL_UDF_INVALIDATE_VOLUMES,&h,sizeof(h),NULL,0,&returned,NULL) ) { + KdPrint((" IOCTL_UDF_INVALIDATE_VOLUMES ok, status %x\n", GetLastError())); + CloseHandle(h); + continue; + } + KdPrint((" IOCTL_UDF_INVALIDATE_VOLUMES, error %x\n", GetLastError())); +//#endif //CDRW_W32 + } + UserPrint(("can't lock volume, retry\n")); + CloseHandle(h); + continue; + } +#endif //CDRW_W32 + UserPrint(("can't lock volume\n")); +#ifndef NT_NATIVE_MODE + // In native mode the volume can be not mounted yet !!! + CantLock = TRUE; + CloseHandle(h); + h = NULL; + goto try_as_file; +#endif //NT_NATIVE_MODE + } +//#ifndef CDRW_W32 + if(!DeviceIoControl(h,FSCTL_ALLOW_EXTENDED_DASD_IO,NULL,0,NULL,0,&returned,NULL)) { + KdPrint(("Warning: can't allow extended DASD i/o\n")); + } +//#endif //CDRW_W32 + + KdPrint((" opened, h=%x\n", h)); + return h; + } + RC = GetLastError(); + +#ifndef NT_NATIVE_MODE + h = CreateFileW(deviceNameBuffer, GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); +#else //NT_NATIVE_MODE + RC = NtCreateFile(&h, + GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &ioStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_COMPLETE_IF_OPLOCKED | FILE_WRITE_THROUGH, + NULL, + 0); + if(!NT_SUCCESS(RC)) { + h = ((HANDLE)-1); + } +#endif //NT_NATIVE_MODE + if(h != ((HANDLE)-1)) { + + KdPrint((" opened R/O, h=%x\n", h)); +#ifndef CDRW_W32 + my_retrieve_vol_type(Vcb, fn); +#else + my_retrieve_vol_type(fn); +#endif + + UserPrint(("read-only open\n")); + if(!NT_SUCCESS(MyLockVolume(h,pLockMode))) { +#ifndef CDRW_W32 + if(retry < MAX_INVALIDATE_VOLUME_RETRY) { + retry++; + if(!Privilege(SE_TCB_NAME, TRUE)) { + KdPrint(("SE_TCB privilege not held\n")); + } else + if(DeviceIoControl(h,FSCTL_INVALIDATE_VOLUMES,&h,sizeof(h),NULL,0,&returned,NULL) ) { + CloseHandle(h); + continue; + } + UserPrint(("can't lock read-only volumem retry")); + CloseHandle(h); + continue; + } +#endif //CDRW_W32 + UserPrint(("can't lock read-only volume")); +#ifndef NT_NATIVE_MODE + CantLock = TRUE; + CloseHandle(h); + h = NULL; + goto try_as_file; +#endif //NT_NATIVE_MODE + } +// write_cdfs = TRUE; +// DeviceIoControl(h,FSCTL_DISMOUNT_VOLUME,NULL,0,NULL,0,&returned,NULL); + return h; + } +#ifndef NT_NATIVE_MODE +try_as_file: +#endif //NT_NATIVE_MODE + +#ifndef CDRW_W32 +#ifdef UDF_FORMAT_MEDIA + fms-> +#endif + open_as_device = FALSE; + // open as plain file + Vcb->PhDeviceType = FILE_DEVICE_DISK; +#endif //CDRW_W32 + + UserPrint(("try image file\n")); +#ifndef NT_NATIVE_MODE + h = CreateFileW(fn, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); +#else //NT_NATIVE_MODE + RC = NtCreateFile(&h, + GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &ioStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_COMPLETE_IF_OPLOCKED | FILE_WRITE_THROUGH, + NULL, + 0); + if(!NT_SUCCESS(RC)) { + h = ((HANDLE)-1); + } +#endif //NT_NATIVE_MODE + if(h == ((HANDLE)-1)) { + + RC = GetLastError(); + if(CantLock) { +#ifndef CDRW_W32 + my_exit( +#ifdef UDF_FORMAT_MEDIA + fms, +#endif + MKUDF_CANT_LOCK_VOL); +#else + return NULL; +#endif //CDRW_W32 + } +#ifndef CDRW_W32 + UserPrint(("error opening device or image file")); + my_exit( +#ifdef UDF_FORMAT_MEDIA + fms, +#endif + MKUDF_CANT_OPEN_FILE); +#else + return NULL; +#endif //CDRW_W32 + } + KdPrint((" opened as file, h=%x\n", h)); + break; + + } while(TRUE); + return h; +} // end my_open() + +#endif //LIBUDF + +#ifndef CDRW_W32 + +uint64 +udf_lseek64( + HANDLE fd, + uint64 offset, + int whence) +{ + LONG offh = (ULONG)(offset>>32); + LONG offl; + offl = SetFilePointer(fd, (ULONG)offset, &offh, whence); + if(offl == -1 && offh == -1) { + return -1; + } + return (((uint64)offh) << 32) | (uint64)offl; +} // end udf_lseek64() + +#ifdef LIBUDFFMT +BOOLEAN +udf_get_sizes( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG* blocks + ) +{ + ULONG bs; + int64 sz; + ULONG RC; + + RC = _lphUdf->lpGetSizeFunc(_lphUdf->lpParameter, &sz, &bs); + + (*blocks) = (ULONG)(sz/bs); + + return(OS_SUCCESS(RC)); +} +#endif //LIBUDFFMT + +#include "string_lib.cpp" + +#ifdef _BROWSE_UDF_ +#ifndef LIBUDF + +ULONG +UDFGetDevType( + PDEVICE_OBJECT DeviceObject + ) +{ + if(DeviceObject && DeviceObject == Vcb->TargetDeviceObject) { + return Vcb->PhDeviceType; + } + return FILE_DEVICE_DISK; +} // end UDFGetDevType() + +#else // LIBUDF + +ULONG +UDFGetDevType( + PDEVICE_OBJECT DeviceObject + ) +{ +#define lphUdf ((PUDF_VOL_HANDLE_I)(DeviceObject->lpContext)) + return lphUdf->bHddDevice ? FILE_DEVICE_DISK : FILE_DEVICE_CD_ROM; +#undef lphUdf +} // end UDFGetDevType() + +#endif // LIBUDF + +#endif //_BROWSE_UDF_ + +#endif //CDRW_W32 + +#ifndef NT_NATIVE_MODE + +#ifdef PRINT_DBG_CONSOLE +CHAR dbg_print_tmp_buff[2048]; + +BOOLEAN was_enter = TRUE; + +extern "C" +VOID +PrintDbgConsole( + PCHAR DebugMessage, + ... + ) +{ + int len; + va_list ap; + va_start(ap, DebugMessage); + + if(was_enter) { + strcpy(&dbg_print_tmp_buff[0], JS_DBG_PREFIX); + len = _vsnprintf(&dbg_print_tmp_buff[sizeof(JS_DBG_PREFIX)-1], 2047-sizeof(JS_DBG_PREFIX), DebugMessage, ap); + } else { + len = _vsnprintf(&dbg_print_tmp_buff[0], 2047, DebugMessage, ap); + } + dbg_print_tmp_buff[2047] = 0; + if(len > 0 && + (dbg_print_tmp_buff[len-1] == '\n' || + dbg_print_tmp_buff[len-1] == '\r') ) { + was_enter = TRUE; + } else { + was_enter = FALSE; + } + + OutputDebugString(&dbg_print_tmp_buff[0]); + + va_end(ap); + +} // end PrintDbgConsole() +#else // PRINT_DBG_CONSOLE +VOID +PrintDbgConsole( + PCHAR DebugMessage, + ... + ) +{ +} // end ClassDebugPrint() +#endif //PRINT_DBG_CONSOLE + +BOOLEAN +RtlTimeFieldsToTime( + IN PTIME_FIELDS TimeFields, + IN PLARGE_INTEGER Time + ) +{ + SYSTEMTIME st; + + st.wYear = TimeFields->Year; + st.wMonth = TimeFields->Month; + st.wDayOfWeek = 0; + st.wDay = TimeFields->Day; + st.wHour = TimeFields->Hour; + st.wMinute = TimeFields->Minute; + st.wSecond = TimeFields->Second; + st.wMilliseconds = TimeFields->Milliseconds; + + return SystemTimeToFileTime(&st, (PFILETIME)Time); +} // end RtlTimeFieldsToTime() + +BOOLEAN +RtlTimeToTimeFields( + IN PLARGE_INTEGER Time, + IN PTIME_FIELDS TimeFields + ) +{ + SYSTEMTIME st; + BOOLEAN retval; + + retval = FileTimeToSystemTime((PFILETIME)Time, &st); + + TimeFields->Year = st.wYear; + TimeFields->Month = st.wMonth; + TimeFields->Weekday = st.wDayOfWeek; + TimeFields->Day = st.wDay; + TimeFields->Hour = st.wHour; + TimeFields->Minute = st.wMinute; + TimeFields->Second = st.wSecond; + TimeFields->Milliseconds = st.wMilliseconds; + + return retval; +} // end () + +#endif //NT_NATIVE_MODE + +#ifdef USE_THREAD_HEAPS + +HANDLE MemLock = NULL; + +VOID +ExInitThreadPools() +{ + MemLock = CreateMutex(NULL, 0, NULL); +} + +VOID +ExDeInitThreadPools() +{ + if(MemLock) + CloseHandle(MemLock); +} + +#define MAX_THREADS_WITH_OWN_POOL 128 + +typedef struct _THREAD_POOL_LIST_ITEM { + HANDLE HeapHandle; + ULONG ThreadId; +} THREAD_POOL_LIST_ITEM, *PTHREAD_POOL_LIST_ITEM; + +ULONG LastThreadPool = -1; +THREAD_POOL_LIST_ITEM ThreadPoolList[MAX_THREADS_WITH_OWN_POOL]; + +extern "C" +PVOID +#ifdef KERNEL_MODE_MM_BEHAVIOR +_ExAllocatePool_( +#else +ExAllocatePool( +#endif + ULONG MemoryType, + ULONG Size + ) +{ + ULONG i; + ULONG ThreadId = GetCurrentThreadId(); + BOOLEAN found = FALSE; + + WaitForSingleObject(MemLock,-1); + + for(i=0; i<(LastThreadPool+1); i++) { + if(ThreadPoolList[i].ThreadId == ThreadId) { + found = TRUE; + break; + } + } + if(found) { + ReleaseMutex(MemLock); + return HeapAlloc(ThreadPoolList[i].HeapHandle, HEAP_NO_SERIALIZE, Size); + } + for(i=0; i<(LastThreadPool+1); i++) { + if(ThreadPoolList[i].ThreadId == -1) { + break; + } + } + if(i>=MAX_THREADS_WITH_OWN_POOL) { + ReleaseMutex(MemLock); + return NULL; + } + ThreadPoolList[i].ThreadId = ThreadId; + ThreadPoolList[i].HeapHandle = HeapCreate(HEAP_NO_SERIALIZE, 128*PAGE_SIZE, 0); + if(!ThreadPoolList[i].HeapHandle) { + ThreadPoolList[i].ThreadId = -1; + ReleaseMutex(MemLock); + return NULL; + } + + if(i+1 > LastThreadPool+1) + LastThreadPool = i; + + ReleaseMutex(MemLock); + + return HeapAlloc(ThreadPoolList[i].HeapHandle, HEAP_NO_SERIALIZE, Size); + +} // end ExAllocatePool() + +extern "C" +VOID +#ifdef KERNEL_MODE_MM_BEHAVIOR +_ExFreePool_( +#else +ExFreePool( +#endif + PVOID Addr + ) +{ + ULONG ThreadId = GetCurrentThreadId(); + ULONG i; + + WaitForSingleObject(MemLock,-1); + for(i=0; i<(LastThreadPool+1); i++) { + if(ThreadPoolList[i].ThreadId == ThreadId) { + break; + } + } + if(i+1 > LastThreadPool+1) { + // Not found + BrutePoint(); + //__asm int 3; + return; + } + HeapFree(ThreadPoolList[i].HeapHandle, HEAP_NO_SERIALIZE, Addr); + + ReleaseMutex(MemLock); + +} // end ExFreePool() + +extern "C" +VOID +ExFreeThreadPool() +{ + ULONG ThreadId = GetCurrentThreadId(); + ULONG i; + + WaitForSingleObject(MemLock,-1); + for(i=0; i<(LastThreadPool+1); i++) { + if(ThreadPoolList[i].ThreadId == ThreadId) { + break; + } + } + if(i+1 > LastThreadPool+1) { + // Not found + BrutePoint(); + //__asm int 3; + return; + } + HeapDestroy(ThreadPoolList[i].HeapHandle); + ThreadPoolList[i].HeapHandle = INVALID_HANDLE_VALUE; + ThreadPoolList[i].ThreadId = -1; + + ReleaseMutex(MemLock); +} + +#endif //USE_THREAD_HEAPS + +#if defined(KERNEL_MODE_MM_BEHAVIOR) +extern "C" +PVOID +ExAllocatePool( + ULONG MemoryType, + ULONG Size + ) +{ + PVOID Addr; + PVOID uAddr; + if(Size < PAGE_SIZE) { +#ifdef USE_THREAD_HEAPS + Addr = _ExAllocatePool_(MemoryType, Size+8); +#else + Addr = GlobalAlloc(GMEM_DISCARDABLE, Size+8); +#endif + if(!Addr) + return NULL; + uAddr = ((PCHAR)Addr)+8; + } else { +#ifdef USE_THREAD_HEAPS + Addr = _ExAllocatePool_(MemoryType, Size+PAGE_SIZE*2); +#else + Addr = GlobalAlloc(GMEM_DISCARDABLE, Size+PAGE_SIZE*2); +#endif + if(!Addr) + return NULL; + uAddr = (PVOID)(((ULONG)(((PCHAR)Addr)+PAGE_SIZE)) & ~(PAGE_SIZE-1)); + } + *(((PULONG)uAddr)-2) = (ULONG)Addr; + *(((PULONG)uAddr)-1) = 0xFEDCBA98; + return uAddr; +} // end ExAllocatePool() + +extern "C" +VOID +ExFreePool( + PVOID uAddr + ) +{ + PVOID Addr; + + if(*(((PULONG)uAddr)-1) == 0xFEDCBA98) { + Addr = (PVOID)(*(((PULONG)uAddr)-2)); +#ifdef USE_THREAD_HEAPS + _ExFreePool_(Addr); +#else + GlobalFree(Addr); +#endif + return; + } + BrutePoint(); +} // end ExFreePool() +#endif //defined(KERNEL_MODE_MM_BEHAVIOR) || defined(NT_NATIVE_MODE) + +#ifdef _lphUdf +#undef _lphUdf +#endif //_lphUdf + +extern "C" +BOOLEAN +ProbeMemory( + PVOID MemPtr, + ULONG Length, + BOOLEAN ForWrite + ) +{ + ULONG i; + UCHAR a; + if(!MemPtr && !Length) + return TRUE; + if(!MemPtr || !Length) + return FALSE; + _SEH2_TRY { + a = ((PCHAR)MemPtr)[Length-1]; + if(ForWrite) { + ((PCHAR)MemPtr)[Length-1] = a; + } + for(i=0; i +#endif //NT_NATIVE_MODE +#include "platform.h" +//#ifndef WITHOUT_FORMATTER +#include "udferr_usr.h" +//#endif WITHOUT_FORMATTER + +#ifndef NT_NATIVE_MODE +#ifdef ASSERT + #undef ASSERT + #define ASSERT(a) if(!(a)) {__asm int 3;} +#endif +#endif //NT_NATIVE_MODE + +#ifndef MAXIMUM_FILENAME_LENGTH +#define MAXIMUM_FILENAME_LENGTH MAX_PATH +#endif //MAXIMUM_FILENAME_LENGTH + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif //PAGE_SHIFT + +#ifndef PAGE_SIZE +#define PAGE_SIZE (ULONG)0x1000 +#endif //PAGE_SIZE + +#ifndef PHYSICAL_ADDRESS +#define PHYSICAL_ADDRESS LARGE_INTEGER +#endif //PHYSICAL_ADDRESS + +#define OS_SUCCESS(a) NT_SUCCESS(a) +#define OSSTATUS NTSTATUS + +#if defined UDF_DBG || defined DEBUG +#define DBG +#ifndef CDRW_W32 +#define UDF_DBG +#endif //CDRW_W32 +#endif + +#define ERESEOURCE ULONG +#define PERESEOURCE PULONG + +#define KEVENT ULONG +#define PKEVENT PULONG + +typedef ULONG KSPIN_LOCK; // winnt ntndis +typedef KSPIN_LOCK *PKSPIN_LOCK; + +#ifndef NT_NATIVE_MODE +// Status ot +#define NTSTATUS LONG + +#define NT_SUCCESS(x) ( (NTSTATUS)(x)>=0 ) + +#define PsGetCurrentThread() GetCurrentThreadId() + +#define PsGetVersion(a,b,c,d) { \ + OSVERSIONINFO OsVer; \ + OsVer.dwOSVersionInfoSize = sizeof(OsVer); \ + GetVersionEx(&OsVer); \ + if(a) (*(a)) = OsVer.dwMajorVersion; \ + if(b) (*(b)) = OsVer.dwMinorVersion; \ + if(c) (*(c)) = OsVer.dwBuildNumber; \ + if(d) (d)->Buffer = L""; \ + if(d) (d)->Length = 0; \ + if(d) (d)->MaximumLength = 0; \ +} + +extern "C" +VOID +PrintDbgConsole( + PCHAR DebugMessage, + ... + ); + +#else //NT_NATIVE_MODE +#define HINSTANCE HANDLE +#endif //NT_NATIVE_MODE + +typedef +int (*PSKIN_INIT) ( + HINSTANCE hInstance, // handle to current instance + HINSTANCE hPrevInstance, // handle to previous instance + int nCmdShow // show state + ); + +typedef +int (*PSKIN_PRINTF) ( + const char* Message, + ... + ); + +typedef +PWCHAR (__stdcall *PSKIN_GETCMDLINE) ( + VOID + ); + +typedef +ULONG (__stdcall *PSKIN_MSG) ( + ULONG MsgId, + ULONG MsgSubId, + PVOID DataIn, + ULONG DataInLen, + PVOID DataOut, + ULONG DataInOut + ); + +typedef struct _SKIN_API { + PSKIN_INIT Init; + PSKIN_PRINTF Printf; + PSKIN_GETCMDLINE GetCommandLine; + PSKIN_MSG Msg; +} SKIN_API, *PSKIN_API; + +#ifdef USE_SKIN_MODEL + +extern "C" PSKIN_API SkinAPI; +extern PSKIN_API SkinLoad( + PWCHAR path, + HINSTANCE hInstance, // handle to current instance + HINSTANCE hPrevInstance, // handle to previous instance + int nCmdShow // show state + ); + +#define SkinPrintf SkinAPI->Printf +#define SkinGetCmdLine SkinAPI->GetCommandLine +#define SkinNotify(op, state, ctx, sz) SkinAPI->Msg(op, state, ctx, sz, NULL, 0) +#define SkinAsk(op, state, ctx, def) SkinAPI->Msg(op, state, ctx, sizeof(ctx), NULL, 0) + +#else + +#define SkinLoad(path) {;} + +#if defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + #define SkinPrintf(x) {;} +/*VOID +inline +SkinPrintf( + PCHAR Message, + ... + ) +{ + //do nothing + return; +}*/ +#else // defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + #define SkinPrintf printf +#endif + +#define SkinGetCmdLine GetCommandLineW +#define SkinNotify(op, state, ctx) {;} +#define SkinAsk(op, state, ctx, def) (def) + +#endif // defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + +#if defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + + #if defined(PRINT_TO_DBG_LOG) || defined(PRINT_ALWAYS) + #define UserPrint(x) PrintDbgConsole x + #else + #define UserPrint(x) {;} + #endif // PRINT_TO_DBG_LOG + +#else // defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + + #if defined(PRINT_TO_DBG_LOG) || defined(PRINT_ALWAYS) + + #define UserPrint(x) \ + { \ + SkinPrintf x ; \ + PrintDbgConsole x ; \ + } + + #else // PRINT_TO_DBG_LOG + + #define UserPrint(x) \ + { \ + SkinPrintf x ; \ + } + + #endif // PRINT_TO_DBG_LOG + +#endif // defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + +#if defined(DBG) || defined(PRINT_ALWAYS) + + #define DbgPrint SkinPrintf + + #ifdef KdPrint + #undef KdPrint + #endif + + #if defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + #ifdef PRINT_TO_DBG_LOG + #define KdPrint(x) PrintDbgConsole x; + #else + #define KdPrint(x) {;} + #endif + #else + + #if defined(PRINT_TO_DBG_LOG) || defined(PRINT_ALWAYS) + #define KdPrint(x) \ + { \ + SkinPrintf x ; \ + PrintDbgConsole x ; \ + } + #else + #define KdPrint(x) \ + { \ + SkinPrintf x ; \ + } + #endif + #endif + + #ifdef USE_MM_PRINT + #define MmPrint(_x_) DbgPrint _x_ + #else + #define MmPrint(_x_) {NOTHING;} + #endif //USE_MM_PRINT + + #ifdef USE_TIME_PRINT + extern ULONG UdfTimeStamp; + #define TmPrint(_x_) {UdfTimeStamp++;KdPrint(("TM:%d: ",UdfTimeStamp));KdPrint(_x_);} + #else + #define TmPrint KdPrint + #endif //USE_MM_PRINT + + #ifdef USE_PERF_PRINT + #define PerfPrint(_x_) DbgPrint _x_ + #else + #define PerfPrint(_x_) {NOTHING;} + #endif //USE_MM_PRINT + +#if defined(CDRW_W32) || defined(LIBUDFFMT) || defined(LIBUDF) + #ifdef USE_AD_PRINT + #undef USE_AD_PRINT + #endif + #ifdef USE_TH_PRINT + #undef USE_TH_PRINT + #endif +#endif + + #ifdef USE_AD_PRINT + #define AdPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} + #else + #define AdPrint(_x_) {NOTHING;} + #endif + + #ifdef USE_TH_PRINT + #define ThPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} + #else + #define ThPrint(_x_) {NOTHING;} + #endif + + #ifdef USE_DUMP_EXT + #define ExtPrint(_x_) DbgPrint _x_ + #else + #define ExtPrint(_x_) {NOTHING;} + #endif //USE_MM_PRINT + +#else + #define KdPrint(x) {NOTHING;} + #define MmPrint(_x_) {NOTHING;} + #define TmPrint(_x_) {NOTHING;} + #define PerfPrint(_x_) {NOTHING;} + #define AdPrint(_x_) {NOTHING;} + #define ThPrint(_x_) {NOTHING;} + #define ExtPrint(_x_) {NOTHING;} +#endif + +#define DbgTouch(a) + +#ifndef NT_NATIVE_MODE +#include "assert.h" + +#define ASSERT(_x_) assert(_x_) +#define UDFTouch(a) + +#endif //NT_NATIVE_MODE + +#define NonPagedPool 0 +#define PagedPool 1 +//#define NonPagedPoolMustSucceed 2 +#define NonPagedPoolCacheAligned 4 + +#define KdDump(a,b) \ +if((a)!=NULL) { \ + ULONG i; \ + for(i=0; i<(b); i++) { \ + ULONG c; \ + c = (ULONG)(*(((PUCHAR)(a))+i)); \ + KdPrint(("%2.2x ",c)); \ + if ((i & 0x0f) == 0x0f) KdPrint(("\n")); \ + } \ + KdPrint(("\n")); \ +} + +//mem ot +//#define ExAllocatePool(hernya,size) MyAllocatePool(size) +//#define ExFreePool(size) MyFreePool((PCHAR)(size)) +//#define SystemAllocatePool(hernya,size) GlobalAlloc(GMEM_DISCARDABLE, size); +//#define SystemFreePool(addr) GlobalFree((PVOID)(addr)) +#define DbgMoveMemory RtlMoveMemory +#define DbgCompareMemory RtlCompareMemory +#define DbgCopyMemory RtlCopyMemory +#define DbgAllocatePool ExAllocatePool +#define DbgAllocatePoolWithTag(a,b,c) ExAllocatePool(a,b) +#define DbgFreePool ExFreePool + +#ifdef NT_NATIVE_MODE +/* +#define GlobalAlloc(foo, size) MyGlobalAlloc( size ); +#define GlobalFree(ptr) MyGlobalFree( ptr ); + +extern "C" +PVOID MyGlobalAlloc(ULONG Size); + +extern "C" +VOID MyGlobalFree(PVOID Addr); +*/ +#endif + +#if !defined(KERNEL_MODE_MM_BEHAVIOR) && !defined(USE_THREAD_HEAPS) +#define ExAllocatePoolWithTag(hernya,size,tag) GlobalAlloc(GMEM_DISCARDABLE, (size)) +#define ExAllocatePool(hernya,size) GlobalAlloc(GMEM_DISCARDABLE, (size)) +#define ExFreePool(addr) GlobalFree((PVOID)(addr)) +#endif + +#if defined(KERNEL_MODE_MM_BEHAVIOR) || defined(USE_THREAD_HEAPS) +#define ExAllocatePoolWithTag(MemoryType,size,tag) ExAllocatePool((MemoryType), (size)) + +extern "C" +PVOID ExAllocatePool(ULONG MemoryType, ULONG Size); + +extern "C" +VOID ExFreePool(PVOID Addr); +#endif //KERNEL_MODE_MM_BEHAVIOR || USE_THREAD_HEAPS + +#ifndef NT_NATIVE_MODE + +//string ot +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING; +typedef UNICODE_STRING *PUNICODE_STRING; + +typedef struct _ANSI_STRING { + USHORT Length; + USHORT MaximumLength; + PSTR Buffer; +} ANSI_STRING; +typedef ANSI_STRING *PANSI_STRING; + +#endif //NT_NATIVE_MODE + +#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG)(OFFSET) - (ULONG)(BASE))) + +// Device object ot + +#ifndef DO_UNLOAD_PENDING +// Define Device Object (DO) flags +// + +#define DO_UNLOAD_PENDING 0x00000001 +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_BUFFERED_IO 0x00000004 +#define DO_EXCLUSIVE 0x00000008 +#define DO_DIRECT_IO 0x00000010 +#define DO_MAP_IO_BUFFER 0x00000020 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_DEVICE_INITIALIZING 0x00000080 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_SHUTDOWN_REGISTERED 0x00000800 + +#endif //DO_UNLOAD_PENDING + +#ifdef NT_NATIVE_MODE +#define _DEVICE_OBJECT _MY_DEVICE_OBJECT +#define DEVICE_OBJECT MY_DEVICE_OBJECT +#define PDEVICE_OBJECT PMY_DEVICE_OBJECT +#endif //NT_NATIVE_MODE + +typedef struct _DEVICE_OBJECT { + +#ifndef LIBUDF + + HANDLE h; + PVOID DeviceExtension; + ULONG Flags; + ULONG AlignmentRequirement; + UCHAR StackSize; + +#endif // LIBUDF + + +#ifdef LIBUDFFMT + + struct _UDF_FMT_PARAMETERS* cbio; + PVOID lpContext; + +#else +#ifdef LIBUDF + PVOID lpContext; +#endif // LIBUDF +#endif // LIBUDFFMT + +} DEVICE_OBJECT, *PDEVICE_OBJECT; + +#ifndef CDRW_W32 +/* +typedef ULONG DEVICE_OBJECT; +typedef ULONG PDEVICE_OBJECT; +*/ +#define INVALID_PACKET 0x01 + +typedef struct _PACKET { + // Node Identifier +// UDFIdentifier NodeIdentifier; + // Pointer to the buffer (in non-paged pool) + PCHAR buffer; + // Offset, from which this data was read + LARGE_INTEGER offset; + // Flags + UCHAR flags; +} PACKET, *PPACKET; + +#define UDFInitPacket(x) STATUS_SUCCESS +#endif //CDRW_W32 + +#define try_return(S) { S; goto try_exit; } +#define NOTHING + +#define FlagOn(x,f) ((x) & (f)) + +#define RtlCompareMemory(s1,s2,l) MyRtlCompareMemory(s1,s2,l) +// Structure ot +extern "C" +ULONG +MyRtlCompareMemory( + PVOID s1, + PVOID s2, + ULONG len + ); +//#define RtlCompareMemory(d1,d2,l) (ULONG)(memcmp (d1,d2,l)) + +#define KeSetEvent(pEvt, foo, foo2) {NOTHING;} +#define KeInitializeEvent(pEvt, foo, foo2) {NOTHING;} +#define KeWaitForSingleObject(pEvt, foo, a, b, c) {NOTHING;} +#define DbgWaitForSingleObject(o, to) KeWaitForSingleObject(o, Executive, KernelMode, FALSE, to); +//#define DbgWaitForSingleObject KeWaitForSingleObject +#ifdef NT_NATIVE_MODE +#define KeDelayExecutionThread(mode, foo, t) { NtDelayExecution(false, t); } +#else //NT_NATIVE_MODE +#define KeDelayExecutionThread(mode, foo, t) { Sleep( abs((LONG)(((t)->QuadPart)/10000)) ); } +#endif //NT_NATIVE_MODE + +/*#define RtlCompareUnicodeString(s1,s2,cs) \ + (((s1)->Length == (s2)->Length) && \ + (RtlCompareMemory(s1,s2,(s1)->Length))) +*/ +#ifndef CDRW_W32 +#ifdef _X86_ + +// This is an illegal use of INT3 +#define UDFBreakPoint() __asm int 3 +#else // _X86_ + +#define UDFBreakPoint() DbgBreakPoint() +#endif // _X86_ + +#ifdef BRUTE +#define BrutePoint() UDFBreakPoint() +#else +#define BrutePoint() {} +#endif // BRUTE + +#ifdef VALIDATE_STRUCTURES +#define ValidateFileInfo(fi) \ +{ /* validate FileInfo */ \ + if((fi)->IntegrityTag) { \ + KdPrint(("UDF: ERROR! Using deallocated structure !!!\n"));\ + /*BrutePoint();*/ \ + } \ +} +#else +#define ValidateFileInfo(fi) {} +#endif + +#else //CDRW_W32 + +#ifdef BRUTE +#ifdef _X86_ + +// This is an illegal use of INT3 +#define BrutePoint() __asm int 3 +#else // _X86_ + +#define BrutePoint() DbgBreakPoint() +#endif // _X86_ +#else +#define BrutePoint() {} +#endif // BRUTE + +#endif //CDRW_W32 + +#ifndef NT_NATIVE_MODE + +extern "C" +ULONG +RtlCompareUnicodeString( + PUNICODE_STRING s1, + PUNICODE_STRING s2, + BOOLEAN UpCase); + +extern "C" +NTSTATUS +RtlUpcaseUnicodeString( + PUNICODE_STRING dst, + PUNICODE_STRING src, + BOOLEAN Alloc + ); + +extern "C" +NTSTATUS +RtlAppendUnicodeToString( + IN PUNICODE_STRING Str1, + IN PWSTR Str2 + ); + +#endif //NT_NATIVE_MODE + +extern "C" +NTSTATUS +MyInitUnicodeString( + IN PUNICODE_STRING Str1, + IN PCWSTR Str2 + ); + +#ifndef NT_NATIVE_MODE +#define KeQuerySystemTime(t) GetSystemTimeAsFileTime((LPFILETIME)(t)); + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +#endif //NT_NATIVE_MODE + +typedef UCHAR KIRQL; +typedef KIRQL *PKIRQL; + +typedef ULONG ERESOURCE; +typedef ERESOURCE *PERESOURCE; + +#define KeRaiseIrql(irql, oldIrql) \ +{ \ + *oldIrql = 0; \ +} + +#define KeLowerIrql(oldIrql) {;} + +#define KeInitializeSpinLock(sl) \ +{ \ + *(sl) = 0; \ +} + +#define KeAcquireSpinLock(sl,irql) \ +{ \ + ULONG isLocked = TRUE; \ + while(isLocked) AcquireXLock(*(sl), isLocked, TRUE);\ +} + +#define ExAcquireResourceExclusiveLite(res, wait) \ +{ \ + ULONG isLocked = TRUE; \ + while(isLocked) AcquireXLock(*(res), isLocked, TRUE);\ +} + +#define ExAcquireResourceSharedLite(res, wait) \ +{ \ + ULONG isLocked = TRUE; \ + while(isLocked) AcquireXLock(*(res), isLocked, TRUE);\ +} + +#define KeReleaseSpinLock(sl,irql) \ +{ \ + ULONG isLocked; \ + AcquireXLock(*(sl), isLocked, FALSE); \ +} + +#define ExGetCurrentResourceThread() 0 + +#define ExReleaseResourceForThreadLite(res, thrdID) \ +{ \ + ULONG isLocked; \ + AcquireXLock(*(res), isLocked, FALSE); \ +} + +NTSTATUS inline ExInitializeResourceLite(PULONG res) +{ + *(res) = 0; + return STATUS_SUCCESS; +} + +#define ExDeleteResourceLite(res) \ +{ \ + *(res) = 0; \ +} + +#define ExConvertExclusiveToSharedLite(res) {/* do nothing */} + +#ifndef CDRW_W32 + +#define UDFAcquireResourceExclusive(Resource,CanWait) \ + ExAcquireResourceExclusiveLite((Resource),(CanWait)) +#define UDFAcquireResourceShared(Resource,CanWait) \ + ExAcquireResourceSharedLite((Resource),(CanWait)) +// a convenient macro (must be invoked in the context of the thread that acquired the resource) +#define UDFReleaseResource(Resource) \ + ExReleaseResourceForThreadLite((Resource), ExGetCurrentResourceThread()) +#define UDFDeleteResource(Resource) \ + ExDeleteResourceLite((Resource)) +#define UDFConvertExclusiveToSharedLite(Resource) \ + ExConvertExclusiveToSharedLite((Resource)) +#define UDFInitializeResourceLite(Resource) \ + ExInitializeResourceLite((Resource)) +#define UDFAcquireSharedStarveExclusive(Resource,CanWait) \ + ExAcquireSharedStarveExclusive((Resource),(CanWait)) +#define UDFAcquireSharedWaitForExclusive(Resource,CanWait) \ + ExAcquireSharedWaitForExclusive((Resource),(CanWait)) +//#define UDFDebugAcquireResourceExclusiveLite(a,b,c,d) ExAcquireResourceExclusiveLite(a,b) + +#define UDFInterlockedIncrement(addr) \ + ((*addr)++) +#define UDFInterlockedDecrement(addr) \ + ((*addr)--) +int +__inline +UDFInterlockedExchangeAdd(PLONG addr, LONG i) { + LONG Old = (*addr); + (*addr) += i; + return Old; +} + +#endif //CDRW_W32 + +// +// Interrupt Request Level definitions +// + +#define PASSIVE_LEVEL 0 // Passive release level +#define LOW_LEVEL 0 // Lowest interrupt level +#define APC_LEVEL 1 // APC interrupt level +#define DISPATCH_LEVEL 2 // Dispatcher level + +#define PROFILE_LEVEL 27 // timer used for profiling. +#define CLOCK1_LEVEL 28 // Interval clock 1 level - Not used on x86 +#define CLOCK2_LEVEL 28 // Interval clock 2 level +#define IPI_LEVEL 29 // Interprocessor interrupt level +#define POWER_LEVEL 30 // Power failure level +#define HIGH_LEVEL 31 // Highest interrupt level +#define SYNCH_LEVEL (IPI_LEVEL-1) // synchronization level + +#define KeGetCurrentIrql() PASSIVE_LEVEL + +#ifndef NT_NATIVE_MODE + +typedef struct _TIME_FIELDS { + USHORT Year; // range [1601...] + USHORT Month; // range [1..12] + USHORT Day; // range [1..31] + USHORT Hour; // range [0..23] + USHORT Minute; // range [0..59] + USHORT Second; // range [0..59] + USHORT Milliseconds;// range [0..999] + USHORT Weekday; // range [0..6] == [Sunday..Saturday] +} TIME_FIELDS; +typedef TIME_FIELDS *PTIME_FIELDS; + +//#define RtlTimeFieldsToTime(a,b) TRUE +BOOLEAN +RtlTimeFieldsToTime( + IN PTIME_FIELDS TimeFields, + IN PLARGE_INTEGER Time + ); + +#define ExSystemTimeToLocalTime(SysTime, LocTime) FileTimeToLocalFileTime((PFILETIME)(SysTime), (PFILETIME)(LocTime)) + +//#define RtlTimeToTimeFields(a,b) {} +BOOLEAN +RtlTimeToTimeFields( + IN PLARGE_INTEGER Time, + IN PTIME_FIELDS TimeFields + ); + +#define ExLocalTimeToSystemTime(LocTime, SysTime) LocalFileTimeToFileTime((PFILETIME)(LocTime), (PFILETIME)(SysTime)) + +#endif //NT_NATIVE_MODE + +#ifndef CDRW_W32 + +typedef struct _FSRTL_COMMON_FCB_HEADER { + SHORT NodeTypeCode; + SHORT NodeByteSize; + UCHAR Flags; + UCHAR IsFastIoPossible; +#if (_WIN32_WINNT >= 0x0400) + UCHAR Flags2; + UCHAR Reserved; +#endif // (_WIN32_WINNT >= 0x0400) + PERESOURCE Resource; + PERESOURCE PagingIoResource; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER FileSize; + LARGE_INTEGER ValidDataLength; +} FSRTL_COMMON_FCB_HEADER, *PFSRTL_COMMON_FCB_HEADER; + +typedef struct _SECTION_OBJECT_POINTERS { + PVOID DataSectionObject; + PVOID SharedCacheMap; + PVOID ImageSectionObject; +} SECTION_OBJECT_POINTERS; +typedef SECTION_OBJECT_POINTERS *PSECTION_OBJECT_POINTERS; + + +extern NTSTATUS UDFPhReadSynchronous( + PDEVICE_OBJECT DeviceObject, + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG ReadBytes, + ULONG Flags); + +extern NTSTATUS UDFPhWriteSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags); + +#if 0 +extern NTSTATUS +UDFPhWriteVerifySynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags + ); +#endif + +#define UDFPhWriteVerifySynchronous UDFPhWriteSynchronous + +extern NTSTATUS UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PVOID Iosb OPTIONAL); + +#endif //CDRW_W32 + +VOID set_image_size(HANDLE h, +// ULONG LBA); + int64 len); + +#ifdef UDF_FORMAT_MEDIA +struct _UDFVolumeControlBlock; +#endif + +#ifndef UDF_FORMAT_MEDIA +ULONG write( + HANDLE h, + PCHAR buff, + ULONG len); +#endif + +extern "C" +HANDLE +my_open( +#ifndef CDRW_W32 + struct _UDFVolumeControlBlock* Vcb, +#endif //CDRW_W32 + PWCHAR fn); + +#ifdef UDF_FORMAT_MEDIA +struct _UDFFmtState; +#endif //UDF_FORMAT_MEDIA + +extern +void +my_exit( +#ifdef UDF_FORMAT_MEDIA + struct _UDFFmtState* fms, +#endif //UDF_FORMAT_MEDIA + int rc + ); + +#ifndef CDRW_W32 +uint64 udf_lseek64(HANDLE fd, uint64 offset, int whence); +#endif //CDRW_W32 + +#ifdef LIBUDFFMT +BOOLEAN +udf_get_sizes( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG* blocks + ); +#endif //LIBUDFFMT + +int64 +get_file_size( + HANDLE h + ); + +int64 +set_file_pointer( + HANDLE h, + int64 sz + ); + +#ifndef NT_NATIVE_MODE +typedef struct _IO_STATUS_BLOCK { + ULONG Status; + ULONG Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +#endif //NT_NATIVE_MODE + + +#ifndef UDF_FORMAT_MEDIA +extern ULONG LockMode; +extern BOOLEAN open_as_device; +extern BOOLEAN opt_invalidate_volume; +#endif //UDF_FORMAT_MEDIA + +extern "C" +ULONG +MyLockVolume( + HANDLE h, + ULONG* pLockMode // OUT + ); + +extern "C" +ULONG +MyUnlockVolume( + HANDLE h, + ULONG* pLockMode // IN + ); + +#ifndef CDRW_W32 +ULONG +UDFGetDevType(PDEVICE_OBJECT DeviceObject); +#endif //CDRW_W32 + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)(-1)) +#endif + +#ifndef ANSI_DOS_STAR + +#define ANSI_DOS_STAR ('<') +#define ANSI_DOS_QM ('>') +#define ANSI_DOS_DOT ('"') + +#define DOS_STAR (L'<') +#define DOS_QM (L'>') +#define DOS_DOT (L'"') + +#endif //ANSI_DOS_STAR + +extern "C" +BOOLEAN +ProbeMemory( + PVOID MemPtr, + ULONG Length, + BOOLEAN ForWrite + ); + +#ifdef NT_NATIVE_MODE +#include "env_spec_nt.h" +#endif //NT_NATIVE_MODE + +#ifndef InitializeListHead + +// +// Doubly-linked list manipulation routines. Implemented as macros +// but logically these are procedures. +// + +// +// VOID +// InitializeListHead( +// PLIST_ENTRY ListHead +// ); +// + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +// +// PLIST_ENTRY +// RemoveTailList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveTailList(ListHead) \ + (ListHead)->Blink;\ + {RemoveEntryList((ListHead)->Blink)} + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +// +// VOID +// InsertHeadList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertHeadList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Flink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Flink = _EX_ListHead->Flink;\ + (Entry)->Flink = _EX_Flink;\ + (Entry)->Blink = _EX_ListHead;\ + _EX_Flink->Blink = (Entry);\ + _EX_ListHead->Flink = (Entry);\ + } + +#endif //InitializeListHead + +#endif // __ENV_SPEC_W32__H_ diff --git a/reactos/drivers/filesystems/udfs/Include/format_common.cpp b/reactos/drivers/filesystems/udfs/Include/format_common.cpp new file mode 100644 index 00000000000..636e0964b01 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/format_common.cpp @@ -0,0 +1,262 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +/// Initial drive selection from command line. +CHAR szDisc[4] = ""; +BOOL bChanger = FALSE; + +/// Return CD-RW device type +JS_DEVICE_TYPE +CheckCDType( + PCHAR m_szFile, + PCHAR VendorId + ) +{ + HANDLE hDevice; + CHAR szDeviceName[256]; + CHAR ioBuf[4096]; + ULONG RC; + BOOL DvdRW = false; + BOOL DvdpRW = false; + BOOL DvdRAM = false; + BOOL DvdpR = false; + BOOL DvdR = false; + + bChanger = FALSE; + + // Make string representing full path + sprintf(szDeviceName, "\\\\.\\%s", m_szFile); + if (szDeviceName[strlen(szDeviceName)-1] == '\\') szDeviceName[strlen(szDeviceName)-1] = '\0'; + + // Open device volume + hDevice = OpenOurVolume(szDeviceName); + + if (hDevice == ((HANDLE)-1)) { + strcpy(VendorId,""); + return BUSY; + } else { + + // Get our cdrw.sys signature + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_SIGNATURE,hDevice, + &ioBuf,sizeof(GET_SIGNATURE_USER_OUT), + &ioBuf,sizeof(GET_SIGNATURE_USER_OUT),FALSE,NULL); + + if (RC == 1) { + // Get device information + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_INFO,hDevice, + &ioBuf,sizeof(GET_DEVICE_INFO_USER_OUT), + &ioBuf,sizeof(GET_DEVICE_INFO_USER_OUT),FALSE,NULL); + if (RC != 1) { + strcpy(VendorId,"Unknown Vendor"); + } else { + if(((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features & CDRW_FEATURE_CHANGER) + bChanger = TRUE; + strcpy(VendorId,(PCHAR)&(((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->VendorId[0])); + if (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features & CDRW_FEATURE_GET_CFG) { + DvdRW = (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features2[0] >> PFNUM_DVDRW_RESTRICTED_OVERWRITE) & 1; + DvdRAM = (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features2[0] >> PFNUM_DVDRAM) & 1; + DvdpRW = (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features2[0] >> PFNUM_DVDpRW) & 1; + DvdR = (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features2[0] >> PFNUM_DVDR) & 1; + DvdpR = (((PGET_DEVICE_INFO_USER_OUT)&ioBuf)->Features2[0] >> PFNUM_DVDpR) & 1; + } + } + + // Get device capabilities + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_CAPABILITIES,hDevice, + &ioBuf,sizeof(GET_CAPABILITIES_USER_OUT), + &ioBuf,sizeof(GET_CAPABILITIES_USER_OUT),FALSE,NULL); + if(RC != 1) { + CloseHandle(hDevice); + return OTHER; + } + + // Check capabilities + if(((PGET_CAPABILITIES_USER_OUT)&ioBuf)->WriteCap & (DevCap_write_cd_r | DevCap_write_cd_rw | DevCap_write_dvd_ram | DevCap_write_dvd_r) || + DvdRW || DvdpRW || DvdRAM) { + + if (DvdRAM || ((PGET_CAPABILITIES_USER_OUT)&ioBuf)->WriteCap & DevCap_write_dvd_ram) { + CloseHandle(hDevice); + return DVDRAM; + } +/* if (DvdR) { + CloseHandle(hDevice); + return DVDR; + }*/ + if (DvdRW) { + CloseHandle(hDevice); + return DVDRW; + } + if (DvdpRW) { + CloseHandle(hDevice); + return DVDPRW; + } +/* if (DvdpR) { + CloseHandle(hDevice); + return DVDPR; + }*/ + if (((PGET_CAPABILITIES_USER_OUT)&ioBuf)->WriteCap & DevCap_write_dvd_r) { + CloseHandle(hDevice); + return DVDR; + } + if (((PGET_CAPABILITIES_USER_OUT)&ioBuf)->WriteCap & DevCap_write_cd_rw) { + CloseHandle(hDevice); + return CDRW; + } + if (((PGET_CAPABILITIES_USER_OUT)&ioBuf)->WriteCap & DevCap_write_cd_r) { + CloseHandle(hDevice); + return CDR; + } + } + else { + CloseHandle(hDevice); + return OTHER; + } + } else { + strcpy(VendorId,"Unknown Vendor"); + } + CloseHandle(hDevice); + } + + return OTHER; +} // end CheckCDType() + +/** Intialize asbtract device list via calls to CallBack function. + \param hDlg Not used. + \param hwndControl Passed to the CallBack function. See #PADD_DEVICE. + \param CallBack Callback function. Called on each CD device in system. +*/ +void +InitDeviceList( + HWND hDlg, + HWND hwndControl, + PADD_DEVICE CallBack + ) +{ + char Buffer[MAX_PATH] = ""; + char VendorId[25]; + char seps[] = ","; + char* token; + char info[MAX_PATH]; + bool add_drive = false; + + JS_DEVICE_TYPE drive_type; + + // Get all device letter in system + GetLogicalDriveStrings((DWORD)MAX_PATH,(LPTSTR)&Buffer); + token = (char *)&Buffer; + // Replace all zeroes with comma. + while (token != NULL) { + token = (char *)memchr(Buffer,'\0',MAX_PATH); + if (token) { + if (*(token-1) == ',') { + token = NULL; + } else { + *token=','; + } + } + } + // Parse string of drive letters separated by comma + token = strtok((char *)&Buffer,seps); + while (token != NULL) { + add_drive = false; + switch (GetDriveType(token)) { +/* + case DRIVE_FIXED: + add_drive = true; + break; +*/ + case DRIVE_CDROM: + // Determine CD/DVD-ROM type (R,RW,RAM,other) + drive_type = CheckCDType(token,&VendorId[0]); + add_drive = true; + break; + } + if (add_drive) { + + // Append to drive letter VendorId + strncpy(info,token,strlen(token)-1); + info[strlen(token)-1]='\0'; + strcat(info," "); + strcat(info,VendorId); + + BOOL bSelect = !strcmp(strupr(szDisc),strupr(token)); + if (drive_type != OTHER) { + CallBack(hwndControl,token,info,MediaTypeStrings[drive_type],bSelect); + } else { + CallBack(hwndControl,token,info,"[Unsupported]",FALSE); + } + + } + // Move to the next drive letter in string + token = strtok(NULL,seps); + } +} // end InitDeviceList() + +HANDLE +FmtAcquireDrive_( + PCHAR _Drive, + CHAR Level + ) +{ + WCHAR LockName[32]; + HANDLE evt; + + WCHAR Drive[1]; + Drive[0] = _Drive[0] & ~('a' ^ 'A'); + + swprintf(LockName, L"DwFmtLock_%1.1S%d", Drive, Level); + evt = CreatePublicEvent(LockName); + if(!evt) { + return NULL; + } + if(GetLastError() == ERROR_ALREADY_EXISTS) { + CloseHandle(evt); + return INVALID_HANDLE_VALUE; + } + return evt; +} // end FmtAcquireDrive_() + +HANDLE +FmtAcquireDrive( + PCHAR Drive, + CHAR Level + ) +{ + HANDLE evt; + + evt = FmtAcquireDrive_(Drive, Level); + if(!evt || evt == INVALID_HANDLE_VALUE) { + return NULL; + } + return evt; +} // end FmtAcquireDrive() + +BOOLEAN +FmtIsDriveAcquired( + PCHAR Drive, + CHAR Level + ) +{ + HANDLE evt; + + evt = FmtAcquireDrive_(Drive, Level); + if(evt == INVALID_HANDLE_VALUE) { + return TRUE; + } + if(evt) { + CloseHandle(evt); + } + return FALSE; +} // end FmtIsDriveAcquired() + +VOID +FmtReleaseDrive( + HANDLE evt + ) +{ + if(evt) { + CloseHandle(evt); + } +} // end FmtReleaseDrive() diff --git a/reactos/drivers/filesystems/udfs/Include/format_common.h b/reactos/drivers/filesystems/udfs/Include/format_common.h new file mode 100644 index 00000000000..85d96347e04 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/format_common.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +JS_DEVICE_TYPE +CheckCDType( + PCHAR m_szFile, + PCHAR VendorId + ); + +typedef void (*PADD_DEVICE)(HWND hwndControl, PCHAR Drive, PCHAR Line1, PCHAR Line2,BOOL bSelect); + +void +InitDeviceList( + HWND hDlg, + HWND hwndControl, + PADD_DEVICE CallBack + ); + +extern CHAR szDisc[4]; +extern BOOL bChanger; + +HANDLE +FmtAcquireDrive( + PCHAR Drive, + CHAR Level + ); + +#define FmtAcquireDriveW(Drive, Level) FmtAcquireDrive((PCHAR)(Drive), Level) + +VOID +FmtReleaseDrive( + HANDLE evt + ); + +BOOLEAN +FmtIsDriveAcquired( + PCHAR Drive, + CHAR Level + ); diff --git a/reactos/drivers/filesystems/udfs/Include/getopt.cpp b/reactos/drivers/filesystems/udfs/Include/getopt.cpp new file mode 100644 index 00000000000..f03c40685cc --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/getopt.cpp @@ -0,0 +1,485 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#include "getopt.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#define my_index wcschr + +#define my_strtoul wcstoul +#define my_strlen wcslen +#define my_strncmp wcsncmp +#define my_strcpy wcscpy +#define my_strcat wcscat +#define my_strcmp wcscmp + +/* Handle permutation of arguments. */ + + +void +getopt_init(optarg_ctx* o) { + + o->optarg = NULL; + o->optind = 0; + o->optopt = BAD_OPTION; + o->opterr = 1; +} + +static void +exchange ( + optarg_ctx* o, + WCHAR **argv + ) +{ + WCHAR *temp, **first, **last; + + /* Reverse all the elements [first_nonopt, optind) */ + first = &argv[o->first_nonopt]; + last = &argv[o->optind-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + /* Put back the options in order */ + first = &argv[o->first_nonopt]; + o->first_nonopt += (o->optind - o->last_nonopt); + last = &argv[o->first_nonopt - 1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + + /* Put back the non options in order */ + first = &argv[o->first_nonopt]; + o->last_nonopt = o->optind; + last = &argv[o->last_nonopt-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return BAD_OPTION after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return BAD_OPTION. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal( + optarg_ctx* o, + int argc, + WCHAR *const *argv, + const WCHAR *optstring, + const struct option *longopts, + int *longind, + int long_only) +{ + int option_index; + + o->optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (o->optind == 0) + { + o->first_nonopt = o->last_nonopt = o->optind = 1; + + o->nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') { + ordering = RETURN_IN_ORDER; + ++optstring; + } else if (optstring[0] == '+') { + ordering = REQUIRE_ORDER; + ++optstring; +/* } else if (getenv ("POSIXLY_CORRECT") != NULL) { + ordering = REQUIRE_ORDER;*/ + } else { + ordering = PERMUTE; + } + } + + if (o->nextchar == NULL || *(o->nextchar) == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (o->first_nonopt != o->last_nonopt && o->last_nonopt != o->optind) { + exchange (o, (WCHAR **) argv); + } else if (o->last_nonopt != o->optind) { + o->first_nonopt = o->optind; + } + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (o->optind < argc + && (argv[o->optind][0] != '-' || argv[o->optind][1] == '\0') + ) { + o->optind++; + } + o->last_nonopt = o->optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (o->optind != argc && !my_strcmp (argv[o->optind], L"--")) + { + o->optind++; + + if (o->first_nonopt != o->last_nonopt && o->last_nonopt != o->optind) { + exchange (o, (WCHAR **) argv); + } else if (o->first_nonopt == o->last_nonopt) { + o->first_nonopt = o->optind; + } + o->last_nonopt = argc; + + o->optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (o->optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (o->first_nonopt != o->last_nonopt) + o->optind = o->first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[o->optind][0] != '-' || argv[o->optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + o->optarg = argv[o->optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + o->nextchar = (argv[o->optind] + 1 + + (longopts != NULL && argv[o->optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[o->optind][0] == '-' + && (argv[o->optind][1] == '-' || long_only)) + )) + { + const struct option *p; + WCHAR *s = o->nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; + p->name; + p++, option_index++) + if ( (p->val) && (!my_strncmp (p->name, o->nextchar, s - o->nextchar)) ) + { + if (s - o->nextchar == (int)my_strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else { + /* Second nonexact match found. */ + ambig = 1; + } + } + + if (ambig && !exact) { + if (o->opterr) { + KdPrint(("%ws: option `%s' is ambiguous\n", + argv[0], argv[o->optind])); + } + o->nextchar += my_strlen (o->nextchar); + o->optind++; + return BAD_OPTION; + } + + if (pfound != NULL) + { + option_index = indfound; + o->optind++; + if (*s) { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) { + o->optarg = s + 1; + } else { + if (o->opterr) { + if (argv[o->optind - 1][1] == '-') { + /* --option */ + KdPrint(( + "%ws: option `--%ws' doesn't allow an argument\n", + argv[0], pfound->name)); + } else { + /* +option or -option */ + KdPrint(( + "%ws: option `%c%ws' doesn't allow an argument\n", + argv[0], argv[o->optind - 1][0], pfound->name)); + } + } + o->nextchar += my_strlen (o->nextchar); + return BAD_OPTION; + } + } + else if (pfound->has_arg == 1) + { + if (o->optind < argc) { + o->optarg = argv[(o->optind)++]; + } else { + if (o->opterr) + KdPrint(("%ws: option `%ws' requires an argument\n", + argv[0], argv[o->optind - 1])); + o->nextchar += my_strlen (o->nextchar); + return optstring[0] == ':' ? ':' : BAD_OPTION; + } + } + o->nextchar += my_strlen (o->nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[o->optind][1] == '-' + || my_index (optstring, *(o->nextchar)) == NULL) + { + if (o->opterr) + { + if (argv[o->optind][1] == '-') { + /* --option */ + KdPrint(("%ws: unrecognized option `--%ws'\n", + argv[0], o->nextchar)); + } else { + /* +option or -option */ + KdPrint(("%ws: unrecognized option `%c%ws'\n", + argv[0], argv[o->optind][0], o->nextchar)); + } + } + o->nextchar = (WCHAR *) L""; + o->optind++; + return BAD_OPTION; + } + } + + /* Look at and handle the next option-character. */ + + { + WCHAR c = *(o->nextchar)++; + WCHAR *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*(o->nextchar) == '\0') + ++(o->optind); + + if (temp == NULL || c == ':') + { + if (o->opterr) + { + KdPrint(("%ws: illegal option -- %c\n", argv[0], c)); + } + o->optopt = c; + return BAD_OPTION; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*(o->nextchar) != '\0') { + o->optarg = o->nextchar; + o->optind++; + } else { + o->optarg = 0; + } + o->nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*(o->nextchar) != '\0') + { + o->optarg = o->nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + o->optind++; + } + else if (o->optind == argc) + { + if (o->opterr) + { + KdPrint(("%ws: option requires an argument -- %c\n", + argv[0], c)); + } + o->optopt = c; + if (optstring[0] == ':') { + c = ':'; + } else { + c = BAD_OPTION; + } + } + else + { + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + o->optarg = argv[o->optind++]; + } + o->nextchar = NULL; + } + } + return c; + } +} + +int +getopt ( + optarg_ctx* o, + int argc, + WCHAR *const *argv, + const WCHAR *optstring) +{ + return _getopt_internal (o, argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +int +getopt_long ( + optarg_ctx* o, + int argc, + WCHAR *const *argv, + const WCHAR *options, + const struct option *long_options, + int *opt_index) +{ + return _getopt_internal (o, argc, argv, options, long_options, opt_index, 0); +} + + +#ifdef __cplusplus +} +#endif diff --git a/reactos/drivers/filesystems/udfs/Include/getopt.h b/reactos/drivers/filesystems/udfs/Include/getopt.h new file mode 100644 index 00000000000..d732afa58a4 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/getopt.h @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef _GETOPT_H +#define _GETOPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BAD_OPTION '\0' + +typedef struct _optarg_ctx { + /* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + + WCHAR* optarg; + + /* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + + int optind; + + /* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + + WCHAR *nextchar; + + /* Callers store zero here to inhibit the error message + for unrecognized options. */ + + int opterr; + + /* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + + int optopt; + + /* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + + int first_nonopt; + int last_nonopt; + + /* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. + + To perform the swap, we first reverse the order of all elements. So + all options now come before all non options, but they are in the + wrong order. So we put back the options and non options in original + order by reversing them again. For example: + original input: a b c -x -y + reverse all: -y -x c b a + reverse options: -x -y c b a + reverse non options: -x -y a b c + */ + +} optarg_ctx, *P_optarg_ctx; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + WCHAR *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +extern void getopt_init(optarg_ctx* o); + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +extern int getopt (optarg_ctx* o, int argc, WCHAR *const *argv, const WCHAR *shortopts); +extern int getopt_long (optarg_ctx* o, int argc, WCHAR *const *argv, const WCHAR *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (optarg_ctx* o, int argc, WCHAR *const *argv, + const WCHAR *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (optarg_ctx* o, int argc, WCHAR *const *argv, + const WCHAR *shortopts, + const struct option *longopts, int *longind, + int long_only); + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/reactos/drivers/filesystems/udfs/Include/key_lib.cpp b/reactos/drivers/filesystems/udfs/Include/key_lib.cpp new file mode 100644 index 00000000000..7496150a2a9 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/key_lib.cpp @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +static const char XPEHb[] = "zfvbgt^&*()aq,lpwdenjsxnygv!@yhuhb#$%chimuokbr"; + +UDF_FibonachiNum( + int n, + int* f + ) +{ + int a=0xff557788; + int i; + // do something + n <<= 8; + for(i=0; i= n) { + n >>= 4; + (*f) = (*f) ^ (a+n); + n >>= 1; + a = n & a; + } + } + n >>= 3; + // if(n < 2) + if(!(n & ~1)) + return 1; + n--; + if(!(n+1)) + return 1; + a = UDF_FibonachiNum(n, f); + return UDF_FibonachiNum(n-1, f) + a; +} + +void +UDF_build_long_key( + char* buffer, + int blen, + char* key_str, + int klen + ) +{ + int i, k, j; + int r[32]; + int* tmp = (int*)buffer; + int f, fn; + + memcpy(buffer, key_str, klen); + for(i=0; i=blen/4) + break; + r[j%(klen/4)] = (int32)( ((int64)r[j%(klen/4)] * 0x8088405 + 1) >> 3 ); + tmp[i] = r[j%(klen/4)] ^ f; + j++; + fn--; + } +} // end UDF_build_long_key() + + +void +UDF_build_hash_by_key( + char* longkey_buffer, + int longkey_len, + char* key_hash, + char* key_str + ) +{ + UDF_MD5_CTX context; + char key1[16]; + int m; + + UDF_build_long_key(longkey_buffer, longkey_len, key_str, 16); + UDF_MD5Init(&context); + UDF_MD5Update(&context, (PUCHAR)longkey_buffer, longkey_len); + UDF_MD5Pad (&context); + UDF_MD5Final((PUCHAR)key_hash, &context); + memcpy(key1, key_hash, 16); + for(m = 0; m<113; m++) { + UDF_build_long_key(longkey_buffer, longkey_len, key_hash, 16); + UDF_MD5Init(&context); + UDF_MD5Update(&context, (PUCHAR)longkey_buffer, longkey_len); + UDF_MD5Pad (&context); + UDF_MD5Final((PUCHAR)key_hash, &context); + } + for(m=0; m<16; m++) { + key_hash[m] = key_hash[m] ^ key1[m]; + } +} // end UDF_build_hash_by_key() + diff --git a/reactos/drivers/filesystems/udfs/Include/key_lib.h b/reactos/drivers/filesystems/udfs/Include/key_lib.h new file mode 100644 index 00000000000..96fbde571fd --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/key_lib.h @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#include "platform.h" +#include "md5.h" + +#define UDF_LONG_KEY_SIZE 1024 + +extern void +UDF_build_long_key( + char* buffer, + int blen, + char* key_str, + int klen + ); + +extern void +UDF_build_hash_by_key( + char* longkey_buffer, + int longkey_len, + char* key_hash, + char* key_str + ); diff --git a/reactos/drivers/filesystems/udfs/Include/keys.cpp.tpl b/reactos/drivers/filesystems/udfs/Include/keys.cpp.tpl new file mode 100644 index 00000000000..8840e17698a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/keys.cpp.tpl @@ -0,0 +1,589 @@ +{0x464eb272,0x9f4d726f,0x40f95d9c,0x3987ae09}, +{0x456423b2,0x6b084fb2,0x779f232e,0x3433bcb2}, +{0x120b2a5f,0xa015659c,0x37d3a35b,0xedddc7c6}, +{0x58eb88c0,0x93b4d904,0x39289e8c,0x485c18d0}, +{0x05da8341,0x1a37a08a,0xab5b9093,0xc1ad8dd0}, +{0x9f157c9c,0xeefec917,0x14f2f336,0x717fcc0c}, +{0x6b7a8089,0xa2097489,0x45dbe485,0x37d0f63b}, +{0xe28ba237,0xb97e5d70,0xb07696bc,0xa506a664}, +{0xd19ad8eb,0x7a0f236a,0xf80290c1,0x71f2b5b2}, +{0x2b0ec7d5,0x88271955,0xa90f3199,0x9dc098da}, +{0x5b0fcd3e,0x5778354a,0xda5e2509,0xf396b58b}, +{0xdf75eeeb,0xba02b001,0x68c29e6f,0xc5514d9c}, +{0x7c6ea336,0x41cbcd58,0xb777e433,0x664ab6d1}, +{0x960026ce,0x9cbd1c87,0xfa1a7818,0x84c673b6}, +{0x2ac852ac,0x8eaa9681,0x6819f875,0x6fc551a9}, +{0xc518549b,0x7a0a8230,0x5a1bfb84,0xa46f9027}, +{0x9e5eaa05,0xb9cdb6c6,0xccd325d7,0xf4d9c68f}, +{0x41b3b128,0xc3c8ce01,0x5f42b5e3,0x91b0d7e6}, +{0x0db18065,0x7e263df0,0xce72309b,0xcd15c548}, +{0x8fa12a15,0xf034c880,0x462828da,0x30720e25}, +{0xe4580867,0xc4323a04,0x2aad1d4a,0xabb5f2ae}, +{0x2d409ac0,0xca426d96,0xb6cff690,0x7ed609b1}, +{0x846bc82a,0xa2c5220b,0xfc8f9e6e,0x90cbb453}, +{0xe4461b74,0x9ebbf4ab,0x35d634e6,0xc026a6e8}, +{0x6f1aad49,0xf6812aef,0x0ee812a4,0xf878c9fc}, +{0xf5f1e6c0,0xffb384c5,0xea5fc9ab,0x4489c71c}, +{0x0a992ebb,0xd335a4ef,0x7d804a9e,0xcb7712fe}, +{0x27973f49,0x98b65183,0xecc6eb21,0xd7562406}, +{0xde9aa2fe,0x0a8ba7a6,0x762f5c9e,0x85dfc7e1}, +{0x9eb2a02a,0x08b8013e,0x58414587,0x14075bd0}, +{0xd6d2aa52,0xa5776692,0xd654a793,0xf8b2cd1e}, +{0x39acbf3c,0x91cfaedf,0xcda41b5a,0xbd1f43d9}, +{0xcb4e4068,0xfde0605e,0xa200dfa8,0x55a179d7}, +{0x505783e6,0xccd8c3bf,0x6f533151,0xb70b4ba9}, +{0x5dc7eeac,0xc3170129,0x942820e0,0x39663808}, +{0xc42d92cb,0xd32fc416,0x9b0e7e03,0x1d06b84c}, +{0x03f18479,0x7415b991,0x45fdb32f,0xfad21e67}, +{0x3bbcc977,0xcdceddc3,0x3087028f,0x3931f927}, +{0x3f600fc9,0x117dd904,0x53517eea,0x0f9063d1}, +{0xa23d715c,0x0da00448,0x7b397ad1,0x9fd7dd2a}, +{0x0d663599,0x4ff3e55d,0xe699dd5f,0x67d8cda1}, +{0x1fc05d79,0x5ef1a023,0x3541c6ca,0x5c087e48}, +{0x4bcbadc0,0xf2dafc5d,0x36ae4de2,0x3a360d1d}, +{0xae6a5788,0x1af7450b,0x10016900,0x6dca6aa3}, +{0xe8f6ff62,0xd2d9648c,0x3a914a56,0x887e6f02}, +{0x94a20036,0xd2ad657d,0x131df7d6,0xda27739d}, +{0x3ad80c90,0xc88d6b6a,0xed0c5936,0xb7848cff}, +{0xe85b07f9,0x43ef69a7,0x0649cac1,0x3724d61c}, +{0x7a6b0657,0x0fbb8c0d,0xe58e7262,0xf91c8036}, +{0x712b77b4,0xe4b1b0be,0xeb63ffd5,0x92bf033c}, +{0x54f1a982,0x83b6eb99,0x0b867758,0x2f213a25}, +{0x4e8c8976,0x1164dcac,0x53fbe278,0xad869afd}, +{0x05b566d7,0x467e202a,0xde861a33,0x73cd0c01}, +{0x50be1f0d,0xaf750eb0,0x55b8f755,0x5acb4ee7}, +{0x6f50daef,0x8537a233,0xb66ee044,0x2826c9a9}, +{0x942ddb0b,0xf5cb9067,0x78b2d2df,0x247d59b3}, +{0x90c659cf,0x444b27f5,0xe594e04a,0x4bb89ef2}, +{0x166e744e,0xeb9a0b8e,0x5ed79141,0x16c03653}, +{0x9da99fe5,0x1aef04a2,0x166a6d89,0x20fe85cc}, +{0x659a562e,0xc6a1d311,0x27d436b8,0xdf880426}, +{0x3c01541a,0x4dcdedf2,0x26bf4d05,0x9d7b80a1}, +{0x547cce62,0xdffbe77d,0xbc465468,0xab8813d5}, +{0xe8e5fe73,0x0a99255e,0x0f1848ac,0x9249c412}, +{0xb7c8f524,0x14016b68,0x92bf5ba9,0xd9860a34}, +{0xf3987bec,0xabc1d48f,0xc2295390,0x920807fd}, +{0x21f31bc9,0xdd912f06,0x04d4b523,0x511c166a}, +{0xd314e200,0x122253bc,0x586860a4,0xbdefecb0}, +{0x81e3b97f,0x5a34322e,0x901f12da,0x96ac5962}, +{0xbe70be25,0x9708c176,0x40515add,0x6670a8c6}, +{0x5a55b6bf,0xc41d077b,0x2be20a8b,0xa9346d1d}, +{0xf0940335,0x2dba5988,0x2b8de508,0xf10f90c4}, +{0x0858b635,0x98de0a2f,0xeb8826ee,0x99cccb5a}, +{0xf5970be7,0xa6206cae,0xa37967e4,0x7e3bdc8a}, +{0x620fd372,0x073b8288,0xeab77455,0xcfac4b96}, +{0x5a06daad,0x4d4f13f9,0x8815aa2d,0x418dba52}, +{0x5592b759,0xc54bf215,0x4d77971f,0xa569eec6}, +{0x6870ac5d,0xe715f4e0,0x188dbd7f,0xa0382fe1}, +{0xe438b05d,0x3743cffb,0x248b2ef1,0x2f37a8e7}, +{0xd075a482,0x787d34f6,0x999fc5a6,0x72c85a6e}, +{0x8cd0f999,0x67df4221,0x5aed7b04,0xc1887d1b}, +{0x8c983d3e,0x659ea055,0xec19849b,0x6da93a70}, +{0xfa69945f,0xa01e9036,0x6d1aba4f,0x6e001f63}, +{0x2f4cac40,0x004cfb9e,0x90c69b60,0xf4b4e109}, +{0xea15c026,0x4020cba9,0x935c4015,0xcd05f40e}, +{0x02e36239,0x9e05673a,0x6ee41e8c,0xd0cda541}, +{0x73a11589,0x5353d35e,0xe5bcb258,0x5fdea079}, +{0x97399ffd,0x05f9dc63,0x726e96c1,0xdcb01c47}, +{0xda84fbbc,0xf2c3c339,0xc48b9dc3,0xa68c7944}, +{0x4ab14c3a,0x47fe735d,0x4655bc4e,0xbb012871}, +{0x59fe1d5e,0x3f384cb1,0x4c377278,0x1850c1b5}, +{0x894d4e2e,0xb10e74b4,0x5e66dfb6,0x11f2f75c}, +{0xea4c6df5,0x95977aa6,0x442ed4bf,0x00767341}, +{0x9d8de9e3,0xad5c1bff,0x7745fff8,0x84d8282d}, +{0x676ac7b5,0x7b86dcd8,0x04631a2e,0x87a89cbb}, +{0x1d5ff8bc,0x13867c85,0x744f5d2f,0x776b6be7}, +{0x2de75ec7,0xf934c55b,0x338e7ef9,0x7c2a4174}, +{0x2225c2da,0x29fe9067,0x49351267,0x74d2831e}, +{0x661146b1,0x98a6751f,0xaf2e7c12,0xfd68d646}, +{0xc355f1d4,0xb5969617,0xdafa73d5,0xc6d36593}, +{0xfaa00891,0xa50a94d5,0xa859ebf3,0x90c6b97d}, +{0xdf2655ad,0xa48b57c5,0xc98e0d75,0xb1eb6547}, +{0xedc5fcf9,0x94bb1c9e,0xd9a457bd,0xdaa1f872}, +{0x04610e08,0x39a2ae50,0xeeb1ef12,0x5e3c0b85}, +{0x80125cae,0x375dd9ab,0x39795460,0x8ef0b2a6}, +{0x7ba2a83d,0x3e1c749a,0x50441a9e,0xf3d9286b}, +{0x22b80ffd,0x5a90460b,0x37304e96,0x100d0c16}, +{0xfc036a30,0xf2f3e782,0x1a1c52e0,0x818e62e3}, +{0x8fb2a8f0,0x78180dd5,0xf0146702,0x25e00c6c}, +{0xec8df538,0x5c116a43,0xec5ea158,0xfdb3c321}, +{0xc1e5afd7,0x63697a31,0x1e851111,0x0527619a}, +{0xe2990e8a,0xbf60a048,0x3f4b4881,0xb6f2d454}, +{0xe81da5b7,0x1d07e924,0x466d4108,0xb92c1ddb}, +{0xba4b51c5,0xb59f9676,0x9f6dca34,0x5014ff20}, +{0xdff0815b,0xba3359a2,0x290a931e,0x6afe9b4d}, +{0x488cead2,0xb5eba54c,0xab40db01,0x63ddaeb7}, +{0xb003cb57,0x3d0aa6ae,0x163fb5fd,0x2d1e180f}, +{0x8a661121,0x6fdcee1e,0x1d523b8f,0x04b6fb93}, +{0xba0611da,0x35b5cb6e,0x104a28bf,0x14816580}, +{0x1646b6c1,0x821ce88e,0xf5dcb33a,0xa502e55c}, +{0x943a0578,0x13a11f1d,0xb88506e0,0x2103d157}, +{0x99f2bd0a,0xe4557ea2,0x0607eb79,0x7661c9b7}, +{0x8e107dd4,0xec16b306,0xaeeb6102,0x5bed2e1c}, +{0xa0a91efa,0x373cf627,0xfeff21f0,0x15a26e9f}, +{0xa65100d1,0x0c1f1ea1,0x16473e4d,0xed2cd7ba}, +{0xb24fea09,0x18e8d920,0x49a53cac,0xf6854d17}, +{0xb5614dea,0x94e20a25,0x6b7233e8,0x1d9c3206}, +{0xf4a92d75,0x5f85c883,0xab122f23,0x437ca5d0}, +{0x374dd522,0xaac5ad1a,0x38f909f6,0xcc12fee2}, +{0xc2a96679,0xc0bb18fb,0xcd6d815c,0xbe637fe2}, +{0x652ce71f,0xe9425870,0xa42108df,0x68b4ccf0}, +{0xe5bbe5c4,0xfd090753,0xdac4efd2,0x5ea56477}, +{0x8f67d8a0,0x8fd61beb,0x0be2ff50,0x77078ab9}, +{0x71b68a44,0x75b34d51,0x885fd1d0,0x1b3f28ab}, +{0x670800ed,0x2802d7d8,0x23e22f3e,0xfdf3fb80}, +{0xcf519664,0xd9a4d453,0xd2623c20,0xa9a80f2d}, +{0x5f7af403,0xf859e86a,0xc7098674,0x8e46ebb8}, +{0x188c447b,0x94c207aa,0xd493db27,0x67f11959}, +{0x39f6f669,0xe07725e8,0x11e48861,0x6a2e8fac}, +{0xce335586,0xc6516c67,0xf65ef1c4,0xe9069f25}, +{0x75b2f286,0x0c8c4720,0xd63d60ea,0xe4340b83}, +{0x7d98ea1e,0x9da042ba,0x00a7c496,0x973aeaef}, +{0x8586cbb6,0x6c621b59,0xb5786657,0x143dd33c}, +{0x8c5da8f3,0x4c5aa120,0xc446424a,0x346681cf}, +{0x3df341bd,0xa9bbf625,0xcc0d6b59,0x5bce0859}, +{0x1cf1de06,0xc423eb66,0xe2a84cc1,0x8aa424e3}, +{0x8ab60890,0x2a032b4c,0xb564278f,0xb6eff9d4}, +{0x85e25a8f,0xfc8e7dc7,0xb94c8d7e,0xbd92faaa}, +{0x9849a0b5,0x9a6c8a7a,0x60b658e6,0x73c26c6d}, +{0xc6508f66,0xf39b1a2b,0xe9b4b7d5,0x42e524df}, +{0x98b3efb4,0x0515335d,0x56ea9c83,0xb09d656e}, +{0xe8390256,0x127e9239,0x0df5c7f7,0x2aaf968c}, +{0x62e426fb,0xf23ae4e1,0x23cc1adf,0x903c2634}, +{0x13a2b181,0x28a68411,0x033514ce,0x6f2d392c}, +{0x96d0993c,0xc95e6371,0xa3ecb3d7,0x32c580c2}, +{0xdbdd9789,0x4b063cf0,0xd3ca705d,0xff1dde9e}, +{0x744210fe,0xb47cb775,0xe9209529,0x5d92fb9d}, +{0x576aa312,0x4b7fde61,0xba2b3590,0xe1919c0b}, +{0x8c414c99,0x8d2f9965,0x70e75b2e,0x201daf0c}, +{0xe74c5ce2,0xe0730812,0x32ac229b,0x8b574aab}, +{0x6a27385e,0xf7e62ce0,0x996569f5,0xca9d3768}, +{0x51583907,0x2375d2d2,0x511db2d8,0xed73b351}, +{0xc2181bce,0xded144b4,0x4121147a,0xfc367633}, +{0xaa9dac85,0x25346819,0x3077443f,0x54c0227c}, +{0x2fefcbd5,0x74ce5196,0x96971fc5,0x6c8f60ac}, +{0xff990570,0xcc61f389,0x3fd1992c,0xd0c617e7}, +{0x67a4f115,0x12d1de80,0x13d0a638,0x39616006}, +{0xd9ce36a8,0x18818b09,0x3e12c13b,0xb941cefe}, +{0xcc118030,0xff2b39f9,0x9ec14ffb,0x75be156a}, +{0x1124525b,0x507b707e,0xb2c2f2ab,0x7fd1545e}, +{0x222288f9,0xc44b221e,0xffd6cbd0,0xb128a234}, +{0xe71aa36b,0x35b1b1a1,0x040ca92d,0x5f33f73f}, +{0x4869432d,0x268e6b9d,0x6151a2c3,0x9cf7b4f2}, +{0x38ff5534,0x75588fd1,0x52502688,0x9d516413}, +{0xf64add9b,0x1dddd827,0x88fea8ad,0xa2d1af76}, +{0x0fe4a7e7,0xd6fe3fc2,0xba6d6256,0xa4fd8553}, +{0x285bd0aa,0x9f53a7b8,0x0302a4fe,0x12ba4a22}, +{0xf0a02afe,0x5669141a,0x05958a39,0xe87f04ea}, +{0xdac350d0,0xd29fb016,0x5c5f0b02,0x01f143b2}, +{0x4d20fe77,0xadcbb181,0xc0f04454,0x64b2be37}, +{0xfe0212a7,0x718abe5e,0x98061ae2,0x0dd9e431}, +{0x191a152f,0x87f27de9,0xd054af43,0x00d6b04d}, +{0xc0735210,0x0bd58b3f,0x96ac6912,0x2eb53fcd}, +{0x796f04fa,0xd2689737,0xddc044ff,0x508cb995}, +{0x733e1ee7,0xf579535e,0x9ae30c09,0x1ee0f7e9}, +{0x627b1ebf,0x1604bd39,0x75ffe5f5,0x0c8ca8f1}, +{0x11d7f6fd,0xe86e800b,0x9339f931,0x9798ad9d}, +{0xed7bd57d,0x0db9e1c5,0x2df8a441,0x4a4aab0c}, +{0x69822c06,0xafd7902e,0xb5f897cd,0x2fefbc9d}, +{0x1ae2a0a3,0x71413064,0x53df291b,0x5579b863}, +{0xfdd3de57,0x63d05fd0,0x9fa32952,0x9b84c9c0}, +{0xebecac20,0xbf9f67cb,0x61210e29,0x2d110b22}, +{0x5e1aa86b,0xf928b1bb,0xc43dc3f0,0x5e7a53ca}, +{0x6aeb61c7,0x30acacaa,0x0a758d2f,0x7761a984}, +{0xce30d965,0x4a288c7d,0x7fe3d287,0x805912b1}, +{0x8201f728,0x690c296c,0x41e25b06,0x6ef30ed1}, +{0xd18879df,0x901a3eb3,0xb4e2e516,0x6a25ef09}, +{0x16dea57b,0x874d54b7,0xe7f33a53,0x803701c3}, +{0x16acef19,0xfbe1905c,0xd412145a,0xf25ac334}, +{0x6037cdfc,0x6f33a11b,0x145d5f39,0x5413eeda}, +{0x5aa2bc9f,0xa19c6a1d,0xd6389f34,0x2dd08f8f}, +{0xd6bb0e57,0x148bc047,0x0ba7bca1,0xf0f96f47}, +{0x6a6f0b8d,0x9f713a8d,0x080c8048,0x8fd9d3c5}, +{0x0541a5cb,0x78cebc1d,0xcbbac10d,0xecb49da3}, +{0x2648b918,0x05cf1b76,0xa71b29de,0x4cd4bd85}, +{0x8aca0fef,0x882360fe,0x574f3705,0xffab6346}, +{0xe27847e3,0x4c840db1,0x4cb1ad0d,0xa1502e7f}, +{0x26f3dbef,0xb8586678,0x6ac33e62,0xa79d4883}, +{0x5cf8424b,0xa8d5bdd7,0xdf8e2aff,0x03c2452b}, +{0x04a4e58c,0x586ea473,0xac19957b,0x3cd1808f}, +{0x2276c1ae,0x0f1672e8,0x6ccccefa,0xb474d276}, +{0xca4b83aa,0x5ca07ca6,0x7bad899f,0xcb9cd680}, +{0xaaa3c07a,0x52028a10,0x9921d96c,0xd606e704}, +{0xf7872f1f,0xaf05198d,0x57349b0b,0x7b8bb956}, +{0xf04908e0,0x8f7d2b71,0xcd8689b7,0x08994cb9}, +{0x67be9e79,0x959f2850,0xdfa2ea88,0x2d34c458}, +{0x51066f0f,0x0ecf8473,0x442592e0,0x2a208172}, +{0xb1443065,0xcb4b6c99,0x08fbe6db,0x2dc08b9b}, +{0x68b653df,0x3597e82c,0xb66feb5f,0x6f338761}, +{0x3f660aae,0x121166ba,0xd365615e,0x495b3451}, +{0xe20162e5,0xb5e6c7f3,0x53205114,0x1dd3aa7f}, +{0x6298b11b,0xbb89ed63,0x2d5103e8,0x4fa81473}, +{0xa3d1e970,0x7d4c2764,0x8b8c3d1c,0x8092e54a}, +{0x127eae63,0xacb401d8,0xcc2534f2,0x82678387}, +{0xfead8828,0xd383c70c,0xb01e6836,0x0956c3d6}, +{0x79cc0594,0xb15be42c,0x7f80de1f,0x949636be}, +{0xee08f04d,0x71733158,0x59a04640,0x3efe92c9}, +{0x7c40cc35,0x80211f91,0xe16f901d,0x1664733f}, +{0x4243fc5b,0xf59972ad,0xc2b2d815,0xd4ec83e0}, +{0xd0cce67b,0xc9ed8a0b,0x6938f254,0x26d8a0c6}, +{0xdf14738a,0x22793292,0xca1b8f93,0x5678362f}, +{0x0802182d,0x7c924a03,0xfe99f175,0x15272607}, +{0xc07a61dc,0x383e9160,0x4cf2de36,0xc4112b3b}, +{0x403e1c63,0xd95077ad,0xf70d08ab,0x724e9745}, +{0xf6598de8,0xc024e2b9,0x3ab423f4,0x49238fa9}, +{0xe8869cb8,0xfd517256,0x6c26c298,0x420a6993}, +{0xe9435dbb,0x7ad6419b,0xfa941963,0x3c14b6d6}, +{0x771916a1,0x48ae53cd,0x7d9bd148,0xa2116f9e}, +{0x717b6010,0x08d2ed76,0x7ab952c4,0x2300bf03}, +{0x670d8997,0x09e23cdb,0xeff00f50,0x1698ffad}, +{0xfcb0552c,0x1ad81994,0x643e8022,0xa6a6b588}, +{0x792f05fe,0x10c4910d,0xfcc6d591,0xe8d946aa}, +{0xfa26c441,0xda604668,0x6eaf7282,0x06a523b4}, +{0x534d6d76,0x7c08ddd1,0xdc0b23e5,0x69c7a581}, +{0x308dbe91,0x516877f5,0xe16cb6e6,0xe7947f22}, +{0x677b572b,0x89a23727,0xff1e80f3,0xb5fb00c6}, +{0x9831a920,0x8352bd61,0x79e2867d,0x961d16f3}, +{0x49681542,0xde5393c5,0x8e64217d,0xa4787fcc}, +{0xa5a6f59e,0xeb8826ab,0xfe76dc57,0x3c91e330}, +{0x11b4ff07,0x3207b417,0x4e3a90ff,0xced4c105}, +{0x055f738b,0xd090f472,0x2793925e,0x069c3c9d}, +{0x34895169,0x969a4bac,0x8152a1ec,0x7a429a21}, +{0xabb398b9,0xd1b8b55b,0x2f27435a,0x3b35827e}, +{0x1e5395c7,0xb2f1e9fb,0xd6be7903,0xb139b803}, +{0x0ced7375,0x43f670c1,0x8490f305,0xf953c4ee}, +{0x98ea2ac8,0xed9c2790,0x688551f7,0x88677401}, +{0x6d19e99a,0x17ebf706,0x63e71abb,0x5150811e}, +{0x16ee26fd,0x3cae3d22,0x8bf06d71,0xbdaf50b1}, +{0xd737dfd3,0x6bf72882,0x22455b57,0x6da57325}, +{0x5e062082,0xc8fcf42d,0x7050da6d,0x5ee62bc1}, +{0x762f7783,0xd7f0d368,0x5a424857,0x7f371f3d}, +{0x0c9298a1,0x4685bc48,0x625f5e47,0x74b8c5d7}, +{0xe0157161,0x8c82749c,0x38d25bd2,0x82740065}, +{0x6639d77d,0x3dcc6db6,0x5677ed3e,0xc92f1f5b}, +{0x4e4ffe36,0xd09f9e04,0x35cbaecc,0x635f0f29}, +{0xf27a1827,0x35021b69,0x0b2fec9b,0x3832c35b}, +{0x9370fa61,0x648e4484,0x874a687a,0xff15f1fa}, +{0x6552b060,0xe1eea13c,0x79a81141,0x125a731b}, +{0xcf74e28c,0x361d99cf,0x735ad0d7,0x17781338}, +{0x64c55a26,0x8cf2b57f,0xcffb0eed,0xd44b664b}, +{0x897dbf3e,0xa73d5b3f,0x606eba0b,0x7fea83eb}, +{0xa6cfa45a,0x8e19869e,0xb35b4a59,0xda9790f0}, +{0x5381db83,0xf3e06cca,0xceb51e21,0x806546a5}, +{0x7079e3c7,0x7081515b,0x5d0f2805,0x42077d2e}, +{0x9ebbc897,0x13dea72b,0xe7520b89,0xa0f70f23}, +{0xdc8d587f,0x1563c103,0x752ef3ee,0x3a8aa821}, +{0x8587cf23,0x1a160e5c,0x01a29306,0x8c84e4df}, +{0xb4ef90bd,0x896818ac,0xf6320f47,0xe584a06e}, +{0x5edc16f9,0xda75c31f,0xd73d791f,0x08fc05fb}, +{0x7d9676a7,0x48483537,0x87377025,0xd477e615}, +{0xf9648730,0xbfc1f99a,0xf84247ee,0xf3fbbdd6}, +{0xce336727,0xd9fbc28b,0x173622e8,0xe50427b0}, +{0xb22da76a,0x2f56a7b5,0x9c4a5304,0x26b61345}, +{0x12b2e9f7,0xd91b9ee3,0xc50c580b,0x11bfbf8e}, +{0x5b68aca6,0x9f9c45cc,0x4226003c,0x5033387f}, +{0xcc0b7db1,0x0cbd30ef,0x040fbb96,0xff92790f}, +{0xd8441e4b,0x506feedd,0xf0ef7ef6,0x5278dac5}, +{0xa586b239,0x9057d034,0x045a10d4,0xff0a4501}, +{0x44c84aca,0x72c7e534,0x9d8b762e,0x09ce7080}, +{0xb19f89f4,0x64807b1b,0x5fc256f5,0x484beaed}, +{0xdeee7e78,0xf7953521,0x5ab0d38a,0xd9c5ccf2}, +{0x2752ba06,0xb149df6a,0xa86bdf71,0x98177806}, +{0x0b165963,0x80c9e332,0x45b05eb9,0x56436678}, +{0x07db7854,0xafbfa56c,0xd598aef9,0x20291690}, +{0x34105580,0x3ebff180,0xb54f0d9f,0x5aac4179}, +{0x9216b3c1,0x0ea2ccc3,0x15e72dba,0x8109567c}, +{0xf3f71644,0x8300bfa8,0xc7762650,0x52cffa43}, +{0xf0e3fcd9,0x0692f957,0x29cb6333,0x6551e83e}, +{0xaf299261,0x0fd8ad80,0x953d045a,0xdcdc0dd8}, +{0xe4e0e616,0x5697b667,0x739cdf50,0x1632e015}, +{0xa463afb0,0x00037812,0xe0ff4e3b,0x7f9370d4}, +{0x8d0dcddd,0xa0222788,0x75a07e11,0x928890db}, +{0xfae0d7f6,0x547c9f6c,0xcaa46153,0x26151c95}, +{0xf09671ce,0x39c5ad01,0x503458f5,0x55c989c9}, +{0xa0be3f26,0x8e164850,0xf62f453b,0x15763688}, +{0x6277b34d,0x5cf05538,0xf98f5180,0xaac7a458}, +{0x194be347,0xe9652177,0x4c76c864,0x43b90beb}, +{0x04334387,0x6c9a1c64,0xb478b652,0xa68a0530}, +{0xe0b5287c,0xdd5fa3c9,0x18ac0290,0x6355f990}, +{0xfb975657,0x11030bd2,0xf873a64b,0xe908982b}, +{0x0c039dcc,0xb4a27dcd,0x7f91df01,0x6ca660cf}, +{0x4a5f70c7,0x08d66dad,0xbaeb303d,0xeaf6ac62}, +{0x6134df3f,0x4346c32d,0x0ccef492,0x80d58162}, +{0x3f9e9cb8,0xa3008f54,0xf7022502,0x096aa2db}, +{0x09643405,0x0bef72e1,0x7a0161e3,0x02b6800d}, +{0x4a9fd7b2,0x2ff2c6e7,0xb0e0f0d6,0x22c5dd5e}, +{0x065c8abe,0x3a54cf26,0x08376d5d,0xd7cdfe40}, +{0xddde7842,0xf5ac25cd,0x2c3a8ba3,0xd8475b2e}, +{0xcb7569f8,0x91c35be9,0x4f235518,0x01922f3b}, +{0x37d9967b,0xfec674e7,0x37ba068d,0xbe1e5473}, +{0xf015ccfa,0x273f9622,0x5b01fa82,0x57b49d65}, +{0xcedfafa7,0xf839a339,0x39de9cb8,0x92af53c7}, +{0xf3a0db2a,0xe94cfc32,0x97d7ba1e,0x63b49741}, +{0xb2b87d08,0x1f1f6080,0xfd768ea4,0x4a975140}, +{0xd81d6db5,0xc8963e38,0x16410bb1,0x2ea27c76}, +{0x8a93e2f6,0x62fbb98e,0x56f90e07,0xbe9e0de9}, +{0x38e10de8,0x39b0022d,0x912eb927,0x8932e981}, +{0x26342052,0xd9b8fc21,0xefb02a6c,0xc904b8aa}, +{0xde4a82f1,0x3bb922f5,0x9b7d98b1,0xa94ba85b}, +{0xacd0ce2c,0xdd191a60,0x0ced9791,0x2ca62c1e}, +{0xc29af305,0xe13d427b,0x37dbd054,0x4c9e741d}, +{0xf835ce44,0xaf77c79a,0x888dd7f4,0x2488e20c}, +{0x08790953,0xe1e8b06a,0x5779d964,0x231b9d94}, +{0xd09a2d81,0x4c3bf9c8,0xda6a82c5,0x1ed5874c}, +{0x264cfcca,0xa15fd61f,0x44a36e1e,0xbff8e65a}, +{0xac7f9e1c,0x93a018cd,0xf946989e,0xdf35f7bd}, +{0xe6b78c52,0x1ab4250b,0xaf864921,0xb2d6cbff}, +{0xc1d932c6,0xd21fc917,0xe80769ea,0x547f1728}, +{0x446a0ef9,0xcd05936a,0xd5b01469,0xb217ad15}, +{0x5b6d04c3,0x4062fa77,0xac7e474f,0x14183152}, +{0x18715a09,0xb425c049,0x271a175e,0xaba13a20}, +{0xe5784f5a,0x06a69f91,0x55c31430,0x1d3c1e03}, +{0x89d90d35,0x9799d79d,0x1aba6e3e,0x5f4820cb}, +{0xc10a24ab,0xbe37d72e,0x4470cb4a,0x238cb818}, +{0xb66ab610,0xa32b76ec,0x35b42469,0x8768088b}, +{0x834bf11c,0x893041a6,0xfbd260d6,0x2d944658}, +{0xa0aafe39,0xb2e78a0a,0x9787b679,0xabad282d}, +{0x83fa9fd0,0x95534f4b,0xc81cd185,0x55f60b8a}, +{0xea82a5e9,0x677b0bf1,0x4930061d,0x9f678be0}, +{0x735dda06,0xba8cf349,0xf70ade7d,0x1202d45d}, +{0xcb40ce40,0x490c44e6,0xadf1af60,0xccb1f81a}, +{0xd93e9fec,0xe32f636a,0xb93d1fa7,0x3a6b765e}, +{0xdf0c87ca,0x3a529193,0x851b2f76,0x0bc7141c}, +{0x05b2f330,0x9f69b5fa,0xaa428d31,0xac88d110}, +{0x1c0c4dca,0xa35f3c72,0xa956c31b,0x7dbe7fad}, +{0xeed1e431,0x1166648f,0xb492d014,0x25592e6f}, +{0xbaca3593,0x4b0f7ba4,0xf9ad5aee,0xb7aa1606}, +{0x230f76b5,0x1139fcbc,0xaf6da823,0x2a007b46}, +{0xe10cc036,0x80bff8dd,0xc487d20f,0x3ff07911}, +{0x2810fe5d,0x738a616f,0x31fcab25,0x8471cfee}, +{0x637d7bf9,0xe6e44c83,0x72c7b44c,0x13ffd522}, +{0xcd8c080e,0x501a9f44,0x96bcb5cf,0x35c7eb31}, +{0x4d2f89e5,0x53dabfa2,0xb4688261,0xc16eed4e}, +{0x93b9050b,0x5be7fa5d,0x18670a44,0x3d2e8456}, +{0x6366c565,0xe2637cc2,0x81991664,0x5f23f909}, +{0x1bd3abdd,0x006e052a,0x15a0ed8c,0xd8ada32f}, +{0xc994c0f7,0xece89aa1,0x246e02f6,0x4cee3b85}, +{0xc6ef8878,0xa1d76898,0xce6168d7,0xdfa16b1f}, +{0x700da326,0x2619930e,0x4caa5968,0x59e3abe6}, +{0x856a3cad,0xacc2c33d,0x3bc61929,0x2eae13e9}, +{0x07f819d2,0xd5606875,0x4f6b2e6b,0x1eeca72a}, +{0x3d18ea86,0xdbb4bd42,0x78075765,0xd667bfe4}, +{0xbe81f615,0xec5e88aa,0x988871bb,0xa58383db}, +{0xaffa1f4e,0x65a0d22e,0xe9392773,0x4b3b6ea8}, +{0x879b6826,0x0f2d90af,0x9c0faa68,0x23c50814}, +{0x16a8fa7f,0xd28e39db,0xe1bf1689,0x81141b58}, +{0x08f20f2e,0x5e7c0849,0xcf82126c,0x55d3f2dc}, +{0x29df49ad,0x6b7075b9,0x80c5d50e,0x9376d286}, +{0x61d7bfc9,0xc391104a,0x457a6f72,0xa4e39391}, +{0x8de80652,0x5792608d,0xf78d1f46,0x1b30848e}, +{0x6cfd4338,0x1ee527a3,0xc36d8800,0x4c3a3fa6}, +{0xfc20c838,0x5f905fe3,0x3262dad2,0x3f4d786c}, +{0xbac1bbd1,0xa9d88edf,0x2540bf26,0x7f7bb536}, +{0xb340a716,0x04477c62,0x8cbd399b,0x49ae3e82}, +{0xe5122fda,0x06f8a717,0x6a74fb7f,0x16dc278f}, +{0xdd97bb16,0x717bb119,0x1c532e28,0x9c60744c}, +{0x3822693b,0x4162c166,0x07d7cfd2,0xe0fd0dcb}, +{0xe7409a2c,0x63fdfae9,0x746cb10a,0x6bf0ad2b}, +{0xd465cd1a,0x5b05a503,0xd54d2a40,0x6f98eedc}, +{0xcf46323a,0xe866b318,0xed155930,0xe5bde5b2}, +{0xe3b07639,0x0b8d6324,0x760e29b3,0x70b0757e}, +{0x71afca08,0x0d27921c,0x19dfe2f1,0xf760a29c}, +{0x39846278,0x3e267cee,0x8212650a,0x1354830b}, +{0xeff59b41,0xd0b5c3fe,0xc1d4602f,0x1ad0a73f}, +{0xbe877473,0x1719120f,0x74ea6b4b,0x2c1f737f}, +{0x089a47bf,0x55a03027,0x05cd7451,0xec378f17}, +{0x309fea5d,0x5e501bc9,0xa7e66bd3,0x22119872}, +{0x2e2245c7,0xc95928d1,0x3cfe99b7,0x493ae7a1}, +{0x89034178,0x27a730e9,0xfcb8ac5c,0x08fc2f6d}, +{0x163f98de,0x97dba8a7,0x85ca93cb,0xeb5dc3e5}, +{0x063e1a1c,0xbf70e24c,0xfa44aff1,0xea79a794}, +{0x62fd1b79,0xabdbfb2c,0x294391ec,0x4e548903}, +{0x81f82bdf,0xc1e2212f,0xeb323e47,0x8a035ea9}, +{0x938f17f2,0xd7b4f4e3,0xa6524903,0xce90d4c7}, +{0xc2c3d170,0x4e92a96b,0x3dc642d6,0x7428a035}, +{0x42ffc9c6,0xe6956db6,0x3c5b5056,0xbe1dc1dd}, +{0xfdb57f6d,0xb473be55,0x77da9d50,0xfc4deaeb}, +{0xaf9410d4,0x7617347b,0xbc5c959a,0xde3aa1e5}, +{0x7af9bd37,0xf6ee13d9,0x0e878d33,0xad754b13}, +{0x61a1a037,0x5d60be5a,0x5318c92d,0x0d2defde}, +{0xdecd4ee1,0x1b3939a5,0x42c58f49,0xffcb5d9a}, +{0x4f38706e,0xbbff414a,0x1522130f,0x2fe1a225}, +{0x2ec120f9,0x56863c05,0x8dae9599,0x8cbf5dbd}, +{0xcb99e13d,0xbd111b43,0x2bfddfbd,0x9453c9d8}, +{0xb3131a0b,0x1b8ed229,0x698e033c,0x83753dde}, +{0x21f17fb0,0x92346c94,0xb8530322,0x8e804091}, +{0x5896fde5,0xd77f371c,0x355261a1,0x69aba8b4}, +{0x9d805551,0xf7d104c3,0xf3403eac,0xbef10cbd}, +{0xe203631e,0xd52a8eb3,0x99977810,0xa154635c}, +{0xb53d09dc,0x47282d39,0xa6b9bc46,0x5a41cbda}, +{0x8b42f8a6,0x54fb5062,0x98d98f2c,0x4048d568}, +{0x6b2bf36a,0xf410b33e,0x8ea5418d,0x52a57797}, +{0xc9229186,0xe31d6507,0x58b4743e,0x2e1713d2}, +{0xaa2f03cb,0x738073d9,0xf0cf1f6b,0x1107acbb}, +{0x1f9f0ad0,0x6768e414,0xd7491dc2,0x96edd0e2}, +{0xe3573f40,0x0e0e17ec,0xf20a8a3f,0x9b87cc8f}, +{0x0c0b0394,0xba487373,0x7ae81327,0xe8d96e96}, +{0xd030039d,0x3e749d93,0x5d8d4d0e,0xf15318e9}, +{0x868c16e8,0x88a83024,0x122c2ba1,0xf96dd833}, +{0x8721acf3,0x7bd8a9be,0x58bfae5c,0xa5e7fed7}, +{0x92a49adc,0x95f4060a,0x76e7e096,0xf352adec}, +{0x2345cb15,0x4a4fb7c2,0x228b9490,0x20a4cf00}, +{0x7b57e2b2,0x0f6c9c4e,0x45ee2dea,0x99f99fab}, +{0x7a4cf357,0x784f4592,0x91f103bd,0x238a8489}, +{0xa91b67db,0xe1adabff,0x70022b11,0xf982c541}, +{0x09d612af,0x15f64357,0x4de883fb,0x6169f8a8}, +{0x22f42165,0xf107c715,0xad84f19a,0xaaa5b394}, +{0xce988ac8,0x34d6e092,0xc81b1d7a,0xc2c0b4e2}, +{0xdc3ea10c,0x8b9f3b3e,0x45320d28,0x4bcab7fa}, +{0x7b7a73b3,0x6832cba1,0x84c9ccf5,0x1679377f}, +{0x3ea8a972,0x92bec59b,0x4250cb29,0xe1cec2b7}, +{0xa4b2f347,0xe0748dd3,0xd23b83d1,0xe74a5af6}, +{0x547fb502,0xf754ad91,0x24350364,0x15fe666c}, +{0xdd5d6c6b,0x061c403a,0x6c38ce6b,0xebaf2e4a}, +{0x8f923f07,0x1a414df0,0x009b4394,0x62afb2c5}, +{0x9569e4f9,0xed87c1d7,0x6331e5b0,0x18cb1f0b}, +{0x30919430,0x8a60b6cc,0xc862a0fb,0x821625ea}, +{0xda80a2d4,0xa76d27ad,0x8d09c4b1,0x1ad8f187}, +{0x043c2f3e,0x79345a4d,0xbe736946,0x7e91d31c}, +{0x507371f8,0x4413bbe9,0xd9b1b1e6,0x810ebfec}, +{0xb03133fe,0xbb3a2ed0,0xd0e672be,0x2ce8c128}, +{0xb0a7215c,0xc7f9727f,0x4d165329,0x2ca5fe24}, +{0x804cfc2c,0xa4a5ebd7,0xa998a8d8,0xc085faf4}, +{0x22f1e6ee,0xf21b641a,0x2be9b979,0xdadd02e4}, +{0xa4fb4025,0x175dfd91,0x7bb8d0bb,0x99ca1700}, +{0x1f958be3,0x8b4a81dd,0x7b0f3c55,0x6b5900c7}, +{0x2850ddee,0x482430dc,0x19c4e3fc,0x149326d4}, +{0x610f8f14,0xfb509efe,0x72660a7b,0xaf9b5c86}, +{0x41600abd,0xde1bba77,0x8aa48714,0x528d5b5c}, +{0xf77ea87f,0xee4bacbe,0x081b8a19,0xad4e3ac1}, +{0x08612899,0x3a80b5f4,0x52cf8a9b,0x66bbef0e}, +{0xf6a6cbf9,0xe95a98cb,0x48229a41,0xc29b1616}, +{0x38aa4210,0xf661366a,0x23fabb55,0xa98a077d}, +{0x7f62945c,0xc81629a5,0x85f18dd9,0x9ba7a22b}, +{0x3f122bb9,0x3f58df3c,0xaffad9d7,0x54e96057}, +{0x93156fd6,0xd3c8e163,0x695d5798,0xf9bfe0ad}, +{0x1e88d32f,0x3476812d,0xea5b5bbd,0x345ab38c}, +{0x7ed6ac4b,0xe7a02cdb,0xe1fc0196,0xabbd50f1}, +{0xe5c3b1c7,0xd50597dc,0xb373364d,0xcf9d612e}, +{0xb53982da,0xe44ce6dc,0xc1cf016a,0xd5b743e5}, +{0x848d5379,0x594cc3e5,0xec8cde6b,0x8b3b0a90}, +{0xafdf7a90,0xd6dd709e,0xa1e2cd85,0xb36883de}, +{0x5f38fb38,0x9ed4ef55,0xd931a44e,0x968f7c1e}, +{0xbd8340f0,0x45dc35bc,0x7dee4bee,0x6619f26a}, +{0x009443c0,0xbd75deff,0x1f67b14a,0xd72cd8d0}, +{0x4df2a323,0x36cc5cd2,0xfb31ff63,0x2b6cb70e}, +{0x5f00903c,0x7b4f16f8,0x3638f65b,0x08d1f343}, +{0xff140de1,0x975278c6,0x8c8c99c0,0xeee649d1}, +{0x99d07ff0,0x7c118702,0x003fbef3,0x866fc947}, +{0x200e93c9,0x0da381e7,0x192133a9,0xf7a68932}, +{0x1e19e29e,0x39ae8c0f,0xb9d35b74,0x7885c910}, +{0xbab75a0a,0x23e6588a,0x54d41722,0x9ff5a933}, +{0x445e3f24,0xa19c14f0,0x61b86fdf,0x66ba5cde}, +{0x9c87212f,0xc213ca35,0x8e628c29,0x1467b5ad}, +{0x50e2ea04,0xf5423dea,0xf0cda44f,0xe7f292a4}, +{0x03b3223b,0xcb9575f7,0xfceb53ac,0x5f4b8d44}, +{0xbf74eda8,0x787dfaa0,0x10f158b9,0x44dc2d7e}, +{0x1fe91a85,0x5e8f979b,0xed50a89c,0x92b652d1}, +{0x89d4883c,0xde28579b,0x9b6b7d66,0xa00cbc26}, +{0x548ecb0d,0xa8a8c49b,0x17719db6,0x302e7673}, +{0xe8d040ef,0x5431091a,0x883af6cd,0xf60d77c9}, +{0x2e88e4ae,0xeb4ddd4c,0xdf2c8a1c,0x49766a25}, +{0xa7f6df0e,0x6c24a6b1,0x463bbe9e,0x0383f419}, +{0x070da0df,0x1a13457f,0x4d46ccb3,0xdc5da545}, +{0x7dbc10d3,0xf0f6f6fa,0x11b20467,0xf1c57633}, +{0x5275c183,0xd1aa76ea,0x1ee695c3,0xeeb67943}, +{0x2bdbc34e,0x386f49d1,0xe331e3ba,0x4f0f91ac}, +{0x14bed861,0xbd18d697,0x02963076,0xddbc03b4}, +{0x39aec481,0x29748962,0xebb2989f,0xa0b873d2}, +{0x0202df24,0x2b36b9d5,0xe069f74b,0xae89a4c7}, +{0x8fbefc48,0xb68a6c2e,0x9c5fcd06,0x5fdc97bc}, +{0xede610bc,0xd1e0d1dd,0x7f7fec84,0x9fb297e0}, +{0xc6723f15,0xcc01ba4e,0x076c641e,0xee2cc9ef}, +{0x22e2b2cc,0xff9fb668,0xb002f1df,0xfbef9e6f}, +{0x6c8bde6d,0xc1cfdb1a,0xeffdbcdb,0xd74ea82d}, +{0x1f3ffa1d,0x5c07754f,0x44d4b8bc,0x56596d99}, +{0xcbb70edb,0xe55af523,0x1846a284,0x0cbf213c}, +{0xf8341166,0xd2c69100,0x70f4304a,0x0fbd0f25}, +{0x90800913,0x94d5e5ed,0xa62431e6,0xab8ad463}, +{0x164eadbb,0x79e26abc,0x416a7056,0x3d8a3921}, +{0x16061f80,0xa33b2975,0xb218851d,0x0d369d49}, +{0xac24d8c4,0x4fe97c8e,0xd09dd89e,0x56d03033}, +{0xce78ce65,0x1e161951,0x0d7405f9,0xeaef2b3b}, +{0xcab7fe13,0x480487fb,0xb0a886f2,0x27b7b925}, +{0x5e27d951,0x746f1313,0xd755c000,0x64d3d793}, +{0xe1fe9327,0xa3f984c5,0xbf1ce31e,0x7193e590}, +{0x248b08e1,0x779a5f02,0x0b77278f,0x8184ce7f}, +{0x08b866d3,0xee8515d3,0x075d381e,0xf890f9ef}, +{0x89a70dd2,0x19993506,0x3c6c8d22,0x27d74b52}, +{0x481a0e47,0xbf04a70f,0x9d7b25fc,0x10a05e73}, +{0x8f177f27,0x98e90f5c,0xe4725c4e,0xc5e4c4f6}, +{0xf261602b,0x70ec416b,0xdf26c965,0xd2e16c42}, +{0xa7d0f663,0xfe1f418d,0xbfd13549,0xa7eadf55}, +{0xcda4caf5,0xb00ad62a,0xcab58e7f,0x905c5a0b}, +{0x885c3809,0xbc088ea2,0x264398d4,0x2c6f88f3}, +{0x54d01c16,0x631a11cb,0xf8892267,0xfb5390d1}, +{0x36a23cdf,0xdaa2f9ba,0x76f7ad35,0x86a948ac}, +{0xf0405bab,0x048ea965,0x69b4bcef,0x2d41cea7}, +{0x2c3561cc,0x9de5633d,0xb3f9f2b2,0x90f0e610}, +{0x4eebddfe,0x39afd2ce,0xd45aa43d,0x940bf668}, +{0x79838fec,0x73d9fb07,0xc8f222da,0x6ac76ad4}, +{0x38d355f0,0x1f1cc653,0x9851e321,0xc03fdaff}, +{0x85dfe841,0xe2b7aa03,0x080e0a18,0x37a1b0f2}, +{0xa315ecf9,0xa746581d,0x05b3c66c,0xa9b6e4aa}, +{0x7ef4a582,0xea2bd629,0x82e42dbc,0xa15b8a38}, +{0xa3615d4a,0x3ea8f313,0xb6539584,0x6d523306}, +{0x1a7c85d2,0xc429859f,0x9dbdbd86,0x19830572}, +{0xdfd77bda,0x9b4c4876,0x2e18a4b1,0x1a27b66f}, +{0x59ab3712,0x68e173ce,0xc67b2c68,0xef155823}, +{0x2de46d99,0x21c21137,0xdf3c62a9,0x7f4ea769}, +{0xcc4136e6,0x69e15d06,0xfc4cf50f,0x4d3bfe8b}, +{0xbd3f0175,0x83eff59d,0x1c45d456,0xcc9530df}, +{0x8cd582d8,0xa6147f4c,0xd3f749d6,0xd0c19e53}, +{0xde01c733,0xb0796358,0x6294065d,0xc7761457}, +{0xbdae5087,0x76eb5294,0x0306327b,0x35a5283e}, +{0x93426b44,0x7a2278ac,0xb90b5f95,0xc08d5aaf}, +{0x7096d988,0x636eab87,0x94416c92,0x65621336}, +{0xe9468627,0x0891e6cd,0x35188a42,0x6ce8b12a}, +{0xd0a68588,0x7bf1403a,0xbf72d8f7,0xa12d5120}, +{0xa418663a,0x830c6326,0xfe00a86f,0x5932135b}, +{0x1d2ce956,0x95f9f5fd,0x2ef30d0e,0x3890c2c1}, +{0x5e98ce4a,0x69f1bbb0,0xd59d25e5,0x3f9f5c8d}, +{0xfe8fed92,0xa91d4c69,0x4919f42a,0x6774466d}, +{0x0fa149aa,0x852b931d,0x44e82356,0x210b28af}, +{0x083985e8,0x0085a625,0xff7a8bda,0x1984b3b9}, +{0x6d97bde7,0x7bbfd0ae,0xea7b36c5,0x4a0580b2}, +{0xbaae4f30,0xe1aa01c1,0x187eb9be,0x86111457}, +{0x307dd97a,0xd014e4de,0x951c1923,0x783a099c}, +{0xca7150de,0xdc0d51d6,0x4b4c0871,0x9f1088bb}, +{0xa6e2180d,0x930635d1,0x7a6057df,0x03a7c0b1}, +{0x7791c086,0xda5aa454,0x9a6e7ac2,0xed7279d0}, +{0xa2b8fb40,0xcdb48947,0xbd1c99c4,0xe728b4a3}, +{0x18cd2ffb,0xcd8c1ad9,0x51c9b2ed,0xb9c439d6}, +{0x64c6ffd0,0x0347766c,0xdc78263d,0x5be61d3f}, +{0xcff092ea,0xf311410a,0xe9e212d1,0xc08fd9cf}, +{0xdb5a3aee,0x9cef0126,0x0bccea65,0xb9534b67}, +{0x476d8ff6,0x4499938c,0xe7f59508,0x3570ab02}, +{0x77c1c2c6,0xaae01b5f,0xcd3cd74a,0x925fd46f}, +{0x1edf2d06,0x28f28308,0xb1f57d3a,0x73fa0a8a}, +{0xe95b317b,0xe8548938,0x1c0f57a2,0x2467a337}, +{0xf5569647,0xa53b9496,0xf8564c17,0xc99fa57b}, +{0xd09e2e97,0xfd93dbab,0xbe5df18d,0x2f407e27}, +{0x35a8cd56,0x96a4d06d,0xac3affbd,0xe17beffc}, +{0,0,0,0} +}; + +#define UDF_NUMBER_OF_KEYS 572 +UCHAR RegKeyName0[] = + "\x2b\x03\x01\x0c\x0b\x0d\x01\x03\x0b\x0c" + "\x89\x8e\x94\x81\x80\xdc\x88\x93\xde\x8e" + "\x8a\xde\xd9\x8a\x83\xcf\x89\x8e\xd4\xcc" + "\x88\x98\x8b\xd8\x95\x9b\xe3\xce\xd9\xcb" + "\x1f\x11\x02\x15\x09\x5f\x5f\x4d\x5f\x5f" + "\xc1\xc1\xb4\x83\x81\x94\xb7\xb6\xb0\x9f" + "\x82\xeb\xff\xe8\xd5\xd9\xdf\x8a\x93\x91" + "\xc5\xde\x9d\xd4\xcf\xd8\x9d\xf6\xce\xd9" + "\x4d\x03\x03\x01\x4c\x03\x01\x05\x02\x1e" + "\x94\x83\x81\xdf\x90\x82\x89\x82\x95\x9e" + ; + diff --git a/reactos/drivers/filesystems/udfs/Include/md5.h b/reactos/drivers/filesystems/udfs/Include/md5.h new file mode 100644 index 00000000000..9638ae93798 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/md5.h @@ -0,0 +1,65 @@ +/* MD5.H - header file for MD5C.C + * $FreeBSD: src/sys/sys/md5.h,v 1.16 2002/06/24 14:18:39 mux Exp $ + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#ifndef _SYS_MD5_H_ +#define _SYS_MD5_H_ +/* MD5 context. */ +typedef struct UDF_MD5Context { + uint32 state[4]; /* state (ABCD) */ + uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} UDF_MD5_CTX; + +#ifdef __cplusplus +#define MD5_DECL extern "C" +#else +#define MD5_DECL extern +#endif + +MD5_DECL +void UDF_MD5Init (UDF_MD5_CTX *); + +MD5_DECL +void UDF_MD5Update (UDF_MD5_CTX *, const unsigned char *, unsigned int); + +MD5_DECL +void UDF_MD5Pad (UDF_MD5_CTX *); + +MD5_DECL +void UDF_MD5Final (unsigned char [16], UDF_MD5_CTX *); + +MD5_DECL +char * UDF_MD5End(UDF_MD5_CTX *, char *); + +typedef struct _UDF_MD5_DIGEST { + uint8 d[16]; +} UDF_MD5_DIGEST , *PUDF_MD5_DIGEST; + +/*char * MD5File(const char *, char *); +char * MD5FileChunk(const char *, char *, off_t, off_t); +char * MD5Data(const unsigned char *, unsigned int, char *);*/ + +#endif /* _SYS_MD5_H_ */ diff --git a/reactos/drivers/filesystems/udfs/Include/md5c.c b/reactos/drivers/filesystems/udfs/Include/md5c.c new file mode 100644 index 00000000000..93b5d13a1dd --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/md5c.c @@ -0,0 +1,567 @@ +/* + * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + * + * This code is the same as the code published by RSA Inc. It has been + * edited for clarity and style only. + */ + +/* + * This file should be kept in sync with src/lib/libmd/md5c.c + */ +//#include "md5.h" + +void UDF_MD5Transform(uint32 [4], const unsigned char [64]); + +/* + * Encodes input (uint32) into output (unsigned char). Assumes len is + * a multiple of 4. + */ + +#define htole32(a) (a) +#define le32dec(a) (*(a)) + +void +UDF_Encode (unsigned char *output, uint32 *input, unsigned int len) +{ + unsigned int i; + unsigned int *op = (unsigned int *)output; + + for (i = 0; i < len / 4; i++) + op[i] = htole32(input[i]); +} + +/* + * Decodes input (unsigned char) into output (uint32). Assumes len is + * a multiple of 4. + */ + +void +UDF_Decode (uint32 *output, const unsigned char *input, unsigned int len) +{ + unsigned int i; + const unsigned int *ip = (const unsigned int *)input; + + for (i = 0; i < len / 4; i++) + output[i] = le32dec(&ip[i]); +} + +static const unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#ifdef _X86_ +__declspec (naked) +uint32 +__fastcall +ROTATE_LEFT( + uint32 x, // ECX + uint32 n // EDX + ) +{ + _asm { + push ecx + mov eax,ecx + mov ecx,edx + rol eax,cl + pop ecx + ret + } +} +#else // NO X86 optimization , use generic C/C++ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +#endif // _X86_ + +/* + * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ + +void +FF( +/* uint32 &a, + uint32 b, + uint32 c, + uint32 d,*/ + uint32 a[4], + uint32 x, + uint32 s, + uint32 ac + ) +{ + a[0] += F (a[1], a[2], a[3]) + (x) + (uint32)(ac); + a[0] = ROTATE_LEFT (a[0], (s)); + a[0] += (a[1]); +} + +void +GG( +/* uint32 &a, + uint32 b, + uint32 c, + uint32 d,*/ + uint32 a[4], + uint32 x, + uint32 s, + uint32 ac + ) +{ +/* a += G ((b), (c), (d)) + (x) + (uint32)(ac); + a = ROTATE_LEFT ((a), (s)); + a += (b);*/ + a[0] += G (a[1], a[2], a[3]) + (x) + (uint32)(ac); + a[0] = ROTATE_LEFT (a[0], (s)); + a[0] += (a[1]); +} + +void +HH( +/* uint32 &a, + uint32 b, + uint32 c, + uint32 d,*/ + uint32 a[4], + uint32 x, + uint32 s, + uint32 ac + ) +{ +/* a += H ((b), (c), (d)) + (x) + (uint32)(ac); + a = ROTATE_LEFT ((a), (s)); + a += (b);*/ + a[0] += H (a[1], a[2], a[3]) + (x) + (uint32)(ac); + a[0] = ROTATE_LEFT (a[0], (s)); + a[0] += (a[1]); +} + +void +II( +/* uint32 &a, + uint32 b, + uint32 c, + uint32 d,*/ + uint32 a[4], + uint32 x, + uint32 s, + uint32 ac + ) +{ +/* a += I ((b), (c), (d)) + (x) + (uint32)(ac); + a = ROTATE_LEFT ((a), (s)); + a += (b);*/ + a[0] += I (a[1], a[2], a[3]) + (x) + (uint32)(ac); + a[0] = ROTATE_LEFT (a[0], (s)); + a[0] += (a[1]); +} + +#if 0 // NO X86 optimization , use generic C/C++ + +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#endif // _X86_ + +/* MD5 initialization. Begins an MD5 operation, writing a new context. */ + +static const uint32 UDF_MD5Init_state[4] = { + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476 + }; + +void +UDF_MD5Init ( + UDF_MD5_CTX *context + ) +{ + + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. */ +#if 0 + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +#endif + memcpy(context->state, UDF_MD5Init_state, sizeof(UDF_MD5Init_state)); +} + +/* + * MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ + +void +UDF_MD5Update ( + UDF_MD5_CTX *context, + const unsigned char *input, + unsigned int inputLen + ) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((uint32)inputLen << 3)) + < ((uint32)inputLen << 3)) + context->count[1]++; + context->count[1] += ((uint32)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy((void *)&context->buffer[index], (const void *)input, + partLen); + UDF_MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + UDF_MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy ((void *)&context->buffer[index], (const void *)&input[i], + inputLen-i); +} + +/* + * MD5 padding. Adds padding followed by original length. + */ + +void +UDF_MD5Pad ( + UDF_MD5_CTX *context + ) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + UDF_Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + UDF_MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + UDF_MD5Update (context, bits, 8); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ + +void +UDF_MD5Final ( + unsigned char digest[16], + UDF_MD5_CTX *context + ) +{ + /* Do padding. */ + UDF_MD5Pad (context); + + /* Store state in digest */ + UDF_Encode (digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset ((void *)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. */ + +static const uint32 UDF_MD5Transform_dwords[4][16] = { + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 + }, + { + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a + }, + { + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 + }, + { + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + } +}; + +static const uint32 UDF_MD5Transform_idx[4][16] = { + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }, + { + 1, 6, 11, 0, 5, 10, 15, 4, + 9, 14, 3, 8, 13, 2, 7, 12 + }, + { + 5, 8, 11, 14, 1, 4, 7, 10, + 13, 0, 3, 6, 9, 12, 15, 2 + }, + { + 0, 7, 14, 5, 12, 3, 10, 1, + 8, 15, 6, 13, 4, 11, 2, 9 + } +}; + +static const uint32 UDF_MD5Transform_Sxx[4][4] = { + { 7 , 12, 17, 22 }, + { 5 , 9 , 14, 20 }, + { 4 , 11, 16, 23 }, + { 6 , 10, 15, 21 } +}; + +void +UDF_MD5Rotate ( + uint32 state[4] + ) +{ + uint32 a = state[3]; + /* Load magic initialization constants. */ +#if 0 + state[3] = state[0]; + state[2] = state[3]; + state[1] = state[4]; +#endif + memmove(&state[1], &state[0], sizeof(state[0])*3); + state[0] = a; +} + +typedef void (*P_MD5_XX) + ( +/* uint32 &a, + uint32 b, + uint32 c, + uint32 d,*/ + uint32 a[4], + uint32 x, + uint32 s, + uint32 ac + ); + +void +UDF_MD5Transform ( + uint32 state[4], + const unsigned char block[64] + ) +{ +// uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + uint32 x[16]; + uint32 state1[4]; + uint32 i, j, k; + + P_MD5_XX MD5_func[] = {FF, GG, HH, II}; + + memcpy(state1, state, sizeof(state1)); + + UDF_Decode (x, block, 64); + + for(j=0; j<4; j++) { + for(i=0; i<16;) { + for(k=0; k<4; k++, i++) { + MD5_func[j] (state1, x[UDF_MD5Transform_idx[j][i]], UDF_MD5Transform_Sxx[j][k], UDF_MD5Transform_dwords[j][i]); /* 1 */ + UDF_MD5Rotate(state1); + } + } + } +#if 0 + for(i=0; i<16;) { + #define j 0 + for(k=0; k<4; k++, i++) { + FF (state1, x[UDF_MD5Transform_idx[j][i]], UDF_MD5Transform_Sxx[j][k], UDF_MD5Transform_dwords[j][i]); /* 1 */ + UDF_MD5Rotate(state1); + } + #undef j + } + for(i=0; i<16;) { + #define j 1 + for(k=0; k<4; k++, i++) { + GG (state1, x[UDF_MD5Transform_idx[j][i]], UDF_MD5Transform_Sxx[j][k], UDF_MD5Transform_dwords[j][i]); /* 1 */ + UDF_MD5Rotate(state1); + } + #undef j + } + for(i=0; i<16;) { + #define j 2 + for(k=0; k<4; k++, i++) { + HH (state1, x[UDF_MD5Transform_idx[j][i]], UDF_MD5Transform_Sxx[j][k], UDF_MD5Transform_dwords[j][i]); /* 1 */ + UDF_MD5Rotate(state1); + } + #undef j + } + for(i=0; i<16;) { + #define j 3 + for(k=0; k<4; k++, i++) { + II (state1, x[UDF_MD5Transform_idx[j][i]], UDF_MD5Transform_Sxx[j][k], UDF_MD5Transform_dwords[j][i]); /* 1 */ + UDF_MD5Rotate(state1); + } + #undef j + } +#endif //0 + +#if 0 + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ +#endif //0 + + state[0] += state1[0]; + state[1] += state1[1]; + state[2] += state1[2]; + state[3] += state1[3]; + + /* Zeroize sensitive information. */ + memset ((void *)x, 0, sizeof (x)); +} diff --git a/reactos/drivers/filesystems/udfs/Include/mem_tools.cpp b/reactos/drivers/filesystems/udfs/Include/mem_tools.cpp new file mode 100644 index 00000000000..f88423273be --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/mem_tools.cpp @@ -0,0 +1,952 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifdef MY_USE_INTERNAL_MEMMANAGER + +#ifdef _X86_ + +__inline VOID DbgTouch(IN PVOID addr) +{ + __asm { + mov eax,addr + mov al,[byte ptr eax] + } +} + +#else // NO X86 optimization , use generic C/C++ + +__inline VOID DbgTouch(IN PVOID addr) +{ + UCHAR a = ((PUCHAR)addr)[0]; +} + +#endif // _X86_ + +//MEM_ALLOC_DESC Allocs[MY_HEAP_MAX_BLOCKS]; + +MEM_FRAME_ALLOC_DESC FrameList[MY_HEAP_MAX_FRAMES]; +#ifdef MEM_LOCK_BY_SPINLOCK +KSPIN_LOCK FrameLock; +KIRQL oldIrql; +#define LockMemoryManager() KeAcquireSpinLock(&FrameLock, &oldIrql) +#define UnlockMemoryManager() KeReleaseSpinLock(&FrameLock, oldIrql) +__inline +NTSTATUS +InitLockMemoryManager() { + KeInitializeSpinLock(&FrameLock); + return STATUS_SUCCESS; +} +#define DeinitLockMemoryManager() {NOTHING;} +#else //MEM_LOCK_BY_SPINLOCK +ERESOURCE FrameLock; +#define LockMemoryManager() ExAcquireResourceExclusiveLite(&FrameLock, TRUE) +#define UnlockMemoryManager() ExReleaseResourceForThreadLite(&FrameLock, ExGetCurrentResourceThread()) +#define InitLockMemoryManager() ExInitializeResourceLite(&FrameLock) +#define DeinitLockMemoryManager() ExDeleteResourceLite(&FrameLock) +#endif //MEM_LOCK_BY_SPINLOCK +ULONG FrameCount; +ULONG LastFrame; +BOOLEAN MyMemInitialized = FALSE; + +#define MyAllocIsFrameFree(FrameList, i) \ + (!(FrameList[i].LastUsed || FrameList[i].FirstFree)) + +#ifdef UDF_DBG +ULONG MemTotalAllocated; +PCHAR BreakAddr; + +VOID +MyAllocDumpDescr( + PMEM_ALLOC_DESC Allocs, + ULONG i + ) +{ + BOOLEAN Used; + + Used = (Allocs[i].Len & MY_HEAP_FLAG_USED) ? TRUE : FALSE; + KdPrint(("block %x \t%s addr %x len %x \t", i, Used ? "used" : "free", Allocs[i].Addr, (Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK)); +#ifdef MY_HEAP_TRACK_OWNERS + KdPrint(("src %x \t line %d \t", Allocs[i].Src, Allocs[i].Line)); +#endif +#ifdef MY_HEAP_TRACK_REF + KdPrint(("%s%s", Used ? " " : "-", Allocs[i].Tag ? Allocs[i].Tag : "")); +#endif + KdPrint(("\n")); +} + +//#define CHECK_ALLOC_FRAMES + +#define DUMP_MEM_FRAMES + +#ifdef DUMP_MEM_FRAMES +ULONG MyDumpMem = FALSE; +#endif //DUMP_MEM_FRAMES + +#define DUMP_MEM_FRAMES2 + +//#ifdef CHECK_ALLOC_FRAMES +VOID +MyAllocDumpFrame( + ULONG Frame + ) +{ + ULONG i; + PMEM_ALLOC_DESC Allocs; + Allocs = FrameList[Frame].Frame; + ULONG k=0; + BOOLEAN Used; +#ifdef DUMP_MEM_FRAMES + if(!MyDumpMem) +#endif //DUMP_MEM_FRAMES + return; + + KdPrint(("Dumping frame %x\n",Frame)); + KdPrint(("FirstFree %x LastUsed %x ", FrameList[Frame].FirstFree, FrameList[Frame].LastUsed)); + KdPrint(("Type %x\n", FrameList[Frame].Type)); + if(Allocs) { + for(i=0;i< (MY_HEAP_MAX_BLOCKS/*-1*/);i++) { + Used = (Allocs[i].Len & MY_HEAP_FLAG_USED) ? TRUE : FALSE; + KdPrint(("block %x \t%s addr %x len %x \t", i, Used ? "used" : "free", Allocs[i].Addr, (Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK)); +#ifdef MY_HEAP_TRACK_OWNERS + KdPrint(("src %x \t line %d \t", Allocs[i].Src, Allocs[i].Line)); +#endif +#ifdef MY_HEAP_TRACK_REF + KdPrint(("%s%s", Used ? " " : "-", Allocs[i].Tag ? Allocs[i].Tag : "")); +#endif + KdPrint(("\n")); + if(!(Allocs[i].Len) && !(Allocs[i].Addr)) { + break; + } + if(Allocs[i].Len & MY_HEAP_FLAG_USED) + k += ((Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK); + } + } + KdPrint((" Wasted %x bytes from %x\n", MY_HEAP_FRAME_SIZE - k, MY_HEAP_FRAME_SIZE)); +} // end MyAllocDumpFrame() + +VOID +MyAllocDumpFrames( + VOID + ) +{ + ULONG i; + + for(i=0;i= (MY_HEAP_MAX_BLOCKS-1)) + return NULL; + + for(i=FirstFree, Allocs = &(Allocs0[i]);i<=LastUsed;i++, Allocs++) { + if( !((l = Allocs->Len) & MY_HEAP_FLAG_USED) && + ((l &= MY_HEAP_FLAG_LEN_MASK) >= size) ) { + // check if minimal + // check for first occurence + if(l < min_len || !min_len) { + min_len = l; + best_i = i; + } + if(l == size) + break; + } + } + // not enough resources + if(best_i >= MY_HEAP_MAX_BLOCKS) return NULL; + // mark as used + Allocs = Allocs0+best_i; + addr = Allocs->Addr; + // create entry for unallocated tail + if(Allocs->Len != size) { // this element is always FREE + if(Allocs[1].Len) { + if(Allocs0[MY_HEAP_MAX_BLOCKS-1].Len) return NULL; +/* for(i=MY_HEAP_MAX_BLOCKS-1;i>best_i;i--) { + Allocs[i] = Allocs[i-1]; + }*/ + RtlMoveMemory(&(Allocs[1]), &(Allocs[0]), (LastUsed-best_i+1)*sizeof(MEM_ALLOC_DESC)); + } + Allocs[1].Addr = Allocs->Addr + size; + if(Allocs[1].Len) { + Allocs[1].Len -= size; + } else { + Allocs[1].Len = MY_HEAP_FRAME_SIZE - (addr - Allocs0[0].Addr) - size; + } +// Allocs[best_i+1].Used = FALSE; // this had been done by prev. ops. + FrameList[Frame].LastUsed++; + } + // update FirstFree pointer + if(FirstFree == best_i) { + for(i=best_i+1, Allocs++; (i<=LastUsed) && (Allocs->Len & MY_HEAP_FLAG_USED);i++, Allocs++) { + // do nothing but scan + } + FrameList[Frame].FirstFree = i; + Allocs = Allocs0+best_i; + } + Allocs->Len = size | MY_HEAP_FLAG_USED; +#ifdef MY_HEAP_TRACK_OWNERS + Allocs->Src = Src; + Allocs->Line = Line; +#endif +#ifdef MY_HEAP_TRACK_REF + Allocs->Tag = Tag; +#endif //MY_HEAP_TRACK_REF + +// KdPrint(( "Mem: Allocated %x at addr %x\n", size, (ULONG)addr )); + // this will set IntegrityTag to zero + *((PULONG)addr) = 0x00000000; +#ifdef MY_HEAP_CHECK_BOUNDS + for(i=0; i> 1; +// KdPrint(("Mem: Freeing %x\n", (ULONG)addr)); DEADDA7A +// for(i=0;i> 1; + if( (Allocs[i].Len & MY_HEAP_FLAG_USED) && (Allocs[i].Addr == (ULONG)addr) ) { +FIF_Found: + return i; + } + if(right - left == 1) { + if( (Allocs[i+1].Len & MY_HEAP_FLAG_USED) && (Allocs[i+1].Addr == (ULONG)addr) ) { + i++; + goto FIF_Found; + } + break; + } + if(Allocs[i].Addr && (Allocs[i].Addr < (ULONG)addr)) { + left = i; + } else { + right = i; + } + } + return -1; +} // end MyFindMemDescByAddr() + +VOID +__fastcall +MyFreePoolInFrame( + ULONG Frame, + PCHAR addr + ) +{ + LONG i, j; + ULONG pc; + ULONG len, len2; + PMEM_ALLOC_DESC Allocs; + + Allocs = FrameList[Frame].Frame; + pc = 0; + i = MyFindMemDescByAddr(Frame, addr); + if(i < 0) { + KdPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); + MyAllocDumpFrame(Frame); + BrutePoint(); + return; + } + Allocs[i].Len &= ~MY_HEAP_FLAG_USED; + len = Allocs[i].Len; // USED bit is already cleared + +#ifdef MY_HEAP_CHECK_BOUNDS + for(j=0; j>> when somebody try to use it + *((PULONG)addr) = 0xDEADDA7A; + MemTotalAllocated -= len; +#endif + if((i0) && !((len2 = Allocs[i-1].Len) & MY_HEAP_FLAG_USED)) { + // pack down + len += (len2 & MY_HEAP_FLAG_LEN_MASK); + pc++; + i--; + } + if(pc) { + // pack + + Allocs[i+pc].Addr = Allocs[i].Addr; + Allocs[i+pc].Len = len; +/* for(;i (ULONG)i) + FrameList[Frame].FirstFree = (ULONG)i; + //ASSERT(FrameList[Frame].LastUsed >= pc); + if(FrameList[Frame].LastUsed < pc) { + FrameList[Frame].LastUsed = 0; + } else { + FrameList[Frame].LastUsed -= pc; + } + return; +} // end MyFreePoolInFrame() + +BOOLEAN +__fastcall +MyResizePoolInFrame( + ULONG Frame, + PCHAR addr, + ULONG new_len +#ifdef MY_HEAP_TRACK_REF + ,PCHAR* Tag +#endif //MY_HEAP_TRACK_REF + ) +{ + LONG i, j; + ULONG len, len2; + PMEM_ALLOC_DESC Allocs; + + if(FrameList[Frame].LastUsed >= (MY_HEAP_MAX_BLOCKS-1)) + return FALSE; + Allocs = FrameList[Frame].Frame; + i = MyFindMemDescByAddr(Frame, addr); + if(i < 0) { + KdPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); + MyAllocDumpFrame(Frame); + BrutePoint(); + return FALSE; + } + if(i>=(MY_HEAP_MAX_BLOCKS-2)) + return FALSE; + +#ifdef MY_HEAP_TRACK_REF + *Tag = Allocs[i].Tag; +#endif //MY_HEAP_TRACK_REF + + len = (Allocs[i].Len & MY_HEAP_FLAG_LEN_MASK); + +#ifdef MY_HEAP_CHECK_BOUNDS + new_len += MY_HEAP_CHECK_BOUNDS_BSZ; + for(j=0; j len ) { + if(Allocs[i+1].Len & MY_HEAP_FLAG_USED) + return FALSE; + if(len + (Allocs[i+1].Len & MY_HEAP_FLAG_LEN_MASK) < new_len) + return FALSE; + Allocs[i].Len += (len2 = (new_len - len)); + Allocs[i+1].Len -= len2; + Allocs[i+1].Addr += len2; + +#ifdef MY_HEAP_CHECK_BOUNDS + for(j=0; j (ULONG)i) + FrameList[Frame].FirstFree = i; + FrameList[Frame].LastUsed++; + + } else { + Allocs[i+1].Len += len2; + Allocs[i+1].Addr -= len2; + } +#ifdef UDF_DBG + MemTotalAllocated -= len2; +#endif + } + + return TRUE; +} // end MyResizePoolInFrame() + +VOID +__fastcall +MyAllocInitFrame( + ULONG Type, + ULONG Frame + ) +{ + PMEM_ALLOC_DESC Allocs; + + Allocs = (PMEM_ALLOC_DESC)DbgAllocatePool(NonPagedPool, sizeof(MEM_ALLOC_DESC)*(MY_HEAP_MAX_BLOCKS+1)); + if(!Allocs) { + KdPrint(("Insufficient resources to allocate frame descriptor\n")); + FrameList[Frame].Frame = NULL; + MyAllocDumpFrames(); + BrutePoint(); + return; + } + RtlZeroMemory(Allocs, sizeof(MEM_ALLOC_DESC)*(MY_HEAP_MAX_BLOCKS+1)); + // alloc heap + Allocs[0].Addr = (ULONG)DbgAllocatePool((POOL_TYPE)Type, MY_HEAP_FRAME_SIZE); + if(!Allocs[0].Addr) { + KdPrint(("Insufficient resources to allocate frame\n")); + DbgFreePool(Allocs); + FrameList[Frame].Frame = NULL; + MyAllocDumpFrames(); + BrutePoint(); + return; + } + Allocs[0].Len = MY_HEAP_FRAME_SIZE; +// Allocs[0].Used = FALSE; + FrameList[Frame].Frame = Allocs; + FrameList[Frame].LastUsed = + FrameList[Frame].FirstFree = 0; + FrameList[Frame].Type = Type; + FrameCount++; + if(LastFrame < Frame) + LastFrame = Frame; +} // end MyAllocInitFrame() + +VOID +__fastcall +MyAllocFreeFrame( + ULONG Frame + ) +{ + // check if already deinitialized + if(!FrameList[Frame].Frame) { + BrutePoint(); + return; + } + DbgFreePool((PVOID)(FrameList[Frame].Frame)[0].Addr); + DbgFreePool((PVOID)(FrameList[Frame].Frame)); + FrameList[Frame].Frame = NULL; + FrameCount--; + if(LastFrame == Frame) { + LONG i; + for(i=LastFrame; i>0; i--) { + if(FrameList[i].Frame) + break; + } + LastFrame = i; + } +} // end MyAllocFreeFrame() + +PCHAR +#ifndef MY_HEAP_TRACK_OWNERS +__fastcall +#endif +MyAllocatePool( + ULONG type, + ULONG size +#ifdef MY_HEAP_TRACK_OWNERS + ,USHORT Src, + USHORT Line +#endif +#ifdef MY_HEAP_TRACK_REF + ,PCHAR Tag +#endif //MY_HEAP_TRACK_REF + ) +{ + ULONG i; + ULONG addr; + +// KdPrint(("MemFrames: %x\n",FrameCount)); + + if(!size || (size > MY_HEAP_FRAME_SIZE)) return NULL; + +#ifdef DUMP_MEM_FRAMES2 + if(MyDumpMem) + MyAllocDumpFrames(); +#endif + + LockMemoryManager(); + for(i=0;i= (ULONG)BreakAddr && addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { +// if(addr<=(ULONG)BreakAddr && addr+sizeof(UDF_FILE_INFO) > (ULONG)BreakAddr) { +// KdPrint(("ERROR !!! Allocating in examined block\n")); +// KdPrint(("addr %x\n", addr)); +// MyAllocDumpFrame(i); +// BrutePoint(); +// } +#endif //UDF_DBG + + UnlockMemoryManager(); + DbgTouch((PVOID)addr); + return (PCHAR)addr; + } + } +#ifdef DUMP_MEM_FRAMES2 + MyAllocDumpFrames(); +#endif + addr = 0; + for(i=0;i= (ULONG)BreakAddr && addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { +// if(addr<=(ULONG)BreakAddr && addr+sizeof(UDF_FILE_INFO) > (ULONG)BreakAddr) { +// KdPrint(("ERROR !!! Allocating in examined block\n")); +// KdPrint(("addr %x\n", addr)); +// MyAllocDumpFrame(i); +// BrutePoint(); +// } +// } else { +// addr = 0; +#endif //UDF_DBG + } +#ifdef DUMP_MEM_FRAMES2 + MyAllocDumpFrames(); +#endif + break; + } + } + UnlockMemoryManager(); + return (PCHAR)addr; +} // end MyAllocatePool() + +LONG +__fastcall +MyFindFrameByAddr( + PCHAR addr + ) +{ + ULONG i; +// ULONG j; + PMEM_ALLOC_DESC Allocs; + + for(i=0;i<=LastFrame; i++) { + if( (Allocs = FrameList[i].Frame) && + (Allocs[0].Addr <= (ULONG)addr) && + (Allocs[0].Addr + MY_HEAP_FRAME_SIZE > (ULONG)addr) ) { + return i; + } + } + return -1; +} + +VOID +__fastcall +MyFreePool( + PCHAR addr + ) +{ + LONG i; + +// KdPrint(("MemFrames: %x\n",FrameCount)); + + LockMemoryManager(); + i = MyFindFrameByAddr(addr); + if(i < 0) { + UnlockMemoryManager(); + KdPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); + BrutePoint(); + return; + } + +#ifdef UDF_DBG + // BreakAddr <= addr < BreakAddr + sizeof(UDF_FILE_INFO) +// if((ULONG)addr >= (ULONG)BreakAddr && (ULONG)addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { +// KdPrint(("Deallocating in examined block\n")); +// KdPrint(("addr %x\n", addr)); +// MyAllocDumpFrame(i); +// BrutePoint(); +// BreakAddr = NULL; +// } +#endif //UDF_DBG + + MyFreePoolInFrame(i,addr); +/* for(j=0;j>> Double deallocation at %x !!! ;( \n", addr)); + BrutePoint(); + return 0; + } + + if(MyResizePoolInFrame(i,addr,NewLength +#ifdef MY_HEAP_TRACK_REF + , &Tag +#endif + )) { +#ifdef CHECK_ALLOC_FRAMES +MyAllocCheck(i); +#endif + + (*NewBuff) = addr; + DbgTouch((PVOID)addr); + UnlockMemoryManager(); + return NewLength; + } + + new_buff = MyAllocatePool(FrameList[i].Type, MyAlignSize__(NewLength) +#ifdef MY_HEAP_TRACK_OWNERS + ,Src,Line +#endif +#ifdef MY_HEAP_TRACK_REF + ,Tag +#endif //MY_HEAP_TRACK_REF + ); + if(!new_buff) { + UnlockMemoryManager(); + return 0; + } + + if(OldLength > NewLength) OldLength = NewLength; + RtlCopyMemory(new_buff, addr, OldLength); + + MyFreePoolInFrame(i,addr); + + if(MyAllocIsFrameFree(FrameList, i)) { + MyAllocFreeFrame(i); + } + UnlockMemoryManager(); + + DbgTouch((PVOID)new_buff); + (*NewBuff) = new_buff; + return OldLength; + +} // end MyReallocPool() + +#ifdef UDF_DBG +LONG +MyFindMemDescByRangeInFrame( + ULONG Frame, + PCHAR addr + ) +{ + ULONG i; + ULONG left; + ULONG right; + PMEM_ALLOC_DESC Allocs; + ULONG curaddr; + ULONG curlen; + + Allocs = FrameList[Frame].Frame; +// i = FrameList[Frame].LastUsed >> 1; +// KdPrint(("Mem: Freeing %x\n", (ULONG)addr)); DEADDA7A +// for(i=0;i> 1; + curaddr = Allocs[i].Addr; + curlen = Allocs[i].Len; + if( (curlen & MY_HEAP_FLAG_USED) && + (curaddr <= (ULONG)addr) && + ((curaddr+(curlen & MY_HEAP_FLAG_LEN_MASK)) > (ULONG)addr) ) { +FIF_Found: + return i; + } + if(right - left == 1) { + if( (Allocs[i+1].Len & MY_HEAP_FLAG_USED) && (Allocs[i+1].Addr == (ULONG)addr) ) { + i++; + goto FIF_Found; + } + break; + } + if(Allocs[i].Addr && (Allocs[i].Addr < (ULONG)addr)) { + left = i; + } else { + right = i; + } + } + return -1; +} // end MyFindMemDescByRangeInFrame() + +LONG +MyFindMemBaseByAddr( + PCHAR addr + ) +{ + ULONG Frame, Base, i; + + LockMemoryManager(); + Frame = MyFindFrameByAddr(addr); + if(Frame < 0) { + UnlockMemoryManager(); + KdPrint(("Mem: <<<*** WARNING ***>>> Unknown base for %x !!! ;( \n", addr)); + BrutePoint(); + return -1; + } + i = MyFindMemDescByRangeInFrame(Frame, addr); + Base = FrameList[Frame].Frame[i].Addr; + UnlockMemoryManager(); + return Base; +} // end MyFindMemBaseByAddr() +#endif //UDF_DBG + +BOOLEAN +MyAllocInit(VOID) +{ + RtlZeroMemory(&FrameList, sizeof(FrameList)); + if(!OS_SUCCESS(InitLockMemoryManager())) { + return FALSE; + } + MyAllocInitFrame(NonPagedPool, 0); + LastFrame = 0; + return (MyMemInitialized = TRUE); +} // end MyAllocInit() + +VOID +MyAllocRelease(VOID) +{ + ULONG i; + PMEM_ALLOC_DESC Allocs; + + if(!MyMemInitialized) + return; + LockMemoryManager(); + for(i=0;i len) { + //RtlZeroMemory(newaddr+len, newlen - len); + } +/* +#ifdef MY_MEM_BOUNDS_CHECK + for(i=0; iModified)) & 0x80000000) + Vcb->Modified = 2; +} // end UDFSetModified() + +VOID +UDFPreClrModified( + IN PVCB Vcb + ) +{ + Vcb->Modified = 1; +} // end UDFPreClrModified() + +VOID +UDFClrModified( + IN PVCB Vcb + ) +{ + KdPrint(("ClrModified\n")); + UDFInterlockedDecrement((PLONG)&(Vcb->Modified)); +} // end UDFClrModified() + diff --git a/reactos/drivers/filesystems/udfs/Include/mountmgr.h b/reactos/drivers/filesystems/udfs/Include/mountmgr.h new file mode 100644 index 00000000000..b2703cb1cd1 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/mountmgr.h @@ -0,0 +1,169 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/*++ + +Copyright (c) 1997-1999 Microsoft Corporation + +Module Name: + + mountmgr.h + +Abstract: + + This file defines the external mount point interface for administering + mount points. + +Author: + + norbertk + +Revision History: + +--*/ + +#ifndef _MOUNTMGR_ +#define _MOUNTMGR_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifndef FAR +#define FAR +#endif + + +#define MOUNTMGR_DEVICE_NAME L"\\Device\\MountPointManager" +#define MOUNTMGR_DOS_DEVICE_NAME L"\\\\.\\MountPointManager" + +#define MOUNTMGRCONTROLTYPE ((ULONG) 'm') +#define MOUNTDEVCONTROLTYPE ((ULONG) 'M') + +// +// These are the IOCTLs supported by the mount point manager. +// + +#define IOCTL_MOUNTMGR_CREATE_POINT CTL_CODE(MOUNTMGRCONTROLTYPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS CTL_CODE(MOUNTMGRCONTROLTYPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_POINTS CTL_CODE(MOUNTMGRCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY CTL_CODE(MOUNTMGRCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER CTL_CODE(MOUNTMGRCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS CTL_CODE(MOUNTMGRCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED CTL_CODE(MOUNTMGRCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED CTL_CODE(MOUNTMGRCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHANGE_NOTIFY CTL_CODE(MOUNTMGRCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE CTL_CODE(MOUNTMGRCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES CTL_CODE(MOUNTMGRCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION CTL_CODE(MOUNTMGRCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// Input structure for IOCTL_MOUNTMGR_CREATE_POINT. +// + +typedef struct _MOUNTMGR_CREATE_POINT_INPUT { + USHORT SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_CREATE_POINT_INPUT, *PMOUNTMGR_CREATE_POINT_INPUT; + +// +// Input structure for IOCTL_MOUNTMGR_DELETE_POINTS, +// IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY. +// + +typedef struct _MOUNTMGR_MOUNT_POINT { + ULONG SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + ULONG UniqueIdOffset; + USHORT UniqueIdLength; + ULONG DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_MOUNT_POINT, *PMOUNTMGR_MOUNT_POINT; + +// +// Output structure for IOCTL_MOUNTMGR_DELETE_POINTS, +// IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY. +// + +typedef struct _MOUNTMGR_MOUNT_POINTS { + ULONG Size; + ULONG NumberOfMountPoints; + MOUNTMGR_MOUNT_POINT MountPoints[1]; +} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS; + +// +// Input structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER. +// + +typedef struct _MOUNTMGR_DRIVE_LETTER_TARGET { + USHORT DeviceNameLength; + WCHAR DeviceName[1]; +} MOUNTMGR_DRIVE_LETTER_TARGET, *PMOUNTMGR_DRIVE_LETTER_TARGET; + +// +// Output structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER. +// + +typedef struct _MOUNTMGR_DRIVE_LETTER_INFORMATION { + BOOLEAN DriveLetterWasAssigned; + UCHAR CurrentDriveLetter; +} MOUNTMGR_DRIVE_LETTER_INFORMATION, *PMOUNTMGR_DRIVE_LETTER_INFORMATION; + +// +// Input structure for IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED and +// IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED. +// + +typedef struct _MOUNTMGR_VOLUME_MOUNT_POINT { + USHORT SourceVolumeNameOffset; + USHORT SourceVolumeNameLength; + USHORT TargetVolumeNameOffset; + USHORT TargetVolumeNameLength; +} MOUNTMGR_VOLUME_MOUNT_POINT, *PMOUNTMGR_VOLUME_MOUNT_POINT; + +// +// Input structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY. +// Output structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY. +// + +typedef struct _MOUNTMGR_CHANGE_NOTIFY_INFO { + ULONG EpicNumber; +} MOUNTMGR_CHANGE_NOTIFY_INFO, *PMOUNTMGR_CHANGE_NOTIFY_INFO; + +// +// Input structure for IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE and +// IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION. +// + +typedef struct _MOUNTMGR_TARGET_NAME { + USHORT DeviceNameLength; + WCHAR DeviceName[1]; +} MOUNTMGR_TARGET_NAME, *PMOUNTMGR_TARGET_NAME; + +// +// The following IOCTL is supported by mounted devices. +// + +#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME CTL_CODE(MOUNTDEVCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Output structure for IOCTL_MOUNTDEV_QUERY_DEVICE_NAME. +// + +typedef struct _MOUNTDEV_NAME { + USHORT NameLength; + WCHAR Name[1]; +} MOUNTDEV_NAME, *PMOUNTDEV_NAME; + +// +// Devices that wish to be mounted should report this GUID in +// IoRegisterDeviceInterface. +// + +//DEFINE_GUID(MOUNTDEV_MOUNTED_DEVICE_GUID, 0x53f5630d, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); + +#endif + diff --git a/reactos/drivers/filesystems/udfs/Include/nt_native.h b/reactos/drivers/filesystems/udfs/Include/nt_native.h new file mode 100644 index 00000000000..533a88e80ea --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/nt_native.h @@ -0,0 +1,1951 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +//====================================================================== +// +// NT_Native.h +// +//====================================================================== + +#ifndef __NT_NATIVE_DEFS__H__ +#define __NT_NATIVE_DEFS__H__ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _KTHREAD *PKTHREAD; +typedef struct _ETHREAD *PETHREAD; +typedef struct _EPROCESS *PEPROCESS; +typedef struct _PEB *PPEB; +typedef struct _KINTERRUPT *PKINTERRUPT; +typedef struct _IO_TIMER *PIO_TIMER; +typedef struct _OBJECT_TYPE *POBJECT_TYPE; +typedef struct _CALLBACK_OBJECT *PCALLBACK_OBJECT; +typedef struct _DEVICE_HANDLER_OBJECT *PDEVICE_HANDLER_OBJECT; +typedef struct _BUS_HANDLER *PBUS_HANDLER; + + +typedef ULONG ACCESS_MASK; +typedef ACCESS_MASK *PACCESS_MASK; + +#define BOOL BOOLEAN +#define DWORD ULONG +#define LPVOID PVOID +#define LPDWORD PULONG + +#define APIENTRY __stdcall + +#define FASTCALL _fastcall + +// end_winnt +// +// The following are masks for the predefined standard access types +// + +#define DELETE (0x00010000L) +#define READ_CONTROL (0x00020000L) +#define WRITE_DAC (0x00040000L) +#define WRITE_OWNER (0x00080000L) +#define SYNCHRONIZE (0x00100000L) + +#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) + +#define STANDARD_RIGHTS_READ (READ_CONTROL) +#define STANDARD_RIGHTS_WRITE (READ_CONTROL) +#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) + +#define STANDARD_RIGHTS_ALL (0x001F0000L) + +#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) + +// +// AccessSystemAcl access type +// + +#define ACCESS_SYSTEM_SECURITY (0x01000000L) + +// +// MaximumAllowed access type +// + +#define MAXIMUM_ALLOWED (0x02000000L) + +// +// These are the generic rights. +// + +#define GENERIC_READ (0x80000000L) +#define GENERIC_WRITE (0x40000000L) +#define GENERIC_EXECUTE (0x20000000L) +#define GENERIC_ALL (0x10000000L) + + +// +// Subroutines for dealing with the Registry +// + +typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +typedef struct _RTL_QUERY_REGISTRY_TABLE { + PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; + ULONG Flags; + PWSTR Name; + PVOID EntryContext; + ULONG DefaultType; + PVOID DefaultData; + ULONG DefaultLength; + +} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; + + +// +// The following flags specify how the Name field of a RTL_QUERY_REGISTRY_TABLE +// entry is interpreted. A NULL name indicates the end of the table. +// + +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 // Name is a subkey and remainder of + // table or until next subkey are value + // names for that subkey to look at. + +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 // Reset current key to original key for + // this and all following table entries. + +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 // Fail if no match found for this table + // entry. + +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 // Used to mark a table entry that has no + // value name, just wants a call out, not + // an enumeration of all values. + +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 // Used to suppress the expansion of + // REG_MULTI_SZ into multiple callouts or + // to prevent the expansion of environment + // variable values in REG_EXPAND_SZ + +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 // QueryRoutine field ignored. EntryContext + // field points to location to store value. + // For null terminated strings, EntryContext + // points to UNICODE_STRING structure that + // that describes maximum size of buffer. + // If .Buffer field is NULL then a buffer is + // allocated. + // + +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 // Used to delete value keys after they + // are queried. + +// +// The following values for the RelativeTo parameter determine what the +// Path parameter to RtlQueryRegistryValues is relative to. +// + +#define RTL_REGISTRY_ABSOLUTE 0 // Path is a full path +#define RTL_REGISTRY_SERVICES 1 // \Registry\Machine\System\CurrentControlSet\Services +#define RTL_REGISTRY_CONTROL 2 // \Registry\Machine\System\CurrentControlSet\Control +#define RTL_REGISTRY_WINDOWS_NT 3 // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion +#define RTL_REGISTRY_DEVICEMAP 4 // \Registry\Machine\Hardware\DeviceMap +#define RTL_REGISTRY_USER 5 // \Registry\User\CurrentUser +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 // Low order bits are registry handle +#define RTL_REGISTRY_OPTIONAL 0x80000000 // Indicates the key node is optional + + + +NTSYSAPI +NTSTATUS +NTAPI +RtlCharToInteger ( + PCSZ String, + ULONG Base, + PULONG Value + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIntegerToUnicodeString ( + ULONG Value, + ULONG Base, + PUNICODE_STRING String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToInteger ( + PUNICODE_STRING String, + ULONG Base, + PULONG Value + ); + + +// +// String manipulation routines +// + +#ifdef _NTSYSTEM_ + +#define NLS_MB_CODE_PAGE_TAG NlsMbCodePageTag +#define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag + +#else + +#define NLS_MB_CODE_PAGE_TAG (*NlsMbCodePageTag) +#define NLS_MB_OEM_CODE_PAGE_TAG (*NlsMbOemCodePageTag) + +#endif // _NTSYSTEM_ + +extern BOOLEAN NLS_MB_CODE_PAGE_TAG; // TRUE -> Multibyte CP, FALSE -> Singlebyte +extern BOOLEAN NLS_MB_OEM_CODE_PAGE_TAG; // TRUE -> Multibyte CP, FALSE -> Singlebyte + +NTSYSAPI +VOID +NTAPI +RtlInitString( + PSTRING DestinationString, + PCSZ SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlInitAnsiString( + PANSI_STRING DestinationString, + PCSZ SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlInitUnicodeString( + PUNICODE_STRING DestinationString, + PCWSTR SourceString + ); + + +NTSYSAPI +VOID +NTAPI +RtlCopyString( + PSTRING DestinationString, + PSTRING SourceString + ); + +NTSYSAPI +CHAR +NTAPI +RtlUpperChar ( + CHAR Character + ); + +NTSYSAPI +LONG +NTAPI +RtlCompareString( + PSTRING String1, + PSTRING String2, + BOOLEAN CaseInSensitive + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualString( + PSTRING String1, + PSTRING String2, + BOOLEAN CaseInSensitive + ); + + +NTSYSAPI +VOID +NTAPI +RtlUpperString( + PSTRING DestinationString, + PSTRING SourceString + ); + +// +// NLS String functions +// + +NTSYSAPI +NTSTATUS +NTAPI +RtlAnsiStringToUnicodeString( + PUNICODE_STRING DestinationString, + PANSI_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToAnsiString( + PANSI_STRING DestinationString, + PUNICODE_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +LONG +NTAPI +RtlCompareUnicodeString( + PUNICODE_STRING String1, + PUNICODE_STRING String2, + BOOLEAN CaseInSensitive + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualUnicodeString( + PUNICODE_STRING String1, + PUNICODE_STRING String2, + BOOLEAN CaseInSensitive + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlPrefixUnicodeString( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeString( + PUNICODE_STRING DestinationString, + PUNICODE_STRING SourceString, + BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +VOID +NTAPI +RtlCopyUnicodeString( + PUNICODE_STRING DestinationString, + PUNICODE_STRING SourceString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeStringToString ( + PUNICODE_STRING Destination, + PUNICODE_STRING Source + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeToString ( + PUNICODE_STRING Destination, + PWSTR Source + ); + + +NTSYSAPI +VOID +NTAPI +RtlFreeUnicodeString( + PUNICODE_STRING UnicodeString + ); + +NTSYSAPI +VOID +NTAPI +RtlFreeAnsiString( + PANSI_STRING AnsiString + ); + + +NTSYSAPI +ULONG +NTAPI +RtlxAnsiStringToUnicodeSize( + PANSI_STRING AnsiString + ); + +// +// NTSYSAPI +// ULONG +// NTAPI +// RtlAnsiStringToUnicodeSize( +// PANSI_STRING AnsiString +// ); +// + +#define RtlAnsiStringToUnicodeSize(STRING) ( \ + NLS_MB_CODE_PAGE_TAG ? \ + RtlxAnsiStringToUnicodeSize(STRING) : \ + ((STRING)->Length + sizeof((UCHAR)NULL)) * sizeof(WCHAR) \ +) + +#if DBG +NTSYSAPI +VOID +NTAPI +RtlAssert( + PVOID FailedAssertion, + PVOID FileName, + ULONG LineNumber, + PCHAR Message + ); + +#define ASSERT( exp ) \ + if (!(exp)) \ + RtlAssert( #exp, __FILE__, __LINE__, NULL ) + +#define ASSERTMSG( msg, exp ) \ + if (!(exp)) \ + RtlAssert( #exp, __FILE__, __LINE__, msg ) + +#else +#define ASSERT( exp ) +#define ASSERTMSG( msg, exp ) +#endif // DBG + +// +// Fast primitives to compare, move, and zero memory +// + +// begin_winnt begin_ntndis +#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_ALPHA) + +#if defined(_M_MRX000) +NTSYSAPI +ULONG +NTAPI +RtlEqualMemory ( + CONST VOID *Source1, + CONST VOID *Source2, + ULONG Length + ); + +#else +#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) +#endif + +#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) +#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) +#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + +#else // _M_PPC + +NTSYSAPI +ULONG +NTAPI +RtlEqualMemory ( + CONST VOID *Source1, + CONST VOID *Source2, + ULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyMemory ( + VOID UNALIGNED *Destination, + CONST VOID UNALIGNED *Source, + ULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyMemory32 ( + VOID UNALIGNED *Destination, + CONST VOID UNALIGNED *Source, + ULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlMoveMemory ( + VOID UNALIGNED *Destination, + CONST VOID UNALIGNED *Source, + ULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlFillMemory ( + VOID UNALIGNED *Destination, + ULONG Length, + UCHAR Fill + ); + +NTSYSAPI +VOID +NTAPI +RtlZeroMemory ( + VOID UNALIGNED *Destination, + ULONG Length + ); +#endif +// end_winnt end_ntndis + +NTSYSAPI +ULONG +NTAPI +RtlCompareMemory ( + PVOID Source1, + PVOID Source2, + ULONG Length + ); + +typedef struct _TIME_FIELDS { + CSHORT Year; // range [1601...] + CSHORT Month; // range [1..12] + CSHORT Day; // range [1..31] + CSHORT Hour; // range [0..23] + CSHORT Minute; // range [0..59] + CSHORT Second; // range [0..59] + CSHORT Milliseconds;// range [0..999] + CSHORT Weekday; // range [0..6] == [Sunday..Saturday] +} TIME_FIELDS; +typedef TIME_FIELDS *PTIME_FIELDS; + + +NTSYSAPI +VOID +NTAPI +RtlTimeToTimeFields ( + PLARGE_INTEGER Time, + PTIME_FIELDS TimeFields + ); + +// +// A time field record (Weekday ignored) -> 64 bit Time value +// + +NTSYSAPI +BOOLEAN +NTAPI +RtlTimeFieldsToTime ( + PTIME_FIELDS TimeFields, + PLARGE_INTEGER Time + ); + +// +// Define the generic mapping array. This is used to denote the +// mapping of each generic access right to a specific access mask. +// + +typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; +} GENERIC_MAPPING; +typedef GENERIC_MAPPING *PGENERIC_MAPPING; + +// +// Define the various device type values. Note that values used by Microsoft +// Corporation are in the range 0-32767, and 32768-65535 are reserved for use +// by customers. +// + +#define DEVICE_TYPE ULONG + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// +// Define the method codes for how buffers are passed for I/O and FS controls +// + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// + + +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe +#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe + + +// begin_winnt + +// +// Define access rights to files and directories +// + +// +// The FILE_READ_DATA and FILE_WRITE_DATA constants are also defined in +// devioctl.h as FILE_READ_ACCESS and FILE_WRITE_ACCESS. The values for these +// constants *MUST* always be in sync. +// The values are redefined in devioctl.h because they must be available to +// both DOS and NT. +// + +#define FILE_READ_DATA ( 0x0001 ) // file & pipe +#define FILE_LIST_DIRECTORY ( 0x0001 ) // directory + +#define FILE_WRITE_DATA ( 0x0002 ) // file & pipe +#define FILE_ADD_FILE ( 0x0002 ) // directory + +#define FILE_APPEND_DATA ( 0x0004 ) // file +#define FILE_ADD_SUBDIRECTORY ( 0x0004 ) // directory +#define FILE_CREATE_PIPE_INSTANCE ( 0x0004 ) // named pipe + +#define FILE_READ_EA ( 0x0008 ) // file & directory + +#define FILE_WRITE_EA ( 0x0010 ) // file & directory + +#define FILE_EXECUTE ( 0x0020 ) // file +#define FILE_TRAVERSE ( 0x0020 ) // directory + +#define FILE_DELETE_CHILD ( 0x0040 ) // directory + +#define FILE_READ_ATTRIBUTES ( 0x0080 ) // all + +#define FILE_WRITE_ATTRIBUTES ( 0x0100 ) // all + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ |\ + FILE_READ_DATA |\ + FILE_READ_ATTRIBUTES |\ + FILE_READ_EA |\ + SYNCHRONIZE) + + +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\ + FILE_WRITE_DATA |\ + FILE_WRITE_ATTRIBUTES |\ + FILE_WRITE_EA |\ + FILE_APPEND_DATA |\ + SYNCHRONIZE) + + +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE |\ + FILE_READ_ATTRIBUTES |\ + FILE_EXECUTE |\ + SYNCHRONIZE) + +// end_winnt + + +// +// Define share access rights to files and directories +// + +#define FILE_SHARE_READ 0x00000001 // winnt +#define FILE_SHARE_WRITE 0x00000002 // winnt +#define FILE_SHARE_DELETE 0x00000004 // winnt +#define FILE_SHARE_VALID_FLAGS 0x00000007 + +// +// Define the file attributes values +// +// Note: 0x00000008 is reserved for use for the old DOS VOLID (volume ID) +// and is therefore not considered valid in NT. +// +// Note: 0x00000010 is reserved for use for the old DOS SUBDIRECTORY flag +// and is therefore not considered valid in NT. This flag has +// been disassociated with file attributes since the other flags are +// protected with READ_ and WRITE_ATTRIBUTES access to the file. +// +// Note: Note also that the order of these flags is set to allow both the +// FAT and the Pinball File Systems to directly set the attributes +// flags in attributes words without having to pick each flag out +// individually. The order of these flags should not be changed! +// + +#define FILE_ATTRIBUTE_READONLY 0x00000001 // winnt +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 // winnt +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 // winnt +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 // winnt +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 // winnt +#define FILE_ATTRIBUTE_NORMAL 0x00000080 // winnt +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 // winnt +#define FILE_ATTRIBUTE_RESERVED0 0x00000200 +#define FILE_ATTRIBUTE_RESERVED1 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 // winnt +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 // winnt +#define FILE_ATTRIBUTE_PROPERTY_SET 0x00002000 +#define FILE_ATTRIBUTE_VALID_FLAGS 0x00003fb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x00003fa7 + +// +// Define the create disposition values +// + +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + + +// +// Define the create/open option flags +// + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +//UNUSED 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_TRANSACTED_MODE 0x00200000 +#define FILE_OPEN_OFFLINE_FILE 0x00400000 + +#define FILE_VALID_OPTION_FLAGS 0x007fffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 + +// +// Define the I/O status information return values for NtCreateFile/NtOpenFile +// + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +// +// Define special ByteOffset parameters for read and write operations +// + +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe + +// +// Define alignment requirement values +// + +#define FILE_BYTE_ALIGNMENT 0x00000000 +#define FILE_WORD_ALIGNMENT 0x00000001 +#define FILE_LONG_ALIGNMENT 0x00000003 +#define FILE_QUAD_ALIGNMENT 0x00000007 +#define FILE_OCTA_ALIGNMENT 0x0000000f +#define FILE_32_BYTE_ALIGNMENT 0x0000001f +#define FILE_64_BYTE_ALIGNMENT 0x0000003f +#define FILE_128_BYTE_ALIGNMENT 0x0000007f +#define FILE_256_BYTE_ALIGNMENT 0x000000ff +#define FILE_512_BYTE_ALIGNMENT 0x000001ff + +// +// Define the maximum length of a filename string +// + +#define MAXIMUM_FILENAME_LENGTH 256 + +// +// Define the various device characteristics flags +// + +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 + +#ifndef _FILESYSTEMFSCTL_ +#define _FILESYSTEMFSCTL_ + +#endif // _FILESYSTEMFSCTL_ + +// +// The following is a list of the native file system fsctls followed by +// additional network file system fsctls. Some values have been +// decommissioned. +// + +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_BATCH_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPBATCH_ACK_CLOSE_PENDING CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_NOTIFY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +// decommissioned fsctl value 9 +#define FSCTL_IS_VOLUME_MOUNTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_IS_PATHNAME_VALID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) // PATHNAME_BUFFER, +#define FSCTL_MARK_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +// decommissioned fsctl value 13 +#define FSCTL_QUERY_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_GET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) +// decommissioned fsctl value 17 +// decommissioned fsctl value 18 +#define FSCTL_MARK_AS_SYSTEM_HIVE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACK_NO_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_INVALIDATE_VOLUMES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_FAT_BPB CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) // FSCTL_QUERY_FAT_BPB_BUFFER +#define FSCTL_REQUEST_FILTER_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) // FILESYSTEM_STATISTICS +#if(_WIN32_WINNT >= 0x0400) +#define FSCTL_GET_NTFS_VOLUME_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS) // NTFS_VOLUME_DATA_BUFFER +#define FSCTL_GET_NTFS_FILE_RECORD CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS) // NTFS_FILE_RECORD_INPUT_BUFFER, NTFS_FILE_RECORD_OUTPUT_BUFFER +#define FSCTL_GET_VOLUME_BITMAP CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS) // STARTING_LCN_INPUT_BUFFER, VOLUME_BITMAP_BUFFER +#define FSCTL_GET_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS) // STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER +#define FSCTL_MOVE_FILE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // MOVE_FILE_DATA, +#define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) +// decomissioned fsctl value 31 +#define FSCTL_ALLOW_EXTENDED_DASD_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS) +#endif /* _WIN32_WINNT >= 0x0400 */ + +// +// Define the base asynchronous I/O argument types +// + +typedef struct _IO_STATUS_BLOCK { + NTSTATUS Status; + ULONG Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +// +// Define an Asynchronous Procedure Call from I/O viewpoint +// + +typedef +VOID +(*PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved + ); + +// +// Define the file information class values +// +// WARNING: The order of the following values are assumed by the I/O system. +// Any changes made here should be reflected there as well. +// + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileCopyOnWriteInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileOleClassIdInformation, + FileOleStateBitsInformation, + FileNetworkOpenInformation, + FileObjectIdInformation, + FileOleAllInformation, + FileOleDirectoryInformation, + FileContentIndexInformation, + FileInheritContentIndexInformation, + FileOleInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +// +// Define the various structures which are returned on query operations +// + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NETWORK_OPEN_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + + +typedef struct _FILE_FULL_EA_INFORMATION { + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + +// +// Define the file system information class values +// +// WARNING: The order of the following values are assumed by the I/O system. +// Any changes made here should be reflected there as well. + +typedef enum _FSINFOCLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsQuotaQueryInformation, // temporary + FileFsQuotaSetInformation, // temporary + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +// +// Registry Specific Access Rights. +// + +#define KEY_QUERY_VALUE (0x0001) +#define KEY_SET_VALUE (0x0002) +#define KEY_CREATE_SUB_KEY (0x0004) +#define KEY_ENUMERATE_SUB_KEYS (0x0008) +#define KEY_NOTIFY (0x0010) +#define KEY_CREATE_LINK (0x0020) + +#define KEY_READ ((STANDARD_RIGHTS_READ |\ + KEY_QUERY_VALUE |\ + KEY_ENUMERATE_SUB_KEYS |\ + KEY_NOTIFY) \ + & \ + (~SYNCHRONIZE)) + + +#define KEY_WRITE ((STANDARD_RIGHTS_WRITE |\ + KEY_SET_VALUE |\ + KEY_CREATE_SUB_KEY) \ + & \ + (~SYNCHRONIZE)) + +#define KEY_EXECUTE ((KEY_READ) \ + & \ + (~SYNCHRONIZE)) + +#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL |\ + KEY_QUERY_VALUE |\ + KEY_SET_VALUE |\ + KEY_CREATE_SUB_KEY |\ + KEY_ENUMERATE_SUB_KEYS |\ + KEY_NOTIFY |\ + KEY_CREATE_LINK) \ + & \ + (~SYNCHRONIZE)) + +// +// Open/Create Options +// + +#define REG_OPTION_RESERVED (0x00000000L) // Parameter is reserved + +#define REG_OPTION_NON_VOLATILE (0x00000000L) // Key is preserved + // when system is rebooted + +#define REG_OPTION_VOLATILE (0x00000001L) // Key is not preserved + // when system is rebooted + +#define REG_OPTION_CREATE_LINK (0x00000002L) // Created key is a + // symbolic link + +#define REG_OPTION_BACKUP_RESTORE (0x00000004L) // open for backup or restore + // special access rules + // privilege required + +#define REG_OPTION_OPEN_LINK (0x00000008L) // Open symbolic link + +#define REG_LEGAL_OPTION \ + (REG_OPTION_RESERVED |\ + REG_OPTION_NON_VOLATILE |\ + REG_OPTION_VOLATILE |\ + REG_OPTION_CREATE_LINK |\ + REG_OPTION_BACKUP_RESTORE |\ + REG_OPTION_OPEN_LINK) + +// +// Key creation/open disposition +// + +#define REG_CREATED_NEW_KEY (0x00000001L) // New Registry Key created +#define REG_OPENED_EXISTING_KEY (0x00000002L) // Existing Key opened + +// +// Key restore flags +// + +#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) // Restore whole hive volatile +#define REG_REFRESH_HIVE (0x00000002L) // Unwind changes to last flush +#define REG_NO_LAZY_FLUSH (0x00000004L) // Never lazy flush this hive + +// +// Key query structures +// + +typedef struct _KEY_BASIC_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; // Variable length string +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +typedef struct _KEY_NODE_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; // Variable length string +// Class[1]; // Variable length string not declared +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION { + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; // Variable length +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +typedef enum _KEY_INFORMATION_CLASS { + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation +} KEY_INFORMATION_CLASS; + +typedef struct _KEY_WRITE_TIME_INFORMATION { + LARGE_INTEGER LastWriteTime; +} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION; + +typedef enum _KEY_SET_INFORMATION_CLASS { + KeyWriteTimeInformation +} KEY_SET_INFORMATION_CLASS; + +// +// Value entry query structures +// + +typedef struct _KEY_VALUE_BASIC_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; // Variable size +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +typedef struct _KEY_VALUE_FULL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; // Variable size +// Data[1]; // Variable size data not declared +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; // Variable size +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef struct _KEY_VALUE_ENTRY { + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + +typedef enum _KEY_VALUE_INFORMATION_CLASS { + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation +} KEY_VALUE_INFORMATION_CLASS; + + +NTSYSAPI +NTSTATUS +NTAPI +NtEnumerateKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + IN PVOID KeyValueInformation, + IN ULONG Length, + IN PULONG ResultLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtSetValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex OPTIONAL, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtDeleteValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName + ); + + +#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\') + +// +// Object Manager Object Type Specific Access Rights. +// + +#define OBJECT_TYPE_CREATE (0x0001) + +#define OBJECT_TYPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +// +// Object Manager Directory Specific Access Rights. +// + +#define DIRECTORY_QUERY (0x0001) +#define DIRECTORY_TRAVERSE (0x0002) +#define DIRECTORY_CREATE_OBJECT (0x0004) +#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) + +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) + +// +// Object Manager Symbolic Link Specific Access Rights. +// + +#define SYMBOLIC_LINK_QUERY (0x0001) + +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +typedef struct _OBJECT_NAME_INFORMATION { + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +// +// Section Information Structures. +// + +typedef enum _SECTION_INHERIT { + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +// +// Section Access Rights. +// + +// begin_winnt +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 + +#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|\ + SECTION_MAP_WRITE | \ + SECTION_MAP_READ | \ + SECTION_MAP_EXECUTE | \ + SECTION_EXTEND_SIZE) +// end_winnt + +#define SEGMENT_ALL_ACCESS SECTION_ALL_ACCESS + +#define PAGE_NOACCESS 0x01 // winnt +#define PAGE_READONLY 0x02 // winnt +#define PAGE_READWRITE 0x04 // winnt +#define PAGE_WRITECOPY 0x08 // winnt +#define PAGE_EXECUTE 0x10 // winnt +#define PAGE_EXECUTE_READ 0x20 // winnt +#define PAGE_EXECUTE_READWRITE 0x40 // winnt +#define PAGE_EXECUTE_WRITECOPY 0x80 // winnt +#define PAGE_GUARD 0x100 // winnt +#define PAGE_NOCACHE 0x200 // winnt + +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#define MEM_LARGE_PAGES 0x20000000 +#define SEC_RESERVE 0x4000000 +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + 0xFFF) + + +#define MAXIMUM_PROCESSORS 32 + +// end_winnt + +// +// Thread Specific Access Rights +// + +#define THREAD_TERMINATE (0x0001) // winnt +#define THREAD_SET_INFORMATION (0x0020) // winnt + +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + 0x3FF) + +// +// ClientId +// + +typedef struct _CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID; +typedef CLIENT_ID *PCLIENT_ID; + +// +// Define the size of the 80387 save area, which is in the context frame. +// + +#define SIZE_OF_80387_REGISTERS 80 + +// +// The following flags control the contents of the CONTEXT structure. +// + +#if !defined(RC_INVOKED) + +#define CONTEXT_i386 0x00010000 // this assumes that i386 and +#define CONTEXT_i486 0x00010000 // i486 have identical context records + +// end_wx86 + +#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP +#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI +#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) // DS, ES, FS, GS +#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) // 387 state +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) // DB 0-3,6,7 + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER |\ + CONTEXT_SEGMENTS) + +// begin_wx86 + +#endif + +typedef struct _FLOATING_SAVE_AREA { + ULONG ControlWord; + ULONG StatusWord; + ULONG TagWord; + ULONG ErrorOffset; + ULONG ErrorSelector; + ULONG DataOffset; + ULONG DataSelector; + UCHAR RegisterArea[SIZE_OF_80387_REGISTERS]; + ULONG Cr0NpxState; +} FLOATING_SAVE_AREA; + +typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; + +// +// Context Frame +// +// This frame has a several purposes: 1) it is used as an argument to +// NtContinue, 2) is is used to constuct a call frame for APC delivery, +// and 3) it is used in the user level thread creation routines. +// +// The layout of the record conforms to a standard call frame. +// + +typedef struct _CONTEXT { + + // + // The flags values within this flag control the contents of + // a CONTEXT record. + // + // If the context record is used as an input parameter, then + // for each portion of the context record controlled by a flag + // whose value is set, it is assumed that that portion of the + // context record contains valid context. If the context record + // is being used to modify a threads context, then only that + // portion of the threads context will be modified. + // + // If the context record is used as an IN OUT parameter to capture + // the context of a thread, then only those portions of the thread's + // context corresponding to set flags will be returned. + // + // The context record is never used as an OUT only parameter. + // + + ULONG ContextFlags; + + // + // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is + // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT + // included in CONTEXT_FULL. + // + + ULONG Dr0; + ULONG Dr1; + ULONG Dr2; + ULONG Dr3; + ULONG Dr6; + ULONG Dr7; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_FLOATING_POINT. + // + + FLOATING_SAVE_AREA FloatSave; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_SEGMENTS. + // + + ULONG SegGs; + ULONG SegFs; + ULONG SegEs; + ULONG SegDs; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_INTEGER. + // + + ULONG Edi; + ULONG Esi; + ULONG Ebx; + ULONG Edx; + ULONG Ecx; + ULONG Eax; + + // + // This section is specified/returned if the + // ContextFlags word contians the flag CONTEXT_CONTROL. + // + + ULONG Ebp; + ULONG Eip; + ULONG SegCs; // MUST BE SANITIZED + ULONG EFlags; // MUST BE SANITIZED + ULONG Esp; + ULONG SegSs; + +} CONTEXT; + + + +typedef CONTEXT *PCONTEXT; + +// +// Predefined Value Types. +// + +#define REG_NONE ( 0 ) // No value type +#define REG_SZ ( 1 ) // Unicode nul terminated string +#define REG_EXPAND_SZ ( 2 ) // Unicode nul terminated string + // (with environment variable references) +#define REG_BINARY ( 3 ) // Free form binary +#define REG_DWORD ( 4 ) // 32-bit number +#define REG_DWORD_LITTLE_ENDIAN ( 4 ) // 32-bit number (same as REG_DWORD) +#define REG_DWORD_BIG_ENDIAN ( 5 ) // 32-bit number +#define REG_LINK ( 6 ) // Symbolic Link (unicode) +#define REG_MULTI_SZ ( 7 ) // Multiple Unicode strings +#define REG_RESOURCE_LIST ( 8 ) // Resource list in the resource map +#define REG_FULL_RESOURCE_DESCRIPTOR ( 9 ) // Resource list in the hardware description +#define REG_RESOURCE_REQUIREMENTS_LIST ( 10 ) + +/* +LONG +FASTCALL +InterlockedIncrement( + IN PLONG Addend + ); + +LONG +FASTCALL +InterlockedDecrement( + IN PLONG Addend + ); + +LONG +FASTCALL +InterlockedExchange( + IN OUT PLONG Target, + IN LONG Value + ); + +LONG +FASTCALL +InterlockedExchangeAdd( + IN OUT PLONG Addend, + IN LONG Increment + ); + +PVOID +FASTCALL +InterlockedCompareExchange( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + ); +*/ +// +// Environment information, which includes command line and +// image file name +// +typedef struct { + ULONG Unknown[21]; + UNICODE_STRING CommandLine; + UNICODE_STRING ImageFile; +} ENVIRONMENT_INFORMATION, *PENVIRONMENT_INFORMATION; + +// +// This structure is passed as NtProcessStartup's parameter +// +typedef struct { + ULONG Unknown[3]; + PENVIRONMENT_INFORMATION Environment; +} STARTUP_ARGUMENT, *PSTARTUP_ARGUMENT; + +// +// Data structure for heap definition. This includes various +// sizing parameters and callback routines, which, if left NULL, +// result in default behavior +// +typedef struct { + ULONG Length; + ULONG Unknown[11]; +} RTL_HEAP_DEFINITION, *PRTL_HEAP_DEFINITION; + +// +// Native NT api function to write something to the boot-time +// blue screen +// +NTSTATUS +NTAPI +NtDisplayString( + PUNICODE_STRING String + ); + +// +// Native applications must kill themselves when done - the job +// of this native API +// +NTSTATUS +NTAPI +NtTerminateProcess( + HANDLE ProcessHandle, + LONG ExitStatus + ); + +// +// Thread start function +// + +typedef +VOID +(*PKSTART_ROUTINE) ( + IN PVOID StartContext + ); + +typedef struct StackInfo_t { + ULONG Unknown1; + ULONG Unknown2; + ULONG TopOfStack; + ULONG OnePageBelowTopOfStack; + ULONG BottomOfStack; +} STACKINFO, *PSTACKINFO; + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateThread( + OUT PHANDLE phThread, + IN ACCESS_MASK AccessMask, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN HANDLE hProcess, + OUT PCLIENT_ID pClientId, + IN PCONTEXT pContext, + OUT PSTACKINFO pStackInfo, + IN BOOLEAN bSuspended +); + +/*NTSTATUS +PsCreateSystemThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle OPTIONAL, + OUT PCLIENT_ID ClientId OPTIONAL, + IN PKSTART_ROUTINE StartRoutine, + IN PVOID StartContext + ); +*/ +NTSTATUS +NtTerminateThread( + IN HANDLE ThreadHandle OPTIONAL, + IN NTSTATUS ExitStatus + ); + +/* +BOOLEAN +PsGetVersion( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ); + +HANDLE +PsGetCurrentProcessId( VOID ); + +HANDLE +PsGetCurrentThreadId( VOID ); +*/ +// +// Definition to represent current process +// +#define NtCurrentProcess() ( (HANDLE) -1 ) + +typedef NTSTATUS +(*PRTL_HEAP_COMMIT_ROUTINE)( + IN PVOID Base, + IN OUT PVOID *CommitAddress, + IN OUT PULONG CommitSize + ); + +typedef struct _RTL_HEAP_PARAMETERS { + ULONG Length; + ULONG SegmentReserve; + ULONG SegmentCommit; + ULONG DeCommitFreeBlockThreshold; + ULONG DeCommitTotalFreeThreshold; + ULONG MaximumAllocationSize; + ULONG VirtualMemoryThreshold; + ULONG InitialCommit; + ULONG InitialReserve; + PRTL_HEAP_COMMIT_ROUTINE CommitRoutine; + ULONG Reserved[ 2 ]; +} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS; + +NTSYSAPI +PVOID +NTAPI +RtlCreateHeap( + IN ULONG Flags, + IN PVOID HeapBase OPTIONAL, + IN ULONG ReserveSize OPTIONAL, + IN ULONG CommitSize OPTIONAL, + IN PVOID Lock OPTIONAL, + IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL + ); + +#define HEAP_NO_SERIALIZE 0x00000001 // winnt +#define HEAP_GROWABLE 0x00000002 // winnt +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 // winnt +#define HEAP_ZERO_MEMORY 0x00000008 // winnt +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 // winnt +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 // winnt +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 // winnt +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 // winnt + +#define HEAP_CREATE_ALIGN_16 0x00010000 // winnt Create heap with 16 byte alignment +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 // winnt Create heap call tracing enabled + +#define HEAP_SETTABLE_USER_VALUE 0x00000100 +#define HEAP_SETTABLE_USER_FLAG1 0x00000200 +#define HEAP_SETTABLE_USER_FLAG2 0x00000400 +#define HEAP_SETTABLE_USER_FLAG3 0x00000800 +#define HEAP_SETTABLE_USER_FLAGS 0x00000E00 + +#define HEAP_CLASS_0 0x00000000 // process heap +#define HEAP_CLASS_1 0x00001000 // private heap +#define HEAP_CLASS_2 0x00002000 // Kernel Heap +#define HEAP_CLASS_3 0x00003000 // GDI heap +#define HEAP_CLASS_4 0x00004000 // User heap +#define HEAP_CLASS_5 0x00005000 // Console heap +#define HEAP_CLASS_6 0x00006000 // User Desktop heap +#define HEAP_CLASS_7 0x00007000 // Csrss Shared heap +#define HEAP_CLASS_8 0x00008000 // Csr Port heap +#define HEAP_CLASS_MASK 0x0000F000 + +#define HEAP_MAXIMUM_TAG 0x0FFF // winnt +#define HEAP_GLOBAL_TAG 0x0800 +#define HEAP_PSEUDO_TAG_FLAG 0x8000 // winnt +#define HEAP_TAG_SHIFT 16 // winnt +#define HEAP_MAKE_TAG_FLAGS( b, o ) ((ULONG)((b) + ((o) << 16))) // winnt +#define HEAP_TAG_MASK (HEAP_MAXIMUM_TAG << HEAP_TAG_SHIFT) + +#define HEAP_CREATE_VALID_MASK (HEAP_NO_SERIALIZE | \ + HEAP_GROWABLE | \ + HEAP_GENERATE_EXCEPTIONS | \ + HEAP_ZERO_MEMORY | \ + HEAP_REALLOC_IN_PLACE_ONLY | \ + HEAP_TAIL_CHECKING_ENABLED | \ + HEAP_FREE_CHECKING_ENABLED | \ + HEAP_DISABLE_COALESCE_ON_FREE | \ + HEAP_CLASS_MASK | \ + HEAP_CREATE_ALIGN_16 | \ + HEAP_CREATE_ENABLE_TRACING) + +NTSYSAPI +PVOID +NTAPI +RtlDestroyHeap( + IN PVOID HeapHandle + ); + +// +// Heap allocation function (ala "malloc") +// +PVOID +NTAPI +RtlAllocateHeap( + HANDLE Heap, + ULONG Flags, + ULONG Size + ); + +// +// Heap free function (ala "free") +// +BOOLEAN +NTAPI +RtlFreeHeap( + HANDLE Heap, + ULONG Flags, + PVOID Address + ); + + +NTSTATUS +NTAPI +NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenFile( + OUT PHANDLE phFile, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + IN ULONG ShareMode, + IN ULONG OpenMode +); + +NTSYSAPI +NTSTATUS +NTAPI +NtDeviceIoControlFile( + IN HANDLE hFile, + IN HANDLE hEvent OPTIONAL, + IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, + IN PVOID IoApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + IN ULONG DeviceIoControlCode, + IN PVOID InBuffer OPTIONAL, + IN ULONG InBufferLength, + OUT PVOID OutBuffer OPTIONAL, + IN ULONG OutBufferLength +); + +NTSYSAPI +NTSTATUS +NTAPI +NtFsControlFile( + IN HANDLE hFile, + IN HANDLE hEvent OPTIONAL, + IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, + IN PVOID IoApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + IN ULONG DeviceIoControlCode, + IN PVOID InBuffer OPTIONAL, + IN ULONG InBufferLength, + OUT PVOID OutBuffer OPTIONAL, + IN ULONG OutBufferLength +); + +NTSYSAPI +NTSTATUS +NTAPI +NtReadFile( + IN HANDLE hFile, + IN HANDLE hEvent OPTIONAL, + IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, + IN PVOID IoApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + OUT PVOID ReadBuffer, + IN ULONG ReadBufferLength, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN PULONG LockOperationKey +); + +NTSYSAPI +NTSTATUS +NTAPI +NtWriteFile( + IN HANDLE hFile, + IN HANDLE hEvent OPTIONAL, + IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, + IN PVOID IoApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + IN PVOID WriteBuffer, + IN ULONG WriteBufferLength, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN PULONG LockOperationKey OPTIONAL +); + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryInformationFile( + IN HANDLE hFile, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + OUT PVOID FileInformationBuffer, + IN ULONG FileInformationBufferLength, + IN FILE_INFORMATION_CLASS FileInfoClass +); + +NTSYSAPI +NTSTATUS +NTAPI +NtSetInformationFile( + IN HANDLE hFile, + OUT PIO_STATUS_BLOCK pIoStatusBlock, + IN PVOID FileInformationBuffer, + IN ULONG FileInformationBufferLength, + IN FILE_INFORMATION_CLASS FileInfoClass +); + +NTSTATUS +NTAPI +NtClose( + IN HANDLE Handle + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtWaitForSingleObject( + IN HANDLE hObject, + IN BOOLEAN bAlertable, + IN PLARGE_INTEGER Timeout +); + +NTSTATUS +NTAPI +NtDelayExecution ( + IN BOOLEAN Alertable, + IN PLARGE_INTEGER DelayInterval + ); + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#endif //__NT_NATIVE_DEFS__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/ntddk_ex.h b/reactos/drivers/filesystems/udfs/Include/ntddk_ex.h new file mode 100644 index 00000000000..bf8d471dbd2 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/ntddk_ex.h @@ -0,0 +1,212 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __NTDDK_EX__H__ +#define __NTDDK_EX__H__ + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, +#if !defined PO_CB_SYSTEM_POWER_POLICY + SystemPowerInformation, +#else + _SystemPowerInformation, +#endif + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation +} SYSTEM_INFORMATION_CLASS; + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL +); + +typedef struct _SYSTEM_MODULE_ENTRY +{ + ULONG Unused; + ULONG Always0; + PVOID ModuleBaseAddress; + ULONG ModuleSize; + ULONG Unknown; + ULONG ModuleEntryIndex; + USHORT ModuleNameLength; + USHORT ModuleNameOffset; + CHAR ModuleName [256]; +} SYSTEM_MODULE_ENTRY, * PSYSTEM_MODULE_ENTRY; + +typedef struct _SYSTEM_MODULE_INFORMATION +{ + ULONG Count; + SYSTEM_MODULE_ENTRY Module [1]; +} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; + +typedef unsigned short WORD; +typedef unsigned int BOOL; +typedef unsigned long DWORD; +typedef unsigned char BYTE; + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + LONG e_lfanew; // File address of new exe header +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + // + // NT additional fields. + // + + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; // RVA from base of image + DWORD AddressOfNames; // RVA from base of image + DWORD AddressOfNameOrdinals; // RVA from base of image +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif //__NTDDK_EX__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/ntddscsi.h b/reactos/drivers/filesystems/udfs/Include/ntddscsi.h new file mode 100644 index 00000000000..6ec175ae80c --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/ntddscsi.h @@ -0,0 +1,235 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1990-1993 Microsoft Corporation + +Module Name: + + ntddscsi.h + +Abstract: + + This is the include file that defines all constants and types for + accessing the SCSI port adapters. + +Author: + + Jeff Havens + +Revision History: + +--*/ + +#ifndef _NTDDSCSIH_ +#define _NTDDSCSIH_ + +#pragma pack(push, 8) + +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// + +#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER + +#define DD_SCSI_DEVICE_NAME "\\Device\\ScsiPort" + + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Define the SCSI pass through structure. +// + +typedef struct _SCSI_PASS_THROUGH { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + +// +// Define the SCSI pass through direct structure. +// + +typedef struct _SCSI_PASS_THROUGH_DIRECT { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + +// +// Define SCSI information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_BUS_DATA { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +}SCSI_BUS_DATA, *PSCSI_BUS_DATA; + +// +// Define SCSI adapter bus information structure.. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_ADAPTER_BUS_INFO { + UCHAR NumberOfBuses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + +// +// Define SCSI adapter bus information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_INQUIRY_DATA { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +}SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + +// +// Define header for I/O control SRB. +// + +typedef struct _SRB_IO_CONTROL { + ULONG HeaderLength; + UCHAR Signature[8]; + ULONG Timeout; + ULONG ControlCode; + ULONG ReturnCode; + ULONG Length; +} SRB_IO_CONTROL, *PSRB_IO_CONTROL; + +// +// SCSI port driver capabilities structure. +// + +typedef struct _IO_SCSI_CAPABILITIES { + + // + // Length of this structure + // + + ULONG Length; + + // + // Maximum transfer size in single SRB + // + + ULONG MaximumTransferLength; + + // + // Maximum number of physical pages per data buffer + // + + ULONG MaximumPhysicalPages; + + // + // Async calls from port to class + // + + ULONG SupportedAsynchronousEvents; + + // + // Alignment mask for data transfers. + // + + ULONG AlignmentMask; + + // + // Supports tagged queuing + // + + BOOLEAN TaggedQueuing; + + // + // Host adapter scans down for bios devices. + // + + BOOLEAN AdapterScansDown; + + // + // The host adapter uses programmed I/O. + // + + BOOLEAN AdapterUsesPio; + +} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES; + +typedef struct _SCSI_ADDRESS { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +}SCSI_ADDRESS, *PSCSI_ADDRESS; + +// +// Define structure for returning crash dump pointers. +// + +struct _ADAPTER_OBJECT; + +typedef struct _DUMP_POINTERS { + struct _ADAPTER_OBJECT *AdapterObject; + PVOID MappedRegisterBase; + PVOID PortConfiguration; + PVOID CommonBufferVa; + LARGE_INTEGER CommonBufferPa; + ULONG CommonBufferSize; +} DUMP_POINTERS, *PDUMP_POINTERS; + +// +// Define values for pass-through DataIn field. +// + +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +#pragma pack(pop) + +#endif + diff --git a/reactos/drivers/filesystems/udfs/Include/phys_lib.cpp b/reactos/drivers/filesystems/udfs/Include/phys_lib.cpp new file mode 100644 index 00000000000..ef37b451dc7 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/phys_lib.cpp @@ -0,0 +1,4380 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module Name: Phys_lib.cpp + + Execution: Kernel mode only + + Description: + + Contains code that implement read/write operations for physical device +*/ + +#include "phys_lib.h" + +static const char Signature [16] = {CDRW_SIGNATURE_v1}; + +// Local functions: + +OSSTATUS +UDFSetSpeeds( + IN PVCB Vcb + ); + +NTSTATUS +UDFSetCaching( + IN PVCB Vcb + ); + +OSSTATUS +UDFRecoverFromError( + IN PVCB Vcb, + IN BOOLEAN WriteOp, + IN OSSTATUS status, + IN uint32 Lba, + IN uint32 BCount, + IN OUT uint32* retry); + +#ifdef _BROWSE_UDF_ + +uint32 +UDFFixFPAddress( + IN PVCB Vcb, // Volume control block from this DevObj + IN uint32 Lba + ); + +#endif //_BROWSE_UDF_ + +NTSTATUS +UDFSyncCache( + IN PVCB Vcb + ) +{ + KdPrint(("UDFSyncCache:\n")); + OSSTATUS RC; + RC = UDFPhSendIOCTL( IOCTL_CDRW_SYNC_CACHE, Vcb->TargetDeviceObject, + NULL,0, NULL,0, FALSE, NULL); + if(OS_SUCCESS(RC)) { + // clear LAST_WRITE flag + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + } + return RC; +} // end UDFSyncCache() + + +OSSTATUS +UDFReallocTrackMap( + IN PVCB Vcb, + IN uint32 TrackNum + ) +{ +#ifdef _BROWSE_UDF_ + if(Vcb->TrackMap) { + MyFreePool__(Vcb->TrackMap); + Vcb->TrackMap = NULL; + } + Vcb->TrackMap = (PUDFTrackMap) + MyAllocatePool__(NonPagedPool, TrackNum*sizeof(UDFTrackMap)); + if(!Vcb->TrackMap) { + return STATUS_INSUFFICIENT_RESOURCES; + } +#endif //_BROWSE_UDF_ + RtlZeroMemory(Vcb->TrackMap,TrackNum*sizeof(UDFTrackMap)); + return STATUS_SUCCESS; +} // end UDFReallocTrackMap() + +#ifdef _BROWSE_UDF_ + + +OSSTATUS +__fastcall +UDFTIOVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* IOBytes, + IN uint32 Flags + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + uint32 i, j; + uint32 mask; + uint32 lba0, len, lba1; + PUCHAR tmp_buff; + PUCHAR p; + PCHAR cached_block; + uint32 tmp_wb; + BOOLEAN need_remap; + OSSTATUS final_RC = STATUS_SUCCESS; + BOOLEAN zero; + BOOLEAN non_zero; + BOOLEAN packet_ok; + BOOLEAN free_tmp = FALSE; + BOOLEAN single_packet = FALSE; + +#define Vcb ((PVCB)_Vcb) + // ATTENTION! Do not touch bad block bitmap here, since it describes PHYSICAL addresses WITHOUT remapping, + // while here we work with LOGICAL addresses + + if(Vcb->VerifyCtx.ItemCount > UDF_MAX_VERIFY_CACHE) { + UDFVVerify(Vcb, 0/*UFD_VERIFY_FLAG_WAIT*/); + } + + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + Flags |= PH_IO_LOCKED; + + tmp_wb = (uint32)_Vcb; + if(Flags & PH_EX_WRITE) { + KdPrint(("IO-Write-Verify\n")); + RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_VCB_IN_RETLEN); + } else { + KdPrint(("IO-Read-Verify\n")); + RC = UDFTRead(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_VCB_IN_RETLEN); + } + (*IOBytes) = tmp_wb; + + switch(RC) { + default: + UDFReleaseResource(&(Vcb->IoResource)); + return RC; + case STATUS_FT_WRITE_RECOVERY: + case STATUS_DEVICE_DATA_ERROR: + case STATUS_IO_DEVICE_ERROR: + break; + /* FALL THROUGH */ + } // end switch(RC) + + if(!Vcb->SparingCount || + !Vcb->SparingCountFree || + Vcb->CDR_Mode) { + KdPrint(("Can't remap\n")); + UDFReleaseResource(&(Vcb->IoResource)); + return RC; + } + + if(Flags & PH_EX_WRITE) { + KdPrint(("Write failed, try relocation\n")); + } else { + if(Vcb->Modified) { + KdPrint(("Read failed, try relocation\n")); + } else { + KdPrint(("no remap on not modified volume\n")); + UDFReleaseResource(&(Vcb->IoResource)); + return RC; + } + } + if(Flags & PH_LOCK_CACHE) { + UDFReleaseResource(&(Vcb->IoResource)); + WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE); + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + } + + Flags &= ~PH_KEEP_VERIFY_CACHE; + + // NOTE: SparingBlockSize may be not equal to PacketSize + // perform recovery + mask = Vcb->SparingBlockSize-1; + lba0 = LBA & ~mask; + len = ((LBA+(Length>>Vcb->BlockSizeBits)+mask) & ~mask) - lba0; + j=0; + if((lba0 == LBA) && (len == mask+1) && (len == (Length>>Vcb->BlockSizeBits))) { + single_packet = TRUE; + tmp_buff = NULL; + } else { + tmp_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Vcb->SparingBlockSize << Vcb->BlockSizeBits, 'bNWD'); + if(!tmp_buff) { + KdPrint((" can't alloc tmp\n")); + UDFReleaseResource(&(Vcb->IoResource)); + return STATUS_DEVICE_DATA_ERROR; + } + free_tmp = TRUE; + } + + for(i=0; iSparingCountFree) { + KdPrint((" no more free spare blocks, abort verification\n")); + break; + } + KdPrint((" read LBA %x (%x)\n", lba0+i, j)); + if(!j) { + need_remap = FALSE; + lba1 = lba0+i; + non_zero = FALSE; + if(single_packet) { + // single packet requested + tmp_buff = (PUCHAR)Buffer; + if(Flags & PH_EX_WRITE) { + KdPrint((" remap single write\n")); + KdPrint((" try del from verify cache @ %x, %x\n", lba0, len)); + UDFVForget(Vcb, len, UDFRelocateSector(Vcb, lba0), 0); + goto do_remap; + } else { + KdPrint((" recover and remap single read\n")); + } + } + } + p = tmp_buff+(j<BlockSizeBits); + // not cached, try to read + // prepare for error, if block cannot be read, assume it is zero-filled + RtlZeroMemory(p, Vcb->BlockSize); + + // check if block valid + if(Vcb->BSBM_Bitmap) { + if(UDFGetBit__((uint32*)(Vcb->BSBM_Bitmap), UDFRelocateSector(Vcb, lba0+i))) { + KdPrint((" remap: known BB @ %x, mapped to %x\n", lba0+i, UDFRelocateSector(Vcb, lba0+i))); + need_remap = TRUE; + } + } + zero = FALSE; + if(Vcb->FSBM_Bitmap) { + if(UDFGetFreeBit((uint32*)(Vcb->FSBM_Bitmap), lba0+i)) { + KdPrint((" unused @ %x\n", lba0+i)); + zero = TRUE; + } + } + if(!zero && Vcb->ZSBM_Bitmap) { + if(UDFGetZeroBit((uint32*)(Vcb->ZSBM_Bitmap), lba0+i)) { + KdPrint((" unused @ %x (Z)\n", lba0+i)); + zero = TRUE; + } + } + non_zero |= !zero; + + if(!j) { + packet_ok = FALSE; + if(!single_packet) { + // try to read entire packet, this returs error more often then sequential reading of all blocks one by one + tmp_wb = (uint32)_Vcb; + RC = UDFTRead(_Vcb, p, Vcb->SparingBlockSize << Vcb->BlockSizeBits, lba0+i, &tmp_wb, + Flags | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN); + } else { + // Note: we get here ONLY if original request failed + // do not retry if it was single-packet request + RC = STATUS_UNSUCCESSFUL; + } + if(RC == STATUS_SUCCESS) { + KdPrint((" packet ok @ %x\n", lba0+i)); + packet_ok = TRUE; + i += Vcb->SparingBlockSize-1; + continue; + } else { + need_remap = TRUE; + } + } + + if(!zero) { + if(WCacheIsCached__(&(Vcb->FastCache), lba0+i, 1)) { + // even if block is cached, we have to verify if it is readable + if(!packet_ok && !UDFVIsStored(Vcb, lba0+i)) { + + tmp_wb = (uint32)_Vcb; + RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb, + Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN); + if(!OS_SUCCESS(RC)) { + KdPrint((" Found BB @ %x\n", lba0+i)); + } + + } + RC = WCacheDirect__(&(Vcb->FastCache), _Vcb, lba0+i, FALSE, &cached_block, TRUE/* cached only */); + } else { + cached_block = NULL; + if(!packet_ok) { + RC = STATUS_UNSUCCESSFUL; + } else { + RC = STATUS_SUCCESS; + } + } + if(OS_SUCCESS(RC)) { + // cached or successfully read + if(cached_block) { + // we can get from cache the most fresh data + RtlCopyMemory(p, cached_block, Vcb->BlockSize); + } + + } else { + if(!UDFVIsStored(Vcb, lba0+i)) { + tmp_wb = (uint32)_Vcb; + RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb, + Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN); + } else { + // get it from verify-cache + RC = STATUS_UNSUCCESSFUL; + } + if(!OS_SUCCESS(RC)) { +/* + KdPrint((" retry @ %x\n", lba0+i)); + tmp_wb = (uint32)_Vcb; + RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb, + Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN); +*/ + KdPrint((" try get from verify cache @ %x\n", lba0+i)); + RC = UDFVRead(Vcb, p, 1, UDFRelocateSector(Vcb, lba0+i), + Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER); + need_remap = TRUE; + } + } + } else { + RtlZeroMemory(p, Vcb->BlockSize); + } + if(!packet_ok) { + KdPrint((" try del from verify cache @ %x\n", lba0+i)); + RC = UDFVForget(Vcb, 1, UDFRelocateSector(Vcb, lba0+i), 0); + } + + if(!packet_ok || need_remap) { + KdPrint((" block in bad packet @ %x\n", lba0+i)); + if(Vcb->BSBM_Bitmap) { + UDFSetBit(Vcb->BSBM_Bitmap, lba0+i); + } + if(Vcb->FSBM_Bitmap) { + UDFSetUsedBit(Vcb->FSBM_Bitmap, lba0+i); + } + } + + j++; + if(j >= Vcb->SparingBlockSize) { + // remap this packet + if(need_remap) { + ASSERT(!packet_ok); + if(!non_zero) { + KdPrint((" forget Z packet @ %x\n", lba1)); + UDFUnmapRange(Vcb, lba1, Vcb->SparingBlockSize); + RC = STATUS_SUCCESS; + } else { +do_remap: + for(j=0; j<3; j++) { + KdPrint((" remap packet @ %x\n", lba1)); + RC = UDFRemapPacket(Vcb, lba1, FALSE); + if(!OS_SUCCESS(RC)) { + if(RC == STATUS_SHARING_VIOLATION) { + KdPrint((" remap2\n")); + // remapped location have died + RC = UDFRemapPacket(Vcb, lba1, TRUE); + } + if(!OS_SUCCESS(RC)) { + // packet cannot be remapped :( + RC = STATUS_DEVICE_DATA_ERROR; + } + } + KdPrint((" remap status %x\n", RC)); + if(OS_SUCCESS(RC)) { + // write to remapped area + tmp_wb = (uint32)_Vcb; + RC = UDFTWrite(_Vcb, tmp_buff, Vcb->SparingBlockSize << Vcb->BlockSizeBits, lba1, &tmp_wb, + Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN); + KdPrint((" write status %x\n", RC)); + if(RC != STATUS_SUCCESS) { + // will be remapped + KdPrint((" retry remap\n")); + + // Note: when remap of already remapped block is requested, verify of + // entire sparing are will be performed. + + } else { + KdPrint((" remap OK\n")); + break; + } + } else { + KdPrint((" failed remap\n")); + break; + } + } // for + } + if(!OS_SUCCESS(RC) && !OS_SUCCESS(final_RC)) { + final_RC = RC; + } + } else { + KdPrint((" NO remap for @ %x\n", (lba0+i) & ~mask)); + } + j=0; + } + } + if(free_tmp) { + DbgFreePool(tmp_buff); + } + + tmp_wb = (uint32)_Vcb; + if(Flags & PH_EX_WRITE) { + KdPrint(("IO-Write-Verify (2)\n")); + //RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN); + } else { + KdPrint(("IO-Read-Verify (2)\n")); + RC = UDFTRead(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN); + } + (*IOBytes) = tmp_wb; + KdPrint(("Final %x\n", RC)); + + UDFReleaseResource(&(Vcb->IoResource)); + if(Flags & PH_LOCK_CACHE) { + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } + + return RC; +} // end UDFTIOVerify() + +OSSTATUS +UDFTWriteVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* WrittenBytes, + IN uint32 Flags + ) +{ + return UDFTIOVerify(_Vcb, Buffer, Length, LBA, WrittenBytes, Flags | PH_VCB_IN_RETLEN | PH_EX_WRITE | PH_KEEP_VERIFY_CACHE); +} // end UDFTWriteVerify() + +OSSTATUS +UDFTReadVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* ReadBytes, + IN uint32 Flags + ) +{ + return UDFTIOVerify(_Vcb, Buffer, Length, LBA, ReadBytes, Flags | PH_VCB_IN_RETLEN | PH_KEEP_VERIFY_CACHE); +} // end UDFTReadVerify() +#endif //_BROWSE_UDF_ + +/* + This routine performs low-level write + + ATTENTION! When we are in Variable-Packet mode (CDR_Mode = TRUE) + LBA is ignored and assumed to be equal to NWA by CD-R(W) driver + */ +OSSTATUS +UDFTWrite( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* WrittenBytes, + IN uint32 Flags + ) +{ +#ifndef UDF_READ_ONLY_BUILD +#define Vcb ((PVCB)_Vcb) + +#ifdef _BROWSE_UDF_ + PEXTENT_MAP RelocExtent; + PEXTENT_MAP RelocExtent_saved = NULL; +#endif //_BROWSE_UDF_ + uint32 retry; + BOOLEAN res_acq = FALSE; + + OSSTATUS RC = STATUS_SUCCESS; + uint32 rLba; + uint32 BCount; + uint32 i; + +#ifdef DBG + //ASSERT(!(LBA & (32-1))); +#endif //DBG + + (*WrittenBytes) = 0; + BCount = Length>>Vcb->BlockSizeBits; + + KdPrint(("TWrite %x (%x)\n", LBA, BCount)); +#ifdef _BROWSE_UDF_ + if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) { + KdPrint(("DEAD\n")); + return STATUS_NO_SUCH_DEVICE; + } + + Vcb->VCBFlags |= (UDF_VCB_SKIP_EJECT_CHECK | UDF_VCB_LAST_WRITE); + if(!Vcb->CDR_Mode) { + RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount); + if(!RelocExtent) { + KdPrint(("can't relocate\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + rLba = LBA; + } else { + RelocExtent = UDF_NO_EXTENT_MAP; + rLba = Vcb->NWA; + } +#else //_BROWSE_UDF_ + rLba = LBA; +#endif //_BROWSE_UDF_ + +#ifdef DBG + //ASSERT(!(rLba & (32-1))); +#endif //DBG + + _SEH2_TRY { +#ifdef _BROWSE_UDF_ + + if(!(Flags & PH_IO_LOCKED)) { + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + res_acq = TRUE; + } + + if(RelocExtent == UDF_NO_EXTENT_MAP) { +#endif //_BROWSE_UDF_ + retry = UDF_WRITE_MAX_RETRY; +retry_1: + RC = UDFPrepareForWriteOperation(Vcb, rLba, BCount); + if(!OS_SUCCESS(RC)) { + KdPrint(("prepare failed\n")); + try_return(RC); + } + if(Flags & PH_VCB_IN_RETLEN) { + (*WrittenBytes) = (ULONG)Vcb; + } + RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Buffer, Length, + ((uint64)rLba) << Vcb->BlockSizeBits, WrittenBytes, Flags); +#ifdef _BROWSE_UDF_ + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; +#endif //_BROWSE_UDF_ + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, rLba, BCount, &retry)) ) + goto retry_1; + UDFUpdateNWA((PVCB)_Vcb, rLba, BCount, RC); + try_return(RC); +#ifdef _BROWSE_UDF_ + } + // write according to relocation table + RelocExtent_saved = RelocExtent; + for(i=0; RelocExtent->extLength; i++, RelocExtent++) { + uint32 _WrittenBytes; + rLba = RelocExtent->extLocation; + BCount = RelocExtent->extLength>>Vcb->BlockSizeBits; + retry = UDF_WRITE_MAX_RETRY; +retry_2: + RC = UDFPrepareForWriteOperation(Vcb, rLba, BCount); + if(!OS_SUCCESS(RC)) { + KdPrint(("prepare failed (2)\n")); + break; + } + if(Flags & PH_VCB_IN_RETLEN) { + _WrittenBytes = (ULONG)Vcb; + } + RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength, + ((uint64)rLba) << Vcb->BlockSizeBits, &_WrittenBytes, Flags); + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, rLba, BCount, &retry)) ) + goto retry_2; + UDFUpdateNWA((PVCB)_Vcb, rLba, BCount, RC); + LBA += BCount; + (*WrittenBytes) += _WrittenBytes; + if(!OS_SUCCESS(RC)) break; + *((uint32*)&Buffer) += RelocExtent->extLength; + } +#endif //_BROWSE_UDF_ +try_exit: NOTHING; + } _SEH2_FINALLY { + if(res_acq) { + UDFReleaseResource(&(Vcb->IoResource)); + } +#ifdef _BROWSE_UDF_ + if(RelocExtent_saved) { + MyFreePool__(RelocExtent_saved); + } +#endif //_BROWSE_UDF_ + } _SEH2_END; + KdPrint(("TWrite: %x\n", RC)); + return RC; + +#undef Vcb +#else //UDF_READ_ONLY_BUILD + return STATUS_ACCESS_DENIED; +#endif //UDF_READ_ONLY_BUILD +} // end UDFTWrite() + +/* + This routine performs low-level read + */ +OSSTATUS +UDFTRead( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* ReadBytes, + IN uint32 Flags + ) +{ + uint32 rLba; + OSSTATUS RC = STATUS_SUCCESS; + uint32 retry; + PVCB Vcb = (PVCB)_Vcb; + uint32 BCount = Length >> Vcb->BlockSizeBits; + uint32 i; +#ifdef _BROWSE_UDF_ + PEXTENT_MAP RelocExtent; + PEXTENT_MAP RelocExtent_saved = NULL; + BOOLEAN res_acq = FALSE; +// LARGE_INTEGER delay; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + ASSERT(Buffer); + + (*ReadBytes) = 0; + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) + return STATUS_NO_SUCH_DEVICE; + + RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount); + if(!RelocExtent) return STATUS_INSUFFICIENT_RESOURCES; + + _SEH2_TRY { + + if(!(Flags & PH_IO_LOCKED)) { + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + res_acq = TRUE; + } + + if(RelocExtent == UDF_NO_EXTENT_MAP) { + rLba = LBA; + if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) { + RtlZeroMemory(Buffer, Length); + try_return(RC = STATUS_SUCCESS); + } + retry = UDF_WRITE_MAX_RETRY; +retry_1: + RC = UDFPrepareForReadOperation(Vcb, rLba, Length >> Vcb->BlockSizeBits); + if(!OS_SUCCESS(RC)) try_return(RC); + rLba = UDFFixFPAddress(Vcb, rLba); +#else + rLba = LBA; + retry = UDF_WRITE_MAX_RETRY; +retry_1: + RC = UDFPrepareForReadOperation(Vcb, rLba, Length >> Vcb->BlockSizeBits); + if(!OS_SUCCESS(RC)) return RC; // this is for !_BROWSE_UDF only +#endif //_BROWSE_UDF_ + if(Flags & PH_VCB_IN_RETLEN) { + (*ReadBytes) = (ULONG)Vcb; + } + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Length, + ((uint64)rLba) << Vcb->BlockSizeBits, ReadBytes, Flags); + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; +#ifdef _BROWSE_UDF_ + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; +#endif //_BROWSE_UDF_ + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) { + if(RC != STATUS_BUFFER_ALL_ZEROS) { + goto retry_1; + } + RtlZeroMemory(Buffer, Length); + (*ReadBytes) = Length; + RC = STATUS_SUCCESS; + } +#ifdef _BROWSE_UDF_ + try_return(RC); + } + // read according to relocation table + RelocExtent_saved = RelocExtent; + for(i=0; RelocExtent->extLength; i++, RelocExtent++) { + uint32 _ReadBytes; + rLba = RelocExtent->extLocation; + if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) { + RtlZeroMemory(Buffer, _ReadBytes = RelocExtent->extLength); + RC = STATUS_SUCCESS; + goto TR_continue; + } + BCount = RelocExtent->extLength>>Vcb->BlockSizeBits; + retry = UDF_WRITE_MAX_RETRY; +retry_2: + RC = UDFPrepareForReadOperation(Vcb, rLba, RelocExtent->extLength >> Vcb->BlockSizeBits); + if(!OS_SUCCESS(RC)) break; + rLba = UDFFixFPAddress(Vcb, rLba); + if(Flags & PH_VCB_IN_RETLEN) { + _ReadBytes = (ULONG)Vcb; + } + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength, + ((uint64)rLba) << Vcb->BlockSizeBits, &_ReadBytes, Flags); + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) { + if(RC != STATUS_BUFFER_ALL_ZEROS) { + goto retry_2; + } + RtlZeroMemory(Buffer, RelocExtent->extLength); + _ReadBytes = RelocExtent->extLength; + RC = STATUS_SUCCESS; + } +TR_continue: + (*ReadBytes) += _ReadBytes; + if(!OS_SUCCESS(RC)) break; + *((uint32*)&Buffer) += RelocExtent->extLength; + } +try_exit: NOTHING; + } _SEH2_FINALLY { + if(res_acq) { + UDFReleaseResource(&(Vcb->IoResource)); + } + if(RelocExtent_saved) { + MyFreePool__(RelocExtent_saved); + } + } _SEH2_END; +#endif //_BROWSE_UDF_ + return RC; +} // end UDFTRead() + +#ifdef UDF_ASYNC_IO +/* + This routine performs asynchronous low-level read + Is not used now. + */ +OSSTATUS +UDFTReadAsync( + IN void* _Vcb, + IN void* _WContext, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* ReadBytes + ) +{ + PEXTENT_MAP RelocExtent; + PEXTENT_MAP RelocExtent_saved; + OSSTATUS RC = STATUS_SUCCESS; +// LARGE_INTEGER delay; + uint32 retry = UDF_READ_MAX_RETRY; + PVCB Vcb = (PVCB)_Vcb; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + uint32 rLba; + uint32 BCount; + + ASSERT(Buffer); + + (*ReadBytes) = 0; + + RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount = Length >> Vcb->BlockSizeBits); + if(!RelocExtent) return STATUS_INSUFFICIENT_RESOURCES; + if(RelocExtent == UDF_NO_EXTENT_MAP) { + rLba = LBA; + if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) { + RtlZeroMemory(Buffer, Length); + return STATUS_SUCCESS; + } +retry_1: + RC = UDFPrepareForReadOperation(Vcb, rLba, BCount); + if(!OS_SUCCESS(RC)) return RC; + rLba = UDFFixFPAddress(Vcb, rLba); + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Length, + ((uint64)rLba) << Vcb->BlockSizeBits, ReadBytes, 0); + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) + goto retry_1; + return RC; + } + // read according to relocation table + RelocExtent_saved = RelocExtent; + for(uint32 i=0; RelocExtent->extLength; i++, RelocExtent++) { + uint32 _ReadBytes; + rLba = RelocExtent->extLocation; + if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) { + RtlZeroMemory(Buffer, _ReadBytes = RelocExtent->extLength); + RC = STATUS_SUCCESS; + goto TR_continue; + } + BCount = RelocExtent->extLength>>Vcb->BlockSizeBits; +retry_2: + RC = UDFPrepareForReadOperation(Vcb, rLba, RelocExtent->extLength >> Vcb->BlockSizeBits); + if(!OS_SUCCESS(RC)) break; + rLba = UDFFixFPAddress(Vcb, rLba); + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength, + ((uint64)rLba) << Vcb->BlockSizeBits, &_ReadBytes, 0); + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) + goto retry_2; +TR_continue: + (*ReadBytes) += _ReadBytes; + if(!OS_SUCCESS(RC)) break; + *((uint32*)&Buffer) += RelocExtent->extLength; + } + MyFreePool__(RelocExtent_saved); + return RC; +} // end UDFTReadAsync() + +#endif //UDF_ASYNC_IO + +/* + + */ +NTSTATUS +UDFSetMRWMode( + IN PVCB Vcb + ) +{ + GET_MRW_MODE_USER_OUT MRWPage; + OSSTATUS RC; + + if(Vcb->MediaClassEx != CdMediaClass_CDRW) + return STATUS_SUCCESS; +//#ifdef _BROWSE_UDF_ + if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM) + return STATUS_SUCCESS; +//#endif //_BROWSE_UDF_ + + if(!Vcb->MRWStatus) { + KdPrint(("Non-MRW disk. Skip setting MRW_MODE\n")); + return STATUS_SUCCESS; + } + KdPrint(("try set MRW_MODE\n")); + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MRW_MODE, Vcb->TargetDeviceObject, + NULL,0, + (PVOID)&MRWPage,sizeof(MRWPage), + FALSE, NULL); + if(!NT_SUCCESS(RC)) { + return RC; + } + KdPrint(("GET_MRW_MODE ok (current %x)\n", MRWPage.AddressMode)); + MRWPage.AddressMode = Vcb->MRWStatus ? 0 : MrwPage_use_GAA; + KdPrint(("SET_MRW_MODE %x\n", MRWPage.AddressMode)); + RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_MRW_MODE, Vcb->TargetDeviceObject, + (PVOID)&MRWPage,sizeof(MRWPage), + NULL,0, + FALSE, NULL); + KdPrint(("SET_MRW_MODE status %x\n", RC)); + + return STATUS_SUCCESS; +} // end UDFSetMRWMode() + +OSSTATUS +UDFDoOPC( + IN PVCB Vcb + ) +{ + OSSTATUS RC; + if(Vcb->OPCNum && !Vcb->OPCDone) { + KdPrint(("UDFDoOPC\n")); + if(!Vcb->OPCh) { + Vcb->OPCh = + (PSEND_OPC_INFO_HEADER_USER_IN)MyAllocatePool__(NonPagedPool, + sizeof(SEND_OPC_INFO_HEADER_USER_IN) ); + } + if(!Vcb->OPCh) + return STATUS_INSUFFICIENT_RESOURCES; + Vcb->OPCh->DoOpc = TRUE; + Vcb->OPCh->OpcBlocksNumber = 0; + RC = UDFPhSendIOCTL(IOCTL_CDRW_SEND_OPC_INFO, Vcb->TargetDeviceObject, + (void*)(Vcb->OPCh),sizeof(SEND_OPC_INFO_HEADER_USER_IN), + NULL,0, + FALSE, NULL); + if(!OS_SUCCESS(RC)) { + KdPrint(("UDFDoOPC failed\n")); + Vcb->OPCNum = 0; +// Vcb->VCBFlags |= UDF_VCB_FLAGS_OPC_FAILED; + } + Vcb->OPCDone = TRUE; + } + return RC; +} // end UDFDoOPC() + +/* + This routine performs media-type dependent preparations + for write operation. + + For CDR/RW it sets WriteParameters according to track parameters, + in some cases issues SYNC_CACHE command. + It can also send OPC info if requered. + If write-requested block is located beyond last formatted LBA + on incompletely formatted DVD media, this routine performs + all neccessary formatting operations in order to satisfy + subsequent write request. + */ +OSSTATUS +UDFPrepareForWriteOperation( + IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BCount + ) +{ +#ifndef UDF_READ_ONLY_BUILD +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; +#else + #define fms FALSE +#endif //UDF_FORMAT_MEDIA + +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BSBM_Bitmap) { + ULONG i; + for(i=0; iBSBM_Bitmap), Lba+i)) { + KdPrint(("W: Known BB @ %#x\n", Lba)); + //return STATUS_FT_WRITE_RECOVERY; // this shall not be treated as error and + // we shall get IO request to BAD block + return STATUS_DEVICE_DATA_ERROR; + } + } + } +#endif //_UDF_STRUCTURES_H_ + + Vcb->VCBFlags |= UDF_VCB_LAST_WRITE; + + if( +#ifdef _BROWSE_UDF_ + (((Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) || + !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) || + (Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + && !fms + ) || +#endif //_BROWSE_UDF_ +#ifdef UDF_FORMAT_MEDIA + (fms && fms->SkipPrepareW) || +#endif //UDF_FORMAT_MEDIA + !(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) + ) { + KdPrint(("Skip prepare for Write @%x\n", Lba)); + return STATUS_SUCCESS; + } + + // check if the device requires OPC before each write operation + UDFDoOPC(Vcb); + + if(Vcb->SyncCacheState == SYNC_CACHE_RECOVERY_ATTEMPT) { + Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_RETRY; + } else { + Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_NONE; + } + if(Vcb->LastModifiedTrack && + (Vcb->TrackMap[Vcb->LastModifiedTrack].FirstLba <= Lba) && + (Vcb->TrackMap[Vcb->LastModifiedTrack].LastLba >= Lba) && + !( (Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDpRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM || + Vcb->MRWStatus == DiscInfo_BGF_Interrupted || + Vcb->MRWStatus == DiscInfo_BGF_InProgress) && (Lba > Vcb->LastLBA)) + ) { + // Ok, we needn't change Write Parameters +// if(Vcb->TrackMap[Vcb->LastModifiedTrack].Flags & TrackMap_Try_variation) +// Vcb->TrackMap[Vcb->LastModifiedTrack].Flags |= TrackMap_Use_variation; + KdPrint(("Skip prepare for Write (2) @%x\n", Lba)); + return STATUS_SUCCESS; + } + + UDFSetMRWMode(Vcb); + + if(!UDFIsWriteParamsReq(Vcb)) { +#ifdef UDF_FORMAT_MEDIA + if(fms) { + return STATUS_SUCCESS; + } +#endif //UDF_FORMAT_MEDIA + } + + for(uint32 i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) { + if((Vcb->TrackMap[i].FirstLba > Lba) || + (Vcb->TrackMap[i].LastLba < Lba)) { + //KdPrint(("not in track %d\n")); + continue; + } + OSSTATUS RC; + PGET_WRITE_MODE_USER_OUT WParams; + + if(!UDFIsWriteParamsReq(Vcb)) { + RC = STATUS_SUCCESS; + goto check_dvd_bg_format; + } + + if(!Vcb->WParams) { + Vcb->WParams = + (PGET_WRITE_MODE_USER_OUT)MyAllocatePool__(NonPagedPool, 512); + } + if(!(WParams = Vcb->WParams)) { + KdPrint(("!WParams\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_WRITE_MODE, Vcb->TargetDeviceObject, + NULL,0, + (void*)(Vcb->WParams),sizeof(GET_WRITE_MODE_USER_OUT), + FALSE, NULL); + if(!OS_SUCCESS(RC)) { +#ifdef UDF_FORMAT_MEDIA + if(fms) { + fms->SkipPrepareW = 1; + MyFreePool__(WParams); + return STATUS_SUCCESS; + } +#endif //UDF_FORMAT_MEDIA + KdPrint(("!get WParams\n")); + return RC; + } + // clear unnecassary flags + WParams->Byte2.Flags &= ~WParam_TestWrite; + WParams->Byte2.Flags &= ~WParam_WType_Mask; + // select packet writing + WParams->Byte2.Flags |= WParam_WType_Packet; + + WParams->Byte3.Flags &= ~(WParam_TrkMode_Mask | + WParam_TrkMode_AllowCpy | + WParam_Copy); + WParams->Byte3.Flags |= Vcb->TrackMap[i].TrackParam & + (WParam_TrkMode_Mask | + WParam_TrkMode_AllowCpy | + WParam_Copy); + + // set packet type (VP/FP) +// if(opt_partition == PT_VAT15 || +// opt_blank_vat15) + if(WParams->Byte2.Flags & WParam_LS_V) { + WParams->LinkSize = 7; + } + + if(Vcb->TrackMap[i].DataParam & TrkInfo_Packet) { + if((Vcb->TrackMap[i].DataParam & TrkInfo_FP) && + !Vcb->CDR_Mode) { + WParams->Byte3.Flags |= WParam_FP; + } else { + WParams->Byte3.Flags &= ~WParam_FP; + } + } else { + if(!Vcb->CDR_Mode) { + WParams->Byte3.Flags |= WParam_FP; + } else { + WParams->Byte3.Flags &= ~WParam_FP; + } + } + + // select multisession mode + WParams->Byte3.Flags &= ~WParam_MultiSes_Mask; + if((Vcb->DiscStat & DiscInfo_Disk_Mask) == DiscInfo_Disk_Appendable) { + WParams->Byte3.Flags |= WParam_Multises_Multi; + } else + if(Vcb->LastSession > 1) { + WParams->Byte3.Flags |= WParam_Multises_Final; + } else { + WParams->Byte3.Flags |= WParam_Multises_None; + } + // set sector mode (Mode1/XA) + WParams->Byte4.Flags &= ~WParam_BlkType_Mask; + if((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask) == TrkInfo_Dat_XA) { + // XA Mode2 + WParams->Byte4.Flags |= WParam_BlkType_M2XAF1_2048; + WParams->SesFmt = WParam_SesFmt_CdRomXa; + } else if((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask) == TrkInfo_Dat_Mode1) { + // Mode1 + WParams->Byte4.Flags |= WParam_BlkType_M1_2048; + WParams->SesFmt = WParam_SesFmt_CdRom; + } else { +#ifdef UDF_FORMAT_MEDIA + if(fms) { + fms->SkipPrepareW = 1; + MyFreePool__(WParams); + return STATUS_SUCCESS; + } +#endif //UDF_FORMAT_MEDIA + KdPrint((" inv sector mode\n")); + return STATUS_INVALID_PARAMETER; + } + // set packet size + *((uint32*)&(WParams->PacketSize)) = BCount; + *((uint32*)&(WParams->SubHeader)) = 0; + // set additional flags for VP + + if(Vcb->CDR_Mode) { +// if(opt_partition == PT_VAT15) + WParams->SubHeader.Params.Params1.SubMode = WParam_SubHdr_SubMode1; + } + WParams->PageLength = sizeof(GET_WRITE_MODE_USER_OUT)-2; + WParams->PageCode = MODE_PAGE_WRITE_PARAMS; + // apply write parameters + RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_WRITE_MODE, Vcb->TargetDeviceObject, + (void*)WParams,sizeof(SET_WRITE_MODE_USER_IN), + NULL,0,FALSE,NULL); + +#ifdef UDF_FORMAT_MEDIA + if(fms) { + if(!NT_SUCCESS(RC)) { + fms->SkipPrepareW = 1; + MyFreePool__(WParams); + return STATUS_SUCCESS; + } + + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_WRITE_MODE, Vcb->TargetDeviceObject, + NULL,0, + (PVOID)WParams,sizeof(GET_WRITE_MODE_USER_OUT), + FALSE, NULL); + if(!NT_SUCCESS(RC)) { + MyFreePool__(WParams); + return RC; + } + + if(fms->opt_partition == PT_VAT15 || + fms->opt_blank_vat15) { + if(WParams->Byte3.Flags & WParam_FP) { + MyFreePool__(WParams); + return STATUS_INVALID_DEVICE_STATE; + } + } else { + if(!(WParams->Byte3.Flags & WParam_FP)) { + MyFreePool__(WParams); + return STATUS_INVALID_DEVICE_STATE; + } + } + } +#endif //UDF_FORMAT_MEDIA + + // switch to random access mode + ((PSET_RANDOM_ACCESS_USER_IN)WParams)->RandomAccessMode = Vcb->CDR_Mode ? FALSE : TRUE; +// ((PSET_RANDOM_ACCESS_USER_IN)WParams)->RandomAccessMode = (opt_partition != PT_VAT15) ? TRUE : FALSE; + RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_RANDOM_ACCESS, Vcb->TargetDeviceObject, + (void*)WParams,sizeof(SET_RANDOM_ACCESS_USER_IN), + NULL,0,FALSE, NULL); + +check_dvd_bg_format: + + KdPrint((" check BGF\n")); + if(!Vcb->CDR_Mode) { + if(OS_SUCCESS(RC)) { + Vcb->LastModifiedTrack = i; + if(!(Vcb->TrackMap[i].Flags & TrackMap_Use_variation)) { + if(Vcb->TrackMap[i].Flags & TrackMap_Try_variation) { + Vcb->TrackMap[i].Flags |= TrackMap_Use_variation; + } else { + Vcb->TrackMap[i].Flags |= TrackMap_Try_variation; + } + } + } + } else { + Vcb->LastModifiedTrack = 0; + } +// fms->SkipPrepareW = 1; + + + if((Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDpRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM || + Vcb->MRWStatus == DiscInfo_BGF_Interrupted ) + && (Lba > Vcb->LastLBA)) { + + ULONG fLba; + ULONG WrittenBytes; + ULONG PSz = BCount << Vcb->BlockSizeBits; +#ifdef _BROWSE_UDF_ + ULONG retry; +#endif //_BROWSE_UDF_ + PFORMAT_CDRW_PARAMETERS_USER_IN ForBuf; + + ASSERT((Vcb->LastLBA+1) == Vcb->NWA); + + if(Lba+BCount <= (Vcb->LastLBA+1) ) { + KdPrint(("DVD cont. fmt, LBA+BCount<=NWA, exiting\n")); + return STATUS_SUCCESS; + } + if((Vcb->MRWStatus != DiscInfo_BGF_Interrupted) && + (Lba <= (Vcb->LastLBA+1)) ) { + KdPrint(("!PausedBGF + DVD cont. fmt, LBA<=NWA, exiting\n")); + return STATUS_SUCCESS; + } + + if(Vcb->MRWStatus == DiscInfo_BGF_Interrupted) { + // This code also can restart background MRW formatting + KdPrint(("DVD cont. fmt, LastLBA %x, Lba %x\n", Vcb->LastLBA, Lba)); + + ForBuf = (PFORMAT_CDRW_PARAMETERS_USER_IN)DbgAllocatePoolWithTag(NonPagedPool, sizeof(FORMAT_CDRW_PARAMETERS_USER_IN), 'zNWD'); + if(ForBuf) { + RtlZeroMemory(ForBuf, sizeof(FORMAT_CDRW_PARAMETERS_USER_IN)); + ForBuf->Flags.FlagsEx = FORMAT_UNIT_RESTART_MRW; + ForBuf->BlockCount = 0xffffffff; + + RC = UDFPhSendIOCTL(IOCTL_CDRW_FORMAT_UNIT, Vcb->TargetDeviceObject, + ForBuf,sizeof(FORMAT_CDRW_PARAMETERS_USER_IN), + NULL,0,FALSE, NULL); + DbgFreePool(ForBuf); + if(OS_SUCCESS(RC)) { + KdPrint(("BGFormat restarted Interrupted->InProgress\n")); + Vcb->MRWStatus = DiscInfo_BGF_InProgress; + } else { + PGET_LAST_ERROR_USER_OUT Error = NULL; + if(!Vcb->Error) { + Vcb->Error = (PGET_LAST_ERROR_USER_OUT) + MyAllocatePool__(NonPagedPool, sizeof(GET_LAST_ERROR_USER_OUT)); + } + Error = Vcb->Error; + if(Error) { + UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject, + NULL,0, + Error,sizeof(GET_LAST_ERROR_USER_OUT), + TRUE,NULL); + KdPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n", + Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError)); + // check for Long Write In Progress + if( (Error->SenseKey == SCSI_SENSE_NOT_READY) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && + ((Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS) || + (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) ) { + RC = STATUS_SUCCESS; + KdPrint(("Seems, BGFormat already restarted\n")); + Vcb->MRWStatus = DiscInfo_BGF_InProgress; + } + } + } + } + } else { + RC = STATUS_SUCCESS; + } + + KdPrint(("DVD cont. write, LastLBA %x, Lba %x\n", Vcb->LastLBA, Lba)); + + ASSERT(Vcb->MediaClassEx == CdMediaClass_DVDRW); + if(!Vcb->fZBuffer) { + Vcb->fZBuffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, PSz, 'zNWD'); + RtlZeroMemory(Vcb->fZBuffer, PSz); + Vcb->fZBufferSize = PSz; + } else + if(Vcb->fZBufferSize < PSz) { + PSz = Vcb->fZBufferSize; + } + if(!Vcb->fZBuffer) { + BrutePoint(); + RC = STATUS_INSUFFICIENT_RESOURCES; + } else { + for(fLba = Vcb->NWA; fLba < Lba; fLba+=BCount) { +#ifdef _BROWSE_UDF_ + retry = UDF_WRITE_MAX_RETRY; +retry_1: +#endif //_BROWSE_UDF_ + RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Vcb->fZBuffer, PSz, + ((uint64)fLba) << Vcb->BlockSizeBits, &WrittenBytes, PH_TMP_BUFFER); + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + KdPrint(("Fmt status: %x\n", RC)); +#ifdef _BROWSE_UDF_ + if(!OS_SUCCESS(RC) && + OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, fLba, BCount, &retry)) ) { + goto retry_1; + KdPrint(("Fmt retry\n")); + } +#endif //_BROWSE_UDF_ + if(!OS_SUCCESS(RC)) { + BrutePoint(); + KdPrint(("Fmt break on ERROR\n")); + break; + } + UDFUpdateNWA(Vcb, fLba, BCount, RC); + } + } + } else { + KdPrint((" no special processing\n")); + } + + return RC; + } +#endif //UDF_READ_ONLY_BUILD + KdPrint((" no suitable track!\n")); + return STATUS_INVALID_PARAMETER; +} // end UDFPrepareForWriteOperation() + +//#ifdef _BROWSE_UDF_ +/* + This routine tries to recover from hardware error + Return: STATUS_SUCCESS - retry requst + STATUS_XXX - unrecoverable error + */ +OSSTATUS +UDFRecoverFromError( + IN PVCB Vcb, + IN BOOLEAN WriteOp, + IN OSSTATUS status, + IN uint32 Lba, + IN uint32 BCount, + IN OUT uint32* retry + ) +{ + PGET_LAST_ERROR_USER_OUT Error = NULL; + LARGE_INTEGER delay; + OSSTATUS RC; + uint32 i; + BOOLEAN UpdateBB = FALSE; + + if(!(*retry) || + !(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) || + (Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM)) + return status; + (*retry)--; + // allocate tmp buffer + _SEH2_TRY { + if(!Vcb->Error) { + if(!(Vcb->Error = (PGET_LAST_ERROR_USER_OUT) + MyAllocatePool__(NonPagedPool, sizeof(GET_LAST_ERROR_USER_OUT)))) + try_return(status); + } + if(status == STATUS_NO_SUCH_DEVICE) { + KdPrint(("Error recovery: STATUS_NO_SUCH_DEVICE, die.....\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL | UDF_VCB_FLAGS_DEAD; + try_return(status); + } + +#ifdef _UDF_STRUCTURES_H_ + if(status == STATUS_NO_MEDIA_IN_DEVICE && !Vcb->EjectWaiter) { + KdPrint(("Error recovery: STATUS_NO_MEDIA_IN_DEVICE, prevent further remount.....\n")); + // Make sure, that volume will never be quick-remounted + // It is very important for ChkUdf utility and + // some CD-recording libraries + Vcb->SerialNumber--; + try_return(status); + } +#endif //_UDF_STRUCTURES_H_ + + Error = Vcb->Error; + UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject, + NULL,0, + Error,sizeof(GET_LAST_ERROR_USER_OUT), + TRUE,NULL); + KdPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n", + Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError)); + // check for Long Write In Progress + if( ((Error->SenseKey == SCSI_SENSE_NOT_READY) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && + (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS)) ) { + // we should wait... + if(WriteOp) { + if((*retry) == UDF_WRITE_MAX_RETRY-1) { + KdPrint(("Error recovery: reserve retry count for write retries\n")); + (*retry) = UDF_WRITE_MAX_RETRY*3; + } else + if((*retry) == UDF_WRITE_MAX_RETRY) { + KdPrint(("Error recovery: jump over UDF_WRITE_MAX_RETRY\n")); + (*retry)--; + } + delay.QuadPart = -500000; // 0.05 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + if(WriteOp && ((*retry) > UDF_WRITE_MAX_RETRY-1)) { + KdPrint(("Error recovery: simple write retry with delay\n")); + try_return(status = STATUS_SUCCESS); + } + } else { + delay.QuadPart = -500000; // 0.05 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + if((*retry) == UDF_WRITE_MAX_RETRY-1) { + KdPrint(("Error recovery: retry read after small delay\n")); + try_return(status = STATUS_SUCCESS); + } + } + KdPrint(("Error recovery: sync cache\n")); + // ...flush device cache... + RC = UDFSyncCache(Vcb); + // wait again & retry + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BGWriters) (*retry)++; +#endif //_UDF_STRUCTURES_H_ + try_return(status = STATUS_SUCCESS); + } else + // check for Long Write In Progress + if((Error->SenseKey == SCSI_SENSE_NOT_READY) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && + ((Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS) || + (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) || + (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_OPERATION_IN_PROGRESS) ) ) { + // we should wait & retry + KdPrint(("Error recovery: op. in progress, waiting 0.3 sec\n")); + delay.QuadPart = -3000000; // 0.3 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BGWriters) (*retry)++; +#endif //_UDF_STRUCTURES_H_ + Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_ATTEMPT; + try_return(status = STATUS_SUCCESS); + } else + // check for non empty cache special case + if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_CMD_SEQUENCE)) { + // we should wait & retry + if(!WriteOp) { + KdPrint(("Error recovery: invalid command sequence on read\n")); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + KdPrint(("Error recovery: sync cache\n")); + // ...flush device cache... + RC = UDFSyncCache(Vcb); + // wait again & retry + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BGWriters) (*retry)++; +#endif //_UDF_STRUCTURES_H_ + try_return(status = STATUS_SUCCESS); + } + goto reinit_sector_mode; + } else + // check for Bus Reset (sometimes it happends...) + if((Error->SenseKey == SCSI_SENSE_UNIT_ATTENTION) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_BUS_RESET) ) { + // we should wait + KdPrint(("Error recovery: bus reset...\n")); + Vcb->MediaChangeCount = Error->MediaChangeCount; + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + // reset driver + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + // lock it +/* ((PPREVENT_MEDIA_REMOVAL_USER_IN)(Error))->PreventMediaRemoval = TRUE; + UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + Vcb->TargetDeviceObject, + Error,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay);*/ + + // reinit write mode the following is performed inside UDFResetDeviceDriver() + //Vcb->LastModifiedTrack = 0; + //Vcb->OPCDone = FALSE; + +reinit_sector_mode: + // reinit sector mode + Vcb->LastModifiedTrack = 0; + UDFPrepareForWriteOperation(Vcb, Lba, BCount); + try_return(status = STATUS_SUCCESS); + } else + // check for Illegal Sector Mode. + // We can get this error 'cause of 2 reasons: + // a) Bus reset occured. We should reinit + // b) CopyProtection settings missmatch + // c) preblems with DNA of firmware developer, some TEACs fall into such state + // after failed streaming read + if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK)) { +bad_rw_seek_recovery: + if(WriteOp) { + + if((*retry) <= 1) { + // Variate CopyProtection... + for(i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) { + if((Vcb->TrackMap[i].FirstLba > Lba) || + (Vcb->TrackMap[i].LastLba < Lba)) + continue; + /* if(Vcb->TrackMap[i].Flags & TrackMap_CopyBit_variated) + // Last chance.... + goto reinit_sector_mode;*/ + + // check if we have successuflly completed WriteOp + // using Variation. + // We should not variate these bits again in this case. + if(Vcb->TrackMap[i].Flags & TrackMap_Use_variation) + break; + Vcb->TrackMap[i].Flags &= ~TrackMap_Try_variation; + /* if((Vcb->TrackMap[i].Flags & TrackMap_Try_variation) && + (Vcb->TrackMap[i].Flags & (TrackMap_AllowCopyBit_variated | + TrackMap_CopyBit_variated))) + break;*/ + /* if(Vcb->TrackMap[i].Flags & TrackMap_Use_variation) + break;*/ + Vcb->TrackMap[i].Flags |= TrackMap_Try_variation; + // Try variation. + if(!(Vcb->TrackMap[i].Flags ^= TrackMap_AllowCopyBit_variated)) + Vcb->TrackMap[i].Flags ^= TrackMap_CopyBit_variated; + if(Vcb->TrackMap[i].Flags & (TrackMap_AllowCopyBit_variated | + TrackMap_CopyBit_variated) ) { + (*retry) = 1; + } else { + Vcb->TrackMap[i].Flags &= ~TrackMap_Try_variation; + } + // reinit sector mode + Vcb->LastModifiedTrack = 0; + UDFPrepareForWriteOperation(Vcb, Lba, BCount); + break; + } + } else { + // Reinit... +//reinit_sector_mode: + // we should wait + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + // reinit sector mode + goto reinit_sector_mode; +/* + Vcb->LastModifiedTrack = 0; + UDFPrepareForWriteOperation(Vcb, Lba, BCount); + try_return(status = STATUS_SUCCESS); +*/ + } + } else + if((Vcb->CompatFlags & UDF_VCB_IC_BAD_RW_SEEK) && + (Vcb->IncrementalSeekState != INCREMENTAL_SEEK_DONE)) { + KdPrint(("Using incremental seek workaround...\n")); + Vcb->IncrementalSeekState = INCREMENTAL_SEEK_WORKAROUND; + try_return(status = STATUS_SUCCESS); + } else { + KdPrint(("Seems to be BB @ %x\n", Lba)); + UpdateBB = TRUE; + } + } else + if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_SESSION_MODE)) { + if(WriteOp && + (Vcb->SavedFeatures & CDRW_FEATURE_STREAMING) && + Lba+BCount <= Vcb->LastLBA+1) { + KdPrint(("bad Session in streaming mode. Lba %x, try fix-up\n", Lba)); + // ...flush device cache... + RC = UDFSyncCache(Vcb); + // we should wait + delay.QuadPart = -10000000; // 1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + try_return(status = STATUS_SUCCESS); + } + } else + if((Error->LastError == CDRW_ERR_WRITE_IN_PROGRESS_BUSY) || + (status == STATUS_DEVICE_BUSY)) { + delay.QuadPart = -5000000; // 0.5 sec + KdPrint(("CDRW_ERR_WRITE_IN_PROGRESS_BUSY || STATUS_DEVICE_BUSY\n")); + KeDelayExecutionThread(KernelMode, FALSE, &delay); +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BGWriters) (*retry)++; +#endif //_UDF_STRUCTURES_H_ + try_return(status = STATUS_SUCCESS); + } else + // some devices (SONY) return such a strange sequence.... + if( ((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_CDB)) && + WriteOp) { + // reinit write mode + Vcb->LastModifiedTrack = 0; + UDFPrepareForWriteOperation(Vcb, Lba, BCount); + try_return(status = STATUS_SUCCESS); + } else + // No seek on Read... to morgue, I'm afraid + if((Error->SenseKey == SCSI_SENSE_MEDIUM_ERROR) /*&& + ((Error->AdditionalSenseCode == SCSI_ADSENSE_CD_READ_ERROR) || + (Error->AdditionalSenseCode == SCSI_ADSENSE_NO_SENSE) || + (Error->AdditionalSenseCode == SCSI_ADSENSE_FORMAT_CORRUPTED) || + (Error->AdditionalSenseCode == SCSI_ADSENSE_SEEK_ERROR))*/ && + !WriteOp) { + if(Error->AdditionalSenseCode == SCSI_ADSENSE_SEEK_ERROR) { + KdPrint(("Seek error\n")); + if(Vcb->CompatFlags & UDF_VCB_IC_BAD_RW_SEEK) { + KdPrint(("try recovery\n")); + goto bad_rw_seek_recovery; + } + KdPrint(("map error to STATUS_NONEXISTENT_SECTOR\n")); + status = STATUS_NONEXISTENT_SECTOR; + } + KdPrint(("Seems to be BB @ %x (read 2)\n", Lba)); + UpdateBB = TRUE; + } else + // handle invalid block address + if( ((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_BLOCK)) ) { + if(!WriteOp && + (Vcb->SavedFeatures & CDRW_FEATURE_STREAMING) && + Lba+BCount <= Vcb->LastLBA+1) { + KdPrint(("bad LBA %x in streaming mode, try fix-up\n", Lba)); + // ...flush device cache... + RC = UDFSyncCache(Vcb); + try_return(status = STATUS_SUCCESS); + } + + if((Lba+BCount >= Vcb->LastLBA) && + (Vcb->MRWStatus == DiscInfo_BGF_Interrupted)) { + KdPrint(("stupid drive, cannot read beyond formatted area on DiscInfo_BGF_Interrupted\n")); + UpdateBB = FALSE; + try_return(status = STATUS_BUFFER_ALL_ZEROS); + } + // prevent Bad Block Bitmap modification + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { +#ifdef UDF_DBG + if(OS_SUCCESS(status)) { + KdPrint(("Retry\n")); + } +#endif //UDF_DBG + } _SEH2_END; + if(!OS_SUCCESS(status)) { + if((Vcb->MountPhErrorCount != -1) && + (Vcb->MountPhErrorCount < 0x7fffffff)) { + Vcb->MountPhErrorCount++; + } +//#ifdef _UDF_STRUCTURES_H_ + if(UpdateBB && (BCount == 1)) { + uint32* bm; + if(!(bm = (uint32*)(Vcb->BSBM_Bitmap))) { + bm = (uint32*)(Vcb->BSBM_Bitmap = (int8*)DbgAllocatePoolWithTag(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3), 'mNWD' )); + if(bm) { + RtlZeroMemory(bm, i); + } else { + KdPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA)); + } + } + if(bm) { + UDFSetBit__(bm, Lba); + KdPrint(("Set BB @ %#x\n", Lba)); + } +#ifdef _BROWSE_UDF_ + bm = (uint32*)(Vcb->FSBM_Bitmap); + if(bm) { + UDFSetUsedBit(bm, Lba); + KdPrint(("Set BB @ %#x as used\n", Lba)); + } +#endif //_BROWSE_UDF_ + } +//#endif //_UDF_STRUCTURES_H_ + } + return status; +} // end UDFRecoverFromError() + +//#endif //_BROWSE_UDF_ +/* + This routine attempts to read disk layout using ReadDisk/Track info cmd + */ +OSSTATUS +UDFReadDiscTrackInfo( + PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb // Volume Control Block for ^ DevObj + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + PDISC_INFO_BLOCK_USER_OUT DiscInfo = (PDISC_INFO_BLOCK_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(DISC_INFO_BLOCK_USER_OUT) ); + PTRACK_INFO_BLOCK_USER_OUT TrackInfoOut = (PTRACK_INFO_BLOCK_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(TRACK_INFO_BLOCK_USER_OUT) ); + PTRACK_INFO_BLOCK_USER_IN TrackInfoIn = (PTRACK_INFO_BLOCK_USER_IN)TrackInfoOut; + READ_CAPACITY_USER_OUT CapacityBuffer; + LONG TrackNumber; + BOOLEAN NotFP = FALSE; + BOOLEAN ForceFP = FALSE; + BOOLEAN PacketTrack = FALSE; + BOOLEAN MRWRetry = FALSE; + BOOLEAN ReadCapacityOk = FALSE; +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; +#endif + + _SEH2_TRY { + if(!DiscInfo || !TrackInfoOut) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + +MRWRetry_label: + + RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_DISC_INFO, DeviceObject, + NULL, 0, + DiscInfo,sizeof(DISC_INFO_BLOCK_USER_OUT), TRUE, NULL); + if(!OS_SUCCESS(RC)) { + KdPrint(("ReadDiskInfo failed. Use default.\n")); + if(Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDpRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM) { + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD; + } else + if(Vcb->MediaClassEx == CdMediaClass_BDRE) { + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_BD; + } else { + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_FP_CD; + } + try_return(RC); + } +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("ReadDiskInfo OK\n")); + } +#endif //UDF_FORMAT_MEDIA + + RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_CAPACITY, DeviceObject, + NULL, 0, + &CapacityBuffer,sizeof(READ_CAPACITY_USER_OUT), TRUE, NULL); + if(!OS_SUCCESS(RC)) { + KdPrint(("ReadCapacity failed.\n")); + if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) { + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD; + } + } else { + KdPrint(("ReadCapacity ok.\n")); + KdPrint(("Last possible LBA %#x.\n", CapacityBuffer.LogicalBlockAddress)); + if(!(CapacityBuffer.LogicalBlockAddress & 0xc0000000) && + (CapacityBuffer.LogicalBlockAddress != 0x7fffffff)) { + // good value from ReadCapacity + KdPrint(("Update Last possible LBA %#x.\n", CapacityBuffer.LogicalBlockAddress)); + Vcb->LastPossibleLBA = CapacityBuffer.LogicalBlockAddress; + ReadCapacityOk = TRUE; +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("ReadCapacity OK\n")); + } +#endif //UDF_FORMAT_MEDIA + } + } + +#ifdef _CONSOLE + Vcb->PhDeviceType = FILE_DEVICE_CD_ROM; +#endif //_CONSOLE + Vcb->PhSerialNumber = *((uint32*)&(DiscInfo->DiskId)); + Vcb->PhErasable = DiscInfo->DiscStat.Flags & DiscInfo_Disk_Erasable; + Vcb->PhDiskType = DiscInfo->DiskType; + // save OPC info + if(DiscInfo->OPCNum) + Vcb->OPCNum = DiscInfo->OPCNum; + KdPrint(("DiskInfo: SN %x, OPCn %x(%x), Stat %x, Flg: %x\n", + Vcb->PhSerialNumber, Vcb->OPCNum, DiscInfo->OPCNum, DiscInfo->DiscStat.Flags, DiscInfo->Flags.Flags)); +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("Media type: ")); + switch(Vcb->MediaClassEx) { + case CdMediaClass_CDROM : UserPrint(("CD-ROM \n")); break; + case CdMediaClass_CDR : UserPrint(("CD-R \n")); break; + case CdMediaClass_CDRW : UserPrint(("CD-RW \n")); break; + case CdMediaClass_DVDROM : UserPrint(("DVD-ROM \n")); break; + case CdMediaClass_DVDRAM : UserPrint(("DVD-RAM \n")); break; + case CdMediaClass_DVDR : UserPrint(("DVD-R \n")); break; + case CdMediaClass_DVDRW : UserPrint(("DVD-RW \n")); break; + case CdMediaClass_DVDpR : UserPrint(("DVD+R \n")); break; + case CdMediaClass_DVDpRW : UserPrint(("DVD+RW \n")); break; + case CdMediaClass_DDCDROM : UserPrint(("DDCD-ROM \n")); break; + case CdMediaClass_DDCDR : UserPrint(("DDCD-R \n")); break; + case CdMediaClass_DDCDRW : UserPrint(("DDCD-RW \n")); break; + case CdMediaClass_BDROM : UserPrint(("BD-ROM \n")); break; + case CdMediaClass_BDRE : UserPrint(("BD-RE \n")); break; + case CdMediaClass_BDR : UserPrint(("BD-R \n")); break; + case CdMediaClass_HD_DVDROM : UserPrint(("HD DVD-ROM \n")); break; + case CdMediaClass_HD_DVDRAM : UserPrint(("HD DVD-RAM \n")); break; + case CdMediaClass_HD_DVDR : UserPrint(("HD DVD-R \n")); break; + case CdMediaClass_HD_DVDRW : UserPrint(("HD DVD-RW \n")); break; + default: UserPrint(("Unknown\n")); break; + } + UserPrint(("SN %#x, OPCn %#x\n", + Vcb->PhSerialNumber, Vcb->OPCNum, DiscInfo->OPCNum)); + UserPrint(("Disk State: ")); + switch(DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) { + case DiscInfo_Disk_Empty: + UserPrint(("Empty\n")); + break; + case DiscInfo_Disk_Appendable: + UserPrint(("Appendable\n")); + break; + case DiscInfo_Disk_Complete: + UserPrint(("Complete\n")); + break; + case DiscInfo_Disk_OtherRW: + UserPrint(("RW in unknown state\n")); + break; + } + UserPrint(("Last Session State: ")); + switch(DiscInfo->DiscStat.Flags & DiscInfo_Ses_Mask) { + case DiscInfo_Ses_Empty: + UserPrint(("Empty\n")); + break; + case DiscInfo_Ses_Incomplete: + UserPrint(("Incomplete\n")); + break; + case DiscInfo_Ses_Complete: + UserPrint(("Complete\n")); + break; + default: + UserPrint(("unknown state\n")); + break; + } + UserPrint(("Erasable: %s\n", + (DiscInfo->DiscStat.Flags & DiscInfo_Disk_Erasable) ? "yes" : "no" + )); + } +#endif //UDF_FORMAT_MEDIA + // Save disk status + Vcb->DiscStat = DiscInfo->DiscStat.Flags; + if((DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty) { + KdPrint(("Blank\n")); + Vcb->BlankCD = TRUE; + } + if( (DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty || + (DiscInfo->DiscStat.Flags & DiscInfo_Ses_Mask) == DiscInfo_Ses_Incomplete) { + // we shall mount empty disk to make it possible for + // external applications to perform format operation + // or something like this + KdPrint(("Try RAW_MOUNT\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + PacketTrack = TRUE; + } + +#ifndef _BROWSE_UDF_ + // If drive returned reasonable value from ReadCapacity, do not use + // last LeadIn/LeadOut + if(Vcb->MediaClassEx != CdMediaClass_DVDpRW && + !ReadCapacityOk) { + // +RW returns bad value + KdPrint(("+RW returns bad value\n")); + Vcb->LastPossibleLBA = (DiscInfo->LastSesLeadOutLBA & 0x80000000) ? + 0 : DiscInfo->LastSesLeadOutLBA; + if(!(DiscInfo->LastSesLeadInLBA & 0x80000000)) { + Vcb->LastPossibleLBA = max(DiscInfo->LastSesLeadInLBA, Vcb->LastPossibleLBA); + } + } +#endif // _BROWSE_UDF_ + if((DiscInfo->Flags.Flags & DiscInfo_BGF_Mask) != 0) { + KdPrint(("ForceFP + MRW\n")); + ForceFP = TRUE; + Vcb->MRWStatus = DiscInfo->Flags.Flags & DiscInfo_BGF_Mask; + // update addressing mode + if(!MRWRetry) { + UDFSetMRWMode(Vcb); + MRWRetry = TRUE; + goto MRWRetry_label; + } + } + KdPrint(("MRW state %x\n", Vcb->MRWStatus)); + if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { + if(Vcb->PhMediaCapFlags & CdCapFlags_RandomWritable) { + KdPrint(("DVD-RW Rewritable\n")); + ForceFP = TRUE; + } else + if((DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty) { + KdPrint(("Blank DVD-RW\n")); + ForceFP = TRUE; + } else { + KdPrint(("DVD-RW Sequential\n")); + NotFP = TRUE; + } + } else + if(CdrwIsDvdOverwritable(Vcb->MediaClassEx)) { + KdPrint(("force Rewritable (2)\n")); + ForceFP = TRUE; + } + // We have incomplete last session, so process each track from last to first +// Vcb->LastPossibleLBA = DiscInfo->LastSesLeadInLBA; + + Vcb->LastSession = DiscInfo->Status.NumOfSes; + Vcb->LastTrackNum = DiscInfo->Status.LastTrackNumLastSes; + Vcb->FirstTrackNum = DiscInfo->FirstTrackNum; + // some devices report LastTrackNum=0 for full disks + Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum); + if(!Vcb->LastTrackNum) { + KdPrint(("Try read 1st track...\n")); + Vcb->LastTrackNum = 1; + } + KdPrint(("DiskInfo: 1st trk %x, last trk %x\n", Vcb->FirstTrackNum, Vcb->LastTrackNum)); +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("First track: %d\n" + "Last track: %d\n", Vcb->FirstTrackNum, Vcb->LastTrackNum)); + UserPrint(("------------------------------------------\n")); + } +#endif //UDF_FORMAT_MEDIA + + RC = UDFReallocTrackMap(Vcb, Vcb->LastTrackNum+1); + if(!OS_SUCCESS(RC)) + try_return(RC); + + // Get last LBA from invisible track (if any) + RtlZeroMemory(TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT)); + + TrackInfoIn->LBA_TrkNum = 0; // invisible track + TrackInfoIn->Track = TRUE; + + RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_TRACK_INFO, DeviceObject, + TrackInfoIn, sizeof(TRACK_INFO_BLOCK_USER_IN), + TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT), TRUE, NULL); + if(OS_SUCCESS(RC)) { + if((Vcb->LastTrackNum < TrackInfoOut->TrackNum) && + TrackInfoOut->TrackLength && + (TrackInfoOut->TrackStartLBA != TrackInfoOut->NextWriteLBA)) { + Vcb->LastTrackNum = TrackInfoOut->TrackNum; + if(!(TrackInfoOut->NextWriteLBA & 0x80000000)) + Vcb->NWA = TrackInfoOut->NextWriteLBA; + if(TrackInfoOut->TrackLength > 1) { + Vcb->LastPossibleLBA = + TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0); + KdPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA)); + } + } + + KdPrint(("Ses %d, Track %d (%x, len %x) PckSize %x: \n" + " NWA: %x (%s) DatType:%x, %s %s %s %s TrkType:%x %s %s\n" + " LRA: %x (%s) RC_LBA:%x\n", + TrackInfoOut->SesNum, + 0, + TrackInfoOut->TrackStartLBA, + TrackInfoOut->TrackLength, + TrackInfoOut->FixPacketSize, + + TrackInfoOut->NextWriteLBA, + TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv", + TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask, + (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "", + + TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask, + (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "", + (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "", + + TrackInfoOut->LastRecordedAddr, + (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv", + + TrackInfoOut->ReadCompatLBA + )); +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("Invisible track: \n")); + UserPrint((" Ses %d, Track %d (%x, len %x) PckSize %x: \n" + " NWA: %x (%s) DatType:%x, %s %s %s %s TrkType:%x %s %s\n" + " LRA: %x (%s) RC_LBA:%x\n", + TrackInfoOut->SesNum, + 0, + TrackInfoOut->TrackStartLBA, + TrackInfoOut->TrackLength, + TrackInfoOut->FixPacketSize, + + TrackInfoOut->NextWriteLBA, + TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv", + TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask, + (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "", + + TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask, + (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "", + (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "", + + TrackInfoOut->LastRecordedAddr, + (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv", + + TrackInfoOut->ReadCompatLBA + )); + } +#endif //UDF_FORMAT_MEDIA + + } + + for (TrackNumber=(LONG)DiscInfo->FirstTrackNum;TrackNumber <= (LONG)Vcb->LastTrackNum;TrackNumber++) { + + RtlZeroMemory(TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT)); + TrackInfoIn->LBA_TrkNum = TrackNumber; + TrackInfoIn->Track = TRUE; + + RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_TRACK_INFO, DeviceObject, + TrackInfoIn, sizeof(TRACK_INFO_BLOCK_USER_IN), + TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT), TRUE, NULL); + // fill sector type map + if(TrackInfoOut->TrackStartLBA & 0x80000000) { + KdPrint(("TrkInfo: Bad FirstLba (%x), change to %x\n", TrackInfoOut->TrackStartLBA, 0)); + Vcb->TrackMap[TrackNumber].FirstLba = 0; + } else { + Vcb->TrackMap[TrackNumber].FirstLba = TrackInfoOut->TrackStartLBA; + } + if(TrackInfoOut->TrackLength & 0x80000000) { + KdPrint(("TrkInfo: Bad TrackLength (%x), change to %x\n", TrackInfoOut->TrackLength, + Vcb->LastPossibleLBA - Vcb->TrackMap[TrackNumber].FirstLba + 1)); + TrackInfoOut->TrackLength = Vcb->LastPossibleLBA - Vcb->TrackMap[TrackNumber].FirstLba + 1; + } + Vcb->TrackMap[TrackNumber].LastLba = TrackInfoOut->TrackStartLBA + + TrackInfoOut->TrackLength - + (TrackInfoOut->TrackLength ? 1 : 0); + + Vcb->TrackMap[TrackNumber].TrackParam = TrackInfoOut->TrackParam.Flags; + Vcb->TrackMap[TrackNumber].DataParam = TrackInfoOut->DataParam.Flags; + Vcb->TrackMap[TrackNumber].NWA_V = TrackInfoOut->NWA_V; + if((TrackInfoOut->NextWriteLBA & 0x80000000) || + (TrackInfoOut->NextWriteLBA < TrackInfoOut->TrackStartLBA)) { + if(!(Vcb->TrackMap[TrackNumber].LastLba & 0x8000000)) { + KdPrint(("TrkInfo: set NWA to LastLba (%x)\n", Vcb->TrackMap[TrackNumber].LastLba)); + Vcb->TrackMap[TrackNumber].NWA = + Vcb->TrackMap[TrackNumber].LastLba; + } else { + KdPrint(("TrkInfo: set NWA to INV (1)\n")); + Vcb->TrackMap[TrackNumber].NWA = 0; + Vcb->TrackMap[TrackNumber].NWA_V = 0; + } + } else { + if(!(TrackInfoOut->NextWriteLBA & 0x80000000)) { + KdPrint(("TrkInfo: Good NWA (%x)\n", TrackInfoOut->NextWriteLBA)); + Vcb->TrackMap[TrackNumber].NWA = + TrackInfoOut->NextWriteLBA; + } else { + KdPrint(("TrkInfo: set NWA to INV (2)\n")); + Vcb->TrackMap[TrackNumber].NWA = 0; + Vcb->TrackMap[TrackNumber].NWA_V = 0; + } + } + Vcb->TrackMap[TrackNumber].Session = TrackInfoOut->SesNum; + // for FP tracks we shall get PacketSize from returned info + // otherwise set to default UDF value (0x20) + if(NotFP) { + KdPrint(("Apply NotFP\n")); + Vcb->TrackMap[TrackNumber].DataParam &= ~TrkInfo_FP; +#ifdef DBG + TrackInfoOut->DataParam.Flags &= ~TrkInfo_FP; +#endif //DBG + } else + if(ForceFP) { + KdPrint(("Apply ForceFP\n")); + PacketTrack = TRUE; + Vcb->TrackMap[TrackNumber].DataParam |= TrkInfo_FP; +#ifdef DBG + TrackInfoOut->DataParam.Flags |= TrkInfo_FP; +#endif //DBG + } + if(Vcb->TrackMap[TrackNumber].DataParam & TrkInfo_FP) { + Vcb->TrackMap[TrackNumber].PacketSize = TrackInfoOut->FixPacketSize; + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + Vcb->FP_disc = TRUE; + } else { + Vcb->TrackMap[TrackNumber].PacketSize = PACKETSIZE_UDF; + } + // presence of Damaged track means, that we should mount this disk in RAW mode + if(Vcb->TrackMap[TrackNumber].TrackParam & TrkInfo_Damage) { + KdPrint(("TrkInfo_Damage, Try RAW_MOUNT\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + } + // presence of track with Unknown data type means, that we should mount + // this disk in RAW mode + if((TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask) == TrkInfo_Trk_unknown) { + KdPrint(("Unknown DatType, Try RAW_MOUNT\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + } + + PacketTrack |= ((TrackInfoOut->DataParam.Flags & TrkInfo_Packet) != 0); + + KdPrint(("Ses %d, Track %d (%x - %x) PckSize %x: \n" + " NWA: %x (%s) DatType:%x, %s %s %s %s TrkType:%x %s %s\n" + " LRA: %x (%s) RC_LBA:%x\n", + TrackInfoOut->SesNum, + TrackNumber, + Vcb->TrackMap[TrackNumber].FirstLba, + Vcb->TrackMap[TrackNumber].LastLba, + TrackInfoOut->FixPacketSize, + + TrackInfoOut->NextWriteLBA, + TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv", + TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask, + (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "", + + TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask, + (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "", + (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "", + + TrackInfoOut->LastRecordedAddr, + (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv", + + TrackInfoOut->ReadCompatLBA + )); +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("Track %d: \n", TrackNumber)); + UserPrint((" Ses %d, Track %d (%x, len %x) PckSize %x: \n" + " NWA: %x (%s) DatType:%x, %s %s %s %s TrkType:%x %s %s\n" + " LRA: %x (%s) RC_LBA:%x\n", + TrackInfoOut->SesNum, + TrackNumber, + TrackInfoOut->TrackStartLBA, + TrackInfoOut->TrackLength, + TrackInfoOut->FixPacketSize, + + TrackInfoOut->NextWriteLBA, + TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv", + TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask, + (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "", + (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "", + + TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask, + (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "", + (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "", + + TrackInfoOut->LastRecordedAddr, + (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv", + + TrackInfoOut->ReadCompatLBA + )); + } +#endif //UDF_FORMAT_MEDIA + + if(TrackNumber == DiscInfo->FirstTrackNum) { + if(!(Vcb->TrackMap[TrackNumber].FirstLba & 0x80000000)) { + KdPrint(("TrkInfo: Update FirstLBA (%x)\n", Vcb->TrackMap[TrackNumber].FirstLba)); + Vcb->FirstLBA = Vcb->TrackMap[TrackNumber].FirstLba; + } + } + if((TrackInfoOut->SesNum == Vcb->LastSession) && !Vcb->FirstTrackNumLastSes) { + if(!(Vcb->TrackMap[TrackNumber].FirstLba & 0x80000000)) { + KdPrint(("TrkInfo: Update FirstLBALastSes (%x)\n", Vcb->TrackMap[TrackNumber].FirstLba)); + Vcb->FirstLBALastSes = Vcb->TrackMap[TrackNumber].FirstLba; + } + Vcb->FirstTrackNumLastSes = TrackNumber; + } + } + + if(!(TrackInfoOut->NextWriteLBA & 0x80000000) && + !(TrackInfoOut->TrackLength & 0x80000000) && + (Vcb->NWA < TrackInfoOut->NextWriteLBA) + ) { + KdPrint((" set NWA to %x\n", TrackInfoOut->NextWriteLBA)); + if(Vcb->MediaClassEx != CdMediaClass_DVDpRW) { + Vcb->NWA = TrackInfoOut->NextWriteLBA; + } else { + Vcb->NWA = + TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0); + } + } + if(Vcb->MediaClassEx != CdMediaClass_DVDpRW && + !(TrackInfoOut->TrackLength & 0x80000000) && + TrackInfoOut->TrackLength > 1) { + Vcb->LastPossibleLBA = + TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0); + KdPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA)); + } + TrackNumber = Vcb->LastTrackNum; + // quick formatted +RW returns bogus value + if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) { + KdPrint((" check quick formatted +RW\n")); + if(Vcb->TrackMap[TrackNumber].LastLba && + !(Vcb->TrackMap[TrackNumber].LastLba & 0x80000000) && + Vcb->TrackMap[TrackNumber].LastLba < Vcb->LastPossibleLBA /*&& + Vcb->TrackMap[TrackNumber].LastLba != Vcb->LastPossibleLBA*/ + ) { + KdPrint((" track LastLBA %x != LastPossibleLBA %x, verify\n", + Vcb->TrackMap[TrackNumber].LastLba, Vcb->LastPossibleLBA)); + + if(Vcb->MRWStatus == DiscInfo_BGF_Complete) { + KdPrint((" complete MRW state\n")); +#ifdef _BROWSE_UDF_ + Vcb->LastPossibleLBA = + Vcb->NWA = + Vcb->LastLBA = + Vcb->TrackMap[TrackNumber].LastLba; + goto valid_track_length; +#endif // _BROWSE_UDF_ + } else + if(Vcb->MRWStatus) { + uint8* buff; + uint32 ReadBytes; + + KdPrint((" MRW state %x\n", Vcb->MRWStatus)); + + buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' ); + if(buff) { + RC = UDFTRead(Vcb, + buff, + Vcb->WriteBlockSize, + Vcb->TrackMap[TrackNumber].LastLba+1, + &ReadBytes, + PH_TMP_BUFFER); + DbgFreePool(buff); + if(!OS_SUCCESS(RC)) { + KdPrint((" Can't read beyond track LastLBA (%x)\n", Vcb->TrackMap[TrackNumber].LastLba+1)); + Vcb->LastLBA = Vcb->TrackMap[TrackNumber].LastLba; + Vcb->NWA = Vcb->LastLBA+1; + Vcb->TrackMap[TrackNumber].NWA_V = 1; + Vcb->TrackMap[TrackNumber].NWA = Vcb->NWA; + Vcb->TrackMap[TrackNumber].LastLba = Vcb->LastPossibleLBA; + RC = STATUS_SUCCESS; + goto valid_track_length; + } + } + } + } + KdPrint((" set track LastLBA %x\n", Vcb->LastPossibleLBA)); + Vcb->NWA = + Vcb->LastLBA = + Vcb->TrackMap[TrackNumber].LastLba = + Vcb->LastPossibleLBA; + } +valid_track_length: + // Test for last empty session + if((Vcb->TrackMap[TrackNumber].Session != + Vcb->TrackMap[TrackNumber-1].Session) && + (Vcb->LastSession > 1)) { + // Note: some devices return negative track length + if((Vcb->TrackMap[TrackNumber].LastLba <= + Vcb->TrackMap[TrackNumber].FirstLba) || + (Vcb->TrackMap[TrackNumber].FirstLba == + Vcb->TrackMap[TrackNumber].NWA)) { + // empty last session... + Vcb->LastTrackNum--; +// TrackNumber--; +/* for(SesNum = Vcb->TrackMap[TrackNumber].Session; + Vcb->TrackMap[TrackNumber].Session == SesNum; + TrackNumber--) { + }*/ + if(TrackNumber>1) + Vcb->LastSession = Vcb->TrackMap[TrackNumber-1].Session; + } + } + + TrackNumber = Vcb->LastTrackNum; +#ifdef _BROWSE_UDF_ + Vcb->LastLBA = min(Vcb->TrackMap[TrackNumber].LastLba, Vcb->TrackMap[TrackNumber].NWA); +#endif //_BROWSE_UDF_ + + if(Vcb->TrackMap[TrackNumber].NWA_V & TrkInfo_NWA_V) { + KdPrint((" NWA ok, set LastLBA to min(Last %x, NWA %x\n", + Vcb->TrackMap[TrackNumber].LastLba, + Vcb->TrackMap[TrackNumber].NWA)); + Vcb->LastLBA = min(Vcb->TrackMap[TrackNumber].LastLba, Vcb->TrackMap[TrackNumber].NWA); + } else { + KdPrint((" no NWA, set LastLBA to Last %x\n", Vcb->TrackMap[TrackNumber].LastLba)); + Vcb->LastLBA = Vcb->TrackMap[TrackNumber].LastLba; + } + + Vcb->VCBFlags |= UDF_VCB_FLAGS_TRACKMAP; + if(!PacketTrack && Vcb->MediaClassEx != CdMediaClass_DVDRAM ) { + KdPrint((" disable Raw mount\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(DiscInfo) MyFreePool__(DiscInfo); + if(TrackInfoOut) MyFreePool__(TrackInfoOut); + } _SEH2_END; + + return RC; +} // end UDFReadDiscTrackInfo() + +/* + This routine attempts to read disk layout using ReadFullTOC cmd + */ +OSSTATUS +UDFReadAndProcessFullToc( + PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + PREAD_FULL_TOC_USER_OUT toc = (PREAD_FULL_TOC_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(READ_FULL_TOC_USER_OUT) ); + uint32 index; + uint8 POINT; + uint8 CurTrack = 0; + uint32 LastLeadOut = 0; +// BOOLEAN IsMRW = FALSE; + + KdPrint(("UDFReadAndProcessFullToc\n")); + + if(!toc) return STATUS_INSUFFICIENT_RESOURCES; + Vcb->FirstTrackNum = 0xFF; + + RtlZeroMemory(toc,sizeof(READ_FULL_TOC_USER_OUT)); + + RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_FULL_TOC,DeviceObject, + NULL,0, + toc,sizeof(READ_FULL_TOC_USER_OUT), + TRUE,NULL); + + if(!OS_SUCCESS(RC)) { + + MyFreePool__(toc); + return RC; + } + +#ifdef _CONSOLE + Vcb->PhDeviceType = FILE_DEVICE_CD_ROM; +#endif //_CONSOLE + Vcb->LastSession = toc->Sessions.Last_TrackSes; + + RC = UDFReallocTrackMap(Vcb, 0x100); + if(!OS_SUCCESS(RC)) { + MyFreePool__(toc); + return RC; + } + + // get LastPossibleLBA + + // Note: some drives return Full TOC items unordered. + // So, LeadOut position may come before Track definition. + // In order to handle such situation, we must initialize + // CurTrack when First or Last Track descriptor comes + for (index=0;(indexSessionData[index].Adr == TOC_ADR_TrackInfo) && + ((toc->SessionData[index].Control == TOC_CTL_MRWTrackInfo) || (toc->SessionData[index].Control == TOC_CTL_MRWLastSes))) { + IsMRW = TRUE; + }*/ + if(toc->SessionData[index].Adr == 1) { + switch (POINT = toc->SessionData[index].POINT) { + case POINT_FirstTrackNum: { + Vcb->FirstTrackNum = toc->SessionData[index].Params.FirstTrackNum.FirstTrackNum; + if(!CurTrack) + CurTrack = (uint8)(Vcb->FirstTrackNum); + break; + } + case POINT_LastTrackNum: { + Vcb->LastTrackNum = toc->SessionData[index].Params.LastTrackNum.LastTrackNum; + if(CurTrack < Vcb->LastTrackNum) + CurTrack = (uint8)(Vcb->FirstTrackNum); + break; + } + case POINT_StartPositionOfLeadOut: { +#define TempMSF toc->SessionData[index].Params.StartPositionOfLeadOut.MSF + Vcb->TrackMap[CurTrack].LastLba = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]); + LastLeadOut = max(LastLeadOut, Vcb->TrackMap[CurTrack].LastLba); +#undef TempMSF + break; + } + default: { + if( (Vcb->FirstTrackNum != 0x0FF) && + (toc->SessionData[index].POINT == Vcb->FirstTrackNum) ) { +#define TempMSF toc->SessionData[index].Params.StartPositionOfTrack.MSF + Vcb->FirstLBA = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]); + if(Vcb->FirstLBA & 0x80000000) { + Vcb->FirstLBA = 0; + } +#undef TempMSF + } + break; + } + } + if((POINT >= POINT_StartPositionOfTrack_Min) && + (POINT <= POINT_StartPositionOfTrack_Max)) { +#define TempMSF toc->SessionData[index].Params.StartPositionOfTrack.MSF + Vcb->TrackMap[POINT].FirstLba = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2])-1; + if(Vcb->TrackMap[POINT].FirstLba & 0x80000000) { + if(POINT == 1) { + Vcb->TrackMap[POINT].FirstLba = 0; + } else { + if(Vcb->TrackMap[POINT-1].LastLba) { + Vcb->TrackMap[POINT].FirstLba = Vcb->TrackMap[POINT-1].LastLba+1; + } + } + } +#undef TempMSF + if(POINT > POINT_StartPositionOfTrack_Min) { + Vcb->TrackMap[POINT-1].LastLba = Vcb->TrackMap[POINT].FirstLba-1; + } + CurTrack = POINT; + } + } else + if(toc->SessionData[index].Adr == 5) { + switch (POINT = toc->SessionData[index].POINT) { + case POINT_StartPositionOfNextProgramArea: { +#define TempMSF toc->SessionData[index].Params.StartPositionOfNextProgramArea.MaxLeadOut_MSF + Vcb->LastPossibleLBA = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]); +#undef TempMSF + break; + } + default: { + break; + } + } + } + + } + +/* if(!IsMRW) { + KdPrint(("No MRW\n")); + Vcb->CompatFlags &= ~UDF_VCB_IC_MRW_ADDR_PROBLEM; + }*/ +// Vcb->CompatFlags &= ~UDF_VCB_IC_MRW_ADDR_PROBLEM; + // some devices report LastTrackNum=0 for full disks + Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum); + Vcb->TrackMap[Vcb->LastTrackNum].LastLba = max(LastLeadOut, Vcb->TrackMap[Vcb->LastTrackNum].LastLba); + + Vcb->LastLBA = Vcb->TrackMap[Vcb->LastTrackNum].LastLba; + + MyFreePool__(toc); +// Vcb->LastLBA=PacketVariable2Fixed(Vcb->LastLBA)-2; + return STATUS_SUCCESS; +} // end UDFReadAndProcessFullToc() + +/* + use standard way to determine disk layout (ReadTOC cmd) + */ +OSSTATUS +UDFUseStandard( + PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb // Volume control block from this DevObj + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + PREAD_TOC_USER_OUT toc = (PREAD_TOC_USER_OUT)MyAllocatePool__(NonPagedPool,max(Vcb->BlockSize, sizeof(READ_TOC_USER_OUT)) ); + PGET_LAST_SESSION_USER_OUT LastSes = (PGET_LAST_SESSION_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(GET_LAST_SESSION_USER_OUT) ); + uint32 LocalTrackCount; + uint32 LocalTocLength; + uint32 TocEntry; +#ifdef _BROWSE_UDF_ + uint32 OldTrkNum; + uint32 TrkNum; + uint32 ReadBytes, i, len; +#endif //_BROWSE_UDF_ +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; +#else + #define fms FALSE +#endif //UDF_FORMAT_MEDIA + + KdPrint(("UDFUseStandard\n")); + + _SEH2_TRY { + + if(!toc || !LastSes) { + try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(toc,sizeof(READ_TOC_TOC)); + + Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_STD; + + RC = UDFPhSendIOCTL(IOCTL_CDROM_READ_TOC,DeviceObject, + toc,sizeof(READ_TOC_USER_OUT), + toc,sizeof(READ_TOC_USER_OUT), + TRUE,NULL ); + + if((RC == STATUS_DEVICE_NOT_READY) || (RC == STATUS_NO_MEDIA_IN_DEVICE)) { + try_return(RC); + } +#ifdef UDF_FORMAT_MEDIA + if(fms->opt_media == MT_none) { + try_return(RC = STATUS_NO_MEDIA_IN_DEVICE); + } +#endif //UDF_FORMAT_MEDIA + + // If even standard read toc does not work, then use default values + if(!OS_SUCCESS(RC)) { + + RC = UDFReallocTrackMap(Vcb, 2); + if(!OS_SUCCESS(RC)) { + try_return(RC); + } + + Vcb->LastSession=1; + Vcb->FirstTrackNum=1; +// Vcb->FirstLBA=0; + Vcb->LastTrackNum=1; + Vcb->TrackMap[1].FirstLba = Vcb->FirstLBA; + Vcb->TrackMap[1].LastLba = Vcb->LastLBA; + Vcb->TrackMap[1].PacketSize = PACKETSIZE_UDF; +#ifdef UDF_FORMAT_MEDIA + if(!fms) { +#endif //UDF_FORMAT_MEDIA + +#ifdef _BROWSE_UDF_ +#ifdef UDF_HDD_SUPPORT + if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) { + try_return(RC = STATUS_SUCCESS); + } +#endif //UDF_HDD_SUPPORT +#endif //_BROWSE_UDF_ + +#ifdef UDF_FORMAT_MEDIA + } else { + + if(fms->opt_media == MT_HD) { + Vcb->LastPossibleLBA = Vcb->LastLBA; + try_return(RC = STATUS_SUCCESS); + } + } +#endif //UDF_FORMAT_MEDIA + Vcb->LastPossibleLBA = max(Vcb->LastLBA, DEFAULT_LAST_LBA_FP_CD); + Vcb->TrackMap[1].DataParam = TrkInfo_Dat_XA | TrkInfo_FP | TrkInfo_Packet; + Vcb->TrackMap[1].TrackParam = TrkInfo_Trk_XA; + Vcb->TrackMap[1].NWA = 0xffffffff; + Vcb->NWA = DEFAULT_LAST_LBA_FP_CD + 7 + 1; + try_return(RC = STATUS_SUCCESS); + } + +#ifdef _CONSOLE + Vcb->PhDeviceType = FILE_DEVICE_CD_ROM; +#endif //_CONSOLE + + LocalTrackCount = toc->Tracks.Last_TrackSes - toc->Tracks.First_TrackSes + 1; + LocalTocLength = PtrOffset( toc, &(toc->TrackData[LocalTrackCount + 1]) ); + + // Get out if there is an immediate problem with the TOC. + if(toc->Tracks.First_TrackSes > toc->Tracks.Last_TrackSes) { + try_return(RC = STATUS_DISK_CORRUPT_ERROR); + } + +#ifdef _BROWSE_UDF_ + Vcb->LastTrackNum=toc->Tracks.Last_TrackSes; + Vcb->FirstTrackNum=toc->Tracks.First_TrackSes; + // some devices report LastTrackNum=0 for full disks + Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum); + + RC = UDFReallocTrackMap(Vcb, MAXIMUM_NUMBER_OF_TRACKS+1); +/* if(Vcb->TrackMap) { + MyFreePool__(Vcb->TrackMap); + Vcb->TrackMap = NULL; + } + Vcb->TrackMap = (PUDFTrackMap) + MyAllocatePool__(NonPagedPool, (MAXIMUM_NUMBER_OF_TRACKS+1)*sizeof(UDFTrackMap)); + if(!Vcb->TrackMap) { + MyFreePool__(toc); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(Vcb->TrackMap,(MAXIMUM_NUMBER_OF_TRACKS+1)*sizeof(UDFTrackMap)); +*/ + if(!OS_SUCCESS(RC)) { + BrutePoint(); + try_return(RC); + } + // find 1st and last session + RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_LAST_SESSION,DeviceObject, + LastSes,sizeof(GET_LAST_SESSION_USER_OUT), + LastSes,sizeof(GET_LAST_SESSION_USER_OUT), + TRUE,NULL ); + + if(OS_SUCCESS(RC)) { + TrkNum = LastSes->LastSes_1stTrack.TrackNum; + Vcb->LastSession = LastSes->Sessions.First_TrackSes; + for(TocEntry=0;TocEntryTrackData[TocEntry].TrackNum == TrkNum) { + Vcb->TrackMap[TrkNum].Session = Vcb->LastSession; + } + } + } + + OldTrkNum = 0; + // Scan toc for first & last LBA + for(TocEntry=0;TocEntryTrackData[TocEntry].LBA + TrkNum = toc->TrackData[TocEntry].TrackNum; +#ifdef UDF_DBG + if (TrkNum >= MAXIMUM_NUMBER_OF_TRACKS && + TrkNum != TOC_LastTrack_ID) { + KdPrint(("UDFUseStandard: Array out of bounds\n")); + BrutePoint(); + try_return(RC = STATUS_SUCCESS); + } + KdPrint(("Track N %d (0x%x) first LBA %ld (%lx) \n",TrkNum,TrkNum, + MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]), + MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]))); +#endif // UDF_DBG + if(Vcb->FirstTrackNum == TrkNum) { + Vcb->FirstLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]); + if(Vcb->FirstLBA & 0x80000000) { + Vcb->FirstLBA = 0; + } + } + if(TOC_LastTrack_ID == TrkNum) { + Vcb->LastLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3])-1; + Vcb->TrackMap[OldTrkNum].LastLba = Vcb->LastLBA-1; + KdPrint(("UDFUseStandard: Last track entry, break TOC scan\n")); +// continue; + break; + } else { + Vcb->TrackMap[TrkNum].FirstLba = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]); + if(Vcb->TrackMap[TrkNum].FirstLba & 0x80000000) + Vcb->TrackMap[TrkNum].FirstLba = 0; + if(TrkNum) { + if (TOC_LastTrack_ID == OldTrkNum) { + KdPrint(("UDFUseStandard: Wrong previous track number\n")); + BrutePoint(); + } else { + Vcb->TrackMap[OldTrkNum].LastLba = Vcb->TrackMap[TrkNum].FirstLba-1; + } + } + } + // check track type + switch(toc->TrackData[TocEntry].Control & TocControl_TrkMode_Mask) { + case TocControl_TrkMode_Data: + case TocControl_TrkMode_IncrData: + Vcb->TrackMap[TrkNum].DataParam = TrkInfo_Dat_XA; + Vcb->TrackMap[TrkNum].TrackParam = TrkInfo_Trk_XA; + break; + default: + Vcb->TrackMap[TrkNum].DataParam = TrkInfo_Dat_unknown; + Vcb->TrackMap[TrkNum].TrackParam = TrkInfo_Trk_unknown; + } + OldTrkNum = TrkNum; +#undef TempMSF + } + + TrkNum = Vcb->LastTrackNum; + RC = STATUS_SUCCESS; + // find last _valid_ track + for(;TrkNum;TrkNum--) { + if((Vcb->TrackMap[TrkNum].DataParam != TrkInfo_Dat_unknown) && + (Vcb->TrackMap[TrkNum].TrackParam != TrkInfo_Trk_unknown)) { + RC = STATUS_UNSUCCESSFUL; + Vcb->LastTrackNum = TrkNum; + break; + } + } + // no valid tracks... + if(!TrkNum) { + KdPrint(("UDFUseStandard: no valid tracks...\n")); + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + } + i = 0; + + // Check for last VP track. Some last sectors may belong to Link-data & + // be unreadable. We should forget about them, because UDF needs + // last _readable_ sector. + while(!OS_SUCCESS(RC) && (i<8)) { + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, (int8*)toc, Vcb->BlockSize, + ((uint64)(Vcb->TrackMap[TrkNum].LastLba-i)) << Vcb->BlockSizeBits, &ReadBytes, PH_TMP_BUFFER); + i++; + } + if(OS_SUCCESS(RC)) { + Vcb->LastLBA = Vcb->TrackMap[TrkNum].LastLba-i+1; +/* if(i) { + Vcb->TrackMap[TrkNum].PacketSize = PACKETSIZE_UDF; + Vcb->TrackMap[TrkNum].; + }*/ + } else { + + // Check for FP track. READ_TOC reports actual track length, but + // Link-data is hidden & unreadable for us. So, available track + // length may be less than actual. Here we assume that Packet-size + // is PACKETSIZE_UDF. + i = 0; + len = Vcb->TrackMap[TrkNum].LastLba - Vcb->TrackMap[TrkNum].FirstLba + 1; + len = (uint32)(((int64)len*PACKETSIZE_UDF) / (PACKETSIZE_UDF+7)); + + while(!OS_SUCCESS(RC) && (i<9)) { + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, (int8*)toc, Vcb->BlockSize, + ((uint64)(Vcb->TrackMap[TrkNum].FirstLba-i+len)) << Vcb->BlockSizeBits, &ReadBytes, PH_TMP_BUFFER); + i++; + } + if(OS_SUCCESS(RC)) { + Vcb->LastLBA = + Vcb->TrackMap[TrkNum].LastLba = Vcb->TrackMap[TrkNum].FirstLba-i+len+1; + Vcb->TrackMap[TrkNum].PacketSize = PACKETSIZE_UDF; +// Vcb->TrackMap[TrkNum].; + } else + if(RC == STATUS_INVALID_DEVICE_REQUEST) { + // wrap return code from Audio-disk + RC = STATUS_SUCCESS; + } + } + +#ifdef UDF_CDRW_EMULATION_ON_ROM + Vcb->LastPossibleLBA = Vcb->LastLBA+7+1+1024; + Vcb->NWA = Vcb->LastLBA+7+1; +#else + Vcb->LastPossibleLBA = + Vcb->NWA = Vcb->LastLBA+7+1; +#endif //UDF_CDRW_EMULATION_ON_ROM + +#else //_BROWSE_UDF_ + + Vcb->FirstTrackNum=toc->Tracks.Last_TrackSes; + Vcb->LastTrackNum=toc->Tracks.First_TrackSes; + + // Scan toc for first & last LBA + for(TocEntry=0;TocEntryTrackData[TocEntry].LBA + if(Vcb->FirstTrackNum == toc->TrackData[TocEntry].TrackNum) { + Vcb->FirstLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]); + if(Vcb->FirstLBA & 0x80000000) { + Vcb->FirstLBA = 0; + } + } + if(TOC_LastTrack_ID == toc->TrackData[TocEntry].TrackNum) { + Vcb->LastLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3])-1; + } +#undef TempMSF + } + +// Vcb->LastLBA=PacketVariable2Fixed(Vcb->LastLBA)-2; + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_FP_CD; +#endif //_BROWSE_UDF_ +try_exit: NOTHING; + } _SEH2_FINALLY { + if(toc) MyFreePool__(toc); + if(LastSes) MyFreePool__(LastSes); + } _SEH2_END; + + return RC; +} // end UDFUseStandard() + +/* + Get block size (for read operation) + */ +OSSTATUS +UDFGetBlockSize( + IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb // Volume control block from this DevObj + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + PDISK_GEOMETRY DiskGeometry = (PDISK_GEOMETRY)MyAllocatePool__(NonPagedPool,sizeof(DISK_GEOMETRY)); + PPARTITION_INFORMATION PartitionInfo = (PPARTITION_INFORMATION)MyAllocatePool__(NonPagedPool,sizeof(PARTITION_INFORMATION)*2); +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; +#else + #define fms FALSE +#endif //UDF_FORMAT_MEDIA + + if(!DiskGeometry || !PartitionInfo) + try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + +#ifdef _BROWSE_UDF_ + +#ifdef UDF_HDD_SUPPORT + if(!fms) { + if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) { + KdPrint(("UDFGetBlockSize: HDD\n")); + RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY,DeviceObject, + 0,NULL, + DiskGeometry,sizeof(DISK_GEOMETRY), + TRUE,NULL ); + Vcb->BlockSize = (OS_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 512; + if(!NT_SUCCESS(RC)) + try_return(RC); + RC = UDFPhSendIOCTL(IOCTL_DISK_GET_PARTITION_INFO,DeviceObject, + 0,NULL, + PartitionInfo,sizeof(PARTITION_INFORMATION), + TRUE,NULL ); + if(!NT_SUCCESS(RC)) { + KdPrint(("UDFGetBlockSize: IOCTL_DISK_GET_PARTITION_INFO failed\n")); + if(RC = STATUS_INVALID_DEVICE_REQUEST) + RC = STATUS_UNRECOGNIZED_VOLUME; + try_return(RC); + } + if(PartitionInfo->PartitionType != PARTITION_IFS) { + KdPrint(("UDFGetBlockSize: PartitionInfo->PartitionType != PARTITION_IFS\n")); + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + } + } else { +#endif //UDF_HDD_SUPPORT + RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,DeviceObject, + DiskGeometry,sizeof(DISK_GEOMETRY), + DiskGeometry,sizeof(DISK_GEOMETRY), + TRUE,NULL ); + + if(RC == STATUS_DEVICE_NOT_READY) { + // probably, the device is really busy, may be by CD/DVD recording + UserPrint((" busy (0)\n")); + try_return(RC); + } + + Vcb->BlockSize = (OS_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 2048; +#ifdef UDF_HDD_SUPPORT + } + } +#endif //UDF_HDD_SUPPORT + +#endif //_BROWSE_UDF_ + +#ifdef UDF_FORMAT_MEDIA + if(fms) { + RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,DeviceObject, + DiskGeometry,sizeof(DISK_GEOMETRY), + DiskGeometry,sizeof(DISK_GEOMETRY), + FALSE, NULL ); + + if(!NT_SUCCESS(RC)) { + RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY,DeviceObject, + DiskGeometry,sizeof(DISK_GEOMETRY), + DiskGeometry,sizeof(DISK_GEOMETRY), + FALSE, NULL ); + if(NT_SUCCESS(RC)) { + fms->opt_media = MT_HD; + RC = UDFPhSendIOCTL(IOCTL_DISK_GET_PARTITION_INFO,DeviceObject, + NULL,0, + PartitionInfo,sizeof(PARTITION_INFORMATION)*2, + FALSE, NULL ); + if(!NT_SUCCESS(RC)) { + LONG HiOffs=0; + RC = SetFilePointer(DeviceObject->h,0,&HiOffs,FILE_END); + } + } + } + + if(RC == STATUS_DEVICE_NOT_READY) { + // probably, the device is really busy, may be by CD/DVD recording + UserPrint((" busy\n")); + try_return(RC ); + } + + Vcb->BlockSize = (NT_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 2048; + } +#endif //UDF_FORMAT_MEDIA + + // Block size must be an even multiple of 512 + switch (Vcb->BlockSize) { + case 2048: Vcb->BlockSizeBits = 11; break; +#ifdef UDF_HDD_SUPPORT + case 512: Vcb->BlockSizeBits = 9; break; + case 1024: Vcb->BlockSizeBits = 10; break; + case 4096: Vcb->BlockSizeBits = 12; break; + case 8192: Vcb->BlockSizeBits = 13; break; +#endif //UDF_HDD_SUPPORT + default: + { + UserPrint(("UDF: Bad block size (%ld)\n", Vcb->BlockSize)); + try_return(RC = STATUS_UNSUCCESSFUL); + } + } + +#ifdef UDF_HDD_SUPPORT + if( +#ifdef _BROWSE_UDF_ + (!fms && (UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK)) + || +#endif //_BROWSE_UDF_ +#ifdef UDF_FORMAT_MEDIA + (fms && fms->opt_media == MT_HD) + || +#endif //UDF_FORMAT_MEDIA + FALSE ) { + +#ifdef UDF_FORMAT_MEDIA + if(fms && !NT_SUCCESS(RC)) + try_return(STATUS_UNSUCCESSFUL); +#endif //UDF_FORMAT_MEDIA + + Vcb->FirstLBA=0;//(ULONG)(PartitionInfo->StartingOffset.QuadPart >> Vcb->BlockSizeBits); + Vcb->LastPossibleLBA = + Vcb->LastLBA = (uint32)(PartitionInfo->PartitionLength.QuadPart >> Vcb->BlockSizeBits)/* + Vcb->FirstLBA*/ - 1; + } else { +#endif //UDF_HDD_SUPPORT + Vcb->FirstLBA=0; + if(OS_SUCCESS(RC)) { + Vcb->LastLBA = (uint32)(DiskGeometry->Cylinders.QuadPart * + DiskGeometry->TracksPerCylinder * + DiskGeometry->SectorsPerTrack - 1); + if(Vcb->LastLBA == 0x7fffffff) { + Vcb->LastLBA = UDFIsDvdMedia(Vcb) ? DEFAULT_LAST_LBA_DVD : DEFAULT_LAST_LBA_FP_CD; + } + } else { + Vcb->LastLBA = UDFIsDvdMedia(Vcb) ? DEFAULT_LAST_LBA_DVD : DEFAULT_LAST_LBA_FP_CD; + } + Vcb->LastPossibleLBA = Vcb->LastLBA; +#ifdef UDF_HDD_SUPPORT + } +#endif //UDF_HDD_SUPPORT + +#ifdef _BROWSE_UDF_ +// if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) { + Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize; +// } else { +// Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize; +// } +#else //_BROWSE_UDF_ + if(fms->opt_media == MT_HD) { + Vcb->WriteBlockSize = Vcb->BlockSize; + } else { + Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize; + } +#endif //_BROWSE_UDF_ + + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + KdPrint(("UDFGetBlockSize:\nBlock size is %x, Block size bits %x, Last LBA is %x\n", + Vcb->BlockSize, Vcb->BlockSizeBits, Vcb->LastLBA)); + + MyFreePool__(PartitionInfo); + MyFreePool__(DiskGeometry); + return RC; + +} // end UDFGetBlockSize() + +#ifdef _BROWSE_UDF_ + +OSSTATUS +UDFCheckTrackFPAddressing( +// IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb, // Volume control block from this DevObj + IN ULONG TrackNum + ) +{ + OSSTATUS RC = STATUS_SUCCESS; +// OSSTATUS RC2 = STATUS_UNSUCCESSFUL; + uint32 lba=0; + uint32 i; + uint8* Buffer; +// uint32 ReadBytes; + + uint8 user_data; + + ULONG FirstChunkLen = 0; + + ULONG NextChunkLen = 0; + ULONG NextChunkLenCount = 0; + + ULONG NextChunkLenOth = 0; + ULONG NextChunkLenOthCount = 0; +// ULONG MRW_Offset = 0; + + PLL_READ_USER_IN pLLR_in; + PCD_SECTOR_HEADER pHdr; +/* uint8 cMSF[3] = {0,2,0}; + uint8 cMSF1[3] = {0,2,1};*/ + + + if(!Vcb->TrackMap) { + Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM; + return STATUS_SUCCESS; + } + + Buffer = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, max(Vcb->BlockSize, + sizeof(LL_READ_USER_IN)+16), 'pNWD'); + if(!Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + pLLR_in = (PLL_READ_USER_IN)Buffer; + pHdr = (PCD_SECTOR_HEADER)(Buffer+sizeof(LL_READ_USER_IN)); + +/* if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM) { + MRW_Offset = (MRW_DMA_OFFSET/32)*39; + }*/ + + user_data = 0; + for(i=0; i<=0x200; i++) { + + RtlZeroMemory(pLLR_in, sizeof(pLLR_in)+16); + pLLR_in->ExpectedBlkType = ReadCd_BlkType_Any; + pLLR_in->LBA = i; + pLLR_in->NumOfBlocks = 1; + pLLR_in->Flags.Flags = ReadCd_Header_Hdr; +// pLLR_in->UseMFS = FALSE; // already zero +// MOV_MSF(pLLR_in->Starting_MSF, cMSF); +// MOV_MSF(pLLR_in->Ending_MSF, cMSF1); + RtlZeroMemory(pHdr, sizeof(CD_SECTOR_HEADER)); + RC = UDFPhSendIOCTL(IOCTL_CDRW_LL_READ, Vcb->TargetDeviceObject, + pLLR_in, sizeof(LL_READ_USER_IN), + pHdr, sizeof(CD_SECTOR_HEADER), + TRUE, NULL ); + +/* RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Vcb->BlockSize, + ((uint64)(i+MRW_Offset)) << Vcb->BlockSizeBits, &ReadBytes, 0);*/ + + // skip unreadable + if(!OS_SUCCESS(RC)) { + KdPrint((" Read error at lba %x\n", i)); + continue; + } + + // skip strange (damaged ?) blocks + if((pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask) != WParam_SubHdr_Mode1 && + (pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask) != WParam_SubHdr_Mode2) { + KdPrint((" Unexpected data type (%x) at lba %x\n", pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask, i)); + continue; + } + + if((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) == WParam_SubHdr_Format_UserData && + !user_data) { + lba = i; + } + +/* if(OS_SUCCESS(RC) && !OS_SUCCESS(RC2)) { + lba = i; + }*/ + + if((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) != WParam_SubHdr_Format_UserData && + user_data) { +// if(!OS_SUCCESS(RC) && OS_SUCCESS(RC2)) { + KdPrint((" %x - %x (%x sectors)\n", lba, i-1, i-lba)); + if(!FirstChunkLen) { + FirstChunkLen = i-lba; + } else { + if(!NextChunkLen) { + NextChunkLen = i-lba; + NextChunkLenCount++; + } else { + if(NextChunkLen == i-lba) { + NextChunkLenCount++; + } else { + if((NextChunkLenOth+1) % (NextChunkLen+1)) { + NextChunkLenOth = i-lba; + NextChunkLenOthCount++; + } else { + NextChunkLenCount++; + } + } + } + } + } + user_data = ((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) == WParam_SubHdr_Format_UserData); +// RC2 = RC; + } + + DbgFreePool(Buffer); + + if(!NextChunkLenCount && !NextChunkLenOthCount) { + Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM; + return STATUS_SUCCESS; + } + if(NextChunkLenOthCount > NextChunkLenCount) { + NextChunkLen = NextChunkLenOth; + } + if(NextChunkLen > PACKETSIZE_UDF+7) { + Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM; + return STATUS_SUCCESS; + } + Vcb->TrackMap[TrackNum].DataParam &= ~TrkInfo_Dat_Mask; + Vcb->TrackMap[TrackNum].DataParam |= TrkInfo_Dat_XA; + Vcb->TrackMap[TrackNum].Flags |= TrackMap_FixFPAddressing; + Vcb->TrackMap[TrackNum].PacketSize = 1; + while(NextChunkLen >> Vcb->TrackMap[TrackNum].PacketSize) { + Vcb->TrackMap[TrackNum].PacketSize++; + } + Vcb->TrackMap[TrackNum].PacketSize = 1 << (Vcb->TrackMap[TrackNum].PacketSize-1); + Vcb->TrackMap[TrackNum].TrackFPOffset = NextChunkLen - FirstChunkLen; // !!!!! + Vcb->TrackMap[TrackNum].PacketFPOffset = Vcb->TrackMap[TrackNum].TrackFPOffset;//0;//NextChunkLenOth - FirstChunkLen; + Vcb->TrackMap[TrackNum].LastLba = (Vcb->TrackMap[TrackNum].LastLba*Vcb->TrackMap[TrackNum].PacketSize) / + (Vcb->TrackMap[TrackNum].PacketSize + 7); + + return STATUS_SUCCESS; +} // end UDFCheckTrackFPAddressing() + +uint32 +UDFFixFPAddress( + IN PVCB Vcb, // Volume control block from this DevObj + IN uint32 Lba + ) +{ + uint32 i = Vcb->LastReadTrack; + uint32 pk; + uint32 rel; + +// if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM) { + if(Vcb->TrackMap[i].Flags & TrackMap_FixMRWAddressing) { + pk = Lba / MRW_DA_SIZE; + rel = Lba % MRW_DA_SIZE; + Lba = pk*MRW_DMA_SEGMENT_SIZE + rel; + Lba += MRW_DMA_OFFSET; + } + if(Vcb->TrackMap[i].Flags & TrackMap_FixFPAddressing) { + if(Lba < 0x20) + return Lba; + pk = Lba / Vcb->TrackMap[i].PacketSize; + rel = Lba % Vcb->TrackMap[i].PacketSize; + KdPrint(("FixFPAddr: %x -> %x\n", Lba, pk*(Vcb->TrackMap[i].PacketSize+7) + rel)); + return pk*(Vcb->TrackMap[i].PacketSize+7) + rel /*- Vcb->TrackMap[i].PacketFPOffset*/; + } + return Lba; +} // end UDFFixFPAddress() + +#endif //_BROWSE_UDF_ + +/* + detect device driver & try to read disk layout (use all methods) + */ +OSSTATUS +UDFGetDiskInfo( + IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb // Volume control block from this DevObj + ) +{ + OSSTATUS RC = STATUS_UNRECOGNIZED_VOLUME; + int8* ioBuf = (int8*)MyAllocatePool__(NonPagedPool,4096); + uint8 MediaType; + PLUN_WRITE_PERF_DESC_USER WPerfDesc; + uint32 i; +// BOOLEAN MRW_problem = FALSE; + uint32 SavedFeatures = 0; +#ifdef UDF_FORMAT_MEDIA + PUDFFmtState fms = Vcb->fms; +#else + #define fms FALSE +#endif //UDF_FORMAT_MEDIA + + KdPrint(("UDFGetDiskInfo\n")); + + if(!ioBuf) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + _SEH2_TRY { + RC = UDFGetBlockSize(DeviceObject, Vcb); + if(!OS_SUCCESS(RC)) try_return(RC); + + + // Get lower driver signature + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_SIGNATURE,DeviceObject, + ioBuf,sizeof(GET_SIGNATURE_USER_OUT), + ioBuf,sizeof(GET_SIGNATURE_USER_OUT), + TRUE,NULL); + + if(!OS_SUCCESS(RC)) { + + RC = UDFUseStandard(DeviceObject, Vcb); +#ifdef _BROWSE_UDF_ + if(!NT_SUCCESS(RC) || fms) + try_return(RC); + + // assume Device Recordable for now + goto GetSignatureFailed; +#endif //_BROWSE_UDF_ + } + + KdPrint(("UDF: Signature of low driver is : %s \n", + ((PGET_SIGNATURE_USER_OUT)(ioBuf))->VendorId)); + + if(!strncmp( (const char *)(&( ((PGET_SIGNATURE_USER_OUT)(ioBuf))->VendorId[0]) ), + Signature,strlen(Signature) )) { + KdPrint(("UDF: *****************************************\n")); + KdPrint(("UDF: ********* Our Device Driver Found ******\n")); + KdPrint(("UDF: *****************************************\n")); + + (Vcb->VCBFlags) |= UDF_VCB_FLAGS_OUR_DEVICE_DRIVER; +#ifndef _BROWSE_UDF_ + // reset driver +#ifdef UDF_FORMAT_MEDIA + if(!fms->opt_probe) { +#endif //UDF_FORMAT_MEDIA + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE); + // lock it + ((PPREVENT_MEDIA_REMOVAL_USER_IN)(ioBuf))->PreventMediaRemoval = TRUE; + UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + DeviceObject, + ioBuf,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE, NULL); +#ifdef UDF_FORMAT_MEDIA + } +#endif //UDF_FORMAT_MEDIA +#endif //_BROWSE_UDF_ +//#else //_BROWSE_UDF_ + // get device features + UDFPhSendIOCTL( IOCTL_CDRW_GET_DEVICE_INFO, + DeviceObject, + NULL,0, + ioBuf,sizeof(GET_DEVICE_INFO_USER_OUT), + FALSE,NULL); + + Vcb->SavedFeatures = + SavedFeatures = ((PGET_DEVICE_INFO_USER_OUT)ioBuf)->Features; + if(!(SavedFeatures & CDRW_FEATURE_SYNC_ON_WRITE)) { + KdPrint(("UDFGetDiskInfo: UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE\n")); + Vcb->CompatFlags |= UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE; + } + if(!(SavedFeatures & CDRW_FEATURE_FORCE_SYNC_BEFORE_READ)) { + KdPrint(("UDFGetDiskInfo: UDF_VCB_IC_SYNCCACHE_BEFORE_READ\n")); + Vcb->CompatFlags |= UDF_VCB_IC_SYNCCACHE_BEFORE_READ; + } + if(SavedFeatures & CDRW_FEATURE_BAD_RW_SEEK) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_BAD_RW_SEEK\n")); + Vcb->CompatFlags |= UDF_VCB_IC_BAD_RW_SEEK; + } + // we must check if this is FP-formatted disk in old devices + // independently of MediaType they report + if(SavedFeatures & CDRW_FEATURE_FP_ADDRESSING_PROBLEM) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_FP_ADDRESSING_PROBLEM ?\n")); + Vcb->CompatFlags |= UDF_VCB_IC_FP_ADDR_PROBLEM; + } + if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM ?\n")); + } + if(SavedFeatures & CDRW_FEATURE_FORCE_SYNC_ON_WRITE) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_FORCE_SYNC_ON_WRITE\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_FORCE_SYNC_CACHE; + } + if(SavedFeatures & CDRW_FEATURE_BAD_DVD_LAST_LBA) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_BAD_DVD_LAST_LBA\n")); + Vcb->CompatFlags |= UDF_VCB_IC_BAD_DVD_LAST_LBA; + } + if(SavedFeatures & CDRW_FEATURE_STREAMING) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_STREAMING\n")); + } + if(SavedFeatures & CDRW_FEATURE_OPC) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_OPC -> assume OPCNum=1\n")); + Vcb->OPCNum = 1; + } +#ifdef UDF_FORMAT_MEDIA + if(SavedFeatures & CDRW_FEATURE_FULL_BLANK_ON_FORMAT) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_FULL_BLANK_ON_FORMAT\n")); + if((fms->opt_probe || fms->opt_smart_f)/* && + (fms->format_media && fms->blank_media*/) { + KdPrint(("UDFGetDiskInfo: force Full Erase\n")); + fms->opt_qblank = FALSE; + } + } +#endif //UDF_FORMAT_MEDIA +#ifdef _BROWSE_UDF_ + // get device buffer size + RC = UDFPhSendIOCTL( IOCTL_CDRW_BUFFER_CAPACITY, + DeviceObject, + NULL,0, + ioBuf,sizeof(BUFFER_CAPACITY_BLOCK_USER_OUT), + FALSE,NULL); + if(NT_SUCCESS(RC)) { + Vcb->CdrwBufferSize = ((PBUFFER_CAPACITY_BLOCK_USER_OUT)ioBuf)->BufferLength; + } else { + Vcb->CdrwBufferSize = 0; + } + KdPrint(("UDFGetDiskInfo: CdrwBufferSize = %dKb\n", Vcb->CdrwBufferSize / 1024)); + Vcb->CdrwBufferSizeCounter = 0; +#endif //_BROWSE_UDF_ + // get media type + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MEDIA_TYPE,DeviceObject, + NULL,0,ioBuf,sizeof(GET_MEDIA_TYPE_USER_OUT), + FALSE, NULL); + if(!OS_SUCCESS(RC)) goto Try_FullToc; + Vcb->MediaType = + MediaType = ((PGET_MEDIA_TYPE_USER_OUT)ioBuf)->MediaType; + KdPrint(("UDFGetDiskInfo: MediaType %x\n", MediaType)); + +#ifndef UDF_FORMAT_MEDIA + // we shall ignore audio-disks + switch(MediaType) { + case MediaType_120mm_CDROM_AudioOnly: + case MediaType_80mm_CDROM_AudioOnly: + case MediaType_120mm_CDR_AudioOnly: + case MediaType_80mm_CDR_AudioOnly: + case MediaType_120mm_CDRW_AudioOnly: + case MediaType_80mm_CDRW_AudioOnly: +// case : + KdPrint(("UDFGetDiskInfo: we shall ignore audio-disks...\n")); + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + } +#endif //UDF_FORMAT_MEDIA + + KdPrint(("UDFGetDiskInfo: Check DVD-disks...\n")); + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MEDIA_TYPE_EX,DeviceObject, + NULL,0,ioBuf,sizeof(GET_MEDIA_TYPE_EX_USER_OUT), + FALSE, NULL); + if(!OS_SUCCESS(RC)) goto Try_FullToc; + Vcb->MediaClassEx = + MediaType = (((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->MediaClass); + KdPrint(("UDFGetDiskInfo: MediaClassEx %x\n", MediaType)); + +#ifdef _BROWSE_UDF_ + if(!fms) { + + switch(MediaType) { + + case CdMediaClass_CDR: + case CdMediaClass_DVDR: + case CdMediaClass_DVDpR: + case CdMediaClass_HD_DVDR: + case CdMediaClass_BDR: + KdPrint(("UDFGetDiskInfo: MediaClass R\n")); + Vcb->MediaType = MediaType_UnknownSize_CDR; + break; + case CdMediaClass_CDRW: + + if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on CD-RW\n")); + Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM; + } + + case CdMediaClass_DVDRW: + case CdMediaClass_DVDpRW: + case CdMediaClass_DVDRAM: + case CdMediaClass_HD_DVDRW: + case CdMediaClass_HD_DVDRAM: + case CdMediaClass_BDRE: + KdPrint(("UDFGetDiskInfo: MediaClass RW\n")); + Vcb->MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_CDROM: + case CdMediaClass_DVDROM: + case CdMediaClass_HD_DVDROM: + case CdMediaClass_BDROM: + KdPrint(("UDFGetDiskInfo: MediaClass ROM\n")); + Vcb->MediaType = MediaType_Unknown; + // Vcb->MediaType = MediaType_UnknownSize_CDROM; + break; + default: + KdPrint(("UDFGetDiskInfo: MediaClass Unknown\n")); + Vcb->MediaType = MediaType_Unknown; + break; + } + MediaType = Vcb->MediaType; + + } +#endif //_BROWSE_UDF_ + +#ifdef UDF_FORMAT_MEDIA + + if(fms) { + + switch(MediaType) { + case CdMediaClass_CDR: + KdPrint(("CdMediaClass_CDR\n")); + MediaType = MediaType_UnknownSize_CDR; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_CDR; + break; + case CdMediaClass_DVDR: + KdPrint(("CdMediaClass_DVDR -> MediaType_UnknownSize_CDR\n")); + MediaType = MediaType_UnknownSize_CDR; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDR; + break; + case CdMediaClass_DVDpR: + KdPrint(("CdMediaClass_DVDpR -> MediaType_UnknownSize_CDR\n")); + MediaType = MediaType_UnknownSize_CDR; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDpR; + break; + case CdMediaClass_HD_DVDR: + KdPrint(("CdMediaClass_HD_DVDR -> MediaType_UnknownSize_CDR\n")); + MediaType = MediaType_UnknownSize_CDR; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDR; + break; + case CdMediaClass_BDR: + KdPrint(("CdMediaClass_BDR -> MediaType_UnknownSize_CDR\n")); + MediaType = MediaType_UnknownSize_CDR; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDR; + break; + case CdMediaClass_CDRW: + KdPrint(("CdMediaClass_CDRW\n")); + MediaType = MediaType_UnknownSize_CDRW; + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_CDRW; + if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on CD-RW\n")); + Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM; + } + break; + case CdMediaClass_DVDRW: + KdPrint((" CdMediaClass_DVDRW -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDRW; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_DVDpRW: + KdPrint((" CdMediaClass_DVDpRW -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDpRW; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_DVDRAM: + KdPrint((" CdMediaClass_DVDRAM -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDRAM; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_HD_DVDRW: + KdPrint((" CdMediaClass_HD_DVDRW -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDRW; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_HD_DVDRAM: + KdPrint((" CdMediaClass_HD_DVDRAM -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDRAM; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_BDRE: + KdPrint((" CdMediaClass_BDRE -> MediaType_UnknownSize_CDRW\n")); + if(fms->opt_media == MT_AUTO) + fms->opt_media = MT_DVDRW; + MediaType = MediaType_UnknownSize_CDRW; + break; + case CdMediaClass_NoDiscPresent: + KdPrint((" CdMediaClass_NoDiscPresent -> MediaType_NoDiscPresent\n")); + MediaType = MediaType_NoDiscPresent; + fms->opt_media = MT_none; + break; + case CdMediaClass_DoorOpen: + KdPrint((" CdMediaClass_DoorOpen -> MediaType_DoorOpen\n")); + MediaType = MediaType_DoorOpen; + fms->opt_media = MT_none; + break; + default: + KdPrint((" MediaType_Unknown\n")); + MediaType = MediaType_Unknown; + break; + } + if(!apply_force_r(fms)) { + my_exit(fms, MKUDF_CANT_APPLY_R); + } + } + +#endif //UDF_FORMAT_MEDIA + + Vcb->DVD_Mode = (((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->MediaClassEx == CdMediaClassEx_DVD); + Vcb->PhMediaCapFlags = ((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->CapFlags; + Vcb->WriteParamsReq = (Vcb->PhMediaCapFlags & CdCapFlags_WriteParamsReq) ? TRUE : FALSE; + if(Vcb->DVD_Mode && + !(Vcb->PhMediaCapFlags & CdCapFlags_RandomWritable)) { + KdPrint(("UDFGetDiskInfo: DVD && !CdCapFlags_RandomWritable\n")); + KdPrint((" Read-only volume\n")); +// BrutePoint(); +#ifndef UDF_CDRW_EMULATION_ON_ROM + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; +#endif + } +#ifdef UDF_FORMAT_MEDIA + if(fms) { + if((MediaType == MediaType_NoDiscPresent) || + (MediaType == MediaType_DoorOpen)) { + UserPrint(("No media in device\n")); + my_exit(fms, MKUDF_NO_MEDIA_IN_DEVICE); + } + } +#endif //UDF_FORMAT_MEDIA + if(!Vcb->WriteParamsReq) { + KdPrint(("UDFGetDiskInfo: do not use WriteParams\n")); + } + if(Vcb->PhMediaCapFlags & CdCapFlags_Cav) { + KdPrint(("UDFGetDiskInfo: Use CAV (1)\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_CAV; + } + +#ifdef _BROWSE_UDF_ + if(!fms) { + // check if this device is capable to write on such media + if(UDFIsDvdMedia(Vcb)) { + //RC = + KdPrint(("UDFGetDiskInfo: update defaulted LastLBA\n")); + UDFGetBlockSize(DeviceObject,Vcb); + //if(!OS_SUCCESS(RC)) goto Try_FullToc; + } else { + if((SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) && + (SavedFeatures & UDF_VCB_IC_FP_ADDR_PROBLEM)) { + KdPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on old CD-ROM\n")); + Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM; + } + } + } +#endif //_BROWSE_UDF_ + +/*#ifdef UDF_FORMAT_MEDIA + if(fms) { + if(MediaType == CdMediaClass_DVDRW) { + UserPrint(("Not empty media. Erase required.\n")); + my_exit(fms, MKUDF_BLANK_FORMAT_REQUIRED); + } + } +#endif //UDF_FORMAT_MEDIA*/ + +#define cap ((PGET_CAPABILITIES_3_USER_OUT)ioBuf) + // get device capabilities + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_CAPABILITIES,DeviceObject, + NULL,0,ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT), + FALSE, NULL); + if(!OS_SUCCESS(RC)) goto Try_FullToc; + + // check if this device is capable to write on such media + RC = UDFPhSendIOCTL(IOCTL_DISK_IS_WRITABLE,DeviceObject, + NULL,0,NULL,0,FALSE, NULL); + if(RC != STATUS_SUCCESS) { + KdPrint(("IS_WRITABLE - false, doing additional check...\n")); + if( ((MediaType >= MediaType_UnknownSize_CDRW) && !(cap->WriteCap & DevCap_write_cd_rw)) || + ((MediaType >= MediaType_UnknownSize_CDR) && !(cap->WriteCap & DevCap_write_cd_r)) || + (MediaType < MediaType_UnknownSize_CDR) ) { + UserPrint(("Hardware Read-only volume\n")); +#ifndef UDF_CDRW_EMULATION_ON_ROM + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; +#endif //UDF_CDRW_EMULATION_ON_ROM +#ifdef UDF_FORMAT_MEDIA + if(fms && !fms->opt_read_iso) + my_exit(fms, MKUDF_HW_READ_ONLY); +#endif //UDF_FORMAT_MEDIA + } + } else { + KdPrint(("Writable disk\n")); + } + Vcb->MaxWriteSpeed = cap->MaximumWriteSpeedSupported; + Vcb->MaxReadSpeed = cap->MaximumSpeedSupported; + if(cap->PageLength >= (sizeof(GET_CAPABILITIES_3_USER_OUT)-2)) { + Vcb->CurSpeed = max(cap->CurrentSpeed, cap->CurrentWriteSpeed3); + if(cap->LunWPerfDescriptorCount && cap->LunWPerfDescriptorCount != 0xffff) { + ULONG n; + KdPrint(("Write performance descriptor(s) found: %x\n", cap->LunWPerfDescriptorCount)); + n = (4096 - sizeof(GET_CAPABILITIES_3_USER_OUT)) / sizeof(LUN_WRITE_PERF_DESC_USER); + n = min(n, cap->LunWPerfDescriptorCount); + // get device capabilities + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_CAPABILITIES,DeviceObject, + ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT)+n*sizeof(LUN_WRITE_PERF_DESC_USER), + ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT)+n*sizeof(LUN_WRITE_PERF_DESC_USER), + TRUE,NULL); + if(OS_SUCCESS(RC)) { + WPerfDesc = (PLUN_WRITE_PERF_DESC_USER)(ioBuf + sizeof(GET_CAPABILITIES_3_USER_OUT)); + n = FALSE; + for(i = 0; iVCBFlags |= UDF_VCB_FLAGS_USE_CAV; + if(!n) { + Vcb->CurSpeed = WPerfDesc[i].WriteSpeedSupported; + n = TRUE; + KdPrint(("Use CAV\n")); + } else { + Vcb->CurSpeed = max(WPerfDesc[i].WriteSpeedSupported, Vcb->CurSpeed); + } + KdPrint(("supports speed %dX\n", Vcb->CurSpeed/176)); + //break; + } + } + if(n) { + KdPrint(("Set r/w speeds to %dX\n", Vcb->CurSpeed/176)); + Vcb->MaxWriteSpeed = + Vcb->MaxReadSpeed = Vcb->CurSpeed; + } + } + } + } else { + Vcb->CurSpeed = max(cap->CurrentSpeed, cap->CurrentWriteSpeed); + } + KdPrint((" Speeds r/w %dX/%dX\n", Vcb->CurSpeed/176, cap->CurrentWriteSpeed/176)); + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) { + // limit both read & write speed to last write speed for CAV mode + // some drives damage data when speed is adjusted during recording process + // even in packet mode + UDFSetSpeeds(Vcb); + } + UDFSetCaching(Vcb); + +#undef cap +#ifdef UDF_FORMAT_MEDIA + if(fms) { + if( (fms->auto_media || (fms->opt_media == MT_AUTO)) && + (fms->opt_media < MT_DVDR) ) { + if(MediaType < MediaType_UnknownSize_CDRW) { + fms->opt_media = MT_CDR; + } else { + fms->opt_media = MT_CDRW; + } + } + if(!apply_force_r(fms)) { + my_exit(fms, MKUDF_CANT_APPLY_R); + } + } +#endif //UDF_FORMAT_MEDIA + RC = UDFReadDiscTrackInfo(DeviceObject, Vcb); + + if(!OS_SUCCESS(RC)) { + // may be we have a CD-ROM device +Try_FullToc: + KdPrint(("Hardware Read-only volume (2)\n")); +// BrutePoint(); +#ifndef UDF_CDRW_EMULATION_ON_ROM + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; +#endif + + RC = UDFReadAndProcessFullToc(DeviceObject, Vcb); + + if(!OS_SUCCESS(RC)) { + RC = UDFUseStandard(DeviceObject,Vcb); + if(!OS_SUCCESS(RC)) try_return(RC); + } + + } + } else { +#ifdef _BROWSE_UDF_ +GetSignatureFailed: +#endif + RC = UDFUseStandard(DeviceObject, Vcb); + if(!OS_SUCCESS(RC)) try_return(RC); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(ioBuf) MyFreePool__(ioBuf); + + if(UDFIsDvdMedia(Vcb) && + (Vcb->CompatFlags & UDF_VCB_IC_BAD_DVD_LAST_LBA) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + Vcb->LastLBA && + (Vcb->LastLBA < DEFAULT_LAST_LBA_DVD)) { + KdPrint(("UDF: Bad DVD last LBA %x, fixup!\n", Vcb->LastLBA)); + Vcb->LastLBA = DEFAULT_LAST_LBA_DVD; + Vcb->NWA = 0; + } + + + if(UDFIsDvdMedia(Vcb) && !Vcb->FirstLBA && !Vcb->LastPossibleLBA) { + KdPrint(("UDF: Empty DVD. Use bogus values for now\n")); + Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD; + Vcb->LastLBA = 0; + } + + if((Vcb->LastPossibleLBA & 0x80000000) || (Vcb->LastPossibleLBA < Vcb->LastLBA)) { + KdPrint(("UDF: bad LastPossibleLBA %x -> %x\n", Vcb->LastPossibleLBA, Vcb->LastLBA)); + Vcb->LastPossibleLBA = Vcb->LastLBA; + } + if(!Vcb->WriteBlockSize) + Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize; + +#ifdef _BROWSE_UDF_ + if(Vcb->TrackMap) { + if(Vcb->TrackMap[Vcb->LastTrackNum].LastLba > Vcb->NWA) { + if(Vcb->NWA) { + if(Vcb->TrackMap[Vcb->LastTrackNum].DataParam & TrkInfo_FP) { + Vcb->LastLBA = Vcb->NWA-1; + } else { + Vcb->LastLBA = Vcb->NWA-7-1; + } + } + } else { + if((Vcb->LastTrackNum > 1) && + (Vcb->TrackMap[Vcb->LastTrackNum-1].FirstLba >= Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) { + Vcb->LastLBA = Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba; + } + } + } + + for(i=0; i<32; i++) { + if(!(Vcb->LastPossibleLBA >> i)) + break; + } + if(i > 20) { + Vcb->WCacheBlocksPerFrameSh = max(Vcb->WCacheBlocksPerFrameSh, (2*i)/5+2); + Vcb->WCacheBlocksPerFrameSh = min(Vcb->WCacheBlocksPerFrameSh, 16); + } + + if(Vcb->CompatFlags & UDF_VCB_IC_FP_ADDR_PROBLEM) { + // Check first 0x200 blocks + UDFCheckTrackFPAddressing(Vcb, Vcb->FirstTrackNum); + // if we really have such a problem, fix LastLBA + if(Vcb->CompatFlags & UDF_VCB_IC_FP_ADDR_PROBLEM) { + KdPrint(("UDF: Fix LastLBA: %x -> %x\n", Vcb->LastLBA, (Vcb->LastLBA*32) / 39)); + Vcb->LastLBA = (Vcb->LastLBA*32) / 39; + } + } +#endif //_BROWSE_UDF_ + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) { + if(!Vcb->BlankCD && Vcb->MediaType != MediaType_UnknownSize_CDRW) { + KdPrint(("UDFGetDiskInfo: R/O+!Blank+!RW -> !RAW\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + } else { + KdPrint(("UDFGetDiskInfo: Blank or RW\n")); + } + } + + KdPrint(("UDF: ------------------------------------------\n")); + KdPrint(("UDF: Media characteristics\n")); + KdPrint(("UDF: Last session: %d\n",Vcb->LastSession)); + KdPrint(("UDF: First track in first session: %d\n",Vcb->FirstTrackNum)); + KdPrint(("UDF: First track in last session: %d\n",Vcb->FirstTrackNumLastSes)); + KdPrint(("UDF: Last track in last session: %d\n",Vcb->LastTrackNum)); + KdPrint(("UDF: First LBA in first session: %x\n",Vcb->FirstLBA)); + KdPrint(("UDF: First LBA in last session: %x\n",Vcb->FirstLBALastSes)); + KdPrint(("UDF: Last LBA in last session: %x\n",Vcb->LastLBA)); + KdPrint(("UDF: First writable LBA (NWA) in last session: %x\n",Vcb->NWA)); + KdPrint(("UDF: Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA)); + KdPrint(("UDF: blocks per frame: %x\n",1 << Vcb->WCacheBlocksPerFrameSh)); + KdPrint(("UDF: Flags: %s%s\n", + Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK ? "RAW " : "", + Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY ? "R/O " : "WR " + )); + KdPrint(("UDF: ------------------------------------------\n")); + +#ifdef UDF_FORMAT_MEDIA + if(fms && fms->opt_disk_info) { + UserPrint(("------------------------------------------\n")); + UserPrint(("Media characteristics:\n")); + UserPrint((" First writable LBA (NWA) in last session: %x\n",Vcb->NWA)); + UserPrint((" Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA)); + UserPrint(("------------------------------------------\n")); + } +#endif //UDF_FORMAT_MEDIA + + } _SEH2_END; + + KdPrint(("UDFGetDiskInfo: %x\n", RC)); + return(RC); + +} // end UDFGetDiskInfo() + +//#ifdef _BROWSE_UDF_ + +OSSTATUS +UDFPrepareForReadOperation( + IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BCount + ) +{ + if( (Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) ) { + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + return STATUS_SUCCESS; + } + uint32 i = Vcb->LastReadTrack; + BOOLEAN speed_changed = FALSE; +#ifdef _BROWSE_UDF_ + PUCHAR tmp; + OSSTATUS RC; + ULONG ReadBytes; +#endif //_BROWSE_UDF_ + +#ifdef _UDF_STRUCTURES_H_ + if(Vcb->BSBM_Bitmap) { + ULONG i; + for(i=0; iBSBM_Bitmap), Lba+i)) { + KdPrint(("R: Known BB @ %#x\n", Lba)); + //return STATUS_FT_WRITE_RECOVERY; // this shall not be treated as error and + // we shall get IO request to BAD block + return STATUS_DEVICE_DATA_ERROR; + } + } + } +#endif //_UDF_STRUCTURES_H_ + + if(!UDFIsDvdMedia(Vcb) && + (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) && + !(Vcb->CompatFlags & UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE)){ + + OSSTATUS RC; + + RC = UDFSyncCache(Vcb); + } + if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) && +#ifndef UDF_FORMAT_MEDIA + (Vcb->CompatFlags & UDF_VCB_IC_SYNCCACHE_BEFORE_READ) && +#endif //UDF_FORMAT_MEDIA + TRUE) + { + OSSTATUS RC; + RC = UDFSyncCache(Vcb); + } + +#ifdef _BROWSE_UDF_ + if(!UDFIsDvdMedia(Vcb)) { + // limit read speed after write operation + // to avoid performance degrade durring speed-up/down + // on read/write mode switching + if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) { + // limit both read & write speed to last write speed for CAV mode + // some drives damage data when speed is adjusted during recording process + // even in packet mode + if(Vcb->CurSpeed != Vcb->MaxWriteSpeed || + Vcb->CurSpeed != Vcb->MaxReadSpeed) { + Vcb->CurSpeed = Vcb->MaxWriteSpeed; + speed_changed = TRUE; + } + } else + if(Vcb->VCBFlags & UDF_VCB_LAST_WRITE) { + // limit read speed to last write speed + if(Vcb->CurSpeed > Vcb->MaxWriteSpeed) { + Vcb->CurSpeed = Vcb->MaxWriteSpeed; + speed_changed = TRUE; + } + } else + if(Vcb->CurSpeed < Vcb->MaxReadSpeed ) { + // increment read speed (+1X) + Vcb->CurSpeed += 176/1; + speed_changed = TRUE; + } + + if(Vcb->CurSpeed > Vcb->MaxReadSpeed) { + Vcb->CurSpeed = Vcb->MaxReadSpeed; + } + // send speed limits to drive + if(speed_changed) { + RtlZeroMemory(&(Vcb->SpeedBuf), sizeof(SET_CD_SPEED_EX_USER_IN)); + Vcb->SpeedBuf.ReadSpeed = Vcb->CurSpeed; + Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed; + if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) { + Vcb->SpeedBuf.RotCtrl = CdSpeed_RotCtrl_CAV; + } + KdPrint((" UDFPrepareForReadOperation: set speed to %s %dX/%dX\n", + (Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) ? "CAV" : "CLV", + Vcb->SpeedBuf.ReadSpeed, + Vcb->SpeedBuf.WriteSpeed)); + UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED, + Vcb->TargetDeviceObject, + &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_EX_USER_IN), + NULL,0,TRUE,NULL); + } + } + + if(UDFIsDvdMedia(Vcb)) + return STATUS_SUCCESS; + + if(Vcb->LastReadTrack && + ((Vcb->TrackMap[i].FirstLba <= Lba) || (Vcb->TrackMap[i].FirstLba & 0x80000000)) && + (Vcb->TrackMap[i].LastLba >= Lba)) { +check_for_data_track: + // check track mode (Mode1/XA) + switch((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask)) { + case TrkInfo_Dat_Mode1: // Mode1 + case TrkInfo_Dat_XA: // XA Mode2 + case TrkInfo_Dat_Unknown: // for some stupid irons + UDFSetMRWMode(Vcb); + break; + default: + Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE; + return STATUS_INVALID_PARAMETER; + } + } else { + for(i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) { + if(((Vcb->TrackMap[i].FirstLba > Lba) && !(Vcb->TrackMap[i].FirstLba & 0x80000000)) || + (Vcb->TrackMap[i].LastLba < Lba)) + continue; + Vcb->LastReadTrack = i; + goto check_for_data_track; + } + Vcb->LastReadTrack = 0; + } + if(Vcb->IncrementalSeekState != INCREMENTAL_SEEK_WORKAROUND) { + Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE; + return STATUS_SUCCESS; + } + KdPrint((" UDFPrepareForReadOperation: seek workaround...\n")); + Vcb->IncrementalSeekState = INCREMENTAL_SEEK_DONE; + + tmp = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Vcb->BlockSize, 'bNWD'); + if(!tmp) { + Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE; + return STATUS_INSUFFICIENT_RESOURCES; + } + for(i=0x1000; i<=Lba; i+=0x1000) { + RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, tmp, Vcb->BlockSize, + ((uint64)UDFFixFPAddress(Vcb,i)) << Vcb->BlockSizeBits, &ReadBytes, 0); + KdPrint((" seek workaround, LBA %x, status %x\n", i, RC)); + } + DbgFreePool(tmp); +#endif //_BROWSE_UDF_ + + return STATUS_SUCCESS; +} // end UDFPrepareForReadOperation() + +//#endif //_BROWSE_UDF_ + +void +UDFUpdateNWA( + PVCB Vcb, + uint32 LBA, // physical + uint32 BCount, + OSSTATUS RC + ) +{ +#ifndef UDF_READ_ONLY_BUILD +#ifdef _BROWSE_UDF_ + if(!OS_SUCCESS(RC)) { + return; + } + if(!Vcb->CDR_Mode) { + + if((Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDpRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM || + Vcb->MRWStatus == DiscInfo_BGF_Interrupted || + Vcb->MRWStatus == DiscInfo_BGF_InProgress) + && (LBA+BCount-1) > Vcb->LastLBA) { + ASSERT(Vcb->NWA > Vcb->LastLBA); + Vcb->NWA = LBA+BCount; + Vcb->LastLBA = Vcb->NWA-1; + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_FORCE_SYNC_CACHE) + goto sync_cache; +/* if(Vcb->CdrwBufferSize) { + Vcb->CdrwBufferSizeCounter += BCount * 2048; + if(Vcb->CdrwBufferSizeCounter >= Vcb->CdrwBufferSize + 2*2048) { + KdPrint((" UDFUpdateNWA: buffer is full, sync...\n")); + Vcb->CdrwBufferSizeCounter = 0; + goto sync_cache; + } + }*/ + if(Vcb->SyncCacheState == SYNC_CACHE_RECOVERY_RETRY) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_FORCE_SYNC_CACHE; + } + Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_NONE; + return; + } + if(Vcb->LastLBA < (LBA+BCount)) + Vcb->LastLBA = LBA+BCount; + if(Vcb->NWA) + Vcb->NWA+=BCount+7; +sync_cache: + if(!(Vcb->CompatFlags & UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE)) { + KdPrint((" UDFUpdateNWA: syncing...\n")); + RC = UDFSyncCache(Vcb); + } +#endif //_BROWSE_UDF_ +#endif //UDF_READ_ONLY_BUILD +} // end UDFUpdateNWA() + + +/* + This routine reads physical sectors + */ +/*OSSTATUS +UDFReadSectors( + IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN uint32 Lba, + IN uint32 BCount, + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + + if(Vcb->FastCache.ReadProc && (KeGetCurrentIrql() < DISPATCH_LEVEL)) { + return WCacheReadBlocks__(&(Vcb->FastCache), Vcb, Buffer, Lba, BCount, ReadBytes); + } + return UDFTRead(Vcb, Buffer, BCount*Vcb->BlockSize, Lba, ReadBytes); +} // end UDFReadSectors()*/ + +#ifdef _BROWSE_UDF_ + +/* + This routine reads physical sectors + */ +OSSTATUS +UDFReadInSector( + IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN uint32 Lba, + IN uint32 i, // offset in sector + IN uint32 l, // transfer length + IN BOOLEAN Direct, // Disable access to non-cached data + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + int8* tmp_buff; + OSSTATUS status; + uint32 _ReadBytes; + + (*ReadBytes) = 0; + if(WCacheIsInitialized__(&(Vcb->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) { + status = WCacheDirect__(&(Vcb->FastCache), Vcb, Lba, FALSE, &tmp_buff, Direct); + if(OS_SUCCESS(status)) { + (*ReadBytes) += l; + RtlCopyMemory(Buffer, tmp_buff+i, l); + } + if(!Direct) WCacheEODirect__(&(Vcb->FastCache), Vcb); + } else { + if(Direct) { + return STATUS_INVALID_PARAMETER; + } + tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, Vcb->BlockSize); + if(!tmp_buff) return STATUS_INSUFFICIENT_RESOURCES; + status = UDFReadSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &_ReadBytes); + if(OS_SUCCESS(status)) { + (*ReadBytes) += l; + RtlCopyMemory(Buffer, tmp_buff+i, l); + } + MyFreePool__(tmp_buff); + } + return status; +} // end UDFReadInSector() + +/* + This routine reads data of unaligned offset & length + */ +OSSTATUS +UDFReadData( + IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN int64 Offset, + IN uint32 Length, + IN BOOLEAN Direct, // Disable access to non-cached data + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + uint32 i, l, Lba, BS=Vcb->BlockSize; + uint32 BSh=Vcb->BlockSizeBits; + OSSTATUS status; + uint32 _ReadBytes = 0; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + uint32 to_read; + + (*ReadBytes) = 0; + if(!Length) return STATUS_SUCCESS; + if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) + return STATUS_NO_SUCH_DEVICE; + // read tail of the 1st sector if Offset is not sector_size-aligned + Lba = (uint32)(Offset >> BSh); + if(i = (uint32)(Offset & (BS-1))) { + l = (BS - i) < Length ? + (BS - i) : Length; + // here we use 'ReadBytes' 'cause now it's set to zero + status = UDFReadInSector(Vcb, Translate, Lba, i, l, Direct, Buffer, ReadBytes); + if(!OS_SUCCESS(status)) return status; + if(!(Length = Length - l)) return STATUS_SUCCESS; + Lba ++; + Buffer += l; + } + // read sector_size-aligned part + i = Length >> BSh; + while(i) { + to_read = min(i, 64); + status = UDFReadSectors(Vcb, Translate, Lba, to_read, Direct, Buffer, &_ReadBytes); + (*ReadBytes) += _ReadBytes; + if(!OS_SUCCESS(status)) { + return status; + } + Buffer += to_read<Modified || (Vcb->IntegrityType == INTEGRITY_TYPE_CLOSE)) { + UDFSetModified(Vcb); + if(Vcb->LVid && !Direct) { + status = UDFUpdateLogicalVolInt(Vcb,FALSE); + } + } + + if(Vcb->CDR_Mode) { + if(Vcb->LastLBA < Lba+BCount-1) + Vcb->LastLBA = Lba+BCount-1; + } +#endif //_BROWSE_UDF_ + + if(Vcb->FastCache.WriteProc && (KeGetCurrentIrql() < DISPATCH_LEVEL)) { + status = WCacheWriteBlocks__(&(Vcb->FastCache), Vcb, Buffer, Lba, BCount, WrittenBytes, Direct); + ASSERT(OS_SUCCESS(status)); +#ifdef _BROWSE_UDF_ + UDFClrZeroBits(Vcb->ZSBM_Bitmap, Lba, BCount); +#endif //_BROWSE_UDF_ + return status; + } +/* void* buffer; + OSSTATUS status; + uint32 _ReadBytes; + (*WrittenBytes) = 0; + buffer = DbgAllocatePool(NonPagedPool, Vcb->WriteBlockSize); + if(!buffer) return STATUS_INSUFFICIENT_RESOURCES; + status = UDFTRead(Vcb, Buffer, BCount<BlockSizeBits, (Lba&~(Vcb->WriteBlockSize-1), _WrittenBytes);*/ +#ifdef UDF_DBG + status = UDFTWrite(Vcb, Buffer, BCount<BlockSizeBits, Lba, WrittenBytes); + ASSERT(OS_SUCCESS(status)); + return status; +#else // UDF_DBG + return UDFTWrite(Vcb, Buffer, BCount<BlockSizeBits, Lba, WrittenBytes); +#endif // UDF_DBG +} // end UDFWriteSectors() + +OSSTATUS +UDFWriteInSector( + IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN uint32 Lba, + IN uint32 i, // offset in sector + IN uint32 l, // transfer length + IN BOOLEAN Direct, // Disable access to non-cached data + OUT int8* Buffer, + OUT uint32* WrittenBytes + ) +{ + int8* tmp_buff; + OSSTATUS status; +#ifdef _BROWSE_UDF_ + uint32 _WrittenBytes; + uint32 ReadBytes; + + if(!Vcb->Modified) { + UDFSetModified(Vcb); + if(Vcb->LVid) + status = UDFUpdateLogicalVolInt(Vcb,FALSE); + } + + if(Vcb->CDR_Mode) { + if(Vcb->LastLBA < Lba) + Vcb->LastLBA = Lba; + } +#endif //_BROWSE_UDF_ + + (*WrittenBytes) = 0; +#ifdef _BROWSE_UDF_ + if(WCacheIsInitialized__(&(Vcb->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) { +#endif //_BROWSE_UDF_ + status = WCacheDirect__(&(Vcb->FastCache), Vcb, Lba, TRUE, &tmp_buff, Direct); + if(OS_SUCCESS(status)) { +#ifdef _BROWSE_UDF_ + UDFClrZeroBit(Vcb->ZSBM_Bitmap, Lba); +#endif //_BROWSE_UDF_ + (*WrittenBytes) += l; + RtlCopyMemory(tmp_buff+i, Buffer, l); + } + if(!Direct) WCacheEODirect__(&(Vcb->FastCache), Vcb); +#ifdef _BROWSE_UDF_ + } else { + // If Direct = TRUE we should never get here, but... + if(Direct) { + BrutePoint(); + return STATUS_INVALID_PARAMETER; + } + tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, Vcb->BlockSize); + if(!tmp_buff) { + BrutePoint(); + return STATUS_INSUFFICIENT_RESOURCES; + } + // read packet + status = UDFReadSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &ReadBytes); + if(!OS_SUCCESS(status)) goto EO_WrSctD; + // modify packet + RtlCopyMemory(tmp_buff+i, Buffer, l); + // write modified packet + status = UDFWriteSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &_WrittenBytes); + if(OS_SUCCESS(status)) + (*WrittenBytes) += l; +EO_WrSctD: + MyFreePool__(tmp_buff); + } + ASSERT(OS_SUCCESS(status)); + if(!OS_SUCCESS(status)) { + KdPrint(("UDFWriteInSector() for LBA %x failed\n", Lba)); + } +#endif //_BROWSE_UDF_ + return status; +} // end UDFWriteInSector() + +/* + This routine writes data at unaligned offset & length + */ +OSSTATUS +UDFWriteData( + IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN int64 Offset, + IN uint32 Length, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN int8* Buffer, + OUT uint32* WrittenBytes + ) +{ + uint32 i, l, Lba, BS=Vcb->BlockSize; + uint32 BSh=Vcb->BlockSizeBits; + OSSTATUS status; + uint32 _WrittenBytes; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + (*WrittenBytes) = 0; + if(!Length) return STATUS_SUCCESS; + if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) + return STATUS_NO_SUCH_DEVICE; + // write tail of the 1st sector if Offset is not sector_size-aligned + Lba = (uint32)(Offset >> BSh); + if(i = ((uint32)Offset & (BS-1))) { + l = (BS - i) < Length ? + (BS - i) : Length; + status = UDFWriteInSector(Vcb, Translate, Lba, i, l, Direct, Buffer, WrittenBytes); + if(!OS_SUCCESS(status)) return status; + if(!(Length = Length - l)) return STATUS_SUCCESS; + Lba ++; + Buffer += l; + } + // write sector_size-aligned part + i = Length >> BSh; + if(i) { + status = UDFWriteSectors(Vcb, Translate, Lba, i, Direct, Buffer, &_WrittenBytes); + (*WrittenBytes) += _WrittenBytes; + if(!OS_SUCCESS(status)) return status; + l = i<ZSBM_Bitmap, Lba, i); +#endif //_BROWSE_UDF_ + if(!(Length = Length - l)) return STATUS_SUCCESS; + Lba += i; + Buffer += l; + } + status = UDFWriteInSector(Vcb, Translate, Lba, 0, Length, Direct, Buffer, &_WrittenBytes); + (*WrittenBytes) += _WrittenBytes; +#ifdef _BROWSE_UDF_ + UDFClrZeroBit(Vcb->ZSBM_Bitmap, Lba); +#endif //_BROWSE_UDF_ + + return status; +} // end UDFWriteData() + +#endif //UDF_READ_ONLY_BUILD + +OSSTATUS +UDFResetDeviceDriver( + IN PVCB Vcb, + IN PDEVICE_OBJECT TargetDeviceObject, + IN BOOLEAN Unlock + ) +{ + PCDRW_RESET_DRIVER_USER_IN tmp = (PCDRW_RESET_DRIVER_USER_IN) + MyAllocatePool__(NonPagedPool, sizeof(CDRW_RESET_DRIVER_USER_IN)); + OSSTATUS RC; + if(!tmp) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(tmp, sizeof(CDRW_RESET_DRIVER_USER_IN)); + tmp->UnlockTray = (Unlock ? 1 : 0); + tmp->MagicWord = 0x3a6 | (Unlock ? 1 : 0); + RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_DRIVER_EX, TargetDeviceObject, + tmp, sizeof(CDRW_RESET_DRIVER_USER_IN), NULL, 0, TRUE,NULL); + if(Vcb) { + Vcb->LastReadTrack = 0; + Vcb->LastModifiedTrack = 0; + Vcb->OPCDone = FALSE; + if((Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) && + Vcb->TargetDeviceObject) { + // limit both read & write speed to last write speed for CAV mode + // some drives damage data when speed is adjusted during recording process + // even in packet mode + UDFSetSpeeds(Vcb); + } + UDFSetCaching(Vcb); + } + + MyFreePool__(tmp); + return RC; +} // end UDFResetDeviceDriver() + +OSSTATUS +UDFSetSpeeds( + IN PVCB Vcb + ) +{ + OSSTATUS RC; + + RtlZeroMemory(&(Vcb->SpeedBuf), sizeof(SET_CD_SPEED_EX_USER_IN)); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) { + Vcb->SpeedBuf.RotCtrl = CdSpeed_RotCtrl_CAV; + Vcb->CurSpeed = + Vcb->SpeedBuf.ReadSpeed = + Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed; + } else { + Vcb->SpeedBuf.ReadSpeed = Vcb->CurSpeed; + Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed; + } + KdPrint((" UDFSetSpeeds: set speed to %s %dX/%dX\n", + (Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) ? "CAV" : "CLV", + Vcb->SpeedBuf.ReadSpeed / 176, + Vcb->SpeedBuf.WriteSpeed / 176)); + RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED, + Vcb->TargetDeviceObject, + &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_EX_USER_IN), + NULL,0,TRUE,NULL); + KdPrint(("UDFSetSpeeds: %x\n", RC)); + return RC; +} // end UDFSetSpeeds() + +NTSTATUS +UDFSetCaching( + IN PVCB Vcb + ) +{ +#pragma pack(push,1) + struct { + MODE_PARAMETER_HEADER Header; + MODE_CACHING_PAGE Data; + CHAR Padding [16]; + } CachingPage; + + struct { + MODE_PARAMETER_HEADER Header; + MODE_READ_WRITE_RECOVERY_PAGE Data; + CHAR Padding [16]; + } RecoveryPage; +#pragma pack(pop,1) + + MODE_SENSE_USER_IN ModeSenseCtl; + OSSTATUS RC; + + KdPrint(("UDFSetCaching:\n")); + + ModeSenseCtl.PageCode.Byte = MODE_PAGE_ERROR_RECOVERY; + RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SENSE, Vcb->TargetDeviceObject, + &ModeSenseCtl,sizeof(ModeSenseCtl), + (PVOID)&RecoveryPage,sizeof(RecoveryPage), + FALSE, NULL); + if(OS_SUCCESS(RC)) { + KdPrint((" Error recovery page:\n" + "PageCode %d\n" + "PageLength %d\n" + + "DCRBit %d\n" + "DTEBit %d\n" + "PERBit %d\n" + "EERBit %d\n" + "RCBit %d\n" + "TBBit %d\n" + "ARRE %d\n" + "AWRE %d\n" + + "ReadRetryCount %d\n" + "CorrectionSpan %d\n" + "HeadOffsetCount %d\n" + "DataStrobOffsetCount %d\n" + + "ErrorRecoveryParam2.Fields.EMCDR %d\n" + + "WriteRetryCount %d\n", + + RecoveryPage.Data.PageCode, + RecoveryPage.Data.PageLength, + + RecoveryPage.Data.ErrorRecoveryParam.Fields.DCRBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.DTEBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.PERBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.EERBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.RCBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.TBBit, + RecoveryPage.Data.ErrorRecoveryParam.Fields.ARRE, + RecoveryPage.Data.ErrorRecoveryParam.Fields.AWRE, + + RecoveryPage.Data.ReadRetryCount, + RecoveryPage.Data.CorrectionSpan, + RecoveryPage.Data.HeadOffsetCount, + RecoveryPage.Data.DataStrobOffsetCount, + + RecoveryPage.Data.ErrorRecoveryParam2.Fields.EMCDR, + + RecoveryPage.Data.WriteRetryCount + + )); + } + + ModeSenseCtl.PageCode.Byte = MODE_PAGE_CACHING; + RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SENSE, Vcb->TargetDeviceObject, + &ModeSenseCtl,sizeof(ModeSenseCtl), + (PVOID)&CachingPage,sizeof(CachingPage), + FALSE, NULL); + if(!OS_SUCCESS(RC)) { + return RC; + } + + KdPrint((" Caching page:\n" + "PageCode %d\n" + "PageLength %d\n" + "ReadDisableCache %d\n" + "MultiplicationFactor %d\n" + "WriteCacheEnable %d\n" + "WriteRetensionPriority %d\n" + "ReadRetensionPriority %d\n", + + CachingPage.Data.PageCode, + CachingPage.Data.PageLength, + CachingPage.Data.ReadDisableCache, + CachingPage.Data.MultiplicationFactor, + CachingPage.Data.WriteCacheEnable, + CachingPage.Data.WriteRetensionPriority, + CachingPage.Data.ReadRetensionPriority + )); + + RtlZeroMemory(&CachingPage.Header, sizeof(CachingPage.Header)); + CachingPage.Data.PageCode = MODE_PAGE_CACHING; + CachingPage.Data.PageSavable = 0; + if( CachingPage.Data.ReadDisableCache || + !CachingPage.Data.WriteCacheEnable) { + CachingPage.Data.ReadDisableCache = 0; + CachingPage.Data.WriteCacheEnable = 1; + RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SELECT, Vcb->TargetDeviceObject, + (PVOID)&CachingPage,sizeof(CachingPage.Header) + 2 + CachingPage.Data.PageLength, + NULL,0, + FALSE, NULL); + } else { + RC = STATUS_SUCCESS; + } + KdPrint(("UDFSetCaching: %x\n", RC)); + return RC; +} // end UDFSetCaching() diff --git a/reactos/drivers/filesystems/udfs/Include/phys_lib.h b/reactos/drivers/filesystems/udfs/Include/phys_lib.h new file mode 100644 index 00000000000..b79bfb8e68d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/phys_lib.h @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDF_PHYS_LIB__H__ +#define __UDF_PHYS_LIB__H__ + +#ifndef UDF_FORMAT_MEDIA +extern BOOLEAN open_as_device; +extern BOOLEAN opt_invalidate_volume; +extern ULONG LockMode; +#endif //UDF_FORMAT_MEDIA + +extern NTSTATUS UDFSyncCache( + IN PVCB Vcb + ); + +OSSTATUS +__fastcall +UDFTIOVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* IOBytes, + IN uint32 Flags + ); + +extern OSSTATUS +UDFTWriteVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* WrittenBytes, + IN uint32 Flags + ); + +extern OSSTATUS +UDFTReadVerify( + IN void* _Vcb, + IN void* Buffer, // Target buffer + IN uint32 Length, + IN uint32 LBA, + OUT uint32* ReadBytes, + IN uint32 Flags + ); + +extern OSSTATUS UDFTRead(PVOID _Vcb, + PVOID Buffer, // Target buffer + ULONG Length, + ULONG LBA, + PULONG ReadBytes, + ULONG Flags = 0); + +extern OSSTATUS UDFTWrite(IN PVOID _Vcb, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN ULONG LBA, + OUT PULONG WrittenBytes, + IN ULONG Flags = 0); + +#define PH_TMP_BUFFER 1 +#define PH_VCB_IN_RETLEN 2 +#define PH_LOCK_CACHE 0x10000000 + +#define PH_EX_WRITE 0x80000000 +#define PH_IO_LOCKED 0x20000000 + + +extern +OSSTATUS +UDFDoOPC( + IN PVCB Vcb + ); + +extern OSSTATUS UDFPrepareForWriteOperation( + IN PVCB Vcb, + IN ULONG Lba, + IN ULONG BCount); + +extern OSSTATUS UDFReadDiscTrackInfo(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume Control Block for ^ DevObj + +extern OSSTATUS UDFReadAndProcessFullToc(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); + +extern OSSTATUS UDFUseStandard(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume control block fro this DevObj + +extern OSSTATUS UDFGetBlockSize(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume control block fro this DevObj + +extern OSSTATUS UDFGetDiskInfo(IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb); // Volume control block from this DevObj + +extern VOID UDFEjectReqWaiter(IN PVOID Context); + +extern VOID UDFStopEjectWaiter(PVCB Vcb); + +extern OSSTATUS UDFPrepareForReadOperation(IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BCount + ); +//#define UDFPrepareForReadOperation(a,b) (STATUS_SUCCESS) + +extern VOID UDFUpdateNWA(PVCB Vcb, + ULONG LBA, + ULONG BCount, + OSSTATUS RC); + +extern OSSTATUS UDFDoDismountSequence(IN PVCB Vcb, + IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf, + IN BOOLEAN Eject); + +// read physical sectors +/*OSSTATUS UDFReadSectors(IN PVCB Vcb, + IN BOOLEAN Translate,// Translate Logical to Physical + IN ULONG Lba, + IN ULONG BCount, + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes);*/ +#define UDFReadSectors(Vcb, Translate, Lba, BCount, Direct, Buffer, ReadBytes) \ + (( WCacheIsInitialized__(&((Vcb)->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) ? \ + (WCacheReadBlocks__(&((Vcb)->FastCache), Vcb, Buffer, Lba, BCount, ReadBytes, Direct)) : \ + (UDFTRead(Vcb, Buffer, (BCount)<<((Vcb)->BlockSizeBits), Lba, ReadBytes, 0))) + + +// read data inside physical sector +extern OSSTATUS UDFReadInSector(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG i, // offset in sector + IN ULONG l, // transfer length + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes); +// read unaligned data +extern OSSTATUS UDFReadData(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN LONGLONG Offset, + IN ULONG Length, + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes); + +#ifndef UDF_READ_ONLY_BUILD +// write physical sectors +OSSTATUS UDFWriteSectors(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG WBCount, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN PCHAR Buffer, + OUT PULONG WrittenBytes); +// write directly to cached sector +OSSTATUS UDFWriteInSector(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG i, // offset in sector + IN ULONG l, // transfer length + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG WrittenBytes); +// write data at unaligned offset & length +OSSTATUS UDFWriteData(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN LONGLONG Offset, + IN ULONG Length, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN PCHAR Buffer, + OUT PULONG WrittenBytes); +#endif //UDF_READ_ONLY_BUILD + +OSSTATUS UDFResetDeviceDriver(IN PVCB Vcb, + IN PDEVICE_OBJECT TargetDeviceObject, + IN BOOLEAN Unlock); + + +#endif //__UDF_PHYS_LIB__H__ \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/Include/platform.h b/reactos/drivers/filesystems/udfs/Include/platform.h new file mode 100644 index 00000000000..58aa2334af6 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/platform.h @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef _PLATFORM_SPECIFIC_H_ +#define _PLATFORM_SPECIFIC_H_ + +#if defined _X86_ +typedef char int8; +typedef short int16; +typedef long int32; +typedef long long int64; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned long long uint64; + +typedef uint32 lba_t; + +#elif defined _AMD64_ + +typedef __int8 int8; +typedef __int16 int16; +typedef __int32 int32; +typedef __int64 int64; + +typedef unsigned __int8 uint8; +typedef unsigned __int16 uint16; +typedef unsigned __int32 uint32; +typedef unsigned __int64 uint64; + +typedef uint32 lba_t; + + +#else // Please define appropriate types here + +#error !!!! You must define your types here for compilation to proceed !!!! + +#endif // if _X86_ + +#endif // _PLATFORM_SPECIFIC_H_ diff --git a/reactos/drivers/filesystems/udfs/Include/product.tph b/reactos/drivers/filesystems/udfs/Include/product.tph new file mode 100644 index 00000000000..c5d8d0c84f2 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/product.tph @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: product.h +// +// Description: Product header template file +//-------------------------------------------------------------------------- + +#ifndef __UDF_PRODUCT__H__ +#define __UDF_PRODUCT__H__ + +#define VER_STR_PRODUCT "%UdfVersionNumber%.%UdfBuildNumber%" +#define VER_RAW_STR_PRODUCT %UdfVersionNumber% +#define VER_BIN_PRODUCT %UdfVersionNumberBin%,%UdfBuildNumber% + +#define UDF_CURRENT_BUILD %UdfBuildNumber% + +#define VER_STR_PRODUCT_NAME "DVD Write Now" +#define VER_STR_VENDOR_NAME "DVD Write Now" +#define VER_STR_VENDOR_SHORT_NAME "DVD Write Now" + +#define VER_LEGALCOPYRIGHT_YEARS "1999-2007" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 " VER_STR_VENDOR_NAME " " VER_LEGALCOPYRIGHT_YEARS + +#endif //__UDF_PRODUCT__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/protect.h b/reactos/drivers/filesystems/udfs/Include/protect.h new file mode 100644 index 00000000000..efc2a1b69e0 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/protect.h @@ -0,0 +1,119 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDF_PROTECT__H__ +#define __UDF_PROTECT__H__ + +//#include "udf_eval_time.h" +//#include "product.h" + +//#define EVALUATION_TIME_LIMIT !!! // this must be defined in compiler options + +#define TIME_JAN_1_2003 0x23d8b +#define EVALUATION_TERM 30 +#define EVALUATION_TERM_XOR 0x75fd63c8 +#define EVALUATION_TERM_DIE ((-1) ^ EVALUATION_TERM_XOR) + +//#define UDF_CURRENT_VERSION 0x00015002 +// xx.1.50.02 +//#define UDF_CURRENT_BUILD 110 + +#define REG_TRIAL_DATE1_KEY_NAME L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer" +#define REG_TRIAL_DATE1_VAL_NAME L"AlwaysOnTop" + +#define REG_TRIAL_DATE2_KEY_NAME L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer" +#define REG_TRIAL_DATE2_VAL_NAME L"AlwaysOnTop" + +#define REG_TRIAL_DATE3_KEY_NAME_A "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Compatibility32" +#define REG_TRIAL_DATE3_KEY_NAME_W L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Compatibility32" +#define REG_TRIAL_DATE3_VAL_NAME_A "DWGUIFMTUDF32" +#define REG_TRIAL_DATE3_VAL_NAME_W L"DWGUIFMTUDF32" + +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Compatibility, RUN.EXE Date +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ModuleCompatibility, EXPLORER.EXE Date +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WOW\Compatibility, CMD32.EXE Version +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion, InstallTime Version +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer, SmallIcons TrialEnd +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Nls\LocaleMapIDs, CurrentLocaleID TrialEnd +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved, 62ad7960-e634-11d8-b031-00024451f90c not used now + +/* +#define XOR_STR_DECL(n, val) \ + ULONG UdfXorStr##n = val; +*/ + +#define UDF_INSTALL_INFO_LOCATIONS 2 + +#define XOR_VAR(suff, n) UdfXorVal##suff##n +#define XOR_VAR_DECL(suff, n, val) \ + ULONG XOR_VAR(suff, n) = val; +#define XOR_VAR_DECLH(suff, n) \ + extern ULONG XOR_VAR(suff, n); + +extern ULONG PresentDateMask; +extern BOOLEAN TrialEndOnStart; + +XOR_VAR_DECLH(Date, 0); +XOR_VAR_DECLH(Date, 1); +XOR_VAR_DECLH(Version, 0); +XOR_VAR_DECLH(Version, 1); +XOR_VAR_DECLH(TrialEnd, 0); +XOR_VAR_DECLH(TrialEnd, 1); +//XOR_VAR_DECL(Date, 0, 0xff7765cc); +//XOR_VAR_DECL(Date, 1, 0xf76caa82); + +//#include "protect_reg.h" + + +#define GET_XXX_REG_VAL_TYPE(str, n) (REG_##str##_TYPE_##n) +#define GET_XXX_REG_XOR(xxx, n) (REG_##xxx##_XOR_##n) + +//#define GET_DATE_REG_XOR(n) (UdfXorVal##Date##n) + +// str pointer to the buffer to extract name to +#define GET_XXX_REG_YYY_NAME(xxx, yyy, _str, n) /* Kernel */ \ +{ \ + ULONG i; \ + PCHAR str = (PCHAR)(_str); \ + PCHAR tmp = REG_##xxx##_##yyy##_NAME_##n; \ + for(i=0; i< sizeof(REG_##xxx##_##yyy##_NAME_##n); i++) { \ + str[i] = tmp[i] ^ (UCHAR)GET_##xxx##_REG_XOR(n) ; \ + } \ +} + +#define GET_DATE_REG_XOR(n) GET_XXX_REG_XOR(DATE, n) +// str pointer to the buffer to extract name to +#define GET_DATE_REG_KEY_NAME(_str, n) GET_XXX_REG_YYY_NAME(DATE, KEY, _str, n) +#define GET_DATE_REG_VAL_NAME(_str, n) GET_XXX_REG_YYY_NAME(DATE, VAL, _str, n) + + +#define GET_VERSION_REG_XOR(n) GET_XXX_REG_XOR(VERSION, n) +//#define GET_VERSION_REG_XOR(n) (UdfXorVal##Version##n) +#define GET_VERSION_REG_KEY_NAME(_str, n) GET_XXX_REG_YYY_NAME(VERSION, KEY, _str, n) +#define GET_VERSION_REG_VAL_NAME(_str, n) GET_XXX_REG_YYY_NAME(VERSION, VAL, _str, n) + +#define GET_TRIAL_REG_XOR(n) GET_XXX_REG_XOR(TRIAL, n) +//#define GET_TRIAL_REG_XOR(n) (UdfXorVal##Trial##n) +#define GET_TRIAL_REG_KEY_NAME(_str, n) GET_XXX_REG_YYY_NAME(TRIAL, KEY, _str, n) +#define GET_TRIAL_REG_VAL_NAME(_str, n) GET_XXX_REG_YYY_NAME(TRIAL, VAL, _str, n) + +////////////// + +#define UDF_LICENSE_KEY L"LicenseKey" +#define UDF_LICENSE_KEY_USER "LicenseKey" + +#define UDF_USER_KEY L"UserName" +#define UDF_USER_KEY_USER "UserName" + +#endif // __UDF_PROTECT__H__ + +#ifdef INCLUDE_XOR_DECL_ONLY + XOR_VAR_DECL(Date, 0, 0xf826fab2); + XOR_VAR_DECL(Date, 1, 0x12fcb245); + XOR_VAR_DECL(Version, 0, 0x8c36acf3); + XOR_VAR_DECL(Version, 1, 0x9437cfa4); + XOR_VAR_DECL(TrialEnd, 0, 0xfc9387a6); + XOR_VAR_DECL(TrialEnd, 1, 0x287cfbde); +#endif // INCLUDE_XOR_DECL_ONLY diff --git a/reactos/drivers/filesystems/udfs/Include/protect_reg.tph b/reactos/drivers/filesystems/udfs/Include/protect_reg.tph new file mode 100644 index 00000000000..4bddd44cd17 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/protect_reg.tph @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: protect_reg.h.h +// +// Description: Protection header template file +//-------------------------------------------------------------------------- + + + +#define REG_DATE_XOR_0 0x167ff6c9 +#define REG_DATE_XOR_1 0x4f76baac + +#define REG_VERSION_XOR_0 0x938bcfa2 +#define REG_VERSION_XOR_1 0xf8d9614c + +#define REG_TRIAL_XOR_0 0x87cbadef +#define REG_TRIAL_XOR_1 0xd8736da6 + +// TYPE_X 0 - dword +// TYPE_X 1 - string + +#define REG_DATE_TYPE_0 1 +#define REG_DATE_TYPE_1 1 + +#define REG_VERSION_TYPE_0 1 +#define REG_VERSION_TYPE_1 0 + +#define REG_TRIAL_TYPE_0 0 +#define REG_TRIAL_TYPE_1 0 + +#if defined(_NTDDK_) || defined(_NTIFS_) || defined(NT_DEFINED) + +%BeginStringDefines% +#define REG_DATE_KEY_NAME_0 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Compatibility" +#define REG_DATE_VAL_NAME_0 L"RUN32" +#define REG_DATE_KEY_NAME_1 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ModuleCompatibility" +#define REG_DATE_VAL_NAME_1 L"EXPLORER2" + +#define REG_VERSION_KEY_NAME_0 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WOW\\Compatibility" +#define REG_VERSION_VAL_NAME_0 L"CMD32" +#define REG_VERSION_KEY_NAME_1 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" +#define REG_VERSION_VAL_NAME_1 L"InstallTime" + +#define REG_TRIAL_KEY_NAME_0 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer" +#define REG_TRIAL_VAL_NAME_0 L"SmallIcons" +#define REG_TRIAL_KEY_NAME_1 L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Nls\\LocaleMapIDs" +#define REG_TRIAL_VAL_NAME_1 L"CurrentLocaleID" +%EndStringDefines% + +#define XCHAR PWCHAR + +#else // defined(_NTDDK_) || defined(_NTIFS_) || defined(NT_DEFINED) + +%PlaceStringDefines% + +#define XCHAR PCHAR + +#endif // defined(_NTDDK_) || defined(_NTIFS_) || defined(NT_DEFINED) and K' diff --git a/reactos/drivers/filesystems/udfs/Include/protect_user_mode.cpp b/reactos/drivers/filesystems/udfs/Include/protect_user_mode.cpp new file mode 100644 index 00000000000..7bedef9ef35 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/protect_user_mode.cpp @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +//#define EVALUATION_TIME_LIMIT + +#ifdef EVALUATION_TIME_LIMIT + +#define VAR_SAVED(preff, n) Var##preff##n##Saved + +#define KEY(preff, n) preff##n##Key +#define VAL(preff, n) preff##n##Val + +#define CheckAndSave(preff, n, val, type) \ + if (!VAR_SAVED(##preff, ##n)) { \ + if (##type==1) \ + RegisterDword(KEY(##preff,##n),VAL(##preff,##n),##val ^ XOR_VAR(##preff, ##n) ); \ + else { \ + szTemp[16]; \ + sprintf(szTemp,"0x%08x", ##val ^ XOR_VAR(##preff, ##n)); \ + RegisterString(KEY(##preff,##n),VAL(##preff,##n), &szTemp[0], FALSE, 0); \ + }\ + VAR_SAVED(##preff, ##n) = TRUE; \ + } + +#define RegisterTrialEnd() \ + CheckAndSave(TrialEnd, 0, 1, 1); \ + CheckAndSave(TrialEnd, 1, 1, 1); + +#define ClearTrialEnd() \ + CheckAndSave(TrialEnd, 0, 0, 1); \ + CheckAndSave(TrialEnd, 1, 0, 1); + +#define RegisterDate() \ + CheckAndSave(Date, 0, dwDaysSince2003, 0); \ + CheckAndSave(Date, 1, dwDaysSince2003, 0); + +#define RegisterVersion() \ + CheckAndSave(Version, 0, UDF_CURRENT_BUILD, 0); \ + CheckAndSave(Version, 1, UDF_CURRENT_BUILD, 1); + +#define PATH_VAR_DECL(preff, n) \ +CHAR KEY(preff, n)[256], VAL(preff, n)[64]; \ +BOOL VAR_SAVED(preff, n) = FALSE; + + +#define GET_KEY_DATE(n) GET_DATE_REG_KEY_NAME(Date##n##Key, ##n) +#define GET_VAL_DATE(n) GET_DATE_REG_VAL_NAME(Date##n##Val, ##n) + +#define GET_KEY_VERSION(n) GET_VERSION_REG_KEY_NAME(Version##n##Key, ##n) +#define GET_VAL_VERSION(n) GET_VERSION_REG_VAL_NAME(Version##n##Val, ##n) + +#define GET_KEY_TRIAL(n) GET_TRIAL_REG_KEY_NAME(TrialEnd##n##Key, ##n) +#define GET_VAL_TRIAL(n) GET_TRIAL_REG_VAL_NAME(TrialEnd##n##Val, ##n) + + CHAR szTemp[16]; + ULONG dwDaysSince2003, dwDaysSince2003fromReg0 = 0, dwDaysSince2003fromReg1 = 0; + ULONG TrialEnd0, TrialEnd1; + ULONG Version0 = 0, Version1 = 0; + SYSTEMTIME SystemTime, SystemTime2003; + FILETIME FileTime, FileTime2003; + ULARGE_INTEGER Time, Time2003; + + +#define INCLUDE_XOR_DECL_ONLY +#include "protect.h" +#undef INCLUDE_XOR_DECL_ONLY + + PATH_VAR_DECL(Date, 0); + PATH_VAR_DECL(Date, 1); + PATH_VAR_DECL(Version, 0); + PATH_VAR_DECL(Version, 1); + PATH_VAR_DECL(TrialEnd, 0); + PATH_VAR_DECL(TrialEnd, 1); + + GET_KEY_TRIAL(0); + GET_VAL_TRIAL(1); + +#ifndef NO_KEY_PRESENCE_CHECK + CHAR Key[17]; + if (GetRegString(UDF_SERVICE_PATH,UDF_LICENSE_KEY_USER,Key, sizeof(Key))) { + goto LicenseKeyPresent; + } +#endif // NO_KEY_PRESENCE_CHECK + + GetSystemTime(&SystemTime); + SystemTimeToFileTime(&SystemTime, &FileTime); + memset(&SystemTime2003, 0, sizeof(SystemTime2003)); + SystemTime2003.wYear = 2003; + + GET_KEY_DATE(0); + GET_VAL_DATE(0); + GET_KEY_VERSION(0); + + SystemTime2003.wMonth = 1; + SystemTime2003.wDay = 1; + + GET_VAL_VERSION(1); + + SystemTimeToFileTime(&SystemTime2003, &FileTime2003); + + memcpy(&Time , &FileTime, sizeof(ULARGE_INTEGER)); + memcpy(&Time2003, &FileTime2003, sizeof(ULARGE_INTEGER)); + Time.QuadPart -= Time2003.QuadPart; + + GET_KEY_TRIAL(1); + GET_VAL_TRIAL(0); + + dwDaysSince2003 = (ULONG)(Time.QuadPart/10000000I64/3600/24); + + GET_KEY_DATE(1); + GET_VAL_VERSION(0); + GET_KEY_VERSION(1); + + if (GetRegString(KEY(Version, 0), VAL(Version, 0),&szTemp[0], sizeof(szTemp))) { + sscanf(szTemp,"0x%08x", &Version0); + Version0 ^= XOR_VAR(Version,0); + } + + GET_VAL_DATE(1); + + if (GetRegUlong(KEY(Version, 1), VAL(Version, 1),&Version1)) { + Version1 ^= XOR_VAR(Version,1); + } + + if (Version0 < UDF_CURRENT_BUILD && Version1 < UDF_CURRENT_BUILD) { + RegisterVersion(); + ClearTrialEnd(); + RegisterDate(); + return 1; + } + + if ((LONGLONG)(Time.QuadPart) < 0 || + GetRegUlong(KEY(TrialEnd, 0), VAL(TrialEnd, 0),&TrialEnd0) && (TrialEnd0 ^ XOR_VAR(TrialEnd, 0)) != 0 || + GetRegUlong(KEY(TrialEnd, 1), VAL(TrialEnd, 1),&TrialEnd1) && (TrialEnd1 ^ XOR_VAR(TrialEnd, 1)) != 0) { + RegisterTrialEnd(); +#ifndef NO_MESSAGE_BOXES + if (MyMessageBox(hInst, + GetDesktopWindow(), + MAKEINTRESOURCE(IDS_EXPIRED_TEXT), + MAKEINTRESOURCE(IDS_EXPIRED), MB_YESNO | MB_ICONQUESTION) == IDYES) goto EnterRegistration; + +#endif // NO_MESSAGE_BOXES + return 0; + } + + if (GetRegString(KEY(Date, 0), VAL(Date, 0),&szTemp[0], sizeof(szTemp))) { + sscanf(szTemp,"0x%08x", &dwDaysSince2003fromReg0); + dwDaysSince2003fromReg0 ^= XOR_VAR(Date,0); + } + + if (GetRegString(KEY(Date, 1), VAL(Date, 1),&szTemp[0], sizeof(szTemp))) { + sscanf(szTemp,"0x%08x", &dwDaysSince2003fromReg1); + dwDaysSince2003fromReg1 ^= XOR_VAR(Date,1); + } + + if (dwDaysSince2003fromReg1 > dwDaysSince2003fromReg0) dwDaysSince2003fromReg0 = dwDaysSince2003fromReg1; + + if (!dwDaysSince2003fromReg0 && !dwDaysSince2003fromReg1) { + RegisterDate(); + dwDaysSince2003fromReg0 = dwDaysSince2003; + } else if (!dwDaysSince2003fromReg0) { + CheckAndSave(Date, 0, dwDaysSince2003fromReg1, 0); + dwDaysSince2003fromReg0 = dwDaysSince2003fromReg1; + } else if (!dwDaysSince2003fromReg1) { + CheckAndSave(Date, 1, dwDaysSince2003fromReg0, 0); + } + + if(dwDaysSince2003 - dwDaysSince2003fromReg0 > EVALUATION_TERM || dwDaysSince2003 < dwDaysSince2003fromReg0 || + dwDaysSince2003 > UDF_MAX_DATE || + dwDaysSince2003 < UDF_MIN_DATE) { + RegisterTrialEnd(); +#ifndef NO_MESSAGE_BOXES + if (MyMessageBox(hInst, + GetDesktopWindow(), + MAKEINTRESOURCE(IDS_EXPIRED_TEXT), + MAKEINTRESOURCE(IDS_EXPIRED), MB_YESNO | MB_ICONQUESTION) == IDYES) goto EnterRegistration; + +#endif // NO_MESSAGE_BOXES + return 0; + } + +#endif EVALUATION_TIME_LIMIT diff --git a/reactos/drivers/filesystems/udfs/Include/regtools.cpp b/reactos/drivers/filesystems/udfs/Include/regtools.cpp new file mode 100644 index 00000000000..4aca224c839 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/regtools.cpp @@ -0,0 +1,284 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#include "regtools.h" + +#ifndef WIN_32_MODE + +NTSTATUS +RegTGetKeyHandle( + IN HKEY hRootKey, + IN PWCHAR KeyName, + OUT HKEY* hKey + ) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING NameString; + NTSTATUS status; + + //KdPrint(("RegTGetKeyHandle: h=%x, %S\n", hRootKey, KeyName)); + + NameString.Buffer = KeyName; + NameString.Length = wcslen(KeyName)*sizeof(WCHAR); + NameString.MaximumLength = NameString.Length + sizeof(WCHAR); + + InitializeObjectAttributes( + &ObjectAttributes, + &NameString, + OBJ_CASE_INSENSITIVE, + hRootKey, + NULL + ); + + status = ZwOpenKey( + hKey, + KEY_WRITE | KEY_READ, + &ObjectAttributes + ); + + if(!NT_SUCCESS(status)) { + //KdPrint((" status %x\n", status)); + *hKey = NULL; + } + + return status; +} // end RegTGetKeyHandle() + +VOID +RegTCloseKeyHandle( + IN HKEY hKey +) +{ + ZwClose(hKey); +} // end RegTCloseKeyHandle() + +#else //WIN_32_MODE + +NTSTATUS +RegTGetKeyHandle( + IN HKEY hRootKey, + IN PWCHAR KeyName, + OUT HKEY* hKey + ) +{ + LONG status; + + if(!hRootKey) + hRootKey = HKEY_LOCAL_MACHINE; + + status = RegOpenKeyExW( + hRootKey, + KeyName, + 0, + KEY_WRITE | KEY_READ, + hKey + ); + + if(status != ERROR_SUCCESS) { + *hKey = NULL; + } + + return status; +} // end RegTGetKeyHandle() + +VOID +RegTCloseKeyHandle( + IN HKEY hKey +) +{ + if(!hKey) { + return; + } + RegCloseKey(hKey); +} // end RegTCloseKeyHandle() + +#endif //WIN_32_MODE + +BOOLEAN +RegTGetDwordValue( + IN HKEY hRootKey, + IN PWSTR RegistryPath, + IN PWSTR Name, + IN PULONG pUlong + ) +{ +#ifndef WIN_32_MODE + UNICODE_STRING NameString; + PKEY_VALUE_PARTIAL_INFORMATION ValInfo; +#endif //WIN_32_MODE + ULONG len; + NTSTATUS status; + HKEY hKey; + BOOLEAN retval = FALSE; + BOOLEAN free_h = FALSE; + +#ifdef WIN_32_MODE + if(!hRootKey) + hRootKey = HKEY_LOCAL_MACHINE; +#endif //WIN_32_MODE + + if(RegistryPath && RegistryPath[0]) { + status = RegTGetKeyHandle(hRootKey, RegistryPath, &hKey); +#ifdef WIN_32_MODE + if(status != ERROR_SUCCESS) +#else //WIN_32_MODE + if(!NT_SUCCESS(status)) +#endif //WIN_32_MODE + return FALSE; + free_h = TRUE; + } else { + hKey = hRootKey; + } + if(!hKey) + return FALSE; + +#ifndef WIN_32_MODE +/* + KdPrint(("h=%x|%S, %S (%x)\n", + hRootKey, RegistryPath, Name, *pUlong)); +*/ + len = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) + 0x20; + ValInfo = (PKEY_VALUE_PARTIAL_INFORMATION) + MyAllocatePool__(NonPagedPool, len); + if(!ValInfo) { + if(free_h) { + RegTCloseKeyHandle(hKey); + } + return FALSE; + } + + NameString.Buffer = Name; + NameString.Length = wcslen(Name)*sizeof(WCHAR); + NameString.MaximumLength = NameString.Length + sizeof(WCHAR); + + status = ZwQueryValueKey(hKey, + &NameString, + KeyValuePartialInformation, + ValInfo, + len, + &len); + if(NT_SUCCESS(status) && + ValInfo->DataLength == sizeof(ULONG)) { + RtlCopyMemory(pUlong, ValInfo->Data, sizeof(ULONG)); + retval = TRUE; + //KdPrint((" -> %x\n",*pUlong)); + } else { + //KdPrint((" err %x\n",status)); + } + + MyFreePool__(ValInfo); +#else //WIN_32_MODE + len = sizeof(ULONG); + if (ERROR_SUCCESS == RegQueryValueExW( + hKey, // handle of key to query + Name, // address of name of value to query + 0, // reserved + NULL, // address of buffer for value type + (BYTE *)pUlong, // address of data buffer + &len // address of data buffer size + ) && len == sizeof(ULONG)) { + retval = TRUE; + } +#endif //WIN_32_MODE + if(free_h) { + RegTCloseKeyHandle(hKey); + } + return retval; +} // end RegTGetDwordValue() + +BOOLEAN +RegTGetStringValue( + IN HKEY hRootKey, + IN PWSTR RegistryPath, + IN PWSTR Name, + IN PWCHAR pStr, + IN ULONG MaxLen + ) +{ +#ifndef WIN_32_MODE + UNICODE_STRING NameString; + PKEY_VALUE_PARTIAL_INFORMATION ValInfo; +#endif //USER_MODE + ULONG len; + NTSTATUS status; + HKEY hKey; + BOOLEAN retval = FALSE; + BOOLEAN free_h = FALSE; + +#ifdef WIN_32_MODE + if(!hRootKey) + hRootKey = HKEY_LOCAL_MACHINE; +#endif //WIN_32_MODE + + if(RegistryPath && RegistryPath[0]) { + status = RegTGetKeyHandle(hRootKey, RegistryPath, &hKey); +#ifdef WIN_32_MODE + if(status != ERROR_SUCCESS) +#else //WIN_32_MODE + if(!NT_SUCCESS(status)) +#endif //WIN_32_MODE + return FALSE; + free_h = TRUE; + } else { + hKey = hRootKey; + } + if(!hKey) + return FALSE; + + pStr[0] = 0; +#ifndef WIN_32_MODE + len = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MaxLen + 0x20; + ValInfo = (PKEY_VALUE_PARTIAL_INFORMATION) + MyAllocatePool__(NonPagedPool, len); + if(!ValInfo) { + if(free_h) { + RegTCloseKeyHandle(hKey); + } + return FALSE; + } + + NameString.Buffer = Name; + NameString.Length = wcslen(Name)*sizeof(WCHAR); + NameString.MaximumLength = NameString.Length + sizeof(WCHAR); + + status = ZwQueryValueKey(hKey, + &NameString, + KeyValuePartialInformation, + ValInfo, + len, + &len); + if(NT_SUCCESS(status) && + ValInfo->DataLength) { + RtlCopyMemory(pStr, ValInfo->Data, min(ValInfo->DataLength, MaxLen) ); + if(pStr[(ValInfo->DataLength)/sizeof(WCHAR)-1]) { + pStr[(ValInfo->DataLength)/sizeof(WCHAR)-1] = 0; + } + retval = TRUE; + } + + MyFreePool__(ValInfo); +#else //WIN_32_MODE + len = MaxLen; + if (ERROR_SUCCESS == RegQueryValueExW( + hKey, // handle of key to query + Name, // address of name of value to query + 0, // reserved + NULL, // address of buffer for value type + (BYTE *)pStr, // address of data buffer + &len // address of data buffer size + ) && len) { + if(pStr[len-1]) { + pStr[len-1] = 0; + } + retval = TRUE; + } +#endif //WIN_32_MODE + + if(free_h) { + RegTCloseKeyHandle(hKey); + } + return retval; +} // end RegTGetStringValue() + diff --git a/reactos/drivers/filesystems/udfs/Include/regtools.h b/reactos/drivers/filesystems/udfs/Include/regtools.h new file mode 100644 index 00000000000..d0eb5dd1271 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/regtools.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __MULTIENV_REG_TOOLS__H__ +#define __MULTIENV_REG_TOOLS__H__ + +#include "check_env.h" + +#ifndef WIN_32_MODE +#define HKEY HANDLE +#endif //WIN_32_MODE + +NTSTATUS +RegTGetKeyHandle( + IN HKEY hRootKey, + IN PWCHAR KeyName, + OUT HKEY* hKey + ); + +VOID +RegTCloseKeyHandle( + IN HKEY hKey + ); + +BOOLEAN +RegTGetDwordValue( + IN HKEY hRootKey, + IN PWSTR RegistryPath, + IN PWSTR Name, + IN PULONG pUlong + ); + +BOOLEAN +RegTGetStringValue( + IN HKEY hRootKey, + IN PWSTR RegistryPath, + IN PWSTR Name, + IN PWCHAR pStr, + IN ULONG MaxLen + ); + +#endif //__MULTIENV_REG_TOOLS__H__ \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/Include/string_lib.cpp b/reactos/drivers/filesystems/udfs/Include/string_lib.cpp new file mode 100644 index 00000000000..9d1d36d8b9d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/string_lib.cpp @@ -0,0 +1,165 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +extern "C" +ULONG +MyRtlCompareMemory( + PVOID s1, + PVOID s2, + ULONG len + ) +{ + ULONG i; + + for(i=0; iLength != s2->Length) return (-1); + i = memcmp(s1->Buffer, s2->Buffer, (s1->Length) ? (s1->Length) : (s2->Length)); + return i; +} + +extern "C" +NTSTATUS +RtlUpcaseUnicodeString( + PUNICODE_STRING dst, + PUNICODE_STRING src, + BOOLEAN Alloc + ) +{ +// if(s1->Length != s2->Length) return (-1); + memcpy(dst->Buffer, src->Buffer, src->Length); + dst->Buffer[src->Length/sizeof(WCHAR)] = 0; + dst->Length = src->Length; + _wcsupr(dst->Buffer); + return STATUS_SUCCESS; +} + +extern "C" +NTSTATUS +RtlAppendUnicodeToString( + IN PUNICODE_STRING Str1, + IN PWSTR Str2 + ) +{ + PWCHAR tmp; + USHORT i; + +#ifdef _X86_ + + __asm push ebx + __asm push esi + __asm xor ebx,ebx + __asm mov esi,Str2 +Scan_1: + __asm cmp [word ptr esi+ebx],0 + __asm je EO_Scan + __asm add ebx,2 + __asm jmp Scan_1 +EO_Scan: + __asm mov i,bx + __asm pop esi + __asm pop ebx + +#else // NO X86 optimization, use generic C/C++ + + i=0; + while(Str2[i]) { + i++; + } + i *= sizeof(WCHAR); + +#endif // _X86_ + + tmp = Str1->Buffer; + ASSERT(Str1->MaximumLength); + if((Str1->Length+i+sizeof(WCHAR)) > Str1->MaximumLength) { + PWCHAR tmp2 = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, STRING_BUFFER_ALIGN(i + Str1->Length + sizeof(WCHAR))*2, 'ilTS'); + if(!tmp2) + return STATUS_INSUFFICIENT_RESOURCES; + memcpy(tmp2, tmp, Str1->MaximumLength); + ExFreePool(tmp); + tmp = tmp2; + Str1->MaximumLength = STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2; + Str1->Buffer = tmp; + } + RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2, i); + i+=Str1->Length; + tmp[(i / sizeof(WCHAR))] = 0; + Str1->Length = i; + + return STATUS_SUCCESS; + +#undef UDF_UNC_STR_TAG + +} // end RtlAppendUnicodeToString() + +#endif //NT_NATIVE_MODE + +#ifdef CDRW_W32 +NTSTATUS +MyInitUnicodeString( + IN PUNICODE_STRING Str1, + IN PCWSTR Str2 + ) +{ + + USHORT i; + +#ifdef _X86_ + + __asm push ebx + __asm push esi + __asm xor ebx,ebx + __asm mov esi,Str2 +Scan_1: + __asm cmp [word ptr esi+ebx],0 + __asm je EO_Scan + __asm add ebx,2 + __asm jmp Scan_1 +EO_Scan: + __asm mov i,bx + __asm pop esi + __asm pop ebx + +#else // NO X86 optimization, use generic C/C++ + + i=0; + while(Str2[i]) { + i++; + } + i *= sizeof(WCHAR); + +#endif // _X86_ + + Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = i) + sizeof(WCHAR)); + Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); + if(!Str1->Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(Str1->Buffer, Str2, i); + Str1->Buffer[i/sizeof(WCHAR)] = 0; + return STATUS_SUCCESS; + +} // end MyInitUnicodeString() +#endif //CDRW_W32 \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/Include/tools.cpp b/reactos/drivers/filesystems/udfs/Include/tools.cpp new file mode 100644 index 00000000000..84f69243768 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/tools.cpp @@ -0,0 +1,165 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* +Module Name: + + tools.cpp + +Abstract: + + This module contains some useful functions for data manipulation. + +Environment: + + */ +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +//---------------- + +#include "tools.h" + +//---------------- + +#ifdef _X86_ + +__declspec (naked) +void +__fastcall +_MOV_DD_SWP( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov eax,[edx] + bswap eax + mov [ecx],eax + ret + } +} + +__declspec (naked) +void +__fastcall +_MOV_DW_SWP( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov ax,[edx] + rol ax,8 + mov [ecx],ax + ret + } +} + +__declspec (naked) +void +__fastcall +_REVERSE_DD( + void* a // ECX + ) +{ + _asm { + mov eax,[ecx] + bswap eax + mov [ecx],eax + ret + } +} + +__declspec (naked) +void +__fastcall +_REVERSE_DW( + void* a // ECX + ) +{ + _asm { + mov ax,[ecx] + rol ax,8 + mov [ecx],ax + ret + } +} + +__declspec (naked) +void +__fastcall +_MOV_DW2DD_SWP( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov ax,[edx] + rol ax,8 + mov [ecx+2],ax + mov [ecx],0 + ret + } +} + +__declspec (naked) +void +__fastcall +_MOV_MSF( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov eax,[edx] + mov [ecx],ax + shr eax,16 + mov [ecx+2],al + ret + } +} + +__declspec (naked) +void +__fastcall +_MOV_MSF_SWP( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov eax,[edx] + mov [ecx+2],al + bswap eax + shr eax,8 + mov [ecx],ax + ret + } +} + +__declspec (naked) +void +__fastcall +_XCHG_DD( + void* a, // ECX + void* b // EDX + ) +{ + _asm { + mov eax,[edx] + xchg eax,[ecx] + mov [edx],eax + ret + } +} + +#endif _X86_ + +#ifdef __cplusplus +}; +#endif diff --git a/reactos/drivers/filesystems/udfs/Include/tools.h b/reactos/drivers/filesystems/udfs/Include/tools.h new file mode 100644 index 00000000000..b4cc36e6dcb --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/tools.h @@ -0,0 +1,287 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#ifndef __TOOLS_H__ +#define __TOOLS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __CROSSNT_MISC__H__ + +typedef struct _FOUR_BYTE { + UCHAR Byte0; + UCHAR Byte1; + UCHAR Byte2; + UCHAR Byte3; +} FOUR_BYTE, *PFOUR_BYTE; + +#if defined _X86_ && defined __CROSS_VERSION_LIB_NT__H__ + +#define AcquireXLock(gLock, oldValue, newValue) \ +{ \ + PULONG _gLock_ = &(gLock); \ + __asm push ebx \ + __asm mov eax,newValue \ + __asm mov ebx,_gLock_ \ + __asm xchg eax,[ebx] \ + __asm mov oldValue,eax \ + __asm pop ebx \ +} + +void +__fastcall +_MOV_DD_SWP( + void* a, // ECX + void* b // EDX + ); +#define MOV_DD_SWP(a,b) _MOV_DD_SWP(&(a),&(b)) +/*#define MOV_DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm bswap eax \ + __asm mov ebx,_to_ \ + __asm mov [ebx],eax \ +}*/ + +void +__fastcall +_MOV_DW_SWP( + void* a, // ECX + void* b // EDX + ); +#define MOV_DW_SWP(a,b) _MOV_DW_SWP(&(a),&(b)) +/*#define MOV_DW_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm push ebx \ + __asm mov ebx,_from_ \ + __asm mov ax,[ebx] \ + __asm rol ax,8 \ + __asm mov ebx,_to_ \ + __asm mov [ebx],ax \ + __asm pop ebx \ +}*/ + +void +__fastcall +_REVERSE_DD( + void* a // ECX + ); +#define REVERSE_DD(a) _REVERSE_DD(&(a)) +/*#define REVERSE_DD(a) { \ + PFOUR_BYTE _from_; \ + _from_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm bswap eax \ + __asm mov [ebx],eax \ +}*/ + +void +__fastcall +_REVERSE_DW( + void* a // ECX + ); +#define REVERSE_DW(a) _REVERSE_DW(&(a)) +/*#define REVERSE_DW(a) { \ + PFOUR_BYTE _from_; \ + _from_ = ((PFOUR_BYTE)&(a)); \ + __asm mov eax,_from_ \ + __asm rol word ptr [eax],8 \ +}*/ + +void +__fastcall +_MOV_DW2DD_SWP( + void* a, // ECX + void* b // EDX + ); +#define MOV_DW2DD_SWP(a,b) _MOV_DW2DD_SWP(&(a),&(b)) +/*#define MOV_DW2DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov ax,[ebx] \ + __asm rol ax,8 \ + __asm mov ebx,_to_ \ + __asm mov [ebx+2],ax \ + __asm mov [ebx],0 \ +}*/ + +void +__fastcall +_MOV_MSF( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF(a,b) _MOV_MSF(&(a),&(b)) +/*#define MOV_MSF(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm mov ebx,_to_ \ + __asm mov [ebx],ax \ + __asm shr eax,16 \ + __asm mov [ebx+2],al \ +}*/ + +void +__fastcall +_MOV_MSF_SWP( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF_SWP(a,b) _MOV_MSF_SWP(&(a),&(b)) +/*#define MOV_MSF_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm mov ebx,_to_ \ + __asm mov [ebx+2],al \ + __asm bswap eax \ + __asm shr eax,8 \ + __asm mov [ebx],ax \ +}*/ + +void +__fastcall +_XCHG_DD( + void* a, // ECX + void* b // EDX + ); +#define XCHG_DD(a,b) _XCHG_DD(&(a),&(b)) +/*#define XCHG_DD(a,b) \ +{ \ + PULONG _from_, _to_; \ + _from_ = ((PULONG)&(b)); \ + _to_ = ((PULONG)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov ecx,_to_ \ + __asm mov eax,[ebx] \ + __asm xchg eax,[ecx] \ + __asm mov [ebx],eax \ +}*/ + +#else // NO X86 optimization , use generic C/C++ + +#define AcquireXLock(gLock, oldValue, newValue) \ +{ \ + oldValue = gLock; \ + gLock = newValue; \ +} + +#define MOV_DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte3; \ + _to_->Byte1 = _from_->Byte2; \ + _to_->Byte2 = _from_->Byte1; \ + _to_->Byte3 = _from_->Byte0; \ +} + +#define MOV_DW_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte1; \ + _to_->Byte1 = _from_->Byte0; \ +} + +#define REVERSE_DD(a) { \ + ULONG _i_; \ + MOV_DD_SWP(_i_,(a)); \ + *((PULONG)&(a)) = _i_; \ +} + +#define REVERSE_DW(a) { \ + USHORT _i_; \ + MOV_DW_SWP(_i_,(a)); \ + *((PUSHORT)&(a)) = _i_; \ +} + +#define MOV_DW2DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + *((PUSHORT)_to_) = 0; \ + _to_->Byte2 = _from_->Byte1; \ + _to_->Byte3 = _from_->Byte0; \ +} + +#define MOV_MSF(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte0; \ + _to_->Byte1 = _from_->Byte1; \ + _to_->Byte2 = _from_->Byte2; \ +} + +#define MOV_MSF_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte2; \ + _to_->Byte1 = _from_->Byte1; \ + _to_->Byte2 = _from_->Byte0; \ +} + +#define XCHG_DD(a,b) \ +{ \ + ULONG _temp_; \ + PULONG _from_, _to_; \ + _from_ = ((PULONG)&(b)); \ + _to_ = ((PULONG)&(a)); \ + _temp_ = *_from_; \ + *_from_ = *_to_; \ + *_to_ = _temp_; \ +} + +#endif // _X86_ + +#endif // __CROSSNT_MISC__H__ + +#define CONV_TO_LL(a) a.Byte0 | a.Byte1 << 8 | a.Byte2 << 16 | a.Byte3 << 8 +#define MSF_TO_LBA(Minutes,Seconds,Frames) \ + (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150)) + +#define PacketFixed2Variable(x,ps) ( ( ( (x) / (ps) ) * (ps+7) ) + ( (x) & (ps-1) ) ) +#define PacketVariable2Fixed(x,ps) ( ( ( (x) / (ps+7) ) * (ps) ) + ( (((x) % (ps+7)) < (ps)) ? ((x) % (ps+7)) : (ps-1) ) ) + +#define WAIT_FOR_XXX_EMU_DELAY 1000LL // 0.0001 s + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#ifndef offsetof +#define offsetof(type, field) (ULONG)&(((type *)0)->field) +#endif //offsetof + +#ifdef __cplusplus +}; +#endif + +#endif // __TOOLS_H__ diff --git a/reactos/drivers/filesystems/udfs/Include/udf_common.h b/reactos/drivers/filesystems/udfs/Include/udf_common.h new file mode 100644 index 00000000000..a87c45fd022 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/udf_common.h @@ -0,0 +1,682 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#ifndef __UDF_COMMON_STRUCT__H__ +#define __UDF_COMMON_STRUCT__H__ + +typedef enum _UDFFSD_MEDIA_TYPE { + MediaUnknown = 0, + MediaHdd, + MediaCdr, + MediaCdrw, + MediaCdrom, + MediaZip, + MediaFloppy, + MediaDvdr, + MediaDvdrw +} UDFFSD_MEDIA_TYPE; + +#define MAX_UDFFSD_MEDIA_TYPE ((ULONG)MediaFloppy) + +typedef struct _UDF_KEY_LIST { + int32 d[4]; +} UDF_KEY_LIST, *PUDF_KEY_LIST; + +struct UDF_MEDIA_CLASS_NAMES +{ + UDFFSD_MEDIA_TYPE MediaClass; + PWCHAR ClassName; +}; + +extern struct UDF_MEDIA_CLASS_NAMES UDFMediaClassName[]; + +#define MAX_ANCHOR_LOCATIONS 11 +#define MAX_SPARING_TABLE_LOCATIONS 32 + +typedef struct _UDFVolumeControlBlock { + +#ifdef _UDF_STRUCTURES_H_ + + //--------------- + // Kernel-only data: + //--------------- + + //--------------- + // Fcb data + //--------------- + + union { + struct { + UDFIdentifier NodeIdentifier; + // compatibility field + PtrUDFNTRequiredFCB NTRequiredFCB; + // UDF related data (compatibility field) + PVOID Reserved0; + // this FCB belongs to some mounted logical volume + // (compatibility field - pointer to itself) + struct _UDFVolumeControlBlock* Vcb; + // a global list of all FCB structures associated with the VCB + LIST_ENTRY NextFCB; + // some state information for the FCB is maintained using the + // flags field + uint32 FCBFlags; + // all CCB's for this particular FCB are linked off the following + // list head. + // For volume open operations, we do not create a FCB (we use the VCB + // directly instead). Therefore, all CCB structures for the volume + // open operation are linked directly off the VCB + LIST_ENTRY VolumeOpenListHead; // CCB + // A count of the number of open files/directories + // As long as the count is != 0, the volume cannot + // be dismounted or locked. + uint32 VolumeOpenCount; + uint32 Reserved2; + uint32 Reserved3; + + PVOID Reserved4; + ERESOURCE CcbListResource; + + struct _UDFFileControlBlock* ParentFcb; + // Pointer to IrpContextLite in delayed queue. + struct _UDFIrpContextLite* IrpContextLite; + uint32 CcbCount; + }; + UDFFCB VcbAsFcb; + }; + + //--------------- + // Vcb-only data + //--------------- + + uint32 VCBOpenCount; + uint32 VCBOpenCountRO; + uint32 VCBHandleCount; + // a resource to protect the fields contained within the VCB + ERESOURCE FcbListResource; + ERESOURCE FlushResource; + // each VCB is accessible off a global linked list + LIST_ENTRY NextVCB; + // each VCB points to a VPB structure created by the NT I/O Manager + PVPB Vpb; + // we will maintain a global list of IRP's that are pending + // because of a directory notify request. + LIST_ENTRY NextNotifyIRP; + // the above list is protected only by the mutex declared below + PNOTIFY_SYNC NotifyIRPMutex; + // for each mounted volume, we create a device object. Here then + // is a back pointer to that device object + PDEVICE_OBJECT VCBDeviceObject; + BOOLEAN ShutdownRegistered; + // We also retain a pointer to the physical device object on which we + // have mounted ourselves. The I/O Manager passes us a pointer to this + // device object when requesting a mount operation. + PDEVICE_OBJECT TargetDeviceObject; + UNICODE_STRING TargetDevName; + PWSTR DefaultRegName; + // the volume structure contains a pointer to the root directory FCB + PtrUDFFCB RootDirFCB; + // the complete name of the user visible drive letter we serve + PUCHAR PtrVolumePath; + // Pointer to a stream file object created for the volume information + // to be more easily read from secondary storage (with the support of + // the NT Cache Manager). +/* PFILE_OBJECT PtrStreamFileObject; + // Required to use the Cache Manager. +*/ + struct _FILE_SYSTEM_STATISTICS* Statistics; + // Volume lock file object - used in Lock/Unlock routines + ULONG VolumeLockPID; + PFILE_OBJECT VolumeLockFileObject; + DEVICE_TYPE FsDeviceType; + + // The following field tells how many requests for this volume have + // either been enqueued to ExWorker threads or are currently being + // serviced by ExWorker threads. If the number goes above + // a certain threshold, put the request on the overflow queue to be + // executed later. + ULONG PostedRequestCount; + ULONG ThreadsPerCpu; + // The following field indicates the number of IRP's waiting + // to be serviced in the overflow queue. + ULONG OverflowQueueCount; + // The following field contains the queue header of the overflow queue. + // The Overflow queue is a list of IRP's linked via the IRP's ListEntry + // field. + LIST_ENTRY OverflowQueue; + // The following spinlock protects access to all the above fields. + KSPIN_LOCK OverflowQueueSpinLock; + ULONG StopOverflowQueue; + ULONG SystemCacheGran; + + //--------------- + // + //--------------- + + // Eject Request waiter + struct _UDFEjectWaitContext* EjectWaiter; + KEVENT WaiterStopped; + ULONG SoftEjectReq; + + ULONG BM_FlushTime; + ULONG BM_FlushPriod; + ULONG Tree_FlushTime; + ULONG Tree_FlushPriod; + ULONG SkipCountLimit; + ULONG SkipEjectCountLimit; + +/* // XP CD Burner related data + UNICODE_STRING CDBurnerVolume; + BOOLEAN CDBurnerVolumeValid; +*/ + // Background writes counter + LONG BGWriters; + // File Id cache + struct _UDFFileIDCacheItem* FileIdCache; + ULONG FileIdCount; + // + ULONG MediaLockCount; + + BOOLEAN IsVolumeJustMounted; +#else + + //--------------- + // Win32-only data: + //--------------- + + #ifdef _BROWSE_UDF_ + PUDF_FILE_INFO RootFileInfo; + #endif + + + #ifdef UDF_FORMAT_MEDIA + struct _UDFFmtState* fms; + #endif //UDF_FORMAT_MEDIA + + + PDEVICE_OBJECT TargetDeviceObject; + ULONG FsDeviceType; + ULONG PhDeviceType; + +#endif //_UDF_STRUCTURES_H_ + + // FS size cache + LONGLONG TotalAllocUnits; + LONGLONG FreeAllocUnits; + LONGLONG EstimatedFreeUnits; + + // a resource to protect the fields contained within the VCB + ERESOURCE VCBResource; + ERESOURCE BitMapResource1; + ERESOURCE FileIdResource; + ERESOURCE DlocResource; + ERESOURCE DlocResource2; + ERESOURCE PreallocResource; + ERESOURCE IoResource; + + //--------------- + // Physical media parameters + //--------------- + + ULONG BlockSize; + ULONG BlockSizeBits; + ULONG WriteBlockSize; + ULONG LBlockSize; + ULONG LBlockSizeBits; + ULONG LB2B_Bits; + // Number of last session + ULONG LastSession; + ULONG FirstTrackNum; + ULONG FirstTrackNumLastSes; + ULONG LastTrackNum; + // First & Last LBA of the last session + ULONG FirstLBA; + ULONG FirstLBALastSes; + ULONG LastLBA; + // Last writable LBA + ULONG LastPossibleLBA; + // First writable LBA + ULONG NWA; + // sector type map + struct _UDFTrackMap* TrackMap; + ULONG LastModifiedTrack; + ULONG LastReadTrack; + ULONG CdrwBufferSize; + ULONG CdrwBufferSizeCounter; + uint32 SavedFeatures; + // OPC info +// PCHAR OPC_buffer; + UCHAR OPCNum; + BOOLEAN OPCDone; + UCHAR MediaType; + UCHAR MediaClassEx; + + UCHAR DiscStat; + UCHAR PhErasable; + UCHAR PhDiskType; + UCHAR PhMediaCapFlags; + + UCHAR MRWStatus; + UCHAR UseEvent; + BOOLEAN BlankCD; + UCHAR Reserved; + + ULONG PhSerialNumber; + + // Speed control + SET_CD_SPEED_EX_USER_IN SpeedBuf; + ULONG MaxWriteSpeed; + ULONG MaxReadSpeed; + ULONG CurSpeed; + + BOOLEAN CDR_Mode; + BOOLEAN DVD_Mode; + BOOLEAN WriteParamsReq; + +#define SYNC_CACHE_RECOVERY_NONE 0 +#define SYNC_CACHE_RECOVERY_ATTEMPT 1 +#define SYNC_CACHE_RECOVERY_RETRY 2 + + UCHAR SyncCacheState; + + // W-cache + W_CACHE FastCache; + ULONG WCacheMaxFrames; + ULONG WCacheMaxBlocks; + ULONG WCacheBlocksPerFrameSh; + ULONG WCacheFramesToKeepFree; + + PCHAR ZBuffer; + PCHAR fZBuffer; + ULONG fZBufferSize; + PSEND_OPC_INFO_HEADER_USER_IN OPCh; + PGET_WRITE_MODE_USER_OUT WParams; + PGET_LAST_ERROR_USER_OUT Error; + + ULONG IoErrorCounter; + // Media change count (equal to the same field in CDFS VCB) + ULONG MediaChangeCount; + +#define INCREMENTAL_SEEK_NONE 0 +#define INCREMENTAL_SEEK_WORKAROUND 1 +#define INCREMENTAL_SEEK_DONE 2 + + UCHAR IncrementalSeekState; + + BOOLEAN VerifyOnWrite; + BOOLEAN DoNotCompareBeforeWrite; + BOOLEAN CacheChainedIo; + + ULONG MountPhErrorCount; + + // a set of flags that might mean something useful + uint32 VCBFlags; + BOOLEAN FP_disc; + + //--------------- + // UDF related data + //--------------- + +#ifdef _BROWSE_UDF_ + + // Anchors LBA + ULONG Anchor[MAX_ANCHOR_LOCATIONS]; + ULONG BadSeqLoc[MAX_ANCHOR_LOCATIONS*2]; + OSSTATUS BadSeqStatus[MAX_ANCHOR_LOCATIONS*2]; + ULONG BadSeqLocIndex; + // Volume label + UNICODE_STRING VolIdent; + // Volume creation time + int64 VolCreationTime; + // Root & SystemStream lb_addr + lb_addr RootLbAddr; + lb_addr SysStreamLbAddr; + // Number of partition + ULONG PartitionMaps; + // Pointer to partition structures + PUDFPartMap Partitions; + LogicalVolIntegrityDesc *LVid; + uint32 IntegrityType; + uint32 origIntegrityType; + extent_ad LVid_loc; + ULONG SerialNumber; + // on-disk structure version control + uint16 CurrentUDFRev; + uint16 minUDFReadRev; + uint16 minUDFWriteRev; + uint16 maxUDFWriteRev; + // file/dir counters for Mac OS + uint32 numFiles; + uint32 numDirs; + // VAT + uint32 InitVatCount; + uint32 VatCount; + uint32* Vat; + uint32 VatPartNdx; + PUDF_FILE_INFO VatFileInfo; + // sparing table + ULONG SparingCountFree; + ULONG SparingCount; + ULONG SparingBlockSize; + struct _SparingEntry* SparingTable; + uint32 SparingTableLoc[MAX_SPARING_TABLE_LOCATIONS]; + uint32 SparingTableCount; + uint32 SparingTableLength; + uint32 SparingTableModified; + // free space bitmap + ULONG FSBM_ByteCount; + // the following 2 fields are equal to NTIFS's RTL_BITMAP structure + ULONG FSBM_BitCount; + PCHAR FSBM_Bitmap; // 0 - free, 1 - used +#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS + PULONG FSBM_Bitmap_owners; // 0 - free + // -1 - used by unknown + // other - owner's FE location +#ifdef UDF_TRACK_FS_STRUCTURES + PEXTENT_MAP FsStructMap; + PULONG FE_link_counts; // 0 - free +#endif //UDF_TRACK_FS_STRUCTURES +#endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS + + PCHAR FSBM_OldBitmap; // 0 - free, 1 - used + ULONG BitmapModified; + + PCHAR ZSBM_Bitmap; // 0 - data, 1 - zero-filleld +#endif //_BROWSE_UDF_ + + PCHAR BSBM_Bitmap; // 0 - normal, 1 - bad-block + +#ifdef _BROWSE_UDF_ + // pointers to Volume Descriptor Sequences + ULONG VDS1; + ULONG VDS1_Len; + ULONG VDS2; + ULONG VDS2_Len; + + ULONG Modified; + + // System Stream Dir + PUDF_FILE_INFO SysSDirFileInfo; + // Non-alloc space + PUDF_FILE_INFO NonAllocFileInfo; + // Unique ID Mapping + PUDF_FILE_INFO UniqueIDMapFileInfo; + // Saved location of Primary Vol Descr (used for setting Label) + UDF_VDS_RECORD PVolDescAddr; + UDF_VDS_RECORD PVolDescAddr2; + // NSR flags + uint32 NSRDesc; + // File Id cache + ULONGLONG NextUniqueId; + // FE location cache + PUDF_DATALOC_INDEX DlocList; + ULONG DlocCount; + // FS compatibility + USHORT DefaultAllocMode; // Default alloc mode (from registry) + BOOLEAN UseExtendedFE; + BOOLEAN LowFreeSpace; + UDFFSD_MEDIA_TYPE MediaTypeEx; + ULONG DefaultUID; + ULONG DefaultGID; + ULONG DefaultAttr; // Default file attributes (NT-style) + + + UCHAR PartitialDamagedVolumeAction; + BOOLEAN NoFreeRelocationSpaceVolumeAction; + BOOLEAN WriteSecurity; + BOOLEAN FlushMedia; + BOOLEAN ForgetVolume; + UCHAR Reserved5[3]; + + // + ULONG FECharge; + ULONG FEChargeSDir; + ULONG PackDirThreshold; + ULONG SparseThreshold; // in blocks + + PUDF_ALLOCATION_CACHE_ITEM FEChargeCache; + ULONG FEChargeCacheMaxSize; + + PUDF_ALLOCATION_CACHE_ITEM PreallocCache; + ULONG PreallocCacheMaxSize; + + UDF_VERIFY_CTX VerifyCtx; + + PUCHAR Cfg; + ULONG CfgLength; + ULONG CfgVersion; + +#endif //_BROWSE_UDF_ + uint32 CompatFlags; + uint32 UserFSFlags; + UCHAR ShowBlankCd; + +} VCB, *PVCB; + + +// some valid flags for the VCB +#define UDF_VCB_FLAGS_VOLUME_MOUNTED (0x00000001) +#define UDF_VCB_FLAGS_VOLUME_LOCKED (0x00000002) +#define UDF_VCB_FLAGS_BEING_DISMOUNTED (0x00000004) +#define UDF_VCB_FLAGS_SHUTDOWN (0x00000008) +#define UDF_VCB_FLAGS_VOLUME_READ_ONLY (0x00000010) + +#define UDF_VCB_FLAGS_VCB_INITIALIZED (0x00000020) +#define UDF_VCB_FLAGS_OUR_DEVICE_DRIVER (0x00000040) +#define UDF_VCB_FLAGS_NO_SYNC_CACHE (0x00000080) +#define UDF_VCB_FLAGS_REMOVABLE_MEDIA (0x00000100) +#define UDF_VCB_FLAGS_MEDIA_LOCKED (0x00000200) +#define UDF_VCB_SKIP_EJECT_CHECK (0x00000400) +//#define UDF_VCB_FS_BITMAP_MODIFIED (0x00000800) // moved to separate flag +#define UDF_VCB_LAST_WRITE (0x00001000) +#define UDF_VCB_FLAGS_TRACKMAP (0x00002000) +#define UDF_VCB_ASSUME_ALL_USED (0x00004000) + +#define UDF_VCB_FLAGS_RAW_DISK (0x00040000) +#define UDF_VCB_FLAGS_USE_STD (0x00080000) + +#define UDF_VCB_FLAGS_STOP_WAITER_EVENT (0x00100000) +#define UDF_VCB_FLAGS_NO_DELAYED_CLOSE (0x00200000) +#define UDF_VCB_FLAGS_MEDIA_READ_ONLY (0x00400000) + +#define UDF_VCB_FLAGS_FLUSH_BREAK_REQ (0x01000000) +#define UDF_VCB_FLAGS_EJECT_REQ (0x02000000) +#define UDF_VCB_FLAGS_FORCE_SYNC_CACHE (0x04000000) + +#define UDF_VCB_FLAGS_USE_CAV (0x08000000) +#define UDF_VCB_FLAGS_UNSAFE_IOCTL (0x10000000) +#define UDF_VCB_FLAGS_DEAD (0x20000000) // device unexpectedly disappeared + + +// flags for FS Interface Compatibility +#define UDF_VCB_IC_UPDATE_ACCESS_TIME (0x00000001) +#define UDF_VCB_IC_UPDATE_MODIFY_TIME (0x00000002) +#define UDF_VCB_IC_UPDATE_ATTR_TIME (0x00000004) +#define UDF_VCB_IC_UPDATE_ARCH_BIT (0x00000008) +#define UDF_VCB_IC_UPDATE_DIR_WRITE (0x00000010) +#define UDF_VCB_IC_UPDATE_DIR_READ (0x00000020) +#define UDF_VCB_IC_WRITE_IN_RO_DIR (0x00000040) +#define UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME (0x00000080) +#define UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS (0x00000100) +#define UDF_VCB_IC_HW_RO (0x00000200) +#define UDF_VCB_IC_OS_NATIVE_DOS_NAME (0x00000400) +#define UDF_VCB_IC_FORCE_WRITE_THROUGH (0x00000800) +#define UDF_VCB_IC_FORCE_HW_RO (0x00001000) +#define UDF_VCB_IC_IGNORE_SEQUENTIAL_IO (0x00002000) +#define UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE (0x00004000) +#define UDF_VCB_IC_BAD_RW_SEEK (0x00008000) +#define UDF_VCB_IC_FP_ADDR_PROBLEM (0x00010000) +#define UDF_VCB_IC_MRW_ADDR_PROBLEM (0x00020000) +#define UDF_VCB_IC_BAD_DVD_LAST_LBA (0x00040000) +#define UDF_VCB_IC_SYNCCACHE_BEFORE_READ (0x00080000) +#define UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS (0x00100000) +#define UDF_VCB_IC_SOFT_RO (0x00200000) + +#define UDF_VCB_IC_DIRTY_RO (0x04000000) +#define UDF_VCB_IC_W2K_COMPAT_VLABEL (0x08000000) +#define UDF_VCB_IC_CACHE_BAD_VDS (0x10000000) +#define UDF_VCB_IC_WAIT_CD_SPINUP (0x20000000) +#define UDF_VCB_IC_SHOW_BLANK_CD (0x40000000) +#define UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT (0x80000000) + +// Some defines +#define UDFIsDvdMedia(Vcb) (Vcb->DVD_Mode) +#define UDFIsWriteParamsReq(Vcb) (Vcb->WriteParamsReq && !Vcb->DVD_Mode) + +/************************************************************************** + we will store all of our global variables in one structure. + Global variables are not specific to any mounted volume BUT + by definition are required for successful operation of the + FSD implementation. +**************************************************************************/ +typedef struct _UDFData { + +#ifdef _UDF_STRUCTURES_H_ + UDFIdentifier NodeIdentifier; + // the fields in this list are protected by the following resource + ERESOURCE GlobalDataResource; + // each driver has a driver object created for it by the NT I/O Mgr. + // we are no exception to this rule. + PDRIVER_OBJECT DriverObject; + // we will create a device object for our FSD as well ... + // Although not really required, it helps if a helper application + // writen by us wishes to send us control information via + // IOCTL requests ... + PDEVICE_OBJECT UDFDeviceObject; + PDEVICE_OBJECT UDFDeviceObject_CD; + PDEVICE_OBJECT UDFDeviceObject_HDD; + PDEVICE_OBJECT UDFDeviceObject_TAPE; + PDEVICE_OBJECT UDFDeviceObject_OTHER; + PDEVICE_OBJECT UDFFilterDeviceObject; + // we will keep a list of all logical volumes for our UDF FSD + LIST_ENTRY VCBQueue; + // the NT Cache Manager, the I/O Manager and we will conspire + // to bypass IRP usage using the function pointers contained + // in the following structure + FAST_IO_DISPATCH UDFFastIoDispatch; + // The NT Cache Manager uses the following call backs to ensure + // correct locking hierarchy is maintained + CACHE_MANAGER_CALLBACKS CacheMgrCallBacks; + // structures allocated from a zone need some fields here. Note + // that under version 4.0, it might be better to use lookaside + // lists + KSPIN_LOCK ZoneAllocationSpinLock; + ZONE_HEADER ObjectNameZoneHeader; + ZONE_HEADER CCBZoneHeader; + ZONE_HEADER FCBZoneHeader; + ZONE_HEADER IrpContextZoneHeader; +// ZONE_HEADER FileInfoZoneHeader; + VOID *ObjectNameZone; + VOID *CCBZone; + VOID *FCBZone; + VOID *IrpContextZone; +// VOID *FileInfoZone; + // currently, there is a single default zone size value used for + // all zones. This should ideally be changed by you to be 1 per + // type of zone (e.g. a default size for the FCB zone might be + // different from the default size for the ByteLock zone). + +#ifdef EVALUATION_TIME_LIMIT + UDF_KEY_LIST CurrentKeyHash; +#endif //EVALUATION_TIME_LIMIT + // Of course, you will need to use different values (min/max) + // for lookaside lists (if you decide to use them instead) + uint32 DefaultZoneSizeInNumStructs; + // Handle returned by the MUP is stored here. + HANDLE MupHandle; + // IsSync Resource +// ERESOURCE IsSyncResource; + // Is operation synchronous flag +// BOOLEAN IsSync; +#ifdef EVALUATION_TIME_LIMIT + ULONG Saved_j; +#endif //EVALUATION_TIME_LIMIT + + // delayed close support + ERESOURCE DelayedCloseResource; + ULONG MaxDelayedCloseCount; + ULONG DelayedCloseCount; + ULONG MinDelayedCloseCount; + ULONG MaxDirDelayedCloseCount; + ULONG DirDelayedCloseCount; + ULONG MinDirDelayedCloseCount; + LIST_ENTRY DelayedCloseQueue; + LIST_ENTRY DirDelayedCloseQueue; + WORK_QUEUE_ITEM CloseItem; + WORK_QUEUE_ITEM LicenseKeyItem; + BOOLEAN LicenseKeyItemStarted; + BOOLEAN FspCloseActive; + BOOLEAN ReduceDelayedClose; + BOOLEAN ReduceDirDelayedClose; + +#ifdef EVALUATION_TIME_LIMIT + LARGE_INTEGER UDFCurrentTime; +#endif //EVALUATION_TIME_LIMIT + ULONG CPU_Count; + LARGE_INTEGER UDFLargeZero; + + // mount event (for udf gui app) + PKEVENT MountEvent; + +#ifdef EVALUATION_TIME_LIMIT + WCHAR LicenseKeyW[16+1]; + WCHAR LKPadding[1]; +#endif //EVALUATION_TIME_LIMIT + +#endif //_UDF_STRUCTURES_H_ + //HKEY hUdfRootKey; + UNICODE_STRING SavedRegPath; + UNICODE_STRING UnicodeStrRoot; + UNICODE_STRING UnicodeStrSDir; + UNICODE_STRING AclName; +// WCHAR UnicodeStrRootBuffer[2]; +#ifdef EVALUATION_TIME_LIMIT + ULONG iTime; + ULONG iVer; + ULONG iTrial; +#endif //EVALUATION_TIME_LIMIT + + ULONG WCacheMaxFrames; + ULONG WCacheMaxBlocks; + ULONG WCacheBlocksPerFrameSh; + ULONG WCacheFramesToKeepFree; + +#ifdef EVALUATION_TIME_LIMIT + UCHAR Page2Padding[PAGE_SIZE]; +#endif //EVALUATION_TIME_LIMIT + + // some state information is maintained in the flags field + uint32 UDFFlags; + + PVOID AutoFormatCount; + +} UDFData, *PtrUDFData; + +// valid flag values for the global data structure +#define UDF_DATA_FLAGS_RESOURCE_INITIALIZED (0x00000001) +#define UDF_DATA_FLAGS_ZONES_INITIALIZED (0x00000002) +#define UDF_DATA_FLAGS_BEING_UNLOADED (0x00000004) +#define UDF_DATA_FLAGS_UNREGISTERED (0x00000008) + +/**/ + +extern VOID UDFSetModified( + IN PVCB Vcb + ); + +extern VOID UDFPreClrModified( + IN PVCB Vcb + ); + +extern VOID UDFClrModified( + IN PVCB Vcb + ); + + +#define FILE_ID_CACHE_GRANULARITY 16 +#define DLOC_LIST_GRANULARITY 16 + +typedef LONGLONG FILE_ID; +typedef FILE_ID *PFILE_ID; + +#endif //__UDF_COMMON_STRUCT__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/udf_lib_common.h b/reactos/drivers/filesystems/udfs/Include/udf_lib_common.h new file mode 100644 index 00000000000..0fe5aaa9a6c --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/udf_lib_common.h @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDF_LIB_COMMON__H__ +#define __UDF_LIB_COMMON__H__ + +#ifndef WITHOUT_FORMATTER +#include "udferr_usr.h" +#endif + +typedef LONG UDF_STATUS; + +#define UDF_SUCCESS(x) ( (UDF_STATUS)(x)>=0 ) + +typedef UDF_STATUS (*PREAD_FUNCTION)( + PVOID lpParameter, + PVOID lpBuffer, + ULONG nLength, + LONGLONG liOffset, + PULONG lpNumberOfBytesRead +); + +typedef UDF_STATUS (*PWRITE_FUNCTION)( + PVOID lpParameter, + PVOID lpBuffer, + ULONG nLength, + LONGLONG liOffset, + PULONG lpNumberOfBytesRead +); + +typedef UDF_STATUS (*PIOCTL_FUNCTION)( + PVOID lpParameter, + DWORD dwIoControlCode, + LPVOID lpInBuffer, + DWORD nInBufferSize, + LPVOID lpOutBuffer, + DWORD nOutBufferSize, + LPDWORD lpBytesReturned +); + +// For formatter + +typedef UDF_STATUS (*PREOPEN_FUNCTION)( + PVOID* lpParameter +); + +typedef UDF_STATUS (*PGETSIZE_FUNCTION)( + PVOID lpParameter, + __int64* size, + ULONG* block_size +); + +typedef UDF_STATUS (*PFLUSH_FUNCTION)( + PVOID lpParameter +); + +#endif //__UDF_LIB_COMMON__H__ diff --git a/reactos/drivers/filesystems/udfs/Include/udf_reg.h b/reactos/drivers/filesystems/udfs/Include/udf_reg.h new file mode 100644 index 00000000000..824499077b5 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/udf_reg.h @@ -0,0 +1,257 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __DWUDF_REGISTRY__H__ +#define __DWUDF_REGISTRY__H__ + +#define DWN_MANAGER_SVC_NAME "DwUdfMgr" +#define DWN_MANAGER_PIPE_NAME "\\\\.\\pipe\\DwUdfManager" + +#define UDF_SERVICE TEXT("DwUdf") +#define CDRW_SERVICE TEXT("DwCdrw") + +#define UDF_KEY TEXT("Software\\DVD Write Now\\UDF") +#define CDRW_SERVICE_PATH TEXT("SYSTEM\\CurrentControlSet\\Services\\") CDRW_SERVICE + +#define UDF_SERVICE_PATH TEXT("SYSTEM\\CurrentControlSet\\Services\\") UDF_SERVICE +#define UDF_SERVICE_PATH_W L"SYSTEM\\CurrentControlSet\\Services\\DwUdf" + +#define UDF_SERVICE_PARAM_PATH TEXT("SYSTEM\\CurrentControlSet\\Services\\DwUdf\\Parameters") +#define UDF_SERVICE_PARAM_PATH_W L"SYSTEM\\CurrentControlSet\\Services\\DwUdf\\Parameters" + +#define UDF_SERVICE_PATH_DEAULT TEXT("SYSTEM\\CurrentControlSet\\Services\\DwUdf\\Parameters_Default") +#define UDF_SERVICE_PATH_DEAULT_W L"SYSTEM\\CurrentControlSet\\Services\\DwUdf\\Parameters_Default" + +#define CDROM_CLASS_PATH TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E965-E325-11CE-BFC1-08002BE10318}") +#define REG_UPPER_FILTER_NAME TEXT("UpperFilters") + +#define UDF_FS_NAME L"\\Udf" +#define UDF_FS_NAME_CD L"\\UdfCd" +#define UDF_FS_NAME_HDD L"\\UdfHdd" +//#define UDF_FS_NAME_VIRT L"\\UdfVirt" +#define UDF_FS_NAME_OTHER L"\\UdfOther" +#define UDF_FS_NAME_TAPE L"\\UdfTape" + +#define UDF_DOS_FS_NAME L"\\DosDevices\\DwUdf" +#define UDF_DOS_FS_NAME_USER "\\\\.\\DwUdf" + +#define CDFS_REC_DEVICE_OBJECT_NAME L"\\CdfsRecognizer" +#define CDFS_DEVICE_OBJECT_NAME L"\\Cdfs" +#define UDFS_REC_DEVICE_OBJECT_NAME L"\\UdfsCdromRecognizer" +#define UDFS_DEVICE_OBJECT_NAME L"\\UdfsCdrom" +#define UDFSD_REC_DEVICE_OBJECT_NAME L"\\UdfsDiskRecognizer" +#define UDFSD_DEVICE_OBJECT_NAME L"\\UdfsDisk" + +#define UDF_ROOTDIR_NAME L"\\" +#define UDF_SN_NT_SYM_LINK L"$UDF NT SymLink" + +#ifndef PRETEND_NTFS +#define UDF_FS_TITLE_DVDRAM L"UDF-DVDRAM" +#define UDF_FS_TITLE_DVDpRW L"UDF-DVD+RW" +#define UDF_FS_TITLE_DVDpR L"UDF-DVD+R" +#define UDF_FS_TITLE_DVDRW L"UDF-DVDRW" +#define UDF_FS_TITLE_DVDR L"UDF-DVDR" +#define UDF_FS_TITLE_DVDROM L"UDF-DVDROM" +#define UDF_FS_TITLE_CDRW L"UDF-CDRW" +#define UDF_FS_TITLE_CDR L"UDF-CDR" +#define UDF_FS_TITLE_CDROM L"UDF-CDROM" +#define UDF_FS_TITLE_HDD L"UDF" +#else //PRETEND_NTFS +#define UDF_FS_TITLE_DVDRAM L"NTFS" +#define UDF_FS_TITLE_DVDpR L"NTFS" +#define UDF_FS_TITLE_DVDpR L"NTFS" +#define UDF_FS_TITLE_DVDRW L"NTFS" +#define UDF_FS_TITLE_DVDR L"NTFS" +#define UDF_FS_TITLE_DVDROM L"NTFS" +#define UDF_FS_TITLE_CDRW L"NTFS" +#define UDF_FS_TITLE_CDR L"NTFS" +#define UDF_FS_TITLE_CDROM L"NTFS" +#define UDF_FS_TITLE_HDD L"NTFS" +#endif //PRETEND_NTFS + +#define REG_DEFAULT_UNKNOWN L"_Default\\Unknown" +#define REG_DEFAULT_HDD L"_Default\\Hdd" +#define REG_DEFAULT_CDR L"_Default\\Cdr" +#define REG_DEFAULT_CDRW L"_Default\\Cdrw" +#define REG_DEFAULT_CDROM L"_Default\\Cdrom" +#define REG_DEFAULT_ZIP L"_Default\\Zip" +#define REG_DEFAULT_FLOPPY L"_Default\\Floppy" +#define REG_DEFAULT_DVDR L"_Default\\Dvdr" +#define REG_DEFAULT_DVDRW L"_Default\\Dvdrw" + +#define REG_NAMELESS_DEV L"\\_Nameless_" + +#define UDF_DEFAULT_LABEL L"Write Now" +#define UDF_DEFAULT_LABEL_USER "Write Now" +#define UDF_MAX_LABEL_LENGTH 11 // Windows shell limitation + +#define UDF_FS_TITLE_BLANK L"Blank media" +#define UDF_FS_TITLE_UNKNOWN L"Unknown" +#define UDF_BLANK_VOLUME_LABEL L"Blank CD" + +#define REG_CD_BURNER_KEY_NAME L"\\REGISTRY\\USER\\CURRENTUSER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CD Burning" +#define REG_CD_BURNER_VOLUME_NAME L"CD Recorder Drive" + +#define REG_USEEXTENDEDFE_NAME L"UseExtendedFE" +#define REG_USEEXTENDEDFE_NAME_USER "UseExtendedFE" + +#define REG_DEFALLOCMODE_NAME L"DefaultAllocMode" +#define REG_DEFALLOCMODE_NAME_USER "DefaultAllocMode" + +#define UDF_DEFAULT_UID_NAME L"DefaultUID" +#define UDF_DEFAULT_UID_NAME_USER "DefaultUID" + +#define UDF_DEFAULT_GID_NAME L"DefaultGID" +#define UDF_DEFAULT_GID_NAME_USER "DefaultGID" + +#define UDF_DIR_PACK_THRESHOLD_NAME L"PackDirThreshold" +#define UDF_DIR_PACK_THRESHOLD_NAME_USER "PackDirThreshold" + +#define UDF_FE_CHARGE_NAME L"FECharge" +#define UDF_FE_CHARGE_NAME_USER "FECharge" + +#define UDF_FE_CHARGE_SDIR_NAME L"FEChargeSDir" +#define UDF_FE_CHARGE_SDIR_NAME_USER "FEChargeSDir" + +#define UDF_BM_FLUSH_PERIOD_NAME L"BitmapFlushPeriod" +#define UDF_BM_FLUSH_PERIOD_NAME_USER "BitmapFlushPeriod" + +#define UDF_TREE_FLUSH_PERIOD_NAME L"DirTreeFlushPeriod" +#define UDF_TREE_FLUSH_PERIOD_NAME_USER "DirTreeFlushPeriod" + +#define UDF_NO_UPDATE_PERIOD_NAME L"MaxNoUpdatePeriod" +#define UDF_NO_UPDATE_PERIOD_NAME_USER "MaxNoUpdatePeriod" + +#define UDF_NO_EJECT_PERIOD_NAME L"MaxNoEjectPeriod" +#define UDF_NO_EJECT_PERIOD_NAME_USER "MaxNoEjectPeriod" + +#define UDF_FSP_THREAD_PER_CPU_NAME L"ThreadsPerCpu" +#define UDF_FSP_THREAD_PER_CPU_NAME_USER "ThreadsPerCpu" + +#define UDF_READAHEAD_GRAN_NAME L"ReadAheadGranlarity" +#define UDF_READAHEAD_GRAN_NAME_USER "ReadAheadGranlarity" + +/*#define UDF_W_SECURITY_CDRW_NAME L"WriteSecurityOnCDRW" +#define UDF_W_SECURITY_CDRW_NAME_USER "WriteSecurityOnCDRW" + +#define UDF_W_SECURITY_CDR_NAME L"WriteSecurityOnCDR" +#define UDF_W_SECURITY_CDR_NAME_USER "WriteSecurityOnCDR"*/ + +#define UDF_SPARSE_THRESHOLD_NAME L"SparseThreshold" +#define UDF_SPARSE_THRESHOLD_NAME_USER "SparseThreshold" + +#define UDF_VERIFY_ON_WRITE_NAME L"VerifyOnWrite" +#define UDF_VERIFY_ON_WRITE_NAME_USER "VerifyOnWrite" + +#define UDF_UPDATE_TIMES_ATTR L"UpdateFileTimesAttrChg" +#define UDF_UPDATE_TIMES_ATTR_USER "UpdateFileTimesAttrChg" + +#define UDF_UPDATE_TIMES_MOD L"UpdateFileTimesLastWrite" +#define UDF_UPDATE_TIMES_MOD_USER "UpdateFileTimesLastWrite" + +#define UDF_UPDATE_TIMES_ACCS L"UpdateFileTimesLastAccess" +#define UDF_UPDATE_TIMES_ACCS_USER "UpdateFileTimesLastAccess" + +#define UDF_UPDATE_ATTR_ARCH L"UpdateFileAttrArchive" +#define UDF_UPDATE_ATTR_ARCH_USER "UpdateFileAttrArchive" + +#define UDF_UPDATE_DIR_TIMES_ATTR_W L"UpdateDirAttrAndTimesOnModify" +#define UDF_UPDATE_DIR_TIMES_ATTR_W_USER "UpdateDirAttrAndTimesOnModify" + +#define UDF_UPDATE_DIR_TIMES_ATTR_R L"UpdateDirAttrAndTimesOnAccess" +#define UDF_UPDATE_DIR_TIMES_ATTR_R_USER "UpdateDirAttrAndTimesOnAccess" + +#define UDF_ALLOW_WRITE_IN_RO_DIR L"AllowCreateInsideReadOnlyDirectory" +#define UDF_ALLOW_WRITE_IN_RO_DIR_USER "AllowCreateInsideReadOnlyDirectory" + +#define UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR L"AllowUpdateAccessTimeInUnchangedDir" +#define UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR_USER "AllowUpdateAccessTimeInUnchangedDir" + +#define UDF_W2K_COMPAT_ALLOC_DESCS L"AllocDescCompatW2K" +#define UDF_W2K_COMPAT_ALLOC_DESCS_USER "AllocDescCompatW2K" + +#define UDF_W2K_COMPAT_VLABEL L"VolumeLabelCompatW2K" +#define UDF_W2K_COMPAT_VLABEL_USER "VolumeLabelCompatW2K" + +#define UDF_INSTANT_COMPAT_ALLOC_DESCS L"AllocDescCompatInstantBurner" +#define UDF_INSTANT_COMPAT_ALLOC_DESCS_USER "AllocDescCompatInstantBurner" + +#define UDF_HANDLE_HW_RO L"HandleHWReadOnly" +#define UDF_HANDLE_HW_RO_USER "HandleHWReadOnly" + +#define UDF_HANDLE_SOFT_RO L"HandleSoftReadOnly" +#define UDF_HANDLE_SOFT_RO_USER "HandleSoftReadOnly" + +#define UDF_FLUSH_MEDIA L"FlushMedia" +#define UDF_FLUSH_MEDIA_USER "FlushMedia" + +#define UDF_FORCE_MOUNT_ALL L"ForcedMountAllAsUDF" +#define UDF_FORCE_MOUNT_ALL_USER "ForcedMountAllAsUDF" + +#define UDF_COMPARE_BEFORE_WRITE L"CompareBeforeWrite" +#define UDF_COMPARE_BEFORE_WRITE_USER "CompareBeforeWrite" + +#define UDF_CACHE_SIZE_MULTIPLIER L"WCacheSizeMultiplier" +#define UDF_CACHE_SIZE_MULTIPLIER_USER "WCacheSizeMultiplier" + +#define UDF_CHAINED_IO L"CacheChainedIo" +#define UDF_CHAINED_IO_USER "CacheChainedIo" + +#define UDF_OS_NATIVE_DOS_NAME L"UseOsNativeDOSName" +#define UDF_OS_NATIVE_DOS_NAME_USER "UseOsNativeDOSName" + +#define UDF_FORCE_WRITE_THROUGH_NAME L"ForceWriteThrough" +#define UDF_FORCE_WRITE_THROUGH_NAME_USER "ForceWriteThrough" + +#define UDF_FORCE_HW_RO L"ForceHWReadOnly" +#define UDF_FORCE_HW_RO_USER "ForceHWReadOnly" + +#define UDF_IGNORE_SEQUENTIAL_IO L"IgnoreSequantialIo" +#define UDF_IGNORE_SEQUENTIAL_IO_USER "IgnoreSequantialIo" + +#define UDF_PART_DAMAGED_BEHAVIOR L"PartitialDamagedVolumeAction" +#define UDF_PART_DAMAGED_BEHAVIOR_USER "PartitialDamagedVolumeAction" + +#define UDF_NO_SPARE_BEHAVIOR L"NoFreeRelocationSpaceVolumeAction" +#define UDF_NO_SPARE_BEHAVIOR_USER "NoFreeRelocationSpaceVolumeAction" + +#define UDF_DIRTY_VOLUME_BEHAVIOR L"DirtyVolumeVolumeAction" +#define UDF_DIRTY_VOLUME_BEHAVIOR_USER "DirtyVolumeVolumeAction" + +#define UDF_SHOW_BLANK_CD L"ShowBlankCd" +#define UDF_SHOW_BLANK_CD_USER "ShowBlankCd" + +#define UDF_WAIT_CD_SPINUP L"WaitCdSpinUpOnMount" +#define UDF_WAIT_CD_SPINUP_USER "WaitCdSpinUpOnMount" + +#define UDF_AUTOFORMAT L"Autoformat" +#define UDF_AUTOFORMAT_USER "Autoformat" + +#define UDF_CACHE_BAD_VDS L"CacheBadVDSLocations" +#define UDF_CACHE_BAD_VDS_USER "CacheBadVDSLocations" + +#define UDF_USE_EJECT_BUTTON L"UseEjectButton" +#define UDF_USE_EJECT_BUTTON_USER "UseEjectButton" + +#define UDF_LICENSE_KEY L"LicenseKey" +#define UDF_LICENSE_KEY_USER "LicenseKey" + +#define REG_MOUNT_ON_CDONLY_NAME L"Mount_CdOnly" +#define REG_MOUNT_ON_CDONLY_NAME_USER "Mount_CdOnly" + +#define REG_MOUNT_ON_HDD_NAME L"Mount_Hdd" +#define REG_MOUNT_ON_HDD_NAME_USER "Mount_Hdd" + +#define REG_MOUNT_ON_ZIP_NAME L"Mount_Zip" +#define REG_MOUNT_ON_ZIP_NAME_USER "Mount_Zip" + + +/// Name of the console formatter tool +#define UDFFMT TEXT("DwConFmtUdf.exe") +#define UDFFMTGUI TEXT("DwGuiFmtUdf.exe") +#define REGISTER_APP TEXT("DwRegister.exe") + + +#endif //__DWUDF_REGISTRY__H__ \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/Include/udferr_usr.cpp b/reactos/drivers/filesystems/udfs/Include/udferr_usr.cpp new file mode 100644 index 00000000000..3f6209e720a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/udferr_usr.cpp @@ -0,0 +1,117 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udferr_usr.h" + +struct err_msg_item mkudf_err_msg[] = { + {MKUDF_OK , "Format completed succesfully"}, + #include "udferr_usr_cpp.h" + //{MKUDF_HW_READ_ONLY , "Read-only media"}, + //{MKUDF_CANT_BLANK , "Can't erase disk"}, + {MKUDF_INVALID_PARAM_MT , "Unknown media type specified"}, + {MKUDF_INVALID_PARAM_PT , "Unknown partition type requested"}, + {MKUDF_INVALID_PARAM , "Invalid comand line"}, + {MKUDF_HW_CANT_READ_LAYOUT , "Can't read disk layout"}, + {MKUDF_AUTO_BLOCKCOUNT_FAILED , "Can't obtain last available block address"}, + {MKUDF_CANT_RECORD_BEA01 , "Write error: Can't record BEA01 descriptor"}, + {MKUDF_CANT_RECORD_NSR02 , "Write error: Can't record NSR02 descriptor"}, + {MKUDF_CANT_RECORD_TEA01 , "Write error: Can't record TEA01 descriptor"}, + {MKUDF_CANT_RECORD_ANCHOR , "Write error: Can't record Anchor Point descriptor"}, + {MKUDF_CANT_RECORD_PVD , "Write error: Can't record Primary Volume descriptor"}, + {MKUDF_CANT_RECORD_LVD , "Write error: Can't record Logical Volume descriptor"}, + {MKUDF_CANT_RECORD_LVID , "Write error: Can't record Logical Volume Integrity descriptor"}, + {MKUDF_CANT_RECORD_PARTD , "Write error: Can't record Partition descriptor"}, + {MKUDF_CANT_RECORD_USD , "Write error: Can't record Unallocated Space descriptor"}, + {MKUDF_CANT_RECORD_IUVD , "Write error: Can't record Implementation Use Volume descriptor"}, + {MKUDF_CANT_RECORD_TERMD , "Write error: Can't record Terminating descriptor"}, + {MKUDF_CANT_RECORD_FSD , "Write error: Can't record Free Space descriptor"}, + {MKUDF_CANT_RECORD_SPT , "Write error: Can't record File Set descriptor"}, + {MKUDF_PARTITION_TOO_SHORT , "Requested partition size is too small."}, + {MKUDF_CANT_RECORD_FSBM , "Write error: Can't record Free Space Bitmap"}, + {MKUDF_CANT_RECORD_ROOT_FE , "Write error: Can't record Root File Entry"}, + {MKUDF_CANT_RECORD_VAT_FE , "Write error: Can't record VAT File Entry"}, + {MKUDF_CANT_OPEN_FILE , "Can't open device or image file"}, + {MKUDF_CANT_RESERVE_TRACK , "Can't reserve track for UDF VAT partition"}, + {MKUDF_VAT_MULTISESS_NOT_SUPP , "Can't add UDF VAT session.\n" + "Blank (empty) media required"}, + {MKUDF_NOT_ENOUGH_PARAMS , "Too few command line parameters"}, + {MKUDF_INVALID_PT_FOR_HDD , "Invalid partition type for HDD"}, + {MKUDF_INVALID_PT_FOR_WORM , "Invalid partition type for CD-R"}, + {MKUDF_CANT_FORMAT , "Can't format media"}, + {MKUDF_MEDIA_TYPE_NOT_SUPP , "Unsupported media type"}, + {MKUDF_INVALID_PARAM_BC_FOR_VAT , "Block Count should not be specified for VAT partitions"}, + {MKUDF_HW_PARTITION_TOO_SHORT , "Not enough free space on media"}, + {MKUDF_CANT_LOCK_VOL , "Can't open volume for exclusive use"}, + {MKUDF_CANT_SET_WPARAMS , "Can't set Write Parameters to prepare for recording"}, + {MKUDF_HW_WRITE_ERROR , "Device write error"}, + {MKUDF_BLANK_MEDIA_REQUIRED , "Blank (empty) media required"}, + {MKUDF_INVALID_PT_FOR_BLANK , "Partition Type should not be specified for Erase operation"}, + {MKUDF_FINALIZE_TOO_MANY_PARAMS , "Extra parameters for VAT partition finalization"}, + {MKUDF_NO_ANCHOR_FOUND , "Can't locate UDF VAT partition: No valid Anchor Point descriptor found"}, + {MKUDF_HW_INVALID_NWA , "Invalid Next Writable Address returned"}, + {MKUDF_NO_MEDIA_IN_DEVICE , "No media in device"}, + {MKUDF_INVALID_BC , "Invalid Block Count"}, + {MKUDF_INVALID_MT_FOR_BLANK , "Can't erase CD/DVD-R"}, + {MKUDF_HW_CANT_SET_WRITE_PARAMS , "Can't set proper write mode"}, + {MKUDF_CANT_ALLOW_DASD_IO , "Direct access to volume not permitted"}, + {MKUDF_CANT_DISMOUNT_VOLUME , "Can't dismount volume"}, + {MKUDF_FORMAT_REQUIRED , "Disc is not formatted (empty).\n" + "Physical format required."}, + {MKUDF_FULL_BLANK_REQUIRED , "CD/DVD Drive requires Full Erase to proceed with format"}, + {MKUDF_NO_SUITABLE_MODE_FOR_FMT , "Can't find suitable write mode to format media"}, + {MKUDF_CANT_BLANK_DVDRAM , "DVD-RAM is not erasable"}, + {MKUDF_CANT_RESERVE_ISO_SPACE , "Can't allocate space for ISO structures"}, + {MKUDF_CANT_RECORD_NOTALLOC_FE , "Can't record Non-Allocated Space File Entry"}, + {MKUDF_BAD_BLOCK_IN_SYSTEM_AREA , "System area of the disk is completely damaged.\n" + "Sectors between 0 and 2048 are unusable."}, + {MKUDF_CANT_OPEN_ISO_IMAGE , "Can't open ISO image"}, + {MKUDF_BAD_ISO_IMAGE_ALIGN , "ISO image must be aligned to sector size (2048 bytes)"}, + {MKUDF_CANT_READ_ISO_IMAGE , "ISO image read error"}, + {MKUDF_CANT_WRITE_ISO_IMAGE , "Can't write ISO image to CD"}, + {MKUDF_INVALID_PARAM_SPEED , "Invalid speed value"}, + {MKUDF_CANT_MAKE_WINUDF , "System area of the disk contains some bad blocks.\n" + "Can't allocate disk structres in Windows-compatible fashion"}, + {MKUDF_FLUSH_ERROR , "Error during data flush. Disk may become unreadable or readonly"}, + {MKUDF_FINAL_VERIFY_FAILED , "Final post-formatting Volume verification failed"}, + {MKUDF_INSUFFICIENT_MEMORY , "Insufficient memory"}, + {MKUDF_CANT_CREATE_THREAD , "Can't start formatting thread"}, + {MKUDF_CANT_APPLY_R , "Can't use media as CD/DVD-R"}, + {MKUDF_USER_BREAK , "Operation aborted by user request"}, + {MKUDF_INVALID_USER_BUFFER , "Invalid user-supplied buffer"}, + {MKUDF_INTERNAL_ERROR , "Internal error"}, + {MKUDF_INVALID_PARAM_VFIN , "Invalid filename for input bad block list"}, + {MKUDF_INVALID_PARAM_VFOUT , "Invalid filename for bad block list storage"}, + {MKUDF_CANT_CREATE_BB_LOG , "Can't create file for bad block list"}, + {MKUDF_CANT_OPEN_BB_LOG , "Can't open file with bad block list"}, + {MKUDF_INSUFFICIENT_PRIVILIGES , "Insufficient privileges. Administrative rights required."}, + {MKUDF_BLANK_FORMAT_REQUIRED , "Disc is not formatted (contains not Packet-formatted tracks).\n" + "Erase and Physical format required."}, + {MKUDF_NO_DEVICE_NAME , "No device name specified."}, + {MKUDF_CANT_FLUSH , "Can't flush volume."}, + {MKUDF_INVALID_PARAM_ISO_MODE , "Invalid sector mode for ISO recording"}, + {MKUDF_INVALID_PARAM_ISO_SES , "Invalid multisession mode for ISO recording"}, + {MKUDF_SMART_BLANK_FORMAT_FAILED, "Disc is not empty.\n" + "Automatic erase+format failed."}, + {MKUDF_SMART_FORMAT_FAILED, "Disc is empty.\n" + "Automatic format failed."}, + {MKUDF_OTHER_PACKET_FS , "Disc is physically formatted, but contains other FS structures"}, + {MKUDF_RAW_PACKET_FS , "Disc is physically formatted and doesn't contain FS structures"}, + {MKUDF_CANT_ZERO , "Zero-filling failed after Erase-via-Format workaround."}, + + {MKUDF_NO_UNERASE_FOR_THIS_MEDIA, "Unerase is available for CD media only."}, + {MKUDF_UNERASE_FAILED , "Can't start unerase process."}, + {MKUDF_INVALID_PARAM_REVISION , "Invalid UDF FS Revision."}, + {MKUDF_FORMAT_IN_PROGRESS , "Format or Erase is already started for this device."}, + + {MKUDF_CANT_CREATE_ISO_IMAGE , "Can't create ISO image"}, + + {MKUDF_ABORTED , "Aborted by user"}, +// {MKUDF_INVALID_MT_FOR_BLANK , "Can't blank WORM"}, +// {MKUDF_INVALID_MT_FOR_BLANK , "Can't blank WORM"}, + + {CHKUDF_CANT_MOUNT , "Can't mount volume for checking"}, + + {0xffffffff , "Unknown error"} +}; + diff --git a/reactos/drivers/filesystems/udfs/Include/udferr_usr.h b/reactos/drivers/filesystems/udfs/Include/udferr_usr.h new file mode 100644 index 00000000000..76247b69472 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/udferr_usr.h @@ -0,0 +1,188 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDFERR_USR_H__ +#define __UDFERR_USR_H__ + +#ifndef WITHOUT_FORMATTER + +#define MKUDF_OK 0x00000000 +#include "udferr_usr_h.h" +//#define MKUDF_HW_READ_ONLY 0x80000001 +//#define MKUDF_CANT_BLANK 0x80000002 +#define MKUDF_INVALID_PARAM_MT 0x80000003 +#define MKUDF_INVALID_PARAM_PT 0x80000004 +#define MKUDF_INVALID_PARAM 0x80000005 +#define MKUDF_HW_CANT_READ_LAYOUT 0x80000006 +#define MKUDF_AUTO_BLOCKCOUNT_FAILED 0x80000007 +#define MKUDF_CANT_RECORD_BEA01 0x80000008 +#define MKUDF_CANT_RECORD_NSR02 0x80000009 +#define MKUDF_CANT_RECORD_TEA01 0x8000000a +#define MKUDF_CANT_RECORD_ANCHOR 0x8000000b +#define MKUDF_CANT_RECORD_PVD 0x8000000c +#define MKUDF_CANT_RECORD_LVD 0x8000000d +#define MKUDF_CANT_RECORD_LVID 0x8000000e +#define MKUDF_CANT_RECORD_PARTD 0x8000000f +#define MKUDF_CANT_RECORD_USD 0x80000010 +#define MKUDF_CANT_RECORD_IUVD 0x80000011 +#define MKUDF_CANT_RECORD_TERMD 0x80000012 +#define MKUDF_CANT_RECORD_FSD 0x80000013 +#define MKUDF_CANT_RECORD_SPT 0x80000014 +#define MKUDF_PARTITION_TOO_SHORT 0x80000015 +#define MKUDF_CANT_RECORD_FSBM 0x80000016 +#define MKUDF_CANT_RECORD_ROOT_FE 0x80000017 +#define MKUDF_CANT_RECORD_VAT_FE 0x80000018 +#define MKUDF_CANT_OPEN_FILE 0x80000019 +#define MKUDF_CANT_RESERVE_TRACK 0x8000001a +#define MKUDF_VAT_MULTISESS_NOT_SUPP 0x8000001b +#define MKUDF_NOT_ENOUGH_PARAMS 0x8000001c +#define MKUDF_INVALID_PT_FOR_HDD 0x8000001d +#define MKUDF_INVALID_PT_FOR_WORM 0x8000001e +#define MKUDF_CANT_FORMAT 0x8000001f +#define MKUDF_MEDIA_TYPE_NOT_SUPP 0x80000020 +#define MKUDF_INVALID_PARAM_BC_FOR_VAT 0x80000021 +#define MKUDF_HW_PARTITION_TOO_SHORT 0x80000022 +#define MKUDF_CANT_LOCK_VOL 0x80000023 +#define MKUDF_CANT_SET_WPARAMS 0x80000024 +#define MKUDF_HW_WRITE_ERROR 0x80000025 +#define MKUDF_BLANK_MEDIA_REQUIRED 0x80000026 +#define MKUDF_INVALID_PT_FOR_BLANK 0x80000027 +#define MKUDF_FINALIZE_TOO_MANY_PARAMS 0x80000028 +#define MKUDF_NO_ANCHOR_FOUND 0x80000029 +#define MKUDF_HW_INVALID_NWA 0x8000002a +#define MKUDF_NO_MEDIA_IN_DEVICE 0x8000002b +#define MKUDF_INVALID_BC 0x8000002c +#define MKUDF_INVALID_MT_FOR_BLANK 0x8000002d +#define MKUDF_HW_CANT_SET_WRITE_PARAMS 0x8000002e +#define MKUDF_CANT_ALLOW_DASD_IO 0x8000002f +#define MKUDF_CANT_DISMOUNT_VOLUME 0x80000030 +#define MKUDF_FORMAT_REQUIRED 0x80000031 +#define MKUDF_FULL_BLANK_REQUIRED 0x80000032 +#define MKUDF_NO_SUITABLE_MODE_FOR_FMT 0x80000033 +#define MKUDF_CANT_BLANK_DVDRAM 0x80000034 +#define MKUDF_CANT_RESERVE_ISO_SPACE 0x80000035 +#define MKUDF_CANT_RECORD_NOTALLOC_FE 0x80000036 +#define MKUDF_BAD_BLOCK_IN_SYSTEM_AREA 0x80000037 +#define MKUDF_CANT_OPEN_ISO_IMAGE 0x80000038 +#define MKUDF_BAD_ISO_IMAGE_ALIGN 0x80000039 +#define MKUDF_CANT_READ_ISO_IMAGE 0x8000003a +#define MKUDF_CANT_WRITE_ISO_IMAGE 0x8000003b +#define MKUDF_INVALID_PARAM_SPEED 0x8000003c +#define MKUDF_CANT_MAKE_WINUDF 0x8000003d +#define MKUDF_FLUSH_ERROR 0x8000003e +#define MKUDF_FINAL_VERIFY_FAILED 0x8000003f +#define MKUDF_INSUFFICIENT_MEMORY 0x80000040 +#define MKUDF_CANT_CREATE_THREAD 0x80000041 +#define MKUDF_CANT_APPLY_R 0x80000042 +#define MKUDF_USER_BREAK 0x80000043 +#define MKUDF_INVALID_USER_BUFFER 0x80000044 +#define MKUDF_INTERNAL_ERROR 0x80000045 +#define MKUDF_INVALID_PARAM_VFIN 0x80000046 +#define MKUDF_INVALID_PARAM_VFOUT 0x80000047 +#define MKUDF_CANT_CREATE_BB_LOG 0x80000048 +#define MKUDF_CANT_OPEN_BB_LOG 0x80000049 +#define MKUDF_INSUFFICIENT_PRIVILIGES 0x8000004a +#define MKUDF_BLANK_FORMAT_REQUIRED 0x8000004b +#define MKUDF_NO_DEVICE_NAME 0x8000004c +#define MKUDF_CANT_FLUSH 0x8000004d +#define MKUDF_INVALID_PARAM_ISO_MODE 0x8000004e +#define MKUDF_INVALID_PARAM_ISO_SES 0x8000004f +#define MKUDF_SMART_BLANK_FORMAT_FAILED 0x80000050 +#define MKUDF_SMART_FORMAT_FAILED 0x80000051 +#define MKUDF_OTHER_PACKET_FS 0x80000052 +#define MKUDF_RAW_PACKET_FS 0x80000053 +#define MKUDF_CANT_ZERO 0x80000054 +#define MKUDF_NO_UNERASE_FOR_THIS_MEDIA 0x80000055 +#define MKUDF_UNERASE_FAILED 0x80000056 +#define MKUDF_INVALID_PARAM_REVISION 0x80000057 +#define MKUDF_FORMAT_IN_PROGRESS 0x80000058 +#define MKUDF_CANT_CREATE_ISO_IMAGE 0x80000059 +#define MKUDF_ABORTED 0x80000100 +//#define MKUDF_ 0x800000 +#define MKUDF_PENDING 0x00000103 + +#define CHKUDF_CANT_MOUNT 0x80010000 + +struct err_msg_item +{ + unsigned int err_code; + const char* err_msg; +}; + +extern struct err_msg_item mkudf_err_msg[]; + +#endif //WITHOUT_FORMATTER + +//NT-like status codes + +#ifndef STATUS_SUCCESS + +#define STATUS_SUCCESS 1 +#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L) +#define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS)0x00000117L) +#define STATUS_FT_WRITE_RECOVERY ((NTSTATUS)0x4000000BL) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_DEVICE_BUSY ((NTSTATUS)0x80000011L) +#define STATUS_VERIFY_REQUIRED ((NTSTATUS)0x80000016L) +#define STATUS_NO_DATA_DETECTED ((NTSTATUS)0x80000022L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +//#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_NO_SUCH_DEVICE ((NTSTATUS)0xC000000EL) +#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) +#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) +#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) +#define STATUS_WRONG_VOLUME ((NTSTATUS)0xC0000012L) +#define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS)0xC0000013L) +#define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS)0xC0000014L) +#define STATUS_NONEXISTENT_SECTOR ((NTSTATUS)0xC0000015L) +#define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS)0xC0000016L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS)0xC0000032L) +#define STATUS_OBJECT_NAME_INVALID ((NTSTATUS)0xC0000033L) +#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L) +#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS)0xC000003AL) +#define STATUS_DATA_OVERRUN ((NTSTATUS)0xC000003CL) +#define STATUS_CRC_ERROR ((NTSTATUS)0xC000003FL) +#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L) +#define STATUS_DISK_FULL ((NTSTATUS)0xC000007FL) +#define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS)0xC0000086L) +#define STATUS_NOT_MAPPED_DATA ((NTSTATUS)0xC0000088L) +#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) +#define STATUS_DEVICE_DATA_ERROR ((NTSTATUS)0xC000009CL) +#define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS)0xC000009DL) +#define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS)0xC00000A2L) +#define STATUS_DEVICE_NOT_READY ((NTSTATUS)0xC00000A3L) +#define STATUS_IO_TIMEOUT ((NTSTATUS)0xC00000B5L) +#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) +#define STATUS_SHARING_PAUSED ((NTSTATUS)0xC00000CFL) +#define STATUS_INVALID_USER_BUFFER ((NTSTATUS)0xC00000E8L) +#define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS)0xC0000101L) +#define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS)0xC0000102L) +#define STATUS_NOT_A_DIRECTORY ((NTSTATUS)0xC0000103L) +#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L) +#define STATUS_CANNOT_DELETE ((NTSTATUS)0xC0000121L) +#define STATUS_FILE_DELETED ((NTSTATUS)0xC0000123L) +#define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS)0xC000014FL) +#define STATUS_TOO_MANY_SECRETS ((NTSTATUS)0xC0000156L) +#define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS)0xC0000173L) +#define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS)0xC0000176L) +#define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS)0xC0000183L) +#define STATUS_INVALID_DEVICE_STATE ((NTSTATUS)0xC0000184L) +#define STATUS_IO_DEVICE_ERROR ((NTSTATUS)0xC0000185L) +#define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS)0xC0000222L) +#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) +#define STATUS_RETRY ((NTSTATUS)0xC000022DL) +#define STATUS_REQUEST_ABORTED ((NTSTATUS)0xC0000240L) +#define STATUS_TOO_MANY_LINKS ((NTSTATUS)0xC0000265L) +#define STATUS_LICENSE_VIOLATION ((NTSTATUS)0xC000026AL) + +#endif // STATUS_SUCCESS + +#endif // __UDFERR_USR_H__ diff --git a/reactos/drivers/filesystems/udfs/Include/user_lib.cpp b/reactos/drivers/filesystems/udfs/Include/user_lib.cpp new file mode 100644 index 00000000000..e96aed1f798 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/user_lib.cpp @@ -0,0 +1,898 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +/************************************************************************* +* +* File: user_lib.cpp +* +* Module: User-mode library +* +* Description: common useful user-mode functions +* +* Author: Ivan +* +*************************************************************************/ + + +#ifndef __USER_LIB_CPP__ +#define __USER_LIB_CPP__ + +#include "user_lib.h" + +TCHAR* MediaTypeStrings[] = +{ + "CD-ROM" , + "CD-R" , + "CD-RW" , + "DVD-ROM" , + "DVD-RAM" , + "DVD-R" , + "DVD-RW" , + "DVD+R" , + "DVD+RW" , + "DD CD-ROM" , + "DD CD-R" , + "DD CD-RW" , + "BD-ROM" , + "BD-RE" , + "[BUSY]" , + "Unknown" +}; + +void * __cdecl mymemchr ( + const void * buf, + int chr, + size_t cnt + ) +{ + while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return(cnt ? (void *)buf : NULL); +} // end mymemchr() + +char * __cdecl mystrrchr( + const char * string, + int ch + ) +{ + char *start = (char *)string; + + while (*string++) {;} + + while (--string != start && *string != (char)ch) {;} + + if (*string == (char)ch) { + return( (char *)string ); + } + + return(NULL); +} // end mystrrchr() + +char * __cdecl mystrchr( + const char * string, + int ch + ) +{ + while (*string != (char)ch && *string != '\0' ) { + string++; + } + + if (*string == (char)ch) { + return( (char *)string ); + } + + return(NULL); +} // end mystrchr() + + +int __cdecl Exist ( + PCHAR path + ) +{ + DWORD attr; + + attr = GetFileAttributes((LPTSTR)path); + if (attr == 0xffffffff) { + return 0; + } + + return 1; + +} // end Exist() + +ULONG +MyMessageBox( + HINSTANCE hInst, + HWND hWnd, + LPCSTR pszFormat, + LPCSTR pszTitle, + UINT fuStyle, + ... + ) +{ + CHAR szTitle[80]; + CHAR szFormat[1024]; + LPSTR pszMessage; + BOOL fOk; + int result; + va_list ArgList; + + if (!HIWORD(pszTitle)) { + LoadString(hInst, LOWORD(pszTitle), szTitle, sizeof(szTitle)/sizeof(szTitle[0])); + pszTitle = szTitle; + } + + if (!HIWORD(pszFormat)) { + // Allow this to be a resource ID + LoadString(hInst, LOWORD(pszFormat), szFormat, sizeof(szFormat)/sizeof(szFormat[0])); + pszFormat = szFormat; + } + + va_start(ArgList, fuStyle); + fOk = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_STRING, + pszFormat, 0, 0, (LPTSTR)&pszMessage, 0, &ArgList); + + va_end(ArgList); + + if (fOk && pszMessage) { + result = MessageBox(hWnd, pszMessage, pszTitle, fuStyle | MB_SETFOREGROUND); + LocalFree(pszMessage); + } else { + return -1; + } + + return result; +} // end MyMessageBox() + + +/// Return service status by service name. +JS_SERVICE_STATE +ServiceInfo( + LPCTSTR ServiceName + ) +{ + SC_HANDLE schService; + DWORD RC; + SERVICE_STATUS ssStatus; + JS_SERVICE_STATE return_value; + SC_HANDLE schSCManager; + + schSCManager = OpenSCManager( + NULL, // machine (NULL == local) + NULL, // database (NULL == default) + SC_MANAGER_ALL_ACCESS // access required + ); + if (!schSCManager) { + schSCManager = OpenSCManager( + NULL, // machine (NULL == local) + NULL, // database (NULL == default) + SC_MANAGER_CONNECT // access required + ); + } + if (!schSCManager) + return JS_ERROR_STATUS; + schService = OpenService(schSCManager, ServiceName, SERVICE_QUERY_STATUS); + if (!schService) { + RC = GetLastError(); + CloseServiceHandle(schSCManager); + if (RC == ERROR_SERVICE_DOES_NOT_EXIST) return JS_SERVICE_NOT_PRESENT; + else return JS_ERROR_STATUS; + } + QueryServiceStatus(schService, &ssStatus); + if(ssStatus.dwCurrentState == SERVICE_RUNNING) { + return_value = JS_SERVICE_RUNNING; + } else { + return_value = JS_SERVICE_NOT_RUNNING; + } + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return return_value; +} // end ServiceInfo() + +BOOL +CheckCdrwFilter( + BOOL ReInstall + ) +{ + char CdromUpperFilters[1024]; + bool found = false; + + if (LOBYTE(LOWORD(GetVersion())) < 5) { + return true; + } + + if (GetRegString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],arraylen(CdromUpperFilters))) { + char *token = &CdromUpperFilters[0]; + + while (*token) { + if (!strcmp(token,CDRW_SERVICE)) { + found = true; + break; + } + token += strlen(token)+1; + } + if (!found) { + memcpy(token,CDRW_SERVICE,sizeof(CDRW_SERVICE)); + *(token+sizeof(CDRW_SERVICE)) = '\0'; + *(token+sizeof(CDRW_SERVICE)+1) = '\0'; + if(ReInstall) { + RegisterString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],TRUE,token-&CdromUpperFilters[0]+sizeof(CDRW_SERVICE)+1); + found = true; + } + } + } else { + memcpy(CdromUpperFilters,CDRW_SERVICE,sizeof(CDRW_SERVICE)); + CdromUpperFilters[sizeof(CDRW_SERVICE)] = '\0'; + CdromUpperFilters[sizeof(CDRW_SERVICE)+1] = '\0'; + if(ReInstall) { + RegisterString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],TRUE,sizeof(CDRW_SERVICE)+1); + found = true; + } + } + return found; + +} // end CheckCdrwFilter() + +BOOL +RegisterString( + LPSTR pszKey, + LPSTR pszValue, + LPSTR pszData, + BOOLEAN MultiSz, + DWORD size + ) +{ + + HKEY hKey; + DWORD dwDisposition; + + // Create the key, if it exists it will be opened + if (ERROR_SUCCESS != + RegCreateKeyEx( + HKEY_LOCAL_MACHINE, // handle of an open key + pszKey, // address of subkey name + 0, // reserved + NULL, // address of class string + REG_OPTION_NON_VOLATILE, // special options flag + KEY_ALL_ACCESS, // desired security access + NULL, // address of key security structure + &hKey, // address of buffer for opened handle + &dwDisposition)) // address of disposition value buffer + { + return FALSE; + } + + // Write the value and it's data to the key + if (ERROR_SUCCESS != + RegSetValueEx( + hKey, // handle of key to set value for + pszValue, // address of value to set + 0, // reserved + MultiSz ? REG_MULTI_SZ : REG_SZ, // flag for value type + (CONST BYTE *)pszData, // address of value data + MultiSz ? size : strlen(pszData) )) // size of value data + { + + RegCloseKey(hKey); + return FALSE; + } + + // Close the key + RegCloseKey(hKey); + + return TRUE; +} // end RegisterString() + +BOOL +RegDelString( + LPSTR pszKey, + LPSTR pszValue + ) +{ + + HKEY hKey; + DWORD dwDisposition; + + // Create the key, if it exists it will be opened + if (ERROR_SUCCESS != + RegCreateKeyEx( + HKEY_LOCAL_MACHINE, // handle of an open key + pszKey, // address of subkey name + 0, // reserved + NULL, // address of class string + REG_OPTION_NON_VOLATILE, // special options flag + KEY_ALL_ACCESS, // desired security access + NULL, // address of key security structure + &hKey, // address of buffer for opened handle + &dwDisposition)) // address of disposition value buffer + { + return FALSE; + } + + // Write the value and it's data to the key + if (ERROR_SUCCESS != + RegDeleteValue( + hKey, // handle of key to set value for + pszValue)) + { + + RegCloseKey(hKey); + return FALSE; + } + + // Close the key + RegCloseKey(hKey); + + return TRUE; +} // end RegDelString() + +/// Get string from registry by Key path and Value name +BOOL +GetRegString( + LPSTR pszKey, + LPSTR pszValue, + LPSTR pszData, + DWORD dwBufSize + ) +{ + + HKEY hKey; + DWORD dwDataSize = dwBufSize; + DWORD dwValueType = REG_SZ; + + if(!dwBufSize) + return FALSE; + + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + pszKey, // address of name of subkey to open + 0, // reserved + KEY_QUERY_VALUE, // security access mask + &hKey // address of handle of open key + ); + + if (ERROR_SUCCESS != RegQueryValueEx( + hKey, // handle of key to query + pszValue, // address of name of value to query + 0, // reserved + &dwValueType, // address of buffer for value type + (BYTE *)pszData, // address of data buffer + &dwDataSize // address of data buffer size + )) return FALSE; + + if (pszData[dwDataSize-1] != '\0') + pszData[dwDataSize-1] = '\0'; + + return TRUE; +} // end GetRegString() + +BOOL +RegisterDword( + LPSTR pszKey, + LPSTR pszValue, + DWORD dwData + ) +{ + + HKEY hKey; + DWORD dwDisposition; + + // Create the key, if it exists it will be opened + if (ERROR_SUCCESS != + RegCreateKeyEx( + HKEY_LOCAL_MACHINE, // handle of an open key + pszKey, // address of subkey name + 0, // reserved + NULL, // address of class string + REG_OPTION_NON_VOLATILE, // special options flag + KEY_ALL_ACCESS, // desired security access + NULL, // address of key security structure + &hKey, // address of buffer for opened handle + &dwDisposition)) // address of disposition value buffer + { + return FALSE; + } + + // Write the value and it's data to the key + if (ERROR_SUCCESS != + RegSetValueEx( + hKey, // handle of key to set value for + pszValue, // address of value to set + 0, // reserved + REG_DWORD, // flag for value type + (CONST BYTE *)&dwData, // address of value data + 4 )) // size of value data + { + + RegCloseKey(hKey); + return FALSE; + } + + // Close the key + RegCloseKey(hKey); + + return TRUE; +} // end RegisterDword() + +BOOL +GetRegUlong( + LPSTR pszKey, + LPSTR pszValue, + PULONG pszData + ) +{ + + HKEY hKey; + DWORD dwDataSize = 4; + DWORD dwValueType = REG_DWORD; + ULONG origValue = *pszData; + + if(RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + pszKey, // address of name of subkey to open + 0, // reserved + KEY_QUERY_VALUE, // security access mask + &hKey // address of handle of open key + ) != ERROR_SUCCESS) { + (*pszData) = origValue; + return FALSE; + } + + if(RegQueryValueEx( + hKey, // handle of key to query + pszValue, // address of name of value to query + 0, // reserved + &dwValueType,// address of buffer for value type + (BYTE *)pszData, // address of data buffer + &dwDataSize // address of data buffer size + ) != ERROR_SUCCESS) { + (*pszData) = origValue; + } + + RegCloseKey(hKey); + + return TRUE; +} // end GetRegUlong() + +BOOL +SetRegUlong( + LPSTR pszKey, + LPSTR pszValue, + PULONG pszData + ) +{ + + HKEY hKey; + DWORD dwDataSize = 4; + DWORD dwValueType = REG_DWORD; + LPVOID lpMsgBuf; + LONG RC; + + if (!(ERROR_SUCCESS == (RC = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + pszKey, // address of name of subkey to open + 0, // reserved + KEY_ALL_ACCESS , // security access mask + &hKey // address of handle of open key + )))) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + RC, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL); + + // Display the string. + MessageBox( NULL, (CCHAR*)lpMsgBuf, "Error", MB_OK|MB_ICONHAND ); + + // Free the buffer. + LocalFree( lpMsgBuf ); + return FALSE; + } + + if (!(ERROR_SUCCESS == (RC = RegSetValueEx( + hKey, // handle of key to query + pszValue, // address of name of value to query + 0, // reserved + REG_DWORD,// address of buffer for value type + (BYTE *)pszData, // address of data buffer + sizeof(ULONG) // data buffer size + )))) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + RC, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL); + + // Display the string. + MessageBox( NULL, (CCHAR*)lpMsgBuf, "Error", MB_OK|MB_ICONHAND ); + + // Free the buffer. + LocalFree( lpMsgBuf ); + + } + RegCloseKey(hKey); + return TRUE; +} // end SetRegUlong() + +BOOL +Privilege( + LPTSTR pszPrivilege, + BOOL bEnable + ) +{ + + HANDLE hToken; + TOKEN_PRIVILEGES tp; + + // + // obtain the token, first check the thread and then the process + // + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &hToken)){ + if (GetLastError() == ERROR_NO_TOKEN) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + return FALSE; + } + else return FALSE; + } + + // + // get the luid for the privilege + // + if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid)) + return FALSE; + + tp.PrivilegeCount = 1; + + if (bEnable) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // + // enable or disable the privilege + // + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0)) + return FALSE; + + if (!CloseHandle(hToken)) + return FALSE; + + return TRUE; +} // end Privilege() + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + + +BOOL IsWow64(VOID) +{ + BOOL bIsWow64 = FALSE; + LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process"); + + if (NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) + { + return FALSE; + } + } + return bIsWow64; +} // end IsWow64() + + +HANDLE +CreatePublicEvent( + PWCHAR EventName + ) +{ + SECURITY_DESCRIPTOR sdPublic; + SECURITY_ATTRIBUTES saPublic; + + InitializeSecurityDescriptor( + &sdPublic, + SECURITY_DESCRIPTOR_REVISION + ); + + SetSecurityDescriptorDacl( + &sdPublic, + TRUE, + NULL, + FALSE + ); + + saPublic.nLength = sizeof(saPublic); + saPublic.lpSecurityDescriptor = &sdPublic; + + return CreateEventW( + &saPublic, + TRUE, + FALSE, + EventName); + +} // end CreatePublicEvent() + +/// Send Device IO Controls to undelaying level via handle +ULONG +UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN HANDLE DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + IN PVOID Dummy + ) +{ + ULONG real_read; + ULONG ret; + LONG offh=0; + ULONG RC = DeviceIoControl(DeviceObject,IoControlCode, + InputBuffer,InputBufferLength, + OutputBuffer,OutputBufferLength, + &real_read,NULL); + + if (!RC) { + ret = GetLastError(); + } + return RC ? 1 : -1; +} // end UDFPhSendIOCTL() + +CHAR RealDeviceName[MAX_PATH+1]; + +PCHAR +UDFGetDeviceName( + PCHAR szDeviceName + ) +{ + HANDLE hDevice; + WCHAR DeviceName[MAX_PATH+1]; + ULONG RC; + + ODS(" UDFGetDeviceName\r\n"); + hDevice = CreateFile(szDeviceName, GENERIC_READ , + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (hDevice == ((HANDLE)-1)) { + strcpy(RealDeviceName,""); + return (PCHAR)&RealDeviceName; + } + + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME,hDevice, + &DeviceName,(MAX_PATH+1)*sizeof(WCHAR), + &DeviceName,(MAX_PATH+1)*sizeof(WCHAR), FALSE,NULL); + + if(RC == 1) { + wcstombs((PCHAR)&RealDeviceName,&DeviceName[1],(USHORT)DeviceName[0]); + RealDeviceName[(USHORT)DeviceName[0]/sizeof(USHORT)] = '\0'; + } else { + strcpy(RealDeviceName, szDeviceName+4); + } + + CloseHandle(hDevice); + + return (PCHAR)(strrchr(RealDeviceName, '\\')+1); +} // end UDFGetDeviceName() + +BOOL +GetOptUlong( + PCHAR Path, + PCHAR OptName, + PULONG OptVal + ) +{ + if(!Path) { + return FALSE; + } + if(Path[0] && Path[1] == ':') { + CHAR SettingFile[MAX_PATH]; + CHAR Setting[16]; + + sprintf(SettingFile, "%s\\%s", Path, UDF_CONFIG_STREAM_NAME); + GetPrivateProfileString("DiskSettings", OptName, "d", &Setting[0], 10, SettingFile); + Setting[15]=0; + if (Setting[0] != 'd') { + if(Setting[0] == '0' && Setting[1] == 'x') { + sscanf(Setting+2, "%x", OptVal); + } else { + sscanf(Setting, "%d", OptVal); + } + return TRUE; + } + return FALSE; + } + return GetRegUlong(Path, OptName, OptVal); +} // end GetOptUlong() + +BOOL +SetOptUlong( + PCHAR Path, + PCHAR OptName, + PULONG OptVal + ) +{ + if(!Path) { + return FALSE; + } + if(Path[0] && Path[1] == ':') { + CHAR SettingFile[MAX_PATH]; + CHAR Setting[16]; + if(Path[2] != '\\') { + sprintf(SettingFile, "%s\\%s", Path, UDF_CONFIG_STREAM_NAME); + } else { + sprintf(SettingFile, "%s%s", Path, UDF_CONFIG_STREAM_NAME); + } + sprintf(Setting, "%d\n", (*OptVal)); + return WritePrivateProfileString("DiskSettings", OptName, Setting, SettingFile); + } + return SetRegUlong(Path, OptName, OptVal); +} // end SetOptUlong() + +ULONG +UDFGetOptUlongInherited( + PCHAR Drive, + PCHAR OptName, + PULONG OptVal, + ULONG CheckDepth + ) +{ + CHAR LocalPath[1024]; + ULONG retval = 0; + + ODS(" UDFGetOptUlongInherited\r\n"); + + if(GetOptUlong(UDF_SERVICE_PARAM_PATH, OptName, OptVal)) { + retval = UDF_OPTION_GLOBAL; + } + if(CheckDepth <= UDF_OPTION_GLOBAL) { + return retval; + } + strcpy(LocalPath,UDF_SERVICE_PARAM_PATH); + strcat(LocalPath,"\\"); + strcat(LocalPath,UDFGetDeviceName(Drive)); + if(GetOptUlong(LocalPath, OptName, OptVal)) { + retval = UDF_OPTION_DEVSPEC; + } + if(CheckDepth <= UDF_OPTION_DEVSPEC) { + return retval; + } + if(GetOptUlong(Drive, OptName, OptVal)) + retval = UDF_OPTION_DISKSPEC; + return retval; +} // end UDFGetOptUlongInherited() + +HANDLE +OpenOurVolume( + PCHAR szDeviceName + ) +{ + HANDLE hDevice; + + // Open device volume + hDevice = CreateFile(szDeviceName, GENERIC_READ , + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (hDevice == ((HANDLE)-1)) { + hDevice = CreateFile(szDeviceName, GENERIC_READ , + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + } + return hDevice; +} // end OpenOurVolume() + +ULONG +drv_letter_to_index( + WCHAR a + ) +{ + if(a >= 'a' && a <= 'z') { + return a - 'a'; + } + if(a >= 'A' && a <= 'Z') { + return a - 'A'; + } + return -1; +} // end drv_letter_to_index() + +/// Start app with desired parameters +DWORD +WINAPI +LauncherRoutine2( + LPVOID lpParameter + ) +{ + PCHAR ParamStr = (PCHAR)lpParameter; + STARTUPINFO proc_startup_info; + PROCESS_INFORMATION proc_info; + CHAR szLaunchPath[MAX_PATH],ErrMes[50]; + INT index; + ULONG MkUdfRetCode; + CHAR szTemp[256]; + + GetRegString(UDF_KEY,"ToolsPath",szLaunchPath, sizeof(szLaunchPath)); + SetCurrentDirectory(szLaunchPath); + + strcat(szLaunchPath,"\\"); + //strcat(szLaunchPath,UDFFMT); + strcat(szLaunchPath,ParamStr); + + //strcpy(MkUdfStatus,""); + +#ifndef TESTMODE + proc_startup_info.cb = sizeof(proc_startup_info); + proc_startup_info.lpReserved = 0; + proc_startup_info.lpReserved2 = 0; + proc_startup_info.cbReserved2 = 0; + proc_startup_info.lpDesktop = 0; + proc_startup_info.lpTitle = 0; + proc_startup_info.dwFlags = 0; + + proc_startup_info.hStdInput = NULL; + proc_startup_info.hStdOutput = NULL; + proc_startup_info.hStdError = NULL; + + if(CreateProcess(NULL, szLaunchPath, 0,0, TRUE, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, + 0,0, &proc_startup_info, &proc_info)) { + + //hFmtProc[i] = proc_info.hProcess; + WaitForSingleObject(proc_info.hProcess, -1); + GetExitCodeProcess(proc_info.hProcess, &MkUdfRetCode); + index=0; +/* + while (mkudf_err_msg[index].err_code != 0xffffffff){ + if (mkudf_err_msg[index].err_code == MkUdfRetCode) break; + index++; + } +*/ + //strcpy(MkUdfStatus,mkudf_err_msg[index].err_msg); + + CloseHandle(proc_info.hThread); + CloseHandle(proc_info.hProcess); + } else { + strcpy(ErrMes,"Stop: Cannot launch "); + strcat(ErrMes,szLaunchPath); + sprintf(szTemp," error %d",GetLastError()); + strcat(ErrMes,szTemp); + MessageBox(NULL,ErrMes,"UDFFormat",MB_OK | MB_ICONHAND); + + } +#else + MessageBox(NULL,szLaunchPath,"Message",MB_OK); + Sleep(500); + MkUdfRetCode = MKUDF_OK; +// MkUdfRetCode = MKUDF_FORMAT_REQUIRED; +// MkUdfRetCode = MKUDF_CANT_BLANK; + + index = 0; + while (mkudf_err_msg[index].err_code != 0xffffffff){ + if (mkudf_err_msg[index].err_code == MkUdfRetCode) break; + index++; + } + //strcpy(MkUdfStatus,mkudf_err_msg[index].err_msg); + +#endif + return MkUdfRetCode; +} // end LauncherRoutine2() + + +#endif // __USER_LIB_CPP__ diff --git a/reactos/drivers/filesystems/udfs/Include/user_lib.h b/reactos/drivers/filesystems/udfs/Include/user_lib.h new file mode 100644 index 00000000000..35bc0dc8e1f --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/user_lib.h @@ -0,0 +1,194 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +/************************************************************************* +* +* File: user_lib.h +* +* Module: User-mode library header +* +* Description: common useful user-mode functions +* +* Author: Ivan +* +*************************************************************************/ + + +#ifndef __USER_LIB_H__ +#define __USER_LIB_H__ + +#if defined DBG || defined PRINT_ALWAYS +#define ODS(sz) OutputDebugString(sz) +#else +#define ODS(sz) {} +#endif + +#define arraylen(a) (sizeof(a)/sizeof(a[0])) + +/// CD/DVD-RW device types +typedef enum _JS_DEVICE_TYPE { + OTHER = 0, + CDR, + CDRW, + DVDROM, + DVDRAM, + DVDR, + DVDRW, + DVDPR, + DVDPRW, + DDCDROM, + DDCDR, + DDCDRW, + BDROM, + BDRE, + BUSY +} JS_DEVICE_TYPE; + +extern TCHAR* MediaTypeStrings[]; + +/// Service state constants +typedef enum _JS_SERVICE_STATE { + JS_SERVICE_NOT_PRESENT, ///< Service not installed + JS_SERVICE_RUNNING, ///< Service is running + JS_SERVICE_NOT_RUNNING, ///< Service installed, but not running + JS_ERROR_STATUS ///< Errror while taking service status +} JS_SERVICE_STATE; + +void * __cdecl mymemchr ( + const void * buf, + int chr, + size_t cnt + ); + +char * __cdecl mystrrchr ( + const char * string, + int ch + ); + +char * __cdecl mystrchr ( + const char * string, + int ch + ); + +int __cdecl Exist ( + PCHAR path + ); + +ULONG MyMessageBox( + HINSTANCE hInst, + HWND hWnd, + LPCSTR pszFormat, + LPCSTR pszTitle, + UINT fuStyle, + ... + ); + +// simple win32 registry api wrappers +BOOL RegisterString (LPSTR pszKey, LPSTR pszValue, LPSTR pszData,BOOLEAN MultiSz,DWORD size); +BOOL +GetRegString ( + LPSTR pszKey, + LPSTR pszValue, + LPSTR pszData, + DWORD dwBufSize + ); +BOOL RegDelString (LPSTR pszKey, LPSTR pszValue); +BOOL RegisterDword (LPSTR pszKey, LPSTR pszValue, DWORD dwData); +BOOL +GetRegUlong ( + LPSTR pszKey, + LPSTR pszValue, + LPDWORD pszData + ); + + +JS_SERVICE_STATE +ServiceInfo( + LPCTSTR ServiceName + ); + +BOOL +CheckCdrwFilter( + BOOL ReInstall + ); + +BOOL +Privilege( + LPTSTR pszPrivilege, + BOOL bEnable + ); + +BOOL IsWow64(VOID); + +#define DW_GLOBAL_QUIT_EVENT_NAME L"Global\\DwQuitEvent" +#define DW_QUIT_EVENT_NAME L"DwQuitEvent" + +HANDLE +CreatePublicEvent( + PWCHAR EventName + ); + +ULONG +UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN HANDLE DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + IN PVOID Dummy + ); + +PCHAR +UDFGetDeviceName( + PCHAR szDeviceName + ); + +BOOL +GetOptUlong( + PCHAR Path, + PCHAR OptName, + PULONG OptVal + ); + +BOOL +SetOptUlong( + PCHAR Path, + PCHAR OptName, + PULONG OptVal + ); + +#define UDF_OPTION_GLOBAL 1 +#define UDF_OPTION_MEDIASPEC 10 +#define UDF_OPTION_DEVSPEC 2 +#define UDF_OPTION_DISKSPEC 3 +#define UDF_OPTION_MAX_DEPTH 0xffffffff + +ULONG +UDFGetOptUlongInherited( + PCHAR Drive, + PCHAR OptName, + PULONG OptVal, + ULONG CheckDepth + ); + +HANDLE +OpenOurVolume( + PCHAR szDeviceName + ); + +ULONG +drv_letter_to_index( + WCHAR a + ); + +DWORD +WINAPI +LauncherRoutine2( + LPVOID lpParameter + ); + +#endif // __USER_LIB_H__ diff --git a/reactos/drivers/filesystems/udfs/Include/version.h b/reactos/drivers/filesystems/udfs/Include/version.h new file mode 100644 index 00000000000..acf5ba62563 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/version.h @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: version.h +// +//-------------------------------------------------------------------------- + +//#include "product.h" + +#define VER_STR_CHKUDF "0.2" +#define VER_BIN_CHKUDF 0,2,0 + +#define VER_STR_CDRW "0.69" +#define VER_BIN_CDRW 0,69,0,0 + +#define VER_STR_UDFFS "0.137" +#define VER_BIN_UDFFS 0,137,0 + +#define VER_STR_UDFFMT "0.18" +#define VER_BIN_UDFFMT 0,18,0 + +#define VER_STR_UDFFORMAT "0.17" +#define VER_BIN_UDFFORMAT 0,17,0,0 + +#define VER_STR_UDFGUI "0.1" +#define VER_BIN_UDFGUI 0,1,0,0 + +#define VER_STR_JSSETUP "0.17" +#define VER_BIN_JSSETUP 0,17,0 + +#define VER_STR_LIBUDF "0.1" +#define VER_BIN_LIBUDF 0,1,0,0 + +#define VER_STR_JSREG "0.1" +#define VER_BIN_JSREG 0,1,0,0 + +#define VER_STR_BUGREPORT "0.1" +#define VER_BIN_BUGREPORT 0,1,0,0 + +#define VER_STR_SHELLEXTUDF "0.6b" +#define VER_BIN_SHELLEXTUDF 0,6,2,0 + +#define VER_STR_COMMRES "0.1" +#define VER_BIN_COMMRES 0,1,0,0 + diff --git a/reactos/drivers/filesystems/udfs/Include/wcache_lib.cpp b/reactos/drivers/filesystems/udfs/Include/wcache_lib.cpp new file mode 100644 index 00000000000..069c5a9a0b4 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/wcache_lib.cpp @@ -0,0 +1,3646 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +/*********************************************************************/ + +OSSTATUS __fastcall WCacheCheckLimits(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount); + +OSSTATUS __fastcall WCacheCheckLimitsRAM(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount); + +OSSTATUS __fastcall WCacheCheckLimitsRW(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount); + +OSSTATUS __fastcall WCacheCheckLimitsR(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount); + +VOID __fastcall WCachePurgeAllRW(IN PW_CACHE Cache, + IN PVOID Context); + +VOID __fastcall WCacheFlushAllRW(IN PW_CACHE Cache, + IN PVOID Context); + +VOID __fastcall WCachePurgeAllR(IN PW_CACHE Cache, + IN PVOID Context); + +OSSTATUS __fastcall WCacheDecodeFlags(IN PW_CACHE Cache, + IN ULONG Flags); + +#define ASYNC_STATE_NONE 0 +#define ASYNC_STATE_READ_PRE 1 +#define ASYNC_STATE_READ 2 +#define ASYNC_STATE_WRITE_PRE 3 +#define ASYNC_STATE_WRITE 4 +#define ASYNC_STATE_DONE 5 + +#define ASYNC_CMD_NONE 0 +#define ASYNC_CMD_READ 1 +#define ASYNC_CMD_UPDATE 2 + +#define WCACHE_MAX_CHAIN (0x10) + +#define MEM_WCCTX_TAG 'xtCW' +#define MEM_WCFRM_TAG 'rfCW' +#define MEM_WCBUF_TAG 'fbCW' + +#define USE_WC_PRINT + +#ifdef USE_WC_PRINT + #define WcPrint KdPrint +#else + #define WcPrint(x) {;} +#endif + +typedef struct _W_CACHE_ASYNC { + UDF_PH_CALL_CONTEXT PhContext; + ULONG State; + ULONG Cmd; + PW_CACHE Cache; + PVOID Buffer; + PVOID Buffer2; + ULONG TransferredBytes; + ULONG BCount; + lba_t Lba; + struct _W_CACHE_ASYNC* NextWContext; + struct _W_CACHE_ASYNC* PrevWContext; +} W_CACHE_ASYNC, *PW_CACHE_ASYNC; + +VOID +WCacheUpdatePacketComplete( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context + IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context + IN BOOLEAN FreePacket = TRUE + ); + +/*********************************************************************/ +ULONG WCache_random; + +/* + WCacheInit__() fills all necesary fileds in passed in PW_CACHE Cache + structure, allocates memory and synchronization resources. + Cacheable area is subdiveded on Frames - contiguous sets of blocks. + Internally each Frame is an array of pointers and attributes of cached + Blocks. To optimize memory usage WCache keeps in memory limited number + of frames (MaxFrames). + Frame length (number of Blocks) must be be a power of 2 and aligned on + minimum writeable block size - Packet. + Packet size must be a power of 2 (2, 4, 8, 16, etc.). + Each cached Block belongs to one of the Frames. To optimize memory usage + WCache keeps in memory limited number of Blocks (MaxBlocks). Block size + must be a power of 2. + WCache splits low-level request(s) into some parts if requested data length + exceeds MaxBytesToRead. + If requested data length exceeds maximum cache size WCache makes + recursive calls to read/write routines with shorter requests + + WCacheInit__() returns initialization status. If initialization failed, + all allocated memory and resources are automaticelly freed. + + Public routine + */ +OSSTATUS +WCacheInit__( + IN PW_CACHE Cache, // pointer to the Cache Control structure to be initialized + IN ULONG MaxFrames, // maximum number of Frames to be kept in memory + // simultaneously + IN ULONG MaxBlocks, // maximum number of Blocks to be kept in memory + // simultaneously + IN ULONG MaxBytesToRead, // maximum IO length (split boundary) + IN ULONG PacketSizeSh, // number of blocks in packet (bit shift) + // Packes size = 2^PacketSizeSh + IN ULONG BlockSizeSh, // Block size (bit shift) + // Block size = 2^BlockSizeSh + IN ULONG BlocksPerFrameSh,// number of blocks in Frame (bit shift) + // Frame size = 2^BlocksPerFrameSh + IN lba_t FirstLba, // Logical Block Address (LBA) of the 1st block + // in cacheable area + IN lba_t LastLba, // Logical Block Address (LBA) of the last block + // in cacheable area + IN ULONG Mode, // media mode: + // WCACHE_MODE_ROM + // WCACHE_MODE_RW + // WCACHE_MODE_R + // WCACHE_MODE_RAM + // the following modes are planned to be implemented: + // WCACHE_MODE_EWR + IN ULONG Flags, // cache mode flags: + // WCACHE_CACHE_WHOLE_PACKET + // read long (Packet-sized) blocks of + // data from media + IN ULONG FramesToKeepFree, + // number of Frames to be flushed & purged from cache + // when Frame counter reaches top-limit and allocation + // of a new Frame required + IN PWRITE_BLOCK WriteProc, + // pointer to synchronous physical write call-back routine + IN PREAD_BLOCK ReadProc, + // pointer to synchronous physical read call-back routine + IN PWRITE_BLOCK_ASYNC WriteProcAsync, + // pointer to _asynchronous_ physical write call-back routine + // currently must be set to NULL because async support + // is not completly implemented + IN PREAD_BLOCK_ASYNC ReadProcAsync, + // pointer to _asynchronous_ physical read call-back routine + // must be set to NULL (see above) + IN PCHECK_BLOCK CheckUsedProc, + // pointer to call-back routine that checks whether the Block + // specified (by LBA) is allocated for some data or should + // be treated as unused (and thus, zero-filled). + // Is used to avoid physical reads and writes from/to such Blocks + IN PUPDATE_RELOC UpdateRelocProc, + // pointer to call-back routine that updates caller's + // relocation table _after_ physical write (append) in WORM + // (WCACHE_MODE_R) mode. WCache sends original and new + // (derived from last LBA) logical addresses to this routine + IN PWC_ERROR_HANDLER ErrorHandlerProc + ) +{ + ULONG l1, l2, l3; + ULONG PacketSize = (1) << PacketSizeSh; + ULONG BlockSize = (1) << BlockSizeSh; + ULONG BlocksPerFrame = (1) << BlocksPerFrameSh; + OSSTATUS RC = STATUS_SUCCESS; + LARGE_INTEGER rseed; + ULONG res_init_flags = 0; + +#define WCLOCK_RES 1 + + _SEH2_TRY { + // check input parameters + if(Mode == WCACHE_MODE_R) { + KdPrint(("Disable Async-Write for WORM media\n")); + WriteProcAsync = NULL; + } + if((MaxBlocks % PacketSize) || !MaxBlocks) { + KdPrint(("Total number of sectors must be packet-size-aligned\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(BlocksPerFrame % PacketSize) { + KdPrint(("Number of sectors per Frame must be packet-size-aligned\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(!ReadProc) { + KdPrint(("Read routine pointer must be valid\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(FirstLba >= LastLba) { + KdPrint(("Invalid cached area parameters: (%x - %x)\n",FirstLba, LastLba)); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(!MaxFrames) { + KdPrint(("Total frame number must be non-zero\n",FirstLba, LastLba)); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(Mode > WCACHE_MODE_MAX) { + KdPrint(("Invalid media mode. Should be 0-%x\n",WCACHE_MODE_MAX)); + try_return(RC = STATUS_INVALID_PARAMETER); + } + if(FramesToKeepFree >= MaxFrames/2) { + KdPrint(("Invalid FramesToKeepFree (%x). Should be Less or equal to MaxFrames/2 (%x)\n", FramesToKeepFree, MaxFrames/2)); + try_return(RC = STATUS_INVALID_PARAMETER); + } + // check 'features' + if(!WriteProc) { + KdPrint(("Write routine not specified\n")); + KdPrint(("Read-only mode enabled\n")); + } + MaxBlocks = max(MaxBlocks, BlocksPerFrame*3); + // initialize required structures + // we'll align structure size on system page size to + // avoid system crashes caused by pool fragmentation + if(!(Cache->FrameList = + (PW_CACHE_FRAME)MyAllocatePoolTag__(NonPagedPool, l1 = (((LastLba >> BlocksPerFrameSh)+1)*sizeof(W_CACHE_FRAME)), MEM_WCFRM_TAG) )) { + KdPrint(("Cache init err 1\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!(Cache->CachedBlocksList = + (PULONG)MyAllocatePoolTag__(NonPagedPool, l2 = ((MaxBlocks+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) { + KdPrint(("Cache init err 2\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!(Cache->CachedModifiedBlocksList = + (PULONG)MyAllocatePoolTag__(NonPagedPool, l2, MEM_WCFRM_TAG) )) { + KdPrint(("Cache init err 3\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!(Cache->CachedFramesList = + (PULONG)MyAllocatePoolTag__(NonPagedPool, l3 = ((MaxFrames+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) { + KdPrint(("Cache init err 4\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(Cache->FrameList, l1); + RtlZeroMemory(Cache->CachedBlocksList, l2); + RtlZeroMemory(Cache->CachedModifiedBlocksList, l2); + RtlZeroMemory(Cache->CachedFramesList, l3); + // remember all useful parameters + Cache->BlocksPerFrame = BlocksPerFrame; + Cache->BlocksPerFrameSh = BlocksPerFrameSh; + Cache->BlockCount = 0; + Cache->MaxBlocks = MaxBlocks; + Cache->MaxBytesToRead = MaxBytesToRead; + Cache->FrameCount = 0; + Cache->MaxFrames = MaxFrames; + Cache->PacketSize = PacketSize; + Cache->PacketSizeSh = PacketSizeSh; + Cache->BlockSize = BlockSize; + Cache->BlockSizeSh = BlockSizeSh; + Cache->WriteCount = 0; + Cache->FirstLba = FirstLba; + Cache->LastLba = LastLba; + Cache->Mode = Mode; + + if(!OS_SUCCESS(RC = WCacheDecodeFlags(Cache, Flags))) { + return RC; + } + + Cache->FramesToKeepFree = FramesToKeepFree; + Cache->WriteProc = WriteProc; + Cache->ReadProc = ReadProc; + Cache->WriteProcAsync = WriteProcAsync; + Cache->ReadProcAsync = ReadProcAsync; + Cache->CheckUsedProc = CheckUsedProc; + Cache->UpdateRelocProc = UpdateRelocProc; + Cache->ErrorHandlerProc = ErrorHandlerProc; + // init permanent tmp buffers + if(!(Cache->tmp_buff = + (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) { + KdPrint(("Cache init err 5.W\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!(Cache->tmp_buff_r = + (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) { + KdPrint(("Cache init err 5.R\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!(Cache->reloc_tab = + (PULONG)MyAllocatePoolTag__(NonPagedPool, Cache->PacketSize*sizeof(ULONG), MEM_WCFRM_TAG))) { + KdPrint(("Cache init err 6\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + if(!OS_SUCCESS(RC = ExInitializeResourceLite(&(Cache->WCacheLock)))) { + KdPrint(("Cache init err (res)\n")); + try_return(RC); + } + res_init_flags |= WCLOCK_RES; + KeQuerySystemTime((PLARGE_INTEGER)(&rseed)); + WCache_random = rseed.LowPart; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(!OS_SUCCESS(RC)) { + if(res_init_flags & WCLOCK_RES) + ExDeleteResourceLite(&(Cache->WCacheLock)); + if(Cache->FrameList) + MyFreePool__(Cache->FrameList); + if(Cache->CachedBlocksList) + MyFreePool__(Cache->CachedBlocksList); + if(Cache->CachedModifiedBlocksList) + MyFreePool__(Cache->CachedModifiedBlocksList); + if(Cache->CachedFramesList) + MyFreePool__(Cache->CachedFramesList); + if(Cache->tmp_buff_r) + MyFreePool__(Cache->tmp_buff_r); + if(Cache->tmp_buff) + MyFreePool__(Cache->tmp_buff); + if(Cache->reloc_tab) + MyFreePool__(Cache->reloc_tab); + RtlZeroMemory(Cache, sizeof(W_CACHE)); + } else { + Cache->Tag = 0xCAC11E00; + } + + } _SEH2_END; + + return RC; +} // end WCacheInit__() + +/* + WCacheRandom() - just a random generator + Returns random LONGLONG number + Internal routine + */ +LONGLONG +WCacheRandom(VOID) +{ + WCache_random = (WCache_random * 0x8088405 + 1); + return WCache_random; +} // end WCacheRandom() + +/* + WCacheFindLbaToRelease() finds Block to be flushed and purged from cache + Returns random LBA + Internal routine + */ +lba_t +__fastcall +WCacheFindLbaToRelease( + IN PW_CACHE Cache + ) +{ + if(!(Cache->BlockCount)) + return WCACHE_INVALID_LBA; + return(Cache->CachedBlocksList[((ULONG)WCacheRandom() % Cache->BlockCount)]); +} // end WCacheFindLbaToRelease() + +/* + WCacheFindModifiedLbaToRelease() finds Block to be flushed and purged from cache. + This routine looks for Blocks among modified ones + Returns random LBA (nodified) + Internal routine + */ +lba_t +__fastcall +WCacheFindModifiedLbaToRelease( + IN PW_CACHE Cache + ) +{ + if(!(Cache->WriteCount)) + return WCACHE_INVALID_LBA; + return(Cache->CachedModifiedBlocksList[((ULONG)WCacheRandom() % Cache->WriteCount)]); +} // end WCacheFindModifiedLbaToRelease() + +/* + WCacheFindFrameToRelease() finds Frame to be flushed and purged with all + Blocks (from this Frame) from cache + Returns random Frame number + Internal routine + */ +lba_t +__fastcall +WCacheFindFrameToRelease( + IN PW_CACHE Cache + ) +{ + ULONG i, j; + ULONG frame = 0; + ULONG prev_uc = -1; + ULONG uc = -1; + lba_t lba; + BOOLEAN mod = FALSE; + + if(!(Cache->FrameCount)) + return 0; + /* + return(Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]); + */ + + for(i=0; iFrameCount; i++) { + + j = Cache->CachedFramesList[i]; + + mod |= (Cache->FrameList[j].UpdateCount != 0); + uc = Cache->FrameList[j].UpdateCount*32 + Cache->FrameList[j].AccessCount; + + if(prev_uc > uc) { + prev_uc = uc; + frame = j; + } + } + if(!mod) { + frame = Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]; + lba = frame << Cache->BlocksPerFrameSh; + WcPrint(("WC:-frm %x\n", lba)); + } else { + lba = frame << Cache->BlocksPerFrameSh; + WcPrint(("WC:-frm(mod) %x\n", lba)); + for(i=0; iFrameCount; i++) { + + j = Cache->CachedFramesList[i]; + Cache->FrameList[j].UpdateCount = (Cache->FrameList[j].UpdateCount*2)/3; + Cache->FrameList[j].AccessCount = (Cache->FrameList[j].AccessCount*3)/4; + } + } + return frame; +} // end WCacheFindFrameToRelease() + +/* + WCacheGetSortedListIndex() returns index of searched Lba + (Lba is ULONG in sorted array) or index of minimal cached Lba + greater than searched. + If requested Lba is less than minimum cached, 0 is returned. + If requested Lba is greater than maximum cached, BlockCount value + is returned. + Internal routine + */ + +#pragma warning(push) +#pragma warning(disable:4035) // re-enable below + +ULONG +//__fastcall +WCacheGetSortedListIndex( + IN ULONG BlockCount, // number of items in array (pointed by List) + IN lba_t* List, // pointer to sorted (ASC) array of ULONGs + IN lba_t Lba // ULONG value to be searched for + ) +{ + if(!BlockCount) + return 0; + +//#ifdef _X86_ +#ifdef _MSC_VER + + __asm push ecx + __asm push ebx + __asm push edx + __asm push esi + __asm push edi +// left = 0; +// right = BlockCount - 1; +// pos = 0; + __asm xor edx,edx // left + __asm mov ebx,BlockCount + __asm dec ebx // right + __asm xor esi,esi // pos + __asm mov edi,List // List + __asm mov ecx,Lba // Lba + +While_1: +// while(left != right) { + __asm cmp edx,ebx + __asm jz EO_while_1 + +// pos = (left + right) >> 1; + __asm lea esi,[ebx+edx] + __asm shr esi,1 +// if(List[pos] == Lba) +// return pos; + __asm mov eax,[edi+esi*4] + __asm cmp eax,ecx + __asm jz EO_while_2 + +// if(right - left == 1) { + __asm sub ebx,edx + __asm cmp ebx,1 + __asm jne NO_r_sub_l_eq_1 +// if(List[pos+1] < Lba) <=> if(List[pos+1] >= Lba) +// return (pos+2); <=> break; +// break; <=> return (pos+2); + __asm cmp [edi+esi*4+4],ecx + __asm jae EO_while_1 + __asm add esi,2 + __asm jmp EO_while_2 +// } +NO_r_sub_l_eq_1: +// if(List[pos] < Lba) { + __asm cmp eax,ecx + __asm jae Update_r +// left = pos; + __asm add ebx,edx + __asm mov edx,esi + __asm jmp While_1 +// } else { +Update_r: +// right = pos; + __asm mov ebx,esi + __asm jmp While_1 +// } +// } +EO_while_1: +// if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++; + __asm mov eax,[edi+esi*4] + __asm cmp eax,ecx + __asm jae EO_while_2 + __asm inc esi + __asm cmp esi,BlockCount + __asm jbe EO_while_2 + __asm dec esi +EO_while_2: +// return pos; + __asm mov eax,esi + + __asm pop edi + __asm pop esi + __asm pop edx + __asm pop ebx + __asm pop ecx + +#else // NO X86 optimization , use generic C/C++ + + ULONG pos; + ULONG left; + ULONG right; + + if(!BlockCount) + return 0; + + left = 0; + right = BlockCount - 1; + pos = 0; + while(left != right) { + pos = (left + right) >> 1; + if(List[pos] == Lba) + return pos; + if(right - left == 1) { + if(List[pos+1] < Lba) + return (pos+2); + break; + } + if(List[pos] < Lba) { + left = pos; + } else { + right = pos; + } + } + if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++; + + return pos; + +#endif // _X86_ + +} + +#pragma warning(pop) // re-enable warning #4035 + +/* + WCacheInsertRangeToList() inserts values laying in range described + by Lba (1st value) and BCount (number of sequentially incremented + values) in sorted array of ULONGs pointed by List. + Ex.: (Lba, BCount)=(7,3) will insert values {7,8,9}. + If target array already contains one or more values falling in + requested range, they will be removed before insertion. + WCacheInsertRangeToList() updates value of (*BlockCount) to reflect + performed changes. + WCacheInsertRangeToList() assumes that target array is of enough size. + Internal routine + */ +VOID +__fastcall +WCacheInsertRangeToList( + IN lba_t* List, // pointer to sorted (ASC) array of ULONGs + IN PULONG BlockCount, // pointer to number of items in array (pointed by List) + IN lba_t Lba, // initial value for insertion + IN ULONG BCount // number of sequentially incremented values to be inserted + ) +{ + if(!BCount) + return; + + ASSERT(!(BCount & 0x80000000)); + + ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba); + ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+BCount); + ULONG offs = firstPos + BCount - lastPos; + + if(offs) { + // move list tail +// ASSERT(lastPos+offs + ((*BlockCount) - lastPos) <= qq); + if(*BlockCount) { +#ifdef WCACHE_BOUND_CHECKS + MyCheckArray(List, lastPos+offs+(*BlockCount)-lastPos-1); +#endif //WCACHE_BOUND_CHECKS + DbgMoveMemory(&(List[lastPos+offs]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG)); + } + lastPos += offs; + for(; firstPosFrameCount; +#endif //DBG + + // We are about to add new cache frame. + // Thus check if we have enough free entries and + // flush unused ones if it is neccessary. + if(Cache->FrameCount >= Cache->MaxFrames) { + BrutePoint(); + WCacheCheckLimits(Cache, Context, frame << Cache->BlocksPerFrameSh, Cache->PacketSize*2); + } + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = (PW_CACHE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l = sizeof(W_CACHE_ENTRY) << Cache->BlocksPerFrameSh, MEM_WCFRM_TAG); + Cache->FrameList[frame].Frame = block_array; + + // Keep history !!! + //Cache->FrameList[frame].UpdateCount = 0; + //Cache->FrameList[frame].AccessCount = 0; + + if(block_array) { + ASSERT((ULONG)block_array > 0x1000); + WCacheInsertItemToList(Cache->CachedFramesList, &(Cache->FrameCount), frame); + RtlZeroMemory(block_array, l); + } else { + BrutePoint(); + } + ASSERT(Cache->FrameCount <= Cache->MaxFrames); +#ifdef DBG + ASSERT(old_count < Cache->FrameCount); +#endif //DBG + return block_array; +} // end WCacheInitFrame() + +/* + WCacheRemoveFrame() frees storage for Frame (block_array) with + index 'frame' and removes it's index from sorted array of + frame indexes. + Internal routine + */ +VOID +__fastcall +WCacheRemoveFrame( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user's context (currently unused) + IN ULONG frame // frame index + ) +{ + PW_CACHE_ENTRY block_array; +#ifdef DBG + ULONG old_count = Cache->FrameCount; +#endif //DBG + + ASSERT(Cache->FrameCount <= Cache->MaxFrames); + block_array = Cache->FrameList[frame].Frame; + + WCacheRemoveItemFromList(Cache->CachedFramesList, &(Cache->FrameCount), frame); + MyFreePool__(block_array); +// ASSERT(!(Cache->FrameList[frame].WriteCount)); +// ASSERT(!(Cache->FrameList[frame].WriteCount)); + Cache->FrameList[frame].Frame = NULL; + ASSERT(Cache->FrameCount < Cache->MaxFrames); +#ifdef DBG + ASSERT(old_count > Cache->FrameCount); +#endif //DBG + +} // end WCacheRemoveFrame() + +/* + WCacheSetModFlag() sets Modified flag for Block with offset 'i' + in Frame 'block_array' + Internal routine + */ +#define WCacheSetModFlag(block_array, i) \ + *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_MODIFIED + +/* + WCacheClrModFlag() clears Modified flag for Block with offset 'i' + in Frame 'block_array' + Internal routine + */ +#define WCacheClrModFlag(block_array, i) \ + *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_MODIFIED + +/* + WCacheGetModFlag() returns non-zero value if Modified flag for + Block with offset 'i' in Frame 'block_array' is set. Otherwise + 0 is returned. + Internal routine + */ +#define WCacheGetModFlag(block_array, i) \ + (((UCHAR)(block_array[i].Sector)) & WCACHE_FLAG_MODIFIED) + +#if 0 +/* + WCacheSetBadFlag() sets Modified flag for Block with offset 'i' + in Frame 'block_array' + Internal routine + */ +#define WCacheSetBadFlag(block_array, i) \ + *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_BAD + +/* + WCacheClrBadFlag() clears Modified flag for Block with offset 'i' + in Frame 'block_array' + Internal routine + */ +#define WCacheClrBadFlag(block_array, i) \ + *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_BAD + +/* + WCacheGetBadFlag() returns non-zero value if Modified flag for + Block with offset 'i' in Frame 'block_array' is set. Otherwise + 0 is returned. + Internal routine + */ +#define WCacheGetBadFlag(block_array, i) \ + (((UCHAR)(block_array[i].Sector)) & WCACHE_FLAG_BAD) +#endif //0 + +/* + WCacheSectorAddr() returns pointer to memory block containing cached + data for Block described by Frame (block_array) and offset in this + Frame (i). If requested Block is not cached yet NULL is returned. + Internal routine + */ +#define WCacheSectorAddr(block_array, i) \ + ((ULONG)(block_array[i].Sector) & WCACHE_ADDR_MASK) + +/* + WCacheFreeSector() releases memory block containing cached + data for Block described by Frame (block_array) and offset in this + Frame (i). Should never be called for non-cached Blocks. + Internal routine + */ +#define WCacheFreeSector(frame, offs) \ +{ \ + DbgFreePool((PVOID)WCacheSectorAddr(block_array, offs)); \ + block_array[offs].Sector = NULL; \ + Cache->FrameList[frame].BlockCount--; \ +} + +/* + WCacheAllocAsyncEntry() allocates storage for async IO context, + links it to previously allocated async IO context (if any), + initializes synchronization (completion) event + and allocates temporary IO buffers. + Async IO contexts are used to create chained set of IO requests + durring top-level request precessing and wait for their completion. + Internal routine + */ +PW_CACHE_ASYNC +WCacheAllocAsyncEntry( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to the pointer to + // the head of async IO context chain + IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to the storage for pointer + // to newly allocated async IO context chain + IN ULONG BufferSize // requested IO buffer size + ) +{ + PW_CACHE_ASYNC WContext; + PCHAR Buffer; + + WContext = (PW_CACHE_ASYNC)MyAllocatePoolTag__(NonPagedPool,sizeof(W_CACHE_ASYNC), MEM_WCCTX_TAG); + if(!WContext) + return NULL; + Buffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, BufferSize*(2-Cache->Chained), MEM_WCBUF_TAG); + if(!Buffer) { + MyFreePool__(WContext); + return NULL; + } + + if(!Cache->Chained) + KeInitializeEvent(&(WContext->PhContext.event), SynchronizationEvent, FALSE); + WContext->Cache = Cache; + if(*PrevWContext) + (*PrevWContext)->NextWContext = WContext; +// WContext->NextWContext = (*PrevWContext); + WContext->NextWContext = NULL; + WContext->Buffer = Buffer; + WContext->Buffer2 = Buffer+(Cache->Chained ? 0 : BufferSize); + + if(!(*FirstWContext)) + (*FirstWContext) = WContext; + (*PrevWContext) = WContext; + + return WContext; +} // end WCacheAllocAsyncEntry() + +/* + WCacheFreeAsyncEntry() releases storage previously allocated for + async IO context. + Internal routine + */ +VOID +WCacheFreeAsyncEntry( + IN PW_CACHE Cache, // pointer to the Cache Control structure + PW_CACHE_ASYNC WContext // pointer to async IO context to release + ) +{ + DbgFreePool(WContext->Buffer); + MyFreePool__(WContext); +} // end WCacheFreeAsyncEntry() + +//#define WCacheRaiseIoError(c, ct, s, l, bc, b, o, r) + +OSSTATUS +WCacheRaiseIoError( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, + IN OSSTATUS Status, + IN ULONG Lba, + IN ULONG BCount, + IN PVOID Buffer, + IN BOOLEAN ReadOp, + IN PBOOLEAN Retry + ) +{ + if(!Cache->ErrorHandlerProc) + return Status; + + WCACHE_ERROR_CONTEXT ec; + + ec.WCErrorCode = ReadOp ? WCACHE_ERROR_READ : WCACHE_ERROR_WRITE; + ec.Status = Status; + ec.ReadWrite.Lba = Lba; + ec.ReadWrite.BCount = BCount; + ec.ReadWrite.Buffer = Buffer; + Status = Cache->ErrorHandlerProc(Context, &ec); + if(Retry) + (*Retry) = ec.Retry; + + return Status; + +} // end WCacheRaiseIoError() + +/* + WCacheUpdatePacket() attempts to updates packet containing target Block. + If async IO is enabled new IO context is added to the chain. + If packet containing target Block is modified and PrefereWrite flag + is NOT set, function returns with status STATUS_RETRY. This setting is + user in WCACHE_MODE_R mode to reduce physical writes on flush. + 'State' parameter is used in async mode to determine the next processing + stege for given request + Internal routine + */ +OSSTATUS +WCacheUpdatePacket( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user's context to be passed to user-supplied + // low-level IO routines (IO callbacks) + IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context + IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context + IN PW_CACHE_ENTRY block_array, // pointer to target Frame + IN lba_t firstLba, // LBA of the 1st block in target Frame + IN lba_t Lba, // LBA of target Block + IN ULONG BSh, // bit shift for Block size + IN ULONG BS, // Block size (bytes) + IN ULONG PS, // Packet size (bytes) + IN ULONG PSs, // Packet size (sectors) + IN PULONG ReadBytes, // pointer to number of successfully read/written bytes + IN BOOLEAN PrefereWrite, // allow physical write (flush) of modified packet + IN ULONG State // callers state + ) +{ + OSSTATUS status; + PCHAR tmp_buff = Cache->tmp_buff; + PCHAR tmp_buff2 = Cache->tmp_buff; + BOOLEAN mod; + BOOLEAN read; + BOOLEAN zero; + ULONG i; + lba_t Lba0; + PW_CACHE_ASYNC WContext; + BOOLEAN Async = (Cache->ReadProcAsync && Cache->WriteProcAsync); + ULONG block_type; + BOOLEAN Chained = Cache->Chained; + + // Check if we are going to write down to disk + // all prewiously prepared (chained) data + if(State == ASYNC_STATE_WRITE) { + WContext = (*PrevWContext); + tmp_buff = (PCHAR)(WContext->Buffer); + tmp_buff2 = (PCHAR)(WContext->Buffer2); + if(!Chained) + mod = (DbgCompareMemory(tmp_buff2, tmp_buff, PS) != PS); + goto try_write; + } + + // Check if packet contains modified blocks + // If packet contains non-cached and unchanged, but used + // blocks, it must be read from media before modification + mod = read = zero = FALSE; + Lba0 = Lba - firstLba; + for(i=0; iCheckUsedProc(Context, Lba+i)) & WCACHE_BLOCK_USED) ) { + // + if(block_type & WCACHE_BLOCK_ZERO) { + zero = TRUE; + } else { + read = TRUE; + } + } + } + // check if we are allowed to write to media + if(mod && !PrefereWrite) { + return STATUS_RETRY; + } + // return STATUS_SUCCESS if requested packet contains no modified blocks + if(!mod) { + (*ReadBytes) = PS; + return STATUS_SUCCESS; + } + + // pefrorm full update cycle: prepare(optional)/read/modify/write + + // do some preparations + if(Chained || Async) { + // For chained and async I/O we allocates context entry + // and add it to list (chain) + // We shall only read data to temporary buffer and + // modify it. Write operations will be invoked later. + // This is introduced in order to avoid frequent + // read.write mode switching, because it significantly degrades + // performance + WContext = WCacheAllocAsyncEntry(Cache, FirstWContext, PrevWContext, PS); + if(!WContext) { + //return STATUS_INSUFFICIENT_RESOURCES; + // try to recover + Chained = FALSE; + Async = FALSE; + } else { + tmp_buff = tmp_buff2 = (PCHAR)(WContext->Buffer); + WContext->Lba = Lba; + WContext->Cmd = ASYNC_CMD_UPDATE; + WContext->State = ASYNC_STATE_NONE; + } + } + + // read packet (if it necessary) + if(read) { + if(Async) { + WContext->State = ASYNC_STATE_READ; + status = Cache->ReadProcAsync(Context, WContext, tmp_buff, PS, Lba, + &(WContext->TransferredBytes)); +// tmp_buff2 = (PCHAR)(WContext->Buffer2); + (*ReadBytes) = PS; + return status; + } else { + status = Cache->ReadProc(Context, tmp_buff, PS, Lba, ReadBytes, PH_TMP_BUFFER); + } + if(!OS_SUCCESS(status)) { + status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff, WCACHE_R_OP, NULL); + if(!OS_SUCCESS(status)) { + return status; + } + } + } else + if(zero) { + RtlZeroMemory(tmp_buff, PS); + } + + if(Chained) { + // indicate that we prepared for writing block to disk + WContext->State = ASYNC_STATE_WRITE_PRE; + tmp_buff2 = tmp_buff; + status = STATUS_SUCCESS; + } + + // modify packet + + // If we didn't read packet from media, we can't + // perform comparison to assure that packet was really modified. + // Thus, assume that it is modified in this case. + mod = !read | Cache->DoNotCompare; + Lba0 = Lba - firstLba; + for(i=0; iState == ASYNC_STATE_WRITE_PRE) { + // Return if block is prepared for write and we are in chained mode. + if(!mod) { + // Mark block as written if we have found that data in it + // is not actually modified. + WContext->State = ASYNC_STATE_DONE; + (*ReadBytes) = PS; + } + return STATUS_SUCCESS; + } + + // write packet + + // If the check above reported some changes in packet + // we should write packet out to media. + // Otherwise, just complete request. + if(mod) { +try_write: + if(Async) { + WContext->State = ASYNC_STATE_WRITE; + status = Cache->WriteProcAsync(Context, WContext, tmp_buff2, PS, Lba, + &(WContext->TransferredBytes), FALSE); + (*ReadBytes) = PS; + } else { + status = Cache->WriteProc(Context, tmp_buff2, PS, Lba, ReadBytes, 0); + if(!OS_SUCCESS(status)) { + status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff2, WCACHE_W_OP, NULL); + } + } + } else { + if(Async) + WCacheCompleteAsync__(WContext, STATUS_SUCCESS); + (*ReadBytes) = PS; + return STATUS_SUCCESS; + } + + return status; +} // end WCacheUpdatePacket() + +/* + WCacheFreePacket() releases storage for all Blocks in packet. + 'frame' describes Frame, offset - Block in Frame. offset should be + aligned on Packet size. + Internal routine + */ +VOID +WCacheFreePacket( + IN PW_CACHE Cache, // pointer to the Cache Control structure +// IN PVOID Context, + IN ULONG frame, // Frame index + IN PW_CACHE_ENTRY block_array, // Frame + IN ULONG offs, // offset in Frame + IN ULONG PSs // Packet size (in Blocks) + ) +{ + ULONG i; + // mark as non-cached & free pool + for(i=0; iBlockSize << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG frame; + lba_t firstLba; + + // Walk through all chained blocks and wait + // for completion of read operations. + // Also invoke writes of already prepared packets. + while(WContext) { + if(WContext->Cmd == ASYNC_CMD_UPDATE && + WContext->State == ASYNC_STATE_READ) { + // wait for async read for update + DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); + + WContext->State = ASYNC_STATE_WRITE; + WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, + PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); + } else + if(WContext->Cmd == ASYNC_CMD_UPDATE && + WContext->State == ASYNC_STATE_WRITE_PRE) { + // invoke physical write it the packet is prepared for writing + // by previuous call to WCacheUpdatePacket() + WContext->State = ASYNC_STATE_WRITE; + WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, + PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); + WContext->State = ASYNC_STATE_DONE; + } else + if(WContext->Cmd == ASYNC_CMD_READ && + WContext->State == ASYNC_STATE_READ) { + // wait for async read + DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); + } + WContext = WContext->NextWContext; + } + // Walk through all chained blocks and wait + // and wait for completion of async writes (if any). + // Also free temporary buffers containing already written blocks. + WContext = (*FirstWContext); + while(WContext) { + NextWContext = WContext->NextWContext; + if(WContext->Cmd == ASYNC_CMD_UPDATE && + WContext->State == ASYNC_STATE_WRITE) { + + if(!Cache->Chained) + DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); + + frame = WContext->Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + + if(FreePacket) { + WCacheFreePacket(Cache, frame, + Cache->FrameList[frame].Frame, + WContext->Lba - firstLba, PSs); + } + } + WCacheFreeAsyncEntry(Cache, WContext); + WContext = NextWContext; + } + (*FirstWContext) = NULL; + (*PrevWContext) = NULL; +} // end WCacheUpdatePacketComplete() + +/* + WCacheCheckLimits() checks if we've enough free Frame- & + Block-entries under Frame- and Block-limit to feet + requested Blocks. + If there is not enough entries, WCache initiates flush & purge + process to satisfy request. + This is dispatch routine, which calls + WCacheCheckLimitsR() or WCacheCheckLimitsRW() depending on + media type. + Internal routine + */ +OSSTATUS +__fastcall +WCacheCheckLimits( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t ReqLba, // first LBA to access/cache + IN ULONG BCount // number of Blocks to access/cache + ) +{ +/* if(!Cache->FrameCount || !Cache->BlockCount) { + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + if(!Cache->FrameCount) + return STATUS_SUCCESS; + }*/ + + // check if we have reached Frame or Block limit + if(!Cache->FrameCount && !Cache->BlockCount) { + return STATUS_SUCCESS; + } + + // check for empty frames + if(Cache->FrameCount > (Cache->MaxFrames*3)/4) { + ULONG frame; + ULONG i; + for(i=Cache->FrameCount; i>0; i--) { + frame = Cache->CachedFramesList[i-1]; + // check if frame is empty + if(!(Cache->FrameList[frame].BlockCount)) { + WCacheRemoveFrame(Cache, Context, frame); + } else { + ASSERT(Cache->FrameList[frame].Frame); + } + } + } + + if(!Cache->BlockCount) { + return STATUS_SUCCESS; + } + + // invoke media-specific limit-checker + switch(Cache->Mode) { + case WCACHE_MODE_RAM: + return WCacheCheckLimitsRAM(Cache, Context, ReqLba, BCount); + case WCACHE_MODE_ROM: + case WCACHE_MODE_RW: + return WCacheCheckLimitsRW(Cache, Context, ReqLba, BCount); + case WCACHE_MODE_R: + return WCacheCheckLimitsR(Cache, Context, ReqLba, BCount); + } + return STATUS_DRIVER_INTERNAL_ERROR; +} // end WCacheCheckLimits() + +/* + WCacheCheckLimitsRW() implements automatic flush and purge of + unused blocks to keep enough free cache entries for newly + read/written blocks for Random Access and ReWritable media + using Read/Modify/Write technology. + See also WCacheCheckLimits() + Internal routine + */ +OSSTATUS +__fastcall +WCacheCheckLimitsRW( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t ReqLba, // first LBA to access/cache + IN ULONG BCount // number of Blocks to access/cache + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t lastLba; + lba_t Lba; +// PCHAR tmp_buff = Cache->tmp_buff; + ULONG firstPos; + ULONG lastPos; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG try_count = 0; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + ULONG ReadBytes; + ULONG FreeFrameCount = 0; +// PVOID addr; + PW_CACHE_ASYNC FirstWContext = NULL; + PW_CACHE_ASYNC PrevWContext = NULL; + ULONG chain_count = 0; + + if(Cache->FrameCount >= Cache->MaxFrames) { + FreeFrameCount = Cache->FramesToKeepFree; + } else + if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + + BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { + // we need free space to grow WCache without flushing data + // for some period of time + FreeFrameCount = Cache->FramesToKeepFree; + goto Try_Another_Frame; + } + // remove(flush) some frames + while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { +Try_Another_Frame: + if(!Cache->FrameCount || !Cache->BlockCount) { + //ASSERT(!Cache->FrameCount); + if(Cache->FrameCount) { + KdPrint(("ASSERT: Cache->FrameCount = %d, when 0 is expected\n", Cache->FrameCount)); + } + ASSERT(!Cache->BlockCount); + if(!Cache->FrameCount) + break; + } + + frame = WCacheFindFrameToRelease(Cache); +#if 0 + if(Cache->FrameList[frame].WriteCount) { + try_count++; + if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; + } else { + try_count = 0; + } +#else + if(Cache->FrameList[frame].UpdateCount) { + try_count = MAX_TRIES_FOR_NA; + } else { + try_count = 0; + } +#endif + + if(FreeFrameCount) + FreeFrameCount--; + + firstLba = frame << Cache->BlocksPerFrameSh; + lastLba = firstLba + Cache->BlocksPerFrame; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); + block_array = Cache->FrameList[frame].Frame; + + if(!block_array) { + KdPrint(("Hmm...\n")); + BrutePoint(); + return STATUS_DRIVER_INTERNAL_ERROR; + } + + while(firstPos < lastPos) { + // flush packet + Lba = List[firstPos] & ~(PSs-1); + + // write packet out or prepare and add to chain (if chained mode enabled) + status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, + Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); + + if(status != STATUS_PENDING) { + // free memory + WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); + } + + Lba += PSs; + while((firstPos < lastPos) && (Lba > List[firstPos])) { + firstPos++; + } + chain_count++; + // write chained packets + if(chain_count >= WCACHE_MAX_CHAIN) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); + chain_count = 0; + } + } + // remove flushed blocks from all lists + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); + + WCacheRemoveFrame(Cache, Context, frame); + } + + // check if we try to read too much data + if(BCount > Cache->MaxBlocks) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); + return STATUS_INVALID_PARAMETER; + } + + // remove(flush) packet + while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + + BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { + try_count = 0; +Try_Another_Block: + + Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); + if(Lba == WCACHE_INVALID_LBA) { + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + break; + } + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + // write already prepared blocks to disk and return error + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); + ASSERT(FALSE); + return STATUS_DRIVER_INTERNAL_ERROR; + } + + // write packet out or prepare and add to chain (if chained mode enabled) + status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, + Lba, BSh, BS, PS, PSs, &ReadBytes, (try_count >= MAX_TRIES_FOR_NA), ASYNC_STATE_NONE); + + if(status == STATUS_RETRY) { + try_count++; + goto Try_Another_Block; + } + + // free memory + WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); + + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); + // check if frame is empty + if(!(Cache->FrameList[frame].BlockCount)) { + WCacheRemoveFrame(Cache, Context, frame); + } else { + ASSERT(Cache->FrameList[frame].Frame); + } + chain_count++; + if(chain_count >= WCACHE_MAX_CHAIN) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); + chain_count = 0; + } + } + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); + return STATUS_SUCCESS; +} // end WCacheCheckLimitsRW() + +OSSTATUS +__fastcall +WCacheFlushBlocksRAM( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + PW_CACHE_ENTRY block_array, + lba_t* List, + ULONG firstPos, + ULONG lastPos, + BOOLEAN Purge + ) +{ + ULONG frame; + lba_t Lba; + lba_t PrevLba; + lba_t firstLba; + PCHAR tmp_buff = NULL; + ULONG n; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; +// ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG _WrittenBytes; + OSSTATUS status = STATUS_SUCCESS; + + frame = List[firstPos] >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + + while(firstPos < lastPos) { + // flush blocks + ASSERT(Cache->FrameCount <= Cache->MaxFrames); + Lba = List[firstPos]; + if(!WCacheGetModFlag(block_array, Lba - firstLba)) { + // free memory + if(Purge) { + WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, 1); + } + firstPos++; + continue; + } + tmp_buff = Cache->tmp_buff; + PrevLba = Lba; + n=1; + while((firstPos+n < lastPos) && + (List[firstPos+n] == PrevLba+1)) { + PrevLba++; + if(!WCacheGetModFlag(block_array, PrevLba - firstLba)) + break; + DbgCopyMemory(tmp_buff + (n << BSh), + (PVOID)WCacheSectorAddr(block_array, PrevLba - firstLba), + BS); + n++; + if(n >= PSs) + break; + } + if(n > 1) { + DbgCopyMemory(tmp_buff, + (PVOID)WCacheSectorAddr(block_array, Lba - firstLba), + BS); + } else { + tmp_buff = (PCHAR)WCacheSectorAddr(block_array, Lba - firstLba); + } + // write sectors out + status = Cache->WriteProc(Context, tmp_buff, n<CachedBlocksList; + lba_t lastLba; + lba_t Lba; +// PCHAR tmp_buff = Cache->tmp_buff; + ULONG firstPos; + ULONG lastPos; +// ULONG BSh = Cache->BlockSizeSh; +// ULONG BS = Cache->BlockSize; +// ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG try_count = 0; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + ULONG FreeFrameCount = 0; +// PVOID addr; + + if(Cache->FrameCount >= Cache->MaxFrames) { + FreeFrameCount = Cache->FramesToKeepFree; + } else + if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + + BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { + // we need free space to grow WCache without flushing data + // for some period of time + FreeFrameCount = Cache->FramesToKeepFree; + goto Try_Another_Frame; + } + // remove(flush) some frames + while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { + ASSERT(Cache->FrameCount <= Cache->MaxFrames); +Try_Another_Frame: + if(!Cache->FrameCount || !Cache->BlockCount) { + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + if(!Cache->FrameCount) + break; + } + + frame = WCacheFindFrameToRelease(Cache); +#if 0 + if(Cache->FrameList[frame].WriteCount) { + try_count++; + if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; + } else { + try_count = 0; + } +#else + if(Cache->FrameList[frame].UpdateCount) { + try_count = MAX_TRIES_FOR_NA; + } else { + try_count = 0; + } +#endif + + if(FreeFrameCount) + FreeFrameCount--; + + firstLba = frame << Cache->BlocksPerFrameSh; + lastLba = firstLba + Cache->BlocksPerFrame; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); + block_array = Cache->FrameList[frame].Frame; + + if(!block_array) { + KdPrint(("Hmm...\n")); + BrutePoint(); + return STATUS_DRIVER_INTERNAL_ERROR; + } + status = WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); + + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); + WCacheRemoveFrame(Cache, Context, frame); + } + + // check if we try to read too much data + if(BCount > Cache->MaxBlocks) { + return STATUS_INVALID_PARAMETER; + } + + // remove(flush) packet + while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + + BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { + try_count = 0; +//Try_Another_Block: + + ASSERT(Cache->FrameCount <= Cache->MaxFrames); + Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); + if(Lba == WCACHE_INVALID_LBA) { + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + break; + } + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + ASSERT(FALSE); + return STATUS_DRIVER_INTERNAL_ERROR; + } + status = WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); + // check if frame is empty + if(!(Cache->FrameList[frame].BlockCount)) { + WCacheRemoveFrame(Cache, Context, frame); + } else { + ASSERT(Cache->FrameList[frame].Frame); + } + } + return STATUS_SUCCESS; +} // end WCacheCheckLimitsRAM() + +/* + WCachePurgeAllRAM() + Internal routine + */ +OSSTATUS +__fastcall +WCachePurgeAllRAM( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context // user-supplied context for IO callbacks + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t lastLba; + ULONG firstPos; + ULONG lastPos; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + + // remove(flush) some frames + while(Cache->FrameCount) { + + frame = Cache->CachedFramesList[0]; + + firstLba = frame << Cache->BlocksPerFrameSh; + lastLba = firstLba + Cache->BlocksPerFrame; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); + block_array = Cache->FrameList[frame].Frame; + + if(!block_array) { + KdPrint(("Hmm...\n")); + BrutePoint(); + return STATUS_DRIVER_INTERNAL_ERROR; + } + status = WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); + + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); + WCacheRemoveFrame(Cache, Context, frame); + } + + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + return STATUS_SUCCESS; +} // end WCachePurgeAllRAM() + +/* + WCacheFlushAllRAM() + Internal routine + */ +OSSTATUS +__fastcall +WCacheFlushAllRAM( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context // user-supplied context for IO callbacks + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t lastLba; + ULONG firstPos; + ULONG lastPos; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + + // flush frames + while(Cache->WriteCount) { + + frame = Cache->CachedModifiedBlocksList[0] >> Cache->BlocksPerFrameSh; + + firstLba = frame << Cache->BlocksPerFrameSh; + lastLba = firstLba + Cache->BlocksPerFrame; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); + block_array = Cache->FrameList[frame].Frame; + + if(!block_array) { + KdPrint(("Hmm...\n")); + BrutePoint(); + return STATUS_DRIVER_INTERNAL_ERROR; + } + status = WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, FALSE); + + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); + } + + return STATUS_SUCCESS; +} // end WCacheFlushAllRAM() + +/* + WCachePreReadPacket__() reads & caches the whole packet containing + requested LBA. This routine just caches data, it doesn't copy anything + to user buffer. + In general we have no user buffer here... ;) + Public routine +*/ +OSSTATUS +WCachePreReadPacket__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t Lba // LBA to cache together with whole packet + ) +{ + ULONG frame; + OSSTATUS status = STATUS_SUCCESS; + PW_CACHE_ENTRY block_array; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + PCHAR addr; + ULONG _ReadBytes; + ULONG PS = Cache->PacketSize; // (in blocks) + ULONG BCount = PS; + ULONG i, n, err_count; + BOOLEAN sector_added = FALSE; + ULONG block_type; + BOOLEAN zero = FALSE;//TRUE; +/* + ULONG first_zero=0, last_zero=0; + BOOLEAN count_first_zero = TRUE; +*/ + + Lba &= ~(PS-1); + frame = Lba >> Cache->BlocksPerFrameSh; + i = Lba - (frame << Cache->BlocksPerFrameSh); + + // assume successful operation + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) + return STATUS_INSUFFICIENT_RESOURCES; + } + + // skip cached extent (if any) + n=0; + while((n < BCount) && + (n < Cache->BlocksPerFrame)) { + + addr = (PCHAR)WCacheSectorAddr(block_array, i+n); + block_type = Cache->CheckUsedProc(Context, Lba+n); + if(/*WCacheGetBadFlag(block_array,i+n)*/ + block_type & WCACHE_BLOCK_BAD) { + // bad packet. no pre-read + return STATUS_DEVICE_DATA_ERROR; + } + if(!(block_type & WCACHE_BLOCK_ZERO)) { + zero = FALSE; + //count_first_zero = FALSE; + //last_zero = 0; + if(!addr) { + // sector is not cached, stop search + break; + } + } else { +/* + if(count_first_zero) { + first_zero++; + } + last_zero++; +*/ + } + n++; + } + // do nothing if all sectors are already cached + if(n < BCount) { + + // read whole packet + if(!zero) { + status = Cache->ReadProc(Context, Cache->tmp_buff_r, PS<tmp_buff_r, WCACHE_R_OP, NULL); + } + } else { + status = STATUS_SUCCESS; + //RtlZeroMemory(Cache->tmp_buff_r, PS<tmp_buff_r+(n<FrameList[frame].BlockCount++; + } + } else { + // read sectors one by one and copy them to cache + // unreadable sectors will be treated as zero-filled + err_count = 0; + for(n=0; nReadProc(Context, Cache->tmp_buff_r, BS, Lba+n, &_ReadBytes, PH_TMP_BUFFER); + if(!OS_SUCCESS(status)) { + status = WCacheRaiseIoError(Cache, Context, status, Lba+n, 1, Cache->tmp_buff_r, WCACHE_R_OP, NULL); + if(!OS_SUCCESS(status)) { + err_count++; + } + } + if(!zero && OS_SUCCESS(status)) { + DbgCopyMemory(addr, Cache->tmp_buff_r, BS); + } else + if(Cache->RememberBB) { + RtlZeroMemory(addr, BS); + /* + if(!OS_SUCCESS(status)) { + WCacheSetBadFlag(block_array,i); + } + */ + } + Cache->FrameList[frame].BlockCount++; + if(err_count >= 2) { + break; + } + } +// _ReadBytes = n<CachedBlocksList, &(Cache->BlockCount), Lba, n); + + return status; +} // end WCachePreReadPacket__() + +/* + WCacheReadBlocks__() reads data from cache or + read it form media and store in cache. + Public routine + */ +OSSTATUS +WCacheReadBlocks__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN PCHAR Buffer, // user-supplied buffer for read blocks + IN lba_t Lba, // LBA to start read from + IN ULONG BCount, // number of blocks to be read + OUT PULONG ReadBytes, // user-supplied pointer to ULONG that will + // recieve number of actually read bytes + IN BOOLEAN CachedOnly // specifies that cache is already locked + ) +{ + ULONG frame; + ULONG i, saved_i, saved_BC = BCount, n; + OSSTATUS status = STATUS_SUCCESS; + PW_CACHE_ENTRY block_array; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + PCHAR addr; + ULONG to_read, saved_to_read; +// PCHAR saved_buff = Buffer; + ULONG _ReadBytes; + ULONG PS = Cache->PacketSize; + ULONG MaxR = Cache->MaxBytesToRead; + ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n + ULONG d; + ULONG block_type; + + WcPrint(("WC:R %x (%x)\n", Lba, BCount)); + + (*ReadBytes) = 0; + // check if we try to read too much data + if(BCount >= Cache->MaxBlocks) { + i = 0; + if(CachedOnly) { + status = STATUS_INVALID_PARAMETER; + goto EO_WCache_R2; + } + while(TRUE) { + status = WCacheReadBlocks__(Cache, Context, Buffer + (i<FirstLba) || + (Lba + BCount - 1 > Cache->LastLba)) { + status = Cache->ReadProc(Context, Buffer, BCount, Lba, ReadBytes, 0); + if(!OS_SUCCESS(status)) { + status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_R_OP, NULL); + } + return status; + } + if(!CachedOnly) { + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + } + + frame = Lba >> Cache->BlocksPerFrameSh; + i = Lba - (frame << Cache->BlocksPerFrameSh); + + if(Cache->CacheWholePacket && (BCount < PS)) { + if(!CachedOnly && + !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba & ~(PS-1), PS*2)) ) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return status; + } + } else { + if(!CachedOnly && + !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return status; + } + } + if(!CachedOnly) { + // convert to shared +// ExConvertExclusiveToSharedLite(&(Cache->WCacheLock)); + } + + // pre-read packet. It is very useful for + // highly fragmented files + if(Cache->CacheWholePacket && (BCount < PS)) { +// status = WCacheReadBlocks__(Cache, Context, Cache->tmp_buff_r, Lba & (~PacketMask), PS, &_ReadBytes, TRUE); + // we should not perform IO if user requested CachedOnly data + if(!CachedOnly) { + status = WCachePreReadPacket__(Cache, Context, Lba); + } + status = STATUS_SUCCESS; + } + + // assume successful operation + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + ASSERT(!CachedOnly); + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_R; + } + } + + Cache->FrameList[frame].AccessCount++; + while(BCount) { + if(i >= Cache->BlocksPerFrame) { + frame++; + block_array = Cache->FrameList[frame].Frame; + i -= Cache->BlocksPerFrame; + } + if(!block_array) { + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_R; + } + } + // 'read' cached extent (if any) + // it is just copying + while(BCount && + (i < Cache->BlocksPerFrame) && + (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { + block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); + if(block_type & WCACHE_BLOCK_BAD) { + //if(WCacheGetBadFlag(block_array,i)) { + status = STATUS_DEVICE_DATA_ERROR; + goto EO_WCache_R; + } + DbgCopyMemory(Buffer, addr, BS); + Buffer += BS; + *ReadBytes += BS; + i++; + BCount--; + } + // read non-cached packet-size-aligned extent (if any) + // now we'll calculate total length & decide if it has enough size + if(!((d = Lba+saved_BC-BCount) & PacketMask) && d ) { + n = 0; + while(BCount && + (i < Cache->BlocksPerFrame) && + (!WCacheSectorAddr(block_array, i)) ) { + n++; + BCount--; + } + BCount += n; + n &= ~PacketMask; + if(n>PS) { + if(!OS_SUCCESS(status = Cache->ReadProc(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_ReadBytes, 0))) { + status = WCacheRaiseIoError(Cache, Context, status, Lba+saved_BC-BCount, n, Buffer, WCACHE_R_OP, NULL); + if(!OS_SUCCESS(status)) { + goto EO_WCache_R; + } + } +// WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); + BCount -= n; + Lba += saved_BC - BCount; + saved_BC = BCount; + i += n; + Buffer += BS*n; + *ReadBytes += BS*n; + } +// } else { +// KdPrint(("Unaligned\n")); + } + // read non-cached extent (if any) + // firstable, we'll get total number of sectors to read + to_read = 0; + saved_i = i; + d = BCount; + while(d && + (i < Cache->BlocksPerFrame) && + (!WCacheSectorAddr(block_array, i)) ) { + i++; + to_read += BS; + d--; + } + // read some not cached sectors + if(to_read) { + i = saved_i; + saved_to_read = to_read; + d = BCount - d; + // split request if necessary + if(saved_to_read > MaxR) { + WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); + n = MaxR >> BSh; + do { + status = Cache->ReadProc(Context, Buffer, MaxR, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); + *ReadBytes += _ReadBytes; + if(!OS_SUCCESS(status)) { + _ReadBytes &= ~(BS-1); + BCount -= _ReadBytes >> BSh; + saved_to_read -= _ReadBytes; + Buffer += _ReadBytes; + saved_BC = BCount; + goto store_read_data_1; + } + Buffer += MaxR; + saved_to_read -= MaxR; + i += n; + BCount -= n; + d -= n; + } while(saved_to_read > MaxR); + saved_BC = BCount; + } + if(saved_to_read) { + status = Cache->ReadProc(Context, Buffer, saved_to_read, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); + *ReadBytes += _ReadBytes; + if(!OS_SUCCESS(status)) { + _ReadBytes &= ~(BS-1); + BCount -= _ReadBytes >> BSh; + saved_to_read -= _ReadBytes; + Buffer += _ReadBytes; + goto store_read_data_1; + } + Buffer += saved_to_read; + saved_to_read = 0; + BCount -= d; + } + +store_read_data_1: + // and now we'll copy them to cache + + // + Buffer -= (to_read - saved_to_read); + i = saved_i; + while(to_read - saved_to_read) { + block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); + if(!block_array[i].Sector) { + BCount += to_read >> BSh; + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_R; + } + DbgCopyMemory(block_array[i].Sector, Buffer, BS); + Cache->FrameList[frame].BlockCount++; + i++; + Buffer += BS; + to_read -= BS; + } + if(!OS_SUCCESS(status)) + goto EO_WCache_R; + to_read = 0; + } + } + +EO_WCache_R: + + // we know the number of unread sectors if an error occured + // so we can need to update BlockCount + // return number of read bytes + WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); +// Cache->FrameList[frame].BlockCount -= BCount; +EO_WCache_R2: + if(!CachedOnly) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + } + + return status; +} // end WCacheReadBlocks__() + +/* + WCacheWriteBlocks__() writes data to cache. + Data is written directly to media if: + 1) requested block is Packet-aligned + 2) requested Lba(s) lays beyond cached area + Public routine + */ +OSSTATUS +WCacheWriteBlocks__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN PCHAR Buffer, // user-supplied buffer containing data to be written + IN lba_t Lba, // LBA to start write from + IN ULONG BCount, // number of blocks to be written + OUT PULONG WrittenBytes, // user-supplied pointer to ULONG that will + // recieve number of actually written bytes + IN BOOLEAN CachedOnly // specifies that cache is already locked + ) +{ + ULONG frame; + ULONG i, saved_BC = BCount, n, d; + OSSTATUS status = STATUS_SUCCESS; + PW_CACHE_ENTRY block_array; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + PCHAR addr; +// PCHAR saved_buff = Buffer; + ULONG _WrittenBytes; + ULONG PS = Cache->PacketSize; + ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n + ULONG block_type; +// BOOLEAN Aligned = FALSE; + + BOOLEAN WriteThrough = FALSE; + lba_t WTh_Lba; + ULONG WTh_BCount; + + WcPrint(("WC:W %x (%x)\n", Lba, BCount)); + + *WrittenBytes = 0; +// KdPrint(("BCount:%x\n",BCount)); + // check if we try to read too much data + if(BCount >= Cache->MaxBlocks) { + i = 0; + if(CachedOnly) { + status = STATUS_INVALID_PARAMETER; + goto EO_WCache_W2; + } + while(TRUE) { +// KdPrint((" BCount:%x\n",BCount)); + status = WCacheWriteBlocks__(Cache, Context, Buffer + (i<FirstLba) || + (Lba + BCount - 1 > Cache->LastLba)) { + return STATUS_INVALID_PARAMETER; + } + if(!CachedOnly) { + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + } + + frame = Lba >> Cache->BlocksPerFrameSh; + i = Lba - (frame << Cache->BlocksPerFrameSh); + + if(!CachedOnly && + !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return status; + } + + // assume successful operation + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + + if(BCount && !(BCount & (PS-1)) && !(Lba & (PS-1)) && + (Cache->Mode != WCACHE_MODE_R) && + (i+BCount <= Cache->BlocksPerFrame) && + !Cache->NoWriteThrough) { + status = Cache->WriteProc(Context, Buffer, BCount<FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_W; + } + } + + if(Cache->Mode == WCACHE_MODE_RAM && + BCount && +// !(Lba & (PS-1)) && + (!(BCount & (PS-1)) || (BCount > PS)) ) { + WriteThrough = TRUE; + WTh_Lba = Lba; + WTh_BCount = BCount; + } else + if(Cache->Mode == WCACHE_MODE_RAM && + ((Lba & ~PacketMask) != ((Lba+BCount-1) & ~PacketMask)) + ) { + WriteThrough = TRUE; + WTh_Lba = Lba & ~PacketMask; + WTh_BCount = PS; + } + + Cache->FrameList[frame].UpdateCount++; +// KdPrint((" BCount:%x\n",BCount)); + while(BCount) { + if(i >= Cache->BlocksPerFrame) { + frame++; + block_array = Cache->FrameList[frame].Frame; + i -= Cache->BlocksPerFrame; + } + if(!block_array) { + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_W; + } + } + // 'write' cached extent (if any) + // it is just copying + while(BCount && + (i < Cache->BlocksPerFrame) && + (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { +// KdPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",addr, Buffer, BS, BCount)); + block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); + if(Cache->NoWriteBB && + /*WCacheGetBadFlag(block_array,i)*/ + (block_type & WCACHE_BLOCK_BAD)) { + // bad packet. no cached write + status = STATUS_DEVICE_DATA_ERROR; + goto EO_WCache_W; + } + DbgCopyMemory(addr, Buffer, BS); + WCacheSetModFlag(block_array, i); + Buffer += BS; + *WrittenBytes += BS; + i++; + BCount--; + } + // write non-cached not-aligned extent (if any) till aligned one + while(BCount && + (i & PacketMask) && + (Cache->Mode != WCACHE_MODE_R) && + (i < Cache->BlocksPerFrame) && + (!WCacheSectorAddr(block_array, i)) ) { + block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); + if(!block_array[i].Sector) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_W; + } +// KdPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); + DbgCopyMemory(block_array[i].Sector, Buffer, BS); + WCacheSetModFlag(block_array, i); + i++; + Buffer += BS; + *WrittenBytes += BS; + BCount--; + Cache->FrameList[frame].BlockCount ++; + } + // write non-cached packet-size-aligned extent (if any) + // now we'll calculate total length & decide if has enough size + if(!Cache->NoWriteThrough + && + ( !(i & PacketMask) || + ((Cache->Mode == WCACHE_MODE_R) && (BCount >= PS)) )) { + n = 0; + while(BCount && + (i < Cache->BlocksPerFrame) && + (!WCacheSectorAddr(block_array, i)) ) { + n++; + BCount--; + } + BCount += n; + n &= ~PacketMask; +// if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE))) + if(n) { + // add previously written data to list + d = saved_BC - BCount; + WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, d); + WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); + Lba += d; + saved_BC = BCount; + + while(n) { + if(Cache->Mode == WCACHE_MODE_R) + Cache->UpdateRelocProc(Context, Lba, NULL, PS); + if(!OS_SUCCESS(status = Cache->WriteProc(Context, Buffer, PS<BlocksPerFrame) && + (!WCacheSectorAddr(block_array, i)) ) { + block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); + if(!block_array[i].Sector) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_W; + } +// KdPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); + DbgCopyMemory(block_array[i].Sector, Buffer, BS); + WCacheSetModFlag(block_array, i); + i++; + Buffer += BS; + *WrittenBytes += BS; + BCount--; + Cache->FrameList[frame].BlockCount ++; + } + } + +EO_WCache_W: + + // we know the number of unread sectors if an error occured + // so we can need to update BlockCount + // return number of read bytes + WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); + WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, saved_BC - BCount); + + if(WriteThrough && !BCount) { + ULONG d; +// lba_t lastLba; + ULONG firstPos; + ULONG lastPos; + + BCount = WTh_BCount; + Lba = WTh_Lba; + while(BCount) { + frame = Lba >> Cache->BlocksPerFrameSh; +// firstLba = frame << Cache->BlocksPerFrameSh; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba); + d = min(Lba+BCount, (frame+1) << Cache->BlocksPerFrameSh) - Lba; + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba+d); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + ASSERT(FALSE); + BCount -= d; + Lba += d; + continue; + } + status = WCacheFlushBlocksRAM(Cache, Context, block_array, Cache->CachedBlocksList, firstPos, lastPos, FALSE); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); + BCount -= d; + Lba += d; + } + } + +EO_WCache_W2: + + if(!CachedOnly) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + } + return status; +} // end WCacheWriteBlocks__() + +/* + WCacheFlushAll__() copies all data stored in cache to media. + Flushed blocks are kept in cache. + Public routine + */ +VOID +WCacheFlushAll__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context) // user-supplied context for IO callbacks +{ + if(!(Cache->ReadProc)) return; + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + + switch(Cache->Mode) { + case WCACHE_MODE_RAM: + WCacheFlushAllRAM(Cache, Context); + break; + case WCACHE_MODE_ROM: + case WCACHE_MODE_RW: + WCacheFlushAllRW(Cache, Context); + break; + case WCACHE_MODE_R: + WCachePurgeAllR(Cache, Context); + break; + } + + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return; +} // end WCacheFlushAll__() + +/* + WCachePurgeAll__() copies all data stored in cache to media. + Flushed blocks are removed cache. + Public routine + */ +VOID +WCachePurgeAll__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context) // user-supplied context for IO callbacks +{ + if(!(Cache->ReadProc)) return; + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + + switch(Cache->Mode) { + case WCACHE_MODE_RAM: + WCachePurgeAllRAM(Cache, Context); + break; + case WCACHE_MODE_ROM: + case WCACHE_MODE_RW: + WCachePurgeAllRW(Cache, Context); + break; + case WCACHE_MODE_R: + WCachePurgeAllR(Cache, Context); + break; + } + + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return; +} // end WCachePurgeAll__() +/* + WCachePurgeAllRW() copies modified blocks from cache to media + and removes them from cache + This routine can be used for RAM, RW and ROM media. + For ROM media blocks are just removed. + Internal routine + */ +VOID +__fastcall +WCachePurgeAllRW( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context) // user-supplied context for IO callbacks +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t Lba; + ULONG firstPos; + ULONG lastPos; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + ULONG ReadBytes; + PW_CACHE_ASYNC FirstWContext = NULL; + PW_CACHE_ASYNC PrevWContext = NULL; + ULONG chain_count = 0; + + if(!(Cache->ReadProc)) return; + + while(Cache->BlockCount) { + Lba = List[0] & ~(PSs-1); + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); + lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + BrutePoint(); + return; + } + + status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, + Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); + + // free memory + WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); + + WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); + WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); + // check if frame is empty + if(!(Cache->FrameList[frame].BlockCount)) { + WCacheRemoveFrame(Cache, Context, frame); + } else { + ASSERT(Cache->FrameList[frame].Frame); + } + chain_count++; + if(chain_count >= WCACHE_MAX_CHAIN) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); + chain_count = 0; + } + } + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); + return; +} // end WCachePurgeAllRW() + +/* + WCacheFlushAllRW() copies modified blocks from cache to media. + All blocks are not removed from cache. + This routine can be used for RAM, RW and ROM media. + Internal routine + */ +VOID +__fastcall +WCacheFlushAllRW( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context) // user-supplied context for IO callbacks +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedModifiedBlocksList; + lba_t Lba; + ULONG firstPos; + ULONG lastPos; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG BFs = Cache->BlocksPerFrameSh; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + ULONG ReadBytes; + PW_CACHE_ASYNC FirstWContext = NULL; + PW_CACHE_ASYNC PrevWContext = NULL; + ULONG i; + ULONG chain_count = 0; + + if(!(Cache->ReadProc)) return; + + // walk through modified blocks + while(Cache->WriteCount) { + Lba = List[0] & ~(PSs-1); + frame = Lba >> BFs; + firstLba = frame << BFs; + firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); + lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + BrutePoint(); + continue;; + } + // queue modify request + status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, + Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); + // clear MODIFIED flag for queued blocks + WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); + Lba -= firstLba; + for(i=0; i= WCACHE_MAX_CHAIN) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); + chain_count = 0; + } + } + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); +#ifdef DBG +#if 1 + // check consistency + List = Cache->CachedBlocksList; + for(i=0; iBlockCount; i++) { + Lba = List[i] /*& ~(PSs-1)*/; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + BrutePoint(); + } + ASSERT(!WCacheGetModFlag(block_array, Lba-firstLba)); + } +#endif // 1 +#endif // DBG + return; +} // end WCacheFlushAllRW() + +/* + WCacheRelease__() frees all allocated memory blocks and + deletes synchronization resources + Public routine + */ +VOID +WCacheRelease__( + IN PW_CACHE Cache // pointer to the Cache Control structure + ) +{ + ULONG i, j, k; + PW_CACHE_ENTRY block_array; + + Cache->Tag = 0xDEADCACE; + if(!(Cache->ReadProc)) return; +// ASSERT(Cache->Tag == 0xCAC11E00); + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + for(i=0; iFrameCount; i++) { + j = Cache->CachedFramesList[i]; + block_array = Cache->FrameList[j].Frame; + if(block_array) { + for(k=0; kBlocksPerFrame; k++) { + if(WCacheSectorAddr(block_array, k)) { + WCacheFreeSector(j, k); + } + } + MyFreePool__(block_array); + } + } + if(Cache->FrameList) + MyFreePool__(Cache->FrameList); + if(Cache->CachedBlocksList) + MyFreePool__(Cache->CachedBlocksList); + if(Cache->CachedBlocksList) + MyFreePool__(Cache->CachedModifiedBlocksList); + if(Cache->CachedFramesList) + MyFreePool__(Cache->CachedFramesList); + if(Cache->tmp_buff_r) + MyFreePool__(Cache->tmp_buff_r); + if(Cache->CachedFramesList) + MyFreePool__(Cache->tmp_buff); + if(Cache->CachedFramesList) + MyFreePool__(Cache->reloc_tab); + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + ExDeleteResourceLite(&(Cache->WCacheLock)); + RtlZeroMemory(Cache, sizeof(W_CACHE)); + return; +} // end WCacheRelease__() + +/* + WCacheIsInitialized__() checks if the pointer supplied points + to initialized cache structure. + Public routine + */ +BOOLEAN +WCacheIsInitialized__( + IN PW_CACHE Cache + ) +{ + return (Cache->ReadProc != NULL); +} // end WCacheIsInitialized__() + +OSSTATUS +WCacheFlushBlocksRW( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t _Lba, // LBA to start flush from + IN ULONG BCount // number of blocks to be flushed + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedModifiedBlocksList; + lba_t Lba; + ULONG firstPos; + ULONG lastPos; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG BFs = Cache->BlocksPerFrameSh; + PW_CACHE_ENTRY block_array; + OSSTATUS status; + ULONG ReadBytes; + PW_CACHE_ASYNC FirstWContext = NULL; + PW_CACHE_ASYNC PrevWContext = NULL; + ULONG i; + ULONG chain_count = 0; + lba_t lim; + + if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; + + // walk through modified blocks + lim = (_Lba+BCount+PSs-1) & ~(PSs-1); + for(Lba = _Lba & ~(PSs-1);Lba < lim ; Lba += PSs) { + frame = Lba >> BFs; + firstLba = frame << BFs; + firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); + lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + // not cached block may be requested for flush + Lba += (1 << BFs) - PSs; + continue; + } + // queue modify request + status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, + Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); + // clear MODIFIED flag for queued blocks + WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); + Lba -= firstLba; + for(i=0; i= WCACHE_MAX_CHAIN) { + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); + chain_count = 0; + } + } + WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); +/* + if(Cache->Mode != WCACHE_MODE_RAM) + return STATUS_SUCCESS; +*/ + + return STATUS_SUCCESS; +} // end WCacheFlushBlocksRW() + +/* + WCacheFlushBlocks__() copies specified blocks stored in cache to media. + Flushed blocks are kept in cache. + Public routine + */ +OSSTATUS +WCacheFlushBlocks__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t Lba, // LBA to start flush from + IN ULONG BCount // number of blocks to be flushed + ) +{ + OSSTATUS status; + + if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + + // check if we try to access beyond cached area + if((Lba < Cache->FirstLba) || + (Lba+BCount-1 > Cache->LastLba)) { + KdPrint(("LBA %#x (%x) is beyond cacheable area\n", Lba, BCount)); + BrutePoint(); + status = STATUS_INVALID_PARAMETER; + goto EO_WCache_F; + } + + switch(Cache->Mode) { + case WCACHE_MODE_RAM: +// WCacheFlushBlocksRW(Cache, Context); +// break; + case WCACHE_MODE_ROM: + case WCACHE_MODE_RW: + status = WCacheFlushBlocksRW(Cache, Context, Lba, BCount); + break; + case WCACHE_MODE_R: + status = STATUS_SUCCESS; + break; + } +EO_WCache_F: + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return status; +} // end WCacheFlushBlocks__() + +/* + WCacheDirect__() returns pointer to memory block where + requested block is stored in. + If no #CachedOnly flag specified this routine locks cache, + otherwise it assumes that cache is already locked by previous call + to WCacheStartDirect__(). + Cache can be unlocked by WCacheEODirect__(). + Using this routine caller can access cached block directly in memory + without Read_to_Tmp and Modify/Write steps. + Public routine + */ +OSSTATUS +WCacheDirect__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t Lba, // LBA of block to get pointer to + IN BOOLEAN Modified, // indicates that block will be modified + OUT PCHAR* CachedBlock, // address for pointer to cached block to be stored in + IN BOOLEAN CachedOnly // specifies that cache is already locked + ) +{ + ULONG frame; + ULONG i; + OSSTATUS status = STATUS_SUCCESS; + PW_CACHE_ENTRY block_array; + ULONG BS = Cache->BlockSize; + PCHAR addr; + ULONG _ReadBytes; + ULONG block_type; + + WcPrint(("WC:%sD %x (1)\n", Modified ? "W" : "R", Lba)); + + // lock cache if nececcary + if(!CachedOnly) { + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + } + // check if we try to access beyond cached area + if((Lba < Cache->FirstLba) || + (Lba > Cache->LastLba)) { + KdPrint(("LBA %#x is beyond cacheable area\n", Lba)); + BrutePoint(); + status = STATUS_INVALID_PARAMETER; + goto EO_WCache_D; + } + + frame = Lba >> Cache->BlocksPerFrameSh; + i = Lba - (frame << Cache->BlocksPerFrameSh); + // check if we have enough space to store requested block + if(!CachedOnly && + !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, 1))) { + BrutePoint(); + goto EO_WCache_D; + } + + // small updates are more important + block_array = Cache->FrameList[frame].Frame; + if(Modified) { + Cache->FrameList[frame].UpdateCount+=8; + } else { + Cache->FrameList[frame].AccessCount+=8; + } + if(!block_array) { + ASSERT(Cache->FrameCount < Cache->MaxFrames); + block_array = WCacheInitFrame(Cache, Context, frame); + if(!block_array) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_D; + } + } + // check if requested block is already cached + if( !(addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { + // block is not cached + // allocate memory and read block from media + // do not set block_array[i].Sector here, because if media access fails and recursive access to cache + // comes, this block should not be marked as 'cached' + addr = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); + if(!addr) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto EO_WCache_D; + } + block_type = Cache->CheckUsedProc(Context, Lba); + if(block_type == WCACHE_BLOCK_USED) { + status = Cache->ReadProc(Context, addr, BS, Lba, &_ReadBytes, PH_TMP_BUFFER); + if(Cache->RememberBB) { + if(!OS_SUCCESS(status)) { + RtlZeroMemory(addr, BS); + //WCacheSetBadFlag(block_array,i); + } + } + } else { + if(block_type & WCACHE_BLOCK_BAD) { + DbgFreePool(addr); + addr = NULL; + status = STATUS_DEVICE_DATA_ERROR; + goto EO_WCache_D; + } + if(!(block_type & WCACHE_BLOCK_ZERO)) { + BrutePoint(); + } + status = STATUS_SUCCESS; + RtlZeroMemory(addr, BS); + } + // now add pointer to buffer to common storage + block_array[i].Sector = addr; + WCacheInsertItemToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba); + if(Modified) { + WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + WCacheSetModFlag(block_array, i); + } + Cache->FrameList[frame].BlockCount ++; + } else { + // block is not cached + // just return pointer + block_type = Cache->CheckUsedProc(Context, Lba); + if(block_type & WCACHE_BLOCK_BAD) { + //if(WCacheGetBadFlag(block_array,i)) { + // bad packet. no pre-read + status = STATUS_DEVICE_DATA_ERROR; + goto EO_WCache_D; + } +#ifndef UDF_CHECK_UTIL + ASSERT(block_type & WCACHE_BLOCK_USED); +#else + if(!(block_type & WCACHE_BLOCK_USED)) { + KdPrint(("LBA %#x is not marked as used\n", Lba)); + } +#endif + if(Modified && + !WCacheGetModFlag(block_array, i)) { + WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + WCacheSetModFlag(block_array, i); + } + } + (*CachedBlock) = addr; + +EO_WCache_D: + + return status; +} // end WCacheDirect__() + +/* + WCacheEODirect__() must be used to unlock cache after calls to + to WCacheStartDirect__(). + Public routine + */ +OSSTATUS +WCacheEODirect__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context // user-supplied context for IO callbacks + ) +{ + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return STATUS_SUCCESS; +} // end WCacheEODirect__() + +/* + WCacheStartDirect__() locks cache for exclusive use. + Using this routine caller can access cached block directly in memory + without Read_to_Tmp and Modify/Write steps. + See also WCacheDirect__() + Cache can be unlocked by WCacheEODirect__(). + Public routine + */ +OSSTATUS +WCacheStartDirect__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN BOOLEAN Exclusive // lock cache for exclusive use, + // currently must be TRUE. + ) +{ + if(Exclusive) { + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + } else { + BrutePoint(); + ExAcquireResourceSharedLite(&(Cache->WCacheLock), TRUE); + } + return STATUS_SUCCESS; +} // end WCacheStartDirect__() + +/* + WCacheIsCached__() checks if requested blocks are immediately available. + Cache must be previously locked for exclusive use with WCacheStartDirect__(). + Using this routine caller can access cached block directly in memory + without Read_to_Tmp and Modify/Write steps. + See also WCacheDirect__(). + Cache can be unlocked by WCacheEODirect__(). + Public routine + */ +BOOLEAN +WCacheIsCached__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN lba_t Lba, // LBA to start check from + IN ULONG BCount // number of blocks to be checked + ) +{ + ULONG frame; + ULONG i; + PW_CACHE_ENTRY block_array; + + // check if we try to access beyond cached area + if((Lba < Cache->FirstLba) || + (Lba + BCount - 1 > Cache->LastLba)) { + return FALSE; + } + + frame = Lba >> Cache->BlocksPerFrameSh; + i = Lba - (frame << Cache->BlocksPerFrameSh); + + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + return FALSE; + } + + while(BCount) { + if(i >= Cache->BlocksPerFrame) { + frame++; + block_array = Cache->FrameList[frame].Frame; + i -= Cache->BlocksPerFrame; + } + if(!block_array) { + return FALSE; + } + // 'read' cached extent (if any) + while(BCount && + (i < Cache->BlocksPerFrame) && + WCacheSectorAddr(block_array, i) && + /*!WCacheGetBadFlag(block_array, i)*/ + /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/ + TRUE ) { + i++; + BCount--; + Lba++; + } + if(BCount && + (i < Cache->BlocksPerFrame) /*&& + (!WCacheSectorAddr(block_array, i))*/ ) { + return FALSE; + } + } + return TRUE; +} // end WCacheIsCached__() + +/* + WCacheCheckLimitsR() implements automatic flush and purge of + unused blocks to keep enough free cache entries for newly + read/written blocks for WORM media. + See also WCacheCheckLimits() + Internal routine + */ +OSSTATUS +__fastcall +WCacheCheckLimitsR( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context, // user-supplied context for IO callbacks + IN lba_t ReqLba, // first LBA to access/cache + IN ULONG BCount // number of Blocks to access/cache + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t Lba; + PCHAR tmp_buff = Cache->tmp_buff; + ULONG firstPos; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; + ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) + ULONG PSs = Cache->PacketSize; + ULONG i; + PW_CACHE_ENTRY block_array; + BOOLEAN mod; + OSSTATUS status; + ULONG ReadBytes; + ULONG MaxReloc = Cache->PacketSize; + PULONG reloc_tab = Cache->reloc_tab; + + // check if we try to read too much data + if(BCount > Cache->MaxBlocks) { + return STATUS_INVALID_PARAMETER; + } + + // remove(flush) packets from entire frame(s) + while( ((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + + BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) || + (Cache->FrameCount >= Cache->MaxFrames) ) { + +WCCL_retry_1: + + Lba = WCacheFindLbaToRelease(Cache); + if(Lba == WCACHE_INVALID_LBA) { + ASSERT(!Cache->FrameCount); + ASSERT(!Cache->BlockCount); + break; + } + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + return STATUS_DRIVER_INTERNAL_ERROR; + } + // check if modified + mod = WCacheGetModFlag(block_array, Lba - firstLba); + // read/modify/write + if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { + if(Cache->WriteCount < MaxReloc) goto WCCL_retry_1; + firstPos = WCacheGetSortedListIndex(Cache->WriteCount, Cache->CachedModifiedBlocksList, Lba); + if(!block_array) { + return STATUS_DRIVER_INTERNAL_ERROR; + } + // prepare packet & reloc table + for(i=0; iCachedModifiedBlocksList[firstPos]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + DbgCopyMemory(tmp_buff + (i << BSh), + (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), + BS); + reloc_tab[i] = Lba; + WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); + WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + // mark as non-cached & free pool + WCacheFreeSector(frame, Lba-firstLba); + // check if frame is empty + if(!Cache->FrameList[frame].BlockCount) { + WCacheRemoveFrame(Cache, Context, frame); + } + if(firstPos >= Cache->WriteCount) firstPos=0; + } + // write packet +// status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); + Cache->UpdateRelocProc(Context, NULL, reloc_tab, MaxReloc); + status = Cache->WriteProc(Context, tmp_buff, PS, NULL, &ReadBytes, 0); + if(!OS_SUCCESS(status)) { + status = WCacheRaiseIoError(Cache, Context, status, NULL, PSs, tmp_buff, WCACHE_W_OP, NULL); + } + } else { + + if((i = Cache->BlockCount - Cache->WriteCount) > MaxReloc) i = MaxReloc; + // discard blocks + for(; i; i--) { + Lba = List[firstPos]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + + if( (mod = WCacheGetModFlag(block_array, Lba - firstLba)) && + (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED) ) + continue; + WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); + if(mod) + WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + // mark as non-cached & free pool + WCacheFreeSector(frame, Lba-firstLba); + // check if frame is empty + if(!Cache->FrameList[frame].BlockCount) { + WCacheRemoveFrame(Cache, Context, frame); + } + if(firstPos >= Cache->WriteCount) firstPos=0; + } + } + } + return STATUS_SUCCESS; +} // end WCacheCheckLimitsR() + +/* + WCachePurgeAllR() copies modified blocks from cache to media + and removes them from cache + This routine can be used for R media only. + Internal routine + */ +VOID +__fastcall +WCachePurgeAllR( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN PVOID Context) // user-supplied context for IO callbacks +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t Lba; + PCHAR tmp_buff = Cache->tmp_buff; + ULONG BSh = Cache->BlockSizeSh; + ULONG BS = Cache->BlockSize; +// ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) +// ULONG PSs = Cache->PacketSize; + PW_CACHE_ENTRY block_array; + BOOLEAN mod; + OSSTATUS status; + ULONG ReadBytes; + ULONG MaxReloc = Cache->PacketSize; + PULONG reloc_tab = Cache->reloc_tab; + ULONG RelocCount = 0; + BOOLEAN IncompletePacket; + ULONG i=0; + ULONG PacketTail; + + while(Cache->WriteCount < Cache->BlockCount) { + + Lba = List[i]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + BrutePoint(); + return; + } + // check if modified + mod = WCacheGetModFlag(block_array, Lba - firstLba); + // just discard + if(!mod || !(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { + // mark as non-cached & free pool + if(WCacheSectorAddr(block_array,Lba-firstLba)) { + WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); + if(mod) + WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + // mark as non-cached & free pool + WCacheFreeSector(frame, Lba-firstLba); + // check if frame is empty + if(!Cache->FrameList[frame].BlockCount) { + WCacheRemoveFrame(Cache, Context, frame); + } + } else { + BrutePoint(); + } + } else { + i++; + } + } + + PacketTail = Cache->WriteCount & (MaxReloc-1); + IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; + + // remove(flush) packet + while((Cache->WriteCount > PacketTail) || (Cache->WriteCount && IncompletePacket)) { + + Lba = List[0]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + BrutePoint(); + return; + } + // check if modified + mod = WCacheGetModFlag(block_array, Lba - firstLba); + // pack/reloc/write + if(mod) { + DbgCopyMemory(tmp_buff + (RelocCount << BSh), + (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), + BS); + reloc_tab[RelocCount] = Lba; + RelocCount++; + // write packet + if((RelocCount >= MaxReloc) || (Cache->BlockCount == 1)) { +// status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); + Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); + status = Cache->WriteProc(Context, tmp_buff, RelocCount<CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + } else { + BrutePoint(); + } + // mark as non-cached & free pool + if(WCacheSectorAddr(block_array,Lba-firstLba)) { + WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); + // mark as non-cached & free pool + WCacheFreeSector(frame, Lba-firstLba); + // check if frame is empty + if(!Cache->FrameList[frame].BlockCount) { + WCacheRemoveFrame(Cache, Context, frame); + } + } else { + BrutePoint(); + } + } +} // end WCachePurgeAllR() + +/* + WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM). + Public routine + */ +OSSTATUS +WCacheSetMode__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN ULONG Mode // cache mode/media type to be used + ) +{ + if(Mode > WCACHE_MODE_MAX) return STATUS_INVALID_PARAMETER; + Cache->Mode = Mode; + return STATUS_SUCCESS; +} // end WCacheSetMode__() + +/* + WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM). + Public routine + */ +ULONG +WCacheGetMode__( + IN PW_CACHE Cache + ) +{ + return Cache->Mode; +} // end WCacheGetMode__() + +/* + WCacheGetWriteBlockCount__() returns number of modified blocks, those are + not flushed to media. Is usually used to preallocate blocks for + relocation table on WORM (R) media. + Public routine + */ +ULONG +WCacheGetWriteBlockCount__( + IN PW_CACHE Cache + ) +{ + return Cache->WriteCount; +} // end WCacheGetWriteBlockCount__() + +/* + WCacheSyncReloc__() builds list of all modified blocks, currently + stored in cache. For each modified block WCacheSyncReloc__() calls + user-supplied callback routine in order to update relocation table + on WORM (R) media. + Public routine + */ +VOID +WCacheSyncReloc__( + IN PW_CACHE Cache, + IN PVOID Context) +{ + ULONG frame; + lba_t firstLba; + lba_t* List = Cache->CachedBlocksList; + lba_t Lba; +// ULONG BSh = Cache->BlockSizeSh; +// ULONG BS = Cache->BlockSize; +// ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) +// ULONG PSs = Cache->PacketSize; + PW_CACHE_ENTRY block_array; + BOOLEAN mod; + ULONG MaxReloc = Cache->PacketSize; + PULONG reloc_tab = Cache->reloc_tab; + ULONG RelocCount = 0; + BOOLEAN IncompletePacket; + + IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; + // enumerate modified blocks + for(ULONG i=0; IncompletePacket && (iBlockCount); i++) { + + Lba = List[i]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + return; + } + // check if modified + mod = WCacheGetModFlag(block_array, Lba - firstLba); + // update relocation table for modified sectors + if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { + reloc_tab[RelocCount] = Lba; + RelocCount++; + if(RelocCount >= Cache->WriteCount) { + Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); + break; + } + } + } +} // end WCacheSyncReloc__() + +/* + WCacheDiscardBlocks__() removes specified blocks from cache. + Blocks are not flushed to media. + Public routine + */ +VOID +WCacheDiscardBlocks__( + IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount + ) +{ + ULONG frame; + lba_t firstLba; + lba_t* List; + lba_t Lba; + PW_CACHE_ENTRY block_array; + BOOLEAN mod; + ULONG i; + + ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); + + KdPrint((" Discard req: %x@%x\n",BCount, ReqLba)); + + List = Cache->CachedBlocksList; + if(!List) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + return; + } + i = WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba); + + // enumerate requested blocks + while((List[i] < (ReqLba+BCount)) && (i < Cache->BlockCount)) { + + Lba = List[i]; + frame = Lba >> Cache->BlocksPerFrameSh; + firstLba = frame << Cache->BlocksPerFrameSh; + block_array = Cache->FrameList[frame].Frame; + if(!block_array) { + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); + BrutePoint(); + return; + } + // check if modified + mod = WCacheGetModFlag(block_array, Lba - firstLba); + // just discard + + // mark as non-cached & free pool + if(WCacheSectorAddr(block_array,Lba-firstLba)) { + WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); + if(mod) + WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); + // mark as non-cached & free pool + WCacheFreeSector(frame, Lba-firstLba); + // check if frame is empty + if(!Cache->FrameList[frame].BlockCount) { + WCacheRemoveFrame(Cache, Context, frame); + } else { + ASSERT(Cache->FrameList[frame].Frame); + } + } else { + // we should never get here !!! + // getting this part of code means that we have + // placed non-cached block in CachedBlocksList + BrutePoint(); + } + } + ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); +} // end WCacheDiscardBlocks__() + +OSSTATUS +WCacheCompleteAsync__( + IN PVOID WContext, + IN OSSTATUS Status + ) +{ + PW_CACHE_ASYNC AsyncCtx = (PW_CACHE_ASYNC)WContext; +// PW_CACHE Cache = AsyncCtx->Cache; + + AsyncCtx->PhContext.IosbToUse.Status = Status; + KeSetEvent(&(AsyncCtx->PhContext.event), 0, FALSE); + + return STATUS_SUCCESS; +} // end WCacheSetMode__() + +/* + WCacheDecodeFlags() updates internal BOOLEANs according to Flags + Internal routine + */ +OSSTATUS +__fastcall +WCacheDecodeFlags( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN ULONG Flags // cache mode flags + ) +{ + //ULONG OldFlags; + if(Flags & ~WCACHE_VALID_FLAGS) { + KdPrint(("Invalid flags: %x\n", Flags & ~WCACHE_VALID_FLAGS)); + return STATUS_INVALID_PARAMETER; + } + Cache->CacheWholePacket = (Flags & WCACHE_CACHE_WHOLE_PACKET) ? TRUE : FALSE; + Cache->DoNotCompare = (Flags & WCACHE_DO_NOT_COMPARE) ? TRUE : FALSE; + Cache->Chained = (Flags & WCACHE_CHAINED_IO) ? TRUE : FALSE; + Cache->RememberBB = (Flags & WCACHE_MARK_BAD_BLOCKS) ? TRUE : FALSE; + if(Cache->RememberBB) { + Cache->NoWriteBB = (Flags & WCACHE_RO_BAD_BLOCKS) ? TRUE : FALSE; + } + Cache->NoWriteThrough = (Flags & WCACHE_NO_WRITE_THROUGH) ? TRUE : FALSE; + + Cache->Flags = Flags; + + return STATUS_SUCCESS; +} + +/* + WCacheChFlags__() changes cache flags. + Public routine + */ +ULONG +WCacheChFlags__( + IN PW_CACHE Cache, // pointer to the Cache Control structure + IN ULONG SetFlags, // cache mode/media type to be set + IN ULONG ClrFlags // cache mode/media type to be cleared + ) +{ + ULONG Flags; + + if(SetFlags || ClrFlags) { + Flags = (Cache->Flags & ~ClrFlags) | SetFlags; + + if(!OS_SUCCESS(WCacheDecodeFlags(Cache, Flags))) { + return -1; + } + } else { + return Cache->Flags; + } + return Flags; +} // end WCacheSetMode__() diff --git a/reactos/drivers/filesystems/udfs/Include/wcache_lib.h b/reactos/drivers/filesystems/udfs/Include/wcache_lib.h new file mode 100644 index 00000000000..c6d648630a8 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/wcache_lib.h @@ -0,0 +1,309 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __CDRW_WCACHE_LIB_H__ +#define __CDRW_WCACHE_LIB_H__ + +extern "C" { + +#include "platform.h" + +#ifdef _CONSOLE +#include "env_spec_w32.h" +#else +//#include "env_spec.h" +#endif + +#define WCACHE_BOUND_CHECKS + +typedef OSSTATUS (*PWRITE_BLOCK) (IN PVOID Context, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN lba_t Lba, + OUT PULONG WrittenBytes, + IN uint32 Flags); + +typedef OSSTATUS (*PREAD_BLOCK) (IN PVOID Context, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN lba_t Lba, + OUT PULONG ReadBytes, + IN uint32 Flags); + +typedef OSSTATUS (*PWRITE_BLOCK_ASYNC) (IN PVOID Context, + IN PVOID WContext, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN lba_t Lba, + OUT PULONG WrittenBytes, + IN BOOLEAN FreeBuffer); + +typedef OSSTATUS (*PREAD_BLOCK_ASYNC) (IN PVOID Context, + IN PVOID WContext, + IN PVOID Buffer, // Source buffer + IN ULONG Length, + IN lba_t Lba, + OUT PULONG ReadBytes); + +/*typedef BOOLEAN (*PCHECK_BLOCK) (IN PVOID Context, + IN lba_t Lba);*/ + +#define WCACHE_BLOCK_USED 0x01 +#define WCACHE_BLOCK_ZERO 0x02 +#define WCACHE_BLOCK_BAD 0x04 + +typedef ULONG (*PCHECK_BLOCK) (IN PVOID Context, + IN lba_t Lba); + +typedef OSSTATUS (*PUPDATE_RELOC) (IN PVOID Context, + IN lba_t Lba, + IN PULONG RelocTab, + IN ULONG BCount); + +#define WCACHE_ERROR_READ 0x0001 +#define WCACHE_ERROR_WRITE 0x0002 +#define WCACHE_ERROR_INTERNAL 0x0003 + +#define WCACHE_W_OP FALSE +#define WCACHE_R_OP TRUE + +typedef struct _WCACHE_ERROR_CONTEXT { + ULONG WCErrorCode; + OSSTATUS Status; + BOOLEAN Retry; + UCHAR Padding[3]; + union { + struct { + ULONG Lba; + ULONG BCount; + PVOID Buffer; + } ReadWrite; + struct { + ULONG p1; + ULONG p2; + ULONG p3; + ULONG p4; + } Internal; + }; +} WCACHE_ERROR_CONTEXT, *PWCACHE_ERROR_CONTEXT; + +typedef OSSTATUS (*PWC_ERROR_HANDLER) (IN PVOID Context, + IN PWCACHE_ERROR_CONTEXT ErrorInfo); +// array of pointers to cached data +// each entry corresponds to logical block on disk +typedef struct _W_CACHE_ENTRY { + union { + PCHAR Sector; + UCHAR Flags:3; + }; +} W_CACHE_ENTRY, *PW_CACHE_ENTRY; + +// array of pointers to cache frames +// each frame corresponds to extent of logical blocks +typedef struct _W_CACHE_FRAME { + PW_CACHE_ENTRY Frame; + ULONG BlockCount; + //ULONG WriteCount; // number of modified packets in cache frame, is always 0, shall be removed + ULONG UpdateCount; // number of updates in cache frame + ULONG AccessCount; // number of accesses to cache frame +} W_CACHE_FRAME, *PW_CACHE_FRAME; + +// memory type for cached blocks +#define CACHED_BLOCK_MEMORY_TYPE PagedPool +#define MAX_TRIES_FOR_NA 3 + +#define WCACHE_ADDR_MASK 0xfffffff8 +#define WCACHE_FLAG_MASK 0x00000007 +#define WCACHE_FLAG_MODIFIED 0x00000001 +#define WCACHE_FLAG_ZERO 0x00000002 +#define WCACHE_FLAG_BAD 0x00000004 + +#define WCACHE_MODE_ROM 0x00000000 // read only (CD-ROM) +#define WCACHE_MODE_RW 0x00000001 // rewritable (CD-RW) +#define WCACHE_MODE_R 0x00000002 // WORM (CD-R) +#define WCACHE_MODE_RAM 0x00000003 // random writable device (HDD) +#define WCACHE_MODE_EWR 0x00000004 // ERASE-cycle required (MO) +#define WCACHE_MODE_MAX WCACHE_MODE_RAM + +#define PH_TMP_BUFFER 1 + +struct _W_CACHE_ASYNC; + +typedef struct _W_CACHE { + // cache tables + ULONG Tag; + PW_CACHE_FRAME FrameList; // pointer to list of Frames + lba_t* CachedBlocksList; // sorted list of cached blocks + lba_t* CachedFramesList; // sorted list of cached frames + lba_t* CachedModifiedBlocksList; // sorted list of cached modified blocks + // settings & current state + ULONG BlocksPerFrame; + ULONG BlocksPerFrameSh; + ULONG BlockCount; + ULONG MaxBlocks; + ULONG MaxBytesToRead; + ULONG FrameCount; + ULONG MaxFrames; + ULONG PacketSize; // number of blocks in packet + ULONG PacketSizeSh; + ULONG BlockSize; + ULONG BlockSizeSh; + ULONG WriteCount; // number of modified packets in cache + lba_t FirstLba; + lba_t LastLba; + ULONG Mode; // RO/WOR/RW/EWR + + ULONG Flags; + BOOLEAN CacheWholePacket; + BOOLEAN DoNotCompare; + BOOLEAN Chained; + BOOLEAN RememberBB; + BOOLEAN NoWriteBB; + BOOLEAN NoWriteThrough; + UCHAR Padding[2]; + + ULONG RBalance; + ULONG WBalance; + ULONG FramesToKeepFree; + // callbacks + PWRITE_BLOCK WriteProc; + PREAD_BLOCK ReadProc; + PWRITE_BLOCK_ASYNC WriteProcAsync; + PREAD_BLOCK_ASYNC ReadProcAsync; + PCHECK_BLOCK CheckUsedProc; + PUPDATE_RELOC UpdateRelocProc; + PWC_ERROR_HANDLER ErrorHandlerProc; + // sync resource + ERESOURCE WCacheLock; +// BOOLEAN WCResInit; + // preallocated tmp buffers + PCHAR tmp_buff; + PCHAR tmp_buff_r; + PULONG reloc_tab; + +} W_CACHE, *PW_CACHE; + +#define WCACHE_INVALID_LBA ((lba_t)(-1)) + +#define WCACHE_CACHE_WHOLE_PACKET 0x01 +#define WCACHE_DO_NOT_COMPARE 0x02 +#define WCACHE_CHAINED_IO 0x04 +#define WCACHE_MARK_BAD_BLOCKS 0x08 +#define WCACHE_RO_BAD_BLOCKS 0x10 +#define WCACHE_NO_WRITE_THROUGH 0x20 + +#define WCACHE_VALID_FLAGS (WCACHE_CACHE_WHOLE_PACKET | \ + WCACHE_DO_NOT_COMPARE | \ + WCACHE_CHAINED_IO | \ + WCACHE_MARK_BAD_BLOCKS | \ + WCACHE_RO_BAD_BLOCKS | \ + WCACHE_NO_WRITE_THROUGH) + +#define WCACHE_INVALID_FLAGS (0xffffffff) + +// init cache +OSSTATUS WCacheInit__(IN PW_CACHE Cache, + IN ULONG MaxFrames, + IN ULONG MaxBlocks, + IN ULONG MaxBytesToRead, + IN ULONG PacketSizeSh, // number of blocks in packet (bit shift) + IN ULONG BlockSizeSh, // bit shift + IN ULONG BlocksPerFrameSh,// bit shift + IN lba_t FirstLba, + IN lba_t LastLba, + IN ULONG Mode, + IN ULONG Flags, + IN ULONG FramesToKeepFree, + IN PWRITE_BLOCK WriteProc, + IN PREAD_BLOCK ReadProc, + IN PWRITE_BLOCK_ASYNC WriteProcAsync, + IN PREAD_BLOCK_ASYNC ReadProcAsync, + IN PCHECK_BLOCK CheckUsedProc, + IN PUPDATE_RELOC UpdateRelocProc, + IN PWC_ERROR_HANDLER ErrorHandlerProc); +// write cached +OSSTATUS WCacheWriteBlocks__(IN PW_CACHE Cache, + IN PVOID Context, + IN PCHAR Buffer, + IN lba_t Lba, + IN ULONG BCount, + OUT PULONG WrittenBytes, + IN BOOLEAN CachedOnly); +// read cached +OSSTATUS WCacheReadBlocks__(IN PW_CACHE Cache, + IN PVOID Context, + IN PCHAR Buffer, + IN lba_t Lba, + IN ULONG BCount, + OUT PULONG ReadBytes, + IN BOOLEAN CachedOnly); +// flush blocks +OSSTATUS WCacheFlushBlocks__(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t Lba, + IN ULONG BCount); +// discard blocks +VOID WCacheDiscardBlocks__(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t Lba, + IN ULONG BCount); +// flush whole cache +VOID WCacheFlushAll__(IN PW_CACHE Cache, + IN PVOID Context); +// purge whole cache +VOID WCachePurgeAll__(IN PW_CACHE Cache, + IN PVOID Context); +// free structures +VOID WCacheRelease__(IN PW_CACHE Cache); + +// check if initialized +BOOLEAN WCacheIsInitialized__(IN PW_CACHE Cache); + +// direct access to cached data +OSSTATUS WCacheDirect__(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t Lba, + IN BOOLEAN Modified, + OUT PCHAR* CachedBlock, + IN BOOLEAN CachedOnly); +// release resources after direct access +OSSTATUS WCacheEODirect__(IN PW_CACHE Cache, + IN PVOID Context); +// release resources before direct access +OSSTATUS WCacheStartDirect__(IN PW_CACHE Cache, + IN PVOID Context, + IN BOOLEAN Exclusive); +// check if requested extent completly cached +BOOLEAN WCacheIsCached__(IN PW_CACHE Cache, + IN lba_t Lba, + IN ULONG BCount); + +// change cache media mode +OSSTATUS WCacheSetMode__(IN PW_CACHE Cache, + IN ULONG Mode); +// +ULONG WCacheGetMode__(IN PW_CACHE Cache); +// +ULONG WCacheGetWriteBlockCount__(IN PW_CACHE Cache); +// +VOID WCacheSyncReloc__(IN PW_CACHE Cache, + IN PVOID Context); + +VOID WCacheDiscardBlocks__(IN PW_CACHE Cache, + IN PVOID Context, + IN lba_t ReqLba, + IN ULONG BCount); + +ULONG WCacheChFlags__(IN PW_CACHE Cache, + IN ULONG SetFlags, + IN ULONG ClrFlags); + +}; + +// complete async request (callback) +OSSTATUS WCacheCompleteAsync__(IN PVOID WContext, + IN OSSTATUS Status); + +#endif // __CDRW_WCACHE_LIB_H__ diff --git a/reactos/drivers/filesystems/udfs/Include/zw_2_nt.h b/reactos/drivers/filesystems/udfs/Include/zw_2_nt.h new file mode 100644 index 00000000000..2d19c379337 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/Include/zw_2_nt.h @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __Zw_to_Nt__NameConvert__H__ +#define __Zw_to_Nt__NameConvert__H__ + +#ifdef NT_NATIVE_MODE + +#define ZwClose NtClose +#define ZwOpenKey NtOpenKey +#define ZwQueryValueKey NtQueryValueKey + +//#define ExAllocatePool(hernya,size) MyGlobalAlloc(size) +//#define ExFreePool(addr) MyGlobalFree((PVOID)(addr)) + +#endif //NT_NATIVE_MODE + +#endif //__Zw_to_Nt__NameConvert__H__ diff --git a/reactos/drivers/filesystems/udfs/cleanup.cpp b/reactos/drivers/filesystems/udfs/cleanup.cpp new file mode 100644 index 00000000000..3a3dae0c5a2 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/cleanup.cpp @@ -0,0 +1,784 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module name: Cleanup.cpp + + Abstract: + + Contains code to handle the "Cleanup" dispatch entry point. + + Environment: + + Kernel mode only +*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP + + +/************************************************************************* +* +* Function: UDFCleanup() +* +* Description: +* The I/O Manager will invoke this routine to handle a cleanup +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFCleanup( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFCleanup\n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // If we were called with our file system device object instead of a + // volume device object, just complete this request with STATUS_SUCCESS + if (UDFIsFSDevObj(DeviceObject)) { + // this is a cleanup of the FSD itself + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + + if(UDFGlobalData.AutoFormatCount == IoGetCurrentIrpStackLocation(Irp)->FileObject) { + KdPrint(("Deregister Autoformat\n")); + UDFGlobalData.AutoFormatCount = NULL; + } + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + FsRtlExitFileSystem(); + return(RC); + } + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonCleanup(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFCleanup() + +/************************************************************************* +* +* Function: UDFCommonCleanup() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS +UDFCommonCleanup( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp) +{ + IO_STATUS_BLOCK IoStatus; + NTSTATUS RC = STATUS_SUCCESS; + NTSTATUS RC2; + PIO_STACK_LOCATION IrpSp = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + ULONG lc = 0; + BOOLEAN AcquiredVcb = FALSE; + BOOLEAN AcquiredFCB = FALSE; + BOOLEAN AcquiredParentFCB = FALSE; + +// BOOLEAN CompleteIrp = TRUE; +// BOOLEAN PostRequest = FALSE; + BOOLEAN ChangeTime = FALSE; +#ifdef UDF_DBG + BOOLEAN CanWait = FALSE; +#endif // UDF_DBG + BOOLEAN ForcedCleanUp = FALSE; + + PUDF_FILE_INFO NextFileInfo = NULL; +#ifdef UDF_DBG + UNICODE_STRING CurName; + PDIR_INDEX_HDR DirNdx; +#endif // UDF_DBG +// PUDF_DATALOC_INFO Dloc; +#ifdef EVALUATION_TIME_LIMIT + ULONG t; +#endif //EVALUATION_TIME_LIMIT + + TmPrint(("UDFCommonCleanup\n")); + +// BrutePoint(); + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + if(!IrpSp) try_return(RC = STATUS_INVALID_PARAMETER); + + FileObject = IrpSp->FileObject; + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(Vcb); + ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); +// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; +#ifdef UDF_DBG + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + AdPrint((" %s\n", CanWait ? "Wt" : "nw")); + ASSERT(CanWait); +#endif // UDF_DBG + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + // Steps we shall take at this point are: + // (a) Acquire the file (FCB) exclusively + // (b) Flush file data to disk + // (c) Talk to the FSRTL package (if we use it) about pending oplocks. + // (d) Notify the FSRTL package for use with pending notification IRPs + // (e) Unlock byte-range locks (if any were acquired by process) + // (f) Update time stamp values (e.g. fast-IO had been performed) + // (g) Inform the Cache Manager to uninitialize Cache Maps ... + // and other similar stuff. + // BrutePoint(); + NtReqFcb = Fcb->NTRequiredFCB; + + if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + AdPrint(("Cleaning up Volume\n")); + AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); + + UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); + UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); + if(FileObject->Flags & FO_CACHE_SUPPORTED) { + // we've cached close + UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); + } + ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); + + // If this handle had write access, and actually wrote something, + // flush the device buffers, and then set the verify bit now + // just to be safe (in case there is no dismount). + if( FileObject->WriteAccess && + (FileObject->Flags & FO_FILE_MODIFIED)) { + + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + } + // User may decide to close locked volume without call to unlock proc + // So, handle this situation properly & unlock it now... + if (FileObject == Vcb->VolumeLockFileObject) { + Vcb->VolumeLockFileObject = NULL; + Vcb->VolumeLockPID = -1; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->Vpb->Flags &= ~VPB_LOCKED; + UDFNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); + } + + MmPrint((" CcUninitializeCacheMap()\n")); + CcUninitializeCacheMap(FileObject, NULL, NULL); + // reset device + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) { + // this call doesn't modify data buffer + // it just requires its presence + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); + } + // We must clean up the share access at this time, since we may not + // get a Close call for awhile if the file was mapped through this + // File Object. + IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); + + try_return(RC = STATUS_SUCCESS); + } +// BrutePoint(); +#ifdef UDF_DBG + DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo); + if(DirNdx) { + CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer; + if(CurName.Buffer) { + AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject)); + } else { + AdPrint(("Cleaning up file: ??? \n")); + } + } +#endif //UDF_DBG + AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); + // Acquire parent object + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource),TRUE); + } else { + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + } + AcquiredParentFCB = TRUE; + // Acquire current object + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); + AcquiredFCB = TRUE; + // dereference object + UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); + UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); + if(FileObject->Flags & FO_CACHE_SUPPORTED) { + // we've cached close + UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); + } + ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); + // check if Ccb being cleaned up has DeleteOnClose flag set +#ifndef UDF_READ_ONLY_BUILD + if(Ccb->CCBFlags & UDF_CCB_DELETE_ON_CLOSE) { + AdPrint((" DeleteOnClose\n")); + // Ok, now we'll become 'delete on close'... + ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; + FileObject->DeletePending = TRUE; + // Report this to the dir notify package for a directory. + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PVOID)Ccb, NULL, FALSE, FALSE, + 0, NULL, NULL, NULL ); + } + } +#endif //UDF_READ_ONLY_BUILD + + if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // Unlock all outstanding file locks. + FsRtlFastUnlockAll(&(NtReqFcb->FileLock), + FileObject, + IoGetRequestorProcess(Irp), + NULL); + } + // get Link count + lc = UDFGetFileLinkCount(Fcb->FileInfo); + +#ifndef UDF_READ_ONLY_BUILD + if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && + !(Fcb->OpenHandleCount)) { + // This can be useful for Streams, those were brutally deleted + // (together with parent object) + ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + FileObject->DeletePending = TRUE; + + // we should mark all streams of the file being deleted + // for deletion too, if there are no more Links to + // main data stream + if((lc <= 1) && + !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) { + RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete + } + // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE + // flag is already set & the file can't be opened + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource)); + } else { + UDFReleaseResource(&(Vcb->VCBResource)); + } + AcquiredParentFCB = FALSE; + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + + // Make system to issue last Close request + // for our Target ... + UDFRemoveFromSystemDelayedQueue(Fcb); + +#ifdef UDF_DELAYED_CLOSE + // remove file from our DelayedClose queue + UDFRemoveFromDelayedQueue(Fcb); + ASSERT(!Fcb->IrpContextLite); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); + } else { + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + } + AcquiredParentFCB = TRUE; + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); + AcquiredFCB = TRUE; + + // we should set file sizes to zero if there are no more + // links to this file + if(lc <= 1) { + // Synchronize here with paging IO + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource),TRUE); + // set file size to zero (for system cache manager) +// NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = + NtReqFcb->CommonFCBHeader.FileSize.QuadPart = + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0; + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); + + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + } + } +#endif //UDF_READ_ONLY_BUILD + +#ifdef UDF_DELAYED_CLOSE + if ((Fcb->ReferenceCount == 1) && + /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above + (!(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)) ) { + Fcb->FCBFlags |= UDF_FCB_DELAY_CLOSE; + } +#endif //UDF_DELAYED_CLOSE + + NextFileInfo = Fcb->FileInfo; + +#ifndef UDF_READ_ONLY_BUILD + // do we need to delete it now ? + if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && + !(Fcb->OpenHandleCount)) { + + // can we do it ? + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + if(!UDFIsDirEmpty__(NextFileInfo)) { + // forget about it + Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; + goto DiscardDelete; + } + } else + if (lc <= 1) { + // Synchronize here with paging IO + BOOLEAN AcquiredPagingIo; + AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource)); + // set file size to zero (for UdfInfo package) + // we should not do this for directories and linked files + UDFResizeFile__(Vcb, NextFileInfo, 0); + if(AcquiredPagingIo) { + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + } + } + // mark parent object for deletion if requested + if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) && + Fcb->ParentFcb) { + ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; + } + // flush file. It is required by UDFUnlinkFile__() + RC = UDFFlushFile__(Vcb, NextFileInfo); + if(!NT_SUCCESS(RC)) { + AdPrint(("Error flushing file !!!\n")); + } + // try to unlink + if((RC = UDFUnlinkFile__(Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) { + // If we can't delete file with Streams due to references, + // mark SDir & Streams + // for Deletion. We shall also set DELETE_PARENT flag to + // force Deletion of the current file later... when curently + // opened Streams would be cleaned up. + + // WARNING! We should keep SDir & Streams if there is a + // link to this file + if(NextFileInfo->Dloc && + NextFileInfo->Dloc->SDirInfo && + NextFileInfo->Dloc->SDirInfo->Fcb) { + + BrutePoint(); + if(!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) { +// RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete +//#ifdef UDF_ALLOW_PRETEND_DELETED + UDFPretendFileDeleted__(Vcb, Fcb->FileInfo); +//#endif //UDF_ALLOW_PRETEND_DELETED + } + goto NotifyDelete; + + } else { + // Getting here means that we can't delete file because of + // References/PemissionsDenied/Smth.Else, + // but not Linked+OpenedStream + BrutePoint(); +// RC = STATUS_SUCCESS; + goto DiscardDelete_1; + } + } else { +DiscardDelete_1: + // We have got an ugly ERROR, or + // file is deleted, so forget about it + ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + ForcedCleanUp = TRUE; + if(NT_SUCCESS(RC)) + Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; + Fcb->FCBFlags |= UDF_FCB_DELETED; + RC = STATUS_SUCCESS; + } +NotifyDelete: + // We should prevent SetEOF operations on completly + // deleted data streams + if(lc < 1) { + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; + } + // Report that we have removed an entry. + if(UDFIsAStream(NextFileInfo)) { + UDFNotifyFullReportChange( Vcb, NextFileInfo, + FILE_NOTIFY_CHANGE_STREAM_NAME, + FILE_ACTION_REMOVED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, NextFileInfo, + UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED); + } + } else + if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { +DiscardDelete: + UDFNotifyFullReportChange( Vcb, NextFileInfo, + ((Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) | + ((Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) | + 0, + UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED); + } +#endif //UDF_READ_ONLY_BUILD + + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + // Report to the dir notify package for a directory. + FsRtlNotifyCleanup( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb ); + } + + // we can't purge Cache when more than one link exists + if(lc > 1) { + ForcedCleanUp = FALSE; + } + + if ( (FileObject->Flags & FO_CACHE_SUPPORTED) && + (NtReqFcb->SectionObject.DataSectionObject) ) { + BOOLEAN LastNonCached = (!Fcb->CachedOpenHandleCount && + Fcb->OpenHandleCount); + // If this was the last cached open, and there are open + // non-cached handles, attempt a flush and purge operation + // to avoid cache coherency overhead from these non-cached + // handles later. We ignore any I/O errors from the flush. + // We shall not flush deleted files + RC = STATUS_SUCCESS; + if( LastNonCached + || + (!Fcb->OpenHandleCount && + !ForcedCleanUp) ) { + +#ifndef UDF_READ_ONLY_BUILD + LONGLONG OldFileSize, NewFileSize; + + if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) < + (NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) { +/* UDFZeroDataEx(NtReqFcb, + OldFileSize, + NewFileSize - OldFileSize, + TRUE, Vcb, FileObject);*/ + + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize; + } +#endif //UDF_READ_ONLY_BUILD + MmPrint((" CcFlushCache()\n")); + CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, &IoStatus ); + if(!NT_SUCCESS(IoStatus.Status)) { + MmPrint((" CcFlushCache() error: %x\n", IoStatus.Status)); + RC = IoStatus.Status; + } + } + // If file is deleted or it is last cached open, but there are + // some non-cached handles we should purge cache section + if(ForcedCleanUp || LastNonCached) { + if(NtReqFcb->SectionObject.DataSectionObject) { + MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); + } +/* MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/ + } + // we needn't Flush here. It will be done in UDFCloseFileInfoChain() + } + +#ifndef UDF_READ_ONLY_BUILD + // Update FileTimes & Attrs + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + !(Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETED /*| + UDF_FCB_DIRECTORY /*| + UDF_FCB_READ_ONLY*/)) && + !UDFIsAStreamDir(NextFileInfo)) { + LONGLONG NtTime; + LONGLONG ASize; + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); + // Check if we should set ARCHIVE bit & LastWriteTime + if(FileObject->Flags & FO_FILE_MODIFIED) { + ULONG Attr; + PDIR_INDEX_ITEM DirNdx; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index); + ASSERT(DirNdx); + // Archive bit + if(!(Ccb->CCBFlags & UDF_CCB_ATTRIBUTES_SET) && + (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) { + Attr = UDFAttributesToNT(DirNdx, NextFileInfo->Dloc->FileEntry); + if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) + UDFAttributesToUDF(DirNdx, NextFileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); + } + // WriteTime + if(!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) && + (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME)) { + UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, &NtTime); + NtReqFcb->LastWriteTime.QuadPart = + NtReqFcb->LastAccessTime.QuadPart = NtTime; + ChangeTime = TRUE; + } + } +#ifdef EVALUATION_TIME_LIMIT + KeQuerySystemTime(&UDFGlobalData.UDFCurrentTime); + t = (ULONG)(UDFGlobalData.UDFCurrentTime.QuadPart / (10*1000*1000)); + t /= (60*60*24); + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + if(t-TIME_JAN_1_2003 > UDF_MAX_DATE || + t-TIME_JAN_1_2003 < UDF_MIN_DATE) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } + } +#endif //EVALUATION_TIME_LIMIT + if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // Update sizes in DirIndex + if(!Fcb->OpenHandleCount) { + ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo); +// NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; + UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); + } else + if(FileObject->Flags & FO_FILE_SIZE_CHANGED) { + ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo); + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; + UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); + } + } + // AccessTime + if((FileObject->Flags & FO_FILE_FAST_IO_READ) && + !(Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) && + (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME)) { + UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, NULL); + NtReqFcb->LastAccessTime.QuadPart = NtTime; +// ChangeTime = TRUE; + } + // ChangeTime (AttrTime) + if(!(Ccb->CCBFlags & UDF_CCB_MODIFY_TIME_SET) && + (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) && + (ChangeTime || (Ccb->CCBFlags & (UDF_CCB_ATTRIBUTES_SET | + UDF_CCB_CREATE_TIME_SET | + UDF_CCB_ACCESS_TIME_SET | + UDF_CCB_WRITE_TIME_SET))) ) { + UDFSetFileXTime(NextFileInfo, NULL, NULL, &NtTime, NULL); + NtReqFcb->ChangeTime.QuadPart = NtTime; + } + } +#endif //UDF_READ_ONLY_BUILD + + if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) && + ForcedCleanUp) { + // flush system cache + MmPrint((" CcUninitializeCacheMap()\n")); + CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL); + } else { + MmPrint((" CcUninitializeCacheMap()\n")); + CcUninitializeCacheMap(FileObject, NULL, NULL); + } + + // release resources now. + // they'll be acquired in UDFCloseFileInfoChain() + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); + } else { + UDFReleaseResource(&(Vcb->VCBResource)); + } + AcquiredParentFCB = FALSE; + // close the chain + ASSERT(AcquiredVcb); + RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE); + if(NT_SUCCESS(RC)) + RC = RC2; + + Ccb->CCBFlags |= UDF_CCB_CLEANED; + + // We must clean up the share access at this time, since we may not + // get a Close call for awhile if the file was mapped through this + // File Object. + IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); + + NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); + + FileObject->Flags |= FO_CLEANUP_COMPLETE; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + } + + if(AcquiredParentFCB) { + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); + } else { + UDFReleaseResource(&(Vcb->VCBResource)); + } + } + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + + if (!_SEH2_AbnormalTermination()) { + // complete the IRP + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + } + + } _SEH2_END; // end of "__finally" processing + return(RC); +} // end UDFCommonCleanup() + +/* + This routine walks through the tree to RootDir & + calls UDFCloseFile__() for each file instance + imho, Useful feature + */ +NTSTATUS +UDFCloseFileInfoChain( + IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN ULONG TreeLength, + IN BOOLEAN VcbAcquired + ) +{ + PUDF_FILE_INFO ParentFI; + PtrUDFFCB Fcb; + PtrUDFFCB ParentFcb = NULL; + NTSTATUS RC = STATUS_SUCCESS; + NTSTATUS RC2; + + // we can't process Tree until we can acquire Vcb + if(!VcbAcquired) + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + + AdPrint(("UDFCloseFileInfoChain\n")); + for(; TreeLength && fi; TreeLength--) { + + // close parent chain (if any) + // if we started path parsing not from RootDir on Create, + // we would never get RootDir here + ValidateFileInfo(fi); + + // acquire parent + if(ParentFI = fi->ParentFile) { + ParentFcb = fi->Fcb->ParentFcb; + ASSERT(ParentFcb); + ASSERT(ParentFcb->NTRequiredFCB); + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE); + ASSERT(ParentFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); + ASSERT(ParentFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); + } else { + AdPrint(("Acquiring VCB...\n")); + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + AdPrint(("Done\n")); + } + // acquire current file/dir + // we must assure that no more threads try to reuse this object + if(Fcb = fi->Fcb) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(Fcb->NTRequiredFCB->MainResource),TRUE); + ASSERT_REF(Fcb->ReferenceCount >= fi->RefCount); + if(!(Fcb->FCBFlags & UDF_FCB_DELETED) && + (Fcb->FCBFlags & UDF_FCB_VALID)) + UDFWriteSecurity(Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc)); + RC2 = UDFCloseFile__(Vcb,fi); + if(!NT_SUCCESS(RC2)) + RC = RC2; + ASSERT_REF(Fcb->ReferenceCount > fi->RefCount); + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); + } else { + BrutePoint(); + RC2 = UDFCloseFile__(Vcb,fi); + if(!NT_SUCCESS(RC2)) + RC = RC2; + } + + if(ParentFI) { + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); + } else { + UDFReleaseResource(&(Vcb->VCBResource)); + } + fi = ParentFI; + } + + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + + return RC; + +} // end UDFCloseFileInfoChain() diff --git a/reactos/drivers/filesystems/udfs/close.cpp b/reactos/drivers/filesystems/udfs/close.cpp new file mode 100644 index 00000000000..1639d5e5406 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/close.cpp @@ -0,0 +1,1193 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Close.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Close" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_CLOSE + +typedef BOOLEAN (*PCHECK_TREE_ITEM) (IN PUDF_FILE_INFO FileInfo); +#define TREE_ITEM_LIST_GRAN 32 + +NTSTATUS +UDFBuildTreeItemsList( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN PCHECK_TREE_ITEM CheckItemProc, + IN PUDF_DATALOC_INFO** PassedList, + IN PULONG PassedListSize, + IN PUDF_DATALOC_INFO** FoundList, + IN PULONG FoundListSize); + +// callbacks, can't be __fastcall +BOOLEAN +UDFIsInDelayedCloseQueue( + PUDF_FILE_INFO FileInfo); + +BOOLEAN +UDFIsLastClose( + PUDF_FILE_INFO FileInfo); + +/************************************************************************* +* +* Function: UDFClose() +* +* Description: +* The I/O Manager will invoke this routine to handle a close +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFClose( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + AdPrint(("UDFClose: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // If we were called with our file system device object instead of a + // volume device object, just complete this request with STATUS_SUCCESS + if (UDFIsFSDevObj(DeviceObject)) { + // this is a close of the FSD itself + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + FsRtlExitFileSystem(); + return(RC); + } + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = UDFCommonClose(PtrIrpContext, Irp); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + + +/************************************************************************* +* +* Function: UDFCommonClose() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: must be STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS +UDFCommonClose( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; +// PERESOURCE PtrResourceAcquired = NULL; + BOOLEAN AcquiredVcb = FALSE; + BOOLEAN AcquiredGD = FALSE; + PUDF_FILE_INFO fi; + ULONG i = 0; + ULONG clean_stat = 0; + +// BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + +#ifdef UDF_DBG + UNICODE_STRING CurName; + PDIR_INDEX_HDR DirNdx; +#endif + + AdPrint(("UDFCommonClose: \n")); + + _SEH2_TRY { + if (Irp) { + + // If this is the first (IOManager) request + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + if(Ccb->CCBFlags & UDF_CCB_READ_ONLY) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_READ_ONLY; + } + Fcb = Ccb->Fcb; + } else { + // If this is a queued call (for our dispatch) + // Get saved Fcb address + Fcb = PtrIrpContext->Fcb; + i = PtrIrpContext->TreeLength; + } + + ASSERT(Fcb); + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(Vcb); + ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); +// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + // Steps we shall take at this point are: + // (a) Acquire the VCB shared + // (b) Acquire the FCB's CCB list exclusively + // (c) Delete the CCB structure (free memory) + // (d) If this is the last close, release the FCB structure + // (unless we keep these around for "delayed close" functionality. + // Note that it is often the case that the close dispatch entry point is invoked + // in the most inconvenient of situations (when it is not possible, for example, + // to safely acquire certain required resources without deadlocking or waiting). + // Therefore, be extremely careful in implementing this close dispatch entry point. + // Also note that we do not have the option of returning a failure code from the + // close dispatch entry point; the system expects that the close will always succeed. + + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + // Is this is the first (IOManager) request ? + if (Irp) { + PtrIrpContext->TreeLength = + i = Ccb->TreeLength; + // remember the number of incomplete Close requests + InterlockedIncrement((PLONG)&(Fcb->CcbCount)); + // we can release CCB in any case + UDFCleanUpCCB(Ccb); + FileObject->FsContext2 = NULL; +#ifdef DBG +/* } else { + ASSERT(Fcb->NTRequiredFCB); + if(Fcb->NTRequiredFCB) { + ASSERT(Fcb->NTRequiredFCB->FileObject); + if(Fcb->NTRequiredFCB->FileObject) { + ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2); + } + }*/ +#endif //DBG + } + +#ifdef UDF_DELAYED_CLOSE + // check if this is the last Close (no more Handles) + // and try to Delay it.... + if((Fcb->FCBFlags & UDF_FCB_DELAY_CLOSE) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) && + !(Fcb->OpenHandleCount)) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + if((RC = UDFQueueDelayedClose(PtrIrpContext,Fcb)) == STATUS_SUCCESS) + try_return(RC = STATUS_SUCCESS); + // do standard Close if we can't Delay this opeartion + AdPrint((" Cant queue Close Irp, status=%x\n", RC)); + } +#endif //UDF_DELAYED_CLOSE + + if(Irp) { + // We should post actual procesing if this is a recursive call + if((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) || + (Fcb->NTRequiredFCB->AcqFlushCount)) { + AdPrint((" post NOT_TOP_LEVEL Irp\n")); + PostRequest = TRUE; + try_return(RC = STATUS_SUCCESS); + } + } + + // Close request is near completion, Vcb is acquired. + // Now we can safely decrease CcbCount, because no Rename + // operation can run until Vcb release. + InterlockedDecrement((PLONG)&(Fcb->CcbCount)); + + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_READ_ONLY) + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCountRO)); + + if(!i || (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)) { + + AdPrint(("UDF: Closing volume\n")); + AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount)); + + if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE) { + ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); + UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + ASSERT(Fcb->NTRequiredFCB); + UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); + + try_return(RC = STATUS_SUCCESS); + } + + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } else { + BrutePoint(); + } + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + AcquiredGD = TRUE; +// // Acquire Vcb + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + + + ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); + UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + ASSERT(Fcb->NTRequiredFCB); + UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); + + //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n")); + //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE); + + AdPrint(("UDF: Closing volume, reset write status\n")); + RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS, Vcb->TargetDeviceObject, + NULL, 0, NULL, 0, TRUE, NULL); + + if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) || + ((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) { + // Try to KILL dismounted volume.... + // w2k requires this, NT4 - recomends + AcquiredVcb = UDFCheckForDismount(PtrIrpContext, Vcb, TRUE); + } + + try_return(RC = STATUS_SUCCESS); + } + + fi = Fcb->FileInfo; +#ifdef UDF_DBG + if(!fi) { + BrutePoint(); + } + + DirNdx = UDFGetDirIndexByFileInfo(fi); + if(DirNdx) { + CurName.Buffer = UDFDirIndex(DirNdx,fi->Index)->FName.Buffer; + if(CurName.Buffer) { + AdPrint(("Closing file: %ws %8.8x\n", CurName.Buffer, FileObject)); + } else { + AdPrint(("Closing file: ??? \n")); + } + } + AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount)); +#endif // UDF_DBG + // try to clean up as long chain as it is possible + clean_stat = UDFCleanUpFcbChain(Vcb, fi, i, TRUE); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + if(AcquiredGD) { + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + } + + // Post IRP if required + if (PostRequest) { + + // Perform the post operation & complete the IRP + // if this is first call of UDFCommonClose + // and will return STATUS_SUCCESS back to us + PtrIrpContext->Irp = NULL; + PtrIrpContext->Fcb = Fcb; + UDFPostRequest(PtrIrpContext, NULL); + } + + if (!_SEH2_AbnormalTermination()) { + // If this is not async close complete the IRP + if (Irp) { +/* if( FileObject ) { + if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) { +// ASSERT(!FileObject->FsContext2); + FileObject->FsContext = NULL; +#ifdef DBG + } else { + UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext)); + if(NtReqFcb->FileObject == FileObject) { + NtReqFcb->FileObject = NULL; + } +#endif //DBG + } + }*/ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + // Free up the Irp Context + if(!PostRequest) + UDFReleaseIrpContext(PtrIrpContext); + } + + } _SEH2_END; // end of "__finally" processing + + return STATUS_SUCCESS ; +} // end UDFCommonClose() + +/* + This routine walks through the tree to RootDir & kills all unreferenced + structures.... + imho, Useful feature + */ +ULONG +UDFCleanUpFcbChain( + IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN ULONG TreeLength, + IN BOOLEAN VcbAcquired + ) +{ + PtrUDFFCB Fcb = NULL; + PtrUDFFCB ParentFcb = NULL; + PUDF_FILE_INFO ParentFI; + UDFNTRequiredFCB* NtReqFcb; + ULONG CleanCode; + LONG RefCount, ComRefCount; + BOOLEAN Delete = FALSE; + ULONG ret_val = 0; + + ValidateFileInfo(fi); + AdPrint(("UDFCleanUpFcbChain\n")); + + ASSERT(TreeLength); + + // we can't process Tree until we can acquire Vcb + if(!VcbAcquired) + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + + // cleanup parent chain (if any & unused) + while(fi) { + + // acquire parent + if(ParentFI = fi->ParentFile) { + ASSERT(fi->Fcb); + ParentFcb = fi->Fcb->ParentFcb; + ASSERT(ParentFcb); + ASSERT(ParentFcb->NTRequiredFCB); + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE); + } else { + // we get to RootDir, it has no parent + if(!VcbAcquired) + UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); + } + Fcb = fi->Fcb; + ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); + + NtReqFcb = Fcb->NTRequiredFCB; + ASSERT(NtReqFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); + + // acquire current file/dir + // we must assure that no more threads try to re-use this object +#ifdef UDF_DBG + _SEH2_TRY { +#endif // UDF_DBG + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); +#ifdef UDF_DBG + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + if(ParentFI) { + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); + } else { + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + } + break; + } _SEH2_END; +#endif // UDF_DBG + ASSERT_REF((Fcb->ReferenceCount > fi->RefCount) || !TreeLength); + // If we haven't pass through all files opened + // in UDFCommonCreate before target file (TreeLength specfies + // the number of such files) dereference them. + // Otherwise we'll just check if the file has no references. +#ifdef UDF_DBG + if(Fcb) { + if(TreeLength) { + ASSERT(Fcb->ReferenceCount); + ASSERT(NtReqFcb->CommonRefCount); + RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); + } + } else { + BrutePoint(); + } + if(TreeLength) + TreeLength--; + ASSERT(Fcb->OpenHandleCount <= Fcb->ReferenceCount); +#else + if(TreeLength) { + RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); + TreeLength--; + } +#endif + +/* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) { + AdPrint((" %ws (%x)\n", + Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount)); + } else if (Fcb) { + AdPrint((" ??? (%x)\n",Fcb->ReferenceCount)); + } else { + AdPrint((" ??? (??)\n")); + }*/ + // ...and delete if it has gone + + if(!RefCount && !Fcb->OpenHandleCount) { + // no more references... current file/dir MUST DIE!!! + BOOLEAN AutoInherited = UDFIsAStreamDir(fi) || UDFIsAStream(fi); + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + // do nothing + } else +#ifndef UDF_READ_ONLY_BUILD + if(Delete) { +/* if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // set file size to zero (for UdfInfo package) + // we should not do this for directories + UDFResizeFile__(Vcb, fi, 0); + }*/ + UDFReferenceFile__(fi); + ASSERT(Fcb->ReferenceCount < fi->RefCount); + UDFFlushFile__(Vcb, fi); + UDFUnlinkFile__(Vcb, fi, TRUE); + UDFCloseFile__(Vcb, fi); + ASSERT(Fcb->ReferenceCount == fi->RefCount); + Fcb->FCBFlags |= UDF_FCB_DELETED; + Delete = FALSE; + } else +#endif //UDF_READ_ONLY_BUILD + if(!(Fcb->FCBFlags & UDF_FCB_DELETED)) { + UDFFlushFile__(Vcb, fi); + } else { +// BrutePoint(); + } +#ifndef UDF_READ_ONLY_BUILD + // check if we should try to delete Parent for the next time + if(Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) + Delete = TRUE; +#endif //UDF_READ_ONLY_BUILD + + // remove references to OS-specific structures + // to let UDF_INFO release FI & Co + fi->Fcb = NULL; + if(!ComRefCount) { + // CommonFcb is also completly dereferenced + // Kill it! + fi->Dloc->CommonFcb = NULL; + } + + if(CleanCode = UDFCleanUpFile__(Vcb, fi)) { + // Check, if we can uninitialize & deallocate CommonFcb part + // kill some cross links + Fcb->FileInfo = NULL; + // release allocated resources + if(CleanCode & UDF_FREE_DLOC) { + // Obviously, it is a good time & place to release + // CommonFcb structure + +// NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID; + // Unitialize byte-range locks support structure + FsRtlUninitializeFileLock(&(NtReqFcb->FileLock)); + // Remove resources + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + if(NtReqFcb->CommonFCBHeader.Resource) { + UDFDeleteResource(&(NtReqFcb->MainResource)); + UDFDeleteResource(&(NtReqFcb->PagingIoResource)); + } + NtReqFcb->CommonFCBHeader.Resource = + NtReqFcb->CommonFCBHeader.PagingIoResource = NULL; + UDFDeassignAcl(NtReqFcb, AutoInherited); + KdPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb)); +#ifdef DBG +// NtReqFcb->FileObject->FsContext2 = NULL; +// ASSERT(NtReqFcb->FileObject); +/* if(NtReqFcb->FileObject) { + ASSERT(!NtReqFcb->FileObject->FsContext2); + NtReqFcb->FileObject->FsContext = NULL; + NtReqFcb->FileObject->SectionObjectPointer = NULL; + }*/ +#endif //DBG + MyFreePool__(NtReqFcb); + ret_val |= UDF_CLOSE_NTREQFCB_DELETED; + } else { + // we usually get here when the file has some opened links + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + } + // remove some references & free Fcb structure + Fcb->NTRequiredFCB = NULL; + Fcb->ParentFcb = NULL; + UDFCleanUpFCB(Fcb); + MyFreePool__(fi); + ret_val |= UDF_CLOSE_FCB_DELETED; + // get pointer to parent FCB + fi = ParentFI; + // free old parent's resource... + if(fi) { + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); + } else { + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + } + } else { + // Stop cleaning up + + // Restore pointers + fi->Fcb = Fcb; + fi->Dloc->CommonFcb = NtReqFcb; + // free all acquired resources + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + fi = ParentFI; + if(fi) { + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); + } else { + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + } + // If we have dereferenced all parents 'associated' + // with input file & current file is still in use + // then it isn't worth walking down the tree + // 'cause in this case all the rest files are also used + if(!TreeLength) + break; +// AdPrint(("Stop on referenced File/Dir\n")); + } + } else { + // we get to referenced file/dir. Stop search & release resource + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + if(ParentFI) { + UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); + } else { + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + } + Delete = FALSE; + if(!TreeLength) + break; + fi = ParentFI; + } + } + if(fi) { + Fcb = fi->Fcb; + for(;TreeLength && fi;TreeLength--) { + if(Fcb) { + ParentFcb = Fcb->ParentFcb; + ASSERT(Fcb->ReferenceCount); + ASSERT(Fcb->NTRequiredFCB->CommonRefCount); + ASSERT_REF(Fcb->ReferenceCount > fi->RefCount); + UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); +#ifdef UDF_DBG + } else { + BrutePoint(); +#endif + } + Fcb = ParentFcb; + } + } + if(!VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + return ret_val; + +} // end UDFCleanUpFcbChain() + +VOID +UDFDoDelayedClose( + IN PtrUDFIrpContextLite NextIrpContextLite + ) +{ + PtrUDFIrpContext IrpContext; + + AdPrint((" UDFDoDelayedClose\n")); + UDFInitializeIrpContextFromLite(&IrpContext,NextIrpContextLite); + IrpContext->Fcb->IrpContextLite = NULL; + MyFreePool__(NextIrpContextLite); + IrpContext->Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; + UDFCommonClose(IrpContext,NULL); +} // end UDFDoDelayedClose() + +/* + This routine removes request from Delayed Close queue. + It operates until reach lower threshold + */ +VOID +UDFDelayedClose( + PVOID unused + ) +{ + PLIST_ENTRY Entry; + PtrUDFIrpContextLite NextIrpContextLite; + + AdPrint((" UDFDelayedClose\n")); + // Acquire DelayedCloseResource + UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); + + while (UDFGlobalData.ReduceDelayedClose && + (UDFGlobalData.DelayedCloseCount > UDFGlobalData.MinDelayedCloseCount)) { + + Entry = UDFGlobalData.DelayedCloseQueue.Flink; + + if (!IsListEmpty(Entry)) { + // Extract the IrpContext. + NextIrpContextLite = CONTAINING_RECORD( Entry, + UDFIrpContextLite, + DelayedCloseLinks ); + + RemoveEntryList( Entry ); + UDFGlobalData.DelayedCloseCount--; + UDFDoDelayedClose(NextIrpContextLite); + } else { + BrutePoint(); + } + } + + while (UDFGlobalData.ReduceDirDelayedClose && + (UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MinDirDelayedCloseCount)) { + + Entry = UDFGlobalData.DirDelayedCloseQueue.Flink; + + if (!IsListEmpty(Entry)) { + // Extract the IrpContext. + NextIrpContextLite = CONTAINING_RECORD( Entry, + UDFIrpContextLite, + DelayedCloseLinks ); + + RemoveEntryList( Entry ); + UDFGlobalData.DirDelayedCloseCount--; + UDFDoDelayedClose(NextIrpContextLite); + } else { + BrutePoint(); + } + } + + UDFGlobalData.FspCloseActive = FALSE; + UDFGlobalData.ReduceDelayedClose = FALSE; + UDFGlobalData.ReduceDirDelayedClose = FALSE; + + // Release DelayedCloseResource + UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); + + return; +} // end UDFDelayedClose() + +/* + This routine performs Close operation for all files from + Delayed Close queue. + */ +VOID +UDFCloseAllDelayed( + IN PVCB Vcb + ) +{ + PLIST_ENTRY Entry; + PtrUDFIrpContextLite NextIrpContextLite; + BOOLEAN GlobalDataAcquired = FALSE; + + AdPrint((" UDFCloseAllDelayed\n")); + // Acquire DelayedCloseResource + if (!ExIsResourceAcquiredExclusive(&UDFGlobalData.GlobalDataResource)) { + UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); + GlobalDataAcquired = TRUE; + } + + Entry = UDFGlobalData.DelayedCloseQueue.Flink; + + while (Entry != &UDFGlobalData.DelayedCloseQueue) { + // Extract the IrpContext. + NextIrpContextLite = CONTAINING_RECORD( Entry, + UDFIrpContextLite, + DelayedCloseLinks ); + Entry = Entry->Flink; + if (NextIrpContextLite->Fcb->Vcb == Vcb) { + RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); + UDFGlobalData.DelayedCloseCount--; + UDFDoDelayedClose(NextIrpContextLite); + } + } + + Entry = UDFGlobalData.DirDelayedCloseQueue.Flink; + + while (Entry != &UDFGlobalData.DirDelayedCloseQueue) { + // Extract the IrpContext. + NextIrpContextLite = CONTAINING_RECORD( Entry, + UDFIrpContextLite, + DelayedCloseLinks ); + Entry = Entry->Flink; + if (NextIrpContextLite->Fcb->Vcb == Vcb) { + RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); + UDFGlobalData.DirDelayedCloseCount--; + UDFDoDelayedClose(NextIrpContextLite); + } + } + + // Release DelayedCloseResource + if(GlobalDataAcquired) + UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); + +} // end UDFCloseAllDelayed() + +NTSTATUS +UDFBuildTreeItemsList( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN PCHECK_TREE_ITEM CheckItemProc, + IN PUDF_FILE_INFO** PassedList, + IN PULONG PassedListSize, + IN PUDF_FILE_INFO** FoundList, + IN PULONG FoundListSize + ) +{ + PDIR_INDEX_HDR hDirNdx; + PUDF_FILE_INFO SDirInfo; + ULONG i; + + KdPrint((" UDFBuildTreeItemsList():\n")); + if(!(*PassedList) || !(*FoundList)) { + + (*PassedList) = (PUDF_FILE_INFO*) + MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN); + if(!(*PassedList)) + return STATUS_INSUFFICIENT_RESOURCES; + (*PassedListSize) = 0; + + (*FoundList) = (PUDF_FILE_INFO*) + MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN); + if(!(*FoundList)) { + MyFreePool__(*PassedList); + *PassedList = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + (*FoundListSize) = 0; + } + + // check if already passed + for(i=0;i<(*PassedListSize);i++) { + if( ((*PassedList)[i]) == FileInfo ) + return STATUS_SUCCESS; + } + // remember passed object + // we should not proceed linked objects twice + (*PassedListSize)++; + if( !((*PassedListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) { + if(!MyReallocPool__((PCHAR)(*PassedList), (*PassedListSize)*sizeof(PUDF_FILE_INFO), + (PCHAR*)PassedList, ((*PassedListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_FILE_INFO))) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + (*PassedList)[(*PassedListSize)-1] = FileInfo; + + // check if this object matches our conditions + if(CheckItemProc(FileInfo)) { + // remember matched object + (*FoundListSize)++; + if( !((*FoundListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) { + if(!MyReallocPool__((PCHAR)(*FoundList), (*FoundListSize)*sizeof(PUDF_DATALOC_INFO), + (PCHAR*)FoundList, ((*FoundListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_DATALOC_INFO))) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + (*FoundList)[(*FoundListSize)-1] = FileInfo; + } + + // walk through SDir (if any) + if(SDirInfo = FileInfo->Dloc->SDirInfo) + UDFBuildTreeItemsList(Vcb, SDirInfo, CheckItemProc, + PassedList, PassedListSize, FoundList, FoundListSize); + + // walk through subsequent objects (if any) + if(hDirNdx = FileInfo->Dloc->DirIndex) { + + // scan DirIndex + UDF_DIR_SCAN_CONTEXT ScanContext; + PDIR_INDEX_ITEM DirNdx; + PUDF_FILE_INFO CurFileInfo; + + if(UDFDirIndexInitScan(FileInfo, &ScanContext, 2)) { + while(DirNdx = UDFDirIndexScan(&ScanContext, &CurFileInfo)) { + if(!CurFileInfo) + continue; + UDFBuildTreeItemsList(Vcb, CurFileInfo, CheckItemProc, + PassedList, PassedListSize, FoundList, FoundListSize); + } + } + + } + return STATUS_SUCCESS; +} // end UDFBuildTreeItemsList() + +BOOLEAN +UDFIsInDelayedCloseQueue( + PUDF_FILE_INFO FileInfo) +{ + ASSERT(FileInfo); + return (FileInfo->Fcb && FileInfo->Fcb->IrpContextLite); +} // end UDFIsInDelayedCloseQueue() + +BOOLEAN +UDFIsLastClose( + PUDF_FILE_INFO FileInfo) +{ + ASSERT(FileInfo); + PtrUDFFCB Fcb = FileInfo->Fcb; + if( Fcb && + !Fcb->OpenHandleCount && + Fcb->ReferenceCount && + Fcb->NTRequiredFCB->SectionObject.DataSectionObject) { + return TRUE; + } + return FALSE; +} // UDFIsLastClose() + +NTSTATUS +UDFCloseAllXXXDelayedInDir( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN System + ) +{ + PUDF_FILE_INFO* PassedList = NULL; + ULONG PassedListSize = 0; + PUDF_FILE_INFO* FoundList = NULL; + ULONG FoundListSize = 0; + NTSTATUS RC; + ULONG i; + BOOLEAN ResAcq = FALSE; + BOOLEAN AcquiredVcb = FALSE; + UDFNTRequiredFCB* NtReqFcb; + PUDF_FILE_INFO CurFileInfo; + PFE_LIST_ENTRY CurListPtr; + PFE_LIST_ENTRY* ListPtrArray = NULL; + + _SEH2_TRY { + + KdPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n")); + // Acquire DelayedCloseResource + UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); + ResAcq = TRUE; + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + RC = UDFBuildTreeItemsList(Vcb, FileInfo, + System ? UDFIsLastClose : UDFIsInDelayedCloseQueue, + &PassedList, &PassedListSize, &FoundList, &FoundListSize); + + if(!NT_SUCCESS(RC)) { + KdPrint((" UDFBuildTreeItemsList(): error %x\n", RC)); + try_return(RC); + } + + if(!FoundList || !FoundListSize) { + try_return(RC = STATUS_SUCCESS); + } + + // build array of referenced pointers + ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY))); + if(!ListPtrArray) { + KdPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize)); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + + for(i=0;iListPtr) { + CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY))); + if(!CurFileInfo->ListPtr) { + KdPrint((" Can't alloc ListPtrEntry for items %x\n", i)); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + CurFileInfo->ListPtr->FileInfo = CurFileInfo; + CurFileInfo->ListPtr->EntryRefCount = 0; + } + CurFileInfo->ListPtr->EntryRefCount++; + ListPtrArray[i] = CurFileInfo->ListPtr; + + } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + } + + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + + if(System) { + // Remove from system queue + PtrUDFFCB Fcb; + IO_STATUS_BLOCK IoStatus; + BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ? + TRUE : FALSE; + + Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; + for(i=FoundListSize;i>0;i--) { + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + _SEH2_TRY { + + CurListPtr = ListPtrArray[i-1]; + CurFileInfo = CurListPtr->FileInfo; + if(CurFileInfo && + (Fcb = CurFileInfo->Fcb)) { + NtReqFcb = Fcb->NTRequiredFCB; + ASSERT((ULONG)NtReqFcb > 0x1000); +// ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000); + if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) && + (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) { + MmPrint((" CcFlushCache()\n")); + CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus); + } + if(NtReqFcb->SectionObject.ImageSectionObject) { + MmPrint((" MmFlushImageSection()\n")); + MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite); + } + if(NtReqFcb->SectionObject.DataSectionObject) { + MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); + } + } else { + MmPrint((" Skip item: deleted\n")); + } + CurListPtr->EntryRefCount--; + if(!CurListPtr->EntryRefCount) { + if(CurListPtr->FileInfo) + CurListPtr->FileInfo->ListPtr = NULL; + MyFreePool__(CurListPtr); + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + if(!NoDelayed) + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE; + } else { + // Remove from internal queue + PtrUDFIrpContextLite NextIrpContextLite; + + for(i=FoundListSize;i>0;i--) { + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + CurListPtr = ListPtrArray[i-1]; + CurFileInfo = CurListPtr->FileInfo; + + if(CurFileInfo && + CurFileInfo->Fcb && + (NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) { + RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); + if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) { +// BrutePoint(); + UDFGlobalData.DirDelayedCloseCount--; + } else { + UDFGlobalData.DelayedCloseCount--; + } + UDFDoDelayedClose(NextIrpContextLite); + } + CurListPtr->EntryRefCount--; + if(!CurListPtr->EntryRefCount) { + if(CurListPtr->FileInfo) + CurListPtr->FileInfo->ListPtr = NULL; + MyFreePool__(CurListPtr); + } + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + } + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + // release Vcb + if(AcquiredVcb) + UDFReleaseResource(&(Vcb->VCBResource)); + // Release DelayedCloseResource + if(ResAcq) + UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); + + if(ListPtrArray) + MyFreePool__(ListPtrArray); + if(PassedList) + MyFreePool__(PassedList); + if(FoundList) + MyFreePool__(FoundList); + } _SEH2_END; + + return RC; +} // end UDFCloseAllXXXDelayedInDir( + + +/* + This routine adds request to Delayed Close queue. + If number of queued requests exceeds higher threshold it fires + UDFDelayedClose() + */ +NTSTATUS +UDFQueueDelayedClose( + PtrUDFIrpContext IrpContext, + PtrUDFFCB Fcb + ) +{ + PtrUDFIrpContextLite IrpContextLite; + BOOLEAN StartWorker = FALSE; + BOOLEAN AcquiredVcb = FALSE; + NTSTATUS RC; + + AdPrint((" UDFQueueDelayedClose\n")); + + _SEH2_TRY { + // Acquire DelayedCloseResource + UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); + + UDFAcquireResourceShared(&(Fcb->Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { + try_return(RC = STATUS_DELETE_PENDING); + } + + if(Fcb->IrpContextLite || + Fcb->FCBFlags & UDF_FCB_POSTED_RENAME) { +// BrutePoint(); + try_return(RC = STATUS_UNSUCCESSFUL); + } + + if(!NT_SUCCESS(RC = UDFInitializeIrpContextLite(&IrpContextLite,IrpContext,Fcb))) { + try_return(RC); + } + + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + InsertTailList( &UDFGlobalData.DirDelayedCloseQueue, + &IrpContextLite->DelayedCloseLinks ); + UDFGlobalData.DirDelayedCloseCount++; + } else { + InsertTailList( &UDFGlobalData.DelayedCloseQueue, + &IrpContextLite->DelayedCloseLinks ); + UDFGlobalData.DelayedCloseCount++; + } + Fcb->IrpContextLite = IrpContextLite; + + // If we are above our threshold then start the delayed + // close operation. + if(UDFGlobalData.DelayedCloseCount > UDFGlobalData.MaxDelayedCloseCount) { + + UDFGlobalData.ReduceDelayedClose = TRUE; + + if(!UDFGlobalData.FspCloseActive) { + + UDFGlobalData.FspCloseActive = TRUE; + StartWorker = TRUE; + } + } + // If we are above our threshold then start the delayed + // close operation. + if(UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MaxDirDelayedCloseCount) { + + UDFGlobalData.ReduceDirDelayedClose = TRUE; + + if(!UDFGlobalData.FspCloseActive) { + + UDFGlobalData.FspCloseActive = TRUE; + StartWorker = TRUE; + } + } + // Start the FspClose thread if we need to. + if(StartWorker) { + ExQueueWorkItem( &UDFGlobalData.CloseItem, CriticalWorkQueue ); + } + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(!NT_SUCCESS(RC)) { + Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; + } + if(AcquiredVcb) { + UDFReleaseResource(&(Fcb->Vcb->VCBResource)); + } + // Release DelayedCloseResource + UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); + } _SEH2_END; + return RC; +} // end UDFQueueDelayedClose() + diff --git a/reactos/drivers/filesystems/udfs/create.cpp b/reactos/drivers/filesystems/udfs/create.cpp new file mode 100644 index 00000000000..af7220e70e0 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/create.cpp @@ -0,0 +1,2569 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Create.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Create"/"Open" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +#define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess)) + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_CREATE + +#define MEM_USABS_TAG "US_Abs" +#define MEM_USLOC_TAG "US_Loc" +#define MEM_USOBJ_TAG "US_Obj" + +#define UDF_LOG_CREATE_DISPOSITION + +/************************************************************************* +* +* Function: UDFCreate() +* +* Description: +* The I/O Manager will invoke this routine to handle a create/open +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFCreate( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFCreate:\n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // sometimes, we may be called here with the device object representing + // the file system (instead of the device object created for a logical + // volume. In this case, there is not much we wish to do (this create + // typically will happen 'cause some process has to open the FSD device + // object so as to be able to send an IOCTL to the FSD) + + // All of the logical volume device objects we create have a device + // extension whereas the device object representing the FSD has no + // device extension. This seems like a good enough method to identify + // between the two device objects ... + if (UDFIsFSDevObj(DeviceObject)) { + // this is an open of the FSD itself + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = FILE_OPENED; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + FsRtlExitFileSystem(); + return(RC); + } + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonCreate(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + AdPrint(("UDFCreate: %x\n", RC)); + + FsRtlExitFileSystem(); + + return(RC); + +} // end UDFCreate() + +/* + */ +VOID +__fastcall +UDFReleaseResFromCreate( + IN PERESOURCE* PagingIoRes, + IN PERESOURCE* Res1, + IN PERESOURCE* Res2 + ) +{ + if(*PagingIoRes) { + UDFReleaseResource(*PagingIoRes); + (*PagingIoRes) = NULL; + } + if(*Res1) { + UDFReleaseResource(*Res1); + (*Res1) = NULL; + } + if(*Res2) { + UDFReleaseResource(*Res2); + (*Res2) = NULL; + } +} // end UDFReleaseResFromCreate() + +/* + */ +VOID +__fastcall +UDFAcquireParent( + IN PUDF_FILE_INFO RelatedFileInfo, + IN PERESOURCE* Res1, + IN PERESOURCE* Res2 + ) +{ + if(RelatedFileInfo->Fcb && + RelatedFileInfo->Fcb->ParentFcb) { + + UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB); + UDFAcquireResourceExclusive((*Res2) = &(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); + } + + UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive((*Res1) = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + + UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Fcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Dloc->CommonFcb->CommonRefCount)); + UDFReferenceFile__(RelatedFileInfo); + ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount); +} // end UDFAcquireParent() + +/************************************************************************* +* +* Function: UDFCommonCreate() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFCommonCreate( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; + PFILE_OBJECT PtrNewFileObject = NULL; + PFILE_OBJECT PtrRelatedFileObject = NULL; + LONGLONG AllocationSize; // if we create a new file + PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; + ULONG RequestedOptions; + ULONG RequestedDisposition; + USHORT FileAttributes; + USHORT TmpFileAttributes; + USHORT ShareAccess; + ULONG ExtAttrLength = 0; + ACCESS_MASK DesiredAccess; + PACCESS_STATE AccessState; + + PVCB Vcb = NULL; + BOOLEAN AcquiredVcb = FALSE; + BOOLEAN OpenExisting = FALSE; + PERESOURCE Res1 = NULL; + PERESOURCE Res2 = NULL; + PERESOURCE PagingIoRes = NULL; + +// BOOLEAN DirectoryOnlyRequested; +// BOOLEAN FileOnlyRequested; +// BOOLEAN NoBufferingSpecified; + BOOLEAN WriteThroughRequested; + BOOLEAN DeleteOnCloseSpecified; +// BOOLEAN NoExtAttrKnowledge; +// BOOLEAN CreateTreeConnection = FALSE; +// BOOLEAN OpenByFileId; + + // Are we dealing with a page file? + BOOLEAN PageFileManipulation; + // Is this open for a target directory (used in rename operations)? + BOOLEAN OpenTargetDirectory; + // Should we ignore case when attempting to locate the object? + BOOLEAN IgnoreCase; + + PtrUDFCCB PtrRelatedCCB = NULL, PtrNewCcb = NULL; + PtrUDFFCB PtrRelatedFCB = NULL, PtrNewFcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb; + + ULONG ReturnedInformation; + + UNICODE_STRING TargetObjectName; + UNICODE_STRING RelatedObjectName; + + UNICODE_STRING AbsolutePathName; // '\aaa\cdf\fff\rrrr.tre:s' + UNICODE_STRING LocalPath; // '\aaa\cdf' + UNICODE_STRING CurName; // 'cdf' + UNICODE_STRING TailName; // 'fff\rrrr.tre:s' + UNICODE_STRING LastGoodName; // it depends... + UNICODE_STRING LastGoodTail; // it depends... + UNICODE_STRING StreamName; // ':s' + + PUDF_FILE_INFO RelatedFileInfo; + PUDF_FILE_INFO OldRelatedFileInfo = NULL; + PUDF_FILE_INFO NewFileInfo = NULL; + PUDF_FILE_INFO LastGoodFileInfo = NULL; + PWCHAR TmpBuffer; + ULONG TreeLength = 0; +// ULONG i = 0; + + BOOLEAN StreamOpen = FALSE; + BOOLEAN StreamExists = FALSE; + BOOLEAN RestoreVCBOpenCounter = FALSE; + BOOLEAN RestoreShareAccess = FALSE; + PWCHAR TailNameBuffer = NULL; + ULONG SNameIndex = 0; + + TmPrint(("UDFCommonCreate:\n")); + + ASSERT(PtrIrpContext); + ASSERT(Irp); + + _SEH2_TRY { + + AbsolutePathName.Buffer = + LocalPath.Buffer = NULL; + // If we were called with our file system device object instead of a + // volume device object, just complete this request with STATUS_SUCCESS. + if (!(PtrIrpContext->TargetDeviceObject->DeviceExtension)) { + + ReturnedInformation = FILE_OPENED; + try_return(RC = STATUS_SUCCESS); + } + + AbsolutePathName.Length = AbsolutePathName.MaximumLength = + LocalPath.Length = LocalPath.MaximumLength = 0; + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + // If the caller cannot block, post the request to be handled + // asynchronously + if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK)) { + // We must defer processing of this request since we could + // block anytime while performing the create/open ... + ASSERT(FALSE); + RC = UDFPostRequest(PtrIrpContext, Irp); + try_return(RC); + } + + // Now, we can obtain the parameters specified by the user. + // Note that the file object is the new object created by the + // I/O Manager in anticipation that this create/open request + // will succeed. + PtrNewFileObject = IrpSp->FileObject; + TargetObjectName = PtrNewFileObject->FileName; + PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject; + + // If a related file object is present, get the pointers + // to the CCB and the FCB for the related file object + if (PtrRelatedFileObject) { + PtrRelatedCCB = (PtrUDFCCB)(PtrRelatedFileObject->FsContext2); + ASSERT(PtrRelatedCCB); + ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB); + // each CCB in turn points to a FCB + PtrRelatedFCB = PtrRelatedCCB->Fcb; + ASSERT(PtrRelatedFCB); + ASSERT((PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) + ||(PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)); + RelatedObjectName = PtrRelatedFileObject->FileName; + if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { + if(PtrRelatedFCB->FCBName) + RelatedObjectName = PtrRelatedFCB->FCBName->ObjectName; + } + } + + // Allocation size is only used if a new file is created + // or a file is superseded. + AllocationSize = Irp->Overlay.AllocationSize.QuadPart; + + // Get a ptr to the supplied security context + PtrSecurityContext = IrpSp->Parameters.Create.SecurityContext; + AccessState = PtrSecurityContext->AccessState; + + // The desired access can be obtained from the SecurityContext + DesiredAccess = PtrSecurityContext->DesiredAccess; + + // Two values are supplied in the Create.Options field: + // (a) the actual user supplied options + // (b) the create disposition + RequestedOptions = (IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS); + + // The file disposition is packed with the user options ... + // Disposition includes FILE_SUPERSEDE, FILE_OPEN_IF, etc. + RequestedDisposition = (IrpSp->Parameters.Create.Options >> 24);// & 0xFF; + +//#ifdef UDF_LOG_CREATE_DISPOSITION + switch(RequestedDisposition) { + case FILE_SUPERSEDE: + AdPrint((" Dispos: FILE_SUPERSEDE\n")); + break; + case FILE_OPEN: + AdPrint((" Dispos: FILE_OPEN\n")); + break; + case FILE_CREATE: + AdPrint((" Dispos: FILE_CREATE\n")); + break; + case FILE_OPEN_IF: + AdPrint((" Dispos: FILE_OPEN_IF\n")); + break; + case FILE_OVERWRITE: + AdPrint((" Dispos: FILE_OVERWRITE\n")); + break; + case FILE_OVERWRITE_IF: + AdPrint((" Dispos: FILE_OVERWRITE_IF\n")); + break; + default: + AdPrint((" Dispos: *** Unknown ***\n")); + break; + } +//#endif // UDF_LOG_CREATE_DISPOSITION + + FileAttributes = (USHORT)(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); + ShareAccess = IrpSp->Parameters.Create.ShareAccess; + + // If the FSD does not support EA manipulation, we might return + // invalid parameter if the following are supplied. + // EA arguments are only used if a new file is created or a file is + // superseded + + // But some applications _require_ EA support + // (Notepad... rather strange, isn't it ?) + + // So, for such stupid ones + // !!! We shall ignore these parameters !!! + +// PtrExtAttrBuffer = (struct _FILE_FULL_EA_INFORMATION *) Irp->AssociatedIrp.SystemBuffer; +// ExtAttrLength = IrpSp->Parameters.Create.EaLength; + + // Get the options supplied by the user + +#define OpenForBackup (RequestedOptions & FILE_OPEN_FOR_BACKUP_INTENT) + // User specifies that returned object MUST be a directory. + // Lack of presence of this flag does not mean it *cannot* be a + // directory *unless* FileOnlyRequested is set (see below) + + // Presence of the flag however, does require that the returned object be + // a directory (container) object. +#define DirectoryOnlyRequested (RequestedOptions & FILE_DIRECTORY_FILE) + + // User specifies that returned object MUST NOT be a directory. + // Lack of presence of this flag does not mean it *cannot* be a + // file *unless* DirectoryOnlyRequested is set (see above). + + // Presence of the flag however does require that the returned object be + // a simple file (non-container) object. +#define FileOnlyRequested (RequestedOptions & FILE_NON_DIRECTORY_FILE) + + // We cannot cache the file if the following flag is set. + // However, things do get a little bit interesting if caching + // has been already initiated due to a previous open ... + // (maintaining consistency then becomes a little bit more + // of a headache - see read/write file descriptions) +#define NoBufferingSpecified (RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) + + // Write-through simply means that the FSD must *not* return from + // a user write request until the data has been flushed to secondary + // storage (either to disks directly connected to the node or across + // the network in the case of a redirector) + WriteThroughRequested = (RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE; + +#define SequentialIoRequested (RequestedOptions & FILE_SEQUENTIAL_ONLY ? TRUE : FALSE) + + // Not all of the native file system implementations support + // the delete-on-close option. All this means is that after the + // last close on the FCB has been performed, the FSD should + // delete the file. It simply saves the caller from issuing a + // separate delete request. Also, some FSD implementations might choose + // to implement a Windows NT idiosyncratic behavior wherein we + // could create such "delete-on-close" marked files under directories + // marked for deletion. Ordinarily, a FSD will not allow us to create + // a new file under a directory that has been marked for deletion. + DeleteOnCloseSpecified = (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE; + + if(DeleteOnCloseSpecified) { + AdPrint((" DeleteOnClose\n")); + } + +#define NoExtAttrKnowledge /*(RequestedOptions & FILE_NO_EA_KNOWLEDGE) ?*/ TRUE /*: FALSE*/ + + // The following flag is only used by the LAN Manager redirector + // to initiate a "new mapping" to a remote share. Typically, + // a FSD will not see this flag (especially disk based FSD's) + // CreateTreeConnection = (RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE; + + // The NTFS file system for exmaple supports the OpenByFileId option. + // The FSD may also be able to associate a unique numerical ID with + // an on-disk object. The caller would get this ID in a "query file + // information" call. + + // Later, the caller might decide to reopen the object, this time + // though it may supply the FSD with the file identifier instead of + // a file/path name. +#define OpenByFileId (RequestedOptions & FILE_OPEN_BY_FILE_ID) + + // Are we dealing with a page file? + PageFileManipulation = (IrpSp->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; + + // The open target directory flag is used as part of the sequence of + // operations performed by the I/O Manager is response to a file/dir + // rename operation. See the explanation in the book for details. + OpenTargetDirectory = (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE; + + // If the FSD supports case-sensitive file name checks, we may + // choose to honor the following flag ... + IgnoreCase = (IrpSp->Flags & SL_CASE_SENSITIVE) ? FALSE : TRUE; + + // Ensure that the operation has been directed to a valid VCB ... + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(Vcb); + ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); +// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + WriteThroughRequested = WriteThroughRequested || + (Vcb->CompatFlags & UDF_VCB_IC_FORCE_WRITE_THROUGH); + + // Do some preliminary checks to make sure the operation is supported. + // We fail in the following cases immediately. + // - Open a paging file. + // - Open a file with Eas. + if(PageFileManipulation) { + ReturnedInformation = 0; + AdPrint(("Can't create a page file\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + if(ExtAttrLength) { + ReturnedInformation = 0; + AdPrint(("Can't create file with EAs\n")); + try_return(RC = STATUS_EAS_NOT_SUPPORTED); + } + + UDFFlushTryBreak(Vcb); + + if (Vcb->SoftEjectReq) { + AdPrint((" Eject requested\n")); + try_return(RC = STATUS_FILE_INVALID); + } + + // If the volume has been locked, fail the request + if ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) && + (Vcb->VolumeLockPID != GetCurrentPID())) { + AdPrint((" Volume is locked\n")); + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + // We need EXCLUSIVE access to Vcb to avoid parallel calls to UDFVerifyVcb() + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + // Disk based file systems might decide to verify the logical volume + // (if required and only if removable media are supported) at this time + RC = UDFVerifyVcb(PtrIrpContext,Vcb); + if(!NT_SUCCESS(RC)) + try_return(RC); + + UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); + + ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED); + + // We fail in the following cases for Read-Only volumes + // - Open a target directory. + // - Create a file. + if( + ( + ((Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) && + (Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) +#ifndef UDF_READ_ONLY_BUILD + || (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) +#endif //UDF_READ_ONLY_BUILD + ) && + (DeleteOnCloseSpecified || + OpenTargetDirectory || + (RequestedDisposition == FILE_CREATE) || + (RequestedDisposition == FILE_OVERWRITE) || + (RequestedDisposition == FILE_OVERWRITE_IF) || + (RequestedDisposition == FILE_SUPERSEDE) || + AllocationSize) ) { + ReturnedInformation = 0; + AdPrint((" Write protected or dirty\n")); + try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); + } + +/* if(DesiredAccess & (FILE_READ_EA | FILE_WRITE_EA)) { + ReturnedInformation = 0; + AdPrint((" EAs not supported\n")); + try_return(RC = STATUS_ACCESS_DENIED); + }*/ + + // **************** + // If a Volume open is requested, satisfy it now + // **************** + if (!(PtrNewFileObject->FileName.Length) && (!PtrRelatedFileObject || + (PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB))) { + + BOOLEAN UndoLock = FALSE; + + AdPrint((" Opening Volume\n")); + // If the supplied file name is NULL *and* either there exists + // no related file object *or* if a related file object was supplied + // but it too refers to a previously opened instance of a logical + // volume, this open must be for a logical volume. + + // Note: the FSD might decide to do "special" things (whatever they + // might be) in response to an open request for the logical volume. + + // Logical volume open requests are done primarily to get/set volume + // information, lock the volume, dismount the volume (using the IOCTL + // FSCTL_DISMOUNT_VOLUME) etc. + + // If a volume open is requested, perform checks to ensure that + // invalid options have not also been specified ... + if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) { + try_return(RC = STATUS_INVALID_PARAMETER); + } + + if (DirectoryOnlyRequested) { + // a volume is not a directory + try_return(RC = STATUS_NOT_A_DIRECTORY); + } + +#ifndef UDF_READ_ONLY_BUILD + if (DeleteOnCloseSpecified) { + // delete volume.... hmm + try_return(RC = STATUS_CANNOT_DELETE); + } + + if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) { + // cannot create a new volume, I'm afraid ... + try_return(RC = STATUS_ACCESS_DENIED); + } +#endif //UDF_READ_ONLY_BUILD + + KdPrint((" ShareAccess %x, DesiredAccess %x\n", ShareAccess, DesiredAccess)); +/* + if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && + !(DesiredAccess & (FILE_GENERIC_WRITE & ~SYNCHRONIZE)) && + (ShareAccess & FILE_SHARE_READ) ) { +*/ + if(!(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && + (ShareAccess & FILE_SHARE_READ) ) { + KdPrint((" R/O volume open\n")); + } else { + + KdPrint((" R/W volume open\n")); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { + KdPrint((" media-ro\n")); + try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); + } + } + + if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && + !(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && + (ShareAccess & FILE_SHARE_READ) ) { + // do nothing + } else { + + if(!(ShareAccess & FILE_SHARE_READ) || + (DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) ) { + // As soon as OpenVolume flushes the volume + // we should complete all pending requests (Close) + + KdPrint((" set UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH2_REQUIRED; + +/* + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + } +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); +*/ + } + } + + // If the user does not want to share write or delete then we will try + // and take out a lock on the volume. + if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE))) { + // Do a quick check here for handles on exclusive open. + if ((Vcb->VCBHandleCount) && + !(ShareAccess & FILE_SHARE_READ)) { + // Sharing violation + KdPrint((" !FILE_SHARE_READ + open handles (%d)\n", Vcb->VCBHandleCount)); + try_return(RC = STATUS_SHARING_VIOLATION); + } + if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { + + KdPrint((" perform flush\n")); + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED; + + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + } +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + + UDFFlushLogicalVolume(NULL, NULL, Vcb); + + if((ShareAccess & FILE_SHARE_READ) && + ((Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE) != (Vcb->VCBOpenCountRO))) { + KdPrint((" FILE_SHARE_READ + R/W handles: %d(%d) -> STATUS_SHARING_VIOLATION ?\n", + Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE, + Vcb->VCBOpenCountRO)); + /* we shall not check it here, let System do it in IoCheckShareAccess() */ + //try_return(RC = STATUS_SHARING_VIOLATION); + } + } + // Lock the volume + if(!(ShareAccess & FILE_SHARE_READ)) { + KdPrint((" set Lock\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = PtrNewFileObject; + UndoLock = TRUE; + } else + if(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) { + KdPrint((" set UDF_IRP_CONTEXT_FLUSH_REQUIRED\n")); + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH_REQUIRED; + } + } + + PtrNewFcb = (PtrUDFFCB)Vcb; + ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)); + + RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); + if (!NT_SUCCESS(RC)) + goto op_vol_accs_dnd; + + PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); + if(PtrNewCcb) PtrNewCcb->CCBFlags |= UDF_CCB_VOLUME_OPEN; + // Check _Security_ + RC = UDFCheckAccessRights(NULL, AccessState, Vcb->RootDirFCB, PtrNewCcb, DesiredAccess, ShareAccess); + if (!NT_SUCCESS(RC)) { + AdPrint((" Access violation (Volume)\n")); + goto op_vol_accs_dnd; + } + // Check _ShareAccess_ + RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if(!NT_SUCCESS(RC)) { + AdPrint((" Sharing violation (Volume)\n")); +op_vol_accs_dnd: + if(UndoLock) { + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = NULL; + } + try_return(RC); + } + +// NoBufferingSpecified = TRUE; See #define above + RequestedOptions |= FILE_NO_INTERMEDIATE_BUFFERING; + + ReturnedInformation = FILE_OPENED; + UDFNotifyVolumeEvent(PtrNewFileObject, FSRTL_VOLUME_LOCK); + try_return(RC); + } + + if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + (!(Vcb->CompatFlags & UDF_VCB_IC_SHOW_BLANK_CD) || UDFGlobalData.AutoFormatCount)) { + ReturnedInformation = 0; + AdPrint((" Can't open anything on blank volume ;)\n")); + try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); + } + + if(UdfIllegalFcbAccess(Vcb,DesiredAccess)) { + ReturnedInformation = 0; + AdPrint((" Illegal share access\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + // we could mount blank R/RW media in order to allow + // user-mode applications to get access with Write privileges + ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED); + + // we should check appropriate privilege if OpenForBackup requested + if(OpenForBackup) { + RC = SeSinglePrivilegeCheck(SeExports->SeBackupPrivilege, UserMode); + if(!NT_SUCCESS(RC)) + try_return(RC); + } + + // The FSD might wish to implement the open-by-id option. The "id" + // is some unique numerical representation of the on-disk object. + // The caller then therefore give us this file id and the FSD + // should be completely capable of "opening" the object (it must + // exist since the caller received an id for the object from the + // FSD in a "query file" call ... + + // If the file has been deleted in the meantime, we'll return + // "not found" + + // **************** + // Open by FileID + // **************** + if (OpenByFileId) { + // perform the open ... + PUNICODE_STRING TmpPath; + LONGLONG Id; + + KdPrint((" open by File ID\n")); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + ReturnedInformation = 0; + AdPrint((" Can't open by FileID on blank volume ;)\n")); + try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); + } + + if (TargetObjectName.Length != sizeof(FILE_ID)) { + AdPrint((" Invalid file ID\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + Id = *((FILE_ID*)(TargetObjectName.Buffer)); + AdPrint((" Opening by ID %8.8x%8.8x\n", (ULONG)(Id>>32), (ULONG)Id)); + if ((RequestedDisposition != FILE_OPEN) && + (RequestedDisposition != FILE_OPEN_IF)) { + AdPrint((" Illegal disposition for ID open\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + + RC = UDFGetOpenParamsByFileId(Vcb, Id, &TmpPath, &IgnoreCase); + if(!NT_SUCCESS(RC)) { + AdPrint((" ID open failed\n")); + try_return(RC); + } + // simulate absolute path open +/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&TargetObjectName, L"")) || + !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&TargetObjectName, TmpPath, MEM_USABS_TAG))) {*/ + if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TargetObjectName, TmpPath))) { + AdPrint((" Init String failed\n")); + try_return(RC); + } + //ASSERT(TargetObjectName.Buffer); + AbsolutePathName = TargetObjectName; + PtrRelatedFileObject = NULL; + } else + // **************** + // Relative open + // **************** + // Now determine the starting point from which to begin the parsing + if (PtrRelatedFileObject) { + // We have a user supplied related file object. + // This implies a "relative" open i.e. relative to the directory + // represented by the related file object ... + + KdPrint((" PtrRelatedFileObject %x, FCB %x\n", PtrRelatedFileObject, PtrRelatedFCB)); + // Note: The only purpose FSD implementations ever have for + // the related file object is to determine whether this + // is a relative open or not. At all other times (including + // during I/O operations), this field is meaningless from + // the FSD's perspective. + if (!(PtrRelatedFCB->FCBFlags & UDF_FCB_DIRECTORY)) { + // we must have a directory as the "related" object + RC = STATUS_INVALID_PARAMETER; + AdPrint((" Related object must be a directory\n")); + AdPrint((" Flags %x\n", PtrRelatedFCB->FCBFlags)); + _SEH2_TRY { + AdPrint((" ObjName %x, ", PtrRelatedFCB->FCBName->ObjectName)); + AdPrint((" Name %S\n", PtrRelatedFCB->FCBName->ObjectName.Buffer)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + AdPrint((" exception when printing name\n")); + } _SEH2_END; + try_return(RC); + } + + // So we have a directory, ensure that the name begins with + // a "\" i.e. begins at the root and does *not* begin with a "\\" + // NOTE: This is just an example of the kind of path-name string + // validation that a FSD must do. Although the remainder of + // the code may not include such checks, any commercial + // FSD *must* include such checking (no one else, including + // the I/O Manager will perform checks on the FSD's behalf) + if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { + AdPrint((" Wrong pathname (1)\n")); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + // similarly, if the target file name starts with a "\", it + // is wrong since the target file name can no longer be absolute + ASSERT(TargetObjectName.Buffer || !TargetObjectName.Length); + if (TargetObjectName.Length && (TargetObjectName.Buffer[0] == L'\\')) { + AdPrint((" Wrong pathname (2)\n")); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + // Create an absolute path-name. We could potentially use + // the absolute path-name if we cache previously opened + // file/directory object names. +/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || + !NT_SUCCESS(RC MyAppendUnicodeStringToStringTag(&AbsolutePathName, &RelatedObjectName, MEM_USABS_TAG)))*/ + if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &RelatedObjectName))) + try_return(RC); + if(RelatedObjectName.Length && + (RelatedObjectName.Buffer[ (RelatedObjectName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { + RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); + if(!NT_SUCCESS(RC)) try_return(RC); + } + if(!AbsolutePathName.Length || + (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { + ASSERT(TargetObjectName.Buffer); + if(TargetObjectName.Length && TargetObjectName.Buffer[0] != L'\\') { + RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); + if(!NT_SUCCESS(RC)) try_return(RC); + } + } + //ASSERT(TargetObjectName.Buffer); + RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG); + if(!NT_SUCCESS(RC)) + try_return(RC); + + } else { + // **************** + // Absolute open + // **************** + // The suplied path-name must be an absolute path-name i.e. + // starting at the root of the file system tree + KdPrint((" Absolute open\n")); + ASSERT(TargetObjectName.Buffer); + if (!TargetObjectName.Length || TargetObjectName.Buffer[0] != L'\\') { + AdPrint((" Wrong target name (1)\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } +/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || + !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG)))*/ + ASSERT(TargetObjectName.Buffer); + if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &TargetObjectName))) + try_return(RC); + } + // Win 32 protection :) + if ((AbsolutePathName.Length >= sizeof(WCHAR)*2) && + (AbsolutePathName.Buffer[1] == L'\\') && + (AbsolutePathName.Buffer[0] == L'\\')) { + + // If there are still two beginning backslashes, the name is bogus. + if ((AbsolutePathName.Length > 2*sizeof(WCHAR)) && + (AbsolutePathName.Buffer[2] == L'\\')) { + AdPrint((" Wrong target name (2)\n")); + try_return (RC = STATUS_OBJECT_NAME_INVALID); + } + // Slide the name down in the buffer. + RtlMoveMemory( AbsolutePathName.Buffer, + AbsolutePathName.Buffer + 1, + AbsolutePathName.Length ); // .Length includes + // NULL-terminator + AbsolutePathName.Length -= sizeof(WCHAR); + } + if ( (AbsolutePathName.Length > sizeof(WCHAR) ) && + (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] == L'\\') ) { + + AbsolutePathName.Length -= sizeof(WCHAR); + } + // TERMINATOR (2) ;) + AbsolutePathName.Buffer[AbsolutePathName.Length/sizeof(WCHAR)] = 0; + + // Sometimes W2000 decides to duplicate handle of + // already opened File/Dir. In this case it sends us + // RelatedFileObject & specifies zero-filled RelativePath + if(!TargetObjectName.Length) { + TargetObjectName = AbsolutePathName; + OpenExisting = TRUE; + } + //ASSERT(TargetObjectName.Buffer); + + // **************** + // First, check if the caller simply wishes to open the Root + // of the file system tree. + // **************** + if (AbsolutePathName.Length == sizeof(WCHAR)) { + AdPrint((" Opening RootDir\n")); + // this is an open of the root directory, ensure that the caller + // has not requested a file only + if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || + (RequestedDisposition == FILE_OVERWRITE) || + (RequestedDisposition == FILE_OVERWRITE_IF)) { + AdPrint((" Can't overwrite RootDir\n")); + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + +#if 0 + CollectStatistics(Vcb, MetaDataReads); +#endif + + if (DeleteOnCloseSpecified) { + // delete RootDir.... rather strange idea... I dislike it + AdPrint((" Can't delete RootDir\n")); + try_return(RC = STATUS_CANNOT_DELETE); + } + + PtrNewFcb = Vcb->RootDirFCB; + RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); + if(!NT_SUCCESS(RC)) try_return(RC); +// DbgPrint("UDF: Open/Create RootDir : ReferenceCount %x\n",PtrNewFcb->ReferenceCount); + UDFReferenceFile__(PtrNewFcb->FileInfo); + PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); + TreeLength = 1; + + RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if(!NT_SUCCESS(RC)) { + AdPrint((" Access/Sharing violation (RootDir)\n")); + try_return(RC); + } + + ReturnedInformation = FILE_OPENED; + + try_return(RC); + } // end of OpenRootDir + + _SEH2_TRY { + AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + AdPrint((" Exception when printing FN\n")); + } _SEH2_END; + // **************** + // Check if we have DuplicateHandle (or Reopen) request + // **************** + if(OpenExisting) { + +// BrutePoint(); + // We don't handle OpenTargetDirectory in this case + if(OpenTargetDirectory) + try_return(RC = STATUS_INVALID_PARAMETER); + + // Init environment to simulate normal open procedure behavior +/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&LocalPath, L"")) || + !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&LocalPath, &TargetObjectName, MEM_USLOC_TAG)))*/ + ASSERT(TargetObjectName.Buffer); + if(!NT_SUCCESS(RC = MyCloneUnicodeString(&LocalPath, &TargetObjectName))) + try_return(RC); + + ASSERT(PtrRelatedFCB); + RelatedFileInfo = PtrRelatedFCB->FileInfo; + + RC = STATUS_SUCCESS; + NewFileInfo = + LastGoodFileInfo = RelatedFileInfo; + + RelatedFileInfo = + OldRelatedFileInfo = RelatedFileInfo->ParentFile; + PtrRelatedFCB = PtrRelatedFCB->ParentFcb; + // prevent releasing parent structures + UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); + TreeLength++; + + if(Res1) UDFReleaseResource(Res1); + if(Res2) UDFReleaseResource(Res2); + + UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res2 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + PtrNewFcb = NewFileInfo->Fcb; + + UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res1 = &(PtrNewFcb->NTRequiredFCB->MainResource),TRUE); + UDFReferenceFile__(NewFileInfo); + TreeLength++; + + goto AlreadyOpened; + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + ReturnedInformation = 0; + AdPrint((" Can't open File on blank volume ;)\n")); + try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); + } + + //AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); + + if(AbsolutePathName.Length > UDF_X_PATH_LEN*sizeof(WCHAR)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + + // validate path specified + // (sometimes we can see here very strange characters ;) + if(!UDFIsNameValid(&AbsolutePathName, &StreamOpen, &SNameIndex)) { + AdPrint((" Absolute path is not valid\n")); + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + if(StreamOpen && !UDFStreamsSupported(Vcb)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + + RC = MyInitUnicodeString(&LocalPath, L""); + if(!NT_SUCCESS(RC)) + try_return(RC); + if (PtrRelatedFileObject) { + // Our "start directory" is the one identified + // by the related file object + RelatedFileInfo = PtrRelatedFCB->FileInfo; + if(RelatedFileInfo != Vcb->RootDirFCB->FileInfo) { + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(PtrRelatedFCB->FCBName->ObjectName), MEM_USLOC_TAG); + if(!NT_SUCCESS(RC)) + try_return(RC); + } + if(TargetObjectName.Buffer != AbsolutePathName.Buffer) { + ASSERT(TargetObjectName.Buffer); + if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TailName, &TargetObjectName))) { + AdPrint((" Init String 'TargetObjectName' failed\n")); + try_return(RC); + } + TailNameBuffer = TailName.Buffer; + } else { + TailName = AbsolutePathName; + } + } else { + // Start at the root of the file system + RelatedFileInfo = Vcb->RootDirFCB->FileInfo; + TailName = AbsolutePathName; + } + + if(StreamOpen) { + StreamName = AbsolutePathName; + StreamName.Buffer += SNameIndex; + StreamName.Length -= (USHORT)SNameIndex*sizeof(WCHAR); + // if StreamOpen specified & stream name starts with NULL character + // we should create Stream Dir at first + TailName.Length -= (AbsolutePathName.Length - (USHORT)SNameIndex*sizeof(WCHAR)); + AbsolutePathName.Length = (USHORT)SNameIndex*sizeof(WCHAR); + } + CurName.MaximumLength = TailName.MaximumLength; + + RC = STATUS_SUCCESS; + LastGoodName.Length = 0; + LastGoodFileInfo = RelatedFileInfo; + // reference RelatedObject to prevent releasing parent structures + UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); + TreeLength++; + + // go into a loop parsing the supplied name + + // Note that we may have to "open" intermediate directory objects + // while traversing the path. We should __try to reuse existing code + // whenever possible therefore we should consider using a common + // open routine regardless of whether the open is on behalf of the + // caller or an intermediate (internal) open performed by the driver. + + // **************** + // now we'll parse path to desired file + // **************** + + while (TRUE) { + + // remember last 'good' ('good' means NO ERRORS before) path tail + if(NT_SUCCESS(RC)) { + LastGoodTail = TailName; + while(LastGoodTail.Buffer[0] == L'\\') { + LastGoodTail.Buffer++; + LastGoodTail.Length -= sizeof(WCHAR); + } + } + // get next path part... + TmpBuffer = TailName.Buffer; + TailName.Buffer = UDFDissectName(TailName.Buffer,&(CurName.Length) ); + TailName.Length -= (USHORT)((ULONG)(TailName.Buffer) - (ULONG)TmpBuffer); + CurName.Buffer = TailName.Buffer - CurName.Length; + CurName.Length *= sizeof(WCHAR); + CurName.MaximumLength = CurName.Length + sizeof(WCHAR); + // check if we have already opened the component before last one + // in this case OpenTargetDir request will be served in a special + // way... + if(OpenTargetDirectory && NT_SUCCESS(RC) && !TailName.Length) { + // check if we should open SDir.. + if(!StreamOpen || + (TailName.Buffer[0]!=L':')) { + // no, we should not. Continue with OpenTargetDir + break; + } + } + + if( CurName.Length && + (NT_SUCCESS(RC) || !StreamOpen)) { + // ...wow! non-zero! try to open! + if(!NT_SUCCESS(RC)) { + AdPrint((" Error opening path component\n")); + // we haven't reached last name part... hm.. + // probably, the path specified is invalid.. + // or we had a hard error... What else can we do ? + // Only say ..CK OFF !!!! + if(RC == STATUS_OBJECT_NAME_NOT_FOUND) + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return(RC); + } + + ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount); + + if(RelatedFileInfo && (TreeLength>1)) { + // it was an internal Open operation. Thus, assume + // RelatedFileInfo's Fcb to be valid + RelatedFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; + RelatedFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; + } + // check path fragment size + if(CurName.Length > UDF_X_NAME_LEN * sizeof(WCHAR)) { + AdPrint((" Path component is too long\n")); + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + // ...and now release previously acquired objects, + if(Res1) UDFReleaseResource(Res1); + if(Res2) { + UDFReleaseResource(Res2); + Res2 = NULL; + } + // acquire new _parent_ directory & try to open what + // we want. + + UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res1 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + + // check traverse rights + RC = UDFCheckAccessRights(NULL, NULL, RelatedFileInfo->Fcb, PtrRelatedCCB, FILE_TRAVERSE, 0); + if(!NT_SUCCESS(RC)) { + NewFileInfo = NULL; + AdPrint((" Traverse check failed\n")); + goto Skip_open_attempt; + } + // check if we should open normal File/Dir or SDir + if(CurName.Buffer[0] != ':') { + // standard open, nothing interesting.... + RC = UDFOpenFile__(Vcb, + IgnoreCase,TRUE,&CurName, + RelatedFileInfo,&NewFileInfo,NULL); + if(RC == STATUS_FILE_DELETED) { + // file has gone, but system still remembers it... + NewFileInfo = NULL; + AdPrint((" File deleted\n")); + RC = STATUS_ACCESS_DENIED; +#ifdef UDF_DBG + } else + if(RC == STATUS_NOT_A_DIRECTORY) { + AdPrint((" Not a directory\n")); +#endif // UDF_DBG + } else + if(RC == STATUS_SHARING_PAUSED) { + AdPrint((" Dloc is being initialized\n")); + BrutePoint(); + RC = STATUS_SHARING_VIOLATION; + } + } else { + // And here we should open Stream Dir (if any, of cource) + RC = UDFOpenStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); + if(NT_SUCCESS(RC)) { +SuccessOpen_SDir: + // this indicates that we needn't Stream Dir creation + StreamExists = TRUE; + StreamName.Buffer++; + StreamName.Length-=sizeof(WCHAR); + // update TailName + TailName = StreamName; + } else + if(RC == STATUS_NOT_FOUND) { +#ifndef UDF_READ_ONLY_BUILD + // Stream Dir doesn't exist, but caller wants it to be + // created. Lets try to help him... + if((RequestedDisposition == FILE_CREATE) || + (RequestedDisposition == FILE_OPEN_IF) || + (RequestedDisposition == FILE_OVERWRITE_IF) || + OpenTargetDirectory ) { + RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); + if(NT_SUCCESS(RC)) + goto SuccessOpen_SDir; + } +#endif //UDF_READ_ONLY_BUILD + } +/* } else { + AdPrint((" File deleted (2)\n")); + RC = STATUS_ACCESS_DENIED;*/ + } +#if 0 + CollectStatistics(Vcb, MetaDataReads); +#endif + +Skip_open_attempt: + + // check if we have successfully opened path component + if(NT_SUCCESS(RC)) { + // Yesss !!! + if (!(PtrNewFcb = NewFileInfo->Fcb)) { + // It is a first open operation + // Allocate new FCB + // Here we set FileObject pointer to NULL to avoid + // new CCB allocation + RC = UDFFirstOpenFile(Vcb, + NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, + &LocalPath, &CurName); + + if(!NT_SUCCESS(RC)) { + BrutePoint(); + AdPrint((" Can't perform FirstOpen\n")); + UDFCloseFile__(Vcb, NewFileInfo); + if(PtrNewFcb) UDFCleanUpFCB(PtrNewFcb); + PtrNewFcb = NULL; + NewFileInfo->Fcb = NULL; + if(UDFCleanUpFile__(Vcb, NewFileInfo)) { + MyFreePool__(NewFileInfo); + NewFileInfo = NULL; + } + try_return(RC); + } + } else { + // It is not a first open operation + // Validate Fcb. It is possible to get + // not completly initialized Fcb here. + if(!(PtrNewFcb->FCBFlags & UDF_FCB_VALID)) { + BrutePoint(); + AdPrint((" Fcb not valid\n")); + UDFCloseFile__(Vcb, NewFileInfo); + PtrNewFcb = NULL; + if(UDFCleanUpFile__(Vcb, NewFileInfo)) { + MyFreePool__(NewFileInfo); + NewFileInfo = NULL; + } + try_return(RC = STATUS_ACCESS_DENIED); + } + } + // Acquire newly opened File... + Res2 = Res1; + UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res1 = &(NewFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + // ...and reference it + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + + ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); + // update unwind information + LastGoodFileInfo = NewFileInfo; + LastGoodName = CurName; + TreeLength++; + // update current path + if(!StreamOpen || + ((CurName.Buffer[0] != L':') && + (!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/sizeof(WCHAR)-1] != L':'))) ) { + // we should not insert '\' before or after ':' + ASSERT(!LocalPath.Length || + (LocalPath.Buffer[LocalPath.Length/2-1] != L'\\')); + RC = MyAppendUnicodeToString(&LocalPath, L"\\"); + if(!NT_SUCCESS(RC)) try_return(RC); + } + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &CurName, MEM_USLOC_TAG); + if(!NT_SUCCESS(RC)) + try_return(RC); +// DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount); + } else { + AdPrint((" Can't open file\n")); + // We have failed durring last Open attempt + // Roll back to last good state + PtrUDFNTRequiredFCB NtReqFcb = NULL; + // Cleanup FileInfo if any + if(NewFileInfo) { + PtrNewFcb = NewFileInfo->Fcb; + // acquire appropriate resource if possible + if(PtrNewFcb && + PtrNewFcb->NTRequiredFCB) { + NtReqFcb = PtrNewFcb->NTRequiredFCB; + Res2 = Res1; + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceExclusive(Res1 = &(NtReqFcb->MainResource),TRUE); + } + // cleanup pointer to Fcb in FileInfo to allow + // UDF_INFO package release FileInfo if there are + // no more references + if(PtrNewFcb && + !PtrNewFcb->ReferenceCount && + !PtrNewFcb->OpenHandleCount) { + NewFileInfo->Fcb = NULL; + } + // cleanup pointer to CommonFcb in Dloc to allow + // UDF_INFO package release Dloc if there are + // no more references + if(NewFileInfo->Dloc && + !NewFileInfo->Dloc->LinkRefCount && + (!PtrNewFcb || !PtrNewFcb->ReferenceCount)) { + NewFileInfo->Dloc->CommonFcb = NULL; + } + // try to release FileInfo + if(UDFCleanUpFile__(Vcb, NewFileInfo)) { + ASSERT(!PtrNewFcb); + if(PtrNewFcb) { + BrutePoint(); + UDFCleanUpFCB(PtrNewFcb); + } + MyFreePool__(NewFileInfo); + } else { + // if we can't release FileInfo + // restore pointers to Fcb & CommonFcb in + // FileInfo & Dloc + NewFileInfo->Fcb = PtrNewFcb; + if(NtReqFcb) + NewFileInfo->Dloc->CommonFcb = NtReqFcb; + } + // forget about last FileInfo & Fcb, + // further unwind staff needs only last good + // structures + PtrNewFcb = NULL; + NewFileInfo = NULL; + } + } + + // should return error if 'delete in progress' + if(LastGoodFileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETED | + UDF_FCB_POSTED_RENAME)) { + AdPrint((" Return DeletePending (no err)\n")); + try_return(RC = STATUS_DELETE_PENDING); + } + // update last good state information... + OldRelatedFileInfo = RelatedFileInfo; + RelatedFileInfo = NewFileInfo; + // ...and go to the next open cycle + } else { + // ************ + if(StreamOpen && (RC == STATUS_NOT_FOUND)) + // handle SDir return code + RC = STATUS_OBJECT_NAME_NOT_FOUND; + if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { + // good path, but no such file.... Amen + // break open loop and continue with Create + break; + } + if (!NT_SUCCESS(RC)) { + // Hard error or damaged data structures ... +#ifdef UDF_DBG + if((RC != STATUS_OBJECT_PATH_NOT_FOUND) && + (RC != STATUS_ACCESS_DENIED) && + (RC != STATUS_NOT_A_DIRECTORY)) { + AdPrint((" Hard error or damaged data structures\n")); + } +#endif // UDF_DBG + // ... and exit with error + try_return(RC); + } + // discard changes for last successfully opened file + UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + RC = STATUS_SUCCESS; + ASSERT(!OpenTargetDirectory); + // break open loop and continue with Open + // (Create will be skipped) + break; + } + } // end of while(TRUE) + + // **************** + // If "open target directory" was specified + // **************** + if(OpenTargetDirectory) { + + if(!UDFIsADirectory(LastGoodFileInfo)) { + AdPrint((" Not a directory (2)\n")); + RC = STATUS_NOT_A_DIRECTORY; + } + if(!NT_SUCCESS(RC) || + TailName.Length) { + AdPrint((" Target name should not contain (back)slashes\n")); + NewFileInfo = NULL; + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + + NewFileInfo = LastGoodFileInfo; + RtlCopyUnicodeString(&(PtrNewFileObject->FileName), &CurName); + + // now we have to check if last component exists... + if(NT_SUCCESS(RC = UDFFindFile__(Vcb, IgnoreCase, + &CurName, RelatedFileInfo))) { + // file exists, set this information in the Information field + ReturnedInformation = FILE_EXISTS; + AdPrint((" Open Target: FILE_EXISTS\n")); + } else + if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { +#ifdef UDF_DBG + // check name. If there are '\\'s in TailName, some + // directories in path specified do not exist + for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { + if((*TmpBuffer) == L'\\') { + ASSERT(FALSE); + AdPrint((" Target name should not contain (back)slashes\n")); + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + } +#endif // UDF_DBG + // Tell the I/O Manager that file does not exit + ReturnedInformation = FILE_DOES_NOT_EXIST; + AdPrint((" Open Target: FILE_DOES_NOT_EXIST\n")); + RC = STATUS_SUCCESS; // is already set here + } else { + AdPrint((" Open Target: unexpected error\n")); + NewFileInfo = NULL; + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + +// RC = STATUS_SUCCESS; // is already set here + + // Update the file object FsContext and FsContext2 fields + // to reflect the fact that the parent directory of the + // target has been opened + PtrNewFcb = NewFileInfo->Fcb; + UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); + ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); + if (!NT_SUCCESS(RC)) { + AdPrint((" Can't perform OpenFile operation for target\n")); + try_return(RC); + } + PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); + + ASSERT(Res1); + RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if(!NT_SUCCESS(RC)) { + AdPrint((" Access/Share access check failed (Open Target)\n")); + } + + try_return(RC); + } + + // **************** + // should we CREATE a new file ? + // **************** + if (!NT_SUCCESS(RC)) { + if (RC == STATUS_OBJECT_NAME_NOT_FOUND || + RC == STATUS_OBJECT_PATH_NOT_FOUND) { + if( ((RequestedDisposition == FILE_OPEN) || + (RequestedDisposition == FILE_OVERWRITE)) /*&& + (!StreamOpen || !StreamExists)*/ ){ + ReturnedInformation = FILE_DOES_NOT_EXIST; + AdPrint((" File doesn't exist\n")); + try_return(RC); + } + } else { + // Any other operation return STATUS_ACCESS_DENIED. + AdPrint((" Can't create due to unexpected error\n")); + try_return(RC); + } + // Object was not found, create if requested + if ((RequestedDisposition != FILE_CREATE) && (RequestedDisposition != FILE_OPEN_IF) && + (RequestedDisposition != FILE_OVERWRITE_IF) && (RequestedDisposition != FILE_SUPERSEDE)) { + AdPrint((" File doesn't exist (2)\n")); + try_return(RC); + } + // Check Volume ReadOnly attr +#ifndef UDF_READ_ONLY_BUILD + if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { +#endif //UDF_READ_ONLY_BUILD + ReturnedInformation = 0; + AdPrint((" Write protected\n")); + try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); +#ifndef UDF_READ_ONLY_BUILD + } + // Check r/o + delete on close + if(DeleteOnCloseSpecified && + (FileAttributes & FILE_ATTRIBUTE_READONLY)) { + AdPrint((" Can't create r/o file marked for deletion\n")); + try_return(RC = STATUS_CANNOT_DELETE); + } + + // Create a new file/directory here ... + if(StreamOpen) + StreamName.Buffer[StreamName.Length/sizeof(WCHAR)] = 0; + for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { + if((*TmpBuffer) == L'\\') { + AdPrint((" Target name should not contain (back)slashes\n")); + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + } + if( DirectoryOnlyRequested && + ((IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY) || + StreamOpen || FALSE)) { + AdPrint((" Creation of _temporary_ directory not permited\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + // check access rights + ASSERT(Res1); + RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, DirectoryOnlyRequested ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0); + if(!NT_SUCCESS(RC)) { + AdPrint((" Creation of File/Dir not permitted\n")); + try_return(RC); + } + // Note that a FCB structure will be allocated at this time + // and so will a CCB structure. Assume that these are called + // PtrNewFcb and PtrNewCcb respectively. + // Further, note that since the file is being created, no other + // thread can have the file stream open at this time. + RelatedFileInfo = OldRelatedFileInfo; + + RC = UDFCreateFile__(Vcb, IgnoreCase, &LastGoodTail, 0, 0, + Vcb->UseExtendedFE || (StreamOpen && !StreamExists), + (RequestedDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); + if(!NT_SUCCESS(RC)) { + AdPrint((" Creation error\n")); +Creation_Err_1: + if(NewFileInfo) { + PtrNewFcb = NewFileInfo->Fcb; + ASSERT(!PtrNewFcb); + if(PtrNewFcb && + !PtrNewFcb->ReferenceCount && + !PtrNewFcb->OpenHandleCount) { + NewFileInfo->Fcb = NULL; + } + if(NewFileInfo->Dloc && + !NewFileInfo->Dloc->LinkRefCount) { + NewFileInfo->Dloc->CommonFcb = NULL; + } + if(UDFCleanUpFile__(Vcb, NewFileInfo)) { + if(PtrNewFcb) { + BrutePoint(); + UDFCleanUpFCB(PtrNewFcb); + } + MyFreePool__(NewFileInfo); + PtrNewFcb = PtrNewFcb; + } else { + NewFileInfo->Fcb = PtrNewFcb; + } + PtrNewFcb = NULL; + } + try_return(RC); + } + // Update parent object + if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && + PtrRelatedFCB && + PtrRelatedFileObject && + (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { + PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); + } +#if 0 + CollectStatistics(Vcb, MetaDataWrites); +#endif + + if(DirectoryOnlyRequested) { + // user wants the directory to be created + RC = UDFRecordDirectory__(Vcb, NewFileInfo); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't transform to directory\n")); +Undo_Create_1: + if((RC != STATUS_FILE_IS_A_DIRECTORY) && + (RC != STATUS_NOT_A_DIRECTORY) && + (RC != STATUS_ACCESS_DENIED)) { + UDFFlushFile__(Vcb, NewFileInfo); + UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); + } + UDFCloseFile__(Vcb, NewFileInfo); + BrutePoint(); + goto Creation_Err_1; + } +#if 0 + CollectStatistics(Vcb, MetaDataWrites); +#endif + } else if(AllocationSize) { + // set initial file size +/* if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { + AdPrint((" Can't set initial file size\n")); + goto Undo_Create_1; + } + CollectStatistics(Vcb, MetaDataWrites);*/ + } + + if(StreamOpen && !StreamExists) { + + // PHASE 0 + + // Open the newly created object (file) + if (!(PtrNewFcb = NewFileInfo->Fcb)) { + // It is a first open operation + // Allocate new FCB + // Here we set FileObject pointer to NULL to avoid + // new CCB allocation + RC = UDFFirstOpenFile(Vcb, + NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, + &LocalPath, &LastGoodTail); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n")); + BrutePoint(); + UDFCleanUpFCB(NewFileInfo->Fcb); + NewFileInfo->Fcb = NULL; + goto Creation_Err_1; + } + } else { + BrutePoint(); + } + + // Update unwind information + TreeLength++; + LastGoodFileInfo = NewFileInfo; + // update FCB tree + RC = MyAppendUnicodeToString(&LocalPath, L"\\"); + if(!NT_SUCCESS(RC)) try_return(RC); + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &LastGoodTail, MEM_USLOC_TAG); + if(!NT_SUCCESS(RC)) + goto Creation_Err_1; + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); + PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; + PtrNewFcb->FCBFlags |= UDF_FCB_VALID; + + UDFNotifyFullReportChange( Vcb, NewFileInfo, + UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED); + + // PHASE 1 + + // we need to create Stream Dir + RelatedFileInfo = NewFileInfo; + RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't create SDir\n")); + BrutePoint(); + goto Creation_Err_1; + } +#if 0 + CollectStatistics(Vcb, MetaDataWrites); +#endif + + // normalize stream name + StreamName.Buffer++; + StreamName.Length-=sizeof(WCHAR); + // Open the newly created object + if (!(PtrNewFcb = NewFileInfo->Fcb)) { + // It is a first open operation + // Allocate new FCB + // Here we set FileObject pointer to NULL to avoid + // new CCB allocation + RC = UDFFirstOpenFile(Vcb, + NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, + &LocalPath, &(UDFGlobalData.UnicodeStrSDir)); + } else { + BrutePoint(); + } + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't perform OpenFile operation for SDir\n")); + BrutePoint(); + goto Creation_Err_1; + } + + // Update unwind information + TreeLength++; + LastGoodFileInfo = NewFileInfo; + // update FCB tree + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(UDFGlobalData.UnicodeStrSDir), MEM_USLOC_TAG); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't append UNC str\n")); + BrutePoint(); + goto Creation_Err_1; + } + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); + PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; + PtrNewFcb->FCBFlags |= UDF_FCB_VALID; + + // PHASE 2 + + // create stream + RelatedFileInfo = NewFileInfo; + RC = UDFCreateFile__(Vcb, IgnoreCase, &StreamName, 0, 0, + Vcb->UseExtendedFE, (RequestedDisposition == FILE_CREATE), + RelatedFileInfo, &NewFileInfo); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't create Stream\n")); + BrutePoint(); + goto Creation_Err_1; + } +#if 0 + CollectStatistics(Vcb, MetaDataWrites); +#endif + + // Update unwind information + LastGoodTail = StreamName; + } + // NT wants ARCHIVE bit to be set on Files + if(!DirectoryOnlyRequested) + FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + // Open the newly created object + if (!(PtrNewFcb = NewFileInfo->Fcb)) { + // It is a first open operation +#ifndef IFS_40 + // Set attributes for the file ... + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), + NewFileInfo->Dloc->FileEntry, FileAttributes); +#endif //IFS_40 + // Allocate new FCB + // Here we set FileObject pointer to NULL to avoid + // new CCB allocation + RC = UDFFirstOpenFile(Vcb, + PtrNewFileObject, &PtrNewFcb, RelatedFileInfo, NewFileInfo, + &LocalPath, &LastGoodTail); + } else { + BrutePoint(); + } + + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't perform OpenFile operation for file or stream\n")); + BrutePoint(); + goto Undo_Create_1; + } + + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart = + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0; + if(AllocationSize) { + // inform NT about size changes + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = AllocationSize; + MmPrint((" CcIsFileCached()\n")); + if(CcIsFileCached(PtrNewFileObject)) { + MmPrint((" CcSetFileSizes()\n")); + BrutePoint(); + CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize)); + PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + } + } + + // Update unwind information + TreeLength++; + LastGoodFileInfo = NewFileInfo; + + // Set the Share Access for the file stream. + // The FCBShareAccess field will be set by the I/O Manager. + PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); + RC = UDFSetAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't set Access Rights on Create\n")); + BrutePoint(); + UDFFlushFile__(Vcb, NewFileInfo); + UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); + try_return(RC); + } + +#ifdef IFS_40 + // Set attributes for the file ... + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), + NewFileInfo->Dloc->FileEntry, FileAttributes); + // It is rather strange for me, but NT requires us to allow + // Create operation for r/o + WriteAccess, but denies all + // the rest operations in this case. Thus, we should update + // r/o flag in Fcb _after_ Access check :-/ + if(FileAttributes & FILE_ATTRIBUTE_READONLY) + PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY; +#endif //IFS_40 + // We call the notify package to report that the + // we have added a stream. + if(UDFIsAStream(NewFileInfo)) { + UDFNotifyFullReportChange( Vcb, NewFileInfo, + FILE_NOTIFY_CHANGE_STREAM_NAME, + FILE_ACTION_ADDED_STREAM ); + } else { + UDFNotifyFullReportChange( Vcb, NewFileInfo, + UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED); + } +/*#ifdef UDF_DBG + { + ULONG i; + PDIR_INDEX_HDR hDirIndex = NewFileInfo->ParentFile->Dloc->DirIndex; + + for(i=0;DirIndex[i].FName.Buffer;i++) { + AdPrint(("%ws\n", DirIndex[i].FName.Buffer)); + } + } +#endif*/ + ReturnedInformation = FILE_CREATED; + + try_return(RC); +#endif //UDF_READ_ONLY_BUILD + + } + +AlreadyOpened: + + // **************** + // we have always STATUS_SUCCESS here + // **************** + + ASSERT(NewFileInfo != OldRelatedFileInfo); + // A new CCB will be allocated. + // Assume that this structure named PtrNewCcb + RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); + if (!NT_SUCCESS(RC)) try_return(RC); + PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); + + if(RequestedDisposition == FILE_CREATE) { + ReturnedInformation = FILE_EXISTS; + AdPrint((" Object name collision\n")); + try_return(RC = STATUS_OBJECT_NAME_COLLISION); + } + + NtReqFcb = PtrNewFcb->NTRequiredFCB; + NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(PtrNewFcb); + + // Check if caller wanted a directory only and target object + // is not a directory, or caller wanted a file only and target + // object is not a file ... + if((PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || + (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF) || + FileOnlyRequested)) { + if(FileOnlyRequested) { + AdPrint((" Can't open directory as a plain file\n")); + } else { + AdPrint((" Can't supersede directory\n")); + } + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + if(DirectoryOnlyRequested && !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) { + AdPrint((" This is not a directory\n")); + RC = STATUS_NOT_A_DIRECTORY; + try_return(RC); + } + + if(DeleteOnCloseSpecified && (PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY)) { + AdPrint((" Can't delete Read-Only file\n")); + RC = STATUS_CANNOT_DELETE; + try_return(RC); + } + // Check share access and fail if the share conflicts with an existing + // open. + ASSERT(Res1 != NULL); + ASSERT(Res2 != NULL); + RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if(!NT_SUCCESS(RC)) { + AdPrint((" Access/Share access check failed\n")); + try_return(RC); + } + + RestoreShareAccess = TRUE; + + if(FileOnlyRequested) { + // If the user wants 'write access' access to the file make sure there + // is not a process mapping this file as an image. Any attempt to + // delete the file will be stopped in fileinfo.cpp + // + // If the user wants to delete on close, we must check at this + // point though. + if( (DesiredAccess & FILE_WRITE_DATA) || DeleteOnCloseSpecified ) { + MmPrint((" MmFlushImageSection();\n")); + NtReqFcb->AcqFlushCount++; + if(!MmFlushImageSection( &(NtReqFcb->SectionObject), + MmFlushForWrite )) { + + NtReqFcb->AcqFlushCount--; + RC = DeleteOnCloseSpecified ? STATUS_CANNOT_DELETE : + STATUS_SHARING_VIOLATION; + AdPrint((" File is mapped or deletion in progress\n")); + try_return (RC); + } + NtReqFcb->AcqFlushCount--; + } + if( NoBufferingSpecified && + /* (PtrNewFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) &&*/ + !(PtrNewFcb->CachedOpenHandleCount) && + (NtReqFcb->SectionObject.DataSectionObject) ) { + // If this is a non-cached open, and there are no open cached + // handles, but there is still a data section, attempt a flush + // and purge operation to avoid cache coherency overhead later. + // We ignore any I/O errors from the flush. + MmPrint((" CcFlushCache()\n")); + CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, NULL ); + MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); + } + } + + if(DeleteOnCloseSpecified && UDFIsADirectory(NewFileInfo) && !UDFIsDirEmpty__(NewFileInfo)) { + AdPrint((" Directory in not empry\n")); + try_return (RC = STATUS_DIRECTORY_NOT_EMPTY); + } + + // Get attributes for the file ... + TmpFileAttributes = + (USHORT)UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), + NewFileInfo->Dloc->FileEntry); + + if(DeleteOnCloseSpecified && + (TmpFileAttributes & FILE_ATTRIBUTE_READONLY)) { + ASSERT(Res1 != NULL); + ASSERT(Res2 != NULL); + RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, FILE_DELETE_CHILD, 0); + if(!NT_SUCCESS(RC)) { + AdPrint((" Read-only. DeleteOnClose attempt failed\n")); + try_return (RC = STATUS_CANNOT_DELETE); + } + } + + // If a supersede or overwrite was requested, do so now ... + if((RequestedDisposition == FILE_SUPERSEDE) || + (RequestedDisposition == FILE_OVERWRITE) || + (RequestedDisposition == FILE_OVERWRITE_IF)) { + // Attempt the operation here ... + +#ifndef UDF_READ_ONLY_BUILD + ASSERT(!UDFIsADirectory(NewFileInfo)); + + if(RequestedDisposition == FILE_SUPERSEDE) { + BOOLEAN RestoreRO = FALSE; + + ASSERT(Res1 != NULL); + ASSERT(Res2 != NULL); + // NT wants us to allow Supersede on RO files + if(PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY) { + // Imagine, that file is not RO and check other permissions + RestoreRO = TRUE; + PtrNewFcb->FCBFlags &= ~UDF_FCB_READ_ONLY; + } + RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, DELETE, 0); + if(RestoreRO) { + // Restore RO state if changed + PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY; + } + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't supersede. DELETE permission required\n")); + try_return (RC); + } + } else { + ASSERT(Res1 != NULL); + ASSERT(Res2 != NULL); + RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, + FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES, 0); + if(!NT_SUCCESS(RC)) { + AdPrint((" Can't overwrite. Permission denied\n")); + try_return (RC); + } + } + // Existing & requested System and Hidden bits must match + if( (TmpFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) & + (FileAttributes ^ (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) ) { + AdPrint((" The Hidden and/or System bits do not match\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + + // Before we actually truncate, check to see if the purge + // is going to fail. + MmPrint((" MmCanFileBeTruncated()\n")); + if (!MmCanFileBeTruncated( &NtReqFcb->SectionObject, + &(UDFGlobalData.UDFLargeZero) )) { + AdPrint((" Can't truncate. File is mapped\n")); + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + ASSERT(Res1 != NULL); + ASSERT(Res2 != NULL); + +#if 0 + CollectStatistics(Vcb, MetaDataWrites); +#endif + // Synchronize with PagingIo + UDFAcquireResourceExclusive(PagingIoRes = &(NtReqFcb->PagingIoResource),TRUE); + // Set file sizes + if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, 0))) { + AdPrint((" Error during resize operation\n")); + try_return(RC); + } +/* if(AllocationSize) { + if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { + AdPrint((" Error during resize operation (2)\n")); + try_return(RC); + } + }*/ + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize); + NtReqFcb->CommonFCBHeader.FileSize.QuadPart = + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0 /*AllocationSize*/; + PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; + MmPrint((" CcSetFileSizes()\n")); + CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + // Release PagingIoResource + UDFReleaseResource(PagingIoRes); + PagingIoRes = NULL; + + if(NT_SUCCESS(RC)) { + FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + if (RequestedDisposition == FILE_SUPERSEDE) { + // Set attributes for the file ... + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), + NewFileInfo->Dloc->FileEntry, FileAttributes); + ReturnedInformation = FILE_SUPERSEDED; + } else { + // Get attributes for the file ... + FileAttributes |= TmpFileAttributes; + // Set attributes for the file ... + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), + NewFileInfo->Dloc->FileEntry, FileAttributes); + ReturnedInformation = FILE_OVERWRITTEN; + } + } + // notify changes + UDFNotifyFullReportChange( Vcb, NewFileInfo, + FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + + // Update parent object + if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && + PtrRelatedFCB && + PtrRelatedFileObject && + (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { + PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); + } +#else //UDF_READ_ONLY_BUILD + try_return(RC = STATUS_ACCESS_DENIED); +#endif //UDF_READ_ONLY_BUILD + } else { + ReturnedInformation = FILE_OPENED; + } + + // Update parent object + if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_READ) && + PtrRelatedFCB && + PtrRelatedFileObject && + (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { + PtrRelatedFileObject->Flags |= FO_FILE_FAST_IO_READ; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + // Complete the request unless we are here as part of unwinding + // when an exception condition was encountered, OR + // if the request has been deferred (i.e. posted for later handling) + + if(RestoreVCBOpenCounter) { + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + RestoreVCBOpenCounter = FALSE; + } + + if (RC != STATUS_PENDING) { + // If any intermediate (directory) open operations were performed, + // implement the corresponding close (do *not* however close + // the target we have opened on behalf of the caller ...). + +#if 0 + if(NT_SUCCESS(RC)) { + CollectStatistics2(Vcb, SuccessfulCreates); + } else { + CollectStatistics2(Vcb, FailedCreates); + } +#endif + + if (NT_SUCCESS(RC) && PtrNewFcb) { + // Update the file object such that: + // (a) the FsContext field points to the NTRequiredFCB field + // in the FCB + // (b) the FsContext2 field points to the CCB created as a + // result of the open operation + + // If write-through was requested, then mark the file object + // appropriately + + // directories are not cached + // so we should prevent flush attepmts on cleanup + if(!(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) { +#ifndef UDF_READ_ONLY_BUILD + if(WriteThroughRequested) { + PtrNewFileObject->Flags |= FO_WRITE_THROUGH; + PtrNewFcb->FCBFlags |= UDF_FCB_WRITE_THROUGH; + MmPrint((" FO_WRITE_THROUGH\n")); + } +#endif //UDF_READ_ONLY_BUILD + if(SequentialIoRequested && + !(Vcb->CompatFlags & UDF_VCB_IC_IGNORE_SEQUENTIAL_IO)) { + PtrNewFileObject->Flags |= FO_SEQUENTIAL_ONLY; + MmPrint((" FO_SEQUENTIAL_ONLY\n")); +#ifndef UDF_READ_ONLY_BUILD + if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { + PtrNewFileObject->Flags &= ~FO_WRITE_THROUGH; + PtrNewFcb->FCBFlags &= ~UDF_FCB_WRITE_THROUGH; + MmPrint((" FILE_REMOVABLE_MEDIA + FO_SEQUENTIAL_ONLY => ~FO_WRITE_THROUGH\n")); + } +#endif //UDF_READ_ONLY_BUILD + if(PtrNewFcb->FileInfo) { + UDFSetFileAllocMode__(PtrNewFcb->FileInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL); + } + } + if(NoBufferingSpecified) { + PtrNewFileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; + MmPrint((" FO_NO_INTERMEDIATE_BUFFERING\n")); + } else { + PtrNewFileObject->Flags |= FO_CACHE_SUPPORTED; + MmPrint((" FO_CACHE_SUPPORTED\n")); + } + } + + if((DesiredAccess & FILE_EXECUTE) /*&& + !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)*/) { + MmPrint((" FO_FILE_FAST_IO_READ\n")); + PtrNewFileObject->Flags |= FO_FILE_FAST_IO_READ; + } + // All right. Now we can safely increment OpenHandleCount + UDFInterlockedIncrement((PLONG)&(Vcb->VCBHandleCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->OpenHandleCount)); + + if(PtrNewFileObject->Flags & FO_CACHE_SUPPORTED) + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->CachedOpenHandleCount)); + // Store some flags in CCB + if(PtrNewCcb) { + PtrNewCcb->TreeLength = TreeLength; + // delete on close +#ifndef UDF_READ_ONLY_BUILD + if(DeleteOnCloseSpecified) { + ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + PtrNewCcb->CCBFlags |= UDF_CCB_DELETE_ON_CLOSE; + } +#endif //UDF_READ_ONLY_BUILD + // case sensetivity + if(!IgnoreCase) { + // remember this for possible Rename/Move operation + PtrNewCcb->CCBFlags |= UDF_CCB_CASE_SENSETIVE; + PtrNewFileObject->Flags |= FO_OPENED_CASE_SENSITIVE; + } + if(IsFileObjectReadOnly(PtrNewFileObject)) { + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCountRO)); + PtrNewCcb->CCBFlags |= UDF_CCB_READ_ONLY; + } + } else { + BrutePoint(); + } + // it was a stream... + if(StreamOpen) + PtrNewFileObject->Flags |= FO_STREAM_FILE; +// PtrNewCcb->CCBFlags |= UDF_CCB_VALID; + // increment the number of outstanding open operations on this + // logical volume (i.e. volume cannot be dismounted) + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; + PtrNewFcb->FCBFlags |= UDF_FCB_VALID; +#ifdef UDF_DBG + // We have no FileInfo for Volume + if(PtrNewFcb->FileInfo) { + ASSERT_REF(PtrNewFcb->ReferenceCount >= PtrNewFcb->FileInfo->RefCount); + } +#endif // UDF_DBG + AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb, PtrNewCcb, PtrNewFileObject, PtrNewFcb->FCBFlags)); + + UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); + + } else if(!NT_SUCCESS(RC)) { + // Perform failure related post-processing now + if(RestoreShareAccess && NtReqFcb && PtrNewFileObject) { + IoRemoveShareAccess(PtrNewFileObject, &(NtReqFcb->FCBShareAccess)); + } + UDFCleanUpCCB(PtrNewCcb); + if(PtrNewFileObject) { + PtrNewFileObject->FsContext2 = NULL; + } + // We have successfully opened LastGoodFileInfo, + // so mark it as VALID to avoid future troubles... + if(LastGoodFileInfo && LastGoodFileInfo->Fcb) { + LastGoodFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; + if(LastGoodFileInfo->Fcb->NTRequiredFCB) { + LastGoodFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; + } + } + // Release resources... + UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); + ASSERT(AcquiredVcb); + // close the chain + UDFCloseFileInfoChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); + // cleanup FCBs (if any) + if( Vcb && (PtrNewFcb != Vcb->RootDirFCB) && + LastGoodFileInfo ) { + UDFCleanUpFcbChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); + } else { + ASSERT(!LastGoodFileInfo); + } + } else { + UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); + } + // As long as this unwinding is not being performed as a result of + // an exception condition, complete the IRP ... + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = ReturnedInformation; + + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + } + } else { + UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); + } + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + // free allocated tmp buffers (if any) + if(AbsolutePathName.Buffer) + MyFreePool__(AbsolutePathName.Buffer); + if(LocalPath.Buffer) + MyFreePool__(LocalPath.Buffer); + if(TailNameBuffer) + MyFreePool__(TailNameBuffer); + } _SEH2_END; + + return(RC); +} // end UDFCommonCreate() + +/************************************************************************* +* +* Function: UDFFirstOpenFile() +* +* Description: +* Perform first Open/Create initialization. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFFirstOpenFile( + IN PVCB Vcb, // volume control block + IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object + OUT PtrUDFFCB* PtrNewFcb, + IN PUDF_FILE_INFO RelatedFileInfo, + IN PUDF_FILE_INFO NewFileInfo, + IN PUNICODE_STRING LocalPath, + IN PUNICODE_STRING CurName + ) +{ +// DIR_INDEX NewFileIndex; + PtrUDFObjectName NewFCBName; + PtrUDFNTRequiredFCB NtReqFcb; + NTSTATUS RC; + BOOLEAN Linked = TRUE; + PDIR_INDEX_HDR hDirIndex; + PDIR_INDEX_ITEM DirIndex; + + AdPrint(("UDFFirstOpenFile\n")); + + if(!((*PtrNewFcb) = UDFAllocateFCB())) { + AdPrint(("Can't allocate FCB\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Allocate and set new FCB unique name (equal to absolute path name) + if(!(NewFCBName = UDFAllocateObjectName())) return STATUS_INSUFFICIENT_RESOURCES; + + if(RelatedFileInfo && RelatedFileInfo->Fcb && + !(RelatedFileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) { + RC = MyCloneUnicodeString(&(NewFCBName->ObjectName), &(RelatedFileInfo->Fcb->FCBName->ObjectName)); + } else { + RC = MyInitUnicodeString(&(NewFCBName->ObjectName), L""); + } + if(!NT_SUCCESS(RC)) + return STATUS_INSUFFICIENT_RESOURCES; + if( (CurName->Buffer[0] != L':') && + (!LocalPath->Length || + ((LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L':') /*&& + (LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L'\\')*/) )) { + RC = MyAppendUnicodeToString(&(NewFCBName->ObjectName), L"\\"); + if(!NT_SUCCESS(RC)) return STATUS_INSUFFICIENT_RESOURCES; + } + + // Make link between Fcb and FileInfo + (*PtrNewFcb)->FileInfo = NewFileInfo; + NewFileInfo->Fcb = (*PtrNewFcb); + (*PtrNewFcb)->ParentFcb = RelatedFileInfo->Fcb; + + if(!((*PtrNewFcb)->NTRequiredFCB = NewFileInfo->Dloc->CommonFcb)) { + if(!((*PtrNewFcb)->NTRequiredFCB = + (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + + KdPrint(("UDFAllocateNtReqFCB: %x\n", (*PtrNewFcb)->NTRequiredFCB)); + RtlZeroMemory((*PtrNewFcb)->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); + (*PtrNewFcb)->FileInfo->Dloc->CommonFcb = (*PtrNewFcb)->NTRequiredFCB; + Linked = FALSE; + } else { + if(!(NewFileInfo->Dloc->CommonFcb->NtReqFCBFlags & UDF_NTREQ_FCB_VALID)) { + (*PtrNewFcb)->NTRequiredFCB = NULL; + BrutePoint(); + return STATUS_ACCESS_DENIED; + } + } + + NtReqFcb = (*PtrNewFcb)->NTRequiredFCB; + // Set times + if(!Linked) { + UDFGetFileXTime((*PtrNewFcb)->FileInfo, + &(NtReqFcb->CreationTime.QuadPart), + &(NtReqFcb->LastAccessTime.QuadPart), + &(NtReqFcb->ChangeTime.QuadPart), + &(NtReqFcb->LastWriteTime.QuadPart) ); + + // Set the allocation size for the object is specified + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = + UDFSysGetAllocSize(Vcb, NewFileInfo->Dloc->DataLoc.Length); +// NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, NewFileInfo); + NtReqFcb->CommonFCBHeader.FileSize.QuadPart = + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileInfo->Dloc->DataLoc.Length; + } + // begin transaction + UDFAcquireResourceExclusive(&(Vcb->FcbListResource), TRUE); + + RC = UDFInitializeFCB(*PtrNewFcb, Vcb, NewFCBName, + UDFIsADirectory(NewFileInfo) ? UDF_FCB_DIRECTORY : 0, PtrNewFileObject); + if(!NT_SUCCESS(RC)) { + if(!Linked) { + MyFreePool__((*PtrNewFcb)->NTRequiredFCB); + (*PtrNewFcb)->NTRequiredFCB = NULL; + } + UDFReleaseResource(&(Vcb->FcbListResource)); + return RC; + } + // set Read-only attribute + if(!UDFIsAStreamDir(NewFileInfo)) { + hDirIndex = UDFGetDirIndexByFileInfo(NewFileInfo); +#ifdef UDF_DBG + if(!hDirIndex) { + BrutePoint(); + } else { +#endif // UDF_DBG + if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, NewFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { + (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; + } + MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), &(DirIndex->FName), MEM_USOBJ_TAG); +#ifdef UDF_DBG + } +#endif // UDF_DBG + } else if (RelatedFileInfo->ParentFile) { + hDirIndex = UDFGetDirIndexByFileInfo(RelatedFileInfo); + if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, RelatedFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { + (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; + } + RC = MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), CurName, MEM_USOBJ_TAG); +// } else { +// BrutePoint(); + } + // do not allocate CCB if it is internal Create/Open + if(NT_SUCCESS(RC)) { + if(PtrNewFileObject) { + RC = UDFOpenFile(Vcb, PtrNewFileObject, *PtrNewFcb); + } else { + RC = STATUS_SUCCESS; + } + } + UDFReleaseResource(&(Vcb->FcbListResource)); + // end transaction + +// if(!NT_SUCCESS(RC)) return RC; + + return RC; +} // end UDFFirstOpenFile() + +/************************************************************************* +* +* Function: UDFOpenFile() +* +* Description: +* Open a file/dir for the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFOpenFile( + PVCB Vcb, // volume control block + PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object + PtrUDFFCB PtrNewFcb + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFCCB Ccb = NULL; + PtrUDFNTRequiredFCB NtReqFcb; + + AdPrint(("UDFOpenFile\n")); + ASSERT((PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) + ||(PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)); + + _SEH2_TRY { + +#if 0 + CollectStatistics2(Vcb, CreateHits); +#endif + // create a new CCB structure + if (!(Ccb = UDFAllocateCCB())) { + AdPrint(("Can't allocate CCB\n")); + PtrNewFileObject->FsContext2 = NULL; + // + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + // initialize the CCB + Ccb->Fcb = PtrNewFcb; + // initialize the CCB to point to the file object + Ccb->FileObject = PtrNewFileObject; + + // initialize the file object appropriately + PtrNewFileObject->FsContext2 = (PVOID)(Ccb); + PtrNewFileObject->Vpb = Vcb->Vpb; + PtrNewFileObject->FsContext = (PVOID)(NtReqFcb = PtrNewFcb->NTRequiredFCB); + PtrNewFileObject->SectionObjectPointer = &(NtReqFcb->SectionObject); +#ifdef DBG +// NtReqFcb ->FileObject = PtrNewFileObject; +#endif //DBG + +#ifdef UDF_DELAYED_CLOSE + PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(PtrNewFcb->CcbListResource),TRUE); + // insert CCB into linked list of open file object to Fcb or + // to Vcb and do other intialization + InsertTailList(&(PtrNewFcb->NextCCB), &(Ccb->NextCCB)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); + UDFReleaseResource(&(PtrNewFcb->CcbListResource)); + +try_exit: NOTHING; + } _SEH2_FINALLY { + NOTHING; + } _SEH2_END; + + return(RC); +} // end UDFOpenFile() + + +/************************************************************************* +* +* Function: UDFInitializeFCB() +* +* Description: +* Initialize a new FCB structure and also the sent-in file object +* (if supplied) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS +UDFInitializeFCB( + IN PtrUDFFCB PtrNewFcb, // FCB structure to be initialized + IN PVCB Vcb, // logical volume (VCB) pointer + IN PtrUDFObjectName PtrObjectName, // name of the object + IN ULONG Flags, // is this a file/directory, etc. + IN PFILE_OBJECT FileObject) // optional file object to be initialized +{ + AdPrint(("UDFInitializeFCB\n")); + NTSTATUS status; + BOOLEAN Linked = TRUE; + + if(!PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource) { + // record signature + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode = UDF_NODE_TYPE_NT_REQ_FCB; + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeByteSize = sizeof(UDFNTRequiredFCB); + // Initialize the ERESOURCE objects + if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->MainResource)))) { + AdPrint((" Can't init resource\n")); + return status; + } + if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)))) { + AdPrint((" Can't init resource (2)\n")); + UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); + return status; + } + // Fill NT required Fcb part + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = &(PtrNewFcb->NTRequiredFCB->MainResource); + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = &(PtrNewFcb->NTRequiredFCB->PagingIoResource); + // Itialize byte-range locks support structure + FsRtlInitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock),NULL,NULL); + // Init reference counter + PtrNewFcb->NTRequiredFCB->CommonRefCount = 0; + Linked = FALSE; + } else { + ASSERT(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); + } + if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->CcbListResource)))) { + AdPrint((" Can't init resource (3)\n")); + BrutePoint(); + if(!Linked) { + UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)); + UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = + PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = NULL; + FsRtlUninitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock)); + } + return status; + } + + // caller MUST ensure that VCB has been acquired exclusively + InsertTailList(&(Vcb->NextFCB), &(PtrNewFcb->NextFCB)); + + // initialize the various list heads + InitializeListHead(&(PtrNewFcb->NextCCB)); + + PtrNewFcb->ReferenceCount = 0; + PtrNewFcb->OpenHandleCount = 0; + + PtrNewFcb->FCBFlags = Flags | UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE; + + PtrNewFcb->FCBName = PtrObjectName; + + PtrNewFcb->Vcb = Vcb; + + return STATUS_SUCCESS; +} // end UDFInitializeFCB() + diff --git a/reactos/drivers/filesystems/udfs/devcntrl.cpp b/reactos/drivers/filesystems/udfs/devcntrl.cpp new file mode 100644 index 00000000000..218722289a2 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/devcntrl.cpp @@ -0,0 +1,1586 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Devcntrl.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Device IOCTL" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +#include "..\CDRW\scsi_port.h" + +#ifdef EVALUATION_TIME_LIMIT +#include "..\Include\protect.h" +#endif //EVALUATION_TIME_LIMIT + +#define UDF_CURRENT_BUILD 123456789 + +// define the file specific bug-check id +#ifdef UDF_BUG_CHECK_ID +#undef UDF_BUG_CHECK_ID +#endif +#define UDF_BUG_CHECK_ID UDF_FILE_DEVICE_CONTROL + +NTSTATUS +UDFGetFileAllocModeFromICB( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ); + +NTSTATUS +UDFSetFileAllocModeFromICB( + PtrUDFIrpContext IrpContext, + PIRP Irp + ); + +NTSTATUS +UDFProcessLicenseKey( + PtrUDFIrpContext IrpContext, + PIRP Irp + ); + +/*#if(_WIN32_WINNT < 0x0400) +#define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct _QUERY_PATH_REQUEST { + ULONG PathNameLength; + PIO_SECURITY_CONTEXT SecurityContext; + WCHAR FilePathName[1]; +} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST; + +typedef struct _QUERY_PATH_RESPONSE { + ULONG LengthAccepted; +} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE; + +#endif*/ + + +/************************************************************************* +* +* Function: UDFDeviceControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a Device IOCTL +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFDeviceControl( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFDeviceControl: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + //ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonDeviceControl(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFDeviceControl() + + +/************************************************************************* +* +* Function: UDFCommonDeviceControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFCommonDeviceControl( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; +// PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + BOOLEAN CompleteIrp = FALSE; + ULONG IoControlCode = 0; +// PVOID BufferPointer = NULL; + BOOLEAN AcquiredVcb = FALSE; + BOOLEAN FSDevObj; + ULONG TrackNumber; + BOOLEAN UnsafeIoctl = TRUE; + UCHAR ScsiCommand; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; // FSD buffer + PCDB Cdb; + PCHAR CdbData; + PCHAR ModeSelectData; + + KdPrint(("UDFCommonDeviceControl\n")); + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + // Get the IoControlCode value + IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + FSDevObj = UDFIsFSDevObj(PtrIrpContext->TargetDeviceObject); + + if(FSDevObj) { + switch (IoControlCode) { + case IOCTL_UDF_DISABLE_DRIVER: + case IOCTL_UDF_INVALIDATE_VOLUMES: + case IOCTL_UDF_SET_NOTIFICATION_EVENT: +#ifndef UDF_READ_ONLY_BUILD + case IOCTL_UDF_SEND_LICENSE_KEY: +#endif //UDF_READ_ONLY_BUILD + case IOCTL_UDF_REGISTER_AUTOFORMAT: + break; + default: + KdPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for FsDevObj\n", IoControlCode)); + CompleteIrp = TRUE; + try_return(RC = STATUS_INVALID_PARAMETER); + } + } else { + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + goto ioctl_do_default; + } + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + // Check if the IOCTL is suitable for this type of File + if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + // Everything is acceptable for Volume + Vcb = (PVCB)(Fcb); +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + } else { + Vcb = Fcb->Vcb; +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + CompleteIrp = TRUE; + // For files/disrs only the following are acceptable + switch (IoControlCode) { + case IOCTL_UDF_GET_RETRIEVAL_POINTERS: + case IOCTL_UDF_GET_FILE_ALLOCATION_MODE: + case IOCTL_UDF_SET_FILE_ALLOCATION_MODE: + break; + default: + KdPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for File/Dir Obj\n", IoControlCode)); + try_return(RC = STATUS_INVALID_PARAMETER); + } + } + // check 'safe' IOCTLs + switch (IoControlCode) { + case IOCTL_CDROM_RAW_READ: + + case IOCTL_CDROM_GET_DRIVE_GEOMETRY: + case IOCTL_DISK_GET_DRIVE_GEOMETRY: + case IOCTL_DISK_GET_PARTITION_INFO: + case IOCTL_DISK_GET_DRIVE_LAYOUT: + + case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: + case IOCTL_DISK_GET_PARTITION_INFO_EX: + case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: + case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: + + case IOCTL_STORAGE_CHECK_VERIFY: + case IOCTL_STORAGE_CHECK_VERIFY2: + case IOCTL_DISK_CHECK_VERIFY: + case IOCTL_CDROM_CHECK_VERIFY: + + case IOCTL_CDROM_LOAD_MEDIA: + case IOCTL_DISK_LOAD_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA: + case IOCTL_STORAGE_LOAD_MEDIA2: + + case IOCTL_CDROM_GET_CONFIGURATION: + case IOCTL_CDROM_GET_LAST_SESSION: + case IOCTL_CDROM_READ_TOC: + case IOCTL_CDROM_READ_TOC_EX: + case IOCTL_CDROM_PLAY_AUDIO_MSF: + case IOCTL_CDROM_READ_Q_CHANNEL: + case IOCTL_CDROM_PAUSE_AUDIO: + case IOCTL_CDROM_RESUME_AUDIO: + case IOCTL_CDROM_SEEK_AUDIO_MSF: + case IOCTL_CDROM_STOP_AUDIO: + case IOCTL_CDROM_GET_CONTROL: + case IOCTL_CDROM_GET_VOLUME: + case IOCTL_CDROM_SET_VOLUME: + + case IOCTL_CDRW_SET_SPEED: + case IOCTL_CDRW_GET_CAPABILITIES: + case IOCTL_CDRW_GET_MEDIA_TYPE_EX: + case IOCTL_CDRW_GET_MEDIA_TYPE: + + case IOCTL_DISK_GET_MEDIA_TYPES: + case IOCTL_STORAGE_GET_MEDIA_TYPES: + case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: + + case IOCTL_DISK_IS_WRITABLE: + + case IOCTL_CDRW_GET_WRITE_MODE: + case IOCTL_CDRW_READ_TRACK_INFO: + case IOCTL_CDRW_READ_DISC_INFO: + case IOCTL_CDRW_BUFFER_CAPACITY: + case IOCTL_CDRW_GET_SIGNATURE: + case IOCTL_CDRW_TEST_UNIT_READY: + case IOCTL_CDRW_GET_LAST_ERROR: + case IOCTL_CDRW_MODE_SENSE: + case IOCTL_CDRW_LL_READ: + case IOCTL_CDRW_READ_ATIP: + case IOCTL_CDRW_READ_CD_TEXT: + case IOCTL_CDRW_READ_TOC_EX: + case IOCTL_CDRW_READ_FULL_TOC: + case IOCTL_CDRW_READ_PMA: + case IOCTL_CDRW_READ_SESSION_INFO: + case IOCTL_CDRW_GET_DEVICE_INFO: + case IOCTL_CDRW_GET_EVENT: + + case IOCTL_DVD_READ_STRUCTURE: + + case IOCTL_CDRW_GET_DEVICE_NAME: + case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: + + case IOCTL_UDF_GET_RETRIEVAL_POINTERS: + case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS: + case IOCTL_UDF_GET_FILE_ALLOCATION_MODE: + case IOCTL_UDF_GET_VERSION: + case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED: + case IOCTL_UDF_SET_OPTIONS: +// case : + + case FSCTL_IS_VOLUME_DIRTY: + + UnsafeIoctl = FALSE; + break; +#ifdef EVALUATION_TIME_LIMIT + case IOCTL_CDRW_RESERVE_TRACK: + case IOCTL_CDRW_SET_STREAMING: + case IOCTL_CDRW_SYNC_CACHE: + case IOCTL_CDRW_BLANK: + case IOCTL_CDRW_LL_WRITE: + case IOCTL_CDRW_FORMAT_UNIT: + case IOCTL_CDRW_SET_WRITE_MODE: + case IOCTL_CDRW_CLOSE_TRK_SES: + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + KdPrint(("Unregistered version. IOCTL blocked\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + CompleteIrp = TRUE; + try_return(RC = STATUS_INVALID_PARAMETER); + } + break; +#endif //EVALUATION_TIME_LIMIT + } + + if(IoControlCode != IOCTL_CDROM_DISK_TYPE) { + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + } else { + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + } + AcquiredVcb = TRUE; + } + + KdPrint(("UDF Irp %x, ctx %x, DevIoCtl %x\n", Irp, PtrIrpContext, IoControlCode)); + + // We may wish to allow only volume open operations. + switch (IoControlCode) { + + case IOCTL_SCSI_PASS_THROUGH_DIRECT: + case IOCTL_SCSI_PASS_THROUGH: + + if(!Irp->AssociatedIrp.SystemBuffer) + goto ioctl_do_default; + + if(IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) { + Cdb = (PCDB)&(((PSCSI_PASS_THROUGH_DIRECT)(Irp->AssociatedIrp.SystemBuffer))->Cdb); + CdbData = (PCHAR)(((PSCSI_PASS_THROUGH_DIRECT)(Irp->AssociatedIrp.SystemBuffer))->DataBuffer); + } else { + Cdb = (PCDB)&(((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb); + if(((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->DataBufferOffset) { + CdbData = ((PCHAR)Cdb) + + ((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->DataBufferOffset; + } else { + CdbData = NULL; + } + } + ScsiCommand = Cdb->CDB6.OperationCode; + + if(ScsiCommand == SCSIOP_WRITE_CD) { + KdPrint(("Write10, LBA %2.2x%2.2x%2.2x%2.2x\n", + Cdb->WRITE_CD.LBA[0], + Cdb->WRITE_CD.LBA[1], + Cdb->WRITE_CD.LBA[2], + Cdb->WRITE_CD.LBA[3] + )); + } else + if(ScsiCommand == SCSIOP_WRITE12) { + KdPrint(("Write12, LBA %2.2x%2.2x%2.2x%2.2x\n", + Cdb->CDB12READWRITE.LBA[0], + Cdb->CDB12READWRITE.LBA[1], + Cdb->CDB12READWRITE.LBA[2], + Cdb->CDB12READWRITE.LBA[3] + )); + } else { + } + + switch(ScsiCommand) { + case SCSIOP_MODE_SELECT: { +// PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData; + ModeSelectData = CdbData+4; + switch(ModeSelectData[0]) { + case MODE_PAGE_MRW2: + case MODE_PAGE_WRITE_PARAMS: + case MODE_PAGE_MRW: + KdPrint(("Unsafe MODE_SELECT_6 via pass-through (%2.2x)\n", ModeSelectData[0])); + goto unsafe_direct_scsi_cmd; + } + break; } + + case SCSIOP_MODE_SELECT10: { +// PMODE_PARAMETER_HEADER10 ParamHdr = (PMODE_PARAMETER_HEADER10)CdbData; + ModeSelectData = CdbData+8; + switch(ModeSelectData[0]) { + case MODE_PAGE_MRW2: + case MODE_PAGE_WRITE_PARAMS: + case MODE_PAGE_MRW: + KdPrint(("Unsafe MODE_SELECT_10 via pass-through (%2.2x)\n", ModeSelectData[0])); + goto unsafe_direct_scsi_cmd; + } + break; } + + case SCSIOP_RESERVE_TRACK: + case SCSIOP_SEND_CUE_SHEET: + case SCSIOP_SEND_DVD_STRUCTURE: + case SCSIOP_CLOSE_TRACK_SESSION: + case SCSIOP_FORMAT_UNIT: + case SCSIOP_WRITE6: + case SCSIOP_WRITE_CD: + case SCSIOP_BLANK: + case SCSIOP_WRITE12: + case SCSIOP_SET_STREAMING: + KdPrint(("UDF Direct media modification via pass-through (%2.2x)\n", ScsiCommand)); +unsafe_direct_scsi_cmd: + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) + goto ioctl_do_default; + + KdPrint(("Forget this volume\n")); + // Acquire Vcb resource (Shared -> Exclusive) + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + UDFReleaseResource(&(Vcb->VCBResource)); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + } +#ifdef UDF_DELAYED_CLOSE + // Acquire exclusive access to the Vcb. + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + // allocate tmp buffer for FSD calls + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + + UDFDoDismountSequence(Vcb, Buf, FALSE); + MyFreePool__(Buf); + Buf = NULL; + Vcb->MediaLockCount = 0; + + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + + // Release the Vcb resource. + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + // disable Eject Request Waiter if any + UDFStopEjectWaiter(Vcb); + + // Make sure, that volume will never be quick-remounted + // It is very important for ChkUdf utility and + // some CD-recording libraries + Vcb->SerialNumber--; + + KdPrint(("Forgotten\n")); + + goto notify_media_change; + + case SCSIOP_START_STOP_UNIT: + case SCSIOP_DOORLOCK: + case SCSIOP_DOORUNLOCK: + case SCSIOP_MEDIUM_REMOVAL: + KdPrint(("UDF Medium/Tray control IOCTL via pass-through\n")); + } + goto ioctl_do_default; + + case IOCTL_CDRW_BLANK: + case IOCTL_CDRW_LL_WRITE: + case IOCTL_CDRW_FORMAT_UNIT: + +notify_media_change: +/* Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL; + // Make sure, that volume will never be quick-remounted + // It is very important for ChkUdf utility and + // some CD-recording libraries + Vcb->SerialNumber--; +*/ goto ioctl_do_default; + + case IOCTL_UDF_REGISTER_AUTOFORMAT: { + + KdPrint(("UDF Register Autoformat\n")); + if(UDFGlobalData.AutoFormatCount) { + RC = STATUS_SHARING_VIOLATION; + } else { + UDFGlobalData.AutoFormatCount = FileObject; + RC = STATUS_SUCCESS; + } + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + break; + } + + case IOCTL_UDF_DISABLE_DRIVER: { + + KdPrint(("UDF Disable driver\n")); + IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject); + // Now, delete any device objects, etc. we may have created + if (UDFGlobalData.UDFDeviceObject) { + IoDeleteDevice(UDFGlobalData.UDFDeviceObject); + UDFGlobalData.UDFDeviceObject = NULL; + } + + // free up any memory we might have reserved for zones/lookaside + // lists + if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_ZONES_INITIALIZED) { + UDFDestroyZones(); + } + + // delete the resource we may have initialized + if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_RESOURCE_INITIALIZED) { + // un-initialize this resource + UDFDeleteResource(&(UDFGlobalData.GlobalDataResource)); + UDFClearFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED); + } + RC = STATUS_SUCCESS; + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + break; + } + case IOCTL_UDF_INVALIDATE_VOLUMES: { + KdPrint(("UDF Invaidate volume\n")); + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + RC = UDFInvalidateVolumes( PtrIrpContext, Irp ); + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + break; + } + + case IOCTL_UDF_SET_NOTIFICATION_EVENT: + { + if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(HANDLE)) + { + RC = STATUS_INVALID_PARAMETER; + } + else + { + HANDLE MountEventHandle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; + if (MountEventHandle) + { + if (!UDFGlobalData.MountEvent) + { + RC = ObReferenceObjectByHandle( + MountEventHandle, + 0, + NULL, + UserMode, + (PVOID *) &UDFGlobalData.MountEvent, + NULL); + + if (!NT_SUCCESS(RC)) + { + UDFGlobalData.MountEvent = NULL; + } + } + else + { + RC = STATUS_INVALID_PARAMETER; + } + } + else + { + if (!UDFGlobalData.MountEvent) + { + RC = STATUS_INVALID_PARAMETER; + } + else + { + ObDereferenceObject(UDFGlobalData.MountEvent); + UDFGlobalData.MountEvent = NULL; + } + } + } + + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + break; + } + + case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED: + { + if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BOOLEAN)) + { + RC = STATUS_INVALID_PARAMETER; + } + else + { + *(PBOOLEAN)Irp->AssociatedIrp.SystemBuffer = Vcb->IsVolumeJustMounted; + Vcb->IsVolumeJustMounted = FALSE; + } + + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + break; + } + + + //case FSCTL_GET_RETRIEVAL_POINTERS + case IOCTL_UDF_GET_RETRIEVAL_POINTERS: { + KdPrint(("UDF: Get Retrieval Pointers\n")); + RC = UDFGetRetrievalPointers( PtrIrpContext, Irp, 0 ); + CompleteIrp = TRUE; + break; + } + case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS: { + KdPrint(("UDF: Get Spec Retrieval Pointers\n")); + PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN SpecRetrPointer; + SpecRetrPointer = (PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN)(Irp->AssociatedIrp.SystemBuffer); + RC = UDFGetRetrievalPointers( PtrIrpContext, Irp, SpecRetrPointer->Special ); + CompleteIrp = TRUE; + break; + } + case IOCTL_UDF_GET_FILE_ALLOCATION_MODE: { + KdPrint(("UDF: Get File Alloc mode (from ICB)\n")); + RC = UDFGetFileAllocModeFromICB( PtrIrpContext, Irp ); + CompleteIrp = TRUE; + break; + } +#ifndef UDF_READ_ONLY_BUILD + case IOCTL_UDF_SET_FILE_ALLOCATION_MODE: { + KdPrint(("UDF: Set File Alloc mode\n")); + RC = UDFSetFileAllocModeFromICB( PtrIrpContext, Irp ); + CompleteIrp = TRUE; + break; + } +#endif //UDF_READ_ONLY_BUILD + case IOCTL_UDF_LOCK_VOLUME_BY_PID: + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + RC = UDFLockVolume( PtrIrpContext, Irp, GetCurrentPID() ); + CompleteIrp = TRUE; + break; + case IOCTL_UDF_UNLOCK_VOLUME_BY_PID: + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + RC = UDFUnlockVolume( PtrIrpContext, Irp, GetCurrentPID() ); + CompleteIrp = TRUE; + break; +#ifndef UDF_READ_ONLY_BUILD + case IOCTL_UDF_SEND_LICENSE_KEY: +#ifdef EVALUATION_TIME_LIMIT + RC = UDFProcessLicenseKey( PtrIrpContext, Irp ); +#else //EVALUATION_TIME_LIMIT + RC = STATUS_SUCCESS; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; +#endif //EVALUATION_TIME_LIMIT + CompleteIrp = TRUE; + break; +#endif //UDF_READ_ONLY_BUILD + case IOCTL_UDF_GET_VERSION: { + + PUDF_GET_VERSION_OUT udf_ver; + + KdPrint(("UDFUserFsCtrlRequest: IOCTL_UDF_GET_VERSION\n")); + + Irp->IoStatus.Information = 0; + CompleteIrp = TRUE; + + if(!IrpSp->Parameters.DeviceIoControl.OutputBufferLength) { + KdPrint(("!OutputBufferLength\n")); + try_return(RC = STATUS_SUCCESS); + } + // Check the size of the output buffer. + if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UDF_GET_VERSION_OUT)) { + KdPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_VERSION_OUT))); + try_return(RC = STATUS_BUFFER_TOO_SMALL); + } + + udf_ver = (PUDF_GET_VERSION_OUT)(Irp->AssociatedIrp.SystemBuffer); + if(!udf_ver) { + KdPrint(("!udf_ver\n")); + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + + RtlZeroMemory(udf_ver, IrpSp->Parameters.DeviceIoControl.OutputBufferLength); + + udf_ver->header.Length = sizeof(UDF_GET_VERSION_OUT); + udf_ver->header.DriverVersionMj = 0x00010005; + udf_ver->header.DriverVersionMn = 0x12; + udf_ver->header.DriverVersionBuild = UDF_CURRENT_BUILD; + + udf_ver->FSVersionMj = Vcb->CurrentUDFRev >> 8; + udf_ver->FSVersionMn = Vcb->CurrentUDFRev & 0xff; + udf_ver->FSFlags = Vcb->UserFSFlags; + if( ((Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) && + (Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) + || + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ) { + KdPrint((" UDF_USER_FS_FLAGS_RO\n")); + udf_ver->FSFlags |= UDF_USER_FS_FLAGS_RO; + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) { + KdPrint((" UDF_USER_FS_FLAGS_OUR_DRIVER\n")); + udf_ver->FSFlags |= UDF_USER_FS_FLAGS_OUR_DRIVER; + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + KdPrint((" UDF_USER_FS_FLAGS_RAW\n")); + udf_ver->FSFlags |= UDF_USER_FS_FLAGS_RAW; + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { + KdPrint((" UDF_USER_FS_FLAGS_MEDIA_RO\n")); + udf_ver->FSFlags |= UDF_USER_FS_FLAGS_MEDIA_RO; + } + if(Vcb->FP_disc) { + KdPrint((" UDF_USER_FS_FLAGS_FP\n")); + udf_ver->FSFlags |= UDF_USER_FS_FLAGS_FP; + } + udf_ver->FSCompatFlags = Vcb->CompatFlags; + + udf_ver->FSCfgVersion = Vcb->CfgVersion; + + Irp->IoStatus.Information = sizeof(UDF_GET_VERSION_OUT); + RC = STATUS_SUCCESS; + CompleteIrp = TRUE; + + break; } + case IOCTL_UDF_SET_OPTIONS: { + + PUDF_SET_OPTIONS_IN udf_opt; + BOOLEAN PrevVerifyOnWrite; + + KdPrint(("UDF: IOCTL_UDF_SET_OPTIONS\n")); + + Irp->IoStatus.Information = 0; + CompleteIrp = TRUE; + + if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UDF_SET_OPTIONS_IN)) { + KdPrint(("InputBufferLength < %x\n", sizeof(UDF_SET_OPTIONS_IN))); + try_return(RC = STATUS_BUFFER_TOO_SMALL); + } + + udf_opt = (PUDF_SET_OPTIONS_IN)(Irp->AssociatedIrp.SystemBuffer); + if(!udf_opt) { + KdPrint(("!udf_opt\n")); + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + + if((udf_opt->header.Flags & UDF_SET_OPTIONS_FLAG_MASK) != UDF_SET_OPTIONS_FLAG_TEMPORARY) { + KdPrint(("invalid opt target\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + + PrevVerifyOnWrite = Vcb->VerifyOnWrite; + + Vcb->Cfg = ((PUCHAR)(udf_opt)) + udf_opt->header.HdrLength; + Vcb->CfgLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - offsetof(UDF_SET_OPTIONS_IN, Data); + UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE /*cfg*/); + Vcb->Cfg = NULL; + Vcb->CfgLength = 0; + Vcb->CfgVersion++; + //UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE); + if(PrevVerifyOnWrite != Vcb->VerifyOnWrite) { + if(Vcb->VerifyOnWrite) { + UDFVInit(Vcb); + } else { + WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); + UDFVFlush(Vcb); + UDFVRelease(Vcb); + } + } + + RC = STATUS_SUCCESS; + break; } +#if 0 + case IOCTL_UDF_GET_OPTIONS_VERSION: { + + PUDF_GET_OPTIONS_VERSION_OUT udf_opt_ver; + + KdPrint(("UDF: IOCTL_UDF_GET_OPTIONS_VERSION\n")); + + Irp->IoStatus.Information = 0; + CompleteIrp = TRUE; + + if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UDF_GET_OPTIONS_VERSION_OUT)) { + KdPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_OPTIONS_VERSION_OUT))); + try_return(RC = STATUS_BUFFER_TOO_SMALL); + } + + udf_opt_ver = (PUDF_GET_OPTIONS_VERSION_OUT)(Irp->AssociatedIrp.SystemBuffer); + if(!udf_opt_ver) { + KdPrint(("!udf_opt-ver\n")); + try_return(RC = STATUS_INVALID_USER_BUFFER); + } +/* + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; +*/ + udf_opt_ver->CfgVersion = Vcb->CfgVersion; + Irp->IoStatus.Information = sizeof(UDF_GET_OPTIONS_VERSION_OUT); + + RC = STATUS_SUCCESS; + break; } +#endif //0 + case IOCTL_CDRW_RESET_DRIVER: + + KdPrint(("UDF: IOCTL_CDRW_RESET_DRIVER\n")); + Vcb->MediaLockCount = 0; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED; + goto ioctl_do_default; + +#ifdef EVALUATION_TIME_LIMIT + case IOCTL_CDRW_GET_SIGNATURE: + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; +// CompleteIrp = TRUE; +// try_return(RC = STATUS_INVALID_PARAMETER); + } + goto ioctl_do_default; +#endif //EVALUATION_TIME_LIMIT + + case FSCTL_ALLOW_EXTENDED_DASD_IO: + + KdPrint(("UDFUserFsCtrlRequest: FSCTL_ALLOW_EXTENDED_DASD_IO\n")); + // DASD i/o is always permitted + // So, no-op this call + RC = STATUS_SUCCESS; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + CompleteIrp = TRUE; + break; + + case FSCTL_IS_VOLUME_DIRTY: + + KdPrint(("UDFUserFsCtrlRequest: FSCTL_IS_VOLUME_DIRTY\n")); + // DASD i/o is always permitted + // So, no-op this call + RC = UDFIsVolumeDirty(PtrIrpContext, Irp); + CompleteIrp = TRUE; + break; + + case IOCTL_STORAGE_EJECT_MEDIA: + case IOCTL_DISK_EJECT_MEDIA: + case IOCTL_CDROM_EJECT_MEDIA: { + + KdPrint(("UDF Reset/Eject request\n")); +// PPREVENT_MEDIA_REMOVAL_USER_IN Buf; + + if(Vcb->EjectWaiter) { + KdPrint((" Vcb->EjectWaiter present\n")); + Irp->IoStatus.Information = 0; + Vcb->EjectWaiter->SoftEjectReq = TRUE; + Vcb->SoftEjectReq = TRUE; + CompleteIrp = TRUE; + try_return(RC = STATUS_SUCCESS); + } + KdPrint((" !Vcb->EjectWaiter\n")); + goto ioctl_do_default; +/* + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + // Acquire Vcb resource (Shared -> Exclusive) + UDFReleaseResource(&(Vcb->VCBResource)); + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + + UDFDoDismountSequence(Vcb, Buf, IoControlCode == IOCTL_CDROM_EJECT_MEDIA); + // disable Eject Request Waiter if any + MyFreePool__(Buf); + // Release the Vcb resource. + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + UDFStopEjectWaiter(Vcb); + CompleteIrp = TRUE; + RC = STATUS_SUCCESS; + break;*/ + } + case IOCTL_CDROM_DISK_TYPE: { + + KdPrint(("UDF Cdrom Disk Type\n")); + CompleteIrp = TRUE; + // Verify the Vcb in this case to detect if the volume has changed. + Irp->IoStatus.Information = 0; + RC = UDFVerifyVcb(PtrIrpContext,Vcb); + if(!NT_SUCCESS(RC)) + try_return(RC); + + // Check the size of the output buffer. + if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_DISK_DATA_USER_OUT)) + try_return(RC = STATUS_BUFFER_TOO_SMALL); + + // Copy the data from the Vcb. + ((PCDROM_DISK_DATA_USER_OUT)(Irp->AssociatedIrp.SystemBuffer))->DiskData = CDROM_DISK_DATA_TRACK; + for(TrackNumber=Vcb->FirstTrackNum; TrackNumberLastTrackNum; TrackNumber++) { + if(Vcb->TrackMap[TrackNumber].TrackParam & Trk_QSubChan_Type_Mask == + Trk_QSubChan_Type_Audio) { + ((PCDROM_DISK_DATA_USER_OUT)(Irp->AssociatedIrp.SystemBuffer))->DiskData |= CDROM_DISK_AUDIO_TRACK; + break; + } + } + + Irp->IoStatus.Information = sizeof(CDROM_DISK_DATA_USER_OUT); + RC = STATUS_SUCCESS; + break; + } + + case IOCTL_CDRW_LOCK_DOOR: + case IOCTL_STORAGE_MEDIA_REMOVAL: + case IOCTL_DISK_MEDIA_REMOVAL: + case IOCTL_CDROM_MEDIA_REMOVAL: { + KdPrint(("UDF Lock/Unlock\n")); + PPREVENT_MEDIA_REMOVAL_USER_IN buffer; // user supplied buffer + buffer = (PPREVENT_MEDIA_REMOVAL_USER_IN)(Irp->AssociatedIrp.SystemBuffer); + if(!buffer) { + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + KdPrint(("!mounted\n")); + goto ioctl_do_default; + } + KdPrint(("abort\n")); + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + UnsafeIoctl = FALSE; + RC = STATUS_INVALID_PARAMETER; + break; + } + if(!buffer->PreventMediaRemoval && + !Vcb->MediaLockCount) { + + KdPrint(("!locked + unlock req\n")); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + KdPrint(("!mounted\n")); + goto ioctl_do_default; + } +#if 0 + // allocate tmp buffer for FSD calls + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + // Acquire Vcb resource (Shared -> Exclusive) + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + UDFReleaseResource(&(Vcb->VCBResource)); + +#ifdef UDF_DELAYED_CLOSE + // Acquire exclusive access to the Vcb. + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + + UDFDoDismountSequence(Vcb, Buf, FALSE); + MyFreePool__(Buf); + Buf = NULL; + Vcb->MediaLockCount = 0; + // Release the Vcb resource. + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + // disable Eject Request Waiter if any + UDFStopEjectWaiter(Vcb); +#else + // just ignore +#endif +ignore_lock: + KdPrint(("ignore lock/unlock\n")); + CompleteIrp = TRUE; + Irp->IoStatus.Information = 0; + RC = STATUS_SUCCESS; + break; + } + if(buffer->PreventMediaRemoval) { + KdPrint(("lock req\n")); + Vcb->MediaLockCount++; + Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_LOCKED; + UnsafeIoctl = FALSE; + } else { + KdPrint(("unlock req\n")); + if(Vcb->MediaLockCount) { + KdPrint(("lock count %d\n", Vcb->MediaLockCount)); + UnsafeIoctl = FALSE; + Vcb->MediaLockCount--; + } + } + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + KdPrint(("!mounted\n")); + goto ioctl_do_default; + } + goto ignore_lock; + } + default: + + KdPrint(("default processing Irp %x, ctx %x, DevIoCtl %x\n", Irp, PtrIrpContext, IoControlCode)); +ioctl_do_default: + + // make sure volume is Sync'ed BEFORE sending unsafe IOCTL + if(Vcb && UnsafeIoctl) { + UDFFlushLogicalVolume(NULL, NULL, Vcb, 0); + KdPrint((" sync'ed\n")); + } + // Invoke the lower level driver in the chain. + //PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp); + //*PtrNextIoStackLocation = *IrpSp; + IoSkipCurrentIrpStackLocation(Irp); +/* + // Set a completion routine. + IoSetCompletionRoutine(Irp, UDFDevIoctlCompletion, PtrIrpContext, TRUE, TRUE, TRUE); + // Send the request. +*/ + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + if(!CompleteIrp) { + // since now we do not use IoSetCompletionRoutine() + UDFReleaseIrpContext(PtrIrpContext); + } + break; + } + + if(Vcb && UnsafeIoctl) { + KdPrint((" set UnsafeIoctl\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + + if(Buf) { + MyFreePool__(Buf); + } + + if (!_SEH2_AbnormalTermination() && + CompleteIrp) { + KdPrint((" complete Irp %x, ctx %x, status %x, iolen %x\n", + Irp, PtrIrpContext, RC, Irp->IoStatus.Information)); + Irp->IoStatus.Status = RC; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + // Release the IRP context + UDFReleaseIrpContext(PtrIrpContext); + } + } _SEH2_END; + + return(RC); +} // end UDFCommonDeviceControl() + + +/************************************************************************* +* +* Function: UDFDevIoctlCompletion() +* +* Description: +* Completion routine. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFDevIoctlCompletion( + PDEVICE_OBJECT PtrDeviceObject, + PIRP Irp, + VOID *Context) +{ +/* PIO_STACK_LOCATION IrpSp = NULL; + ULONG IoControlCode = 0;*/ + PtrUDFIrpContext PtrIrpContext = (PtrUDFIrpContext)Context; + + KdPrint(("UDFDevIoctlCompletion Irp %x, ctx %x\n", Irp, Context)); + if (Irp->PendingReturned) { + KdPrint((" IoMarkIrpPending\n")); + IoMarkIrpPending(Irp); + } + + UDFReleaseIrpContext(PtrIrpContext); +/* if(Irp->IoStatus.Status == STATUS_SUCCESS) { + IrpSp = IoGetCurrentIrpStackLocation(Irp); + IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; + + switch(IoControlCode) { + case IOCTL_CDRW_RESET_DRIVER: { + Vcb->MediaLockCount = 0; + } + } + }*/ + + return STATUS_SUCCESS; +} // end UDFDevIoctlCompletion() + + +/************************************************************************* +* +* Function: UDFHandleQueryPath() +* +* Description: +* Handle the MUP request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +/*NTSTATUS UDFHandleQueryPath( +VOID *BufferPointer) +{ + NTSTATUS RC = STATUS_SUCCESS; + PQUERY_PATH_REQUEST RequestBuffer = (PQUERY_PATH_REQUEST)BufferPointer; + PQUERY_PATH_RESPONSE ReplyBuffer = (PQUERY_PATH_RESPONSE)BufferPointer; + ULONG LengthOfNameToBeMatched = RequestBuffer->PathNameLength; + ULONG LengthOfMatchedName = 0; + WCHAR *NameToBeMatched = RequestBuffer->FilePathName; + + KdPrint(("UDFHandleQueryPath\n")); + // So here we are. Simply check the name supplied. + // We can use whatever algorithm we like to determine whether the + // sent in name is acceptable. + // The first character in the name is always a "\" + // If we like the name sent in (probably, we will like a subset + // of the name), set the matching length value in LengthOfMatchedName. + + // if (FoundMatch) { + // ReplyBuffer->LengthAccepted = LengthOfMatchedName; + // } else { + // RC = STATUS_OBJECT_NAME_NOT_FOUND; + // } + + return(RC); +}*/ + +NTSTATUS +UDFGetFileAllocModeFromICB( + PtrUDFIrpContext IrpContext, + PIRP Irp + ) +{ + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PUDF_GET_FILE_ALLOCATION_MODE_OUT OutputBuffer; + + KdPrint(("UDFGetFileAllocModeFromICB\n")); + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + Irp->IoStatus.Information = 0; + if(IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT)) + return STATUS_BUFFER_TOO_SMALL; + + OutputBuffer = (PUDF_GET_FILE_ALLOCATION_MODE_OUT)(Irp->AssociatedIrp.SystemBuffer); + if(!OutputBuffer) + return STATUS_INVALID_USER_BUFFER; + + OutputBuffer->AllocMode = UDFGetFileICBAllocMode__(Fcb->FileInfo); + Irp->IoStatus.Information = sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT); + + return STATUS_SUCCESS; +} // end UDFGetFileAllocModeFromICB() + +#ifndef UDF_READ_ONLY_BUILD +NTSTATUS +UDFSetFileAllocModeFromICB( + PtrUDFIrpContext IrpContext, + PIRP Irp + ) +{ + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PUDF_SET_FILE_ALLOCATION_MODE_IN InputBuffer; + NTSTATUS RC; + UCHAR AllocMode; + + KdPrint(("UDFSetFileAllocModeFromICB\n")); + + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + Irp->IoStatus.Information = 0; + if(IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(UDF_SET_FILE_ALLOCATION_MODE_IN)) + return STATUS_BUFFER_TOO_SMALL; + + InputBuffer = (PUDF_SET_FILE_ALLOCATION_MODE_IN)(Irp->AssociatedIrp.SystemBuffer); + if(!InputBuffer) + return STATUS_INVALID_USER_BUFFER; + + UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0); + RC = Irp->IoStatus.Status; + if(!NT_SUCCESS(RC)) + return RC; + + if(InputBuffer->AllocMode != ICB_FLAG_AD_IN_ICB) { + AllocMode = UDFGetFileICBAllocMode__(Fcb->FileInfo); + if(AllocMode == ICB_FLAG_AD_IN_ICB) { + RC = UDFConvertFEToNonInICB(Vcb, Fcb->FileInfo, InputBuffer->AllocMode); + } else + if(AllocMode != InputBuffer->AllocMode) { + RC = STATUS_INVALID_PARAMETER; + } else { + RC = STATUS_SUCCESS; + } + } else { + RC = STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} // end UDFSetFileAllocModeFromICB() +#endif //UDF_READ_ONLY_BUILD + +#ifdef EVALUATION_TIME_LIMIT + +#define UDF_MD5Init UDF_MD5Init3 +#define UDF_MD5Update UDF_MD5Update3 +#define UDF_MD5Pad UDF_MD5Pad3 +#define UDF_MD5Final UDF_MD5Final3 +#define UDF_MD5End UDF_MD5End3 +#define UDF_MD5Transform UDF_MD5Transform3 +#define UDF_Encode UDF_Encode3 +#define UDF_Decode UDF_Decode3 +#define PADDING PADDING3 + +#define ROTATE_LEFT ROTATE_LEFT3 +#define FF FF3 +#define GG GG3 +#define HH HH3 +#define II II3 + +#define UDF_MD5Transform_dwords UDF_MD5Transform_dwords3 +#define UDF_MD5Transform_idx UDF_MD5Transform_idx3 +#define UDF_MD5Transform_Sxx UDF_MD5Transform_Sxx3 +#define UDF_MD5Rotate UDF_MD5Rotate3 + +#include "..\Include\md5.h" +#include "..\Include\md5c.c" + +#define UDF_FibonachiNum UDF_FibonachiNum3 +#define XPEHb XPEHb3 +#define UDF_build_long_key UDF_build_long_key3 +#define UDF_build_hash_by_key UDF_build_hash_by_key3 + +#include "..\Include\key_lib.h" +#include "..\Include\key_lib.cpp" + +extern ULONG UDFNumberOfKeys; +extern PCHAR pUDFLongKey; +extern PUDF_KEY_LIST pUDFKeyList; +extern PUCHAR pRegKeyName0; + +NTSTATUS +UDFProcessLicenseKey( + PtrUDFIrpContext IrpContext, + PIRP Irp + ) +{ + WCHAR RegPath[128]; + WCHAR RegKeyName[64]; + CHAR LicenseKey[16+1]; + WCHAR LicenseKeyW[16+1]; + HKEY hUdfRootKey; + NTSTATUS RC = STATUS_INVALID_USER_BUFFER; + + ULONG i, j; + int checksum[4] = {0,0,0,0}; + + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); +/* + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; +*/ + PUDF_KEY_LIST OutputBuffer; + + // Decode the file object, the only type of opens we accept are + // user volume opens. +/* + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; +*/ + Irp->IoStatus.Information = 0; + if(IrpSp->Parameters.FileSystemControl.InputBufferLength < 16) + return STATUS_BUFFER_TOO_SMALL; + if(IrpSp->Parameters.FileSystemControl.OutputBufferLength < 16) + return STATUS_BUFFER_TOO_SMALL; + + OutputBuffer = (PUDF_KEY_LIST)UDFGetCallersBuffer(Irp->AssociatedIrp.SystemBuffer); + if(!OutputBuffer) + return STATUS_INVALID_USER_BUFFER; + + // Build Registry Value name for License Key + for(i=0; i> 16)); + } + RegKeyName[i] = 0; + + RegTGetKeyHandle(NULL, UDFGlobalData.SavedRegPath.Buffer, &hUdfRootKey); + if(hUdfRootKey) { + if(!RegTGetStringValue(hUdfRootKey, NULL, + RegKeyName, LicenseKeyW, (16+1)*sizeof(WCHAR)) ) { + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + RegTCloseKeyHandle(hUdfRootKey); + } + LicenseKeyW[16] = 0; + // convert WCHAR Key to CHAR key + for(i=0; i<16; i++) { + LicenseKey[i] = (UCHAR)(LicenseKeyW[i]); + } + + // build hash + UDF_build_hash_by_key(pUDFLongKey, UDF_LONG_KEY_SIZE, (PCHAR)&(UDFGlobalData.CurrentKeyHash), LicenseKey); + // check if it is correct + for(i=0; i (UDF_MAX_DATE+TIME_JAN_1_2003) || + t2 < (UDF_MIN_DATE+TIME_JAN_1_2003)) { + KdPrint(("Eval time expired: %x <= %x <= %x\n", + UDF_MIN_DATE+TIME_JAN_1_2003, t2, UDF_MAX_DATE+TIME_JAN_1_2003)); + } else { + ULONG iTime; + ULONG iVer; + if(!UDFGetInstallVersion((PULONG)&iVer) || + !UDFGetInstallTime(&iTime)) { + KdPrint(("UDFGetInstallTime() or UDFGetInstallVersion() failed\n")); + } else + if(iVer > UDF_CURRENT_BUILD) { + KdPrint(("Init: Detected newer build\n")); + } else + if(UDFGetTrialEnd((PULONG)&iVer)) { + KdPrint(("UDFGetTrialEnd() read TRUE from Registry !!!\n")); + } else { + iTime += TIME_JAN_1_2003; + KdPrint(("cTime = %x, iTime = %x\n", t2, iTime)); + if((ULONG)t2 < (ULONG)iTime) { + KdPrint(("Eval time expired: System (%x) < Install (%x)\n", + t2, iTime)); + } else + if((ULONG)t2 > (ULONG)iTime + EVALUATION_TERM) { + KdPrint(("Eval time expired above EVALUATION_TERM: System (%x) > Install+Eval (%x)\n", + t2, iTime+EVALUATION_TERM)); + } else + if((iTime >> 2) & (0x80000000 >> 2)) { + KdPrint(("Eval time expired (negative install time)\n")); + } else { + j = 4; + } + } + KdPrint(("Eval time %s\n", j == 4 ? "ok" : "failed")); + //RC = STATUS_SUCCESS; + } + } + + UDFGlobalData.Saved_j = j; + + { + PIO_STACK_LOCATION IrpSp = NULL; + PVCB Vcb; + PLIST_ENTRY Link; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + // Walk through all of the Vcb's attached to the global data. + Link = UDFGlobalData.VCBQueue.Flink; + + while (Link != &(UDFGlobalData.VCBQueue)) { + // Get 'next' Vcb + Vcb = CONTAINING_RECORD( Link, VCB, NextVCB ); + // Move to the next link now + Link = Link->Flink; + ASSERT(Link != Link->Flink); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) { + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + if(j!=4) { + KdPrint(("DevCtl: unregistered\n")); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } else { + KdPrint(("DevCtl: registered :)\n")); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) { + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } + UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_UNREGISTERED; + } + UDFReleaseResource(&(Vcb->VCBResource)); + } + } + if(j == 4) { + KdPrint(("DevCtl: registered (2)\n")); + UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_UNREGISTERED; + } else { + KdPrint(("DevCtl: unregistered (2)\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + // Once we have processed all the mounted logical volumes, we can release + // all acquired global resources and leave (in peace :-) + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + } + + if(j == 4) { + KdPrint(("DevCtl: registered (3)\n")); + RtlCopyMemory(UDFGlobalData.LicenseKeyW, LicenseKeyW, 16*sizeof(WCHAR)); + UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_UNREGISTERED; + } else { + WCHAR s[16]; + ULONG type, sz; + ULONG d; + PVOID pdata; + NTSTATUS RC; + + KdPrint(("DevCtl: unregistered (3): Write BIAKAs to Registry\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + + // End of trial + d = 1 ^ XOR_VAR(TrialEnd, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_TRIAL_REG_KEY_NAME(RegPath, 0); + GET_TRIAL_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + d = 1 ^ XOR_VAR(TrialEnd, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_TRIAL_REG_KEY_NAME(RegPath, 1); + GET_TRIAL_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + // Install Date + if(!TrialEndOnStart) { + d = UDFGlobalData.iTime ^ XOR_VAR(Date, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_DATE_REG_KEY_NAME(RegPath, 0); + GET_DATE_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(DATE, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(DATE, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(DATE, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + if(PresentDateMask & (1 << 0)) { + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } + d = UDFGlobalData.iTime ^ XOR_VAR(Date, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_DATE_REG_KEY_NAME(RegPath, 1); + GET_DATE_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(DATE, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(DATE, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(DATE, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + if(PresentDateMask & (1 << 1)) { + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } + } + // Highest version + d = UDFGlobalData.iVer ^ XOR_VAR(Version, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_VERSION_REG_KEY_NAME(RegPath, 0); + GET_VERSION_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + d = UDFGlobalData.iVer ^ XOR_VAR(Version, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_VERSION_REG_KEY_NAME(RegPath, 1); + GET_VERSION_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } + return RC; +} // end UDFProcessLicenseKey() + +#endif //EVALUATION_TIME_LIMIT diff --git a/reactos/drivers/filesystems/udfs/dircntrl.cpp b/reactos/drivers/filesystems/udfs/dircntrl.cpp new file mode 100644 index 00000000000..6159058fd6a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/dircntrl.cpp @@ -0,0 +1,790 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: DirCntrl.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "directory control" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_DIR_CONTROL + +/* +// Local support routine(s): +*/ + +#define UDF_FNM_FLAG_CAN_BE_8D3 0x01 +#define UDF_FNM_FLAG_IGNORE_CASE 0x02 +#define UDF_FNM_FLAG_CONTAINS_WC 0x04 + +NTSTATUS UDFFindNextMatch( + IN PVCB Vcb, + IN PDIR_INDEX_HDR hDirIndex, + IN PLONG CurrentNumber, // Must be modified + IN PUNICODE_STRING PtrSearchPattern, + IN UCHAR FNM_Flags, + IN PHASH_ENTRY hashes, + OUT PDIR_INDEX_ITEM* _DirNdx); + +/************************************************************************* +* +* Function: UDFDirControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a directory control +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFDirControl( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFDirControl: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonDirControl(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFDirControl() + + + +/************************************************************************* +* +* Function: UDFCommonDirControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFCommonDirControl( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + BOOLEAN AcquiredVcb = FALSE; + + TmPrint(("UDFCommonDirControl: \n")); +// BrutePoint(); + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(Vcb); + ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); +// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + UDFFlushTryBreak(Vcb); + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVcb = TRUE; + // Get some of the parameters supplied to us + switch (IrpSp->MinorFunction) { + case IRP_MN_QUERY_DIRECTORY: + RC = UDFQueryDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb); + break; + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + RC = UDFNotifyChangeDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb); + break; + default: + // This should not happen. + RC = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + +//try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVcb = FALSE; + } + } _SEH2_END; + return(RC); +} // end UDFCommonDirControl() + + +/************************************************************************* +* +* Function: UDFQueryDirectory() +* +* Description: +* Query directory request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFQueryDirectory( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PIO_STACK_LOCATION IrpSp, + PFILE_OBJECT FileObject, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN PostRequest = FALSE; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN CanWait = FALSE; + PVCB Vcb = NULL; + BOOLEAN AcquiredFCB = FALSE; + unsigned long BufferLength = 0; + UNICODE_STRING SearchPattern; + PUNICODE_STRING PtrSearchPattern; + FILE_INFORMATION_CLASS FileInformationClass; + BOOLEAN ReturnSingleEntry = FALSE; + PUCHAR Buffer = NULL; + BOOLEAN FirstTimeQuery = FALSE; + LONG NextMatch; + LONG PrevMatch = -1; + ULONG CurrentOffset; + ULONG BaseLength; + ULONG FileNameBytes; + ULONG Information = 0; + ULONG LastOffset = 0; + BOOLEAN AtLeastOneFound = FALSE; + PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp; + PUDF_FILE_INFO DirFileInfo = NULL; + PDIR_INDEX_HDR hDirIndex = NULL; + PFILE_BOTH_DIR_INFORMATION DirInformation = NULL; // Returned from udf_info module + PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; // Pointer in callers buffer + PFILE_NAMES_INFORMATION NamesInfo; + ULONG BytesRemainingInBuffer; + UCHAR FNM_Flags = 0; + PHASH_ENTRY cur_hashes = NULL; + PDIR_INDEX_ITEM DirNdx; + // do some pre-init... + SearchPattern.Buffer = NULL; + + KdPrint(("UDFQueryDirectory: @=%#x\n", &PtrIrpContext)); + +#define CanBe8dot3 (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3) +#define IgnoreCase (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE) +#define ContainsWC (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC) + + _SEH2_TRY + { + + // Validate the sent-in FCB + if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // We will only allow notify requests on directories. + try_return(RC = STATUS_INVALID_PARAMETER); + } + + // Obtain the callers parameters + NtReqFcb = Fcb->NTRequiredFCB; + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + Vcb = Fcb->Vcb; + //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? 0 : UDF_FNM_FLAG_IGNORE_CASE; + DirFileInfo = Fcb->FileInfo; + BufferLength = pStackLocation->Parameters.QueryDirectory.Length; + + // If the caller does not want to block, it would be easier to + // simply post the request now. + if (!CanWait) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + // Continue obtaining the callers parameters... + if(IgnoreCase && pStackLocation->Parameters.QueryDirectory.FileName) { + PtrSearchPattern = &SearchPattern; + if(!NT_SUCCESS(RC = RtlUpcaseUnicodeString(PtrSearchPattern, (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName), TRUE))) + try_return(RC); + } else { + PtrSearchPattern = (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName); + } + FileInformationClass = pStackLocation->Parameters.QueryDirectory.FileInformationClass; + + // Calculate baselength (without name) for each InfoClass + switch (FileInformationClass) { + + case FileDirectoryInformation: + BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); + break; + case FileFullDirectoryInformation: + BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); + break; + case FileNamesInformation: + BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); + break; + case FileBothDirectoryInformation: + BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); + break; + default: + try_return(RC = STATUS_INVALID_INFO_CLASS); + } + + // Some additional arguments that affect the FSD behavior + ReturnSingleEntry = (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) ? TRUE : FALSE; + + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceShared(&(NtReqFcb->MainResource), TRUE); + AcquiredFCB = TRUE; + + // We must determine the buffer pointer to be used. Since this + // routine could either be invoked directly in the context of the + // calling thread, or in the context of a worker thread, here is + // a general way of determining what we should use. + if(Irp->MdlAddress) { + Buffer = (PUCHAR) MmGetSystemAddressForMdlSafer(Irp->MdlAddress); + if(!Buffer) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } else { + Buffer = (PUCHAR) Irp->UserBuffer; + if(!Buffer) + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + + // The method of determining where to look from and what to look for is + // unfortunately extremely confusing. However, here is a methodology + // we broadly adopt: + // (a) We have to maintain a search buffer per CCB structure. + // (b) This search buffer is initialized the very first time + // a query directory operation is performed using the file object. + // (For the UDF FSD, the search buffer is stored in the + // DirectorySearchPattern field) + // However, the caller still has the option of "overriding" this stored + // search pattern by supplying a new one in a query directory operation. + if(PtrSearchPattern && + PtrSearchPattern->Buffer && + !(PtrSearchPattern->Buffer[PtrSearchPattern->Length/sizeof(WCHAR) - 1])) { + PtrSearchPattern->Length -= sizeof(WCHAR); + } + + if(IrpSp->Flags & SL_INDEX_SPECIFIED) { + // Good idea from M$: we should continue search from NEXT item + // when FileIndex specified... + // Strange idea from M$: we should do it with EMPTY pattern... + PtrSearchPattern = NULL; + Ccb->CCBFlags |= UDF_CCB_MATCH_ALL; + } else if(PtrSearchPattern && + PtrSearchPattern->Buffer && + !UDFIsMatchAllMask(PtrSearchPattern, NULL) ) { + + Ccb->CCBFlags &= ~(UDF_CCB_MATCH_ALL | + UDF_CCB_WILDCARD_PRESENT | + UDF_CCB_CAN_BE_8_DOT_3); + // Once we have validated the search pattern, we must + // check whether we need to store this search pattern in + // the CCB. + if(Ccb->DirectorySearchPattern) { + MyFreePool__(Ccb->DirectorySearchPattern->Buffer); + MyFreePool__(Ccb->DirectorySearchPattern); + Ccb->DirectorySearchPattern = NULL; + } + // This must be the very first query request. + FirstTimeQuery = TRUE; + + // Now, allocate enough memory to contain the caller + // supplied search pattern and fill in the DirectorySearchPattern + // field in the CCB + Ccb->DirectorySearchPattern = (PUNICODE_STRING)MyAllocatePool__(NonPagedPool,sizeof(UNICODE_STRING)); + if(!(Ccb->DirectorySearchPattern)) { + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + Ccb->DirectorySearchPattern->Length = PtrSearchPattern->Length; + Ccb->DirectorySearchPattern->MaximumLength = PtrSearchPattern->MaximumLength; + Ccb->DirectorySearchPattern->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool,PtrSearchPattern->MaximumLength); + if(!(Ccb->DirectorySearchPattern->Buffer)) { + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + RtlCopyMemory(Ccb->DirectorySearchPattern->Buffer,PtrSearchPattern->Buffer, + PtrSearchPattern->MaximumLength); + if(FsRtlDoesNameContainWildCards(PtrSearchPattern)) { + Ccb->CCBFlags |= UDF_CCB_WILDCARD_PRESENT; + } else { + UDFBuildHashEntry(Vcb, PtrSearchPattern, cur_hashes = &(Ccb->hashes), HASH_POSIX | HASH_ULFN); + } + if(UDFCanNameBeA8dot3(PtrSearchPattern)) + Ccb->CCBFlags |= UDF_CCB_CAN_BE_8_DOT_3; + + } else if(!Ccb->DirectorySearchPattern && + !(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) ) { + + // If the filename is not specified or is a single '*' then we will + // match all names. + FirstTimeQuery = TRUE; + PtrSearchPattern = NULL; + Ccb->CCBFlags |= UDF_CCB_MATCH_ALL; + + } else { + // The caller has not supplied any search pattern that we are + // forced to use. However, the caller had previously supplied + // a pattern (or we must have invented one) and we will use it. + // This is definitely not the first query operation on this + // directory using this particular file object. + if(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) { + PtrSearchPattern = NULL; +/* if(Ccb->CurrentIndex) + Ccb->CurrentIndex++;*/ + } else { + PtrSearchPattern = Ccb->DirectorySearchPattern; + if(!(Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT)) { + cur_hashes = &(Ccb->hashes); + } + } + } + + if(IrpSp->Flags & SL_INDEX_SPECIFIED) { + // Caller has told us wherefrom to begin. + // We may need to round this to an appropriate directory entry + // entry alignment value. + NextMatch = pStackLocation->Parameters.QueryDirectory.FileIndex + 1; + } else if(IrpSp->Flags & SL_RESTART_SCAN) { + NextMatch = 0; + } else { + // Get the starting offset from the CCB. + // Remember to update this value on our way out from this function. + // But, do not update the CCB CurrentByteOffset field if our reach + // the end of the directory (or get an error reading the directory) + // while performing the search. + NextMatch = Ccb->CurrentIndex + 1; // Last good index + } + + FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT) ? UDF_FNM_FLAG_CONTAINS_WC : 0; + // this is used only when mask is supplied + FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CAN_BE_8_DOT_3) ? UDF_FNM_FLAG_CAN_BE_8D3 : 0; + + // This is an additional verifying + if(!UDFIsADirectory(DirFileInfo)) { + try_return(RC = STATUS_INVALID_PARAMETER); + } + + hDirIndex = DirFileInfo->Dloc->DirIndex; + if(!hDirIndex) { + try_return(RC = STATUS_INVALID_PARAMETER); + } + + RC = STATUS_SUCCESS; + // Allocate buffer enough to save both DirInformation and FileName + DirInformation = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool, + sizeof(FILE_BOTH_DIR_INFORMATION)+((ULONG)UDF_NAME_LEN*sizeof(WCHAR)) ); + if(!DirInformation) { + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + CurrentOffset=0; + BytesRemainingInBuffer = pStackLocation->Parameters.QueryDirectory.Length; + RtlZeroMemory(Buffer,BytesRemainingInBuffer); + + if((!FirstTimeQuery) && !UDFDirIndex(hDirIndex, (uint_di)NextMatch) ) { + try_return( RC = STATUS_NO_MORE_FILES); + } + + // One final note though: + // If we do not find a directory entry OR while searching we reach the + // end of the directory, then the return code should be set as follows: + + // (a) If any files have been returned (i.e. ReturnSingleEntry was FALSE + // and we did find at least one match), then return STATUS_SUCCESS + // (b) If no entry is being returned then: + // (i) If this is the first query i.e. FirstTimeQuery is TRUE + // then return STATUS_NO_SUCH_FILE + // (ii) Otherwise, return STATUS_NO_MORE_FILES + + while(TRUE) { + // If the user had requested only a single match and we have + // returned that, then we stop at this point. + if(ReturnSingleEntry && AtLeastOneFound) { + try_return(RC); + } + // We call UDFFindNextMatch to look down the next matching dirent. + RC = UDFFindNextMatch(Vcb, hDirIndex,&NextMatch,PtrSearchPattern, FNM_Flags, cur_hashes, &DirNdx); + // If we didn't receive next match, then we are at the end of the + // directory. If we have returned any files, we exit with + // success, otherwise we return STATUS_NO_MORE_FILES. + if(!NT_SUCCESS(RC)) { + RC = AtLeastOneFound ? STATUS_SUCCESS : + (FirstTimeQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES); + try_return(RC); + } + // We found at least one matching file entry + AtLeastOneFound = TRUE; + if(!NT_SUCCESS(RC = UDFFileDirInfoToNT(Vcb, DirNdx, DirInformation))) { + // this happends when we can't allocate tmp buffers + try_return(RC); + } + DirInformation->FileIndex = NextMatch; + FileNameBytes = DirInformation->FileNameLength; + + if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) { + // We haven't successfully transfered current data & + // later NextMatch will be incremented. Thus we should + // prevent loosing information in such a way: + if(NextMatch) NextMatch --; + // If this won't fit and we have returned a previous entry then just + // return STATUS_SUCCESS. Otherwise + // use a status code of STATUS_BUFFER_OVERFLOW. + if(CurrentOffset) { + try_return(RC = STATUS_SUCCESS); + } + // strange policy... + ReturnSingleEntry = TRUE; + FileNameBytes = BaseLength + FileNameBytes - BytesRemainingInBuffer; + RC = STATUS_BUFFER_OVERFLOW; + } + // Now we have an entry to return to our caller. + // We'll case on the type of information requested and fill up + // the user buffer if everything fits. + switch (FileInformationClass) { + + case FileBothDirectoryInformation: + case FileFullDirectoryInformation: + case FileDirectoryInformation: + + BothDirInformation = (PFILE_BOTH_DIR_INFORMATION)(Buffer + CurrentOffset); + RtlCopyMemory(BothDirInformation,DirInformation,BaseLength); + BothDirInformation->FileIndex = NextMatch; + BothDirInformation->FileNameLength = FileNameBytes; + break; + + case FileNamesInformation: + + NamesInfo = (PFILE_NAMES_INFORMATION)(Buffer + CurrentOffset); + NamesInfo->FileIndex = NextMatch; + NamesInfo->FileNameLength = FileNameBytes; + break; + } + if (FileNameBytes) { + // This is a Unicode name, we can copy the bytes directly. + RtlCopyMemory( (PVOID)(Buffer + CurrentOffset + BaseLength), + DirInformation->FileName, FileNameBytes ); + } + + Information = CurrentOffset + BaseLength + FileNameBytes; + + // ((..._INFORMATION)(PointerToPreviousEntryInBuffer))->NextEntryOffset = CurrentOffset - LastOffset; + *((PULONG)(Buffer+LastOffset)) = CurrentOffset - LastOffset; + // Set up our variables for the next dirent. + FirstTimeQuery = FALSE; + + LastOffset = CurrentOffset; + PrevMatch = NextMatch; + NextMatch++; + CurrentOffset = UDFQuadAlign(Information); + BytesRemainingInBuffer = BufferLength - CurrentOffset; + } + +try_exit: NOTHING; + + + } _SEH2_FINALLY { + + if (PostRequest) { + + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + } + // Map the users buffer and then post the request. + RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, BufferLength); + ASSERT(NT_SUCCESS(RC)); + + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else { +#ifdef UDF_DBG + if(!NT_SUCCESS(RC)) { + KdPrint((" Not found\n")); + } +#endif // UDF_DBG + // Remember to update the CurrentByteOffset field in the CCB if required. + if(Ccb) Ccb->CurrentIndex = PrevMatch; + + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + } + if (!_SEH2_AbnormalTermination()) { + // complete the IRP + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = Information; + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + } + } + + if(SearchPattern.Buffer) RtlFreeUnicodeString(&SearchPattern); + if(DirInformation) MyFreePool__(DirInformation); + } _SEH2_END; + + return(RC); +} // end UDFQueryDirectory() + +/* + Return: STATUS_NO_SUCH_FILE if no more files found +*/ +NTSTATUS +UDFFindNextMatch( + IN PVCB Vcb, + IN PDIR_INDEX_HDR hDirIndex, + IN PLONG CurrentNumber, // Must be modified in case, when we found next match + IN PUNICODE_STRING PtrSearchPattern, + IN UCHAR FNM_Flags, + IN PHASH_ENTRY hashes, + OUT PDIR_INDEX_ITEM* _DirNdx + ) +{ + LONG EntryNumber = (*CurrentNumber); + PDIR_INDEX_ITEM DirNdx; + +#define CanBe8dot3 (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3) +#define IgnoreCase (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE) +#define ContainsWC (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC) + + for(;DirNdx = UDFDirIndex(hDirIndex, EntryNumber);EntryNumber++) { + if(!DirNdx->FName.Buffer || + UDFIsDeleted(DirNdx)) + continue; + if(hashes && + (DirNdx->hashes.hLfn != hashes->hLfn) && + (DirNdx->hashes.hPosix != hashes->hPosix) && + (!CanBe8dot3 || ((DirNdx->hashes.hDos != hashes->hLfn) && (DirNdx->hashes.hDos != hashes->hPosix))) ) + continue; + if(UDFIsNameInExpression(Vcb, &(DirNdx->FName),PtrSearchPattern, NULL,IgnoreCase, + ContainsWC, CanBe8dot3 && !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS), + EntryNumber < 2) && + !(DirNdx->FI_Flags & UDF_FI_FLAG_FI_INTERNAL)) + break; + } + + if(DirNdx) { + // Modify CurrentNumber to appropriate value + *CurrentNumber = EntryNumber; + *_DirNdx = DirNdx; + return STATUS_SUCCESS; + } else { + // Do not modify CurrentNumber because we have not found next match entry + return STATUS_NO_MORE_FILES; + } +} // end UDFFindNextMatch() + +/************************************************************************* +* +* Function: UDFNotifyChangeDirectory() +* +* Description: +* Handle the notify request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFNotifyChangeDirectory( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PIO_STACK_LOCATION IrpSp, + PFILE_OBJECT FileObject, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN CompleteRequest = FALSE; + BOOLEAN PostRequest = FALSE; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN CanWait = FALSE; + ULONG CompletionFilter = 0; + BOOLEAN WatchTree = FALSE; + PVCB Vcb = NULL; + BOOLEAN AcquiredFCB = FALSE; + PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp; + + KdPrint(("UDFNotifyChangeDirectory\n")); + + _SEH2_TRY { + + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + CompleteRequest = TRUE; + try_return(RC = STATUS_INVALID_PARAMETER); + } + + NtReqFcb = Fcb->NTRequiredFCB; + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + Vcb = Fcb->Vcb; + + // Acquire the FCB resource shared + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + + // If the file is marked as DELETE_PENDING then complete this + // request immediately. + if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { + ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + try_return(RC = STATUS_DELETE_PENDING); + } + + // Obtain some parameters sent by the caller + CompletionFilter = pStackLocation ->Parameters.NotifyDirectory.CompletionFilter; + WatchTree = (IrpSp->Flags & SL_WATCH_TREE) ? TRUE : FALSE; + + // If we wish to capture the subject context, we can do so as + // follows: + // { + // PSECURITY_SUBJECT_CONTEXT SubjectContext; + // SubjectContext = MyAllocatePool__(PagedPool, + // sizeof(SECURITY_SUBJECT_CONTEXT)); + // SeCaptureSubjectContext(SubjectContext); + // } + + FsRtlNotifyFullChangeDirectory(Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb, + (Fcb->FileInfo->ParentFile) ? (PSTRING)&(Fcb->FCBName->ObjectName) : (PSTRING)&(UDFGlobalData.UnicodeStrRoot), + WatchTree, FALSE, CompletionFilter, Irp, + NULL, // UDFTraverseAccessCheck(...) ? + NULL); // SubjectContext ? + + RC = STATUS_PENDING; + + try_exit: NOTHING; + + } _SEH2_FINALLY { + + if (PostRequest) { + // Perform appropriate related post processing here + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + RC = UDFPostRequest(PtrIrpContext, Irp); + } else if (CompleteRequest) { + + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } else { + // Simply free up the IrpContext since the IRP has been queued + if (!_SEH2_AbnormalTermination()) + UDFReleaseIrpContext(PtrIrpContext); + } + + // Release the FCB resources if acquired. + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + + } _SEH2_END; + + return(RC); +} // end UDFNotifyChangeDirectory() diff --git a/reactos/drivers/filesystems/udfs/dldetect.cpp b/reactos/drivers/filesystems/udfs/dldetect.cpp new file mode 100644 index 00000000000..dfd9c92dcea --- /dev/null +++ b/reactos/drivers/filesystems/udfs/dldetect.cpp @@ -0,0 +1,484 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module Name: + + DLDetect.cpp + + Abstract: + + This file contains all source code related to DeadLock Detector. + + Environment: + + NT Kernel Mode + +*/ + +#include "udffs.h" + +/// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_DLD + + +/// Resource event (ExclusiveWaiters) +#define RESOURCE_EVENT_TAG 'vEeR' +/// Resource semaphore (SharedWaiters) +#define RESOURCE_SEMAFORE_TAG 'eSeR' +/// Resource owner table (OwnerTable) +#define RESOURCE_TABLE_TAG 'aTeR' + +/// Maxmum recurse level while exploring thread-resource aquisition graf +#define DLD_MAX_REC_LEVEL 40 + +/// Maximum supported number of threads (initialized by DLDInit()) +ULONG MaxThreadCount = 0; + +/// Waiters table +PTHREAD_STRUCT DLDThreadTable; +/// 4 sec +LARGE_INTEGER DLDpTimeout; +/// 8 sec +ULONG DLDpResourceTimeoutCount = 0x2; + +THREAD_REC_BLOCK DLDThreadAcquireChain[DLD_MAX_REC_LEVEL]; + +/// Initialize deadlock detector +VOID DLDInit(ULONG MaxThrdCount /// Maximum supported number of threads +) { + if (*KeNumberProcessors>1) { + KdPrint(("Deadlock Detector is designed for uniprocessor machines only!\n")); + BrutePoint(); + } + DLDpTimeout.QuadPart = -40000000I64; + + MaxThreadCount = MaxThrdCount; + DLDThreadTable = (PTHREAD_STRUCT) DLDAllocatePool(MaxThreadCount*sizeof(THREAD_STRUCT)); + RtlZeroMemory(DLDThreadTable, sizeof(THREAD_STRUCT)*MaxThreadCount); +} + +VOID DLDFree(VOID) { + + DLDFreePool(DLDThreadTable); + +} + +PTHREAD_STRUCT DLDAllocFindThread(ULONG ThreadId) { + ULONG i = 0; + PTHREAD_STRUCT Temp = DLDThreadTable; + ULONG FirstEmpty = -1; + + while (iThreadId == ThreadId) { + return Temp; + } else if (FirstEmpty == -1 && !Temp->ThreadId) { + FirstEmpty = i; + } + Temp++; + i++; + } + // Not found. Allocate new one. + if (i == MaxThreadCount) { + if (FirstEmpty == -1) { + KdPrint(("Not enough table entries. Try to increase MaxThrdCount on next build")); + BrutePoint(); + } + i = FirstEmpty; + } + Temp = DLDThreadTable + i; + + RtlZeroMemory(Temp, sizeof(THREAD_STRUCT)); + Temp->ThreadId = ThreadId; + + return Temp; +} + +PTHREAD_STRUCT DLDFindThread(ULONG ThreadId) { + ULONG i = 0; + PTHREAD_STRUCT Temp = DLDThreadTable; + ULONG FirstEmpty = -1; + + + while (iThreadId == ThreadId) { + return Temp; + } + Temp++; + i++; + } + + return NULL; +} + +BOOLEAN DLDProcessResource(PERESOURCE Resource, + PTHREAD_STRUCT ThrdStruct, + ULONG RecLevel); + + +/// TRUE Indicates deadlock +BOOLEAN DLDProcessThread(PTHREAD_STRUCT ThrdOwner, + PTHREAD_STRUCT ThrdStruct, + PERESOURCE Resource, + ULONG RecLevel) { + + if (ThrdOwner == ThrdStruct) { + // ERESOURCE wait cycle. Deadlock detected. + KdPrint(("DLD: *********DEADLOCK DETECTED*********\n")); + KdPrint(("Thread %x holding resource %x\n",ThrdOwner->ThreadId,Resource)); + return TRUE; + } + + for (int i=RecLevel+1;iThreadId == ThrdOwner->ThreadId) { + // ERESOURCE wait cycle. Deadlock detected. + KdPrint(("DLD: *********DEADLOCK DETECTED*********\n")); + KdPrint(("Thread %x holding resource %x\n",ThrdOwner->ThreadId,Resource)); + for (int j=RecLevel+1;j<=i;j++) { + KdPrint((" awaited by thread %x at (BugCheckId:%x:Line:%d) holding resource %x\n", + DLDThreadAcquireChain[i].Thread->ThreadId, + DLDThreadAcquireChain[i].Thread->BugCheckId, + DLDThreadAcquireChain[i].Thread->Line, + Resource)); + } + BrutePoint(); + return FALSE; + } + } + DLDThreadAcquireChain[RecLevel].Thread = ThrdOwner; + DLDThreadAcquireChain[RecLevel].HoldingResource = Resource; + + // Find resource, awaited by thread + if (ThrdOwner->WaitingResource) { + if (DLDProcessResource(ThrdOwner->WaitingResource, ThrdStruct,RecLevel)) { + KdPrint((" awaited by thread %x at (BugCheckId:%x:Line:%d) holding resource %x\n", + ThrdOwner->ThreadId, + ThrdOwner->BugCheckId, + ThrdOwner->Line, + Resource)); + return TRUE; + } + } + + return FALSE; +} + + +/// TRUE Indicates deadlock +BOOLEAN DLDProcessResource( PERESOURCE Resource, // resource to process + PTHREAD_STRUCT ThrdStruct, // thread structure of caller's thread + ULONG RecLevel) // current recurse level +{ + if (RecLevel <= 0) { + BrutePoint(); + return FALSE; + } + + + // If resource is free, just return. Not possible, but we must check. + if (!Resource->ActiveCount) { + return FALSE; + } + + PTHREAD_STRUCT ThreadOwner; + + + if (Resource->Flag & ResourceOwnedExclusive || (Resource->OwnerThreads[1].OwnerCount == 1)) { + + // If only one owner + + // Find thread owning this resource + if (Resource->Flag & ResourceOwnedExclusive) { + ThreadOwner = DLDFindThread(Resource->OwnerThreads[0].OwnerThread); + } else { + ThreadOwner = DLDFindThread(Resource->OwnerThreads[1].OwnerThread); + } + + BOOLEAN Result = FALSE; + if (ThreadOwner) { + Result = DLDProcessThread(ThreadOwner, ThrdStruct, Resource,RecLevel-1); + } + return Result; + } else { + // Many owners + int i; + for (i=0; iOwnerThreads[0].TableSize; i++) { + if (Resource->OwnerTable[i].OwnerThread) { + + ThreadOwner = DLDFindThread(Resource->OwnerTable[i].OwnerThread); + if (ThreadOwner && DLDProcessThread(ThreadOwner, ThrdStruct, Resource,RecLevel-1)) { + + return TRUE; + } + } + } + } + + return FALSE; +} + + + +VOID DLDpWaitForResource( + IN PERESOURCE Resource, + IN DISPATCHER_HEADER *DispatcherObject, + IN PTHREAD_STRUCT ThrdStruct + ) { + KIRQL oldIrql; + ULONG ResourceWaitCount = 0; + + Resource->ContentionCount++; + + while (KeWaitForSingleObject(DispatcherObject,Executive,KernelMode,FALSE,&DLDpTimeout) == STATUS_TIMEOUT) { + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql); + if (++ResourceWaitCount>DLDpResourceTimeoutCount) { + // May be deadlock? + ResourceWaitCount = 0; + + if (DLDProcessResource(Resource, ThrdStruct,DLD_MAX_REC_LEVEL)) { + KdPrint((" which thread %x has tried to acquire at (BugCheckId:%x:Line:%d)\n", + ThrdStruct->ThreadId, + ThrdStruct->BugCheckId, + ThrdStruct->Line + )); + BrutePoint(); + } + } + // Priority boosts + // ..... + // End of priority boosts + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + } + +} + + + + +VOID DLDpAcquireResourceExclusiveLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD Thread, + IN KIRQL oldIrql, + IN ULONG BugCheckId, + IN ULONG Line + ) { + KIRQL oldIrql2; + + if (!(Resource->ExclusiveWaiters)) { + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql2); + + // If ExclusiveWaiters Event not yet allocated allocate new one + if (!(Resource->ExclusiveWaiters)) { + Resource->ExclusiveWaiters = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT),RESOURCE_EVENT_TAG); + KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,FALSE); + } + KeReleaseSpinLock(&Resource->SpinLock, oldIrql2); + DLDAcquireExclusive(Resource,BugCheckId,Line); + + } else { + Resource->NumberOfExclusiveWaiters++; + + PTHREAD_STRUCT ThrdStruct = DLDAllocFindThread(Thread); + + + // Set WaitingResource for current thread + ThrdStruct->WaitingResource = Resource; + ThrdStruct->BugCheckId = BugCheckId; + ThrdStruct->Line = Line; + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + + DLDpWaitForResource(Resource,&(Resource->ExclusiveWaiters->Header),ThrdStruct); + + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql); + + ThrdStruct->WaitingResource = NULL; + ThrdStruct->ThreadId = 0; + ThrdStruct->BugCheckId = 0; + ThrdStruct->Line = 0; + Resource->OwnerThreads[0].OwnerThread = Thread; + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + } +} + + + + +VOID DLDAcquireExclusive(PERESOURCE Resource, + ULONG BugCheckId, + ULONG Line +) { + + KIRQL oldIrql; + + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql); + + ERESOURCE_THREAD Thread = (ERESOURCE_THREAD)PsGetCurrentThread(); + + if (!Resource->ActiveCount) goto SimpleAcquire; + if ((Resource->Flag & ResourceOwnedExclusive) && Resource->OwnerThreads[0].OwnerThread == Thread) { + Resource->OwnerThreads[0].OwnerCount++; + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + return; + } + + DLDpAcquireResourceExclusiveLite(Resource, Thread, oldIrql,BugCheckId,Line); + return; + +SimpleAcquire: + + Resource->Flag |= ResourceOwnedExclusive; + Resource->ActiveCount = 1; + Resource->OwnerThreads[0].OwnerThread = Thread; + Resource->OwnerThreads[0].OwnerCount = 1; + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); +} + + +POWNER_ENTRY DLDpFindCurrentThread( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD Thread + ) { + + if (Resource->OwnerThreads[0].OwnerThread == Thread) return &(Resource->OwnerThreads[0]); + if (Resource->OwnerThreads[1].OwnerThread == Thread) return &(Resource->OwnerThreads[1]); + + POWNER_ENTRY LastEntry, CurrentEntry, FirstEmptyEntry = NULL; + if (!(Resource->OwnerThreads[1].OwnerThread)) FirstEmptyEntry = &(Resource->OwnerThreads[1]); + + CurrentEntry = Resource->OwnerTable; + LastEntry = &(Resource->OwnerTable[Resource->OwnerThreads[0].TableSize]); + + while (CurrentEntry != LastEntry) { + if (CurrentEntry->OwnerThread == Thread) { + PCHAR CurrentThread = (PCHAR)PsGetCurrentThread(); + *((PULONG)(CurrentThread + 0x136)) = CurrentEntry - Resource->OwnerTable; + return CurrentEntry; + } + if (!(CurrentEntry->OwnerThread)) { + FirstEmptyEntry = CurrentEntry; + } + CurrentEntry++; + } + if (FirstEmptyEntry) { + PCHAR CurrentThread = (PCHAR)PsGetCurrentThread(); + *((PULONG)(CurrentThread + 0x136)) = FirstEmptyEntry - Resource->OwnerTable; + return FirstEmptyEntry; + } else { + // Grow OwnerTable + + + USHORT OldSize = Resource->OwnerThreads[0].TableSize; + USHORT NewSize = 3; + if (OldSize) NewSize = OldSize + 4; + POWNER_ENTRY NewEntry = (POWNER_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(OWNER_ENTRY)*NewSize,RESOURCE_TABLE_TAG); + RtlZeroMemory(NewEntry,sizeof(OWNER_ENTRY)*NewSize); + if (Resource->OwnerTable) { + RtlMoveMemory(NewEntry,Resource->OwnerTable,sizeof(OWNER_ENTRY)*OldSize); + ExFreePool(Resource->OwnerTable); + } + Resource->OwnerTable = NewEntry; + + PCHAR CurrentThread = (PCHAR)PsGetCurrentThread(); + *((PULONG)(CurrentThread + 0x136)) = OldSize; + Resource->OwnerThreads[0].TableSize = NewSize; + + return &(NewEntry[OldSize]); + } +} + + +VOID DLDAcquireShared(PERESOURCE Resource, + ULONG BugCheckId, + ULONG Line, + BOOLEAN WaitForExclusive) +{ + + KIRQL oldIrql; + + ERESOURCE_THREAD Thread = (ERESOURCE_THREAD)PsGetCurrentThread(); + POWNER_ENTRY pOwnerEntry; + + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql); + + if (!Resource->ActiveCount) { + Resource->Flag &= ~ResourceOwnedExclusive; + Resource->ActiveCount = 1; + Resource->OwnerThreads[1].OwnerThread = Thread; + Resource->OwnerThreads[1].OwnerCount = 1; + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + return; + } + + if (Resource->Flag & ResourceOwnedExclusive ) { + if (Resource->OwnerThreads[0].OwnerThread == Thread) { + Resource->OwnerThreads[0].OwnerCount++; + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + return; + } + + pOwnerEntry = DLDpFindCurrentThread(Resource, 0); + + } else { + // owned shared by some thread(s) + + pOwnerEntry = DLDpFindCurrentThread(Resource, Thread); + + if (!WaitForExclusive && pOwnerEntry->OwnerThread == Thread) { + pOwnerEntry->OwnerCount++; + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + return; + } + + if (!(Resource->NumberOfExclusiveWaiters)) { + + pOwnerEntry->OwnerThread = Thread; + pOwnerEntry->OwnerCount = 1; + Resource->ActiveCount++; + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + + return; + } + } + + if (!(Resource->SharedWaiters)) { + Resource->SharedWaiters = (PKSEMAPHORE)ExAllocatePoolWithTag(NonPagedPool, sizeof(KSEMAPHORE),RESOURCE_SEMAFORE_TAG); + KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff); + } + + Resource->NumberOfSharedWaiters++; + + PTHREAD_STRUCT ThrdStruct = DLDAllocFindThread(Thread); + + + // Set WaitingResource for current thread + ThrdStruct->WaitingResource = Resource; + ThrdStruct->BugCheckId = BugCheckId; + ThrdStruct->Line = Line; + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + + DLDpWaitForResource(Resource,&(Resource->SharedWaiters->Header),ThrdStruct); + + KeAcquireSpinLock(&Resource->SpinLock, &oldIrql); + + pOwnerEntry = DLDpFindCurrentThread(Resource, Thread); + pOwnerEntry->OwnerThread = Thread; + pOwnerEntry->OwnerCount = 1; + + ThrdStruct->WaitingResource = NULL; + ThrdStruct->ThreadId = 0; + ThrdStruct->BugCheckId = 0; + ThrdStruct->Line = 0; + + KeReleaseSpinLock(&Resource->SpinLock, oldIrql); + + return; + +} diff --git a/reactos/drivers/filesystems/udfs/dldetect.h b/reactos/drivers/filesystems/udfs/dldetect.h new file mode 100644 index 00000000000..634d5c84877 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/dldetect.h @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + +Module Name: + + DLDetect.h + +Abstract: + + This file contains all defines and protos related to DeadLock Detector. + +Environment: + + NT Kernel Mode +*/ + +#ifndef _DL_DETECT_H_ +#define _DL_DETECT_H_ + + +#define DLDAllocatePool(size) MyAllocatePool__(NonPagedPool,size) +#define DLDFreePool(addr) MyFreePool__((addr)) + +#define DLDGetCurrentResourceThread() \ + ((ERESOURCE_THREAD)PsGetCurrentThread()) + +#ifndef ResourceOwnedExclusive +#define ResourceOwnedExclusive 0x80 +#endif +#define ResourceDisableBoost 0x08 + + +VOID DLDInit(ULONG MaxThrdCount); + + +VOID DLDAcquireExclusive(PERESOURCE Resource, + ULONG BugCheckId, + ULONG Line); + +VOID DLDAcquireShared(PERESOURCE Resource, + ULONG BugCheckId, + ULONG Line, + BOOLEAN WaitForExclusive); + +VOID DLDAcquireSharedStarveExclusive(PERESOURCE Resource, + ULONG BugCheckId, + ULONG Line); + +VOID DLDUnblock(PERESOURCE Resource); + + +VOID DLDFree(VOID); + +typedef struct _THREAD_STRUCT { + ERESOURCE_THREAD ThreadId; + PERESOURCE WaitingResource; + ULONG BugCheckId; + ULONG Line; +} THREAD_STRUCT, *PTHREAD_STRUCT; + + +typedef struct _THREAD_REC_BLOCK { + PTHREAD_STRUCT Thread; + PERESOURCE HoldingResource; +} THREAD_REC_BLOCK, *PTHREAD_REC_BLOCK; + +#endif // _DL_DETECT_H_ diff --git a/reactos/drivers/filesystems/udfs/env_spec.cpp b/reactos/drivers/filesystems/udfs/env_spec.cpp new file mode 100644 index 00000000000..0a71ba96314 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/env_spec.cpp @@ -0,0 +1,628 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Env_Spec.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains environment-secific code to handle physical +* operations: read, write and device IOCTLS +* +*************************************************************************/ + +#include "udffs.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC + +#define MEASURE_IO_PERFORMANCE + +#ifdef MEASURE_IO_PERFORMANCE +LONGLONG IoReadTime=0; +LONGLONG IoWriteTime=0; +LONGLONG WrittenData=0; +LONGLONG IoRelWriteTime=0; +#endif //MEASURE_IO_PERFORMANCE + +#ifdef DBG +ULONG UDF_SIMULATE_WRITES=0; +#endif //DBG + +/* + + */ +NTSTATUS +NTAPI +UDFAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + KdPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt)); + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; + PMDL Mdl, NextMdl; + + Context->IosbToUse = Irp->IoStatus; +#if 1 + // Unlock pages that are described by MDL (if any)... + Mdl = Irp->MdlAddress; + while(Mdl) { + MmPrint((" Unlock MDL=%x\n", Mdl)); + MmUnlockPages(Mdl); + Mdl = Mdl->Next; + } + // ... and free MDL + Mdl = Irp->MdlAddress; + while(Mdl) { + MmPrint((" Free MDL=%x\n", Mdl)); + NextMdl = Mdl->Next; + IoFreeMdl(Mdl); + Mdl = NextMdl; + } + Irp->MdlAddress = NULL; + IoFreeIrp(Irp); + + KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_MORE_PROCESSING_REQUIRED; +#else + KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_SUCCESS; +#endif +} // end UDFAsyncCompletionRoutine() + +NTSTATUS +NTAPI +UDFSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + KdPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt)); + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; + + Context->IosbToUse = Irp->IoStatus; + //KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_SUCCESS; +} // end UDFSyncCompletionRoutine() + +/* +NTSTATUS +UDFSyncCompletionRoutine2( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + KdPrint(("UDFSyncCompletionRoutine2\n")); + PKEVENT SyncEvent = (PKEVENT)Contxt; + + KeSetEvent( SyncEvent, 0, FALSE ); + + return STATUS_SUCCESS; +} // end UDFSyncCompletionRoutine2() +*/ + +/* + + Function: UDFPhReadSynchronous() + + Description: + UDFFSD will invoke this rotine to read physical device synchronously/asynchronously + + Expected Interrupt Level (for execution) : + + <= IRQL_DISPATCH_LEVEL + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +NTAPI +UDFPhReadSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG ReadBytes, + ULONG Flags + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + LARGE_INTEGER ROffset; + PUDF_PH_CALL_CONTEXT Context; + PIRP irp; + KIRQL CurIrql = KeGetCurrentIrql(); + PVOID IoBuf = NULL; +// ULONG i; +#ifdef MEASURE_IO_PERFORMANCE + LONGLONG IoEnterTime; + LONGLONG IoExitTime; + ULONG dt; + ULONG dtm; +#endif //MEASURE_IO_PERFORMANCE +#ifdef _BROWSE_UDF_ + PVCB Vcb = NULL; + if(Flags & PH_VCB_IN_RETLEN) { + Vcb = (PVCB)(*ReadBytes); + } +#endif //_BROWSE_UDF_ + +#ifdef MEASURE_IO_PERFORMANCE + KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime); +#endif //MEASURE_IO_PERFORMANCE + + KdPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0xb,Offset>>0xb)); +// KdPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9)); + + ROffset.QuadPart = Offset; + (*ReadBytes) = 0; +/* + // DEBUG !!! + Flags |= PH_TMP_BUFFER; +*/ + if(Flags & PH_TMP_BUFFER) { + IoBuf = Buffer; + } else { + IoBuf = DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD'); + } + if (!IoBuf) { + KdPrint((" !IoBuf\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); + if (!Context) { + KdPrint((" !Context\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + // Create notification event object to be used to signal the request completion. + KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); + + if (CurIrql > PASSIVE_LEVEL) { + irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, + Length, &ROffset, &(Context->IosbToUse) ); + if (!irp) { + KdPrint((" !irp Async\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); + IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine, + Context, TRUE, TRUE, TRUE ); + } else { + irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, + Length, &ROffset, &(Context->event), &(Context->IosbToUse) ); + if (!irp) { + KdPrint((" !irp Sync\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); + } + + (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + RC = IoCallDriver(DeviceObject, irp); + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&(Context->event), NULL); + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } +// *ReadBytes = Context->IosbToUse.Information; + } else { +// *ReadBytes = irp->IoStatus.Information; + } + if(NT_SUCCESS(RC)) { + (*ReadBytes) = Context->IosbToUse.Information; + } + if(!(Flags & PH_TMP_BUFFER)) { + RtlCopyMemory(Buffer, IoBuf, *ReadBytes); + } + + if(NT_SUCCESS(RC)) { +/* + for(i=0; i<(*ReadBytes); i+=2048) { + KdPrint(("IOCRC %8.8x R %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) )); + } +*/ +#ifdef _BROWSE_UDF_ + if(Vcb) { + RC = UDFVRead(Vcb, IoBuf, Length >> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags); + } +#endif //_BROWSE_UDF_ + } + +try_exit: NOTHING; + + if(Context) MyFreePool__(Context); + if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf); + +#ifdef MEASURE_IO_PERFORMANCE + KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime); + IoReadTime += (IoExitTime-IoEnterTime); + dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000); + dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000); + PerfPrint(("\nUDFPhReadSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm)); +#else + KdPrint(("UDFPhReadSynchronous() exit: %08X\n", RC)); +#endif //MEASURE_IO_PERFORMANCE + + return(RC); +} // end UDFPhReadSynchronous() + + +/* + + Function: UDFPhWriteSynchronous() + + Description: + UDFFSD will invoke this rotine to write physical device synchronously + + Expected Interrupt Level (for execution) : + + <= IRQL_DISPATCH_LEVEL + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +NTAPI +UDFPhWriteSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + LARGE_INTEGER ROffset; + PUDF_PH_CALL_CONTEXT Context; + PIRP irp; +// LARGE_INTEGER timeout; + KIRQL CurIrql = KeGetCurrentIrql(); + PVOID IoBuf = NULL; +// ULONG i; +#ifdef MEASURE_IO_PERFORMANCE + LONGLONG IoEnterTime; + LONGLONG IoExitTime; + ULONG dt; + ULONG dtm; +#endif //MEASURE_IO_PERFORMANCE +#ifdef _BROWSE_UDF_ + PVCB Vcb = NULL; + if(Flags & PH_VCB_IN_RETLEN) { + Vcb = (PVCB)(*WrittenBytes); + } +#endif //_BROWSE_UDF_ + +#ifdef MEASURE_IO_PERFORMANCE + KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime); +#endif //MEASURE_IO_PERFORMANCE + +#if defined DBG || defined USE_PERF_PRINT + ULONG Lba = (ULONG)(Offset>>0xb); +// ASSERT(!(Lba & (32-1))); + PerfPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0xb,Lba)); +// KdPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9)); +#endif //DBG + +#ifdef DBG + if(UDF_SIMULATE_WRITES) { + UCHAR a; + for(ULONG i=0; ievent), NotificationEvent, FALSE); + + if (CurIrql > PASSIVE_LEVEL) { + irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, + Length, &ROffset, &(Context->IosbToUse) ); + if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); + IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine, + Context, TRUE, TRUE, TRUE ); + } else { + irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, + Length, &ROffset, &(Context->event), &(Context->IosbToUse) ); + if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + MmPrint((" Alloc Irp MDL=%x\n, ctx=%x", irp->MdlAddress, Context)); + } + + (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + RC = IoCallDriver(DeviceObject, irp); +/* + for(i=0; i> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags); + } +#endif //_BROWSE_UDF_ + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&(Context->event), NULL); + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } +// *WrittenBytes = Context->IosbToUse.Information; + } else { +// *WrittenBytes = irp->IoStatus.Information; + } + if(NT_SUCCESS(RC)) { + (*WrittenBytes) = Context->IosbToUse.Information; + } + +try_exit: NOTHING; + + if(Context) MyFreePool__(Context); +// if(IoBuf) ExFreePool(IoBuf); +// if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf); + if(!NT_SUCCESS(RC)) { + KdPrint(("WriteError\n")); + } + +#ifdef MEASURE_IO_PERFORMANCE + KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime); + IoWriteTime += (IoExitTime-IoEnterTime); + if (WrittenData > 1024*1024*8) { + PerfPrint(("\nUDFPhWriteSynchronous() Relative size=%I64d, time=%I64d.\n", WrittenData, IoRelWriteTime)); + WrittenData = IoRelWriteTime = 0; + } + WrittenData += Length; + IoRelWriteTime += (IoExitTime-IoEnterTime); + dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000); + dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000); + PerfPrint(("\nUDFPhWriteSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm)); +#else + KdPrint(("nUDFPhWriteSynchronous() exit: %08X\n", RC)); +#endif //MEASURE_IO_PERFORMANCE + + return(RC); +} // end UDFPhWriteSynchronous() + +#if 0 +NTSTATUS +UDFPhWriteVerifySynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags + ) +{ + NTSTATUS RC; + //PUCHAR v_buff = NULL; + //ULONG ReadBytes; + + RC = UDFPhWriteSynchronous(DeviceObject, Buffer, Length, Offset, WrittenBytes, Flags); +/* + if(!Verify) + return RC; + v_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD'); + if(!v_buff) + return RC; + RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, Flags); + if(!NT_SUCCESS(RC)) { + BrutePoint(); + DbgFreePool(v_buff); + return RC; + } + if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) { + DbgFreePool(v_buff); + return RC; + } + BrutePoint(); + DbgFreePool(v_buff); + return STATUS_LOST_WRITEBEHIND_DATA; +*/ + return RC; +} // end UDFPhWriteVerifySynchronous() +#endif //0 + +NTSTATUS +NTAPI +UDFTSendIOCTL( + IN ULONG IoControlCode, + IN PVCB Vcb, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN Acquired; + + Acquired = UDFAcquireResourceExclusiveWithCheck(&(Vcb->IoResource)); + + _SEH2_TRY { + + RC = UDFPhSendIOCTL(IoControlCode, + Vcb->TargetDeviceObject, + InputBuffer , + InputBufferLength, + OutputBuffer , + OutputBufferLength, + OverrideVerify, + Iosb + ); + + } _SEH2_FINALLY { + if(Acquired) + UDFReleaseResource(&(Vcb->IoResource)); + } _SEH2_END; + + return RC; +} // end UDFTSendIOCTL() + +/* + + Function: UDFPhSendIOCTL() + + Description: + UDF FSD will invoke this rotine to send IOCTL's to physical + device + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +NTAPI +UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIRP irp; + PUDF_PH_CALL_CONTEXT Context; + LARGE_INTEGER timeout; + + KdPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode)); + + Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); + if (!Context) return STATUS_INSUFFICIENT_RESOURCES; + // Check if the user gave us an Iosb. + + // Create notification event object to be used to signal the request completion. + KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer , + InputBufferLength, OutputBuffer, OutputBufferLength,FALSE,&(Context->event),&(Context->IosbToUse)); + + if (!irp) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); +/* + if (KeGetCurrentIrql() > PASSIVE_LEVEL) { + KdPrint(("Setting completion routine\n")); + IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine, + Context, TRUE, TRUE, TRUE ); + } +*/ + if(OverrideVerify) { + (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + } + + RC = IoCallDriver(DeviceObject, irp); + + if (RC == STATUS_PENDING) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + KdPrint(("Enter wait state on evt %x\n", Context)); + + if (KeGetCurrentIrql() > PASSIVE_LEVEL) { + timeout.QuadPart = -1000; + KdPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); + RC = DbgWaitForSingleObject(&(Context->event), &timeout); + while(RC == STATUS_TIMEOUT) { + timeout.QuadPart *= 2; + KdPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); + RC = DbgWaitForSingleObject(&(Context->event), &timeout); + } + + } else { + DbgWaitForSingleObject(&(Context->event), NULL); + } + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } + KdPrint(("Exit wait state on evt %x, status %8.8x\n", Context, RC)); +/* if(Iosb) { + (*Iosb) = Context->IosbToUse; + }*/ + } else { + KdPrint(("No wait completion on evt %x\n", Context)); +/* if(Iosb) { + (*Iosb) = irp->IoStatus; + }*/ + } + + if(Iosb) { + (*Iosb) = Context->IosbToUse; + } + +try_exit: NOTHING; + + if(Context) MyFreePool__(Context); + return(RC); +} // end UDFPhSendIOCTL() + + +#ifdef UDF_DBG +VOID +UDFNotifyFullReportChange( + PVCB V, + PUDF_FILE_INFO FI, + ULONG E, + ULONG A + ) +{ + if((FI)->ParentFile) { + FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), + (PSTRING)&((FI)->Fcb->FCBName->ObjectName), + ((FI)->ParentFile->Fcb->FCBName->ObjectName.Length + sizeof(WCHAR)), + NULL,NULL, + E, A, + NULL); + } else { + FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), + (PSTRING)&((FI)->Fcb->FCBName->ObjectName), + 0, + NULL,NULL, + E, A, + NULL); + } +} // end UDFNotifyFullReportChange() + +VOID +UDFNotifyVolumeEvent( + IN PFILE_OBJECT FileObject, + IN ULONG EventCode + ) +{ + if(!FsRtlNotifyVolumeEvent) + return; + //FsRtlNotifyVolumeEvent(FileObject, EventCode); +} // end UDFNotifyVolumeEvent() +#endif // UDF_DBG + diff --git a/reactos/drivers/filesystems/udfs/env_spec.h b/reactos/drivers/filesystems/udfs/env_spec.h new file mode 100644 index 00000000000..2b1d5bb8275 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/env_spec.h @@ -0,0 +1,154 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: sys_spec.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the UDF file system driver. +* +* Author: Alter +* +*************************************************************************/ + +#ifndef _UDF_ENV_SPEC_H_ +#define _UDF_ENV_SPEC_H_ + +extern NTSTATUS NTAPI UDFPhReadSynchronous( + PDEVICE_OBJECT DeviceObject, + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG ReadBytes, + ULONG Flags); + +extern NTSTATUS NTAPI UDFPhWriteSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags); +/* +extern NTSTATUS UDFPhWriteVerifySynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG Length, + LONGLONG Offset, + PULONG WrittenBytes, + ULONG Flags); +*/ +#define UDFPhWriteVerifySynchronous UDFPhWriteSynchronous + +extern NTSTATUS NTAPI +UDFTSendIOCTL( + IN ULONG IoControlCode, + IN PVCB Vcb, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL + ); + +extern NTSTATUS NTAPI UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL); +/* +// This routine performs low-level write (asynchronously if possible) +extern NTSTATUS UDFTWriteAsync( + IN PVOID _Vcb, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN ULONG LBA, + OUT PULONG WrittenBytes, + IN BOOLEAN FreeBuffer); + +extern VOID UDFBGWrite( + IN PVOID Context); +*/ + +/*#define UDFNotifyFullReportChange(V,FI,E,A) \ + FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), \ + ((FI)->ParentFile) ? (PSTRING)&((FI)->Fcb->FCBName->ObjectName) : (PSTRING)&(UDFGlobalData.UnicodeStrRoot), \ + ((FI)->ParentFile) ? ((FI)->ParentFile->Fcb->FCBName->ObjectName.Length + sizeof(WCHAR)) : 0, \ + NULL,NULL, \ + E, A, \ + NULL);*/ + +#ifdef UDF_DBG +VOID UDFNotifyFullReportChange(PVCB V, + PUDF_FILE_INFO FI, + ULONG E, + ULONG A); +VOID UDFNotifyVolumeEvent(IN PFILE_OBJECT FileObject, + IN ULONG EventCode); +#else // UDF_DBG +__inline VOID UDFNotifyFullReportChange( + PVCB V, + PUDF_FILE_INFO FI, + ULONG E, + ULONG A + ) +{ + FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), + (PSTRING)&((FI)->Fcb->FCBName->ObjectName), + ((FI)->ParentFile) ? ((FI)->ParentFile->Fcb->FCBName->ObjectName.Length + sizeof(WCHAR)) : 0, + NULL,NULL, + E, A, + NULL); +} + +#define UDFNotifyVolumeEvent(FileObject, EventCode) \ + {/*if(FsRtlNotifyVolumeEvent) FsRtlNotifyVolumeEvent(FileObject, EventCode)*/;} + +#endif // UDF_DBG + + +#define CollectStatistics(VCB, Field) { \ + ((VCB)->Statistics[KeGetCurrentProcessorNumber()].Common.##Field) ++; \ +} + +#define CollectStatisticsEx(VCB, Field, a) { \ + ((VCB)->Statistics[KeGetCurrentProcessorNumber()].Common.##Field) += a; \ +} + +#define CollectStatistics2(VCB, Field) { \ + ((VCB)->Statistics[KeGetCurrentProcessorNumber()].Fat.##Field) ++; \ +} + +#define CollectStatistics2Ex(VCB, Field, a) { \ + ((VCB)->Statistics[KeGetCurrentProcessorNumber()].Fat.##Field) += a; \ +} + +NTSTATUS NTAPI UDFAsyncCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +NTSTATUS NTAPI UDFSyncCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +NTSTATUS NTAPI UDFSyncCompletionRoutine2(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +#define UDFGetDevType(DevObj) (DevObj->DeviceType) + +#define OSGetCurrentThread() PsGetCurrentThread() + +#define GetCurrentPID() ((ULONG)PsGetCurrentProcessId()) + + +#endif // _UDF_ENV_SPEC_H_ diff --git a/reactos/drivers/filesystems/udfs/errmsg.h b/reactos/drivers/filesystems/udfs/errmsg.h new file mode 100644 index 00000000000..337acbea2d8 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/errmsg.h @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: errmsg.msg +* +* Product: UDF FSD +* +* Module: UDF FSD Event Log Messages +* +* Description: +* Contains error strings in a format understandable to the message compiler. +* Please compile (using mc) with the -c option which will set the +* "Customer" bit in all errors. +* Use values beginning at 0xA000 (e.g. 0xA001) for the UDF FSD +* errors. +* Do NOT use %1 for insertion strings. The I/O manager assumes that +* the first insertion string is the name of the driver/device. +* +*************************************************************************/ +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 + + +// +// MessageId: UDF_ERROR_INTERNAL_ERROR +// +// MessageText: +// +// The UDF FSD encountered an internal error. Please check log data information. +// +#define UDF_ERROR_INTERNAL_ERROR ((ULONG)0xE004A001L) + diff --git a/reactos/drivers/filesystems/udfs/fastio.cpp b/reactos/drivers/filesystems/udfs/fastio.cpp new file mode 100644 index 00000000000..67c3ab8c9a0 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/fastio.cpp @@ -0,0 +1,1195 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Fastio.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various "fast-io" calls. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_FAST_IO + + + +/************************************************************************* +* +* Function: UDFFastIoCheckIfPossible() +* +* Description: +* To fast-io or not to fast-io, that is the question ... +* This routine helps the I/O Manager determine whether the FSD wishes +* to permit fast-io on a specific file stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN +NTAPI +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 ReturnedStatus = FALSE; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + LARGE_INTEGER IoLength; + + // Obtain a pointer to the FCB and CCB for the file stream. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + // Validate that this is a fast-IO request to a regular file. + // The UDF FSD for example, will not allow fast-IO requests + // to volume objects, or to directories. + if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // This is not allowed. + IoStatus->Status = STATUS_INVALID_PARAMETER; + MmPrint((" UDFFastIoCheckIfPossible() TRUE, Failed\n")); + return FALSE; + } +/* + // back pressure for very smart and fast system cache ;) + if(Fcb->Vcb->VerifyCtx.ItemCount >= UDF_MAX_VERIFY_CACHE) { + AdPrint((" Verify queue overflow -> UDFFastIoCheckIfPossible() = FALSE\n")); + return FALSE; + } +*/ + IoLength.QuadPart = Length; + + // The FSD can determine the checks that it needs to perform. + // Typically, a FSD will check whether there exist any byte-range + // locks that would prevent a fast-IO operation from proceeding. + + // ... (FSD specific checks go here). + + if (CheckForReadOperation) { + // The following routine is exported by the FSRTL + // package and it returns TRUE if the read operation should be + // allowed to proceed based on the status of the current byte-range + // locks on the file stream. If we do not use the FSRTL package + // for byte-range locking support, then we must substitute our + // own checks over here. + ReturnedStatus = FsRtlFastCheckLockForRead(&(Fcb->NTRequiredFCB->FileLock), + FileOffset, &IoLength, LockKey, FileObject, + PsGetCurrentProcess()); + } else { +// if(Fcb->Vcb->VCBFlags ); + // This is a write request. Invoke the FSRTL byte-range lock package + // to see whether the write should be allowed to proceed. + ReturnedStatus = FsRtlFastCheckLockForWrite(&(Fcb->NTRequiredFCB->FileLock), + FileOffset, &IoLength, LockKey, FileObject, + PsGetCurrentProcess()); + } + + MmPrint((" UDFFastIoCheckIfPossible() %s\n", ReturnedStatus ? "TRUE" : "FALSE")); + return(ReturnedStatus); +// return FALSE; + +} // end UDFFastIoCheckIfPossible() + +/* + */ +FAST_IO_POSSIBLE +NTAPI +UDFIsFastIoPossible( + IN PtrUDFFCB Fcb + ) +{ + if( !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) /*|| + !FsRtlOplockIsFastIoPossible(&(Fcb->Oplock))*/ ) { + KdPrint((" FastIoIsNotPossible\n")); + return FastIoIsNotPossible; + } +/* + // back pressure for very smart and fast system cache ;) + if(Fcb->Vcb->VerifyCtx.ItemCount >= UDF_MAX_VERIFY_CACHE) { + AdPrint((" Verify queue overflow -> UDFIsFastIoPossible() = FastIoIsNotPossible\n")); + return FastIoIsNotPossible; + } +*/ + if(FsRtlAreThereCurrentFileLocks(&(Fcb->NTRequiredFCB->FileLock)) ) { + KdPrint((" FastIoIsQuestionable\n")); + return FastIoIsQuestionable; + } + KdPrint((" FastIoIsPossible\n")); + return FastIoIsPossible; +} // end UDFIsFastIoPossible() + +/************************************************************************* +* +* Function: UDFFastIoQueryBasicInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query basic +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN +NTAPI +UDFFastIoQueryBasicInfo( + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_BASIC_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + LONG Length = sizeof(FILE_BASIC_INFORMATION); + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN MainResourceAcquired = FALSE; + + FsRtlEnterFileSystem(); + + KdPrint(("UDFFastIo \n")); + // if the file is already opended we can satisfy this request + // immediately 'cause all the data we need must be cached + _SEH2_TRY { + + _SEH2_TRY { + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + NtReqFcb = Fcb->NTRequiredFCB; + //Fcb->Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + if (!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), Wait)) { + try_return(RC = STATUS_CANT_WAIT); + } + MainResourceAcquired = TRUE; + } + + ReturnedStatus = + ((RC = UDFGetBasicInformation(FileObject, Fcb, Buffer, &Length)) == STATUS_SUCCESS); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } _SEH2_END; +try_exit: NOTHING; + } _SEH2_FINALLY { + if (MainResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + MainResourceAcquired = FALSE; + } + IoStatus->Status = RC; + if(ReturnedStatus) { + IoStatus->Information = sizeof(FILE_BASIC_INFORMATION); + } else { + IoStatus->Information = 0; + } + } _SEH2_END; + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} // end UDFFastIoQueryBasicInfo() + + +/************************************************************************* +* +* Function: UDFFastIoQueryStdInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query standard +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN +NTAPI +UDFFastIoQueryStdInfo( + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_STANDARD_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + LONG Length = sizeof(FILE_STANDARD_INFORMATION); + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PtrUDFNTRequiredFCB NtReqFcb = NULL; +// BOOLEAN MainResourceAcquired = FALSE; + + FsRtlEnterFileSystem(); + + KdPrint(("UDFFastIo \n")); + // if the file is already opended we can satisfy this request + // immediately 'cause all the data we need must be cached + _SEH2_TRY { + + _SEH2_TRY { + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + NtReqFcb = Fcb->NTRequiredFCB; + //Fcb->Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + +/* + if (!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), Wait)) { + try_return(RC = STATUS_CANT_WAIT); + } + MainResourceAcquired = TRUE; + } +*/ + ReturnedStatus = + ((RC = UDFGetStandardInformation(Fcb, Buffer, &Length)) == STATUS_SUCCESS); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } _SEH2_END; +//try_exit: NOTHING; + } _SEH2_FINALLY { +/* + if (MainResourceAcquired) { + UDFReleaseResource(&(NtReqFcb->MainResource)); + MainResourceAcquired = FALSE; + } +*/ + IoStatus->Status = RC; + if(ReturnedStatus) { + IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION); + } else { + IoStatus->Information = 0; + } + } _SEH2_END; + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} // end UDFFastIoQueryStdInfo() + + +/************************************************************************* +* +* Function: UDFFastIoAcqCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None (we must be prepared to handle VMM initiated calls) +* +*************************************************************************/ +VOID +NTAPI +UDFFastIoAcqCreateSec( + IN PFILE_OBJECT FileObject + ) +{ + PtrUDFNTRequiredFCB NtReqFcb = (PtrUDFNTRequiredFCB)(FileObject->FsContext); + + MmPrint((" AcqForCreateSection()\n")); + // Acquire the MainResource exclusively for the file stream + if(!ExIsResourceAcquiredExclusiveLite(&(NtReqFcb->MainResource)) || + !ExIsResourceAcquiredExclusiveLite(&(NtReqFcb->PagingIoResource)) ) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + } else { + MmPrint((" already acquired\n")); + } + UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE); + + // Although this is typically not required, the UDF FSD will + // also acquire the PagingIoResource exclusively at this time + // to conform with the resource acquisition described in the set + // file information routine. Once again though, we will probably + // not need to do this. + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE); + NtReqFcb->AcqSectionCount++; + + return; +} // end UDFFastIoAcqCreateSec() + + +/************************************************************************* +* +* Function: UDFFastIoRelCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +NTAPI +UDFFastIoRelCreateSec( + IN PFILE_OBJECT FileObject) +{ + PtrUDFNTRequiredFCB NtReqFcb = (PtrUDFNTRequiredFCB)(FileObject->FsContext); + + MmPrint((" RelFromCreateSection()\n")); + + NtReqFcb->AcqSectionCount--; + // Release the PagingIoResource for the file stream + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + + // Release the MainResource for the file stream + UDFReleaseResource(&(NtReqFcb->MainResource)); + + return; +} // end UDFFastIoRelCreateSec() + + +/************************************************************************* +* +* Function: UDFAcqLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a delayed write (write behind/lazy write) +* operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN NTAPI UDFAcqLazyWrite( + IN PVOID Context, + IN BOOLEAN Wait) +{ + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the UDF FSD + // implementation, this context is a pointer to the NT_REQ_FCB structure. + PtrUDFNTRequiredFCB NtReqFcb = (PtrUDFNTRequiredFCB)Context; + + MmPrint((" UDFAcqLazyWrite()\n")); + + // Acquire the PagingIoResource in the NT_REQ_FCB exclusively. Then, set the + // lazy-writer thread id in the NT_REQ_FCB structure for identification + // when an actual write request is received by the FSD. + // Note: The lazy-writer typically always supplies WAIT set to TRUE. + if (!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), Wait)) + return FALSE; + + // Now, set the lazy-writer thread id. + ASSERT(!(NtReqFcb->LazyWriterThreadID)); + NtReqFcb->LazyWriterThreadID = (unsigned int)(PsGetCurrentThread()); + + ASSERT(IoGetTopLevelIrp() == NULL); + IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); + + // If our FSD needs to perform some special preparations in anticipation + // of receving a lazy-writer request, do so now. + return TRUE; +} // end UDFAcqLazyWrite() + + +/************************************************************************* +* +* Function: UDFRelLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a delayed write (write behind/lazy write) +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +NTAPI +UDFRelLazyWrite( + IN PVOID Context) +{ + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the UDF FSD + // implementation, this context is a pointer to the NT_REQ_FCB structure. + PtrUDFNTRequiredFCB NtReqFcb = (PtrUDFNTRequiredFCB)Context; + + MmPrint((" UDFRelLazyWrite()\n")); + + // Remove the current thread-id from the NT_REQ_FCB + // and release the MainResource. + ASSERT((NtReqFcb->LazyWriterThreadID) == (unsigned int)PsGetCurrentThread()); + NtReqFcb->LazyWriterThreadID = 0; + + // Release the acquired resource. + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + + IoSetTopLevelIrp( NULL ); + return; +} // end UDFRelLazyWrite() + + +/************************************************************************* +* +* Function: UDFAcqReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a read-ahead operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN +NTAPI +UDFAcqReadAhead( + IN PVOID Context, + IN BOOLEAN Wait + ) +{ + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the UDF FSD + // implementation, this context is a pointer to the NT_REQ_FCB structure. +#define NtReqFcb ((PtrUDFNTRequiredFCB)Context) + + MmPrint((" AcqForReadAhead()\n")); + + // Acquire the MainResource in the NT_REQ_FCB shared. + // Note: The read-ahead thread typically always supplies WAIT set to TRUE. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), Wait)) + return FALSE; + + ASSERT(IoGetTopLevelIrp() == NULL); + IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); + + return TRUE; +#undef NtReqFcb + +} // end UDFAcqReadAhead() + + +/************************************************************************* +* +* Function: UDFRelReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a read-ahead operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +NTAPI +UDFRelReadAhead( + IN PVOID Context) +{ + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the UDF FSD + // implementation, this context is a pointer to the NT_REQ_FCB structure. +#define NtReqFcb ((PtrUDFNTRequiredFCB)Context) + + MmPrint((" RelFromReadAhead()\n")); + + // Release the acquired resource. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + + // Of course, the FSD should undo whatever else seems appropriate at this + // time. + IoSetTopLevelIrp( NULL ); + + return; +#undef NtReqFcb +} // end UDFRelReadAhead() + +/* the remaining are only valid under NT Version 4.0 and later */ +#if(_WIN32_WINNT >= 0x0400) + + +/************************************************************************* +* +* Function: UDFFastIoQueryNetInfo() +* +* Description: +* Get information requested by a redirector across the network. This call +* will originate from the LAN Manager server. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN +NTAPI +UDFFastIoQueryNetInfo( + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + LONG Length = sizeof(FILE_NETWORK_OPEN_INFORMATION); + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN MainResourceAcquired = FALSE; + + FsRtlEnterFileSystem(); + + KdPrint(("UDFFastIo \n")); + // if the file is already opended we can satisfy this request + // immediately 'cause all the data we need must be cached + _SEH2_TRY { + + _SEH2_TRY { + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + NtReqFcb = Fcb->NTRequiredFCB; + //Fcb->Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + if (!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), Wait)) { + try_return(RC = STATUS_CANT_WAIT); + } + MainResourceAcquired = TRUE; + } + + ReturnedStatus = + ((RC = UDFGetNetworkInformation(Fcb, Buffer, &Length)) == STATUS_SUCCESS); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } _SEH2_END; +try_exit: NOTHING; + } _SEH2_FINALLY { + if (MainResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + MainResourceAcquired = FALSE; + } + IoStatus->Status = RC; + if(ReturnedStatus) { + IoStatus->Information = sizeof(FILE_NETWORK_OPEN_INFORMATION); + } else { + IoStatus->Information = 0; + } + } _SEH2_END; + + FsRtlExitFileSystem(); + + return(ReturnedStatus); + +} // end UDFFastIoQueryNetInfo() + + +/************************************************************************* +* +* Function: UDFFastIoMdlRead() +* +* Description: +* Bypass the traditional IRP method to perform a MDL read operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +/*BOOLEAN UDFFastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL* MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + _SEH2_TRY { + + _SEH2_TRY { + + // See description in UDFFastIoRead() before filling-in the + // stub here. + NOTHING; + + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } + + //try_exit: NOTHING; + + } _SEH2_FINALLY { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +}*/ + + +/************************************************************************* +* +* Function: UDFFastIoMdlReadComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller no longer requires the data locked in the system cache +* or the MDL to stay around anymore .. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +/*BOOLEAN UDFFastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + _SEH2_TRY { + + _SEH2_TRY { + + // See description in UDFFastIoRead() before filling-in the + // stub here. + NOTHING; + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } + + //try_exit: NOTHING; + + } _SEH2_FINALLY { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +}*/ + + +/************************************************************************* +* +* Function: UDFFastIoPrepareMdlWrite() +* +* Description: +* Bypass the traditional IRP method to prepare for a MDL write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +/*BOOLEAN +UDFFastIoPrepareMdlWrite( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + _SEH2_TRY { + + _SEH2_TRY { + + // See description in UDFFastIoRead() before filling-in the + // stub here. + NOTHING; + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } + + //try_exit: NOTHING; + + } _SEH2_FINALLY { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +}*/ + + +/************************************************************************* +* +* Function: UDFFastIoMdlWriteComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller has updated the contents of the MDL. This data can +* now be asynchronously written out to secondary storage by the Cache Mgr. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +/*BOOLEAN UDFFastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + _SEH2_TRY { + + _SEH2_TRY { + + // See description in UDFFastIoRead() before filling-in the + // stub here. + NOTHING; + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, NULL); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + + } + + //try_exit: NOTHING; + + } _SEH2_FINALLY { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +}*/ + + +/************************************************************************* +* +* Function: UDFFastIoAcqModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before initiating a write operation via the Modified Page/Block Writer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (__try not to return an error, will 'ya ? :-) +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFastIoAcqModWrite( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE *ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + + FsRtlEnterFileSystem(); + + MmPrint((" AcqModW %I64x\n", EndingOffset->QuadPart)); + +#define NtReqFcb ((PtrUDFNTRequiredFCB)(FileObject->FsContext)) + + // We must determine which resource(s) we would like to + // acquire at this time. We know that a write is imminent; + // we will probably therefore acquire appropriate resources + // exclusively. + + // We must first get the FCB and CCB pointers from the file object + // that is passed in to this function (as an argument). Note that + // the ending offset (when examined in conjunction with current valid data + // length) may help us in determining the appropriate resource(s) to acquire. + + // For example, if the ending offset is beyond current valid data length, + // We may decide to acquire *both* the MainResource and the PagingIoResource + // exclusively; otherwise, we may decide simply to acquire the PagingIoResource. + + // Consult the text for more information on synchronization in FSDs. + + // One final note; the VMM expects that we will return a pointer to + // the resource that we acquired (single return value). This pointer + // will be returned back to we in the release call (below). + + if(UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), FALSE)) { + if(EndingOffset->QuadPart <= NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) { + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + RC = STATUS_CANT_WAIT; + } else { + NtReqFcb->AcqFlushCount++; + (*ResourceToRelease) = &(NtReqFcb->PagingIoResource); + MmPrint((" AcqModW OK\n")); + } + } else { + RC = STATUS_CANT_WAIT; + } + +#undef NtReqFcb + + FsRtlExitFileSystem(); + + return RC; +} // end UDFFastIoAcqModWrite() + + +/************************************************************************* +* +* Function: UDFFastIoRelModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a modified page/block write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!) +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFastIoRelModWrite( + IN PFILE_OBJECT FileObject, + IN PERESOURCE ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + FsRtlEnterFileSystem(); + + MmPrint((" RelModW\n")); + +#define NtReqFcb ((PtrUDFNTRequiredFCB)(FileObject->FsContext)) + + // The MPW has complete the write for modified pages and therefore + // wants us to release pre-acquired resource(s). + + // We must undo here whatever it is that we did in the + // UDFFastIoAcqModWrite() call above. + + NtReqFcb->AcqFlushCount--; + ASSERT(ResourceToRelease == &(NtReqFcb->PagingIoResource)); + UDFReleaseResource(ResourceToRelease); + +#undef NtReqFcb + + FsRtlExitFileSystem(); + + return(STATUS_SUCCESS); +} // end UDFFastIoRelModWrite() + + +/************************************************************************* +* +* Function: UDFFastIoAcqCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFastIoAcqCcFlush( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject) +{ +// NTSTATUS RC = STATUS_SUCCESS; + + FsRtlEnterFileSystem(); + + MmPrint((" AcqCcFlush\n")); + + // Acquire appropriate resources that will allow correct synchronization + // with a flush call (and avoid deadlock). + +#define NtReqFcb ((PtrUDFNTRequiredFCB)(FileObject->FsContext)) + +// UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE); + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE); +// ASSERT(!(NtReqFcb->AcqFlushCount)); + NtReqFcb->AcqFlushCount++; + +#undef NtReqFcb + + FsRtlExitFileSystem(); + + return(STATUS_SUCCESS); + +} // end UDFFastIoAcqCcFlush() + +/************************************************************************* +* +* Function: UDFFastIoRelCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFastIoRelCcFlush( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject + ) +{ +// NTSTATUS RC = STATUS_SUCCESS; + + FsRtlEnterFileSystem(); + + MmPrint((" RelCcFlush\n")); + +#define NtReqFcb ((PtrUDFNTRequiredFCB)(FileObject->FsContext)) + + // Release resources acquired in UDFFastIoAcqCcFlush() above. + + NtReqFcb->AcqFlushCount--; + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); +// UDFReleaseResource(&(NtReqFcb->MainResource)); + +#undef NtReqFcb + + FsRtlExitFileSystem(); + + return(STATUS_SUCCESS); + +} // end UDFFastIoRelCcFlush() + + +/*BOOLEAN +UDFFastIoDeviceControl ( + IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) +{ + switch(IoControlCode) { + case FSCTL_ALLOW_EXTENDED_DASD_IO: { + IoStatus->Information = 0; + IoStatus->Status = STATUS_SUCCESS; + break; + } + case FSCTL_IS_VOLUME_MOUNTED: { + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + Fcb = Ccb->Fcb; + + if(Fcb && + !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ) { + return FALSE; + } + + IoStatus->Information = 0; + IoStatus->Status = STATUS_SUCCESS; + + break; + } + default: + return FALSE; + } + return TRUE; +}*/ + +#endif //_WIN32_WINNT >= 0x0400 + +BOOLEAN +NTAPI +UDFFastIoCopyWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) +{ + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + // Obtain a pointer to the FCB and CCB for the file stream. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + // back pressure for very smart and fast system cache ;) + if(Fcb->Vcb->VerifyCtx.QueuedCount || + Fcb->Vcb->VerifyCtx.ItemCount >= UDF_MAX_VERIFY_CACHE) { + AdPrint((" Verify queue overflow -> UDFFastIoCopyWrite() = FALSE\n")); + return FALSE; + } + if(Fcb->NTRequiredFCB->SectionObject.DataSectionObject && + Length >= 0x10000 && + FileOffset->LowPart && + !(FileOffset->LowPart & 0x00ffffff)) { + + MmPrint((" no FastIo 16Mb\n")); + return FALSE; + } + return FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + +} // end UDFFastIoCopyWrite() diff --git a/reactos/drivers/filesystems/udfs/fileinfo.cpp b/reactos/drivers/filesystems/udfs/fileinfo.cpp new file mode 100644 index 00000000000..98440524cb1 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/fileinfo.cpp @@ -0,0 +1,2700 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Fileinfo.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "set/query file information" dispatch +* entry points. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_INFORMATION + +#define MEM_USREN_TAG "US_Ren" +#define MEM_USREN2_TAG "US_Ren2" +#define MEM_USFIDC_TAG "US_FIDC" +#define MEM_USHL_TAG "US_HL" + +/************************************************************************* +* +* Function: UDFFileInfo() +* +* Description: +* The I/O Manager will invoke this routine to handle a set/query file +* information request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFileInfo( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFFileInfo: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonFileInfo(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if(AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFFileInfo() + + +/************************************************************************* +* +* Function: UDFCommonFileInfo() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFCommonFileInfo( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN ParentResourceAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; + PVOID PtrSystemBuffer = NULL; + LONG BufferLength = 0; + FILE_INFORMATION_CLASS FunctionalityRequested; + BOOLEAN CanWait = FALSE; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVcb = FALSE; + PIRP TopIrp; + + TmPrint(("UDFCommonFileInfo: irp %x\n", Irp)); + + TopIrp = IoGetTopLevelIrp(); + switch((ULONG)TopIrp) { + case FSRTL_FSP_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); + break; + case FSRTL_CACHE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); + break; + case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n")); + break; + case FSRTL_FAST_IO_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n")); + BrutePoint() + break; + case NULL: + KdPrint((" NULL TOP_LEVEL_IRP\n")); + break; + default: + if(TopIrp == Irp) { + KdPrint((" TOP_LEVEL_IRP\n")); + } else { + KdPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); + } + } + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location. + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + if(!Ccb) { + // some applications sends us FO without Ccb + // This is not allowed... + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + NtReqFcb = Fcb->NTRequiredFCB; + + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + + // If the caller has opened a logical volume and is attempting to + // query information for it as a file stream, return an error. + if(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + // This is not allowed. Caller must use get/set volume information instead. + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + + Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); + ASSERT(Vcb); + ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); + //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + + // The NT I/O Manager always allocates and supplies a system + // buffer for query and set file information calls. + // Copying information to/from the user buffer and the system + // buffer is performed by the I/O Manager and the FSD need not worry about it. + PtrSystemBuffer = Irp->AssociatedIrp.SystemBuffer; + + UDFFlushTryBreak(Vcb); + if(!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredVcb = TRUE; + + if(IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) { + // Now, obtain some parameters. + BufferLength = IrpSp->Parameters.QueryFile.Length; + FunctionalityRequested = IrpSp->Parameters.QueryFile.FileInformationClass; +#ifdef UDF_ENABLE_SECURITY + RC = IoCheckFunctionAccess( + Ccb->PreviouslyGrantedAccess, + PtrIrpContext->MajorFunction, + PtrIrpContext->MinorFunction, + 0, + &FunctionalityRequested, + NULL); + if(!NT_SUCCESS(RC)) { + try_return(RC); + } +#endif //UDF_ENABLE_SECURITY + // Acquire the MainResource shared (NOTE: for paging-IO on a + // page file, we should avoid acquiring any resources and simply + // trust the VMM to do the right thing, else we could possibly + // run into deadlocks). + if(!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceShared(&(NtReqFcb->MainResource), TRUE); + MainResourceAcquired = TRUE; + } + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) { + case FileBasicInformation: + RC = UDFGetBasicInformation(FileObject, Fcb, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileStandardInformation: + RC = UDFGetStandardInformation(Fcb, (PFILE_STANDARD_INFORMATION) PtrSystemBuffer, &BufferLength); + break; +#if(_WIN32_WINNT >= 0x0400) + case FileNetworkOpenInformation: + RC = UDFGetNetworkInformation(Fcb, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength); + break; +#endif // _WIN32_WINNT >= 0x0400 + case FileInternalInformation: + RC = UDFGetInternalInformation(PtrIrpContext, Fcb, Ccb, (PFILE_INTERNAL_INFORMATION) PtrSystemBuffer, &BufferLength); + break; + case FileEaInformation: + RC = UDFGetEaInformation(PtrIrpContext, Fcb, (PFILE_EA_INFORMATION) PtrSystemBuffer, &BufferLength); + break; + case FileNameInformation: + RC = UDFGetFullNameInformation(FileObject, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength); + break; + case FileAlternateNameInformation: + RC = UDFGetAltNameInformation(Fcb, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength); + break; +// case FileCompressionInformation: +// // RC = UDFGetCompressionInformation(...); +// break; + case FilePositionInformation: + RC = UDFGetPositionInformation(FileObject, (PFILE_POSITION_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileStreamInformation: + RC = UDFGetFileStreamInformation(Fcb, (PFILE_STREAM_INFORMATION) PtrSystemBuffer, &BufferLength); + break; + case FileAllInformation: + // The I/O Manager supplies the Mode, Access, and Alignment + // information. The rest is up to us to provide. + // Therefore, decrement the BufferLength appropriately (assuming + // that the above 3 types on information are already in the + // buffer) + { + PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer; + + BufferLength -= (sizeof(FILE_MODE_INFORMATION) + + sizeof(FILE_ACCESS_INFORMATION) + + sizeof(FILE_ALIGNMENT_INFORMATION)); + + // Get the remaining stuff. + if(!NT_SUCCESS(RC = UDFGetBasicInformation(FileObject, Fcb, &(PtrAllInfo->BasicInformation), &BufferLength)) || + !NT_SUCCESS(RC = UDFGetStandardInformation(Fcb, &(PtrAllInfo->StandardInformation), &BufferLength)) || + !NT_SUCCESS(RC = UDFGetInternalInformation(PtrIrpContext, Fcb, Ccb, &(PtrAllInfo->InternalInformation), &BufferLength)) || + !NT_SUCCESS(RC = UDFGetEaInformation(PtrIrpContext, Fcb, &(PtrAllInfo->EaInformation), &BufferLength)) || + !NT_SUCCESS(RC = UDFGetPositionInformation(FileObject, &(PtrAllInfo->PositionInformation), &BufferLength)) || + !NT_SUCCESS(RC = UDFGetFullNameInformation(FileObject, &(PtrAllInfo->NameInformation), &BufferLength)) + ) + try_return(RC); + } + break; + default: + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + +#ifndef UDF_READ_ONLY_BUILD + } else { +// if(IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) { + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + ASSERT(IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION); + // Now, obtain some parameters. + FunctionalityRequested = IrpSp->Parameters.SetFile.FileInformationClass; + if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + (FunctionalityRequested != FilePositionInformation)) { + try_return(RC = STATUS_ACCESS_DENIED); + } +#ifdef UDF_ENABLE_SECURITY + RC = IoCheckFunctionAccess( + Ccb->PreviouslyGrantedAccess, + PtrIrpContext->MajorFunction, + PtrIrpContext->MinorFunction, + 0, + &FunctionalityRequested, + NULL); + if(!NT_SUCCESS(RC)) { + try_return(RC); + } +#endif //UDF_ENABLE_SECURITY + // If the FSD supports opportunistic locking, + // then we should check whether the oplock state + // allows the caller to proceed. + + // Rename, and link operations require creation of a directory + // entry and possibly deletion of another directory entry. + + // Unless this is an operation on a page file, we should go ahead and + // acquire the FCB exclusively at this time. Note that we will pretty + // much block out anything being done to the FCB from this point on. + if(!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE) && + (FunctionalityRequested != FilePositionInformation) && + (FunctionalityRequested != FileRenameInformation) && + (FunctionalityRequested != FileLinkInformation)) { + // Acquire the Parent & Main Resources exclusive. + if(Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); + if(!UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + ParentResourceAcquired = TRUE; + } + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + } else + // The only operations that could conceivably proceed from this point + // on are paging-IO read/write operations. For delete, link (rename), + // set allocation size, and set EOF, should also acquire the paging-IO + // resource, thereby synchronizing with paging-IO requests. + if((Fcb->FCBFlags & UDF_FCB_PAGE_FILE) && + ((FunctionalityRequested == FileDispositionInformation) || + (FunctionalityRequested == FileAllocationInformation) || + (FunctionalityRequested == FileEndOfFileInformation)) ) { + + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + // Acquire the PagingResource exclusive. + if(!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + PagingIoResourceAcquired = TRUE; + } else if((FunctionalityRequested != FileRenameInformation) && + (FunctionalityRequested != FileLinkInformation)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + } + + if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + (FunctionalityRequested != FilePositionInformation)) { + AdPrint((" Can't change File Information on blank volume ;)\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) { + case FileBasicInformation: + RC = UDFSetBasicInformation(Fcb, Ccb, FileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer); + break; + case FilePositionInformation: { + // Check if no intermediate buffering has been specified. + // If it was specified, do not allow non-aligned set file + // position requests to succeed. + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; + + if(FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { + if(PtrFileInfoBuffer->CurrentByteOffset.LowPart & IrpSp->DeviceObject->AlignmentRequirement) { + // Invalid alignment. + try_return(RC = STATUS_INVALID_PARAMETER); + } + } + + FileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset; + break; + } + case FileDispositionInformation: + RC = UDFSetDispositionInformation(Fcb, Ccb, Vcb, FileObject, + ((PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer)->DeleteFile ? TRUE : FALSE); + break; + case FileRenameInformation: + if(!CanWait) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + RC = UDFRename(IrpSp, Fcb, Ccb, FileObject, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); + if(RC == STATUS_PENDING) { + PostRequest = TRUE; + try_return(RC); + } + break; +#ifdef UDF_ALLOW_HARD_LINKS + case FileLinkInformation: + if(!CanWait) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + RC = UDFHardLink(IrpSp, Fcb, Ccb, FileObject, (PFILE_LINK_INFORMATION)PtrSystemBuffer); + break; +#endif //UDF_ALLOW_HARD_LINKS + case FileAllocationInformation: + RC = UDFSetAllocationInformation(Fcb, Ccb, Vcb, FileObject, + PtrIrpContext, Irp, + (PFILE_ALLOCATION_INFORMATION)PtrSystemBuffer); + break; + case FileEndOfFileInformation: + RC = UDFSetEOF(IrpSp, Fcb, Ccb, Vcb, FileObject, Irp, (PFILE_END_OF_FILE_INFORMATION)PtrSystemBuffer); + break; + default: + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } +#endif //UDF_READ_ONLY_BUILD + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(PagingIoResourceAcquired) { + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + PagingIoResourceAcquired = FALSE; + } + + if(MainResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + MainResourceAcquired = FALSE; + } + + if(ParentResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource)); + ParentResourceAcquired = FALSE; + } + + // Post IRP if required + if(PostRequest) { + + // Since, the I/O Manager gave us a system buffer, we do not + // need to "lock" anything. + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else { + + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + // Set status for "query" requests + if(IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) { + // Return the amount of information transferred. + Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - BufferLength; +#ifndef UDF_READ_ONLY_BUILD +#ifdef UDF_DELAYED_CLOSE + } else + if(NT_SUCCESS(RC)) { + if(FunctionalityRequested == FileDispositionInformation) { + if(AcquiredVcb) { + AcquiredVcb = FALSE; + UDFReleaseResource(&(Vcb->VCBResource)); + } + UDFRemoveFromDelayedQueue(Fcb); + } +#endif //UDF_DELAYED_CLOSE +#endif //UDF_READ_ONLY_BUILD + } + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + } // can we complete the IRP ? + + } + if(AcquiredVcb) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + } _SEH2_END;// end of "__finally" processing + + return(RC); +} // end UDFCommonFileInfo() + +/* + Return some time-stamps and file attributes to the caller. + */ +NTSTATUS +UDFGetBasicInformation( + IN PFILE_OBJECT FileObject, + IN PtrUDFFCB Fcb, + IN PFILE_BASIC_INFORMATION PtrBuffer, + IN OUT LONG* PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO FileInfo; + PDIR_INDEX_ITEM DirNdx; + + AdPrint(("UDFGetBasicInformation: \n")); + + _SEH2_TRY { + + if(*PtrReturnedLength < sizeof(FILE_BASIC_INFORMATION)) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION)); + + // Get information from the FCB and update TimesCache in DirIndex + FileInfo = Fcb->FileInfo; + + if(!FileInfo) { + AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); + AdPrint(("!!!! GetBasicInfo to unopened file !!!!\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); + + PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime; + DirNdx->CreationTime = PtrBuffer->CreationTime.QuadPart; + + PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime; + DirNdx->LastAccessTime = PtrBuffer->LastAccessTime.QuadPart; + + PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime; + DirNdx->LastWriteTime = PtrBuffer->LastWriteTime.QuadPart; + + PtrBuffer->ChangeTime = Fcb->NTRequiredFCB->ChangeTime; + DirNdx->ChangeTime = PtrBuffer->ChangeTime.QuadPart; + + // Now fill in the attributes. + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; +#ifdef UDF_DBG + if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n")); +#endif + } + // Similarly, fill in attributes indicating a hidden file, system + // file, compressed file, temporary file, etc. if the FSD supports + // such file attribute values. + PtrBuffer->FileAttributes |= UDFAttributesToNT(DirNdx,NULL); + if(FileObject->Flags & FO_TEMPORARY_FILE) { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_TEMPORARY; + } else { + PtrBuffer->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY; + } + if(!PtrBuffer->FileAttributes) { + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(NT_SUCCESS(RC)) { + // Return the amount of information filled in. + (*PtrReturnedLength) -= sizeof(FILE_BASIC_INFORMATION); + } + } _SEH2_END; + return(RC); +} // end UDFGetBasicInformation() + + +/* + Return file sizes to the caller. + */ +NTSTATUS +UDFGetStandardInformation( + IN PtrUDFFCB Fcb, + IN PFILE_STANDARD_INFORMATION PtrBuffer, + IN OUT LONG* PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO FileInfo; + PVCB Vcb; + + AdPrint(("UDFGetStandardInformation: \n")); + + _SEH2_TRY { + + if(*PtrReturnedLength < sizeof(FILE_STANDARD_INFORMATION)) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_STANDARD_INFORMATION)); + + FileInfo = Fcb->FileInfo; + + if(!FileInfo) { + AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); + AdPrint(("!!!! GetStandardInfo to unopened file !!!!\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + Vcb = Fcb->Vcb; + PtrBuffer->NumberOfLinks = UDFGetFileLinkCount(FileInfo); + PtrBuffer->DeletePending = (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) ? TRUE : FALSE; +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + // Case on whether this is a file or a directory, and extract + // the information and fill in the fcb/dcb specific parts + // of the output buffer + if(UDFIsADirectory(Fcb->FileInfo)) { + PtrBuffer->Directory = TRUE; + } else { + if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.LowPart == 0xffffffff) { + Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = + UDFSysGetAllocSize(Fcb->Vcb, UDFGetFileSize(FileInfo)); + } + PtrBuffer->AllocationSize = Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize; + PtrBuffer->EndOfFile = Fcb->NTRequiredFCB->CommonFCBHeader.FileSize; + + PtrBuffer->Directory = FALSE; + } + + try_exit: NOTHING; + } _SEH2_FINALLY { + if(NT_SUCCESS(RC)) { + // Return the amount of information filled in. + *PtrReturnedLength -= sizeof(FILE_STANDARD_INFORMATION); + } + } _SEH2_END; + return(RC); +} // end UDFGetStandardInformation() + +/* + Return some time-stamps and file attributes to the caller. + */ +NTSTATUS +UDFGetNetworkInformation( + IN PtrUDFFCB Fcb, + IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO FileInfo; + + AdPrint(("UDFGetNetworkInformation: \n")); + + _SEH2_TRY { + + if(*PtrReturnedLength < sizeof(FILE_NETWORK_OPEN_INFORMATION)) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_NETWORK_OPEN_INFORMATION)); + + // Get information from the FCB. + PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime; + PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime; + PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime; + + FileInfo = Fcb->FileInfo; + + if(!FileInfo) { + AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); + AdPrint(("!!!! UDFGetNetworkInformation to unopened file !!!!\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + // Now fill in the attributes. + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; +#ifdef UDF_DBG + if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n")); +#endif + } + // Similarly, fill in attributes indicating a hidden file, system + // file, compressed file, temporary file, etc. if the FSD supports + // such file attribute values. + PtrBuffer->FileAttributes |= UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index),NULL); + if(!PtrBuffer->FileAttributes) { + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(NT_SUCCESS(RC)) { + // Return the amount of information filled in. + (*PtrReturnedLength) -= sizeof(FILE_NETWORK_OPEN_INFORMATION); + } + } _SEH2_END; + return(RC); +} // end UDFGetNetworkInformation() + + +/* + Return some time-stamps and file attributes to the caller. + */ +NTSTATUS +UDFGetInternalInformation( + PtrUDFIrpContext PtrIrpContext, + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PFILE_INTERNAL_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO FileInfo; + PVCB Vcb; + + AdPrint(("UDFGetInternalInformation\n")); + + _SEH2_TRY { + + if(*PtrReturnedLength < sizeof(FILE_INTERNAL_INFORMATION)) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_INTERNAL_INFORMATION)); + + FileInfo = Fcb->FileInfo; + + if(!FileInfo) { + AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); + AdPrint(("!!!! UDFGetInternalInformation to unopened file !!!!\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + + Vcb = Fcb->Vcb; + PtrBuffer->IndexNumber.QuadPart = UDFGetNTFileId(Vcb, FileInfo, &(Fcb->FCBName->ObjectName)); + + UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE); + // remember File Id & full path + UDFStoreFileId(Fcb->Vcb, Ccb, FileInfo, PtrBuffer->IndexNumber.QuadPart); + UDFReleaseResource(&(Fcb->Vcb->FileIdResource)); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(NT_SUCCESS(RC)) { + // Return the amount of information filled in. + *PtrReturnedLength -= sizeof(FILE_INTERNAL_INFORMATION); + } + } _SEH2_END; + return(RC); +} // end UDFGetInternalInformation() + +/* + Return zero-filled EAs to the caller. + */ +NTSTATUS +UDFGetEaInformation( + PtrUDFIrpContext PtrIrpContext, + IN PtrUDFFCB Fcb, + IN PFILE_EA_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + AdPrint(("UDFGetEaInformation\n")); + + _SEH2_TRY { + + if(*PtrReturnedLength < sizeof(FILE_EA_INFORMATION)) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + PtrBuffer->EaSize = 0; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(NT_SUCCESS(RC)) { + // Return the amount of information filled in. + *PtrReturnedLength -= sizeof(FILE_EA_INFORMATION); + } + } _SEH2_END; + return(RC); +} // end UDFGetEaInformation() + +/* + Return file's long name to the caller. + */ +NTSTATUS +UDFGetFullNameInformation( + IN PFILE_OBJECT FileObject, + IN PFILE_NAME_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + + AdPrint(("UDFGetFullNameInformation\n")); + + PtrBuffer->FileNameLength = FileObject->FileName.Length; + + if (PtrBuffer->FileNameLength + sizeof( ULONG ) > (ULONG)(*PtrReturnedLength)) { + + PtrBuffer->FileNameLength = *PtrReturnedLength - sizeof( ULONG ); + RC = STATUS_BUFFER_OVERFLOW; + } + + RtlCopyMemory( PtrBuffer->FileName, FileObject->FileName.Buffer, PtrBuffer->FileNameLength ); + + // Reduce the available bytes by the amount stored into this buffer. + *PtrReturnedLength -= sizeof( ULONG ) + PtrBuffer->FileNameLength; + + return RC; +} // end UDFGetFullNameInformation() + +/* + Return file short(8.3) name to the caller. + */ +NTSTATUS +UDFGetAltNameInformation( + IN PtrUDFFCB Fcb, + IN PFILE_NAME_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + PDIR_INDEX_ITEM DirNdx; + ULONG BytesToCopy; + UNICODE_STRING ShortName; + WCHAR ShortNameBuffer[13]; + + AdPrint(("UDFGetAltNameInformation: \n")); + + *PtrReturnedLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]); + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); + + ShortName.MaximumLength = 13 * sizeof(WCHAR); + ShortName.Buffer = (PWCHAR)&ShortNameBuffer; + + UDFDOSName__(Fcb->Vcb, &ShortName, &(DirNdx->FName), Fcb->FileInfo); + + if(*PtrReturnedLength < ShortName.Length) { + return(STATUS_BUFFER_OVERFLOW); + } else { + BytesToCopy = ShortName.Length; + *PtrReturnedLength -= ShortName.Length; + } + + RtlCopyMemory( &(PtrBuffer->FileName), + ShortName.Buffer, + BytesToCopy ); + + PtrBuffer->FileNameLength = ShortName.Length; + + return(STATUS_SUCCESS); +} // end UDFGetAltNameInformation() + +/* + Get file position information + */ +NTSTATUS +UDFGetPositionInformation( + IN PFILE_OBJECT FileObject, + IN PFILE_POSITION_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + if(*PtrReturnedLength < sizeof(FILE_POSITION_INFORMATION)) { + return(STATUS_BUFFER_OVERFLOW); + } + PtrBuffer->CurrentByteOffset = FileObject->CurrentByteOffset; + // Modify the local variable for BufferLength appropriately. + *PtrReturnedLength -= sizeof(FILE_POSITION_INFORMATION); + + return(STATUS_SUCCESS); +} // end UDFGetAltNameInformation() + +/* + Get file file stream(s) information + */ +NTSTATUS +UDFGetFileStreamInformation( + IN PtrUDFFCB Fcb, + IN PFILE_STREAM_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO FileInfo; + PUDF_FILE_INFO SDirInfo; + PVCB Vcb; + BOOLEAN FcbAcquired = FALSE; + uint_di i; + LONG l; + PDIR_INDEX_HDR hSDirIndex; + PDIR_INDEX_ITEM SDirIndex; + PFILE_BOTH_DIR_INFORMATION NTFileInfo = NULL; + + AdPrint(("UDFGetFileStreamInformation\n")); + + _SEH2_TRY { + + UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE); + FcbAcquired = TRUE; + + FileInfo = Fcb->FileInfo; + if(!FileInfo) { + AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); + AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n")); + try_return(RC = STATUS_INVALID_PARAMETER); + } + Vcb = Fcb->Vcb; + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, *PtrReturnedLength); + if(!(SDirInfo = FileInfo->Dloc->SDirInfo) || + UDFIsSDirDeleted(SDirInfo) ) { + (*PtrReturnedLength) -= (sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR)); + try_return(RC = STATUS_SUCCESS); + } + + hSDirIndex = SDirInfo->Dloc->DirIndex; + NTFileInfo = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool, sizeof(FILE_BOTH_DIR_INFORMATION)+UDF_NAME_LEN*sizeof(WCHAR)); + if(!NTFileInfo) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + for(i=2; SDirIndex = UDFDirIndex(hSDirIndex,i); i++) { + if((SDirIndex->FI_Flags & UDF_FI_FLAG_FI_INTERNAL) || + UDFIsDeleted(SDirIndex) || + !SDirIndex->FName.Buffer ) + continue; + // copy data to buffer + if(*PtrReturnedLength < (l = ((sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR)) + + SDirIndex->FName.Length + 3) & (~3)) ) { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + RC = UDFFileDirInfoToNT(Vcb, SDirIndex, NTFileInfo); + + PtrBuffer->NextEntryOffset = l; + PtrBuffer->StreamNameLength = SDirIndex->FName.Length; + PtrBuffer->StreamSize = NTFileInfo->EndOfFile; + PtrBuffer->StreamAllocationSize = NTFileInfo->AllocationSize; + RtlCopyMemory(&(PtrBuffer->StreamName), SDirIndex->FName.Buffer, SDirIndex->FName.Length); + *PtrReturnedLength -= l; + *((PCHAR*)(&PtrBuffer)) += l; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(FcbAcquired) + UDFReleaseResource(&(Fcb->Vcb->FileIdResource)); + if(NTFileInfo) + MyFreePool__(NTFileInfo); + } _SEH2_END; + return(RC); +} // end UDFGetFileStreamInformation() + +//******************************************************************* + +#ifndef UDF_READ_ONLY_BUILD + +/* + Set some time-stamps and file attributes supplied by the caller. + */ +NTSTATUS +UDFSetBasicInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PFILE_OBJECT FileObject, + IN PFILE_BASIC_INFORMATION PtrBuffer) +{ + NTSTATUS RC = STATUS_SUCCESS; + ULONG NotifyFilter = 0; + + AdPrint(("UDFSetBasicInformation\n")); + + _SEH2_TRY { + + // Obtain a pointer to the directory entry associated with + // the FCB being modifed. The directory entry is obviously + // part of the data associated with the parent directory that + // contains this particular file stream. + if(PtrBuffer->FileAttributes) { + UDFUpdateAttrTime(Fcb->Vcb, Fcb->FileInfo); + } else + if( UDFIsADirectory(Fcb->FileInfo) && + !(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME) && + ((Fcb->FileInfo->Dloc->DataLoc.Modified || + Fcb->FileInfo->Dloc->AllocLoc.Modified || + (Fcb->FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || + Fcb->FileInfo->Dloc->FELoc.Modified)) + ) { + // ignore Access Time Modification for unchanged Dir + if(!PtrBuffer->CreationTime.QuadPart && + PtrBuffer->LastAccessTime.QuadPart && + !PtrBuffer->ChangeTime.QuadPart && + !PtrBuffer->LastWriteTime.QuadPart) + try_return(RC); + } + + UDFSetFileXTime(Fcb->FileInfo, + &(PtrBuffer->CreationTime.QuadPart), + &(PtrBuffer->LastAccessTime.QuadPart), + &(PtrBuffer->ChangeTime.QuadPart), + &(PtrBuffer->LastWriteTime.QuadPart) ); + + if(PtrBuffer->CreationTime.QuadPart) { + // The interesting thing here is that the user has set certain time + // fields. However, before doing this, the user may have performed + // I/O which in turn would have caused FSD to mark the fact that + // write/access time should be modifed at cleanup. + // We'll mark the fact that such updates are no longer + // required since the user has explicitly specified the values he + // wishes to see associated with the file stream. + Fcb->NTRequiredFCB->CreationTime = PtrBuffer->CreationTime; + Ccb->CCBFlags |= UDF_CCB_CREATE_TIME_SET; + NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION; + } + if(PtrBuffer->LastAccessTime.QuadPart) { + Fcb->NTRequiredFCB->LastAccessTime = PtrBuffer->LastAccessTime; + Ccb->CCBFlags |= UDF_CCB_ACCESS_TIME_SET; + NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + } + if(PtrBuffer->ChangeTime.QuadPart) { + Fcb->NTRequiredFCB->ChangeTime = PtrBuffer->ChangeTime; + Ccb->CCBFlags |= UDF_CCB_MODIFY_TIME_SET; + } + if(PtrBuffer->LastWriteTime.QuadPart) { + Fcb->NTRequiredFCB->LastWriteTime = PtrBuffer->LastWriteTime; + Ccb->CCBFlags |= UDF_CCB_WRITE_TIME_SET; + NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE; + } + + // Now come the attributes. + if(PtrBuffer->FileAttributes) { + // We have a non-zero attribute value. + // The presence of a particular attribute indicates that the + // user wishes to set the attribute value. The absence indicates + // the user wishes to clear the particular attribute. + + // Our routine ignores unsupported flags + PtrBuffer->FileAttributes &= ~(FILE_ATTRIBUTE_NORMAL); + + // Similarly, we should pick out other invalid flag values. + if( (PtrBuffer->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) + try_return(RC = STATUS_INVALID_PARAMETER); + + if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) { + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) + try_return(RC = STATUS_INVALID_PARAMETER); + FileObject->Flags |= FO_TEMPORARY_FILE; + } else { + FileObject->Flags &= ~FO_TEMPORARY_FILE; + } + + if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_READONLY) { + Fcb->FCBFlags |= UDF_FCB_READ_ONLY; + } else { + Fcb->FCBFlags &= ~UDF_FCB_READ_ONLY; + } + + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index), + NULL, PtrBuffer->FileAttributes); + + (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index)) + ->FI_Flags |= UDF_FI_FLAG_SYS_ATTR; + // If the FSD supports file compression, we may wish to + // note the user's preferences for compressing/not compressing + // the file at this time. + Ccb->CCBFlags |= UDF_CCB_ATTRIBUTES_SET; + NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + } + + if(NotifyFilter) { + UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo, + NotifyFilter, FILE_ACTION_MODIFIED); + UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, NULL); + Fcb->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } + +try_exit: NOTHING; + } _SEH2_FINALLY { + ; + } _SEH2_END; + return(RC); +} // end UDFSetBasicInformation() + +NTSTATUS +UDFMarkStreamsForDeletion( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN BOOLEAN ForDel + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PUDF_FILE_INFO SDirInfo = NULL; + PUDF_FILE_INFO FileInfo = NULL; + ULONG lc; + BOOLEAN SDirAcq = FALSE; + BOOLEAN StrAcq = FALSE; + uint_di d,i; + + _SEH2_TRY { + + // In some cases we needn't marking Streams for deleteion + // (Not opened or Don't exist) + if(UDFIsAStream(Fcb->FileInfo) || + UDFIsAStreamDir(Fcb->FileInfo) || + !UDFHasAStreamDir(Fcb->FileInfo) || + !Fcb->FileInfo->Dloc->SDirInfo || + UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) || + (UDFGetFileLinkCount(Fcb->FileInfo) > 1) ) + try_return (RC /*=STATUS_SUCCESS*/); + + // We shall mark Streams for deletion if there is no + // Links to the file. Otherwise we'll delete only the file. + // If we are asked to unmark Streams, we'll precess the whole Tree + RC = UDFOpenStreamDir__(Vcb, Fcb->FileInfo, &SDirInfo); + if(!NT_SUCCESS(RC)) + try_return(RC); + + if(SDirInfo->Fcb && + SDirInfo->Fcb->NTRequiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + SDirAcq = TRUE; + } + + if(!ForDel || ((lc = UDFGetFileLinkCount(Fcb->FileInfo)) < 2)) { + + UDF_DIR_SCAN_CONTEXT ScanContext; + PDIR_INDEX_ITEM DirNdx; + + // It is not worth checking whether the Stream can be deleted if + // Undelete requested + if(ForDel && + // scan DirIndex + UDFDirIndexInitScan(SDirInfo, &ScanContext, 2)) { + + // Check if we can delete Streams + while(DirNdx = UDFDirIndexScan(&ScanContext, &FileInfo)) { + if(!FileInfo) + continue; + if(FileInfo->Fcb) { + FileInfo->Fcb->NTRequiredFCB->AcqFlushCount++; + MmPrint((" MmFlushImageSection() for Stream\n")); + if(!MmFlushImageSection(&(FileInfo->Fcb->NTRequiredFCB->SectionObject), MmFlushForDelete)) { + FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--; + try_return(RC = STATUS_CANNOT_DELETE); + } + FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--; + } + } + } + // (Un)Mark Streams for deletion + + // Perform sequencial Open for Streams & mark 'em + // for deletion. We should not get FileInfo pointers directly + // from DirNdx[i] to prevent great troubles with linked + // files. We should mark for deletion FI with proper ParentFile + // pointer. + d = UDFDirIndexGetLastIndex(SDirInfo->Dloc->DirIndex); + for(i=2; iFcb) { + if(FileInfo->Fcb->NTRequiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(FileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + StrAcq = TRUE; + } +#ifndef UDF_ALLOW_LINKS_TO_STREAMS + if(UDFGetFileLinkCount(FileInfo) >= 2) { + // Currently, UDF_INFO package doesn't + // support this case, so we'll inform developer + // about this to prevent on-disk space leaks... + BrutePoint(); + try_return(RC = STATUS_CANNOT_DELETE); + } +#endif //UDF_ALLOW_LINKS_TO_STREAMS + if(ForDel) { + AdPrint((" SET stream DeleteOnClose\n")); +#ifdef UDF_DBG + ASSERT(!(FileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + if(FileInfo->ParentFile && + FileInfo->ParentFile->Fcb) { + ASSERT(!(FileInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + } +#endif // UDF_DBG + FileInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETE_PARENT); + } else { + AdPrint((" CLEAR stream DeleteOnClose\n")); + FileInfo->Fcb->FCBFlags &= !(UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETE_PARENT); + } + } + UDFCloseFile__(Vcb, FileInfo); + } else + if(RC == STATUS_FILE_DELETED) { + // That's OK if STATUS_FILE_DELETED returned... + RC = STATUS_SUCCESS; + } + if(FileInfo) { + if(UDFCleanUpFile__(Vcb, FileInfo)) { + ASSERT(!StrAcq && !(FileInfo->Fcb)); + MyFreePool__(FileInfo); + } + if(StrAcq) { + UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); + UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource)); + StrAcq = FALSE; + } + } + FileInfo = NULL; + } + // Mark SDir for deletion + if(SDirInfo->Fcb) { + if(ForDel) { +#ifdef UDF_DBG + ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + if(SDirInfo->ParentFile && + SDirInfo->ParentFile->Fcb) { + ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + } +#endif // UDF_DBG + AdPrint((" SET stream dir DeleteOnClose\n")); + SDirInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETE_PARENT); + } else { + AdPrint((" CLEAR stream dir DeleteOnClose\n")); + SDirInfo->Fcb->FCBFlags &= ~(UDF_FCB_DELETE_ON_CLOSE | + UDF_FCB_DELETE_PARENT); + } + } + } else + if(lc >= 2) { + // if caller wants us to perform DelTree for Streams, but + // someone keeps Stream opened and there is a Link to this + // file, we can't delete it immediately (on Cleanup) & should + // not delete the whole Tree. Instead, we'll set DELETE_PARENT + // flag in SDir to kill this file later, when all the Handles + // to Streams, opened via this file, would be closed +#ifdef UDF_DBG + ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + if(SDirInfo->ParentFile && + SDirInfo->ParentFile->Fcb) { + ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); + } +#endif // UDF_DBG + if(SDirInfo->Fcb) + SDirInfo->Fcb->FCBFlags |= UDF_FCB_DELETE_PARENT; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(FileInfo) { + UDFCloseFile__(Vcb, FileInfo); + if(UDFCleanUpFile__(Vcb, FileInfo)) { + ASSERT(!StrAcq && !(FileInfo->Fcb)); + MyFreePool__(FileInfo); + } + if(StrAcq) { + UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); + UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource)); + } + SDirInfo = NULL; + } + if(SDirInfo) { + UDFCloseFile__(Vcb, SDirInfo); + if(SDirAcq) { + UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); + UDFReleaseResource(&(SDirInfo->Fcb->NTRequiredFCB->MainResource)); + } + if(UDFCleanUpFile__(Vcb, SDirInfo)) { + MyFreePool__(SDirInfo); + } + SDirInfo = NULL; + } + } _SEH2_END; + return RC; +} // end UDFMarkStreamsForDeletion() + +/* + (Un)Mark file for deletion. + */ +NTSTATUS +UDFSetDispositionInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN BOOLEAN Delete + ) +{ + NTSTATUS RC = STATUS_SUCCESS; +// PUDF_FILE_INFO SDirInfo = NULL; +// PUDF_FILE_INFO FileInfo = NULL; + ULONG lc; + + AdPrint(("UDFSetDispositionInformation\n")); + + _SEH2_TRY { + + if(!Delete) { + AdPrint((" CLEAR DeleteOnClose\n")); + // "un-delete" the file. + Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; + if(FileObject) + FileObject->DeletePending = FALSE; + RC = UDFMarkStreamsForDeletion(Vcb, Fcb, FALSE); // Undelete + try_return(RC); + } + AdPrint((" SET DeleteOnClose\n")); + + // The easy part is over. Now, we know that the user wishes to + // delete the corresponding directory entry (of course, if this + // is the only link to the file stream, any on-disk storage space + // associated with the file stream will also be released when the + // (only) link is deleted!) + + // Do some checking to see if the file can even be deleted. + if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { + // All done! + try_return(RC); + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) { + try_return(RC = STATUS_CANNOT_DELETE); + } + + if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) { + RC = UDFCheckAccessRights(NULL, NULL, Fcb->ParentFcb, NULL, FILE_DELETE_CHILD, 0); + if(!NT_SUCCESS(RC)) { + try_return (RC = STATUS_CANNOT_DELETE); + } + } + + // It would not be prudent to allow deletion of either a root + // directory or a directory that is not empty. + if(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) + try_return(RC = STATUS_CANNOT_DELETE); + + lc = UDFGetFileLinkCount(Fcb->FileInfo); + + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + // Perform check to determine whether the directory + // is empty or not. + if(!UDFIsDirEmpty__(Fcb->FileInfo)) { + try_return(RC = STATUS_DIRECTORY_NOT_EMPTY); + } + + } else { + // An important step is to check if the file stream has been + // mapped by any process. The delete cannot be allowed to proceed + // in this case. + MmPrint((" MmFlushImageSection()\n")); + Fcb->NTRequiredFCB->AcqFlushCount++; + if(!MmFlushImageSection(&(Fcb->NTRequiredFCB->SectionObject), + (lc > 1) ? MmFlushForWrite : MmFlushForDelete)) { + Fcb->NTRequiredFCB->AcqFlushCount--; + try_return(RC = STATUS_CANNOT_DELETE); + } + Fcb->NTRequiredFCB->AcqFlushCount--; + } + // We should also mark Streams for deletion if there are no + // Links to the file. Otherwise we'll delete only the file + + if(lc > 1) { + RC = STATUS_SUCCESS; + } else { + RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete + if(!NT_SUCCESS(RC)) + try_return(RC); + } + + // Set a flag to indicate that this directory entry will become history + // at cleanup. + Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; + if(FileObject) + FileObject->DeletePending = TRUE; + + if((Fcb->FCBFlags & UDF_FCB_DIRECTORY) && Ccb) { + FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PVOID)Ccb, NULL, FALSE, FALSE, + 0, NULL, NULL, NULL ); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + ; + } _SEH2_END; + return(RC); +} // end UDFSetDispositionInformation() + + +/* + Change file allocation length. + */ +NTSTATUS +UDFSetAllocationInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp, + IN PFILE_ALLOCATION_INFORMATION PtrBuffer + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN TruncatedFile = FALSE; + BOOLEAN ModifiedAllocSize = FALSE; + BOOLEAN CacheMapInitialized = FALSE; + BOOLEAN AcquiredPagingIo = FALSE; + + AdPrint(("UDFSetAllocationInformation\n")); + + _SEH2_TRY { + // Increasing the allocation size associated with a file stream + // is relatively easy. All we have to do is execute some FSD + // specific code to check whether we have enough space available + // (and if the FSD supports user/volume quotas, whether the user + // is not exceeding quota), and then increase the file size in the + // corresponding on-disk and in-memory structures. + // Then, all we should do is inform the Cache Manager about the + // increased allocation size. + + // First, do whatever error checking is appropriate here (e.g. whether + // the caller is trying the change size for a directory, etc.). + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) + try_return(RC = STATUS_INVALID_PARAMETER); + + Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); + + if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) && + (FileObject->SectionObjectPointer->SharedCacheMap == NULL) && + !FlagOn(Irp->Flags, IRP_PAGING_IO)) { + ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ); + // Now initialize the cache map. + MmPrint((" CcInitializeCacheMap()\n")); + CcInitializeCacheMap( FileObject, + (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize, + FALSE, + &(UDFGlobalData.CacheMgrCallBacks), + Fcb->NTRequiredFCB ); + + CacheMapInitialized = TRUE; + } + + // Are we increasing the allocation size? + if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart < + PtrBuffer->AllocationSize.QuadPart) { + + // Yes. Do the FSD specific stuff i.e. increase reserved + // space on disk. + if(((LONGLONG)UDFGetFreeSpace(Vcb) << Vcb->LBlockSizeBits) < PtrBuffer->AllocationSize.QuadPart) { + try_return(RC = STATUS_DISK_FULL); + } +// RC = STATUS_SUCCESS; + ModifiedAllocSize = TRUE; + + } else if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart > + PtrBuffer->AllocationSize.QuadPart) { + // This is the painful part. See if the VMM will allow us to proceed. + // The VMM will deny the request if: + // (a) any image section exists OR + // (b) a data section exists and the size of the user mapped view + // is greater than the new size + // Otherwise, the VMM should allow the request to proceed. + MmPrint((" MmCanFileBeTruncated()\n")); + if(!MmCanFileBeTruncated(&(Fcb->NTRequiredFCB->SectionObject), &(PtrBuffer->AllocationSize))) { + // VMM said no way! + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + // Perform our directory entry modifications. Release any on-disk + // space we may need to in the process. + ModifiedAllocSize = TRUE; + TruncatedFile = TRUE; + } + + ASSERT(NT_SUCCESS(RC)); + // This is a good place to check if we have performed a truncate + // operation. If we have perform a truncate (whether we extended + // or reduced file size or even leave it intact), we should update + // file time stamps. + FileObject->Flags |= FO_FILE_MODIFIED; + + // Last, but not the lease, we must inform the Cache Manager of file size changes. + if(ModifiedAllocSize) { + + // If we decreased the allocation size to less than the + // current file size, modify the file size value. + // Similarly, if we decreased the value to less than the + // current valid data length, modify that value as well. + + AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource)); + // Update the FCB Header with the new allocation size. + if(TruncatedFile) { + if(Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart > + PtrBuffer->AllocationSize.QuadPart) { + // Decrease the valid data length value. + Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength = + PtrBuffer->AllocationSize; + } + if(Fcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart > + PtrBuffer->AllocationSize.QuadPart) { + // Decrease the file size value. + Fcb->NTRequiredFCB->CommonFCBHeader.FileSize = + PtrBuffer->AllocationSize; + RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->AllocationSize.QuadPart); +// UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL); + } + } else { + Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize; +// UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, +// &(PtrBuffer->AllocationSize.QuadPart)); + } + if(AcquiredPagingIo) { + UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); + AcquiredPagingIo = FALSE; + } + // If the FCB has not had caching initiated, it is still valid + // for us to invoke the NT Cache Manager. It is possible in such + // situations for the call to be no'oped (unless some user has + // mapped in the file) + + // NOTE: The invocation to CcSetFileSizes() will quite possibly + // result in a recursive call back into the file system. + // This is because the NT Cache Manager will typically + // perform a flush before telling the VMM to purge pages + // especially when caching has not been initiated on the + // file stream, but the user has mapped the file into + // the process' virtual address space. + MmPrint((" CcSetFileSizes()\n")); + Fcb->NTRequiredFCB->AcqFlushCount++; + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize)); + Fcb->NTRequiredFCB->AcqFlushCount--; + Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + + // Inform any pending IRPs (notify change directory). + if(UDFIsAStream(Fcb->FileInfo)) { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_STREAM_SIZE, + FILE_ACTION_MODIFIED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + } + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(AcquiredPagingIo) { + UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); + AcquiredPagingIo = FALSE; + } + if (CacheMapInitialized) { + + MmPrint((" CcUninitializeCacheMap()\n")); + CcUninitializeCacheMap( FileObject, NULL, NULL ); + } + } _SEH2_END; + return(RC); +} // end UDFSetAllocationInformation() + +/* + Set end of file (resize). + */ +NTSTATUS +UDFSetEOF( + IN PIO_STACK_LOCATION PtrSp, + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN PIRP Irp, + IN PFILE_END_OF_FILE_INFORMATION PtrBuffer + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN TruncatedFile = FALSE; + BOOLEAN ModifiedAllocSize = FALSE; + ULONG Attr; + PDIR_INDEX_ITEM DirNdx; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + LONGLONG OldFileSize; + BOOLEAN ZeroBlock; + BOOLEAN CacheMapInitialized = FALSE; + BOOLEAN AcquiredPagingIo = FALSE; + + AdPrint(("UDFSetEOF\n")); + + _SEH2_TRY { + // Increasing the allocation size associated with a file stream + // is relatively easy. All we have to do is execute some FSD + // specific code to check whether we have enough space available + // (and if the FSD supports user/volume quotas, whether the user + // is not exceeding quota), and then increase the file size in the + // corresponding on-disk and in-memory structures. + // Then, all we should do is inform the Cache Manager about the + // increased allocation size. + + // First, do whatever error checking is appropriate here (e.g. whether + // the caller is trying the change size for a directory, etc.). + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) + try_return(RC = STATUS_INVALID_PARAMETER); + + NtReqFcb = Fcb->NTRequiredFCB; + + if((Fcb->FCBFlags & UDF_FCB_DELETED) || + (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)) { +#ifdef UDF_DBG + if(UDFGetFileLinkCount(Fcb->FileInfo) < 1) { + BrutePoint(); + try_return(RC = STATUS_SUCCESS); + } else +#endif // UDF_DBG + try_return(RC = STATUS_SUCCESS); + } + + NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); + + if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) && + (FileObject->SectionObjectPointer->SharedCacheMap == NULL) && + !(Irp->Flags & IRP_PAGING_IO)) { + ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ); + // Now initialize the cache map. + MmPrint((" CcInitializeCacheMap()\n")); + CcInitializeCacheMap( FileObject, + (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize, + FALSE, + &(UDFGlobalData.CacheMgrCallBacks), + Fcb->NTRequiredFCB ); + + CacheMapInitialized = TRUE; + } + + AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource)); + // Do a special case here for the lazy write of file sizes. + if(PtrSp->Parameters.SetFile.AdvanceOnly) { + // Never have the dirent filesize larger than the fcb filesize + PtrBuffer->EndOfFile.QuadPart = + min(PtrBuffer->EndOfFile.QuadPart, + NtReqFcb->CommonFCBHeader.FileSize.QuadPart); + // Only advance the file size, never reduce it with this call + RC = STATUS_SUCCESS; + if(UDFGetFileSizeFromDirNdx(Vcb, Fcb->FileInfo) >= + PtrBuffer->EndOfFile.QuadPart) + try_return(RC); + + UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart)); + goto notify_size_changes; + } + + // !!! IMPORTANT !!! + + // We can get here after all Handles to the file are closed + // To prevent allocation size incoherency we should + // reference FileInfo _before_ call to UDFResizeFile__() + // and use UDFCloseFile__() _after_ that + + // Are we increasing the allocation size? + OldFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart; + if(OldFileSize < PtrBuffer->EndOfFile.QuadPart) { + + // Yes. Do the FSD specific stuff i.e. increase reserved + // space on disk. + if (FileObject->PrivateCacheMap) + ZeroBlock = TRUE; + + // reference file to pretend that it is opened + UDFReferenceFile__(Fcb->FileInfo); + UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount)); + // perform resize operation + RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); + // dereference file + UDFCloseFile__(Vcb, Fcb->FileInfo); + UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); + // update values in NtReqFcb + NtReqFcb->CommonFCBHeader.FileSize.QuadPart = +// NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = + PtrBuffer->EndOfFile.QuadPart; + ModifiedAllocSize = TRUE; + + } else if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart > + PtrBuffer->EndOfFile.QuadPart) { + + // This is the painful part. See if the VMM will allow us to proceed. + // The VMM will deny the request if: + // (a) any image section exists OR + // (b) a data section exists and the size of the user mapped view + // is greater than the new size + // Otherwise, the VMM should allow the request to proceed. + + MmPrint((" MmCanFileBeTruncated()\n")); + if(!MmCanFileBeTruncated(&(NtReqFcb->SectionObject), &(PtrBuffer->EndOfFile))) { + // VMM said no way! + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + // Perform directory entry modifications. Release any on-disk + // space we may need to in the process. + UDFReferenceFile__(Fcb->FileInfo); + UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount)); + // perform resize operation + RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); + // dereference file + UDFCloseFile__(Vcb, Fcb->FileInfo); + UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); + + ModifiedAllocSize = TRUE; + TruncatedFile = TRUE; + } + + // This is a good place to check if we have performed a truncate + // operation. If we have perform a truncate (whether we extended + // or reduced file size), we should update file time stamps. + + // Last, but not the least, we must inform the Cache Manager of file size changes. + if(ModifiedAllocSize && NT_SUCCESS(RC)) { + // If we decreased the allocation size to less than the + // current file size, modify the file size value. + // Similarly, if we decreased the value to less than the + // current valid data length, modify that value as well. + if(TruncatedFile) { + if(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart > + PtrBuffer->EndOfFile.QuadPart) { + // Decrease the valid data length value. + NtReqFcb->CommonFCBHeader.ValidDataLength = + PtrBuffer->EndOfFile; + } + if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart > + PtrBuffer->EndOfFile.QuadPart) { + // Decrease the file size value. + NtReqFcb->CommonFCBHeader.FileSize = + PtrBuffer->EndOfFile; + } + UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL); + } else { + // Update the FCB Header with the new allocation size. + // NT expects AllocationSize to be decreased on Close only + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = + PtrBuffer->EndOfFile.QuadPart; +// UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo)); + UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart)); + } + + FileObject->Flags |= FO_FILE_MODIFIED; +// UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); + + // If the FCB has not had caching initiated, it is still valid + // for us to invoke the NT Cache Manager. It is possible in such + // situations for the call to be no'oped (unless some user has + // mapped in the file) + + // Archive bit + if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) { + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); + Ccb->CCBFlags &= ~UDF_CCB_ATTRIBUTES_SET; + Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry); + if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) + UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); + } + + // NOTE: The invocation to CcSetFileSizes() will quite possibly + // result in a recursive call back into the file system. + // This is because the NT Cache Manager will typically + // perform a flush before telling the VMM to purge pages + // especially when caching has not been initiated on the + // file stream, but the user has mapped the file into + // the process' virtual address space. + MmPrint((" CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread())); + Fcb->NTRequiredFCB->AcqFlushCount++; + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); + Fcb->NTRequiredFCB->AcqFlushCount--; +/* if(ZeroBlock) { + UDFZeroDataEx(NtReqFcb, + OldFileSize, + PtrBuffer->EndOfFile.QuadPart - OldFileSize, + TRUE/*CanWait, Vcb, FileObject); + }*/ + Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + +notify_size_changes: + if(AcquiredPagingIo) { + UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); + AcquiredPagingIo = FALSE; + } + + // Inform any pending IRPs (notify change directory). + if(UDFIsAStream(Fcb->FileInfo)) { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_STREAM_SIZE, + FILE_ACTION_MODIFIED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + } + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(AcquiredPagingIo) { + UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); + AcquiredPagingIo = FALSE; + } + if (CacheMapInitialized) { + + MmPrint((" CcUninitializeCacheMap()\n")); + CcUninitializeCacheMap( FileObject, NULL, NULL ); + } + } _SEH2_END; + return(RC); +} // end UDFSetEOF() + +NTSTATUS +UDFPrepareForRenameMoveLink( + PVCB Vcb, + PBOOLEAN AcquiredVcb, + PBOOLEAN AcquiredVcbEx, + PBOOLEAN SingleDir, + PBOOLEAN AcquiredDir1, + PBOOLEAN AcquiredFcb1, + IN PtrUDFCCB Ccb1, + PUDF_FILE_INFO File1, + PUDF_FILE_INFO Dir1, + PUDF_FILE_INFO Dir2, + BOOLEAN HardLink + ) +{ + // convert acquisition to Exclusive + // this will prevent us from the following situation: + // There is a pair of objects among input dirs & + // one of them is a parent of another. Sequential resource + // acquisition may lead to deadlock due to concurrent + // CleanUpFcbChain() or UDFCloseFileInfoChain() + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + UDFReleaseResource(&(Vcb->VCBResource)); + (*AcquiredVcb) = FALSE; + + // At first, make system to issue last Close request + // for our Source & Target ... + // we needn't flush/purge for Source on HLink + UDFRemoveFromSystemDelayedQueue(Dir2->Fcb); + if(!HardLink && (Dir2 != Dir1)) + UDFRemoveFromSystemDelayedQueue(File1->Fcb); + +#ifdef UDF_DELAYED_CLOSE + _SEH2_TRY { + // Do actual close for all "delayed close" calls + + // ... and now remove the rest from our queue + if(!HardLink) { + UDFCloseAllDelayedInDir(Vcb, Dir1); + if(Dir2 != Dir1) + UDFCloseAllDelayedInDir(Vcb, Dir2); + } else { + UDFCloseAllDelayedInDir(Vcb, Dir2); + } + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + return (STATUS_DRIVER_INTERNAL_ERROR); + } _SEH2_END; +#endif //UDF_DELAYED_CLOSE + + (*SingleDir) = ((Dir1 == Dir2) && (Dir1->Fcb)); + + if(!(*SingleDir) || + (UDFGetFileLinkCount(File1) != 1)) { + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + (*AcquiredVcb) = TRUE; + (*AcquiredVcbEx) = TRUE; + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + } else { + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + (*AcquiredVcb) = TRUE; + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(Dir1->Fcb->NTRequiredFCB->MainResource),TRUE); + (*AcquiredDir1) = TRUE; + + UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(&(File1->Fcb->NTRequiredFCB->MainResource),TRUE); + (*AcquiredFcb1) = TRUE; + } + return STATUS_SUCCESS; +} // end UDFPrepareForRenameMoveLink() + +/* + Rename or move file + */ +NTSTATUS +UDFRename( + IN PIO_STACK_LOCATION PtrSp, + IN PtrUDFFCB Fcb1, + IN PtrUDFCCB Ccb1, + IN PFILE_OBJECT FileObject1, // Source File + IN PFILE_RENAME_INFORMATION PtrBuffer + ) +{ + // Source Directory + PFILE_OBJECT DirObject1 = FileObject1->RelatedFileObject; + // Target Directory + PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject; + // Overwite Flag + BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists && + PtrBuffer->ReplaceIfExists; + NTSTATUS RC; + PVCB Vcb = Fcb1->Vcb; + PtrUDFFCB Fcb2; + BOOLEAN ic; + BOOLEAN AcquiredVcb = TRUE; + BOOLEAN AcquiredVcbEx = FALSE; + BOOLEAN AcquiredDir1 = FALSE; + BOOLEAN AcquiredFcb1 = FALSE; + BOOLEAN SingleDir = TRUE; + BOOLEAN UseClose; + + PUDF_FILE_INFO File1; + PUDF_FILE_INFO Dir1; + PUDF_FILE_INFO Dir2; + PUDF_FILE_INFO NextFileInfo, fi; + + UNICODE_STRING NewName; + UNICODE_STRING LocalPath; + PtrUDFCCB CurCcb = NULL; + PLIST_ENTRY Link; + ULONG i; + ULONG DirRefCount; + ULONG FileInfoRefCount; + ULONG Attr; + PDIR_INDEX_ITEM DirNdx; + + AdPrint(("UDFRename %8.8x\n", DirObject2)); + + LocalPath.Buffer = NULL; + + _SEH2_TRY { + // do we try to rename Volume ? +#ifdef UDF_ALLOW_RENAME_MOVE + if(!(File1 = Fcb1->FileInfo)) +#endif //UDF_ALLOW_RENAME_MOVE + try_return (RC = STATUS_ACCESS_DENIED); + + // do we try to rename RootDir ? + if(!(Dir1 = File1->ParentFile)) + try_return (RC = STATUS_ACCESS_DENIED); + + // do we try to rename to RootDir or Volume ? + if(!DirObject2) { + Dir2 = File1->ParentFile; + DirObject2 = DirObject1; + } else + if(DirObject2->FsContext2 && + (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) { + Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo; + } else { + try_return (RC = STATUS_INVALID_PARAMETER); + } + // invalid destination ? + if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED); + + // Stream can't be a Dir or have StreamDir + if(UDFIsAStreamDir(Dir2)) { +#ifdef UDF_ENABLE_SECURITY + if(UDFIsADirectory(File1)) { + try_return (RC = STATUS_ACCESS_DENIED); + } + // We should check whether File1 has only Internal + // (or Deleted) streams. In this case SDir should be + // removed (in UDFRenameMoveFile__()). Otherwise + // return STATUS_ACCESS_DENIED + if(UDFHasAStreamDir(File1)) { + KdPrint(("TODO: We should remove Streams from source file\n")); + try_return (RC = STATUS_ACCESS_DENIED); + } +#else //UDF_ENABLE_SECURITY + if(UDFIsADirectory(File1) || + UDFHasAStreamDir(File1)) { + try_return (RC = STATUS_ACCESS_DENIED); + } +#endif //UDF_ENABLE_SECURITY + } + + RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx, + &SingleDir, + &AcquiredDir1, &AcquiredFcb1, + Ccb1, File1, + Dir1, Dir2, + FALSE); // it is Rename operation + if(!NT_SUCCESS(RC)) + try_return(RC); + + // check if the source file is in use + if(Fcb1->OpenHandleCount > 1) + try_return (RC = STATUS_ACCESS_DENIED); + ASSERT(Fcb1->OpenHandleCount); + ASSERT(!Fcb1->IrpContextLite); + if(Fcb1->IrpContextLite) { + try_return (RC = STATUS_ACCESS_DENIED); + } + // Check if we have parallel/pending Close threads + if(Fcb1->CcbCount && !SingleDir) { + // if this is the 1st attempt, we'll try to + // synchronize with Close requests + // otherwise fail request + RC = STATUS_ACCESS_DENIED; +post_rename: + if(Fcb1->FCBFlags & UDF_FCB_POSTED_RENAME) { + Fcb1->FCBFlags &= ~UDF_FCB_POSTED_RENAME; + try_return (RC); + } + Fcb1->FCBFlags |= UDF_FCB_POSTED_RENAME; + try_return (RC = STATUS_PENDING); + } + + if(!DirObject2) { + // Make sure the name is of legal length. + if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); + NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); + } else { + // This name is by definition legal. + NewName = *((PUNICODE_STRING)&DirObject2->FileName); + } + + ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE; + + AdPrint((" %ws ->\n %ws\n", + Fcb1->FCBName->ObjectName.Buffer, + NewName.Buffer)); + + if(UDFIsDirOpened__(File1)) { + // We can't rename file because of unclean references. + // UDF_INFO package can safely do it, but NT side cannot. + // In this case NT requires STATUS_OBJECT_NAME_COLLISION + // rather than STATUS_ACCESS_DENIED + if(NT_SUCCESS(UDFFindFile__(Vcb, ic, &NewName, Dir2))) + try_return(RC = STATUS_OBJECT_NAME_COLLISION); + try_return (RC = STATUS_ACCESS_DENIED); + } else { + // Last check before Moving. + // We can't move across Dir referenced (even internally) file + if(!SingleDir) { + RC = UDFDoesOSAllowFileToBeMoved__(File1); + if(!NT_SUCCESS(RC)) { +// try_return(RC); + goto post_rename; + } + } + + ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); + ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); + ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); + + RC = UDFRenameMoveFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1); + } + if(!NT_SUCCESS(RC)) + try_return (RC); + + ASSERT(UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index)->FileInfo == File1); + + RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? + &UDFGlobalData.UnicodeStrRoot : + &(Dir2->Fcb->FCBName->ObjectName) ); + if(!NT_SUCCESS(RC)) try_return (RC); +// RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName)); +// if(!NT_SUCCESS(RC)) try_return (RC); + if(Dir2->ParentFile) { + RC = MyAppendUnicodeToString(&LocalPath, L"\\"); + if(!NT_SUCCESS(RC)) try_return (RC); + } + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USREN_TAG); + if(!NT_SUCCESS(RC)) try_return (RC); + + // Set Archive bit + DirNdx = UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index); + if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) { + Attr = UDFAttributesToNT(DirNdx, File1->Dloc->FileEntry); + if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) + UDFAttributesToUDF(DirNdx, File1->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); + } + // Update Parent Objects (mark 'em as modified) + if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) { + if(DirObject1) + DirObject1->Flags |= FO_FILE_MODIFIED; + if(DirObject2) { + DirObject2->Flags |= FO_FILE_MODIFIED; + if(!Replace) + DirObject2->Flags |= FO_FILE_SIZE_CHANGED; + } + } + // report changes + if(SingleDir && !Replace) { + UDFNotifyFullReportChange( Vcb, File1, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_OLD_NAME); +/* UDFNotifyFullReportChange( Vcb, File2, + UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_NEW_NAME );*/ + FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_NEW_NAME, + NULL); + } else { + UDFNotifyFullReportChange( Vcb, File1, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED); + if(Replace) { +/* UDFNotifyFullReportChange( Vcb, File2, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? + 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED, + NULL); + } else { +/* UDFNotifyFullReportChange( Vcb, File2, + UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? + 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(File1) ? + FILE_NOTIFY_CHANGE_DIR_NAME : + FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED, + NULL); + } + } + + // this will prevent structutre release before call to + // UDFCleanUpFcbChain() + UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->ReferenceCount)); + UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->NTRequiredFCB->CommonRefCount)); + ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); + + // Look through Ccb list & decrement OpenHandleCounter(s) + // acquire CcbList + if(!SingleDir) { + UDFAcquireResourceExclusive(&(Fcb1->CcbListResource),TRUE); + Link = Fcb1->NextCCB.Flink; + DirRefCount = 0; + FileInfoRefCount = 0; + ASSERT(Link != &(Fcb1->NextCCB)); + while (Link != &(Fcb1->NextCCB)) { + NextFileInfo = Dir1; + CurCcb = CONTAINING_RECORD(Link, UDFCCB, NextCCB); + ASSERT(CurCcb->TreeLength); + i = (CurCcb->TreeLength) ? (CurCcb->TreeLength - 1) : 0; + Link = Link->Flink; + UseClose = (CurCcb->CCBFlags & UDF_CCB_CLEANED) ? FALSE : TRUE; + + AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb, UseClose ? "Close" : "",i)); + // cleanup old parent chain + for(; i && NextFileInfo; i--) { + // remember parent file now + // it will prevent us from data losses + // due to eventual structure release + fi = NextFileInfo->ParentFile; + if(UseClose) { + ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount); + UDFCloseFile__(Vcb, NextFileInfo); + } + ASSERT_REF(NextFileInfo->Fcb->ReferenceCount > NextFileInfo->RefCount); + ASSERT_REF(NextFileInfo->Fcb->ReferenceCount); + ASSERT_REF(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount); + UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->ReferenceCount)); + UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount)); + ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount); + NextFileInfo = fi; + } + + if(CurCcb->TreeLength > 1) { + DirRefCount++; + if(UseClose) + FileInfoRefCount++; + CurCcb->TreeLength = 2; +#ifdef UDF_DBG + } else { + BrutePoint(); +#endif // UDF_DBG + } + } + UDFReleaseResource(&(Fcb1->CcbListResource)); + + ASSERT_REF(DirRefCount >= FileInfoRefCount); + // update counters & pointers + Fcb1->ParentFcb = Dir2->Fcb; + // move references to Dir2 + UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->ReferenceCount), DirRefCount); + UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->NTRequiredFCB->CommonRefCount), DirRefCount); + ASSERT_REF(Dir2->Fcb->ReferenceCount > Dir2->RefCount); + UDFReferenceFileEx__(Dir2,FileInfoRefCount); + ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); + } + ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); + ASSERT_REF(Dir2->RefCount); + + ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); + // Modify name in Fcb1 + if(Fcb1->FCBName) { + if(Fcb1->FCBName->ObjectName.Buffer) { + MyFreePool__(Fcb1->FCBName->ObjectName.Buffer); + } + UDFReleaseObjectName(Fcb1->FCBName); + } + Fcb1->FCBName = UDFAllocateObjectName(); + if(!(Fcb1->FCBName)) { +insuf_res: + BrutePoint(); + // UDFCleanUpFcbChain()... + if(AcquiredFcb1) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); + UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); + AcquiredDir1 = FALSE; + } + if(AcquiredDir1) { + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); + UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); + AcquiredDir1 = FALSE; + } + UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + + RC = MyCloneUnicodeString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName)); + if(!NT_SUCCESS(RC)) + goto insuf_res; +/* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName)); + if(!NT_SUCCESS(RC)) + goto insuf_res;*/ + // if Dir2 is a RootDir, we shoud not append '\\' because + // uit will be the 2nd '\\' character (RootDir's name is also '\\') + if(Dir2->ParentFile) { + RC = MyAppendUnicodeToString(&(Fcb1->FCBName->ObjectName), L"\\"); + if(!NT_SUCCESS(RC)) + goto insuf_res; + } + RC = MyAppendUnicodeStringToStringTag(&(Fcb1->FCBName->ObjectName), &NewName, MEM_USREN2_TAG); + if(!NT_SUCCESS(RC)) + goto insuf_res; + + ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); + ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); + ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); + + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredFcb1) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); + UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); + } + if(AcquiredDir1) { + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); + UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); + } + // perform protected structure release + if(NT_SUCCESS(RC) && + (RC != STATUS_PENDING)) { + ASSERT(AcquiredVcb); + UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE); + ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); + ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); + } + + if(AcquiredVcb) { + if(AcquiredVcbEx) + UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); + } else { + // caller assumes Vcb to be acquired shared + BrutePoint(); + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + } + + if(LocalPath.Buffer) { + MyFreePool__(LocalPath.Buffer); + } + } _SEH2_END; + + return RC; +} // end UDFRename() + +#endif //UDF_READ_ONLY_BUILD + +LONG +UDFFindFileId( + IN PVCB Vcb, + IN LONGLONG Id + ) +{ + if(!Vcb->FileIdCache) return (-1); + for(ULONG i=0; iFileIdCount; i++) { + if(Vcb->FileIdCache[i].Id == Id) return i; + } + return (-1); +} // end UDFFindFileId() + +LONG +UDFFindFreeFileId( + IN PVCB Vcb, + IN LONGLONG Id + ) +{ + if(!Vcb->FileIdCache) { + if(!(Vcb->FileIdCache = (PUDFFileIDCacheItem)MyAllocatePool__(NonPagedPool, sizeof(UDFFileIDCacheItem)*FILE_ID_CACHE_GRANULARITY))) + return (-1); + RtlZeroMemory(Vcb->FileIdCache, FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem)); + Vcb->FileIdCount = FILE_ID_CACHE_GRANULARITY; + } + for(ULONG i=0; iFileIdCount; i++) { + if(!Vcb->FileIdCache[i].FullName.Buffer) return i; + } + if(!MyReallocPool__((PCHAR)(Vcb->FileIdCache), Vcb->FileIdCount*sizeof(UDFFileIDCacheItem), + (PCHAR*)&(Vcb->FileIdCache), (Vcb->FileIdCount+FILE_ID_CACHE_GRANULARITY)*sizeof(UDFFileIDCacheItem))) { + return (-1); + } + RtlZeroMemory(&(Vcb->FileIdCache[Vcb->FileIdCount]), FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem)); + Vcb->FileIdCount += FILE_ID_CACHE_GRANULARITY; + return (Vcb->FileIdCount - FILE_ID_CACHE_GRANULARITY); +} // end UDFFindFreeFileId() + +NTSTATUS +UDFStoreFileId( + IN PVCB Vcb, + IN PtrUDFCCB Ccb, + IN PUDF_FILE_INFO fi, + IN LONGLONG Id + ) +{ + LONG i; + NTSTATUS RC = STATUS_SUCCESS; + + if((i = UDFFindFileId(Vcb, Id)) == (-1)) { + if((i = UDFFindFreeFileId(Vcb, Id)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES; + } else { + return STATUS_SUCCESS; + } + Vcb->FileIdCache[i].Id = Id; + Vcb->FileIdCache[i].CaseSens = (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? TRUE : FALSE; + RC = MyCloneUnicodeString(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName)); +/* if(NT_SUCCESS(RC)) { + RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG); + }*/ + return RC; +} // end UDFStoreFileId() + +NTSTATUS +UDFRemoveFileId( + IN PVCB Vcb, + IN LONGLONG Id + ) +{ + LONG i; + + if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_INVALID_PARAMETER; + MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer); + RtlZeroMemory(&(Vcb->FileIdCache[i]), sizeof(UDFFileIDCacheItem)); + return STATUS_SUCCESS; +} // end UDFRemoveFileId() + +VOID +UDFReleaseFileIdCache( + IN PVCB Vcb + ) +{ + if(!Vcb->FileIdCache) return; + for(ULONG i=0; iFileIdCount; i++) { + if(Vcb->FileIdCache[i].FullName.Buffer) { + MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer); + } + } + MyFreePool__(Vcb->FileIdCache); + Vcb->FileIdCache = NULL; + Vcb->FileIdCount = 0; +} // end UDFReleaseFileIdCache() + +NTSTATUS +UDFGetOpenParamsByFileId( + IN PVCB Vcb, + IN LONGLONG Id, + OUT PUNICODE_STRING* FName, + OUT BOOLEAN* CaseSens + ) +{ + LONG i; + + if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_NOT_FOUND; + (*FName) = &(Vcb->FileIdCache[i].FullName); + (*CaseSens) = !(Vcb->FileIdCache[i].CaseSens); + return STATUS_SUCCESS; +} // end UDFGetOpenParamsByFileId() + +#ifndef UDF_READ_ONLY_BUILD + +#ifdef UDF_ALLOW_HARD_LINKS +/* + create hard link for the file + */ +NTSTATUS +UDFHardLink( + IN PIO_STACK_LOCATION PtrSp, + IN PtrUDFFCB Fcb1, + IN PtrUDFCCB Ccb1, + IN PFILE_OBJECT FileObject1, // Source File + IN PFILE_LINK_INFORMATION PtrBuffer + ) +{ + // Target Directory + PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject; + // Overwite Flag + BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists && + PtrBuffer->ReplaceIfExists; + NTSTATUS RC; + PVCB Vcb = Fcb1->Vcb; + PtrUDFFCB Fcb2; + BOOLEAN ic; + BOOLEAN AcquiredVcb = TRUE; + BOOLEAN AcquiredVcbEx = FALSE; + BOOLEAN AcquiredDir1 = FALSE; + BOOLEAN AcquiredFcb1 = FALSE; + BOOLEAN SingleDir = TRUE; + + PUDF_FILE_INFO File1; + PUDF_FILE_INFO Dir1 = NULL; + PUDF_FILE_INFO Dir2; + + UNICODE_STRING NewName; + UNICODE_STRING LocalPath; +// PtrUDFCCB CurCcb = NULL; + + AdPrint(("UDFHardLink\n")); + + LocalPath.Buffer = NULL; + + _SEH2_TRY { + + // do we try to link Volume ? + if(!(File1 = Fcb1->FileInfo)) + try_return (RC = STATUS_ACCESS_DENIED); + + // do we try to link RootDir ? + if(!(Dir1 = File1->ParentFile)) + try_return (RC = STATUS_ACCESS_DENIED); + + // do we try to link Stream / Stream Dir ? +#ifdef UDF_ALLOW_LINKS_TO_STREAMS + if(UDFIsAStreamDir(File1)) + try_return (RC = STATUS_ACCESS_DENIED); +#else //UDF_ALLOW_LINKS_TO_STREAMS + if(UDFIsAStream(File1) || UDFIsAStreamDir(File1) /*|| + UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/) + try_return (RC = STATUS_ACCESS_DENIED); +#endif // UDF_ALLOW_LINKS_TO_STREAMS + + // do we try to link to RootDir or Volume ? + if(!DirObject2) { + Dir2 = File1->ParentFile; + DirObject2 = FileObject1->RelatedFileObject; + } else + if(DirObject2->FsContext2 && + (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) { + Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo; + } else { + try_return (RC = STATUS_INVALID_PARAMETER); + } + + // check target dir + if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED); + + // Stream can't be a Dir or have Streams + if(UDFIsAStreamDir(Dir2)) { + try_return (RC = STATUS_ACCESS_DENIED); +/* if(UDFIsADirectory(File1) || + UDFHasAStreamDir(File1)) { + BrutePoint(); + try_return (RC = STATUS_ACCESS_DENIED); + }*/ + } + +/* if(UDFIsAStreamDir(Dir2)) + try_return (RC = STATUS_ACCESS_DENIED);*/ + + RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx, + &SingleDir, + &AcquiredDir1, &AcquiredFcb1, + Ccb1, File1, + Dir1, Dir2, + TRUE); // it is HLink operation + if(!NT_SUCCESS(RC)) + try_return(RC); + + // check if the source file is used + if(!DirObject2) { + // Make sure the name is of legal length. + if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); + NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); + } else { + // This name is by definition legal. + NewName = *((PUNICODE_STRING)&DirObject2->FileName); + } + + ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE; + + AdPrint((" %ws ->\n %ws\n", + Fcb1->FCBName->ObjectName.Buffer, + NewName.Buffer)); + + RC = UDFHardLinkFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1); + if(!NT_SUCCESS(RC)) try_return (RC); + + // Update Parent Objects (mark 'em as modified) + if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) { + if(DirObject2) { + DirObject2->Flags |= FO_FILE_MODIFIED; + if(!Replace) + DirObject2->Flags |= FO_FILE_SIZE_CHANGED; + } + } + // report changes + UDFNotifyFullReportChange( Vcb, File1, + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS, + FILE_ACTION_MODIFIED ); + + RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? + &UDFGlobalData.UnicodeStrRoot : + &(Dir2->Fcb->FCBName->ObjectName)); + if(!NT_SUCCESS(RC)) try_return (RC); +/* RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName)); + if(!NT_SUCCESS(RC)) try_return (RC);*/ + // if Dir2 is a RootDir, we shoud not append '\\' because + // it will be the 2nd '\\' character (RootDir's name is also '\\') + if(Dir2->ParentFile) { + RC = MyAppendUnicodeToString(&LocalPath, L"\\"); + if(!NT_SUCCESS(RC)) try_return (RC); + } + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USHL_TAG); + if(!NT_SUCCESS(RC)) try_return (RC); + + if(!Replace) { +/* UDFNotifyFullReportChange( Vcb, File2, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED, + NULL); + } else { +/* UDFNotifyFullReportChange( Vcb, File2, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + NULL); + } + + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AcquiredFcb1) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); + UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); + } + if(AcquiredDir1) { + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); + UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); + } + if(AcquiredVcb) { + if(AcquiredVcbEx) + UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); + } else { + // caller assumes Vcb to be acquired shared + BrutePoint(); + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + } + + if(LocalPath.Buffer) { + MyFreePool__(LocalPath.Buffer); + } + } _SEH2_END; + + return RC; +} // end UDFHardLink() +#endif //UDF_ALLOW_HARD_LINKS + +#endif //UDF_READ_ONLY_BUILD diff --git a/reactos/drivers/filesystems/udfs/filter.cpp b/reactos/drivers/filesystems/udfs/filter.cpp new file mode 100644 index 00000000000..069149d7798 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/filter.cpp @@ -0,0 +1,157 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module Name: Filter.cpp + + Abstract: + + Contains code to handle register file system notification and attach to + CDFS if required. + + Environment: + + Kernel mode only + +*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_FILTER + +VOID +UDFCheckOtherFS(PDEVICE_OBJECT deviceObject) { + PFILTER_DEV_EXTENSION FilterDevExt; + PDEVICE_OBJECT filterDeviceObject; + NTSTATUS RC; + +// BrutePoint(); + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + if (!NT_SUCCESS(RC = IoCreateDevice( + UDFGlobalData.DriverObject, // our driver object + sizeof(FILTER_DEV_EXTENSION), // don't need an extension + // for this object + NULL, // name - can be used to + // "open" the driver + // see the R.Nagar's book + // for alternate choices + FILE_DEVICE_CD_ROM_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an + // exclusive device, though + // we might + FALSE, + &filterDeviceObject))) { + // failed to create a filter device object, leave ... + // Release the global resource. + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + return; + } + FilterDevExt = (PFILTER_DEV_EXTENSION)filterDeviceObject->DeviceExtension; + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(FilterDevExt, sizeof(FILTER_DEV_EXTENSION)); + + // Initialize the signature fields + FilterDevExt->NodeIdentifier.NodeType = UDF_NODE_TYPE_FILTER_DEVOBJ; + FilterDevExt->NodeIdentifier.NodeSize = sizeof(FILTER_DEV_EXTENSION); + + KdPrint(("UDFCheckOtherFS: Attaching filter devobj %x to FS devobj %x \n",filterDeviceObject,deviceObject)); + deviceObject = IoGetAttachedDevice( deviceObject ); + KdPrint(("UDFCheckOtherFS: top devobj is %x \n",deviceObject)); + FilterDevExt->lowerFSDeviceObject = deviceObject; + + RC = IoAttachDeviceByPointer( filterDeviceObject, deviceObject ); + if (!NT_SUCCESS(RC)) { + IoDeleteDevice( filterDeviceObject ); + } else { + filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + } + // Release the global resource. + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); +} + +VOID +UDFCheckOtherFSByName(PCWSTR DeviceObjectName) { + PFILE_OBJECT fileObject; + PDEVICE_OBJECT deviceObject; + UNICODE_STRING nameString; + NTSTATUS RC; + + KdPrint(("UDFCheckOtherFSByName: trying %s \n",DeviceObjectName)); + + RtlInitUnicodeString( &nameString, DeviceObjectName ); + RC = IoGetDeviceObjectPointer( + &nameString, + FILE_READ_ATTRIBUTES, + &fileObject, + &deviceObject + ); + + if (!NT_SUCCESS(RC)) { + KdPrint(("UDFCheckOtherFSByName: error %x while calling IoGetDeviceObjectPointer \n",RC)); + return; + } + + UDFCheckOtherFS(deviceObject); + + ObDereferenceObject( fileObject ); +} + +#if 0 +VOID +NTAPI +UDFFsNotification( + IN PDEVICE_OBJECT DeviceObject, + IN BOOLEAN FsActive + ) + +/* + +Routine Description: + + This routine is invoked whenever a file system has either registered or + unregistered itself as an active file system. + + For the former case, this routine creates a device object and attaches it + to the specified file system's device object. This allows this driver + to filter all requests to that file system. + + For the latter case, this file system's device object is located, + detached, and deleted. This removes this file system as a filter for + the specified file system. + +Arguments: + + DeviceObject - Pointer to the file system's device object. + + FsActive - bolean indicating whether the file system has registered + (TRUE) or unregistered (FALSE) itself as an active file system. + +Return Value: + + None. + +*/ + +{ + // Begin by determine whether or not the file system is a cdrom-based file + // system. If not, then this driver is not concerned with it. + if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) { + return; + } + + // Begin by determining whether this file system is registering or + // unregistering as an active file system. + if (FsActive) { + KdPrint(("UDFFSNotification \n")); + UDFCheckOtherFS(DeviceObject); + } +} +#endif diff --git a/reactos/drivers/filesystems/udfs/flush.cpp b/reactos/drivers/filesystems/udfs/flush.cpp new file mode 100644 index 00000000000..a697bae52b5 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/flush.cpp @@ -0,0 +1,632 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Flush.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Flush Buffers" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_FLUSH + + + +/************************************************************************* +* +* Function: UDFFlush() +* +* Description: +* The I/O Manager will invoke this routine to handle a flush buffers +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFlush( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFFlush: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonFlush(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFFlush() + + + +/************************************************************************* +* +* Function: UDFCommonFlush() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFCommonFlush( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN AcquiredVCB = FALSE; + BOOLEAN AcquiredFCB = FALSE; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = TRUE; + + KdPrint(("UDFCommonFlush: \n")); + + _SEH2_TRY { + + // Get some of the parameters supplied to us + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous. + if (!CanWait) { + PostRequest = TRUE; + try_return(RC); + } + + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + NtReqFcb = Fcb->NTRequiredFCB; + + // Check the type of object passed-in. That will determine the course of + // action we take. + if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || (Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) { + + if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + Vcb = (PVCB)(Fcb); + } else { + Vcb = Fcb->Vcb; + } + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + AcquiredVCB = TRUE; + // The caller wishes to flush all files for the mounted + // logical volume. The flush volume routine below should simply + // walk through all of the open file streams, acquire the + // VCB resource, and request the flush operation from the Cache + // Manager. Basically, the sequence of operations listed below + // for a single file should be executed on all open files. + + UDFFlushLogicalVolume(PtrIrpContext, Irp, Vcb, 0); + + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVCB = FALSE; + + try_return(RC); + } else + if (!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + // This is a regular file. + Vcb = Fcb->Vcb; + ASSERT(Vcb); + if(!ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) && + !ExIsResourceAcquiredSharedLite(&(Vcb->VCBResource))) { + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + AcquiredVCB = TRUE; + } + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE); + AcquiredFCB = TRUE; + + // Request the Cache Manager to perform a flush operation. + // Further, instruct the Cache Manager that we wish to flush the + // entire file stream. + UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0); + RC = Irp->IoStatus.Status; + + // Some log-based FSD implementations may wish to flush their + // log files at this time. Finally, we should update the time-stamp + // values for the file stream appropriately. This would involve + // obtaining the current time and modifying the appropriate directory + // entry fields. + } else { + Vcb = Fcb->Vcb; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + if (AcquiredVCB) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVCB = FALSE; + } + + if(!_SEH2_AbnormalTermination()) { + if (PostRequest) { + // Nothing to lock now. + BrutePoint(); + RC = UDFPostRequest(PtrIrpContext, Irp); + } else { + // Some applications like this request very much + // (ex. WinWord). But it's not a good idea for CD-R/RW media + if(Vcb->FlushMedia) { + PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + NTSTATUS RC1 = STATUS_SUCCESS; + + // Send the request down at this point. + // To do this, we must set the next IRP stack location, and + // maybe set a completion routine. + // Be careful about marking the IRP pending if the lower level + // driver returned pending and we do have a completion routine! + PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp); + *PtrNextIoStackLocation = *IrpSp; + + // Set the completion routine to "eat-up" any + // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower + // level driver. + IoSetCompletionRoutine(Irp, UDFFlushCompletion, NULL, TRUE, TRUE, TRUE); + + RC1 = IoCallDriver(Vcb->TargetDeviceObject, Irp); + + RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1); + + // Release the IRP context at this time. + UDFReleaseIrpContext(PtrIrpContext); + } else { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } + } + } _SEH2_END; + + return(RC); +} // end UDFCommonFlush() + + +/************************************************************************* +* +* Function: UDFFlushAFile() +* +* Description: +* Tell the Cache Manager to perform a flush. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +ULONG +UDFFlushAFile( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + OUT PIO_STATUS_BLOCK PtrIoStatus, + IN ULONG FlushFlags + ) +{ + BOOLEAN SetArchive = FALSE; + BOOLEAN PurgeCache = FALSE; + ULONG ret_val = 0; + + KdPrint(("UDFFlushAFile: \n")); + if(!Fcb) + return 0; + + _SEH2_TRY { + if(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) + return 0; + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +#ifndef UDF_READ_ONLY_BUILD + // Flush Security if required + _SEH2_TRY { + UDFWriteSecurity(Fcb->Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +#endif //UDF_READ_ONLY_BUILD + // Flush SDir if any + _SEH2_TRY { + if(UDFHasAStreamDir(Fcb->FileInfo) && + Fcb->FileInfo->Dloc->SDirInfo && + !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) ) { + ret_val |= + UDFFlushADirectory(Fcb->Vcb, Fcb->FileInfo->Dloc->SDirInfo, PtrIoStatus, FlushFlags); + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + // Flush File + _SEH2_TRY { + if((Fcb->CachedOpenHandleCount || !Fcb->OpenHandleCount) && + Fcb->NTRequiredFCB->SectionObject.DataSectionObject) { + if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) + && + ((Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED) || + (Ccb && !(Ccb->CCBFlags & UDF_CCB_FLUSHED)) )) { + MmPrint((" CcFlushCache()\n")); + CcFlushCache(&(Fcb->NTRequiredFCB->SectionObject), NULL, 0, PtrIoStatus); + } + // notice, that we should purge cache + // we can't do it now, because it may cause last Close + // request & thus, structure deallocation + PurgeCache = TRUE; + +#ifndef UDF_READ_ONLY_BUILD + if(Ccb) { + if( (Ccb->FileObject->Flags & FO_FILE_MODIFIED) && + !(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET)) { + if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME) { + LONGLONG NtTime; + KeQuerySystemTime((PLARGE_INTEGER)&NtTime); + UDFSetFileXTime(Fcb->FileInfo, NULL, NULL, NULL, &NtTime); + Fcb->NTRequiredFCB->LastWriteTime.QuadPart = NtTime; + } + SetArchive = TRUE; + Ccb->FileObject->Flags &= ~FO_FILE_MODIFIED; + } + if(Ccb->FileObject->Flags & FO_FILE_SIZE_CHANGED) { + LONGLONG ASize = UDFGetFileAllocationSize(Fcb->Vcb, Fcb->FileInfo); + UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, &ASize); + Ccb->FileObject->Flags &= ~FO_FILE_SIZE_CHANGED; + } + } +#endif //UDF_READ_ONLY_BUILD + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + _SEH2_TRY { +#ifndef UDF_READ_ONLY_BUILD + if(SetArchive && + (Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) { + ULONG Attr; + PDIR_INDEX_ITEM DirNdx; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); + // Archive bit + Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry); + if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) + UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); + } +#endif //UDF_READ_ONLY_BUILD + UDFFlushFile__( Fcb->Vcb, Fcb->FileInfo, FlushFlags); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + +/* if(PurgeCache) { + _SEH2_TRY { + MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection( &(Fcb->NTRequiredFCB->SectionObject), NULL, 0, FALSE ); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + }*/ + + return ret_val; +} // end UDFFlushAFile() + +/************************************************************************* +* +* Function: UDFFlushADirectory() +* +* Description: +* Tell the Cache Manager to perform a flush for all files +* in current directory & all subdirectories and flush all metadata +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +ULONG +UDFFlushADirectory( + IN PVCB Vcb, + IN PUDF_FILE_INFO FI, + OUT PIO_STATUS_BLOCK PtrIoStatus, + IN ULONG FlushFlags + ) +{ + KdPrint(("UDFFlushADirectory: \n")); + PDIR_INDEX_HDR hDI; + PDIR_INDEX_ITEM DI; +// BOOLEAN Referenced = FALSE; + ULONG ret_val = 0; + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) + return 0; + + if(!FI || !FI->Dloc || !FI->Dloc->DirIndex) goto SkipFlushDir; + hDI = FI->Dloc->DirIndex; + + // Flush Security if required + _SEH2_TRY { + UDFWriteSecurity(Vcb, FI->Fcb, &(FI->Fcb->NTRequiredFCB->SecurityDesc)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + // Flush SDir if any + _SEH2_TRY { + if(UDFHasAStreamDir(FI) && + FI->Dloc->SDirInfo && + !UDFIsSDirDeleted(FI->Dloc->SDirInfo) ) { + ret_val |= + UDFFlushADirectory(Vcb, FI->Dloc->SDirInfo, PtrIoStatus, FlushFlags); + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + // Flush Dir Tree + _SEH2_TRY { + UDF_DIR_SCAN_CONTEXT ScanContext; + PUDF_FILE_INFO tempFI; + + if(UDFDirIndexInitScan(FI, &ScanContext, 2)) { + while(DI = UDFDirIndexScan(&ScanContext, &tempFI)) { + // Flush Dir entry + _SEH2_TRY { + if(!tempFI) continue; + if(UDFIsADirectory(tempFI)) { + UDFFlushADirectory(Vcb, tempFI, PtrIoStatus, FlushFlags); + } else { + UDFFlushAFile(tempFI->Fcb, NULL, PtrIoStatus, FlushFlags); + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + if(UDFFlushIsBreaking(Vcb, FlushFlags)) { + ret_val |= UDF_FLUSH_FLAGS_INTERRUPTED; + break; + } + } + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +SkipFlushDir: + // Flush Dir + _SEH2_TRY { + UDFFlushFile__( Vcb, FI, FlushFlags ); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + return ret_val; +} // end UDFFlushADirectory() + +/************************************************************************* +* +* Function: UDFFlushLogicalVolume() +* +* Description: +* Flush everything beginning from root directory. +* Vcb must be previously acquired exclusively. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +ULONG +UDFFlushLogicalVolume( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp, + IN PVCB Vcb, + IN ULONG FlushFlags + ) +{ + ULONG ret_val = 0; +#ifndef UDF_READ_ONLY_BUILD + IO_STATUS_BLOCK IoStatus; + + KdPrint(("UDFFlushLogicalVolume: \n")); + + _SEH2_TRY { + if(Vcb->VCBFlags & (UDF_VCB_FLAGS_RAW_DISK/* | + UDF_VCB_FLAGS_MEDIA_READ_ONLY*/)) + return 0; + if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + !(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED)) + return 0; + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) + return 0; + + // NOTE: This function may also be invoked internally as part of + // processing a shutdown request. + ASSERT(Vcb->RootDirFCB); + ret_val |= UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, FlushFlags); + +// if(UDFFlushIsBreaking(Vcb, FlushFlags)) +// return; + // flush internal cache + if(FlushFlags & UDF_FLUSH_FLAGS_LITE) { + KdPrint((" Lite flush, keep Modified=%d.\n", Vcb->Modified)); + } else { + if(Vcb->VerifyOnWrite) { + KdPrint(("UDF: Flushing cache for verify\n")); + //WCacheFlushAll__(&(Vcb->FastCache), Vcb); + WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); + UDFVFlush(Vcb); + } + // umount (this is internal operation, NT will "dismount" volume later) + UDFUmount__(Vcb); + + UDFPreClrModified(Vcb); + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + UDFClrModified(Vcb); + } + + } _SEH2_FINALLY { + ; + } _SEH2_END; +#endif //UDF_READ_ONLY_BUILD + + return ret_val; +} // end UDFFlushLogicalVolume() + + +/************************************************************************* +* +* Function: UDFFlushCompletion() +* +* Description: +* Eat up any bad errors. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFFlushCompletion( + PDEVICE_OBJECT PtrDeviceObject, + PIRP Irp, + PVOID Context + ) +{ +// NTSTATUS RC = STATUS_SUCCESS; + + KdPrint(("UDFFlushCompletion: \n")); + + if (Irp->PendingReturned) { + IoMarkIrpPending(Irp); + } + + if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) { + // cannot do much here, can we? + Irp->IoStatus.Status = STATUS_SUCCESS; + } + + return(STATUS_SUCCESS); +} // end UDFFlushCompletion() + + +/* + Check if we should break FlushTree process + */ +BOOLEAN +UDFFlushIsBreaking( + IN PVCB Vcb, + IN ULONG FlushFlags + ) +{ + BOOLEAN ret_val = FALSE; +// if(!(FlushFlags & UDF_FLUSH_FLAGS_BREAKABLE)) + return FALSE; + UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE); + ret_val = (Vcb->VCBFlags & UDF_VCB_FLAGS_FLUSH_BREAK_REQ) ? TRUE : FALSE; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_FLUSH_BREAK_REQ; + UDFReleaseResource(&(Vcb->FlushResource)); + return ret_val; +} // end UDFFlushIsBreaking() + +/* + Signal FlushTree break request. Note, this is + treated as recommendation only + */ +VOID +UDFFlushTryBreak( + IN PVCB Vcb + ) +{ + UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE); + Vcb->VCBFlags |= UDF_VCB_FLAGS_FLUSH_BREAK_REQ; + UDFReleaseResource(&(Vcb->FlushResource)); +} // end UDFFlushTryBreak() diff --git a/reactos/drivers/filesystems/udfs/fscntrl.cpp b/reactos/drivers/filesystems/udfs/fscntrl.cpp new file mode 100644 index 00000000000..ff8f6ab9c3d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/fscntrl.cpp @@ -0,0 +1,2642 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module Name: FsCntrl.cpp + + Abstract: + + Contains code to handle the "File System IOCTL" dispatch entry point. + + Environment: + + Kernel mode only + +*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_FS_CONTROL + +NTSTATUS UDFBlankMount(IN PVCB Vcb); + +PDIR_INDEX_HDR UDFDirIndexAlloc(IN uint_di i); + +/* + Function: UDFFSControl() + + Description: + The I/O Manager will invoke this routine to handle a File System + Control request (this is IRP_MJ_FILE_SYSTEM_CONTROL dispatch point) + +*/ +NTSTATUS +NTAPI +UDFFSControl( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("\nUDFFSControl: \n\n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonFSControl(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + KdPrint(("UDFFSControl: exception ***")); + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if(AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFFSControl() + +/* + Function: UDFCommonFSControl() + + Description: + The actual work is performed here. + + Expected Interrupt Level (for execution) : + IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution + to be deferred to a worker thread context) + + Return Value: STATUS_SUCCESS/Error +*/ + +NTSTATUS +NTAPI +UDFCommonFSControl( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_UNRECOGNIZED_VOLUME; + PIO_STACK_LOCATION IrpSp = NULL; +// PDEVICE_OBJECT PtrTargetDeviceObject = NULL; + + KdPrint(("\nUDFCommonFSControl\n\n")); +// BrutePoint(); + + _SEH2_TRY { + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + switch ((IrpSp)->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + KdPrint((" UDFFSControl: UserFsReq request ....\n")); + + RC = UDFUserFsCtrlRequest(PtrIrpContext,Irp); + break; + case IRP_MN_MOUNT_VOLUME: + + KdPrint((" UDFFSControl: MOUNT_VOLUME request ....\n")); + + RC = UDFMountVolume(PtrIrpContext,Irp); + break; + case IRP_MN_VERIFY_VOLUME: + + KdPrint((" UDFFSControl: VERIFY_VOLUME request ....\n")); + + RC = UDFVerifyVolume(Irp); + break; + default: + KdPrint((" UDFFSControl: STATUS_INVALID_DEVICE_REQUEST MinorFunction %x\n", (IrpSp)->MinorFunction)); + RC = STATUS_INVALID_DEVICE_REQUEST; + + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + break; + } + +//try_exit: NOTHING; + } _SEH2_FINALLY { + if (!_SEH2_AbnormalTermination()) { + // Free up the Irp Context + KdPrint((" UDFCommonFSControl: finally\n")); + UDFReleaseIrpContext(PtrIrpContext); + } else { + KdPrint((" UDFCommonFSControl: finally after exception ***\n")); + } + } _SEH2_END; + + return(RC); +} // end UDFCommonFSControl() + +/* +Routine Description: + This is the common routine for implementing the user's requests made + through NtFsControlFile. + +Arguments: + Irp - Supplies the Irp being processed + +Return Value: + NTSTATUS - The return status for the operation + +*/ +NTSTATUS +NTAPI +UDFUserFsCtrlRequest( + PtrUDFIrpContext IrpContext, + PIRP Irp + ) +{ + NTSTATUS RC; + PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation( Irp ); + + // Case on the control code. + switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) { + + case FSCTL_REQUEST_OPLOCK_LEVEL_1 : + case FSCTL_REQUEST_OPLOCK_LEVEL_2 : + case FSCTL_REQUEST_BATCH_OPLOCK : + case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE : + case FSCTL_OPBATCH_ACK_CLOSE_PENDING : + case FSCTL_OPLOCK_BREAK_NOTIFY : + case FSCTL_OPLOCK_BREAK_ACK_NO_2 : + case FSCTL_REQUEST_FILTER_OPLOCK : + + KdPrint(("UDFUserFsCtrlRequest: OPLOCKS\n")); + RC = STATUS_INVALID_DEVICE_REQUEST; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + break; +/* + RC = UDFOplockRequest( IrpContext, Irp ); + break; +*/ + case FSCTL_INVALIDATE_VOLUMES : + + RC = UDFInvalidateVolumes( IrpContext, Irp ); + break; +/* + case FSCTL_MOVE_FILE: + + case FSCTL_QUERY_ALLOCATED_RANGES: + case FSCTL_SET_ZERO_DATA: + case FSCTL_SET_SPARSE: + + case FSCTL_MARK_VOLUME_DIRTY: + + RC = UDFDirtyVolume( IrpContext, Irp ); + break; + + */ + case FSCTL_IS_VOLUME_DIRTY: + + RC = UDFIsVolumeDirty(IrpContext, Irp); + break; + + case FSCTL_ALLOW_EXTENDED_DASD_IO: + + KdPrint(("UDFUserFsCtrlRequest: FSCTL_ALLOW_EXTENDED_DASD_IO\n")); + // DASD i/o is always permitted + // So, no-op this call + RC = STATUS_SUCCESS; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case FSCTL_DISMOUNT_VOLUME: + + RC = UDFDismountVolume( IrpContext, Irp ); + break; + + case FSCTL_IS_VOLUME_MOUNTED: + + RC = UDFIsVolumeMounted( IrpContext, Irp ); + break; + + case FSCTL_FILESYSTEM_GET_STATISTICS: + + RC = UDFGetStatistics( IrpContext, Irp ); + break; + + case FSCTL_LOCK_VOLUME: + + RC = UDFLockVolume( IrpContext, Irp ); + break; + + case FSCTL_UNLOCK_VOLUME: + + RC = UDFUnlockVolume( IrpContext, Irp ); + break; + + case FSCTL_IS_PATHNAME_VALID: + + RC = UDFIsPathnameValid( IrpContext, Irp ); + break; + + case FSCTL_GET_VOLUME_BITMAP: + + KdPrint(("UDFUserFsCtrlRequest: FSCTL_GET_VOLUME_BITMAP\n")); + RC = UDFGetVolumeBitmap( IrpContext, Irp ); + break; + + case FSCTL_GET_RETRIEVAL_POINTERS: + + KdPrint(("UDFUserFsCtrlRequest: FSCTL_GET_RETRIEVAL_POINTERS\n")); + RC = UDFGetRetrievalPointers( IrpContext, Irp, 0 ); + break; + + + // We don't support any of the known or unknown requests. + default: + + KdPrint(("UDFUserFsCtrlRequest: STATUS_INVALID_DEVICE_REQUEST for %x\n", + IrpSp->Parameters.FileSystemControl.FsControlCode)); + RC = STATUS_INVALID_DEVICE_REQUEST; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + IoCompleteRequest(Irp,IO_DISK_INCREMENT); + return RC; + +} // end UDFUserFsCtrlRequest() + + +/* +Routine Description: + This is the common routine for implementing the mount requests + +Arguments: + Irp - Supplies the Irp being processed + +Return Value: + NTSTATUS - The return status for the operation + +*/ +NTSTATUS +NTAPI +UDFMountVolume( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp + ) +{ + NTSTATUS RC; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PDEVICE_OBJECT TargetDeviceObject = NULL; + PFILTER_DEV_EXTENSION filterDevExt; + PDEVICE_OBJECT fsDeviceObject; + PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; + PVCB Vcb = NULL; +// PVCB OldVcb = NULL; + PDEVICE_OBJECT VolDo = NULL; + IO_STATUS_BLOCK Iosb; + ULONG MediaChangeCount = 0; + ULONG Characteristics; + DEVICE_TYPE FsDeviceType; + BOOLEAN RestoreDoVerify = FALSE; + BOOLEAN WrongMedia = FALSE; + BOOLEAN RemovableMedia = TRUE; + BOOLEAN CompleteIrp = FALSE; + ULONG Mode; + TEST_UNIT_READY_USER_OUT TestUnitReadyBuffer; + ULONG i; + LARGE_INTEGER delay; + BOOLEAN VcbAcquired = FALSE; + BOOLEAN DeviceNotTouched = TRUE; + BOOLEAN Locked = FALSE; + int8* ioBuf = NULL; + + ASSERT(IrpSp); + KdPrint(("\n !!! UDFMountVolume\n")); +// KdPrint(("Build " VER_STR_PRODUCT "\n\n")); + + fsDeviceObject = PtrIrpContext->TargetDeviceObject; + KdPrint(("Mount on device object %x\n")); + filterDevExt = (PFILTER_DEV_EXTENSION)fsDeviceObject->DeviceExtension; + if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_FILTER_DEVOBJ && + filterDevExt->NodeIdentifier.NodeSize == sizeof(FILTER_DEV_EXTENSION)) { + CompleteIrp = FALSE; + } else + if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_UDFFS_DEVOBJ && + filterDevExt->NodeIdentifier.NodeSize == sizeof(UDFFS_DEV_EXTENSION)) { + CompleteIrp = TRUE; + } else { + KdPrint(("Invalid node type in FS or FILTER DeviceObject\n")); + ASSERT(FALSE); + } + // Get a pointer to the target physical/virtual device object. + TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; + + if(((Characteristics = TargetDeviceObject->Characteristics) & FILE_FLOPPY_DISKETTE) || + (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_BEING_UNLOADED) ) { + WrongMedia = TRUE; + } else { + RemovableMedia = (Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE; + if(TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM) { + if(UDFGetRegParameter(NULL, REG_MOUNT_ON_CDONLY_NAME, TRUE)) { + WrongMedia = TRUE; + } + } + if(TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) { + FsDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; +#ifdef UDF_HDD_SUPPORT + } else + if (TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) { + if(RemovableMedia) { + if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_ZIP_NAME, FALSE)) { + WrongMedia = TRUE; + } + } else { + if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_HDD_NAME, FALSE)) { + WrongMedia = TRUE; + } + } + FsDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM; +#endif //UDF_HDD_SUPPORT + } else { + WrongMedia = TRUE; + } + } + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + _SEH2_TRY { + + UDFScanForDismountedVcb(PtrIrpContext); + + if(WrongMedia) try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + + if(RemovableMedia) { + KdPrint(("UDFMountVolume: removable media\n")); + // just remember current MediaChangeCount + // or fail if No Media .... + + // experimental CHECK_VERIFY, for fucking BENQ DVD_DD_1620 + + // Now we can get device state via GET_EVENT (if supported) + // or still one TEST_UNIT_READY command + RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY, + TargetDeviceObject, + NULL,0, + &MediaChangeCount,sizeof(ULONG), + FALSE,&Iosb ); + + // Send TEST_UNIT_READY comment + // This can spin-up or wake-up the device + if(UDFGetRegParameter(NULL, UDF_WAIT_CD_SPINUP, TRUE)) { + delay.QuadPart = -15000000LL; // 1.5 sec + for(i=0; iPreventMediaRemoval = TRUE; + RC = UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + TargetDeviceObject, + &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + Locked = TRUE; + } + + } + // Now before we can initialize the Vcb we need to set up the + // Get our device object and alignment requirement. + // Device extension == VCB + KdPrint(("UDFMountVolume: create device\n")); + RC = IoCreateDevice( UDFGlobalData.DriverObject, + sizeof(VCB), + NULL, + FsDeviceType, + 0, + FALSE, + &VolDo ); + + if(!NT_SUCCESS(RC)) try_return(RC); + + // Our alignment requirement is the larger of the processor alignment requirement + // already in the volume device object and that in the DeviceObjectWeTalkTo + if(TargetDeviceObject->AlignmentRequirement > VolDo->AlignmentRequirement) { + VolDo->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; + } + + VolDo->Flags &= ~DO_DEVICE_INITIALIZING; + + // device object field in the VPB to point to our new volume device + // object. + Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo; + + // We must initialize the stack size in our device object before + // the following reads, because the I/O system has not done it yet. + ((PDEVICE_OBJECT)VolDo)->StackSize = (CCHAR) (TargetDeviceObject->StackSize + 1); + + Vcb = (PVCB)VolDo->DeviceExtension; + + // Initialize the Vcb. This routine will raise on an allocation + // failure. + RC = UDFInitializeVCB(VolDo,TargetDeviceObject,Vpb); + if(!NT_SUCCESS(RC)) { + Vcb = NULL; + try_return(RC); + } + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.Saved_j != 4) { + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } +#endif //EVALUATION_TIME_LIMIT + + VolDo = NULL; + Vpb = NULL; + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE ); + VcbAcquired = TRUE; + + // Let's reference the Vpb to make sure we are the one to + // have the last dereference. + Vcb->Vpb->ReferenceCount ++; + + Vcb->MediaChangeCount = MediaChangeCount; + Vcb->FsDeviceType = FsDeviceType; + + // Clear the verify bit for the start of mount. + if(Vcb->Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) { + Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME; + RestoreDoVerify = TRUE; + } + + DeviceNotTouched = FALSE; + RC = UDFGetDiskInfo(TargetDeviceObject,Vcb); + if(!NT_SUCCESS(RC)) try_return(RC); + + // **** Read registry settings **** + UDFReadRegKeys(Vcb, FALSE, FALSE); + + Vcb->MountPhErrorCount = 0; + + // Initialize internal cache + Mode = WCACHE_MODE_ROM; + RC = WCacheInit__(&(Vcb->FastCache), + Vcb->WCacheMaxFrames, + Vcb->WCacheMaxBlocks, + Vcb->WriteBlockSize, + 5, Vcb->BlockSizeBits, + Vcb->WCacheBlocksPerFrameSh, + 0/*Vcb->FirstLBA*/, Vcb->LastPossibleLBA, Mode, + 0/*WCACHE_CACHE_WHOLE_PACKET*/ | + (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) | + (Vcb->CacheChainedIo ? WCACHE_CHAINED_IO : 0) | + WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS, // this will be cleared after mount + Vcb->WCacheFramesToKeepFree, +// UDFTWrite, UDFTRead, + UDFTWriteVerify, UDFTReadVerify, +#ifdef UDF_ASYNC_IO + UDFTWriteAsync, UDFTReadAsync, +#else //UDF_ASYNC_IO + NULL, NULL, +#endif //UDF_ASYNC_IO + UDFIsBlockAllocated, + UDFUpdateVAT, + UDFWCacheErrorHandler); + if(!NT_SUCCESS(RC)) try_return(RC); + + RC = UDFVInit(Vcb); + if(!NT_SUCCESS(RC)) try_return(RC); + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); + RC = UDFGetDiskInfoAndVerify(TargetDeviceObject,Vcb); + UDFReleaseResource(&(Vcb->BitMapResource1)); + + ASSERT(!Vcb->Modified); + WCacheChFlags__(&(Vcb->FastCache), + WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet + WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS); // let user retry request on Bad Blocks + +#ifdef UDF_READ_ONLY_BUILD + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY; +#endif //UDF_READ_ONLY_BUILD +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + + if(!NT_SUCCESS(RC)) { + KdPrint(("UDFMountVolume: try raw mount\n")); + if(Vcb->NSRDesc & VRS_ISO9660_FOUND) { + KdPrint(("UDFMountVolume: block raw mount due to ISO9660 presence\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + try_return(RC); + } +try_raw_mount: + KdPrint(("UDFMountVolume: try raw mount (2)\n")); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + + KdPrint(("UDFMountVolume: trying raw mount...\n")); + Vcb->VolIdent.Length = + (Vcb->VolIdent.MaximumLength = sizeof(UDF_BLANK_VOLUME_LABEL)) - 2; + if(Vcb->VolIdent.Buffer) + MyFreePool__(Vcb->VolIdent.Buffer); + Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(UDF_BLANK_VOLUME_LABEL)); + if(!Vcb->VolIdent.Buffer) + try_return(STATUS_INSUFFICIENT_RESOURCES); + RtlCopyMemory(Vcb->VolIdent.Buffer, UDF_BLANK_VOLUME_LABEL, sizeof(UDF_BLANK_VOLUME_LABEL)); + + RC = UDFBlankMount(Vcb); + if(!NT_SUCCESS(RC)) try_return(RC); + + } else { +// Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + try_return(RC); + } + } else { + Vcb->MountPhErrorCount = -1; +#ifndef UDF_READ_ONLY_BUILD + // set cache mode according to media type + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) { + KdPrint(("UDFMountVolume: writable volume\n")); + if(!Vcb->CDR_Mode) { + if((FsDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || + CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) { + KdPrint(("UDFMountVolume: RAM mode\n")); + Mode = WCACHE_MODE_RAM; + } else { + KdPrint(("UDFMountVolume: RW mode\n")); + Mode = WCACHE_MODE_RW; + } +/* if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) { + } else { + Vcb->WriteSecurity = TRUE; + }*/ + } else { + KdPrint(("UDFMountVolume: R mode\n")); + Mode = WCACHE_MODE_R; + } + // we can't record ACL on old format disks + if(!UDFNtAclSupported(Vcb)) { + KdPrint(("UDFMountVolume: NO ACL and ExtFE support\n")); + Vcb->WriteSecurity = FALSE; + Vcb->UseExtendedFE = FALSE; + } + } + WCacheSetMode__(&(Vcb->FastCache), Mode); +#endif //UDF_READ_ONLY_BUILD + // Complete mount operations: create root FCB + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); + RC = UDFCompleteMount(Vcb); + UDFReleaseResource(&(Vcb->BitMapResource1)); + if(!NT_SUCCESS(RC)) { + // We must have Vcb->VCBOpenCount = 1 for UDFBlankMount() + // Thus, we should not decrement it here + // Also, if we shall not perform BlankMount, + // but simply cleanup and return error, Vcb->VCBOpenCount + // will be decremented during cleanup. Thus anyway it must + // stay 1 unchanged here + //UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + UDFCloseResidual(Vcb); + Vcb->VCBOpenCount = 1; + if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + goto try_raw_mount; + } + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + } + +#ifndef UDF_READ_ONLY_BUILD + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) { + RC = UDFStartEjectWaiter(Vcb); + if(!NT_SUCCESS(RC)) try_return(RC); + } else { + KdPrint(("UDFMountVolume: RO mount\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //UDF_READ_ONLY_BUILD + + Vcb->Vpb->SerialNumber = Vcb->PhSerialNumber; + Vcb->Vpb->VolumeLabelLength = Vcb->VolIdent.Length; + RtlCopyMemory( Vcb->Vpb->VolumeLabel, + Vcb->VolIdent.Buffer, + Vcb->VolIdent.Length ); + + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED; + + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + Vcb->TotalAllocUnits = UDFGetTotalSpace(Vcb); + Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb); + // Register shutdown routine + if(!Vcb->ShutdownRegistered) { + KdPrint(("UDFMountVolume: Register shutdown routine\n")); + IoRegisterShutdownNotification(Vcb->VCBDeviceObject); + Vcb->ShutdownRegistered = TRUE; + } + + // unlock media + if(RemovableMedia) { + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { + KdPrint(("UDFMountVolume: unlock media on RO volume\n")); + ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE; + UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + TargetDeviceObject, + &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); + } + } + + if (UDFGlobalData.MountEvent) + { + Vcb->IsVolumeJustMounted = TRUE; + KeSetEvent(UDFGlobalData.MountEvent, 0, FALSE); + } + + // The new mount is complete. + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + Vcb = NULL; + + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + } _SEH2_FINALLY { + + KdPrint(("UDFMountVolume: RC = %x\n", RC)); + + if(ioBuf) { + MyFreePool__(ioBuf); + } + + if(!NT_SUCCESS(RC)) { + + if(RemovableMedia && Locked) { + KdPrint(("UDFMountVolume: unlock media\n")); + ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE; + UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + TargetDeviceObject, + &MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + } +/* if((RC != STATUS_DEVICE_NOT_READY) && + (RC != STATUS_NO_MEDIA_IN_DEVICE) ) {*/ + // reset driver + if(!DeviceNotTouched && + (!Vcb || (Vcb && (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)))) { + KdPrint(("UDFMountVolume: reset driver\n")); + UDFResetDeviceDriver(Vcb, TargetDeviceObject, TRUE); + } + + if(RC == STATUS_CRC_ERROR || RC == STATUS_FILE_CORRUPT_ERROR) { + KdPrint(("UDFMountVolume: status -> STATUS_UNRECOGNIZED_VOLUME\n")); + RC = STATUS_UNRECOGNIZED_VOLUME; + } + + // If we didn't complete the mount then cleanup any remaining structures. + if(Vpb) { + Vpb->DeviceObject = NULL; + } + + if(Vcb) { + // Restore the verify bit. + if(RestoreDoVerify) { + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + } + // Make sure there is no Vcb since it could go away + if(Vcb->VCBOpenCount) + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + // This procedure will also delete the volume device object + if(UDFDismountVcb( Vcb, VcbAcquired )) { + UDFReleaseResource( &(Vcb->VCBResource) ); + } + } else if(VolDo) { + IoDeleteDevice( VolDo ); + } + } + // Release the global resource. + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + + if (CompleteIrp || NT_SUCCESS(RC)) { + if(!_SEH2_AbnormalTermination()) { + // Set mount event + + KdPrint(("UDFMountVolume: complete req RC %x\n", RC)); + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_MOUNT); + // Complete the IRP. + Irp->IoStatus.Status = RC; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + } else { + // Pass Irp to lower driver (CDFS) + + // Get this driver out of the driver stack and get to the next driver as + // quickly as possible. + Irp->CurrentLocation++; + Irp->Tail.Overlay.CurrentStackLocation++; + + // Now call the appropriate file system driver with the request. + return IoCallDriver( filterDevExt->lowerFSDeviceObject, Irp ); + + } + + } _SEH2_END; + + KdPrint(("UDFMountVolume: final RC = %x\n", RC)); + return RC; + +} // end UDFMountVolume() + +NTSTATUS +UDFStartEjectWaiter( + IN PVCB Vcb + ) +{ + NTSTATUS RC; + PREVENT_MEDIA_REMOVAL_USER_IN Buff; + KdPrint(("UDFStartEjectWaiter:\n")); + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.Saved_j != 4) { + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } +#endif //EVALUATION_TIME_LIMIT + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { + KdPrint((" UDF_VCB_FLAGS_MEDIA_READ_ONLY\n")); + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) { + KdPrint((" UDF_VCB_FLAGS_MEDIA_LOCKED\n")); + } + KdPrint((" EjectWaiter=%x\n", Vcb->EjectWaiter)); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) && + /*!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) &&*/ + !(Vcb->EjectWaiter)) { + + KdPrint(("UDFStartEjectWaiter: check driver\n")); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) && + (Vcb->FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)) { + // we don't know how to write without our device driver + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + KdPrint((" not our driver, ignore\n")); + return STATUS_SUCCESS; + } + KdPrint(("UDFStartEjectWaiter: check removable\n")); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) { + // prevent media removal + KdPrint(("UDFStartEjectWaiter: lock media\n")); + Buff.PreventMediaRemoval = TRUE; + RC = UDFTSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + Vcb, + &Buff,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL ); + Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_LOCKED; + } + KdPrint(("UDFStartEjectWaiter: prepare to start\n")); + // initialize Eject Request waiter + Vcb->EjectWaiter = (PUDFEjectWaitContext)MyAllocatePool__(NonPagedPool, sizeof(UDFEjectWaitContext)); + if(!(Vcb->EjectWaiter)) return STATUS_INSUFFICIENT_RESOURCES; + KeInitializeEvent(&(Vcb->WaiterStopped), NotificationEvent, FALSE); + Vcb->EjectWaiter->Vcb = Vcb; + Vcb->EjectWaiter->SoftEjectReq = FALSE; + KeInitializeEvent(&(Vcb->EjectWaiter->StopReq), NotificationEvent, FALSE); +// Vcb->EjectWaiter->StopReq = FALSE; + Vcb->EjectWaiter->WaiterStopped = &(Vcb->WaiterStopped); + // This can occure after unexpected media loss, when EjectRequestWaiter + // terminates automatically + ASSERT(!(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT)); + Vcb->VCBFlags |= UDF_VCB_FLAGS_STOP_WAITER_EVENT; + ExInitializeWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), (PWORKER_THREAD_ROUTINE)UDFEjectReqWaiter, Vcb->EjectWaiter); + KdPrint(("UDFStartEjectWaiter: create thread\n")); + ExQueueWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), DelayedWorkQueue); + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + + } else { + KdPrint((" ignore\n")); + } + return STATUS_SUCCESS; +} // end UDFStartEjectWaiter() + +NTSTATUS +UDFCompleteMount( + IN PVCB Vcb + ) +{ + NTSTATUS RC;// = STATUS_SUCCESS; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL; + UNICODE_STRING LocalPath; + PtrUDFObjectName RootName; + PtrUDFFCB RootFcb; + + KdPrint(("UDFCompleteMount:\n")); + Vcb->ZBuffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, max(Vcb->LBlockSize, PAGE_SIZE), 'zNWD'); + if(!Vcb->ZBuffer) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(Vcb->ZBuffer, Vcb->LBlockSize); + + KdPrint(("UDFCompleteMount: alloc Root FCB\n")); + // Create the root index and reference it in the Vcb. + RootFcb = + Vcb->RootDirFCB = UDFAllocateFCB(); + if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES; + + KdPrint(("UDFCompleteMount: alloc Root ObjName\n")); + // Allocate and set root FCB unique name + RootName = UDFAllocateObjectName(); + if(!RootName) { + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME); + if(!NT_SUCCESS(RC)) + goto insuf_res_1; + + RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO)); + if(!RootFcb->FileInfo) { + RC = STATUS_INSUFFICIENT_RESOURCES; +insuf_res_1: + MyFreePool__(RootName->ObjectName.Buffer); + UDFReleaseObjectName(RootName); + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return RC; + } + KdPrint(("UDFCompleteMount: open Root Dir\n")); + // Open Root Directory + RC = UDFOpenRootFile__( Vcb, &(Vcb->RootLbAddr), RootFcb->FileInfo ); + if(!NT_SUCCESS(RC)) { +insuf_res_2: + UDFCleanUpFile__(Vcb, RootFcb->FileInfo); + MyFreePool__(RootFcb->FileInfo); + goto insuf_res_1; + } + RootFcb->FileInfo->Fcb = RootFcb; + + if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) { + KdPrint(("UDFCompleteMount: alloc Root ObjName (2)\n")); + if(!(RootFcb->NTRequiredFCB = + (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) { + RC = STATUS_INSUFFICIENT_RESOURCES; + goto insuf_res_2; + } + RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); + RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB; + } + KdPrint(("UDFCompleteMount: init FCB\n")); + RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL); + if(!NT_SUCCESS(RC)) { + // if we get here, no resources are inited + RootFcb->OpenHandleCount = + RootFcb->ReferenceCount = + RootFcb->NTRequiredFCB->CommonRefCount = 0; + + UDFCleanUpFile__(Vcb, RootFcb->FileInfo); + MyFreePool__(RootFcb->FileInfo); + MyFreePool__(RootFcb->NTRequiredFCB); + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return RC; + } + + // this is a part of UDF_RESIDUAL_REFERENCE + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + RootFcb->OpenHandleCount = + RootFcb->ReferenceCount = + RootFcb->NTRequiredFCB->CommonRefCount = 1; + + UDFGetFileXTime(RootFcb->FileInfo, + &(RootFcb->NTRequiredFCB->CreationTime.QuadPart), + &(RootFcb->NTRequiredFCB->LastAccessTime.QuadPart), + &(RootFcb->NTRequiredFCB->ChangeTime.QuadPart), + &(RootFcb->NTRequiredFCB->LastWriteTime.QuadPart) ); + + if(Vcb->SysStreamLbAddr.logicalBlockNum) { + Vcb->SysSDirFileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO)); + if(!Vcb->SysSDirFileInfo) { + RC = STATUS_INSUFFICIENT_RESOURCES; + goto unwind_1; + } + // Open System SDir Directory + RC = UDFOpenRootFile__( Vcb, &(Vcb->SysStreamLbAddr), Vcb->SysSDirFileInfo ); + if(!NT_SUCCESS(RC)) { + UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo); + MyFreePool__(Vcb->SysSDirFileInfo); + Vcb->SysSDirFileInfo = NULL; + goto unwind_1; + } else { + Vcb->SysSDirFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; + } + } + + // Open Unallocatable space stream + // Generally, it should be placed in SystemStreamDirectory, but some + // stupid apps think that RootDirectory is much better place.... :(( + RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE); + if(NT_SUCCESS(RC)) { + RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); + } + if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) { + +//unwind_2: + UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo); + Vcb->NonAllocFileInfo = NULL; + // this was a part of UDF_RESIDUAL_REFERENCE + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); +unwind_1: + + // UDFCloseResidual() will clean up everything + + return RC; + } + + /* process Non-allocatable */ + if(NT_SUCCESS(RC)) { + UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used + UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + } else { + /* try to read Non-allocatable from alternate locations */ + RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2); + if(!NT_SUCCESS(RC)) { + goto unwind_1; + } + RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); + if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) { + goto unwind_1; + } + if(NT_SUCCESS(RC)) { + UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used + UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + } else + if(Vcb->SysSDirFileInfo) { + RC = MyInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE); + if(!NT_SUCCESS(RC)) { + goto unwind_1; + } + RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); + if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) { + goto unwind_1; + } + if(NT_SUCCESS(RC)) { + UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used +// UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + } else { + RC = STATUS_SUCCESS; + } + } else { + RC = STATUS_SUCCESS; + } + } + + /* Read SN UID mapping */ + if(Vcb->SysSDirFileInfo) { + RC = MyInitUnicodeString(&LocalPath, UDF_SN_UID_MAPPING); + if(!NT_SUCCESS(RC)) + goto unwind_3; + RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->UniqueIDMapFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); + if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) { +unwind_3: +// UDFCloseFile__(Vcb, Vcb->NonAllocFileInfo); +// UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo); +// if(Vcb->NonAllocFileInfo) +// MyFreePool__(Vcb->NonAllocFileInfo); +// Vcb->NonAllocFileInfo = NULL; + goto unwind_1; + } else { + Vcb->UniqueIDMapFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; + } + RC = STATUS_SUCCESS; + } + +#define DWN_MAX_CFG_FILE_SIZE 0x10000 + + /* Read DWN config file from disk with disk-specific options */ + RC = MyInitUnicodeString(&LocalPath, UDF_CONFIG_STREAM_NAME_W); + if(NT_SUCCESS(RC)) { + + int8* buff; + uint32 len; + PUDF_FILE_INFO CfgFileInfo = NULL; + + RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &CfgFileInfo, NULL); + if(OS_SUCCESS(RC)) { + + len = (ULONG)UDFGetFileSize(CfgFileInfo); + if(len && len < DWN_MAX_CFG_FILE_SIZE) { + buff = (int8*)MyAllocatePool__(NonPagedPool, len); + if(buff) { + RC = UDFReadFile__(Vcb, CfgFileInfo, 0, len, FALSE, buff, &len); + if(OS_SUCCESS(RC)) { + // parse config + Vcb->Cfg = (PUCHAR)buff; + Vcb->CfgLength = len; + UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE /*cfg*/); + Vcb->Cfg = NULL; + Vcb->CfgLength = 0; + Vcb->CfgVersion = 0; + } + MyFreePool__(buff); + } + } + + UDFCloseFile__(Vcb, CfgFileInfo); + } + if(CfgFileInfo) { + UDFCleanUpFile__(Vcb, CfgFileInfo); + } + MyFreePool__(LocalPath.Buffer); + } + RC = STATUS_SUCCESS; + + // clear Modified flags. It was not real modify, just + // bitmap construction + Vcb->BitmapModified = FALSE; + //Vcb->Modified = FALSE; + UDFPreClrModified(Vcb); + UDFClrModified(Vcb); + // this is a part of UDF_RESIDUAL_REFERENCE + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + + NtReqFcb = RootFcb->NTRequiredFCB; + + // Start initializing the fields contained in the CommonFCBHeader. + PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader); + + // DisAllow fast-IO for now. +// PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible; + PtrCommonFCBHeader->IsFastIoPossible = FastIoIsPossible; + + // Initialize the MainResource and PagingIoResource pointers in + // the CommonFCBHeader structure to point to the ERESOURCE structures we + // have allocated and already initialized above. +// PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource); +// PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource); + + // Initialize the file size values here. + PtrCommonFCBHeader->AllocationSize.QuadPart = 0; + PtrCommonFCBHeader->FileSize.QuadPart = 0; + + // The following will disable ValidDataLength support. +// PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFI64; + PtrCommonFCBHeader->ValidDataLength.QuadPart = 0; + + if(!NT_SUCCESS(RC)) + return RC; + UDFAssignAcl(Vcb, NULL, RootFcb, NtReqFcb); +/* + Vcb->CDBurnerVolumeValid = true; + + len = + Vcb->CDBurnerVolume.Length = 256; + Vcb->CDBurnerVolume.MaximumLength = 256; + Vcb->CDBurnerVolume.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256); + RC = RegTGetStringValue(NULL, REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME, Vcb->CDBurnerVolume.Buffer, + len); + Vcb->CDBurnerVolume.Length = (USHORT)(wcslen(Vcb->CDBurnerVolume.Buffer)*sizeof(WCHAR)); + + if(RC != STATUS_OBJECT_NAME_NOT_FOUND && !NT_SUCCESS(RC) ) + return RC; + + if (NT_SUCCESS(RC)) { + RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, + REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME, + REG_SZ,L"",sizeof(L"")+1); + + } else { + Vcb->CDBurnerVolumeValid = false; + RC = STATUS_SUCCESS; + } +*/ + ASSERT(!Vcb->Modified); + + return RC; +} // end UDFCompleteMount() + +NTSTATUS +UDFBlankMount( + IN PVCB Vcb + ) +{ + NTSTATUS RC;// = STATUS_SUCCESS; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL; + PtrUDFObjectName RootName; + PtrUDFFCB RootFcb; + PDIR_INDEX_HDR hDirNdx; + PDIR_INDEX_ITEM DirNdx; + + // Create the root index and reference it in the Vcb. + RootFcb = + Vcb->RootDirFCB = UDFAllocateFCB(); + if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(RootFcb,sizeof(UDFFCB)); + + // Allocate and set root FCB unique name + RootName = UDFAllocateObjectName(); + if(!RootName) { +//bl_unwind_2: + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME); + if(!NT_SUCCESS(RC)) + goto bl_unwind_1; + + RootFcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB; + RootFcb->NodeIdentifier.NodeSize = sizeof(UDFFCB); + + RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO)); + if(!RootFcb->FileInfo) { + MyFreePool__(RootName->ObjectName.Buffer); + RC = STATUS_INSUFFICIENT_RESOURCES; +bl_unwind_1: + UDFReleaseObjectName(RootName); + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return RC; + } + RtlZeroMemory(RootFcb->FileInfo, sizeof(UDF_FILE_INFO)); + if(!OS_SUCCESS(RC = UDFStoreDloc(Vcb, RootFcb->FileInfo, 1))) { + MyFreePool__(RootFcb->FileInfo); + RootFcb->FileInfo = NULL; + MyFreePool__(RootName->ObjectName.Buffer); + goto bl_unwind_1; + } + RootFcb->FileInfo->NextLinkedFile = + RootFcb->FileInfo->PrevLinkedFile = RootFcb->FileInfo; + + hDirNdx = UDFDirIndexAlloc(2); + DirNdx = UDFDirIndex(hDirNdx,0); + DirNdx->FileCharacteristics = FILE_DIRECTORY; + DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR; + DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY; + DirNdx->FName.Buffer = L"."; + DirNdx->FName.Length = + (DirNdx->FName.MaximumLength = sizeof(L".")) - sizeof(WCHAR); + DirNdx->FileInfo = RootFcb->FileInfo; + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL | HASH_KEEP_NAME); + + DirNdx = UDFDirIndex(hDirNdx,1); + DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR; + if(Vcb->ShowBlankCd == 2) { + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + } + DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY; + DirNdx->FName.Buffer = L"Blank.CD"; + DirNdx->FName.Length = + (DirNdx->FName.MaximumLength = sizeof(L"Blank.CD")) - sizeof(WCHAR); + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL); + + RootFcb->FileInfo->Dloc->DirIndex = hDirNdx; + RootFcb->FileInfo->Fcb = RootFcb; + + if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) { + if(!(RootFcb->NTRequiredFCB = + (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) { + MyFreePool__(RootName->ObjectName.Buffer); + UDFReleaseObjectName(RootName); + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); + RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB; + } + RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL); + if(!NT_SUCCESS(RC)) { + // if we get here, no resources are inited + RootFcb->OpenHandleCount = + RootFcb->ReferenceCount = + RootFcb->NTRequiredFCB->CommonRefCount = 0; + + UDFCleanUpFile__(Vcb, RootFcb->FileInfo); + MyFreePool__(RootFcb->FileInfo); + MyFreePool__(RootFcb->NTRequiredFCB); + UDFCleanUpFCB(RootFcb); + Vcb->RootDirFCB = NULL; + return RC; + } + + // this is a part of UDF_RESIDUAL_REFERENCE + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + RootFcb->OpenHandleCount = + RootFcb->ReferenceCount = + RootFcb->NTRequiredFCB->CommonRefCount = + RootFcb->FileInfo->RefCount = + RootFcb->FileInfo->Dloc->LinkRefCount = 1; + + // this is a part of UDF_RESIDUAL_REFERENCE + UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); + + NtReqFcb = RootFcb->NTRequiredFCB; + + // Start initializing the fields contained in the CommonFCBHeader. + PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader); + + // DisAllow fast-IO for now. + PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible; + + // Initialize the MainResource and PagingIoResource pointers in + // the CommonFCBHeader structure to point to the ERESOURCE structures we + // have allocated and already initialized above. + PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource); + PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource); + + // Initialize the file size values here. + PtrCommonFCBHeader->AllocationSize.QuadPart = 0; + PtrCommonFCBHeader->FileSize.QuadPart = 0; + + // The following will disable ValidDataLength support. + PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFLL; + + return RC; +} // end UDFBlankMount() + +VOID +UDFCloseResidual( + IN PVCB Vcb + ) +{ + // Deinitialize Non-alloc file + if(Vcb->VCBOpenCount) + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + KdPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo)); + if(Vcb->NonAllocFileInfo) { + UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo); + UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo); + MyFreePool__(Vcb->NonAllocFileInfo); + Vcb->NonAllocFileInfo = NULL; + } + // Deinitialize Unique ID Mapping + KdPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo)); + if(Vcb->UniqueIDMapFileInfo) { + UDFCloseFile__(Vcb,Vcb->UniqueIDMapFileInfo); + UDFCleanUpFile__(Vcb, Vcb->UniqueIDMapFileInfo); + MyFreePool__(Vcb->UniqueIDMapFileInfo); + Vcb->UniqueIDMapFileInfo = NULL; + } + // Deinitialize VAT file + KdPrint(("UDFCloseResidual: VatFileInfo %x\n", Vcb->VatFileInfo)); + if(Vcb->VatFileInfo) { + UDFCloseFile__(Vcb,Vcb->VatFileInfo); + UDFCleanUpFile__(Vcb, Vcb->VatFileInfo); + MyFreePool__(Vcb->VatFileInfo); + Vcb->VatFileInfo = NULL; + } + // System StreamDir + KdPrint(("UDFCloseResidual: SysSDirFileInfo %x\n", Vcb->SysSDirFileInfo)); + if(Vcb->SysSDirFileInfo) { + UDFCloseFile__(Vcb, Vcb->SysSDirFileInfo); + UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo); + MyFreePool__(Vcb->SysSDirFileInfo); + Vcb->SysSDirFileInfo = NULL; + } +/* // Deinitialize root dir fcb + if(Vcb->RootDirFCB) { + UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo); + UDFCleanUpFile__(Vcb, Vcb->RootDirFCB->FileInfo); + MyFreePool__(Vcb->RootDirFCB->FileInfo); + UDFCleanUpFCB(Vcb->RootDirFCB); + // Remove root FCB reference in vcb + if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--; + } + + // Deinitialize Non-alloc file + if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--; + if(Vcb->NonAllocFileInfo) { + UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo); + // We must release VCB here !!!! +// UDFCleanUpFcbChain(Vcb, Vcb->NonAllocFileInfo, 1); + Vcb->NonAllocFileInfo = NULL; + } + // Deinitialize VAT file + if(Vcb->VatFileInfo) { + UDFCloseFile__(Vcb,Vcb->VatFileInfo); + // We must release VCB here !!!! +// UDFCleanUpFcbChain(Vcb, Vcb->VatFileInfo, 1); + Vcb->VatFileInfo = NULL; + }*/ + + // Deinitialize root dir fcb + KdPrint(("UDFCloseResidual: RootDirFCB %x\n", Vcb->RootDirFCB)); + if(Vcb->RootDirFCB) { + UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo); + if(Vcb->RootDirFCB->OpenHandleCount) + Vcb->RootDirFCB->OpenHandleCount--; + UDFCleanUpFcbChain(Vcb, Vcb->RootDirFCB->FileInfo, 1, TRUE); + // Remove root FCB reference in vcb + if(Vcb->VCBOpenCount) + UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); + Vcb->RootDirFCB = NULL; + } +} // end UDFCloseResidual() + +VOID +UDFCleanupVCB( + IN PVCB Vcb + ) +{ + _SEH2_TRY { + UDFReleaseFileIdCache(Vcb); + UDFReleaseDlocList(Vcb); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + if(Vcb->ShutdownRegistered && Vcb->VCBDeviceObject) { + IoUnregisterShutdownNotification(Vcb->VCBDeviceObject); + Vcb->ShutdownRegistered = FALSE; + } + + MyFreeMemoryAndPointer(Vcb->Partitions); + MyFreeMemoryAndPointer(Vcb->LVid); + MyFreeMemoryAndPointer(Vcb->Vat); + MyFreeMemoryAndPointer(Vcb->SparingTable); + + if(Vcb->FSBM_Bitmap) { + DbgFreePool(Vcb->FSBM_Bitmap); + Vcb->FSBM_Bitmap = NULL; + } + if(Vcb->ZSBM_Bitmap) { + DbgFreePool(Vcb->ZSBM_Bitmap); + Vcb->ZSBM_Bitmap = NULL; + } + if(Vcb->BSBM_Bitmap) { + DbgFreePool(Vcb->BSBM_Bitmap); + Vcb->BSBM_Bitmap = NULL; + } +#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS + if(Vcb->FSBM_Bitmap_owners) { + DbgFreePool(Vcb->FSBM_Bitmap_owners); + Vcb->FSBM_Bitmap_owners = NULL; + } +#endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS + if(Vcb->FSBM_OldBitmap) { + DbgFreePool(Vcb->FSBM_OldBitmap); + Vcb->FSBM_OldBitmap = NULL; + } + + MyFreeMemoryAndPointer(Vcb->Statistics); + MyFreeMemoryAndPointer(Vcb->NTRequiredFCB); + MyFreeMemoryAndPointer(Vcb->VolIdent.Buffer); + MyFreeMemoryAndPointer(Vcb->TargetDevName.Buffer); + + if(Vcb->ZBuffer) { + DbgFreePool(Vcb->ZBuffer); + Vcb->ZBuffer = NULL; + } + + if(Vcb->fZBuffer) { + DbgFreePool(Vcb->fZBuffer); + Vcb->fZBuffer = NULL; + } + + MyFreeMemoryAndPointer(Vcb->OPCh); + MyFreeMemoryAndPointer(Vcb->WParams); + MyFreeMemoryAndPointer(Vcb->Error); + MyFreeMemoryAndPointer(Vcb->TrackMap); + +} // end UDFCleanupVCB() + +/* + +Routine Description: + + This routine walks through the list of Vcb's looking for any which may + now be deleted. They may have been left on the list because there were + outstanding references. + +Arguments: + +Return Value: + + None + +*/ +VOID +UDFScanForDismountedVcb( + IN PtrUDFIrpContext IrpContext + ) +{ + PVCB Vcb; + PLIST_ENTRY Link; + + + // Walk through all of the Vcb's attached to the global data. + Link = UDFGlobalData.VCBQueue.Flink; + + while (Link != &(UDFGlobalData.VCBQueue)) { + + Vcb = CONTAINING_RECORD( Link, VCB, NextVCB ); + + // Move to the next link now since the current Vcb may be deleted. + Link = Link->Flink; + + // If dismount is already underway then check if this Vcb can + // go away. + if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) || + ((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) { + + UDFCheckForDismount( IrpContext, Vcb, FALSE ); + } + } + + return; +} // end UDFScanForDismountedVcb() + +/* +Routine Description: + This routine determines if a volume is currently mounted. + +Arguments: + Irp - Supplies the Irp to process + +Return Value: + NTSTATUS - The return status for the operation + +*/ +NTSTATUS +UDFIsVolumeMounted( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + + KdPrint(("UDFIsVolumeMounted\n")); + + Ccb = (PtrUDFCCB)IrpSp->FileObject->FsContext2; + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + + if(Fcb && + !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + !(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ) { + + // Disable PopUps, we want to return any error. + IrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS; + + // Verify the Vcb. This will raise in the error condition. + UDFVerifyVcb( IrpContext, Fcb->Vcb ); + } + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + + return STATUS_SUCCESS; +} // end UDFIsVolumeMounted() + +/* + This routine returns the filesystem performance counters from the + appropriate VCB. + +Arguments: + Irp - Supplies the Irp to process + +Return Value: + NTSTATUS - The return status for the operation +*/ +NTSTATUS +UDFGetStatistics( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + NTSTATUS status; + PVCB Vcb; + + PFILE_SYSTEM_STATISTICS Buffer; + ULONG BufferLength; + ULONG StatsSize; + ULONG BytesToCopy; + + KdPrint(("UDFGetStatistics\n")); + + // Extract the buffer + BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + // Get a pointer to the output buffer. + Buffer = (PFILE_SYSTEM_STATISTICS)(Irp->AssociatedIrp.SystemBuffer); + + // Make sure the buffer is big enough for at least the common part. + if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) { + status = STATUS_BUFFER_TOO_SMALL; + Irp->IoStatus.Information = 0; + goto EO_stat; + } + + // Now see how many bytes we can copy. + StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors; + if (BufferLength < StatsSize) { + BytesToCopy = BufferLength; + status = STATUS_BUFFER_OVERFLOW; + } else { + BytesToCopy = StatsSize; + status = STATUS_SUCCESS; + } + + Vcb = (PVCB)(((PDEVICE_OBJECT)IrpSp->DeviceObject)->DeviceExtension); + // Fill in the output buffer + RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy ); + Irp->IoStatus.Information = BytesToCopy; +EO_stat: + Irp->IoStatus.Status = status; + + return status; +} // end UDFGetStatistics() + + +/* + This routine determines if pathname is valid path for UDF Filesystem + +Arguments: + Irp - Supplies the Irp to process + +Return Value: + NTSTATUS - The return status for the operation +*/ +NTSTATUS +UDFIsPathnameValid( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + NTSTATUS RC; + PPATHNAME_BUFFER PathnameBuffer; + UNICODE_STRING PathName; + UNICODE_STRING CurName; + PWCHAR TmpBuffer; + + KdPrint(("UDFIsPathnameValid\n")); + + // Extract the pathname + PathnameBuffer = (PPATHNAME_BUFFER)Irp->AssociatedIrp.SystemBuffer; + PathName.Buffer = PathnameBuffer->Name; + PathName.Length = (USHORT)PathnameBuffer->PathNameLength; + + _SEH2_TRY { + // Check for an invalid buffer + if (FIELD_OFFSET(PATHNAME_BUFFER, Name[0]) + PathnameBuffer->PathNameLength > + IrpSp->Parameters.FileSystemControl.InputBufferLength) { + try_return( RC = STATUS_INVALID_PARAMETER); + } + while (TRUE) { + // get next path part... + TmpBuffer = PathName.Buffer; + PathName.Buffer = UDFDissectName(PathName.Buffer,&(CurName.Length) ); + PathName.Length -= (USHORT)((ULONG)(PathName.Buffer) - (ULONG)TmpBuffer); + CurName.Buffer = PathName.Buffer - CurName.Length; + CurName.Length *= sizeof(WCHAR); + CurName.MaximumLength -= CurName.Length; + + if (CurName.Length) { + // check path fragment size + if (CurName.Length > UDF_NAME_LEN*sizeof(WCHAR)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + if (!UDFIsNameValid(&CurName, NULL, NULL)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + } else { + try_return(RC = STATUS_SUCCESS); + } + } +try_exit: NOTHING; + } _SEH2_FINALLY { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = RC; + } _SEH2_END; + + return RC; +} // end UDFIsPathnameValid() + +/* + This routine performs the lock volume operation. It is responsible for + either completing of enqueuing the input Irp. +Arguments: + Irp - Supplies the Irp to process +Return Value: + NTSTATUS - The return status for the operation +*/ +NTSTATUS +UDFLockVolume( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG PID + ) +{ + NTSTATUS RC; + + KIRQL SavedIrql; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + BOOLEAN VcbAcquired = FALSE; + + KdPrint(("UDFLockVolume: PID %x\n", PID)); + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + // Check for volume open + if (Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK); + + _SEH2_TRY { + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + // Acquire exclusive access to the Vcb. + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE ); + VcbAcquired = TRUE; + + // Verify the Vcb. + UDFVerifyVcb( IrpContext, Vcb ); + + // If the volume is already locked then complete with success if this file + // object has the volume locked, fail otherwise. +/* if (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) { + + if (Vcb->VolumeLockFileObject == IrpSp->FileObject) { + RC = STATUS_SUCCESS; + } else { + RC = STATUS_ACCESS_DENIED; + } + // If the open count for the volume is greater than 1 then this request + // will fail. + } else if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE+1) { + RC = STATUS_ACCESS_DENIED; + // We will try to get rid of all of the user references. If there is only one + // remaining after the purge then we can allow the volume to be locked. + } else { + // flush system cache + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + }*/ + + } _SEH2_FINALLY { + + // Release the Vcb. + if(VcbAcquired) { + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + } + } _SEH2_END; + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE ); + VcbAcquired = TRUE; + UDFFlushLogicalVolume(NULL, NULL, Vcb/*, 0*/); + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + // Check if the Vcb is already locked, or if the open file count + // is greater than 1 (which implies that someone else also is + // currently using the volume, or a file on the volume). + IoAcquireVpbSpinLock( &SavedIrql ); + + if (!(Vcb->Vpb->Flags & VPB_LOCKED) && + (Vcb->VolumeLockPID == -1) && + (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE+1) && + (Vcb->Vpb->ReferenceCount == 2)) { + + // Mark volume as locked + if(PID == -1) { + Vcb->Vpb->Flags |= VPB_LOCKED; + } + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = IrpSp->FileObject; + Vcb->VolumeLockPID = PID; + + RC = STATUS_SUCCESS; + + } else { + + RC = STATUS_ACCESS_DENIED; + } + + IoReleaseVpbSpinLock( SavedIrql ); + + if(!NT_SUCCESS(RC)) { + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED); + } + + // Complete the request if there haven't been any exceptions. + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = RC; + return RC; +} // end UDFLockVolume() + +/* + This routine performs the unlock volume operation. It is responsible for + either completing of enqueuing the input Irp. +Arguments: + Irp - Supplies the Irp to process +Return Value: + NTSTATUS - The return status for the operation +*/ +NTSTATUS +UDFUnlockVolume( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG PID + ) +{ + NTSTATUS RC = STATUS_INVALID_PARAMETER; + + KIRQL SavedIrql; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + + KdPrint(("UDFUnlockVolume: PID %x\n", PID)); + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + // Check for volume open + if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + // Acquire exclusive access to the Vcb/Vpb. + IoAcquireVpbSpinLock( &SavedIrql ); + + _SEH2_TRY { + + // We won't check for a valid Vcb for this request. An unlock will always + // succeed on a locked volume. + if(Vcb->Vpb->Flags & VPB_LOCKED || + Vcb->VolumeLockPID == PID) { + Vcb->Vpb->Flags &= ~VPB_LOCKED; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = NULL; + Vcb->VolumeLockPID = -1; + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_UNLOCK); + RC = STATUS_SUCCESS; + } else { + RC = STATUS_NOT_LOCKED; + RC = STATUS_SUCCESS; + RC = STATUS_VOLUME_DISMOUNTED; + } + + } _SEH2_FINALLY { + ; + } _SEH2_END; + + // Release all of our resources + IoReleaseVpbSpinLock( SavedIrql ); + + // Complete the request if there haven't been any exceptions. + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = RC; + return RC; +} // end UDFUnlockVolume() + + +/* + This routine performs the dismount volume operation. It is responsible for + either completing of enqueuing the input Irp. We only dismount a volume which + has been locked. The intent here is that someone has locked the volume (they are the + only remaining handle). We set the verify bit here and the user will close his handle. + We will dismount a volume with no user's handles in the verify path. +Arguments: + Irp - Supplies the Irp to process +Return Value: + NTSTATUS - The return status for the operation +*/ +NTSTATUS +UDFDismountVolume( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + NTSTATUS RC; + + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + BOOLEAN VcbAcquired = FALSE; + + KdPrint(("\n ### UDFDismountVolume ###\n\n")); + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + // Check for volume open + if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + // Acquire exclusive access to the Vcb. + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE ); + VcbAcquired = TRUE; + + _SEH2_TRY { + + // Mark the volume as needs to be verified, but only do it if + // the vcb is locked by this handle and the volume is currently mounted. + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + // disable Eject Request Waiter if any + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + + UDFStopEjectWaiter(Vcb); + RC = STATUS_SUCCESS; + } else + if(/*!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||*/ + !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) || + (Vcb->VCBOpenCount > (UDF_RESIDUAL_REFERENCE+1))) { + + RC = STATUS_NOT_LOCKED; + } else + if((Vcb->VolumeLockFileObject != IrpSp->FileObject)) { + + RC = STATUS_INVALID_PARAMETER; + + } else { + + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + UDFDoDismountSequence(Vcb, Buf, FALSE); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + // disable Eject Request Waiter if any + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + + UDFStopEjectWaiter(Vcb); + RC = STATUS_SUCCESS; + } +try_exit: NOTHING; + } _SEH2_FINALLY { + // Free memory + if(Buf) MyFreePool__(Buf); + // Release all of our resources + if(VcbAcquired) + UDFReleaseResource( &(Vcb->VCBResource) ); + } _SEH2_END; + + if(!NT_SUCCESS(RC)) { + UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED); + } + + // Complete the request if there haven't been any exceptions. + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = RC; + return RC; +} // end UDFDismountVolume() + +/* + + This routine returns the volume allocation bitmap. + + Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in + through the input buffer. + Output = the VOLUME_BITMAP_BUFFER data structure is returned through + the output buffer. + + We return as much as the user buffer allows starting the specified input + LCN (trucated to a byte). If there is no input buffer, we start at zero. + +Arguments: + + Irp - Supplies the Irp being processed. + +Return Value: + + NTSTATUS - The return status for the operation. + + */ +NTSTATUS +UDFGetVolumeBitmap( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + NTSTATUS RC; + + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + + KdPrint(("UDFGetVolumeBitmap\n")); + + ULONG BytesToCopy; + ULONG TotalClusters; + ULONG DesiredClusters; + ULONG StartingCluster; + ULONG InputBufferLength; + ULONG OutputBufferLength; + LARGE_INTEGER StartingLcn; + PVOLUME_BITMAP_BUFFER OutputBuffer; + ULONG i, lim; + PULONG FSBM, Dest; + ULONG LSh; + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + + OutputBuffer = (PVOLUME_BITMAP_BUFFER)UDFGetCallersBuffer(IrpContext, Irp); + if(!OutputBuffer) + return STATUS_INVALID_USER_BUFFER; + + // Check for a minimum length on the input and output buffers. + if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) || + (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) { + + UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + return STATUS_BUFFER_TOO_SMALL; + } + + // Check if a starting cluster was specified. + TotalClusters = Vcb->FSBM_BitCount; + StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn; + + if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) { + + UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + + } else { + + StartingCluster = StartingLcn.LowPart & ~7; + } + + OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); + DesiredClusters = TotalClusters - StartingCluster; + + if (OutputBufferLength < (DesiredClusters + 7) / 8) { + + BytesToCopy = OutputBufferLength; + RC = STATUS_BUFFER_OVERFLOW; + + } else { + + BytesToCopy = (DesiredClusters + 7) / 8; + RC = STATUS_SUCCESS; + } + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE ); + + _SEH2_TRY { + + // Fill in the fixed part of the output buffer + OutputBuffer->StartingLcn.QuadPart = StartingCluster; + OutputBuffer->BitmapSize.QuadPart = DesiredClusters; + + RtlZeroMemory( &OutputBuffer->Buffer[0], BytesToCopy ); + lim = BytesToCopy * 8; + FSBM = (PULONG)(Vcb->FSBM_Bitmap); + LSh = Vcb->LB2B_Bits; + Dest = (PULONG)(&OutputBuffer->Buffer[0]); + + for(i=StartingCluster & ~7; iVCBResource)); + UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; + return STATUS_INVALID_USER_BUFFER; + } _SEH2_END; + + UDFReleaseResource(&(Vcb->VCBResource)); + + UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + + BytesToCopy; + Irp->IoStatus.Status = STATUS_SUCCESS; + + return STATUS_SUCCESS; + + +} // end UDFGetVolumeBitmap() + + +NTSTATUS +UDFGetRetrievalPointers( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG Special + ) +{ + NTSTATUS RC; + + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + PUDF_FILE_INFO FileInfo; + + ULONG InputBufferLength; + ULONG OutputBufferLength; + + PRETRIEVAL_POINTERS_BUFFER OutputBuffer; + PSTARTING_VCN_INPUT_BUFFER InputBuffer; + + LARGE_INTEGER StartingVcn; + int64 AllocationSize; + + PEXTENT_MAP SubMapping = NULL; + ULONG SubExtInfoSz; + ULONG i; + ULONG LBS; + ULONG LBSh; + ULONG L2BSh; + + KdPrint(("UDFGetRetrievalPointers\n")); + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + // Get the input and output buffer lengths and pointers. + // Initialize some variables. + InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + + //OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)UDFGetCallersBuffer( IrpContext, Irp ); + if(Special) { + OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->AssociatedIrp.SystemBuffer; + } else { + OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->UserBuffer; + } + InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer; + if(!InputBuffer) { + InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)OutputBuffer; + } + + _SEH2_TRY { + + Irp->IoStatus.Information = 0; + // Check for a minimum length on the input and ouput buffers. + if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) || + (OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) { + + try_return( RC = STATUS_BUFFER_TOO_SMALL ); + } + + _SEH2_TRY { + + if (Irp->RequestorMode != KernelMode) { + ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer, + InputBufferLength, + sizeof(UCHAR) ); + ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) ); + } + StartingVcn = InputBuffer->StartingVcn; + + } _SEH2_EXCEPT(Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) { + + RC = _SEH2_GetExceptionCode(); + RC = FsRtlIsNtstatusExpected(RC) ? + RC : STATUS_INVALID_USER_BUFFER; + try_return(RC); + } _SEH2_END; + + switch(Special) { + case 0: + FileInfo = Fcb->FileInfo; + break; + case 1: + FileInfo = Vcb->NonAllocFileInfo; + break; + default: + try_return( RC = STATUS_INVALID_PARAMETER ); + } + + if(!FileInfo) { + try_return( RC = STATUS_OBJECT_NAME_NOT_FOUND ); + } + + AllocationSize = UDFGetFileAllocationSize(Vcb, FileInfo); + + LBS = Vcb->LBlockSize; + LBSh = Vcb->LBlockSizeBits; + L2BSh = Vcb->LB2B_Bits; + + if (StartingVcn.HighPart || + StartingVcn.LowPart >= (ULONG)(AllocationSize >> LBSh)) { + + try_return( RC = STATUS_END_OF_FILE ); + } + + SubExtInfoSz = (OutputBufferLength - FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0])) / (sizeof(LARGE_INTEGER)*2); + // re-use AllocationSize as NextVcn + RC = UDFReadFileLocation__(Vcb, FileInfo, StartingVcn.QuadPart << LBSh, + &SubMapping, &SubExtInfoSz, &AllocationSize); + if(!NT_SUCCESS(RC)) + try_return(RC); + + OutputBuffer->ExtentCount = SubExtInfoSz; + OutputBuffer->StartingVcn = StartingVcn; + for(i=0; iExtents[i].Lcn.QuadPart = (int64)(-1); + } else + if(SubMapping[i].extLocation & 0x80000000) { + OutputBuffer->Extents[i].Lcn.LowPart = (SubMapping[i].extLocation & 0x7fffffff) >> L2BSh; + OutputBuffer->Extents[i].Lcn.HighPart = 0x80000000; + } else { + OutputBuffer->Extents[i].Lcn.LowPart = SubMapping[i].extLocation >> L2BSh; + OutputBuffer->Extents[i].Lcn.HighPart = 0; + } + // alignment for last sector + SubMapping[i].extLength += LBS-1; + StartingVcn.QuadPart += SubMapping[i].extLength >> LBSh; + OutputBuffer->Extents[i].NextVcn = StartingVcn; + } + + Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]) + i * sizeof(LARGE_INTEGER) * 2; + +try_exit: NOTHING; + } _SEH2_FINALLY { + + if(SubMapping) + MyFreePool__(SubMapping); + Irp->IoStatus.Status = RC; + } _SEH2_END; + + return RC; +} // end UDFGetRetrievalPointers() + + +NTSTATUS +UDFIsVolumeDirty( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + PULONG VolumeState; + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + + PVCB Vcb; + PtrUDFFCB Fcb; + PtrUDFCCB Ccb; + + KdPrint(("UDFIsVolumeDirty\n")); + + Irp->IoStatus.Information = 0; + + if (Irp->AssociatedIrp.SystemBuffer != NULL) { + VolumeState = (PULONG)(Irp->AssociatedIrp.SystemBuffer); + } else if (Irp->MdlAddress != NULL) { + VolumeState = (PULONG)MmGetSystemAddressForMdl(Irp->MdlAddress); + } else { + KdPrint((" STATUS_INVALID_USER_BUFFER\n")); + Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; + return STATUS_INVALID_USER_BUFFER; + } + + if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) { + KdPrint((" STATUS_BUFFER_TOO_SMALL\n")); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + return STATUS_BUFFER_TOO_SMALL; + } + + (*VolumeState) = 0; + + // Decode the file object, the only type of opens we accept are + // user volume opens. + Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2); + if(!Ccb) { + KdPrint((" !Ccb\n")); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + Fcb = Ccb->Fcb; + Vcb = Fcb->Vcb; + + if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) { + KdPrint((" !Volume\n")); + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + KdPrint((" !Mounted\n")); + Irp->IoStatus.Status = STATUS_VOLUME_DISMOUNTED; + return STATUS_VOLUME_DISMOUNTED; + } + + if(Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) { + KdPrint((" Dirty\n")); + (*VolumeState) |= VOLUME_IS_DIRTY; + Irp->IoStatus.Information = sizeof(ULONG); + } else { + KdPrint((" Clean\n")); + } + Irp->IoStatus.Status = STATUS_SUCCESS; + + return STATUS_SUCCESS; + +} // end UDFIsVolumeDirty() + + +NTSTATUS +UDFInvalidateVolumes( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp + ) +{ + NTSTATUS RC; + PEXTENDED_IO_STACK_LOCATION IrpSp = + (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp ); + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + + KdPrint(("UDFInvalidateVolumes\n")); + + KIRQL SavedIrql; + + LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0}; + + HANDLE Handle; + + PVPB NewVpb; + PVCB Vcb; + + PLIST_ENTRY Link; + + PFILE_OBJECT FileToMarkBad; + PDEVICE_OBJECT DeviceToMarkBad; + + Irp->IoStatus.Information = 0; + + // Check for the correct security access. + // The caller must have the SeTcbPrivilege. + if (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && + IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST && + IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES && + !SeSinglePrivilegeCheck( TcbPrivilege, UserMode )) { + KdPrint(("UDFInvalidateVolumes: STATUS_PRIVILEGE_NOT_HELD\n")); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + return STATUS_PRIVILEGE_NOT_HELD; + } + // Try to get a pointer to the device object from the handle passed in. + if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) { + KdPrint(("UDFInvalidateVolumes: STATUS_INVALID_PARAMETER\n")); + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return STATUS_INVALID_PARAMETER; + } + + Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer); + + RC = ObReferenceObjectByHandle( Handle, + 0, + *IoFileObjectType, + KernelMode, + (PVOID*)&FileToMarkBad, + NULL ); + + if (!NT_SUCCESS(RC)) { + KdPrint(("UDFInvalidateVolumes: can't get handle, RC=%x\n", RC)); + Irp->IoStatus.Status = RC; + return RC; + } + + // We only needed the pointer, not a reference. + ObDereferenceObject( FileToMarkBad ); + + // Grab the DeviceObject from the FileObject. + DeviceToMarkBad = FileToMarkBad->DeviceObject; + + // Create a new Vpb for this device so that any new opens will mount + // a new volume. + NewVpb = (PVPB)DbgAllocatePoolWithTag( NonPagedPool, sizeof( VPB ), 'bpvU' ); + if(!NewVpb) { + KdPrint(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES\n")); + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory( NewVpb, sizeof( VPB ) ); + + NewVpb->Type = IO_TYPE_VPB; + NewVpb->Size = sizeof( VPB ); + NewVpb->RealDevice = DeviceToMarkBad; + NewVpb->Flags = DeviceToMarkBad->Vpb->Flags & VPB_REMOVE_PENDING; + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + // Nothing can go wrong now. + IoAcquireVpbSpinLock( &SavedIrql ); + if (DeviceToMarkBad->Vpb->Flags & VPB_MOUNTED) { + DeviceToMarkBad->Vpb = NewVpb; + NewVpb = NULL; + } + ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL ); + IoReleaseVpbSpinLock( SavedIrql ); + + if (NewVpb) { + DbgFreePool( NewVpb ); + } + + // Walk through all of the Vcb's attached to the global data. + Link = UDFGlobalData.VCBQueue.Flink; + + //ASSERT(FALSE); + + while (Link != &(UDFGlobalData.VCBQueue)) { + // Get 'next' Vcb + Vcb = CONTAINING_RECORD( Link, VCB, NextVCB ); + // Move to the next link now since the current Vcb may be deleted. + Link = Link->Flink; + + // Acquire Vcb resource + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + + if (Vcb->Vpb->RealDevice == DeviceToMarkBad) { + + if(!Buf) { + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)*2); + if(!Buf) { + KdPrint(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES (2)\n")); + UDFReleaseResource(&(Vcb->VCBResource)); + MyFreePool__(NewVpb); + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_INSUFFICIENT_RESOURCES; + } + } + +#ifdef UDF_DELAYED_CLOSE + KdPrint((" UDFInvalidateVolumes: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; + UDFReleaseResource(&(Vcb->VCBResource)); +#endif //UDF_DELAYED_CLOSE + + if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) { + KdPrint((" UDFInvalidateVolumes: UDFCloseAllSystemDelayedInDir\n")); + RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + ASSERT(OS_SUCCESS(RC)); + } +#ifdef UDF_DELAYED_CLOSE + KdPrint((" UDFInvalidateVolumes: UDFCloseAllDelayed\n")); + UDFCloseAllDelayed(Vcb); + //ASSERT(OS_SUCCESS(RC)); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + + UDFDoDismountSequence(Vcb, Buf, FALSE); + UDFReleaseResource(&(Vcb->VCBResource)); + + UDFStopEjectWaiter(Vcb); + KdPrint(("UDFInvalidateVolumes: Vcb %x dismounted\n", Vcb)); + break; + } else { + KdPrint(("UDFInvalidateVolumes: skip Vcb %x\n", Vcb)); + UDFReleaseResource(&(Vcb->VCBResource)); + } + + } + // Once we have processed all the mounted logical volumes, we can release + // all acquired global resources and leave (in peace :-) + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + + Irp->IoStatus.Status = STATUS_SUCCESS; + + if(Buf) { + KdPrint(("UDFInvalidateVolumes: free buffer\n")); + MyFreePool__(Buf); + } + + // drop volume completly + KdPrint(("UDFInvalidateVolumes: drop volume completly\n")); + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + UDFScanForDismountedVcb(IrpContext); + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + + KdPrint(("UDFInvalidateVolumes: done\n")); + return STATUS_SUCCESS; + +} // end UDFInvalidateVolumes() diff --git a/reactos/drivers/filesystems/udfs/lockctrl.cpp b/reactos/drivers/filesystems/udfs/lockctrl.cpp new file mode 100644 index 00000000000..1125018a88b --- /dev/null +++ b/reactos/drivers/filesystems/udfs/lockctrl.cpp @@ -0,0 +1,564 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: LockCtrl.cpp.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "byte-range locking" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN + + +/************************************************************************* +* +* Function: UDFLockControl() +* +* Description: +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFLockControl( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFLockControl\n")); +// BrutePoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + // Call the common Lock Control routine, with blocking allowed if + // synchronous + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonLockControl(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFLockControl() + + +/************************************************************************* +* +* Function: UDFCommonLockControl() +* +* Description: +* This is the common routine for doing Lock control operations called +* by both the fsd and fsp threads +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFCommonLockControl( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + //IO_STATUS_BLOCK LocalIoStatus; + BOOLEAN CompleteRequest = FALSE; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = FALSE; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN AcquiredFCB = FALSE; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + KdPrint(("UDFCommonLockControl\n")); + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location. + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + CompleteRequest = TRUE; + try_return(RC = STATUS_INVALID_PARAMETER); + } + + NtReqFcb = Fcb->NTRequiredFCB; + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // Acquire the FCB resource shared + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + + RC = FsRtlProcessFileLock(&(NtReqFcb->FileLock), Irp, NULL); + CompleteRequest = TRUE; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + // Release the FCB resources if acquired. + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + if (PostRequest) { + // Perform appropriate post related processing here + RC = UDFPostRequest(PtrIrpContext, Irp); + } else + if(!_SEH2_AbnormalTermination()) { + // Simply free up the IrpContext since the IRP has been queued or + // Completed by FsRtlProcessFileLock + UDFReleaseIrpContext(PtrIrpContext); + } + } _SEH2_END; // end of "__finally" processing + + return(RC); +} // end UDFCommonLockControl() + + +/* +Routine Description: + This is a call back routine for doing the fast lock call. +Arguments: + FileObject - Supplies the file object used in this operation + FileOffset - Supplies the file offset used in this operation + Length - Supplies the length used in this operation + ProcessId - Supplies the process ID used in this operation + Key - Supplies the key used in this operation + FailImmediately - Indicates if the request should fail immediately + if the lock cannot be granted. + ExclusiveLock - Indicates if this is a request for an exclusive or + shared lock + IoStatus - Receives the Status if this operation is successful + +Return Value: + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. +*/ + +BOOLEAN +NTAPI +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 Results = FALSE; + +// BOOLEAN AcquiredFCB = FALSE; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + KdPrint(("UDFFastLock\n")); + // Decode the type of file object we're being asked to process and make + // sure it is only a user file open. + + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; + return TRUE; + } + + // Acquire exclusive access to the Fcb this operation can always wait + + FsRtlEnterFileSystem(); + + // BUGBUG: kenr + // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); + + _SEH2_TRY { + + // We check whether we can proceed + // based on the state of the file oplocks. + + // Now call the FsRtl routine to do the actual processing of the + // Lock request + if (Results = FsRtlFastLock( &(Fcb->NTRequiredFCB->FileLock), + FileObject, + FileOffset, + Length, + ProcessId, + Key, + FailImmediately, + ExclusiveLock, + IoStatus, + NULL, + FALSE )) { + + // Set the flag indicating if Fast I/O is possible + Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); + } + +//try_exit: NOTHING; + } _SEH2_FINALLY { + + // Release the Fcb, and return to our caller + + // BUGBUG: kenr + // UDFReleaseResource( (Fcb)->Header.Resource ); + + FsRtlExitFileSystem(); + + } _SEH2_END; + + return Results; +} // end UDFFastLock() + + +/* +Routine Description: + + This is a call back routine for doing the fast unlock single call. + +Arguments: + + FileObject - Supplies the file object used in this operation + FileOffset - Supplies the file offset used in this operation + Length - Supplies the length used in this operation + ProcessId - Supplies the process ID used in this operation + Key - Supplies the key used in this operation + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. +*/ +BOOLEAN +NTAPI +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 Results = FALSE; + +// BOOLEAN AcquiredFCB = FALSE; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + KdPrint(("UDFFastUnlockSingle\n")); + // Decode the type of file object we're being asked to process and make + // sure it is only a user file open. + + IoStatus->Information = 0; + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + return TRUE; + } + + // Acquire exclusive access to the Fcb this operation can always wait + + FsRtlEnterFileSystem(); + + // BUGBUG: kenr + // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); + + _SEH2_TRY { + + // We check whether we can proceed + // based on the state of the file oplocks. + + // Now call the FsRtl routine to do the actual processing of the + // Lock request + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockSingle( &(Fcb->NTRequiredFCB->FileLock), + FileObject, + FileOffset, + Length, + ProcessId, + Key, + NULL, + FALSE ); + // Set the flag indicating if Fast I/O is possible + Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); + +//try_exit: NOTHING; + } _SEH2_FINALLY { + + // Release the Fcb, and return to our caller + + // BUGBUG: kenr + // UDFReleaseResource( (Fcb)->Header.Resource ); + + FsRtlExitFileSystem(); + + } _SEH2_END; + + return Results; +} // end UDFFastUnlockSingle() + + +/* +Routine Description: + + This is a call back routine for doing the fast unlock all call. + +Arguments: + FileObject - Supplies the file object used in this operation + ProcessId - Supplies the process ID used in this operation + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. +*/ +BOOLEAN +NTAPI +UDFFastUnlockAll( + IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +{ + BOOLEAN Results = FALSE; + +// BOOLEAN AcquiredFCB = FALSE; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + KdPrint(("UDFFastUnlockAll\n")); + + IoStatus->Information = 0; + // Decode the type of file object we're being asked to process and make + // sure it is only a user file open. + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + return TRUE; + } + + // Acquire shared access to the Fcb this operation can always wait + + FsRtlEnterFileSystem(); + + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE ); + + _SEH2_TRY { + + // We check whether we can proceed + // based on the state of the file oplocks. + + // Now call the FsRtl routine to do the actual processing of the + // Lock request + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockAll( &(Fcb->NTRequiredFCB->FileLock), + FileObject, + ProcessId, + NULL ); + + // Set the flag indicating if Fast I/O is questionable + + Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb ); + +//try_exit: NOTHING; + } _SEH2_FINALLY { + + // Release the Fcb, and return to our caller + + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); + FsRtlExitFileSystem(); + + } _SEH2_END; + + return Results; +} // end UDFFastUnlockAll() + + +/* +Routine Description: + + This is a call back routine for doing the fast unlock all call. + +Arguments: + FileObject - Supplies the file object used in this operation + ProcessId - Supplies the process ID used in this operation + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. +*/ + +BOOLEAN +NTAPI +UDFFastUnlockAllByKey( + IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +{ + BOOLEAN Results = FALSE; + +// BOOLEAN AcquiredFCB = FALSE; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + KdPrint(("UDFFastUnlockAllByKey\n")); + + IoStatus->Information = 0; + // Decode the type of file object we're being asked to process and make + // sure it is only a user file open. + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + // Validate the sent-in FCB + if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || + (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + return TRUE; + } + + // Acquire shared access to the Fcb this operation can always wait + + FsRtlEnterFileSystem(); + + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE ); + + _SEH2_TRY { + + // We check whether we can proceed + // based on the state of the file oplocks. + + // Now call the FsRtl routine to do the actual processing of the + // Lock request + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockAllByKey( &(Fcb->NTRequiredFCB->FileLock), + FileObject, + ProcessId, + Key, + NULL ); + + // Set the flag indicating if Fast I/O is possible + + Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb ); + +//try_exit: NOTHING; + } _SEH2_FINALLY { + + // Release the Fcb, and return to our caller + + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); + UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); + FsRtlExitFileSystem(); + + } _SEH2_END; + + return Results; +} // end UDFFastUnlockAllByKey() diff --git a/reactos/drivers/filesystems/udfs/mem.cpp b/reactos/drivers/filesystems/udfs/mem.cpp new file mode 100644 index 00000000000..355c2a8e6dc --- /dev/null +++ b/reactos/drivers/filesystems/udfs/mem.cpp @@ -0,0 +1,10 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_MEM + +#include "..\Include\Mem_tools.cpp" diff --git a/reactos/drivers/filesystems/udfs/mem.h b/reactos/drivers/filesystems/udfs/mem.h new file mode 100644 index 00000000000..b229f9e959e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/mem.h @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __MY_MEM_H__ +#define __MY_MEM_H__ + +#ifdef UDF_DBG +#define MY_HEAP_TRACK_OWNERS +#define MY_HEAP_TRACK_REF +#define MY_HEAP_CHECK_BOUNDS +#define MY_HEAP_CHECK_BOUNDS_SZ 2 +#define MY_HEAP_CHECK_BOUNDS_BSZ (MY_HEAP_CHECK_BOUNDS_SZ*sizeof(ULONG)) +#endif //UDF_DBG + +//#define MY_HEAP_FORCE_NONPAGED +//#define MY_USE_INTERNAL_MEMMANAGER + +//#include "udffs.h" +#include "..\Include\Mem_tools.h" + +#endif // __MY_MEM_H__ diff --git a/reactos/drivers/filesystems/udfs/misc.cpp b/reactos/drivers/filesystems/udfs/misc.cpp new file mode 100644 index 00000000000..64396ef40d4 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/misc.cpp @@ -0,0 +1,2595 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + File: Misc.cpp + + Module: UDF File System Driver (Kernel mode execution only) + + Description: + This file contains some miscellaneous support routines. + +*/ + +#include "udffs.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_MISC + +#include + +//CCHAR DefLetter[] = {""}; + +/* + + Function: UDFInitializeZones() + + Description: + Allocates some memory for global zones used to allocate FSD structures. + Either all memory will be allocated or we will back out gracefully. + + Expected Interrupt Level (for execution) : + + IRQL_PASSIVE_LEVEL + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +UDFInitializeZones(VOID) +{ + NTSTATUS RC = STATUS_SUCCESS; + uint32 SizeOfZone = UDFGlobalData.DefaultZoneSizeInNumStructs; + uint32 SizeOfObjectNameZone = 0; + uint32 SizeOfCCBZone = 0; +// uint32 SizeOfFCBZone = 0; + uint32 SizeOfIrpContextZone = 0; +// uint32 SizeOfFileInfoZone = 0; + + _SEH2_TRY { + + // initialize the spinlock protecting the zones + KeInitializeSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock)); + + // determine memory requirements + switch (MmQuerySystemSize()) { +#ifndef DEMO + case MmMediumSystem: + SizeOfObjectNameZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + UDFGlobalData.MaxDelayedCloseCount = 24; + UDFGlobalData.MinDelayedCloseCount = 6; + UDFGlobalData.MaxDirDelayedCloseCount = 8; + UDFGlobalData.MinDirDelayedCloseCount = 2; + UDFGlobalData.WCacheMaxFrames = 8*4; + UDFGlobalData.WCacheMaxBlocks = 16*64; + UDFGlobalData.WCacheBlocksPerFrameSh = 8; + UDFGlobalData.WCacheFramesToKeepFree = 4; + break; + case MmLargeSystem: + SizeOfObjectNameZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + UDFGlobalData.MaxDelayedCloseCount = 72; + UDFGlobalData.MinDelayedCloseCount = 18; + UDFGlobalData.MaxDirDelayedCloseCount = 24; + UDFGlobalData.MinDirDelayedCloseCount = 6; + UDFGlobalData.WCacheMaxFrames = 2*16*4; + UDFGlobalData.WCacheMaxBlocks = 2*16*64; + UDFGlobalData.WCacheBlocksPerFrameSh = 8; + UDFGlobalData.WCacheFramesToKeepFree = 8; + break; +#endif //DEMO + case MmSmallSystem: + default: + SizeOfObjectNameZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + UDFGlobalData.MaxDelayedCloseCount = 8; + UDFGlobalData.MinDelayedCloseCount = 2; + UDFGlobalData.MaxDirDelayedCloseCount = 6; + UDFGlobalData.MinDirDelayedCloseCount = 1; + UDFGlobalData.WCacheMaxFrames = 8*4/2; + UDFGlobalData.WCacheMaxBlocks = 16*64/2; + UDFGlobalData.WCacheBlocksPerFrameSh = 8; + UDFGlobalData.WCacheFramesToKeepFree = 2; + } + + // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-) + if (MmIsThisAnNtAsSystem()) { + SizeOfObjectNameZone *= UDF_NTAS_MULTIPLE; + SizeOfCCBZone *= UDF_NTAS_MULTIPLE; + SizeOfIrpContextZone *= UDF_NTAS_MULTIPLE; + } + + // allocate memory for each of the zones and initialize the zones ... + if (!(UDFGlobalData.ObjectNameZone = DbgAllocatePool(NonPagedPool, SizeOfObjectNameZone))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(UDFGlobalData.CCBZone = DbgAllocatePool(NonPagedPool, SizeOfCCBZone))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(UDFGlobalData.IrpContextZone = DbgAllocatePool(NonPagedPool, SizeOfIrpContextZone))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // initialize each of the zone headers ... + if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.ObjectNameZoneHeader), + UDFQuadAlign(sizeof(UDFObjectName)), + UDFGlobalData.ObjectNameZone, SizeOfObjectNameZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.CCBZoneHeader), + UDFQuadAlign(sizeof(UDFCCB)), + UDFGlobalData.CCBZone, + SizeOfCCBZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.IrpContextZoneHeader), + UDFQuadAlign(sizeof(UDFIrpContext)), + UDFGlobalData.IrpContextZone, + SizeOfIrpContextZone))) { + // failed the initialization, leave ... + try_return(RC); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if (!NT_SUCCESS(RC)) { + // invoke the destroy routine now ... + UDFDestroyZones(); + } else { + // mark the fact that we have allocated zones ... + UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_ZONES_INITIALIZED); + } + } _SEH2_END; + + return(RC); +} + + +/************************************************************************* +* +* Function: UDFDestroyZones() +* +* Description: +* Free up the previously allocated memory. NEVER do this once the +* driver has been successfully loaded. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID UDFDestroyZones(VOID) +{ +// BrutePoint(); + + _SEH2_TRY { + // free up each of the pools + if(UDFGlobalData.ObjectNameZone) { + DbgFreePool(UDFGlobalData.ObjectNameZone); + UDFGlobalData.ObjectNameZone = NULL; + } + if(UDFGlobalData.CCBZone) { + DbgFreePool(UDFGlobalData.CCBZone); + UDFGlobalData.CCBZone = NULL; + } + if(UDFGlobalData.IrpContextZone) { + DbgFreePool(UDFGlobalData.IrpContextZone); + UDFGlobalData.IrpContextZone = NULL; + } + +//try_exit: NOTHING; + + } _SEH2_FINALLY { + UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_ZONES_INITIALIZED; + } _SEH2_END; + + return; +} + + +/************************************************************************* +* +* Function: UDFIsIrpTopLevel() +* +* Description: +* Helps the FSD determine who the "top level" caller is for this +* request. A request can originate directly from a user process +* (in which case, the "top level" will be NULL when this routine +* is invoked), OR the user may have originated either from the NT +* Cache Manager/VMM ("top level" may be set), or this could be a +* recursion into our code in which we would have set the "top level" +* field the last time around. +* +* Expected Interrupt Level (for execution) : +* +* whatever level a particular dispatch routine is invoked at. +* +* Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked) +* +*************************************************************************/ +BOOLEAN +__fastcall +UDFIsIrpTopLevel( + PIRP Irp) // the IRP sent to our dispatch routine +{ + if(!IoGetTopLevelIrp()) { + // OK, so we can set ourselves to become the "top level" component + IoSetTopLevelIrp(Irp); + return TRUE; + } + return FALSE; +} + + +/************************************************************************* +* +* Function: UDFExceptionFilter() +* +* Description: +* This routines allows the driver to determine whether the exception +* is an "allowed" exception i.e. one we should not-so-quietly consume +* ourselves, or one which should be propagated onwards in which case +* we will most likely bring down the machine. +* +* This routine employs the services of FsRtlIsNtstatusExpected(). This +* routine returns a BOOLEAN result. A RC of FALSE will cause us to return +* EXCEPTION_CONTINUE_SEARCH which will probably cause a panic. +* The FsRtl.. routine returns FALSE iff exception values are (currently) : +* STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION || +* STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH +* +*************************************************************************/ +long +UDFExceptionFilter( + PtrUDFIrpContext PtrIrpContext, + PEXCEPTION_POINTERS PtrExceptionPointers + ) +{ + long ReturnCode = EXCEPTION_EXECUTE_HANDLER; + NTSTATUS ExceptionCode = STATUS_SUCCESS; +#if defined UDF_DBG || defined PRINT_ALWAYS + ULONG i; + + KdPrint(("UDFExceptionFilter\n")); + KdPrint((" Ex. Code: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionCode)); + KdPrint((" Ex. Addr: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionAddress)); + KdPrint((" Ex. Flag: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionFlags)); + KdPrint((" Ex. Pnum: %x\n",PtrExceptionPointers->ExceptionRecord->NumberParameters)); + for(i=0;iExceptionRecord->NumberParameters;i++) { + KdPrint((" %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionInformation[i])); + } + KdPrint(("Exception context:\n")); + if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_INTEGER) { + KdPrint(("EAX=%8.8x ",PtrExceptionPointers->ContextRecord->Eax)); + KdPrint(("EBX=%8.8x ",PtrExceptionPointers->ContextRecord->Ebx)); + KdPrint(("ECX=%8.8x ",PtrExceptionPointers->ContextRecord->Ecx)); + KdPrint(("EDX=%8.8x\n",PtrExceptionPointers->ContextRecord->Edx)); + + KdPrint(("ESI=%8.8x ",PtrExceptionPointers->ContextRecord->Esi)); + KdPrint(("EDI=%8.8x ",PtrExceptionPointers->ContextRecord->Edi)); + } + if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_CONTROL) { + KdPrint(("EBP=%8.8x ",PtrExceptionPointers->ContextRecord->Esp)); + KdPrint(("ESP=%8.8x\n",PtrExceptionPointers->ContextRecord->Ebp)); + + KdPrint(("EIP=%8.8x\n",PtrExceptionPointers->ContextRecord->Eip)); + } +// KdPrint(("Flags: %s %s ",PtrExceptionPointers->ContextRecord->Eip)); + +#endif // UDF_DBG + + // figure out the exception code + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode; + + if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) { + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2]; + } + + if (PtrIrpContext) { + PtrIrpContext->SavedExceptionCode = ExceptionCode; + UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_EXCEPTION); + } + + // check if we should propagate this exception or not + if (!(FsRtlIsNtstatusExpected(ExceptionCode))) { + + // better free up the IrpContext now ... + if (PtrIrpContext) { + KdPrint((" UDF Driver internal error\n")); + BrutePoint(); + } else { + // we are not ok, propagate this exception. + // NOTE: we will bring down the machine ... + ReturnCode = EXCEPTION_CONTINUE_SEARCH; + } + } + + + // return the appropriate code + return(ReturnCode); +} // end UDFExceptionFilter() + + +/************************************************************************* +* +* Function: UDFExceptionHandler() +* +* Description: +* One of the routines in the FSD or in the modules we invoked encountered +* an exception. We have decided that we will "handle" the exception. +* Therefore we will prevent the machine from a panic ... +* You can do pretty much anything you choose to in your commercial +* driver at this point to ensure a graceful exit. In the UDF +* driver, We shall simply free up the IrpContext (if any), set the +* error code in the IRP and complete the IRP at this time ... +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: Error code +* +*************************************************************************/ +NTSTATUS +UDFExceptionHandler( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ +// NTSTATUS RC; + NTSTATUS ExceptionCode = STATUS_INSUFFICIENT_RESOURCES; + PDEVICE_OBJECT Device; + PVPB Vpb; + PETHREAD Thread; + + KdPrint(("UDFExceptionHandler \n")); + +// ASSERT(Irp); + + if (!Irp) { + KdPrint((" !Irp, return\n")); + ASSERT(!PtrIrpContext); + return ExceptionCode; + } + // If it was a queued close (or something like this) then we need not + // completing it because of MUST_SUCCEED requirement. + + if (PtrIrpContext) { + ExceptionCode = PtrIrpContext->SavedExceptionCode; + // Free irp context here +// UDFReleaseIrpContext(PtrIrpContext); + } else { + KdPrint((" complete Irp and return\n")); + // must be insufficient resources ...? + ExceptionCode = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = ExceptionCode; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ExceptionCode; + } + + // Check if we are posting this request. One of the following must be true + // if we are to post a request. + // + // - Status code is STATUS_CANT_WAIT and the request is asynchronous + // or we are forcing this to be posted. + // + // - Status code is STATUS_VERIFY_REQUIRED and we are at APC level + // or higher. Can't wait for IO in the verify path in this case. + // + // Set the MORE_PROCESSING flag in the IrpContext to keep if from being + // deleted if this is a retryable condition. + + if (ExceptionCode == STATUS_VERIFY_REQUIRED) { + if (KeGetCurrentIrql() >= APC_LEVEL) { + KdPrint((" use UDFPostRequest()\n")); + ExceptionCode = UDFPostRequest( PtrIrpContext, Irp ); + } + } + + // If we posted the request or our caller will retry then just return here. + if ((ExceptionCode == STATUS_PENDING) || + (ExceptionCode == STATUS_CANT_WAIT)) { + + KdPrint((" STATUS_PENDING/STATUS_CANT_WAIT, return\n")); + return ExceptionCode; + } + + // Store this error into the Irp for posting back to the Io system. + Irp->IoStatus.Status = ExceptionCode; + if (IoIsErrorUserInduced( ExceptionCode )) { + + // Check for the various error conditions that can be caused by, + // and possibly resolved my the user. + if (ExceptionCode == STATUS_VERIFY_REQUIRED) { + + // Now we are at the top level file system entry point. + // + // If we have already posted this request then the device to + // verify is in the original thread. Find this via the Irp. + Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread ); + IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL ); + + // If there is no device in that location then check in the + // current thread. + if (Device == NULL) { + + Device = IoGetDeviceToVerify( PsGetCurrentThread() ); + IoSetDeviceToVerify( PsGetCurrentThread(), NULL ); + + ASSERT( Device != NULL ); + + // Let's not BugCheck just because the driver screwed up. + if (Device == NULL) { + + KdPrint((" Device == NULL, return\n")); + ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR; + Irp->IoStatus.Status = ExceptionCode; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + UDFReleaseIrpContext(PtrIrpContext); + + return ExceptionCode; + } + } + + KdPrint((" use UDFPerformVerify()\n")); + // UDFPerformVerify() will do the right thing with the Irp. + // If we return STATUS_CANT_WAIT then the current thread + // can retry the request. + return UDFPerformVerify( PtrIrpContext, Irp, Device ); + } + + // + // The other user induced conditions generate an error unless + // they have been disabled for this request. + // + + if (FlagOn( PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS )) { + + KdPrint((" DISABLE_POPUPS, complete Irp and return\n")); + Irp->IoStatus.Status = ExceptionCode; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + UDFReleaseIrpContext(PtrIrpContext); + return ExceptionCode; + } else { + + // Generate a pop-up + if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) { + + Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb; + } else { + + Vpb = NULL; + } + // The device to verify is either in my thread local storage + // or that of the thread that owns the Irp. + Thread = Irp->Tail.Overlay.Thread; + Device = IoGetDeviceToVerify( Thread ); + + if (Device == NULL) { + + Thread = PsGetCurrentThread(); + Device = IoGetDeviceToVerify( Thread ); + ASSERT( Device != NULL ); + + // Let's not BugCheck just because the driver screwed up. + if (Device == NULL) { + KdPrint((" Device == NULL, return(2)\n")); + Irp->IoStatus.Status = ExceptionCode; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + UDFReleaseIrpContext(PtrIrpContext); + + return ExceptionCode; + } + } + + // This routine actually causes the pop-up. It usually + // does this by queuing an APC to the callers thread, + // but in some cases it will complete the request immediately, + // so it is very important to IoMarkIrpPending() first. + IoMarkIrpPending( Irp ); + IoRaiseHardError( Irp, Vpb, Device ); + + // We will be handing control back to the caller here, so + // reset the saved device object. + + KdPrint((" use IoSetDeviceToVerify()\n")); + IoSetDeviceToVerify( Thread, NULL ); + // The Irp will be completed by Io or resubmitted. In either + // case we must clean up the IrpContext here. + + UDFReleaseIrpContext(PtrIrpContext); + return STATUS_PENDING; + } + } + + // If it was a normal request from IOManager then complete it + if (Irp) { + KdPrint((" complete Irp\n")); + // set the error code in the IRP + Irp->IoStatus.Status = ExceptionCode; + Irp->IoStatus.Information = 0; + + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + UDFReleaseIrpContext(PtrIrpContext); + } + + KdPrint((" return from exception handler with code %x\n", ExceptionCode)); + return(ExceptionCode); +} // end UDFExceptionHandler() + +/************************************************************************* +* +* Function: UDFLogEvent() +* +* Description: +* Log a message in the NT Event Log. This is a rather simplistic log +* methodology since we can potentially utilize the event log to +* provide a lot of information to the user (and you should too!) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +UDFLogEvent( + NTSTATUS UDFEventLogId, // the UDF private message id + NTSTATUS RC) // any NT error code we wish to log ... +{ + _SEH2_TRY { + + // Implement a call to IoAllocateErrorLogEntry() followed by a call + // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry() + // will free memory for the entry once the write completes (which in actuality + // is an asynchronous operation). + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + // nothing really we can do here, just do not wish to crash ... + NOTHING; + } _SEH2_END; + + return; +} // end UDFLogEvent() + + +/************************************************************************* +* +* Function: UDFAllocateObjectName() +* +* Description: +* Allocate a new ObjectName structure to represent an open on-disk object. +* Also initialize the ObjectName structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the ObjectName structure OR NULL. +* +*************************************************************************/ +PtrUDFObjectName +UDFAllocateObjectName(VOID) +{ + PtrUDFObjectName PtrObjectName = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, __try to allocate out of the zone + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(UDFGlobalData.ObjectNameZoneHeader))) { + // we have enough memory + PtrObjectName = (PtrUDFObjectName)ExAllocateFromZone(&(UDFGlobalData.ObjectNameZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM + PtrObjectName = (PtrUDFObjectName)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFObjectName))); + AllocatedFromZone = FALSE; + } + + if (!PtrObjectName) { + return NULL; + } + + // zero out the allocated memory block + RtlZeroMemory(PtrObjectName, UDFQuadAlign(sizeof(UDFObjectName))); + + // set up some fields ... + PtrObjectName->NodeIdentifier.NodeType = UDF_NODE_TYPE_OBJECT_NAME; + PtrObjectName->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFObjectName)); + + + if (!AllocatedFromZone) { + UDFSetFlag(PtrObjectName->ObjectNameFlags, UDF_OBJ_NAME_NOT_FROM_ZONE); + } + + return(PtrObjectName); +} // end UDFAllocateObjectName() + + +/************************************************************************* +* +* Function: UDFReleaseObjectName() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +__fastcall +UDFReleaseObjectName( + PtrUDFObjectName PtrObjectName) +{ + KIRQL CurrentIrql; + + ASSERT(PtrObjectName); + + // give back memory either to the zone or to the VMM + if (!(PtrObjectName->ObjectNameFlags & UDF_OBJ_NAME_NOT_FROM_ZONE)) { + // back to the zone + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(UDFGlobalData.ObjectNameZoneHeader), PtrObjectName); + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + MyFreePool__(PtrObjectName); + } + + return; +} // end UDFReleaseObjectName() + + +/************************************************************************* +* +* Function: UDFAllocateCCB() +* +* Description: +* Allocate a new CCB structure to represent an open on-disk object. +* Also initialize the CCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the CCB structure OR NULL. +* +*************************************************************************/ +PtrUDFCCB +UDFAllocateCCB(VOID) +{ + PtrUDFCCB Ccb = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, __try to allocate out of the zone + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(UDFGlobalData.CCBZoneHeader))) { + // we have enough memory + Ccb = (PtrUDFCCB)ExAllocateFromZone(&(UDFGlobalData.CCBZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM + Ccb = (PtrUDFCCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFCCB))); + AllocatedFromZone = FALSE; +// KdPrint((" CCB allocated @%x\n",Ccb)); + } + + if (!Ccb) { + return NULL; + } + + // zero out the allocated memory block + RtlZeroMemory(Ccb, UDFQuadAlign(sizeof(UDFCCB))); + + // set up some fields ... + Ccb->NodeIdentifier.NodeType = UDF_NODE_TYPE_CCB; + Ccb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFCCB)); + + + if (!AllocatedFromZone) { + UDFSetFlag(Ccb->CCBFlags, UDF_CCB_NOT_FROM_ZONE); + } + + KdPrint(("UDFAllocateCCB: %x\n", Ccb)); + return(Ccb); +} // end UDFAllocateCCB() + + +/************************************************************************* +* +* Function: UDFReleaseCCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +__fastcall +UDFReleaseCCB( + PtrUDFCCB Ccb + ) +{ + KIRQL CurrentIrql; + + ASSERT(Ccb); + + KdPrint(("UDFReleaseCCB: %x\n", Ccb)); + // give back memory either to the zone or to the VMM + if(!(Ccb->CCBFlags & UDF_CCB_NOT_FROM_ZONE)) { + // back to the zone + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(UDFGlobalData.CCBZoneHeader), Ccb); + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + MyFreePool__(Ccb); + } + + return; +} // end UDFReleaseCCB() + +/* + Function: UDFCleanupCCB() + + Description: + Cleanup and deallocate a previously allocated structure. + + Expected Interrupt Level (for execution) : + + IRQL_PASSIVE_LEVEL + + Return Value: None + +*/ +VOID +__fastcall +UDFCleanUpCCB( + PtrUDFCCB Ccb) +{ +// ASSERT(Ccb); + if(!Ccb) return; // probably, we havn't allocated it... + ASSERT(Ccb->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB); + + _SEH2_TRY { + if(Ccb->Fcb) { + UDFTouch(&(Ccb->Fcb->CcbListResource)); + UDFAcquireResourceExclusive(&(Ccb->Fcb->CcbListResource),TRUE); + RemoveEntryList(&(Ccb->NextCCB)); + UDFReleaseResource(&(Ccb->Fcb->CcbListResource)); + } else { + BrutePoint(); + } + + if (Ccb->DirectorySearchPattern) { + if (Ccb->DirectorySearchPattern->Buffer) { + MyFreePool__(Ccb->DirectorySearchPattern->Buffer); + Ccb->DirectorySearchPattern->Buffer = NULL; + } + + MyFreePool__(Ccb->DirectorySearchPattern); + Ccb->DirectorySearchPattern = NULL; + } + + UDFReleaseCCB(Ccb); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +} // end UDFCleanUpCCB() + +/************************************************************************* +* +* Function: UDFAllocateFCB() +* +* Description: +* Allocate a new FCB structure to represent an open on-disk object. +* Also initialize the FCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the FCB structure OR NULL. +* +*************************************************************************/ +PtrUDFFCB +UDFAllocateFCB(VOID) +{ + PtrUDFFCB Fcb = NULL; + + Fcb = (PtrUDFFCB)MyAllocatePool__(UDF_FCB_MT, UDFQuadAlign(sizeof(UDFFCB))); + + if (!Fcb) { + return NULL; + } + + // zero out the allocated memory block + RtlZeroMemory(Fcb, UDFQuadAlign(sizeof(UDFFCB))); + + // set up some fields ... + Fcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB; + Fcb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFFCB)); + + KdPrint(("UDFAllocateFCB: %x\n", Fcb)); + return(Fcb); +} // end UDFAllocateFCB() + + +/************************************************************************* +* +* Function: UDFReleaseFCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +/*VOID +UDFReleaseFCB( + PtrUDFFCB Fcb + ) +{ + ASSERT(Fcb); + + MyFreePool__(Fcb); + + return; +}*/ + +/************************************************************************* +* +* +*************************************************************************/ +VOID +__fastcall +UDFCleanUpFCB( + PtrUDFFCB Fcb + ) +{ + KdPrint(("UDFCleanUpFCB: %x\n", Fcb)); + if(!Fcb) return; + + ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); + + _SEH2_TRY { + // Deinitialize FCBName field + if (Fcb->FCBName) { + if(Fcb->FCBName->ObjectName.Buffer) { + MyFreePool__(Fcb->FCBName->ObjectName.Buffer); + Fcb->FCBName->ObjectName.Buffer = NULL; +#ifdef UDF_DBG + Fcb->FCBName->ObjectName.Length = + Fcb->FCBName->ObjectName.MaximumLength = 0; +#endif + } +#ifdef UDF_DBG + else { + KdPrint(("UDF: Fcb has invalid FCBName Buffer\n")); + BrutePoint(); + } +#endif + UDFReleaseObjectName(Fcb->FCBName); + Fcb->FCBName = NULL; + } +#ifdef UDF_DBG + else { + KdPrint(("UDF: Fcb has invalid FCBName field\n")); + BrutePoint(); + } +#endif + + + // begin transaction { + UDFTouch(&(Fcb->Vcb->FcbListResource)); + UDFAcquireResourceExclusive(&(Fcb->Vcb->FcbListResource), TRUE); + // Remove this FCB from list of all FCB in VCB + RemoveEntryList(&(Fcb->NextFCB)); + UDFReleaseResource(&(Fcb->Vcb->FcbListResource)); + // } end transaction + + if(Fcb->FCBFlags & UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE) + UDFDeleteResource(&(Fcb->CcbListResource)); + + // Free memory + UDFReleaseFCB(Fcb); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +} // end UDFCleanUpFCB() + +#ifdef UDF_DBG +ULONG IrpContextCounter = 0; +#endif //UDF_DBG + +/************************************************************************* +* +* Function: UDFAllocateIrpContext() +* +* Description: +* The UDF FSD creates an IRP context for each request received. This +* routine simply allocates (and initializes to NULL) a UDFIrpContext +* structure. +* Most of the fields in the context structure are then initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the IrpContext structure OR NULL. +* +*************************************************************************/ +PtrUDFIrpContext +UDFAllocateIrpContext( + PIRP Irp, + PDEVICE_OBJECT PtrTargetDeviceObject + ) +{ + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + PIO_STACK_LOCATION IrpSp = NULL; + + // first, __try to allocate out of the zone + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(UDFGlobalData.IrpContextZoneHeader))) { + // we have enough memory + PtrIrpContext = (PtrUDFIrpContext)ExAllocateFromZone(&(UDFGlobalData.IrpContextZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM + PtrIrpContext = (PtrUDFIrpContext)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFIrpContext))); + AllocatedFromZone = FALSE; + } + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrIrpContext) { + return NULL; + } + +#ifdef UDF_DBG + IrpContextCounter++; +#endif //UDF_DBG + + // zero out the allocated memory block + RtlZeroMemory(PtrIrpContext, UDFQuadAlign(sizeof(UDFIrpContext))); + + // set up some fields ... + PtrIrpContext->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT; + PtrIrpContext->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFIrpContext)); + + + PtrIrpContext->Irp = Irp; + PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject; + + // copy over some fields from the IRP and set appropriate flag values + if (Irp) { + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + PtrIrpContext->MajorFunction = IrpSp->MajorFunction; + PtrIrpContext->MinorFunction = IrpSp->MinorFunction; + + // Often, a FSD cannot honor a request for asynchronous processing + // of certain critical requests. For example, a "close" request on + // a file object can typically never be deferred. Therefore, do not + // be surprised if sometimes our FSD (just like all other FSD + // implementations on the Windows NT system) has to override the flag + // below. + if (IrpSp->FileObject == NULL) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; + } else { + if (IoIsOperationSynchronous(Irp)) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; + } + } + } + + if (!AllocatedFromZone) { + UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_FROM_ZONE); + } + + // Are we top-level ? This information is used by the dispatching code + // later (and also by the FSD dispatch routine) + if (IoGetTopLevelIrp() != Irp) { + // We are not top-level. Note this fact in the context structure + UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_TOP_LEVEL); + } + + return(PtrIrpContext); +} // end UDFAllocateIrpContext() + + +/************************************************************************* +* +* Function: UDFReleaseIrpContext() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +UDFReleaseIrpContext( + PtrUDFIrpContext PtrIrpContext) +{ + if(!PtrIrpContext) return; +// ASSERT(PtrIrpContext); + +#ifdef UDF_DBG + IrpContextCounter--; +#endif //UDF_DBG + + // give back memory either to the zone or to the VMM + if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_FROM_ZONE)) { + // back to the zone + KIRQL CurrentIrql; + + KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(UDFGlobalData.IrpContextZoneHeader), PtrIrpContext); + KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + MyFreePool__(PtrIrpContext); + } + + return; +} // end UDFReleaseIrpContext() + + +/************************************************************************* +* +* Function: UDFPostRequest() +* +* Description: +* Queue up a request for deferred processing (in the context of a system +* worker thread). The caller must have locked the user buffer (if required) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_PENDING +* +*************************************************************************/ +NTSTATUS +UDFPostRequest( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp + ) +{ + KIRQL SavedIrql; +// PIO_STACK_LOCATION IrpSp; + PVCB Vcb; + +// IrpSp = IoGetCurrentIrpStackLocation(Irp); + +/* + if(Vcb->StopOverflowQueue) { + if(Irp) { + Irp->IoStatus.Status = STATUS_WRONG_VOLUME; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + UDFReleaseIrpContext(PtrIrpContext); + return STATUS_WRONG_VOLUME; + } +*/ + // mark the IRP pending if this is not double post + if(Irp) + IoMarkIrpPending(Irp); + + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql); + + if ( Vcb->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) { + + // We cannot currently respond to this IRP so we'll just enqueue it + // to the overflow queue on the volume. + // Note: we just reuse LIST_ITEM field inside WorkQueueItem, this + // doesn't matter to regular processing of WorkItems. + InsertTailList( &(Vcb->OverflowQueue), + &(PtrIrpContext->WorkQueueItem.List) ); + Vcb->OverflowQueueCount++; + KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql ); + + } else { + + // We are going to send this Irp to an ex worker thread so up + // the count. + Vcb->PostedRequestCount++; + + KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql ); + + // queue up the request + ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), (PWORKER_THREAD_ROUTINE)UDFCommonDispatch, PtrIrpContext); + + ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), CriticalWorkQueue); + // ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), DelayedWorkQueue); + + } + + // return status pending + return STATUS_PENDING; +} // end UDFPostRequest() + + +/************************************************************************* +* +* Function: UDFCommonDispatch() +* +* Description: +* The common dispatch routine invoked in the context of a system worker +* thread. All we do here is pretty much case off the major function +* code and invoke the appropriate FSD dispatch routine for further +* processing. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +UDFCommonDispatch( + IN PVOID Context // actually is a pointer to IRPContext structure + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + PIRP Irp = NULL; + PVCB Vcb; + KIRQL SavedIrql; + PLIST_ENTRY Entry; + BOOLEAN SpinLock = FALSE; + + // The context must be a pointer to an IrpContext structure + PtrIrpContext = (PtrUDFIrpContext)Context; + + // Assert that the Context is legitimate + if ( !PtrIrpContext || + (PtrIrpContext->NodeIdentifier.NodeType != UDF_NODE_TYPE_IRP_CONTEXT) || + (PtrIrpContext->NodeIdentifier.NodeSize != UDFQuadAlign(sizeof(UDFIrpContext))) /*|| + !(PtrIrpContext->Irp)*/) { + KdPrint((" Invalid Context\n")); + BrutePoint(); + return; + } + + Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(Vcb); + + KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Started!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount)); + + while(TRUE) { + + KdPrint((" Next IRP\n")); + FsRtlEnterFileSystem(); + + // Get a pointer to the IRP structure + // in some cases we can get Zero pointer to Irp + Irp = PtrIrpContext->Irp; + // Now, check if the FSD was top level when the IRP was originally invoked + // and set the thread context (for the worker thread) appropriately + if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) { + // The FSD is not top level for the original request + // Set a constant value in TLS to reflect this fact + IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); + } else { + IoSetTopLevelIrp(Irp); + } + + // Since the FSD routine will now be invoked in the context of this worker + // thread, we should inform the FSD that it is perfectly OK to block in + // the context of this thread + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; + + _SEH2_TRY { + + // Pre-processing has been completed; check the Major Function code value + // either in the IrpContext (copied from the IRP), or directly from the + // IRP itself (we will need a pointer to the stack location to do that), + // Then, switch based on the value on the Major Function code + KdPrint((" *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread())); + switch (PtrIrpContext->MajorFunction) { + case IRP_MJ_CREATE: + // Invoke the common create routine + RC = UDFCommonCreate(PtrIrpContext, Irp); + break; + case IRP_MJ_READ: + // Invoke the common read routine + RC = UDFCommonRead(PtrIrpContext, Irp); + break; +#ifndef UDF_READ_ONLY_BUILD + case IRP_MJ_WRITE: + // Invoke the common write routine + RC = UDFCommonWrite(PtrIrpContext, Irp); + break; +#endif //UDF_READ_ONLY_BUILD + case IRP_MJ_CLEANUP: + // Invoke the common cleanup routine + RC = UDFCommonCleanup(PtrIrpContext, Irp); + break; + case IRP_MJ_CLOSE: + // Invoke the common close routine + RC = UDFCommonClose(PtrIrpContext, Irp); + break; + case IRP_MJ_DIRECTORY_CONTROL: + // Invoke the common directory control routine + RC = UDFCommonDirControl(PtrIrpContext, Irp); + break; + case IRP_MJ_QUERY_INFORMATION: +#ifndef UDF_READ_ONLY_BUILD + case IRP_MJ_SET_INFORMATION: +#endif //UDF_READ_ONLY_BUILD + // Invoke the common query/set information routine + RC = UDFCommonFileInfo(PtrIrpContext, Irp); + break; + case IRP_MJ_QUERY_VOLUME_INFORMATION: + // Invoke the common query volume routine + RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp); + break; +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO // release + case IRP_MJ_SET_VOLUME_INFORMATION: + // Invoke the common query volume routine + RC = UDFCommonSetVolInfo(PtrIrpContext, Irp); + break; +#endif // DEMO +#endif //UDF_READ_ONLY_BUILD +#ifdef UDF_HANDLE_EAS +/* case IRP_MJ_QUERY_EA: + // Invoke the common query EAs routine + RC = UDFCommonGetExtendedAttr(PtrIrpContext, Irp); + break; + case IRP_MJ_SET_EA: + // Invoke the common set EAs routine + RC = UDFCommonSetExtendedAttr(PtrIrpContext, Irp); + break;*/ +#endif // UDF_HANDLE_EAS +#ifdef UDF_ENABLE_SECURITY + case IRP_MJ_QUERY_SECURITY: + // Invoke the common query Security routine + RC = UDFCommonGetSecurity(PtrIrpContext, Irp); + break; +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO // release + case IRP_MJ_SET_SECURITY: + // Invoke the common set Security routine + RC = UDFCommonSetSecurity(PtrIrpContext, Irp); + break; +#endif // DEMO +#endif //UDF_READ_ONLY_BUILD +#endif // UDF_ENABLE_SECURITY + // Continue with the remaining possible dispatch routines below ... + default: + KdPrint((" unhandled *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread())); + // This is the case where we have an invalid major function + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + break; + } + + // Note: PtrIrpContext is invalid here + KdPrint((" *** Thr: %x Done!\n", PsGetCurrentThread())); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + // Enable preemption + FsRtlExitFileSystem(); + + // Ensure that the "top-level" field is cleared + IoSetTopLevelIrp(NULL); + + // If there are any entries on this volume's overflow queue, service + // them. + if(!Vcb) { + BrutePoint(); + break; + } + + KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql); + SpinLock = TRUE; + if(!Vcb->OverflowQueueCount) + break; + + Vcb->OverflowQueueCount--; + Entry = RemoveHeadList(&Vcb->OverflowQueue); + KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql); + SpinLock = FALSE; + + PtrIrpContext = CONTAINING_RECORD( Entry, + UDFIrpContext, + WorkQueueItem.List ); + } + + if(!SpinLock) + KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql); + Vcb->PostedRequestCount--; + KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql); + + KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Terminated!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount)); + + return; +} // end UDFCommonDispatch() + + +/************************************************************************* +* +* Function: UDFInitializeVCB() +* +* Description: +* Perform the initialization for a VCB structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: status +* +*************************************************************************/ +NTSTATUS +UDFInitializeVCB( + IN PDEVICE_OBJECT PtrVolumeDeviceObject, + IN PDEVICE_OBJECT PtrTargetDeviceObject, + IN PVPB PtrVPB + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PVCB Vcb = NULL; + SHORT i; + + BOOLEAN VCBResourceInit = FALSE; + BOOLEAN BitMapResource1Init = FALSE; + BOOLEAN FcbListResourceInit = FALSE; + BOOLEAN FileIdResourceInit = FALSE; + BOOLEAN DlocResourceInit = FALSE; + BOOLEAN DlocResource2Init = FALSE; + BOOLEAN FlushResourceInit = FALSE; + BOOLEAN PreallocResourceInit= FALSE; + BOOLEAN IoResourceInit = FALSE; + + Vcb = (PVCB)(PtrVolumeDeviceObject->DeviceExtension); + + _SEH2_TRY { + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(Vcb, sizeof(VCB)); + + // Initialize the signature fields + Vcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_VCB; + Vcb->NodeIdentifier.NodeSize = sizeof(VCB); + + // Initialize the ERESOURCE object. + RC = UDFInitializeResourceLite(&(Vcb->VCBResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + VCBResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->BitMapResource1)); + if(!NT_SUCCESS(RC)) + try_return(RC); + BitMapResource1Init = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->FcbListResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + FcbListResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->FileIdResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + FileIdResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->DlocResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + DlocResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->DlocResource2)); + if(!NT_SUCCESS(RC)) + try_return(RC); + DlocResource2Init = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->FlushResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + FlushResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->PreallocResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + PreallocResourceInit = TRUE; + + RC = UDFInitializeResourceLite(&(Vcb->IoResource)); + if(!NT_SUCCESS(RC)) + try_return(RC); + IoResourceInit = TRUE; + +// RC = UDFInitializeResourceLite(&(Vcb->DelayedCloseResource)); +// ASSERT(NT_SUCCESS(RC)); + + // Allocate buffer for statistics + Vcb->Statistics = (PFILE_SYSTEM_STATISTICS)MyAllocatePool__(NonPagedPool, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors ); + if(!Vcb->Statistics) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors ); + for (i=0; i < (KeNumberProcessors); i++) { + Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_NTFS; + Vcb->Statistics[i].Common.Version = 1; + Vcb->Statistics[i].Common.SizeOfCompleteStructure = + sizeof(FILE_SYSTEM_STATISTICS); + } + + // We know the target device object. + // Note that this is not neccessarily a pointer to the actual + // physical/virtual device on which the logical volume should + // be mounted. This is actually a pointer to either the actual + // (real) device or to any device object that may have been + // attached to it. Any IRPs that we send down should be sent to this + // device object. However, the "real" physical/virtual device object + // on which we perform our mount operation can be determined from the + // RealDevice field in the VPB sent to us. + Vcb->TargetDeviceObject = PtrTargetDeviceObject; + + // We also have a pointer to the newly created device object representing + // this logical volume (remember that this VCB structure is simply an + // extension of the created device object). + Vcb->VCBDeviceObject = PtrVolumeDeviceObject; + + // We also have the VPB pointer. This was obtained from the + // Parameters.MountVolume.Vpb field in the current I/O stack location + // for the mount IRP. + Vcb->Vpb = PtrVPB; + // Target Vcb field in Vcb onto itself. This required for check in + // open/lock/unlock volume dispatch poits + Vcb->Vcb=Vcb; + + // Set the removable media flag based on the real device's + // characteristics + if (PtrVPB->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_REMOVABLE_MEDIA; + } + + // Initialize the list anchor (head) for some lists in this VCB. + InitializeListHead(&(Vcb->NextFCB)); + InitializeListHead(&(Vcb->NextNotifyIRP)); + InitializeListHead(&(Vcb->VolumeOpenListHead)); + + // Initialize the overflow queue for the volume + Vcb->OverflowQueueCount = 0; + InitializeListHead(&(Vcb->OverflowQueue)); + + Vcb->PostedRequestCount = 0; + KeInitializeSpinLock(&(Vcb->OverflowQueueSpinLock)); + + // Initialize the notify IRP list mutex + FsRtlNotifyInitializeSync(&(Vcb->NotifyIRPMutex)); + + // Intilize NtRequiredFCB for this VCB + Vcb->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); + if(!Vcb->NTRequiredFCB) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RtlZeroMemory(Vcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); + + // Set the initial file size values appropriately. Note that our FSD may + // wish to guess at the initial amount of information we would like to + // read from the disk until we have really determined that this a valid + // logical volume (on disk) that we wish to mount. + // Vcb->FileSize = Vcb->AllocationSize = ?? + + // We do not want to bother with valid data length callbacks + // from the Cache Manager for the file stream opened for volume metadata + // information + Vcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFULL; + + Vcb->VolumeLockPID = -1; + + Vcb->VCBOpenCount = 1; + + Vcb->WCacheMaxBlocks = UDFGlobalData.WCacheMaxBlocks; + Vcb->WCacheMaxFrames = UDFGlobalData.WCacheMaxFrames; + Vcb->WCacheBlocksPerFrameSh = UDFGlobalData.WCacheBlocksPerFrameSh; + Vcb->WCacheFramesToKeepFree = UDFGlobalData.WCacheFramesToKeepFree; + + // Create a stream file object for this volume. + //Vcb->PtrStreamFileObject = IoCreateStreamFileObject(NULL, + // Vcb->Vpb->RealDevice); + //ASSERT(Vcb->PtrStreamFileObject); + + // Initialize some important fields in the newly created file object. + //Vcb->PtrStreamFileObject->FsContext = (PVOID)Vcb; + //Vcb->PtrStreamFileObject->FsContext2 = NULL; + //Vcb->PtrStreamFileObject->SectionObjectPointer = &(Vcb->SectionObject); + + //Vcb->PtrStreamFileObject->Vpb = PtrVPB; + + // Link this chap onto the global linked list of all VCB structures. + // We consider that GlobalDataResource was acquired in past + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + InsertTailList(&(UDFGlobalData.VCBQueue), &(Vcb->NextVCB)); + + Vcb->TargetDevName.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(MOUNTDEV_NAME)); + if(!Vcb->TargetDevName.Buffer) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject, + NULL,0, + (PVOID)(Vcb->TargetDevName.Buffer),sizeof(MOUNTDEV_NAME), + FALSE, NULL); + if(!NT_SUCCESS(RC)) { + + if(RC == STATUS_BUFFER_OVERFLOW) { + if(!MyReallocPool__((PCHAR)(Vcb->TargetDevName.Buffer), sizeof(MOUNTDEV_NAME), + (PCHAR*)&(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME)) ) { + goto Kill_DevName_buffer; + } + + RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject, + NULL,0, + (PVOID)(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME), + FALSE, NULL); + if(!NT_SUCCESS(RC)) + goto Kill_DevName_buffer; + + } else { +Kill_DevName_buffer: + if(!MyReallocPool__((PCHAR)Vcb->TargetDevName.Buffer, sizeof(MOUNTDEV_NAME), + (PCHAR*)&(Vcb->TargetDevName.Buffer), sizeof(REG_NAMELESS_DEV))) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RtlCopyMemory(Vcb->TargetDevName.Buffer, REG_NAMELESS_DEV, sizeof(REG_NAMELESS_DEV)); + Vcb->TargetDevName.Length = sizeof(REG_NAMELESS_DEV)-sizeof(WCHAR); + Vcb->TargetDevName.MaximumLength = sizeof(REG_NAMELESS_DEV); + goto read_reg; + } + } + + Vcb->TargetDevName.MaximumLength = + (Vcb->TargetDevName.Length = Vcb->TargetDevName.Buffer[0]) + sizeof(WCHAR); + RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+1), Vcb->TargetDevName.Buffer[0]); + Vcb->TargetDevName.Buffer[i = (SHORT)(Vcb->TargetDevName.Length/sizeof(WCHAR))] = 0; + + for(;i>=0;i--) { + if(Vcb->TargetDevName.Buffer[i] == L'\\') { + + Vcb->TargetDevName.Length -= i*sizeof(WCHAR); + RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+i), Vcb->TargetDevName.Length); + Vcb->TargetDevName.Buffer[Vcb->TargetDevName.Length/sizeof(WCHAR)] = 0; + break; + } + } + + KdPrint((" TargetDevName: %S\n", Vcb->TargetDevName.Buffer)); + + // Initialize caching for the stream file object. + //CcInitializeCacheMap(Vcb->PtrStreamFileObject, (PCC_FILE_SIZES)(&(Vcb->AllocationSize)), + // TRUE, // We will use pinned access. + // &(UDFGlobalData.CacheMgrCallBacks), Vcb); + +read_reg: + + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + + // Mark the fact that this VCB structure is initialized. + Vcb->VCBFlags |= UDF_VCB_FLAGS_VCB_INITIALIZED; + + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(!NT_SUCCESS(RC)) { + if(Vcb->TargetDevName.Buffer) + MyFreePool__(Vcb->TargetDevName.Buffer); + if(Vcb->NTRequiredFCB) + MyFreePool__(Vcb->NTRequiredFCB); + if(Vcb->Statistics) + MyFreePool__(Vcb->Statistics); + + if(VCBResourceInit) + UDFDeleteResource(&(Vcb->VCBResource)); + if(BitMapResource1Init) + UDFDeleteResource(&(Vcb->BitMapResource1)); + if(FcbListResourceInit) + UDFDeleteResource(&(Vcb->FcbListResource)); + if(FileIdResourceInit) + UDFDeleteResource(&(Vcb->FileIdResource)); + if(DlocResourceInit) + UDFDeleteResource(&(Vcb->DlocResource)); + if(DlocResource2Init) + UDFDeleteResource(&(Vcb->DlocResource2)); + if(FlushResourceInit) + UDFDeleteResource(&(Vcb->FlushResource)); + if(PreallocResourceInit) + UDFDeleteResource(&(Vcb->PreallocResource)); + if(IoResourceInit) + UDFDeleteResource(&(Vcb->IoResource)); + } + } _SEH2_END; + + return RC; +} // end UDFInitializeVCB() + +UDFFSD_MEDIA_TYPE +UDFGetMediaClass( + PVCB Vcb + ) +{ + switch(Vcb->FsDeviceType) { + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + if(Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY | + UDF_VCB_FLAGS_MEDIA_READ_ONLY)) + return MediaCdrom; + if(Vcb->CDR_Mode) + return MediaCdr; + if((Vcb->MediaType >= MediaType_UnknownSize_CDR) && + (Vcb->MediaType < MediaType_UnknownSize_CDRW)) { + return MediaCdr; + } + if((Vcb->MediaType >= MediaType_UnknownSize_CDRW) && + (Vcb->MediaType < MediaType_UnknownSize_Unknown)) { + return MediaCdrw; + } + if(Vcb->MediaClassEx == CdMediaClass_CDR) { + return MediaCdr; + } + if(Vcb->MediaClassEx == CdMediaClass_DVDR || + Vcb->MediaClassEx == CdMediaClass_DVDpR || + Vcb->MediaClassEx == CdMediaClass_HD_DVDR || + Vcb->MediaClassEx == CdMediaClass_BDR) { + return MediaDvdr; + } + if(Vcb->MediaClassEx == CdMediaClass_CDRW) { + return MediaCdrw; + } + if(Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDpRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM || + Vcb->MediaClassEx == CdMediaClass_HD_DVDRW || + Vcb->MediaClassEx == CdMediaClass_HD_DVDRAM || + Vcb->MediaClassEx == CdMediaClass_BDRE) { + return MediaDvdrw; + } + // + if(Vcb->MediaClassEx == CdMediaClass_CDROM || + Vcb->MediaClassEx == CdMediaClass_DVDROM || + Vcb->MediaClassEx == CdMediaClass_HD_DVDROM || + Vcb->MediaClassEx == CdMediaClass_BDROM) { + return MediaCdrom; + } + return MediaCdrom; +#ifdef UDF_HDD_SUPPORT + case FILE_DEVICE_DISK_FILE_SYSTEM: + if(Vcb->TargetDeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) + return MediaFloppy; + if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) + return MediaZip; + return MediaHdd; +#endif //UDF_HDD_SUPPORT + } + return MediaUnknown; +} // end UDFGetMediaClass() + +typedef ULONG +(*ptrUDFGetParameter)( + IN PVCB Vcb, + IN PWSTR Name, + IN ULONG DefValue + ); + +VOID +UDFUpdateCompatOption( + PVCB Vcb, + BOOLEAN Update, + BOOLEAN UseCfg, + PWCHAR Name, + ULONG Flag, + BOOLEAN Default + ) +{ + ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter; + + if(UDFGetParameter(Vcb, Name, Update ? ((Vcb->CompatFlags & Flag) ? TRUE : FALSE) : Default)) { + Vcb->CompatFlags |= Flag; + } else { + Vcb->CompatFlags &= ~Flag; + } +} // end UDFUpdateCompatOption() + +VOID +UDFReadRegKeys( + PVCB Vcb, + BOOLEAN Update, + BOOLEAN UseCfg + ) +{ + ULONG mult = 1; + ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter; + + Vcb->DefaultRegName = UDFMediaClassName[(ULONG)UDFGetMediaClass(Vcb)].ClassName; + + // Should we use Extended FE by default ? + Vcb->UseExtendedFE = (UCHAR)UDFGetParameter(Vcb, REG_USEEXTENDEDFE_NAME, + Update ? Vcb->UseExtendedFE : FALSE); + if(Vcb->UseExtendedFE != TRUE) Vcb->UseExtendedFE = FALSE; + // What type of AllocDescs should we use + Vcb->DefaultAllocMode = (USHORT)UDFGetParameter(Vcb, REG_DEFALLOCMODE_NAME, + Update ? Vcb->DefaultAllocMode : ICB_FLAG_AD_SHORT); + if(Vcb->DefaultAllocMode > ICB_FLAG_AD_LONG) Vcb->DefaultAllocMode = ICB_FLAG_AD_SHORT; + // Default UID & GID to be set on newly created files + Vcb->DefaultUID = UDFGetParameter(Vcb, UDF_DEFAULT_UID_NAME, Update ? Vcb->DefaultUID : -1); + Vcb->DefaultGID = UDFGetParameter(Vcb, UDF_DEFAULT_GID_NAME, Update ? Vcb->DefaultGID : -1); + // FE allocation charge for plain Dirs + Vcb->FECharge = UDFGetParameter(Vcb, UDF_FE_CHARGE_NAME, Update ? Vcb->FECharge : 0); + if(!Vcb->FECharge) + Vcb->FECharge = UDF_DEFAULT_FE_CHARGE; + // FE allocation charge for Stream Dirs (SDir) + Vcb->FEChargeSDir = UDFGetParameter(Vcb, UDF_FE_CHARGE_SDIR_NAME, + Update ? Vcb->FEChargeSDir : 0); + if(!Vcb->FEChargeSDir) + Vcb->FEChargeSDir = UDF_DEFAULT_FE_CHARGE_SDIR; + // How many Deleted entries should contain Directory to make us + // start packing it. + Vcb->PackDirThreshold = UDFGetParameter(Vcb, UDF_DIR_PACK_THRESHOLD_NAME, + Update ? Vcb->PackDirThreshold : 0); + if(Vcb->PackDirThreshold == 0xffffffff) + Vcb->PackDirThreshold = UDF_DEFAULT_DIR_PACK_THRESHOLD; + // The binary exponent for the number of Pages to be read-ahead'ed + // This information would be sent to System Cache Manager + if(!Update) { + Vcb->SystemCacheGran = (1 << UDFGetParameter(Vcb, UDF_READAHEAD_GRAN_NAME, 0)) * PAGE_SIZE; + if(!Vcb->SystemCacheGran) + Vcb->SystemCacheGran = UDF_DEFAULT_READAHEAD_GRAN; + } + // Timeouts for FreeSpaceBitMap & TheWholeDirTree flushes + Vcb->BM_FlushPriod = UDFGetParameter(Vcb, UDF_BM_FLUSH_PERIOD_NAME, + Update ? Vcb->BM_FlushPriod : 0); + if(!Vcb->BM_FlushPriod) { + Vcb->BM_FlushPriod = UDF_DEFAULT_BM_FLUSH_TIMEOUT; + } else + if(Vcb->BM_FlushPriod == -1) { + Vcb->BM_FlushPriod = 0; + } + Vcb->Tree_FlushPriod = UDFGetParameter(Vcb, UDF_TREE_FLUSH_PERIOD_NAME, + Update ? Vcb->Tree_FlushPriod : 0); + if(!Vcb->Tree_FlushPriod) { + Vcb->Tree_FlushPriod = UDF_DEFAULT_TREE_FLUSH_TIMEOUT; + } else + if(Vcb->Tree_FlushPriod == -1) { + Vcb->Tree_FlushPriod = 0; + } + Vcb->SkipCountLimit = UDFGetParameter(Vcb, UDF_NO_UPDATE_PERIOD_NAME, + Update ? Vcb->SkipCountLimit : 0); + if(!Vcb->SkipCountLimit) + Vcb->SkipCountLimit = -1; + + Vcb->SkipEjectCountLimit = UDFGetParameter(Vcb, UDF_NO_EJECT_PERIOD_NAME, + Update ? Vcb->SkipEjectCountLimit : 3); + + if(!Update) { + // How many threads are allowed to sodomize Disc simultaneously on each CPU + Vcb->ThreadsPerCpu = UDFGetParameter(Vcb, UDF_FSP_THREAD_PER_CPU_NAME, + Update ? Vcb->ThreadsPerCpu : 2); + if(Vcb->ThreadsPerCpu < 2) + Vcb->ThreadsPerCpu = UDF_DEFAULT_FSP_THREAD_PER_CPU; + } + // The mimimum FileSize increment when we'll decide not to allocate + // on-disk space. + Vcb->SparseThreshold = UDFGetParameter(Vcb, UDF_SPARSE_THRESHOLD_NAME, + Update ? Vcb->SparseThreshold : 0); + if(!Vcb->SparseThreshold) + Vcb->SparseThreshold = UDF_DEFAULT_SPARSE_THRESHOLD; + // This option is used to VERIFY all the data written. It decreases performance + Vcb->VerifyOnWrite = UDFGetParameter(Vcb, UDF_VERIFY_ON_WRITE_NAME, + Update ? Vcb->VerifyOnWrite : FALSE) ? TRUE : FALSE; + +#ifndef UDF_READ_ONLY_BUILD + // Should we update AttrFileTime on Attr changes + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ATTR, UDF_VCB_IC_UPDATE_ATTR_TIME, FALSE); + // Should we update ModifyFileTime on Writes changes + // It also affects ARCHIVE bit setting on write operations + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_MOD, UDF_VCB_IC_UPDATE_MODIFY_TIME, FALSE); + // Should we update AccessFileTime on Exec & so on. + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ACCS, UDF_VCB_IC_UPDATE_ACCESS_TIME, FALSE); + // Should we update Archive bit + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_ATTR_ARCH, UDF_VCB_IC_UPDATE_ARCH_BIT, FALSE); + // Should we update Dir's Times & Attrs on Modify + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_W, UDF_VCB_IC_UPDATE_DIR_WRITE, FALSE); + // Should we update Dir's Times & Attrs on Access + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_R, UDF_VCB_IC_UPDATE_DIR_READ, FALSE); + // Should we allow user to write into Read-Only Directory + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_WRITE_IN_RO_DIR, UDF_VCB_IC_WRITE_IN_RO_DIR, TRUE); + // Should we allow user to change Access Time for unchanged Directory + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR, UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME, FALSE); +#endif //UDF_READ_ONLY_BUILD + // Should we record Allocation Descriptors in W2k-compatible form + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_ALLOC_DESCS, UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS, TRUE); + // Should we read LONG_ADs with invalid PartitionReferenceNumber (generated by Nero Instant Burner) + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_INSTANT_COMPAT_ALLOC_DESCS, UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS, TRUE); + // Should we make a copy of VolumeLabel in LVD + // usually only PVD is updated + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_VLABEL, UDF_VCB_IC_W2K_COMPAT_VLABEL, TRUE); + // Should we handle or ignore HW_RO flag + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_HW_RO, UDF_VCB_IC_HW_RO, FALSE); + // Should we handle or ignore SOFT_RO flag + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_SOFT_RO, UDF_VCB_IC_SOFT_RO, TRUE); + + // Check if we should generate UDF-style or OS-style DOS-names + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_OS_NATIVE_DOS_NAME, UDF_VCB_IC_OS_NATIVE_DOS_NAME, FALSE); +#ifndef UDF_READ_ONLY_BUILD + // should we force FO_WRITE_THROUGH on removable media + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_WRITE_THROUGH_NAME, UDF_VCB_IC_FORCE_WRITE_THROUGH, + (Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE + ); +#endif //UDF_READ_ONLY_BUILD + // Should we ignore FO_SEQUENTIAL_ONLY + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_IGNORE_SEQUENTIAL_IO, UDF_VCB_IC_IGNORE_SEQUENTIAL_IO, FALSE); +// Force Read-only mounts +#ifndef UDF_READ_ONLY_BUILD + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_HW_RO, UDF_VCB_IC_FORCE_HW_RO, FALSE); +#else //UDF_READ_ONLY_BUILD + Vcb->CompatFlags |= UDF_VCB_IC_FORCE_HW_RO; +#endif //UDF_READ_ONLY_BUILD + // Check if we should send FLUSH request for File/Dir down to + // underlaying driver + if(UDFGetParameter(Vcb, UDF_FLUSH_MEDIA,Update ? Vcb->FlushMedia : FALSE)) { + Vcb->FlushMedia = TRUE; + } else { + Vcb->FlushMedia = FALSE; + } + // compare data from packet with data to be writen there + // before physical writing + if(!UDFGetParameter(Vcb, UDF_COMPARE_BEFORE_WRITE, Update ? Vcb->DoNotCompareBeforeWrite : FALSE)) { + Vcb->DoNotCompareBeforeWrite = TRUE; + } else { + Vcb->DoNotCompareBeforeWrite = FALSE; + } + if(!Update) { + if(UDFGetParameter(Vcb, UDF_CHAINED_IO, TRUE)) { + Vcb->CacheChainedIo = TRUE; + } + + if(UDFGetParameter(Vcb, UDF_FORCE_MOUNT_ALL, FALSE)) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + } + // Should we show Blank.Cd file on damaged/unformatted, + // but UDF-compatible disks + Vcb->ShowBlankCd = (UCHAR)UDFGetParameter(Vcb, UDF_SHOW_BLANK_CD, FALSE); + if(Vcb->ShowBlankCd) { + Vcb->CompatFlags |= UDF_VCB_IC_SHOW_BLANK_CD; + if(Vcb->ShowBlankCd > 2) { + Vcb->ShowBlankCd = 2; + } + } + // Should we wait util CD device return from + // Becoming Ready state + if(UDFGetParameter(Vcb, UDF_WAIT_CD_SPINUP, TRUE)) { + Vcb->CompatFlags |= UDF_VCB_IC_WAIT_CD_SPINUP; + } + // Should we remenber bad VDS locations during mount + // Caching will improve mount performance on bad disks, but + // will degrade mauntability of unreliable discs + if(UDFGetParameter(Vcb, UDF_CACHE_BAD_VDS, TRUE)) { + Vcb->CompatFlags |= UDF_VCB_IC_CACHE_BAD_VDS; + } + + // Set partitially damaged volume mount mode + Vcb->PartitialDamagedVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_PART_DAMAGED_BEHAVIOR, UDF_PART_DAMAGED_RW); + if(Vcb->PartitialDamagedVolumeAction > 2) { + Vcb->PartitialDamagedVolumeAction = UDF_PART_DAMAGED_RW; + } + + // Set partitially damaged volume mount mode + Vcb->NoFreeRelocationSpaceVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_NO_SPARE_BEHAVIOR, UDF_PART_DAMAGED_RW); + if(Vcb->NoFreeRelocationSpaceVolumeAction > 1) { + Vcb->NoFreeRelocationSpaceVolumeAction = UDF_PART_DAMAGED_RW; + } + + // Set dirty volume mount mode + if(UDFGetParameter(Vcb, UDF_DIRTY_VOLUME_BEHAVIOR, UDF_PART_DAMAGED_RO)) { + Vcb->CompatFlags |= UDF_VCB_IC_DIRTY_RO; + } + + mult = UDFGetParameter(Vcb, UDF_CACHE_SIZE_MULTIPLIER, 1); + if(!mult) mult = 1; + Vcb->WCacheMaxBlocks *= mult; + Vcb->WCacheMaxFrames *= mult; + + if(UDFGetParameter(Vcb, UDF_USE_EJECT_BUTTON, TRUE)) { + Vcb->UseEvent = TRUE; + } + } + return; +} // end UDFReadRegKeys() + +ULONG +UDFGetRegParameter( + IN PVCB Vcb, + IN PWSTR Name, + IN ULONG DefValue + ) +{ + return UDFRegCheckParameterValue(&(UDFGlobalData.SavedRegPath), + Name, + Vcb ? &(Vcb->TargetDevName) : NULL, + Vcb ? Vcb->DefaultRegName : NULL, + DefValue); +} // end UDFGetRegParameter() + +ULONG +UDFGetCfgParameter( + IN PVCB Vcb, + IN PWSTR Name, + IN ULONG DefValue + ) +{ + ULONG len; + CHAR NameA[128]; + ULONG ret_val=0; + CHAR a; + BOOLEAN wait_name=TRUE; + BOOLEAN wait_val=FALSE; + BOOLEAN wait_nl=FALSE; + ULONG radix=10; + ULONG i; + + PUCHAR Cfg = Vcb->Cfg; + ULONG Length = Vcb->CfgLength; + + if(!Cfg || !Length) + return DefValue; + + len = wcslen(Name); + if(len >= sizeof(NameA)) + return DefValue; + sprintf(NameA, "%S", Name); + + for(i=0; i Length) + return DefValue; + if(RtlCompareMemory(Cfg+i, NameA, len) == len) { + a=Cfg[i+len]; + switch(a) { + case '\n': + case '\r': + case ',': + case ';': + case '#': + return DefValue; + case '=': + case ' ': + case '\t': + break; + default: + wait_nl = TRUE; + wait_val = FALSE; + i+=len; + continue; + } + wait_name = FALSE; + wait_nl = FALSE; + wait_val = TRUE; + i+=len; + + } else { + wait_nl = TRUE; + } + continue; + } + if(wait_val) { + if(i+3 > Length) { + if(a=='0' && Cfg[i+1]=='x') { + i+=2; + radix=16; + } + } + if(i >= Length) { + return DefValue; + } + while(i= '0' && a <= '9') { + a -= '0'; + } else { + if(radix != 16) + return DefValue; + if(a >= 'a' && a <= 'f') { + a -= 'a'; + } else + if(a >= 'A' && a <= 'F') { + a -= 'A'; + } else { + return DefValue; + } + a += 0x0a; + } + ret_val = ret_val*radix + a; + wait_val = FALSE; + i++; + } + return ret_val; + } + } + return DefValue; + +} // end UDFGetCfgParameter() + +VOID +UDFReleaseVCB( + PVCB Vcb + ) +{ + LARGE_INTEGER delay; + KdPrint(("UDFReleaseVCB\n")); + + delay.QuadPart = -500000; // 0.05 sec + while(Vcb->PostedRequestCount) { + KdPrint(("UDFReleaseVCB: PostedRequestCount = %d\n", Vcb->PostedRequestCount)); + // spin until all queues IRPs are processed + KeDelayExecutionThread(KernelMode, FALSE, &delay); + delay.QuadPart -= 500000; // grow delay 0.05 sec + } + + _SEH2_TRY { + KdPrint(("UDF: Flushing buffers\n")); + UDFVRelease(Vcb); + WCacheFlushAll__(&(Vcb->FastCache),Vcb); + WCacheRelease__(&(Vcb->FastCache)); + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + +#ifdef UDF_DBG + _SEH2_TRY { + if (!ExIsResourceAcquiredShared(&UDFGlobalData.GlobalDataResource)) { + KdPrint(("UDF: attempt to access to not protected data\n")); + KdPrint(("UDF: UDFGlobalData\n")); + BrutePoint(); + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +#endif + + _SEH2_TRY { + RemoveEntryList(&(Vcb->NextVCB)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + +/* _SEH2_TRY { + if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT) + KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT; + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + }*/ + + _SEH2_TRY { + KdPrint(("UDF: Delete resources\n")); + UDFDeleteResource(&(Vcb->VCBResource)); + UDFDeleteResource(&(Vcb->BitMapResource1)); + UDFDeleteResource(&(Vcb->FcbListResource)); + UDFDeleteResource(&(Vcb->FileIdResource)); + UDFDeleteResource(&(Vcb->DlocResource)); + UDFDeleteResource(&(Vcb->DlocResource2)); + UDFDeleteResource(&(Vcb->FlushResource)); + UDFDeleteResource(&(Vcb->PreallocResource)); + UDFDeleteResource(&(Vcb->IoResource)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + _SEH2_TRY { + KdPrint(("UDF: Cleanup VCB\n")); + ASSERT(IsListEmpty(&(Vcb->NextNotifyIRP))); + FsRtlNotifyUninitializeSync(&(Vcb->NotifyIRPMutex)); + UDFCleanupVCB(Vcb); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + + _SEH2_TRY { + KdPrint(("UDF: Delete DO\n")); + IoDeleteDevice(Vcb->VCBDeviceObject); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + +} // end UDFReleaseVCB() + +/* + Read DWORD from Registry +*/ +ULONG +UDFRegCheckParameterValue( + IN PUNICODE_STRING RegistryPath, + IN PWSTR Name, + IN PUNICODE_STRING PtrVolumePath, + IN PWSTR DefaultPath, + IN ULONG DefValue + ) +{ + NTSTATUS status; + + ULONG val = DefValue; + + UNICODE_STRING paramStr; + UNICODE_STRING defaultParamStr; + UNICODE_STRING paramPathUnknownStr; + + UNICODE_STRING paramSuffix; + UNICODE_STRING paramPath; + UNICODE_STRING paramPathUnknown; + UNICODE_STRING paramDevPath; + UNICODE_STRING defaultParamPath; + + _SEH2_TRY { + + paramPath.Buffer = NULL; + paramDevPath.Buffer = NULL; + paramPathUnknown.Buffer = NULL; + defaultParamPath.Buffer = NULL; + + // First append \Parameters to the passed in registry path + // Note, RtlInitUnicodeString doesn't allocate memory + RtlInitUnicodeString(¶mStr, L"\\Parameters"); + RtlInitUnicodeString(¶mPath, NULL); + + RtlInitUnicodeString(¶mPathUnknownStr, REG_DEFAULT_UNKNOWN); + RtlInitUnicodeString(¶mPathUnknown, NULL); + + paramPathUnknown.MaximumLength = RegistryPath->Length + paramPathUnknownStr.Length + paramStr.Length + sizeof(WCHAR); + paramPath.MaximumLength = RegistryPath->Length + paramStr.Length + sizeof(WCHAR); + + paramPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPath.MaximumLength); + if(!paramPath.Buffer) { + KdPrint(("UDFCheckRegValue: couldn't allocate paramPath\n")); + try_return(val = DefValue); + } + paramPathUnknown.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPathUnknown.MaximumLength); + if(!paramPathUnknown.Buffer) { + KdPrint(("UDFCheckRegValue: couldn't allocate paramPathUnknown\n")); + try_return(val = DefValue); + } + + RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength); + status = RtlAppendUnicodeToString(¶mPath, RegistryPath->Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + status = RtlAppendUnicodeToString(¶mPath, paramStr.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + KdPrint(("UDFCheckRegValue: (1) |%S|\n", paramPath.Buffer)); + + RtlZeroMemory(paramPathUnknown.Buffer, paramPathUnknown.MaximumLength); + status = RtlAppendUnicodeToString(¶mPathUnknown, RegistryPath->Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + status = RtlAppendUnicodeToString(¶mPathUnknown, paramStr.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + status = RtlAppendUnicodeToString(¶mPathUnknown, paramPathUnknownStr.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + KdPrint(("UDFCheckRegValue: (2) |%S|\n", paramPathUnknown.Buffer)); + + // First append \Parameters\Default_XXX to the passed in registry path + if(DefaultPath) { + RtlInitUnicodeString(&defaultParamStr, DefaultPath); + RtlInitUnicodeString(&defaultParamPath, NULL); + defaultParamPath.MaximumLength = paramPath.Length + defaultParamStr.Length + sizeof(WCHAR); + defaultParamPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, defaultParamPath.MaximumLength); + if(!defaultParamPath.Buffer) { + KdPrint(("UDFCheckRegValue: couldn't allocate defaultParamPath\n")); + try_return(val = DefValue); + } + + RtlZeroMemory(defaultParamPath.Buffer, defaultParamPath.MaximumLength); + status = RtlAppendUnicodeToString(&defaultParamPath, paramPath.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + status = RtlAppendUnicodeToString(&defaultParamPath, defaultParamStr.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + KdPrint(("UDFCheckRegValue: (3) |%S|\n", defaultParamPath.Buffer)); + } + + if(PtrVolumePath) { + paramSuffix = *PtrVolumePath; + } else { + RtlInitUnicodeString(¶mSuffix, NULL); + } + + RtlInitUnicodeString(¶mDevPath, NULL); + // now build the device specific path + paramDevPath.MaximumLength = paramPath.Length + paramSuffix.Length + sizeof(WCHAR); + paramDevPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramDevPath.MaximumLength); + if(!paramDevPath.Buffer) { + try_return(val = DefValue); + } + + RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength); + status = RtlAppendUnicodeToString(¶mDevPath, paramPath.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + if(paramSuffix.Buffer) { + status = RtlAppendUnicodeToString(¶mDevPath, paramSuffix.Buffer); + if(!NT_SUCCESS(status)) { + try_return(val = DefValue); + } + } + + KdPrint(( " Parameter = %ws\n", Name)); + + { + HKEY hk = NULL; + status = RegTGetKeyHandle(NULL, RegistryPath->Buffer, &hk); + if(NT_SUCCESS(status)) { + RegTCloseKeyHandle(hk); + } + } + + + // *** Read GLOBAL_DEFAULTS from + // \DwUdf\Parameters_Unknown\ + + status = RegTGetDwordValue(NULL, paramPath.Buffer, Name, &val); + + // *** Read DEV_CLASS_SPEC_DEFAULTS (if any) from + // \DwUdf\Parameters_%DevClass%\ + + if(DefaultPath) { + status = RegTGetDwordValue(NULL, defaultParamPath.Buffer, Name, &val); + } + + // *** Read DEV_SPEC_PARAMS from (if device supports GetDevName) + // \DwUdf\Parameters\%DevName%\ + + status = RegTGetDwordValue(NULL, paramDevPath.Buffer, Name, &val); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(DefaultPath && defaultParamPath.Buffer) { + MyFreePool__(defaultParamPath.Buffer); + } + if(paramPath.Buffer) { + MyFreePool__(paramPath.Buffer); + } + if(paramDevPath.Buffer) { + MyFreePool__(paramDevPath.Buffer); + } + if(paramPathUnknown.Buffer) { + MyFreePool__(paramPathUnknown.Buffer); + } + } _SEH2_END; + + KdPrint(( "UDFCheckRegValue: %ws for drive %s is %x\n\n", Name, PtrVolumePath, val)); + return val; +} // end UDFRegCheckParameterValue() + +/* +Routine Description: + This routine is called to initialize an IrpContext for the current + UDFFS request. The IrpContext is on the stack and we need to initialize + it for the current request. The request is a close operation. + +Arguments: + + IrpContext - IrpContext to initialize. + + IrpContextLite - source for initialization + +Return Value: + + None + +*/ +VOID +UDFInitializeIrpContextFromLite( + OUT PtrUDFIrpContext *IrpContext, + IN PtrUDFIrpContextLite IrpContextLite + ) +{ + (*IrpContext) = UDFAllocateIrpContext(NULL, IrpContextLite->RealDevice); + // Zero and then initialize the structure. + + // Major/Minor Function codes + (*IrpContext)->MajorFunction = IRP_MJ_CLOSE; + (*IrpContext)->Fcb = IrpContextLite->Fcb; + (*IrpContext)->TreeLength = IrpContextLite->TreeLength; + (*IrpContext)->IrpContextFlags |= (IrpContextLite->IrpContextFlags & ~UDF_IRP_CONTEXT_NOT_FROM_ZONE); + + // Set the wait parameter + UDFSetFlag( (*IrpContext)->IrpContextFlags, UDF_IRP_CONTEXT_CAN_BLOCK ); + + return; +} // end UDFInitializeIrpContextFromLite() + +/* +Routine Description: + This routine is called to initialize an IrpContext for the current + UDFFS request. The IrpContext is on the stack and we need to initialize + it for the current request. The request is a close operation. + +Arguments: + + IrpContext - IrpContext to initialize. + + IrpContextLite - source for initialization + +Return Value: + + None + +*/ +NTSTATUS +UDFInitializeIrpContextLite( + OUT PtrUDFIrpContextLite *IrpContextLite, + IN PtrUDFIrpContext IrpContext, + IN PtrUDFFCB Fcb + ) +{ + PtrUDFIrpContextLite LocalIrpContextLite = (PtrUDFIrpContextLite)MyAllocatePool__(NonPagedPool,sizeof(UDFIrpContextLite)); + if(!LocalIrpContextLite) + return STATUS_INSUFFICIENT_RESOURCES; + // Zero and then initialize the structure. + RtlZeroMemory( LocalIrpContextLite, sizeof( UDFIrpContextLite )); + + LocalIrpContextLite->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT_LITE; + LocalIrpContextLite->NodeIdentifier.NodeSize = sizeof(UDFIrpContextLite); + + LocalIrpContextLite->Fcb = Fcb; + LocalIrpContextLite->TreeLength = IrpContext->TreeLength; + // Copy RealDevice for workque algorithms. + LocalIrpContextLite->RealDevice = IrpContext->TargetDeviceObject; + LocalIrpContextLite->IrpContextFlags = IrpContext->IrpContextFlags; + *IrpContextLite = LocalIrpContextLite; + + return STATUS_SUCCESS; +} // end UDFInitializeIrpContextLite() + +NTSTATUS +NTAPI +UDFQuerySetEA( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; +// PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFQuerySetEA: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + RC = STATUS_EAS_NOT_SUPPORTED; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + + if(AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFQuerySetEA() + +ULONG +UDFIsResourceAcquired( + IN PERESOURCE Resource + ) +{ + ULONG ReAcqRes = + ExIsResourceAcquiredExclusiveLite(Resource) ? 1 : + (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0); + return ReAcqRes; +} // end UDFIsResourceAcquired() + +BOOLEAN +UDFAcquireResourceExclusiveWithCheck( + IN PERESOURCE Resource + ) +{ + ULONG ReAcqRes = + ExIsResourceAcquiredExclusiveLite(Resource) ? 1 : + (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0); + if(ReAcqRes) { + KdPrint(("UDFAcquireResourceExclusiveWithCheck: ReAcqRes, %x\n", ReAcqRes)); + } else { +// BrutePoint(); + } + + if(ReAcqRes == 1) { + // OK + } else + if(ReAcqRes == 2) { + KdPrint(("UDFAcquireResourceExclusiveWithCheck: !!! Shared !!!\n")); + //BrutePoint(); + } else { + UDFAcquireResourceExclusive(Resource, TRUE); + return TRUE; + } + return FALSE; +} // end UDFAcquireResourceExclusiveWithCheck() + +BOOLEAN +UDFAcquireResourceSharedWithCheck( + IN PERESOURCE Resource + ) +{ + ULONG ReAcqRes = + ExIsResourceAcquiredExclusiveLite(Resource) ? 1 : + (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0); + if(ReAcqRes) { + KdPrint(("UDFAcquireResourceSharedWithCheck: ReAcqRes, %x\n", ReAcqRes)); +/* } else { + BrutePoint();*/ + } + + if(ReAcqRes == 2) { + // OK + } else + if(ReAcqRes == 1) { + KdPrint(("UDFAcquireResourceSharedWithCheck: Exclusive\n")); + //BrutePoint(); + } else { + UDFAcquireResourceShared(Resource, TRUE); + return TRUE; + } + return FALSE; +} // end UDFAcquireResourceSharedWithCheck() + +NTSTATUS +UDFWCacheErrorHandler( + IN PVOID Context, + IN PWCACHE_ERROR_CONTEXT ErrorInfo + ) +{ + InterlockedIncrement((PLONG)&(((PVCB)Context)->IoErrorCounter)); + return ErrorInfo->Status; +} + +#include "..\include\misc_common.cpp" +#include "..\include\regtools.cpp" diff --git a/reactos/drivers/filesystems/udfs/namesup.cpp b/reactos/drivers/filesystems/udfs/namesup.cpp new file mode 100644 index 00000000000..9cbf07069a7 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/namesup.cpp @@ -0,0 +1,297 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module: + Namesup.cpp + + Abstract: FileName support routines +*/ + +#include "udffs.h" + +// '\dfdf\aaa\ffg' --> '\aaa\ffg' +// '\aaa\ffg' --> '\ffg' +PWCHAR +__fastcall +UDFDissectName( + IN PWCHAR Buffer, + OUT PUSHORT Length + ) +{ + + USHORT i; + +//#ifdef _X86_ +#ifdef _MSC_VER + + PWCHAR retval; + + __asm push ebx + __asm push ecx + + __asm mov ebx,Buffer + __asm xor ecx,ecx +Remove_leading_slash: + __asm cmp [word ptr ebx],L'\\' + __asm jne No_IncPointer + __asm add ebx,2 + __asm jmp Remove_leading_slash +No_IncPointer: + __asm cmp [word ptr ebx],L':' + __asm jne Scan_1 + __asm add ebx,2 + __asm inc ecx + __asm jmp EO_Dissect +Scan_1: + __asm mov ax,[word ptr ebx] + __asm cmp ax,L'\\' + __asm je EO_Dissect + __asm or ax,ax + __asm jz EO_Dissect + __asm cmp ax,L':' + __asm jne Cont_scan + __asm or ecx,ecx + __asm jnz EO_Dissect +Cont_scan: + __asm inc ecx + __asm add ebx,2 + __asm jmp Scan_1 +EO_Dissect: + __asm mov retval,ebx + __asm mov i,cx + + __asm pop ecx + __asm pop ebx + + *Length = i; + return retval; + +#else // NO X86 optimization , use generic C/C++ + + while (Buffer[0] == L'\\') { + Buffer++; + } + if (Buffer[0] == L':') { + *Length = 1; + return &(Buffer[1]); + } + for(i = 0; ( Buffer[i] != L'\\' && + ((Buffer[i] != L':') || !i) && + Buffer[i]); i++); + *Length = i; + return &(Buffer[i]); + +#endif // _X86_ + +} // end UDFDissectName() + +BOOLEAN +__fastcall +UDFIsNameValid( + IN PUNICODE_STRING SearchPattern, + OUT BOOLEAN* StreamOpen, + OUT ULONG* SNameIndex +) { + LONG Index, l; + BOOLEAN _StreamOpen = FALSE; + PWCHAR Buffer; + WCHAR c, c0; + + if(StreamOpen) (*StreamOpen) = FALSE; + // We can't create nameless file or too long path + if(!(l = SearchPattern->Length/sizeof(WCHAR)) || + (l>UDF_X_PATH_LEN)) return FALSE; + Buffer = SearchPattern->Buffer; + for(Index = 0; Index') || + (c == L'\"') || + (c == L'/') || + (c == L'<') || + (c == L'|') || + ((c >= 0x0000) && (c <= 0x001f)) || + (c == L'?')) return FALSE; + // check if this a Stream path (& validate it) + if(!(_StreamOpen) && // sub-streams are not allowed + (Index<(l-1)) && // stream name must be specified + ((_StreamOpen) = (c == L':'))) { + if(StreamOpen) (*StreamOpen) = TRUE; + if(SNameIndex) (*SNameIndex) = Index; + } + // According to NT IFS documentation neither SPACE nor DOT can be + // a trailing character + if(Index && (c == L'\\') ) { + if((c0 == L' ') || + (_StreamOpen) || // stream is not a directory + (c0 == L'.')) return FALSE; + } + c0 = c; + } + // According to NT IFS documentation neither SPACE nor DOT can be + // a trailing character + if((c0 == L' ') || + (c0 == L'.')) return FALSE; + return TRUE; +} // end UDFIsNameValid() + + +#ifndef _CONSOLE +/* + +Routine Description: + + This routine will compare two Unicode strings. + PtrSearchPattern may contain wildcards + +Return Value: + + BOOLEAN - TRUE if the expressions match, FALSE otherwise. + +*/ +BOOLEAN +UDFIsNameInExpression( + IN PVCB Vcb, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING PtrSearchPattern, + OUT PBOOLEAN DosOpen, + IN BOOLEAN IgnoreCase, + IN BOOLEAN ContainsWC, + IN BOOLEAN CanBe8dot3, + IN BOOLEAN KeepIntact // passed to UDFDOSName + ) +{ + BOOLEAN Match = TRUE; + UNICODE_STRING ShortName; + WCHAR Buffer[13]; + + if(!PtrSearchPattern) return TRUE; + // we try to open file by LFN by default + if(DosOpen) (*DosOpen) = FALSE; + // If there are wildcards in the expression then we call the + // appropriate FsRtlRoutine. + if(ContainsWC) { + Match = FsRtlIsNameInExpression( PtrSearchPattern, FileName, IgnoreCase, NULL ); + // Otherwise do a direct memory comparison for the name string. + } else if (RtlCompareUnicodeString(FileName, PtrSearchPattern, IgnoreCase)) { + Match = FALSE; + } + + if(Match) return TRUE; + + // check if SFN can match this pattern + if(!CanBe8dot3) + return FALSE; + + // try to open by SFN + ShortName.Buffer = (PWCHAR)(&Buffer); + ShortName.MaximumLength = 13*sizeof(WCHAR); + UDFDOSName(Vcb, &ShortName, FileName, KeepIntact); + + // PtrSearchPattern is upcased if we are called with IgnoreCase=TRUE + // DOSName is always upcased + // thus, we can use case-sensetive compare here to improve performance + if(ContainsWC) { + Match = FsRtlIsNameInExpression( PtrSearchPattern, &ShortName, FALSE, NULL ); + // Otherwise do a direct memory comparison for the name string. + } else if (!RtlCompareUnicodeString(&ShortName, PtrSearchPattern, FALSE)) { + Match = TRUE; + } + if(DosOpen && Match) { + // remember that we've opened file by SFN + (*DosOpen) = TRUE; + } + return Match; +} // end UDFIsNameInExpression() + +#endif + +BOOLEAN +__fastcall +UDFIsMatchAllMask( + IN PUNICODE_STRING Name, + OUT BOOLEAN* DosOpen + ) +{ + USHORT i; + PWCHAR Buffer; + + if(DosOpen) + *DosOpen = FALSE; + Buffer = Name->Buffer; + if(Name->Length == sizeof(WCHAR)) { + // Win32-style wildcard + if((*Buffer) != L'*') + return FALSE; + return TRUE; + } else + if(Name->Length == sizeof(WCHAR)*(8+1+3)) { + // DOS-style wildcard + for(i=0;i<8;i++,Buffer++) { + if((*Buffer) != DOS_QM) + return FALSE; + } + if((*Buffer) != DOS_DOT) + return FALSE; + Buffer++; + for(i=9;i<12;i++,Buffer++) { + if((*Buffer) != DOS_QM) + return FALSE; + } + if(*DosOpen) + *DosOpen = TRUE; + return TRUE; + } else + if(Name->Length == sizeof(WCHAR)*(3)) { + // DOS-style wildcard + if(Buffer[0] != DOS_STAR) + return FALSE; + if(Buffer[1] != DOS_DOT) + return FALSE; + if(Buffer[2] != DOS_STAR) + return FALSE; + if(*DosOpen) + *DosOpen = TRUE; + return TRUE; + } else { + return FALSE; + } +} // end UDFIsMatchAllMask() + +BOOLEAN +__fastcall +UDFCanNameBeA8dot3( + IN PUNICODE_STRING Name + ) +{ + if(Name->Length >= 13 * sizeof(WCHAR)) + return FALSE; + + ULONG i,l; + ULONG dot_pos=0; + ULONG ext_len=0; + PWCHAR buff = Name->Buffer; + + l = Name->Length / sizeof(WCHAR); + + for(i=0; i 3) + return FALSE; + } else + if(i >= 8) { + return FALSE; + } + } + return TRUE; +} // end UDFCanNameBeA8dot3() diff --git a/reactos/drivers/filesystems/udfs/namesup.h b/reactos/drivers/filesystems/udfs/namesup.h new file mode 100644 index 00000000000..ec12c782f73 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/namesup.h @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDF_NAME_SUP__H__ +#define __UDF_NAME_SUP__H__ + +extern PWCHAR __fastcall UDFDissectName(IN PWCHAR Buffer, + OUT PUSHORT Length); + +extern BOOLEAN UDFIsNameInExpression(IN PVCB Vcb, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING PtrSearchPattern, + OUT PBOOLEAN DosOpen, + IN BOOLEAN IgnoreCase, + IN BOOLEAN ContainsWC, + IN BOOLEAN CanBe8dot3, + IN BOOLEAN KeepIntact); + +extern BOOLEAN UDFDoesNameContainWildCards(IN PUNICODE_STRING SearchPattern); + +extern BOOLEAN __fastcall UDFIsNameValid(IN PUNICODE_STRING SearchPattern, + OUT BOOLEAN* StreamOpen, + OUT ULONG* SNameIndex); + +extern BOOLEAN __fastcall UDFIsMatchAllMask(IN PUNICODE_STRING Name, + OUT BOOLEAN* DosOpen); + +extern BOOLEAN __fastcall UDFCanNameBeA8dot3(IN PUNICODE_STRING Name); + +#endif //__UDF_NAME_SUP__H__ \ No newline at end of file diff --git a/reactos/drivers/filesystems/udfs/ntifs_ex.h b/reactos/drivers/filesystems/udfs/ntifs_ex.h new file mode 100644 index 00000000000..8ad07e6381e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/ntifs_ex.h @@ -0,0 +1,459 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __NTIFS_EX_H__ +#define __NTIFS_EX_H__ + +#ifndef WIN64 + +// _MM_PAGE_PRIORITY_ provides a method for the system to handle requests +// intelligently in low resource conditions. +// +// LowPagePriority should be used when it is acceptable to the driver for the +// mapping request to fail if the system is low on resources. An example of +// this could be for a non-critical network connection where the driver can +// handle the failure case when system resources are close to being depleted. +// +// NormalPagePriority should be used when it is acceptable to the driver for the +// mapping request to fail if the system is very low on resources. An example +// of this could be for a non-critical local filesystem request. +// +// HighPagePriority should be used when it is unacceptable to the driver for the +// mapping request to fail unless the system is completely out of resources. +// An example of this would be the paging file path in a driver. +// + +#if 0 +typedef enum _MM_PAGE_PRIORITY { + LowPagePriority, + NormalPagePriority = 16, + HighPagePriority = 32 +} MM_PAGE_PRIORITY; +#endif + +#endif //WIN64 + +// +// Note: This function is not available in WDM 1.0 +// +#if 0 +NTKERNELAPI +PVOID +MmMapLockedPagesSpecifyCache ( + IN PMDL MemoryDescriptorList, + IN KPROCESSOR_MODE AccessMode, + IN MEMORY_CACHING_TYPE CacheType, + IN PVOID BaseAddress, + IN ULONG BugCheckOnFailure, + IN MM_PAGE_PRIORITY Priority + ); +#endif + +// PVOID +// MmGetSystemAddressForMdlSafe ( +// IN PMDL MDL, +// IN MM_PAGE_PRIORITY PRIORITY +// ) +// +// Routine Description: +// +// This routine returns the mapped address of an MDL. If the +// Mdl is not already mapped or a system address, it is mapped. +// +// Arguments: +// +// MemoryDescriptorList - Pointer to the MDL to map. +// +// Priority - Supplies an indication as to how important it is that this +// request succeed under low available PTE conditions. +// +// Return Value: +// +// Returns the base address where the pages are mapped. The base address +// has the same offset as the virtual address in the MDL. +// +// Unlike MmGetSystemAddressForMdl, Safe guarantees that it will always +// return NULL on failure instead of bugchecking the system. +// +// This macro is not usable by WDM 1.0 drivers as 1.0 did not include +// MmMapLockedPagesSpecifyCache. The solution for WDM 1.0 drivers is to +// provide synchronization and set/reset the MDL_MAPPING_CAN_FAIL bit. +// +//-- + +#if 0 +#define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) \ + (((MDL)->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \ + MDL_SOURCE_IS_NONPAGED_POOL)) ? \ + ((MDL)->MappedSystemVa) : \ + (MmMapLockedPagesSpecifyCache((MDL), \ + KernelMode, \ + MmCached, \ + NULL, \ + FALSE, \ + (PRIORITY)))) +#endif + + +__inline PVOID MmGetSystemAddressForMdlSafer(IN PMDL Mdl) +{ + PVOID Addr; + + if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL)) { + Addr = Mdl->MappedSystemVa; + } else { + CSHORT PrevFlag = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL; + + Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL; + Addr = MmMapLockedPages(Mdl, KernelMode); + Mdl->MdlFlags = (Mdl->MdlFlags & ~MDL_MAPPING_CAN_FAIL) | PrevFlag; + } + + return(Addr); +} + +#define FULL_SECURITY_INFORMATION (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION) + +#ifndef WIN64 +#if 0 +NTSYSAPI +ULONG +NTAPI +RtlLengthRequiredSid ( + IN UCHAR SubAuthorityCount +); +#endif + +#endif //WIN64 + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetGroupSecurityDescriptor ( + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN PSID Group, + IN BOOLEAN GroupDefaulted +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSaclSecurityDescriptor ( + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN BOOLEAN SaclPresent, + IN PACL Sacl, + IN BOOLEAN SaclDefaulted +); + +NTSYSAPI +PUCHAR +NTAPI +RtlSubAuthorityCountSid ( + IN PSID Sid +); + +#if 0 +NTKERNELAPI +HANDLE +PsReferencePrimaryToken ( + IN PEPROCESS Process +); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlAbsoluteToSelfRelativeSD ( + IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + IN PULONG BufferLength +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateAndInitializeSid ( + IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + IN UCHAR SubAuthorityCount, + IN ULONG SubAuthority0, + IN ULONG SubAuthority1, + IN ULONG SubAuthority2, + IN ULONG SubAuthority3, + IN ULONG SubAuthority4, + IN ULONG SubAuthority5, + IN ULONG SubAuthority6, + IN ULONG SubAuthority7, + OUT PSID *Sid +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlConvertSidToUnicodeString ( + OUT PUNICODE_STRING DestinationString, + IN PVOID Sid, + IN BOOLEAN AllocateDestinationString +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetGroupSecurityDescriptor ( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT PSID *Group, + OUT PBOOLEAN GroupDefaulted +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetOwnerSecurityDescriptor ( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT PSID *Owner, + OUT PBOOLEAN OwnerDefaulted +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeSid ( + IN OUT PSID Sid, + IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + IN UCHAR SubAuthorityCount +); + +#ifndef WIN64 + +#if 0 + +typedef struct _TOKEN_OWNER { // to + PSID Owner; +} TOKEN_OWNER; + +typedef struct _TOKEN_PRIMARY_GROUP { // tpg + PSID PrimaryGroup; +} TOKEN_PRIMARY_GROUP; + +#endif + +#endif //WIN64 + +// 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)) + +// +#ifndef FSCTL_GET_COMPRESSION + +#define FSCTL_GET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +#define FSCTL_GET_NTFS_VOLUME_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_GET_NTFS_FILE_RECORD CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSCTL_GET_HFS_INFORMATION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif //FSCTL_GET_COMPRESSION + + +#if (_WIN32_WINNT >= 0x0500) +#if 0 +#define FSCTL_READ_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_WRITE_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_FIND_FILES_BY_SID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define FSCTL_DUMP_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_SET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_GET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_ENUM_USN_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_SECURITY_ID_CHECK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_READ_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_SET_OBJECT_ID_EXTENDED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_CREATE_OR_GET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_QUERY_ALLOCATED_RANGES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_ENABLE_UPGRADE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_ENCRYPTION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_ENCRYPTION_FSCTL_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_WRITE_RAW_ENCRYPTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_READ_RAW_ENCRYPTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_CREATE_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_READ_FILE_USN_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_WRITE_USN_CLOSE_RECORD CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_EXTEND_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 61, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 62, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_MARK_HANDLE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 63, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SIS_COPYFILE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 64, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SIS_LINK_FILES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 65, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_HSM_MSG CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 66, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +#define FSCTL_HSM_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 68, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_RECALL_FILE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 69, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define FSCTL_READ_FROM_PLEX CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 71, METHOD_OUT_DIRECT, FILE_READ_DATA) +#define FSCTL_FILE_PREFETCH CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 72, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +#endif +#endif // (_WIN32_WINNT >= 0x0500) + +// file system flags +#ifndef FILE_VOLUME_QUOTAS + +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FS_LFN_APIS 0x00004000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 + +#endif //FILE_VOLUME_QUOTAS + +// Output flags for the FSCTL_IS_VOLUME_DIRTY +#define VOLUME_IS_DIRTY (0x00000001) +#define VOLUME_UPGRADE_SCHEDULED (0x00000002) + +NTSYSAPI +NTSTATUS +NTAPI +ZwFsControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +ZwDeviceIoControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass + ); + + +#ifndef FILE_ATTRIBUTE_SPARSE_FILE + +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 + +#endif //FILE_ATTRIBUTE_SPARSE_FILE + +#define FileFsFullSizeInformation (FS_INFORMATION_CLASS(7)) +#define FileFsObjectIdInformation (FS_INFORMATION_CLASS(8)) +#define FileFsDriverPathInformation (FS_INFORMATION_CLASS(9)) + +#ifndef WIN64 + +#if 0 +typedef struct _FILE_FS_FULL_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; +#endif + +#endif //WIN64 + +#ifndef IRP_MN_SURPRISE_REMOVAL +#define IRP_MN_SURPRISE_REMOVAL 0x17 +#endif //IRP_MN_SURPRISE_REMOVAL + +#ifndef IoCopyCurrentIrpStackLocationToNext + +#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \ + PIO_STACK_LOCATION irpSp; \ + PIO_STACK_LOCATION nextIrpSp; \ + irpSp = IoGetCurrentIrpStackLocation( (Irp) ); \ + nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); \ + RtlCopyMemory( nextIrpSp, irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \ + nextIrpSp->Control = 0; } + +#define IoSkipCurrentIrpStackLocation( Irp ) \ + (Irp)->CurrentLocation++; \ + (Irp)->Tail.Overlay.CurrentStackLocation++; + +#endif //IoCopyCurrentIrpStackLocationToNext + +#ifndef VPB_REMOVE_PENDING +#define VPB_REMOVE_PENDING 0x00000008 +#endif //VPB_REMOVE_PENDING + + +// +// Volume lock/unlock notification routines, implemented in PnP.c +// +// These routines provide PnP volume lock notification support +// for all filesystems. +// + +#define FSRTL_VOLUME_DISMOUNT 1 +#define FSRTL_VOLUME_DISMOUNT_FAILED 2 +#define FSRTL_VOLUME_LOCK 3 +#define FSRTL_VOLUME_LOCK_FAILED 4 +#define FSRTL_VOLUME_UNLOCK 5 +#define FSRTL_VOLUME_MOUNT 6 + +/*NTKERNELAPI +NTSTATUS +FsRtlNotifyVolumeEvent ( + IN PFILE_OBJECT FileObject, + IN ULONG EventCode + );*/ + +typedef NTSTATUS (*ptrFsRtlNotifyVolumeEvent) ( + IN PFILE_OBJECT FileObject, + IN ULONG EventCode + ); + +#include "..\Include\ntddk_ex.h" + +#endif //__NTIFS_EX_H__ diff --git a/reactos/drivers/filesystems/udfs/pnp.cpp b/reactos/drivers/filesystems/udfs/pnp.cpp new file mode 100644 index 00000000000..6c8cddc59d3 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/pnp.cpp @@ -0,0 +1,740 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Pnp.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* This module implements the Plug and Play routines for UDF called by +* the dispatch driver. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_PNP + + +NTSTATUS +UDFPnpQueryRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ); + +NTSTATUS +UDFPnpRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ); + +NTSTATUS +UDFPnpSurpriseRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ); + +NTSTATUS +UDFPnpCancelRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ); + +NTSTATUS +NTAPI +UDFPnpCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +NTSTATUS +UDFCommonPnp ( + PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp + ); + +/* + This routine implements the FSD part of PnP operations + +Arguments: + + VolumeDeviceObject - Supplies the volume device object where the + file exists + Irp - Supplies the Irp being processed + +Return Value: + + NTSTATUS - The FSD status for the IRP + + */ +NTSTATUS +UDFPnp ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + NTSTATUS RC; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel; + + KdPrint(("UDFPnp\n")); + ASSERT(FALSE); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + + _SEH2_TRY { + // We expect there to never be a fileobject, in which case we will always + // wait. Since at the moment we don't have any concept of pending Pnp + // operations, this is a bit nitpicky. + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonPnp(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter( PtrIrpContext, _SEH2_GetExceptionInformation() )) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return RC; +} + +/* + This is the common routine for doing PnP operations called + by both the fsd and fsp threads + +Arguments: + + Irp - Supplies the Irp to process + +Return Value: + + NTSTATUS - The return status for the operation + */ +NTSTATUS +UDFCommonPnp ( + PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp + ) +{ + NTSTATUS RC; + PIO_STACK_LOCATION IrpSp; + PVCB Vcb; + KdPrint(("UDFCommonPnp\n")); + + _SEH2_TRY { + // Get the current Irp stack location. + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + // Make sure this device object really is big enough to be a volume device + // object. If it isn't, we need to get out before we try to reference some + // field that takes us past the end of an ordinary device object. + Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); + + if (Vcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) { + // We were called with something we don't understand. + if(Irp->Flags & IRP_INPUT_OPERATION) { + Irp->IoStatus.Information = 0; + } + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + + IoCompleteRequest( Irp, IO_DISK_INCREMENT ); + try_return (RC = STATUS_INVALID_PARAMETER); + } + + // Force everything to wait. + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; + + // Case on the minor code. + switch ( IrpSp->MinorFunction ) { + + case IRP_MN_QUERY_REMOVE_DEVICE: + RC = UDFPnpQueryRemove( PtrIrpContext, Irp, Vcb ); + break; + + case IRP_MN_SURPRISE_REMOVAL: + RC = UDFPnpSurpriseRemove( PtrIrpContext, Irp, Vcb ); + break; + + case IRP_MN_REMOVE_DEVICE: + RC = UDFPnpRemove( PtrIrpContext, Irp, Vcb ); + break; + +/* case IRP_MN_CANCEL_REMOVE_DEVICE: + RC = UDFPnpCancelRemove( PtrIrpContext, Irp, Vcb ); + break;*/ + + default: + KdPrint(("UDFCommonPnp: pass through\n")); + // Just pass the IRP on. As we do not need to be in the + // way on return, ellide ourselves out of the stack. + IoSkipCurrentIrpStackLocation( Irp ); + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + ASSERT(RC != STATUS_PENDING); + + break; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + UDFReleaseIrpContext(PtrIrpContext); + } _SEH2_END; + + return RC; +} + + +/* +Routine Description: + This routine handles the PnP query remove operation. The filesystem + is responsible for answering whether there are any reasons it sees + that the volume can not go away (and the device removed). Initiation + of the dismount begins when we answer yes to this question. + + Query will be followed by a Cancel or Remove. + +Arguments: + Irp - Supplies the Irp to process + Vcb - Supplies the volume being queried. + +Return Value: + NTSTATUS - The return status for the operation + */ +NTSTATUS +UDFPnpQueryRemove( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ) +{ + NTSTATUS RC; + KEVENT Event; + BOOLEAN VcbDeleted = FALSE; + BOOLEAN GlobalHeld = FALSE; + BOOLEAN VcbAcquired = FALSE; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + + // Having said yes to a QUERY, any communication with the + // underlying storage stack is undefined (and may block) + // until the bounding CANCEL or REMOVE is sent. + + _SEH2_TRY { + + // Acquire the global resource so that we can try to vaporize + // the volume, and the vcb resource itself. + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + GlobalHeld = TRUE; + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + VcbAcquired = TRUE; + + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + // With the volume held locked, note that we must finalize as much + // as possible right now. + UDFDoDismountSequence(Vcb, Buf, FALSE); + + // disable Eject Request Waiter if any + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + UDFStopEjectWaiter(Vcb); + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + VcbAcquired = TRUE; + + // We need to pass this down before starting the dismount, which + // could disconnect us immediately from the stack. + + // Get the next stack location, and copy over the stack location + IoCopyCurrentIrpStackLocationToNext( Irp ); + + // Set up the completion routine + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + IoSetCompletionRoutine( Irp, + UDFPnpCompletionRoutine, + &Event, + TRUE, + TRUE, + TRUE ); + // Send the request and wait. + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + + if (RC == STATUS_PENDING) { + KeWaitForSingleObject( &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + RC = Irp->IoStatus.Status; + } + + // Now if no one below us failed already, initiate the dismount + // on this volume, make it go away. PnP needs to see our internal + // streams close and drop their references to the target device. + + // Since we were able to lock the volume, we are guaranteed to + // move this volume into dismount state and disconnect it from + // the underlying storage stack. The force on our part is actually + // unnecesary, though complete. + + // What is not strictly guaranteed, though, is that the closes + // for the metadata streams take effect synchronously underneath + // of this call. This would leave references on the target device + // even though we are disconnected! + if (NT_SUCCESS( RC )) { + VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, TRUE ); + ASSERT( VcbDeleted ); + } + + // Release the Vcb if it could still remain. + + // Note: if everything else succeeded and the Vcb is persistent because the + // internal streams did not vaporize, we really need to pend this IRP off on + // the side until the dismount is completed. I can't think of a reasonable + // case (in UDF) where this would actually happen, though it might still need + // to be implemented. + // + // The reason this is the case is that handles/fileobjects place a reference + // on the device objects they overly. In the filesystem case, these references + // are on our target devices. PnP correcly thinks that if references remain + // on the device objects in the stack that someone has a handle, and that this + // counts as a reason to not succeed the query - even though every interrogated + // driver thinks that it is OK. + ASSERT( !(NT_SUCCESS( RC ) && !VcbDeleted )); + + } _SEH2_FINALLY { + + if (!VcbDeleted && VcbAcquired) { + UDFReleaseResource( &(Vcb->VCBResource) ); + } + + if (GlobalHeld) { + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + } + + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } _SEH2_END; + + return RC; +} // end UDFPnpQueryRemove() + + +/* +Routine Description: + This routine handles the PnP remove operation. This is our notification + that the underlying storage device for the volume we have is gone, and + an excellent indication that the volume will never reappear. The filesystem + is responsible for initiation or completion of the dismount. + +Arguments: + Irp - Supplies the Irp to process + Vcb - Supplies the volume being removed. + +Return Value: + NTSTATUS - The return status for the operation + +--*/ +NTSTATUS +UDFPnpRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ) +{ + NTSTATUS RC; + KEVENT Event; + BOOLEAN VcbDeleted; + BOOLEAN VcbAcquired; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + + // REMOVE - a storage device is now gone. We either got + // QUERY'd and said yes OR got a SURPRISE OR a storage + // stack failed to spin back up from a sleep/stop state + // (the only case in which this will be the first warning). + // + // Note that it is entirely unlikely that we will be around + // for a REMOVE in the first two cases, as we try to intiate + // dismount. + + // Acquire the global resource so that we can try to vaporize + // the volume, and the vcb resource itself. + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + VcbAcquired = TRUE; + + // The device will be going away. Remove our lock (benign + // if we never had it). + if((Vcb->Vpb->Flags & VPB_LOCKED) || + (Vcb->VolumeLockPID != -1) ) { + Vcb->Vpb->Flags &= ~VPB_LOCKED; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = NULL; + Vcb->VolumeLockPID = -1; + RC = STATUS_SUCCESS; + } + + // We need to pass this down before starting the dismount, which + // could disconnect us immediately from the stack. + + // Get the next stack location, and copy over the stack location + IoCopyCurrentIrpStackLocationToNext( Irp ); + + // Set up the completion routine + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + IoSetCompletionRoutine( Irp, + UDFPnpCompletionRoutine, + &Event, + TRUE, + TRUE, + TRUE ); + + // Send the request and wait. + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + + if (RC == STATUS_PENDING) { + + KeWaitForSingleObject( &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + RC = Irp->IoStatus.Status; + } + + _SEH2_TRY { + + // Knock as many files down for this volume as we can. + + // Now make our dismount happen. This may not vaporize the + // Vcb, of course, since there could be any number of handles + // outstanding if we were not preceeded by a QUERY. + // + // PnP will take care of disconnecting this stack if we + // couldn't get off of it immediately. + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + UDFDoDismountSequence(Vcb, Buf, FALSE); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + // disable Eject Request Waiter if any + UDFReleaseResource( &(Vcb->VCBResource) ); + VcbAcquired = FALSE; + + UDFStopEjectWaiter(Vcb); + + VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE ); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + // Release the Vcb if it could still remain. + if (!VcbDeleted && VcbAcquired) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + + if(Buf) + MyFreePool__(Buf); + + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } _SEH2_END; + + return RC; +} + + +NTSTATUS +UDFPnpSurpriseRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ) + +/*++ + +Routine Description: + + This routine handles the PnP surprise remove operation. This is another + type of notification that the underlying storage device for the volume we + have is gone, and is excellent indication that the volume will never reappear. + The filesystem is responsible for initiation or completion the dismount. + + For the most part, only "real" drivers care about the distinction of a + surprise remove, which is a result of our noticing that a user (usually) + physically reached into the machine and pulled something out. + + Surprise will be followed by a Remove when all references have been shut down. + +Arguments: + + Irp - Supplies the Irp to process + + Vcb - Supplies the volume being removed. + +Return Value: + + NTSTATUS - The return status for the operation + +--*/ + +{ + NTSTATUS RC; + KEVENT Event; + BOOLEAN VcbDeleted; + BOOLEAN VcbAcquired; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + + // SURPRISE - a device was physically yanked away without + // any warning. This means external forces. + + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + VcbAcquired = TRUE; + + // We need to pass this down before starting the dismount, which + // could disconnect us immediately from the stack. + + // Get the next stack location, and copy over the stack location + IoCopyCurrentIrpStackLocationToNext( Irp ); + + // Set up the completion routine + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + IoSetCompletionRoutine( Irp, + UDFPnpCompletionRoutine, + &Event, + TRUE, + TRUE, + TRUE ); + + // Send the request and wait. + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + + if (RC == STATUS_PENDING) { + + KeWaitForSingleObject( &Event, + Executive, + KernelMode, + FALSE, + NULL ); + + RC = Irp->IoStatus.Status; + } + + _SEH2_TRY { + // Knock as many files down for this volume as we can. + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + UDFDoDismountSequence(Vcb, Buf, FALSE); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + + UDFReleaseResource(&(Vcb->VCBResource)); + VcbAcquired = FALSE; + + UDFStopEjectWaiter(Vcb); + + // Now make our dismount happen. This may not vaporize the + // Vcb, of course, since there could be any number of handles + // outstanding since this is an out of band notification. + VcbDeleted = !UDFCheckForDismount( PtrIrpContext, Vcb, FALSE ); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + // Release the Vcb if it could still remain. + if (!VcbDeleted && VcbAcquired) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + + if(Buf) + MyFreePool__(Buf); + + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } _SEH2_END; + + return RC; +} + +/* +NTSTATUS +UDFPnpCancelRemove ( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVCB Vcb + ) + +/*++ + +Routine Description: + + This routine handles the PnP cancel remove operation. This is our + notification that a previously proposed remove (query) was eventually + vetoed by a component. The filesystem is responsible for cleaning up + and getting ready for more IO. + +Arguments: + + Irp - Supplies the Irp to process + + Vcb - Supplies the volume being removed. + +Return Value: + + NTSTATUS - The return status for the operation + +--*/ + +/*{ + NTSTATUS RC; + + // CANCEL - a previous QUERY has been rescinded as a result + // of someone vetoing. Since PnP cannot figure out who may + // have gotten the QUERY (think about it: stacked drivers), + // we must expect to deal with getting a CANCEL without having + // seen the QUERY. + // + // For UDF, this is quite easy. In fact, we can't get a + // CANCEL if the underlying drivers succeeded the QUERY since + // we disconnect the Vpb on our dismount initiation. This is + // actually pretty important because if PnP could get to us + // after the disconnect we'd be thoroughly unsynchronized + // with respect to the Vcb getting torn apart - merely referencing + // the volume device object is insufficient to keep us intact. + + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + + // Unlock the volume. This is benign if we never had seen + // a QUERY. + if(Vcb->Vpb->Flags & VPB_LOCKED) { + Vcb->Vpb->Flags &= ~VPB_LOCKED; + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; + Vcb->VolumeLockFileObject = NULL; + RC = STATUS_SUCCESS; + } else { + RC = STATUS_NOT_LOCKED; + } + + try { + + // We must re-enable allocation support if we got through + // the first stages of a QUERY_REMOVE; i.e., we decided we + // could place a lock on the volume. + if (NT_SUCCESS( RC )) { + FatSetupAllocationSupport( PtrIrpContext, Vcb ); + } + + } finally { + UDFReleaseResource(&(Vcb->VCBResource)); + } + + // Send the request. The underlying driver will complete the + // IRP. Since we don't need to be in the way, simply ellide + // ourselves out of the IRP stack. + IoSkipCurrentIrpStackLocation( Irp ); + + RC = IoCallDriver(Vcb->TargetDeviceObject, Irp); + +// if (!AbnormalTermination()) { + Irp->IoStatus.Status = RC; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); +// } + + return RC; +} */ + + +// Local support routine +NTSTATUS +NTAPI +UDFPnpCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + PKEVENT Event = (PKEVENT) Contxt; + + KeSetEvent( Event, 0, FALSE ); + + return STATUS_MORE_PROCESSING_REQUIRED; + + UNREFERENCED_PARAMETER( DeviceObject ); + UNREFERENCED_PARAMETER( Contxt ); +} + + diff --git a/reactos/drivers/filesystems/udfs/protos.h b/reactos/drivers/filesystems/udfs/protos.h new file mode 100644 index 00000000000..97c68762e0e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/protos.h @@ -0,0 +1,1153 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: protos.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains the prototypes for functions in UDF FSD. +* +*************************************************************************/ + +#ifndef _UDF_PROTOS_H_ +#define _UDF_PROTOS_H_ + +#include "mem.h" + +/************************************************************************* +* Prototypes for the file create.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFCreate( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonCreate( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFFirstOpenFile( + IN PVCB Vcb, // volume control block + IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object + OUT PtrUDFFCB* PtrNewFcb, + IN PUDF_FILE_INFO RelatedFileInfo, + IN PUDF_FILE_INFO NewFileInfo, + IN PUNICODE_STRING LocalPath, + IN PUNICODE_STRING CurName); + +extern NTSTATUS UDFOpenFile( + IN PVCB Vcb, // volume control block + IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object + IN PtrUDFFCB PtrNewFcb); + +extern NTSTATUS UDFInitializeFCB( + IN PtrUDFFCB PtrNewFcb, // FCB structure to be initialized + IN PVCB Vcb, // logical volume (VCB) pointer + IN PtrUDFObjectName PtrObjectName, // name of the object + IN ULONG Flags, // is this a file/directory, etc. + IN PFILE_OBJECT FileObject); // optional file object to be initialized + +/************************************************************************* +* Prototypes for the file cleanup.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFCleanup( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonCleanup( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS UDFCloseFileInfoChain(IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN ULONG TreeLength, + IN BOOLEAN VcbAcquired); +/************************************************************************* +* Prototypes for the file close.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFClose( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonClose( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +#define UDF_CLOSE_NTREQFCB_DELETED 0x01 +#define UDF_CLOSE_FCB_DELETED 0x02 + +extern ULONG UDFCleanUpFcbChain(IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN ULONG TreeLength, + IN BOOLEAN VcbAcquired); + +extern VOID UDFCloseAllDelayed(PVCB Vcb); + +extern VOID UDFDelayedClose(PVOID unused = NULL); + +extern NTSTATUS UDFCloseAllXXXDelayedInDir(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN System); + +#define UDFCloseAllDelayedInDir(Vcb,FI) \ + UDFCloseAllXXXDelayedInDir(Vcb,FI,FALSE); + +#define UDFCloseAllSystemDelayedInDir(Vcb,FI) \ + UDFCloseAllXXXDelayedInDir(Vcb,FI,TRUE); + +extern NTSTATUS UDFQueueDelayedClose(PtrUDFIrpContext IrpContext, + PtrUDFFCB Fcb); + +//extern VOID UDFRemoveFromDelayedQueue(PtrUDFFCB Fcb); +#define UDFRemoveFromDelayedQueue(Fcb) \ + UDFCloseAllDelayedInDir((Fcb)->Vcb, (Fcb)->FileInfo) + +#define UDFRemoveFromSystemDelayedQueue(Fcb) \ + UDFCloseAllSystemDelayedInDir((Fcb)->Vcb, (Fcb)->FileInfo) + +/************************************************************************* +* Prototypes for the file dircntrl.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFDirControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS NTAPI UDFCommonDirControl( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS NTAPI UDFQueryDirectory( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp, +PIO_STACK_LOCATION IrpSp, +PFILE_OBJECT FileObject, +PtrUDFFCB Fcb, +PtrUDFCCB Ccb); + +extern NTSTATUS NTAPI UDFNotifyChangeDirectory( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp, +PIO_STACK_LOCATION IrpSp, +PFILE_OBJECT FileObject, +PtrUDFFCB Fcb, +PtrUDFCCB Ccb); + +/************************************************************************* +* Prototypes for the file devcntrl.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFDeviceControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS NTAPI UDFCommonDeviceControl( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS NTAPI UDFDevIoctlCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP Irp, +PVOID Context); + +extern NTSTATUS NTAPI UDFHandleQueryPath( +PVOID BufferPointer); + +/************************************************************************* +* Prototypes for the file fastio.cpp +*************************************************************************/ +extern BOOLEAN NTAPI 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); + +extern FAST_IO_POSSIBLE NTAPI UDFIsFastIoPossible( +IN PtrUDFFCB Fcb); + +extern BOOLEAN NTAPI UDFFastIoQueryBasicInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_BASIC_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastIoQueryStdInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_STANDARD_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern VOID NTAPI UDFFastIoAcqCreateSec( +IN PFILE_OBJECT FileObject); + +extern VOID NTAPI UDFFastIoRelCreateSec( +IN PFILE_OBJECT FileObject); + +extern BOOLEAN NTAPI UDFAcqLazyWrite( +IN PVOID Context, +IN BOOLEAN Wait); + +extern VOID NTAPI UDFRelLazyWrite( +IN PVOID Context); + +extern BOOLEAN NTAPI UDFAcqReadAhead( +IN PVOID Context, +IN BOOLEAN Wait); + +extern VOID NTAPI UDFRelReadAhead( +IN PVOID Context); + +VOID NTAPI UDFDriverUnload( + IN PDRIVER_OBJECT DriverObject); + +// the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + +extern BOOLEAN NTAPI UDFFastIoQueryNetInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT struct _FILE_NETWORK_OPEN_INFORMATION* Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL* MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN UDFFastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastIoPrepareMdlWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL* MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS NTAPI UDFFastIoAcqModWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER EndingOffset, +OUT PERESOURCE* ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS NTAPI UDFFastIoRelModWrite( +IN PFILE_OBJECT FileObject, +IN PERESOURCE ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS NTAPI UDFFastIoAcqCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS NTAPI UDFFastIoRelCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastIoDeviceControl ( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +IN PVOID InputBuffer OPTIONAL, +IN ULONG InputBufferLength, +OUT PVOID OutputBuffer OPTIONAL, +IN ULONG OutputBufferLength, +IN ULONG IoControlCode, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN +NTAPI +UDFFastIoCopyWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ); + +#endif // (_WIN32_WINNT >= 0x0400) + +/************************************************************************* +* Prototypes for the file fileinfo.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFFileInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonFileInfo( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS UDFGetBasicInformation( + IN PFILE_OBJECT FileObject, + IN PtrUDFFCB Fcb, + IN PFILE_BASIC_INFORMATION PtrBuffer, + IN OUT LONG* PtrReturnedLength); + +extern NTSTATUS UDFGetNetworkInformation( + IN PtrUDFFCB Fcb, + IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetStandardInformation( + IN PtrUDFFCB Fcb, + IN PFILE_STANDARD_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetInternalInformation( + PtrUDFIrpContext PtrIrpContext, + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PFILE_INTERNAL_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetEaInformation( + PtrUDFIrpContext PtrIrpContext, + IN PtrUDFFCB Fcb, + IN PFILE_EA_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetFullNameInformation( + IN PFILE_OBJECT FileObject, + IN PFILE_NAME_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetAltNameInformation( + IN PtrUDFFCB Fcb, + IN PFILE_NAME_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetPositionInformation( + IN PFILE_OBJECT FileObject, + IN PFILE_POSITION_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFGetFileStreamInformation( + IN PtrUDFFCB Fcb, + IN PFILE_STREAM_INFORMATION PtrBuffer, + IN OUT PLONG PtrReturnedLength); + +extern NTSTATUS UDFSetBasicInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PFILE_OBJECT FileObject, + IN PFILE_BASIC_INFORMATION PtrBuffer); + +extern NTSTATUS UDFMarkStreamsForDeletion( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN BOOLEAN ForDel); + +extern NTSTATUS UDFSetDispositionInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN BOOLEAN Delete); + +extern NTSTATUS UDFSetAllocationInformation( + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp, + IN PFILE_ALLOCATION_INFORMATION PtrBuffer); + +extern NTSTATUS UDFSetEOF( + IN PIO_STACK_LOCATION PtrSp, + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, + IN PIRP Irp, + IN PFILE_END_OF_FILE_INFORMATION PtrBuffer); + +extern NTSTATUS UDFRename(IN PIO_STACK_LOCATION IrpSp, + IN PtrUDFFCB Fcb, + IN PtrUDFCCB Ccb, + IN PFILE_OBJECT FileObject, + IN PFILE_RENAME_INFORMATION PtrBuffer); + +extern NTSTATUS UDFStoreFileId( + IN PVCB Vcb, + IN PtrUDFCCB Ccb, + IN PUDF_FILE_INFO fi, + IN LONGLONG Id); + +extern NTSTATUS UDFRemoveFileId( + IN PVCB Vcb, + IN LONGLONG Id); + +#define UDFRemoveFileId__(Vcb, fi) \ + UDFRemoveFileId(Vcb, UDFGetNTFileId(Vcb, fi, &(fi->Fcb->FCBName->ObjectName))); + +extern VOID UDFReleaseFileIdCache( + IN PVCB Vcb); + +extern NTSTATUS UDFGetOpenParamsByFileId( + IN PVCB Vcb, + IN LONGLONG Id, + OUT PUNICODE_STRING* FName, + OUT BOOLEAN* CaseSens); + +extern NTSTATUS UDFHardLink( + IN PIO_STACK_LOCATION PtrSp, + IN PtrUDFFCB Fcb1, + IN PtrUDFCCB Ccb1, + IN PFILE_OBJECT FileObject1, // Source File + IN PFILE_LINK_INFORMATION PtrBuffer); +/************************************************************************* +* Prototypes for the file flush.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFFlush( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonFlush( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern ULONG UDFFlushAFile( +PtrUDFFCB Fcb, +PtrUDFCCB Ccb, +PIO_STATUS_BLOCK PtrIoStatus, +IN ULONG FlushFlags = 0); + +extern ULONG UDFFlushADirectory( +IN PVCB Vcb, +IN PUDF_FILE_INFO FI, +OUT PIO_STATUS_BLOCK PtrIoStatus, +ULONG FlushFlags = 0); + +extern ULONG UDFFlushLogicalVolume( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp, +PVCB Vcb, +ULONG FlushFlags = 0); + +extern NTSTATUS NTAPI UDFFlushCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP Irp, +PVOID Context); + +extern BOOLEAN UDFFlushIsBreaking( +IN PVCB Vcb, +IN ULONG FlushFlags = 0); + +extern VOID UDFFlushTryBreak( +IN PVCB Vcb); + +/************************************************************************* +* Prototypes for the file fscntrl.cpp +*************************************************************************/ + +extern NTSTATUS NTAPI UDFFSControl( +PDEVICE_OBJECT DeviceObject, +PIRP Irp); + +extern NTSTATUS NTAPI UDFCommonFSControl( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); // I/O Request Packet + +extern NTSTATUS NTAPI UDFUserFsCtrlRequest( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS NTAPI UDFMountVolume( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS UDFStartEjectWaiter(IN PVCB Vcb); + +extern VOID UDFScanForDismountedVcb (IN PtrUDFIrpContext IrpContext); + +extern NTSTATUS UDFCompleteMount(IN PVCB Vcb); + +extern VOID UDFCloseResidual(IN PVCB Vcb); + +extern VOID UDFCleanupVCB(IN PVCB Vcb); + +extern NTSTATUS UDFIsVolumeMounted(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFIsVolumeDirty(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFGetStatistics(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFLockVolume (IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG PID = -1); + +extern NTSTATUS UDFUnlockVolume (IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG PID = -1); + +extern NTSTATUS UDFIsPathnameValid(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFDismountVolume(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFGetVolumeBitmap(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +extern NTSTATUS UDFGetRetrievalPointers(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN ULONG Special); + +extern NTSTATUS UDFInvalidateVolumes(IN PtrUDFIrpContext IrpContext, + IN PIRP Irp); + +/************************************************************************* +* Prototypes for the file LockCtrl.cpp +*************************************************************************/ + +extern NTSTATUS NTAPI UDFLockControl( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp); // I/O Request Packet + +extern NTSTATUS NTAPI UDFCommonLockControl( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp); + +extern BOOLEAN NTAPI 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); + +extern BOOLEAN NTAPI 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); + +extern BOOLEAN NTAPI UDFFastUnlockAll( + IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN NTAPI UDFFastUnlockAllByKey( + IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject); + +/************************************************************************* +* Prototypes for the file misc.cpp +*************************************************************************/ +extern NTSTATUS UDFInitializeZones( +VOID); + +extern VOID UDFDestroyZones( +VOID); + +extern BOOLEAN __fastcall UDFIsIrpTopLevel( +PIRP Irp); // the IRP sent to our dispatch routine + +extern long UDFExceptionFilter( +PtrUDFIrpContext PtrIrpContext, +PEXCEPTION_POINTERS PtrExceptionPointers); + +extern NTSTATUS UDFExceptionHandler( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern VOID UDFLogEvent( +NTSTATUS UDFEventLogId, // the UDF private message id +NTSTATUS RC); // any NT error code we wish to log ... + +extern PtrUDFObjectName UDFAllocateObjectName( +VOID); + +extern VOID __fastcall UDFReleaseObjectName( +PtrUDFObjectName PtrObjectName); + +extern PtrUDFCCB UDFAllocateCCB( +VOID); + +extern VOID __fastcall UDFReleaseCCB( +PtrUDFCCB Ccb); + +extern VOID __fastcall UDFCleanUpCCB( +PtrUDFCCB Ccb); + +extern PtrUDFFCB UDFAllocateFCB( +VOID); + +/*extern VOID __fastcall UDFReleaseFCB( +PtrUDFFCB Fcb);*/ +__inline +VOID +UDFReleaseFCB( + PtrUDFFCB Fcb + ) +{ + ASSERT(Fcb); + + MyFreePool__(Fcb); + + return; +} + +extern VOID __fastcall UDFCleanUpFCB( +PtrUDFFCB Fcb) ; + +extern PtrUDFIrpContext UDFAllocateIrpContext( +PIRP Irp, +PDEVICE_OBJECT PtrTargetDeviceObject); + +extern VOID UDFReleaseIrpContext( +PtrUDFIrpContext PtrIrpContext); + +extern NTSTATUS UDFPostRequest( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern VOID UDFCommonDispatch( +VOID *Context); // actually an IRPContext structure + +extern NTSTATUS UDFInitializeVCB( +PDEVICE_OBJECT PtrVolumeDeviceObject, +PDEVICE_OBJECT PtrTargetDeviceObject, +PVPB PtrVPB); + +extern VOID +UDFReadRegKeys( + PVCB Vcb, + BOOLEAN Update, + BOOLEAN UseCfg); + +extern ULONG UDFGetRegParameter( + IN PVCB Vcb, + IN PWSTR Name, + IN ULONG DefValue = 0); + +extern ULONG +UDFGetCfgParameter( + IN PVCB Vcb, + IN PWSTR Name, + IN ULONG DefValue + ); + +extern VOID UDFReleaseVCB( + PVCB Vcb); + +extern ULONG UDFRegCheckParameterValue( + IN PUNICODE_STRING RegistryPath, + IN PWSTR Name, + IN PUNICODE_STRING PtrVolumePath, + IN PWSTR DefaultPath, + IN ULONG DefValue = 0); + +extern VOID UDFInitializeIrpContextFromLite ( + OUT PtrUDFIrpContext *IrpContext, + IN PtrUDFIrpContextLite IrpContextLite); + +extern NTSTATUS UDFInitializeIrpContextLite ( + OUT PtrUDFIrpContextLite *IrpContextLite, + IN PtrUDFIrpContext IrpContext, + IN PtrUDFFCB Fcb); + + +extern NTSTATUS NTAPI UDFQuerySetEA( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ); + +extern ULONG +UDFIsResourceAcquired( + IN PERESOURCE Resource + ); + +extern BOOLEAN UDFAcquireResourceExclusiveWithCheck( + IN PERESOURCE Resource + ); + +extern BOOLEAN UDFAcquireResourceSharedWithCheck( + IN PERESOURCE Resource + ); + +extern NTSTATUS UDFWCacheErrorHandler( + IN PVOID Context, + IN PWCACHE_ERROR_CONTEXT ErrorInfo + ); + +/************************************************************************* +* Prototypes for the file NameSup.cpp +*************************************************************************/ + +#include "NameSup.h" + +/************************************************************************* +* Prototypes for the file Udf_info\physical.cpp +*************************************************************************/ +#if 0 + +extern OSSTATUS UDFTRead(PVOID _Vcb, + PVOID Buffer, // Target buffer + ULONG Length, + ULONG LBA, + PULONG ReadBytes, + ULONG Flags = 0); + +extern OSSTATUS UDFTWrite(IN PVOID _Vcb, + IN PVOID Buffer, // Target buffer + IN ULONG Length, + IN ULONG LBA, + OUT PULONG WrittenBytes, + IN ULONG Flags = 0); + +extern OSSTATUS UDFPrepareForWriteOperation( + IN PVCB Vcb, + IN ULONG Lba, + IN ULONG BCount); + +extern OSSTATUS UDFReadDiscTrackInfo(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume Control Block for ^ DevObj + +extern OSSTATUS UDFReadAndProcessFullToc(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); + +extern OSSTATUS UDFUseStandard(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume control block fro this DevObj + +extern OSSTATUS UDFGetBlockSize(PDEVICE_OBJECT DeviceObject, // the target device object + PVCB Vcb); // Volume control block fro this DevObj + +extern OSSTATUS UDFGetDiskInfo(IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb); // Volume control block from this DevObj + +extern VOID UDFEjectReqWaiter(IN PVOID Context); + +extern VOID UDFStopEjectWaiter(PVCB Vcb); + +//extern OSSTATUS UDFPrepareForReadOperation(IN PVCB Vcb, +// IN ULONG Lba); +//#define UDFPrepareForReadOperation(a,b) (STATUS_SUCCESS) + +extern VOID UDFUpdateNWA(PVCB Vcb, + ULONG LBA, + ULONG BCount, + OSSTATUS RC); + +extern OSSTATUS UDFDoDismountSequence(IN PVCB Vcb, + IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf, + IN BOOLEAN Eject); + +// read physical sectors +/*OSSTATUS UDFReadSectors(IN PVCB Vcb, + IN BOOLEAN Translate,// Translate Logical to Physical + IN ULONG Lba, + IN ULONG BCount, + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes);*/ +#define UDFReadSectors(Vcb, Translate, Lba, BCount, Direct, Buffer, ReadBytes) \ + (( WCacheIsInitialized__(&((Vcb)->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) ? \ + (WCacheReadBlocks__(&((Vcb)->FastCache), Vcb, Buffer, Lba, BCount, ReadBytes, Direct)) : \ + (UDFTRead(Vcb, Buffer, (BCount)<<((Vcb)->BlockSizeBits), Lba, ReadBytes, 0))) + + +// read data inside physical sector +extern OSSTATUS UDFReadInSector(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG i, // offset in sector + IN ULONG l, // transfer length + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes); +// read unaligned data +extern OSSTATUS UDFReadData(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN LONGLONG Offset, + IN ULONG Length, + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG ReadBytes); + +// write physical sectors +OSSTATUS UDFWriteSectors(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG WBCount, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN PCHAR Buffer, + OUT PULONG WrittenBytes); +// write directly to cached sector +OSSTATUS UDFWriteInSector(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN ULONG Lba, + IN ULONG i, // offset in sector + IN ULONG l, // transfer length + IN BOOLEAN Direct, + OUT PCHAR Buffer, + OUT PULONG WrittenBytes); +// write data at unaligned offset & length +OSSTATUS UDFWriteData(IN PVCB Vcb, + IN BOOLEAN Translate, // Translate Logical to Physical + IN LONGLONG Offset, + IN ULONG Length, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN PCHAR Buffer, + OUT PULONG WrittenBytes); + +OSSTATUS UDFResetDeviceDriver(IN PVCB Vcb. + IN PDEVICE_OBJECT TargetDeviceObject, + IN BOOLEAN Unlock); +#endif +/************************************************************************* +* Prototypes for the file Pnp.cpp +*************************************************************************/ +NTSTATUS +UDFPnp ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +/************************************************************************* +* Prototypes for the file read.cpp +*************************************************************************/ +extern OSSTATUS NTAPI UDFRead( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFPostStackOverflowRead( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp, + IN PtrUDFFCB Fcb); + +extern VOID NTAPI UDFStackOverflowRead( + IN PVOID Context, + IN PKEVENT Event); + +extern NTSTATUS UDFCommonRead( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp); + +extern PVOID UDFGetCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp); + +extern NTSTATUS UDFLockCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + BOOLEAN IsReadOperation, + uint32 Length); + +extern NTSTATUS UDFUnlockCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVOID SystemBuffer); + +extern VOID UDFMdlComplete( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PIO_STACK_LOCATION IrpSp, + BOOLEAN ReadCompletion); + +/************************************************************************* +* Prototypes for the file SecurSup.cpp +*************************************************************************/ +extern NTSTATUS UDFGetSecurity( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFSetSecurity( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonGetSecurity( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS UDFCommonSetSecurity( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern NTSTATUS +UDFReadSecurity( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc); + +extern NTSTATUS +UDFAssignAcl( + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, // OPTIONAL + IN PtrUDFFCB Fcb, + IN PtrUDFNTRequiredFCB NtReqFcb); + +extern VOID +UDFDeassignAcl( + IN PtrUDFNTRequiredFCB NtReqFcb, + IN BOOLEAN AutoInherited); + +extern NTSTATUS +UDFWriteSecurity( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc); + +extern NTSTATUS +UDFCheckAccessRights( + PFILE_OBJECT FileObject, + PACCESS_STATE AccessState, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb, + ACCESS_MASK DesiredAccess, + USHORT ShareAccess); + +extern NTSTATUS +UDFSetAccessRights( + PFILE_OBJECT FileObject, + PACCESS_STATE AccessState, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb, + ACCESS_MASK DesiredAccess, + USHORT ShareAccess); + +/************************************************************************* +* Prototypes for the file Shutdown.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFShutdown( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonShutdown( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +/************************************************************************* +* Prototypes for the file Udf_dbg.cpp +*************************************************************************/ +extern BOOLEAN +UDFDebugAcquireResourceSharedLite( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line); + +extern BOOLEAN +UDFDebugAcquireSharedStarveExclusive( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line); + +extern BOOLEAN +UDFDebugAcquireResourceExclusiveLite( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line); + +extern VOID +UDFDebugReleaseResourceForThreadLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line); + +extern VOID +UDFDebugDeleteResource( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line); + +extern NTSTATUS +UDFDebugInitializeResourceLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line); + +extern VOID +UDFDebugConvertExclusiveToSharedLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line); + +extern BOOLEAN +UDFDebugAcquireSharedWaitForExclusive( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line); + +extern LONG +UDFDebugInterlockedIncrement( + IN PLONG addr, + ULONG BugCheckId, + ULONG Line); + +extern LONG +UDFDebugInterlockedDecrement( + IN PLONG addr, + ULONG BugCheckId, + ULONG Line); + +extern LONG +UDFDebugInterlockedExchangeAdd( + IN PLONG addr, + IN LONG i, + ULONG BugCheckId, + ULONG Line); + +/************************************************************************* +* Prototypes for the file UDFinit.cpp +*************************************************************************/ +extern "C" NTSTATUS NTAPI DriverEntry( +PDRIVER_OBJECT DriverObject, // created by the I/O sub-system +PUNICODE_STRING RegistryPath); // path to the registry key + +extern VOID NTAPI UDFInitializeFunctionPointers( +PDRIVER_OBJECT DriverObject); // created by the I/O sub-system + +extern VOID NTAPI +UDFFsNotification(IN PDEVICE_OBJECT DeviceObject, + IN BOOLEAN FsActive); + +#ifndef WIN64 +//extern ptrFsRtlNotifyVolumeEvent FsRtlNotifyVolumeEvent; +#endif //WIN64 + +extern BOOLEAN +UDFGetInstallVersion(PULONG iVer); + +extern BOOLEAN +UDFGetInstallTime(PULONG iTime); + +extern BOOLEAN +UDFGetTrialEnd(PULONG iTrial); + +/************************************************************************* +* Prototypes for the file verify.cpp +*************************************************************************/ + +extern NTSTATUS UDFVerifyVcb ( + IN PtrUDFIrpContext IrpContext, + IN PVCB Vcb + ); + +extern NTSTATUS UDFVerifyVolume ( + IN PIRP Irp); + +extern NTSTATUS UDFPerformVerify ( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN PDEVICE_OBJECT DeviceToVerify + ); + +extern BOOLEAN UDFCheckForDismount ( + IN PtrUDFIrpContext IrpContext, + IN PVCB Vcb, + IN BOOLEAN VcbAcquired + ); + +extern BOOLEAN UDFDismountVcb ( + IN PVCB Vcb, + IN BOOLEAN VcbAcquired); + +extern NTSTATUS UDFCompareVcb(IN PVCB OldVcb, + IN PVCB NewVcb, + IN BOOLEAN PhysicalOnly); + +/************************************************************************* +* Prototypes for the file VolInfo.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFQueryVolInfo(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +extern NTSTATUS UDFCommonQueryVolInfo (PtrUDFIrpContext PtrIrpContext, + PIRP Irp); + +extern NTSTATUS NTAPI UDFSetVolInfo(PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonSetVolInfo(PtrUDFIrpContext PtrIrpContext, + PIRP Irp); + +/************************************************************************* +* Prototypes for the file write.cpp +*************************************************************************/ +extern NTSTATUS NTAPI UDFWrite( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS UDFCommonWrite( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp); + +extern VOID NTAPI UDFDeferredWriteCallBack ( +VOID *Context1, // Should be PtrIrpContext +VOID *Context2); // Should be Irp + +extern VOID UDFPurgeCacheEx_( +PtrUDFNTRequiredFCB NtReqFcb, +LONGLONG Offset, +LONGLONG Length, +//#ifndef ALLOW_SPARSE +BOOLEAN CanWait, +//#endif ALLOW_SPARSE +PVCB Vcb, +PFILE_OBJECT FileObject +); + +/*#ifdef ALLOW_SPARSE + #define UDFZeroDataEx(NtReqFcb, Offset, Length, CanWait) \ + UDFPurgeCacheEx_(NtReqFcb, Offset, Length) + #define UDFPurgeCacheEx(NtReqFcb, Offset, Length, CanWait) \ + UDFPurgeCacheEx_(NtReqFcb, Offset, Length) +#else // ALLOW_SPARSE*/ + #define UDFZeroDataEx(NtReqFcb, Offset, Length, CanWait, Vcb, FileObject) \ + UDFPurgeCacheEx_(NtReqFcb, Offset, Length, CanWait, Vcb, FileObject) + #define UDFPurgeCacheEx(NtReqFcb, Offset, Length, CanWait, Vcb, FileObject) \ + UDFPurgeCacheEx_(NtReqFcb, Offset, Length, CanWait, Vcb, FileObject) +//#endif //ALLOW_SPARSE + + + +#endif // _UDF_PROTOS_H_ diff --git a/reactos/drivers/filesystems/udfs/read.cpp b/reactos/drivers/filesystems/udfs/read.cpp new file mode 100644 index 00000000000..6edcb7698cf --- /dev/null +++ b/reactos/drivers/filesystems/udfs/read.cpp @@ -0,0 +1,1164 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Read.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Read" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_READ + +#ifdef _M_IX86 +#if DBG +#define OVERFLOW_READ_THRESHHOLD (0xE00) +#else +#define OVERFLOW_READ_THRESHHOLD (0xA00) +#endif // UDF_DBG +#else // defined(_M_IX86) +#define OVERFLOW_READ_THRESHHOLD (0x1000) +#endif // defined(_M_IX86) + +//#define POST_LOCK_PAGES + + +/************************************************************************* +* +* Function: UDFRead() +* +* Description: +* The I/O Manager will invoke this routine to handle a read +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFRead( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFRead: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonRead(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFRead() + + +/************************************************************************* +* +* Function: UDFPostStackOverflowRead() +* +* Description: +* Post a read request that could not be processed by +* the fsp thread because of stack overflow potential. +* +* Arguments: +* Irp - Supplies the request to process. +* Fcb - Supplies the file. +* +* Return Value: STATUS_PENDING. +* +*************************************************************************/ +NTSTATUS +UDFPostStackOverflowRead( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp, + IN PtrUDFFCB Fcb + ) +{ + PKEVENT Event; + PERESOURCE Resource; + + KdPrint(("Getting too close to stack limit pass request to Fsp\n")); + + // Allocate an event and get shared on the resource we will + // be later using the common read. + Event = (PKEVENT)MyAllocatePool__(NonPagedPool, sizeof(KEVENT)); + if(!Event) + return STATUS_INSUFFICIENT_RESOURCES; + KeInitializeEvent( Event, NotificationEvent, FALSE ); + + if ((Irp->Flags & IRP_PAGING_IO) && (Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource)) { + Resource = Fcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource; + } else { + Resource = Fcb->NTRequiredFCB->CommonFCBHeader.Resource; + } + + UDFAcquireResourceShared( Resource, TRUE ); + + _SEH2_TRY { + // If this read is the result of a verify, we have to + // tell the overflow read routne to temporarily + // hijack the Vcb->VerifyThread field so that reads + // can go through. + FsRtlPostStackOverflow(PtrIrpContext, Event, UDFStackOverflowRead); + // And wait for the worker thread to complete the item + DbgWaitForSingleObject(Event, NULL); + + } _SEH2_FINALLY { + + UDFReleaseResource( Resource ); + MyFreePool__( Event ); + } _SEH2_END; + + return STATUS_PENDING; + +} // end UDFPostStackOverflowRead() + +/************************************************************************* +* +* Function: UDFStackOverflowRead() +* +* Description: +* Process a read request that could not be processed by +* the fsp thread because of stack overflow potential. +* +* Arguments: +* Context - Supplies the IrpContext being processed +* Event - Supplies the event to be signaled when we are done processing this +* request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None. +* +*************************************************************************/ +VOID +NTAPI +UDFStackOverflowRead( + IN PVOID Context, + IN PKEVENT Event + ) +{ + PtrUDFIrpContext PtrIrpContext = (PtrUDFIrpContext)Context; + NTSTATUS RC; + + KdPrint(("UDFStackOverflowRead: \n")); + // Make it now look like we can wait for I/O to complete + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK; + + // Do the read operation protected by a try-except clause + _SEH2_TRY { + UDFCommonRead(PtrIrpContext, PtrIrpContext->Irp); + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + RC = UDFExceptionHandler(PtrIrpContext, PtrIrpContext->Irp); + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + // Set the stack overflow item's event to tell the original + // thread that we're done. + KeSetEvent( Event, 0, FALSE ); +} // end UDFStackOverflowRead() + + +/************************************************************************* +* +* Function: UDFCommonRead() +* +* Description: +* The actual work is performed here. This routine may be invoked in one +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFCommonRead( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + LARGE_INTEGER ByteOffset; + ULONG ReadLength = 0, TruncatedLength = 0; + ULONG NumberBytesRead = 0; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + PERESOURCE PtrResourceAcquired = NULL; + PERESOURCE PtrResourceAcquired2 = NULL; + PVOID SystemBuffer = NULL; + PIRP TopIrp; +// uint32 KeyValue = 0; + + ULONG Res1Acq = 0; + ULONG Res2Acq = 0; + + BOOLEAN CacheLocked = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + + TmPrint(("UDFCommonRead: irp %x\n", Irp)); + + _SEH2_TRY { + + TopIrp = IoGetTopLevelIrp(); + switch((ULONG)TopIrp) { + case FSRTL_FSP_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); + break; + case FSRTL_CACHE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); + break; + case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n")); +// BrutePoint() + break; + case FSRTL_FAST_IO_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n")); +// BrutePoint() + break; + case NULL: + KdPrint((" NULL TOP_LEVEL_IRP\n")); + break; + default: + if(TopIrp == Irp) { + KdPrint((" TOP_LEVEL_IRP\n")); + } else { + KdPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); + } + break; + } + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + MmPrint((" Enter Irp, MDL=%x\n", Irp->MdlAddress)); + if(Irp->MdlAddress) { + UDFTouch(Irp->MdlAddress); + } + + // If this happens to be a MDL read complete request, then + // there is not much processing that the FSD has to do. + if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + UDFMdlComplete(PtrIrpContext, Irp, IrpSp, TRUE); + // The IRP has been completed. + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post + // the request (your FSD may choose to process it synchronously + // if you implement the support correctly; obviously you will be + // quite constrained in what you can do at such IRQL). + if (IrpSp->MinorFunction & IRP_MN_DPC) { + try_return(RC = STATUS_PENDING); + } + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + Vcb = Fcb->Vcb; + + if(Fcb->FCBFlags & UDF_FCB_DELETED) { + ASSERT(FALSE); + try_return(RC = STATUS_ACCESS_DENIED); + } + + // check for stack overflow + if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { + RC = UDFPostStackOverflowRead( PtrIrpContext, Irp, Fcb ); + try_return(RC); + } + + // Disk based file systems might decide to verify the logical volume + // (if required and only if removable media are supported) at this time + // As soon as Tray is locked, we needn't call UDFVerifyVcb() + + ByteOffset = IrpSp->Parameters.Read.ByteOffset; + + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + PagingIo = (Irp->Flags & IRP_PAGING_IO) ? TRUE : FALSE; + NonBufferedIo = (Irp->Flags & IRP_NOCACHE) ? TRUE : FALSE; + SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE; + KdPrint((" Flags: %s %s %s %s\n", + CanWait ? "W" : "w", PagingIo ? "Pg" : "pg", + NonBufferedIo ? "NBuf" : "buff", SynchronousIo ? "Snc" : "Asc")); + + if(!NonBufferedIo && + (Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { + if(UDFIsAStream(Fcb->FileInfo)) { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_LAST_ACCESS, + FILE_ACTION_MODIFIED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_LAST_ACCESS, + FILE_ACTION_MODIFIED); + } + } + + // Get some of the parameters supplied to us + ReadLength = IrpSp->Parameters.Read.Length; + if (ReadLength == 0) { + // a 0 byte read can be immediately succeeded + try_return(RC); + } + KdPrint((" ByteOffset = %I64x, ReadLength = %x\n", ByteOffset.QuadPart, ReadLength)); + + // Is this a read of the volume itself ? + if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + // Yup, we need to send this on to the disk driver after + // validation of the offset and length. + Vcb = (PVCB)Fcb; + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + if(!CanWait) + try_return(RC = STATUS_PENDING); + + + if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { + + KdPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED; + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + } +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + } + + if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH_REQUIRED) { + + KdPrint((" UDF_IRP_CONTEXT_FLUSH_REQUIRED\n")); + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH_REQUIRED; + + // Acquire the volume resource exclusive + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + PtrResourceAcquired = &(Vcb->VCBResource); + + UDFFlushLogicalVolume(NULL, NULL, Vcb, 0); + + UDFReleaseResource(PtrResourceAcquired); + PtrResourceAcquired = NULL; + } + + // Acquire the volume resource shared ... + UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); + PtrResourceAcquired = &(Vcb->VCBResource); + +#if 0 + if(PagingIo) { + CollectStatistics(Vcb, MetaDataReads); + CollectStatisticsEx(Vcb, MetaDataReadBytes, NumberBytesRead); + } +#endif + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + // Forward the request to the lower level driver + // Lock the callers buffer + if (!NT_SUCCESS(RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength))) { + try_return(RC); + } + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) { + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) { + RC = UDFReadData(Vcb, TRUE, ByteOffset.QuadPart, + ReadLength, FALSE, (PCHAR)SystemBuffer, + &NumberBytesRead); + } else { + RC = UDFTRead(Vcb, SystemBuffer, ReadLength, + (ULONG)(ByteOffset.QuadPart >> Vcb->BlockSizeBits), + &NumberBytesRead); + } + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + try_return(RC); + } + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + + // If the read request is directed to a page file (if your FSD + // supports paging files), send the request directly to the disk + // driver. For requests directed to a page file, you have to trust + // that the offsets will be set correctly by the VMM. You should not + // attempt to acquire any FSD resources either. + if(Fcb->FCBFlags & UDF_FCB_PAGE_FILE) { + NonBufferedIo = TRUE; + } + + if(ByteOffset.HighPart == 0xFFFFFFFF) { + if(ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) { + ByteOffset = FileObject->CurrentByteOffset; + } + } + + // If this read is directed to a directory, it is not allowed + // by the UDF FSD. + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + NtReqFcb = Fcb->NTRequiredFCB; + + Res1Acq = UDFIsResourceAcquired(&(NtReqFcb->MainResource)); + if(!Res1Acq) { + Res1Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES1_ACQ; + } + Res2Acq = UDFIsResourceAcquired(&(NtReqFcb->PagingIoResource)); + if(!Res2Acq) { + Res2Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES2_ACQ; + } + +#if 0 + if(PagingIo) { + CollectStatistics(Vcb, UserFileReads); + CollectStatisticsEx(Vcb, UserFileReadBytes, NumberBytesRead); + } +#endif + + // This is a good place for oplock related processing. + + // If this is the normal file we have to check for + // write access according to the current state of the file locks. + if (!PagingIo && + !FsRtlCheckLockForReadAccess( &(NtReqFcb->FileLock), Irp )) { + try_return( RC = STATUS_FILE_LOCK_CONFLICT ); + } + + // Validate start offset and length supplied. + // If start offset is > end-of-file, return an appropriate error. Note + // that since a FCB resource has already been acquired, and since all + // file size changes require acquisition of both FCB resources, + // the contents of the FCB and associated data structures + // can safely be examined. + + // Also note that we are using the file size in the "Common FCB Header" + // to perform the check. However, your FSD might decide to keep a + // separate copy in the FCB (or some other representation of the + // file associated with the FCB). + + TruncatedLength = ReadLength; + if (ByteOffset.QuadPart >= NtReqFcb->CommonFCBHeader.FileSize.QuadPart) { + // Starting offset is >= file size + try_return(RC = STATUS_END_OF_FILE); + } + // We can also go ahead and truncate the read length here + // such that it is contained within the file size + if( NtReqFcb->CommonFCBHeader.FileSize.QuadPart < (ByteOffset.QuadPart + ReadLength) ) { + TruncatedLength = (ULONG)(NtReqFcb->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); + // we can't get ZERO here + } + KdPrint((" TruncatedLength = %x\n", TruncatedLength)); + + // There are certain complications that arise when the same file stream + // has been opened for cached and non-cached access. The FSD is then + // responsible for maintaining a consistent view of the data seen by + // the caller. + // Also, it is possible for file streams to be mapped in both as data files + // and as an executable. This could also lead to consistency problems since + // there now exist two separate sections (and pages) containing file + // information. + + // The test below flushes the data cached in system memory if the current + // request madates non-cached access (file stream must be cached) and + // (a) the current request is not paging-io which indicates it is not + // a recursive I/O operation OR originating in the Cache Manager + // (b) OR the current request is paging-io BUT it did not originate via + // the Cache Manager (or is a recursive I/O operation) and we do + // have an image section that has been initialized. +#define UDF_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL)) + + if(NonBufferedIo && + (NtReqFcb->SectionObject.DataSectionObject != NULL)) { + if(!PagingIo) { + +/* // We hold the main resource exclusive here because the flush + // may generate a recursive write in this thread. The PagingIo + // resource is held shared so the drop-and-release serialization + // below will work. + if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + PtrResourceAcquired = &(NtReqFcb->MainResource); + + // We hold PagingIo shared around the flush to fix a + // cache coherency problem. + UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), TRUE );*/ + + MmPrint((" CcFlushCache()\n")); + CcFlushCache(&(NtReqFcb->SectionObject), &ByteOffset, TruncatedLength, &(Irp->IoStatus)); + +/* UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + UDFReleaseResource(PtrResourceAcquired); + PtrResourceAcquired = NULL; + // If the flush failed, return error to the caller + if(!NT_SUCCESS(RC = Irp->IoStatus.Status)) { + try_return(RC); + } + + // Acquiring and immediately dropping the resource serializes + // us behind any other writes taking place (either from the + // lazy writer or modified page writer).*/ + if(!Res2Acq) { + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE ); + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + } + } + } + + // Acquire the appropriate FCB resource shared + if (PagingIo) { + // Try to acquire the FCB PagingIoResource shared + if(!Res2Acq) { + if (!UDFAcquireResourceShared(&(NtReqFcb->PagingIoResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + } else { + // Try to acquire the FCB MainResource shared + if(NonBufferedIo) { + if(!Res2Acq) { + if(!UDFAcquireSharedWaitForExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + } else { + if(!Res1Acq) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + PtrResourceAcquired = &(NtReqFcb->MainResource); + } + } + } + + // This is also a good place to set whether fast-io can be performed + // on this particular file or not. Your FSD must make it's own + // determination on whether or not to allow fast-io operations. + // Commonly, fast-io is not allowed if any byte range locks exist + // on the file or if oplocks prevent fast-io. Practically any reason + // choosen by your FSD could result in your setting FastIoIsNotPossible + // OR FastIoIsQuestionable instead of FastIoIsPossible. + + NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); +/* if(NtReqFcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible) + NtReqFcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable;*/ + +#ifdef UDF_DISABLE_SYSTEM_CACHE_MANAGER + NonBufferedIo = TRUE; +#endif + + if(Fcb && Fcb->FileInfo && Fcb->FileInfo->Dloc) { + AdPrint(("UDFCommonRead: DataLoc %x, Mapping %x\n", &Fcb->FileInfo->Dloc->DataLoc, Fcb->FileInfo->Dloc->DataLoc.Mapping)); + } + + // Branch here for cached vs non-cached I/O + if (!NonBufferedIo) { + + if(FileObject->Flags & FO_WRITE_THROUGH) { + CanWait = TRUE; + } + // The caller wishes to perform cached I/O. Initiate caching if + // this is the first cached I/O operation using this file object + if (!(FileObject->PrivateCacheMap)) { + // This is the first cached I/O operation. You must ensure + // that the FCB Common FCB Header contains valid sizes at this time + MmPrint((" CcInitializeCacheMap()\n")); + CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)(&(NtReqFcb->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(UDFGlobalData.CacheMgrCallBacks), // callbacks + NtReqFcb); // The context used in callbacks + MmPrint((" CcSetReadAheadGranularity()\n")); + CcSetReadAheadGranularity(FileObject, Vcb->SystemCacheGran); + } + + // Check and see if this request requires a MDL returned to the caller + if (IrpSp->MinorFunction & IRP_MN_MDL) { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + MmPrint((" CcMdlRead()\n")); +// CcMdlRead(FileObject, &ByteOffset, TruncatedLength, &(Irp->MdlAddress), &(Irp->IoStatus)); +// NumberBytesRead = Irp->IoStatus.Information; +// RC = Irp->IoStatus.Status; + NumberBytesRead = 0; + RC = STATUS_INVALID_PARAMETER; + + try_return(RC); + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + // First though, we need a buffer pointer (address) that is valid + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) + try_return(RC = STATUS_INVALID_USER_BUFFER); + ASSERT(SystemBuffer); + MmPrint((" CcCopyRead()\n")); + if (!CcCopyRead(FileObject, &(ByteOffset), TruncatedLength, CanWait, SystemBuffer, &(Irp->IoStatus))) { + // The caller was not prepared to block and data is not immediately + // available in the system cache + try_return(RC = STATUS_PENDING); + } + + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + // We have the data + RC = Irp->IoStatus.Status; + NumberBytesRead = Irp->IoStatus.Information; + + try_return(RC); + + } else { + + MmPrint((" Read NonBufferedIo\n")); + +#if 1 + if((ULONG)TopIrp == FSRTL_MOD_WRITE_TOP_LEVEL_IRP) { + KdPrint(("FSRTL_MOD_WRITE_TOP_LEVEL_IRP => CanWait\n")); + CanWait = TRUE; + } else + if((ULONG)TopIrp == FSRTL_CACHE_TOP_LEVEL_IRP) { + KdPrint(("FSRTL_CACHE_TOP_LEVEL_IRP => CanWait\n")); + CanWait = TRUE; + } + + if(NtReqFcb->AcqSectionCount || NtReqFcb->AcqFlushCount) { + MmPrint((" AcqCount (%d/%d)=> CanWait ?\n", NtReqFcb->AcqSectionCount, NtReqFcb->AcqFlushCount)); + CanWait = TRUE; + } else + {} +/* if((TopIrp != Irp)) { + KdPrint(("(TopIrp != Irp) => CanWait\n")); + CanWait = TRUE; + } else*/ +#endif + if(KeGetCurrentIrql() > PASSIVE_LEVEL) { + MmPrint((" !PASSIVE_LEVEL\n")); + CanWait = FALSE; + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FORCED_POST; + } + if(!CanWait && UDFIsFileCached__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, FALSE)) { + MmPrint((" Locked => CanWait\n")); + CacheLocked = TRUE; + CanWait = TRUE; + } + + // Send the request to lower level drivers + if(!CanWait) { + try_return(RC = STATUS_PENDING); + } + +// ASSERT(NT_SUCCESS(RC)); + if(!Res2Acq) { + if(UDFAcquireResourceSharedWithCheck(&(NtReqFcb->PagingIoResource))) + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + + RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, TruncatedLength); + if(!NT_SUCCESS(RC)) { + try_return(RC); + } + + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) { + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + + RC = UDFReadFile__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, + CacheLocked, (PCHAR)SystemBuffer, &NumberBytesRead); +/* // AFAIU, CacheManager wants this: + if(!NT_SUCCESS(RC)) { + NumberBytesRead = 0; + }*/ + + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + +#if 0 + if(PagingIo) { + CollectStatistics(Vcb, UserDiskReads); + } else { + CollectStatistics2(Vcb, NonCachedDiskReads); + } +#endif + + try_return(RC); + + // For paging-io, the FSD has to trust the VMM to do the right thing + + // Here is a common method used by Windows NT native file systems + // that are in the process of sending a request to the disk driver. + // First, mark the IRP as pending, then invoke the lower level driver + // after setting a completion routine. + // Meanwhile, this particular thread can immediately return a + // STATUS_PENDING return code. + // The completion routine is then responsible for completing the IRP + // and unlocking appropriate resources + + // Also, at this point, the FSD might choose to utilize the + // information contained in the ValidDataLength field to simply + // return zeroes to the caller for reads extending beyond current + // valid data length. + + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(CacheLocked) { + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } + + // Release any resources acquired here ... + if(PtrResourceAcquired2) { + UDFReleaseResource(PtrResourceAcquired2); + } + if(PtrResourceAcquired) { + if(NtReqFcb && + (PtrResourceAcquired == + &(NtReqFcb->MainResource))) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + } + UDFReleaseResource(PtrResourceAcquired); + } + + // Post IRP if required + if(RC == STATUS_PENDING) { + + // Lock the callers buffer here. Then invoke a common routine to + // perform the post operation. + if (!(IrpSp->MinorFunction & IRP_MN_MDL)) { + RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, ReadLength); + ASSERT(NT_SUCCESS(RC)); + } + if(PagingIo) { + if(Res1Acq) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES1_ACQ; + } + if(Res2Acq) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES2_ACQ; + } + } + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { + FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + NumberBytesRead; + } + // If the read completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a read was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) { + FileObject->Flags |= FO_FILE_FAST_IO_READ; + Ccb->CCBFlags |= UDF_CCB_ACCESSED; + } + + if(!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = NumberBytesRead; + KdPrint((" NumberBytesRead = %x\n", NumberBytesRead)); + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + MmPrint((" Complete Irp, MDL=%x\n", Irp->MdlAddress)); + if(Irp->MdlAddress) { + UDFTouch(Irp->MdlAddress); + } + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + } _SEH2_END; // end of "__finally" processing + + return(RC); +} // end UDFCommonRead() + + +#ifdef UDF_DBG +ULONG LockBufferCounter = 0; +ULONG BuildMdlCounter = 0; +#endif //UDF_DBG + +/************************************************************************* +* +* Function: UDFGetCallersBuffer() +* +* Description: +* Obtain a pointer to the caller's buffer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +PVOID +UDFGetCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + VOID *ReturnedBuffer = NULL; + + KdPrint(("UDFGetCallersBuffer: \n")); + + // If an MDL is supplied, use it. + if(Irp->MdlAddress) { + MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(Irp->MdlAddress) MDL=%x\n", Irp->MdlAddress)); +// ReturnedBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + ReturnedBuffer = MmGetSystemAddressForMdlSafer(Irp->MdlAddress); + } else + if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) { + // Free buffer +#ifndef POST_LOCK_PAGES + MmPrint((" UDFGetCallersBuffer: MmGetSystemAddressForMdl(PtrIrpContext->PtrMdl) MDL=%x\n", PtrIrpContext->PtrMdl)); + ReturnedBuffer = MmGetSystemAddressForMdlSafe(PtrIrpContext->PtrMdl, NormalPagePriority); +#else //POST_LOCK_PAGES + if(PtrIrpContext->TransitionBuffer) { + MmPrint((" UDFGetCallersBuffer: TransitionBuffer\n")); + return PtrIrpContext->TransitionBuffer; + } + + _SEH2_TRY { + MmPrint((" MmProbeAndLockPages()\n")); + MmProbeAndLockPages(PtrIrpContext->PtrMdl, Irp->RequestorMode, + ((PtrIrpContext->MajorFunction == IRP_MJ_READ) ? IoWriteAccess:IoReadAccess)); +#ifdef UDF_DBG + LockBufferCounter++; +#endif //UDF_DBG + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + //RC = STATUS_INVALID_USER_BUFFER; + BrutePoint(); + return NULL; + } _SEH2_END; + + MmPrint((" MmGetSystemAddressForMdlSafer()\n")); + ReturnedBuffer = MmGetSystemAddressForMdlSafer(PtrIrpContext->PtrMdl); +#endif //POST_LOCK_PAGES + } else { + MmPrint((" UDFGetCallersBuffer: Irp->UserBuffer\n")); + ReturnedBuffer = Irp->UserBuffer; + } + + return(ReturnedBuffer); +} // end UDFGetCallersBuffer() + +/************************************************************************* +* +* Function: UDFLockCallersBuffer() +* +* Description: +* Obtain a MDL that describes the buffer. Lock pages for I/O +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFLockCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + BOOLEAN IsReadOperation, + uint32 Length + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PMDL PtrMdl = NULL; + + KdPrint(("UDFLockCallersBuffer: \n")); + + ASSERT(Irp); + + _SEH2_TRY { + // Is a MDL already present in the IRP + if (!(Irp->MdlAddress)) { + // Allocate a MDL +/* + if(!IsReadOperation) { + MmPrint((" Allocate TransitionBuffer\n")); + PtrIrpContext->TransitionBuffer = (PCHAR)DbgAllocatePool(NonPagedPool, Length); + if(!PtrIrpContext->TransitionBuffer) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + _SEH2_TRY { + RtlCopyMemory(PtrIrpContext->TransitionBuffer, Irp->UserBuffer, Length); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + RC = STATUS_INVALID_USER_BUFFER; + } _SEH2_END; + } else*/ { + + MmPrint((" IoAllocateMdl()\n")); +// if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, NULL))) { + + // This will place allocated Mdl to Irp + if (!(PtrMdl = IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + MmPrint((" Alloc MDL=%x\n", PtrMdl)); +#ifdef UDF_DBG + BuildMdlCounter++; +#endif //UDF_DBG + } + // Probe and lock the pages described by the MDL + // We could encounter an exception doing so, swallow the exception + // NOTE: The exception could be due to an unexpected (from our + // perspective), invalidation of the virtual addresses that comprise + // the passed in buffer +#ifndef POST_LOCK_PAGES + _SEH2_TRY { + MmPrint((" MmProbeAndLockPages()\n")); + MmProbeAndLockPages(PtrMdl, Irp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess)); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + MmPrint((" MmProbeAndLockPages() failed\n")); + Irp->MdlAddress = NULL; + RC = STATUS_INVALID_USER_BUFFER; + } _SEH2_END; +#endif //POST_LOCK_PAGES + + if(NT_SUCCESS(RC)) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_BUFFER_LOCKED; + PtrIrpContext->PtrMdl = PtrMdl; + } + } else { + MmPrint((" UDFLockCallersBuffer: do nothing, MDL=%x\n", Irp->MdlAddress)); + UDFTouch(Irp->MdlAddress); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if (!NT_SUCCESS(RC) && PtrMdl) { + MmPrint((" Free MDL=%x\n", PtrMdl)); + IoFreeMdl(PtrMdl); + } + } _SEH2_END; + + return(RC); +} // end UDFLockCallersBuffer() + +/************************************************************************* +* +* Function: UDFUnlockCallersBuffer() +* +* Description: +* Obtain a MDL that describes the buffer. Lock pages for I/O +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFUnlockCallersBuffer( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp, + PVOID SystemBuffer + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + KdPrint(("UDFUnlockCallersBuffer: \n")); + + ASSERT(Irp); + + _SEH2_TRY { + // Is a nonPaged buffer already present in the IRP + if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_BUFFER_LOCKED) { + + KdPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress)); + if(PtrIrpContext->TransitionBuffer) { + MmPrint((" UDFUnlockCallersBuffer: free TransitionBuffer\n")); + DbgFreePool(PtrIrpContext->TransitionBuffer); + PtrIrpContext->TransitionBuffer = NULL; + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED; + try_return(RC); + } + // Free buffer + KeFlushIoBuffers( PtrIrpContext->PtrMdl, TRUE, FALSE ); +// MmPrint((" IrpCtx->Mdl, MmUnmapLockedPages()\n")); +// MmUnmapLockedPages(SystemBuffer, PtrIrpContext->PtrMdl); + + // This will be done in IoCompleteIrp !!! + + //MmPrint((" MmUnlockPages()\n")); + //MmUnlockPages(PtrIrpContext->PtrMdl); + +#ifdef UDF_DBG + LockBufferCounter--; +#endif //UDF_DBG + + // This will be done in IoCompleteIrp !!! + + //IoFreeMdl(PtrIrpContext->PtrMdl); + +#ifdef UDF_DBG + BuildMdlCounter--; +#endif //UDF_DBG + UDFTouch(PtrIrpContext->PtrMdl); + PtrIrpContext->PtrMdl = NULL; + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_BUFFER_LOCKED; + } else + if(Irp->MdlAddress) { +// MmPrint((" Irp->Mdl, MmUnmapLockedPages()\n")); +// MmUnmapLockedPages(SystemBuffer, Irp->MdlAddress); + KdPrint((" UDF_IRP_CONTEXT_BUFFER_LOCKED MDL=%x, Irp MDL=%x\n", PtrIrpContext->PtrMdl, Irp->MdlAddress)); + UDFTouch(Irp->MdlAddress); + KeFlushIoBuffers( Irp->MdlAddress, + ((IoGetCurrentIrpStackLocation(Irp))->MajorFunction) == IRP_MJ_READ, + FALSE ); + } else + { ; } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + NOTHING; + } _SEH2_END; + + return(RC); +} // end UDFUnlockCallersBuffer() + +/************************************************************************* +* +* Function: UDFMdlComplete() +* +* Description: +* Tell Cache Manager to release MDL (and possibly flush). +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None. +* +*************************************************************************/ +VOID UDFMdlComplete( +PtrUDFIrpContext PtrIrpContext, +PIRP Irp, +PIO_STACK_LOCATION IrpSp, +BOOLEAN ReadCompletion) +{ + NTSTATUS RC = STATUS_SUCCESS; + PFILE_OBJECT FileObject = NULL; + + KdPrint(("UDFMdlComplete: \n")); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + UDFTouch(Irp->MdlAddress); + // Not much to do here. + if (ReadCompletion) { + MmPrint((" CcMdlReadComplete() MDL=%x\n", Irp->MdlAddress)); + CcMdlReadComplete(FileObject, Irp->MdlAddress); + } else { + // The Cache Manager needs the byte offset in the I/O stack location. + MmPrint((" CcMdlWriteComplete() MDL=%x\n", Irp->MdlAddress)); + CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress); + } + + // Clear the MDL address field in the IRP so the IoCompleteRequest() + // does not __try to play around with the MDL. + Irp->MdlAddress = NULL; + + // Free up the Irp Context. + UDFReleaseIrpContext(PtrIrpContext); + + // Complete the IRP. + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return; +} diff --git a/reactos/drivers/filesystems/udfs/secursup.cpp b/reactos/drivers/filesystems/udfs/secursup.cpp new file mode 100644 index 00000000000..7bfb63297c1 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/secursup.cpp @@ -0,0 +1,1128 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: SecurSup.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Get/Set Security" dispatch entry points. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_SECURITY + +#ifdef UDF_ENABLE_SECURITY + +NTSTATUS UDFConvertToSelfRelative( + IN OUT PSECURITY_DESCRIPTOR* SecurityDesc); + +/*UCHAR FullControlSD[] = { +0x01, 0x00, 0x04, 0x80, 0x4c, 0x00, 0x00, 0x00, +0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x38, 0x00, +0x02, 0x00, 0x00, 0x00, 0x00, 0x09, 0x18, 0x00, +0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, +0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x00, 0x00, 0x00, 0x00 +};*/ + +/************************************************************************* +* +* Function: UDFGetSecurity() +* +* Description: +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS +UDFGetSecurity( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFGetSecurity\n")); +// BrutePoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + // Call the common Lock Control routine, with blocking allowed if + // synchronous + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonGetSecurity(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFGetSecurity() + + +/************************************************************************* +* +* Function: UDFCommonGetSecurity() +* +* Description: +* This is the common routine for getting Security (ACL) called +* by both the fsd and fsp threads +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS +UDFCommonGetSecurity( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = FALSE; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN AcquiredFCB = FALSE; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVOID PtrSystemBuffer = NULL; + ULONG BufferLength = 0; + + KdPrint(("UDFCommonGetSecurity\n")); + + _SEH2_TRY { + + // First, get a pointer to the current I/O stack location. + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + +/* if(!Fcb->Vcb->ReadSecurity) + try_return(RC = STATUS_NOT_IMPLEMENTED);*/ + + NtReqFcb = Fcb->NTRequiredFCB; + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // Acquire the FCB resource shared + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { +// if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + + PtrSystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!PtrSystemBuffer) + try_return(RC = STATUS_INVALID_USER_BUFFER); + BufferLength = IrpSp->Parameters.QuerySecurity.Length; + + if(!NtReqFcb->SecurityDesc) { + RC = UDFAssignAcl(Fcb->Vcb, FileObject, Fcb, NtReqFcb); + if(!NT_SUCCESS(RC)) + try_return(RC); + } + + _SEH2_TRY { + RC = SeQuerySecurityDescriptorInfo(&(IrpSp->Parameters.QuerySecurity.SecurityInformation), + (PSECURITY_DESCRIPTOR)PtrSystemBuffer, + &BufferLength, + &(NtReqFcb->SecurityDesc) ); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + RC = STATUS_BUFFER_TOO_SMALL; + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + // Release the FCB resources if acquired. + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + + if (PostRequest) { + // Perform appropriate post related processing here + RC = UDFPostRequest(PtrIrpContext, Irp); + } else + if(!AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = BufferLength; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } // end of "__finally" processing + + return(RC); +} + +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO +/************************************************************************* +* +* Function: UDFSetSecurity() +* +* Description: +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS +UDFSetSecurity( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFSetSecurity\n")); +// BrutePoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + // Call the common Lock Control routine, with blocking allowed if + // synchronous + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonSetSecurity(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFSetSecurity() + + +/************************************************************************* +* +* Function: UDFCommonSetSecurity() +* +* Description: +* This is the common routine for getting Security (ACL) called +* by both the fsd and fsp threads +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS +UDFCommonSetSecurity( + IN PtrUDFIrpContext PtrIrpContext, + IN PIRP Irp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = FALSE; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + BOOLEAN AcquiredFCB = FALSE; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + ACCESS_MASK DesiredAccess = 0; + + KdPrint(("UDFCommonSetSecurity\n")); + + _SEH2_TRY { + + // First, get a pointer to the current I/O stack location. + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + + if(!Fcb->Vcb->WriteSecurity) + try_return(RC = STATUS_NOT_IMPLEMENTED); + + NtReqFcb = Fcb->NTRequiredFCB; + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // Acquire the FCB resource exclusive + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + +//OWNER_SECURITY_INFORMATION + if(IrpSp->Parameters.SetSecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) + DesiredAccess |= WRITE_OWNER; +//GROUP_SECURITY_INFORMATION + if(IrpSp->Parameters.SetSecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) + DesiredAccess |= WRITE_OWNER; +//DACL_SECURITY_INFORMATION + if(IrpSp->Parameters.SetSecurity.SecurityInformation & DACL_SECURITY_INFORMATION) + DesiredAccess |= WRITE_DAC; +//SACL_SECURITY_INFORMATION + if(IrpSp->Parameters.SetSecurity.SecurityInformation & SACL_SECURITY_INFORMATION) + DesiredAccess |= ACCESS_SYSTEM_SECURITY; + + _SEH2_TRY { + UDFConvertToSelfRelative(&(NtReqFcb->SecurityDesc)); + + KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc)); + KdPrint(("\n")); + + RC = SeSetSecurityDescriptorInfo(/*FileObject*/ NULL, + &(IrpSp->Parameters.SetSecurity.SecurityInformation), + IrpSp->Parameters.SetSecurity.SecurityDescriptor, + &(NtReqFcb->SecurityDesc), + NonPagedPool, + IoGetFileObjectGenericMapping() ); + + KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc)); + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + RC = STATUS_INVALID_PARAMETER; + } + if(NT_SUCCESS(RC)) { + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED; + + UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_SECURITY, + FILE_ACTION_MODIFIED); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + // Release the FCB resources if acquired. + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + UDFReleaseResource(&(NtReqFcb->MainResource)); + AcquiredFCB = FALSE; + } + + if (PostRequest) { + // Perform appropriate post related processing here + RC = UDFPostRequest(PtrIrpContext, Irp); + } else + if(!AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } // end of "__finally" processing + + return(RC); +} // ens UDFCommonSetSecurity() + +#endif //DEMO +#endif //UDF_READ_ONLY_BUILD +#endif //UDF_ENABLE_SECURITY + +NTSTATUS +UDFReadSecurity( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ +#ifdef UDF_ENABLE_SECURITY + PUDF_FILE_INFO FileInfo = NULL; + PUDF_FILE_INFO SDirInfo = NULL; + PUDF_FILE_INFO AclInfo = NULL; + NTSTATUS RC; + ULONG NumberBytesRead; + PERESOURCE Res1 = NULL; + + KdPrint(("UDFReadSecurity\n")); + + _SEH2_TRY { + + FileInfo = Fcb->FileInfo; + ASSERT(FileInfo); + if(!FileInfo) { + KdPrint((" Volume Security\n")); + try_return(RC = STATUS_NO_SECURITY_ON_OBJECT); + } + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + KdPrint((" No Security on blank volume\n")); + try_return(RC = STATUS_NO_SECURITY_ON_OBJECT); + } + + // Open Stream Directory + RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo); + + if(RC == STATUS_NOT_FOUND) + try_return(RC = STATUS_NO_SECURITY_ON_OBJECT); + if(!NT_SUCCESS(RC)) { + if(UDFCleanUpFile__(Vcb, SDirInfo)) { + if(SDirInfo) MyFreePool__(SDirInfo); + } + SDirInfo = NULL; + try_return(RC); + } + // Acquire SDir exclusively if Fcb present + if(SDirInfo->Fcb) { + BrutePoint(); + UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + } + + // Open Acl Stream + RC = UDFOpenFile__(Vcb, + FALSE,TRUE,&(UDFGlobalData.AclName), + SDirInfo,&AclInfo,NULL); + if(RC == STATUS_OBJECT_NAME_NOT_FOUND) + try_return(RC = STATUS_NO_SECURITY_ON_OBJECT); + if(!NT_SUCCESS(RC)) { + if(UDFCleanUpFile__(Vcb, AclInfo)) { + if(AclInfo) MyFreePool__(AclInfo); + } + AclInfo = NULL; + try_return(RC); + } + + NumberBytesRead = (ULONG)UDFGetFileSize(AclInfo); + (*SecurityDesc) = DbgAllocatePool(NonPagedPool, NumberBytesRead); + if(!(*SecurityDesc)) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RC = UDFReadFile__(Vcb, AclInfo, 0, NumberBytesRead, + FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead); + if(!NT_SUCCESS(RC)) + try_return(RC); + + RC = RtlValidSecurityDescriptor(*SecurityDesc); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AclInfo) { + UDFCloseFile__(Vcb, AclInfo); + if(UDFCleanUpFile__(Vcb, AclInfo)) + MyFreePool__(AclInfo); + } + + if(SDirInfo) { + UDFCloseFile__(Vcb, SDirInfo); + if(UDFCleanUpFile__(Vcb, SDirInfo)) + MyFreePool__(SDirInfo); + } + + if(!NT_SUCCESS(RC) && (*SecurityDesc)) { + DbgFreePool(*SecurityDesc); + (*SecurityDesc) = NULL; + } + if(Res1) + UDFReleaseResource(Res1); + } + + return RC; +#else + return STATUS_NO_SECURITY_ON_OBJECT; +#endif //UDF_ENABLE_SECURITY + +} // end UDFReadSecurity() + +#ifdef UDF_ENABLE_SECURITY +NTSTATUS +UDFConvertToSelfRelative( + IN OUT PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ + NTSTATUS RC; + SECURITY_INFORMATION SecurityInformation; + PSECURITY_DESCRIPTOR NewSD; + ULONG Len; + + KdPrint((" UDFConvertToSelfRelative\n")); + + if(!(*SecurityDesc)) + return STATUS_NO_SECURITY_ON_OBJECT; + + SecurityInformation = FULL_SECURITY_INFORMATION; + Len = RtlLengthSecurityDescriptor(*SecurityDesc); + ASSERT(Len <= 1024); + NewSD = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len); + if(!NewSD) + return STATUS_INSUFFICIENT_RESOURCES; + _SEH2_TRY { + RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, NewSD, &Len, SecurityDesc); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + RC = STATUS_INSUFFICIENT_RESOURCES; + } + + if(NT_SUCCESS(RC)) { + DbgFreePool(*SecurityDesc); + *SecurityDesc = NewSD; + } else { + DbgFreePool(NewSD); + } + return RC; +} // end UDFConvertToSelfRelative() + +NTSTATUS +UDFInheritAcl( + IN PVCB Vcb, + IN PSECURITY_DESCRIPTOR* ParentSecurityDesc, + IN OUT PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ + NTSTATUS RC; + SECURITY_INFORMATION SecurityInformation; + ULONG Len; + + KdPrint((" UDFInheritAcl\n")); + + if(!(*ParentSecurityDesc)) { + *SecurityDesc = NULL; + return STATUS_SUCCESS; + } + + SecurityInformation = FULL_SECURITY_INFORMATION; + Len = RtlLengthSecurityDescriptor(*ParentSecurityDesc); + *SecurityDesc = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len); + if(!(*SecurityDesc)) + return STATUS_INSUFFICIENT_RESOURCES; + _SEH2_TRY { + RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, *SecurityDesc, &Len, ParentSecurityDesc); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + RC = STATUS_INSUFFICIENT_RESOURCES; + } + + if(!NT_SUCCESS(RC)) { + DbgFreePool(*SecurityDesc); + *SecurityDesc = NULL; + } + return RC; +} // end UDFInheritAcl() + +NTSTATUS +UDFBuildEmptyAcl( + IN PVCB Vcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ + NTSTATUS RC; + ULONG Len = 2 * (sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*RtlLengthSid(SeExports->SeWorldSid)*/); + + KdPrint((" UDFBuildEmptyAcl\n")); + // Create Security Descriptor + (*SecurityDesc) = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, + sizeof(SECURITY_DESCRIPTOR) + Len); + if(!(*SecurityDesc)) + return STATUS_INSUFFICIENT_RESOURCES; + + RC = RtlCreateSecurityDescriptor(*SecurityDesc, SECURITY_DESCRIPTOR_REVISION); + + if(!NT_SUCCESS(RC)) { + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + } + return RC; +} // end UDFBuildEmptyAcl() + +NTSTATUS +UDFBuildFullControlAcl( + IN PVCB Vcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ + NTSTATUS RC; + PACL Acl; + ULONG Len = sizeof(ACL) + 2*(sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*- sizeof(ULONG)*/ /*+ RtlLengthSid(SeExports->SeWorldSid)*/); + + KdPrint((" UDFBuildFullControlAcl\n")); + // Create Security Descriptor + RC = UDFBuildEmptyAcl(Vcb, SecurityDesc); + if(!NT_SUCCESS(RC)) + return RC; + + // Set Owner + RC = RtlSetOwnerSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE); + if(!NT_SUCCESS(RC)) { + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + + // Set Group + RC = RtlSetGroupSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE); + if(!NT_SUCCESS(RC)) { + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + + // Create empty Acl + Acl = (PACL)DbgAllocatePool(NonPagedPool, Len); + if(!Acl) { + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + RtlZeroMemory(Acl, Len); + + RC = RtlCreateAcl(Acl, Len, ACL_REVISION); + if(!NT_SUCCESS(RC)) { + DbgFreePool(Acl); + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + + // Add (All)(All) access for Everyone +/* RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION, + GENERIC_ALL, + SeExports->SeWorldSid);*/ + + RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION, + FILE_ALL_ACCESS, + SeExports->SeWorldSid); + + if(!NT_SUCCESS(RC)) { + DbgFreePool(Acl); + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + + // Add Acl to Security Descriptor + RC = RtlSetDaclSecurityDescriptor(*SecurityDesc, TRUE, Acl, FALSE); + if(!NT_SUCCESS(RC)) { + DbgFreePool(Acl); + DbgFreePool(*SecurityDesc); + *((PULONG)SecurityDesc) = NULL; + return RC; + } + + RC = UDFConvertToSelfRelative(SecurityDesc); + + DbgFreePool(Acl); + + return RC; +} // end UDFBuildFullControlAcl() + +#endif // UDF_ENABLE_SECURITY + +NTSTATUS +UDFAssignAcl( + IN PVCB Vcb, + IN PFILE_OBJECT FileObject, // OPTIONAL + IN PtrUDFFCB Fcb, + IN PtrUDFNTRequiredFCB NtReqFcb + ) +{ + NTSTATUS RC = STATUS_SUCCESS; +#ifdef UDF_ENABLE_SECURITY +// SECURITY_INFORMATION SecurityInformation; + +// KdPrint((" UDFAssignAcl\n")); + if(!NtReqFcb->SecurityDesc) { + + PSECURITY_DESCRIPTOR ExplicitSecurity = NULL; + + if(UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo)) { + // Stream/SDir security + NtReqFcb->SecurityDesc = Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc; + return STATUS_SUCCESS; + } else + if(!Fcb->FileInfo) { + // Volume security + if(Vcb->RootDirFCB && + Vcb->RootDirFCB->FileInfo && + Vcb->RootDirFCB->FileInfo->Dloc && + Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb) { + RC = UDFInheritAcl(Vcb, &(Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity); + } else { + NtReqFcb->SecurityDesc = NULL; + RC = STATUS_NO_SECURITY_ON_OBJECT; + } + return RC; + } + + RC = UDFReadSecurity(Vcb, Fcb, &ExplicitSecurity); + if(RC == STATUS_NO_SECURITY_ON_OBJECT) { + if(!Fcb->FileInfo->ParentFile) { + RC = UDFBuildFullControlAcl(Vcb, &ExplicitSecurity); + } else { + RC = UDFInheritAcl(Vcb, &(Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity); + } +/* if(NT_SUCCESS(RC)) { + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED; + }*/ + } + if(NT_SUCCESS(RC)) { + +// SecurityInformation = FULL_SECURITY_INFORMATION; + NtReqFcb->SecurityDesc = ExplicitSecurity; + +/* RC = SeSetSecurityDescriptorInfo(FileObject, + &SecurityInformation, + ExplicitSecurity, + &(NtReqFcb->SecurityDesc), + NonPagedPool, + IoGetFileObjectGenericMapping() );*/ + + } + } +#endif //UDF_ENABLE_SECURITY + return RC; +} // end UDFAssignAcl() + + +VOID +UDFDeassignAcl( + IN PtrUDFNTRequiredFCB NtReqFcb, + IN BOOLEAN AutoInherited + ) +{ +#ifdef UDF_ENABLE_SECURITY +// NTSTATUS RC = STATUS_SUCCESS; + +// KdPrint((" UDFDeassignAcl\n")); + if(!NtReqFcb->SecurityDesc) + return; + + if(AutoInherited) { + NtReqFcb->SecurityDesc = NULL; + return; + } + + SeDeassignSecurity(&(NtReqFcb->SecurityDesc)); + NtReqFcb->SecurityDesc = NULL; // HA BCRK CLU4 +#endif //UDF_ENABLE_SECURITY + return; +} // end UDFDeassignAcl() + +NTSTATUS +UDFWriteSecurity( + IN PVCB Vcb, + IN PtrUDFFCB Fcb, + IN PSECURITY_DESCRIPTOR* SecurityDesc + ) +{ +#ifdef UDF_ENABLE_SECURITY + PUDF_FILE_INFO FileInfo = NULL; + PUDF_FILE_INFO SDirInfo = NULL; + PUDF_FILE_INFO AclInfo = NULL; + PERESOURCE Res1 = NULL; +#ifndef DEMO + NTSTATUS RC; + ULONG NumberBytesRead; +#endif //DEMO + +// KdPrint(("UDFWriteSecurity\n")); + +#if !defined(DEMO) && !defined(UDF_READ_ONLY_BUILD) + + if(!Vcb->WriteSecurity || + (Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY | + UDF_VCB_FLAGS_MEDIA_READ_ONLY))) + +#endif //!defined(DEMO) && !defined(UDF_READ_ONLY_BUILD) + + return STATUS_SUCCESS; + +#if !defined(DEMO) && !defined(UDF_READ_ONLY_BUILD) + + _SEH2_TRY { + + FileInfo = Fcb->FileInfo; + ASSERT(FileInfo); + if(!FileInfo) { + KdPrint((" Volume Security\n")); + try_return(RC = STATUS_SUCCESS); + } + + if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_SD_MODIFIED)) + try_return(RC = STATUS_SUCCESS); + + // Open Stream Directory + RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo); + + if(RC == STATUS_NOT_FOUND) { + RC = UDFCreateStreamDir__(Vcb, FileInfo, &SDirInfo); + } + if(!NT_SUCCESS(RC)) { + if(UDFCleanUpFile__(Vcb, SDirInfo)) { + if(SDirInfo) MyFreePool__(SDirInfo); + } + SDirInfo = NULL; + try_return(RC); + } + // Acquire SDir exclusively if Fcb present + if(SDirInfo->Fcb) { + BrutePoint(); + UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); + UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE); + } + + // Open Acl Stream + RC = UDFOpenFile__(Vcb, + FALSE,TRUE,&(UDFGlobalData.AclName), + SDirInfo,&AclInfo,NULL); + if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { + RC = UDFCreateFile__(Vcb, FALSE, &(UDFGlobalData.AclName), + 0, 0, FALSE, FALSE, SDirInfo, &AclInfo); + } + if(!NT_SUCCESS(RC)) { + if(UDFCleanUpFile__(Vcb, AclInfo)) { + if(AclInfo) MyFreePool__(AclInfo); + } + AclInfo = NULL; + try_return(RC); + } + + if(!(*SecurityDesc)) { + UDFFlushFile__(Vcb, AclInfo); + RC = UDFUnlinkFile__(Vcb, AclInfo, TRUE); + try_return(RC); + } + NumberBytesRead = RtlLengthSecurityDescriptor(*SecurityDesc); + + RC = UDFWriteFile__(Vcb, AclInfo, 0, NumberBytesRead, + FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead); + if(!NT_SUCCESS(RC)) + try_return(RC); + + Fcb->NTRequiredFCB->NtReqFCBFlags &= ~UDF_NTREQ_FCB_SD_MODIFIED; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(AclInfo) { + UDFCloseFile__(Vcb, AclInfo); + if(UDFCleanUpFile__(Vcb, AclInfo)) + MyFreePool__(AclInfo); + } + + if(SDirInfo) { + UDFCloseFile__(Vcb, SDirInfo); + if(UDFCleanUpFile__(Vcb, SDirInfo)) + MyFreePool__(SDirInfo); + } + if(Res1) + UDFReleaseResource(Res1); + } + + return RC; + +#endif //!defined(DEMO) && !defined(UDF_READ_ONLY_BUILD) +#endif //UDF_ENABLE_SECURITY + + return STATUS_SUCCESS; + +} // end UDFWriteSecurity() + +PSECURITY_DESCRIPTOR +UDFLookUpAcl( + IN PVCB Vcb, + PFILE_OBJECT FileObject, // OPTIONAL + IN PtrUDFFCB Fcb + ) +{ + UDFAssignAcl(Vcb, FileObject, Fcb, Fcb->NTRequiredFCB); + return (Fcb->NTRequiredFCB->SecurityDesc); +} // end UDFLookUpAcl() + + +NTSTATUS +UDFCheckAccessRights( + PFILE_OBJECT FileObject, // OPTIONAL + PACCESS_STATE AccessState, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb, // OPTIONAL + ACCESS_MASK DesiredAccess, + USHORT ShareAccess + ) +{ + NTSTATUS RC; + BOOLEAN SecurityCheck = TRUE; + BOOLEAN ROCheck = FALSE; +#ifdef UDF_ENABLE_SECURITY + PSECURITY_DESCRIPTOR SecDesc; + SECURITY_SUBJECT_CONTEXT SubjectContext; + ACCESS_MASK LocalAccessMask; +#endif //UDF_ENABLE_SECURITY + + // Check attr compatibility + ASSERT(Fcb); + ASSERT(Fcb->Vcb); +#ifdef UDF_READ_ONLY_BUILD + goto treat_as_ro; +#endif //UDF_READ_ONLY_BUILD + +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Fcb->Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + goto treat_as_ro; + } +#endif //EVALUATION_TIME_LIMIT + if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) { + ROCheck = TRUE; + } else + if((Fcb->Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) && + Ccb && !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN) && + (Fcb->Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) { + AdPrint(("force R/O on dirty\n")); + ROCheck = TRUE; + } + if(ROCheck) { +#if defined(EVALUATION_TIME_LIMIT) || defined(UDF_READ_ONLY_BUILD) +treat_as_ro: +#endif //EVALUATION_TIME_LIMIT + ACCESS_MASK DesiredAccessMask = 0; + + if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_WRITE_IN_RO_DIR) { + if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + DesiredAccessMask = (FILE_WRITE_EA | + DELETE); + } else { + DesiredAccessMask = (FILE_WRITE_DATA | + FILE_APPEND_DATA | + FILE_WRITE_EA | + DELETE); + } + } else { + DesiredAccessMask = (FILE_WRITE_DATA | + FILE_APPEND_DATA | + FILE_WRITE_EA | + FILE_DELETE_CHILD | + FILE_ADD_SUBDIRECTORY | + FILE_ADD_FILE | + DELETE); + } + if(DesiredAccess & DesiredAccessMask) + return STATUS_ACCESS_DENIED; + } +#ifdef UDF_ENABLE_SECURITY + // Check Security + // NOTE: we should not perform security check if an empty DesiredAccess + // was specified. AFAIU, SeAccessCheck() will return FALSE in this case. + SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb); + if(SecDesc && DesiredAccess) { + SeCaptureSubjectContext(&SubjectContext); + SecurityCheck = + SeAccessCheck(SecDesc, + &SubjectContext, + FALSE, + DesiredAccess, + Ccb ? Ccb->PreviouslyGrantedAccess : 0, + NULL, + IoGetFileObjectGenericMapping(), + UserMode, + Ccb ? &(Ccb->PreviouslyGrantedAccess) : &LocalAccessMask, + &RC); + SeReleaseSubjectContext(&SubjectContext); + + if(!SecurityCheck) { + return RC; + } else +#endif //UDF_ENABLE_SECURITY + if(DesiredAccess & ACCESS_SYSTEM_SECURITY) { + SecurityCheck = SeSinglePrivilegeCheck(SeExports->SeSecurityPrivilege, UserMode); + if(!SecurityCheck) + return STATUS_ACCESS_DENIED; + Ccb->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY; + } +#ifdef UDF_ENABLE_SECURITY + } +#endif //UDF_ENABLE_SECURITY +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Fcb->Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + if(FileObject) { + if (Fcb->OpenHandleCount) { + // The FCB is currently in use by some thread. + // We must check whether the requested access/share access + // conflicts with the existing open operations. + RC = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject, + &(Fcb->NTRequiredFCB->FCBShareAccess), TRUE); +#ifndef UDF_ENABLE_SECURITY + if(Ccb) + Ccb->PreviouslyGrantedAccess |= DesiredAccess; + IoUpdateShareAccess(FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess)); +#endif //UDF_ENABLE_SECURITY + } else { + IoSetShareAccess(DesiredAccess, ShareAccess, FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess)); +#ifndef UDF_ENABLE_SECURITY + if(Ccb) + Ccb->PreviouslyGrantedAccess = DesiredAccess; +#endif //UDF_ENABLE_SECURITY + RC = STATUS_SUCCESS; + } + } else { + // we get here if given file was opened for internal purposes + RC = STATUS_SUCCESS; + } +#ifdef EVALUATION_TIME_LIMIT + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Fcb->Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } +#endif //EVALUATION_TIME_LIMIT + return RC; +} // end UDFCheckAccessRights() + +NTSTATUS +UDFSetAccessRights( + PFILE_OBJECT FileObject, + PACCESS_STATE AccessState, + PtrUDFFCB Fcb, + PtrUDFCCB Ccb, + ACCESS_MASK DesiredAccess, + USHORT ShareAccess + ) +{ +#ifndef UDF_ENABLE_SECURITY + ASSERT(Ccb); + ASSERT(Fcb->FileInfo); + + return UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess); + +#else //UDF_ENABLE_SECURITY + + NTSTATUS RC; + // Set Security on Object + PSECURITY_DESCRIPTOR SecDesc; + SECURITY_SUBJECT_CONTEXT SubjectContext; + BOOLEAN AutoInherit; + + ASSERT(Ccb); + ASSERT(Fcb->FileInfo); + + SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb); + AutoInherit = UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo); + + if(SecDesc && !AutoInherit) { + // Get caller's User/Primary Group info + SeCaptureSubjectContext(&SubjectContext); + RC = SeAssignSecurity( + Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc, +// NULL, + AccessState->SecurityDescriptor, + &(Fcb->NTRequiredFCB->SecurityDesc), + UDFIsADirectory(Fcb->FileInfo), + &SubjectContext, + IoGetFileObjectGenericMapping(), + NonPagedPool); + SeReleaseSubjectContext(&SubjectContext); + UDFConvertToSelfRelative(&(Fcb->NTRequiredFCB->SecurityDesc)); + + if(!NT_SUCCESS(RC)) { +Clean_Up_SD: + UDFDeassignAcl(Fcb->NTRequiredFCB, AutoInherit); + return RC; + } + } + + RC = UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess); + if(!NT_SUCCESS(RC)) + goto Clean_Up_SD; + return RC; + +#endif //UDF_ENABLE_SECURITY + +} // end UDFSetAccessRights() + diff --git a/reactos/drivers/filesystems/udfs/shutdown.cpp b/reactos/drivers/filesystems/udfs/shutdown.cpp new file mode 100644 index 00000000000..bb6e218afa4 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/shutdown.cpp @@ -0,0 +1,237 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Shutdown.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "shutdown notification" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN + + + +/************************************************************************* +* +* Function: UDFShutdown() +* +* Description: +* All disk-based FSDs can expect to receive this shutdown notification +* request whenever the system is about to be halted gracefully. If you +* design and implement a network redirector, you must register explicitly +* for shutdown notification by invoking the IoRegisterShutdownNotification() +* routine from your driver entry. +* +* Note that drivers that register to receive shutdown notification get +* invoked BEFORE disk-based FSDs are told about the shutdown notification. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFShutdown( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFShutDown\n")); +// BrutePoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + //ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonShutdown(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFShutdown() + + +/************************************************************************* +* +* Function: UDFCommonShutdown() +* +* Description: +* The actual work is performed here. Basically, all we do here is +* internally invoke a flush on all mounted logical volumes. This, in +* tuen, will result in all open file streams being flushed to disk. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS +UDFCommonShutdown( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + PVCB Vcb; + PLIST_ENTRY Link; + PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; + LARGE_INTEGER delay; + + KdPrint(("UDFCommonShutdown\n")); + + _SEH2_TRY { + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + + Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); + if(!Buf) + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + // (a) Block all new "mount volume" requests by acquiring an appropriate + // global resource/lock. + // (b) Go through your linked list of mounted logical volumes and for + // each such volume, do the following: + // (i) acquire the volume resource exclusively + // (ii) invoke UDFFlushLogicalVolume() (internally) to flush the + // open data streams belonging to the volume from the system + // cache + // (iii) Invoke the physical/virtual/logical target device object + // on which the volume is mounted and inform this device + // about the shutdown request (Use IoBuildSynchronouFsdRequest() + // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you + // will then issue to the target device object). + // (iv) Wait for the completion of the shutdown processing by the target + // device object + // (v) Release the VCB resource we will have acquired in (i) above. + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + // Walk through all of the Vcb's attached to the global data. + Link = UDFGlobalData.VCBQueue.Flink; + + while (Link != &(UDFGlobalData.VCBQueue)) { + // Get 'next' Vcb + Vcb = CONTAINING_RECORD( Link, VCB, NextVCB ); + // Move to the next link now since the current Vcb may be deleted. + Link = Link->Flink; + ASSERT(Link != Link->Flink); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) { + +#ifdef UDF_DELAYED_CLOSE + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + KdPrint((" UDFCommonShutdown: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; + UDFReleaseResource(&(Vcb->VCBResource)); +#endif //UDF_DELAYED_CLOSE + + // Note: UDFCloseAllDelayed() doesn't acquire DelayedCloseResource if + // GlobalDataResource is already acquired. Thus for now we should + // release GlobalDataResource and re-acquire it later. + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) { + KdPrint((" UDFCommonShutdown: UDFCloseAllSystemDelayedInDir\n")); + RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + ASSERT(OS_SUCCESS(RC)); + } + +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +// UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); +#endif //UDF_DELAYED_CLOSE + + // re-acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + // disable Eject Waiter + UDFStopEjectWaiter(Vcb); + // Acquire Vcb resource + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + + ASSERT(!Vcb->OverflowQueueCount); + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) { + + UDFDoDismountSequence(Vcb, Buf, FALSE); + if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) { + // let drive flush all data before reset + delay.QuadPart = -10000000; // 1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + } + Vcb->VCBFlags |= (UDF_VCB_FLAGS_SHUTDOWN | + UDF_VCB_FLAGS_VOLUME_READ_ONLY); + } + + UDFReleaseResource(&(Vcb->VCBResource)); + } + } + // Once we have processed all the mounted logical volumes, we can release + // all acquired global resources and leave (in peace :-) + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + RC = STATUS_SUCCESS; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(Buf) MyFreePool__(Buf); + if(!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_END; // end of "__finally" processing + + return(RC); +} // end UDFCommonShutdown() diff --git a/reactos/drivers/filesystems/udfs/struct.h b/reactos/drivers/filesystems/udfs/struct.h new file mode 100644 index 00000000000..0c6a141ba78 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/struct.h @@ -0,0 +1,491 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: struct.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* This file contains structure definitions for the UDF file system +* driver. Note that all structures are prefixed with the letters +* "UDF". The structures are all aligned using normal alignment +* used by the compiler (typically quad-word aligned). +* +*************************************************************************/ + +#ifndef _UDF_STRUCTURES_H_ +#define _UDF_STRUCTURES_H_ + + +/************************************************************************** + some useful definitions +**************************************************************************/ + +#include "..\Include\platform.h" + +/************************************************************************** + some empty typedefs defined here so we can reference them easily +**************************************************************************/ +struct _UDFIdentifier; +struct _UDFObjectName; +struct _UDFContextControlBlock; +struct _UDFNTRequiredFCB; +struct _UDFDiskDependentFCB; +struct _UDFFileControlBlock; +struct _UDFVolumeControlBlock; +struct _UDFIrpContext; +struct _UDFIrpContextLite; +struct _UDF_FILE_INFO; +struct _UDFData; +struct _UDFEjectWaitContext; +struct _UDFFileIDCacheItem; +struct _SparingEntry; +struct _UDFTrackMap; + +/************************************************************************** + include udf related structures *here* (because we need definition of Fcb) +**************************************************************************/ +#include "udf_info\udf_rel.h" + +/************************************************************************** + each structure has a unique "node type" or signature associated with it +**************************************************************************/ +#define UDF_NODE_TYPE_NT_REQ_FCB ((CSHORT)(0xfcb0)) +#define UDF_NODE_TYPE_OBJECT_NAME (0xfdecba01) +#define UDF_NODE_TYPE_CCB (0xfdecba02) +#define UDF_NODE_TYPE_FCB (0xfdecba03) +#define UDF_NODE_TYPE_VCB (0xfdecba04) +#define UDF_NODE_TYPE_IRP_CONTEXT (0xfdecba05) +#define UDF_NODE_TYPE_GLOBAL_DATA (0xfdecba06) +#define UDF_NODE_TYPE_FILTER_DEVOBJ (0xfdecba07) +#define UDF_NODE_TYPE_UDFFS_DEVOBJ (0xfdecba08) +#define UDF_NODE_TYPE_IRP_CONTEXT_LITE (0xfdecba09) +#define UDF_NODE_TYPE_UDFFS_DRVOBJ (0xfdecba0a) + +/************************************************************************** + every structure has a node type, and a node size associated with it. + The node type serves as a signature field. The size is used for + consistency checking ... +**************************************************************************/ +typedef struct _UDFIdentifier { + uint32 NodeType; // a 32 bit identifier for the structure + uint32 NodeSize; // computed as sizeof(structure) +} UDFIdentifier, *PtrUDFIdentifier; + +/************************************************************************** + Every open on-disk object must have a name associated with it + This name has two components: + (a) the path-name (prefix) that leads to this on-disk object + (b) the name of the object itself + Note that with multiply linked objects, a single object might be + associated with more than one name structure. + This UDF FSD does not correctly support multiply linked objects. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _UDFObjectName { + UDFIdentifier NodeIdentifier; + uint32 ObjectNameFlags; + // an absolute pathname of the object is stored below + UNICODE_STRING ObjectName; +} UDFObjectName, *PtrUDFObjectName; + +#define UDF_OBJ_NAME_NOT_FROM_ZONE (0x80000000) + +/************************************************************************** + Each file open instance is represented by a context control block. + For each successful create/open request; a file object and a CCB will + be created. + For open operations performed internally by the FSD, there may not + exist file objects; but a CCB will definitely be created. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _UDFContextControlBlock { + UDFIdentifier NodeIdentifier; + // ptr to the associated FCB + struct _UDFFileControlBlock *Fcb; + // all CCB structures for a FCB are linked together + LIST_ENTRY NextCCB; + // each CCB is associated with a file object + PFILE_OBJECT FileObject; + // flags (see below) associated with this CCB + uint32 CCBFlags; + // current index in directory is required sometimes + ULONG CurrentIndex; + // if this CCB represents a directory object open, we may + // need to maintain a search pattern + PUNICODE_STRING DirectorySearchPattern; + HASH_ENTRY hashes; + ULONG TreeLength; + // Acces rights previously granted to caller's thread + ACCESS_MASK PreviouslyGrantedAccess; +} UDFCCB, *PtrUDFCCB; + + +/************************************************************************** + the following CCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ + +// some on-disk file/directories are opened by UDF itself +// as opposed to being opened on behalf of a user process +#define UDF_CCB_OPENED_BY_UDF (0x00000001) +// the file object specified synchronous access at create/open time. +// this implies that UDF must maintain the current byte offset +#define UDF_CCB_OPENED_FOR_SYNC_ACCESS (0x00000002) +// file object specified sequential access for this file +#define UDF_CCB_OPENED_FOR_SEQ_ACCESS (0x00000004) +// the CCB has had an IRP_MJ_CLEANUP issued on it. we must +// no longer allow the file object / CCB to be used in I/O requests. +#define UDF_CCB_CLEANED (0x00000008) +// if we were invoked via the fast i/o path to perform file i/o; +// we should set the CCB access/modification time at cleanup +#define UDF_CCB_ACCESSED (0x00000010) +#define UDF_CCB_MODIFIED (0x00000020) +// if an application process set the file date time, we must +// honor that request and *not* overwrite the values at cleanup +#define UDF_CCB_ACCESS_TIME_SET (0x00000040) +#define UDF_CCB_MODIFY_TIME_SET (0x00000080) +#define UDF_CCB_CREATE_TIME_SET (0x00000100) +#define UDF_CCB_WRITE_TIME_SET (0x00000200) +#define UDF_CCB_ATTRIBUTES_SET (0x00020000) + +#define UDF_CCB_CASE_SENSETIVE (0x00000400) + +#ifndef UDF_READ_ONLY_BUILD +#define UDF_CCB_DELETE_ON_CLOSE (0x00000800) +#endif //UDF_READ_ONLY_BUILD + +// this CCB was allocated for a "volume open" operation +#define UDF_CCB_VOLUME_OPEN (0x00001000) +#define UDF_CCB_MATCH_ALL (0x00002000) +#define UDF_CCB_WILDCARD_PRESENT (0x00004000) +#define UDF_CCB_CAN_BE_8_DOT_3 (0x00008000) +#define UDF_CCB_READ_ONLY (0x00010000) +//#define UDF_CCB_ATTRIBUTES_SET (0x00020000) // see above + +#define UDF_CCB_FLUSHED (0x20000000) +#define UDF_CCB_VALID (0x40000000) +#define UDF_CCB_NOT_FROM_ZONE (0x80000000) + + +/************************************************************************** + each open file/directory/volume is represented by a file control block. + + Each FCB can logically be divided into two: + (a) a structure that must have a field of type FSRTL_COMMON_FCB_HEADER + as the first field in the structure. + This portion should also contain other structures/resources required + by the NT Cache Manager + We will call this structure the "NT Required" FCB. Note that this + portion of the FCB must be allocated from non-paged pool. + (b) the remainder of the FCB is dependent upon the particular FSD + requirements. + This portion of the FCB could possibly be allocated from paged + memory, though in the UDF FSD, it will always be allocated + from non-paged pool. + + FCB structures are protected by the MainResource as well as the + PagingIoResource. Of course, if the FSD implementation requires + it, we can associate other syncronization structures with the + FCB. + + These structures must be quad-word aligned because they are zone-allocated. +**************************************************************************/ + +typedef struct _UDFNTRequiredFCB { + + FSRTL_COMMON_FCB_HEADER CommonFCBHeader; + SECTION_OBJECT_POINTERS SectionObject; + FILE_LOCK FileLock; + ERESOURCE MainResource; + ERESOURCE PagingIoResource; + // we will maintain some time information here to make our life easier + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + // NT requires that a file system maintain and honor the various + // SHARE_ACCESS modes ... + SHARE_ACCESS FCBShareAccess; + // This counter is used to prevent unexpected structure releases + ULONG CommonRefCount; + PSECURITY_DESCRIPTOR SecurityDesc; + ULONG NtReqFCBFlags; + // to identify the lazy writer thread(s) we will grab and store + // the thread id here when a request to acquire resource(s) + // arrives .. + uint32 LazyWriterThreadID; + UCHAR AcqSectionCount; + UCHAR AcqFlushCount; +#ifdef DBG + PFILE_OBJECT FileObject; +#endif //DBG + PETHREAD CloseThread; +} UDFNTRequiredFCB, *PtrUDFNTRequiredFCB; + +#define UDF_NTREQ_FCB_SD_MODIFIED (0x00000001) +#define UDF_NTREQ_FCB_INLIST (0x00000002) +#define UDF_NTREQ_FCB_DELETED (0x00000004) +#define UDF_NTREQ_FCB_MODIFIED (0x00000008) +#define UDF_NTREQ_FCB_VALID (0x40000000) + +/**************************************************************************/ + +#define UDF_FCB_MT NonPagedPool + +/***************************************************/ +/***************** W A R N I N G *****************/ +/***************************************************/ + +/***************************************************/ +/* DO NOT FORGET TO UPDATE VCB's HEADER ! */ +/***************************************************/ + +typedef struct _UDFFileControlBlock { + UDFIdentifier NodeIdentifier; + // we will not embed the "NT Required FCB" here, 'cause we dislike + // troubles with Hard(&Symbolic) Links + PtrUDFNTRequiredFCB NTRequiredFCB; + // UDF related data + PUDF_FILE_INFO FileInfo; + // this FCB belongs to some mounted logical volume + struct _UDFVolumeControlBlock* Vcb; + // to be able to access all open file(s) for a volume, we will + // link all FCB structures for a logical volume together + LIST_ENTRY NextFCB; + // some state information for the FCB is maintained using the + // flags field + uint32 FCBFlags; + // all CCB's for this particular FCB are linked off the following + // list head. + LIST_ENTRY NextCCB; + // whenever a file stream has a create/open operation performed, + // the Reference count below is incremented AND the OpenHandle count + // below is also incremented. + // When an IRP_MJ_CLEANUP is received, the OpenHandle count below + // is decremented. + // When an IRP_MJ_CLOSE is received, the Reference count below is + // decremented. + // When the Reference count goes down to zero, the FCB can be de-allocated. + // Note that a zero Reference count implies a zero OpenHandle count. + // But when we have mapped data, we can receive no IRP_MJ_CLOSE + // In this case OpenHandleCount may reach zero, but ReferenceCount may + // be non-zero. + uint32 ReferenceCount; + uint32 OpenHandleCount; + uint32 CachedOpenHandleCount; + // for the UDF fsd, there exists a 1-1 correspondence between a + // full object pathname and a FCB + PtrUDFObjectName FCBName; + ERESOURCE CcbListResource; + + struct _UDFFileControlBlock* ParentFcb; + // Pointer to IrpContextLite in delayed queue. + struct _UDFIrpContextLite* IrpContextLite; + uint32 CcbCount; +} UDFFCB, *PtrUDFFCB; + +/************************************************************************** + the following FCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ +#define UDF_FCB_VALID (0x00000002) + +#define UDF_FCB_PAGE_FILE (0x00000004) +#define UDF_FCB_DIRECTORY (0x00000008) +#define UDF_FCB_ROOT_DIRECTORY (0x00000010) +#define UDF_FCB_WRITE_THROUGH (0x00000020) +#define UDF_FCB_MAPPED (0x00000040) +#define UDF_FCB_FAST_IO_READ_IN_PROGESS (0x00000080) +#define UDF_FCB_FAST_IO_WRITE_IN_PROGESS (0x00000100) +#define UDF_FCB_DELETE_ON_CLOSE (0x00000200) +#define UDF_FCB_MODIFIED (0x00000400) +#define UDF_FCB_ACCESSED (0x00000800) +#define UDF_FCB_READ_ONLY (0x00001000) +#define UDF_FCB_DELAY_CLOSE (0x00002000) +#define UDF_FCB_DELETED (0x00004000) + +#define UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE (0x00008000) +#define UDF_FCB_POSTED_RENAME (0x00010000) + +#define UDF_FCB_DELETE_PARENT (0x10000000) +#define UDF_FCB_NOT_FROM_ZONE (0x80000000) + +/************************************************************************** + A logical volume is represented with the following structure. + This structure is allocated as part of the device extension + for a device object that this FSD will create, to represent + the mounted logical volume. + +**************************************************************************/ + +#define _BROWSE_UDF_ + +// Common UDF-related definitions +#include "..\Include\udf_common.h" + +// One for root +#define UDF_RESIDUAL_REFERENCE (2) + +// input flush flags +#define UDF_FLUSH_FLAGS_BREAKABLE (0x00000001) +// see also udf_rel.h +#define UDF_FLUSH_FLAGS_LITE (0x80000000) +// output flush flags +#define UDF_FLUSH_FLAGS_INTERRUPTED (0x00000001) + +#define UDF_MAX_BG_WRITERS 16 + +typedef struct _FILTER_DEV_EXTENSION { + UDFIdentifier NodeIdentifier; + PFILE_OBJECT fileObject; + PDEVICE_OBJECT lowerFSDeviceObject; +} FILTER_DEV_EXTENSION, *PFILTER_DEV_EXTENSION; + +typedef struct _UDFFS_DEV_EXTENSION { + UDFIdentifier NodeIdentifier; +} UDFFS_DEV_EXTENSION, *PUDFFS_DEV_EXTENSION; +/************************************************************************** + The IRP context encapsulates the current request. This structure is + used in the "common" dispatch routines invoked either directly in + the context of the original requestor, or indirectly in the context + of a system worker thread. +**************************************************************************/ +typedef struct _UDFIrpContext { + UDFIdentifier NodeIdentifier; + uint32 IrpContextFlags; + // copied from the IRP + uint8 MajorFunction; + // copied from the IRP + uint8 MinorFunction; + // to queue this IRP for asynchronous processing + WORK_QUEUE_ITEM WorkQueueItem; + // the IRP for which this context structure was created + PIRP Irp; + // the target of the request (obtained from the IRP) + PDEVICE_OBJECT TargetDeviceObject; + // if an exception occurs, we will store the code here + NTSTATUS SavedExceptionCode; + // For queued close operation we save Fcb + _UDFFileControlBlock *Fcb; + ULONG TreeLength; + PMDL PtrMdl; + PCHAR TransitionBuffer; + // support for delayed close +} UDFIrpContext, *PtrUDFIrpContext; + +#define UDF_IRP_CONTEXT_CAN_BLOCK (0x00000001) +#define UDF_IRP_CONTEXT_WRITE_THROUGH (0x00000002) +#define UDF_IRP_CONTEXT_EXCEPTION (0x00000004) +#define UDF_IRP_CONTEXT_DEFERRED_WRITE (0x00000008) +#define UDF_IRP_CONTEXT_ASYNC_PROCESSING (0x00000010) +#define UDF_IRP_CONTEXT_NOT_TOP_LEVEL (0x00000020) +#define UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS (0x00000040) +#define UDF_IRP_CONTEXT_FLUSH_REQUIRED (0x00000080) +#define UDF_IRP_CONTEXT_FLUSH2_REQUIRED (0x00000100) +#define UDF_IRP_CONTEXT_READ_ONLY (0x00010000) +#define UDF_IRP_CONTEXT_RES1_ACQ (0x01000000) +#define UDF_IRP_CONTEXT_RES2_ACQ (0x02000000) +#define UDF_IRP_CONTEXT_FORCED_POST (0x20000000) +#define UDF_IRP_CONTEXT_BUFFER_LOCKED (0x40000000) +#define UDF_IRP_CONTEXT_NOT_FROM_ZONE (0x80000000) + +/************************************************************************** + Following structure is used to queue a request to the delayed close queue. + This structure should be the minimum block allocation size. +**************************************************************************/ +typedef struct _UDFIrpContextLite { + UDFIdentifier NodeIdentifier; + // Fcb for the file object being closed. + _UDFFileControlBlock *Fcb; + // List entry to attach to delayed close queue. + LIST_ENTRY DelayedCloseLinks; + // User reference count for the file object being closed. + //ULONG UserReference; + // Real device object. This represents the physical device closest to the media. + PDEVICE_OBJECT RealDevice; + ULONG TreeLength; + uint32 IrpContextFlags; +} UDFIrpContextLite, *PtrUDFIrpContextLite; + + + + +// a default size of the number of pages of non-paged pool allocated +// for each of the zones ... + +// Note that the values are absolutely arbitrary, the only information +// worth using from the values themselves is that they increase for +// larger systems (i.e. systems with more memory) +#define UDF_DEFAULT_ZONE_SIZE_SMALL_SYSTEM (0x4) +#define UDF_DEFAULT_ZONE_SIZE_MEDIUM_SYSTEM (0x8) +#define UDF_DEFAULT_ZONE_SIZE_LARGE_SYSTEM (0xc) + +// another simplistic (brain dead ? :-) method used is to simply double +// the values for a "server" machine + +// So, for all you guys who "modified" the registry ;-) to change the +// wkstation into a server, tough luck ! +#define UDF_NTAS_MULTIPLE (0x2) + +typedef struct _UDFEjectWaitContext { + PVCB Vcb; + + BOOLEAN SoftEjectReq; + UCHAR Padding0[3]; + + KEVENT StopReq; + PKEVENT WaiterStopped; + WORK_QUEUE_ITEM EjectReqWorkQueueItem; + + GET_EVENT_USER_OUT EjectReqBuffer; + UCHAR PaddingEvt[(0x40 - sizeof(GET_EVENT_USER_OUT)) & 0x0f]; + + GET_CAPABILITIES_USER_OUT DevCap; + UCHAR PaddingDevCap[(0x40 - sizeof(GET_CAPABILITIES_USER_OUT)) & 0x0f]; + + GET_LAST_ERROR_USER_OUT Error; + UCHAR PaddingError[(0x40 - sizeof(GET_LAST_ERROR_USER_OUT)) & 0x0f]; + + ULONG Zero; +} UDFEjectWaitContext, *PUDFEjectWaitContext; + +typedef struct _UDFBGWriteContext { + PVCB Vcb; + PVOID Buffer; // Target buffer + ULONG Length; + ULONG Lba; + ULONG WrittenBytes; + BOOLEAN FreeBuffer; + WORK_QUEUE_ITEM WorkQueueItem; +} UDFBGWriteContext, *PUDFBGWriteContext; + +// Define the file system statistics struct. Vcb->Statistics points to an +// array of these (one per processor) and they must be 64 byte aligned to +// prevent cache line tearing. +typedef struct _FILE_SYSTEM_STATISTICS { + // This contains the actual data. + FILESYSTEM_STATISTICS Common; + FAT_STATISTICS Fat; + // Pad this structure to a multiple of 64 bytes. + UCHAR Pad[64-(sizeof(FILESYSTEM_STATISTICS)+sizeof(FAT_STATISTICS))%64]; +} FILE_SYSTEM_STATISTICS, *PFILE_SYSTEM_STATISTICS; + +// +typedef struct _UDFFileIDCacheItem { + LONGLONG Id; + UNICODE_STRING FullName; + BOOLEAN CaseSens; +} UDFFileIDCacheItem, *PUDFFileIDCacheItem; + +#define DIRTY_PAGE_LIMIT 32 + +#endif /* _UDF_STRUCTURES_H_ */ // has this file been included? + diff --git a/reactos/drivers/filesystems/udfs/sys_spec.cpp b/reactos/drivers/filesystems/udfs/sys_spec.cpp new file mode 100644 index 00000000000..5db8312a0f8 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/sys_spec.cpp @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Sys_Spec.cpp +* +* Module: UDF File System Driver +* (both User and Kernel mode execution) +* +* Description: +* Contains system-secific code +* +*************************************************************************/ + + +#include "udffs.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_SYS_SPEC + +#include "..\Include\Sys_spec_lib.cpp" + +//#include "..\Include\tools.cpp" diff --git a/reactos/drivers/filesystems/udfs/sys_spec.h b/reactos/drivers/filesystems/udfs/sys_spec.h new file mode 100644 index 00000000000..73dce0873e1 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/sys_spec.h @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: sys_spec.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the UDF file system driver. +* +* Author: Alter +* +*************************************************************************/ + + +#ifndef _UDF_SYS_SPEC_H_ +#define _UDF_SYS_SPEC_H_ + +#include "..\Include\Sys_spec_lib.h" + +#endif // _UDF_SYS_SPEC_H_ diff --git a/reactos/drivers/filesystems/udfs/udf_dbg.cpp b/reactos/drivers/filesystems/udfs/udf_dbg.cpp new file mode 100644 index 00000000000..fd1a6dad516 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_dbg.cpp @@ -0,0 +1,526 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udffs.h" +#if defined(UDF_DBG) || defined(PRINT_ALWAYS) + +//#define TRACK_RESOURCES +//#define TRACK_REF_COUNTERS + +ULONG ResCounter = 0; +ULONG AcqCounter = 0; +ULONG UdfTimeStamp = -1; + +BOOLEAN +UDFDebugAcquireResourceSharedLite( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line +) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + + BOOLEAN Success; + +#ifdef USE_DLD + + if (Wait) { + DLDAcquireShared(Resource, BugCheckId, Line,FALSE); + Success = TRUE; + } else { + Success = ExAcquireResourceSharedLite(Resource,Wait); + } + +#else + + Success = ExAcquireResourceSharedLite(Resource,Wait); + +#endif // USE_DLD + + if(Success) { +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + AcqCounter++; + return Success; + } +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + return FALSE; +} + +BOOLEAN +UDFDebugAcquireSharedStarveExclusive( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line +) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + + BOOLEAN Success; + +#ifdef USE_DLD + + if (Wait) { + DLDAcquireShared(Resource, BugCheckId, Line,FALSE); + Success = TRUE; + } else { + Success = ExAcquireResourceSharedLite(Resource,Wait); + } + +#else + + Success = ExAcquireResourceSharedLite(Resource,Wait); + +#endif // USE_DLD + + if(Success) { +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + AcqCounter++; + return Success; + } +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + return FALSE; +} + +BOOLEAN +UDFDebugAcquireResourceExclusiveLite( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line +) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Exc:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + + + BOOLEAN Success; + +#ifdef USE_DLD + + if (Wait) { + DLDAcquireExclusive(Resource, BugCheckId, Line); + Success = TRUE; + } else { + Success = ExAcquireResourceExclusiveLite(Resource,Wait); + } + +#else + + Success = ExAcquireResourceExclusiveLite(Resource,Wait); + +#endif // USE_DLD + + + + if(Success) { +#ifdef TRACK_RESOURCES + KdPrint(("Res:Exc:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + AcqCounter++; + return Success; + } +#ifdef TRACK_RESOURCES + KdPrint(("Res:Exc:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif +// BrutePoint(); + return FALSE; + +} + +VOID +UDFDebugReleaseResourceForThreadLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line + ) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Free:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + ExReleaseResourceForThreadLite(Resource, ResourceThreadId); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Free:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + AcqCounter--; +} + +VOID +UDFDebugDeleteResource( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line + ) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Del:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + _SEH2_TRY { + ASSERT((*((PULONG)Resource))); + ASSERT((*(((PULONG)Resource)+1))); + ExDeleteResourceLite(Resource); + RtlZeroMemory(Resource, sizeof(ERESOURCE)); + } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +#ifdef TRACK_RESOURCES + KdPrint(("Res:Del:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + ResCounter--; +} + +NTSTATUS +UDFDebugInitializeResourceLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line + ) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + NTSTATUS RC; +#ifdef TRACK_RESOURCES + KdPrint(("Res:Ini:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + ASSERT(!(*((PULONG)Resource))); + ASSERT(!(*(((PULONG)Resource)+1))); + RC = ExInitializeResourceLite(Resource); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Ini:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + if(NT_SUCCESS(RC)) { + ResCounter++; + } + return RC; +} + +VOID +UDFDebugConvertExclusiveToSharedLite( + IN PERESOURCE Resource, + IN ERESOURCE_THREAD ResourceThreadId, + ULONG BugCheckId, + ULONG Line + ) +{ + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:2Sha:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif + ExConvertExclusiveToSharedLite(Resource); +#ifdef TRACK_RESOURCES + KdPrint(("Res:2Sha:Ok:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,ResourceThreadId)); +#endif +} + +BOOLEAN +UDFDebugAcquireSharedWaitForExclusive( + IN PERESOURCE Resource, + IN BOOLEAN Wait, + ULONG BugCheckId, + ULONG Line +) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:Try:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + + BOOLEAN Success; + +#ifdef USE_DLD + + if (Wait) { + DLDAcquireShared(Resource, BugCheckId, Line,TRUE); + Success = TRUE; + } else { + Success = ExAcquireSharedWaitForExclusive(Resource,Wait); + } + +#else + + Success = ExAcquireSharedWaitForExclusive(Resource,Wait); + +#endif // USE_DLD + + + if(Success) { +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:OK:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif + return Success; + } +#ifdef TRACK_RESOURCES + KdPrint(("Res:Sha*:Fail:Resource:%x:BugCheckId:%x:Line:%d:ThId:%x\n",Resource, + BugCheckId,Line,PsGetCurrentThread())); +#endif +// BrutePoint(); + return FALSE; + +} + + +LONG +UDFDebugInterlockedIncrement( + IN PLONG addr, + ULONG BugCheckId, + ULONG Line) +{ +#ifdef TRACK_REF_COUNTERS + LONG a; + a = InterlockedIncrement(addr); + KdPrint(("ThId:%x:Ilck:Inc:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n", + PsGetCurrentThread(),BugCheckId,Line,addr,a-1,a)); + return a; +#else + return InterlockedIncrement(addr); +#endif +} + +LONG +UDFDebugInterlockedDecrement( + IN PLONG addr, + ULONG BugCheckId, + ULONG Line) +{ +#ifdef TRACK_REF_COUNTERS + LONG a; + a = InterlockedDecrement(addr); + KdPrint(("ThId:%x:Ilck:Dec:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n", + PsGetCurrentThread(),BugCheckId,Line,addr,a+1,a)); + return a; +#else + return InterlockedDecrement(addr); +#endif +} + +LONG +UDFDebugInterlockedExchangeAdd( + IN PLONG addr, + IN LONG i, + ULONG BugCheckId, + ULONG Line) +{ +#ifdef TRACK_REF_COUNTERS + LONG a; + a = InterlockedExchangeAdd(addr,i); + KdPrint(("ThId:%x:Ilck:Add:FileId:%x:Line:%d:Ref:%x:Val:%x:%x\n", + PsGetCurrentThread(),BugCheckId,Line,addr,a,a+i)); + return a; +#else + return InterlockedExchangeAdd(addr,i); +#endif +} + +#define MAX_MEM_DEBUG_DESCRIPTORS 8192 + +typedef struct _MEM_DESC { + ULONG Length; + PCHAR Addr; +#ifdef TRACK_SYS_ALLOC_CALLERS + ULONG SrcId; + ULONG SrcLine; +#endif //TRACK_SYS_ALLOC_CALLERS + POOL_TYPE Type; +} MEM_DESC, *PMEM_DESC; + + +MEM_DESC MemDesc[MAX_MEM_DEBUG_DESCRIPTORS]; +ULONG cur_max = 0; +ULONG AllocCountPaged = 0; +ULONG AllocCountNPaged = 0; +ULONG MemDescInited = 0; + +PVOID +DebugAllocatePool( + POOL_TYPE Type, + ULONG size +#ifdef TRACK_SYS_ALLOC_CALLERS + , ULONG SrcId, + ULONG SrcLine +#endif //TRACK_SYS_ALLOC_CALLERS +) { + ULONG i; +// KdPrint(("SysAllocated: %x\n",AllocCount)); + if(!MemDescInited) { + RtlZeroMemory(&MemDesc, sizeof(MemDesc)); + MemDescInited = 1; + } + for (i=0;iQuadPart)) LocalTimeout = *Timeout; + else LocalTimeout.QuadPart = 0x7FFFFFFFFFFFFFFFLL; + + KdPrint(("SignalState %x\n", *Object)); + if(!Object) return STATUS_INVALID_PARAMETER; + if((*Object)) return STATUS_SUCCESS; + while(LocalTimeout.QuadPart>0 && !(*Object) ) { + KdPrint(("SignalState %x\n", *Object)); + // Stall for a while. + KeDelayExecutionThread(KernelMode, FALSE, &delay); + LocalTimeout.QuadPart -= WAIT_FOR_XXX_EMU_DELAY; + } + return STATUS_SUCCESS; +} // end UDFWaitForSingleObject() + +NTSTATUS +DbgWaitForSingleObject_( + IN PVOID Object, + IN PLARGE_INTEGER Timeout OPTIONAL + ) +{ + PLARGE_INTEGER to; + LARGE_INTEGER dto; + LARGE_INTEGER cto; + NTSTATUS RC; + ULONG c = 20; + + dto.QuadPart = -5LL*1000000LL*10LL; // 5 sec + cto.QuadPart = Timeout->QuadPart; + if(Timeout) { + if(dto.QuadPart > Timeout->QuadPart) { + to = Timeout; + } else { + to = &dto; + } + } else { + to = &dto; + } + + for(; c--; c) { + RC = KeWaitForSingleObject(Object, Executive, KernelMode, FALSE, to); + if(RC == STATUS_SUCCESS) + break; + KdPrint(("No response ?\n")); + if(c<2) + BrutePoint(); + } + return RC; +} +#endif // UDF_DBG diff --git a/reactos/drivers/filesystems/udfs/udf_dbg.h b/reactos/drivers/filesystems/udfs/udf_dbg.h new file mode 100644 index 00000000000..707bd89870d --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_dbg.h @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + Udf_dbg.h + + Abstract: + + This file contains small set of debug macroses. + It is used by the UDF project. + +*/ + +#ifndef _UDF_DEBUG_H_ +#define _UDF_DEBUG_H_ + +//====================================== + +//#define ALWAYS_CHECK_WAIT_TIMEOUT +//#define PRINT_ALWAYS + +#ifdef UDF_DBG + +//#define CHECK_ALLOC_FRAMES + +//#define TRACK_SYS_ALLOCS +//#define TRACK_SYS_ALLOC_CALLERS + +// Use internal deadlock detector +//#define USE_DLD + +#endif //UDF_DBG + +#define PROTECTED_MEM_RTL + +//#define UDF_SIMULATE_WRITES + +#define USE_PERF_PRINT + +#define USE_KD_PRINT +#define USE_MM_PRINT +#define USE_AD_PRINT +#define UDF_DUMP_EXTENT +//#define USE_TH_PRINT +//#define USE_TIME_PRINT +//#define CHECK_REF_COUNTS + +//====================================== + +#if defined UDF_DBG || defined PRINT_ALWAYS + + ULONG + _cdecl + DbgPrint( + PCH Format, + ... + ); + + + #ifdef KdPrint + #undef KdPrint + #endif + + #ifdef USE_KD_PRINT + #define KdPrint(_x_) DbgPrint _x_ + #else + #define KdPrint(a) {NOTHING;} + #endif //USE_KD_PRINT + + #ifdef USE_MM_PRINT + #define MmPrint(_x_) DbgPrint _x_ + #else + #define MmPrint(_x_) {NOTHING;} + #endif //USE_MM_PRINT + + #ifdef USE_TIME_PRINT + extern ULONG UdfTimeStamp; + #define TmPrint(_x_) {UdfTimeStamp++;KdPrint(("TM:%d: ",UdfTimeStamp));KdPrint(_x_);} + #else + #define TmPrint KdPrint + #endif //USE_MM_PRINT + + #ifdef USE_PERF_PRINT + #define PerfPrint(_x_) DbgPrint _x_ + #else + #define PerfPrint(_x_) {NOTHING;} + #endif //USE_MM_PRINT + + #ifdef USE_AD_PRINT + #define AdPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} + #else + #define AdPrint(_x_) {NOTHING;} + #endif + + #ifdef USE_TH_PRINT + #define ThPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} + #else + #define ThPrint(_x_) {NOTHING;} + #endif + + #ifdef UDF_DUMP_EXTENT + #define ExtPrint(_x_) KdPrint(_x_) + #else + #define ExtPrint(_x_) {NOTHING;} + #endif + +#else // defined UDF_DBG || defined PRINT_ALWAYS + + #define MmPrint(_x_) {NOTHING;} + #define TmPrint(_x_) {NOTHING;} + #define PerfPrint(_x_) {NOTHING;} + #define AdPrint(_x_) {NOTHING;} + #define ThPrint(_x_) {NOTHING;} + #define ExtPrint(_x_) {NOTHING;} + +#endif // defined UDF_DBG || defined PRINT_ALWAYS + +NTSTATUS +DbgWaitForSingleObject_( + IN PVOID Object, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + +#if defined ALWAYS_CHECK_WAIT_TIMEOUT + #define DbgWaitForSingleObject(o, to) DbgWaitForSingleObject_(o, to) +#else + #define DbgWaitForSingleObject(o, to) KeWaitForSingleObject(o, Executive, KernelMode, FALSE, to); +#endif + +#ifdef UDF_DBG + +#ifdef _X86_ +// This is an illegal use of INT3 +#define UDFBreakPoint() { __asm int 3 } +#else // _X86_ + +#define UDFBreakPoint() DbgBreakPoint() +#endif // _X86_ + +#ifdef BRUTE +#define BrutePoint() UDFBreakPoint() +#else +#define BrutePoint() {} +#endif // BRUTE + +#ifdef CHECK_REF_COUNTS +#define ASSERT_REF(_a_) ASSERT(_a_) +#else +#define ASSERT_REF(_a_) {NOTHING;} +#endif //CHECK_REF_COUNTS + +#ifdef TRACK_SYS_ALLOCS + +PVOID DebugAllocatePool(POOL_TYPE Type,ULONG size +#ifdef TRACK_SYS_ALLOC_CALLERS +, ULONG SrcId, ULONG SrcLine +#endif //TRACK_SYS_ALLOC_CALLERS +); +VOID DebugFreePool(PVOID addr); + +#ifdef TRACK_SYS_ALLOC_CALLERS + #define DbgAllocatePoolWithTag(a,b,c) DebugAllocatePool(a,b,UDF_BUG_CHECK_ID,__LINE__) + #define DbgAllocatePool(x,y) DebugAllocatePool(x,y,UDF_BUG_CHECK_ID,__LINE__) +#else //TRACK_SYS_ALLOC_CALLERS + #define DbgAllocatePoolWithTag(a,b,c) DebugAllocatePool(a,b) + #define DbgAllocatePool(x,y) DebugAllocatePool(x,y) +#endif //TRACK_SYS_ALLOC_CALLERS +#define DbgFreePool(x) DebugFreePool(x) + +#else //TRACK_SYS_ALLOCS + +#define DbgAllocatePoolWithTag(a,b,c) ExAllocatePoolWithTag(a,b,c) +#define DbgAllocatePool(x,y) ExAllocatePoolWithTag(x,y,'Fnwd') +#define DbgFreePool(x) ExFreePool(x) + +#endif //TRACK_SYS_ALLOCS + + +#ifdef PROTECTED_MEM_RTL + +#define DbgMoveMemory(d, s, l) \ +_SEH2_TRY { \ + RtlMoveMemory(d, s, l); \ +} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { \ + BrutePoint(); \ +} _SEH2_END; + +#define DbgCopyMemory(d, s, l) \ +_SEH2_TRY { \ + RtlCopyMemory(d, s, l); \ +} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { \ + BrutePoint(); \ +} _SEH2_END; + +__inline +ULONG +DbgCompareMemory(PVOID d, PVOID s, ULONG l) { + _SEH2_TRY { + return RtlCompareMemory(d, s, l); + } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + return -1; +} + +#else //PROTECTED_MEM_RTL + +#define DbgMoveMemory(d, s, l) RtlMoveMemory(d, s, l) +#define DbgCopyMemory(d, s, l) RtlCopyMemory(d, s, l) +#define DbgCompareMemory(d, s, l) RtlCompareMemory(d, s, l) + +#endif //PROTECTED_MEM_RTL + +//#define KdPrint(_x_) + +#ifdef VALIDATE_STRUCTURES +#define ValidateFileInfo(fi) \ +{ /* validate FileInfo */ \ + if(!fi || (fi)->IntegrityTag) { \ + KdPrint(("UDF: ERROR! Using deallocated structure !!!\n"));\ + BrutePoint(); \ + } \ + if(fi && !fi->Dloc) { \ + KdPrint(("UDF: ERROR! FI without Dloc !!!\n"));\ + BrutePoint(); \ + } \ +} + +#else +#define ValidateFileInfo(fi) {} +#endif + +//#ifdef _X86_ +#ifdef _MSC_VER + +__inline VOID UDFTouch(IN PVOID addr) +{ + __asm { + mov eax,addr + mov al,[byte ptr eax] + } +} + +#else // NO X86 optimization , use generic C/C++ + +__inline VOID UDFTouch(IN PVOID addr) +{ + UCHAR a = ((PUCHAR)addr)[0]; + a = a; +} + +#endif // _X86_ + +#else // UDF_DBG + +#define DbgAllocatePool(x,y) ExAllocatePoolWithTag(x,y,'Fnwd') +#define DbgFreePool(x) ExFreePool(x) +#define DbgAllocatePoolWithTag(a,b,c) ExAllocatePoolWithTag(a,b,c) + +#define DbgMoveMemory(d, s, l) RtlMoveMemory(d, s, l) +#define DbgCopyMemory(d, s, l) RtlCopyMemory(d, s, l) +#define DbgCompareMemory(d, s, l) RtlCompareMemory(d, s, l) + +#define ASSERT_REF(_a_) {NOTHING;} + +#define UDFBreakPoint() {} +#define BrutePoint() {} +#define ValidateFileInfo(fi) {} + +#define UDFTouch(addr) {} + +#endif // UDF_DBG + +#if defined UDF_DBG || defined PRINT_ALWAYS + +#define KdDump(a,b) \ +if((a)!=NULL) { \ + ULONG i; \ + for(i=0; i<(b); i++) { \ + ULONG c; \ + c = (ULONG)(*(((PUCHAR)(a))+i)); \ + KdPrint(("%2.2x ",c)); \ + if ((i & 0x0f) == 0x0f) KdPrint(("\n")); \ + } \ + KdPrint(("\n")); \ +} + +#else + +#define KdDump(a,b) {} + +#endif // UDF_DBG + +#define UserPrint KdPrint + +#endif // _UDF_DEBUG_H_ diff --git a/reactos/drivers/filesystems/udfs/udf_info/alloc.cpp b/reactos/drivers/filesystems/udfs/udf_info/alloc.cpp new file mode 100644 index 00000000000..6edadf0b283 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/alloc.cpp @@ -0,0 +1,1448 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + alloc.cpp + + Abstract: + + This file contains filesystem-specific routines + responsible for disk space management + +*/ + +#include "udf.h" + +#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_ALLOC + +static const int8 bit_count_tab[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; + +/* + This routine converts physical address to logical in specified partition + */ +uint32 +UDFPhysLbaToPart( + IN PVCB Vcb, + IN uint32 PartNum, + IN uint32 Addr + ) +{ + PUDFPartMap pm = Vcb->Partitions; +//#ifdef _X86_ +#ifdef _MSC_VER + uint32 retval; + __asm { + push ebx + push ecx + push edx + + mov ebx,Vcb + mov edx,[ebx]Vcb.PartitionMaps + mov ebx,pm + mov ecx,PartNum + xor eax,eax +loop_pl2p: + cmp ecx,edx + jae short EO_pl2p + cmp [ebx]pm.PartitionNum,cx + jne short cont_pl2p + mov eax,Addr + sub eax,[ebx]pm.PartitionRoot + mov ecx,Vcb + mov ecx,[ecx]Vcb.LB2B_Bits + shr eax,cl + jmp short EO_pl2p +cont_pl2p: + add ebx,size UDFPartMap + inc ecx + jmp short loop_pl2p +EO_pl2p: + mov retval,eax + + pop edx + pop ecx + pop ebx + } +#ifdef UDF_DBG + { + // validate return value + lb_addr locAddr; + locAddr.logicalBlockNum = retval; + locAddr.partitionReferenceNum = (uint16)PartNum; + UDFPartLbaToPhys(Vcb, &locAddr); + } +#endif // UDF_DBG + return retval; +#else // NO X86 optimization , use generic C/C++ + uint32 i; + // walk through partition maps to find suitable one... + for(i=PartNum; iPartitionMaps; i++, pm++) { + if(pm->PartitionNum == PartNum) + // wow! return relative address + return (Addr - pm->PartitionRoot) >> Vcb->LB2B_Bits; + } + return 0; +#endif // _X86_ +} // end UDFPhysLbaToPart() + +/* + This routine returns physycal Lba for partition-relative addr + */ +uint32 +__fastcall +UDFPartLbaToPhys( + IN PVCB Vcb, + IN lb_addr* Addr + ) +{ + uint32 i, a; + if(Addr->partitionReferenceNum >= Vcb->PartitionMaps) { + AdPrint(("UDFPartLbaToPhys: part %x, lbn %x (err)\n", + Addr->partitionReferenceNum, Addr->logicalBlockNum)); + if(Vcb->PartitionMaps && + (Vcb->CompatFlags & UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS)) { + AdPrint(("UDFPartLbaToPhys: try to recover: part %x -> %x\n", + Addr->partitionReferenceNum, Vcb->PartitionMaps-1)); + Addr->partitionReferenceNum = (USHORT)(Vcb->PartitionMaps-1); + } else { + return LBA_OUT_OF_EXTENT; + } + } + // walk through partition maps & transform relative address + // to physical + for(i=Addr->partitionReferenceNum; iPartitionMaps; i++) { + if(Vcb->Partitions[i].PartitionNum == Addr->partitionReferenceNum) { + a = Vcb->Partitions[i].PartitionRoot + + (Addr->logicalBlockNum << Vcb->LB2B_Bits); + if(a > Vcb->LastPossibleLBA) { + AdPrint(("UDFPartLbaToPhys: root %x, lbn %x, lba %x (err1)\n", + Vcb->Partitions[i].PartitionRoot, Addr->logicalBlockNum, a)); + BrutePoint(); + return LBA_OUT_OF_EXTENT; + } + return a; + } + } + a = Vcb->Partitions[i-1].PartitionRoot + + (Addr->logicalBlockNum << Vcb->LB2B_Bits); + if(a > Vcb->LastPossibleLBA) { + AdPrint(("UDFPartLbaToPhys: i %x, root %x, lbn %x, lba %x (err2)\n", + i, Vcb->Partitions[i-1].PartitionRoot, Addr->logicalBlockNum, a)); + BrutePoint(); + return LBA_OUT_OF_EXTENT; + } + return a; +} // end UDFPartLbaToPhys() + + +/* + This routine returns physycal Lba for partition-relative addr + No partition bounds check is performed. + This routine only checks if requested partition exists. + It is introduced for 'Adaptec DirectCD' compatibility, + because it uses negative values as extent terminator (against standard) + */ +/*uint32 +__fastcall +UDFPartLbaToPhysCompat( + IN PVCB Vcb, + IN lb_addr* Addr + ) +{ + uint32 i, a; + if(Addr->partitionReferenceNum >= Vcb->PartitionMaps) return LBA_NOT_ALLOCATED; + // walk through partition maps & transform relative address + // to physical + for(i=Addr->partitionReferenceNum; iPartitionMaps; i++) { + if(Vcb->Partitions[i].PartitionNum == Addr->partitionReferenceNum) { + a = Vcb->Partitions[i].PartitionRoot + + (Addr->logicalBlockNum << Vcb->LB2B_Bits); + if(a > Vcb->LastPossibleLBA) { + BrutePoint(); + } + return a; + } + } + a = Vcb->Partitions[i-1].PartitionRoot + + (Addr->logicalBlockNum << Vcb->LB2B_Bits); + if(a > Vcb->LastPossibleLBA) { + BrutePoint(); + } + return a; +} // end UDFPartLbaToPhysCompat()*/ + + +/* + This routine looks for the partition containing given physical sector + */ +uint32 +__fastcall +UDFGetPartNumByPhysLba( + IN PVCB Vcb, + IN uint32 Lba + ) +{ + uint32 i=Vcb->PartitionMaps-1, root; + PUDFPartMap pm = &(Vcb->Partitions[i]); + // walk through the partition maps to find suitable one + for(;i!=0xffffffff;i--,pm--) { + if( ((root = pm->PartitionRoot) <= Lba) && + ((root + pm->PartitionLen) > Lba) ) return (uint16)pm->PartitionNum; + } + return LBA_OUT_OF_EXTENT; // Lba doesn't belong to any partition +} // end UDFGetPartNumByPhysLba() + +/* + Very simple routine. It walks through the Partition Maps & returns + the 1st Lba of the 1st suitable one + */ +uint32 +__fastcall +UDFPartStart( + PVCB Vcb, + uint32 PartNum + ) +{ + uint32 i; + if(PartNum == (uint32)-1) return 0; + if(PartNum == (uint32)-2) return Vcb->Partitions[0].PartitionRoot; + for(i=PartNum; iPartitionMaps; i++) { + if(Vcb->Partitions[i].PartitionNum == PartNum) return Vcb->Partitions[i].PartitionRoot; + } + return 0; +} // end UDFPartStart( + +/* + This routine does almost the same as previous. + The only difference is changing First Lba to Last one... + */ +uint32 +__fastcall +UDFPartEnd( + PVCB Vcb, + uint32 PartNum + ) +{ + uint32 i; + if(PartNum == (uint32)-1) return Vcb->LastLBA; + if(PartNum == (uint32)-2) PartNum = Vcb->PartitionMaps-1; + for(i=PartNum; iPartitionMaps; i++) { + if(Vcb->Partitions[i].PartitionNum == PartNum) + return (Vcb->Partitions[i].PartitionRoot + + Vcb->Partitions[i].PartitionLen); + } + return (Vcb->Partitions[i-1].PartitionRoot + + Vcb->Partitions[i-1].PartitionLen); +} // end UDFPartEnd() + +/* + Very simple routine. It walks through the Partition Maps & returns + the 1st Lba of the 1st suitable one + */ +uint32 +__fastcall +UDFPartLen( + PVCB Vcb, + uint32 PartNum + ) +{ + + if(PartNum == (uint32)-2) return UDFPartEnd(Vcb, -2) - UDFPartStart(Vcb, -2); +/*#ifdef _X86_ + uint32 ret_val; + __asm { + mov ebx,Vcb + mov eax,PartNum + cmp eax,-1 + jne short NOT_last_gpl + mov eax,[ebx]Vcb.LastLBA + jmp short EO_gpl +NOT_last_gpl: + mov esi,eax + xor eax,eax + mov ecx,[ebx]Vcb.PartitionMaps + jecxz EO_gpl + + mov eax,esi + mov edx,size UDFTrackMap + mul edx + add ebx,eax + mov eax,esi +gpl_loop: + cmp [ebx]Vcb.PartitionMaps.PartitionNum,ax + je short EO_gpl_1 + add ebx,size UDFTrackMap + inc eax + cmp eax,ecx + jb short gpl_loop + sub ebx,size UDFTrackMap +EO_gpl_1: + mov eax,[ebx]Vcb.PartitionMaps.PartitionLen + add eax,[ebx]Vcb.PartitionMaps.PartitionRoot +EO_gpl: + mov ret_val,eax + } + return ret_val; +#else // NO X86 optimization , use generic C/C++*/ + uint32 i; + if(PartNum == (uint32)-1) return Vcb->LastLBA; + for(i=PartNum; iPartitionMaps; i++) { + if(Vcb->Partitions[i].PartitionNum == PartNum) + return Vcb->Partitions[i].PartitionLen; + } + return (Vcb->Partitions[i-1].PartitionRoot + + Vcb->Partitions[i-1].PartitionLen); +/*#endif // _X86_*/ +} // end UDFPartLen() + +/* + This routine returns length of bit-chain starting from Offs bit in + array Bitmap. Bitmap scan is limited with Lim. + */ + +//#if defined _X86_ +#if defined _MSC_VER + +__declspec (naked) +uint32 +__stdcall +UDFGetBitmapLen( + uint32* Bitmap, + uint32 Offs, + uint32 Lim // NOT included + ) +{ + _asm { + push ebp + mov ebp, esp + + push ebx + push ecx + push edx + push esi + push edi + + xor edx,edx // init bit-counter + mov ebx,[ebp+0x08] // set base pointer in EBX (Bitmap) + mov esi,[ebp+0x0c] // set Offs in ESI + mov edi,[ebp+0x10] // set Lim in EDI + + // check if Lim <= Offs + cmp esi,edi +// jb start_count +// ja exit_count +// inc edx +// jmp exit_count + jae exit_count + +//start_count: + + // set 1st bit number in CL + mov ecx,esi + and cl,0x1f + // make ESI uint32-index + shr esi,5 + + // save last bit number in CH + mov eax,edi + and al,0x1f + mov ch,al + // make EDI uint32-index of the last uint32 + shr edi,5 + + mov eax,[ebx+esi*4] + shr eax,cl + test eax,1 + + jz Loop_0 + + /* COUNT 1-BITS SECTION */ +Loop_1: + + cmp esi,edi + ja exit_count // must never happen + jb non_last_1 + +Loop_last_1: + + cmp cl,ch + jae exit_count + // do we met 0 ? + test eax,1 + jz exit_count + shr eax,1 + inc edx + inc cl + jmp Loop_last_1 + +non_last_1: + + or cl,cl + jnz std_count_1 + cmp eax,-1 + je quick_count_1 + +std_count_1: + + cmp cl,0x1f + ja next_uint32_1 + // do we met 0 ? + test eax,1 + jz exit_count + shr eax,1 + inc edx + inc cl + jmp std_count_1 + +quick_count_1: + + add edx,0x20 + +next_uint32_1: + + inc esi + mov eax,[ebx+esi*4] + xor cl,cl + jmp Loop_1 + + /* COUNT 0-BITS SECTION */ +Loop_0: + + cmp esi,edi + ja exit_count // must never happen + jb non_last_0 + +Loop_last_0: + + cmp cl,ch + jae exit_count + // do we met 1 ? + test eax,1 + jnz exit_count + shr eax,1 + inc edx + inc cl + jmp Loop_last_0 + +non_last_0: + + or cl,cl + jnz std_count_0 + or eax,eax + jz quick_count_0 + +std_count_0: + + cmp cl,0x1f + ja next_uint32_0 + // do we met 1 ? + test eax,1 + jnz exit_count + shr eax,1 + inc edx + inc cl + jmp std_count_0 + +quick_count_0: + + add edx,0x20 + +next_uint32_0: + + inc esi + mov eax,[ebx+esi*4] + xor cl,cl + jmp Loop_0 + +exit_count: + + mov eax,edx + + pop edi + pop esi + pop edx + pop ecx + pop ebx + + pop ebp + + ret 0x0c + } + +#else // NO X86 optimization , use generic C/C++ + +uint32 +__stdcall +UDFGetBitmapLen( + uint32* Bitmap, + uint32 Offs, + uint32 Lim // NOT included + ) +{ + ASSERT(Offs <= Lim); + if(Offs >= Lim) { + return 0;//(Offs == Lim); + } + + BOOLEAN bit = UDFGetBit(Bitmap, Offs); + uint32 i=Offs>>5; + uint32 len=0; + uint8 j=(uint8)(Offs&31); + uint8 lLim=(uint8)(Lim&31); + + Lim = Lim>>5; + + ASSERT((bit == 0) || (bit == 1)); + + uint32 a; + + a = Bitmap[i] >> j; + + while(i<=Lim) { + + while( j < ((i>=1; + j++; + } + j=0; +While_3: + i++; + a = Bitmap[i]; + + if(iWriteBlockSize >> Vcb->BlockSizeBits; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + + // we'll try to allocate packet-aligned block at first + if(!(Length & (PS-1)) && !Vcb->CDR_Mode && (Length >= PS*2)) + align = TRUE; + if(AllocFlags & EXTENT_FLAG_ALLOC_SEQUENTIAL) + align = TRUE; + if(Length > (uint32)(UDF_MAX_EXTENT_LENGTH >> Vcb->BlockSizeBits)) + Length = (UDF_MAX_EXTENT_LENGTH >> Vcb->BlockSizeBits); + // align Length according to _Logical_ block size & convert it to BCount + i = (1<LB2B_Bits)-1; + Length = (Length+i) & ~i; + cur = (uint32*)(Vcb->FSBM_Bitmap); + +retry_no_align: + + i=SearchStart; + // scan Bitmap + while(i= SearchLim) + break; + } + len = UDFGetBitmapLen(cur, i, SearchLim); + if(UDFGetFreeBit(cur, i)) { // is the extent found free or used ? + // wow! it is free! + if(len >= Length) { + // minimize extent length + if(!best_len || (best_len > len)) { + best_lba = i; + best_len = len; + } + if(len == Length) + break; + } else { + // remember max extent + if(max_len < len) { + max_lba = i; + max_len = len; + } + } + // if this is CD-R mode, we should not think about fragmentation + // due to CD-R nature file will be fragmented in any case + if(Vcb->CDR_Mode) break; + } + i += len; + } + // if we can't find suitable Packet-size aligned block, + // retry without any alignment requirements + if(!best_len && align) { + align = FALSE; + goto retry_no_align; + } + if(best_len) { + // minimal suitable block + (*MaxExtLen) = best_len; + return best_lba; + } + // maximal available + (*MaxExtLen) = max_len; + return max_lba; +} // end UDFFindMinSuitableExtent() +#endif //UDF_READ_ONLY_BUILD + +#ifdef UDF_CHECK_DISK_ALLOCATION +/* + This routine checks space described by Mapping as Used/Freed (optionaly) + */ +void +UDFCheckSpaceAllocation_( + IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ) +{ + uint32 i=0; + uint32 lba, j, len, BS, BSh; + BOOLEAN asUsed = (asXXX == AS_USED); + + if(!Map) return; + + BS = Vcb->BlockSize; + BSh = Vcb->BlockSizeBits; + + UDFAcquireResourceShared(&(Vcb->BitMapResource1),TRUE); + // walk through all frags in data area specified +#ifdef UDF_TRACK_ONDISK_ALLOCATION + AdPrint(("ChkAlloc:Map:%x:File:%x:Line:%d\n", + Map, + BugCheckId, + Line + )); +#endif //UDF_TRACK_ONDISK_ALLOCATION + while(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) { + +#ifdef UDF_TRACK_ONDISK_ALLOCATION + AdPrint(("ChkAlloc:%x:%s:%x:@:%x:(%x):File:%x:Line:%d\n", + FE_lba, + asUsed ? "U" : "F", + (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh, + Map[i].extLocation, + (Map[i].extLength >> 30), + BugCheckId, + Line + )); +#endif //UDF_TRACK_ONDISK_ALLOCATION + if(asUsed) { + UDFCheckUsedBitOwner(Vcb, (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh, FE_lba); + } else { + UDFCheckFreeBitOwner(Vcb, (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); + } + + if((Map[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + // skip unallocated frags +// ASSERT(!(Map[i].extLength & UDF_EXTENT_LENGTH_MASK)); + ASSERT(!Map[i].extLocation); + i++; + continue; + } else { +// ASSERT(!(Map[i].extLength & UDF_EXTENT_LENGTH_MASK)); + ASSERT(Map[i].extLocation); + } + +#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT + ASSERT(!(Map[i].extLength & (BS-1))); +#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT + len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh; + lba = Map[i].extLocation; + if((lba+len) > Vcb->LastPossibleLBA) { + // skip blocks beyond media boundary + if(lba > Vcb->LastPossibleLBA) { + ASSERT(FALSE); + i++; + continue; + } + len = Vcb->LastPossibleLBA - lba; + } + + // mark frag as XXX (see asUsed parameter) + if(asUsed) { + + ASSERT(len); + for(j=0;j Vcb->LastPossibleLBA) { + BrutePoint(); + AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j)); + break; + } + if(!UDFGetUsedBit(Vcb->FSBM_Bitmap, lba+j)) { + BrutePoint(); + AdPrint(("USED Mapping covers FREE block(s) @%x\n",lba+j)); + break; + } + } + + } else { + + ASSERT(len); + for(j=0;j Vcb->LastPossibleLBA) { + BrutePoint(); + AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j)); + break; + } + if(!UDFGetFreeBit(Vcb->FSBM_Bitmap, lba+j)) { + BrutePoint(); + AdPrint(("FREE Mapping covers USED block(s) @%x\n",lba+j)); + break; + } + } + } + + i++; + } + UDFReleaseResource(&(Vcb->BitMapResource1)); +} // end UDFCheckSpaceAllocation_() +#endif //UDF_CHECK_DISK_ALLOCATION + +void +UDFMarkBadSpaceAsUsed( + IN PVCB Vcb, + IN lba_t lba, + IN ULONG len + ) +{ + uint32 j; +#define BIT_C (sizeof(Vcb->BSBM_Bitmap[0])*8) + len = (lba+len+BIT_C-1)/BIT_C; + if(Vcb->BSBM_Bitmap) { + for(j=lba/BIT_C; jFSBM_Bitmap[j] &= ~Vcb->BSBM_Bitmap[j]; + } + } +#undef BIT_C +} // UDFMarkBadSpaceAsUsed() + +/* + This routine marks space described by Mapping as Used/Freed (optionaly) + */ +void +UDFMarkSpaceAsXXXNoProtect_( + IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ) +{ + uint32 i=0; + uint32 lba, j, len, BS, BSh; + uint32 root; + BOOLEAN asUsed = (asXXX == AS_USED || (asXXX & AS_BAD)); +#ifdef UDF_TRACK_ONDISK_ALLOCATION + BOOLEAN bit_before, bit_after; +#endif //UDF_TRACK_ONDISK_ALLOCATION + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + + if(!Map) return; + + BS = Vcb->BlockSize; + BSh = Vcb->BlockSizeBits; + Vcb->BitmapModified = TRUE; + UDFSetModified(Vcb); + // walk through all frags in data area specified + while(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) { + if((Map[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + // skip unallocated frags + i++; + continue; + } + ASSERT(Map[i].extLocation); + +#ifdef UDF_TRACK_ONDISK_ALLOCATION + AdPrint(("Alloc:%x:%s:%x:@:%x:File:%x:Line:%d\n", + FE_lba, + asUsed ? ((asXXX & AS_BAD) ? "B" : "U") : "F", + (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits, + Map[i].extLocation, + BugCheckId, + Line + )); +#endif //UDF_TRACK_ONDISK_ALLOCATION + +#ifdef UDF_DBG +#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT + ASSERT(!(Map[i].extLength & (BS-1))); +#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT +// len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh; +#else // UDF_DBG +// len = (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh; +#endif // UDF_DBG + len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh; + lba = Map[i].extLocation; + if((lba+len) > Vcb->LastPossibleLBA) { + // skip blocks beyond media boundary + if(lba > Vcb->LastPossibleLBA) { + ASSERT(FALSE); + i++; + continue; + } + len = Vcb->LastPossibleLBA - lba; + } + +#ifdef UDF_TRACK_ONDISK_ALLOCATION + if(lba) + bit_before = UDFGetBit(Vcb->FSBM_Bitmap, lba-1); + bit_after = UDFGetBit(Vcb->FSBM_Bitmap, lba+len); +#endif //UDF_TRACK_ONDISK_ALLOCATION + + // mark frag as XXX (see asUsed parameter) + if(asUsed) { +/* for(j=0;jFSBM_Bitmap, lba+j); + }*/ + ASSERT(len); + UDFSetUsedBits(Vcb->FSBM_Bitmap, lba, len); +#ifdef UDF_TRACK_ONDISK_ALLOCATION + for(j=0;jFSBM_Bitmap, lba+j)); + } +#endif //UDF_TRACK_ONDISK_ALLOCATION + + if(Vcb->Vat) { + // mark logical blocks in VAT as used + for(j=0;jVat[lba-root+j] == UDF_VAT_FREE_ENTRY) && + (lba > Vcb->LastLBA)) { + Vcb->Vat[lba-root+j] = 0x7fffffff; + } + } + } + } else { +/* for(j=0;jFSBM_Bitmap, lba+j); + }*/ + ASSERT(len); + UDFSetFreeBits(Vcb->FSBM_Bitmap, lba, len); +#ifdef UDF_TRACK_ONDISK_ALLOCATION + for(j=0;jFSBM_Bitmap, lba+j)); + } +#endif //UDF_TRACK_ONDISK_ALLOCATION + if(asXXX & AS_BAD) { + UDFSetBits(Vcb->BSBM_Bitmap, lba, len); + } + UDFMarkBadSpaceAsUsed(Vcb, lba, len); + + if(asXXX & AS_DISCARDED) { + UDFUnmapRange(Vcb, lba, len); + WCacheDiscardBlocks__(&(Vcb->FastCache), Vcb, lba, len); + UDFSetZeroBits(Vcb->ZSBM_Bitmap, lba, len); + } + if(Vcb->Vat) { + // mark logical blocks in VAT as free + // this operation can decrease resulting VAT size + for(j=0;jVat[lba-root+j] = UDF_VAT_FREE_ENTRY; + } + } + // mark discarded extent as Not-Alloc-Not-Rec to + // prevent writes there + Map[i].extLength = (len << BSh) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + Map[i].extLocation = 0; + } + +#ifdef UDF_TRACK_ONDISK_ALLOCATION + if(lba) + ASSERT(bit_before == UDFGetBit(Vcb->FSBM_Bitmap, lba-1)); + ASSERT(bit_after == UDFGetBit(Vcb->FSBM_Bitmap, lba+len)); +#endif //UDF_TRACK_ONDISK_ALLOCATION + + i++; + } +} // end UDFMarkSpaceAsXXXNoProtect_() + +/* + This routine marks space described by Mapping as Used/Freed (optionaly) + It protects data with sync Resource + */ +void +UDFMarkSpaceAsXXX_( + IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ) +{ + if(!Map) return; + if(!Map[0].extLength) { +#ifdef UDF_DBG + ASSERT(!Map[0].extLocation); +#endif // UDF_DBG + return; + } + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); +#ifdef UDF_TRACK_ONDISK_ALLOCATION + UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX, FE_lba, BugCheckId, Line); +#else //UDF_TRACK_ONDISK_ALLOCATION + UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX); +#endif //UDF_TRACK_ONDISK_ALLOCATION + UDFReleaseResource(&(Vcb->BitMapResource1)); + +} // end UDFMarkSpaceAsXXX_() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine builds mapping for Length bytes in FreeSpace + It should be used when IN_ICB method is unavailable. + */ +OSSTATUS +UDFAllocFreeExtent_( + IN PVCB Vcb, + IN int64 Length, + IN uint32 SearchStart, + IN uint32 SearchLim, // NOT included + OUT PEXTENT_INFO ExtInfo, + IN uint8 AllocFlags +#ifdef UDF_TRACK_ALLOC_FREE_EXTENT + ,IN uint32 src, + IN uint32 line +#endif //UDF_TRACK_ALLOC_FREE_EXTENT + ) +{ + EXTENT_AD Ext; + PEXTENT_MAP Map = NULL; + uint32 len, LBS, BSh, blen; + + LBS = Vcb->LBlockSize; + BSh = Vcb->BlockSizeBits; + blen = (uint32)(((Length+LBS-1) & ~((int64)LBS-1)) >> BSh); + ExtInfo->Mapping = NULL; + ExtInfo->Offset = 0; + + ASSERT(blen <= (uint32)(UDF_MAX_EXTENT_LENGTH >> BSh)); + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); + + if(blen > (SearchLim - SearchStart)) { + goto no_free_space_err; + } + // walk through the free space bitmap & find a single extent or a set of + // frags giving in sum the Length specified + while(blen) { + Ext.extLocation = UDFFindMinSuitableExtent(Vcb, blen, SearchStart, + SearchLim, &len, AllocFlags); + +// ASSERT(len <= (uint32)(UDF_MAX_EXTENT_LENGTH >> BSh)); + if(len >= blen) { + // complete search + Ext.extLength = blen<Mapping) { + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // free + MyFreePool__(ExtInfo->Mapping); + ExtInfo->Mapping = NULL; + } + UDFReleaseResource(&(Vcb->BitMapResource1)); + ExtInfo->Length = 0;//UDFGetExtentLength(ExtInfo->Mapping); + AdPrint((" DISK_FULL\n")); + return STATUS_DISK_FULL; + } + // append the frag found to mapping + ASSERT(!(Ext.extLength >> 30)); + ASSERT(Ext.extLocation); + + // mark newly allocated blocks as zero-filled + UDFSetZeroBits(Vcb->ZSBM_Bitmap, Ext.extLocation, (Ext.extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); + + if(AllocFlags & EXTENT_FLAG_VERIFY) { + if(!UDFCheckArea(Vcb, Ext.extLocation, Ext.extLength >> BSh)) { + AdPrint(("newly allocated extent contains BB\n")); + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // free + UDFMarkBadSpaceAsUsed(Vcb, Ext.extLocation, Ext.extLength >> BSh); // bad -> bad+used + // roll back + blen += Ext.extLength>>BSh; + continue; + } + } + + Ext.extLength |= EXTENT_NOT_RECORDED_ALLOCATED << 30; + if(!(ExtInfo->Mapping)) { + // create new +#ifdef UDF_TRACK_ALLOC_FREE_EXTENT + ExtInfo->Mapping = UDFExtentToMapping_(&Ext, src, line); +#else // UDF_TRACK_ALLOC_FREE_EXTENT + ExtInfo->Mapping = UDFExtentToMapping(&Ext); +#endif // UDF_TRACK_ALLOC_FREE_EXTENT + if(!ExtInfo->Mapping) { + BrutePoint(); + UDFReleaseResource(&(Vcb->BitMapResource1)); + ExtInfo->Length = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_USED); // used + } else { + // update existing + Map = UDFExtentToMapping(&Ext); + if(!Map) { + BrutePoint(); + UDFReleaseResource(&(Vcb->BitMapResource1)); + ExtInfo->Length = UDFGetExtentLength(ExtInfo->Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, Map, AS_USED); // used + ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, Map); + MyFreePool__(Map); + } + if(!ExtInfo->Mapping) { + BrutePoint(); + UDFReleaseResource(&(Vcb->BitMapResource1)); + ExtInfo->Length = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + } + UDFReleaseResource(&(Vcb->BitMapResource1)); + ExtInfo->Length = Length; + return STATUS_SUCCESS; +} // end UDFAllocFreeExtent_() +#endif //UDF_READ_ONLY_BUILD + +/* + Returns block-count + */ +uint32 +__fastcall +UDFGetPartFreeSpace( + IN PVCB Vcb, + IN uint32 partNum + ) +{ + uint32 lim/*, len=1*/; + uint32 s=0; + uint32 j; + PUCHAR cur = (PUCHAR)(Vcb->FSBM_Bitmap); + + lim = (UDFPartEnd(Vcb,partNum)+7)/8; + for(j=(UDFPartStart(Vcb,partNum)+7)/8; jFSBM_Bitmap); + + if(!Vcb->CDR_Mode && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + for(i=0;iPartitionMaps;i++) { +/* lim = UDFPartEnd(Vcb,i); + for(j=UDFPartStart(Vcb,i); jLastPossibleLBA >= max(Vcb->NWA, Vcb->LastLBA)); + s = Vcb->LastPossibleLBA - max(Vcb->NWA, Vcb->LastLBA); + //if(s & ((int64)1 << 64)) s=0; + } + return s >> Vcb->LB2B_Bits; +} // end UDFGetFreeSpace() + +/* + Returns block-count + */ +int64 +__fastcall +UDFGetTotalSpace( + IN PVCB Vcb + ) +{ + int64 s=0; + uint32 i; + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + s= Vcb->LastPossibleLBA; + } else if(!Vcb->CDR_Mode) { + for(i=0;iPartitionMaps;i++) { + s+=Vcb->Partitions[i].PartitionLen; + } + } else { + if(s & ((int64)1 << 64)) s=0; + s= Vcb->LastPossibleLBA - Vcb->Partitions[0].PartitionRoot; + } + return s >> Vcb->LB2B_Bits; +} // end UDFGetTotalSpace() + +/* + Callback for WCache + returns Allocated and Zero-filled flags for given block + any data in 'unallocated' blocks may be changed during flush process + */ +uint32 +UDFIsBlockAllocated( + IN void* _Vcb, + IN uint32 Lba + ) +{ + ULONG ret_val = 0; + uint32* bm; +// return TRUE; + if(!(((PVCB)_Vcb)->VCBFlags & UDF_VCB_ASSUME_ALL_USED)) { + // check used + if((bm = (uint32*)(((PVCB)_Vcb)->FSBM_Bitmap))) + ret_val = (UDFGetUsedBit(bm, Lba) ? WCACHE_BLOCK_USED : 0); + // check zero-filled + if((bm = (uint32*)(((PVCB)_Vcb)->ZSBM_Bitmap))) + ret_val |= (UDFGetZeroBit(bm, Lba) ? WCACHE_BLOCK_ZERO : 0); + } else { + ret_val = WCACHE_BLOCK_USED; + } + // check bad block + + // WCache works with LOGICAL addresses, not PHYSICAL, BB check must be performed UNDER cache +/* + if(bm = (uint32*)(((PVCB)_Vcb)->BSBM_Bitmap)) { + ret_val |= (UDFGetBadBit(bm, Lba) ? WCACHE_BLOCK_BAD : 0); + if(ret_val & WCACHE_BLOCK_BAD) { + KdPrint(("Marked BB @ %#x\n", Lba)); + } + } +*/ + return ret_val; +} // end UDFIsBlockAllocated() + +#ifdef _X86_ + +#pragma warning(disable:4035) // re-enable below + +__declspec (naked) +BOOLEAN +__fastcall +UDFGetBit__( + IN uint32* arr, // ECX + IN uint32 bit // EDX + ) +{ +// CheckAddr(arr); +// ASSERT(bit < 300000); +#ifdef _MSC_VER + __asm { + push ebx + push ecx +// mov eax,bit + mov eax,edx + shr eax,3 + and al,0fch + add eax,ecx // eax+arr + mov eax,[eax] + mov cl,dl + ror eax,cl + and eax,1 + + pop ecx + pop ebx + ret + } +#else +/* FIXME ReactOS */ + return ((BOOLEAN)(((((uint32*)(arr))[(bit)>>5]) >> ((bit)&31)) &1)); +#endif +} // end UDFGetBit__() + +__declspec (naked) +void +__fastcall +UDFSetBit__( + IN uint32* arr, // ECX + IN uint32 bit // EDX + ) +{ +// CheckAddr(arr); +// ASSERT(bit < 300000); +#ifdef _MSC_VER + __asm { + push eax + push ebx + push ecx +// mov eax,bit + mov eax,edx + shr eax,3 + and al,0fch + add eax,ecx // eax+arr + mov ebx,1 + mov cl,dl + rol ebx,cl + or [eax],ebx + + pop ecx + pop ebx + pop eax + ret + } +#else +/* FIXME ReactOS */ + (((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31)); +#endif +} // end UDFSetBit__() + +void +UDFSetBits__( + IN uint32* arr, + IN uint32 bit, + IN uint32 bc + ) +{ +#ifdef _MSC_VER + __asm { + push eax + push ebx + push ecx + push edx + push esi + + mov edx,bc + or edx,edx + jz short EO_sb_loop + + mov ecx,bit + mov esi,arr + + mov ebx,1 + rol ebx,cl + + mov eax,ecx + shr eax,3 + and al,0fch + + test cl, 0x1f + jnz short sb_loop_cont +sb_loop_2: + cmp edx,0x20 + jb short sb_loop_cont + + mov [dword ptr esi+eax],0xffffffff + sub edx,0x20 + jz short EO_sb_loop + add eax,4 + add ecx,0x20 + jmp short sb_loop_2 + +sb_loop_cont: + or [esi+eax],ebx + + rol ebx,1 + inc ecx + dec edx + jz short EO_sb_loop + + test cl, 0x1f + jnz short sb_loop_cont + add eax,4 + jmp short sb_loop_2 +EO_sb_loop: + pop esi + pop edx + pop ecx + pop ebx + pop eax + } +#else +/* FIXME ReactOS */ + uint32 j; + for(j=0;j>5]) &= (~(((uint32)1) << ((bit)&31))); +#endif +} // end UDFClrBit__() + +void +UDFClrBits__( + IN uint32* arr, + IN uint32 bit, + IN uint32 bc + ) +{ +#ifdef _MSC_VER + __asm { + push eax + push ebx + push ecx + push edx + push esi + + mov edx,bc + or edx,edx + jz short EO_cp_loop + + mov ecx,bit + mov esi,arr + + mov ebx,0xfffffffe + rol ebx,cl + + mov eax,ecx + shr eax,3 + and al,0fch + + test cl, 0x1f + jnz short cp_loop_cont +cp_loop_2: + cmp edx,0x20 + jb short cp_loop_cont + + mov [dword ptr esi+eax],0x00000000 + sub edx,0x20 + jz short EO_cp_loop + add eax,4 + add ecx,0x20 + jmp short cp_loop_2 + +cp_loop_cont: + and [esi+eax],ebx + + rol ebx,1 + inc ecx + dec edx + jz short EO_cp_loop + + test cl, 0x1f + jnz short cp_loop_cont + add eax,4 + jmp short cp_loop_2 +EO_cp_loop: + pop esi + pop edx + pop ecx + pop ebx + pop eax + } +#else +/* FIXME ReactOS */ + uint32 j; + for(j=0;jUDF_DIR_INDEX_FRAME) + return NULL; +#endif //UDF_LIMIT_DIR_SIZE + + j = i >> UDF_DIR_INDEX_FRAME_SH; + i &= (UDF_DIR_INDEX_FRAME-1); + + hDirNdx = (PDIR_INDEX_HDR)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, sizeof(DIR_INDEX_HDR)+(j+(i!=0))*sizeof(PDIR_INDEX_ITEM), MEM_DIR_HDR_TAG); + if(!hDirNdx) return NULL; + RtlZeroMemory(hDirNdx, sizeof(DIR_INDEX_HDR)); + + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); + for(k=0; kFrameCount = j+(i!=0); + hDirNdx->LastFrameCount = i ? i : UDF_DIR_INDEX_FRAME; + + return hDirNdx; +} // UDFDirIndexAlloc() + +/* + This routine releases DirIndex array + */ +void +UDFDirIndexFree( + PDIR_INDEX_HDR hDirNdx + ) +{ + uint32 k; + PDIR_INDEX_ITEM* FrameList; + + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); + if(!hDirNdx) return; + for(k=0; kFrameCount; k++, FrameList++) { + if(*FrameList) MyFreePool__(*FrameList); + } + MyFreePool__(hDirNdx); +} // UDFDirIndexFree(); + +/* + This routine grows DirIndex array + */ +OSSTATUS +UDFDirIndexGrow( + IN PDIR_INDEX_HDR* _hDirNdx, + IN uint_di d // increment + ) +{ + uint_di j,k; + PDIR_INDEX_HDR hDirNdx = *_hDirNdx; + PDIR_INDEX_ITEM* FrameList; + + if(d > UDF_DIR_INDEX_FRAME) + return STATUS_INVALID_PARAMETER; + + j = hDirNdx->LastFrameCount+d; + + if(j > UDF_DIR_INDEX_FRAME) { +#ifndef UDF_LIMIT_DIR_SIZE // release + // Grow header + k = hDirNdx->FrameCount; + if(!MyReallocPool__((int8*)hDirNdx, sizeof(DIR_INDEX_HDR) + k*sizeof(PDIR_INDEX_ITEM), + (int8**)(&hDirNdx), sizeof(DIR_INDEX_HDR) + (k+1)*sizeof(PDIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); + // Grow last frame + if(!MyReallocPool__((int8*)(FrameList[k-1]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM), + (int8**)(&(FrameList[k-1])), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(&(FrameList[k-1][hDirNdx->LastFrameCount]), + (UDF_DIR_INDEX_FRAME-hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM)); + hDirNdx->LastFrameCount = UDF_DIR_INDEX_FRAME; + // Allocate new frame + FrameList[k] = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, AlignDirIndex(j-UDF_DIR_INDEX_FRAME)*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG ); + if(!FrameList[k]) + return STATUS_INSUFFICIENT_RESOURCES; + hDirNdx->FrameCount++; + RtlZeroMemory(FrameList[k], (j-UDF_DIR_INDEX_FRAME)*sizeof(DIR_INDEX_ITEM)); + hDirNdx->LastFrameCount = j-UDF_DIR_INDEX_FRAME; + (*_hDirNdx) = hDirNdx; +#else // UDF_LIMIT_DIR_SIZE + return STATUS_INSUFFICIENT_RESOURCES; +#endif // UDF_LIMIT_DIR_SIZE + } else { + k = hDirNdx->FrameCount; + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); + if(!MyReallocPool__((int8*)(FrameList[k-1]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM), + (int8**)(&(FrameList[k-1])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(&(FrameList[k-1][hDirNdx->LastFrameCount]), + (j-hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM)); + hDirNdx->LastFrameCount = j; + } + return STATUS_SUCCESS; +} // end UDFDirIndexGrow() + +/* + Thisd routine truncates DirIndex array + */ +OSSTATUS +UDFDirIndexTrunc( + IN PDIR_INDEX_HDR* _hDirNdx, + IN uint_di d // decrement + ) +{ + uint_di j,k; + + if(d > UDF_DIR_INDEX_FRAME) { + OSSTATUS status; + while(d) { + k = (d > UDF_DIR_INDEX_FRAME) ? UDF_DIR_INDEX_FRAME : d; + if(!OS_SUCCESS(status = UDFDirIndexTrunc(_hDirNdx, k))) { + return status; + } + d -= k; + } + return STATUS_SUCCESS; + } + + PDIR_INDEX_HDR hDirNdx = *_hDirNdx; + PDIR_INDEX_ITEM* FrameList; + + j = UDF_DIR_INDEX_FRAME+hDirNdx->LastFrameCount-d; + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); + k = hDirNdx->FrameCount-1; + + if(j <= UDF_DIR_INDEX_FRAME) { + // free last frame + if(!k && (j < 2)) { + // someone tries to trunc. residual entries... + return STATUS_INVALID_PARAMETER; + } + MyFreePool__(FrameList[k]); + FrameList[k] = NULL; + hDirNdx->LastFrameCount = UDF_DIR_INDEX_FRAME; + hDirNdx->FrameCount--; + // Truncate new last frame + if(!MyReallocPool__((int8*)(FrameList[k-1]), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM), + (int8**)(&(FrameList[k-1])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + hDirNdx->LastFrameCount = j; + // Truncate header + if(!MyReallocPool__((int8*)hDirNdx, sizeof(DIR_INDEX_HDR) + (k+1)*sizeof(PDIR_INDEX_ITEM), + (int8**)(&hDirNdx), sizeof(DIR_INDEX_HDR) + k*sizeof(PDIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + + (*_hDirNdx) = hDirNdx; + + } else { + + j -= UDF_DIR_INDEX_FRAME; + if(!k && (j < 2)) { + // someone tries to trunc. residual entries... + return STATUS_INVALID_PARAMETER; + } + + if(!MyReallocPool__((int8*)(FrameList[k]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM), + (int8**)(&(FrameList[k])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) ) + return STATUS_INSUFFICIENT_RESOURCES; + hDirNdx->LastFrameCount = j; + } + return STATUS_SUCCESS; +} // end UDFDirIndexTrunc() + +#if defined _X86_ && !defined UDF_LIMIT_DIR_SIZE +#pragma warning(disable:4035) // re-enable below +/* + This routine returns pointer to DirIndex item with index i. + */ +__declspec (naked) +PDIR_INDEX_ITEM +__fastcall +UDFDirIndex( + IN PDIR_INDEX_HDR hDirNdx, // ECX + IN uint32 i // EDX + ) +{ +#ifdef _MSC_VER + __asm { + push ebx + push ecx + push edx + +// mov ebx,hDirNdx + mov ebx,ecx + mov ecx,edx + or ebx,ebx + jz EO_udi_err + + mov eax,ecx + shr ecx,UDF_DIR_INDEX_FRAME_SH ; ecx = j + mov edx,[ebx]hDirNdx.FrameCount ; edx = k + cmp ecx,edx + jae EO_udi_err + + and eax,(1 shl UDF_DIR_INDEX_FRAME_SH)-1 ; eax = i + dec edx + cmp ecx,edx + jb No_check + + cmp eax,[ebx].LastFrameCount + jae EO_udi_err +No_check: + add ebx,size DIR_INDEX_HDR ; ((PDIR_INDEX_ITEM*)(hDirNdx+1))... + mov ebx,[ebx+ecx*4] ; ...[j]... + mov edx,size DIR_INDEX_ITEM + mul edx ; ...[i]... + add eax,ebx ; &(...) + jmp udi_OK +EO_udi_err: + xor eax,eax +udi_OK: + pop edx + pop ecx + pop ebx + + ret + } +#else + /* FIXME ReactOS */ + uint_di j, k; + if( hDirNdx && + ((j = (i >> UDF_DIR_INDEX_FRAME_SH)) < (k = hDirNdx->FrameCount) ) && + ((i = (i & (UDF_DIR_INDEX_FRAME-1))) < ((j < (k-1)) ? UDF_DIR_INDEX_FRAME : hDirNdx->LastFrameCount)) ) + return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[j])[i] ); + return NULL; +#endif +} +#pragma warning(default:4035) +#endif // _X86_ + +/* + This routine returns pointer to DirIndex'es frame & index inside it + according to start Index parameter. It also initializes scan parameters + */ +PDIR_INDEX_ITEM +UDFDirIndexGetFrame( + IN PDIR_INDEX_HDR hDirNdx, + IN uint32 Frame, + OUT uint32* FrameLen, + OUT uint_di* Index, + IN uint_di Rel + ) +{ + if(Frame >= hDirNdx->FrameCount) + return NULL; + if(Index) { +#ifdef UDF_LIMIT_DIR_SIZE + (*Index) = Rel; +// if(FrameLen) + (*FrameLen) = hDirNdx->LastFrameCount; +#else //UDF_LIMIT_DIR_SIZE + (*Index) = Frame*UDF_DIR_INDEX_FRAME+Rel; +// if(FrameLen) + (*FrameLen) = (Frame < (hDirNdx->FrameCount-1)) ? UDF_DIR_INDEX_FRAME : + hDirNdx->LastFrameCount; +#endif //UDF_LIMIT_DIR_SIZE + } + return ((PDIR_INDEX_ITEM*)(hDirNdx+1))[Frame]+Rel; +} // end UDFDirIndexGetFrame() + +/* + This routine initializes indexes for optimized DirIndex scan + according to start Index parameter + */ + +BOOLEAN +UDFDirIndexInitScan( + IN PUDF_FILE_INFO DirInfo, // + OUT PUDF_DIR_SCAN_CONTEXT Context, + IN uint_di Index + ) +{ + Context->DirInfo = DirInfo; + Context->hDirNdx = DirInfo->Dloc->DirIndex; + if( (Context->frame = (Index >> UDF_DIR_INDEX_FRAME_SH)) >= + Context->hDirNdx->FrameCount) { + return FALSE; + } + if( (Context->j = Index & (UDF_DIR_INDEX_FRAME-1)) >= + ((Context->frame < (Context->hDirNdx->FrameCount-1)) + ? + UDF_DIR_INDEX_FRAME : Context->hDirNdx->LastFrameCount) ) { + return FALSE; + } + Context->DirNdx = UDFDirIndexGetFrame(Context->hDirNdx, + Context->frame, + &(Context->d), + &(Context->i), + Context->j); + Context->i--; + Context->j--; + Context->DirNdx--; + + return TRUE; +} // end UDFDirIndexInitScan() + +PDIR_INDEX_ITEM +UDFDirIndexScan( + PUDF_DIR_SCAN_CONTEXT Context, + PUDF_FILE_INFO* _FileInfo + ) +{ + PUDF_FILE_INFO FileInfo; + PUDF_FILE_INFO ParFileInfo; + + Context->i++; + Context->j++; + Context->DirNdx++; + + if(Context->j >= Context->d) { + Context->j=0; + Context->frame++; + Context->DirNdx = UDFDirIndexGetFrame(Context->hDirNdx, + Context->frame, + &(Context->d), + &(Context->i), + Context->j); + } + if(!Context->DirNdx) { + if(_FileInfo) + (*_FileInfo) = NULL; + return NULL; + } + + if(_FileInfo) { + if(FileInfo = Context->DirNdx->FileInfo) { + if(FileInfo->ParentFile != Context->DirInfo) { + ParFileInfo = UDFLocateParallelFI(Context->DirInfo, + Context->i, + FileInfo); +#ifdef UDF_DBG + if(ParFileInfo->ParentFile != Context->DirInfo) { + BrutePoint(); + } +#endif // UDF_DBG + FileInfo = ParFileInfo; + } + } + (*_FileInfo) = FileInfo; + } + + return (Context->DirNdx); +} // end UDFDirIndexScan() + +/* + This routine calculates hashes for directory search + */ +uint8 +UDFBuildHashEntry( + IN PVCB Vcb, + IN PUNICODE_STRING Name, + OUT PHASH_ENTRY hashes, + IN uint8 Mask + ) +{ + UNICODE_STRING UName; + WCHAR ShortNameBuffer[13]; + uint8 RetFlags = 0; + + if(!Name->Buffer) return 0; + + if(Mask & HASH_POSIX) + hashes->hPosix = crc32((uint8*)(Name->Buffer), Name->Length); + + if(Mask & HASH_ULFN) { +/* if(OS_SUCCESS(MyInitUnicodeString(&UName, L"")) && + OS_SUCCESS(MyAppendUnicodeStringToStringTag(&UName, Name, MEM_USDIRHASH_TAG))) {*/ + if(OS_SUCCESS(MyCloneUnicodeString(&UName, Name))) { + RtlUpcaseUnicodeString(&UName, &UName, FALSE); + /* if(!RtlCompareUnicodeString(Name, &UName, FALSE)) { + RetFlags |= UDF_FI_FLAG_LFN; + }*/ + hashes->hLfn = crc32((uint8*)(UName.Buffer), UName.Length); + } else { + BrutePoint(); + } + MyFreePool__(UName.Buffer); + } + + if(Mask & HASH_DOS) { + UName.Buffer = (PWCHAR)(&ShortNameBuffer); + UName.MaximumLength = 13*sizeof(WCHAR); + UDFDOSName(Vcb, &UName, Name, (Mask & HASH_KEEP_NAME) ? TRUE : FALSE); + if(!RtlCompareUnicodeString(Name, &UName, TRUE)) { + RetFlags |= UDF_FI_FLAG_DOS; + } + hashes->hDos = crc32((uint8*)(UName.Buffer), UName.Length); + } + return RetFlags; +} // UDFBuildHashEntry() + +#ifdef UDF_CHECK_UTIL +uint32 +UDFFindNextFI( + IN int8* buff, + IN uint32 prevOffset, + IN uint32 Length + ) +{ + PFILE_IDENT_DESC FileId; + while(prevOffset+sizeof(FILE_IDENT_DESC) < Length) { + prevOffset++; + FileId = (PFILE_IDENT_DESC)(buff+prevOffset); + if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC) + continue; + if(FileId->descTag.descVersion != 2 && FileId->descTag.descVersion != 3) + continue; + if(FileId->fileVersionNum != 1) + continue; + if(FileId->fileCharacteristics & (~0x1f)) + continue; + if(prevOffset + ((FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3))) <= Length) { + KdPrint(("UDFFindNextFI OK: %x\n", prevOffset)); + return prevOffset; + } + } + return 0; +} // end UDFFindNextFI() +#else //UDF_CHECK_UTIL +#define UDFFindNextFI(a,b,c) 0 +#endif //UDF_CHECK_UTIL + +/* + This routine scans directory extent & builds index table for FileIdents + */ +OSSTATUS +UDFIndexDirectory( + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo + ) +{ + PDIR_INDEX_HDR hDirNdx; + PDIR_INDEX_ITEM DirNdx; + PFILE_IDENT_DESC FileId; + uint32 Offset = 0; + uint32 prevOffset = 0; + uint_di Count = 0; + OSSTATUS status; + int8* buff; + PEXTENT_INFO ExtInfo; // Extent array for directory + uint16 PartNum; + uint32 ReadBytes; + uint16 valueCRC; + + if(!FileInfo) return STATUS_INVALID_PARAMETER; + ValidateFileInfo(FileInfo); + + ExtInfo = &(FileInfo->Dloc->DataLoc); + FileInfo->Dloc->DirIndex = NULL; + KdPrint(("UDF: scaning directory\n")); + // allocate buffer for the whole directory + ASSERT((uint32)(ExtInfo->Length)); + if(!ExtInfo->Length) + return STATUS_FILE_CORRUPT_ERROR; + buff = (int8*)DbgAllocatePool(PagedPool, (uint32)(ExtInfo->Length)); + if(!buff) + return STATUS_INSUFFICIENT_RESOURCES; + + ExtInfo->Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL; + + // read FileIdents + status = UDFReadExtent(Vcb, ExtInfo, 0, (uint32)(ExtInfo->Length), FALSE, buff, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(buff); + return status; + } + // scan Dir to get entry counter + FileId = (PFILE_IDENT_DESC)buff; + DirPrint((" ExtInfo->Length %x\n", ExtInfo->Length)); + prevOffset = 0; + while(OffsetLength) { + DirPrint((" Offset %x\n", Offset)); + if(!FileId->descTag.tagIdent) { + DirPrint((" term item\n")); + break; + } + if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC) { + DirPrint((" Inv. tag %x\n", FileId->descTag.tagIdent)); + Offset = UDFFindNextFI(buff, prevOffset, (ULONG)(ExtInfo->Length)); + if(!Offset) { + DirPrint((" can't find next\n")); + break; + } else { + DirPrint((" found next offs %x\n", Offset)); + FileId = (PFILE_IDENT_DESC)((buff)+Offset); + } + } + if(((ULONG)Offset & (Vcb->LBlockSize-1)) > (Vcb->LBlockSize-sizeof(FILE_IDENT_DESC))) { + DirPrint((" badly aligned\n", Offset)); + if(Vcb->Modified) { + DirPrint((" queue repack request\n")); + FileInfo->Dloc->DirIndex->DelCount = Vcb->PackDirThreshold+1; + } + } + prevOffset = Offset; + Offset += (FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3)); + FileId = (PFILE_IDENT_DESC)((buff)+Offset); + Count++; + if(Offset+sizeof(FILE_IDENT_DESC) > ExtInfo->Length) { + if(Offset != ExtInfo->Length) { + KdPrint((" Trash at the end of Dir\n")); + } +// BrutePoint(); + break; + } + } + DirPrint((" final Offset %x\n", Offset)); + if(Offset > ExtInfo->Length) { + BrutePoint(); + KdPrint((" Unexpected end of Dir\n")); + DbgFreePool(buff); + return STATUS_FILE_CORRUPT_ERROR; + } + // allocate buffer for directory index & zero it + DirPrint((" Count %x\n", Count)); + hDirNdx = UDFDirIndexAlloc(Count+1); + if(!hDirNdx) { + DbgFreePool(buff); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Offset = Count = 0; + hDirNdx->DIFlags |= (ExtInfo->Offset ? UDF_DI_FLAG_INIT_IN_ICB : 0); + // add entry pointing to the directory itself + DirNdx = UDFDirIndex(hDirNdx,0); + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + DirNdx->FileEntryLoc.partitionReferenceNum = PartNum = + (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + ASSERT(PartNum != -1); + DirNdx->FileEntryLoc.logicalBlockNum = + UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if(DirNdx->FileEntryLoc.logicalBlockNum == -1) { + DirPrint((" err: FileEntryLoc=-1\n")); + DbgFreePool(buff); + return STATUS_FILE_CORRUPT_ERROR; + } + DirNdx->FileCharacteristics = (FileInfo->FileIdent) ? + FileInfo->FileIdent->fileCharacteristics : + FILE_DIRECTORY; +// DirNdx->Offset = 0; +// DirNdx->Length = 0; + DirNdx->FName.Buffer = L"."; + DirNdx->FName.Length = + (DirNdx->FName.MaximumLength = sizeof(L".")) - sizeof(WCHAR); + DirNdx->FileInfo = FileInfo; + DirNdx->FI_Flags |= UDF_FI_FLAG_KEEP_NAME; + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), + HASH_ALL | HASH_KEEP_NAME); + Count++; + FileId = (PFILE_IDENT_DESC)buff; + status = STATUS_SUCCESS; + prevOffset = 0; + while((OffsetLength) && FileId->descTag.tagIdent) { + // add new entry to index list + if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC) { + KdPrint((" Invalid tagIdent %x (expected %x) offst %x\n", FileId->descTag.tagIdent, TID_FILE_IDENT_DESC, Offset)); + DirPrint((" FileId: filen %x, iulen %x, charact %x\n", + FileId->lengthFileIdent, FileId->lengthOfImpUse, FileId->fileCharacteristics)); + DirPrint((" loc: @%x\n", UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, NULL))); + KdDump(FileId, sizeof(FileId->descTag)); + Offset = UDFFindNextFI(buff, prevOffset, (ULONG)(ExtInfo->Length)); + if(!Offset) { + DbgFreePool(buff); + UDFDirIndexFree(hDirNdx); + return STATUS_FILE_CORRUPT_ERROR; + } else { + DirPrint((" found next offs %x\n", Offset)); + FileId = (PFILE_IDENT_DESC)((buff)+Offset); + } + } + DirNdx = UDFDirIndex(hDirNdx,Count); + // allocate buffer & fill it with decompressed unicode filename + if(FileId->fileCharacteristics & FILE_DELETED) { + DirPrint((" FILE_DELETED\n")); + hDirNdx->DelCount++; + } + DirPrint((" FileId: offs %x, filen %x, iulen %x\n", Offset, FileId->lengthFileIdent, FileId->lengthOfImpUse)); + DirNdx->Length = (FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3)); + DirPrint((" DirNdx: Length %x, Charact %x\n", DirNdx->Length, FileId->fileCharacteristics)); + if(FileId->fileCharacteristics & FILE_PARENT) { + DirPrint((" parent\n")); + // init 'parent' entry + // '..' points to Parent Object (if any), + // otherwise it points to the Dir itself + DirNdx->FName.Buffer = L".."; + DirNdx->FName.Length = + (DirNdx->FName.MaximumLength = sizeof(L"..")) - sizeof(WCHAR); + DirNdx->FileInfo = (FileInfo->ParentFile) ? + FileInfo->ParentFile : FileInfo; + DirNdx->FI_Flags |= UDF_FI_FLAG_KEEP_NAME; + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL | HASH_KEEP_NAME); + } else { + // init plain file/dir entry + ASSERT( (Offset+sizeof(FILE_IDENT_DESC)+FileId->lengthOfImpUse+FileId->lengthFileIdent) <= + ExtInfo->Length ); + UDFDecompressUnicode(&(DirNdx->FName), + ((uint8*)(FileId+1)) + (FileId->lengthOfImpUse), + FileId->lengthFileIdent, + &valueCRC); + UDFNormalizeFileName(&(DirNdx->FName), valueCRC); + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL); + } + if((FileId->fileCharacteristics & FILE_METADATA) + || + !DirNdx->FName.Buffer + || + ((DirNdx->FName.Length >= sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) && + (RtlCompareMemory(DirNdx->FName.Buffer, UDF_RESERVED_NAME_HDR, sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) == sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) )) { + DirPrint((" metadata\n")); + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + } +#if 0 + KdPrint(("%ws\n", DirNdx->FName.Buffer)); +#endif + DirPrint(("%ws\n", DirNdx->FName.Buffer)); + // remember FileEntry location... + DirNdx->FileEntryLoc = FileId->icb.extLocation; + // ... and some file characteristics + DirNdx->FileCharacteristics = FileId->fileCharacteristics; + DirNdx->Offset = Offset; +#ifdef UDF_CHECK_DISK_ALLOCATION + if(!(FileId->fileCharacteristics & FILE_DELETED) && + (UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) != LBA_OUT_OF_EXTENT) && + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) )) { + + AdPrint(("Ref to Discarded block %x\n",UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) )); + BrutePoint(); + FileId->fileCharacteristics |= FILE_DELETED; + } else + if(UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) == LBA_OUT_OF_EXTENT) { + AdPrint(("Ref to Invalid block %x\n", UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) )); + BrutePoint(); + FileId->fileCharacteristics |= FILE_DELETED; + } +#endif // UDF_CHECK_DISK_ALLOCATION + prevOffset = Offset; + Offset += DirNdx->Length; + FileId = (PFILE_IDENT_DESC)(((int8*)FileId)+DirNdx->Length); + Count++; + if(Offset+sizeof(FILE_IDENT_DESC) > ExtInfo->Length) { + if(Offset != ExtInfo->Length) { + KdPrint((" Trash at the end of Dir (2)\n")); + } +// BrutePoint(); + break; + } + } // while() + // we needn't writing terminator 'cause the buffer is already zero-filled + DbgFreePool(buff); + if(Count < 2) { + UDFDirIndexFree(hDirNdx); + KdPrint((" Directory too short\n")); + return STATUS_FILE_CORRUPT_ERROR; + } + // store index + FileInfo->Dloc->DirIndex = hDirNdx; + return status; +} // end UDFIndexDirectory() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine removes all DELETED entries from Dir & resizes it. + It must be called before closing, no files sould be opened. + */ +OSSTATUS +UDFPackDirectory__( + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo // source (opened) + ) +{ +#ifdef UDF_PACK_DIRS + uint32 d, LBS; + uint_di i, j; + uint32 IUl, FIl, l; + uint32 DataLocOffset; + uint32 Offset, curOffset; + int8* Buf; + OSSTATUS status; + uint32 ReadBytes; + int8* storedFI; + PUDF_FILE_INFO curFileInfo; + PDIR_INDEX_ITEM DirNdx, DirNdx2; + UDF_DIR_SCAN_CONTEXT ScanContext; + uint_di dc=0; + uint16 PartNum; +#endif //UDF_PACK_DIRS + + ValidateFileInfo(FileInfo); + PDIR_INDEX_HDR hDirNdx = FileInfo->Dloc->DirIndex; + if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; +#ifndef UDF_PACK_DIRS + return STATUS_SUCCESS; +#else // UDF_PACK_DIRS + + // do not pack dirs on unchanged disks + if(!Vcb->Modified) + return STATUS_SUCCESS; + // start packing + LBS = Vcb->LBlockSize; + Buf = (int8*)DbgAllocatePool(PagedPool, LBS*2); + if(!Buf) return STATUS_INSUFFICIENT_RESOURCES; + // we shall never touch 1st entry 'cause it can't be deleted + Offset = UDFDirIndex(hDirNdx,2)->Offset; + DataLocOffset = FileInfo->Dloc->DataLoc.Offset; + + i=j=2; + + if(!UDFDirIndexInitScan(FileInfo, &ScanContext, i)) { + DbgFreePool(Buf); + return STATUS_SUCCESS; + } + + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + PartNum = (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + ASSERT(PartNum != -1); + + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + + if(UDFIsDeleted(DirNdx)) + dc++; + + if(!UDFIsDeleted(DirNdx) || + DirNdx->FileInfo) { + // move down valid entry + status = UDFReadFile__(Vcb, FileInfo, curOffset = DirNdx->Offset, + l = DirNdx->Length, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(Buf); + return status; + } + // remove ImpUse field + IUl = ((PFILE_IDENT_DESC)Buf)->lengthOfImpUse; + curFileInfo = DirNdx->FileInfo; + // align next entry + if((d = LBS - ((curOffset + (l - IUl) + DataLocOffset) & (LBS-1)) ) < sizeof(FILE_IDENT_DESC)) { + + // insufficient space at the end of last sector for + // next FileIdent's tag. fill it with ImpUse data + + // generally, all data should be DWORD-aligned, but if it is not so + // this opearation will help us to avoid glitches + d = (d+3) & ~(3); + if(d != IUl) { + l = l + d - IUl; + FIl = ((PFILE_IDENT_DESC)Buf)->lengthFileIdent; + // copy filename to upper addr + RtlMoveMemory(Buf+sizeof(FILE_IDENT_DESC)+d, + Buf+sizeof(FILE_IDENT_DESC)+IUl, FIl); + RtlZeroMemory(Buf+sizeof(FILE_IDENT_DESC), d); + ((PFILE_IDENT_DESC)Buf)->lengthOfImpUse = (uint16)d; + + if(curFileInfo && curFileInfo->FileIdent) { + // update stored FI if any + if(!MyReallocPool__((int8*)(curFileInfo->FileIdent), l, + (int8**)&(curFileInfo->FileIdent), (l+IUl-d) )) { + DbgFreePool(Buf); + return STATUS_INSUFFICIENT_RESOURCES; + } + storedFI = (int8*)(curFileInfo->FileIdent); + RtlMoveMemory(storedFI+sizeof(FILE_IDENT_DESC)+d, + storedFI+sizeof(FILE_IDENT_DESC)+IUl, FIl); + RtlZeroMemory(storedFI+sizeof(FILE_IDENT_DESC), d); + ((PFILE_IDENT_DESC)storedFI)->lengthOfImpUse = (uint16)d; + FileInfo->Dloc->FELoc.Modified = TRUE; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } + } + } else { + d = 0; + } + // write modified to new addr + if((d != IUl) || + (curOffset != Offset)) { + + UDFSetUpTag(Vcb, (tag*)Buf, (uint16)l, + UDFPhysLbaToPart(Vcb, PartNum, + UDFExtentOffsetToLba(Vcb, FileInfo->Dloc->DataLoc.Mapping, + Offset, NULL, NULL, NULL, NULL))); + + status = UDFWriteFile__(Vcb, FileInfo, Offset, l, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(Buf); + return status; + } + } + DirNdx2 = UDFDirIndex(hDirNdx, j); + *DirNdx2 = *DirNdx; + DirNdx2->Offset = Offset; + DirNdx2->Length = l; + if(curFileInfo) { + curFileInfo->Index = j; + DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + } + Offset += l; + j++; + } + } + // resize DirIndex + DbgFreePool(Buf); + if(dc) { + if(!OS_SUCCESS(status = UDFDirIndexTrunc(&(FileInfo->Dloc->DirIndex), dc))) { + return status; + } + } + // terminator is set by UDFDirIndexTrunc() + FileInfo->Dloc->DirIndex->DelCount = 0; + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + + // now Offset points to EOF. Let's truncate directory + return UDFResizeFile__(Vcb, FileInfo, Offset); +#endif // UDF_PACK_DIRS +} // end UDFPackDirectory__() + +/* + This routine rebuilds tags for all entries from Dir. + */ +OSSTATUS +UDFReTagDirectory( + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo // source (opened) + ) +{ + uint32 l; + uint32 Offset; + int8* Buf; + OSSTATUS status; + uint32 ReadBytes; + PUDF_FILE_INFO curFileInfo; + PDIR_INDEX_ITEM DirNdx; + UDF_DIR_SCAN_CONTEXT ScanContext; + uint16 PartNum; + + ValidateFileInfo(FileInfo); + PDIR_INDEX_HDR hDirNdx = FileInfo->Dloc->DirIndex; + if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; + + // do not pack dirs on unchanged disks + if(!Vcb->Modified) + return STATUS_SUCCESS; + + if( ((hDirNdx->DIFlags & UDF_DI_FLAG_INIT_IN_ICB) ? TRUE : FALSE) == + ((FileInfo->Dloc->DataLoc.Offset) ? TRUE : FALSE) ) { + return STATUS_SUCCESS; + } + + // start packing + Buf = (int8*)DbgAllocatePool(PagedPool, Vcb->LBlockSize*2); + if(!Buf) return STATUS_INSUFFICIENT_RESOURCES; + + Offset = UDFDirIndex(hDirNdx,1)->Offset; + + if(!UDFDirIndexInitScan(FileInfo, &ScanContext, 1)) { + DbgFreePool(Buf); + return STATUS_SUCCESS; + } + + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + PartNum = (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + ASSERT(PartNum != -1); + + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + + status = UDFReadFile__(Vcb, FileInfo, Offset = DirNdx->Offset, + l = DirNdx->Length, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(Buf); + return status; + } + curFileInfo = DirNdx->FileInfo; + // write modified + UDFSetUpTag(Vcb, (tag*)Buf, (uint16)l, + UDFPhysLbaToPart(Vcb, PartNum, + UDFExtentOffsetToLba(Vcb, FileInfo->Dloc->DataLoc.Mapping, + Offset, NULL, NULL, NULL, NULL))); + + if(curFileInfo && curFileInfo->FileIdent) { + FileInfo->Dloc->FELoc.Modified = TRUE; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } + + status = UDFWriteFile__(Vcb, FileInfo, Offset, l, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(Buf); + return status; + } + if(curFileInfo) { + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + } + } + // resize DirIndex + DbgFreePool(Buf); + + hDirNdx->DIFlags &= ~UDF_DI_FLAG_INIT_IN_ICB; + hDirNdx->DIFlags |= (FileInfo->Dloc->DataLoc.Offset ? UDF_DI_FLAG_INIT_IN_ICB : 0); + return status; + +} // end UDFReTagDirectory() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine performs search for specified file in specified directory & + returns corresponding offset in extent if found. + */ +OSSTATUS +UDFFindFile( + IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + IN PUNICODE_STRING Name, + IN PUDF_FILE_INFO DirInfo, + IN OUT uint_di* Index // IN:start index OUT:found file index + ) +{ +// PDIR_INDEX_HDR hDirIndex = DirInfo->Dloc->DirIndex; + UNICODE_STRING ShortName; + WCHAR ShortNameBuffer[13]; + PDIR_INDEX_ITEM DirNdx; + UDF_DIR_SCAN_CONTEXT ScanContext; + uint_di j=(-1), k=(-1); + HASH_ENTRY hashes; + BOOLEAN CanBe8d3; + + UDFBuildHashEntry(Vcb, Name, &hashes, HASH_POSIX | HASH_ULFN); + + if(CanBe8d3 = UDFCanNameBeA8dot3(Name)) { + ShortName.MaximumLength = 13 * sizeof(WCHAR); + ShortName.Buffer = (PWCHAR)&ShortNameBuffer; + } + + if(!UDFDirIndexInitScan(DirInfo, &ScanContext, (*Index))) + return STATUS_OBJECT_NAME_NOT_FOUND; + + if(!IgnoreCase && !CanBe8d3) { + // perform case sensetive sequential directory scan + + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + if( (DirNdx->hashes.hPosix == hashes.hPosix) && + DirNdx->FName.Buffer && + (!RtlCompareUnicodeString(&(DirNdx->FName), Name, FALSE)) && + ( (!UDFIsDeleted(DirNdx)) || (!NotDeleted) ) ) { + (*Index) = ScanContext.i; + return STATUS_SUCCESS; + } + } + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + if(hashes.hPosix == hashes.hLfn) { + + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + if(!DirNdx->FName.Buffer || + (NotDeleted && UDFIsDeleted(DirNdx)) ) + continue; + if( (DirNdx->hashes.hLfn == hashes.hLfn) && + (!RtlCompareUnicodeString(&(DirNdx->FName), Name, IgnoreCase)) ) { + (*Index) = ScanContext.i; + return STATUS_SUCCESS; + } else + if( CanBe8d3 && + !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS) && + (DirNdx->hashes.hDos == hashes.hLfn) && + (k == (uint_di)(-1))) { + UDFDOSName(Vcb, &ShortName, &(DirNdx->FName), ScanContext.i < 2) ; + if(!RtlCompareUnicodeString(&ShortName, Name, IgnoreCase)) + k = ScanContext.i; + } + } + + } else { + + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + // perform sequential directory scan + if(!DirNdx->FName.Buffer || + (NotDeleted && UDFIsDeleted(DirNdx)) ) + continue; + if( (DirNdx->hashes.hPosix == hashes.hPosix) && + (!RtlCompareUnicodeString(&(DirNdx->FName), Name, FALSE)) ) { + (*Index) = ScanContext.i; + return STATUS_SUCCESS; + } else + if( (DirNdx->hashes.hLfn == hashes.hLfn) && + (j == (uint_di)(-1)) && + (!RtlCompareUnicodeString(&(DirNdx->FName), Name, IgnoreCase)) ) { + j = ScanContext.i; + } else + if( CanBe8d3 && + !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS) && + (DirNdx->hashes.hDos == hashes.hLfn) && + (k == (uint_di)(-1))) { + UDFDOSName(Vcb, &ShortName, &(DirNdx->FName), ScanContext.i < 2 ); + if(!RtlCompareUnicodeString(&ShortName, Name, IgnoreCase)) { + k = ScanContext.i; + } + } + } + } + + if(j != (uint_di)(-1)) { + (*Index) = j; + return STATUS_SUCCESS; + } else + if(k != (uint_di)(-1)) { + (*Index) = k; + return STATUS_SUCCESS; + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + +} // end UDFFindFile() + +/* + This routine returns pointer to parent DirIndex +*/ +PDIR_INDEX_HDR +UDFGetDirIndexByFileInfo( + IN PUDF_FILE_INFO FileInfo + ) +{ + ValidateFileInfo(FileInfo); + + if(!FileInfo) { + BrutePoint(); + return NULL; + } + if (FileInfo->ParentFile) { + ValidateFileInfo(FileInfo->ParentFile); + + if(UDFIsAStreamDir(FileInfo)) + return NULL; + if(FileInfo->ParentFile->Dloc) + return FileInfo->ParentFile->Dloc->DirIndex; + return NULL; + } + if(FileInfo->Dloc) + return FileInfo->Dloc->DirIndex; + return NULL; +} + +/* + File Data Location support routines (UDFXxxDloc) + This group is responsible for caching FE locations + If requested FE referenced by another FI the file is assumed to be linked + All linked files reference to common Data Location (& attr) structure + */ + +/* + Check if given FE is already in use + */ +LONG +UDFFindDloc( + IN PVCB Vcb, + IN uint32 Lba + ) +{ + PUDF_DATALOC_INDEX DlocList; + uint32 l; + + if(!(DlocList = Vcb->DlocList) || !Lba) return (-1); + // scan FE location cache + l = Vcb->DlocCount; + for(uint32 i=0; iLba == Lba) + return i; + } + return (-1); +} // end UDFFindDloc() + +/* + Check if given FE is already stored in memory + */ +LONG +UDFFindDlocInMem( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + PUDF_DATALOC_INDEX DlocList; + uint32 l; + + if(!(DlocList = Vcb->DlocList) || !Dloc) return (-1); + // scan FE location cache + l = Vcb->DlocCount; + for(uint32 i=0; iDloc == Dloc) + return i; + } + return (-1); +} // end UDFFindDlocInMem() + +/* + Find free cache entry + */ +LONG +UDFFindFreeDloc( + IN PVCB Vcb, + IN uint32 Lba + ) +{ + PUDF_DATALOC_INDEX DlocList; + uint32 l; + + if(!Vcb->DlocList) { + // init FE location cache + if(!(Vcb->DlocList = (PUDF_DATALOC_INDEX)MyAllocatePoolTag__(NonPagedPool, sizeof(UDF_DATALOC_INDEX)*DLOC_LIST_GRANULARITY, MEM_DLOC_NDX_TAG))) + return (-1); + RtlZeroMemory(Vcb->DlocList, DLOC_LIST_GRANULARITY*sizeof(UDF_DATALOC_INDEX)); + Vcb->DlocCount = DLOC_LIST_GRANULARITY; + } + // scan for free entry + DlocList = Vcb->DlocList; + l = Vcb->DlocCount; + for(uint32 i=0; iDloc) + return i; + } + // alloc some free entries + if(!MyReallocPool__((int8*)(Vcb->DlocList), Vcb->DlocCount*sizeof(UDF_DATALOC_INDEX), + (int8**)&(Vcb->DlocList), (Vcb->DlocCount+DLOC_LIST_GRANULARITY)*sizeof(UDF_DATALOC_INDEX))) { + return (-1); + } + RtlZeroMemory(&(Vcb->DlocList[Vcb->DlocCount]), DLOC_LIST_GRANULARITY*sizeof(UDF_DATALOC_INDEX)); + Vcb->DlocCount += DLOC_LIST_GRANULARITY; + return (Vcb->DlocCount - DLOC_LIST_GRANULARITY); +} // end UDFFindFreeDloc() + +/* + */ +OSSTATUS +UDFAcquireDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + UDFAcquireResourceExclusive(&(Vcb->DlocResource2),TRUE); + if(Dloc->FE_Flags & UDF_FE_FLAG_UNDER_INIT) { + UDFReleaseResource(&(Vcb->DlocResource2)); + return STATUS_SHARING_PAUSED; + } + Dloc->FE_Flags |= UDF_FE_FLAG_UNDER_INIT; + UDFReleaseResource(&(Vcb->DlocResource2)); + return STATUS_SUCCESS; +} // end UDFAcquireDloc() + +/* + */ +OSSTATUS +UDFReleaseDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + UDFAcquireResourceExclusive(&(Vcb->DlocResource2),TRUE); + Dloc->FE_Flags &= ~UDF_FE_FLAG_UNDER_INIT; + UDFReleaseResource(&(Vcb->DlocResource2)); + return STATUS_SUCCESS; +} // end UDFReleaseDloc() + +/* + Try to store FE location in cache + If it is already in use, caller will be informed about it + */ +OSSTATUS +UDFStoreDloc( + IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN uint32 Lba + ) +{ + LONG i; + PUDF_DATALOC_INFO Dloc; + + if(!Lba) return STATUS_INVALID_PARAMETER; + if(Lba == (-1)) return STATUS_INVALID_PARAMETER; + + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + + // check if FE specified is already in use + if((i = UDFFindDloc(Vcb, Lba)) == (-1)) { + // not used + if((i = UDFFindFreeDloc(Vcb, Lba)) == (-1)) { + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_INSUFFICIENT_RESOURCES; + } + } else { + if(!OS_SUCCESS(UDFAcquireDloc(Vcb, Dloc = Vcb->DlocList[i].Dloc))) { + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_SHARING_PAUSED; + } + // update caller's structures & exit + fi->Dloc = Dloc; + UDFReleaseDloc(Vcb, Dloc); +#if defined UDF_DBG && !defined _CONSOLE + if(fi->Dloc->CommonFcb) { + ASSERT((uint32)(fi->Dloc->CommonFcb) != 0xDEADDA7A); + ASSERT(fi->Dloc->CommonFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); + } +#endif // UDF_DBG + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_SUCCESS; + } + // allocate common DataLocation (Dloc) descriptor + Dloc = fi->Dloc = (PUDF_DATALOC_INFO)MyAllocatePoolTag__(UDF_DATALOC_INFO_MT, sizeof(UDF_DATALOC_INFO), MEM_DLOC_INF_TAG); + if(!Dloc) { + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_INSUFFICIENT_RESOURCES; + } + Vcb->DlocList[i].Lba = Lba; + Vcb->DlocList[i].Dloc = Dloc; + RtlZeroMemory(Dloc, sizeof(UDF_DATALOC_INFO)); + Dloc->LinkedFileInfo = fi; + UDFAcquireDloc(Vcb, Dloc); + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_SUCCESS; +} // end UDFStoreDloc() + +/* + Remove unreferenced FE location from cache & free allocated memory + This routine must be invoked when there are no more opened files + associated with given FE + */ +OSSTATUS +UDFRemoveDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + LONG i; + + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + + if((i = UDFFindDlocInMem(Vcb, Dloc)) == (-1)) { + // FE specified is not in cache. exit + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_INVALID_PARAMETER; + } + // remove from cache + ASSERT(Vcb->DlocList); + RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX)); + UDFReleaseResource(&(Vcb->DlocResource)); + MyFreePool__(Dloc); + return STATUS_SUCCESS; +} // end UDFRemoveDloc() + +/* + Remove unlinked FE location from cache & keep allocated memory + This routine must be invoked when there are no more opened files + associated with given FE + */ +OSSTATUS +UDFUnlinkDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + LONG i; + + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + + if((i = UDFFindDlocInMem(Vcb, Dloc)) == (-1)) { + // FE specified is not in cache. exit + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_INVALID_PARAMETER; + } + // remove from cache + ASSERT(Vcb->DlocList); + RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX)); + UDFReleaseResource(&(Vcb->DlocResource)); + return STATUS_SUCCESS; +} // end UDFUnlinkDloc() + +/* + This routine releases memory allocated for Dloc & removes it from + cache (if it is still there) + */ +void +UDFFreeDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc + ) +{ + LONG i; + + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + + if((i = UDFFindDlocInMem(Vcb, Dloc)) != (-1)) { + ASSERT(Vcb->DlocList); + RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX)); + } + UDFReleaseResource(&(Vcb->DlocResource)); + MyFreePool__(Dloc); +} // end UDFFreeDloc() + +/* + This routine updates Dloc LBA after relocation + */ +void +UDFRelocateDloc( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc, + IN uint32 NewLba + ) +{ + LONG i; + + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + + if((i = UDFFindDlocInMem(Vcb, Dloc)) != (-1)) { + ASSERT(Vcb->DlocList); + Vcb->DlocList[i].Lba = NewLba; + } + UDFReleaseResource(&(Vcb->DlocResource)); + +} // end UDFRelocateDloc() + +/* + Release FE cache + */ +void +UDFReleaseDlocList( + IN PVCB Vcb + ) +{ + if(!Vcb->DlocList) return; + UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE); + for(uint32 i=0; iDlocCount; i++) { + if(Vcb->DlocList[i].Dloc) + MyFreePool__(Vcb->DlocList[i].Dloc); + } + MyFreePool__(Vcb->DlocList); + Vcb->DlocList = NULL; + Vcb->DlocCount = 0; + UDFReleaseResource(&(Vcb->DlocResource)); +} // end UDFReleaseDlocList() + +/* + This routine walks through Linked/Parallel FI chain and looks for + FE with same Index & Parent File + */ +PUDF_FILE_INFO +UDFLocateParallelFI( + PUDF_FILE_INFO di, // parent FileInfo + uint_di i, // Index + PUDF_FILE_INFO fi // FileInfo to start search from + ) +{ + PUDF_FILE_INFO ParFileInfo = fi->NextLinkedFile; +// PUDF_DATALOC_INFO Dloc = di->Dloc; + while((ParFileInfo != fi) && + ((ParFileInfo->ParentFile != di) || + (ParFileInfo->Index != i)) ) { + ParFileInfo = ParFileInfo->NextLinkedFile; + } + return ParFileInfo; +// BrutePoint(); +} // end UDFLocateParallelFI() + +/* + This routine walks through Linked/Parallel FI chain and looks for + FE with same Index & Parent Dloc + */ +PUDF_FILE_INFO +UDFLocateAnyParallelFI( + PUDF_FILE_INFO fi // FileInfo to start search from + ) +{ + if(!fi->ParentFile) { + if(fi->NextLinkedFile == fi) + return NULL; + return fi->NextLinkedFile; + } + PUDF_FILE_INFO ParFileInfo = fi->NextLinkedFile; + PUDF_DATALOC_INFO Dloc = fi->ParentFile->Dloc; + uint_di i = fi->Index; + BOOLEAN NotFound = TRUE; + while((ParFileInfo != fi) && + (NotFound = + ((ParFileInfo->Index != i) || + (ParFileInfo->ParentFile->Dloc != Dloc))) ) { + ParFileInfo = ParFileInfo->NextLinkedFile; + } +/* if(NotFound) { + if((ParFileInfo->Index == i) && + (ParFileInfo->ParentFile->Dloc == Dloc)) + return ParFileInfo; + return NULL; + } + return ParFileInfo;*/ + return NotFound ? NULL : ParFileInfo; +// BrutePoint(); +} // end UDFLocateAnyParallelFI() + +void +UDFInsertLinkedFile( + PUDF_FILE_INFO fi, // FileInfo to be added to chain + PUDF_FILE_INFO fi2 // any FileInfo fro the chain + ) +{ + fi->NextLinkedFile = fi2->NextLinkedFile; + fi->PrevLinkedFile = fi2; + fi->NextLinkedFile->PrevLinkedFile = + fi->PrevLinkedFile->NextLinkedFile = fi; + return; +} // end UDFInsertLinkedFile() + diff --git a/reactos/drivers/filesystems/udfs/udf_info/ecma_167.h b/reactos/drivers/filesystems/udfs/udf_info/ecma_167.h new file mode 100644 index 00000000000..0aa5b2e36bb --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/ecma_167.h @@ -0,0 +1,775 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + ecma_167.h + + Abstract: + + This file contains ECMA-167 definitions + +*/ + +#ifndef __ECMA_167_H__ +#define __ECMA_167_H__ + +typedef uint8 dstring; + +#define UDF_COMP_ID_8 0x08 +#define UDF_COMP_ID_16 0x10 + +/* make sure all structures are packed! */ +#pragma pack(push, 1) + +/* CS0 Charspec (ECMA 167 1/7.2.1) */ +typedef struct { + uint8 charSetType; + uint8 charSetInfo[63]; +} charspec; + +/* Timestamp (ECMA 167 1/7.3) */ +typedef struct { + uint16 typeAndTimezone; + uint16 year; + uint8 month; + uint8 day; + uint8 hour; + uint8 minute; + uint8 second; + uint8 centiseconds; + uint8 hundredsOfMicroseconds; + uint8 microseconds; +} timestamp; + +typedef timestamp UDF_TIME_STAMP; +typedef UDF_TIME_STAMP* PUDF_TIME_STAMP; + +/* Timestamp types (ECMA 167 1/7.3.1) */ +#define TIMESTAMP_TYPE_CUT 0x0000U +#define TIMESTAMP_TYPE_LOCAL 0x0001U +#define TIMESTAMP_TYPE_AGREEMENT 0x0002U +#define TIMESTAMP_OFFSET_MASK 0x0FFFU +#define TIMESTAMP_NO_OFFSET 0x0800U + +/* Entity Identifier (ECMA 167 1/7.4) */ +typedef struct { + uint8 flags; + uint8 ident[23]; + uint8 identSuffix[8]; +} EntityID; +#define regid EntityID + +/* Entity identifier flags (ECMA 167 1/7.4.1) */ +#define ENTITYID_FLAGS_DIRTY 0x01U +#define ENTITYID_FLAGS_PROTECTED 0x02U + +/* Volume Structure Descriptor (ECMA 167 2/9.1) */ +#define STD_ID_LEN 5 +struct VolStructDesc { + uint8 structType; + uint8 stdIdent[STD_ID_LEN]; + uint8 structVersion; + uint8 structData[2041]; +}; + +/* Std structure identifiers (ECMA 167 2/9.1.2) */ +#define STD_ID_BEA01 "BEA01" +#define STD_ID_BOOT2 "BOOT2" +#define STD_ID_CD001 "CD001" +#define STD_ID_CDW02 "CDW02" +#define STD_ID_NSR02 "NSR02" +#define STD_ID_NSR03 "NSR03" +#define STD_ID_TEA01 "TEA01" + +/* Beginning Extended Area Descriptor (ECMA 167 2/9.2) */ +struct BeginningExtendedAreaDesc { + uint8 structType; + uint8 stdIdent[STD_ID_LEN]; + uint8 structVersion; + uint8 structData[2041]; +}; + +/* Terminating Extended Area Descriptor (ECMA 167 2/9.3) */ +struct TerminatingExtendedAreaDesc { + uint8 structType; + uint8 stdIdent[STD_ID_LEN]; + uint8 structVersion; + uint8 structData[2041]; +}; + +/* Boot Descriptor (ECMA 167 2/9.4) */ +typedef struct _BootDesc { + uint8 structType; + uint8 stdIdent[STD_ID_LEN]; + uint8 structVersion; + uint8 reserved1; + EntityID architectureType; + EntityID bootIdent; + uint32 bootExtLocation; + uint32 bootExtLength; + uint64 loadAddress; + uint64 startAddress; + timestamp descCreationDateAndTime; + uint16 flags; + uint8 reserved2[32]; + uint8 bootUse[1906]; +} BootDesc, *PBootDesc; + +/* Boot flags (ECMA 167 2/9.4.12) */ +#define BOOT_FLAGS_ERASE 1 + +/* Extent Descriptor (ECMA 167 3/7.1) */ + +typedef struct _EXTENT_AD { + uint32 extLength; + uint32 extLocation; // Lba +} EXTENT_AD, *PEXTENT_AD; + +typedef EXTENT_AD extent_ad; + +typedef EXTENT_AD EXTENT_MAP; +typedef PEXTENT_AD PEXTENT_MAP; + +/* Descriptor Tag (ECMA 167 3/7.2) */ +typedef struct { + uint16 tagIdent; + uint16 descVersion; + uint8 tagChecksum; + uint8 reserved; + uint16 tagSerialNum; + uint16 descCRC; + uint16 descCRCLength; + uint32 tagLocation; +} tag; + +typedef tag DESC_TAG; +typedef DESC_TAG* PDESC_TAG; + +/* Tag Identifiers (ECMA 167 3/7.2.1) */ +#define TID_UNUSED_DESC 0x0000U +#define TID_PRIMARY_VOL_DESC 0x0001U +#define TID_ANCHOR_VOL_DESC_PTR 0x0002U +#define TID_VOL_DESC_PTR 0x0003U +#define TID_IMP_USE_VOL_DESC 0x0004U +#define TID_PARTITION_DESC 0x0005U +#define TID_LOGICAL_VOL_DESC 0x0006U +#define TID_UNALLOC_SPACE_DESC 0x0007U +#define TID_TERMINATING_DESC 0x0008U +#define TID_LOGICAL_VOL_INTEGRITY_DESC 0x0009U + +/* Tag Identifiers (ECMA 167 4/7.2.1) */ +#define TID_FILE_SET_DESC 0x0100U +#define TID_FILE_IDENT_DESC 0x0101U +#define TID_ALLOC_EXTENT_DESC 0x0102U +#define TID_INDIRECT_ENTRY 0x0103U +#define TID_TERMINAL_ENTRY 0x0104U +#define TID_FILE_ENTRY 0x0105U +#define TID_EXTENDED_ATTRE_HEADER_DESC 0x0106U +#define TID_UNALLOCATED_SPACE_ENTRY 0x0107U +#define TID_SPACE_BITMAP_DESC 0x0108U +#define TID_PARTITION_INTEGRITY_ENTRY 0x0109U +#define TID_EXTENDED_FILE_ENTRY 0x010AU + +/* NSR Descriptor (ECMA 167 3/9.1) */ +struct NSRDesc { + uint8 structType; + uint8 stdIdent[STD_ID_LEN]; + uint8 structVersion; + uint8 reserved; + uint8 structData[2040]; +}; + +/* Primary Volume Descriptor (ECMA 167 3/10.1) */ +struct PrimaryVolDesc { + tag descTag; + uint32 volDescSeqNum; + uint32 primaryVolDescNum; + dstring volIdent[32]; + uint16 volSeqNum; + uint16 maxVolSeqNum; + uint16 interchangeLvl; + uint16 maxInterchangeLvl; + uint32 charSetList; + uint32 maxCharSetList; + dstring volSetIdent[128]; + charspec descCharSet; + charspec explanatoryCharSet; + extent_ad volAbstract; + extent_ad volCopyright; + EntityID appIdent; + timestamp recordingDateAndTime; + EntityID impIdent; + uint8 impUse[64]; + uint32 predecessorVolDescSeqLocation; + uint16 flags; + uint8 reserved[22]; +}; + +/* Primary volume descriptor flags (ECMA 167 3/10.1.21) */ +#define VOL_SET_IDENT 1 + +/* Anchor Volume Descriptor Pointer (ECMA 167 3/10.2) */ +struct AnchorVolDescPtr { + tag descTag; + extent_ad mainVolDescSeqExt; + extent_ad reserveVolDescSeqExt; + uint8 reserved[480]; +}; + +/* Volume Descriptor Pointer (ECMA 167 3/10.3) */ +struct VolDescPtr { + tag descTag; + uint32 volDescSeqNum; + extent_ad nextVolDescSeqExt; + uint8 reserved[484]; +}; + +#define MAX_VDS_PARTS 32 + +/* Implementation Use Volume Descriptor (ECMA 167 3/10.4) */ +struct ImpUseVolDesc { + tag descTag; + uint32 volDescSeqNum; + EntityID impIdent; + uint8 impUse[460]; +}; + +/* Partition Descriptor (ECMA 167 3/10.5) */ +struct PartitionDesc { + tag descTag; + uint32 volDescSeqNum; + uint16 partitionFlags; + uint16 partitionNumber; + EntityID partitionContents; + uint8 partitionContentsUse[128]; + uint32 accessType; + uint32 partitionStartingLocation; + uint32 partitionLength; + EntityID impIdent; + uint8 impUse[128]; + uint8 reserved[156]; +}; + +/* Partition Flags (ECMA 167 3/10.5.3) */ +#define PARTITION_FLAGS_ALLOC 1 + +/* Partition Contents (ECMA 167 3/10.5.5) */ +#define PARTITION_CONTENTS_FDC01 "+FDC01" +#define PARTITION_CONTENTS_CD001 "+CD001" +#define PARTITION_CONTENTS_CDW02 "+CDW02" +#define PARTITION_CONTENTS_NSR02 "+NSR02" +#define PARTITION_CONTENTS_NSR03 "+NSR03" + +/* Partition Access Types (ECMA 167 3/10.5.7) */ +#define PARTITION_ACCESS_NONE 0 +#define PARTITION_ACCESS_R 1 +#define PARTITION_ACCESS_WO 2 +#define PARTITION_ACCESS_RW 3 +#define PARTITION_ACCESS_OW 4 +#define PARTITION_ACCESS_MAX_KNOWN PARTITION_ACCESS_OW + +/* Logical Volume Descriptor (ECMA 167 3/10.6) */ +struct LogicalVolDesc { + tag descTag; + uint32 volDescSeqNum; + charspec descCharSet; + dstring logicalVolIdent[128]; + uint32 logicalBlockSize; + EntityID domainIdent; + uint8 logicalVolContentsUse[16]; /* used to find fileset */ + uint32 mapTableLength; + uint32 numPartitionMaps; + EntityID impIdent; + uint8 impUse[128]; + extent_ad integritySeqExt; +// uint8 partitionMaps[0]; +}; + +/* Generic Partition Map (ECMA 167 3/10.7.1) */ +struct GenericPartitionMap { + uint8 partitionMapType; + uint8 partitionMapLength; +// uint8 partitionMapping[0]; +}; + +/* Partition Map Type (ECMA 167 3/10.7.1.1) */ +#define PARTITION_MAP_TYPE_NONE 0 +#define PARTITION_MAP_TYPE_1 1 +#define PARTITION_MAP_TYPE_2 2 + +/* Type 1 Partition Map (ECMA 167 3/10.7.2) */ +struct GenericPartitionMap1 { + uint8 partitionMapType; + uint8 partitionMapLength; + uint16 volSeqNum; + uint16 partitionNum; +}; + +/* Type 2 Partition Map (ECMA 167 3/10.7.3) */ +struct GenericPartitionMap2 { + uint8 partitionMapType; /* 2 */ + uint8 partitionMapLength; + uint8 partitionIdent[62]; +}; + +/* Unallocated Space Descriptor (ECMA 167 3/10.8) */ +typedef struct _UNALLOC_SPACE_DESC { + tag descTag; + uint32 volDescSeqNum; + uint32 numAllocDescs; +// extent_ad allocDescs[0]; +} UNALLOC_SPACE_DESC, *PUNALLOC_SPACE_DESC; + +typedef UNALLOC_SPACE_DESC UnallocatedSpaceDesc; + +/* Terminating Descriptor (ECMA 3/10.9) */ +struct TerminatingDesc { + tag descTag; + uint8 reserved[496]; +}; + +struct GenericDesc +{ + tag descTag; + uint32 volDescSeqNum; +}; + +/* Logical Volume Integrity Descriptor (ECMA 167 3/10.10) */ + +struct LogicalVolIntegrityDesc { + tag descTag; + timestamp recordingDateAndTime; + uint32 integrityType; + extent_ad nextIntegrityExt; + uint8 logicalVolContentsUse[32]; + uint32 numOfPartitions; + uint32 lengthOfImpUse; +// uint32 freeSpaceTable[0]; +// uint32 sizeTable[0]; +// uint8 impUse[0]; +}; + +/* Integrity Types (ECMA 167 3/10.10.3) */ +#define INTEGRITY_TYPE_OPEN 0 +#define INTEGRITY_TYPE_CLOSE 1 + +/* Recorded Address (ECMA 167 4/7.1) */ +typedef struct { + uint32 logicalBlockNum; + uint16 partitionReferenceNum; +} lb_addr; + +/* Extent interpretation (ECMA 167 4/14.14.1.1) */ +#define EXTENT_RECORDED_ALLOCATED 0x00 +#define EXTENT_NOT_RECORDED_ALLOCATED 0x01 +#define EXTENT_NOT_RECORDED_NOT_ALLOCATED 0x02 +#define EXTENT_NEXT_EXTENT_ALLOCDESC 0x03 + +/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */ +typedef struct { + uint32 extLength; + lb_addr extLocation; + uint8 impUse[6]; +} long_ad; + /* upper 2 bits of extLength indicate type */ +typedef long_ad LONG_AD; +typedef LONG_AD* PLONG_AD; + +/* File Set Descriptor (ECMA 167 4/14.1) */ +typedef struct _FILE_SET_DESC { + tag descTag; + timestamp recordingDateAndTime; + uint16 interchangeLvl; + uint16 maxInterchangeLvl; + uint32 charSetList; + uint32 maxCharSetList; + uint32 fileSetNum; + uint32 fileSetDescNum; + charspec logicalVolIdentCharSet; + dstring logicalVolIdent[128]; + charspec fileSetCharSet; + dstring fileSetIdent[32]; + dstring copyrightFileIdent[32]; + dstring abstractFileIdent[32]; + long_ad rootDirectoryICB; //points to Allocation Ext Descriptor + EntityID domainIdent; + long_ad nextExt; + long_ad streamDirectoryICB; + uint8 reserved[32]; +} FILE_SET_DESC, *PFILE_SET_DESC; + +/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */ +typedef struct _SHORT_AD { + uint32 extLength; + uint32 extPosition; +} SHORT_AD, *PSHORT_AD; + +typedef SHORT_AD short_ad; + +/* Partition Header Descriptor (ECMA 167 4/14.3) */ +typedef struct _PARTITION_HEADER_DESC { + short_ad unallocatedSpaceTable; + short_ad unallocatedSpaceBitmap; // 0 - allocated, 1 - free + short_ad partitionIntegrityTable; + short_ad freedSpaceTable; + short_ad freedSpaceBitmap; // 0 - ???? 1 - freed + uint8 reserved[88]; +} PARTITION_HEADER_DESC, *PPARTITION_HEADER_DESC; + +/* File Identifier Descriptor (ECMA 167 4/14.4) */ + +typedef struct _FILE_IDENT_DESC { + tag descTag; + uint16 fileVersionNum; + uint8 fileCharacteristics; + uint8 lengthFileIdent; + long_ad icb; + uint16 lengthOfImpUse; +// uint8 impUse[0]; +// uint8 fileIdent[0]; +// uint8 padding[0]; +} FILE_IDENT_DESC, *PFILE_IDENT_DESC; + +/* File Characteristics (ECMA 167 4/14.4.3) */ +#define FILE_HIDDEN 0x01 +#define FILE_DIRECTORY 0x02 +#define FILE_DELETED 0x04 +#define FILE_PARENT 0x08 +#define FILE_METADATA 0x10 /* UDF 2.0 */ + +/* Allocation Ext Descriptor (ECMA 167 4/14.5) */ +typedef struct _ALLOC_EXT_DESC { + tag descTag; + uint32 previousAllocExtLocation; + uint32 lengthAllocDescs; +} ALLOC_EXT_DESC, *PALLOC_EXT_DESC; + +/* ICB Tag (ECMA 167 4/14.6) */ +typedef struct { + uint32 priorRecordedNumDirectEntries; + uint16 strategyType; + uint16 strategyParameter; + uint16 numEntries; + uint8 reserved; + uint8 fileType; + lb_addr parentICBLocation; + uint16 flags; +} icbtag; + +/* ICB File Type (ECMA 167 4/14.6.6) */ +#define UDF_FILE_TYPE_NONE 0x00U +#define UDF_FILE_TYPE_UNALLOC 0x01U +#define UDF_FILE_TYPE_INTEGRITY 0x02U +#define UDF_FILE_TYPE_INDIRECT 0x03U +#define UDF_FILE_TYPE_DIRECTORY 0x04U +#define UDF_FILE_TYPE_REGULAR 0x05U +#define UDF_FILE_TYPE_BLOCK 0x06U +#define UDF_FILE_TYPE_CHAR 0x07U +#define UDF_FILE_TYPE_EXTENDED 0x08U +#define UDF_FILE_TYPE_FIFO 0x09U +#define UDF_FILE_TYPE_SOCKET 0x0aU +#define UDF_FILE_TYPE_TERMINAL 0x0bU +#define UDF_FILE_TYPE_SYMLINK 0x0cU +#define UDF_FILE_TYPE_STREAMDIR 0x0dU /* ECMA 167 4/13 */ + +/* ICB Flags (ECMA 167 4/14.6.8) */ +#define ICB_FLAG_ALLOC_MASK 0x0007U +#define ICB_FLAG_SORTED 0x0008U +#define ICB_FLAG_NONRELOCATABLE 0x0010U +#define ICB_FLAG_ARCHIVE 0x0020U +#define ICB_FLAG_SETUID 0x0040U +#define ICB_FLAG_SETGID 0x0080U +#define ICB_FLAG_STICKY 0x0100U +#define ICB_FLAG_CONTIGUOUS 0x0200U +#define ICB_FLAG_SYSTEM 0x0400U +#define ICB_FLAG_TRANSFORMED 0x0800U +#define ICB_FLAG_MULTIVERSIONS 0x1000U + +/* ICB Flags Allocation type(ECMA 167 4/14.6.8) */ +#define ICB_FLAG_AD_SHORT 0 +#define ICB_FLAG_AD_LONG 1 +#define ICB_FLAG_AD_EXTENDED 2 +#define ICB_FLAG_AD_IN_ICB 3 + +/* Indirect Entry (ECMA 167 4/14.7) */ +struct IndirectEntry { + tag descTag; + icbtag icbTag; + long_ad indirectICB; +}; + +/* Terminal Entry (ECMA 167 4/14.8) */ +struct TerminalEntry { + tag descTag; + icbtag icbTag; +}; + +/* File Entry (ECMA 167 4/14.9) */ + +typedef struct _FILE_ENTRY { + tag descTag; + icbtag icbTag; + uint32 uid; + uint32 gid; + uint32 permissions; + uint16 fileLinkCount; + uint8 recordFormat; + uint8 recordDisplayAttr; + uint32 recordLength; + uint64 informationLength; + uint64 logicalBlocksRecorded; + timestamp accessTime; + timestamp modificationTime; + timestamp attrTime; + uint32 checkpoint; + long_ad extendedAttrICB; + EntityID impIdent; + uint64 uniqueID; /* 0= root, 16- (2^32-1) */ + + uint32 lengthExtendedAttr; + uint32 lengthAllocDescs; +// uint8 extendedAttr[0]; +// uint8 allocDescs[0]; +} FILE_ENTRY, *PFILE_ENTRY; + +/* File Permissions (ECMA 167 4/14.9.5) */ +#define PERM_O_EXEC 0x00000001U +#define PERM_O_WRITE 0x00000002U +#define PERM_O_READ 0x00000004U +#define PERM_O_CHATTR 0x00000008U +#define PERM_O_DELETE 0x00000010U +#define PERM_G_EXEC 0x00000020U +#define PERM_G_WRITE 0x00000040U +#define PERM_G_READ 0x00000080U +#define PERM_G_CHATTR 0x00000100U +#define PERM_G_DELETE 0x00000200U +#define PERM_U_EXEC 0x00000400U +#define PERM_U_WRITE 0x00000800U +#define PERM_U_READ 0x00001000U +#define PERM_U_CHATTR 0x00002000U +#define PERM_U_DELETE 0x00004000U + +/* File Record Format (ECMA 167 4/14.9.7) */ +#define RECORD_FMT_NONE 0 +#define RECORD_FMT_FIXED_PAD 1 +#define RECORD_FMT_FIXED 2 +#define RECORD_FMT_VARIABLE8 3 +#define RECORD_FMT_VARIABLE16 4 +#define RECORD_FMT_VARIABLE16_MSB 5 +#define RECORD_FMT_VARIABLE32 6 +#define RECORD_FMT_PRINT 7 +#define RECORD_FMT_LF 8 +#define RECORD_FMT_CR 9 +#define RECORD_FMT_CRLF 10 +#define RECORD_FMT_LFCR 10 + +/* Extended Attribute Header Descriptor (ECMA 167 4/14.10.1) */ +struct ExtendedAttrHeaderDesc { + tag descTag; + uint32 impAttrLocation; + uint32 appAttrLocation; +}; + +/* Generic Attribute Format (ECMA 4/14.10.2) */ +struct GenericAttrFormat { + uint32 attrType; + uint8 attrSubtype; + uint8 reserved[3]; + uint32 attrLength; +// uint8 attrData[0]; +}; + +/* Character Set Attribute Format (ECMA 4/14.10.3) */ +struct CharSetAttrFormat { + uint32 attrType; /* 1 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 escapeSeqLength; + uint8 charSetType; +// uint8 escapeSeq[0]; +}; + +/* Alternate Permissions (ECMA 167 4/14.10.4) */ +struct AlternatePermissionsExtendedAttr { + uint32 attrType; /* 3 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint16 ownerIdent; + uint16 groupIdent; + uint16 permission; +}; + +/* File Times Extended Attribute (ECMA 167 4/14.10.5) */ +struct FileTimesExtendedAttr { + uint32 attrType; /* 5 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 dataLength; + uint32 fileTimeExistence; +// timestamp fileTimes[0]; +}; + +/* FileTimeExistence (ECMA 167 4/14.10.5.6) */ +#define FTE_CREATION 0 +#define FTE_DELETION 2 +#define FTE_EFFECTIVE 3 +#define FTE_BACKUP 5 + +/* Information Times Extended Attribute (ECMA 167 4/14.10.6) */ +struct InfoTimesExtendedAttr { + uint32 attrType; /* 6 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 dataLength; + uint32 infoTimeExistence; +// uint8 infoTimes[0]; +}; + +/* Device Specification Extended Attribute (ECMA 167 4/14.10.7) */ +struct DeviceSpecificationExtendedAttr { + uint32 attrType; /* 12 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 impUseLength; + uint32 majorDeviceIdent; + uint32 minorDeviceIdent; +// uint8 impUse[0]; +}; + +/* Implementation Use Extended Attr (ECMA 167 4/14.10.8) */ +struct ImpUseExtendedAttr { + uint32 attrType; /* 2048 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 impUseLength; + EntityID impIdent; +// uint8 impUse[0]; +}; + +/* Application Use Extended Attribute (ECMA 167 4/14.10.9) */ +struct AppUseExtendedAttr { + uint32 attrType; /* 65536 */ + uint8 attrSubtype; /* 1 */ + uint8 reserved[3]; + uint32 attrLength; + uint32 appUseLength; + EntityID appIdent; +// uint8 appUse[0]; +}; + +#define EXTATTR_CHAR_SET 1 +#define EXTATTR_ALT_PERMS 3 +#define EXTATTR_FILE_TIMES 5 +#define EXTATTR_INFO_TIMES 6 +#define EXTATTR_DEV_SPEC 12 +#define EXTATTR_IMP_USE 2048 +#define EXTATTR_APP_USE 65536 + + +/* Unallocated Space Entry (ECMA 167 4/14.11) */ +struct UnallocatedSpaceEntry { + tag descTag; + icbtag icbTag; + uint32 lengthAllocDescs; +// uint8 allocDescs[0]; +}; + +/* Space Bitmap Descriptor (ECMA 167 4/14.12) */ +typedef struct _SPACE_BITMAP_DESC { + tag descTag; + uint32 numOfBits; + uint32 numOfBytes; +// uint8 bitmap[0]; // describes blocks from Lba=0 to Lba=LAST_LBA +} SPACE_BITMAP_DESC, *PSPACE_BITMAP_DESC; + +typedef SPACE_BITMAP_DESC SpaceBitmapDesc; + +/* Partition Integrity Entry (ECMA 167 4/14.13) */ +struct PartitionIntegrityEntry { + tag descTag; + icbtag icbTag; + timestamp recordingDateAndTime; + uint8 integrityType; + uint8 reserved[175]; + EntityID impIdent; + uint8 impUse[256]; +}; + +#define INTEGRITY_TYPE_STABLE 2 + +/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */ +typedef struct _EXT_AD { /* ECMA 167 4/14.14.3 */ + uint32 extLength; + uint32 recordedLength; + uint32 informationLength; + lb_addr extLocation; +} EXT_AD, *PEXT_AD; + +typedef EXT_AD ext_ad; + +/* Logical Volume Header Descriptor (ECMA 167 4/14.5) */ +struct LogicalVolHeaderDesc { + uint64 uniqueID; + uint8 reserved[24]; +}; + +/* Path Component (ECMA 167 4/14.16.1) */ +struct PathComponent { + uint8 componentType; + uint8 lengthComponentIdent; + uint16 componentFileVersionNum; +// dstring componentIdent[0]; +}; + +#define COMPONENT_TYPE_ROOT_X 0x01 /* originator & recipient know its value */ +#define COMPONENT_TYPE_ROOT 0x02 /* root of the volume */ +#define COMPONENT_TYPE_PARENT 0x03 /* predecessor's parent dir */ +#define COMPONENT_TYPE_CURENT 0x04 /* same as predecessor's dir */ +#define COMPONENT_TYPE_OBJECT 0x05 /* terminal entry */ + +/* File Entry (ECMA 167 4/14.17) */ + +typedef struct _EXTENDED_FILE_ENTRY { + tag descTag; + icbtag icbTag; + uint32 uid; + uint32 gid; + uint32 permissions; + uint16 fileLinkCount; + uint8 recordFormat; + uint8 recordDisplayAttr; + uint32 recordLength; + uint64 informationLength; + uint64 objectSize; + uint64 logicalBlocksRecorded; + timestamp accessTime; + timestamp modificationTime; + timestamp createTime; + timestamp attrTime; + uint32 checkpoint; + uint32 reserved; + long_ad extendedAttrICB; + long_ad streamDirectoryICB; + EntityID impIdent; + uint64 uniqueID; + uint32 lengthExtendedAttr; + uint32 lengthAllocDescs; +// uint8 extendedAttr[0]; +// uint8 allocDescs[0]; +} EXTENDED_FILE_ENTRY, *PEXTENDED_FILE_ENTRY; + +typedef EXTENDED_FILE_ENTRY ExtendedFileEntry; + +#pragma pack(pop) + +#endif /* __ECMA_167_H__ */ + diff --git a/reactos/drivers/filesystems/udfs/udf_info/extent.cpp b/reactos/drivers/filesystems/udfs/udf_info/extent.cpp new file mode 100644 index 00000000000..99768c0973a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/extent.cpp @@ -0,0 +1,3412 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + extent.cpp + + Abstract: + + This file contains filesystem-specific routines + responsible for extent & mapping management + +*/ + +#include "udf.h" + +#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_EXTENT + +/* + This routine converts offset in extent to Lba & returns offset in the 1st + sector & bytes before end of block. + Here we assume no references to AllocDescs + */ +uint32 +UDFExtentOffsetToLba( + IN PVCB Vcb, + IN PEXTENT_MAP Extent, // Extent array + IN int64 Offset, // offset in extent + OUT uint32* SectorOffset, + OUT uint32* AvailLength, // available data in this block + OUT uint32* Flags, + OUT uint32* Index + ) +{ + uint32 j=0, l, d, BSh = Vcb->BlockSizeBits; + uint32 Offs; + uint32 i=0, BOffset; // block nums + + BOffset = (uint32)(Offset >> BSh); + // scan extent table for suitable range (frag) + ExtPrint(("ExtLen %x\n", Extent->extLength)); + while(i+(d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)) >> BSh) <= BOffset) { + + if(!l) { + if(Index) (*Index) = j-1; + if(Flags) { + Extent--; + (*Flags) = (Extent->extLength >> 30); + } + return LBA_OUT_OF_EXTENT; + } + if(!d) + break; + i += d; //frag offset + j++; // frag index + Extent++; + } + BOffset -= i; + Offs = (*((uint32*)&Offset)) - (i << BSh); // offset in frag + + if(SectorOffset) + (*SectorOffset) = Offs & (Vcb->BlockSize-1);// offset in 1st Lba + if(AvailLength) + (*AvailLength) = l - Offs;// bytes to EO frag + if(Flags) + (*Flags) = (Extent->extLength >> 30); + if(Index) + (*Index) = j; + + ASSERT(((Extent->extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation); + + return Extent->extLocation + BOffset;// 1st Lba +} // end UDFExtentOffsetToLba() + +uint32 +UDFNextExtentToLba( + IN PVCB Vcb, + IN PEXTENT_MAP Extent, // Extent array + OUT uint32* AvailLength, // available data in this block + OUT uint32* Flags, + OUT uint32* Index + ) +{ +// uint32 Lba; + + uint32 l, d; + + // scan extent table for suitable range (frag) + d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)); + + if(!l) { + (*Index) = -1; + Extent--; + (*Flags) = (Extent->extLength >> 30); + return LBA_OUT_OF_EXTENT; + } + + (*Index) = 0; + (*AvailLength) = l;// bytes to EO frag + (*Flags) = (Extent->extLength >> 30); + + ASSERT(((*Flags) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation); + + return Extent->extLocation;// 1st Lba +} // end UDFNextExtentToLba() + +/* + This routine locates frag containing specified Lba in extent + */ +ULONG +UDFLocateLbaInExtent( + IN PVCB Vcb, + IN PEXTENT_MAP Extent, // Extent array + IN lba_t lba + ) +{ + uint32 l, BSh = Vcb->BlockSizeBits; + uint32 i=0; + + while(l = ((Extent->extLength & UDF_EXTENT_LENGTH_MASK) >> BSh)) { + + if(Extent->extLocation >= lba && + Extent->extLocation+l < lba) { + return i; + } + i++; //frag offset + Extent++; + } + return LBA_OUT_OF_EXTENT;// index of item in extent, containing out Lba +} // end UDFLocateLbaInExtent() + +/* + This routine calculates total length of specified extent. + Here we assume no references to AllocDescs + */ +int64 +UDFGetExtentLength( + IN PEXTENT_MAP Extent // Extent array + ) +{ + if(!Extent) return 0; + int64 i=0; + +//#ifdef _X86_ +#ifdef _MSC_VER + + __asm push ebx + __asm push ecx + __asm push esi + + __asm lea ebx,i + __asm mov esi,Extent + __asm xor ecx,ecx +While_1: + __asm mov eax,[esi+ecx*8] // Extent[j].extLength + __asm and eax,UDF_EXTENT_LENGTH_MASK + __asm jz EO_While + __asm add [ebx],eax + __asm adc [ebx+4],0 + __asm inc ecx + __asm jmp While_1 +EO_While:; + __asm pop esi + __asm pop ecx + __asm pop ebx + +#else // NO X86 optimization , use generic C/C++ + + while(Extent->extLength) { + i += (Extent->extLength & UDF_EXTENT_LENGTH_MASK); + Extent++; + } + +#endif // _X86_ + + return i; +} // UDFGetExtentLength() + +/* + This routine appends Zero-terminator to single Extent-entry. + Such operation makes it compatible with other internal routines + */ +PEXTENT_MAP +__fastcall +UDFExtentToMapping_( + IN PEXTENT_AD Extent +#ifdef UDF_TRACK_EXTENT_TO_MAPPING + ,IN ULONG src, + IN ULONG line +#endif //UDF_TRACK_EXTENT_TO_MAPPING + ) +{ + PEXTENT_MAP Map; + +#ifdef UDF_TRACK_EXTENT_TO_MAPPING +#define UDF_EXT_MAP_MULT 4 +#else //UDF_TRACK_EXTENT_TO_MAPPING +#define UDF_EXT_MAP_MULT 2 +#endif //UDF_TRACK_EXTENT_TO_MAPPING + + Map = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDF_EXT_MAP_MULT * + sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); + if(!Map) return NULL; + RtlZeroMemory((int8*)(Map+1), sizeof(EXTENT_MAP)); + Map[0].extLength = Extent->extLength; + Map[0].extLocation = Extent->extLocation; +#ifdef UDF_TRACK_EXTENT_TO_MAPPING + Map[2].extLength = src; + Map[2].extLocation = line; +#endif //UDF_TRACK_EXTENT_TO_MAPPING + return Map; +} // end UDFExtentToMapping() + +/* + This routine calculates file mapping length (in bytes) including + ZERO-terminator + */ +uint32 +UDFGetMappingLength( + IN PEXTENT_MAP Extent + ) +{ + if(!Extent) return 0; + uint32 i=0; + +//#ifdef _X86_ +#ifdef _MSC_VER + __asm push ebx + + __asm mov ebx,Extent + __asm xor eax,eax +While_1: + __asm mov ecx,[ebx+eax*8] + __asm jecxz EO_While + __asm inc eax + __asm jmp While_1 +EO_While: + __asm inc eax + __asm shl eax,3 + __asm mov i,eax + + __asm pop ebx + +#else // NO X86 optimization , use generic C/C++ + + while(Extent->extLength) { + i++; + Extent++; + } + i++; + i*=sizeof(EXTENT_MAP); + +#endif // _X86_ + + return i; // i*sizeof(EXTENT_MAP) +} // end UDFGetMappingLength() + +/* + This routine merges 2 sequencial file mappings + */ +PEXTENT_MAP +__fastcall +UDFMergeMappings( + IN PEXTENT_MAP Extent, + IN PEXTENT_MAP Extent2 + ) +{ + PEXTENT_MAP NewExt; + uint32 len, len2; + + len = UDFGetMappingLength(Extent); + len2 = UDFGetMappingLength(Extent2); + ASSERT(len2 && len); + if(!len2) { + return Extent; + } + if(MyReallocPool__((int8*)Extent, len, (int8**)(&NewExt), len+len2-sizeof(EXTENT_MAP))) { + RtlCopyMemory(((int8*)NewExt)+len-sizeof(EXTENT_MAP), (int8*)Extent2, len2); + } else { + ExtPrint(("UDFMergeMappings failed\n")); + BrutePoint(); + } + return NewExt; +} // end UDFMergeMappings() + +/* + This routine builds file mapping according to ShortAllocDesc (SHORT_AD) + array + */ +PEXTENT_MAP +UDFShortAllocDescToMapping( + IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc + ) +{ + uint32 i, lim, l, len, BSh, type; + PEXTENT_MAP Extent, Extent2, AllocMap; + EXTENT_AD AllocExt; + PALLOC_EXT_DESC NextAllocDesc; + lb_addr locAddr; + uint32 ReadBytes; + EXTENT_INFO NextAllocLoc; + BOOLEAN w2k_compat = FALSE; + + ExtPrint(("UDFShortAllocDescToMapping: len=%x\n", AllocDescLength)); + + if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; + + locAddr.partitionReferenceNum = (uint16)PartNum; + BSh = Vcb->BlockSizeBits; + l = ((lim = (AllocDescLength/sizeof(SHORT_AD))) + 1 ) * sizeof(EXTENT_AD); + Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); + if(!Extent) return NULL; + + NextAllocLoc.Offset = 0; + + for(i=0;i> 30; + len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; + ExtPrint(("ShExt: type %x, loc %x, len %x\n", type, AllocDesc[i].extPosition, len)); + if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { + // read next frag of allocation descriptors if encountered + if(len < sizeof(ALLOC_EXT_DESC)) { + MyFreePool__(Extent); + return NULL; + } + NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); + if(!NextAllocDesc) { + MyFreePool__(Extent); + return NULL; + } + // record information about this frag + locAddr.logicalBlockNum = AllocDesc[i].extPosition; + AllocExt.extLength = len; + AllocExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address\n")); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + NextAllocLoc.Mapping = + AllocMap = UDFExtentToMapping(&AllocExt); + NextAllocLoc.Length = len; + if(!AllocMap) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); + if(!AllocLoc->Mapping || + // read this frag + !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, + 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) + { + MyFreePool__(AllocMap); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + MyFreePool__(AllocMap); + // check integrity + if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || + (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { + KdPrint(("Integrity check failed\n")); + KdPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent)); + KdPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs)); + KdPrint(("len = %x\n", len)); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + // perform recursive call to obtain mapping + NextAllocLoc.Flags = 0; + Extent2 = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)(NextAllocDesc+1), + NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); + if(!Extent2) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + UDFCheckSpaceAllocation(Vcb, 0, Extent2, AS_USED); // check if used + // and merge this 2 mappings into 1 + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + Extent = UDFMergeMappings(Extent, Extent2); + + if(NextAllocLoc.Flags & EXTENT_FLAG_2K_COMPAT) { + ExtPrint(("w2k-compat\n")); + AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; + } + + MyFreePool__(Extent2); + return Extent; + } + // +#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT + ASSERT(!(len & (Vcb->LBlockSize-1) )); +#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT + if(len & (Vcb->LBlockSize-1)) { + w2k_compat = TRUE; + } + Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1); + locAddr.logicalBlockNum = AllocDesc[i].extPosition; + // Note: for compatibility Adaptec DirectCD we check 'len' here + // That strange implementation records bogus extLocation in terminal entries + if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { + Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address (2)\n")); + MyFreePool__(Extent); + return NULL; + } + } else { + Extent[i].extLocation = 0; + } + if(!len) { + // some UDF implementations set strange AllocDesc sequence length, + // but terminates it with zeros in proper place, so handle + // this case + ASSERT(i>=(lim-1)); + ASSERT(!Extent[i].extLength); + Extent[i].extLocation = 0; + if(/*!SubCallCount &&*/ w2k_compat) { + ExtPrint(("w2k-compat\n")); + AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; + } + return Extent; + } + Extent[i].extLength |= (type << 30); + } + // set terminator + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + + if(/*!SubCallCount &&*/ w2k_compat) { + ExtPrint(("w2k-compat\n")); + AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT; + } + + return Extent; +} // end UDFShortAllocDescToMapping() + +/* + This routine builds file mapping according to LongAllocDesc (LONG_AD) + array + */ +PEXTENT_MAP +UDFLongAllocDescToMapping( + IN PVCB Vcb, + IN PLONG_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) + ) +{ + uint32 i, lim, l, len, BSh, type; + PEXTENT_MAP Extent, Extent2, AllocMap; + EXTENT_AD AllocExt; + PALLOC_EXT_DESC NextAllocDesc; + uint32 ReadBytes; + EXTENT_INFO NextAllocLoc; + + ExtPrint(("UDFLongAllocDescToMapping: len=%x\n", AllocDescLength)); + + if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; + + BSh = Vcb->BlockSizeBits; + l = ((lim = (AllocDescLength/sizeof(LONG_AD))) + 1 ) * sizeof(EXTENT_AD); + Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); + if(!Extent) return NULL; + + NextAllocLoc.Offset = 0; + + for(i=0;i> 30; + len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; + ExtPrint(("LnExt: type %x, loc %x (%x:%x), len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), + AllocDesc[i].extLocation.partitionReferenceNum, AllocDesc[i].extLocation.logicalBlockNum, + len)); + if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { + // read next frag of allocation descriptors if encountered + if(len < sizeof(ALLOC_EXT_DESC)) { + MyFreePool__(Extent); + return NULL; + } + NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); + if(!NextAllocDesc) { + MyFreePool__(Extent); + return NULL; + } + // record information about this frag + AllocExt.extLength = len; + AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); + if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address\n")); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + NextAllocLoc.Mapping = + AllocMap = UDFExtentToMapping(&AllocExt); + NextAllocLoc.Length = len; + if(!AllocMap) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); + if(!AllocLoc->Mapping || + // read this frag + !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, + 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) + { + MyFreePool__(AllocMap); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + MyFreePool__(AllocMap); + // check integrity + if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || + (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { + KdPrint(("Integrity check failed\n")); + KdPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent)); + KdPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs)); + KdPrint(("len = %x\n", len)); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + // perform recursive call to obtain mapping + Extent2 = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)(NextAllocDesc+1), + NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); + if(!Extent2) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + // and merge this 2 mappings into 1 + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + Extent = UDFMergeMappings(Extent, Extent2); + MyFreePool__(Extent2); + return Extent; + } + // + Extent[i].extLength = len; +#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT + ASSERT(!(len & (Vcb->LBlockSize-1) )); +#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT + Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1); + // Note: for compatibility Adaptec DirectCD we check 'len' here + // That strange implementation records bogus extLocation in terminal entries + if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { + Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); + if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address (2)\n")); + MyFreePool__(Extent); + return NULL; + } + } else { + Extent[i].extLocation = 0; + } + if(!len) { + // some UDF implementations set strange AllocDesc sequence length, + // but terminates it with zeros in proper place, so handle + // this case + Extent[i].extLocation = 0; + return Extent; + } + Extent[i].extLength |= (type << 30); + } + // set terminator + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + + return Extent; +} // end UDFLongAllocDescToMapping() + +/* + This routine builds file mapping according to ExtendedAllocDesc (EXT_AD) + array + */ +PEXTENT_MAP +UDFExtAllocDescToMapping( + IN PVCB Vcb, + IN PEXT_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) + ) +{ + uint32 i, lim, l, len, BSh, type; + PEXTENT_MAP Extent, Extent2, AllocMap; + EXTENT_AD AllocExt; + PALLOC_EXT_DESC NextAllocDesc; + uint32 ReadBytes; + EXTENT_INFO NextAllocLoc; + + ExtPrint(("UDFExtAllocDescToMapping: len=%x\n", AllocDescLength)); + + if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL; + + BSh = Vcb->BlockSizeBits; + l = ((lim = (AllocDescLength/sizeof(EXT_AD))) + 1 ) * sizeof(EXTENT_AD); + Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG); + if(!Extent) return NULL; + + NextAllocLoc.Offset = 0; + + for(i=0;i> 30; + len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK; + ExtPrint(("ExExt: type %x, loc %x, len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), len)); + if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) { + // read next frag of allocation descriptors if encountered + if(len < sizeof(ALLOC_EXT_DESC)) { + MyFreePool__(Extent); + return NULL; + } + NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG); + if(!NextAllocDesc) { + MyFreePool__(Extent); + return NULL; + } + // record information about this frag + AllocExt.extLength = len; + AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); + if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address\n")); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + NextAllocLoc.Mapping = + AllocMap = UDFExtentToMapping(&AllocExt); + NextAllocLoc.Length = len; + if(!AllocMap) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap); + if(!AllocLoc->Mapping || + // read this frag + !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc, + 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes))) + { + MyFreePool__(AllocMap); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + MyFreePool__(AllocMap); + // check integrity + if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) || + (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) { + KdPrint(("Integrity check failed\n")); + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + // perform recursive call to obtain mapping + Extent2 = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)(NextAllocDesc+1), + NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc); + if(!Extent2) { + MyFreePool__(NextAllocDesc); + MyFreePool__(Extent); + return NULL; + } + // and merge this 2 mappings into 1 + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + Extent = UDFMergeMappings(Extent, Extent2); + MyFreePool__(Extent2); + return Extent; + } +/* if((AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK) > // Uncomment!!! + (AllocDesc[i].recordedLength & UDF_EXTENT_LENGTH_MASK)) { + Extent[i].extLength = AllocDesc[i].recordedLength; + Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); + }*/ + Extent[i].extLength = len; +#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT + ASSERT(!(len & (Vcb->LBlockSize-1) )); +#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT + // Note: for compatibility Adaptec DirectCD we check 'len' here + // That strange implementation records bogus extLocation in terminal entries + if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) { + Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); + if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { + KdPrint(("bad address (2)\n")); + MyFreePool__(Extent); + return NULL; + } + } else { + Extent[i].extLocation = 0; + } + if(!len) { + // some UDF implementations set strange AllocDesc sequence length, + // but terminates it with zeros in proper place, so handle + // this case + Extent[i].extLocation = 0; + return Extent; + } + Extent[i].extLength |= (type << 30); + } + // set terminator + Extent[i].extLength = 0; + Extent[i].extLocation = 0; + + return Extent; +} // end UDFExtAllocDescToMapping() + + +/* + This routine builds FileMapping according to given FileEntry + Return: pointer to EXTENT_MAP array + or offset inside FileEntry (negative) + when ICB_FLAG_AD_IN_ICB encountered + of NULL if an error occured + */ +PEXTENT_MAP +UDFReadMappingFromXEntry( + IN PVCB Vcb, + IN uint32 PartNum, + IN tag* XEntry, + IN OUT uint32* Offset, + OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero) + ) +{ + PEXTENT_AD Extent; + uint16 AllocMode; + int8* AllocDescs; + uint32 len; +// EntityID* eID; // for compatibility with Adaptec DirectCD + + Extent = NULL; + (*Offset) = 0; + + + if(XEntry->tagIdent == TID_FILE_ENTRY) { +// KdPrint(("Standard FileEntry\n")); + PFILE_ENTRY FileEntry = (PFILE_ENTRY)XEntry; + ExtPrint(("Standard FileEntry\n")); + + AllocDescs = (int8*)(((int8*)(FileEntry+1))+(FileEntry->lengthExtendedAttr)); + len = FileEntry->lengthAllocDescs; + AllocLoc->Offset = sizeof(FILE_ENTRY) + FileEntry->lengthExtendedAttr; +// eID = &(FileEntry->impIdent); + + AllocMode = FileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK; + + } else if(XEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) { +// KdPrint(("Extended FileEntry\n")); + ExtPrint(("Extended FileEntry\n")); + PEXTENDED_FILE_ENTRY ExFileEntry = (PEXTENDED_FILE_ENTRY)XEntry; + + AllocDescs = (((int8*)(ExFileEntry+1))+(ExFileEntry->lengthExtendedAttr)); + len = ExFileEntry->lengthAllocDescs; + AllocLoc->Offset = sizeof(EXTENDED_FILE_ENTRY) + ExFileEntry->lengthExtendedAttr; +// eID = &(FileEntry->impIdent); + + AllocMode = ExFileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK; + + } else { + return NULL; + } + + // for compatibility with Adaptec DirectCD +// if(!(Vcb->UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT)) + + AllocLoc->Length=len; + AllocLoc->Flags |= EXTENT_FLAG_VERIFY; // for metadata + + switch (AllocMode) { + case ICB_FLAG_AD_SHORT: { + Extent = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)AllocDescs, len, 0, AllocLoc); + break; + } + case ICB_FLAG_AD_LONG: { + Extent = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)AllocDescs, len, 0, AllocLoc); + break; + } + case ICB_FLAG_AD_EXTENDED: { + Extent = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)AllocDescs, len, 0, AllocLoc); + break; + } + default : { // case ICB_FLAG_AD_IN_ICB + Extent = NULL; + *Offset = (uint32)AllocDescs - (uint32)XEntry; + AllocLoc->Offset=0; + AllocLoc->Length=0; + if(AllocLoc->Mapping) MyFreePool__(AllocLoc->Mapping); + AllocLoc->Mapping=NULL; + break; + } + } + + ExtPrint(("UDFReadMappingFromXEntry: mode %x, loc %x, len %x\n", AllocMode, + AllocLoc->Mapping ? AllocLoc->Mapping[0].extLocation : -1, len)); + + UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used + + return Extent; +}// end UDFReadMappingFromXEntry() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine builds data for AllocDesc sequence for specified + extent + */ +OSSTATUS +UDFBuildShortAllocDescs( + IN PVCB Vcb, + IN uint32 PartNum, + OUT int8** Buff, // data for AllocLoc + IN uint32 InitSz, + IN OUT PUDF_FILE_INFO FileInfo + ) +{ + uint32 i, j; + uint32 len=0; + PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; + PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); + PSHORT_AD Alloc; + uint32 NewLen; + OSSTATUS status; + uint32 ph_len=0; // in general, this should be uint64, + // but we need its lower part only +#ifdef UDF_ALLOW_FRAG_AD + uint32 ts, ac, len2; + uint32 LBS = Vcb->LBlockSize; + uint32 LBSh = Vcb->BlockSizeBits; + uint32 TagLen = 0; + tag* Tag = NULL; + PSHORT_AD saved_Alloc; + uint32 TagLoc, prevTagLoc; + uint32 BufOffs; + uint32 ExtOffs; + uint32 saved_NewLen; +#endif //UDF_ALLOW_FRAG_AD + + ValidateFileInfo(FileInfo); + ExtPrint(("UDFBuildShortAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + // calculate length + for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i) { + ExtPrint(("bShExt: type %x, loc %x, len %x\n", + Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); + } + Alloc = (PSHORT_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(SHORT_AD), MEM_SHAD_TAG); + if(!Alloc) { + BrutePoint(); + return STATUS_INSUFFICIENT_RESOURCES; + } + // fill contiguous AllocDesc buffer (decribing UserData) + for(i=0;iCompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) { + Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) & + (Vcb->LBlockSize-1); + ExtPrint(("bShExt: cut tail -> %x\n", + Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK)); + } + Alloc[i].extLength = + Alloc[i].extPosition = 0; + j = len*sizeof(SHORT_AD); // required space + len = (InitSz & ~(sizeof(SHORT_AD)-1)); // space available in 1st block + ASSERT(len == InitSz); + + // Ok. Let's init AllocLoc + if(!(FileInfo->Dloc->AllocLoc.Mapping)) { + FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); + if(!(FileInfo->Dloc->AllocLoc.Mapping)) { + BrutePoint(); + MyFreePool__(Alloc); + return STATUS_INSUFFICIENT_RESOURCES; + } + // allocation descriptors are located in the same sector as FileEntry + // (at least their 1st part), just after it + FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; + FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; + FileInfo->Dloc->AllocLoc.Length = 0; + // set terminator + FileInfo->Dloc->AllocLoc.Mapping[1].extLength = + FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; + } + + if(j <= len) { + // we needn't allocating additional blocks to store AllocDescs + AdPrint(("in-ICB AllocDescs, j=%x\n",j)); + RtlCopyMemory(*Buff, (int8*)Alloc, j); + NewLen = j; + MyFreePool__(Alloc); + } else { +#ifndef UDF_ALLOW_FRAG_AD + AdPrint((" DISK_FULL\n")); + return STATUS_DISK_FULL; +#else //UDF_ALLOW_FRAG_AD + AdPrint(("multi-block AllocDescs, j=%x\n",j)); + BufOffs = 0; + TagLoc = prevTagLoc = 0; + // calculate the space available for SHORT_ADs in each block + ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(SHORT_AD))) & ~(sizeof(SHORT_AD)-1); + len2 = len; + // tail size + ts = InitSz - len2; + len -= sizeof(SHORT_AD); + // calculate actual AllocSequence length (in bytes) + NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(SHORT_AD); + MyFreePool__(*Buff); + (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_SHAD_TAG); + if(!(*Buff)) { + status = STATUS_INSUFFICIENT_RESOURCES; + KdPrint(("UDFResizeExtent() failed (%x)\n",status)); + BrutePoint(); + goto sh_alloc_err; + } + if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + if(!OS_SUCCESS(status)) { + KdPrint(("UDFResizeExtent(2) failed (%x)\n",status)); + BrutePoint(); +sh_alloc_err: + MyFreePool__(Alloc); + return status; + } + } + ExtOffs = AllocExtent->Offset; + RtlZeroMemory(*Buff, NewLen); + saved_NewLen = NewLen; + NewLen = 0; // recorded length + saved_Alloc = Alloc; + // fill buffer sector by sector (adding links at the end of each one) + while(TRUE) { + + // j - remained AllocDescs length (in bytes) + // len - bytes available for AllocDescs in current block + // ac - bytes available for AllocDescs in each block + + // leave space for terminator or pointer to next part of sequence + if(j == len2) { + // if we have only 1 SHORT_AD that we can fit in last sector + // we shall do it instead of recording link & allocating new block + len = + TagLen = len2; + } + ASSERT(saved_NewLen >= (BufOffs + len)); + RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); + Alloc = (PSHORT_AD)((int8*)Alloc + len); + j -= len; + BufOffs += len; + if(Tag) { + // Set up Tag for AllocDesc + Tag->tagIdent = TID_ALLOC_EXTENT_DESC; + UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); + prevTagLoc = TagLoc; + } + if(!j) { + // terminate loop + NewLen = BufOffs; + break; + } + len = ac; + if(j <= (len + sizeof(SHORT_AD))) + len = j - sizeof(SHORT_AD); + len2 = len + sizeof(SHORT_AD); + // we have more than 1 SHORT_AD that we can't fit in current block + // so we shall set up pointer to the next block + ((PSHORT_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 | + (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; + ((PSHORT_AD)((*Buff)+BufOffs))->extPosition = TagLoc = + UDFPhysLbaToPart(Vcb, PartNum, + UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, + ExtOffs+BufOffs+sizeof(SHORT_AD)+ts, + NULL, NULL, NULL, NULL) ); + // reflect additional (link) block & LBlock tail (if any) + BufOffs += ts+sizeof(SHORT_AD); + // init AllocDesc + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; + Tag = (tag*)((*Buff)+BufOffs); + TagLen = len2; + ts = LBS-len2-sizeof(ALLOC_EXT_DESC); + BufOffs += sizeof(ALLOC_EXT_DESC); + } + MyFreePool__(saved_Alloc); +#endif //UDF_ALLOW_FRAG_AD + } + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + return status; +} // end UDFBuildShortAllocDescs() + +/* + This routine builds data for AllocDesc sequence for specified + extent + */ +OSSTATUS +UDFBuildLongAllocDescs( + IN PVCB Vcb, + IN uint32 PartNum, + OUT int8** Buff, // data for AllocLoc + IN uint32 InitSz, + IN OUT PUDF_FILE_INFO FileInfo + ) +{ + uint32 i, j; + uint32 len=0; + PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; + PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); + PLONG_AD Alloc; + uint32 NewLen; + OSSTATUS status; + uint32 ph_len=0; // in general, this should be uint64, + // but we need its lower part only +#ifdef UDF_ALLOW_FRAG_AD + uint32 ac, len2, ts; + uint32 TagLoc, prevTagLoc; + uint32 LBS = Vcb->LBlockSize; + uint32 LBSh = Vcb->BlockSizeBits; + uint32 BufOffs; + uint32 ExtOffs = AllocExtent->Offset; + PLONG_AD saved_Alloc; + uint32 TagLen = 0; + tag* Tag = NULL; +#endif //UDF_ALLOW_FRAG_AD + + ValidateFileInfo(FileInfo); + ExtPrint(("UDFBuildLongAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + // calculate length + //for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i); + for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i) { + ExtPrint(("bLnExt: type %x, loc %x, len %x\n", + Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); + } + Alloc = (PLONG_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(LONG_AD), MEM_LNGAD_TAG); + if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES; + // fill contiguous AllocDesc buffer (decribing UserData) + for(i=0;iCompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) { + Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) & + (Vcb->LBlockSize-1); + ExtPrint(("bLnExt: cut tail -> %x\n", + Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK)); + } + RtlZeroMemory(&(Alloc[i]), sizeof(LONG_AD)); + j = len*sizeof(LONG_AD); // required space + len = (InitSz & ~(sizeof(LONG_AD)-1)); // space available in 1st block + ASSERT(len == InitSz); + + // Ok. Let's init AllocLoc + if(!(FileInfo->Dloc->AllocLoc.Mapping)) { + FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG); + if(!(FileInfo->Dloc->AllocLoc.Mapping)) { + MyFreePool__(Alloc); + return STATUS_INSUFFICIENT_RESOURCES; + } + // allocation descriptors are located in the same sector as FileEntry + // (at least their 1st part), just after it + FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; + FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; + FileInfo->Dloc->AllocLoc.Length = 0; + // set terminator + FileInfo->Dloc->AllocLoc.Mapping[1].extLength = + FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; + } + + if(j <= len) { + // we needn't allocating additional blocks to store AllocDescs + RtlCopyMemory(*Buff, (int8*)Alloc, j); + NewLen = j; + MyFreePool__(Alloc); + } else { +#ifndef UDF_ALLOW_FRAG_AD + AdPrint((" DISK_FULL\n")); + return STATUS_DISK_FULL; +#else //UDF_ALLOW_FRAG_AD + BufOffs = 0; + TagLoc = prevTagLoc = 0; + // calculate the space available for LONG_ADs in each block + ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(LONG_AD))) & ~(sizeof(LONG_AD)-1); + len2 = len; + // tail size + ts = InitSz - len2; + len -= sizeof(LONG_AD); + // calculate actual AllocSequence length (in LBlocks) + NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(LONG_AD); + MyFreePool__(*Buff); + (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_LNGAD_TAG); + if(!(*Buff)) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto lad_alloc_err; + } + if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + if(!OS_SUCCESS(status)) { +lad_alloc_err: + MyFreePool__(Alloc); + return status; + } + } + ExtOffs = AllocExtent->Offset; + RtlZeroMemory(*Buff, NewLen); + NewLen = 0; // recorded length + saved_Alloc = Alloc; + len2 = len+sizeof(LONG_AD); + // fill buffer sector by sector (adding links at the end of each one) + while(TRUE) { + + // j - remained AllocDescs length (in bytes) + // len - bytes available for in AllocDescs each block + + // leave space for terminator or pointer to next part of sequence + if(j == len2) { + // if we have only 1 LONG_AD that we can fit in last sector + // we shall do it instead of recording link & allocating new block + len = + TagLen = len2; + } + RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); + Alloc = (PLONG_AD)((int8*)Alloc + len); + j -= len; + BufOffs += len; + if(Tag) { + // Set up Tag for AllocDesc + Tag->tagIdent = TID_ALLOC_EXTENT_DESC; + UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); + prevTagLoc = TagLoc; + } + if(!j) { + // terminate loop + NewLen = BufOffs; + break; + } + len = ac; + if(j <= (len + sizeof(LONG_AD))) + len = j - sizeof(LONG_AD); + len2 = len+sizeof(LONG_AD); + // we have more than 1 LONG_AD that we can't fit in current block + // so we shall set up pointer to the next block + ((PLONG_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 | + (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; + ((PLONG_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc = + UDFPhysLbaToPart(Vcb, PartNum, + UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, + ExtOffs+BufOffs+sizeof(LONG_AD)+ts, + NULL, NULL, NULL, NULL) ); + ((PLONG_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum; + // reflect additional (link) block & LBlock tail (if any) + BufOffs += ts+sizeof(LONG_AD); + // init AllocDesc + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; + Tag = (tag*)((*Buff)+BufOffs); + TagLen = len2; + ts = LBS-len2-sizeof(ALLOC_EXT_DESC); + BufOffs += sizeof(ALLOC_EXT_DESC); + } + MyFreePool__(saved_Alloc); +#endif //UDF_ALLOW_FRAG_AD + } + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + return status; +} // end UDFBuildLongAllocDescs() + +/* + This routine builds data for AllocDesc sequence for specified + extent + */ +/*OSSTATUS +UDFBuildExtAllocDescs( + IN PVCB Vcb, + IN uint32 PartNum, + OUT int8** Buff, // data for AllocLoc + IN uint32 InitSz, + IN OUT PUDF_FILE_INFO FileInfo + ) +{ + uint32 i, j; + uint32 len=0, ac, len2; + uint32 TagLoc, prevTagLoc; + uint32 LBS = Vcb->LBlockSize; + uint32 LBSh = Vcb->BlockSizeBits; + PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping; + PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc); + PEXT_AD Alloc, saved_Alloc; + uint32 BufOffs; + uint32 ExtOffs = AllocExtent->Offset; + uint32 NewLen; + OSSTATUS status; + uint32 TagLen = 0; + tag* Tag = NULL; + + ValidateFileInfo(FileInfo); + // calculate length + for(len=0; Extent[len].extLength; len++); + Alloc = (PEXT_AD)MyAllocatePool__(NonPagedPool, (len+1)*sizeof(EXT_AD)); + if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES; + // fill contiguous AllocDesc buffer (decribing UserData) + for(i=0;iDloc->AllocLoc.Mapping)) { + FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, 2 * sizeof(EXTENT_MAP)); + if(!(FileInfo->Dloc->AllocLoc.Mapping)) { + MyFreePool__(Alloc); + return STATUS_INSUFFICIENT_RESOURCES; + } + // allocation descriptors are located in the same sector as FileEntry + // (at least their 1st part), just after it + FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; + FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen; + FileInfo->Dloc->AllocLoc.Length = 0; + // set terminator + FileInfo->Dloc->AllocLoc.Mapping[1].extLength = + FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0; + } + + if(j <= len) { + // we needn't allocating additional blocks to store AllocDescs + RtlCopyMemory(*Buff, (int8*)Alloc, j); + NewLen = j; + MyFreePool__(Alloc); + } else { + BufOffs = 0; + TagLoc = prevTagLoc = 0; + // calculate the space available for EXT_ADs in each block + ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(EXT_AD))) & ~(sizeof(EXT_AD)-1); + // calculate actual AllocSequence length (in LBlocks) + len -= sizeof(EXT_AD); + NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + len + sizeof(EXT_AD); + MyFreePool__(*Buff); + (*Buff) = (int8*)MyAllocatePool__(NonPagedPool, NewLen); + if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) { + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + if(!OS_SUCCESS(status)) { + MyFreePool__(Alloc); + return status; + } + } + RtlZeroMemory(*Buff, NewLen); + NewLen = 0; // recorded length + saved_Alloc = Alloc; + len2 = len + sizeof(EXT_AD); + // fill buffer sector by sector (adding links at the end of each one) + while(TRUE) { + + // j - remained AllocDescs length (in bytes) + // len - bytes available for in AllocDescs each block + + // leave space for terminator or pointer to next part of sequence + if(j == len2) { + // if we have only 1 EXT_AD that we can fit in last sector + // we shall do it instead of recording link & allocating new block + len = + TagLen = len2; + } + RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len); + Alloc = (PEXT_AD)((int8*)Alloc + len); + j -= len; + BufOffs += len; + if(Tag) { + // Set up Tag for AllocDesc + Tag->tagIdent = TID_ALLOC_EXTENT_DESC; + UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc); + prevTagLoc = TagLoc; + } + if(!j) { + // terminate loop + NewLen = BufOffs; + break; + } + len = ac; + if(j <= (len + sizeof(EXT_AD))) + len = j - sizeof(EXT_AD); + len2 = len + sizeof(EXT_AD); + // we have more than 1 EXT_AD that we can't fit in current block + // so we shall set up pointer to the next block + ((PEXT_AD)((*Buff)+BufOffs))->extLength = + ((PEXT_AD)((*Buff)+BufOffs))->recordedLength = LBS; + ((PEXT_AD)((*Buff)+BufOffs))->informationLength = len2 | + (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ; + ((PEXT_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc = + UDFPhysLbaToPart(Vcb, PartNum, + UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs + BufOffs + 2*sizeof(EXT_AD)-1, NULL, NULL, NULL, NULL) ); + ((PEXT_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum; + BufOffs = (BufOffs + 2*sizeof(EXT_AD) - 1) & ~(sizeof(EXT_AD)-1) ; + // init AllocDesc + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2; + ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc; + Tag = (tag*)((*Buff)+BufOffs); + TagLen = len2; + BufOffs += sizeof(ALLOC_EXT_DESC); + } + MyFreePool__(saved_Alloc); + } + status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent); + return status; +} // end UDFBuildExtAllocDescs()*/ + +void +UDFDiscardFESpace( + IN PVCB Vcb, + IN PEXTENT_MAP Mapping, + IN uint32 lim + ) +{ +#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE + PEXTENT_MAP Mapping2; + uint32 i; + + KdPrint((" DiscardFESpace\n")); + Mapping2 = Mapping; + for(i=0;iextLength >> 30) == EXTENT_RECORDED_ALLOCATED) { + KdPrint((" used @ %x\n", Mapping->extLocation)); + Mapping->extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + Mapping->extLocation = 0; + } else { + KdPrint((" free @ %x\n", Mapping->extLocation)); + } + } + UDFMarkSpaceAsXXX(Vcb, 0, Mapping2, AS_DISCARDED); + + MyFreePool__(Mapping2); +#else // UDF_FE_ALLOCATION_CHARGE + ASSERT(!Dloc->DirIndex->FECharge.Mapping); + return; +#endif // UDF_FE_ALLOCATION_CHARGE +} // end UDFDiscardFESpace() + +OSSTATUS +UDFInitAllocationCache( + IN PVCB Vcb, + IN uint32 AllocClass, + OUT PUDF_ALLOCATION_CACHE_ITEM* _AllocCache, + OUT uint32* _lim, + IN BOOLEAN Init + ) +{ + PUDF_ALLOCATION_CACHE_ITEM AllocCache; + PUDF_ALLOCATION_CACHE_ITEM* pAllocCache; + uint32 i, lim; + uint32* plim; + + switch(AllocClass) { + case UDF_PREALLOC_CLASS_FE: + KdPrint(("AllocationCache FE:\n")); + pAllocCache = &(Vcb->FEChargeCache); + plim = &(Vcb->FEChargeCacheMaxSize); + lim = 32; + break; + case UDF_PREALLOC_CLASS_DIR: + KdPrint(("AllocationCache DIR:\n")); + pAllocCache = &(Vcb->PreallocCache); + plim = &(Vcb->PreallocCacheMaxSize); + lim = 32; + break; + default: + return STATUS_INVALID_PARAMETER; + } + if(!(*plim)) { + if(!Init) { + return STATUS_UNSUCCESSFUL; + } + (*pAllocCache) = AllocCache = + (PUDF_ALLOCATION_CACHE_ITEM) + MyAllocatePoolTag__(NonPagedPool , sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim, + MEM_ALLOC_CACHE_TAG); + if(!AllocCache) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(AllocCache, sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim); + for(i=0; iPreallocResource),TRUE); + + status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE); + if(!OS_SUCCESS(status)) { + UDFReleaseResource(&(Vcb->PreallocResource)); + return status; + } + KdPrint(("Get AllocationCache for %x\n", ParentLocation)); + + for(i=0; iMapping, i)); + if(Items) { + (*Items) = AllocCache[i].Items; + } + RtlZeroMemory(&(AllocCache[i]), sizeof(AllocCache[i])); + AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED; + UDFReleaseResource(&(Vcb->PreallocResource)); + return STATUS_SUCCESS; + } + } + AdPrint((" no map\n")); + UDFReleaseResource(&(Vcb->PreallocResource)); + return STATUS_UNSUCCESSFUL; +} // end UDFGetCachedAllocation() + +OSSTATUS +UDFStoreCachedAllocation( + IN PVCB Vcb, + IN uint32 ParentLocation, + IN PEXTENT_INFO Ext, + IN uint32 Items, + IN uint32 AllocClass + ) +{ + PUDF_ALLOCATION_CACHE_ITEM AllocCache; + uint32 i, lim; + OSSTATUS status; + + UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE); + + status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, TRUE); + if(!OS_SUCCESS(status)) { + UDFReleaseResource(&(Vcb->PreallocResource)); + return status; + } + KdPrint(("Store AllocationCache for %x, map %x\n", ParentLocation, Ext->Mapping)); + + for(i=0; iPreallocResource)); + return STATUS_SUCCESS; + } + } + // + AdPrint((" drop map %x (%x)\n", AllocCache[lim-1].Ext.Mapping, lim-1)); + switch(AllocClass) { + case UDF_PREALLOC_CLASS_FE: + UDFDiscardFESpace(Vcb, AllocCache[lim-1].Ext.Mapping, AllocCache[lim-1].Items); + break; + case UDF_PREALLOC_CLASS_DIR: + UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[lim-1].Ext.Mapping, AS_DISCARDED); + break; + } + RtlMoveMemory(&(AllocCache[1]), &(AllocCache[0]), sizeof(UDF_ALLOCATION_CACHE_ITEM)*(lim-1)); + AllocCache[0].Ext = (*Ext); + AllocCache[0].Items = Items; + AllocCache[0].ParentLocation = ParentLocation; + AdPrint((" stored in 0\n")); + UDFReleaseResource(&(Vcb->PreallocResource)); + return STATUS_SUCCESS; +} // end UDFStoreCachedAllocation() + +OSSTATUS +UDFFlushAllCachedAllocations( + IN PVCB Vcb, + IN uint32 AllocClass + ) +{ + PUDF_ALLOCATION_CACHE_ITEM AllocCache; + uint32 i, lim; + OSSTATUS status; + + KdPrint(("Flush AllocationCache\n")); + UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE); + + status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE); + if(!OS_SUCCESS(status)) { + UDFReleaseResource(&(Vcb->PreallocResource)); + return status; + } + + for(i=0; iFEChargeCache = NULL; + Vcb->FEChargeCacheMaxSize = 0; + break; + case UDF_PREALLOC_CLASS_DIR: + Vcb->PreallocCache = NULL; + Vcb->PreallocCacheMaxSize = 0; + break; + } + UDFReleaseResource(&(Vcb->PreallocResource)); + // + return STATUS_SUCCESS; +} // end UDFFlushAllCachedAllocations() + +/* + This routine allocates space for FE of the file being created + If FE-Charge is enabled it reserves an extent & allocates + space in it. It works much faster then usual way both while + allocating & accessing on disk + If FE-Charge is disabled FE may be allocated at any suitable + location + */ +OSSTATUS +UDFAllocateFESpace( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN uint32 PartNum, + IN PEXTENT_INFO FEExtInfo, + IN uint32 Len + ) +{ +#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE + OSSTATUS status; + PEXTENT_INFO Ext; + EXTENT_AD Extent; + BOOLEAN retry = FALSE; + uint32 i, lim; + +/* + 1. #Dir1#->*File* -> Dir1's FECharge + 2. #Dir1#->*Dir* -> Dir1's FECharge + 3. #Dir1#->*SDir* -> Dir1's FECharge + 4. Dir1->#SDir#->*Stream* -> Dir1's FEChargeSDir + 5. Dir1->#File#->*SDir* -> Dir1's FEChargeSDir + 6. Dir1->#Dir#->*SDir* -> (see p.2) + 7. Dir1->File->#SDir#->*Stream* -> Dir1's FEChargeSDir + 8. Dir1->Dir->#SDir#->*Stream* -> (see p.4) + +## ~ DirInfo +** ~ Object to be created + +*/ + +// ASSERT(!FEExtInfo->Mapping); + // check if DirInfo we are called with is a Directory + // (it can be a file with SDir) + if(!DirInfo || !DirInfo->Dloc->DirIndex || + ((lim = ((DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge)) <= 1)) +#endif // UDF_FE_ALLOCATION_CHARGE + return UDFAllocFreeExtent(Vcb, Len, + UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY); +#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE + + Ext = &(DirInfo->Dloc->DirIndex->FECharge); + + while(TRUE) { + + if(!Ext->Mapping) { + ULONG p_start; + ULONG p_end; + ULONG fe_loc; + ULONG l1, l2; + + p_start = UDFPartStart(Vcb, PartNum); + p_end = UDFPartEnd(Vcb, PartNum); + fe_loc = DirInfo->Dloc->FELoc.Mapping[0].extLocation; + + status = UDFGetCachedAllocation(Vcb, fe_loc, Ext, NULL, UDF_PREALLOC_CLASS_FE); + if(OS_SUCCESS(status)) { + // do nothing, even do not unpack + } else + if(Vcb->LowFreeSpace) { + status = UDFAllocFreeExtent(Vcb, Len << Vcb->LBlockSizeBits,p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY); + if(OS_SUCCESS(status)) { + KdPrint(("FE @ %x (1)\n", FEExtInfo->Mapping[0].extLocation )); + } + return status; + } else { + if(fe_loc > p_start + 512*16) { + l1 = fe_loc - 512*16; + } else { + l1 = p_start; + } + if(fe_loc + 512*16 < p_end) { + l2 = fe_loc + 512*16; + } else { + l2 = p_end; + } + status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, l1, l2, Ext, EXTENT_FLAG_VERIFY); + if(!OS_SUCCESS(status)) { + status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, (p_start+fe_loc)/2, (fe_loc+p_end)/2, Ext, EXTENT_FLAG_VERIFY); + } + if(!OS_SUCCESS(status)) { + status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY); + } + if(!OS_SUCCESS(status)) { + status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start+1024, p_end-1024, Ext, EXTENT_FLAG_VERIFY); + } + if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY) )) { + // can't pre-allocate space for multiple FEs. Try single FE + KdPrint(("allocate single FE entry\n")); + status = UDFAllocFreeExtent(Vcb, Len, + p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY); + if(OS_SUCCESS(status)) { + KdPrint(("FE @ %x (2)\n", FEExtInfo->Mapping[0].extLocation )); + } + return status; + } + status = UDFUnPackMapping(Vcb, Ext); + if(!OS_SUCCESS(status)) { + MyFreePool__(Ext->Mapping); + Ext->Mapping = NULL; + return status; + } + } + } + + for(i=0;iMapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ) { + Ext->Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; // EXTENT_RECORDED_ALLOCATED + + Extent.extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30); + Extent.extLocation = Ext->Mapping[i].extLocation; + + if(Vcb->BSBM_Bitmap) { + uint32 lba = Ext->Mapping[i].extLocation; + if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) { + KdPrint(("Remove BB @ %x from FE charge\n", lba)); + Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + Ext->Mapping[i].extLocation = 0; + continue; + } + } + + FEExtInfo->Mapping = UDFExtentToMapping(&Extent); + if(!FEExtInfo->Mapping) { + ASSERT(!(Ext->Mapping[i].extLength >> 30)); + Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + return STATUS_INSUFFICIENT_RESOURCES; + } + KdPrint(("FE @ %x (3)\n", FEExtInfo->Mapping[0].extLocation )); + FEExtInfo->Length = Len; + FEExtInfo->Offset = 0; + FEExtInfo->Modified = TRUE; + return STATUS_SUCCESS; + } + } + + if(Vcb->LowFreeSpace) { + status = UDFAllocFreeExtent(Vcb, Len, + UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY); + if(OS_SUCCESS(status)) { + KdPrint(("FE @ %x (4)\n", FEExtInfo->Mapping[0].extLocation )); + } + return status; + } + if(retry) + return STATUS_INSUFFICIENT_RESOURCES; + + // we can get here if there are no free slots in + // preallocated FE charge. So, we should release + // memory and try to allocate space for new FE charge. + MyFreePool__(Ext->Mapping); + Ext->Mapping = NULL; + retry = TRUE; + } + return STATUS_INSUFFICIENT_RESOURCES; +#endif // UDF_FE_ALLOCATION_CHARGE + +} // end UDFAllocateFESpace() + +/* + This routine frees space allocated for FE. + */ +void +UDFFreeFESpace( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PEXTENT_INFO FEExtInfo + ) +{ +#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE + PEXTENT_INFO Ext; + uint32 i, lim, j=-1; + uint32 Lba; + + // check if the DirInfo we are called with is a Directory + // (it can be a file with SDir) + if(DirInfo && DirInfo->Dloc->DirIndex && + (Ext = &(DirInfo->Dloc->DirIndex->FECharge))->Mapping) { + if(!FEExtInfo->Mapping) + return; + Lba = FEExtInfo->Mapping[0].extLocation; + + lim = (DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge; + for(i=0;iMapping[i].extLocation == Lba) { + ASSERT(!(Ext->Mapping[i].extLength >> 30)); + Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + goto clean_caller; + } + if(!Ext->Mapping[i].extLocation) { + j = i; + } + } + if(j != -1) { + i = j; + Ext->Mapping[i].extLocation = Lba; + Ext->Mapping[i].extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30); + goto clean_caller; + } + } +#endif // UDF_FE_ALLOCATION_CHARGE + UDFMarkSpaceAsXXX(Vcb, 0, FEExtInfo->Mapping, AS_DISCARDED); // free +clean_caller: + FEExtInfo->Mapping[0].extLocation = 0; + FEExtInfo->Mapping[0].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + return; +} // end UDFFreeFESpace() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine flushes FE-Charge buffer, marks unused blocks as free + in bitmap & releases memory allocated for FE-Charge management + */ +void +UDFFlushFESpace( + IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc, + IN BOOLEAN Discard + ) +{ +#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE + PEXTENT_MAP Mapping; + uint32 lim; + + if(!(Mapping = Dloc->DirIndex->FECharge.Mapping)) + return; + + lim = (Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge; + + if(!Discard) { + // cache it! + if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, + Dloc->FELoc.Mapping[0].extLocation, + &Dloc->DirIndex->FECharge, lim, UDF_PREALLOC_CLASS_FE))) { + Dloc->DirIndex->FECharge.Mapping = NULL; + return; + } + } + Dloc->DirIndex->FECharge.Mapping = NULL; + UDFDiscardFESpace(Vcb, Mapping, lim); +#else // UDF_FE_ALLOCATION_CHARGE + ASSERT(!Dloc->DirIndex->FECharge.Mapping); + return; +#endif // UDF_FE_ALLOCATION_CHARGE +} // end UDFFlushFESpace() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine rebuilds mapping on write attempts to Alloc-Not-Rec area. + Here we assume that required area lays in a single frag. + */ +OSSTATUS +UDFMarkAllocatedAsRecorded( + IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo // Extent array + ) +{ + uint32 i, len, lba, sLen; + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + PEXTENT_MAP NewExtent; + uint32 BS = Vcb->BlockSize; + uint32 LBS = Vcb->LBlockSize; + uint32 BSh = Vcb->BlockSizeBits; + BOOLEAN TryPack = TRUE; +#ifdef UDF_DBG + int64 check_size; +#endif //UDF_DBG + // I don't know what else comment can be added here. + // Just belive that it works + lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, (Offset & ~((int64)LBS-1)), NULL, NULL, NULL, &i); + if(i == -1) return STATUS_INVALID_PARAMETER; +#ifdef UDF_DBG + check_size = UDFGetExtentLength(ExtInfo->Mapping); + ASSERT(!(check_size & (LBS-1))); +#endif //UDF_DBG + AdPrint(("Alloc->Rec ExtInfo %x, Extent %x\n", ExtInfo, Extent)); + if((Extent[i].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) return STATUS_SUCCESS; + if((Extent[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_INVALID_PARAMETER; + ASSERT((((uint32)Offset) & (LBS-1)) + Length <= (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)); + sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; + if((Extent[i].extLocation == lba) && (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK ) >> BSh) == sLen)) { + // xxxxxx -> RRRRRR + Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; +// Extent[i].extLength |= (EXTENT_RECORDED_ALLOCATED << 30); // = 0; + ExtInfo->Modified = TRUE; + if(i && + ((Extent[i-1].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) && + (lba == (Extent[i-1].extLocation + ((len = Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) && + ((len + (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)) <= UDF_MAX_EXTENT_LENGTH) && + (i == ((UDFGetMappingLength(Extent) / sizeof(EXTENT_MAP)) - 2)) && + TRUE) { + // make optimization for sequentially written files + Extent[i-1].extLength += Extent[i].extLength; + Extent[i].extLocation = 0; + Extent[i].extLength = 0; + } else { + UDFPackMapping(Vcb, ExtInfo); + } + AdPrint(("Alloc->Rec (1) new %x\n", ExtInfo->Mapping)); + ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); + AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); + return STATUS_SUCCESS; + } + if(Extent[i].extLocation < lba) { + if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (lba - Extent[i].extLocation)) + > sLen ) { + // xxxxxx -> xxRRxx + NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP)*2, + MEM_EXTMAP_TAG); + if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; + Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLocation = Extent[i].extLocation; + NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh; + NewExtent[i+1].extLength = (Length+BS-1) & ~(BS-1); + NewExtent[i+1].extLocation = lba; + NewExtent[i+2].extLength = Extent[i].extLength - NewExtent[i].extLength - NewExtent[i+1].extLength; + NewExtent[i+2].extLocation = lba + ((Length+BS-1) >> BSh); + ASSERT(!(NewExtent[i].extLength >> 30)); + ASSERT(!(NewExtent[i+2].extLength >> 30)); + NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + NewExtent[i+2].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + TryPack = FALSE; + AdPrint(("Alloc->Rec (2) new %x\n", NewExtent)); + } else { + // xxxxxx -> xxRRRR + NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; + Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLocation = Extent[i].extLocation; + NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh; + NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength; + NewExtent[i+1].extLocation = lba; + ASSERT(!(NewExtent[i].extLength >> 30)); + NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + AdPrint(("Alloc->Rec (3) new %x\n", NewExtent)); + } + } else { + // xxxxxx -> RRRRxx + NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES; + Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK; + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLocation = Extent[i].extLocation; + NewExtent[i].extLength = (Length+BS-1) & ~(BS-1); + NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength; + NewExtent[i+1].extLocation = Extent[i].extLocation + (NewExtent[i].extLength >> BSh); + ASSERT(!(NewExtent[i+1].extLength >> 30)); + NewExtent[i+1].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30); + AdPrint(("Alloc->Rec (4) new %x\n", NewExtent)); + } + + //ASSERT(check_size == UDFGetExtentLength(Extent)); + //ASSERT(!(check_size & (LBS-1))); + + AdPrint(("Free Extent %x (new %x)\n", Extent, NewExtent)); + MyFreePool__(Extent); + ExtInfo->Modified = TRUE; + ExtInfo->Mapping = NewExtent; + if(TryPack) + UDFPackMapping(Vcb, ExtInfo); + ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); + ASSERT(!(check_size & (LBS-1))); + + AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); + + return STATUS_SUCCESS; +} // end UDFMarkAllocatedAsRecorded() + +/* + This routine rebuilds mapping on write attempts to Not-Alloc-Not-Rec area. + Here we assume that required area lays in a single frag. + */ +OSSTATUS +UDFMarkNotAllocatedAsAllocated( + IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo // Extent array + ) +{ + uint32 i, len, /*lba,*/ d, l, BOffs, j; + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + PEXTENT_MAP NewExtent; +// uint32 BS = Vcb->BlockSize; + uint32 BSh = Vcb->BlockSizeBits; + OSSTATUS status; + EXTENT_INFO TmpExtInf; + uint32 aLen, sLen; + uint32 LBS = Vcb->LBlockSize; + // I don't know what else comment can be added here. + // Just belive that it works + /*lba = */ +#ifndef ALLOW_SPARSE + BrutePoint(); +#endif + AdPrint(("Not->Alloc ExtInfo %x, Extent %x\n", ExtInfo, Extent)); + UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i); + if(i == -1) return STATUS_INVALID_PARAMETER; + if((Extent[i].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_SUCCESS; + + uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation); + BOffs = (uint32)(Offset >> BSh); + // length of existing Not-Alloc-Not-Rec frag + sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; + // required allocation length increment (in bytes) + aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1))); + + // try to extend previous frag or allocate space _after_ it to + // avoid backward seeks, if previous frag is not Not-Rec-Not-Alloc + if(i && ((Extent[i-1].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) ) { + status = UDFAllocFreeExtent(Vcb, aLen, + Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh), + min(UDFPartEnd(Vcb, PartNum), Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) + sLen ), + &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); + if(status == STATUS_DISK_FULL) + // if there are not enough free blocks after that frag... + goto try_alloc_anywhere; + } else { +try_alloc_anywhere: + // ... try to alloc required disk space anywhere + status = UDFAllocFreeExtent(Vcb, aLen, + UDFPartStart(Vcb, PartNum), + UDFPartEnd(Vcb, PartNum), + &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); + } + // check for successfull allocation + if(!OS_SUCCESS(status)) { + AdPrint(("Not->Alloc no free\n")); + return status; + } + // get number of frags in allocated block + d = (UDFGetMappingLength(TmpExtInf.Mapping) / sizeof(EXTENT_MAP)) - 1; + // calculate number of existing blocks before the frag to be changed + l=0; + for(j=0; j> BSh); + } + // and now just update mapping... + if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) { + // xxxxxx -> RRRRRR + // (d-1) - since we have to raplace last frag of Extent with 1 or more frags of TmpExtInf.Mapping + NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d-1)*sizeof(EXTENT_MAP) ); + if(!NewExtent) { + MyFreePool__(TmpExtInf.Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); + RtlCopyMemory((int8*)&(NewExtent[i+d]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + AdPrint(("Not->Alloc (1) new %x\n", NewExtent)); + } else + if(l < BOffs) { + // .ExtLength, BOffs & l are already aligned... + if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) { + // xxxxxx -> xxRRxx + NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d+1)*sizeof(EXTENT_MAP) ); + if(!NewExtent) { + MyFreePool__(TmpExtInf.Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); + RtlCopyMemory((int8*)&(NewExtent[i+d+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLocation = 0; + NewExtent[i].extLength = (BOffs - l) << BSh; + NewExtent[i+d+1].extLength = Extent[i].extLength - NewExtent[i].extLength - aLen; + NewExtent[i+d+1].extLocation = 0; + NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + NewExtent[i+d+1].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + AdPrint(("Not->Alloc (2) new %x\n", NewExtent)); + } else { + // xxxxxx -> xxRRRR + NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) ); + if(!NewExtent) { + MyFreePool__(TmpExtInf.Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); + RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLocation = 0; + NewExtent[i].extLength = (BOffs - l) << BSh; + NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + AdPrint(("Not->Alloc (3) new %x\n", NewExtent)); + } + } else { + // xxxxxx -> RRRRxx + NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) ); + if(!NewExtent) { + MyFreePool__(TmpExtInf.Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) ); + RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i+d].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen; + NewExtent[i+d].extLocation = 0; + NewExtent[i+d].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + AdPrint(("Not->Alloc (4) new %x\n", NewExtent)); + } + + AdPrint(("Free Extent %x, TmpExtInf.Mapping, (new %x)\n", Extent, TmpExtInf.Mapping, NewExtent)); + MyFreePool__(Extent); + MyFreePool__(TmpExtInf.Mapping); + ExtInfo->Modified = TRUE; + ExtInfo->Mapping = NewExtent; + + AdPrint(("Not->Alloc: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); + + return STATUS_SUCCESS; +} // end UDFMarkNotAllocatedAsAllocated() + +//#if 0 +/* + This routine rebuilds mapping on write zero attempts to + Alloc-Not-Rec area. + Here we assume that required area lays in a single frag. + */ +OSSTATUS +UDFMarkAllocatedAsNotXXX( + IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo, // Extent array + IN BOOLEAN Deallocate + ) +{ + uint32 i, len, /*lba, d,*/ l, BOffs, j; + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + PEXTENT_MAP NewExtent; +// EXTENT_MAP TmpExtent; +// uint32 BS = Vcb->BlockSize; + uint32 BSh = Vcb->BlockSizeBits; +// OSSTATUS status; + EXTENT_INFO TmpExtInf; + uint32 aLen, sLen; + uint32 flags; + uint32 target_flags = Deallocate ? + EXTENT_NOT_RECORDED_NOT_ALLOCATED : + EXTENT_NOT_RECORDED_ALLOCATED; + uint32 LBS = Vcb->LBlockSize; + EXTENT_MAP DeadMapping[2]; + // I don't know what else comment can be added here. + // Just belive that it works + /*lba = */ +#ifndef ALLOW_SPARSE + if(Deallocate) { + BrutePoint(); + } +#endif + + AdPrint(("Alloc->Not ExtInfo %x, Extent %x\n", ExtInfo, Extent)); + + DeadMapping[0].extLocation = + UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i); + if(i == -1) { + BrutePoint(); + return STATUS_INVALID_PARAMETER; + } + DeadMapping[0].extLength = Extent[i].extLength; + DeadMapping[1].extLocation = + DeadMapping[1].extLength = 0; + TmpExtInf.Mapping = (PEXTENT_MAP)&DeadMapping; + TmpExtInf.Offset = 0; + TmpExtInf.Length = Extent[i].extLength & UDF_EXTENT_LENGTH_MASK; + + flags = Extent[i].extLength >> 30; + if(flags == target_flags) return STATUS_SUCCESS; + +// uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation); + BOffs = (uint32)(Offset >> BSh); + // length of existing Alloc-(Not-)Rec frag (in sectors) + sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh; + // required deallocation length increment (in bytes) + aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)) ); + + l=0; + for(j=0; j> BSh); + } + flags <<= 30; + if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) { + // xxxxxx -> RRRRRR + Extent[i].extLocation = 0; + Extent[i].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) | flags; + NewExtent = Extent; + AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent)); + } else + if(l < BOffs) { + // .ExtLength, BOffs & l are already aligned... + if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) { + // xxxxxx -> xxRRxx + NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) ); + if(!NewExtent) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLength = (BOffs - l) << BSh; + NewExtent[i].extLength |= flags; + NewExtent[i+1].extLocation = 0; + NewExtent[i+1].extLength = aLen | (target_flags << 30); + NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - + (NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ; + NewExtent[i+2].extLocation = Extent[i].extLocation + + (NewExtent[i+2].extLength >> BSh); + NewExtent[i+2].extLength |= flags; + AdPrint(("Alloc->Not (2) new %x\n", NewExtent)); + } else { + // xxxxxx -> xxRRRR + NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) ); + if(!NewExtent) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i].extLength = ((BOffs - l) << BSh) | flags; + NewExtent[i+1].extLocation = 0; + NewExtent[i+1].extLength = aLen | (target_flags << 30); + AdPrint(("Alloc->Not (3) new %x\n", NewExtent)); + } + } else { + // xxxxxx -> RRRRxx + NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) ); + if(!NewExtent) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP)); + RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) ); + NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen; + NewExtent[i+1].extLength |= flags; + NewExtent[i].extLocation = 0; + NewExtent[i].extLength = aLen | (target_flags << 30); + AdPrint(("Alloc->Not (4) new %x\n", NewExtent)); + } + + if(Deallocate) + UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free + + if(Extent) { + AdPrint(("Alloc->Not kill %x\n", Extent)); + MyFreePool__(Extent); + } else { + AdPrint(("Alloc->Not keep %x\n", Extent)); + } + ExtInfo->Modified = TRUE; + ExtInfo->Mapping = NewExtent; + AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping)); + + return STATUS_SUCCESS; +} // end UDFMarkAllocatedAsNotXXX() +//#endif //0 + +/* + This routine resizes extent & updates associated mapping + */ +OSSTATUS +UDFResizeExtent( + IN PVCB Vcb, + IN uint32 PartNum, + IN int64 Length, // Required Length + IN BOOLEAN AlwaysInIcb, // must be TRUE for AllocDescs + OUT PEXTENT_INFO ExtInfo + ) +{ + uint32 i, flags, lba, lim; + int64 l; + OSSTATUS status; + EXTENT_INFO TmpExtInf; + EXTENT_MAP TmpMapping[2]; + uint32 s, req_s, pe, BSh, LBS, PS; + LBS = Vcb->LBlockSize; + BSh = Vcb->BlockSizeBits; + PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits; + uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1)); + BOOLEAN Sequential = FALSE; + + ASSERT(PartNum < 3); + + ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length)); + + if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) { + AdPrint((" cut preallocated\n")); + } else + if(ExtInfo->Length == Length) { + return STATUS_SUCCESS; + } + if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) { + MaxGrow &= ~(Vcb->WriteBlockSize-1); + Sequential = TRUE; + } + + UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used + if(ExtInfo->Offset) { + if(ExtInfo->Offset + Length <= LBS) { + ExtPrint(("Resize IN-ICB\n")); + ExtInfo->Length = Length; + return STATUS_SUCCESS; + } + if(!AlwaysInIcb) // simulate unused 1st sector in extent + ExtInfo->Offset = LBS; // it'll be truncated later + Length += ExtInfo->Offset; // convert to real offset in extent + } + lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i); + if(ExtInfo->Length < Length) { + // increase extent + if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation, + &TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) { + AdPrint(("Resize found cached(1)\n")); + ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); + MyFreePool__(TmpExtInf.Mapping); + } + if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) { + // we have enough space inside extent + ExtInfo->Length = Length; + AdPrint(("Resize do nothing (1)\n")); + } else /*if(lba == LBA_OUT_OF_EXTENT)*/ { + + Length -= ExtInfo->Offset; + if(/*Length && l &&*/ (l % MaxGrow) && + (Length-1)/MaxGrow != (l-1)/MaxGrow) { + AdPrint(("Crossing MAX_FRAG boundary...\n")); + int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow; + status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo); + if(!OS_SUCCESS(status)) { + KdPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status)); + return status; + } + l = ExtInfo->Length; + ASSERT(l == l2); + } + while((Length - l) > MaxGrow) { + status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo); + if(!OS_SUCCESS(status)) { + KdPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status)); + return status; + } + l = ExtInfo->Length; + } + Length += ExtInfo->Offset; + // at first, try to resize existing frag +#ifndef UDF_ALLOW_FRAG_AD + i = UDFGetMappingLength(ExtInfo->Mapping); + if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) { + // this is very important check since we will not + // be able to _record_ too long AllocDesc because of + // some DEMO limitations in UDFBuildXXXAllocDescs() + AdPrint((" DISK_FULL\n")); + return STATUS_DISK_FULL; + } + i /= sizeof(EXTENT_MAP); +#else //UDF_ALLOW_FRAG_AD + i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP); +#endif //UDF_ALLOW_FRAG_AD +#ifdef ALLOW_SPARSE + if(!AlwaysInIcb && !(ExtInfo->Offset) && + (Length - l >= (Vcb->SparseThreshold << BSh))) { + // last frag will be Not-Alloc-Not-Rec... + AdPrint(("Resize sparse (2)\n")); + RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO)); + TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2, + MEM_EXTMAP_TAG); + if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES; + TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + TmpExtInf.Mapping[0].extLocation =// 0; + TmpExtInf.Mapping[1].extLength = + TmpExtInf.Mapping[1].extLocation = 0; + l = Length; + ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); + MyFreePool__(TmpExtInf.Mapping); + } else +#endif //ALLOW_SPARSE + // allocate some sectors + if(i>1 && !(ExtInfo->Offset)) { + i-=2; + // check if Not-Alloc-Not-Rec at the end of mapping + if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) { + // do nothing, but jump directly to allocator + } else + if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + AdPrint(("Resize grow sparse (3)\n")); + ExtInfo->Mapping[i].extLength += + (((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ; + l = Length; + // check if Alloc-Not-Rec at the end of mapping + } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { + AdPrint(("Resize grow Not-Rec (3)\n")); + // current length of last frag + s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); + // prefered location of the next frag + lba = ExtInfo->Mapping[i].extLocation + s; + pe=UDFPartEnd(Vcb,PartNum); + // maximum frag length + if(Sequential) { + lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1); + } else { + lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1); + } + // required last extent length + req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) - + ((l + LBS - 1) & ~(LBS-1)) ) >> BSh); + if(lim > req_s) { + lim = req_s; + } + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); +/* if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) && + ((Length & ~(PS-1)) > (l & ~(PS-1))) && + TRUE) { + status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo); + }*/ + // how many sectors we should add + req_s = lim - s; + ASSERT(req_s); + if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) { + s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)); + } +/* for(s1=lba; (sFSBM_Bitmap, s1); s1++) { + s++; + }*/ + if(s==lim) { + // we can just increase the last frag + AdPrint(("Resize grow last Not-Rec (4)\n")); + ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30); + l = Length; + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used + } else { + // we get here if simple increasing of last frag failed + // it worth truncating last frag and try to allocate + // all required data as a single frag + +/* if(Sequential && s>=PS) { + s &= ~(PS-1); + AdPrint(("Resize grow last Not-Rec (4/2)\n")); + ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30); + l += (s << BSh); + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used + }*/ + AdPrint(("Resize reloc last Not-Rec (5)\n")); + TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!TmpExtInf.Mapping) { + KdPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n")); + UDFReleaseResource(&(Vcb->BitMapResource1)); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP)); + TmpExtInf.Mapping[i].extLength = + TmpExtInf.Mapping[i].extLocation = 0; + TmpExtInf.Offset = ExtInfo->Offset; + l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); + TmpExtInf.Length = l; + ASSERT(i || !ExtInfo->Offset); + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free + MyFreePool__(ExtInfo->Mapping); + (*ExtInfo) = TmpExtInf; + } + UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used + UDFReleaseResource(&(Vcb->BitMapResource1)); + // check if Alloc-Rec + } else { + // current length of last frag + s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh); + // prefered location of the next frag + lba = ExtInfo->Mapping[i].extLocation + s; + pe=UDFPartEnd(Vcb,PartNum); + // maximum frag length + if(Sequential) { + lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1); + } else { + lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1); + } + // required last extent length + req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) - + ((l + LBS - 1) & ~(LBS-1)) ) >> BSh); + if(lim > req_s) { + lim = req_s; + } +// s=0; + // how many sectors we should add + req_s = lim - s; + if(req_s) { + uint32 d=0; + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); + //ASSERT(req_s); + if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) { + s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1))); + } + /* for(s1=lba; (sFSBM_Bitmap, s1); s1++) { + s++; + }*/ + + if(s==lim) { + AdPrint(("Resize grow last Rec (6)\n")); + // we can just increase last frag + TmpMapping[0].extLength = req_s << BSh; + TmpMapping[0].extLocation = lba; + TmpMapping[1].extLength = + TmpMapping[1].extLocation = 0; + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used + l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); + ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh); + } else if(d) { + AdPrint(("Resize part-grow last Rec (6)\n")); + // increase last frag, then alloc rest + TmpMapping[0].extLength = d << BSh; + TmpMapping[0].extLocation = lba; + TmpMapping[1].extLength = + TmpMapping[1].extLocation = 0; + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used + l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); + ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh); + } else { + AdPrint(("Can't grow last Rec (6)\n")); + } + UDFReleaseResource(&(Vcb->BitMapResource1)); + } else { + AdPrint(("Max frag length reached (6)\n")); + } + } + } + if(l < Length) { + // we get here if simple increasing of the last frag failed + AdPrint(("Resize add new frag (7)\n")); + if(l < LBS && Length >= LBS && + (ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) { + AdPrint(("Resize tune for SEQUENTIAL i/o\n")); + } + status = UDFAllocFreeExtent(Vcb, Length - l, + UDFPartStart(Vcb, PartNum), + UDFPartEnd(Vcb, PartNum), + &TmpExtInf, + ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/); + if(!OS_SUCCESS(status)) { + KdPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status)); + return status; + } + ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping); + MyFreePool__(TmpExtInf.Mapping); + } + UDFPackMapping(Vcb, ExtInfo); + } + } else + if(Length) { + // decrease extent + AdPrint(("Resize cut (8)\n")); + lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i); + i++; + ASSERT(lba != LBA_OUT_OF_EXTENT); + ASSERT(lba != LBA_NOT_ALLOCATED); + ASSERT(i); + if(ExtInfo->Mapping[i].extLength) { + UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used + if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) { + + AdPrint(("Resize try save cutted (8)\n")); + RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO)); + s = UDFGetMappingLength(&(ExtInfo->Mapping[i])); + + TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG); + if(TmpExtInf.Mapping) { + RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s); + AdPrint(("Resize save cutted (8)\n")); + if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation, + &TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) { + ExtInfo->Mapping[i].extLength = 0; + ExtInfo->Mapping[i].extLocation = 0; + goto tail_cached; + } + } + } + UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free +tail_cached:; + } + if((lim-1 >= LBS) && + (flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) { + AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim)); + ASSERT(lim); +// BrutePoint(); + EXTENT_MAP ClrMap[2]; + ClrMap[0].extLength = lim & ~(LBS-1); + s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK; + ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation + + (s >> BSh); + ClrMap[1].extLength = + ClrMap[1].extLocation = 0; + ASSERT((ExtInfo->Mapping[i].extLocation < ClrMap[0].extLocation) || + (ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh)))); + UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used + UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free + ExtInfo->Mapping[i-1].extLength = s | (flags << 30); + } + + s = UDFGetMappingLength(ExtInfo->Mapping); + if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) { + // This must never happen on truncate !!! + AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n")); + } + ExtInfo->Mapping[i].extLength = + ExtInfo->Mapping[i].extLocation = 0; + } else { + AdPrint(("Resize zero (9)\n")); + ASSERT(!ExtInfo->Offset); + UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free + s = UDFGetMappingLength(ExtInfo->Mapping); + if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) { + // This must never happen on truncate !!! + AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n")); + } + ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); + ExtInfo->Mapping[0].extLocation = + ExtInfo->Mapping[1].extLength = + ExtInfo->Mapping[1].extLocation = 0; + } + if(ExtInfo->Offset) { + if(!AlwaysInIcb) { + // remove 1st entry pointing to FileEntry + s = UDFGetMappingLength(ExtInfo->Mapping); + RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP)); + if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, + (int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) { + // This must never happen on truncate !!! + AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n")); + } + Length -= ExtInfo->Offset; + ExtInfo->Offset = 0; + } else { + Length -= ExtInfo->Offset; // back to in-icb + } + } + ExtInfo->Length = Length; + UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used + + for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) { + ExtPrint(("Resized Ext: type %x, loc %x, len %x\n", + ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); + } + + return STATUS_SUCCESS; +} // end UDFResizeExtent() + +/* + This routine (re)builds AllocDescs data for all allocation modes except + in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for + already allocated user data extent (FileInfo->Dloc->DataLoc). + AllocMode in FileEntry pointed by FileInfo must be already initialized. + */ +OSSTATUS +UDFBuildAllocDescs( + IN PVCB Vcb, + IN uint32 PartNum, + IN OUT PUDF_FILE_INFO FileInfo, + OUT int8** AllocData + ) +{ + PEXTENT_MAP InMap; +// uint32 i=0; + int8* Allocs; + uint16 AllocMode; + uint32 InitSz; + OSSTATUS status; + + ValidateFileInfo(FileInfo); + AdPrint(("BuildAllocDesc\n")); + // get space available in the 1st LBlock after FE + InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen; + Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz); + if(!Allocs) { + AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz)); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(Allocs, InitSz); + InMap = FileInfo->Dloc->DataLoc.Mapping; + UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used + + // TODO: move data from mapped locations here + + AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; + switch(AllocMode) { + case ICB_FLAG_AD_IN_ICB: { + MyFreePool__(Allocs); + ASSERT(!FileInfo->Dloc->AllocLoc.Mapping); + Allocs = NULL; + status = STATUS_SUCCESS; + break; + } + case ICB_FLAG_AD_SHORT: { + status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); + break; + } + case ICB_FLAG_AD_LONG: { + status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); + break; + } +/* case ICB_FLAG_AD_EXTENDED: { + status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo); + break; + }*/ + default: { + MyFreePool__(Allocs); + Allocs = NULL; + status = STATUS_INVALID_PARAMETER; + } + } + + *AllocData = Allocs; + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used + + return status; +} // end UDFBuildAllocDescs() + +/* + This routine discards file's allocation + */ +void +UDFFreeFileAllocation( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUDF_FILE_INFO FileInfo + ) +{ + if(FileInfo->Dloc->DataLoc.Offset) { + // in-ICB data + if(FileInfo->Dloc->DataLoc.Mapping) { + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == + FileInfo->Dloc->DataLoc.Mapping[0].extLocation); + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free + FileInfo->Dloc->DataLoc.Mapping[1].extLocation = + FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0; + FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0; + FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; + } + if(FileInfo->Dloc->AllocLoc.Mapping) { + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation); + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free + FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = + FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0; + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0; + FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; + } + UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); + } else { + if(FileInfo->Dloc->AllocLoc.Mapping) { + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation == + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation); + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free + FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = + FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0; + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0; + FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30; + } + UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free + } + FileInfo->Dloc->DataLoc.Modified = + FileInfo->Dloc->AllocLoc.Modified = + FileInfo->Dloc->FELoc.Modified = FALSE; +} // end UDFFreeFileAllocation() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine packs physically sequential extents into single one + */ +void +__fastcall +UDFPackMapping( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo // Extent array + ) +{ + PEXTENT_MAP NewMap, OldMap; + uint32 i, j, l; + uint32 LastLba, LastType, OldLen; + uint32 OldSize, NewSize; +#ifdef UDF_DBG + int64 check_size; +#endif //UDF_DBG + + AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + AdPrint((" Length %x\n", ExtInfo->Length)); + + OldMap = ExtInfo->Mapping; + LastLba = OldMap[0].extLocation; + OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; + LastType = OldMap[0].extLength >> 30; + OldSize = + NewSize = UDFGetMappingLength(OldMap); +#ifdef UDF_DBG + check_size = UDFGetExtentLength(ExtInfo->Mapping); + ASSERT(!(check_size & (2048-1))); +#endif //UDF_DBG + + l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK; + // calculate required length + for(i=1; OldMap[i].extLength; i++) { + if((LastType == (OldMap[i].extLength >> 30)) + && + ((OldMap[i].extLocation == LastLba + OldLen) || + (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED))) + && + (l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) { + // we can pack two blocks in one + l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; + NewSize -= sizeof(EXTENT_MAP); + } else { + l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; + } + LastLba = OldMap[i].extLocation; + LastType = OldMap[i].extLength >> 30; + OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; + } + // no changes ? + if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) { + if(OldSize == NewSize) + return; + if(NewSize >= PACK_MAPPING_THRESHOLD) + return; + } + AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping)); + NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize, + MEM_EXTMAP_TAG); + // can't alloc ? + if(!NewMap) return; + // Ok, lets pack it... + j=0; + NewMap[0] = OldMap[0]; + LastLba = OldMap[0].extLocation; + OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; + LastType = OldMap[0].extLength >> 30; + for(i=1; OldMap[i].extLength; i++) { + + ExtPrint(("oShExt: type %x, loc %x, len %x\n", + OldMap[i].extLength >> 30, OldMap[i].extLocation, OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK)); + + if((LastType == (OldMap[i].extLength >> 30)) + && + ((OldMap[i].extLocation == LastLba + OldLen) || + (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED))) + && + ((NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK) + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) { + NewMap[j].extLength += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK; + } else { + j++; + NewMap[j] = OldMap[i]; + } + + ExtPrint(("nShExt: type %x, loc %x, len %x\n", + NewMap[j].extLength >> 30, NewMap[j].extLocation, NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK)); + + LastLba = OldMap[i].extLocation; + LastType = OldMap[i].extLength >> 30; + OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits; + } + // write terminator + j++; + ASSERT(NewSize == (j+1)*sizeof(EXTENT_MAP)); + NewMap[j].extLength = + NewMap[j].extLocation = 0; + + ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping)); + ASSERT(check_size == UDFGetExtentLength(NewMap)); + + AdPrint(("Pack ExtInfo %x, NewMap %x, OldMap %x\n", ExtInfo, NewMap, OldMap)); + + ExtInfo->Mapping = NewMap; + MyFreePool__(OldMap); + + AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + AdPrint((" Length %x\n", ExtInfo->Length)); +} // end UDFPackMapping() + +/* + This routine expands mapping to 'frag-per-LBlock' state + */ +OSSTATUS +__fastcall +UDFUnPackMapping( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo // Extent array + ) +{ + PEXTENT_MAP NewMapping; + PEXTENT_MAP Mapping = ExtInfo->Mapping; + uint32 LBS = Vcb->LBlockSize; + uint32 len = (uint32)(UDFGetExtentLength(Mapping) >> Vcb->LBlockSizeBits); + uint32 i,j, type, base, d; + LONG l; + + NewMapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!NewMapping) return STATUS_INSUFFICIENT_RESOURCES; + + j=0; + d = LBS >> Vcb->BlockSizeBits; + for(i=0; l = (Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) { + base = Mapping[i].extLocation; + type = Mapping[i].extLength & UDF_EXTENT_FLAG_MASK; + for(; l>=(LONG)LBS; j++) { + NewMapping[j].extLength = LBS | type; + NewMapping[j].extLocation = base; + base+=d; + l-=LBS; + } + } + // record terminator + ASSERT(NewMapping); + RtlZeroMemory(&(NewMapping[j]), sizeof(EXTENT_MAP)); + MyFreePool__(Mapping); + ExtInfo->Mapping = NewMapping; + + return STATUS_SUCCESS; +} // end UDFUnPackMapping() + +/* + Relocate a part of extent that starts from relative (inside extent) + block number 'ExtBlock' and has length of 'BC' blocks to continuous + run which starts at block 'Lba' + */ +OSSTATUS +UDFRelocateExtent( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, + IN uint32 ExtBlock, + IN uint32 Lba, + IN uint32 BC + ) +{ + return STATUS_ACCESS_DENIED; +} + +/* + This routine checks if all the data required is in cache. + */ +BOOLEAN +UDFIsExtentCached( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN ForWrite + ) +{ + BOOLEAN retstat = FALSE; + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_read, Lba, sect_offs, flags, i; + + WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE/*FALSE/*ForWrite*/); + if(!ExtInfo || !ExtInfo->Mapping) goto EO_IsCached; + if(!Length) { + retstat = TRUE; + goto EO_IsCached; + } + + // prevent reading out of data space + if(Offset > ExtInfo->Length) goto EO_IsCached; + if(Offset+Length > ExtInfo->Length) goto EO_IsCached; + Offset += ExtInfo->Offset; // used for in-ICB data + // read maximal possible part of each frag of extent + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &i); + while(((LONG)Length) > 0) { + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) goto EO_IsCached; + Extent += (i + 1); + // check for reading tail + to_read = min(to_read, Length); + if(flags == EXTENT_RECORDED_ALLOCATED) { + retstat = UDFIsDataCached(Vcb, Lba, (to_read+sect_offs+Vcb->BlockSize-1)>>Vcb->BlockSizeBits); + if(!retstat) goto EO_IsCached; + } else if(ForWrite) { + goto EO_IsCached; + } + Offset += to_read; + Length -= to_read; + Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &i); + } + retstat = TRUE; +EO_IsCached: + if(!retstat) { + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } + return retstat; +} // end UDFIsExtentCached() + +/* + This routine reads cached data only. + */ +/*OSSTATUS +UDFReadExtentCached( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + (*ReadBytes) = 0; + if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_read, Lba, sect_offs, flags, _ReadBytes; + OSSTATUS status; + // prevent reading out of data space + if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE; + if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset); + Offset += ExtInfo->Offset; // used for in-ICB data + // read maximal possible part of each frag of extent + while(((LONG)Length) > 0) { + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, NULL); + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE; + // check for reading tail + to_read = (to_read < Length) ? + to_read : Length; + if(flags == EXTENT_RECORDED_ALLOCATED) { + status = UDFReadDataCached(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Buffer, &_ReadBytes); + (*ReadBytes) += _ReadBytes; + } else { + RtlZeroMemory(Buffer, to_read); + (*ReadBytes) += to_read; + status = STATUS_SUCCESS; + } + if(!OS_SUCCESS(status)) return status; + // prepare for reading next frag... + Buffer += to_read; + Offset += to_read; + Length -= to_read; + } + return STATUS_SUCCESS; +} // end UDFReadExtentCached()*/ + +/* + This routine reads data at any offset from specified extent. + */ +OSSTATUS +UDFReadExtent( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + (*ReadBytes) = 0; + if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER; + ASSERT((uint32)Buffer > 0x1000); + + AdPrint(("Read ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_read, Lba, sect_offs, flags, _ReadBytes; + OSSTATUS status; + // prevent reading out of data space + if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE; + if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset); + Offset += ExtInfo->Offset; // used for in-ICB data + // read maximal possible part of each frag of extent + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &_ReadBytes); + while(Length) { + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE; + Extent += (_ReadBytes + 1); + // check for reading tail + to_read = min(to_read, Length); + if(flags == EXTENT_RECORDED_ALLOCATED) { + status = UDFReadData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Direct, Buffer, &_ReadBytes); + (*ReadBytes) += _ReadBytes; + if(!OS_SUCCESS(status)) return status; + } else { + RtlZeroMemory(Buffer, to_read); + (*ReadBytes) += to_read; + } + // prepare for reading next frag... + Length -= to_read; + if(!Length) + break; + ASSERT(to_read); + Buffer += to_read; +// Offset += to_read; + Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &_ReadBytes); + sect_offs = 0; + } + return STATUS_SUCCESS; +} // end UDFReadExtent() + +/* + This routine reads and builds mapping for + specified amount of data at any offset from specified extent. + Size of output buffer is limited by *_SubExtInfoSz + */ +OSSTATUS +UDFReadExtentLocation( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent to start SubExtent from + OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array + IN OUT uint32* _SubExtInfoSz, // IN: maximum number of fragments to get + // OUT: actually obtained fragments + OUT int64* _NextOffset // offset, caller can start from to continue + ) +{ + if(!ExtInfo || !ExtInfo->Mapping) + return STATUS_INVALID_PARAMETER; + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + PEXTENT_MAP SubExtInfo; + uint32 to_read, Lba, sect_offs, flags, Skip_MapEntries; + int32 SubExtInfoSz = *_SubExtInfoSz; + int64 Length; + int64 NextOffset; + OSSTATUS status = STATUS_BUFFER_OVERFLOW; + + (*_SubExtInfo) = NULL; + (*_SubExtInfoSz) = 0; + NextOffset = Offset; + // prevent reading out of data space + if(Offset >= ExtInfo->Length) + return STATUS_END_OF_FILE; + Length = ExtInfo->Length - Offset; + Offset += ExtInfo->Offset; // used for in-ICB data + // read maximal possible part of each frag of extent + SubExtInfo = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , SubExtInfoSz*sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + (*_SubExtInfo) = SubExtInfo; + if(!SubExtInfo) + return STATUS_INSUFFICIENT_RESOURCES; + + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_read, &flags, &Skip_MapEntries); + while(Length && SubExtInfoSz) { + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) { + BrutePoint(); + return STATUS_END_OF_FILE; + } + Extent += (Skip_MapEntries + 1); + // check for reading tail + to_read = (int32)min((int64)to_read, Length); + SubExtInfo->extLength = to_read; + if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + SubExtInfo->extLocation = LBA_NOT_ALLOCATED; + } else + if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { + ASSERT(!(Lba & 0x80000000)); + SubExtInfo->extLocation = Lba | 0x80000000; + } else { + SubExtInfo->extLocation = Lba; + } + (*_SubExtInfoSz)++; + SubExtInfoSz--; + NextOffset += to_read; + // prepare for reading next frag... + Length -= to_read; + if(!Length) { + status = STATUS_SUCCESS; + break; + } + ASSERT(to_read); + Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &Skip_MapEntries); + sect_offs = 0; + } + (*_NextOffset) = NextOffset; + return STATUS_SUCCESS; +} // end UDFReadExtentLocation() + +#pragma warning(push) +#pragma warning(disable:4035) // re-enable below + +uint32 +UDFGetZeroLength( + IN int8* Buffer, + IN uint32 Length + ) +{ + uint32 i; + Length /= sizeof(uint32); + for(i=0; iMapping) + return STATUS_INVALID_PARAMETER; + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_write, Lba, sect_offs, flags; + OSSTATUS status; + uint32 _WrittenBytes; + BOOLEAN reread_lba; +// BOOLEAN already_prepared = FALSE; +// BOOLEAN prepare = !Buffer; + + AdPrint(("Write ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + + Offset += ExtInfo->Offset; // used for in-ICB data + // write maximal possible part of each frag of extent + while(((LONG)Length) > 0) { + UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) { + return STATUS_END_OF_FILE; + } +/* if((to_write < Length) && + !Direct && !prepare && !already_prepared) { + // rebuild mapping, allocate space, etc. + // to indicate this, set Buffer to NULL + AdPrint(("UDFWriteExtent: Prepare\n")); + BrutePoint(); + _WrittenBytes = 0; + status = UDFWriteExtent(Vcb, ExtInfo, Offset, Length, *//*Direct*//*FALSE, NULL, &_WrittenBytes); + if(!OS_SUCCESS(status)) { + return status; + } + Extent = ExtInfo->Mapping; + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + already_prepared = TRUE; + }*/ + if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + // here we should allocate space for this extent + if(!OS_SUCCESS(status = UDFMarkNotAllocatedAsAllocated(Vcb, Offset, to_write, ExtInfo))) + return status; + Extent = ExtInfo->Mapping; + UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + if(Lba == LBA_OUT_OF_EXTENT) { + return STATUS_END_OF_FILE; + } + // we have already re-read Lba + reread_lba = FALSE; + } else { + // we may need to re-read Lba if some changes are + // made while converting from Alloc-Not-Rec + reread_lba = TRUE; + } + // check if writing to not recorded allocated + // in this case we must pad blocks with zeros around + // modified area + // + // ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|... + // . . + // . || . + // . \/ . + // . . + // ...|000ddddd|dddddddd|dd000000|... + // . . + // ^ ^ + // sect_offs sect_offs+to_write + // . . + // .<-- to_write -->. + // + to_write = min(to_write, Length); + if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { + if(!OS_SUCCESS(status = UDFMarkAllocatedAsRecorded(Vcb, Offset, to_write, ExtInfo))) + return status; + Extent = ExtInfo->Mapping; + UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used + if(reread_lba) { + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + to_write = min(to_write, Length); + } + /* + we must fill 1st block with zeros in 1 of 2 cases: + 1) start offset is not aligned on LBlock boundary + OR + 2) end offset is not aligned on LBlock boundary and lays in + the same LBlock + + we must fill last block with zeros if both + 1) end offset is not aligned on LBlock boundary + AND + 2) end offset DOESN'T lay in the 1st LBlock + */ + +// if(!prepare) { + // pad 1st logical block + if((sect_offs || (sect_offs + to_write < Vcb->LBlockSize) ) + && + !Vcb->CDR_Mode) { + status = UDFWriteData(Vcb, TRUE, + ( ((uint64)Lba) << Vcb->BlockSizeBits), + Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes); + if(!OS_SUCCESS(status)) + return status; + } + // pad last logical block + if((sect_offs + to_write > Vcb->LBlockSize) && + (sect_offs + to_write) & (Vcb->LBlockSize - 1)) { + status = UDFWriteData(Vcb, TRUE, + (( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs + to_write) & ~((int64)(Vcb->LBlockSize)-1), + Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes); + } + if(!OS_SUCCESS(status)) + return status; +/* } else { + status = STATUS_SUCCESS; + }*/ + } + ASSERT(to_write); +// if(!prepare) { + status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, Direct, Buffer, &_WrittenBytes); + *WrittenBytes += _WrittenBytes; + if(!OS_SUCCESS(status)) return status; +/* } else { + status = STATUS_SUCCESS; + *WrittenBytes += to_write; + }*/ + // prepare for writing next frag... + Buffer += to_write; + Offset += to_write; + Length -= to_write; + } + AdPrint(("Write: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + return STATUS_SUCCESS; +} // end UDFWriteExtent() + +//#if 0 +/* + This routine zeroes/deallocates data at any offset to specified extent. + */ +OSSTATUS +UDFZeroExtent( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Deallocate, // deallocate frag or just mark as unrecorded + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + OUT uint32* WrittenBytes + ) +{ + if(!ExtInfo || !ExtInfo->Mapping) + return STATUS_INVALID_PARAMETER; + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_write, Lba, sect_offs, flags; + OSSTATUS status; + uint32 _WrittenBytes; + uint32 LBS = Vcb->LBlockSize; + + AdPrint(("Zero ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + + Offset += ExtInfo->Offset; // used for in-ICB data + // fill/deallocate maximal possible part of each frag of extent + while(((LONG)Length) > 0) { + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + // EOF check + if(Lba == LBA_OUT_OF_EXTENT) { + return STATUS_END_OF_FILE; + } + // check for writing tail + to_write = min(to_write, Length); + + if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) { + // here we should do nothing + *WrittenBytes += to_write; + } else + if(flags == EXTENT_NOT_RECORDED_ALLOCATED) { + // we should just deallocate this frag + if(Deallocate) { + if(!OS_SUCCESS(status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, to_write, ExtInfo))) + return status; + } + Extent = ExtInfo->Mapping; + *WrittenBytes += to_write; + } else { + // fill tail of the 1st Block with ZEROs + if(sect_offs) { + status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, + min(to_write, LBS-sect_offs), + Direct, Vcb->ZBuffer, &_WrittenBytes); + *WrittenBytes += _WrittenBytes; + if(!OS_SUCCESS(status)) + return status; + Offset += _WrittenBytes; + Length -= _WrittenBytes; + to_write -= _WrittenBytes; + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED); + ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED); + ASSERT(!sect_offs); + } + // deallocate Blocks + if(to_write >= LBS) { + // use 'sect_offs' as length of extent to be deallocated + sect_offs = to_write & ~(LBS - 1); + if(Deallocate) { + status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, sect_offs, ExtInfo); + } else { + status = UDFMarkRecordedAsAllocated(Vcb, Offset, sect_offs, ExtInfo); + } + if(!OS_SUCCESS(status)) + return status; + // reload extent mapping + Extent = ExtInfo->Mapping; + Offset += sect_offs; + Length -= sect_offs; + *WrittenBytes += sect_offs; + to_write -= sect_offs; + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED); + ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED); + ASSERT(!sect_offs); + } + // fill beginning of the last Block with ZEROs + if(to_write) { + status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), to_write, Direct, Vcb->ZBuffer, &_WrittenBytes); + *WrittenBytes += _WrittenBytes; + if(!OS_SUCCESS(status)) + return status; + ASSERT(to_write == _WrittenBytes); + } + } + AdPrint(("Zero... ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + // prepare for filling next frag... + Offset += to_write; + Length -= to_write; + } + AdPrint(("Zero: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping)); + return STATUS_SUCCESS; +} // end UDFZeroExtent() +//#endif //0 +#endif //UDF_READ_ONLY_BUILD diff --git a/reactos/drivers/filesystems/udfs/udf_info/mount.cpp b/reactos/drivers/filesystems/udfs/udf_info/mount.cpp new file mode 100644 index 00000000000..08d22f995a1 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/mount.cpp @@ -0,0 +1,3052 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + mount.cpp + + Abstract: + + This file contains filesystem-specific routines + responsible for Mount/Umount + +*/ + +#include "udf.h" + +/* FIXME*/ +#define XCHG_DD(a,b) \ +{ \ + ULONG _temp_; \ + PULONG _from_, _to_; \ + _from_ = ((PULONG)&(b)); \ + _to_ = ((PULONG)&(a)); \ + _temp_ = *_from_; \ + *_from_ = *_to_; \ + *_to_ = _temp_; \ +} + +#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_MOUNT + +OSSTATUS +__fastcall +UDFSetDstring( + IN PUNICODE_STRING UName, + IN dstring* Dest, + IN uint32 Length + ); + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine loads specified bitmap. + It is also allocate space if the bitmap is not allocated. + */ +OSSTATUS +UDFPrepareXSpaceBitmap( + IN PVCB Vcb, + IN OUT PSHORT_AD XSpaceBitmap, + IN OUT PEXTENT_INFO XSBMExtInfo, + IN OUT int8** XSBM, + IN OUT uint32* XSl + ) +{ + uint32 BS, j, LBS; + uint32 plen; + OSSTATUS status; + EXTENT_MAP TmpExt; + lb_addr locAddr; + int8* _XSBM; + uint16 Ident; + uint32 ReadBytes; + uint32 PartNum; + + if(!(XSpaceBitmap->extLength)) { + *XSl = 0; + *XSBM = NULL; + return STATUS_SUCCESS; + } + + PartNum = UDFGetPartNumByPartNdx(Vcb, Vcb->PartitionMaps-1); + locAddr.partitionReferenceNum = (uint16)PartNum; + plen = UDFPartStart(Vcb, PartNum) + UDFPartLen(Vcb, PartNum); + + BS = Vcb->BlockSize; + LBS = Vcb->LBlockSize; + + *XSl = sizeof(SPACE_BITMAP_DESC) + ((plen+7)>>3); + _XSBM = (int8*)DbgAllocatePool(NonPagedPool, (*XSl + BS - 1) & ~(BS-1) ); + *XSBM = _XSBM; + + switch (XSpaceBitmap->extLength >> 30) { + case EXTENT_RECORDED_ALLOCATED: { + locAddr.logicalBlockNum = XSpaceBitmap->extPosition; + *XSl = min(XSpaceBitmap->extLength, *XSl); + TmpExt.extLength = XSpaceBitmap->extLength = *XSl; + TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) { + BrutePoint(); + } + XSBMExtInfo->Mapping = UDFExtentToMapping(&TmpExt); + XSBMExtInfo->Offset = 0; + XSBMExtInfo->Length = *XSl; + break; + } + case EXTENT_NEXT_EXTENT_ALLOCDESC: + case EXTENT_NOT_RECORDED_NOT_ALLOCATED: { + // allocate space for bitmap + if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, *XSl, + UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), XSBMExtInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL) )) + return status; + if(XSBMExtInfo->Mapping[1].extLength) { + KdPrint(("Can't allocate space for Freed Space bitmap\n")); + *XSl = 0; + } else { + *XSl = (uint32)(XSBMExtInfo->Length); + XSpaceBitmap->extPosition = UDFPhysLbaToPart(Vcb, PartNum, XSBMExtInfo->Mapping[0].extLocation); + } + break; + } + case EXTENT_NOT_RECORDED_ALLOCATED: { + // record Alloc-Not-Rec + locAddr.logicalBlockNum = XSpaceBitmap->extPosition; + *XSl = min((XSpaceBitmap->extLength & UDF_EXTENT_LENGTH_MASK), *XSl); + TmpExt.extLength = XSpaceBitmap->extLength = *XSl; + TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) { + BrutePoint(); + } + XSBMExtInfo->Mapping = UDFExtentToMapping(&TmpExt); + XSBMExtInfo->Offset = 0; + XSBMExtInfo->Length = *XSl; + break; + } + } + + if(!_XSBM) { + BrutePoint(); + return STATUS_INSUFFICIENT_RESOURCES; + } + + switch (XSpaceBitmap->extLength >> 30) { + case EXTENT_RECORDED_ALLOCATED: { + // read descriptor & bitmap + if((!OS_SUCCESS(status = UDFReadTagged(Vcb, *XSBM, (j = TmpExt.extLocation), + locAddr.logicalBlockNum, &Ident))) || + (Ident != TID_SPACE_BITMAP_DESC) || + (!OS_SUCCESS(status = UDFReadExtent(Vcb, XSBMExtInfo, 0, *XSl, FALSE, *XSBM, &ReadBytes))) ) { + if(OS_SUCCESS(status)) { + BrutePoint(); + status = STATUS_FILE_CORRUPT_ERROR; + } + if(XSBMExtInfo->Mapping) { + MyFreePool__(XSBMExtInfo->Mapping); + XSBMExtInfo->Mapping = NULL; + } + DbgFreePool(*XSBM); + *XSl = 0; + *XSBM = NULL; + return status; + } else { +// BrutePoint(); + } + return STATUS_SUCCESS; + } +#if 0 + case EXTENT_NEXT_EXTENT_ALLOCDESC: + case EXTENT_NOT_RECORDED_NOT_ALLOCATED: + case EXTENT_NOT_RECORDED_ALLOCATED: { + break; + } +#endif + } + + PSPACE_BITMAP_DESC XSDesc = (PSPACE_BITMAP_DESC)(*XSBM); + + XSpaceBitmap->extLength = (*XSl + LBS -1) & ~(LBS-1); + RtlZeroMemory(*XSBM, *XSl); + XSDesc->descTag.tagIdent = TID_SPACE_BITMAP_DESC; + UDFSetUpTag(Vcb, &(XSDesc->descTag), 0, XSpaceBitmap->extPosition); + XSDesc->numOfBits = plen; + XSDesc->numOfBytes = (*XSl)-sizeof(SPACE_BITMAP_DESC); + + return STATUS_SUCCESS; +} // end UDFPrepareXSpaceBitmap() + +/* + This routine updates Freed & Unallocated space bitmaps + */ +OSSTATUS +UDFUpdateXSpaceBitmaps( + IN PVCB Vcb, + IN uint32 PartNum, + IN PPARTITION_HEADER_DESC phd // partition header pointing to Bitmaps + ) +{ + uint32 i,j,d; + uint32 plen, pstart, pend; + int8* bad_bm; + int8* old_bm; + int8* new_bm; + int8* fpart_bm; + int8* upart_bm; + OSSTATUS status, status2; + int8* USBM=NULL; + int8* FSBM=NULL; + uint32 USl, FSl; + EXTENT_INFO FSBMExtInfo, USBMExtInfo; + lb_addr locAddr; + uint32 WrittenBytes; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + + plen = UDFPartLen(Vcb, PartNum); + locAddr.partitionReferenceNum = (uint16)PartNum; + // prepare bitmaps for updating + + status = UDFPrepareXSpaceBitmap(Vcb, &(phd->unallocatedSpaceBitmap), &USBMExtInfo, &USBM, &USl); + status2 = UDFPrepareXSpaceBitmap(Vcb, &(phd->freedSpaceBitmap), &FSBMExtInfo, &FSBM, &FSl); + if(!OS_SUCCESS(status) || + !OS_SUCCESS(status2)) { + BrutePoint(); + } + + pstart = UDFPartStart(Vcb, PartNum); + new_bm = Vcb->FSBM_Bitmap; + old_bm = Vcb->FSBM_OldBitmap; + bad_bm = Vcb->BSBM_Bitmap; + + if((status == STATUS_INSUFFICIENT_RESOURCES) || + (status2 == STATUS_INSUFFICIENT_RESOURCES)) { + // try to recover insufficient resources + if(USl && USBMExtInfo.Mapping) { + USl -= sizeof(SPACE_BITMAP_DESC); + status = UDFWriteExtent(Vcb, &USBMExtInfo, sizeof(SPACE_BITMAP_DESC), USl, FALSE, new_bm, &WrittenBytes); +#ifdef UDF_DBG + } else { + KdPrint(("Can't update USBM\n")); +#endif // UDF_DBG + } + if(USBMExtInfo.Mapping) MyFreePool__(USBMExtInfo.Mapping); + + if(FSl && FSBMExtInfo.Mapping) { + FSl -= sizeof(SPACE_BITMAP_DESC); + status2 = UDFWriteExtent(Vcb, &FSBMExtInfo, sizeof(SPACE_BITMAP_DESC), FSl, FALSE, new_bm, &WrittenBytes); + } else { + status2 = status; + KdPrint(("Can't update FSBM\n")); + } + if(FSBMExtInfo.Mapping) MyFreePool__(FSBMExtInfo.Mapping); + } else { + // normal way to record BitMaps + if(USBM) upart_bm = USBM + sizeof(SPACE_BITMAP_DESC); + if(FSBM) fpart_bm = FSBM + sizeof(SPACE_BITMAP_DESC); + pend = min(pstart + plen, Vcb->FSBM_BitCount); + + d=1<LB2B_Bits; + // if we have some bad bits, mark corresponding area as BAD + if(bad_bm) { + for(i=pstart; iPartitionMaps; i++) + { + if((UDFGetPartNumByPartNdx(Vcb,i) == p->partitionNumber) && + (!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || + !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03))) + { + PPARTITION_HEADER_DESC phd; + + phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); +#ifdef UDF_DBG + if(phd->unallocatedSpaceTable.extLength) { + // rebuild unallocatedSpaceTable + KdPrint(("unallocatedSpaceTable (part %d)\n", i)); + } + if(phd->freedSpaceTable.extLength) { + // rebuild freedSpaceTable + KdPrint(("freedSpaceTable (part %d)\n", i)); + } +#endif // UDF_DBG + UDFUpdateXSpaceBitmaps(Vcb, p->partitionNumber, phd); + PTag = (tag*)Buf; + UDFSetUpTag(Vcb, PTag, PTag->descCRCLength, PTag->tagLocation); + UDFWriteSectors(Vcb, TRUE, PTag->tagLocation, 1, FALSE, Buf, &WrittenBytes); + } + } + return STATUS_SUCCESS; +} // end UDFUpdatePartDesc() + +/* + This routine blanks Unalloc Space Desc + *//* +OSSTATUS +UDFUpdateUSpaceDesc( + IN PVCB Vcb, + int8* Buf + ) +{ + PUNALLOC_SPACE_DESC usd; + uint32 WrittenBytes; + + usd = (PUNALLOC_SPACE_DESC)Buf; + usd->numAllocDescs = 0; + RtlZeroMemory(Buf+sizeof(UNALLOC_SPACE_DESC), Vcb->BlockSize - sizeof(UNALLOC_SPACE_DESC)); + UDFSetUpTag(Vcb, &(usd->descTag), 0, usd->descTag.tagLocation); + UDFWriteSectors(Vcb, TRUE, usd->descTag.tagLocation, 1, FALSE, Buf, &WrittenBytes); + return STATUS_SUCCESS; +}*/ + +/* + update Logical volume integrity descriptor + */ +OSSTATUS +UDFUpdateLogicalVolInt( + PVCB Vcb, + BOOLEAN Close + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + uint32 i, len; + uint32 WrittenBytes; +// uint32 lvid_count = 0; + uint32 pSize; + tag* PTag; + LogicalVolIntegrityDesc *lvid; + LogicalVolIntegrityDescImpUse* LVID_iUse; + LogicalVolHeaderDesc* LVID_hd; + uint32* partFreeSpace; + BOOLEAN equal = FALSE; + + if(Vcb->CDR_Mode) + return STATUS_SUCCESS; + if(!Vcb->LVid) { + return STATUS_UNSUCCESSFUL; + } + + KdPrint(("UDF: Updating LVID @%x (%x)\n", Vcb->LVid_loc.extLocation, Vcb->LVid_loc.extLength)); + len = max(Vcb->LVid_loc.extLength, Vcb->BlockSize); + lvid = Vcb->LVid; + if(lvid->descTag.tagSerialNum > UDF_LVID_TTL) { + // TODO: allocate space for new LVID + } + + LVID_iUse = UDFGetLVIDiUse(Vcb); + + if((LVID_iUse->minUDFReadRev == Vcb->minUDFReadRev) && + (LVID_iUse->minUDFReadRev == Vcb->minUDFReadRev) && + (LVID_iUse->maxUDFWriteRev == Vcb->maxUDFWriteRev) && + (LVID_iUse->numFiles == Vcb->numFiles) && + (LVID_iUse->numDirs == Vcb->numDirs)) + equal = TRUE; + + LVID_iUse->minUDFReadRev = Vcb->minUDFReadRev; + LVID_iUse->minUDFWriteRev = Vcb->minUDFWriteRev; + LVID_iUse->maxUDFWriteRev = Vcb->maxUDFWriteRev; + + LVID_iUse->numFiles = Vcb->numFiles; + LVID_iUse->numDirs = Vcb->numDirs; + +#if 0 + UDFSetEntityID_imp(&(LVID_iUse->impIdent), UDF_ID_DEVELOPER); +#endif + + if(Close){ + KdPrint(("UDF: Opening LVID\n")); + lvid->integrityType = INTEGRITY_TYPE_CLOSE; + } else { + KdPrint(("UDF: Closing LVID\n")); + lvid->integrityType = INTEGRITY_TYPE_OPEN; + } + + equal = equal && (Vcb->IntegrityType == lvid->integrityType); + + // update Free Space Table + partFreeSpace = (uint32*)(lvid+1); + for(i=0; inumOfPartitions; i++) { + pSize = UDFGetPartFreeSpace(Vcb, i) >> Vcb->LB2B_Bits; + equal = equal && (partFreeSpace[i] == pSize); + partFreeSpace[i] = pSize; + } + + // Update LVID Header Descriptor + LVID_hd = (LogicalVolHeaderDesc*)&(lvid->logicalVolContentsUse); + equal = equal && (LVID_hd->uniqueID == Vcb->NextUniqueId); + LVID_hd->uniqueID = Vcb->NextUniqueId; + + if(equal) { + KdPrint(("UDF: equal Ids\n")); + return STATUS_SUCCESS; + } + + PTag = &(lvid->descTag); + lvid->lengthOfImpUse = + sizeof(LogicalVolIntegrityDescImpUse); + UDFSetUpTag(Vcb, PTag, + sizeof(LogicalVolIntegrityDesc) + + sizeof(uint32)*2*lvid->numOfPartitions + + sizeof(LogicalVolIntegrityDescImpUse), + PTag->tagLocation); + + Vcb->IntegrityType = INTEGRITY_TYPE_OPEN; // make happy auto-dirty + RC = UDFWriteSectors(Vcb, TRUE, PTag->tagLocation, len >> Vcb->BlockSizeBits, FALSE, (int8*)(lvid), &WrittenBytes); + WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, PTag->tagLocation, len >> Vcb->BlockSizeBits); + // update it here to prevent recursion + Vcb->IntegrityType = lvid->integrityType; + + return RC; +} // end UDFUpdateLogicalVolInt() + +/* + This routine reads all sparing tables & stores them in contiguos memory + space + */ +OSSTATUS +UDFUpdateSparingTable( + IN PVCB Vcb + ) +{ + PSPARING_MAP RelocMap; +// PSPARING_MAP NewRelocMap; + OSSTATUS status = STATUS_SUCCESS; + OSSTATUS status2 = STATUS_SUCCESS; + uint32 i=0, BC, BC2; + PSPARING_TABLE SparTable; + uint32 ReadBytes; +// uint32 n,m; +// BOOLEAN merged; + BOOLEAN sorted; + + KdPrint(("UDF: Updating Sparable Part Map:\n")); + if(!Vcb->SparingTableModified) return STATUS_SUCCESS; + if(!Vcb->SparingTable) return STATUS_SUCCESS; + + BC = (Vcb->SparingTableLength >> Vcb->BlockSizeBits) + 1; + SparTable = (PSPARING_TABLE)MyAllocatePool__(NonPagedPool, BC*Vcb->BlockSize); + if(!SparTable) return STATUS_INSUFFICIENT_RESOURCES; + // if a part of Sparing Table is already loaded, + // update it with data from another one + RelocMap = Vcb->SparingTable; + // sort sparing table + //merged = FALSE; + do { + sorted = FALSE; + for(i=1;iSparingCount;i++) { + if(RelocMap[i-1].origLocation > RelocMap[i].origLocation) { + XCHG_DD(RelocMap[i-1].origLocation, RelocMap[i].origLocation); +swp_loc: + XCHG_DD(RelocMap[i-1].mappedLocation, RelocMap[i].mappedLocation); + //merged = TRUE; + sorted = TRUE; + } else + if(RelocMap[i-1].origLocation == SPARING_LOC_AVAILABLE && + RelocMap[i].origLocation == SPARING_LOC_AVAILABLE && + RelocMap[i-1].mappedLocation > RelocMap[i].mappedLocation) { + goto swp_loc; + } + } + } while(sorted); + + for(i=0;iSparingCount;i++) { + KdPrint((" @%x -> %x \n", + RelocMap[i].origLocation, RelocMap[i].mappedLocation)); + } + + Vcb->SparingTableModified = FALSE; +// if(!merged) { +// KdPrint((" sparing table unchanged\n")); +// MyFreePool__(SparTable); +// return STATUS_SUCCESS; +// } + + // walk through all available Sparing Tables + for(i=0;iSparingTableCount;i++) { + // read (next) table + KdPrint((" sparing table @%x\n", Vcb->SparingTableLoc[i])); + status = UDFReadSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], 1, FALSE, (int8*)SparTable, &ReadBytes); + // tag should be set to TID_UNUSED_DESC + if(OS_SUCCESS(status) && (SparTable->descTag.tagIdent == TID_UNUSED_DESC)) { + + BC2 = ((sizeof(SPARING_TABLE) + + SparTable->reallocationTableLen*sizeof(SparingEntry) + + Vcb->BlockSize-1) + >> Vcb->BlockSizeBits); + if(BC2 > BC) { + KdPrint((" sizeSparingTable @%x too long: %x > %x\n", + Vcb->SparingTableLoc[i], BC2, BC + )); + continue; + } + status = UDFReadSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], + BC2, FALSE, (int8*)SparTable, &ReadBytes); + + if(!OS_SUCCESS(status)) { + KdPrint((" Error reading sizeSparingTable @%x (%x)\n", + Vcb->SparingTableLoc[i], BC2 + )); + continue; + } + + BC2 = ((sizeof(SPARING_TABLE) + + Vcb->SparingCount*sizeof(SparingEntry) + + Vcb->BlockSize-1) + >> Vcb->BlockSizeBits); + if(BC2 > BC) { + KdPrint((" new sizeSparingTable @%x too long: %x > %x\n", + Vcb->SparingTableLoc[i], BC2, BC + )); + continue; + } + + SparTable->reallocationTableLen = (USHORT)Vcb->SparingCount; + RtlCopyMemory((SparTable+1), RelocMap, Vcb->SparingCount*sizeof(SparingEntry)); +/* + merged = FALSE; + NewRelocMap = (PSPARING_MAP)(SparTable+1); + for(n=0; nreallocationTableLen; n++) { + for(m=0; mSparingCount; m++) { + if(RelocMap[m].mappedLocation == NewRelocMap[n].mappedLocation) { + if(RelocMap[m].origLocation != NewRelocMap[n].origLocation) { + KdPrint((" update @%x (%x) -> @%x (%x)\n", + NewRelocMap[m].origLocation, NewRelocMap[m].mappedLocation, + RelocMap[m].origLocation, RelocMap[m].mappedLocation)); + merged = TRUE; + } + } + } + } +*/ +// if(merged) { + KdPrint(("UDF: record updated\n")); + status = UDFWriteSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], BC2, FALSE, (int8*)SparTable, &ReadBytes); + if(!OS_SUCCESS(status)) { + if(!OS_SUCCESS(status2)) { + status2 = status; + } +// } + } + } + } + MyFreePool__(SparTable); + if(!OS_SUCCESS(status2)) { + status = status2; + } + return status; +} // end UDFUpdateSparingTable() + +/* + update Logical volume descriptor + */ +OSSTATUS +UDFUpdateLogicalVol( + IN PVCB Vcb, + IN UDF_VDS_RECORD Lba, + IN PUNICODE_STRING VolIdent + ) +{ + LogicalVolDesc* lvd = NULL; +#define CUR_IDENT_SZ (sizeof(lvd->logicalVolIdent)) + dstring CS0[CUR_IDENT_SZ]; + uint16 ident; + uint32 WrittenBytes; + OSSTATUS status = STATUS_SUCCESS; +// OSSTATUS status2 = STATUS_SUCCESS; + + status = UDFUpdateSparingTable(Vcb); + + if(!(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_VLABEL)) { + goto Err_SetVI; + } + + lvd = (LogicalVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->BlockSize, sizeof(LogicalVolDesc)) ); + + if(!lvd) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Err_SetVI; + } + + KdPrint(("UDF: Updating LVD @%x (%x)\n", Lba.block, Vcb->BlockSize)); + + status = UDFSetDstring(&(Vcb->VolIdent), (dstring*)&CS0, CUR_IDENT_SZ); + if(!OS_SUCCESS(status)) { + if(status == STATUS_INVALID_PARAMETER) { + status = STATUS_INVALID_VOLUME_LABEL; + } + goto Err_SetVI; + } + + if(!Lba.block) { + status = STATUS_INVALID_PARAMETER; + goto Err_SetVI; + } + status = UDFReadTagged(Vcb, (int8*)lvd, Lba.block, Lba.block, &ident); + if(!OS_SUCCESS(status)) goto Err_SetVI; + if(ident != TID_LOGICAL_VOL_DESC) { + status = STATUS_FILE_CORRUPT_ERROR; + goto Err_SetVI; + } + + if(RtlCompareMemory(lvd->logicalVolIdent, CS0, CUR_IDENT_SZ) == CUR_IDENT_SZ) { + // no changes + KdPrint(("UDF: equal VolIds\n")); + status = STATUS_SUCCESS; + goto Err_SetVI; + } + RtlCopyMemory(lvd->logicalVolIdent, CS0, CUR_IDENT_SZ); + + lvd->descTag.tagSerialNum --; + UDFSetUpTag(Vcb, (tag*)lvd, lvd->descTag.descCRCLength, Lba.block); + + status = UDFWriteSectors(Vcb, TRUE, Lba.block, 1, FALSE, (int8*)lvd, &WrittenBytes); + +Err_SetVI: + if(lvd) + MyFreePool__(lvd); + +#undef CUR_IDENT_SZ +//#endif //0 + + return status; +} // end UDFUpdateLogicalVol() + +/* + This routine updates volume descriptor sequence + */ +OSSTATUS +UDFUpdateVDS( + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + IN uint32 flags + ) +{ + OSSTATUS status; + int8* Buf = (int8*)DbgAllocatePool(NonPagedPool,Vcb->LBlockSize); + UDF_VDS_RECORD vds[VDS_POS_LENGTH]; + uint32 i,j; + uint16 ident; + + if (!Buf) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); + if(!OS_SUCCESS(status = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) { + DbgFreePool(Buf); + return status; + } + +/* + // update USD (if any) + for (i=0; iBlockSize); + if (!Buf2) { + DbgFreePool(Buf); + return STATUS_INSUFFICIENT_RESOURCES; + } + for (j=vds[i].block+1; jBlockSize); + if (!Buf2) { + DbgFreePool(Buf); + return STATUS_INSUFFICIENT_RESOURCES; + } + UDFUpdatePartDesc(Vcb,Buf); + for (j=vds[i].block+1; jVolIdent)); + if(!OS_SUCCESS(status)) + continue; + } + } + } + + DbgFreePool(Buf); + return status; +} // end UDFUpdateVDS() +#endif //UDF_READ_ONLY_BUILD + +OSSTATUS +__fastcall +UDFSetDstring( + IN PUNICODE_STRING UName, + IN dstring* Dest, + IN uint32 Length + ) +{ + uint8* CS0; + uint32 len = Length-1; + + UDFCompressUnicode(UName, &CS0, &len); + if(!CS0) + return STATUS_INSUFFICIENT_RESOURCES; + if(len > Length-1) { + MyFreePool__(CS0); + return STATUS_INVALID_PARAMETER; + } + RtlCopyMemory(Dest, CS0, len); + MyFreePool__(CS0); + if(len < Length-1) + RtlZeroMemory(Dest+len, Length-1-len); + Dest[Length-1] = (uint8)len; + return TRUE; +} // end UDFSetDstring() + +void +__fastcall +UDFGetDstring( + IN OUT PUNICODE_STRING UName, + IN dstring* Dest, + IN uint32 Length + ) +{ + uint32 len = Dest[Length-1]; + + UDFDecompressUnicode(UName, Dest, len, NULL); + return; +} // end UDFGetDstring() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine updates Volume Label & some other features stored in + VolIdentDesc + */ +OSSTATUS +UDFUpdateVolIdent( + IN PVCB Vcb, + IN UDF_VDS_RECORD Lba, + IN PUNICODE_STRING VolIdent + ) +{ +#define CUR_IDENT_SZ (sizeof(pvoldesc->volIdent)) + PrimaryVolDesc* pvoldesc = (PrimaryVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->BlockSize, sizeof(PrimaryVolDesc)) ); + OSSTATUS status; + dstring CS0[CUR_IDENT_SZ]; + uint16 ident; + uint32 WrittenBytes; + + if(!pvoldesc) return STATUS_INSUFFICIENT_RESOURCES; + + KdPrint(("UDF: Updating PVD @%x (%x)\n", Lba.block, Vcb->BlockSize)); + + status = UDFSetDstring(&(Vcb->VolIdent), (dstring*)&CS0, CUR_IDENT_SZ); + if(!OS_SUCCESS(status)) { + if(status == STATUS_INVALID_PARAMETER) { + status = STATUS_INVALID_VOLUME_LABEL; + } + goto Err_SetVI; + } + + if(!Lba.block) { + status = STATUS_INVALID_PARAMETER; + goto Err_SetVI; + } + status = UDFReadTagged(Vcb, (int8*)pvoldesc, Lba.block, Lba.block, &ident); + if(!OS_SUCCESS(status)) goto Err_SetVI; + if(ident != TID_PRIMARY_VOL_DESC) { + status = STATUS_FILE_CORRUPT_ERROR; + goto Err_SetVI; + } + + if(RtlCompareMemory(pvoldesc->volIdent, CS0, CUR_IDENT_SZ) == CUR_IDENT_SZ) { + // no changes + status = STATUS_SUCCESS; + goto Err_SetVI; + } + RtlCopyMemory(pvoldesc->volIdent, CS0, CUR_IDENT_SZ); + + pvoldesc->descTag.tagSerialNum --; + UDFSetUpTag(Vcb, (tag*)pvoldesc, pvoldesc->descTag.descCRCLength, Lba.block); + + status = UDFWriteSectors(Vcb, TRUE, Lba.block, 1, FALSE, (int8*)pvoldesc, &WrittenBytes); +Err_SetVI: + MyFreePool__(pvoldesc); + return status; + +#undef CUR_IDENT_SZ +} // end UDFUpdateVolIdent() +#endif //UDF_READ_ONLY_BUILD + +OSSTATUS +UDFUpdateNonAllocated( + IN PVCB Vcb + ) +{ + uint32 PartNum; + uint32 i; + uint32 plen, pstart, pend; + int8* bad_bm; + EXTENT_AD Ext; + PEXTENT_MAP Map = NULL; + PEXTENT_INFO DataLoc; + + KdPrint(("UDFUpdateNonAllocated:\n")); + if(!Vcb->NonAllocFileInfo) { + return STATUS_SUCCESS; + } + if(!(bad_bm = Vcb->BSBM_Bitmap)) { + return STATUS_SUCCESS; + } + + DataLoc = &(Vcb->NonAllocFileInfo->Dloc->DataLoc); + ASSERT(!DataLoc->Offset); + if(Vcb->NonAllocFileInfo->Dloc->DataLoc.Offset) { + KdPrint(("NonAllocFileInfo in IN_ICB mode !!!\n")); + return STATUS_SUCCESS; + } + PartNum = UDFGetPartNumByPhysLba(Vcb, Vcb->NonAllocFileInfo->Dloc->FELoc.Mapping[0].extLocation); + pstart = UDFPartStart(Vcb, PartNum); + plen = UDFPartLen(Vcb, PartNum); + pend = min(pstart + plen, Vcb->FSBM_BitCount); + + //BrutePoint(); + for(i=pstart; iMapping, i) != LBA_OUT_OF_EXTENT) { + KdPrint(("lba %#x is already in NonAllocFileInfo\n", i)); + continue; + } + KdPrint(("add lba %#x to NonAllocFileInfo\n", i)); + DataLoc->Modified = TRUE; + Ext.extLength = Vcb->LBlockSize; + // align lba on LogicalBlock boundary + Ext.extLocation = i & ~((1<LB2B_Bits) - 1); + Map = UDFExtentToMapping(&Ext); + DataLoc->Mapping = UDFMergeMappings(DataLoc->Mapping, Map); + } + UDFPackMapping(Vcb, DataLoc); + DataLoc->Length = UDFGetExtentLength(DataLoc->Mapping); + UDFFlushFile__(Vcb, Vcb->NonAllocFileInfo); + + // ensure that BAD space is marked as USED + UDFMarkSpaceAsXXX(Vcb, 0, &(DataLoc->Mapping[0]), AS_USED); // mark as used + + KdPrint(("UDFUpdateNonAllocated: done\n")); + return STATUS_SUCCESS; +} // end UDFUpdateNonAllocated() + +/* + This routine rebuilds & flushes all system areas + */ +OSSTATUS +UDFUmount__( + IN PVCB Vcb + ) +{ +#ifndef UDF_READ_ONLY_BUILD + uint32 flags = 0; + + if(((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + !(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED)) + || !Vcb->Modified) + return STATUS_SUCCESS; + // prevent discarding metadata + Vcb->VCBFlags |= UDF_VCB_ASSUME_ALL_USED; + if(Vcb->CDR_Mode) { + // flush internal cache + if(WCacheGetWriteBlockCount__(&(Vcb->FastCache)) >= (Vcb->WriteBlockSize >> Vcb->BlockSizeBits) ) + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + // record VAT + return UDFRecordVAT(Vcb); + } + + UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE); + UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR); + + if(Vcb->VerifyOnWrite) { + KdPrint(("UDF: Flushing cache for verify\n")); + //WCacheFlushAll__(&(Vcb->FastCache), Vcb); + WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); + UDFVFlush(Vcb); + } + + // synchronize BAD Block bitmap and NonAllocatable + UDFUpdateNonAllocated(Vcb); + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); + + // RAM mode +#ifdef UDF_DBG + if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)))) + KdPrint(("Error updating VolIdent (1)\n")); + if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)))) + KdPrint(("Error updating VolIdent (2)\n")); +#else + UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)); + UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)); +#endif // UDF_DBG + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + // check if we should update BM + if(Vcb->FSBM_ByteCount == RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) { + flags &= ~1; + } else { + flags |= 1; + } + +#ifdef UDF_DBG + if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags))) + KdPrint(("Error updating Main VDS\n")); + if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags))) + KdPrint(("Error updating Reserve VDS\n")); +#else + UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags); + UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags); +#endif // UDF_DBG + + // Update Integrity Desc if any + if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) { + UDFUpdateLogicalVolInt(Vcb, TRUE); + } + + if(flags & 1) + RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); + +//skip_update_bitmap: + + Vcb->VCBFlags &= ~UDF_VCB_ASSUME_ALL_USED; + + UDFReleaseResource(&(Vcb->BitMapResource1)); +#endif //UDF_READ_ONLY_BUILD + + return STATUS_SUCCESS; +} // end UDFUmount__() + +/************************************************************************* + +/* + Find an anchor volume descriptor. + The UDFGetDiskInfoAndVerify() will invoke this routine to find & check + Anchor Volume Descriptors on the target device +*/ +lba_t +UDFFindAnchor( + PVCB Vcb // Volume control block + ) +{ +// OSSTATUS RC = STATUS_SUCCESS; + + uint16 ident; + uint32 i; + uint32 LastBlock; + OSSTATUS status; + int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + BOOLEAN MRW_candidate; + BOOLEAN IsMRW = (Vcb->MRWStatus != 0); + if(!Buf) + return 0; + + KdPrint(("UDFFindAnchor\n")); + // init probable locations... + RtlZeroMemory(&(Vcb->Anchor), sizeof(Vcb->Anchor)); + Vcb->Anchor[0] = 256 + Vcb->FirstLBALastSes; + Vcb->Anchor[1] = 512 + Vcb->FirstLBALastSes; + Vcb->Anchor[2] = 256 + Vcb->TrackMap[Vcb->LastTrackNum].FirstLba; + Vcb->Anchor[3] = 512 + Vcb->TrackMap[Vcb->LastTrackNum].FirstLba; + Vcb->Anchor[4] = Vcb->LastLBA - 256; + Vcb->Anchor[5] = Vcb->LastLBA - 256 + 1; + Vcb->Anchor[6] = Vcb->LastLBA - 256 - 2; + // vat locations + Vcb->Anchor[7] = Vcb->LastLBA - 2; + Vcb->Anchor[8] = Vcb->LastLBA; + Vcb->Anchor[9] = Vcb->LastLBA - 512; +// Vcb->Anchor[7] = Vcb->LastLBA - 256 - 7; +// Vcb->Anchor[8] = Vcb->LastLBA - 512 - 2; +// Vcb->Anchor[9] = Vcb->LastLBA - 512 - 7; + + LastBlock = 0; + // ... and check them + for (i=0; iAnchor)/sizeof(int); i++) { + if(Vcb->Anchor[i] > Vcb->LastLBA) + Vcb->Anchor[i] = 0; + MRW_candidate = FALSE; + if(Vcb->Anchor[i]) { + KdPrint(("check Anchor %x\n", Vcb->Anchor[i])); + if(!OS_SUCCESS(status = UDFReadTagged(Vcb,Buf, + Vcb->Anchor[i], Vcb->Anchor[i], &ident))) { + + // Fucking MRW... + if(!IsMRW && (i<2) && + (Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM)) { + if(OS_SUCCESS(status = UDFReadTagged(Vcb,Buf, + Vcb->Anchor[i]+MRW_DMA_OFFSET, Vcb->Anchor[i], &ident))) { + // do MRW workaround..... + KdPrint(("UDF: looks like we have MRW....\n")); + MRW_candidate = TRUE; + goto MRW_workaround; + } + } + + Vcb->Anchor[i] = 0; + if(status == STATUS_NONEXISTENT_SECTOR) { + KdPrint(("UDF: disk seems to be incomplete\n")); + break; + } + } else { +MRW_workaround: + if((ident != TID_ANCHOR_VOL_DESC_PTR) && ((i<6) || + (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY))) { + Vcb->Anchor[i] = 0; + } else { + KdPrint(("UDF: Found AVD at %x (point %d)\n",Vcb->Anchor[i], i)); + if(!LastBlock) + LastBlock = Vcb->LastLBA; + if(MRW_candidate) { + KdPrint(("UDF: looks like we _*really*_ have MRW....\n")); + IsMRW = TRUE; + ASSERT(Vcb->LastReadTrack == 1); + Vcb->TrackMap[Vcb->LastReadTrack].Flags |= TrackMap_FixMRWAddressing; + WCachePurgeAll__(&(Vcb->FastCache), Vcb); + KdPrint(("UDF: MRW on non-MRW drive => ReadOnly")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + + UDFRegisterFsStructure(Vcb, Vcb->Anchor[i], Vcb->BlockSize); + + } + } + } + } + } + + KdPrint(("UDF: -----------------\nUDF: Last block %x\n",LastBlock)); + MyFreePool__(Buf); + return LastBlock; +} // end UDFFindAnchor() + +/* + Look for Volume recognition sequence + */ +uint32 +UDFFindVRS( + PVCB Vcb + ) +{ + VolStructDesc *vsd = NULL; + uint32 offset; + uint32 retStat = 0; + uint32 BeginOffset = Vcb->FirstLBA; + OSSTATUS RC; + int8* buffer = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + uint32 ReadBytes; + + if(!buffer) return 0; + // Relative to First LBA in Last Session + offset = Vcb->FirstLBA + 0x10; + + KdPrint(("UDFFindVRS:\n")); + + // Process the sequence (if applicable) + for (;(offset-BeginOffset <=0x20); offset ++) { + // Read a block + RC = UDFReadSectors(Vcb, FALSE, offset, 1, FALSE, buffer, &ReadBytes); + if(!OS_SUCCESS(RC)) continue; + + // Look for ISO descriptors + vsd = (VolStructDesc *)(buffer); + + if(vsd->stdIdent[0]) { + if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_CD001, STD_ID_LEN)) + { + retStat |= VRS_ISO9660_FOUND; + switch (vsd->structType) + { + case 0: + KdPrint(("UDF: ISO9660 Boot Record found\n")); + break; + case 1: + KdPrint(("UDF: ISO9660 Primary Volume Descriptor found\n")); + break; + case 2: + KdPrint(("UDF: ISO9660 Supplementary Volume Descriptor found\n")); + break; + case 3: + KdPrint(("UDF: ISO9660 Volume Partition Descriptor found\n")); + break; + case 255: + KdPrint(("UDF: ISO9660 Volume Descriptor Set Terminator found\n")); + break; + default: + KdPrint(("UDF: ISO9660 VRS (%u) found\n", vsd->structType)); + break; + } + } + else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_BEA01, STD_ID_LEN)) + { + KdPrint(("UDF: BEA01 Found\n")); + } + else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_TEA01, STD_ID_LEN)) + { + KdPrint(("UDF: TEA01 Found\n")); + break; + } + else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_NSR02, STD_ID_LEN)) + { + retStat |= VRS_NSR02_FOUND; + KdPrint(("UDF: NSR02 Found\n")); + break; + } + else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_NSR03, STD_ID_LEN)) + { + retStat |= VRS_NSR03_FOUND; + KdPrint(("UDF: NSR03 Found\n")); + break; + } + } + } + + MyFreePool__(buffer); + + return retStat; +} // end UDFFindVRS() + +/* + process Primary volume descriptor + */ +void +UDFLoadPVolDesc( + PVCB Vcb, + int8* Buf // pointer to buffer containing PVD + ) +{ + PrimaryVolDesc *pvoldesc; +// OSSTATUS RC = STATUS_SUCCESS; + + pvoldesc = (PrimaryVolDesc *)Buf; + KdPrint(("UDF: PrimaryVolDesc:\n")); + KdPrint(("volDescSeqNum = %d\n", pvoldesc->volDescSeqNum)); + KdPrint(("primaryVolDescNum = %d\n", pvoldesc->primaryVolDescNum)); + // remember recording time... + Vcb->VolCreationTime = UDFTimeToNT(&(pvoldesc->recordingDateAndTime)); + // ...VolIdent... +#define CUR_IDENT_SZ (sizeof(pvoldesc->volIdent)) + if (Vcb->VolIdent.Buffer) { + MyFreePool__(Vcb->VolIdent.Buffer); + } + UDFGetDstring(&(Vcb->VolIdent), (dstring*)&(pvoldesc->volIdent), CUR_IDENT_SZ); +#undef CUR_IDENT_SZ + KdPrint(("volIdent[] = '%ws'\n", Vcb->VolIdent.Buffer)); +#ifdef UDF_DBG + KdPrint(("volSeqNum = %d\n", pvoldesc->volSeqNum)); + KdPrint(("maxVolSeqNum = %d\n", pvoldesc->maxVolSeqNum)); + KdPrint(("interchangeLvl = %d\n", pvoldesc->interchangeLvl)); + KdPrint(("maxInterchangeLvl = %d\n", pvoldesc->maxInterchangeLvl)); + KdPrint(("charSetList = %d\n", pvoldesc->charSetList)); + KdPrint(("maxCharSetList = %d\n", pvoldesc->maxCharSetList)); + // ...& just print VolSetIdent + UNICODE_STRING instr; +#define CUR_IDENT_SZ (sizeof(pvoldesc->volSetIdent)) + UDFGetDstring(&instr, (dstring*)&(pvoldesc->volSetIdent), CUR_IDENT_SZ); +#undef CUR_IDENT_SZ + KdPrint(("volSetIdent[] = '%ws'\n", instr.Buffer)); +// KdPrint(("maxInterchangeLvl = %d\n", pvoldesc->maxInterchangeLvl)); + KdPrint(("flags = %x\n", pvoldesc->flags)); + if(instr.Buffer) MyFreePool__(instr.Buffer); +#endif // UDF_DBG +} // end UDFLoadPVolDesc() + +/* + load Logical volume integrity descriptor + */ +OSSTATUS +UDFLoadLogicalVolInt( + PDEVICE_OBJECT DeviceObject, + PVCB Vcb, + extent_ad loc + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + uint32 len; + uint32 _ReadBytes; + int8* Buf = NULL; + uint16 ident; + LogicalVolIntegrityDescImpUse* LVID_iUse; + LogicalVolHeaderDesc* LVID_hd; + extent_ad last_loc; + BOOLEAN read_last = FALSE; + uint32 lvid_count = 0; + + ASSERT(!Vcb->LVid); + if(Vcb->LVid) { + MyFreePool__(Vcb->LVid); + Vcb->LVid = NULL; + } + // walk through all sectors inside LogicalVolumeIntegrityDesc + while(loc.extLength) { + KdPrint(("UDF: Reading LVID @%x (%x)\n", loc.extLocation, loc.extLength)); + len = max(loc.extLength, Vcb->BlockSize); + Buf = (int8*)MyAllocatePool__(NonPagedPool,len); + if(!Buf) + return STATUS_INSUFFICIENT_RESOURCES; + RC = UDFReadTagged(Vcb,Buf, loc.extLocation, loc.extLocation, &ident); + if(!OS_SUCCESS(RC)) { +exit_with_err: + KdPrint(("UDF: Reading LVID @%x (%x) failed.\n", loc.extLocation, loc.extLength)); + switch(Vcb->PartitialDamagedVolumeAction) { + case UDF_PART_DAMAGED_RO: + KdPrint(("UDF: Switch to r/o mode.\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_MEDIA_DEFECT_RO; + RC = STATUS_SUCCESS; + break; + case UDF_PART_DAMAGED_NO: + KdPrint(("UDF: Switch to raw mount mode, return UNRECOGNIZED_VOLUME.\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + //RC = STATUS_WRONG_VOLUME; + break; + case UDF_PART_DAMAGED_RW: + default: + KdPrint(("UDF: Keep r/w mode for your own risk.\n")); + RC = STATUS_SUCCESS; + // asume we have INTEGRITY_TYPE_CLOSE + Vcb->IntegrityType = INTEGRITY_TYPE_CLOSE; + break; + } + + MyFreePool__(Buf); + return RC; + } + UDFRegisterFsStructure(Vcb, loc.extLocation, len); + // handle Terminal Entry + if(ident == TID_TERMINAL_ENTRY) { + read_last = TRUE; + MyFreePool__(Buf); + Vcb->LVid = NULL; + loc = last_loc; + continue; + } else + if(ident != TID_LOGICAL_VOL_INTEGRITY_DESC) { + RC = STATUS_DISK_CORRUPT_ERROR; + goto exit_with_err; + } + + Vcb->LVid = (LogicalVolIntegrityDesc *)Buf; + RC = UDFReadData(Vcb, TRUE, ((uint64)(loc.extLocation)) << Vcb->BlockSizeBits, len, FALSE, Buf, &_ReadBytes); + // update info + if( !read_last && + Vcb->LVid->nextIntegrityExt.extLength) { + // go to next LVID + last_loc = loc; + loc = Vcb->LVid->nextIntegrityExt; + Vcb->LVid = NULL; + MyFreePool__(Buf); + lvid_count++; + if(lvid_count > UDF_MAX_LVID_CHAIN_LENGTH) { + RC = STATUS_DISK_CORRUPT_ERROR; + goto exit_with_err; + } + continue; + } + // process last LVID + Vcb->origIntegrityType = + Vcb->IntegrityType = Vcb->LVid->integrityType; + Vcb->LVid_loc = loc; + + LVID_iUse = UDFGetLVIDiUse(Vcb); + + KdPrint(("UDF: Last LVID:\n")); + KdPrint((" minR: %x\n",LVID_iUse->minUDFReadRev )); + KdPrint((" minW: %x\n",LVID_iUse->minUDFWriteRev)); + KdPrint((" maxW: %x\n",LVID_iUse->maxUDFWriteRev)); + KdPrint((" Type: %s\n",!Vcb->IntegrityType ? "Open" : "Close")); + + Vcb->minUDFReadRev = LVID_iUse->minUDFReadRev; + Vcb->minUDFWriteRev = LVID_iUse->minUDFWriteRev; + Vcb->maxUDFWriteRev = LVID_iUse->maxUDFWriteRev; + + Vcb->numFiles = LVID_iUse->numFiles; + Vcb->numDirs = LVID_iUse->numDirs; + KdPrint((" nFiles: %x\n",Vcb->numFiles )); + KdPrint((" nDirs: %x\n",Vcb->numDirs )); + + // Check if we can understand this format + if(Vcb->minUDFReadRev > UDF_MAX_READ_REVISION) + RC = STATUS_UNRECOGNIZED_VOLUME; + // Check if we know how to write here + if(Vcb->minUDFWriteRev > UDF_MAX_WRITE_REVISION) { + KdPrint((" Target FS requires: %x Revision => ReadOnly\n",Vcb->minUDFWriteRev)); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_NEW_FS_RO; + } + + LVID_hd = (LogicalVolHeaderDesc*)&(Vcb->LVid->logicalVolContentsUse); + Vcb->NextUniqueId = LVID_hd->uniqueID; + KdPrint((" Next FID: %x\n",Vcb->NextUniqueId)); + + break; + } + + return RC; +} // end UDFLoadLogicalVolInt() + + +/* + load Logical volume descriptor + */ +OSSTATUS +UDFLoadLogicalVol( + PDEVICE_OBJECT DeviceObject, + PVCB Vcb, + int8* Buf, + lb_addr *fileset + ) +{ + LogicalVolDesc *lvd = (LogicalVolDesc *)Buf; + uint16 i, offset; + uint8 type; + OSSTATUS status = STATUS_SUCCESS; + KdPrint(("UDF: LogicalVolDesc\n")); + // Validate partition map counter + if(!(Vcb->Partitions)) { + Vcb->PartitionMaps = lvd->numPartitionMaps; + Vcb->Partitions = (PUDFPartMap)MyAllocatePool__(NonPagedPool, sizeof(UDFPartMap) * Vcb->PartitionMaps ); + if(!Vcb->Partitions) + return STATUS_INSUFFICIENT_RESOURCES; + } else { + if(Vcb->PartitionMaps != lvd->numPartitionMaps) + return STATUS_DISK_CORRUPT_ERROR; + } + KdPrint(("UDF: volDescSeqNum = %x\n", lvd->volDescSeqNum)); + // Get logical block size (may be different from physical) + Vcb->LBlockSize = lvd->logicalBlockSize; + // Get current UDF revision + // Get Read-Only flags + UDFReadEntityID_Domain(Vcb, &(lvd->domainIdent)); + + if(Vcb->LBlockSize < Vcb->BlockSize) + return STATUS_DISK_CORRUPT_ERROR; + switch(Vcb->LBlockSize) { + case 512: Vcb->LBlockSizeBits = 9; break; + case 1024: Vcb->LBlockSizeBits = 10; break; + case 2048: Vcb->LBlockSizeBits = 11; break; + case 4096: Vcb->LBlockSizeBits = 12; break; + case 8192: Vcb->LBlockSizeBits = 13; break; + case 16384: Vcb->LBlockSizeBits = 14; break; + case 32768: Vcb->LBlockSizeBits = 15; break; + case 65536: Vcb->LBlockSizeBits = 16; break; + default: + KdPrint(("UDF: Bad block size (%ld)\n", Vcb->LBlockSize)); + return STATUS_DISK_CORRUPT_ERROR; + } + KdPrint(("UDF: logical block size (%ld)\n", Vcb->LBlockSize)); + Vcb->LB2B_Bits = Vcb->LBlockSizeBits - Vcb->BlockSizeBits; + KdPrint(("UDF: mapTableLength = %x\n", lvd->mapTableLength)); + KdPrint(("UDF: numPartitionMaps = %x\n", lvd->numPartitionMaps)); + // walk through all available part maps + for (i=0,offset=0; + iPartitionMaps && offsetmapTableLength; + i++,offset+=((GenericPartitionMap *)( ((uint8*)(lvd+1))+offset) )->partitionMapLength) + { + GenericPartitionMap* gpm = (GenericPartitionMap *)(((uint8*)(lvd+1))+offset); + type = gpm->partitionMapType; + KdPrint(("Partition (%d) type %x, len %x\n", i, type, gpm->partitionMapLength)); + if(type == PARTITION_MAP_TYPE_1) + { + GenericPartitionMap1 *gpm1 = (GenericPartitionMap1 *)(((uint8*)(lvd+1))+offset); + + Vcb->Partitions[i].PartitionType = UDF_TYPE1_MAP15; + Vcb->Partitions[i].VolumeSeqNum = gpm1->volSeqNum; + Vcb->Partitions[i].PartitionNum = gpm1->partitionNum; + status = STATUS_SUCCESS; + } + else if(type == PARTITION_MAP_TYPE_2) + { + UdfPartitionMap2* upm2 = (UdfPartitionMap2 *)(((uint8*)(lvd+1))+offset); + if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) + { + UDFIdentSuffix* udfis = + (UDFIdentSuffix*)&(upm2->partIdent.identSuffix); + + if( (udfis->currentRev == 0x0150)/* || + (Vcb->CurrentUDFRev == 0x0150)*/ ) { + KdPrint(("Found VAT 1.50\n")); + Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP15; + } else + if( (udfis->currentRev == 0x0200) || + (udfis->currentRev == 0x0201) /*|| + (Vcb->CurrentUDFRev == 0x0200) || + (Vcb->CurrentUDFRev == 0x0201)*/ ) { + KdPrint(("Found VAT 2.00\n")); + Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP20; + } + status = STATUS_SUCCESS; + } + else if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) + { + KdPrint(("Load sparing table\n")); + PSPARABLE_PARTITION_MAP spm = (PSPARABLE_PARTITION_MAP)(((uint8*)(lvd+1))+offset); + Vcb->Partitions[i].PartitionType = UDF_SPARABLE_MAP15; + status = UDFLoadSparingTable(Vcb, spm); + } + else if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_METADATA, strlen(UDF_ID_METADATA))) + { + KdPrint(("Found metadata partition\n")); +// PMETADATA_PARTITION_MAP mpm = (PMETADATA_PARTITION_MAP)(((uint8*)(lvd+1))+offset); + Vcb->Partitions[i].PartitionType = UDF_METADATA_MAP25; + //status = UDFLoadSparingTable(Vcb, spm); + } + else + { + KdPrint(("Unknown ident: %s\n", upm2->partIdent.ident)); + continue; + } + Vcb->Partitions[i].VolumeSeqNum = upm2->volSeqNum; + Vcb->Partitions[i].PartitionNum = upm2->partitionNum; + } + } + + if(fileset) { + // remember FileSet location + long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); + *fileset = (la->extLocation); + KdPrint(("FileSet found in LogicalVolDesc at block=%x, partition=%d\n", + fileset->logicalBlockNum, + fileset->partitionReferenceNum)); + } + if(OS_SUCCESS(status)) { + // load Integrity Desc if any + if(lvd->integritySeqExt.extLength) + status = UDFLoadLogicalVolInt(DeviceObject,Vcb,lvd->integritySeqExt); + } + return status; +} // end UDFLoadLogicalVol() + +OSSTATUS +UDFLoadBogusLogicalVol( + PDEVICE_OBJECT DeviceObject, + PVCB Vcb, + int8* Buf, + lb_addr *fileset + ) +{ +// LogicalVolDesc *lvd = (LogicalVolDesc *)Buf; + KdPrint(("UDF: Bogus LogicalVolDesc\n")); + // Validate partition map counter + if(!(Vcb->Partitions)) { + Vcb->PartitionMaps = 1; + Vcb->Partitions = (PUDFPartMap)MyAllocatePool__(NonPagedPool, sizeof(UDFPartMap) * Vcb->PartitionMaps ); + if(!Vcb->Partitions) + return STATUS_INSUFFICIENT_RESOURCES; + } else { + if(Vcb->PartitionMaps != 1) + return STATUS_DISK_CORRUPT_ERROR; + } + KdPrint(("UDF: volDescSeqNum = %x\n", 0)); + // Get logical block size (may be different from physical) + Vcb->LBlockSize = 2048; + // Get current UDF revision + // Get Read-Only flags +// UDFReadEntityID_Domain(Vcb, &(lvd->domainIdent)); + + if(Vcb->LBlockSize < Vcb->BlockSize) + return STATUS_DISK_CORRUPT_ERROR; + Vcb->LBlockSizeBits = 11; + KdPrint(("UDF: logical block size (%ld)\n", Vcb->LBlockSize)); + Vcb->LB2B_Bits = Vcb->LBlockSizeBits - Vcb->BlockSizeBits; + KdPrint(("UDF: mapTableLength = %x\n", 0)); + KdPrint(("UDF: numPartitionMaps = %x\n", 0)); + +// if(CDRW) { + + Vcb->Partitions[0].PartitionType = UDF_TYPE1_MAP15; + Vcb->Partitions[0].VolumeSeqNum = 0; + Vcb->Partitions[0].PartitionNum = 0; + +/* } else if(CDR) + if() + KdPrint(("Found VAT 1.50\n")); + Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP15; + } else + KdPrint(("Found VAT 2.00\n")); + Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP20; + } + } + } +*/ + if(fileset) { + // remember FileSet location +// long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); + fileset->logicalBlockNum = 0; + fileset->partitionReferenceNum = 0; + KdPrint(("FileSet found in LogicalVolDesc at block=%x, partition=%d\n", + fileset->logicalBlockNum, + fileset->partitionReferenceNum)); + } + return STATUS_SUCCESS; +} // end UDFLoadBogusLogicalVol() + +/* + This routine adds given Bitmap to existing one + */ +OSSTATUS +UDFAddXSpaceBitmap( + IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD bm, + IN ULONG bm_type + ) +{ + int8* tmp; + int8* tmp_bm; + uint32 i, lim, j, lba, l, lim2, l2, k; + lb_addr locAddr; + OSSTATUS status; + uint16 Ident; + uint32 flags; + uint32 Length; + uint32 ReadBytes; + BOOLEAN bit_set; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + KdPrint(("UDFAddXSpaceBitmap: at block=%x, partition=%d\n", + bm->extPosition, + PartNum)); + + if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; + i=UDFPartStart(Vcb, PartNum); + flags = bm->extLength >> 30; + if(!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { + tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->BlockSize)); + if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; + locAddr.partitionReferenceNum = (uint16)PartNum; + locAddr.logicalBlockNum = bm->extPosition; + // read header of the Bitmap + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, lba = UDFPartLbaToPhys(Vcb, &(locAddr)), + locAddr.logicalBlockNum, &Ident)) ) { +err_addxsbm_1: + DbgFreePool(tmp); + return status; + } + if(Ident != TID_SPACE_BITMAP_DESC) { + status = STATUS_DISK_CORRUPT_ERROR; + goto err_addxsbm_1; + } + UDFRegisterFsStructure(Vcb, lba, Vcb->BlockSize); + // read the whole Bitmap + if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)lba)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) + goto err_addxsbm_1; + UDFRegisterFsStructure(Vcb, lba, Length); + lim = min(i + ((lim2 = ((PSPACE_BITMAP_DESC)tmp)->numOfBits) << Vcb->LB2B_Bits), Vcb->FSBM_BitCount); + tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); + j = 0; + for(;(l = UDFGetBitmapLen((uint32*)tmp_bm, j, lim2)) && (iLB2B_Bits; + // ...and mark them + if(bm_type == UDF_FSPACE_BM) { + bit_set = UDFGetFreeBit(tmp_bm, j); + for(k=0;(kFSBM_Bitmap, i); + UDFSetFreeBitOwner(Vcb, i); + UDFSetZeroBit(Vcb->ZSBM_Bitmap, i); + } else { + // USED block + UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); + } + i++; + } + } else { + bit_set = UDFGetZeroBit(tmp_bm, j); + for(k=0;(kZSBM_Bitmap, i); + } else { + // DATA block + UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); + } + i++; + } + } + j += l; + } + DbgFreePool(tmp); +/* } else if((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { + i=Vcb->Partitions[PartNum].PartitionRoot; + lim = i + Vcb->Partitions[PartNum].PartitionLen; + for(;iFSBM_Bitmap, i); + }*/ + } + return STATUS_SUCCESS; +} // end UDFAddXSpaceBitmap() + +/* + This routine adds given Bitmap to existing one + */ +OSSTATUS +UDFVerifyXSpaceBitmap( + IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD bm, + IN ULONG bm_type + ) +{ + int8* tmp; + int8* tmp_bm; +// uint32 i, lim, j, lba, l, lim2, l2, k; + uint32 i, lim, j, lba, lim2; + lb_addr locAddr; + OSSTATUS status; + uint16 Ident; + uint32 flags; + uint32 Length; + uint32 ReadBytes; +// BOOLEAN bit_set; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); + + KdPrint((" UDFVerifyXSpaceBitmap: part %x\n", PartNum)); + + if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; + i=UDFPartStart(Vcb, PartNum); + flags = bm->extLength >> 30; + if(!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { + tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->BlockSize)); + if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; + locAddr.partitionReferenceNum = (uint16)PartNum; + locAddr.logicalBlockNum = bm->extPosition; + // read header of the Bitmap + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, lba = UDFPartLbaToPhys(Vcb, &(locAddr)), + locAddr.logicalBlockNum, &Ident)) ) { +err_vfyxsbm_1: + DbgFreePool(tmp); + return status; + } + KdPrint((" BM Lba %x\n", lba)); + if(Ident != TID_SPACE_BITMAP_DESC) { + status = STATUS_DISK_CORRUPT_ERROR; + goto err_vfyxsbm_1; + } + // read the whole Bitmap + if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)lba)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) + goto err_vfyxsbm_1; + UDFRegisterFsStructure(Vcb, lba, Length); + lim = min(i + ((lim2 = ((PSPACE_BITMAP_DESC)tmp)->numOfBits) << Vcb->LB2B_Bits), Vcb->FSBM_BitCount); + tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); + j = 0; +/* for(;(l = UDFGetBitmapLen((uint32*)tmp_bm, j, lim2)) && (iLB2B_Bits; + // ...and mark them + if(bm_type == UDF_FSPACE_BM) { + bit_set = UDFGetFreeBit(tmp_bm, j); + for(k=0;(kFSBM_Bitmap, i); + UDFSetFreeBitOwner(Vcb, i); + UDFSetZeroBit(Vcb->ZSBM_Bitmap, i); + } else { + // USED block + UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); + } + i++; + } + } else { + bit_set = UDFGetZeroBit(tmp_bm, j); + for(k=0;(kZSBM_Bitmap, i); + } else { + // DATA block + UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); + } + i++; + } + } + j += l; + }*/ + DbgFreePool(tmp); +/* } else if((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { + i=Vcb->Partitions[PartNum].PartitionRoot; + lim = i + Vcb->Partitions[PartNum].PartitionLen; + for(;iFSBM_Bitmap, i); + }*/ + } + return STATUS_SUCCESS; +} // end UDFVerifyXSpaceBitmap() + +/* + This routine subtracts given Bitmap to existing one + */ +/*OSSTATUS +UDFDelXSpaceBitmap( + IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD bm + ) +{ + int8* tmp, tmp_bm; + uint32 i, lim, j; + lb_addr locAddr; + OSSTATUS status; + uint16 Ident; + uint32 flags; + uint32 Length; + uint32 ReadBytes; + + if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; + i=0; + flags = bm->extLength >> 30; + if(!flags || flags == EXTENT_NOT_RECORDED_ALLOCATED) { + tmp = (int8*)MyAllocatePool__(NonPagedPool, Length); + if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; + locAddr.partitionReferenceNum = (uint16)PartNum; + locAddr.logicalBlockNum = bm->extPosition; + if((!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, (j = UDFPartLbaToPhys(Vcb, &(locAddr))), + locAddr.logicalBlockNum, &Ident))) || + (Ident != TID_SPACE_BITMAP_DESC) ) { + MyFreePool__(tmp); + return status; + } + if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)j)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) { + MyFreePool__(tmp); + return status; + } + lim = i + ((PSPACE_BITMAP_DESC)tmp)->numOfBits; + tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); + j = 0; + for(;iFSBM_Bitmap, i); + j++; + } + MyFreePool__(tmp); +// } else if((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { +// i=Vcb->Partitions[PartNum].PartitionRoot; +// lim = i + Vcb->Partitions[PartNum].PartitionLen; +// for(;iFSBM_Bitmap, i); +// } + } + return STATUS_SUCCESS; +} // end UDFDelXSpaceBitmap() */ + +/* + This routine verifues FreeSpaceBitmap (internal) according to media + parameters & input data + */ +OSSTATUS +UDFVerifyFreeSpaceBitmap( + IN PVCB Vcb, + IN uint32 PartNdx, + IN PPARTITION_HEADER_DESC phd, // partition header pointing to Bitmaps + IN uint32 Lba // UnallocSpaceDesc + ) +{ + OSSTATUS status; + uint32 i, l; + uint16 Ident; + int8* AllocDesc; + PEXTENT_MAP Extent; + lb_addr locAddr; + uint32 PartNum; + + PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); + + KdPrint(("UDFVerifyFreeSpaceBitmap:\n")); + // read info for partition header (if any) + if(phd) { + // read unallocated Bitmap + if(!OS_SUCCESS(status = UDFVerifyXSpaceBitmap(Vcb, PartNum, &(phd->unallocatedSpaceBitmap), UDF_FSPACE_BM))) + return status; + // read freed Bitmap + if(!OS_SUCCESS(status = UDFVerifyXSpaceBitmap(Vcb, PartNum, &(phd->freedSpaceBitmap), UDF_ZSPACE_BM))) + return status; + } + // read UnallocatedSpaceDesc & convert to Bitmap + if(Lba) { + KdPrint((" Lba @%x\n", Lba)); + if(!(AllocDesc = (int8*)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize + sizeof(EXTENT_AD) ))) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(((int8*)AllocDesc) + Vcb->LBlockSize, sizeof(EXTENT_AD)); + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || + !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, l = (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { + MyFreePool__(AllocDesc); + return status; + } + UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); + RtlCopyMemory((int8*)Extent, AllocDesc+sizeof(UNALLOC_SPACE_DESC), (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ); + locAddr.partitionReferenceNum = (uint16)PartNum; + // read extent is recorded with relative addresses + // so, we should convert it to suitable form + for(i=0; Extent[i].extLength; i++) { + locAddr.logicalBlockNum = Extent[i].extLocation; + Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { + BrutePoint(); + MyFreePool__(AllocDesc); + return STATUS_DISK_CORRUPT_ERROR; + } + if((Extent[i].extLocation >> 30) == EXTENT_NEXT_EXTENT_ALLOCDESC) { + // load continuation + Lba = Extent[i].extLocation & UDF_EXTENT_LENGTH_MASK; + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || + !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { + MyFreePool__(AllocDesc); + return status; + } + if(Ident == TID_UNALLOC_SPACE_DESC) { + UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); + if(!(l = MyReallocPool__((int8*)Extent, l, (int8**)&Extent, i*sizeof(EXTENT_MAP)))) { + MyFreePool__(Extent); + MyFreePool__(AllocDesc); + return STATUS_INSUFFICIENT_RESOURCES; + } + Extent[i].extLength = + Extent[i].extLocation = 0; + Extent = UDFMergeMappings(Extent, (PEXTENT_MAP)(AllocDesc+sizeof(UNALLOC_SPACE_DESC)) ); +#ifdef UDF_DBG + } else { + KdPrint(("Broken unallocated space descriptor sequence\n")); +#endif // UDF_DBG + } + } + } +// UDFMarkSpaceAsXXX(Vcb, (-1), Extent, AS_USED); // mark as used + MyFreePool__(Extent); + MyFreePool__(AllocDesc); + status = STATUS_SUCCESS; + } + return status; +} // end UDFBuildFreeSpaceBitmap() + +/* + This routine builds FreeSpaceBitmap (internal) according to media + parameters & input data + */ +OSSTATUS +UDFBuildFreeSpaceBitmap( + IN PVCB Vcb, + IN uint32 PartNdx, + IN PPARTITION_HEADER_DESC phd, // partition header pointing to Bitmaps + IN uint32 Lba // UnallocSpaceDesc + ) +{ + OSSTATUS status; + uint32 i, l; + uint16 Ident; + int8* AllocDesc; + PEXTENT_MAP Extent; + lb_addr locAddr; + uint32 PartNum; + + PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); + if(!(Vcb->FSBM_Bitmap)) { + // init Bitmap buffer if necessary + Vcb->FSBM_Bitmap = (int8*)DbgAllocatePool(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3) ); + if(!(Vcb->FSBM_Bitmap)) return STATUS_INSUFFICIENT_RESOURCES; + + Vcb->ZSBM_Bitmap = (int8*)DbgAllocatePool(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3) ); + if(!(Vcb->ZSBM_Bitmap)) { +#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS +free_fsbm: +#endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS + MyFreePool__(Vcb->FSBM_Bitmap); + Vcb->FSBM_Bitmap = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Vcb->FSBM_Bitmap, i); + RtlZeroMemory(Vcb->ZSBM_Bitmap, i); +#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS + Vcb->FSBM_Bitmap_owners = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32)); + if(!(Vcb->FSBM_Bitmap_owners)) { + MyFreePool__(Vcb->ZSBM_Bitmap); + Vcb->ZSBM_Bitmap = NULL; + goto free_fsbm; + } + RtlFillMemory(Vcb->FSBM_Bitmap_owners, (Vcb->LastPossibleLBA+1)*sizeof(uint32), 0xff); +#endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS + Vcb->FSBM_ByteCount = i; + Vcb->FSBM_BitCount = Vcb->LastPossibleLBA+1; + } + // read info for partition header (if any) + if(phd) { + // read unallocated Bitmap + if(!OS_SUCCESS(status = UDFAddXSpaceBitmap(Vcb, PartNum, &(phd->unallocatedSpaceBitmap), UDF_FSPACE_BM))) + return status; + // read freed Bitmap + if(!OS_SUCCESS(status = UDFAddXSpaceBitmap(Vcb, PartNum, &(phd->freedSpaceBitmap), UDF_ZSPACE_BM))) + return status; + } + // read UnallocatedSpaceDesc & convert to Bitmap + if(Lba) { + if(!(AllocDesc = (int8*)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize + sizeof(EXTENT_AD) ))) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(((int8*)AllocDesc) + Vcb->LBlockSize, sizeof(EXTENT_AD)); + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || + !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, l = (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { + MyFreePool__(AllocDesc); + return status; + } + UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); + RtlCopyMemory((int8*)Extent, AllocDesc+sizeof(UNALLOC_SPACE_DESC), (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ); + locAddr.partitionReferenceNum = (uint16)PartNum; + // read extent is recorded with relative addresses + // so, we should convert it to suitable form + for(i=0; Extent[i].extLength; i++) { + locAddr.logicalBlockNum = Extent[i].extLocation; + Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); + if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { + BrutePoint(); + MyFreePool__(AllocDesc); + return STATUS_DISK_CORRUPT_ERROR; + } + if((Extent[i].extLocation >> 30) == EXTENT_NEXT_EXTENT_ALLOCDESC) { + // load continuation + Lba = Extent[i].extLocation & UDF_EXTENT_LENGTH_MASK; + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || + !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { + MyFreePool__(AllocDesc); + return status; + } + if(Ident == TID_UNALLOC_SPACE_DESC) { + UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); + if(!(l = MyReallocPool__((int8*)Extent, l, (int8**)&Extent, i*sizeof(EXTENT_MAP)))) { + MyFreePool__(Extent); + MyFreePool__(AllocDesc); + return STATUS_INSUFFICIENT_RESOURCES; + } + Extent[i].extLength = + Extent[i].extLocation = 0; + Extent = UDFMergeMappings(Extent, (PEXTENT_MAP)(AllocDesc+sizeof(UNALLOC_SPACE_DESC)) ); +#ifdef UDF_DBG + } else { + KdPrint(("Broken unallocated space descriptor sequence\n")); +#endif // UDF_DBG + } + } + } + UDFMarkSpaceAsXXX(Vcb, (-1), Extent, AS_USED); // mark as used + MyFreePool__(Extent); + MyFreePool__(AllocDesc); + } + return status; +} // end UDFVerifyFreeSpaceBitmap() + +/* + process Partition descriptor + */ +OSSTATUS +UDFLoadPartDesc( + PVCB Vcb, + int8* Buf + ) +{ + PartitionDesc *p = (PartitionDesc *)Buf; + uint32 i; + OSSTATUS RC; + BOOLEAN Found = FALSE; + KdPrint(("UDF: Pard Descr:\n")); + KdPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); + KdPrint((" partitionFlags = %x\n", p->partitionFlags)); + KdPrint((" partitionNumber = %x\n", p->partitionNumber)); + KdPrint((" accessType = %x\n", p->accessType)); + KdPrint((" partitionStartingLocation = %x\n", p->partitionStartingLocation)); + KdPrint((" partitionLength = %x\n", p->partitionLength)); + // There is nothing interesting to comment here + // Just look at Names & Messages.... + for (i=0; iPartitionMaps; i++) { + KdPrint(("Searching map: (%d == %d)\n", + Vcb->Partitions[i].PartitionNum, (p->partitionNumber) )); + if(Vcb->Partitions[i].PartitionNum == (p->partitionNumber)) { + Found = TRUE; + Vcb->Partitions[i].PartitionRoot = p->partitionStartingLocation + Vcb->FirstLBA; + Vcb->Partitions[i].PartitionLen = + min(p->partitionLength, + Vcb->LastPossibleLBA - Vcb->Partitions[i].PartitionRoot); /* sectors */ + Vcb->Partitions[i].UspaceBitmap = 0xFFFFFFFF; + Vcb->Partitions[i].FspaceBitmap = 0xFFFFFFFF; + Vcb->Partitions[i].AccessType = p->accessType; + KdPrint(("Access mode %x\n", p->accessType)); + if(p->accessType == PARTITION_ACCESS_WO) { + Vcb->CDR_Mode = TRUE; +// Vcb->Partitions[i].PartitionLen = Vcb->LastPossibleLBA - p->partitionStartingLocation; + } else if(p->accessType < PARTITION_ACCESS_WO) { + // Soft-read-only volume + KdPrint(("Soft Read-only volume\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_PART_RO; + } else if(p->accessType > PARTITION_ACCESS_MAX_KNOWN) { + return STATUS_UNRECOGNIZED_MEDIA; + } + + if(!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || + !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03)) + { + PPARTITION_HEADER_DESC phd; + + phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); +#ifdef UDF_DBG + if(phd->unallocatedSpaceTable.extLength) + KdPrint(("unallocatedSpaceTable (part %d)\n", i)); +#endif // UDF_DBG + if(phd->unallocatedSpaceBitmap.extLength) { + Vcb->Partitions[i].UspaceBitmap = + phd->unallocatedSpaceBitmap.extPosition; + KdPrint(("unallocatedSpaceBitmap (part %d) @ %x\n", + i, Vcb->Partitions[i].UspaceBitmap )); + } +#ifdef UDF_DBG + if(phd->partitionIntegrityTable.extLength) + KdPrint(("partitionIntegrityTable (part %d)\n", i)); + if(phd->freedSpaceTable.extLength) + KdPrint(("freedSpaceTable (part %d)\n", i)); +#endif // UDF_DBG + if(phd->freedSpaceBitmap.extLength) { + Vcb->Partitions[i].FspaceBitmap = + phd->freedSpaceBitmap.extPosition; + KdPrint(("freedSpaceBitmap (part %d)\n", i)); + } + RC = UDFBuildFreeSpaceBitmap(Vcb, i, phd, 0); + //Vcb->Modified = FALSE; + UDFPreClrModified(Vcb); + UDFClrModified(Vcb); + if(!OS_SUCCESS(RC)) + return RC; + + if ((Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP15) || + (Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP20)) { + RC = UDFLoadVAT(Vcb, i); + if(!OS_SUCCESS(RC)) + return RC; + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + WCacheSetMode__(&(Vcb->FastCache), WCACHE_MODE_R); + Vcb->LastModifiedTrack = 0; + } + } + } + } +#ifdef UDF_DBG + if(!Found) { + KdPrint(("Partition (%d) not found in partition map\n", (p->partitionNumber) )); + } else { + KdPrint(("Partition (%d:%d type %x) starts at physical %x, length %x\n", + p->partitionNumber, i-1, Vcb->Partitions[i-1].PartitionType, + Vcb->Partitions[i-1].PartitionRoot, Vcb->Partitions[i-1].PartitionLen)); + } +#endif // UDF_DBG + return STATUS_SUCCESS; +} // end UDFLoadPartDesc() + +/* + process Partition descriptor + */ +OSSTATUS +UDFVerifyPartDesc( + PVCB Vcb, + int8* Buf + ) +{ + PartitionDesc *p = (PartitionDesc *)Buf; + uint32 i; + OSSTATUS RC; + BOOLEAN Found = FALSE; + KdPrint(("UDF: Verify Part Descr:\n")); + KdPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); + KdPrint((" partitionFlags = %x\n", p->partitionFlags)); + KdPrint((" partitionNumber = %x\n", p->partitionNumber)); + KdPrint((" accessType = %x\n", p->accessType)); + KdPrint((" partitionStartingLocation = %x\n", p->partitionStartingLocation)); + KdPrint((" partitionLength = %x\n", p->partitionLength)); + // There is nothing interesting to comment here + // Just look at Names & Messages.... + for (i=0; iPartitionMaps; i++) { + KdPrint(("Searching map: (%d == %d)\n", + Vcb->Partitions[i].PartitionNum, (p->partitionNumber) )); + if(Vcb->Partitions[i].PartitionNum == (p->partitionNumber)) { + Found = TRUE; + if(Vcb->Partitions[i].PartitionRoot != p->partitionStartingLocation + Vcb->FirstLBA) + return STATUS_DISK_CORRUPT_ERROR; + if(Vcb->Partitions[i].PartitionLen != + min(p->partitionLength, + Vcb->LastPossibleLBA - Vcb->Partitions[i].PartitionRoot)) /* sectors */ + return STATUS_DISK_CORRUPT_ERROR; +// Vcb->Partitions[i].UspaceBitmap = 0xFFFFFFFF; +// Vcb->Partitions[i].FspaceBitmap = 0xFFFFFFFF; + if(Vcb->Partitions[i].AccessType != p->accessType) + return STATUS_DISK_CORRUPT_ERROR; + KdPrint(("Access mode %x\n", p->accessType)); + if(p->accessType == PARTITION_ACCESS_WO) { + if(Vcb->CDR_Mode != TRUE) + return STATUS_DISK_CORRUPT_ERROR; +// Vcb->Partitions[i].PartitionLen = Vcb->LastPossibleLBA - p->partitionStartingLocation; + } else if(p->accessType < PARTITION_ACCESS_WO) { + // Soft-read-only volume + KdPrint(("Soft Read-only volume\n")); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) + return STATUS_DISK_CORRUPT_ERROR; + } else if(p->accessType > PARTITION_ACCESS_MAX_KNOWN) { + return STATUS_UNRECOGNIZED_MEDIA; + } + + if(!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || + !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03)) + { + PPARTITION_HEADER_DESC phd; + + phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); +#ifdef UDF_DBG + if(phd->unallocatedSpaceTable.extLength) + KdPrint(("unallocatedSpaceTable (part %d)\n", i)); +#endif // UDF_DBG + if(phd->unallocatedSpaceBitmap.extLength) { + if(Vcb->Partitions[i].UspaceBitmap == + phd->unallocatedSpaceBitmap.extPosition) { + KdPrint(("Warning: both USpaceBitmaps have same location\n")); + } + KdPrint(("unallocatedSpaceBitmap (part %d) @ %x\n", + i, Vcb->Partitions[i].UspaceBitmap )); + } +#ifdef UDF_DBG + if(phd->partitionIntegrityTable.extLength) + KdPrint(("partitionIntegrityTable (part %d)\n", i)); + if(phd->freedSpaceTable.extLength) + KdPrint(("freedSpaceTable (part %d)\n", i)); +#endif // UDF_DBG + if(phd->freedSpaceBitmap.extLength) { + if(Vcb->Partitions[i].FspaceBitmap == + phd->freedSpaceBitmap.extPosition) { + KdPrint(("Warning: both FSpaceBitmaps have same location\n")); + } + KdPrint(("freedSpaceBitmap (part %d)\n", i)); + } + RC = UDFVerifyFreeSpaceBitmap(Vcb, i, phd, 0); + //Vcb->Modified = FALSE; + //UDFPreClrModified(Vcb); + //UDFClrModified(Vcb); + if(!OS_SUCCESS(RC)) + return RC; + + if ((Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP15) || + (Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP20)) { +/* RC = UDFLoadVAT(Vcb, i); + if(!OS_SUCCESS(RC)) + return RC; + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + WCacheSetMode__(&(Vcb->FastCache), WCACHE_MODE_R); + Vcb->LastModifiedTrack = 0;*/ + } + } + } + } +#ifdef UDF_DBG + if(!Found) { + KdPrint(("Partition (%d) not found in partition map\n", (p->partitionNumber) )); + } else { + KdPrint(("Partition (%d:%d type %x) starts at physical %x, length %x\n", + p->partitionNumber, i-1, Vcb->Partitions[i-1].PartitionType, + Vcb->Partitions[i-1].PartitionRoot, Vcb->Partitions[i-1].PartitionLen)); + } +#endif // UDF_DBG + return STATUS_SUCCESS; +} // end UDFVerifyPartDesc() + +/* + This routine scans VDS & fills special array with Desc locations + */ +OSSTATUS +UDFReadVDS( + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + IN PUDF_VDS_RECORD vds, + IN int8* Buf + ) +{ + OSSTATUS status; + GenericDesc* gd; + BOOLEAN done=FALSE; + uint32 vdsn; + uint16 ident; + + KdPrint(("UDF: Read VDS (%x - %x)\n", block, lastblock )); + // Read the main descriptor sequence + for (;(!done && block <= lastblock); block++) + { + status = UDFReadTagged(Vcb, Buf, block, block, &ident); + if(!OS_SUCCESS(status)) + return status; + UDFRegisterFsStructure(Vcb, block, Vcb->BlockSize); + + // Process each descriptor (ISO 13346 3/8.3-8.4) + gd = (struct GenericDesc *)Buf; + vdsn = gd->volDescSeqNum; + KdPrint(("LBA %x, Ident = %x, vdsn = %x\n", block, ident, vdsn )); + switch (ident) + { + case TID_PRIMARY_VOL_DESC: // ISO 13346 3/10.1 + if(vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_PRIMARY_VOL_DESC].block = block; + } + break; + case TID_VOL_DESC_PTR: // ISO 13346 3/10.3 + struct VolDescPtr* pVDP; + if(vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) + { + vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn; + vds[VDS_POS_VOL_DESC_PTR].block = block; + vds[VDS_POS_RECURSION_COUNTER].volDescSeqNum++; + if(vds[VDS_POS_RECURSION_COUNTER].volDescSeqNum > MAX_VDS_PARTS) { + KdPrint(("too long multipart VDS -> abort\n")); + return STATUS_DISK_CORRUPT_ERROR; + } + pVDP = (struct VolDescPtr*)Buf; + KdPrint(("multipart VDS...\n")); + return UDFReadVDS(Vcb, pVDP->nextVolDescSeqExt.extLocation, + pVDP->nextVolDescSeqExt.extLocation + (pVDP->nextVolDescSeqExt.extLocation >> Vcb->BlockSizeBits), + vds, Buf); + } + break; + case TID_IMP_USE_VOL_DESC: // ISO 13346 3/10.4 + if(vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_IMP_USE_VOL_DESC].block = block; + } + break; + case TID_PARTITION_DESC: // ISO 13346 3/10.5 + if(!vds[VDS_POS_PARTITION_DESC].block) + vds[VDS_POS_PARTITION_DESC].block = block; + break; + case TID_LOGICAL_VOL_DESC: // ISO 13346 3/10.6 + case TID_ADAPTEC_LOGICAL_VOL_DESC: // Adaptec Compressed UDF extesion + if(vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) + { + vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_LOGICAL_VOL_DESC].block = block; + } + break; + case TID_UNALLOC_SPACE_DESC: // ISO 13346 3/10.8 + if(vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) + { + vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn; + vds[VDS_POS_UNALLOC_SPACE_DESC].block = block; + } + break; + case TID_TERMINATING_DESC: // ISO 13346 3/10.9 + vds[VDS_POS_TERMINATING_DESC].block = block; + done = TRUE; + break; + } + } + return STATUS_SUCCESS; +} // UDFReadVDS() + +OSSTATUS +UDFLoadImpUseVolDesc( + IN PVCB Vcb, + int8* Buf + ) +{ + ImpUseVolDesc* iuvd = (ImpUseVolDesc*)Buf; + ImpUseVolDescImpUse* iuvdiu = (ImpUseVolDescImpUse*)&(iuvd->impUse); + KdPrint(("UDF: Imp Use Vol Desc:\n")); + KdPrint((" volDescSeqNum = %x\n", iuvd->volDescSeqNum)); + KdPrint(("UDF: Imp Use Vol Desc Imp Use:\n")); + KdDump(iuvdiu, sizeof(ImpUseVolDescImpUse)); + return STATUS_SUCCESS; +} // UDFLoadImpUseVolDesc() + +OSSTATUS +UDFLoadUnallocatedSpaceDesc( + IN PVCB Vcb, + int8* Buf + ) +{ + KdPrint(("UDF: Unallocated Space Desc:\n")); +// UnallocatedSpaceDesc* usd = (UnallocatedSpaceDesc*)Buf; + return STATUS_SUCCESS; +} // UDFLoadImpUseVolDesc() + +/* + Process a main/reserve volume descriptor sequence. +*/ +OSSTATUS +UDFProcessSequence( + IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + OUT lb_addr *fileset + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + UDF_VDS_RECORD vds[VDS_POS_LENGTH]; + GenericDesc *gd; + uint32 i,j; + uint16 ident; + int8* Buf2 = NULL; + + _SEH2_TRY { + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); + if(!OS_SUCCESS(RC = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) + try_return(RC); + // walk through Vol Desc Sequence according to locations gained by + // UDFReadVDS() & do some procesing for each one + // It is very simple dispath routine... + for (i=0; iBlockSize); + + if(i == VDS_POS_PRIMARY_VOL_DESC) { + UDFLoadPVolDesc(Vcb,Buf); + if(!Vcb->PVolDescAddr.block) { + Vcb->PVolDescAddr = vds[i]; + } else { + Vcb->PVolDescAddr2 = vds[i]; + } + } else + if(i == VDS_POS_LOGICAL_VOL_DESC) { + RC = UDFLoadLogicalVol(DeviceObject,Vcb, Buf, fileset); + if(!OS_SUCCESS(RC)) try_return(RC); + } else + + if(i == VDS_POS_IMP_USE_VOL_DESC) { + UDFLoadImpUseVolDesc(Vcb, Buf); + } else + if(i == VDS_POS_UNALLOC_SPACE_DESC) { + UDFLoadUnallocatedSpaceDesc(Vcb, Buf); + } else + + if(i == VDS_POS_PARTITION_DESC) + { + Buf2 = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + if(!Buf2) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RC = UDFLoadPartDesc(Vcb,Buf); + if(!OS_SUCCESS(RC)) try_return(RC); + for (j=vds[i].block+1; jBlockSize); + gd = (struct GenericDesc *)Buf2; + if(ident == TID_PARTITION_DESC) { + RC = UDFLoadPartDesc(Vcb,Buf2); + if(!OS_SUCCESS(RC)) try_return(RC); + } else if(ident == TID_UNALLOC_SPACE_DESC) { + RC = UDFBuildFreeSpaceBitmap(Vcb,0,NULL,j); + //Vcb->Modified = FALSE; + UDFPreClrModified(Vcb); + UDFClrModified(Vcb); + if(!OS_SUCCESS(RC)) + try_return(RC); + } + } + MyFreePool__(Buf2); + Buf2 = NULL; + } + } else { + if(i == VDS_POS_LOGICAL_VOL_DESC) { + RC = UDFLoadBogusLogicalVol(DeviceObject,Vcb, Buf, fileset); + if(!OS_SUCCESS(RC)) try_return(RC); + } + } + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(Buf) MyFreePool__(Buf); + if(Buf2) MyFreePool__(Buf2); + } _SEH2_END; + + return RC; +} // end UDFProcessSequence() + +/* + Verifies a main/reserve volume descriptor sequence. +*/ +OSSTATUS +UDFVerifySequence( + IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + OUT lb_addr *fileset + ) +{ + OSSTATUS RC = STATUS_SUCCESS; + int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + UDF_VDS_RECORD vds[VDS_POS_LENGTH]; + GenericDesc *gd; + uint32 i,j; + uint16 ident; + int8* Buf2 = NULL; + + _SEH2_TRY { + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + if(!block) try_return (RC = STATUS_SUCCESS); + RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); + if(!OS_SUCCESS(RC = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) + try_return(RC); + + for (i=0; iBlockSize); + + /* if(i == VDS_POS_PRIMARY_VOL_DESC) + UDFLoadPVolDesc(Vcb,Buf); + else if(i == VDS_POS_LOGICAL_VOL_DESC) { + RC = UDFLoadLogicalVol(DeviceObject,Vcb, Buf, fileset); + if(!OS_SUCCESS(RC)) try_return(RC); + } + else*/ if(i == VDS_POS_PARTITION_DESC) + { + Buf2 = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + if(!Buf2) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RC = UDFVerifyPartDesc(Vcb,Buf); + if(!OS_SUCCESS(RC)) try_return(RC); + for (j=vds[i].block+1; jBlockSize); + gd = (struct GenericDesc *)Buf2; + if(ident == TID_PARTITION_DESC) { + RC = UDFVerifyPartDesc(Vcb,Buf2); + if(!OS_SUCCESS(RC)) try_return(RC); + } else if(ident == TID_UNALLOC_SPACE_DESC) { + RC = UDFVerifyFreeSpaceBitmap(Vcb,0,NULL,j); + Vcb->Modified = FALSE; + if(!OS_SUCCESS(RC)) + try_return(RC); + } + } + MyFreePool__(Buf2); + Buf2 = NULL; + } + } + } +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(Buf) MyFreePool__(Buf); + if(Buf2) MyFreePool__(Buf2); + } _SEH2_END; + + return RC; +} // end UDFVerifySequence() + +/* + remember some useful info about FileSet & RootDir location + */ +void +UDFLoadFileset( + IN PVCB Vcb, + IN PFILE_SET_DESC fset, + OUT lb_addr *root, + OUT lb_addr *sysstream + ) +{ + *root = fset->rootDirectoryICB.extLocation; + Vcb->SerialNumber = fset->descTag.tagSerialNum; + KdPrint(("Rootdir at block=%x, partition=%d\n", + root->logicalBlockNum, root->partitionReferenceNum)); + if(sysstream) { + *sysstream = fset->streamDirectoryICB.extLocation; + KdPrint(("SysStream at block=%x, partition=%d\n", + sysstream->logicalBlockNum, sysstream->partitionReferenceNum)); + } + // Get current UDF revision + // Get Read-Only flags + UDFReadEntityID_Domain(Vcb, &(fset->domainIdent)); + +} // end UDFLoadFileset() + +OSSTATUS +UDFIsCachedBadSequence( + IN PVCB Vcb, + IN uint32 Lba + ) +{ + ULONG j; + OSSTATUS RC = STATUS_SUCCESS; + // Check if it is known bad sequence + for(j=0; jBadSeqLocIndex; j++) { + if(Vcb->BadSeqLoc[j] == Lba) { + RC = Vcb->BadSeqStatus[j]; + break; + } + } + return RC; +} // end UDFIsCachedBadSequence() + +VOID +UDFRememberBadSequence( + IN PVCB Vcb, + IN uint32 Lba, + IN OSSTATUS RC + ) +{ + int j; + if(!OS_SUCCESS(UDFIsCachedBadSequence(Vcb, Lba))) + return; + // Remenber bad sequence + j = Vcb->BadSeqLocIndex; + Vcb->BadSeqLocIndex++; + Vcb->BadSeqLoc[j] = Lba; + Vcb->BadSeqStatus[j] = RC; +} // end UDFRememberBadSequence() + +/* + load partition info + */ +OSSTATUS +UDFLoadPartition( + IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + OUT lb_addr *fileset + ) +{ + OSSTATUS RC = STATUS_UNRECOGNIZED_VOLUME; + OSSTATUS RC2 = STATUS_UNRECOGNIZED_VOLUME; + AnchorVolDescPtr *anchor; + uint16 ident; + int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + uint32 main_s, main_e; + uint32 reserve_s, reserve_e; + int i; + + if(!Buf) return STATUS_INSUFFICIENT_RESOURCES; + // walk through all available Anchors & load data + for (i=0; iAnchor[i] && (OS_SUCCESS(UDFReadTagged(Vcb, Buf, + Vcb->Anchor[i], Vcb->Anchor[i] - Vcb->FirstLBA, &ident)))) + { + anchor = (AnchorVolDescPtr *)Buf; + + // Locate the main sequence + main_s = ( anchor->mainVolDescSeqExt.extLocation ); + main_e = ( anchor->mainVolDescSeqExt.extLength ); + main_e = main_e >> Vcb->BlockSizeBits; + main_e += main_s; + + // Locate the reserve sequence + reserve_s = (anchor->reserveVolDescSeqExt.extLocation); + reserve_e = (anchor->reserveVolDescSeqExt.extLength); + reserve_e = reserve_e >> Vcb->BlockSizeBits; + reserve_e += reserve_s; + + // Check if it is known bad sequence + RC = UDFIsCachedBadSequence(Vcb, main_s); + if(OS_SUCCESS(RC)) { + // Process the main & reserve sequences + // responsible for finding the PartitionDesc(s) + KdPrint(("-----------------------------------\n")); + KdPrint(("UDF: Main sequence:\n")); + RC = UDFProcessSequence(DeviceObject, Vcb, main_s, main_e, fileset); + } + + if(!OS_SUCCESS(RC)) { + // Remenber bad sequence + UDFRememberBadSequence(Vcb, main_s, RC); + + KdPrint(("-----------------------------------\n")); + KdPrint(("UDF: Main sequence failed.\n")); + KdPrint(("UDF: Reserve sequence\n")); + if(Vcb->LVid) MyFreePool__(Vcb->LVid); + Vcb->LVid = NULL; + + RC2 = UDFIsCachedBadSequence(Vcb, reserve_s); + if(OS_SUCCESS(RC2)) { + RC2 = UDFProcessSequence(DeviceObject, Vcb, reserve_s, reserve_e, fileset); + } + + if(OS_SUCCESS(RC2)) { + KdPrint(("-----------------------------------\n")); + Vcb->VDS2_Len = reserve_e - reserve_s; + Vcb->VDS2 = reserve_s; + RC = STATUS_SUCCESS; + // Vcb is already Zero-filled +// Vcb->VDS1_Len = 0; +// Vcb->VDS1 = 0; + break; + } else { + // This is also bad sequence. Remenber it too + UDFRememberBadSequence(Vcb, reserve_s, RC); + } + } else { + // remember these values for umount__ + Vcb->VDS1_Len = main_e - main_s; + Vcb->VDS1 = main_s; +/* if(Vcb->LVid) MyFreePool__(Vcb->LVid); + Vcb->LVid = NULL;*/ + if(OS_SUCCESS(UDFVerifySequence(DeviceObject, Vcb, reserve_s, reserve_e, fileset))) + { + KdPrint(("-----------------------------------\n")); + Vcb->VDS2_Len = reserve_e - reserve_s; + Vcb->VDS2 = reserve_s; + break; + } else { + KdPrint(("UDF: Reserve sequence verification failed.\n")); + switch(Vcb->PartitialDamagedVolumeAction) { + case UDF_PART_DAMAGED_RO: + KdPrint(("UDF: Switch to r/o mode.\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + break; + case UDF_PART_DAMAGED_NO: + KdPrint(("UDF: Switch to raw mount mode, return UNRECOGNIZED_VOLUME.\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + RC = STATUS_WRONG_VOLUME; + break; + case UDF_PART_DAMAGED_RW: + default: + KdPrint(("UDF: Keep r/w mode for your own risk.\n")); + break; + } + } + break; + } + } + } + + if(Vcb->SparingCount && + (Vcb->NoFreeRelocationSpaceVolumeAction != UDF_PART_DAMAGED_RW)) { + KdPrint(("UDF: No free Sparing Entries -> Switch to r/o mode.\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } + + if(i == sizeof(Vcb->Anchor)/sizeof(int)) { + KdPrint(("No Anchor block found\n")); + RC = STATUS_UNRECOGNIZED_VOLUME; +#ifdef UDF_DBG + } else { + KdPrint(("Using anchor in block %x\n", Vcb->Anchor[i])); +#endif // UDF_DBG + } + MyFreePool__(Buf); + return RC; +} // end UDFLoadPartition() + +/* + This routine scans FileSet sequence & returns pointer to last valid + FileSet + */ +OSSTATUS +UDFFindLastFileSet( + IN PVCB Vcb, + IN lb_addr *Addr, // Addr for the 1st FileSet + IN OUT PFILE_SET_DESC FileSetDesc + ) +{ + OSSTATUS status; + uint32 relLocExt = Addr->logicalBlockNum; + uint32 locExt = UDFPartLbaToPhys(Vcb, Addr); + uint16 Ident; + uint32 relPrevExt, prevExt; + + relPrevExt, prevExt = NULL; + FileSetDesc->nextExt.extLength = 1; // ;) + // walk through FileSet chain + // we've just pre-init'd extent length to read 1st FileSet + while(FileSetDesc->nextExt.extLength) { + status = UDFReadTagged(Vcb, (int8*)FileSetDesc, locExt, relLocExt, &Ident); + if(!OS_SUCCESS(status)) { + FileSetDesc->nextExt.extLength = 0; + return status; + } + UDFRegisterFsStructure(Vcb, locExt, Vcb->BlockSize); + if((locExt == LBA_OUT_OF_EXTENT) || (Ident != TID_FILE_SET_DESC)) { + // try to read previous FileSet + if(!prevExt) return STATUS_UNRECOGNIZED_VOLUME; + status = UDFReadTagged(Vcb, (int8*)FileSetDesc, prevExt, relLocExt, &Ident); + if(OS_SUCCESS(status)) { + UDFRegisterFsStructure(Vcb, prevExt, Vcb->BlockSize); + } + return status; + } + prevExt = locExt; + relPrevExt = relLocExt; + locExt = UDFPartLbaToPhys(Vcb, &(FileSetDesc->nextExt.extLocation)); + } + return STATUS_SUCCESS; +} // end UDFFindLastFileSet() + +/* + This routine reads all sparing tables & stores them in contiguos memory + space + */ +OSSTATUS +UDFLoadSparingTable( + IN PVCB Vcb, + IN PSPARABLE_PARTITION_MAP PartMap + ) +{ + PSPARING_MAP RelocMap; + PSPARING_MAP NewRelocMap; + OSSTATUS status; + uint32 i=0, BC, BC2; + PSPARING_TABLE SparTable; + uint32 TabSize, NewSize; + uint32 ReadBytes; + uint32 SparTableLoc; +#ifdef UDF_TRACK_FS_STRUCTURES + uint32 j; +#endif //UDF_TRACK_FS_STRUCTURES + uint32 n,m; + BOOLEAN merged; + + Vcb->SparingCountFree = -1; + + KdPrint(("UDF: Sparable Part Map:\n")); + Vcb->SparingTableLength = PartMap->sizeSparingTable; + BC = (PartMap->sizeSparingTable >> Vcb->BlockSizeBits) + 1; + KdPrint((" partitionMapType = %x\n", PartMap->partitionMapType)); + KdPrint((" partitionMapLength = %x\n", PartMap->partitionMapLength)); + KdPrint((" volSeqNum = %x\n", PartMap->volSeqNum)); + KdPrint((" partitionNum = %x\n", PartMap->partitionNum)); + KdPrint((" packetLength = %x\n", PartMap->packetLength)); + KdPrint((" numSparingTables = %x\n", PartMap->numSparingTables)); + KdPrint((" sizeSparingTable = %x\n", PartMap->sizeSparingTable)); + SparTable = (PSPARING_TABLE)MyAllocatePool__(NonPagedPool, BC*Vcb->BlockSize); + if(!SparTable) return STATUS_INSUFFICIENT_RESOURCES; + if(Vcb->SparingTable) { + // if a part of Sparing Table is already loaded, + // update it with data from another one + RelocMap = Vcb->SparingTable; + TabSize = Vcb->SparingCount * sizeof(SPARING_ENTRY); + } else { + // do some init to load first part of Sparing Table + RelocMap = (PSPARING_MAP)MyAllocatePool__(NonPagedPool, RELOC_MAP_GRAN); + if(!RelocMap) { + MyFreePool__(SparTable); + return STATUS_INSUFFICIENT_RESOURCES; + } + TabSize = RELOC_MAP_GRAN; + Vcb->SparingBlockSize = PartMap->packetLength; + } + // walk through all available Sparing Tables + for(i=0;inumSparingTables;i++) { + // read (next) table + SparTableLoc = ((uint32*)(PartMap+1))[i]; + for(n=0; nSparingTableCount; n++) { + if(Vcb->SparingTableLoc[i] == SparTableLoc) { + KdPrint((" already processed @%x\n", + SparTableLoc + )); + continue; + } + } + status = UDFReadSectors(Vcb, FALSE, SparTableLoc, 1, FALSE, (int8*)SparTable, &ReadBytes); + // tag should be set to TID_UNUSED_DESC + if(OS_SUCCESS(status) && (SparTable->descTag.tagIdent == TID_UNUSED_DESC)) { + + UDFRegisterFsStructure(Vcb, SparTableLoc, Vcb->BlockSize); + BC2 = ((sizeof(SPARING_TABLE) + + SparTable->reallocationTableLen*sizeof(SparingEntry) + + Vcb->BlockSize-1) + >> Vcb->BlockSizeBits); + if(BC2 > BC) { + KdPrint((" sizeSparingTable @%x too long: %x > %x\n", + SparTableLoc, BC2, BC + )); + continue; + } + status = UDFReadSectors(Vcb, FALSE, SparTableLoc, + BC2, FALSE, (int8*)SparTable, &ReadBytes); + UDFRegisterFsStructure(Vcb, SparTableLoc, BC2<BlockSizeBits); + + if(!OS_SUCCESS(status)) { + KdPrint((" Error reading sizeSparingTable @%x (%x)\n", + SparTableLoc, BC2 + )); + continue; + } + // process sparing table + NewSize = sizeof(SparingEntry)*SparTable->reallocationTableLen; + TabSize = MyReallocPool__((int8*)RelocMap, TabSize, (int8**)&RelocMap, TabSize+NewSize); + if(!TabSize) { + MyFreePool__(SparTable); + return STATUS_INSUFFICIENT_RESOURCES; + } + +#ifdef UDF_TRACK_FS_STRUCTURES + for(j=0; jreallocationTableLen; j++) { + UDFRegisterFsStructure(Vcb, ((SparingEntry*)(SparTable+1))[j].mappedLocation, Vcb->WriteBlockSize); + } +#endif //UDF_TRACK_FS_STRUCTURES + + Vcb->SparingTableLoc[Vcb->SparingTableCount] = SparTableLoc; + Vcb->SparingTableCount++; + + NewRelocMap = (PSPARING_MAP)(SparTable+1); + for(n=0; nreallocationTableLen; n++) { + merged = TRUE; + for(m=0; mSparingCount; m++) { + if(RelocMap[m].mappedLocation == NewRelocMap[n].mappedLocation) { + KdPrint((" dup @%x (%x) vs @%x (%x)\n", + RelocMap[m].origLocation, RelocMap[m].mappedLocation, + NewRelocMap[m].origLocation, NewRelocMap[m].mappedLocation)); + merged = FALSE; + } + if((RelocMap[m].origLocation == NewRelocMap[n].origLocation) && + (RelocMap[m].mappedLocation != NewRelocMap[n].mappedLocation) && + (RelocMap[m].origLocation != SPARING_LOC_AVAILABLE) && + (RelocMap[m].origLocation != SPARING_LOC_CORRUPTED)) { + KdPrint((" conflict @%x (%x) vs @%x (%x)\n", + RelocMap[m].origLocation, RelocMap[m].mappedLocation, + NewRelocMap[n].origLocation, NewRelocMap[n].mappedLocation)); + merged = FALSE; + } + } + if(merged) { + RelocMap[Vcb->SparingCount] = NewRelocMap[n]; + KdPrint((" reloc %x -> %x\n", + RelocMap[Vcb->SparingCount].origLocation, RelocMap[Vcb->SparingCount].mappedLocation)); + Vcb->SparingCount++; + if(RelocMap[Vcb->SparingCount].origLocation == SPARING_LOC_AVAILABLE) { + Vcb->NoFreeRelocationSpaceVolumeAction = UDF_PART_DAMAGED_RW; + } + } + } + +/* + RtlCopyMemory((int8*)(RelocMap+Vcb->SparingCount), + (int8*)(SparTable+1), NewSize); + Vcb->SparingCount += NewSize/sizeof(SPARING_ENTRY); +*/ + if(Vcb->SparingTableCount >= MAX_SPARING_TABLE_LOCATIONS) { + KdPrint((" too many Sparing Tables\n")); + break; + } + } + } + Vcb->SparingTable = RelocMap; + MyFreePool__(SparTable); + return STATUS_SUCCESS; +} // end UDFLoadSparingTable() + +/* + This routine checks if buffer is ZERO-filled + */ +BOOLEAN +UDFCheckZeroBuf( + IN int8* Buf, + IN uint32 Length + ) +{ + BOOLEAN RC = FALSE; + +//#ifdef _X86_ +#ifdef _MSC_VER + + uint32 len = Length; + __asm push ecx + __asm push edi + + __asm mov ecx,len + __asm mov edi,Buf + __asm xor eax,eax + __asm shr ecx,2 + __asm repe scasd + __asm jne short not_all_zeros + __asm mov RC,1 + +not_all_zeros: + + __asm pop edi + __asm pop ecx + + return RC; + +#else // _X86_ + + uint32* tmp = (uint32*)Buf; + uint32 i; + + for(i=0; iFsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) { + // check if this disc is mountable for CDFS + KdPrint((" FILE_DEVICE_CD_ROM_FILE_SYSTEM\n")); +check_NSR: + NSRDesc = UDFFindVRS(Vcb); + if(!(NSRDesc & VRS_ISO9660_FOUND)) { + // no CDFS VRS found + KdPrint(("UDFGetDiskInfoAndVerify: no CDFS VRS found\n")); + if(!Vcb->TrackMap[Vcb->LastTrackNum].LastLba && + !Vcb->TrackMap[Vcb->FirstTrackNum].LastLba) { + // such a stupid method of Audio-CD detection... + KdPrint(("UDFGetDiskInfoAndVerify: set UDF_VCB_FLAGS_RAW_DISK\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; + } + } + Vcb->NSRDesc = NSRDesc; + + Buf = (int8*)MyAllocatePool__(NonPagedPool, 0x10000); + if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RC = UDFReadData(Vcb, FALSE, 0, 0x10000, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(RC)) + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + RC = STATUS_UNRECOGNIZED_VOLUME; + if(!UDFCheckZeroBuf(Buf,0x10000)) { + KdPrint(("UDFGetDiskInfoAndVerify: possible FS detected, remove UDF_VCB_FLAGS_RAW_DISK\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; + } + MyFreePool__(Buf); + Buf = NULL; + } + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); + } + + RC = UDFLoadPartition(DeviceObject,Vcb,&fileset); + if(!OS_SUCCESS(RC)) { + if(RC == STATUS_UNRECOGNIZED_VOLUME) { + KdPrint(("UDFGetDiskInfoAndVerify: check NSR presence\n")); + goto check_NSR; + } + try_return(RC); + } + + FileSetDesc = (PFILE_SET_DESC)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); + if(!FileSetDesc) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + RC = UDFFindLastFileSet(Vcb,&fileset,FileSetDesc); + if(!OS_SUCCESS(RC)) try_return(RC); + + UDFLoadFileset(Vcb,FileSetDesc, &(Vcb->RootLbAddr), &(Vcb->SysStreamLbAddr)); + + Vcb->FSBM_OldBitmap = (int8*)DbgAllocatePool(NonPagedPool, Vcb->FSBM_ByteCount); + if(!(Vcb->FSBM_OldBitmap)) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); + +try_exit: NOTHING; + } _SEH2_FINALLY { + if(FileSetDesc) MyFreePool__(FileSetDesc); + if(Buf) MyFreePool__(Buf); + } _SEH2_END; + + return(RC); + +} // end UDFGetDiskInfoAndVerify() + diff --git a/reactos/drivers/filesystems/udfs/udf_info/osta_misc.h b/reactos/drivers/filesystems/udfs/udf_info/osta_misc.h new file mode 100644 index 00000000000..08624a25499 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/osta_misc.h @@ -0,0 +1,352 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef _OSTA_MISC_H_ +#define _OSTA_MISC_H_ + +/* based on ECMA 167 structure definitions */ +#include "ecma_167.h" + +#pragma pack(push, 1) + +/* -------- Basic types and constants ----------- */ +/* UDF character set (UDF 1.50 2.1.2) */ +#define UDF_CHAR_SET_TYPE 0 +#define UDF_CHAR_SET_INFO "OSTA Compressed Unicode" + +#define UDF_ID_DEVELOPER ("*WINNT " VER_STR_PRODUCT_NAME " UDF") + +#define UDF_ID_DEVELOPER_ADAPTEC "*Adaptec DirectCD" + +/* UDF 1.02 2.2.6.4 */ +struct LogicalVolIntegrityDescImpUse +{ + EntityID impIdent; + uint32 numFiles; + uint32 numDirs; + uint16 minUDFReadRev; + uint16 minUDFWriteRev; + uint16 maxUDFWriteRev; +}; + +/* UDF 1.02 2.2.7.2 */ +/* LVInformation may be present in ImpUseVolDesc.impUse */ +struct ImpUseVolDescImpUse +{ + charspec LVICharset; + dstring logicalVolIdent[128]; + dstring LVInfo1[36]; + dstring LVInfo2[36]; + dstring LVInfo3[36]; + EntityID impIdent; + uint8 impUse[128]; +}; + +struct UdfPartitionMap2 +{ + uint8 partitionMapType; + uint8 partitionMapLength; + uint8 reserved1[2]; + EntityID partIdent; + uint16 volSeqNum; + uint16 partitionNum; + uint8 reserved2[24]; +}; + +/* UDF 1.5 2.2.8 */ +struct VirtualPartitionMap +{ + uint8 partitionMapType; /* 2 */ + uint8 partitionMapLength; /* 64 */ + uint8 reserved1[2]; /* #00 */ + EntityID partIdent; + uint16 volSeqNum; + uint16 partitionNum; + uint8 reserved2[24]; /* #00 */ +}; + +#define UDF_VAT_FREE_ENTRY 0xffffffff + +/* UDF 1.5 2.2.9 */ +typedef struct _SPARABLE_PARTITION_MAP +{ + uint8 partitionMapType; /* 2 */ + uint8 partitionMapLength; /* 64 */ + uint8 reserved1[2]; /* #00 */ + EntityID partIdent; /* Flags = 0 */ + /* Id = UDF_ID_SPARABLE */ + /* IdSuf = 2.1.5.3 */ + uint16 volSeqNum; + uint16 partitionNum; + uint16 packetLength; /* 32 */ + uint8 numSparingTables; + uint8 reserved2[1]; /* #00 */ + uint32 sizeSparingTable; +// uint32 locSparingTable[0]; +// uint8 pad[0]; +} SPARABLE_PARTITION_MAP, *PSPARABLE_PARTITION_MAP; + +#define UDF_TYPE1_MAP15 0x1511U +#define UDF_VIRTUAL_MAP15 0x1512U +#define UDF_VIRTUAL_MAP20 0x2012U +#define UDF_SPARABLE_MAP15 0x1522U +#define UDF_METADATA_MAP25 0x2522U + +#ifndef PACKETSIZE_UDF +#define PACKETSIZE_UDF 32 +#endif //PACKETSIZE_UDF + +/* UDF 2.5 */ +typedef struct _METADATA_PARTITION_MAP +{ + uint8 partitionMapType; /* 2 */ + uint8 partitionMapLength; /* 64 */ + uint8 reserved1[2]; /* #00 */ + EntityID partIdent; /* Flags = 0 */ + /* Id = UDF_ID_METADATA */ + /* IdSuf = 2.1.5.3 */ + uint16 volSeqNum; + uint16 partitionNum; + uint32 metadataFELocation; + uint32 metadataMirrorFELocation; + uint32 metadataBitmapFELocation; + uint32 allocationUnit; /* blocks */ + uint16 alignmentUnit; /* blocks */ + uint8 flags; + uint8 pad[5]; +} METADATA_PARTITION_MAP, *PMETADATA_PARTITION_MAP; + +#define UDF_METADATA_DUPLICATED 0x01U + +/* DVD Copyright Management Info, see UDF 1.02 3.3.4.5.1.2 */ +/* when ImpUseExtendedAttr.impIdent= "*UDF DVD CGMS Info" */ +struct DVDCopyrightImpUse { + uint16 headerChecksum; + uint8 CGMSInfo; + uint8 dataType; + uint8 protectionSystemInfo[4]; +}; + +/* the impUse of long_ad used in AllocDescs - UDF 1.02 2.3.10.1 */ +struct ADImpUse +{ + uint16 flags; + uint8 impUse[4]; +}; + +/* the impUse of long_ad used in AllocDescs - UDF 1.02 2.3.10.1 */ +struct FidADImpUse +{ + uint8 reserved[2]; + uint32 uniqueID; +}; + +/* UDF 1.02 2.3.10.1 */ +#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF +#define UDF_EXTENT_FLAG_MASK 0xc0000000 +#define UDF_EXTENT_FLAG_ERASED 0x40000000 + +/* + * Important! VirtualAllocationTables are + * very different between 1.5 and 2.0! + */ + +/* ----------- 1.5 ------------- */ +/* UDF 1.5 2.2.10 */ +#define UDF_FILE_TYPE_VAT15 0x0U + +/* UDF 1.5 2.2.10 - VAT layout: */ +struct VirtualAllocationTable15 { +/* uint32 VirtualSector[0];*/ + EntityID ident; + uint32 previousVATICB; + }; +/* where number of VirtualSector's is (VATSize-36)/4 */ + +/* ----------- 2.0 ------------- */ +/* UDF 2.0 2.2.10 */ +#define UDF_FILE_TYPE_VAT20 0xf8U + +/* UDF 2.0 2.2.10 (different from 1.5!) */ +struct VirtualAllocationTable20 { + uint16 lengthHeader; + uint16 lengthImpUse; + dstring logicalVolIdent[128]; + uint32 previousVatICBLoc; + uint32 numFIDSFiles; + uint32 numFIDSDirectories; /* non-parent */ + uint16 minReadRevision; + uint16 minWriteRevision; + uint16 maxWriteRevision; + uint16 reserved; +/* uint8 impUse[0];*/ +/* uint32 vatEntry[0];*/ +}; + +/* Sparing maps, see UDF 1.5 2.2.11 */ +typedef struct _SparingEntry { + uint32 origLocation; + uint32 mappedLocation; +} SparingEntry; + +#define SPARING_LOC_AVAILABLE 0xffffffff +#define SPARING_LOC_CORRUPTED 0xfffffff0 + +typedef SparingEntry SPARING_ENTRY; +typedef SPARING_ENTRY* PSPARING_ENTRY; + +typedef SPARING_ENTRY SPARING_MAP; +typedef PSPARING_ENTRY PSPARING_MAP; + +/* sparing maps, see UDF 2.0 2.2.11 */ +typedef struct _SPARING_TABLE { + tag descTag; + EntityID sparingIdent; /* *UDF Sparing Table */ + uint16 reallocationTableLen; + uint16 reserved; /* #00 */ + uint32 sequenceNum; +// SparingEntry mapEntry[0]; +} SPARING_TABLE, *PSPARING_TABLE; + +/* Identifier Suffixes, see EntityID */ + +typedef struct { + uint16 currentRev; + uint8 flags; + uint8 reserved[5]; +} domainIdentSuffix; + +#define ENTITYID_FLAGS_HARD_RO 0x01U +#define ENTITYID_FLAGS_SOFT_RO 0x02U + +typedef struct { + uint16 currentRev; + uint8 OSClass; + uint8 OSIdent; + uint8 reserved[4]; +} UDFIdentSuffix; + +typedef struct { + uint8 OSClass; + uint8 OSIdent; + uint8 reserved[6]; +} impIdentSuffix; + +/* Unique ID maps, see UDF 2.0 2.2.11 */ + +typedef struct { + uint32 uniqueID; + uint32 parentLogicalBlock; + uint32 objectLogicalBlock; + uint16 parentPartitionReferenceNum; + uint16 objectPartitionReferenceNum; +} UniqueIDEntry; + +typedef UniqueIDEntry UID_MAPPING_ENTRY; +typedef UID_MAPPING_ENTRY* PUID_MAPPING_ENTRY; + +typedef struct { + EntityID ident; + uint32 flags; + uint32 entryCount; + uint8 reserved[8]; +// UniqueIDEntry mapEntry[0]; +} UniqueIDMappingData; + +typedef UniqueIDMappingData UID_MAPPING_TABLE; +typedef UID_MAPPING_TABLE* PUID_MAPPING_TABLE; + +/* Entity Identifiers (UDF 1.50 6.1) */ +#define UDF_ID_COMPLIANT "*OSTA UDF Compliant" +#define UDF_ID_LV_INFO "*UDF LV Info" +#define UDF_ID_FREE_EA "*UDF FreeEASpace" +#define UDF_ID_FREE_APP_EA "*UDF FreeAppEASpace" +#define UDF_ID_DVD_CGMS "*UDF DVD CGMS Info" +#define UDF_ID_OS2_EA "*UDF OS/2 EA" +#define UDF_ID_OS2_EA_LENGTH "*UDF OS/2 EALength" +#define UDF_ID_OS400_DIRINFO "*UDF OS/400 DirInfo" +#define UDF_ID_MAC_VOLUME "*UDF Mac VolumeInfo" +#define UDF_ID_MAC_FINDER "*UDF Mac FinderInfo" +#define UDF_ID_MAC_UNIQUE "*UDF Mac UniqueIDTable" +#define UDF_ID_MAC_RESOURCE "*UDF Mac ResourceFork" +#define UDF_ID_VIRTUAL "*UDF Virtual Partition" +#define UDF_ID_SPARABLE "*UDF Sparable Partition" +#define UDF_ID_METADATA "*UDF Metadata Partition" +#define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl" +#define UDF_ID_SPARING "*UDF Sparing Table" + +/* Operating System Identifiers (UDF 1.50 6.3) */ +#define UDF_OS_CLASS_UNDEF 0x00U +#define UDF_OS_CLASS_DOS 0x01U +#define UDF_OS_CLASS_OS2 0x02U +#define UDF_OS_CLASS_MAC 0x03U +#define UDF_OS_CLASS_UNIX 0x04U +#define UDF_OS_CLASS_WIN95 0x05U +#define UDF_OS_CLASS_WINNT 0x06U +#define UDF_OS_CLASS_OS400 0x07U +#define UDF_OS_CLASS_BEOS 0x08U +#define UDF_OS_CLASS_WINCE 0x09U + +#define UDF_OS_ID_GENERIC 0x00U +#define UDF_OS_ID_UNDEF 0x00U +#define UDF_OS_ID_DOS 0x00U +#define UDF_OS_ID_OS2 0x00U +#define UDF_OS_ID_MAC 0x00U +#define UDF_OS_ID_UNIX 0x00U +#define UDF_OS_ID_WIN95 0x00U +#define UDF_OS_ID_WINNT 0x00U +#define UDF_OS_ID_OS400 0x00U +#define UDF_OS_ID_BEOS 0x00U + +#define UDF_OS_ID_AIX 0x01U +#define UDF_OS_ID_SOLARIS 0x02U +#define UDF_OS_ID_HPUX 0x03U +#define UDF_OS_ID_IRIX 0x04U +#define UDF_OS_ID_LINUX 0x05U +#define UDF_OS_ID_MKLINUX 0x06U +#define UDF_OS_ID_FREEBSD 0x07U +#define UDF_OS_ID_NETBSD 0x08U + +#define UDF_NAME_PAD 4 +#define UDF_NAME_LEN 255 +#define UDF_EXT_SIZE 5 // ??? +#define UDF_PATH_LEN 1023 +#define UDF_VOL_LABEL_LEN 32 + +/* Reserved file names */ + +#define UDF_FN_NON_ALLOCATABLE L"Non-Allocatable Space" +#define UDF_FN_NON_ALLOCATABLE_2 L"Non-Allocatable List" + +#define UDF_FN_NON_ALLOCATABLE_USER "Non-Allocatable Space" +#define UDF_FN_NON_ALLOCATABLE_2_USER "Non-Allocatable List" + +/* Reserved system stream names */ +/* METADATA bit shall be set to 1 */ + +#define UDF_SN_UID_MAPPING L"*UDF Unique ID Mapping Data" +#define UDF_SN_NON_ALLOCATABLE L"*UDF Non-Allocatable Space" +#define UDF_SN_POWER_CAL_TABLE L"*UDF Power Cal Table" +#define UDF_SN_BACKUP L"*UDF Backup" + +/* Reserved non-system stream names */ +/* METADATA bit shall be set to 0 */ + +#define UDF_SN_MAC_RESOURCE_FORK L"*UDF Macintosh Resource Fork" +#define UDF_SN_OS2_EA L"*UDF OS/2 EA" +#define UDF_SN_NT_ACL L"*UDF NT ACL" +#define UDF_SN_UNIX_ACL L"*UDF UNIX ACL" + +#define UDF_RESERVED_NAME_HDR L"*UDF " + +/* ----------- 2.01 ------------ */ +/* UDF 2.0 2.2.10 */ +#define UDF_FILE_TYPE_REALTIME 0xf9U + +#define TID_ADAPTEC_LOGICAL_VOL_DESC 0x9999U + +#pragma pack(pop) + +#endif /* _OSTA_MISC_H */ diff --git a/reactos/drivers/filesystems/udfs/udf_info/phys_eject.cpp b/reactos/drivers/filesystems/udfs/udf_info/phys_eject.cpp new file mode 100644 index 00000000000..aeb28ac819c --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/phys_eject.cpp @@ -0,0 +1,870 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module Name: Phys_eject.cpp + + Execution: Kernel mode only + + Description: + + Contains code that implement read/write operations for physical device +*/ + +#include "udf.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_PHYS_EJECT + +extern void +UDFKeyWaiter( + IN void* Context + ); + +/* + This routine checks for User Eject request & initiates Dismount + */ +void +UDFEjectReqWaiter( + IN void* Context + ) +{ + PUDFEjectWaitContext WC = (PUDFEjectWaitContext)Context; + PVCB Vcb; + OSSTATUS RC = STATUS_SUCCESS; + OSSTATUS WRC; + LARGE_INTEGER delay; + LARGE_INTEGER time; + BOOLEAN UseEvent = TRUE; + uint32 d; + BOOLEAN FlushWCache = FALSE; + IO_STATUS_BLOCK IoStatus; + BOOLEAN VcbAcquired; + BOOLEAN AllFlushed; + PDEVICE_OBJECT TargetDevObj; + uint32 BM_FlushPriod; + uint32 Tree_FlushPriod; + uint32 SkipCount = 0; + uint32 SkipEjectCount = 0; + uint32 flags = 0; + uint32 flush_stat = 0; + BOOLEAN UseEject = TRUE; + BOOLEAN MediaLoss = FALSE; + + BOOLEAN SkipEject = FALSE; + BOOLEAN SkipFlush = FALSE; + + BOOLEAN FlushAndEject = FALSE; + + KdPrint((" UDFEjectReqWaiter: start\n")); + uint8 supported_evt_classes = 0; + uint32 i, j; + uint8 evt_type; + BOOLEAN OldLowFreeSpace = FALSE; + uint32 space_check_counter = 0x7fffffff; + PGET_LAST_ERROR_USER_OUT Error = NULL; + + // Drain out Event Queue + Vcb = WC->Vcb; + TargetDevObj = Vcb->TargetDeviceObject; + UseEvent = Vcb->UseEvent; + if(UseEvent) { + supported_evt_classes = EventStat_Class_Media; + } else { + KdPrint((" Eject Button ignored\n")); + } + for(j=0; j<4; j++) { + KdPrint((" Reading events... (0)\n")); + if(supported_evt_classes) { + for(i=1; i<=EventRetStat_Class_Mask;i++) { + evt_type = (((UCHAR)1) << i); + if( !(supported_evt_classes & evt_type) ) + continue; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type; + +#ifdef EVALUATION_TIME_LIMIT + KeQuerySystemTime(&UDFGlobalData.UDFCurrentTime); +#endif //EVALUATION_TIME_LIMIT + RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_EVENT, + TargetDevObj, + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), + FALSE,NULL); + + if(RC == STATUS_INVALID_DEVICE_REQUEST) { + UseEvent = FALSE; + break; + } + if(RC == STATUS_NO_SUCH_DEVICE) + break; + if(OS_SUCCESS(RC)) { + supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses; + } + } + } else { +#ifdef EVALUATION_TIME_LIMIT + KeQuerySystemTime(&UDFGlobalData.UDFCurrentTime); +#endif //EVALUATION_TIME_LIMIT + } + if(!UseEvent) + break; + if(RC == STATUS_NO_SUCH_DEVICE) + break; + } + supported_evt_classes = 0; + + // Wait for events + while(TRUE) { + _SEH2_TRY { + + VcbAcquired = FALSE; + delay.QuadPart = -10000000; // 1.0 sec + WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); + if(WRC == STATUS_SUCCESS) { +stop_waiter: +// if(! + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);//) { +/* delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + try_return(RC);*/ +// } + Vcb->EjectWaiter = NULL; + UDFReleaseResource(&(Vcb->VCBResource)); + + KeSetEvent(WC->WaiterStopped, 0, FALSE); + MyFreePool__(WC); + WC = NULL; + KdPrint((" UDFEjectReqWaiter: exit 3\n")); + return; + } + BM_FlushPriod = Vcb->BM_FlushPriod; + Tree_FlushPriod = Vcb->Tree_FlushPriod; + +#ifdef EVALUATION_TIME_LIMIT + if(!UDFGlobalData.LicenseKeyItemStarted) { + UDFGlobalData.LicenseKeyItemStarted = TRUE; + ExInitializeWorkItem(&(UDFGlobalData.LicenseKeyItem), UDFKeyWaiter, NULL); + // KdPrint(("UDFLicenseWaiter: create thread\n")); + ExQueueWorkItem(&(UDFGlobalData.LicenseKeyItem), DelayedWorkQueue); + } +#endif //EVALUATION_TIME_LIMIT + + // check if we approaching end of disk + if(space_check_counter > 2) { + // update FreeAllocUnits if it is necessary + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && Vcb->Modified) { + Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb); + } + // update LowFreeSpace flag + Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128); + if(Vcb->LowFreeSpace && !OldLowFreeSpace) { + // initiate Flush process if we crossed LowFreeSpace boundary + Vcb->Tree_FlushTime = Tree_FlushPriod+1; + Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK; + } + OldLowFreeSpace = Vcb->LowFreeSpace; + space_check_counter = 0; + } + space_check_counter++; + +#ifdef EVALUATION_TIME_LIMIT + KeQuerySystemTime(&UDFGlobalData.UDFCurrentTime); +#endif //EVALUATION_TIME_LIMIT + + if(Vcb->VCBFlags & UDF_VCB_SKIP_EJECT_CHECK) { + SkipCount++; + SkipEjectCount++; + SkipEject = (SkipEjectCount <= Vcb->SkipEjectCountLimit); + SkipFlush = (SkipEjectCount <= Vcb->SkipCountLimit); + if(SkipEject || SkipFlush) { + Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK; + } + } else { + SkipEject = FALSE; + SkipFlush = FALSE; + } + + if(WC->SoftEjectReq) { + SkipEject = FALSE; + SkipFlush = FALSE; + } + + if(SkipFlush) { + Vcb->BM_FlushTime = + Vcb->Tree_FlushTime = 0; + } else { + SkipCount = 0; + } + if(!SkipEject) { + SkipEjectCount = 0; + } + + if(SkipEject && SkipFlush) { +wait_eject: + delay.QuadPart = -10000000; // 1.0 sec + WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); + if(WRC == STATUS_SUCCESS) { + goto stop_waiter; + } + try_return(RC); + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) { + goto wait_eject; + } + + // check if the door is still locked + if(!SkipEject && + (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) { + + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_CAPABILITIES, + TargetDevObj, + NULL,0, + &(WC->DevCap),sizeof(GET_CAPABILITIES_USER_OUT), + FALSE,NULL); + + Error = &(WC->Error); + UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject, + NULL,0, + Error,sizeof(GET_LAST_ERROR_USER_OUT), + TRUE,NULL); + UDFReleaseResource(&(Vcb->IoResource)); + KdPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n", + Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError)); + // check for Long Write In Progress + if( ((Error->SenseKey == SCSI_SENSE_NOT_READY) && + (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && + (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS || + Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) ) { + if((!Vcb->Modified && + !(Vcb->VCBFlags & UDF_VCB_LAST_WRITE)) + || + (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL)) { + // we should forget about this disk... + KdPrint((" LAST_WRITE %x\n", !!(Vcb->VCBFlags & UDF_VCB_LAST_WRITE))); + KdPrint((" UDF_VCB_FLAGS_UNSAFE_IOCTL %x\n", !!(Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL))); + KdPrint((" UDFEjectReqWaiter: Unexpected write-in-progress on !Modified volume\n")); + //ASSERT(FALSE); + Vcb->ForgetVolume = TRUE; + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY | UDF_VCB_FLAGS_MEDIA_READ_ONLY; + MediaLoss = TRUE; + goto device_failure; + } + } + if( OS_SUCCESS(RC) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) && + !(WC->DevCap.Capabilities2 & DevCap_lock_state)) { + // probably bus reset or power failure occured + // re-lock tray + KdPrint((" UDFEjectReqWaiter: Unexpected tray unlock encountered. Try to re-lock\n")); + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + VcbAcquired = TRUE; + +/* UDFResetDeviceDriver(Vcb, TargetDevObj, FALSE); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay);*/ + // lock it + ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&(WC->DevCap)))->PreventMediaRemoval = TRUE; + UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, + TargetDevObj, + &(WC->DevCap),sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + // force write mode re-initialization + Vcb->LastModifiedTrack = 0; +// try_return(RC); + } + } + + UDFVVerify(Vcb, 0 /* partial verify */); + + if(!SkipFlush && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + (BM_FlushPriod || Tree_FlushPriod)) { + KeQuerySystemTime(&delay); + d = (uint32)((delay.QuadPart - time.QuadPart) / 10000000); + time = delay; + Vcb->BM_FlushTime += d; + Vcb->Tree_FlushTime += d; + + if(!Vcb->CDR_Mode) { + + AllFlushed = FALSE; + + KdPrint((" SkipCount=%x, SkipCountLimit=%x\n", + SkipCount, + Vcb->SkipCountLimit)); + + if( Tree_FlushPriod && + (Tree_FlushPriod < Vcb->Tree_FlushTime)) { + + KdPrint((" Tree_FlushPriod %I64x, Vcb->Tree_FlushTime %I64x\n", + Tree_FlushPriod, + Vcb->Tree_FlushTime)); + + // do not touch unchanged volume + if(((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + !(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED)) + || + !Vcb->Modified) + goto skip_BM_flush; + + // Acquire Vcb resource + if(!VcbAcquired) { + if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FALSE)) { + delay.QuadPart = -10000000; // 1.0 sec + WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); + if(WRC == STATUS_SUCCESS) { + goto stop_waiter; + } + try_return(RC); + } + VcbAcquired = TRUE; + } + // License Key check + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + goto skip_BM_flush; + } + + KdPrint(("UDF: Flushing Directory Tree....\n")); + if( BM_FlushPriod && + (BM_FlushPriod < Vcb->BM_FlushTime)) { + KdPrint((" full flush\n")); + flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE); + } else { + KdPrint((" light flush\n")); + flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE | UDF_FLUSH_FLAGS_LITE); + } + if(flush_stat & UDF_FLUSH_FLAGS_INTERRUPTED) + try_return(RC); + FlushWCache = TRUE; + UDFVVerify(Vcb, UFD_VERIFY_FLAG_BG /* partial verify */); + //UDFVFlush(Vcb); +skip_BM_flush: + Vcb->Tree_FlushTime = 0; + } + if( BM_FlushPriod && + (BM_FlushPriod < Vcb->BM_FlushTime)) { + + KdPrint((" BM_FlushPriod %I64x, Vcb->BM_FlushTime %I64x\n", + BM_FlushPriod, + Vcb->BM_FlushTime)); + + + // do not touch unchanged volume + if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && + !(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED)) + goto skip_BM_flush2; + if(!Vcb->Modified) + goto skip_BM_flush2; + + if(!VcbAcquired) { + if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FlushWCache /*|| FALSE*/)) { + delay.QuadPart = -10000000; // 1.0 sec + WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); + if(WRC == STATUS_SUCCESS) { + goto stop_waiter; + } + try_return(RC); + } + VcbAcquired = TRUE; + } + + UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); +// UDF_CHECK_BITMAP_RESOURCE(Vcb); + + if(Vcb->FSBM_ByteCount != RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) { + flags |= 1; + } +/* if(FlushWCache) { + AllFlushed = TRUE; + }*/ + AllFlushed = + FlushWCache = TRUE; +#ifndef UDF_READ_ONLY_BUILD + UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE); + UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR); + + UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)); + UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)); + + if(Vcb->VerifyOnWrite) { + KdPrint(("UDF: Flushing cache for verify\n")); + //WCacheFlushAll__(&(Vcb->FastCache), Vcb); + WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); + UDFVFlush(Vcb); + } +#ifdef UDF_DBG + KdPrint(("UDF: Flushing Free Space Bitmap....\n")); + +// if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)))) +// KdPrint(("Error updating VolIdent\n")); + if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags))) + KdPrint(("Error updating Main VDS\n")); + if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags))) + KdPrint(("Error updating Reserve VDS\n")); +#else + UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags); + UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags); +#endif // UDF_DBG + // Update Integrity Desc if any + if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) { + UDFUpdateLogicalVolInt(Vcb, TRUE); + } + if(flags & 1) { + RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); + } +#endif //UDF_READ_ONLY_BUILD + UDFPreClrModified(Vcb); + UDFReleaseResource(&(Vcb->BitMapResource1)); +skip_BM_flush2: + Vcb->BM_FlushTime = 0; + } + if(FlushWCache) { + FlushWCache = FALSE; + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + } + + if(AllFlushed) { + //Vcb->Modified = FALSE; + UDFClrModified(Vcb); + } + + if(VcbAcquired) { + VcbAcquired = FALSE; + UDFReleaseResource(&(Vcb->VCBResource)); + } + if(!Vcb->Tree_FlushTime && + !Vcb->BM_FlushTime) + SkipCount = 0; + } + } else { + //SkipCount = 0; + } + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) + try_return(RC); + + KdPrint((" UDFEjectReqWaiter: check removable media\n")); + if(!WC->SoftEjectReq && SkipEject) { + try_return(RC); + } + + if(!WC->SoftEjectReq) { + + if(!UseEvent) { + KdPrint((" Eject Button ignored\n")); + try_return(RC); + } + +/* if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) ){ + // delay.QuadPart = -100000; // 0.01 sec + // KeDelayExecutionThread(KernelMode, FALSE, &delay); + OSSTATUS RC; + + KdPrint((" Sync cache before GET_EVENT\n")); + RC = UDFSyncCache(Vcb); + if(RC == STATUS_INVALID_DEVICE_REQUEST) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_SYNC_CACHE; + } + + // delay.QuadPart = -300000; // 0.03 sec + // KeDelayExecutionThread(KernelMode, FALSE, &delay); + Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; + }*/ + + ASSERT(sizeof(TEST_UNIT_READY_USER_OUT) <= sizeof(GET_EVENT_USER_OUT)); + + RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY, + Vcb, + NULL,0, + &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT), + FALSE,NULL); + + if(RC != STATUS_SUCCESS && + RC != STATUS_DATA_OVERRUN) { + if(RC == STATUS_NO_SUCH_DEVICE) { + KdPrint((" Device loss\n")); + goto device_failure; + } + if(RC == STATUS_NO_MEDIA_IN_DEVICE) { + KdPrint((" Media loss\n")); + goto media_loss; + } + } + KdPrint((" Reading events...\n")); + if(supported_evt_classes) { + for(i=1; i<=EventRetStat_Class_Mask;i++) { + evt_type = (((UCHAR)1) << i); + if( !(supported_evt_classes & evt_type) ) + continue; +/* + if( evt_type == EventStat_Class_Media ) + continue; + if( evt_type == EventStat_Class_ExternalReq ) + continue; +*/ + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type; + + RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, + Vcb, + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), + FALSE,NULL); + + if(RC == STATUS_INVALID_DEVICE_REQUEST) { + supported_evt_classes &= ~evt_type; + continue; + } + if(RC == STATUS_NO_SUCH_DEVICE) { + KdPrint((" Device loss (2)\n")); + goto device_failure; + } + if(!OS_SUCCESS(RC)) { + continue; + } + + if(WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_NEA) { + continue; + } + if( evt_type == EventStat_Class_Media ) { + KdPrint((" EventStat_Class_Media:\n")); + if((WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_Class_Mask) != + EventRetStat_Class_Media) { + continue; + } +retry_media_presence_check: + if(!(WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_Present) || + (WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_DoorOpen)) { + // something wrong.... + RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY, + Vcb, + NULL,0, + &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT), + FALSE,NULL); + + if(RC == STATUS_SUCCESS || + RC == STATUS_DATA_OVERRUN) { + KdPrint((" Buggy GET_EVENT media presence flag %x\n", + WC->EjectReqBuffer.MediaChange.Byte1)); + WC->EjectReqBuffer.MediaChange.Byte1.Flags |= EventStat_MediaStat_Present; + WC->EjectReqBuffer.MediaChange.Byte1.Flags &= ~EventStat_MediaStat_DoorOpen; + goto retry_media_presence_check; + } +media_loss: + KdPrint((" Unexpected media loss. Check device status\n")); + UseEject = FALSE; + MediaLoss = TRUE; + } else + // check if eject request occured + if( (WC->EjectReqBuffer.MediaChange.Byte0.Flags & EventStat_MediaEvent_Mask) != + EventStat_MediaEvent_EjectReq ) { + continue; + } + KdPrint((" eject requested\n")); + WC->SoftEjectReq = TRUE; + break; + } + if( evt_type == EventStat_Class_ExternalReq ) { + KdPrint((" EventStat_Class_ExternalReq:\n")); + if((WC->EjectReqBuffer.ExternalReq.Header.Flags.Flags & EventRetStat_Class_Mask) != + EventRetStat_Class_ExternReq) + continue; + switch(WC->EjectReqBuffer.ExternalReq.Byte0.Flags & EventStat_ExtrnReqEvent_Mask) { + case EventStat_ExtrnReqEvent_KeyDown: + case EventStat_ExtrnReqEvent_KeyUp: + case EventStat_ExtrnReqEvent_ExtrnReq: + KdPrint((" eject requested (%x)\n", WC->EjectReqBuffer.ExternalReq.Byte0.Flags)); + WC->SoftEjectReq = TRUE; + break; + } + continue; + } + } + if(!supported_evt_classes) { + UseEvent = FALSE; + } + if(!WC->SoftEjectReq) { + try_return(RC); + } + } else { + + KdPrint((" Reading Media Event...\n")); + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_Media; + + RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, + Vcb, + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), + FALSE,NULL); + + if(!OS_SUCCESS(RC)) { + if(RC == STATUS_NO_SUCH_DEVICE) + goto device_failure; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; + ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_ExternalReq; + + RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, + Vcb, + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), + &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), + FALSE,NULL); + + if(RC == STATUS_NO_SUCH_DEVICE) + goto device_failure; + if(RC == STATUS_INVALID_DEVICE_REQUEST) { + UseEvent = FALSE; + } + try_return(RC); + } + supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses; + try_return(RC); + } + } + FlushAndEject = TRUE; +device_failure: + // Ok. Lets flush all we have in memory, dismount volume & eject disc + // Acquire Vcb resource + Vcb->SoftEjectReq = TRUE; + + KdPrint((" UDFEjectReqWaiter: ejecting...\n")); +#ifdef UDF_DELAYED_CLOSE + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + KdPrint((" UDFEjectReqWaiter: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; + UDFReleaseResource(&(Vcb->VCBResource)); +#endif //UDF_DELAYED_CLOSE + + KdPrint((" UDFEjectReqWaiter: UDFCloseAllSystemDelayedInDir\n")); + RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + ASSERT(OS_SUCCESS(RC)); +#ifdef UDF_DELAYED_CLOSE + KdPrint((" UDFEjectReqWaiter: UDFCloseAllDelayed\n")); + UDFCloseAllDelayed(Vcb); + //ASSERT(OS_SUCCESS(RC)); +#endif //UDF_DELAYED_CLOSE + + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + + KdPrint((" UDFEjectReqWaiter: UDFDoDismountSequence\n")); + UDFDoDismountSequence(Vcb, (PPREVENT_MEDIA_REMOVAL_USER_IN)&(WC->EjectReqBuffer), UseEject); + if (MediaLoss) { + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + } + Vcb->EjectWaiter = NULL; + Vcb->SoftEjectReq = FALSE; + UDFReleaseResource(&(Vcb->VCBResource)); + + KdPrint((" UDFEjectReqWaiter: set WaiterStopped\n")); + KeSetEvent(WC->WaiterStopped, 0, FALSE); + MyFreePool__(WC); + WC = NULL; + + KdPrint((" UDFEjectReqWaiter: exit 1\n")); + return; + +try_exit: NOTHING; + } _SEH2_FINALLY { + + if(VcbAcquired) { + VcbAcquired = FALSE; + UDFReleaseResource(&(Vcb->VCBResource)); + } + +/* if(WC) { + delay.QuadPart = -10000000; // 1.0 sec + WRC = KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, &delay); + if(WRC == STATUS_SUCCESS) { + goto stop_waiter; + } + }*/ + } _SEH2_END; + } + // Simply make compiler happy + return; +} // end UDFEjectReqWaiter() + +void +UDFStopEjectWaiter(PVCB Vcb) { + + KdPrint((" UDFStopEjectWaiter: try\n")); + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + _SEH2_TRY { + if(Vcb->EjectWaiter) { + KdPrint((" UDFStopEjectWaiter: set flag\n")); + KeSetEvent( &(Vcb->EjectWaiter->StopReq), 0, FALSE ); + } else { +// return; + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + UDFReleaseResource(&(Vcb->VCBResource)); + + _SEH2_TRY { + if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT) { + KdPrint((" UDFStopEjectWaiter: wait\n")); + KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL); + } + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT; + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; + ASSERT(!Vcb->EjectWaiter); + KdPrint((" UDFStopEjectWaiter: exit\n")); + +} // end UDFStopEjectWaiter() + +OSSTATUS +UDFDoDismountSequence( + IN PVCB Vcb, + IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf, + IN BOOLEAN Eject + ) +{ + LARGE_INTEGER delay; + OSSTATUS RC; + ULONG i; + + // flush system cache + UDFFlushLogicalVolume(NULL, NULL, Vcb, 0); + KdPrint(("UDFDoDismountSequence:\n")); + + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + // wait for completion of all backgroung writes + while(Vcb->BGWriters) { + delay.QuadPart = -5000000; // 0.5 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + } + // release WCache + WCacheRelease__(&(Vcb->FastCache)); + + UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); + + // unlock media, drop our own Locks + if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) { + KdPrint((" cleanup tray-lock (%d+2):\n", Vcb->MediaLockCount)); + for(i=0; iMediaLockCount+2; i++) { + Buf->PreventMediaRemoval = FALSE; + RC = UDFPhSendIOCTL(IOCTL_STORAGE_MEDIA_REMOVAL, + Vcb->TargetDeviceObject, + Buf,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), + NULL,0, + FALSE,NULL); + KeDelayExecutionThread(KernelMode, FALSE, &delay); + } + delay.QuadPart = -2000000; // 0.2 sec + } + + if(!Vcb->ForgetVolume) { + + if(!UDFIsDvdMedia(Vcb)) { + // send speed limits to drive + KdPrint((" Restore drive speed on dismount\n")); + Vcb->SpeedBuf.ReadSpeed = Vcb->MaxReadSpeed; + Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed; + UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED, + Vcb->TargetDeviceObject, + &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_USER_IN), + NULL,0,TRUE,NULL); + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) { + CLOSE_TRK_SES_USER_IN CBuff; + + // reset driver + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); + delay.QuadPart = -2000000; // 0.2 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + + memset(&CBuff,0,sizeof(CLOSE_TRK_SES_USER_IN)); + // stop BG format + if(Vcb->MRWStatus) { + KdPrint((" Stop background formatting\n")); + + CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed; + CBuff.Byte2.Flags = CloseTrkSes_Ses; + CBuff.TrackNum = 1; + + RC = UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES, + Vcb->TargetDeviceObject, + &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), + &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), + FALSE, NULL ); + /* } else + if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { + KdPrint((" Close BG-formatted track\n")); + + CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed; + CBuff.Byte2.Flags = CloseTrkSes_Trk; + CBuff.TrackNum = 1; + + RC = UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES, + Vcb->TargetDeviceObject, + &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), + &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), + FALSE, NULL ); + */ + } + // reset driver + UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); + delay.QuadPart = -1000000; // 0.1 sec + KeDelayExecutionThread(KernelMode, FALSE, &delay); + } + // eject media + if(Eject && + (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) { + + RC = UDFPhSendIOCTL(IOCTL_STORAGE_EJECT_MEDIA, + Vcb->TargetDeviceObject, + NULL,0, + NULL,0, + FALSE,NULL); + } + // notify media change + /* if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) { + ((PNOTIFY_MEDIA_CHANGE_USER_IN)Buf)->Autorun = FALSE; + RC = UDFPhSendIOCTL(IOCTL_CDRW_NOTIFY_MEDIA_CHANGE, + Vcb->TargetDeviceObject, + Buf,sizeof(NOTIFY_MEDIA_CHANGE_USER_IN), + NULL,0, + FALSE,NULL); + }*/ + } + UDFReleaseResource(&(Vcb->IoResource)); + // unregister shutdown notification + if(Vcb->ShutdownRegistered) { + IoUnregisterShutdownNotification(Vcb->VCBDeviceObject); + Vcb->ShutdownRegistered = FALSE; + } + // allow media change checks (this will lead to dismount) + // ... and make it Read-Only... :-\~ + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED; + + // Return back XP CD Burner Volume +/* + if (Vcb->CDBurnerVolumeValid) { + RtlWriteRegistryValue(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, + REG_CD_BURNER_KEY_NAME,REG_CD_BURNER_VOLUME_NAME, + REG_SZ,(PVOID)&(Vcb->CDBurnerVolume),sizeof(Vcb->CDBurnerVolume)); + ExFreePool(Vcb->CDBurnerVolume.Buffer); + } +*/ + KdPrint((" set UnsafeIoctl\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL; + + return STATUS_SUCCESS; +} // end UDFDoDismountSequence() + diff --git a/reactos/drivers/filesystems/udfs/udf_info/physical.cpp b/reactos/drivers/filesystems/udfs/udf_info/physical.cpp new file mode 100644 index 00000000000..cfe078b053a --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/physical.cpp @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module Name: Physical.cpp + + Execution: Kernel mode only + + Description: + + Contains code that implement read/write operations for physical device +*/ + +#include "udf.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_PHYSICAL + +#include "..\Include\Phys_lib.cpp" + diff --git a/reactos/drivers/filesystems/udfs/udf_info/prec_hdr2.cpp b/reactos/drivers/filesystems/udfs/udf_info/prec_hdr2.cpp new file mode 100644 index 00000000000..1bc857f5ef8 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/prec_hdr2.cpp @@ -0,0 +1,6 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udf.h" + diff --git a/reactos/drivers/filesystems/udfs/udf_info/remap.cpp b/reactos/drivers/filesystems/udfs/udf_info/remap.cpp new file mode 100644 index 00000000000..372d591f1f7 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/remap.cpp @@ -0,0 +1,1059 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + remap.cpp + + Abstract: + + This file contains filesystem-specific routines + responsible for disk space management + +*/ + +#include "udf.h" + +#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_REMAP + +typedef struct _UDF_VERIFY_ITEM { + lba_t lba; + ULONG crc; + PUCHAR Buffer; + LIST_ENTRY vrfList; + BOOLEAN queued; +} UDF_VERIFY_ITEM, *PUDF_VERIFY_ITEM; + +typedef struct _UDF_VERIFY_REQ_RANGE { + lba_t lba; + uint32 BCount; +} UDF_VERIFY_REQ_RANGE, *PUDF_VERIFY_REQ_RANGE; + +#define MAX_VREQ_RANGES 128 + +typedef struct _UDF_VERIFY_REQ { + PVCB Vcb; + PUCHAR Buffer; + ULONG nReq; + UDF_VERIFY_REQ_RANGE vr[MAX_VREQ_RANGES]; +#ifndef _CONSOLE + WORK_QUEUE_ITEM VerifyItem; +#endif +} UDF_VERIFY_REQ, *PUDF_VERIFY_REQ; + +VOID +UDFVRemoveBlock( + PUDF_VERIFY_CTX VerifyCtx, + PUDF_VERIFY_ITEM vItem + ); + +OSSTATUS +UDFVInit( + IN PVCB Vcb + ) +{ + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + uint32 i; + OSSTATUS status = STATUS_SUCCESS; + BOOLEAN res_inited = FALSE; + + if(VerifyCtx->VInited) { + KdPrint(("Already inited\n")); + return STATUS_SUCCESS; + } + + _SEH2_TRY { + RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX)); + if(!Vcb->VerifyOnWrite) { + KdPrint(("Verify is disabled\n")); + return STATUS_SUCCESS; + } + if(Vcb->CDR_Mode) { + KdPrint(("Verify is not intended for CD/DVD-R\n")); + return STATUS_SUCCESS; + } + if(!OS_SUCCESS(status = ExInitializeResourceLite(&(VerifyCtx->VerifyLock)))) { + try_return(status); + } + res_inited = TRUE; + VerifyCtx->ItemCount = 0; + VerifyCtx->StoredBitMap = (uint8*)DbgAllocatePoolWithTag(PagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3), 'mNWD' ); + if(VerifyCtx->StoredBitMap) { + RtlZeroMemory(VerifyCtx->StoredBitMap, i); + } else { + KdPrint(("Can't alloc verify bitmap for %x blocks\n", Vcb->LastPossibleLBA)); + try_return(status = STATUS_INSUFFICIENT_RESOURCES); + } + InitializeListHead(&(VerifyCtx->vrfList)); + KeInitializeEvent(&(VerifyCtx->vrfEvent), SynchronizationEvent, FALSE); + VerifyCtx->WaiterCount = 0; + VerifyCtx->VInited = TRUE; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(!OS_SUCCESS(status)) { + if(res_inited) { + ExDeleteResourceLite(&(VerifyCtx->VerifyLock)); + } + } + } _SEH2_END; + return status; +} // end UDFVInit() + +VOID +UDFVWaitQueued( + PUDF_VERIFY_CTX VerifyCtx + ) +{ + ULONG w; + + while(VerifyCtx->QueuedCount) { + KdPrint(("UDFVWaitQueued: wait for completion (%d)\n", VerifyCtx->QueuedCount)); + w = InterlockedIncrement((PLONG)&(VerifyCtx->WaiterCount)); + KdPrint((" %d waiters\n", w)); + DbgWaitForSingleObject(&(VerifyCtx->vrfEvent), NULL); + if(w = InterlockedDecrement((PLONG)&(VerifyCtx->WaiterCount))) { + KdPrint((" still %d waiters, q %d\n", w, VerifyCtx->QueuedCount)); + if(!VerifyCtx->QueuedCount) { + KdPrint((" pulse event\n", w)); + KeSetEvent(&(VerifyCtx->vrfEvent), 0, FALSE); + } + } + } + return; +} // end UDFVWaitQueued() + +VOID +UDFVRelease( + IN PVCB Vcb + ) +{ + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + PLIST_ENTRY Link; + PUDF_VERIFY_ITEM vItem; + + if(!VerifyCtx->VInited) { + return; + } + + KdPrint(("UDFVRelease: wait for completion\n")); + UDFVWaitQueued(VerifyCtx); + + UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE); + + Link = VerifyCtx->vrfList.Flink; + + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Flink; + //DbgFreePool(vItem); + UDFVRemoveBlock(VerifyCtx, vItem); + } + VerifyCtx->VInited = FALSE; + + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + + ExDeleteResourceLite(&(VerifyCtx->VerifyLock)); + DbgFreePool(VerifyCtx->StoredBitMap); + + RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX)); + + return; +} // end UDFVRelease() + +PUDF_VERIFY_ITEM +UDFVStoreBlock( + IN PVCB Vcb, + IN uint32 LBA, + IN PVOID Buffer, + PLIST_ENTRY Link + ) +{ + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + PUDF_VERIFY_ITEM vItem; + + KdPrint(("v-add %x\n", LBA)); + + vItem = (PUDF_VERIFY_ITEM)DbgAllocatePoolWithTag(PagedPool, sizeof(UDF_VERIFY_ITEM)+Vcb->BlockSize, 'bvWD'); + if(!vItem) + return NULL; + RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize); + vItem->lba = LBA; + vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize); + vItem->Buffer = (PUCHAR)(vItem+1); + vItem->queued = FALSE; + InitializeListHead(&(vItem->vrfList)); + InsertTailList(Link, &(vItem->vrfList)); + UDFSetBit(VerifyCtx->StoredBitMap, LBA); + VerifyCtx->ItemCount++; + return vItem; +} // end UDFVStoreBlock() + +VOID +UDFVUpdateBlock( + IN PVCB Vcb, + IN PVOID Buffer, + PUDF_VERIFY_ITEM vItem + ) +{ + KdPrint(("v-upd %x\n", vItem->lba)); + RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize); + vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize); + return; +} // end UDFVUpdateBlock() + +VOID +UDFVRemoveBlock( + PUDF_VERIFY_CTX VerifyCtx, + PUDF_VERIFY_ITEM vItem + ) +{ + KdPrint(("v-del %x\n", vItem->lba)); + UDFClrBit(VerifyCtx->StoredBitMap, vItem->lba); + RemoveEntryList(&(vItem->vrfList)); + VerifyCtx->ItemCount--; + DbgFreePool(vItem); + return; +} // end UDFVUpdateBlock() + +OSSTATUS +UDFVWrite( + IN PVCB Vcb, + IN void* Buffer, // Target buffer + IN uint32 BCount, + IN uint32 LBA, +// OUT uint32* WrittenBytes, + IN uint32 Flags + ) +{ + PLIST_ENTRY Link; + PUDF_VERIFY_ITEM vItem; + //PUDF_VERIFY_ITEM vItem1; + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + ULONG i; + ULONG n; + //uint32 prev_lba; + + if(!VerifyCtx->VInited) { + return STATUS_SUCCESS; + } + + UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE); + + for(i=0, n=0; iStoredBitMap, LBA+i)) { + // some blocks are remembered + n++; + } + } + + if(n == BCount) { + // update all blocks + n = 0; + Link = VerifyCtx->vrfList.Blink; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Blink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba)); + UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+(vItem->lba-LBA)*Vcb->BlockSize, vItem); + n++; + if(n == BCount) { + // all updated + break; + } + } + } + } else + if(n) { +#if 0 + // find remembered blocks (the 1st one) + Link = VerifyCtx->vrfList.Blink; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Blink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + //UDFVRemoveBlock(VerifyCtx, vItem); + break; + } + } + + // check if contiguous + i=1; + prev_lba = vItem->lba; + vItem1 = vItem; + Link = Link->Blink; + while((i < n) && (Link != &(VerifyCtx->vrfList))) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Blink; + if(vItem->lba > LBA || vItem->lba >= LBA+BCount) { + // end + break; + } + if(vItem->lba < prev_lba) { + // not sorted + break; + } + prev_lba = vItem->lba; + i++; + } + + if(i == n) { + // cont + } else { + // drop all and add again + } + + vItem1 = vItem; + for(i=0; ilba == LBA+i) { + ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)); + UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem); + continue; + } + if(vItem1->lba == LBA+i) { + ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)); + UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem1); + continue; + } + if(vItem1->lba > LBA+i) { + // just insert this block + ASSERT(!UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)); + UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(vItem1->vrfList)); + } else { + vItem = CONTAINING_RECORD( vItem->vrfList.Blink, UDF_VERIFY_ITEM, vrfList ); + } + } +#else + Link = VerifyCtx->vrfList.Blink; + i=0; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Blink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + UDFVRemoveBlock(VerifyCtx, vItem); + i++; + if(i == n) { + // all killed + break; + } + } + } + goto remember_all; +#endif + + } else { +remember_all: + // remember all blocks + for(i=0; iStoredBitMap, LBA+i)); + UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(VerifyCtx->vrfList)); + } + } + + if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE) { + UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED); + } + + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + + if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE*2) { + //UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED); + // TODO: make some delay + } + + return STATUS_SUCCESS; + +} // end UDFVWrite() + +OSSTATUS +UDFVRead( + IN PVCB Vcb, + IN void* Buffer, // Target buffer + IN uint32 BCount, + IN uint32 LBA, +// OUT uint32* ReadBytes, + IN uint32 Flags + ) +{ + PLIST_ENTRY Link; + PUDF_VERIFY_ITEM vItem; + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + ULONG crc; + ULONG i; + ULONG n; + OSSTATUS status = STATUS_SUCCESS; + uint32* bm; + + if(!VerifyCtx->VInited) { + return STATUS_SUCCESS; + //return STATUS_UNSUCCESSFUL; + } + + UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE); + + for(i=0, n=0; iStoredBitMap, LBA+i)) { + // some blocks are remembered + n++; + } + } + + if(!n) { + // no blocks are remembered + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + return STATUS_SUCCESS; + } + + Link = VerifyCtx->vrfList.Flink; + i=0; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Flink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba)); + i++; + if(!(Flags & PH_READ_VERIFY_CACHE)) { + crc = crc32((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, Vcb->BlockSize); + if(vItem->crc != crc) { + KdPrint(("UDFVRead: stored %x != %x\n", vItem->crc, crc)); + RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize); + status = STATUS_FT_WRITE_RECOVERY; + + if(!(bm = (uint32*)(Vcb->BSBM_Bitmap))) { + crc = (Vcb->LastPossibleLBA+1+7) >> 3; // reuse 'crc' variable + bm = (uint32*)(Vcb->BSBM_Bitmap = (int8*)DbgAllocatePoolWithTag(NonPagedPool, crc, 'mNWD' )); + if(bm) { + RtlZeroMemory(bm, crc); + } else { + KdPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA)); + } + } + if(bm) { + UDFSetBit__(bm, vItem->lba); + KdPrint(("Set BB @ %#x\n", vItem->lba)); + } +#ifdef _BROWSE_UDF_ + bm = (uint32*)(Vcb->FSBM_Bitmap); + if(bm) { + UDFSetUsedBit(bm, vItem->lba); + KdPrint(("Set BB @ %#x as used\n", vItem->lba)); + } +#endif //_BROWSE_UDF_ + } else { + // ok + } + } else { + KdPrint(("UDFVRead: get cached @ %x\n", vItem->lba)); + RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize); + } + if(i >= n) { + // no more blocks expected + break; + } + } + } + + if((status == STATUS_SUCCESS && !(Flags & PH_KEEP_VERIFY_CACHE)) || (Flags & PH_FORGET_VERIFIED)) { + // ok, forget this, no errors found + Link = VerifyCtx->vrfList.Flink; + i = 0; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Flink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + i++; + UDFVRemoveBlock(VerifyCtx, vItem); + if(i >= n) { + // no more blocks expected + break; + } + } + } + } + + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + return status; + +} // end UDFVRead() + +OSSTATUS +UDFVForget( + IN PVCB Vcb, + IN uint32 BCount, + IN uint32 LBA, + IN uint32 Flags + ) +{ + PLIST_ENTRY Link; + PUDF_VERIFY_ITEM vItem; + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + ULONG i; + ULONG n; + OSSTATUS status = STATUS_SUCCESS; + + if(!VerifyCtx->VInited) { + return STATUS_UNSUCCESSFUL; + } + + UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE); + + for(i=0, n=0; iStoredBitMap, LBA+i)) { + // some blocks are remembered + n++; + } + } + + if(!n) { + // no blocks are remembered + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + return STATUS_SUCCESS; + } + + Link = VerifyCtx->vrfList.Flink; + i = 0; + while(Link != &(VerifyCtx->vrfList)) { + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Flink; + if(vItem->lba >= LBA && vItem->lba < LBA+BCount) { + i++; + UDFVRemoveBlock(VerifyCtx, vItem); + if(i >= n) { + // no more blocks expected + break; + } + } + } + + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + return status; + +} // end UDFVForget() + +VOID +UDFVWorkItem( + PUDF_VERIFY_REQ VerifyReq + ) +{ + PVCB Vcb = VerifyReq->Vcb; + ULONG ReadBytes; + OSSTATUS RC; + ULONG i; + + ReadBytes = (ULONG)Vcb; +#if 1 + if(Vcb->SparingCountFree) { + WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE); + for(i=0; inReq; i++) { + RC = UDFTIOVerify(Vcb, + VerifyReq->Buffer, // Target buffer + VerifyReq->vr[i].BCount << Vcb->BlockSizeBits, + VerifyReq->vr[i].lba, + &ReadBytes, + PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/); + } + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } else { + for(i=0; inReq; i++) { + KdPrint(("!!! No more space for remap !!!\n")); + KdPrint((" try del from verify cache @ %x\n", VerifyReq->vr[i].lba)); + RC = UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba, + PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER); + } + } +#else + for(i=0; inReq; i++) { + if(Vcb->SparingCountFree) { + WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE); + RC = UDFTIOVerify(Vcb, + VerifyReq->Buffer, // Target buffer + VerifyReq->vr[i].BCount << Vcb->BlockSizeBits, + VerifyReq->vr[i].lba, + &ReadBytes, + PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/); + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } else { + KdPrint(("!!! No more space for remap !!!\n")); + KdPrint((" try del from verify cache @ %x\n", VerifyReq->vr[i].lba)); + RC = UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba, + PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER); + } + } +#endif + DbgFreePool(VerifyReq->Buffer); + DbgFreePool(VerifyReq); + InterlockedDecrement((PLONG)&(Vcb->VerifyCtx.QueuedCount)); + KdPrint((" QueuedCount = %d\n", Vcb->VerifyCtx.QueuedCount)); + KdPrint((" Setting event...\n")); + KeSetEvent(&(Vcb->VerifyCtx.vrfEvent), 0, FALSE); + return; +} // end UDFVWorkItem() + +VOID +UDFVVerify( + IN PVCB Vcb, + IN ULONG Flags + ) +{ + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + PLIST_ENTRY Link; + PUDF_VERIFY_ITEM vItem; + PUDF_VERIFY_REQ VerifyReq = NULL; + ULONG len, max_len=0; + lba_t prev_lba; + //PUCHAR tmp_buff; + ULONG i; + BOOLEAN do_vrf = FALSE; + + if(!VerifyCtx->VInited) { + return; + } + if(VerifyCtx->QueuedCount) { + if(Flags & UFD_VERIFY_FLAG_WAIT) { + KdPrint((" wait for verify flush\n")); + goto wait; + } + KdPrint((" verify flush already queued\n")); + return; + } + + if(!(Flags & (UFD_VERIFY_FLAG_FORCE | UFD_VERIFY_FLAG_BG))) { + if(VerifyCtx->ItemCount < UDF_MAX_VERIFY_CACHE) { + return; + } + + } + if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) { + UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE); + } + + if(Flags & UFD_VERIFY_FLAG_FORCE) { + i = VerifyCtx->ItemCount; + } else { + if(VerifyCtx->ItemCount >= UDF_MAX_VERIFY_CACHE) { + i = VerifyCtx->ItemCount - UDF_VERIFY_CACHE_LOW; + } else { + i = min(UDF_VERIFY_CACHE_GRAN, VerifyCtx->ItemCount); + } + } + + Link = VerifyCtx->vrfList.Flink; + prev_lba = -2; + len = 0; + + while(i) { + ASSERT(Link != &(VerifyCtx->vrfList)); +/* + if(Link == &(VerifyCtx->vrfList)) { + if(!len) + break; + i=1; + goto queue_req; + } +*/ + vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList ); + Link = Link->Flink; + + // + if(!vItem->queued && (prev_lba+len == vItem->lba)) { + vItem->queued = TRUE; + len++; + } else { + if(len) { + do_vrf = TRUE; + } else { + len = 1; + prev_lba = vItem->lba; + } + } + if((i == 1) && len) { + do_vrf = TRUE; + } + if(len >= 0x100) { + do_vrf = TRUE; + } + if(do_vrf) { +//queue_req: + if(!VerifyReq) { + VerifyReq = (PUDF_VERIFY_REQ)DbgAllocatePoolWithTag(NonPagedPool, sizeof(UDF_VERIFY_REQ), 'bNWD'); + if(VerifyReq) { + RtlZeroMemory(VerifyReq, sizeof(UDF_VERIFY_REQ)); + VerifyReq->Vcb = Vcb; + } + } + if(VerifyReq) { + + VerifyReq->vr[VerifyReq->nReq].lba = prev_lba; + VerifyReq->vr[VerifyReq->nReq].BCount = len; + VerifyReq->nReq++; + if(max_len < len) { + max_len = len; + } + + if((VerifyReq->nReq >= MAX_VREQ_RANGES) || (i == 1)) { + + VerifyReq->Buffer = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, max_len * Vcb->BlockSize, 'bNWD'); + if(VerifyReq->Buffer) { + InterlockedIncrement((PLONG)&(VerifyCtx->QueuedCount)); +#ifndef _CONSOLE + ExInitializeWorkItem( &(VerifyReq->VerifyItem), + (PWORKER_THREAD_ROUTINE) UDFVWorkItem, + VerifyReq ); + ExQueueWorkItem( &(VerifyReq->VerifyItem), CriticalWorkQueue ); +#else + UDFVWorkItem(VerifyReq); +#endif + } else { + DbgFreePool(VerifyReq); + } + VerifyReq = NULL; + max_len = 0; + } else { + } + } + len = 1; + prev_lba = vItem->lba; + do_vrf = FALSE; + } + i--; + } + + if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) { + UDFReleaseResource(&(VerifyCtx->VerifyLock)); + } + if(Flags & UFD_VERIFY_FLAG_WAIT) { +wait: + KdPrint(("UDFVVerify: wait for completion\n")); + UDFVWaitQueued(VerifyCtx); + } + + return; +} // end UDFVVerify() + +VOID +UDFVFlush( + IN PVCB Vcb + ) +{ + PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx; + + if(!VerifyCtx->VInited) { + return; + } + + KdPrint(("UDFVFlush: wait for completion\n")); + UDFVWaitQueued(VerifyCtx); + + UDFVVerify(Vcb, UFD_VERIFY_FLAG_FORCE); + + KdPrint(("UDFVFlush: wait for completion (2)\n")); + UDFVWaitQueued(VerifyCtx); +} // end UDFVFlush() + +BOOLEAN +__fastcall +UDFCheckArea( + IN PVCB Vcb, + IN lba_t LBA, + IN uint32 BCount + ) +{ + uint8* buff; + OSSTATUS RC; + uint32 ReadBytes; + uint32 i, d; + BOOLEAN ext_ok = TRUE; + EXTENT_MAP Map[2]; + uint32 PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits; + + buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' ); + if(buff) { + for(i=0; iBlockSizeBits, + LBA+i, + &ReadBytes, + PH_TMP_BUFFER); + + if(RC != STATUS_SUCCESS) { + Map[0].extLocation = LBA+i; + Map[0].extLength = d << Vcb->BlockSizeBits; + UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(Map[0]), AS_DISCARDED | AS_BAD); // free + ext_ok = FALSE; + } + } + DbgFreePool(buff); + } + return ext_ok; +} // end UDFCheckArea() + +/* + This routine remaps sectors from bad packet + */ +OSSTATUS +__fastcall +UDFRemapPacket( + IN PVCB Vcb, + IN uint32 Lba, + IN BOOLEAN RemapSpared + ) +{ + uint32 i, max, BS, orig; + PSPARING_MAP Map; + BOOLEAN verified = FALSE; + + if(Vcb->SparingTable) { + + max = Vcb->SparingCount; + BS = Vcb->SparingBlockSize; + + // use sparing table for relocation + if(Vcb->SparingCountFree == -1) { + KdPrint(("calculate free spare areas\n")); +re_check: + KdPrint(("verify spare area\n")); + Vcb->SparingCountFree = 0; + Map = Vcb->SparingTable; + for(i=0;iorigLocation == SPARING_LOC_AVAILABLE) { + if(UDFCheckArea(Vcb, Map->mappedLocation, BS)) { + Vcb->SparingCountFree++; + } else { + KdPrint(("initial check: bad spare block @ %x\n", Map->mappedLocation)); + Map->origLocation = SPARING_LOC_CORRUPTED; + Vcb->SparingTableModified = TRUE; + } + } + } + } + if(!Vcb->SparingCountFree) { + KdPrint(("sparing table full\n")); + return STATUS_DISK_FULL; + } + + Map = Vcb->SparingTable; + Lba &= ~(BS-1); + for(i=0;iorigLocation; + if(Lba == (orig & ~(BS-1)) ) { + // already remapped + + KdPrint(("remap remapped: bad spare block @ %x\n", Map->mappedLocation)); + if(!verified) { + verified = TRUE; + goto re_check; + } + + if(!RemapSpared) { + return STATUS_SHARING_VIOLATION; + } else { + // look for another remap area + Map->origLocation = SPARING_LOC_CORRUPTED; + Vcb->SparingTableModified = TRUE; + Vcb->SparingCountFree--; + break; + } + } + } + Map = Vcb->SparingTable; + for(i=0;iorigLocation == SPARING_LOC_AVAILABLE) { + KdPrint(("remap %x -> %x\n", Lba, Map->mappedLocation)); + Map->origLocation = Lba; + Vcb->SparingTableModified = TRUE; + Vcb->SparingCountFree--; + return STATUS_SUCCESS; + } + } + KdPrint(("sparing table full\n")); + return STATUS_DISK_FULL; + } + return STATUS_UNSUCCESSFUL; +} // end UDFRemapPacket() + +/* + This routine releases sector mapping when entire packet is marked as free + */ +OSSTATUS +__fastcall +UDFUnmapRange( + IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BCount + ) +{ + uint32 i, max, BS, orig; + PSPARING_MAP Map; + + if(Vcb->SparingTable) { + // use sparing table for relocation + + max = Vcb->SparingCount; + BS = Vcb->SparingBlockSize; + Map = Vcb->SparingTable; + for(i=0;iorigLocation; + switch(orig) { + case SPARING_LOC_AVAILABLE: + case SPARING_LOC_CORRUPTED: + continue; + } + if(orig >= Lba && + (orig+BS) <= (Lba+BCount)) { + // unmap + KdPrint(("unmap %x -> %x\n", orig, Map->mappedLocation)); + Map->origLocation = SPARING_LOC_AVAILABLE; + Vcb->SparingTableModified = TRUE; + Vcb->SparingCountFree++; + } + } + } + return STATUS_SUCCESS; +} // end UDFUnmapRange() + +/* + This routine returns physical address for relocated sector + */ +uint32 +__fastcall +UDFRelocateSector( + IN PVCB Vcb, + IN uint32 Lba + ) +{ + uint32 i, max, BS, orig; + + if(Vcb->SparingTable) { + // use sparing table for relocation + uint32 _Lba; + PSPARING_MAP Map = Vcb->SparingTable; + + max = Vcb->SparingCount; + BS = Vcb->SparingBlockSize; + _Lba = Lba & ~(BS-1); + for(i=0;iorigLocation; + if(_Lba == (orig & ~(BS-1)) ) { + //if( (Lba >= (orig = Map->origLocation)) && (Lba < orig + BS) ) { + return Map->mappedLocation + Lba - orig; + } + } + } else if(Vcb->Vat) { + // use VAT for relocation + uint32* Map = Vcb->Vat; + uint32 root; + // check if given Lba lays in the partition covered by VAT + if(Lba >= Vcb->NWA) + return Vcb->NWA; + if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot)) + return Lba; + Map = &(Vcb->Vat[(i = Lba - root)]); + if((i < Vcb->VatCount) && (i=(*Map)) ) { + if(i != UDF_VAT_FREE_ENTRY) { + return i + root; + } else { + return 0x7fffffff; + } + } + } + return Lba; +} // end UDFRelocateSector() + +/* + This routine checks if the extent specified requires relocation + */ +BOOLEAN +__fastcall +UDFAreSectorsRelocated( + IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BlockCount + ) +{ + + if(Vcb->SparingTable) { + // use sparing table for relocation + uint32 i, BS, orig; + BS = Vcb->SparingBlockSize; + PSPARING_MAP Map; + + Map = Vcb->SparingTable; + for(i=0;iSparingCount;i++,Map++) { + if( ((Lba >= (orig = Map->origLocation)) && (Lba < orig + BS)) || + ((Lba+BlockCount-1 >= orig) && (Lba+BlockCount-1 < orig + BS)) || + ((orig >= Lba) && (orig < Lba+BlockCount)) || + ((orig+BS >= Lba) && (orig+BS < Lba+BlockCount)) ) { + return TRUE; + } + } + } else if(Vcb->Vat) { + // use VAT for relocation + uint32 i, root, j; + uint32* Map; + if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot)) + return FALSE; + if(Lba+BlockCount >= Vcb->NWA) + return TRUE; + Map = &(Vcb->Vat[Lba-root/*+i*/]); + for(i=0; iLastLBA))) + return TRUE; + } + } + return FALSE; +} // end UDFAreSectorsRelocated() + +/* + This routine builds mapping for relocated extent + If relocation is not required (-1) will be returned + */ +PEXTENT_MAP +__fastcall +UDFRelocateSectors( + IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BlockCount + ) +{ + if(!UDFAreSectorsRelocated(Vcb, Lba, BlockCount)) return UDF_NO_EXTENT_MAP; + + PEXTENT_MAP Extent=NULL, Extent2; + uint32 NewLba, LastLba, j, i; + EXTENT_AD locExt; + + LastLba = UDFRelocateSector(Vcb, Lba); + for(i=0, j=1; iBlockSizeBits; + locExt.extLocation = LastLba-j+1; + Extent2 = UDFExtentToMapping(&locExt); + if(!Extent) { + Extent = Extent2; + } else { + Extent = UDFMergeMappings(Extent, Extent2); + MyFreePool__(Extent2); + } + if(!Extent) return NULL; + j = 0; + } + LastLba = NewLba; + } + return Extent; +} // end UDFRelocateSectors() + diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf.h b/reactos/drivers/filesystems/udfs/udf_info/udf.h new file mode 100644 index 00000000000..12ef4842b55 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf.h @@ -0,0 +1,8 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#include "Include\platform.h" +#include "udffs.h" +#include "NameSup.h" diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf_info.cpp b/reactos/drivers/filesystems/udfs/udf_info/udf_info.cpp new file mode 100644 index 00000000000..255bbd98294 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf_info.cpp @@ -0,0 +1,5591 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + Module name: + + udf_info.cpp + + Abstract: + + This file contains filesystem-specific routines + +*/ + +#include "udf.h" + +#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO + +#ifdef _X86_ +static const int8 valid_char_arr[] = + {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, + 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, + 1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1, + 0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // @ABCDE.... + 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0, // ....Z[/]^_ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // `abcde.... + 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1, // ....z{|}~ + + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; +#else // NO X86 optimization , use generic C/C++ +static const char valid_char_arr[] = {"*/:?\"<>|\\"}; +#endif // _X86_ + +#define DOS_CRC_MODULUS 41 +#define hexChar crcChar +static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@"; + +/* Used to convert hex digits to ASCII for readability. */ +//static const char hexChar[] = "0123456789ABCDEF"; + +static const uint16 CrcTable[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, + 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, + 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, + 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, + 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, + 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, + 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, + 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, + 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, + 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, + 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, + 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, + 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, + 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, + 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, + 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, + 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, + 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, + 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, + 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, + 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, + 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, + 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U +}; + +static const uint32 crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* + This routine allocates new memory block, copies data there & free old one +*/ +/*uint32 +UDFMemRealloc( + int8* OldBuff, + uint32 OldLength, + int8** NewBuff, + uint32 NewLength + ) +{ + int8* new_buff; + + (*NewBuff) = OldBuff; + if(OldLength == NewLength) return OldLength; + new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength); + if(!new_buff) return 0; + if(OldLength > NewLength) OldLength = NewLength; + RtlCopyMemory(new_buff, OldBuff, OldLength); + MyFreePool__(OldBuff); + (*NewBuff) = new_buff; + return OldLength; +} // end UDFMemRealloc()*/ + +/* + This routine converts compressed Unicode to standard + */ +void +__fastcall +UDFDecompressUnicode( + IN OUT PUNICODE_STRING UName, + IN uint8* CS0, + IN uint32 Length, + OUT uint16* valueCRC + ) +{ + uint16 compID = CS0[0]; + uint32 unicodeIndex = 0; + uint32 byteIndex = 1; + PWCHAR buff; + uint8* _CS0 = CS0+1; + + if(!Length) goto return_empty_str; + // First check for valid compID. + switch(compID) { + case UDF_COMP_ID_8: { + + buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length)*sizeof(WCHAR), MEM_FNAME_TAG); + if(!buff) goto return_empty_str; + UName->Buffer = buff; + + // Loop through all the bytes. + while (byteIndex < Length) { + (*buff) = (*_CS0); + _CS0++; + byteIndex++; + buff++; + } + unicodeIndex = byteIndex-1; + break; + } + case UDF_COMP_ID_16: { + + buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length-1)+sizeof(WCHAR), MEM_FNAME16_TAG); + if(!buff) goto return_empty_str; + UName->Buffer = buff; + + // Loop through all the bytes. + while (byteIndex < Length) { + // Move the first byte to the high bits of the unicode char. + *buff = ((*_CS0) << 8) | (*(_CS0+1)); + _CS0+=2; + byteIndex+=2; + unicodeIndex++; + buff++; + ASSERT(byteIndex <= Length); + } + break; + } + default: { +return_empty_str: + UName->Buffer = NULL; + UName->MaximumLength = + UName->Length = 0; + return; + } + } + UName->MaximumLength = (UName->Length = (((uint16)unicodeIndex)*sizeof(WCHAR))) + sizeof(WCHAR); + UName->Buffer[unicodeIndex] = 0; + if(valueCRC) { + *valueCRC = UDFCrc(CS0+1, Length-1); + } +} // end UDFDecompressUnicode() + +/* + This routine converts standard Unicode to compressed + */ +void +__fastcall +UDFCompressUnicode( + IN PUNICODE_STRING UName, + IN OUT uint8** _CS0, + IN OUT uint32* Length + ) +{ + uint8* CS0; + uint8 compID; + uint16 unicodeIndex; + uint32 i, len; + PWCHAR Buff; + + len = (UName->Length) / sizeof(WCHAR); + compID = (!len) ? 0 : UDF_COMP_ID_8; + // check for uncompressable characters + Buff = UName->Buffer; + for(i=0; iBuffer; + if(compID == UDF_COMP_ID_16) { + // Loop through all the bytes. + while (unicodeIndex < len) { + // Move the 2nd byte to the low bits of the compressed unicode char. + *CS0 = (uint8)((*Buff) >> 8); + CS0++; + *CS0 = (uint8)(*Buff); + CS0++; + Buff++; + unicodeIndex++; + } + } else { + // Loop through all the bytes. + while (unicodeIndex < len) { + *CS0 = (uint8)(*Buff); + CS0++; + Buff++; + unicodeIndex++; + } + } +} // end UDFCompressUnicode() + +/* +OSSTATUS UDFFindFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN PUNICODE_STRING Name, + IN PUDF_FILE_INFO DirInfo) + see 'Udf_info.h' +*/ + +/* + This routine reads (Extended)FileEntry according to FileDesc + */ +OSSTATUS +UDFReadFileEntry( + IN PVCB Vcb, + IN long_ad* Icb, + IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry + IN OUT uint16* Ident + ) +{ + OSSTATUS status; + + if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry, + UDFPartLbaToPhys(Vcb,&(Icb->extLocation)), + Icb->extLocation.logicalBlockNum, + Ident))) return status; + if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) && + (FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) { + KdPrint((" Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent)); + return STATUS_FILE_CORRUPT_ERROR; + } + return STATUS_SUCCESS; +} // UDFReadFileEntry() + +//#ifndef _X86_ +#ifndef _MSC_VER +/* + Decides if a Unicode character matches one of a list + of ASCII characters. + Used by DOS version of UDFIsIllegalChar for readability, since all of the + illegal characters above 0x0020 are in the ASCII subset of Unicode. + Works very similarly to the standard C function strchr(). + */ +BOOLEAN +UDFUnicodeInString( + IN uint8* string, // String to search through. + IN WCHAR ch // Unicode char to search for. + ) +{ + BOOLEAN found = FALSE; + + while(*string != '\0' && !found) { + // These types should compare, since both are unsigned numbers. + if(*string == ch) { + found = TRUE; + } + string++; + } + return(found); +} // end UDFUnicodeInString() +#endif // _X86_ + +/* + Decides whether character passed is an illegal character for a + DOS file name. +*/ +#pragma warning(push) +#pragma warning(disable:4035) // re-enable below + +#ifdef _X86_ +__declspec (naked) +#endif // _X86_ +BOOLEAN +__fastcall +UDFIsIllegalChar( + IN WCHAR chr // ECX + ) +{ + // Genuine illegal char's for DOS. +//#ifdef _X86_ +#ifdef _MSC_VER + _asm { + push ebx + + xor eax,eax +// mov ax,chr + mov ax,cx + or ah,ah + jnz ERR_IIC + + lea ebx,[valid_char_arr] + xlatb + jmp short ERR_IIC2 +ERR_IIC: + mov al,1 +ERR_IIC2: + + pop ebx + ret + } + +#else // NO X86 optimization , use generic C/C++ + /* FIXME */ + //return ((ch < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, ch)); + return ((chr < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, chr)); +#endif // _X86_ +} // end UDFIsIllegalChar() + +#pragma warning(pop) // re-enable warning #4035 + +/* + Translate udfName to dosName using OSTA compliant. + dosName must be a unicode string with min length of 12. + */ + +/*void UDFDOSName__( + IN PVCB Vcb, + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN PUDF_FILE_INFO FileInfo + ) +{ + BOOLEAN KeepIntact; + + KeepIntact = (FileInfo && (FileInfo->Index < 2)); + UDFDOSName(Vcb, DosName, UdfName, KeepIntact); +}*/ + +void +__fastcall +UDFDOSName( + IN PVCB Vcb, + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact + ) +{ +#ifndef _CONSOLE + if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) { + UDFDOSNameOsNative(DosName, UdfName, KeepIntact); + return; + } +#endif //_CONSOLE + + switch(Vcb->CurrentUDFRev) { + case 0x0100: + case 0x0101: + case 0x0102: + UDFDOSName100(DosName, UdfName, KeepIntact); + break; + + case 0x0150: + // in general, we need bytes-from-media to + // create valid UDF 1.50 name. + // Curently it is impossible, thus, we'll use + // UDF 2.00 translation algorithm + case 0x0200: + UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150); + break; + + case 0x0201: + default: + UDFDOSName201(DosName, UdfName, KeepIntact); + } +} + +void +__fastcall +UDFDOSName100( + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact + ) +{ + PWCHAR dosName = DosName->Buffer; + PWCHAR udfName = UdfName->Buffer; + uint32 udfLen = UdfName->Length / sizeof(WCHAR); + + uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex; + BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE; + uint32 valueCRC; + WCHAR ext[DOS_EXT_LEN], current; + + if(KeepIntact && + (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { + isParent = TRUE; + if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) + isParent = FALSE; + } + + for (index = 0 ; index < udfLen ; index++) { + current = udfName[index]; + if (current == UNICODE_PERIOD && !isParent) { + if (dosIndex==0 || hasExt) { + // Ignore leading periods or any other than used for extension. + needsCRC = TRUE; + } else { + // First, find last character which is NOT a period or space. + lastPeriodIndex = udfLen - 1; + while(lastPeriodIndex >=0 && + (udfName[lastPeriodIndex] == UNICODE_PERIOD || + udfName[lastPeriodIndex] == UNICODE_SPACE)) + lastPeriodIndex--; + // Now search for last remaining period. + while(lastPeriodIndex >= 0 && + udfName[lastPeriodIndex] != UNICODE_PERIOD) + lastPeriodIndex--; + // See if the period we found was the last or not. + if (lastPeriodIndex != index) + needsCRC = TRUE; // If not, name needs translation. + // As long as the period was not trailing, + // the file name has an extension. + if (lastPeriodIndex >= 0) hasExt = TRUE; + } + } else { + if ((!hasExt && dosIndex == DOS_NAME_LEN) || + extIndex == DOS_EXT_LEN) { + // File name or extension is too long for DOS. + needsCRC = TRUE; + } else { + if (current == UNICODE_SPACE) { // Ignore spaces. + needsCRC = TRUE; + } else { + // Look for illegal or unprintable characters. + if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) { + needsCRC = TRUE; + current = ILLEGAL_CHAR_MARK; + /* Skip Illegal characters(even spaces), + * but not periods. + */ + while(index+1 < udfLen && + (UDFIsIllegalChar(udfName[index+1]) /*|| + !UnicodeIsPrint(udfName[index+1])*/) && + udfName[index+1] != UNICODE_PERIOD) + index++; + } + // Add current char to either file name or ext. + if (writingExt) { + ext[extIndex] = current; + extIndex++; + } else { + dosName[dosIndex] = current; + dosIndex++; + } + } + } + } + // See if we are done with file name, either because we reached + // the end of the file name length, or the final period. + if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN || + index == lastPeriodIndex)) { + // If so, and the name has an extension, start reading it. + writingExt = TRUE; + // Extension starts after last period. + index = lastPeriodIndex; + } + } + // + if (needsCRC) { + // Add CRC to end of file name or at position 4. + if (dosIndex >4) dosIndex = 4; + valueCRC = UDFUnicodeCksum(udfName, udfLen); + // set CRC prefix + dosName[dosIndex] = UNICODE_CRC_MARK; + // Convert 12-bit CRC to hex characters. + dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8]; + dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4]; + dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)]; + dosIndex+=4; + } + // Add extension, if any. + if (extIndex != 0) { + dosName[dosIndex] = UNICODE_PERIOD; + dosIndex++; + for (index = 0; index < extIndex; index++) { + dosName[dosIndex] = ext[index]; + dosIndex++; + } + } + DosName->Length = (uint16)dosIndex*sizeof(WCHAR); + RtlUpcaseUnicodeString(DosName, DosName, FALSE); +} // end UDFDOSName100() + +void +__fastcall +UDFDOSName200( + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact, + IN BOOLEAN Mode150 + ) +{ + PWCHAR dosName = DosName->Buffer; + PWCHAR udfName = UdfName->Buffer; + uint32 udfLen = UdfName->Length / sizeof(WCHAR); + + uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex; + BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE; + uint32 valueCRC; + WCHAR ext[DOS_EXT_LEN], current; + + if(KeepIntact && + (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { + isParent = TRUE; + if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) + isParent = FALSE; + } + + for (index = 0 ; index < udfLen ; index++) { + current = udfName[index]; + if (current == UNICODE_PERIOD && !isParent) { + if (dosIndex==0 || hasExt) { + // Ignore leading periods or any other than used for extension. + needsCRC = TRUE; + } else { + // First, find last character which is NOT a period or space. + lastPeriodIndex = udfLen - 1; + while(lastPeriodIndex >=0 && + (udfName[lastPeriodIndex] == UNICODE_PERIOD || + udfName[lastPeriodIndex] == UNICODE_SPACE)) + lastPeriodIndex--; + // Now search for last remaining period. + while(lastPeriodIndex >= 0 && + udfName[lastPeriodIndex] != UNICODE_PERIOD) + lastPeriodIndex--; + // See if the period we found was the last or not. + if (lastPeriodIndex != index) + needsCRC = TRUE; // If not, name needs translation. + // As long as the period was not trailing, + // the file name has an extension. + if (lastPeriodIndex >= 0) hasExt = TRUE; + } + } else { + if ((!hasExt && dosIndex == DOS_NAME_LEN) || + extIndex == DOS_EXT_LEN) { + // File name or extension is too long for DOS. + needsCRC = TRUE; + } else { + if (current == UNICODE_SPACE) { // Ignore spaces. + needsCRC = TRUE; + } else { + // Look for illegal or unprintable characters. + if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) { + needsCRC = TRUE; + current = ILLEGAL_CHAR_MARK; + /* Skip Illegal characters(even spaces), + * but not periods. + */ + while(index+1 < udfLen && + (UDFIsIllegalChar(udfName[index+1]) /*|| + !UnicodeIsPrint(udfName[index+1])*/) && + udfName[index+1] != UNICODE_PERIOD) + index++; + } + // Add current char to either file name or ext. + if (writingExt) { + ext[extIndex] = current; + extIndex++; + } else { + dosName[dosIndex] = current; + dosIndex++; + } + } + } + } + // See if we are done with file name, either because we reached + // the end of the file name length, or the final period. + if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN || + index == lastPeriodIndex)) { + // If so, and the name has an extension, start reading it. + writingExt = TRUE; + // Extension starts after last period. + index = lastPeriodIndex; + } + } + // Now handle CRC if needed. + if (needsCRC) { + // Add CRC to end of file name or at position 4. + if (dosIndex >4) dosIndex = 4; + valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen); + // Convert 16-bit CRC to hex characters. + dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12]; + dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8]; + dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4]; + dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)]; + dosIndex+=4; + } + // Add extension, if any. + if (extIndex != 0) { + dosName[dosIndex] = UNICODE_PERIOD; + dosIndex++; + for (index = 0; index < extIndex; index++) { + dosName[dosIndex] = ext[index]; + dosIndex++; + } + } + DosName->Length = (uint16)dosIndex*sizeof(WCHAR); + RtlUpcaseUnicodeString(DosName, DosName, FALSE); +} // end UDFDOSName200() + + +void +__fastcall +UDFDOSName201( + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact + ) +{ + PWCHAR dosName = DosName->Buffer; + PWCHAR udfName = UdfName->Buffer; + uint16 udfLen = UdfName->Length / sizeof(WCHAR); + + uint16 index, dosIndex = 0; + //uint16 extIndex = 0; + BOOLEAN needsCRC = FALSE, isParent = FALSE; + //BOOLEAN hasExt = FALSE, writingExt = FALSE; + uint16 valueCRC; + WCHAR ext[DOS_EXT_LEN]; + WCHAR current; + + if(KeepIntact && + (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { + isParent = TRUE; + if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) + isParent = FALSE; + } + + #define DOS_CRC_LEN 4 + #define DOS_CRC_MODULUS 41 + + int16 crcIndex; + uint16 extLen; + uint16 nameLen; + uint16 charLen; + int16 overlayBytes; + int16 bytesLeft; + + /* Start at the end of the UDF file name and scan for a period */ + /* ('.'). This will be where the DOS extension starts (if */ + /* any). */ + index = udfLen; + while (index-- > 0) { + if (udfName[index] == '.') + break; + } + if ((index < 0) || isParent) { + /* There name was scanned to the beginning of the buffer */ + /* and no extension was found. */ + extLen = 0; + nameLen = udfLen; + } else { + /* A DOS extension was found, process it first. */ + extLen = udfLen - index - 1; + nameLen = index; + dosIndex = 0; + bytesLeft = DOS_EXT_LEN; + while (++index < udfLen && bytesLeft > 0) { + /* Get the current character and convert it to upper */ + /* case. */ + current = udfName[index]; + if (current == ' ') { + /* If a space is found, a CRC must be appended to */ + /* the mangled file name. */ + needsCRC = TRUE; + } else { + /* Determine if this is a valid file name char and */ + /* calculate its corresponding BCS character byte */ + /* length (zero if the char is not legal or */ + /* undisplayable on this system). */ + + charLen = (UDFIsIllegalChar(current) + /*|| !UnicodeIsPrint(current)*/) ? 0 : 1; + + /* If the char is larger than the available space */ + /* in the buffer, pretend it is undisplayable. */ + if (charLen > bytesLeft) + charLen = 0; + if (charLen == 0) { + /* Undisplayable or illegal characters are */ + /* substituted with an underscore ("_"), and */ + /* required a CRC code appended to the mangled */ + /* file name. */ + needsCRC = TRUE; + charLen = 1; + current = '_'; + /* Skip over any following undiplayable or */ + /* illegal chars. */ + while (index +1 0) { + /* Get the current character and convert it to upper case. */ + current = udfName[index]; + if (current ==' ' || (current == '.' && !isParent) ) { + /* Spaces and periods are just skipped, a CRC code */ + /* must be added to the mangled file name. */ + needsCRC = TRUE; + } else { + /* Determine if this is a valid file name char and */ + /* calculate its corresponding BCS character byte */ + /* length (zero if the char is not legal or */ + /* undisplayable on this system). */ + + charLen = (UDFIsIllegalChar(current) + /*|| !UnicodeIsPrint(current)*/) ? 0 : 1; + + /* If the char is larger than the available space in */ + /* the buffer, pretend it is undisplayable. */ + if (charLen > bytesLeft) + charLen = 0; + + if (charLen == 0) { + /* Undisplayable or illegal characters are */ + /* substituted with an underscore ("_"), and */ + /* required a CRC code appended to the mangled */ + /* file name. */ + needsCRC = TRUE; + charLen = 1; + current = '_'; + /* Skip over any following undisplayable or illegal */ + /* chars. */ + while (index +1 = nameLen) + break; + } + /* Assign the resulting char to the next index in the */ + /* file name buffer and determine how many BCS bytes */ + /* are left. */ + dosName[dosIndex++] = current; + bytesLeft -= charLen; + /* This figures out where the CRC code needs to start */ + /* in the file name buffer. */ + if (bytesLeft >= DOS_CRC_LEN) { + /* If there is enough space left, just tack it */ + /* onto the end. */ + crcIndex = dosIndex; + } else { + /* If there is not enough space left, the CRC */ + /* must overlay a character already in the file */ + /* name buffer. Once this condition has been */ + /* met, the value will not change. */ + if (overlayBytes < 0) { + /* Determine the index and save the length of */ + /* the BCS character that is overlayed. It */ + /* is possible that the CRC might overlay */ + /* half of a two-byte BCS character depending */ + /* upon how the character boundaries line up. */ + overlayBytes = (bytesLeft + charLen > DOS_CRC_LEN)?1 :0; + crcIndex = dosIndex - 1; + } + } + } + /* Advance to the next character. */ + index++; + } + /* If the scan did not reach the end of the file name, or the */ + /* length of the file name is zero, a CRC code is needed. */ + if (index < nameLen || index == 0) + needsCRC = TRUE; + + /* If the name has illegal characters or and extension, it */ + /* is not a DOS device name. */ + +/* if (needsCRC == FALSE && extLen == 0) { + /* If this is the name of a DOS device, a CRC code should */ + /* be appended to the file name. + if (IsDeviceName(udfName, udfLen)) + needsCRC = TRUE; + }*/ + + /* Append the CRC code to the file name, if needed. */ + if (needsCRC) { + /* Get the CRC value for the original Unicode string */ + valueCRC = UDFUnicodeCksum(udfName, udfLen); + + /* begin. */ + dosIndex = crcIndex; + /* If the character being overlayed is a two-byte BCS */ + /* character, replace the first byte with an underscore. */ + if (overlayBytes > 0) + dosName[dosIndex++] = '_'; + /* Append the encoded CRC value with delimiter. */ + dosName[dosIndex++] = '#'; + dosName[dosIndex++] = + crcChar[valueCRC / (DOS_CRC_MODULUS * DOS_CRC_MODULUS)]; + valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS; + dosName[dosIndex++] = + crcChar[valueCRC / DOS_CRC_MODULUS]; + valueCRC %= DOS_CRC_MODULUS; + dosName[dosIndex++] = crcChar[valueCRC]; + } + /* Append the extension, if any. */ + if (extLen > 0) { + /* Tack on a period and each successive byte in the */ + /* extension buffer. */ + dosName[dosIndex++] = '.'; + for (index = 0; index < extLen; index++) + dosName[dosIndex++] = ext[index]; + } + /* Return the length of the resulting Unicode string. */ + DosName->Length = (uint16)dosIndex*sizeof(WCHAR); + RtlUpcaseUnicodeString(DosName, DosName, FALSE); + +} // end UDFDOSName201() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine initializes Tag structure. It must be called after all + manual settings to generate valid CRC & Checksum + */ +void +UDFSetUpTag( + IN PVCB Vcb, + IN tag* Tag, + IN uint16 DataLen, // total length of descriptor _including_ icbTag + IN uint32 TagLoc + ) +{ + uint32 i; + int8* tb; + + AdPrint(("UDF: SetTag Loc=%x(%x), tagIdent=%x\n", TagLoc, Tag->tagLocation, Tag->tagIdent)); + + if(DataLen) DataLen -= sizeof(tag); +// int8* Data = ((int8*)Tag) + sizeof(tag); + // Ecma-167 states, that all implementations + // shall set this field to '3' even if + // disc contains descriptors recorded with + // value '2' + // But we should ignore this to make happy othe UDF implementations :( + Tag->descVersion = (Vcb->NSRDesc & VRS_NSR03_FOUND) ? 3 : 2; + Tag->tagLocation = TagLoc; + Tag->tagSerialNum = (uint16)(Vcb->SerialNumber + 1); + Tag->descCRCLength = DataLen; + Tag->descCRC = UDFCrc((uint8*)(Tag+1), DataLen); + Tag->tagChecksum = 0; + tb = ((int8*)Tag); + for (i=0; itagChecksum += (i!=4) ? (*tb) : 0; +} // end UDFSetUpTag() + +/* + This routine builds FileEntry & associated AllocDescs for specified + extent. + */ +OSSTATUS +UDFBuildFileEntry( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum, + IN uint16 AllocMode, // short/long/ext/in-icb + IN uint32 ExtAttrSz, + IN BOOLEAN Extended + ) +{ + PFILE_ENTRY FileEntry; + OSSTATUS status; + EntityID* eID; + uint32 l; + EXTENT_INFO _FEExtInfo; + uint16* lcp; + + ASSERT(!PartNum); + ASSERT(!ExtAttrSz); + // calculate the length required + l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz; + if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER; + // allocate block for FE + if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) )) + return status; + // remember FE location for future hard link creation + ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1)); + if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) { + ASSERT(status != STATUS_SHARING_PAUSED); + UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free + MyFreePool__(_FEExtInfo.Mapping); + return status; + } + FileEntry = (PFILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l, MEM_FE_TAG); + if(!FileEntry) { + UDFRemoveDloc(Vcb, FileInfo->Dloc); + FileInfo->Dloc = NULL; + UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free + MyFreePool__(_FEExtInfo.Mapping); + return STATUS_INSUFFICIENT_RESOURCES; + } + FileInfo->Dloc->FELoc = _FEExtInfo; + + RtlZeroMemory((int8*)FileEntry, l); + // set up in-memory FE structure + FileEntry->icbTag.flags = AllocMode; + FileEntry->icbTag.fileType = UDF_FILE_TYPE_REGULAR; + FileEntry->icbTag.numEntries = 1; +// if(DirInfo && DirInfo->Dloc && DirInfo->Dloc + FileEntry->icbTag.strategyType = 4; +// FileEntry->icbTag.strategyParameter = 0; + FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY; + FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation); + FileEntry->uid = Vcb->DefaultUID; + FileEntry->gid = Vcb->DefaultGID; + + if(Extended) { + eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent); + lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount); + ((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1; + } else { + eID = &(FileEntry->impIdent); + lcp = &(FileEntry->fileLinkCount); + ((PFILE_ENTRY)FileEntry)->checkpoint = 1; + } + +#if 0 + UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER); +#endif + + /*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) ); + iis = (impIdentSuffix*)&(eID->identSuffix); + iis->OSClass = UDF_OS_CLASS_WINNT; + iis->OSIdent = UDF_OS_ID_WINNT;*/ + + *lcp = 0xffff; + + FileInfo->Dloc->FileEntry = (tag*)FileEntry; + FileInfo->Dloc->FileEntryLen = l; + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + + return STATUS_SUCCESS; +} // end UDFBuildFileEntry() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine builds ExtentInfo for specified (Ex)FileEntry & associated + AllocDescs + */ +OSSTATUS +UDFLoadExtInfo( + IN PVCB Vcb, + IN PFILE_ENTRY fe, + IN PLONG_AD fe_loc, + IN OUT PEXTENT_INFO FExtInfo, // user data + IN OUT PEXTENT_INFO AExtInfo // alloc descs + ) +{ + EXTENT_AD TmpExt; + + KdPrint((" UDFLoadExtInfo:\n")); + FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum, + (tag*)fe, &(FExtInfo->Offset), AExtInfo); + if(!(FExtInfo->Mapping)) { + if(!(FExtInfo->Offset)) + return STATUS_UNSUCCESSFUL; + TmpExt.extLength = fe_loc->extLength; + TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation)); + if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) + return STATUS_FILE_CORRUPT_ERROR; + FExtInfo->Mapping = UDFExtentToMapping(&TmpExt); + } + if(fe->descTag.tagIdent == TID_FILE_ENTRY) { +// KdPrint(("Standard FileEntry\n")); + FExtInfo->Length = fe->informationLength; + } else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ { + FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength; + } + KdPrint((" FExtInfo->Length %x\n", FExtInfo->Length)); + ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping)); + FExtInfo->Modified = FALSE; + + return STATUS_SUCCESS; +} // end UDFLoadExtInfo() + +/* + This routine builds FileIdent for specified FileEntry. + We shall call UDFSetUpTag after all other initializations + This structure is a precise copy of on-disk FileIdent + structure. All modifications of it (including memory block + size) are reflected on Directory extent. This, allocation of + too long block (without changes in ImpUseLen) will lead to + unreadable Directory + */ +OSSTATUS +UDFBuildFileIdent( + IN PVCB Vcb, + IN PUNICODE_STRING fn, + IN PLONG_AD FileEntryIcb, // virtual address of FileEntry + IN uint32 ImpUseLen, + OUT PFILE_IDENT_DESC* _FileId, + OUT uint32* FileIdLen + ) +{ + PFILE_IDENT_DESC FileId; + uint8* CS0; + uint32 Nlen, l; + // prepare filename + UDFCompressUnicode(fn, &CS0, &Nlen); + if(!CS0) return STATUS_INSUFFICIENT_RESOURCES; + if(Nlen < 2) { + Nlen = 0; + } else + if(Nlen > UDF_NAME_LEN) { + if(CS0) MyFreePool__(CS0); + return STATUS_OBJECT_NAME_INVALID; + } + // allocate memory for FI + l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3); + FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG); + if(!FileId) { + if(CS0) MyFreePool__(CS0); + return STATUS_INSUFFICIENT_RESOURCES; + } + // fill FI structure + RtlZeroMemory( (int8*)FileId, l); + RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen); + FileId->descTag.tagIdent = TID_FILE_IDENT_DESC; + FileId->fileVersionNum = 1; + FileId->lengthOfImpUse = (uint16)ImpUseLen; + FileId->lengthFileIdent = (uint8)Nlen; + FileId->icb = *FileEntryIcb; + *_FileId = FileId; + *FileIdLen = l; + + if(CS0) MyFreePool__(CS0); + return STATUS_SUCCESS; +} // end UDFBuildFileIdent() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine sets informationLength field in (Ext)FileEntry + */ +void +UDFSetFileSize( + IN PUDF_FILE_INFO FileInfo, + IN int64 Size + ) +{ + uint16 Ident; +// PDIR_INDEX_ITEM DirIndex; + + ValidateFileInfo(FileInfo); + AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo)); + + //AdPrint((" Dloc %x\n", FileInfo->Dloc)); + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + //AdPrint((" FileEntry %x\n", FileInfo->Dloc->FileEntry)); + Ident = FileInfo->Dloc->FileEntry->tagIdent; + //AdPrint((" Ident %x\n", Ident)); + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + //AdPrint((" fe %x\n", fe)); + fe->informationLength = Size; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + //AdPrint((" ext-fe %x\n", fe)); + fe->informationLength = Size; + } +/* if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) { + DirIndex->FileSize = Size; + }*/ + //AdPrint(("UDFSetFileSize: ok\n")); + return; +} // end UDFSetFileSize() + +void +UDFSetFileSizeInDirNdx( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64* ASize + ) +{ + uint16 Ident; + PDIR_INDEX_ITEM DirIndex; + + ValidateFileInfo(FileInfo); + if(ASize) { + AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize)); + } else { + AdPrint(("UDFSetFileSizeInDirNdx: sync\n")); + } + + DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index); + if(!DirIndex) + return; + + Ident = FileInfo->Dloc->FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + DirIndex->FileSize = fe->informationLength; + if(ASize) { + DirIndex->AllocationSize = *ASize; +// } else { +// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1); + } + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + DirIndex->FileSize = fe->informationLength; + if(ASize) { + DirIndex->AllocationSize = *ASize; +// } else { +// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1); + } + } + return; +} // end UDFSetFileSizeInDirNdx() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine gets informationLength field in (Ext)FileEntry + */ +int64 +UDFGetFileSize( + IN PUDF_FILE_INFO FileInfo + ) +{ + uint16 Ident; + + ValidateFileInfo(FileInfo); + + Ident = FileInfo->Dloc->FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + return fe->informationLength; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + return fe->informationLength; + } + return (-1); +} // end UDFGetFileSize() + +int64 +UDFGetFileSizeFromDirNdx( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + PDIR_INDEX_ITEM DirIndex; + + ValidateFileInfo(FileInfo); + + DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index); + if(!DirIndex) + return -1; + + return DirIndex->FileSize; +} // end UDFGetFileSizeFromDirNdx() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine sets lengthAllocDesc field in (Ext)FileEntry + */ +void +UDFSetAllocDescLen( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + uint16 Ident; + + ValidateFileInfo(FileInfo); + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + if(FileInfo->Dloc->AllocLoc.Length) { + fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - + FileInfo->Dloc->AllocLoc.Offset, + (uint32)(FileInfo->Dloc->AllocLoc.Length)); + } else + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); + } + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + if(FileInfo->Dloc->AllocLoc.Length) { + fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - + FileInfo->Dloc->AllocLoc.Offset, + (uint32)(FileInfo->Dloc->AllocLoc.Length)); + } else + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); + } + } +} // end UDFSetAllocDescLen() + +/* + This routine changes fileLinkCount field in (Ext)FileEntry + */ +void +UDFChangeFileLinkCount( + IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN Increase + ) +{ + uint16 Ident; + + ValidateFileInfo(FileInfo); + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + if(Increase) { + fe->fileLinkCount++; + } else { + fe->fileLinkCount--; + } + if(fe->fileLinkCount & 0x8000) + fe->fileLinkCount = 0xffff; + return; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + if(Increase) { + fe->fileLinkCount++; + } else { + fe->fileLinkCount--; + } + if(fe->fileLinkCount & 0x8000) + fe->fileLinkCount = 0xffff; + return; + } + return; +} // end UDFChangeFileLinkCount() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine gets fileLinkCount field from (Ext)FileEntry + */ +uint16 +UDFGetFileLinkCount( + IN PUDF_FILE_INFO FileInfo + ) +{ + uint16 Ident; + uint16 d; + + ValidateFileInfo(FileInfo); + + if(!FileInfo->Dloc->FileEntry) + return 1; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + // UDF engine assumes that LinkCount is a counter + // of FileIdents, referencing this FE. + // UDF 2.0 states, that it should be counter of ALL + // references (including SDir) - 1. + // Thus we'll write to media UDF-required value, but return + // cooked value to callers + d = UDFHasAStreamDir(FileInfo) ? 0 : 1; + if(Ident == TID_FILE_ENTRY) { + return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d; + } + return UDF_INVALID_LINK_COUNT; +} // end UDFGetFileLinkCount() + +#ifdef UDF_CHECK_UTIL +/* + This routine sets fileLinkCount field in (Ext)FileEntry + */ +void +UDFSetFileLinkCount( + IN PUDF_FILE_INFO FileInfo, + uint16 LinkCount + ) +{ + uint16 Ident; + uint16 d; + + ValidateFileInfo(FileInfo); + + if(!FileInfo->Dloc->FileEntry) + return; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + // UDF engine assumes that LinkCount is a counter + // of FileIdents, referencing this FE. + // UDF 2.0 states, that it should be counter of ALL + // references (including SDir) - 1. + // Thus we'll write to media UDF-required value, but return + // cooked value to callers + d = UDFHasAStreamDir(FileInfo) ? 0 : 1; + if(Ident == TID_FILE_ENTRY) { + ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d; + } + return; +} // end UDFGetFileLinkCount() +#endif //UDF_CHECK_UTIL + +/* + This routine gets lengthExtendedAttr field in (Ext)FileEntry + */ +uint32 +UDFGetFileEALength( + IN PUDF_FILE_INFO FileInfo + ) +{ + uint16 Ident; + + ValidateFileInfo(FileInfo); + + if(!FileInfo->Dloc->FileEntry) + return 1; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + + if(Ident == TID_FILE_ENTRY) { + return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr; + } + return 0; +} // end UDFGetFileEALength() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine sets UniqueID field in (Ext)FileEntry + */ +int64 +UDFAssingNewFUID( + IN PVCB Vcb + ) +{ + Vcb->NextUniqueId++; + if(!((uint32)(Vcb->NextUniqueId))) + Vcb->NextUniqueId += 16; + return Vcb->NextUniqueId; +} + +void +UDFSetFileUID( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + uint16 Ident; + int64 UID; + + ValidateFileInfo(FileInfo); + + UID = UDFAssingNewFUID(Vcb); + +/* UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation | + ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/ + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + Ident = FileInfo->Dloc->FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + fe->uniqueID = UID; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); + fe->uniqueID = UID; + } + if(FileInfo->FileIdent) + ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID; + return; +} // end UDFSetFileUID() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine gets UniqueID field in (Ext)FileEntry + */ +__inline +int64 +UDFGetFileUID_( + IN tag* FileEntry + ) +{ + uint16 Ident; + + Ident = FileEntry->tagIdent; + if(Ident == TID_FILE_ENTRY) { + PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry); + return fe->uniqueID; + } else if(Ident == TID_EXTENDED_FILE_ENTRY) { + PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry); + return fe->uniqueID; + } + return (-1); +} // end UDFGetFileUID() + +int64 +UDFGetFileUID( + IN PUDF_FILE_INFO FileInfo + ) +{ + ValidateFileInfo(FileInfo); + + return UDFGetFileUID_(FileInfo->Dloc->FileEntry); +} // end UDFGetFileUID() + +#ifndef UDF_READ_ONLY_BUILD +void +UDFChangeFileCounter( + IN PVCB Vcb, + IN BOOLEAN FileCounter, + IN BOOLEAN Increase + ) +{ + uint32* counter; + + counter = FileCounter ? + &(Vcb->numFiles) : + &(Vcb->numDirs); + if(*counter == -1) + return; + if(Increase) { + UDFInterlockedIncrement((int32*)counter); + } else { + UDFInterlockedDecrement((int32*)counter); + } + +} // end UDFChangeFileCounter() + +void +UDFSetEntityID_imp_( + IN EntityID* eID, + IN uint8* Str, + IN uint32 Len + ) +{ + impIdentSuffix* iis; + + RtlCopyMemory( (int8*)&(eID->ident), Str, Len ); + iis = (impIdentSuffix*)&(eID->identSuffix); + iis->OSClass = UDF_OS_CLASS_WINNT; + iis->OSIdent = UDF_OS_ID_WINNT; + +} // end UDFSetEntityID_imp_() +#endif //UDF_READ_ONLY_BUILD + +void +UDFReadEntityID_Domain( + PVCB Vcb, + EntityID* eID + ) +{ + domainIdentSuffix* dis; + uint8 flags; + + dis = (domainIdentSuffix*)&(eID->identSuffix); + + KdPrint(("UDF: Entity Id:\n")); + KdPrint(("flags: %x\n", eID->flags)); + KdPrint(("ident[0]: %x\n", eID->ident[0])); + KdPrint(("ident[1]: %x\n", eID->ident[1])); + KdPrint(("ident[2]: %x\n", eID->ident[2])); + KdPrint(("ident[3]: %x\n", eID->ident[3])); + KdPrint(("UDF: Entity Id Domain:\n")); + // Get current UDF revision + Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev); + KdPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev)); + // Get Read-Only flags + flags = dis->flags; + KdPrint(("Flags: %x\n", flags)); + if((flags & ENTITYID_FLAGS_SOFT_RO) && + (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO; + KdPrint((" Soft-RO\n")); + } + if((flags & ENTITYID_FLAGS_HARD_RO) && + (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY; + Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO; + KdPrint((" Hard-RO\n")); + } + +} // end UDFReadEntityID_Domain() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine writes data to file & increases it if necessary. + In case of increasing AllocDescs will be rebuilt & flushed to disc + (via driver's cache, of cource). Free space map will be updated only + durring global media flush. + */ +OSSTATUS +UDFWriteFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, + IN uint32 Length, + IN BOOLEAN Direct, + IN int8* Buffer, + OUT uint32* WrittenBytes + ) +{ + int64 t, elen; + OSSTATUS status; + int8* OldInIcb = NULL; + ValidateFileInfo(FileInfo); + uint32 ReadBytes; + uint32 _WrittenBytes; + PUDF_DATALOC_INFO Dloc; + // unwind staff + BOOLEAN WasInIcb = FALSE; + uint64 OldLen; + +// ASSERT(FileInfo->RefCount >= 1); + + Dloc = FileInfo->Dloc; + ASSERT(Dloc->FELoc.Mapping[0].extLocation); + uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation); + (*WrittenBytes) = 0; + + AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n", + Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping)); + + t = Offset + Length; +// UDFUpdateModifyTime(Vcb, FileInfo); + if(t <= Dloc->DataLoc.Length) { + // write Alloc-Rec area + ExtPrint((" WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length)); + status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes); + return status; + } + elen = UDFGetExtentLength(Dloc->DataLoc.Mapping); + ExtPrint((" DataLoc Offs %x, Len %I64x\n", + Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); + if(t <= (elen - Dloc->DataLoc.Offset)) { + // write Alloc-Not-Rec area + ExtPrint((" WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n", + t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length, + elen - Dloc->DataLoc.Offset, + Dloc->DataLoc.Length)); + UDFSetFileSize(FileInfo, t); + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ExtPrint((" w2k-compat -> rebuild allocs\n")); + Dloc->DataLoc.Modified = TRUE; + } else + if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) { + ExtPrint((" LBS boundary crossed -> rebuild allocs\n")); + Dloc->DataLoc.Modified = TRUE; + } + Dloc->DataLoc.Length = t; + return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes); + } + // We should not get here if Direct=TRUE + if(Direct) return STATUS_INVALID_PARAMETER; + OldLen = Dloc->DataLoc.Length; + if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) { + // read in-icb data. it'll be replaced after resize + ExtPrint((" read in-icb data\n")); + OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length)); + if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES; + status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes); + if(!OS_SUCCESS(status)) { + MyFreePool__(OldInIcb); + return status; + } + } + // init Alloc mode + ExtPrint((" init Alloc mode\n")); + if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; + WasInIcb = TRUE; + } + // increase extent + ExtPrint((" %s %s %s\n", + UDFIsADirectory(FileInfo) ? "DIR" : "FILE", + WasInIcb ? "In-Icb" : "", + Vcb->LowFreeSpace ? "LowSpace" : "")); + if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) { + FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL; + status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc)); + if(OS_SUCCESS(status)) { + AdPrint((" preallocated space for Dir\n")); + FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED; + //UDFSetFileSize(FileInfo, t); + Dloc->DataLoc.Length = t; + } else + if(status == STATUS_DISK_FULL) { + status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc)); + } + } else { + status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc)); + } + ExtPrint((" DataLoc Offs %x, Len %I64x\n", + Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); + AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping)); + if(!OS_SUCCESS(status)) { + // rollback + ExtPrint((" err -> rollback\n")); + if(WasInIcb) { + // restore Alloc mode + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB; + if(Dloc->AllocLoc.Mapping) { + MyFreePool__(Dloc->AllocLoc.Mapping); + Dloc->AllocLoc.Mapping = NULL; + } + } + if(OldInIcb) { + MyFreePool__(OldInIcb); + UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes); + } + if((int64)OldLen != Dloc->DataLoc.Length) { + // restore file size + AdPrint((" restore alloc\n")); + FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; + UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc)); + FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED; + } + return status; + } + if(OldInIcb) { + // replace data from ICB (if any) & free buffer + ExtPrint((" write old in-icd data\n")); + status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes); + MyFreePool__(OldInIcb); + if(!OS_SUCCESS(status)) + return status; + } + // ufff... + // & now we'll write out data to well prepared extent... + // ... like all normal people do... + ExtPrint((" write user data\n")); + if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes))) + return status; + UDFSetFileSize(FileInfo, t); + Dloc->DataLoc.Modified = TRUE; +#ifdef UDF_DBG + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); + } +#endif // UDF_DBG + return STATUS_SUCCESS; +} // end UDFWriteFile__() + +/* + This routine marks file as deleted & decrements file link counter. + It can optionaly free allocation space + */ +OSSTATUS +UDFUnlinkFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN FreeSpace + ) +{ + uint_di Index; // index of file to be deleted + uint16 lc; + PUDF_DATALOC_INFO Dloc; + PUDF_FILE_INFO DirInfo; + PUDF_FILE_INFO SDirInfo; + PDIR_INDEX_HDR hDirNdx; + PDIR_INDEX_HDR hCurDirNdx; + PDIR_INDEX_ITEM DirNdx; + OSSTATUS status; + BOOLEAN IsSDir; + + AdPrint(("UDFUnlinkFile__:\n")); + if(!FileInfo) return STATUS_SUCCESS; + + ValidateFileInfo(FileInfo); + +#ifndef _CONSOLE + // now we can't call this if there is no OS-specific File Desc. present + if(FileInfo->Fcb) + UDFRemoveFileId__(Vcb, FileInfo); +#endif //_CONSOLE + // check references + Dloc = FileInfo->Dloc; + if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) || + (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE; + if(Dloc->SDirInfo) + return STATUS_CANNOT_DELETE; + ASSERT(FileInfo->RefCount == 1); + DirInfo = FileInfo->ParentFile; + // root dir or self + if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE; + hDirNdx = DirInfo->Dloc->DirIndex; + Index = FileInfo->Index; + // we can't delete modified file + // it should be closed & reopened (or flushed) before deletion + DirNdx = UDFDirIndex(hDirNdx,Index); +#if defined UDF_DBG || defined PRINT_ALWAYS + if(DirNdx && DirNdx->FName.Buffer) { + AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer)); + } +#endif // UDF_DBG + if(FreeSpace && + ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || + Dloc->DataLoc.Modified || + Dloc->AllocLoc.Modified || + Dloc->FELoc.Modified || + (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) { +// BrutePoint(); + return STATUS_CANNOT_DELETE; + } + SDirInfo = Dloc->SDirInfo; +/* if(FreeSpace && SDirInfo) { + KdPrint(("Unlink: SDirInfo should be NULL !!!\n")); + BrutePoint(); + return STATUS_CANNOT_DELETE; + }*/ + // stream directory can be deleted even being not empty + // otherwise we should perform some checks + if(!(IsSDir = UDFIsAStreamDir(FileInfo))) { + // check if not empty direcory + if((DirNdx->FileCharacteristics & FILE_DIRECTORY) && + (hCurDirNdx = Dloc->DirIndex) && + FreeSpace) { + if(!UDFIsDirEmpty(hCurDirNdx)) + return STATUS_DIRECTORY_NOT_EMPTY; + } + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FileCharacteristics |= FILE_DELETED; + FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; + hDirNdx->DelCount++; + UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE); + } + UDFDecFileLinkCount(FileInfo); // decrease + lc = UDFGetFileLinkCount(FileInfo); + if(DirNdx && FreeSpace) { + // FileIdent marked as 'deleted' should have an empty ICB + // We shall do it only if object has parent Dir + // (for ex. SDir has parent object, but has no parent Dir) + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; + // Root Files (Root/SDir/Vat/etc.) has no FileIdent... + if(FileInfo->FileIdent) + RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad)); + } + // caller wishes to free allocation, but we can't do it due to + // alive links. In this case we should just remove reference + if(FreeSpace && lc) { + ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0; + ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0; + Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } else + // if caller wishes to free file allocation & + // there are no more references(links) to this file, lets do it >;-> + if(FreeSpace && !lc) { + if(UDFHasAStreamDir(FileInfo) && + !UDFIsSDirDeleted(Dloc->SDirInfo) ) { + // we have a Stream Dir associated... + PUDF_FILE_INFO SFileInfo; + // ... try to open it + if(Dloc->SDirInfo) { + UDFFlushFile__(Vcb, FileInfo); + return STATUS_CANNOT_DELETE; + } + // open SDir + status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo)); + if(!OS_SUCCESS(status)) { + // abort Unlink on error + SFileInfo = Dloc->SDirInfo; +cleanup_SDir: + UDFCleanUpFile__(Vcb, SFileInfo); + if(SFileInfo) MyFreePool__(SFileInfo); + UDFFlushFile__(Vcb, FileInfo); + return status; + } + SDirInfo = Dloc->SDirInfo; + // try to perform deltree for Streams + status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo); + if(!OS_SUCCESS(status)) { + // abort Unlink on error + UDFCloseFile__(Vcb, SDirInfo); + SFileInfo = SDirInfo; + BrutePoint(); + goto cleanup_SDir; + } + // delete SDir + UDFFlushFile__(Vcb, SDirInfo); + AdPrint((" ")); + UDFUnlinkFile__(Vcb, SDirInfo, TRUE); + // close SDir + UDFCloseFile__(Vcb, SDirInfo); + if(UDFCleanUpFile__(Vcb, SDirInfo)) { + MyFreePool__(SDirInfo); +#ifdef UDF_DBG + } else { + BrutePoint(); +#endif // UDF_DBG + } + // update FileInfo + ASSERT(Dloc->FileEntry); + RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad)); + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } else + if(IsSDir) { + // do deltree for Streams + status = UDFUnlinkAllFilesInDir(Vcb, FileInfo); + if(!OS_SUCCESS(status)) { + UDFFlushFile__(Vcb, FileInfo); + return status; + } + // update parent FileInfo + ASSERT(FileInfo->ParentFile->Dloc->FileEntry); + RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad)); + FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR; + FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | + UDF_FE_FLAG_HAS_DEL_SDIR); + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR; + UDFDecFileLinkCount(FileInfo->ParentFile); + } + if(Dloc->DirIndex) { + UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL); + } + // flush file + UDFFlushFile__(Vcb, FileInfo); + UDFUnlinkDloc(Vcb, Dloc); + // free allocation + UDFFreeFileAllocation(Vcb, DirInfo, FileInfo); + ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED)); + FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; + } + return STATUS_SUCCESS; +} // end UDFUnlinkFile__() + +OSSTATUS +UDFUnlinkAllFilesInDir( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo + ) +{ + PDIR_INDEX_HDR hCurDirNdx; + PDIR_INDEX_ITEM CurDirNdx; + PUDF_FILE_INFO FileInfo; + OSSTATUS status; + uint_di i; + + hCurDirNdx = DirInfo->Dloc->DirIndex; + // check if we can delete all files + for(i=2; CurDirNdx = UDFDirIndex(hCurDirNdx,i); i++) { + // try to open Stream + if(CurDirNdx->FileInfo) + return STATUS_CANNOT_DELETE; + } + // start deletion + for(i=2; CurDirNdx = UDFDirIndex(hCurDirNdx,i); i++) { + // try to open Stream + status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i); + if(status == STATUS_FILE_DELETED) { + // we should not release on-disk allocation for + // deleted streams twice + if(CurDirNdx->FileInfo) { + BrutePoint(); + goto err_del_stream; + } + goto skip_del_stream; + } else + if(!OS_SUCCESS(status)) { + // Error :((( +err_del_stream: + UDFCleanUpFile__(Vcb, FileInfo); + if(FileInfo) + MyFreePool__(FileInfo); + return status; + } + + UDFFlushFile__(Vcb, FileInfo); + AdPrint((" ")); + UDFUnlinkFile__(Vcb, FileInfo, TRUE); + UDFCloseFile__(Vcb, FileInfo); +skip_del_stream: + if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) { + MyFreePool__(FileInfo); + } + } + return STATUS_SUCCESS; +} // end UDFUnlinkAllFilesInDir() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine inits UDF_FILE_INFO structure for specified file + If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ + for returned pointer *WITHOUT* using UDFCloseFile__ + */ +OSSTATUS +UDFOpenFile__( + IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + IN PUNICODE_STRING fn, + IN PUDF_FILE_INFO DirInfo, + OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain + // any pointers + IN uint_di* IndexToOpen + ) +{ + OSSTATUS status; + uint_di i=0; + EXTENT_AD FEExt; + uint16 Ident; + PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; + PDIR_INDEX_ITEM DirNdx; + PUDF_FILE_INFO FileInfo; + PUDF_FILE_INFO ParFileInfo; + uint32 ReadBytes; + *_FileInfo = NULL; + if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; + + // find specified file in directory index + // if it is already known, skip this foolish code + if(IndexToOpen) { + i=*IndexToOpen; + } else + if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i))) + return status; + // do this check for OpenByIndex + // some routines may send invalid Index + if(!(DirNdx = UDFDirIndex(hDirNdx,i))) + return STATUS_OBJECT_NAME_NOT_FOUND; + if(FileInfo = DirNdx->FileInfo) { + // file is already opened. + if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { + AdPrint((" FILE_DELETED on open\n")); + return STATUS_FILE_DELETED; + } + if((FileInfo->ParentFile != DirInfo) && + (FileInfo->Index >= 2)) { + ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo); + BrutePoint(); + if(ParFileInfo->ParentFile != DirInfo) { + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); + *_FileInfo = FileInfo; + if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO)); + // FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done + UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo); + DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + FileInfo->RefCount = 0; + FileInfo->ParentFile = DirInfo; + FileInfo->Fcb = NULL; + } else { + FileInfo = ParFileInfo; + } + } + // Just increase some counters & exit + UDFReferenceFile__(FileInfo); + + ASSERT(FileInfo->ParentFile == DirInfo); + ValidateFileInfo(FileInfo); + + *_FileInfo = FileInfo; + return STATUS_SUCCESS; + } else + if(IndexToOpen) { + if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { + AdPrint((" FILE_DELETED on open (2)\n")); + return STATUS_FILE_DELETED; + } + } + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); + *_FileInfo = FileInfo; + if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); + // init horizontal links + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + // read FileIdent + FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG); + if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES; + FileInfo->FileIdentLen = DirNdx->Length; + if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset, + DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) )) + return status; + if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) { + BrutePoint(); + return STATUS_FILE_CORRUPT_ERROR; + } + // check for opened links + if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation))))) + return status; + // init pointer to parent object + FileInfo->Index = i; + FileInfo->ParentFile = DirInfo; + // init pointers to linked files (if any) + if(FileInfo->Dloc->LinkedFileInfo != FileInfo) + UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo); + if(FileInfo->Dloc->FileEntry) + goto init_tree_entry; + // read (Ex)FileEntry + FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG); + if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES; + if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident))) + return status; + // build mappings for Data & AllocDescs + if(!FileInfo->Dloc->AllocLoc.Mapping) { + FEExt.extLength = FileInfo->FileIdent->icb.extLength; + FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) ); + if(FEExt.extLocation == LBA_OUT_OF_EXTENT) + return STATUS_FILE_CORRUPT_ERROR; + FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt); + if(!(FileInfo->Dloc->AllocLoc.Mapping)) + return STATUS_INSUFFICIENT_RESOURCES; + } + // read location info + status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb), + &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ); + if(!OS_SUCCESS(status)) + return status; + // init (Ex)FileEntry mapping + FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset : + FileInfo->Dloc->AllocLoc.Offset; +// FileInfo->Dloc->FELoc.Offset = 0; + FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt); + FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length); + // we get here immediately when opened link encountered +init_tree_entry: + // init back pointer from parent object + ASSERT(!DirNdx->FileInfo); + DirNdx->FileInfo = FileInfo; + // init DirIndex + if(UDFGetFileLinkCount(FileInfo) > 1) { + DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + } else { + DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED; + } + // resize FE cache (0x800 instead of 0x40 is not a good idea) + if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize, + (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen)) + return STATUS_INSUFFICIENT_RESOURCES; + // check if this file has a SDir + if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) && + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength ) + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; + if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) { + UDFReferenceFile__(FileInfo); + ASSERT(FileInfo->ParentFile == DirInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + return STATUS_SUCCESS; + } + + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used + + // build index for directories + if(!FileInfo->Dloc->DirIndex) { + status = UDFIndexDirectory(Vcb, FileInfo); + if(!OS_SUCCESS(status)) + return status; +#ifndef UDF_READ_ONLY_BUILD + if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { + status = UDFPackDirectory__(Vcb, FileInfo); + if(!OS_SUCCESS(status)) + return status; + } +#endif //UDF_READ_ONLY_BUILD + } + UDFReferenceFile__(FileInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + ASSERT(FileInfo->ParentFile == DirInfo); + + return status; +} // end UDFOpenFile__() + + +/* + This routine inits UDF_FILE_INFO structure for root directory + */ +OSSTATUS +UDFOpenRootFile__( + IN PVCB Vcb, + IN lb_addr* RootLoc, + OUT PUDF_FILE_INFO FileInfo + ) +{ + uint32 RootLBA; + OSSTATUS status; +// uint32 PartNum = RootLoc->partitionReferenceNum; + uint32 LBS = Vcb->LBlockSize; + uint16 Ident; + LONG_AD FELoc; + EXTENT_AD FEExt; + uint8 FileType; + + RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); + RootLBA = UDFPartLbaToPhys(Vcb,RootLoc); + if(RootLBA == LBA_OUT_OF_EXTENT) + return STATUS_FILE_CORRUPT_ERROR; + FELoc.extLocation = *RootLoc; + FELoc.extLength = LBS; + // init horizontal links + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + // check for opened links + if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA))) + return status; + if(FileInfo->Dloc->FileEntry) + goto init_tree_entry; + // read (Ex)FileEntry + FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG); + if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES; + + if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident))) + return status; + // build mappings for Data & AllocDescs + FEExt.extLength = LBS; + FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) ); + if(FEExt.extLocation == LBA_OUT_OF_EXTENT) + return STATUS_FILE_CORRUPT_ERROR; + FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt); + if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; + // build mappings for AllocDescs + if(!FileInfo->Dloc->AllocLoc.Mapping) { + FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt); + if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; + } + if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc, + &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) )) + return status; + FileInfo->Dloc->FileEntryLen = (uint32) + (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset : + FileInfo->Dloc->AllocLoc.Offset); +init_tree_entry: + // resize FE cache (0x800 instead of 0x40 is not a good idea) + if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS, + (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen)) + return STATUS_INSUFFICIENT_RESOURCES; + // init DirIndex + if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY && + (FileType != UDF_FILE_TYPE_STREAMDIR) ) { + UDFReferenceFile__(FileInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + return STATUS_SUCCESS; + } + // build index for directories + if(!FileInfo->Dloc->DirIndex) { + status = UDFIndexDirectory(Vcb, FileInfo); + if(!OS_SUCCESS(status)) + return status; +#ifndef UDF_READ_ONLY_BUILD + if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) && + !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { + status = UDFPackDirectory__(Vcb, FileInfo); + if(!OS_SUCCESS(status)) + return status; + } +#endif //UDF_READ_ONLY_BUILD + } + UDFReferenceFile__(FileInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + + return status; +} // end UDFOpenRootFile__() + +/* + This routine frees all memory blocks referenced by given FileInfo + */ +uint32 +UDFCleanUpFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + PUDF_DATALOC_INFO Dloc; + uint32 lc = 0; + BOOLEAN IsASDir; + BOOLEAN KeepDloc; + PDIR_INDEX_ITEM DirNdx, DirNdx2; + BOOLEAN Parallel = FALSE; + BOOLEAN Linked = FALSE; +#ifdef UDF_DBG + BOOLEAN Modified = FALSE; + PDIR_INDEX_HDR hDirNdx; + uint_di Index; + PUDF_FILE_INFO DirInfo; +#endif // UDF_DBG + + if(!FileInfo) return UDF_FREE_FILEINFO; + + ValidateFileInfo(FileInfo); + + if(FileInfo->OpenCount || FileInfo->RefCount) { + KdPrint(("UDF: not all references are closed\n")); + KdPrint((" Skipping cleanup\n")); + KdPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n", + FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount)); + return UDF_FREE_NOTHING; + } + if(FileInfo->Fcb) { + KdPrint(("Operating System still has references to this file\n")); + KdPrint((" Skipping cleanup\n")); +// BrutePoint(); + return UDF_FREE_NOTHING; + } + + IsASDir = UDFIsAStreamDir(FileInfo); + + if(Dloc = FileInfo->Dloc) { + +#ifdef UDF_DBG + DirInfo = FileInfo->ParentFile; + if(DirInfo) { + hDirNdx = DirInfo->Dloc->DirIndex; + Index = FileInfo->Index; + // we can't delete modified file + // it should be closed & reopened (or flushed) before deletion + DirNdx = UDFDirIndex(hDirNdx,Index); + KdPrint(("Cleanup Mod: %s%s%s%s%s%s\n", + (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE " : "", + (Dloc->DataLoc.Modified) ? "DataLoc " : "", + (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "", + (Dloc->AllocLoc.Modified) ? "AllocLoc " : "", + (Dloc->FELoc.Modified) ? "FELoc " : "", + (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : "" + )); + Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || + Dloc->DataLoc.Modified || + (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) || + Dloc->AllocLoc.Modified || + Dloc->FELoc.Modified || + (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ); + } +#endif // UDF_DBG + + PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo); + + Parallel = (ParFileInfo != NULL); + Linked = (FileInfo->NextLinkedFile != FileInfo); + +// Parallel = (FileInfo->NextLinkedFile != FileInfo); + ASSERT(FileInfo->NextLinkedFile); +// ASSERT(!Parallel); + KeepDloc = (Dloc->LinkRefCount || + Dloc->CommonFcb || + Linked ) ? + TRUE : FALSE; + + if(Dloc->DirIndex) { + uint_di i; + for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) { + if(DirNdx->FileInfo) { + if(!KeepDloc) { + BrutePoint(); + KdPrint(("UDF: Found not cleaned up reference.\n")); + KdPrint((" Skipping cleanup (1)\n")); +// BrutePoint(); + return UDF_FREE_NOTHING; + } + // The file being cleaned up may have not closed Dirs + // (linked Dir). In this case each of them may have + // reference to FileInfo in DirIndex[1] + // Here we'll check it and change for valid value if + // necessary (Update Child Objects - I) + if(DirNdx->FileInfo->Dloc) { + // we can get here only when (Parallel == TRUE) + DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1); + // It is enough to check DirNdx2->FileInfo only. + // If one of Parallel FI's has reference (and equal) + // to the FI being removed, it'll be removed from + // the chain & nothing wrong will happen. + if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) { + if(FileInfo->PrevLinkedFile == FileInfo) { + BrutePoint(); + DirNdx2->FileInfo = NULL; + } else { + DirNdx2->FileInfo = Parallel ? + ParFileInfo : FileInfo->PrevLinkedFile; + } + ASSERT(!DirNdx2->FileInfo->RefCount); + } + } + } + } + } + if(Dloc->SDirInfo) { + KdPrint(("UDF: Found not cleaned up reference (SDir).\n")); + + // (Update Child Objects - II) + if(Dloc->SDirInfo->ParentFile == FileInfo) { + BrutePoint(); + ASSERT(ParFileInfo); + Dloc->SDirInfo->ParentFile = ParFileInfo; + } + // We should break Cleanup process if alive reference detected + // and there is no possibility to store pointer in some other + // place (in parallel object) + if(!KeepDloc) { + BrutePoint(); + KdPrint((" Skipping cleanup\n")); + return UDF_FREE_NOTHING; + } + + if(!UDFIsSDirDeleted(Dloc->SDirInfo) && + Dloc->SDirInfo->Dloc) { + DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1); + if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) { + DirNdx2->FileInfo = + Parallel ? ParFileInfo : NULL; + ASSERT(!DirNdx2->FileInfo->RefCount); + } + } + } + + if(!KeepDloc) { + + ASSERT(!Modified); + +#ifndef UDF_TRACK_ONDISK_ALLOCATION + if(Dloc->DataLoc.Mapping) MyFreePool__(Dloc->DataLoc.Mapping); + if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping); + if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping); + if(Dloc->FileEntry) { + // plain file + lc = UDFGetFileLinkCount(FileInfo); + MyFreePool__(Dloc->FileEntry); + Dloc->FileEntry = NULL; + } else if(FileInfo->Index >= 2) { + // error durring open operation + lc = UDF_INVALID_LINK_COUNT; + } +#endif //UDF_TRACK_ONDISK_ALLOCATION + if(FileInfo->Dloc->DirIndex) { + uint_di i; + for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) { + ASSERT(!DirNdx->FileInfo); + if(DirNdx->FName.Buffer) + MyFreePool__(DirNdx->FName.Buffer); + } + // The only place where we can free FE_Charge extent is here + UDFFlushFESpace(Vcb, Dloc); + UDFDirIndexFree(Dloc->DirIndex); + Dloc->DirIndex = NULL; +#ifdef UDF_TRACK_ONDISK_ALLOCATION + UDFIndexDirectory(Vcb, FileInfo); + if(FileInfo->Dloc->DirIndex) { + for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) { + ASSERT(!DirNdx->FileInfo); + if(DirNdx->FName.Buffer) + MyFreePool__(DirNdx->FName.Buffer); + } + UDFDirIndexFree(Dloc->DirIndex); + Dloc->DirIndex = NULL; + } +#endif //UDF_TRACK_ONDISK_ALLOCATION + } + +#ifdef UDF_TRACK_ONDISK_ALLOCATION + if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping); + if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping); + if(Dloc->FileEntry) { + // plain file + lc = UDFGetFileLinkCount(FileInfo); + MyFreePool__(Dloc->FileEntry); + Dloc->FileEntry = NULL; + } else if(FileInfo->Index >= 2) { + // error durring open operation + lc = UDF_INVALID_LINK_COUNT; + } + if(Dloc->DataLoc.Mapping) { + if(lc && (lc != UDF_INVALID_LINK_COUNT)) { + UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used + } else { + UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free + } + MyFreePool__(Dloc->DataLoc.Mapping); + } +#endif //UDF_TRACK_ONDISK_ALLOCATION + + if(lc && (lc != UDF_INVALID_LINK_COUNT)) { + UDFRemoveDloc(Vcb, Dloc); + } else { + UDFFreeDloc(Vcb, Dloc); + } + } else // KeepDloc cannot be FALSE if (Linked == TRUE) + if(Linked) { +// BrutePoint(); + // Update pointers in ParentObject (if any) + if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) + FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile; + DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0); + if(DirNdx && (DirNdx->FileInfo == FileInfo)) + DirNdx->FileInfo = FileInfo->PrevLinkedFile; + DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index); + if(DirNdx && (DirNdx->FileInfo == FileInfo)) + DirNdx->FileInfo = ParFileInfo; + // remove from linked chain + FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile; + FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile; + // update pointer in Dloc + if(FileInfo->Dloc->LinkedFileInfo == FileInfo) + FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile; + } + FileInfo->Dloc = NULL; + } else { + KeepDloc = FALSE; + } + + // Cleanup pointers in ParentObject (if any) + if(IsASDir) { + if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) { + ASSERT(!Linked); + FileInfo->ParentFile->Dloc->SDirInfo = NULL; + FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR; + } + } else + if(FileInfo->ParentFile) { + ASSERT(FileInfo->ParentFile->Dloc); + DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index); + ASSERT(DirNdx); +#ifdef UDF_DBG + PUDF_FILE_INFO OldFI; + if(Parallel) { + ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) || + !(OldFI == FileInfo)); + } else { + ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) || + (OldFI == FileInfo)); + } +#endif + if( DirNdx && (DirNdx->FileInfo == FileInfo) ) { + if(!Parallel) + DirNdx->FileInfo = NULL; +#ifdef UDF_DBG + } else { + // We can get here after incomplete Open + if(!Parallel && DirNdx->FileInfo) + BrutePoint(); +#endif + } +#ifdef UDF_DBG + } else { +// BrutePoint(); +#endif + } + + if(!Parallel && FileInfo->FileIdent) + MyFreePool__(FileInfo->FileIdent); + FileInfo->FileIdent = NULL; + // Kill reference to parent object + FileInfo->ParentFile = NULL; + // Kill references to parallel object(s) since it has no reference to + // this one now + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + if(FileInfo->ListPtr) + FileInfo->ListPtr->FileInfo = NULL;; + return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC); +} // end UDFCleanUpFile__() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine creates FileIdent record in destination directory & + allocates FileEntry with in-ICB zero-sized data + If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ + for returned pointer *WITHOUT* using UDFCloseFile__ + */ +OSSTATUS +UDFCreateFile__( + IN PVCB Vcb, +// IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB + IN BOOLEAN IgnoreCase, + IN PUNICODE_STRING _fn, + IN uint32 ExtAttrSz, + IN uint32 ImpUseLen, + IN BOOLEAN Extended, + IN BOOLEAN CreateNew, + IN OUT PUDF_FILE_INFO DirInfo, + OUT PUDF_FILE_INFO* _FileInfo + ) +{ + uint32 l, d; + uint_di i, j; + OSSTATUS status; + LONG_AD FEicb; + UDF_DIR_SCAN_CONTEXT ScanContext; + PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; + PDIR_INDEX_ITEM DirNdx; + uint32 LBS = Vcb->LBlockSize; + PUDF_FILE_INFO FileInfo; + *_FileInfo = NULL; + BOOLEAN undel = FALSE; + uint32 ReadBytes; +// BOOLEAN PackDir = FALSE; + BOOLEAN FEAllocated = FALSE; + + ValidateFileInfo(DirInfo); + *_FileInfo = NULL; + + ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation); + uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation); + if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; + i = 0; + + _SEH2_TRY { + + // check if exists + status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i); + DirNdx = UDFDirIndex(hDirNdx,i); + if(OS_SUCCESS(status)) { + // file is a Cur(Parent)Dir + if(i<2) try_return (status = STATUS_ACCESS_DENIED); + // file deleted + if(UDFIsDeleted(DirNdx)) { + j=0; + if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) { + i=j; + DirNdx = UDFDirIndex(hDirNdx,i); + goto CreateBothFound; + } + // we needn't allocating new FileIdent inside Dir stream + // perform 'undel' + if(DirNdx->FileInfo) { + // BrutePoint(); + status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo); + if(!OS_SUCCESS(status)) + try_return (status = STATUS_FILE_DELETED); + } else { + undel = TRUE; + } + // BrutePoint(); + goto CreateUndel; + } +CreateBothFound: + // file already exists + if(CreateNew) try_return (status = STATUS_ACCESS_DENIED); + // try to open it + BrutePoint(); + status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i); + // *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it... + DirNdx = UDFDirIndex(hDirNdx,i); + DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; + FileInfo = *_FileInfo; + if(!OS_SUCCESS(status)) { + // :(( can't open.... + if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) { + MyFreePool__(FileInfo); + *_FileInfo = NULL; + } + BrutePoint(); + try_return (status); + } + // check if we can delete this file + if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) { + BrutePoint(); + UDFCloseFile__(Vcb, FileInfo); + try_return (status = STATUS_CANNOT_DELETE); + } + BrutePoint(); + // remove DIRECTORY flag + DirNdx->FileCharacteristics &= ~FILE_DIRECTORY; + FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY; + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + // truncate file size to ZERO + status = UDFResizeFile__(Vcb, FileInfo, 0); + if(!OS_SUCCESS(status)) { + BrutePoint(); + UDFCloseFile__(Vcb, FileInfo); + } + // set NORMAL flag + FileInfo->FileIdent->fileCharacteristics = 0; + DirNdx->FileCharacteristics = 0; + // update DeletedFiles counter in Directory... (for PackDir) + if(undel && OS_SUCCESS(status)) + hDirNdx->DelCount--; + try_return (status); + } + +CreateUndel: + + // allocate FileInfo + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG); + *_FileInfo = FileInfo; + if(!FileInfo) + try_return (status = STATUS_INSUFFICIENT_RESOURCES); + ImpUseLen = (ImpUseLen + 3) & ~((uint16)3); + + RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); + // init horizontal links + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + // allocate space for FileEntry + if(!OS_SUCCESS(status = + UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) { + BrutePoint(); + try_return (status); + } + FEAllocated = TRUE; + FEicb.extLength = LBS; + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; + RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); + + if(!undel) { + // build FileIdent + if(!OS_SUCCESS(status = + UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen, + &(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) )) + try_return (status); + } else { + // read FileIdent + FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG); + if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES); + FileInfo->FileIdentLen = DirNdx->Length; + if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset, + DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) )) + try_return (status); + FileInfo->FileIdent->fileCharacteristics = 0; + FileInfo->FileIdent->icb = FEicb; + ImpUseLen = FileInfo->FileIdent->lengthOfImpUse; + DirNdx->FileCharacteristics = 0; + } + // init 'parentICBLocation' & so on in FE + ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = + UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation); + ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum; + // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4; + // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1; + // try to find suitable unused FileIdent in DirIndex + l = FileInfo->FileIdentLen; + if(undel) goto CrF__2; +#ifndef UDF_LIMIT_DIR_SIZE + if(Vcb->CDR_Mode) { +#endif // UDF_LIMIT_DIR_SIZE + // search for suitable unused entry + if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) { + while(DirNdx = UDFDirIndexScan(&ScanContext, NULL)) { + if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) && + !DirNdx->FileInfo ) { + // free unicode-buffer with old name + if(DirNdx->FName.Buffer) { + MyFreePool__(DirNdx->FName.Buffer); + DirNdx->FName.Buffer = NULL; + } + i = ScanContext.i; + goto CrF__1; + } + } + } +#ifndef UDF_LIMIT_DIR_SIZE + } else { +#endif // UDF_LIMIT_DIR_SIZE + i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex +#ifndef UDF_LIMIT_DIR_SIZE + } +#endif // UDF_LIMIT_DIR_SIZE + + // append entry + if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) { + try_return (status); + } + + // init offset of new FileIdent in directory Data extent + hDirNdx = DirInfo->Dloc->DirIndex; + if(i-1) { + DirNdx = UDFDirIndex(hDirNdx,i-1); + UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length; + DirNdx = UDFDirIndex(hDirNdx,i); + } else { + DirNdx = UDFDirIndex(hDirNdx,i); + DirNdx->Offset = 0; + } + // new terminator is recorded by UDFDirIndexGrow() + if( ((d = (LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) && + d ) { + // insufficient space at the end of last sector for + // next FileIdent's tag. fill it with ImpUse data + + // generally, all data should be DWORD-aligned, but if it is not so + // this opearation will help us to avoid glitches + d = (d+3) & ~((uint32)3); + + uint32 IUl, FIl; + if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l, + (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) )) + try_return (status = STATUS_INSUFFICIENT_RESOURCES); + l += d; + IUl = FileInfo->FileIdent->lengthOfImpUse; + FIl = FileInfo->FileIdent->lengthFileIdent; + // move filename to higher addr + RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d, + ((int8*)(FileInfo->FileIdent+1))+IUl, FIl); + RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d); + FileInfo->FileIdent->lengthOfImpUse += (uint16)d; + FileInfo->FileIdentLen = l; + } + DirNdx->Length = l; +CrF__1: + // clone unicode string + // it **<>** be allocated with internal memory manager + DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG); + DirNdx->FName.Length = _fn->Length; + if(!DirNdx->FName.Buffer) + try_return (status = STATUS_INSUFFICIENT_RESOURCES); + RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length); + DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0; +CrF__2: + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL); + // we get here immediately when 'undel' occured + FileInfo->Index = i; + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; + ASSERT(!DirNdx->FileInfo); + DirNdx->FileInfo = FileInfo; + DirNdx->FileEntryLoc = FEicb.extLocation; + // mark file as 'deleted' for now + DirNdx->FileCharacteristics = FILE_DELETED; + FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; + FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0])); + if(!(FileInfo->Dloc->DataLoc.Mapping)) { + UDFFlushFI(Vcb, FileInfo, PartNum); + try_return (status = STATUS_INSUFFICIENT_RESOURCES); + } + FileInfo->Dloc->DataLoc.Length = 0; + FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; + FileInfo->ParentFile = DirInfo; + // init FileEntry + UDFSetFileUID(Vcb, FileInfo); + UDFSetFileSize(FileInfo, 0); + UDFIncFileLinkCount(FileInfo); // increase to 1 + UDFUpdateCreateTime(Vcb, FileInfo); + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index), + FileInfo->Dloc->FileEntry, Vcb->DefaultAttr); + FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; + FileInfo->Dloc->DataLoc.Modified = TRUE; + FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; + // zero sector for FileEntry + if(!Vcb->CDR_Mode) { + status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes); + if(!OS_SUCCESS(status)) { + UDFFlushFI(Vcb, FileInfo, PartNum); + try_return (status); + } + } +#if 0 + if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) { + BrutePoint(); + } +#endif + +#ifdef UDF_CHECK_DISK_ALLOCATION + if( /*FileInfo->Fcb &&*/ + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { + + if(!FileInfo->FileIdent || + !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { + AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + BrutePoint(); + } + } +#endif // UDF_CHECK_DISK_ALLOCATION + + // make FileIdent valid + FileInfo->FileIdent->fileCharacteristics = 0; + DirNdx->FileCharacteristics = 0; + UDFReferenceFile__(FileInfo); + UDFFlushFE(Vcb, FileInfo, PartNum); + if(undel) + hDirNdx->DelCount--; + UDFReleaseDloc(Vcb, FileInfo->Dloc); + UDFIncFileCounter(Vcb); + + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used + + try_return (status = STATUS_SUCCESS); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if(!OS_SUCCESS(status)) { + if(FEAllocated) + UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); + } + } _SEH2_END + return status; + +} // end UDFCreateFile__() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine reads data from file described by FileInfo + */ +/*__inline +OSSTATUS +UDFReadFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT int8* Buffer, + OUT uint32* ReadBytes + ) +{ + ValidateFileInfo(FileInfo); + + return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes); +} // end UDFReadFile__()*/ + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine zeros data in file described by FileInfo + */ +__inline +OSSTATUS +UDFZeroFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT uint32* ReadBytes + ) +{ + ValidateFileInfo(FileInfo); + + return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes); +} // end UDFZeroFile__()*/ + +/* + This routine makes sparse area in file described by FileInfo + */ +__inline +OSSTATUS +UDFSparseFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT uint32* ReadBytes + ) +{ + ValidateFileInfo(FileInfo); + + return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes); +} // end UDFSparseFile__()*/ + +/* + This routine fills tails of the last sector in extent with ZEROs + */ +OSSTATUS +UDFPadLastSector( + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo + ) +{ + if(!ExtInfo || !(ExtInfo->Mapping) || !(ExtInfo->Length)) return STATUS_INVALID_PARAMETER; + + PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array + uint32 to_write, Lba, sect_offs, flags, WrittenBytes; + OSSTATUS status; + // Length should not be zero + int64 Offset = ExtInfo->Length + ExtInfo->Offset; + // data is sector-size-aligned, we needn't any padding + if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS; + // get Lba of the last sector + Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); + // EOF check. If we have valid ExtInfo this will not happen, but who knows.. + if((Lba == (uint32)-1) || + (flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED)) + return STATUS_END_OF_FILE; + // write tail + status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes); + return status; +} // UDFPadLastSector() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine updates AllocDesc sequence, FileIdent & FileEntry + for given file + */ +OSSTATUS +UDFCloseFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + ValidateFileInfo(FileInfo); + + if(!FileInfo) return STATUS_SUCCESS; + if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) { + KdPrint(("Closing Current or Parent Directory... :-\\\n")); + if(FileInfo->RefCount) { + UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount)); + ASSERT(FileInfo->Dloc); + if(FileInfo->Dloc) + UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount)); +#ifdef UDF_DBG + } else { + BrutePoint(); + KdPrint(("ERROR: Closing unreferenced file!\n")); +#endif // UDF_DBG + } + if(FileInfo->ParentFile->OpenCount) { + UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount)); +#ifdef UDF_DBG + } else { + BrutePoint(); + KdPrint(("ERROR: Closing unopened file!\n")); +#endif // UDF_DBG + } + return STATUS_SUCCESS; + } + PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; + OSSTATUS status; + uint32 PartNum; + if(FileInfo->RefCount) { + UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount)); + ASSERT(FileInfo->Dloc); + if(FileInfo->Dloc) + UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount)); +#ifdef UDF_DBG + } else { + BrutePoint(); + KdPrint(("ERROR: Closing unreferenced file!\n")); +#endif // UDF_DBG + } + if(DirInfo) { + // validate DirInfo + ValidateFileInfo(DirInfo); + + if(DirInfo->OpenCount) { + UDFInterlockedDecrement((PLONG)&(DirInfo->OpenCount)); +#ifdef UDF_DBG + } else { + BrutePoint(); + KdPrint(("ERROR: Closing unopened file!\n")); +#endif // UDF_DBG + } + } + // If the file has gone (unlinked) we should return STATUS_SUCCESS here. + if(!FileInfo->Dloc) return STATUS_SUCCESS; + + if(FileInfo->RefCount || + FileInfo->OpenCount || + !(FileInfo->Dloc->FELoc.Mapping)) return STATUS_SUCCESS; +// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if(PartNum == (uint32)-1) { + KdPrint((" Is DELETED ?\n")); + if(DirInfo) { + PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation); + } else { + BrutePoint(); + } + } +#ifdef UDF_CHECK_DISK_ALLOCATION + if( FileInfo->Fcb && + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { + + //ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if(UDFIsAStreamDir(FileInfo)) { + if(!UDFIsSDirDeleted(FileInfo)) { + KdPrint((" Not DELETED SDir\n")); + BrutePoint(); + } + ASSERT(!FileInfo->Dloc->FELoc.Modified); + } else + if(!FileInfo->FileIdent || + !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { + if(!FileInfo->FileIdent) { + AdPrint((" No FileIdent\n")); + } + if(FileInfo->FileIdent && + !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) + AdPrint((" Not DELETED\n")); + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + BrutePoint(); + } else { + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free + } + } else { + if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation || + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free + } else { + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used + } + } +#endif // UDF_CHECK_DISK_ALLOCATION + // check if we should update parentICBLocation + if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum && + !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum && + DirInfo && + !Vcb->CDR_Mode && + Vcb->Modified && + UDFGetFileLinkCount(FileInfo) ) { + ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation); + ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = + UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation); + ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + } + + // we needn't flushing FE & Allocs untill all links are closed... + if(!FileInfo->Dloc->LinkRefCount) { + + // flush FE and pre-allocation charge for directories + if(FileInfo->Dloc && + FileInfo->Dloc->DirIndex) { + + UDFFlushFESpace(Vcb, FileInfo->Dloc); + if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { + FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; + status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); + FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED); + if(OS_SUCCESS(status)) { + AdPrint(("Dir pre-alloc truncated (Close)\n")); + FileInfo->Dloc->DataLoc.Modified = TRUE; + } + } + } + + if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) { + KdPrint(("Error flushing FE\n")); +//flush_recovery: + BrutePoint(); + if(FileInfo->Index >= 2) { + PDIR_INDEX_ITEM DirNdx; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); + if(DirNdx) { + KdPrint(("Recovery: mark as deleted & flush FI\n")); + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FileCharacteristics |= FILE_DELETED; + FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; + UDFFlushFI(Vcb, FileInfo, PartNum); + } + } + return status; + } + } + // ... but FI must be updated (if any) + if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) { + KdPrint(("Error flushing FI\n")); + return status; + } +#ifdef UDF_DBG +// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if((FileInfo->Dloc->FileEntry->descVersion != 2) && + (FileInfo->Dloc->FileEntry->descVersion != 3)) { + ASSERT(UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + } +#endif // UDF_DBG + return STATUS_SUCCESS; +} // end UDFCloseFile__() + + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine moves file from DirInfo1 to DirInfo2 & renames it to fn + */ +OSSTATUS +UDFRenameMoveFile__( + IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN OUT BOOLEAN* Replace, // replace if destination file exists + IN PUNICODE_STRING fn, // destination + IN OUT PUDF_FILE_INFO DirInfo1, + IN OUT PUDF_FILE_INFO DirInfo2, + IN OUT PUDF_FILE_INFO FileInfo // source (opened) + ) +{ + PUDF_FILE_INFO FileInfo2; + OSSTATUS status; + PDIR_INDEX_ITEM DirNdx1; + PDIR_INDEX_ITEM DirNdx2; + uint_di i,j; + BOOLEAN Recovery = FALSE; + BOOLEAN SameFE = FALSE; + uint32 NTAttr = 0; + + // validate FileInfo + ValidateFileInfo(DirInfo1); + ValidateFileInfo(DirInfo2); + ValidateFileInfo(FileInfo); + + i = j = 0; + if(DirInfo1 == DirInfo2) { + if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) && + (j==FileInfo->Index) ) { + // case-only rename + uint8* CS0; + uint32 Nlen, /* l, FIXME ReactOS */ IUl; + + // prepare filename + UDFCompressUnicode(fn, &CS0, &Nlen); + if(!CS0) return STATUS_INSUFFICIENT_RESOURCES; +/* if(Nlen > UDF_NAME_LEN) { + if(CS0) MyFreePool__(CS0); + return STATUS_OBJECT_NAME_INVALID; + }*/ + // allocate memory for FI + DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j); + IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse; +#if 0 + l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3); +#endif + + RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen); + RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length); + + if(CS0) MyFreePool__(CS0); + + DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + UDFBuildHashEntry(Vcb, &(DirNdx2->FName), &(DirNdx2->hashes), HASH_ALL); + return STATUS_SUCCESS; +/* } else + if(!OS_SUCCESS(status) && (fn->Length == UDFDirIndex(DirInfo2->Dloc->DirIndex, j=FileInfo->Index)->FName.Length)) { + // target file doesn't exist, but name lengthes are equal + RtlCopyMemory((DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex,j))->FName.Buffer, fn->Buffer, fn->Length); + DirNdx1->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + UDFBuildHashEntry(Vcb, &(DirNdx1->FName), &(DirNdx1->hashes), HASH_ALL); + return STATUS_SUCCESS;*/ + } + } + + // PHASE 0 + // try to create new FileIdent & FileEntry in Dir2 + +RenameRetry: + if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo), + 0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY), + TRUE, DirInfo2, &FileInfo2))) { + UDFCleanUpFile__(Vcb, FileInfo2); + if(FileInfo2) MyFreePool__(FileInfo2); + if(status == STATUS_ACCESS_DENIED) { + // try to recover >;-> + if((*Replace) && !Recovery) { + Recovery = TRUE; + status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL); + if(OS_SUCCESS(status)) { + status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2); + if(!OS_SUCCESS(status)) { + UDFCloseFile__(Vcb, FileInfo2); + goto cleanup_and_abort_rename; + } + status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE); +// UDFPretendFileDeleted__(Vcb, FileInfo2); + UDFCloseFile__(Vcb, FileInfo2); + if(UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + FileInfo2 = NULL; + if(SameFE) + return status; + } else { + // we get here if the FileInfo has associated + // system-specific Fcb + // Such fact means that not all system references + // has already gone (except Linked file case) +/* if(SameFE) + return status;*/ +// UDFRemoveOSReferences__(FileInfo2); + if(!OS_SUCCESS(status) || + (UDFGetFileLinkCount(FileInfo2) < 1)) + status = STATUS_ACCESS_DENIED; + } + if(OS_SUCCESS(status)) goto RenameRetry; + } +cleanup_and_abort_rename: + if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + FileInfo2 = NULL; + } + } else { + status = STATUS_OBJECT_NAME_COLLISION; + } + } + return status; + } + // update pointers + DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index); + DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index); + + // copy file attributes to newly created FileIdent + NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry); + FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; + // unlink source FileIdent + if(!OS_SUCCESS(status = UDFUnlinkFile__(Vcb, FileInfo, FALSE))) { + // kill newly created entry + UDFFlushFile__(Vcb, FileInfo2); + UDFUnlinkFile__(Vcb, FileInfo2, TRUE); + UDFCloseFile__(Vcb, FileInfo2); + UDFCleanUpFile__(Vcb, FileInfo2); + MyFreePool__(FileInfo2); + return status; + } + + // PHASE 1 + // drop all unnecessary info from FileInfo & flush FI + + DirNdx1->FileInfo = NULL; + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount), + -((LONG)(FileInfo->RefCount))); + // PHASE 2 + // copy all necessary info from FileInfo to FileInfo2 + + FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb; + FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics; + FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; + MyFreePool__(FileInfo->FileIdent); + FileInfo->FileIdent = NULL; + + // PHASE 3 + // copy all necessary info from FileInfo2 to FileInfo + + DirNdx2->FileInfo = FileInfo; + DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED; + DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc; + DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED; + UDFInterlockedExchangeAdd((PLONG)&(DirInfo2->OpenCount), + FileInfo->RefCount - FileInfo2->RefCount); + + UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr); + + FileInfo->Index = j; + FileInfo->FileIdent = FileInfo2->FileIdent; + FileInfo->FileIdentLen = FileInfo2->FileIdentLen; + FileInfo->ParentFile = DirInfo2; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + + ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation = + ((icbtag*)(FileInfo2->Dloc->FileEntry+1))->parentICBLocation; + + UDFIncFileLinkCount(FileInfo); // increase to 1 + +// UDFUpdateModifyTime(Vcb, FileInfo); + + // PHASE 4 + // drop all unnecessary info from FileInfo2 + + UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc)); + UDFUnlinkDloc(Vcb, FileInfo2->Dloc); + UDFDecFileLinkCount(FileInfo2); + + FileInfo2->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; +/* MyFreePool__(FileInfo2->Dloc->FileEntry); + FileInfo2->Dloc->FileEntry = NULL;*/ + FileInfo2->ParentFile = NULL; + FileInfo2->FileIdent = NULL; + FileInfo2->RefCount = 0; + FileInfo2->Dloc->LinkRefCount = 0; + ASSERT(FileInfo2->Dloc->DataLoc.Mapping); + FileInfo2->Dloc->DataLoc.Mapping[0].extLocation = 0; + FileInfo2->Dloc->DataLoc.Mapping[0].extLength = 0; + + UDFCleanUpFile__(Vcb, FileInfo2); + MyFreePool__(FileInfo2); + + // return 'delete target' status + (*Replace) = Recovery; + + return STATUS_SUCCESS; +} // end UDFRenameMoveFile__() + +/* + This routine transforms zero-sized file to directory + */ +OSSTATUS +UDFRecordDirectory__( + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO DirInfo // source (opened) + ) +{ + OSSTATUS status; + LONG_AD FEicb; + UDF_FILE_INFO FileInfo; + UDF_DATALOC_INFO Dloc; + UNICODE_STRING PName; + uint32 PartNum; + uint32 WrittenBytes; + PDIR_INDEX_ITEM CurDirNdx; + uint32 lba; + + // validate DirInfo + ValidateFileInfo(DirInfo); + if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile)) + return STATUS_ACCESS_DENIED; + // file should be empty + if(UDFGetFileSize(DirInfo)) { + if( DirInfo->FileIdent && + (DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY; + return STATUS_NOT_A_DIRECTORY; + } + if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY; + // create empty DirIndex + if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY; + if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index))) + CurDirNdx->FileCharacteristics |= FILE_DIRECTORY; + ((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY; + // init temporary FileInfo + RtlZeroMemory(&FileInfo, sizeof(UDF_FILE_INFO)); + FileInfo.Dloc = &Dloc; + FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry; + FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen; + FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc; + FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc; + FileInfo.ParentFile = DirInfo; + // prepare FileIdent for 'parent Dir' + lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation; + ASSERT(lba); + PartNum = UDFGetPartNumByPhysLba(Vcb, lba); + FEicb.extLength = Vcb->LBlockSize; + FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba); + FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; + RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); + PName.Buffer = (PWCH)L""; + PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR); + if(!OS_SUCCESS(status = + UDFBuildFileIdent(Vcb, &PName, &FEicb, 0, + &(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) )) + return status; + FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY); + UDFDecFileCounter(Vcb); + UDFIncDirCounter(Vcb); + // init structure + UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen), + FEicb.extLocation.logicalBlockNum); + FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata + // flush + status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes); +// status = UDFFlushFI(Vcb, &FileInfo, PartNum); + +#ifdef UDF_DBG + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == + ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); + } +#endif // UDF_DBG + + MyFreePool__(FileInfo.FileIdent); + if(!OS_SUCCESS(status)) return status; + if(CurDirNdx) CurDirNdx->FileCharacteristics = + DirInfo->FileIdent->fileCharacteristics; + return UDFIndexDirectory(Vcb, DirInfo); +} // end UDFRecordDirectory__() + +/* + This routine changes file size (on disc) + */ +OSSTATUS +UDFResizeFile__( + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo, + IN int64 NewLength + ) +{ + uint32 WrittenBytes; + OSSTATUS status; + uint32 PartNum; + int8* OldInIcb = NULL; + PEXTENT_MAP NewMap; + + KdPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength)); + ValidateFileInfo(FileInfo); +// ASSERT(FileInfo->RefCount >= 1); + + if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) { + KdPrint(("STATUS_DISK_FULL\n")); + return STATUS_DISK_FULL; + } + if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS; + if(FileInfo->ParentFile && (FileInfo->Index >= 2)) { + UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; + } + if(NewLength > FileInfo->Dloc->DataLoc.Length) { + // grow file + return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes); + } + // truncate file + if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) { + // check if we are already in IN_ICB mode + if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) { + // read data from old location + if(NewLength) { + OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)NewLength); + if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES; + status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes); + if(!OS_SUCCESS(status)) { + MyFreePool__(OldInIcb); + return status; + } + } else { + OldInIcb = NULL; + } + // allocate storage for new mapping + NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , 2*sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!(NewMap)) { + MyFreePool__(OldInIcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + // free old location... + if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation != + FileInfo->Dloc->FELoc.Mapping[0].extLocation) { + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); +mark_data_map_0: + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free + } else { + if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK) + > Vcb->LBlockSize) { + BrutePoint(); + FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize; + FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits); + goto mark_data_map_0; + } + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free + } + if(FileInfo->Dloc->AllocLoc.Mapping) { + if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK) + > Vcb->LBlockSize) { + FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize; + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits); + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free + } else { + UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free + } + MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping); + } + MyFreePool__(FileInfo->Dloc->DataLoc.Mapping); + FileInfo->Dloc->AllocLoc.Mapping = NULL; + FileInfo->Dloc->AllocLoc.Length = 0; + FileInfo->Dloc->AllocLoc.Offset = 0; + FileInfo->Dloc->AllocLoc.Modified = TRUE; + // switch to IN_ICB mode + ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; + ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB; + // init new data location descriptors + FileInfo->Dloc->DataLoc.Mapping = NewMap; + RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP)); + FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; + FileInfo->Dloc->DataLoc.Length = NewLength; + FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; + // write data to new location + if(OldInIcb) { + status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes); + } else { + status = STATUS_SUCCESS; + } + FileInfo->Dloc->DataLoc.Modified = TRUE; + if(OldInIcb) MyFreePool__(OldInIcb); + } else { + // just modify Length field + FileInfo->Dloc->DataLoc.Length = NewLength; + status = STATUS_SUCCESS; + } + } else { + // resize extent + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc)); + FileInfo->Dloc->DataLoc.Modified = TRUE; + FileInfo->Dloc->AllocLoc.Modified = TRUE; + } + if(OS_SUCCESS(status)) { + UDFSetFileSize(FileInfo, NewLength); + } + +#ifdef UDF_DBG + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); + } +#endif // UDF_DBG + + return status; +} // end UDFResizeFile__() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine loads VAT. + */ +OSSTATUS +UDFLoadVAT( + IN PVCB Vcb, + IN uint32 PartNdx + ) +{ + lb_addr VatFELoc; + OSSTATUS status; + PUDF_FILE_INFO VatFileInfo; + uint32 len, i=0, j, to_read; + uint32 Offset, hdrOffset; + uint32 ReadBytes; + uint32 root; + uint16 PartNum; +// uint32 VatFirstLba = 0; + int8* VatOldData; + uint32 VatLba[6] = { Vcb->LastLBA, + Vcb->LastLBA - 2, + Vcb->LastLBA - 3, + Vcb->LastLBA - 5, + Vcb->LastLBA - 7, + 0 }; + + if(Vcb->Vat) return STATUS_SUCCESS; + if(!Vcb->CDR_Mode) return STATUS_SUCCESS; + // disable VAT for now. We'll reenable it if VAT is successfuly loaded + Vcb->CDR_Mode = FALSE; + PartNum = Vcb->Partitions[PartNdx].PartitionNum; + root = Vcb->Partitions[PartNdx].PartitionRoot; + if(Vcb->LBlockSize != Vcb->BlockSize) { + // don't know how to operate... :((( + return STATUS_UNRECOGNIZED_VOLUME; + } + if((Vcb->LastTrackNum > 1) && + (Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) { + KdPrint(("Hardware Read-only volume\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + } + + VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG); + if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES; + // load VAT FE (we know its location) + VatFELoc.partitionReferenceNum = PartNum; +retry_load_vat: + VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]); + if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) { + UDFCleanUpFile__(Vcb, VatFileInfo); + // try another location + i++; + if( VatLba[i] && + (status != STATUS_FILE_CORRUPT_ERROR) && + (status != STATUS_CRC_ERROR)) goto retry_load_vat; + MyFreePool__(VatFileInfo); + Vcb->VatFileInfo = NULL; + return status; + } + len = (uint32)UDFGetFileSize(VatFileInfo); + if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) { + // load Vat 1.50 header + KdPrint(("Load VAT 1.50\n")); + VirtualAllocationTable15* Buf; + if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) { + status = STATUS_FILE_CORRUPT_ERROR; + goto err_vat_15; + } + Buf = (VirtualAllocationTable15*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable15)); + if(!Buf) { +err_vat_15_2: + status = STATUS_INSUFFICIENT_RESOURCES; +err_vat_15: + UDFCloseFile__(Vcb, VatFileInfo); + UDFCleanUpFile__(Vcb, VatFileInfo); + MyFreePool__(VatFileInfo); + Vcb->VatFileInfo = NULL; + return status; + } + Offset = 0; + to_read = + hdrOffset = len - sizeof(VirtualAllocationTable15); + MyFreePool__(Buf); + + Vcb->minUDFReadRev = + Vcb->minUDFWriteRev = + Vcb->maxUDFWriteRev = 0x0150; + + Vcb->numFiles = + Vcb->numDirs = -1; + + } else + if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) { + // load Vat 2.00 header + KdPrint(("Load VAT 2.00\n")); + VirtualAllocationTable20* Buf; + if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) { + status = STATUS_FILE_CORRUPT_ERROR; + goto err_vat_15; + } + Buf = (VirtualAllocationTable20*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable20)); + if(!Buf) goto err_vat_15_2; + Offset = Buf->lengthHeader; + to_read = len - Offset; + hdrOffset = 0; + MyFreePool__(Buf); + + Vcb->minUDFReadRev = Buf->minReadRevision; + Vcb->minUDFWriteRev = Buf->minWriteRevision; + Vcb->maxUDFWriteRev = Buf->maxWriteRevision; + + Vcb->numFiles = Buf->numFIDSFiles; + Vcb->numDirs = Buf->numFIDSDirectories; + + } else { + // unknown (or wrong) VAT format + KdPrint(("unknown (or wrong) VAT format\n")); + status = STATUS_FILE_CORRUPT_ERROR; + goto err_vat_15; + } + // read VAT & remember old version + Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) ); + if(!Vcb->Vat) { + goto err_vat_15_2; + } + // store base version of VAT in memory + VatOldData = (int8*)DbgAllocatePool(PagedPool, len); + if(!VatOldData) { + DbgFreePool(Vcb->Vat); + Vcb->Vat = NULL; + goto err_vat_15_2; + } + status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes); + if(!OS_SUCCESS(status)) { + UDFCloseFile__(Vcb, VatFileInfo); + UDFCleanUpFile__(Vcb, VatFileInfo); + MyFreePool__(VatFileInfo); + DbgFreePool(Vcb->Vat); + DbgFreePool(VatOldData); + Vcb->Vat = NULL; + Vcb->VatFileInfo = NULL; + } else { + // initialize VAT + // !!! NOTE !!! + // Both VAT copies - in-memory & on-disc + // contain _relative_ addresses + len = Vcb->NWA - root; + for(i=0; i<=len; i++) { + Vcb->Vat[i] = i; + } + RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read); + Vcb->InitVatCount = + Vcb->VatCount = to_read/sizeof(uint32); + Vcb->VatPartNdx = PartNdx; + Vcb->CDR_Mode = TRUE; + len = Vcb->VatCount; + RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff); + // sync VAT and FSBM + for(i=0; iVat[i] == UDF_VAT_FREE_ENTRY) { + UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i); + } + } + len = Vcb->LastPossibleLBA; + // "pre-format" reserved area + for(i=Vcb->NWA; iFSBM_Bitmap, i); + for(j=0; (j<7) && (iFSBM_Bitmap, i); + } + DbgFreePool(VatOldData); + } + return status; +} // end UDFLoadVAT() + +/* + Reads Extended Attributes + Caller should use UDFGetFileEALength to allocate Buffer of sufficient + size + *//* +OSSTATUS +UDFReadFileEA( + IN PVCB Vcb, + IN PDIR_INDEX FileDirNdx, + OUT int8* Buffer + ) +{ + PFILE_ENTRY FileEntry; + OSSTATUS status; + + if(FileDirNdx->FileInfo) { + FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); + } else { + FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->BlockSize); + if(!FileEntry) return; + if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileDirNdx->FileEntry), FileEntry, &Ident))) { + MyFreePool__(FileEntry); + return status; + } + } +}*/ +/* + This dumb routine checks if the file has been found is deleted + It is introduced to make main modules FS-type independent + */ +/*BOOLEAN +UDFIsDeleted( + IN PDIR_INDEX DirNdx + ) +{ + return (DirNdx->FileCharacteristics & FILE_DELETED); +} */ + +/*BOOLEAN +UDFIsADirectory( + IN PUDF_FILE_INFO FileInfo + ) +{ + ValidateFileInfo(FileInfo); + + if(!FileInfo) return FALSE; + if(FileInfo->Dloc->DirIndex) return TRUE; + if(!(FileInfo->FileIdent)) return FALSE; + return (FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY); +} */ +/* + This routine calculates actual allocation size + */ +/*int64 +UDFGetFileAllocationSize( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + ValidateFileInfo(FileInfo); + + return UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping);// + +// UDFGetExtentLength(FileInfo->Dloc->FELoc.Mapping) + +// UDFGetExtentLength(FileInfo->Dloc->AllocLoc.Mapping) - Vcb->BlockSize; +}*/ + +/* + This routine checks if the directory is empty + */ +BOOLEAN +UDFIsDirEmpty( + IN PDIR_INDEX_HDR hCurDirNdx + ) +{ + uint32 fc; + uint_di i; + PDIR_INDEX_ITEM CurDirNdx; + // not empty + for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { + fc = CurDirNdx->FileCharacteristics; + if(!(fc & (FILE_PARENT | FILE_DELETED)) && + CurDirNdx->Length) + return FALSE; + } + return TRUE; +} // end UDFIsDirEmpty() + +/* + */ +OSSTATUS +UDFFlushFE( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum + ) +{ + int8* NewAllocDescs; + OSSTATUS status; + uint32 WrittenBytes; + uint16 AllocMode; + uint32 lba; + + AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; +#ifdef UDF_DBG +/* if(UDFIsADirectory(FileInfo) && (UDFGetFileSize(FileInfo) < 0x28) && + !UDFIsDeleted(UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index)) ) { + BrutePoint(); + }*/ +// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if(FileInfo->Dloc->FELoc.Offset) { + BrutePoint(); + } + if(FileInfo->Dloc->AllocLoc.Mapping) { + ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); + } +#endif // UDF_DBG +retry_flush_FE: + KdPrint((" FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); +#ifndef UDF_READ_ONLY_BUILD + UDFReTagDirectory(Vcb, FileInfo); + if(FileInfo->Dloc->DataLoc.Modified || + FileInfo->Dloc->AllocLoc.Modified) { + ASSERT(PartNum != (uint32)(-1)); + // prepare new AllocDescs for flushing... + if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) { + KdPrint((" FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status)); + if(NewAllocDescs) + MyFreePool__(NewAllocDescs); + return status; + } +#ifdef UDF_DBG + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); + } + AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; +#endif // UDF_DBG + // initiate update of lengthAllocDescs + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + if(NewAllocDescs) { + ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); + status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc)); + // ... and flush it + status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes); + MyFreePool__(NewAllocDescs); + if(!OS_SUCCESS(status)) { + KdPrint((" FlushFE: UDFWriteExtent() faliled (%x)\n", status)); + return status; + } +#ifdef UDF_DBG + } else { + ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB); +#endif // UDF_DBG + } + FileInfo->Dloc->DataLoc.Modified = FALSE; + FileInfo->Dloc->AllocLoc.Modified = FALSE; + } else { +#if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL) + if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); + } +#endif // UDF_DBG + } +/* if(FileInfo->Fcb && + ((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) || + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) { + BrutePoint(); + }*/ +/* if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) { + ASSERT( FileInfo->Dloc->FileEntry->tagLocation == + (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580)); + }*/ + if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || + FileInfo->Dloc->FELoc.Modified) { + ASSERT(PartNum != (uint32)(-1)); + ASSERT(!PartNum); + if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) { + KdPrint((" bad PartNum: %d\n", PartNum)); + } + // update lengthAllocDescs in FE + UDFSetAllocDescLen(Vcb, FileInfo); +/* ASSERT( FileInfo->Dloc->FileEntry->tagLocation == + (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/ + // flush FileEntry + + // if FE is located in remapped block, place it to reliable space + lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation; + if(Vcb->BSBM_Bitmap) { + if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) { + AdPrint((" bad block under FE @%x\n", lba)); + goto relocate_FE; + } + } + + AdPrint((" setup tag: @%x\n", lba)); + ASSERT( lba ); + UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen), + UDFPhysLbaToPart(Vcb, PartNum, lba)); + status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0, + (uint32)(FileInfo->Dloc->FELoc.Length), FALSE, + (int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes); + if(!OS_SUCCESS(status)) { + KdPrint((" FlushFE: UDFWriteExtent(2) faliled (%x)\n", status)); + if(status == STATUS_DEVICE_DATA_ERROR) { +relocate_FE: + KdPrint((" try to relocate\n")); + + EXTENT_INFO _FEExtInfo; + // calculate the length required + + // allocate block for FE + if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) { + KdPrint((" relocate %x -> %x\n", + lba, + _FEExtInfo.Mapping[0].extLocation)); + + UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD); + + UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation); + MyFreePool__(FileInfo->Dloc->FELoc.Mapping); + FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping; + + FileInfo->Dloc->FELoc.Modified = TRUE; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + + AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; + if(AllocMode == ICB_FLAG_AD_IN_ICB) { + KdPrint((" IN-ICB data lost\n")); + FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation; + FileInfo->Dloc->DataLoc.Modified = TRUE; + } else { + FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation; + FileInfo->Dloc->AllocLoc.Modified = TRUE; + } + + if(FileInfo->Index >= 2) { + PDIR_INDEX_ITEM DirNdx; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); + if(DirNdx) { + KdPrint((" update reference in FI\n")); + DirNdx->FileEntryLoc.logicalBlockNum = + FileInfo->FileIdent->icb.extLocation.logicalBlockNum = + UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation); + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + } + } + // this will update + KdPrint((" retry flush...\n")); + goto retry_flush_FE; + } + } + BrutePoint(); + return status; + } + FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; + FileInfo->Dloc->FELoc.Modified = FALSE; + } else { + ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) || + (FileInfo->Dloc->FileEntry->descVersion == 3)); + } +#endif //UDF_READ_ONLY_BUILD +#ifdef UDF_DBG + if(FileInfo->Dloc->AllocLoc.Mapping) { + ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); + } else { + ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB); + } +#endif // UDF_DBG + return STATUS_SUCCESS; +} // end UDFFlushFE() + +OSSTATUS +UDFFlushFI( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum + ) +{ + PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; + PDIR_INDEX_ITEM DirNdx; + OSSTATUS status; + uint32 WrittenBytes; + // use WrittenBytes variable to store LBA of FI to be recorded + #define lba WrittenBytes + +// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + // some files has no FI + if(!DirInfo || UDFIsAStreamDir(FileInfo)) + return STATUS_SUCCESS; + DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index); +// ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80); +#ifdef UDF_DBG + if(DirNdx->FileCharacteristics & FILE_DELETED) { + ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED); + } +#endif // UDF_DBG + KdPrint((" FlushFI: offs %x\n", (ULONG)(DirNdx->Offset))); +#ifndef UDF_READ_ONLY_BUILD + if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) { + // flush FileIdent + ASSERT(PartNum != (uint32)(-1)); + FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics; + lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping, + DirNdx->Offset, NULL, NULL, NULL, NULL); + AdPrint((" FI lba %x\n", lba)); + // check if requested Offset is allocated + if(lba == (uint32)LBA_OUT_OF_EXTENT) { + // write 1 byte + if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) { + BrutePoint(); + return status; + } + lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping, + DirNdx->Offset, NULL, NULL, NULL, NULL); + AdPrint((" allocated FI lba %x\n", lba)); + // check if requested Offset is allocated + if(lba == (uint32)LBA_OUT_OF_EXTENT) { + BrutePoint(); + return STATUS_UNSUCCESSFUL; + } + } + // init structure + UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen), + UDFPhysLbaToPart(Vcb, PartNum, lba)); + // record data + if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) { + BrutePoint(); + return status; + } + DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED; + } +#endif //UDF_READ_ONLY_BUILD + return STATUS_SUCCESS; +} // end UDFFlushFI() + +/* + This routine updates AllocDesc sequence, FileIdent & FileEntry + for given file + */ +OSSTATUS +UDFFlushFile__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN ULONG FlushFlags + ) +{ + ValidateFileInfo(FileInfo); + + if(!FileInfo) return STATUS_SUCCESS; + OSSTATUS status; + uint32 PartNum; + + ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); + PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + if(PartNum == (uint32)-1) { + KdPrint((" Is DELETED ?\n")); + if(FileInfo->ParentFile) { + PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation); + } else { + BrutePoint(); + } + } +#ifdef UDF_CHECK_DISK_ALLOCATION + if( FileInfo->Fcb && + UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { + + if(UDFIsAStreamDir(FileInfo)) { + if(!UDFIsSDirDeleted(FileInfo)) { + KdPrint((" Not DELETED SDir\n")); + BrutePoint(); + } + ASSERT(!FileInfo->Dloc->FELoc.Modified); + } else + if(!FileInfo->FileIdent || + !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { + if(!FileInfo->FileIdent) + AdPrint((" No FileIdent\n")); + if(FileInfo->FileIdent && + !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) + AdPrint((" Not DELETED\n")); + AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); + BrutePoint(); + } + } +#endif // UDF_CHECK_DISK_ALLOCATION + + // flush FE and pre-allocation charge for directories + if(FileInfo->Dloc && + FileInfo->Dloc->DirIndex) { + // if Lite Flush is used, keep preallocations + if(!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) { +full_flush: + UDFFlushFESpace(Vcb, FileInfo->Dloc); + if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { + FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; + status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); + FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED); + if(OS_SUCCESS(status)) { + AdPrint(("Dir pre-alloc truncated (Flush)\n")); + FileInfo->Dloc->DataLoc.Modified = TRUE; + } + } + } + } + // flush FE + if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) { + KdPrint(("Error flushing FE\n")); + BrutePoint(); + if(FlushFlags & UDF_FLUSH_FLAGS_LITE) { + KdPrint((" flush pre-alloc\n")); + FlushFlags &= ~UDF_FLUSH_FLAGS_LITE; + goto full_flush; + } + if(FileInfo->Index >= 2) { + PDIR_INDEX_ITEM DirNdx; + DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); + if(DirNdx) { + KdPrint(("Recovery: mark as deleted & flush FI\n")); + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FileCharacteristics |= FILE_DELETED; + FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; + UDFFlushFI(Vcb, FileInfo, PartNum); + } + } + return status; + } + if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) + return status; + + ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) || + (FileInfo->Dloc->FileEntry->descVersion == 3)); + + return STATUS_SUCCESS; +} // end UDFFlushFile__() + +/* + This routine compares 2 FileInfo structures + */ +BOOLEAN +UDFCompareFileInfo( + IN PUDF_FILE_INFO f1, + IN PUDF_FILE_INFO f2 + ) +{ + uint_di i; + PDIR_INDEX_HDR hDirIndex1; + PDIR_INDEX_HDR hDirIndex2; + PDIR_INDEX_ITEM DirIndex1; + PDIR_INDEX_ITEM DirIndex2; + + if(!f1 || !f2) return FALSE; + if(f1->Dloc->FileEntryLen != f2->Dloc->FileEntryLen) return FALSE; +// if(f1->FileIdentLen != f2->FileIdentLen) return FALSE; +/* if(f1->Dloc->DirIndex && !f2->Dloc->DirIndex) return FALSE; + if(f2->Dloc->DirIndex && !f1->Dloc->DirIndex) return FALSE; + if((f1->Dloc->DirIndex) && + (f1->Dloc->DirIndex->LastFrameCount != f2->Dloc->DirIndex->LastFrameCount)) return FALSE;*/ + if(f1->Index != f2->Index) return FALSE; + if(!(f1->Dloc->DataLoc.Mapping)) return FALSE; + if(!(f2->Dloc->DataLoc.Mapping)) return FALSE; + if(f1->Dloc->DataLoc.Mapping[0].extLocation != f2->Dloc->DataLoc.Mapping[0].extLocation) return FALSE; + if(f1->Dloc->DataLoc.Mapping[0].extLength != f2->Dloc->DataLoc.Mapping[0].extLength) return FALSE; +// if(f1-> != f2->) return FALSE; +// if(f1-> != f2->) return FALSE; +// if(f1-> != f2->) return FALSE; + if(!(f1->Dloc->FileEntry)) return FALSE; + if(!(f2->Dloc->FileEntry)) return FALSE; + if(RtlCompareMemory(f1->Dloc->FileEntry, f2->Dloc->FileEntry, f2->Dloc->FileEntryLen) != f2->Dloc->FileEntryLen) + return FALSE; + if(!(hDirIndex1 = f1->Dloc->DirIndex)) return FALSE; + if(!(hDirIndex2 = f2->Dloc->DirIndex)) return FALSE; + + for(i=2; (DirIndex1 = UDFDirIndex(hDirIndex1,i)) && + (DirIndex2 = UDFDirIndex(hDirIndex2,i)); i++) { + if( DirIndex1->FName.Buffer && + !DirIndex2->FName.Buffer) + return FALSE; + if( DirIndex2->FName.Buffer && + !DirIndex1->FName.Buffer) + return FALSE; + if(!DirIndex2->FName.Buffer && + !DirIndex1->FName.Buffer) + continue; + if(RtlCompareUnicodeString(&(DirIndex1->FName), + &(DirIndex2->FName),FALSE)) { + return FALSE; + } +// if(DirIndex1[i].FileEntry != DirIndex2[i].FileEntry) +// return FALSE; + if(RtlCompareMemory(&(DirIndex1->FileEntryLoc), + &(DirIndex2->FileEntryLoc), sizeof(lb_addr)) != sizeof(lb_addr)) + return FALSE; + } + + return TRUE; +} // end UDFCompareFileInfo() + +/* + This routine computes 32-bit hash based on CRC-32 from SSH + */ + +#pragma warning(push) +#pragma warning(disable:4035) // re-enable below + +//#ifdef _X86_ +#ifdef _MSC_VER +__declspec (naked) +#endif // _X86_ +uint32 +__fastcall +crc32( + IN uint8* s, // ECX + IN uint32 len // EDX + ) +{ +//#ifdef _X86_ +#ifdef _MSC_VER +// uint32 _Size = len; + + __asm { + push ebx + push ecx + push edx + push esi + + xor eax,eax + mov esi,ecx // ESI <- s + mov ecx,edx // ECX <- len + + jecxz EO_CRC + + lea ebx,[crc32_tab] + xor edx,edx + +CRC_loop: + + mov dl,al + xor dl,[esi] + shr eax,8 + xor eax,[dword ptr ebx+edx*4] + inc esi + loop CRC_loop + +EO_CRC: + + pop esi + pop edx + pop ecx + pop ebx + + ret + } +#else // NO X86 optimization , use generic C/C++ + uint32 i; + uint32 crc32val = 0; + + for(i=0; i> 8); + } + return crc32val; +#endif // _X86_ +} // end crc32() + +/* + Calculate a 16-bit CRC checksum for unicode strings + using ITU-T V.41 polynomial. + + The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. + The polynomial used is: x^16 + x^12 + x^15 + 1 +*/ + +//#ifdef _X86_ +#ifdef _MSC_VER +__declspec (naked) +#endif // _X86_ +uint16 +__fastcall +UDFUnicodeCksum( + PWCHAR s, // ECX + uint32 n // EDX + ) +{ +//#ifdef _X86_ +#ifdef _MSC_VER +// uint32 _Size = n; + + __asm { + push ebx + push ecx + push edx + push esi + + xor eax,eax + mov esi,ecx + mov ecx,edx + + jecxz EO_uCRC + + lea ebx,[CrcTable] + xor edx,edx + +uCRC_loop: + + mov dl,ah // dl = (Crc >> 8) + xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff + mov ah,al + mov al,dh // ax = (Crc << 8) + xor ax,[word ptr ebx+edx*2] // ax = ........... + + mov dl,ah + xor dl,[esi] + mov ah,al + mov al,dh + xor ax,[word ptr ebx+edx*2] + + inc esi + inc esi + loop uCRC_loop + +EO_uCRC: + + pop esi + pop edx + pop ecx + pop ebx + + ret + } +#else // NO X86 optimization , use generic C/C++ + uint16 Crc = 0; + while (n--) { + Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8); + Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8); + } + return Crc; + +#endif // _X86_ +} // end UDFUnicodeCksum() + +//#ifdef _X86_ +#ifdef _MSC_VER +__declspec (naked) +#endif // _X86_ +uint16 +__fastcall +UDFUnicodeCksum150( + PWCHAR s, // ECX + uint32 n // EDX + ) +{ +//#ifdef _X86_ +#ifdef _MSC_VER +// uint32 _Size = n; + + __asm { + push ebx + push ecx + push edx + push esi + push edi + + xor eax,eax + mov esi,ecx + mov ecx,edx + xor edi,edi + + jecxz EO_uCRC + + //lea ebx,[CrcTable] + xor edx,edx + xor ebx,ebx + +uCRC_loop: + + mov dl,ah // dl = (Crc >> 8) + or edi,edx // if(*s & 0xff00) Use16 = TRUE; + xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff + mov ah,al + mov al,0 // ax = (Crc << 8) + xor ax,[word ptr CrcTable+edx*2] // ax = ........... + + mov dl,ah + xor dl,[esi] + mov ah,al + mov al,0 + xor ax,[word ptr CrcTable+edx*2] + + or edi,edi // if(!Use16) { + jnz use16_1 + + rol eax,16 + + mov bl,ah // dl = (Crc >> 8) + xor bl,[esi] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff + mov ah,al + mov al,0 // ax = (Crc << 8) + xor ax,[word ptr CrcTable+ebx*2] // ax = ........... + + rol eax,16 +use16_1: + inc esi + inc esi + loop uCRC_loop + +EO_uCRC: + + or edi,edi // if(!Use16) { + jnz use16_2 + + rol eax,16 // } +use16_2: + and eax,0xffff + + pop edi + pop esi + pop edx + pop ecx + pop ebx + + ret + } +#else // NO X86 optimization , use generic C/C++ + uint16 Crc = 0; + uint16 Crc2 = 0; + BOOLEAN Use16 = FALSE; + while (n--) { + if(!Use16) { + if((*s) & 0xff00) { + Use16 = TRUE; + } else { + Crc2 = CrcTable[(Crc2 >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc2 << 8); + } + } + Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8); + Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8); + } + return Use16 ? Crc : Crc2; +#endif // _X86_ +} // end UDFUnicodeCksum150() + +/* + Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. + + The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. + The polynomial used is: x^16 + x^12 + x^15 + 1 +*/ +//#ifdef _X86_ +#ifdef _MSC_VER +__declspec (naked) +#endif // _X86_ +uint16 +__fastcall +UDFCrc( + IN uint8* Data, // ECX + IN uint32 Size // EDX + ) +{ +//#ifdef _X86_ +#ifdef _MSC_VER +// uint32 _Size = Size; + + __asm { + push ebx + push ecx + push edx + push esi + + mov esi,ecx + mov ecx,edx + xor eax,eax + + jecxz EO_CRC + + lea ebx,[CrcTable] + xor edx,edx + +CRC_loop: + + mov dl,ah + xor dl,[esi] + mov ah,al + mov al,dh + xor ax,[word ptr ebx+edx*2] + inc esi + loop CRC_loop + +EO_CRC: + + pop esi + pop edx + pop ecx + pop ebx + + ret + } +#else // NO X86 optimization , use generic C/C++ + uint16 Crc = 0; + while (Size--) + Crc = CrcTable[(Crc >> 8 ^ *Data++) & 0xff] ^ (Crc << 8); + return Crc; +#endif // _X86_ + +} // end UDFCrc() + +#pragma warning(pop) // re-enable warning #4035 + +/* + Read the first block of a tagged descriptor & check it. +*/ +OSSTATUS +UDFReadTagged( + PVCB Vcb, + int8* Buf, + uint32 Block, + uint32 Location, + uint16 *Ident + ) +{ + OSSTATUS RC; + tag* PTag = (tag*)Buf; +// icbtag* Icb = (icbtag*)(Buf+1); + uint8 checksum; + unsigned int i; + uint32 ReadBytes; + int8* tb; + + // Read the block + if(Block == 0xFFFFFFFF) + return NULL; + + _SEH2_TRY { + RC = UDFReadSectors(Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes); + if(!OS_SUCCESS(RC)) { + KdPrint(("UDF: Block=%x, Location=%x: read failed\n", Block, Location)); + try_return(RC); + } + + *Ident = PTag->tagIdent; + + if(Location != PTag->tagLocation) { + KdPrint(("UDF: location mismatch block %x, tag %x != %x\n", + Block, PTag->tagLocation, Location)); + try_return(RC = STATUS_FILE_CORRUPT_ERROR); + } + + /* Verify the tag checksum */ + checksum = 0; + tb = Buf; + for (i=0; itagChecksum) { + KdPrint(("UDF: tag checksum failed block %x\n", Block)); + try_return(RC = STATUS_CRC_ERROR); + } + + // Verify the tag version + if((PTag->descVersion != 2) && + (PTag->descVersion != 3)) { + KdPrint(("UDF: Tag version 0x%04x != 0x0002 || 0x0003 block %x\n", + (PTag->descVersion), Block)); + try_return(RC = STATUS_FILE_CORRUPT_ERROR); + } + + // Verify the descriptor CRC + if(((PTag->descCRCLength) + sizeof(tag) > Vcb->BlockSize) || + ((PTag->descCRC) == UDFCrc((uint8*)Buf + sizeof(tag), PTag->descCRCLength)) || + !(PTag->descCRC) ) { + /* KdPrint(("Tag ID: %x, ver %x\t", PTag->tagIdent, PTag->descVersion )); + if((i == TID_FILE_ENTRY) || + (i == TID_EXTENDED_FILE_ENTRY)) { + KdPrint(("StrategType: %x, ", Icb->strategyType )); + KdPrint(("FileType: %x\t", Icb->fileType )); + } + KdPrint(("\n"));*/ + try_return(RC = STATUS_SUCCESS); + } + KdPrint(("UDF: Crc failure block %x: crc = %x, crclen = %x\n", + Block, PTag->descCRC, PTag->descCRCLength)); + RC = STATUS_CRC_ERROR; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + ; + } _SEH2_END + + return RC; +} // end UDFReadTagged() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine creates hard link for the file from DirInfo1 + to DirInfo2 & names it as fn + */ +OSSTATUS +UDFHardLinkFile__( + IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN OUT BOOLEAN* Replace, // replace if destination file exists + IN PUNICODE_STRING fn, // destination + IN OUT PUDF_FILE_INFO DirInfo1, + IN OUT PUDF_FILE_INFO DirInfo2, + IN OUT PUDF_FILE_INFO FileInfo // source (opened) + ) +{ + PUDF_FILE_INFO FileInfo2; + OSSTATUS status; + PDIR_INDEX_ITEM DirNdx1; + PDIR_INDEX_ITEM DirNdx2; + uint_di i; + BOOLEAN Recovery = FALSE; + BOOLEAN SameFE = FALSE; + uint32 NTAttr = 0; + + // validate FileInfo + ValidateFileInfo(DirInfo1); + ValidateFileInfo(DirInfo2); + ValidateFileInfo(FileInfo); + + if(UDFGetFileLinkCount(FileInfo) >= UDF_MAX_LINK_COUNT) { + // too many links to file... + return STATUS_TOO_MANY_LINKS; + } + + i = 0; + if(DirInfo1 == DirInfo2) { + if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &i)) && + (i==FileInfo->Index) ) { + // case-only difference + return STATUS_OBJECT_NAME_COLLISION; + } + } + + // PHASE 0 + // try to create new FileIdent & FileEntry in Dir2 + +HLinkRetry: + if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo), + 0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY), + TRUE, DirInfo2, &FileInfo2))) { + if(UDFCleanUpFile__(Vcb, FileInfo2) && FileInfo2) + MyFreePool__(FileInfo2); + if(status == STATUS_ACCESS_DENIED) { + // try to recover >;-> + if((*Replace) && !Recovery) { + Recovery = TRUE; + status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL); + if(OS_SUCCESS(status)) { + status = UDFDoesOSAllowFileToBeTargetForHLink__(FileInfo2); + if(!OS_SUCCESS(status)) { + UDFCloseFile__(Vcb, FileInfo2); + goto cleanup_and_abort_hlink; + } + if((FileInfo->Dloc == FileInfo2->Dloc) && + (FileInfo != FileInfo2)) { + SameFE = TRUE; + // 'status' is already STATUS_SUCCESS here + } else { + status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE); + } + UDFCloseFile__(Vcb, FileInfo2); + if(UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + FileInfo2 = NULL; + if(SameFE) + return STATUS_SUCCESS; + } else { + // we get here if the FileInfo has associated + // system-specific Fcb + // Such fact means that not all system references + // has already gone (except Linked file case) + if(SameFE) + return STATUS_SUCCESS; + if(!OS_SUCCESS(status) || + (UDFGetFileLinkCount(FileInfo) < 1)) + status = STATUS_ACCESS_DENIED; + } + if(OS_SUCCESS(status)) goto HLinkRetry; + } +cleanup_and_abort_hlink: + if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + FileInfo2 = NULL; + } + } else { + status = STATUS_OBJECT_NAME_COLLISION; + } + } + return status; + } + // update pointers + DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, FileInfo->Index); + DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, FileInfo2->Index); + + // copy file attributes to newly created FileIdent + NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry); + FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; + + // PHASE 1 + // copy all necessary info from FileInfo to FileInfo2 + + FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb; + FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics; + FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; + + DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED; + DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc; + DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED | UDF_FI_FLAG_LINKED; + + UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr); + + // PHASE 2 + // update FileInfo + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + DirNdx1->FI_Flags = DirNdx2->FI_Flags; + UDFIncFileLinkCount(FileInfo); // increase to 1 +// UDFUpdateModifyTime(Vcb, FileInfo); + FileInfo->Dloc->LinkRefCount += FileInfo2->Dloc->LinkRefCount; + if(FileInfo2->FileIdent) + ((FidADImpUse*)&(FileInfo2->FileIdent->icb.impUse))->uniqueID = (uint32)UDFAssingNewFUID(Vcb); + + // PHASE 3 + // drop all unnecessary info from FileInfo2 + + UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc)); + UDFRemoveDloc(Vcb, FileInfo2->Dloc); + + // PHASE 4 + // perform in-memory linkage (update driver's tree structures) and flush + + FileInfo2->Dloc = FileInfo->Dloc; + UDFInsertLinkedFile(FileInfo2, FileInfo); + + UDFCloseFile__(Vcb, FileInfo2); + if(UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + } + // return 'delete target' status + (*Replace) = Recovery; + + return STATUS_SUCCESS; +} // end UDFHardLinkFile__() + +/* + This routine allocates FileEntry with in-ICB zero-sized data + If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ + for returned pointer *WITHOUT* using UDFCloseFile__ + */ +OSSTATUS +UDFCreateRootFile__( + IN PVCB Vcb, +// IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB + IN uint32 PartNum, + IN uint32 ExtAttrSz, + IN uint32 ImpUseLen, + IN BOOLEAN Extended, + OUT PUDF_FILE_INFO* _FileInfo + ) +{ + OSSTATUS status; + LONG_AD FEicb; + PUDF_FILE_INFO FileInfo; + *_FileInfo = NULL; + uint32 ReadBytes; + + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); + *_FileInfo = FileInfo; + if(!FileInfo) + return STATUS_INSUFFICIENT_RESOURCES; + ImpUseLen = (ImpUseLen + 3) & ~((uint16)3); + + RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); + // init horizontal links + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + // allocate space for FileEntry + if(!OS_SUCCESS(status = + UDFBuildFileEntry(Vcb, NULL, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) + return status; + FEicb.extLength = Vcb->LBlockSize; + FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; + RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); + + FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0])); + if(!(FileInfo->Dloc->DataLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; + FileInfo->Dloc->DataLoc.Length = 0; + FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; + // init FileEntry + UDFSetFileUID(Vcb, FileInfo); + UDFSetFileSize(FileInfo, 0); + UDFIncFileLinkCount(FileInfo); // increase to 1 + UDFUpdateCreateTime(Vcb, FileInfo); + // zero sector for FileEntry + FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; + FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; + status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, Vcb->LBlockSize, FALSE, Vcb->ZBuffer, &ReadBytes); + if(!OS_SUCCESS(status)) + return status; + + UDFReferenceFile__(FileInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + return STATUS_SUCCESS; +} // end UDFCreateRootFile__() + +/* + This routine tries to create StreamDirectory associated with given file + Caller should use UDFCleanUpFile__ if returned status != STATUS_SUCCESS + */ +OSSTATUS +UDFCreateStreamDir__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, // file containing stream-dir + OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain + // any pointers + ) +{ + OSSTATUS status; + PUDF_FILE_INFO SDirInfo; + uint16 Ident; + + *_SDirInfo = NULL; + ValidateFileInfo(FileInfo); + // check currently recorded UDF revision + if(!UDFStreamsSupported(Vcb)) + return STATUS_INVALID_PARAMETER; + // check if we are allowed to associate Stream Dir with this file + if((FileInfo->ParentFile && UDFIsAStreamDir(FileInfo->ParentFile)) || + UDFHasAStreamDir(FileInfo)) + return STATUS_FILE_DELETED; + // check if we have Deleted SDir + if(FileInfo->Dloc->SDirInfo && + UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo)) + return STATUS_ACCESS_DENIED; + // check if this file has ExtendedFileEntry + if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) { + if(!OS_SUCCESS(status = UDFConvertFEToExtended(Vcb, FileInfo))) + return status; + } + + uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); + // create stream directory file + if(!OS_SUCCESS(status = UDFCreateRootFile__(Vcb, PartNum, 0,0,FALSE, &SDirInfo))) + return status; + // link objects + SDirInfo->ParentFile = FileInfo; + // record directory structure + SDirInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_IS_SDIR); + + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; + UDFIncFileLinkCount(FileInfo); + FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR; + + status = UDFRecordDirectory__(Vcb, SDirInfo); + UDFDecDirCounter(Vcb); + + UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount)); + if(!OS_SUCCESS(status)) { + UDFUnlinkFile__(Vcb, SDirInfo, TRUE); + UDFCloseFile__(Vcb, SDirInfo); + UDFCleanUpFile__(Vcb, SDirInfo); + MyFreePool__(SDirInfo); + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = 0; + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = 0; + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 0; + return status; + } + *_SDirInfo = SDirInfo; + // do some init + ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->icbTag.fileType = UDF_FILE_TYPE_STREAMDIR; + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = Vcb->LBlockSize; + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = (uint16)PartNum; + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = + UDFPhysLbaToPart(Vcb, PartNum, SDirInfo->Dloc->FELoc.Mapping[0].extLocation); + ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->uniqueID = + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->uniqueID; + FileInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_HAS_SDIR); + // open & finalize linkage + FileInfo->Dloc->SDirInfo = SDirInfo; + return STATUS_SUCCESS; +} // end UDFCreateStreamDir__() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine opens Stream Directory associated with file specified + */ +OSSTATUS +UDFOpenStreamDir__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, // file containing stream-dir + OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain + // any pointers + ) +{ + OSSTATUS status; + PUDF_FILE_INFO SDirInfo; + PUDF_FILE_INFO ParSDirInfo; + uint16 Ident; + + *_SDirInfo = NULL; + ValidateFileInfo(FileInfo); + // check if this file has ExtendedFileEntry + if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) { + return STATUS_NOT_FOUND; + } + if((SDirInfo = FileInfo->Dloc->SDirInfo)) { + // it is already opened. Good... + + // check if we have Deleted SDir + if(FileInfo->Dloc->SDirInfo && + UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo)) + return STATUS_FILE_DELETED; + // All right. Look for parallel SDir (if any) + if(SDirInfo->ParentFile != FileInfo) { + ParSDirInfo = UDFLocateParallelFI(FileInfo, 0, SDirInfo); + BrutePoint(); + if(ParSDirInfo->ParentFile != FileInfo) { + SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG); + *_SDirInfo = SDirInfo; + if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(SDirInfo, FileInfo->Dloc->SDirInfo, sizeof(UDF_FILE_INFO)); + // SDirInfo->NextLinkedFile = FileInfo->Dloc->SDirInfo->NextLinkedFile; // is already done + UDFInsertLinkedFile(SDirInfo, FileInfo->Dloc->SDirInfo); + SDirInfo->RefCount = 0; + SDirInfo->ParentFile = FileInfo; + SDirInfo->Fcb = NULL; + } else { + SDirInfo = ParSDirInfo; + } + } + UDFReferenceFile__(SDirInfo); + *_SDirInfo = SDirInfo; + return STATUS_SUCCESS; + } + // normal open + if(!((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength) + return STATUS_NOT_FOUND; + SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG); + if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES; + *_SDirInfo = SDirInfo; + status = UDFOpenRootFile__(Vcb, &(((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation) ,SDirInfo); + if(!OS_SUCCESS(status)) return status; + // open & finalize linkage + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; + SDirInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_SDIR; + FileInfo->Dloc->SDirInfo = SDirInfo; + SDirInfo->ParentFile = FileInfo; + + UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount)); + + return STATUS_SUCCESS; +} // end UDFOpenStreamDir__() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine records VAT & VAT Icb at the end of session + */ +OSSTATUS +UDFRecordVAT( + IN PVCB Vcb + ) +{ + uint32 Offset; + uint32 to_read; + uint32 hdrOffset, hdrOffsetNew; + uint32 hdrLen; + OSSTATUS status; + uint32 ReadBytes; + uint32 len; + uint16 PartNdx = (uint16)Vcb->VatPartNdx; + uint16 PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); + uint32 root = UDFPartStart(Vcb, PartNum); + PUDF_FILE_INFO VatFileInfo = Vcb->VatFileInfo; + uint32 i; + PEXTENT_MAP Mapping; + uint32 off, BS, NWA; + int8* Old; + int8* New; + uint32* Vat; + uint8 AllocMode; + uint32 VatLen; + uint32 PacketOffset; + uint32 BSh = Vcb->BlockSizeBits; + uint32 MaxPacket = Vcb->WriteBlockSize >> BSh; + uint32 OldLen; + EntityID* eID; + + if(!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER; + // Disable VAT-based translation + Vcb->Vat = NULL; + // sync VAT and FSBM + len = min(UDFPartLen(Vcb, PartNum), Vcb->FSBM_BitCount - root); + len = min(Vcb->VatCount, len); + for(i=0; iFSBM_Bitmap, root+i)) + Vat[i] = UDF_VAT_FREE_ENTRY; + } + // Ok, now we shall construct new VAT image... + // !!! NOTE !!! + // Both VAT copies - in-memory & on-disc + // contain _relative_ addresses + OldLen = len = (uint32)UDFGetFileSize(Vcb->VatFileInfo); + VatLen = (Vcb->LastLBA - root + 1) * sizeof(uint32); + Old = (int8*)DbgAllocatePool(PagedPool, OldLen); + if(!Old) { + DbgFreePool(Vat); + return STATUS_INSUFFICIENT_RESOURCES; + } + // read old one + status = UDFReadFile__(Vcb, VatFileInfo, 0, OldLen, FALSE, Old, &ReadBytes); + if(!OS_SUCCESS(status)) { + DbgFreePool(Vat); + DbgFreePool(Old); + return status; + } + // prepare some pointers + // and fill headers + if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) { + Offset = 0; + to_read = + hdrOffset = len - sizeof(VirtualAllocationTable15); + hdrLen = sizeof(VirtualAllocationTable15); + hdrOffsetNew = VatLen; + New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen); + if(!New) { + DbgFreePool(Vat); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen); + ((VirtualAllocationTable15*)(New + hdrOffset))->previousVATICB = + VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root; + eID = &(((VirtualAllocationTable15*)(New + hdrOffset))->ident); + + UDFSetEntityID_imp(eID, UDF_ID_ALLOC); + +/* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_ALLOC, sizeof(UDF_ID_ALLOC) ); + iis = (impIdentSuffix*)&(eID->identSuffix); + iis->OSClass = UDF_OS_CLASS_WINNT; + iis->OSIdent = UDF_OS_ID_WINNT;*/ + } else { + VirtualAllocationTable20* Buf; + + Offset = ((VirtualAllocationTable20*)Old)->lengthHeader; + to_read = len - Offset; + hdrOffset = 0; + hdrLen = sizeof(VirtualAllocationTable20); + hdrOffsetNew = 0; + New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen); + if(!New) { + DbgFreePool(Vat); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen); + ((VirtualAllocationTable20*)New)->previousVatICBLoc = + VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root; + + Buf = (VirtualAllocationTable20*)New; + + Buf->minReadRevision = Vcb->minUDFReadRev; + Buf->minWriteRevision = Vcb->minUDFWriteRev; + Buf->maxWriteRevision = Vcb->maxUDFWriteRev; + + Buf->numFIDSFiles = Vcb->numFiles; + Buf->numFIDSDirectories = Vcb->numDirs; + } + + RtlCopyMemory(New+Offset, Vat, VatLen); + // + if(VatFileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) { + eID = &(((PEXTENDED_FILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent); + } else { + eID = &(((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent); + } + +#if 0 + UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER); +#endif + +/* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) ); + iis = (impIdentSuffix*)&(eID->identSuffix); + iis->OSClass = UDF_OS_CLASS_WINNT; + iis->OSIdent = UDF_OS_ID_WINNT;*/ + + VatFileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + // drop VAT + DbgFreePool(Vat); + len = VatLen; + // the operation of resize can modifiy WriteCount in WCache due to movement + // of the data from FE. That's why we should remember PacketOffset now + if(to_read < VatLen) { + status = UDFResizeFile__(Vcb, VatFileInfo, len = hdrLen + VatLen); + if(!OS_SUCCESS(status)) { + return status; + } + UDFMarkSpaceAsXXX(Vcb, VatFileInfo->Dloc, VatFileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); //free + } + PacketOffset = WCacheGetWriteBlockCount__(&(Vcb->FastCache)); + if( ((((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) ) { + // now we'll place FE & built-in data to the last sector of + // the last packet will be recorded + if(!PacketOffset) { + // add padding + UDFWriteData(Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes); + PacketOffset++; + } else { + Vcb->Vat = (uint32*)(New+Offset); + WCacheSyncReloc__(&(Vcb->FastCache), Vcb); + Vcb->Vat = NULL; + } + VatFileInfo->Dloc->FELoc.Mapping[0].extLocation = + VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation = + Vcb->NWA+PacketOffset; + VatFileInfo->Dloc->FELoc.Modified = TRUE; + // setup descTag + ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation = + UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation); + // record data + if(OS_SUCCESS(status = UDFWriteFile__(Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &ReadBytes))) { + status = UDFFlushFile__(Vcb, VatFileInfo); + } + return status; + } + // We can't fit the whole VAT in FE tail + // Now lets 'unpack' VAT's mapping to make updating easier + status = UDFUnPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc)); + if(!OS_SUCCESS(status)) return status; + // update VAT with locations of not flushed blocks + if(PacketOffset) { + Vcb->Vat = (uint32*)(New+Offset); + WCacheSyncReloc__(&(Vcb->FastCache), Vcb); + Vcb->Vat = NULL; + } + + Mapping = VatFileInfo->Dloc->DataLoc.Mapping; + off=0; + BS = Vcb->BlockSize; + NWA = Vcb->NWA; + VatLen += hdrLen; + // record modified parts of VAT & update mapping + for(i=0; Mapping[i].extLength; i++) { + to_read = (VatLen>=BS) ? BS : VatLen; + if((OldLen < off) || (RtlCompareMemory(Old+off, New+off, to_read) != to_read)) { + // relocate frag + Mapping[i].extLocation = NWA+PacketOffset; + Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; + PacketOffset++; + if(PacketOffset >= MaxPacket) { + NWA += (MaxPacket + 7); + PacketOffset = 0; + } + status = UDFWriteFile__(Vcb, VatFileInfo, off, to_read, FALSE, New+off, &ReadBytes); + if(!OS_SUCCESS(status)) { + return status; + } + } + VatLen-=BS; + off+=BS; + } + // pack mapping + UDFPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc)); + len = UDFGetMappingLength(VatFileInfo->Dloc->DataLoc.Mapping)/sizeof(EXTENT_MAP) - 1; + // obtain AllocMode + AllocMode = ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; + switch(AllocMode) { + case ICB_FLAG_AD_SHORT: { + AllocMode = sizeof(SHORT_AD); + break; + } + case ICB_FLAG_AD_LONG: { + AllocMode = sizeof(LONG_AD); + break; + } + case ICB_FLAG_AD_EXTENDED: { +// break; + } + default: { + return STATUS_INVALID_PARAMETER; + } + } + // calculate actual AllocSequence length (in blocks) + len = (len*AllocMode+BS-1+VatFileInfo->Dloc->AllocLoc.Offset) / +// (((BS - sizeof(ALLOC_EXT_DESC))/sizeof(SHORT_AD))*sizeof(SHORT_AD)); + ((BS - sizeof(ALLOC_EXT_DESC) + AllocMode - 1) & ~(AllocMode-1)); + // Re-init AllocLoc + if(VatFileInfo->Dloc->AllocLoc.Mapping) MyFreePool__(VatFileInfo->Dloc->AllocLoc.Mapping); + VatFileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP), + MEM_EXTMAP_TAG); + if(!(VatFileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; + + VatFileInfo->Dloc->AllocLoc.Offset = (uint32)(VatFileInfo->Dloc->FELoc.Length); + VatFileInfo->Dloc->AllocLoc.Length = 0; + Mapping = VatFileInfo->Dloc->AllocLoc.Mapping; + Mapping[0].extLength = BS-VatFileInfo->Dloc->AllocLoc.Offset; +// Mapping[0].extLocation = ???; + for(i=1; i= MaxPacket) { + NWA += (MaxPacket + 7); + PacketOffset = 0; + } + } + // Terminator + Mapping[i].extLocation = + Mapping[i].extLength = 0; + + if( !PacketOffset && + (VatFileInfo->Dloc->AllocLoc.Length <= (Vcb->BlockSize - (uint32)(VatFileInfo->Dloc->AllocLoc.Offset)) ) ) { + // add padding + UDFWriteData(Vcb, TRUE, ((uint64)NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes); + PacketOffset++; + } + // now we'll place FE & built-in data to the last sector of + // the last packet will be recorded + VatFileInfo->Dloc->FELoc.Mapping[0].extLocation = + VatFileInfo->Dloc->AllocLoc.Mapping[0].extLocation = + NWA+PacketOffset; + VatFileInfo->Dloc->FELoc.Modified = TRUE; + // setup descTag + ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation = + UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation); + VatFileInfo->Dloc->DataLoc.Modified = TRUE; + + status = UDFFlushFile__(Vcb, VatFileInfo); + if(!OS_SUCCESS(status)) + return status; + WCacheFlushAll__(&(Vcb->FastCache), Vcb); + return STATUS_SUCCESS; +} // end UDFRecordVAT() +#endif //UDF_READ_ONLY_BUILD + +/* + This routine updates VAT according to RequestedLbaTable (RelocTab) & + actual physical address where this data will be stored + */ +OSSTATUS +UDFUpdateVAT( + IN void* _Vcb, + IN uint32 Lba, + IN uint32* RelocTab, // can be NULL + IN uint32 BCount + ) +{ +#ifndef UDF_READ_ONLY_BUILD + PVCB Vcb = (PVCB)_Vcb; + uint16 PartNdx = (uint16)(Vcb->VatPartNdx); + uint16 PartNum = (uint16)(Lba ? UDFGetPartNumByPhysLba(Vcb, Lba) : UDFGetPartNumByPartNdx(Vcb, PartNdx)); + if(PartNum != UDFGetPartNumByPartNdx(Vcb, PartNdx)) { + KdPrint(("UDFUpdateVAT: Write to Write-Protected partition\n")); + return STATUS_MEDIA_WRITE_PROTECTED; + } + // !!! NOTE !!! + // Both VAT copies - in-memory & on-disc + // contain _relative_ addresses + uint32 root = Vcb->Partitions[PartNdx].PartitionRoot; + uint32 NWA = Vcb->NWA-root; + uint32 i; + uint32 CurLba; + + if(!Vcb->Vat) return STATUS_SUCCESS; + + for(i=0; i= Vcb->VatCount) + Vcb->VatCount = CurLba+1; + Vcb->Vat[CurLba] = NWA; + } + return STATUS_SUCCESS; +#else //UDF_READ_ONLY_BUILD + return STATUS_MEDIA_WRITE_PROTECTED; +#endif //UDF_READ_ONLY_BUILD +} // end UDFUpdateVAT() + +#ifndef UDF_READ_ONLY_BUILD +/* + This routine rebuilds file's FE in order to move data from + ICB to separate Block. + */ +OSSTATUS +UDFConvertFEToNonInICB( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint8 NewAllocMode + ) +{ + OSSTATUS status; + int8* OldInIcb = NULL; + uint32 OldLen; + ValidateFileInfo(FileInfo); + uint32 ReadBytes; + uint32 _WrittenBytes; + PUDF_DATALOC_INFO Dloc; + +// ASSERT(FileInfo->RefCount >= 1); + + Dloc = FileInfo->Dloc; + ASSERT(Dloc->FELoc.Mapping[0].extLocation); + uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation); + + if(NewAllocMode == ICB_FLAG_AD_DEFAULT_ALLOC_MODE) { + NewAllocMode = (uint8)(Vcb->DefaultAllocMode); + } + // we do not support recording of extended AD now + if(NewAllocMode != ICB_FLAG_AD_SHORT && + NewAllocMode != ICB_FLAG_AD_LONG) + return STATUS_INVALID_PARAMETER; + if(!Dloc->DataLoc.Offset || !Dloc->DataLoc.Length) + return STATUS_SUCCESS; + ASSERT(!Dloc->AllocLoc.Mapping); + // read in-icb data. it'll be replaced after resize + OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length)); + if(!OldInIcb) + return STATUS_INSUFFICIENT_RESOURCES; + OldLen = (uint32)(Dloc->DataLoc.Length); + status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &ReadBytes); + if(!OS_SUCCESS(status)) { + MyFreePool__(OldInIcb); + return status; + } +/* if(!Dloc->AllocLoc.Mapping) { + Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, sizeof(EXTENT_MAP)*2); + if(!Dloc->AllocLoc.Mapping) { + MyFreePool__(OldInIcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + } + // init Alloc mode + if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; + } else { + BrutePoint(); + } + RtlZeroMemory(Dloc->AllocLoc.Mapping, sizeof(EXTENT_MAP)*2); +// Dloc->AllocLoc.Mapping[0].extLocation = 0; + Dloc->AllocLoc.Mapping[0].extLength = Vcb->LBlockSize | EXTENT_NOT_RECORDED_NOT_ALLOCATED; +// Dloc->AllocLoc.Mapping[1].extLocation = 0; +// Dloc->AllocLoc.Mapping[1].extLength = 0; +*/ + + // grow extent in order to force space allocation + status = UDFResizeExtent(Vcb, PartNum, Vcb->LBlockSize, FALSE, &Dloc->DataLoc); + if(!OS_SUCCESS(status)) { + MyFreePool__(OldInIcb); + return status; + } + + // set Alloc mode + if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= NewAllocMode; + } else { + BrutePoint(); + } + + // revert to initial extent size. This will not cause NonInICB->InICB transform + status = UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &Dloc->DataLoc); + if(!OS_SUCCESS(status)) { + MyFreePool__(OldInIcb); + return status; + } + + // replace data from ICB (if any) & free buffer + status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &_WrittenBytes); + MyFreePool__(OldInIcb); + if(!OS_SUCCESS(status)) { + return status; + } + // inform UdfInfo, that AllocDesc's must be rebuilt on flush/close + Dloc->AllocLoc.Modified = TRUE; + Dloc->DataLoc.Modified = TRUE; + return STATUS_SUCCESS; +} // end UDFConvertFEToNonInICB() + +/* + This routine converts file's FE to extended form. + It is needed for stream creation. + */ +OSSTATUS +UDFConvertFEToExtended( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + PEXTENDED_FILE_ENTRY ExFileEntry; + PFILE_ENTRY FileEntry; + uint32 Length, NewLength, l; + OSSTATUS status; + uint32 ReadBytes; + + if(!FileInfo) return STATUS_INVALID_PARAMETER; + ValidateFileInfo(FileInfo); + if(FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) return STATUS_SUCCESS; + if(FileInfo->Dloc->FileEntry->tagIdent != TID_FILE_ENTRY) return STATUS_INVALID_PARAMETER; + +/* if(!OS_SUCCESS(status = UDFFlushFile__(Vcb, FileInfo))) + return status;*/ + + Length = FileInfo->Dloc->FileEntryLen; + NewLength = Length - sizeof(FILE_ENTRY) + sizeof(EXTENDED_FILE_ENTRY); + ExFileEntry = (PEXTENDED_FILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, NewLength, MEM_XFE_TAG); + if(!ExFileEntry) return STATUS_INSUFFICIENT_RESOURCES; + FileEntry = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); + RtlZeroMemory(ExFileEntry, NewLength); + + ExFileEntry->descTag.tagIdent = TID_EXTENDED_FILE_ENTRY; + ExFileEntry->icbTag = FileEntry->icbTag; + ExFileEntry->uid = FileEntry->uid; + ExFileEntry->gid = FileEntry->gid; + ExFileEntry->permissions = FileEntry->permissions; + ExFileEntry->fileLinkCount = FileEntry->fileLinkCount; + ExFileEntry->recordFormat = FileEntry->recordFormat; + ExFileEntry->recordDisplayAttr = FileEntry->recordDisplayAttr; + ExFileEntry->recordLength = FileEntry->recordLength; + ExFileEntry->informationLength = FileEntry->informationLength; + ExFileEntry->logicalBlocksRecorded = FileEntry->logicalBlocksRecorded; + ExFileEntry->accessTime = FileEntry->accessTime; + ExFileEntry->modificationTime = FileEntry->modificationTime; + ExFileEntry->attrTime = FileEntry->attrTime; + ExFileEntry->checkpoint = FileEntry->checkpoint; + ExFileEntry->extendedAttrICB = FileEntry->extendedAttrICB; + ExFileEntry->impIdent = FileEntry->impIdent; + ExFileEntry->uniqueID = FileEntry->uniqueID; + ExFileEntry->lengthExtendedAttr = FileEntry->lengthExtendedAttr; + ExFileEntry->lengthAllocDescs = FileEntry->lengthAllocDescs; + RtlCopyMemory(ExFileEntry+1, FileEntry+1, FileEntry->lengthExtendedAttr); + RtlCopyMemory((int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, (int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, FileEntry->lengthAllocDescs); + + if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { + + if((l = (uint32)(FileInfo->Dloc->DataLoc.Length))) { + + int8* tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, l); + if(!tmp_buff) { + MyFreePool__(ExFileEntry); + return STATUS_INSUFFICIENT_RESOURCES; + } + if(!OS_SUCCESS(status = UDFReadFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) || + !OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, 0)) ) { + MyFreePool__(ExFileEntry); + MyFreePool__(tmp_buff); + return status; + } + FileInfo->Dloc->FELoc.Length = + FileInfo->Dloc->DataLoc.Offset = NewLength; + FileInfo->Dloc->FELoc.Modified = + FileInfo->Dloc->DataLoc.Modified = TRUE; + MyFreePool__(FileInfo->Dloc->FileEntry); + FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; + if(!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, l)) || + !OS_SUCCESS(status = UDFWriteFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ) { + MyFreePool__(ExFileEntry); + MyFreePool__(tmp_buff); + return status; + } + MyFreePool__(tmp_buff); + } else { + FileInfo->Dloc->FELoc.Length = + FileInfo->Dloc->DataLoc.Offset = NewLength; + FileInfo->Dloc->FELoc.Modified = + FileInfo->Dloc->DataLoc.Modified = TRUE; + MyFreePool__(FileInfo->Dloc->FileEntry); + FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; + } + } else { + FileInfo->Dloc->FELoc.Length = + FileInfo->Dloc->AllocLoc.Offset = NewLength; + FileInfo->Dloc->FELoc.Modified = + FileInfo->Dloc->AllocLoc.Modified = TRUE; + MyFreePool__(FileInfo->Dloc->FileEntry); + FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; + } + FileInfo->Dloc->FileEntryLen = NewLength; + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; + if(Vcb->minUDFReadRev < 0x0200) + Vcb->minUDFReadRev = 0x0200; + return STATUS_SUCCESS; +} // end UDFConvertFEToExtended() + +/* + This routine makes file almost unavailable for external callers. + The only way to access Hidden with this routine file is OpenByIndex. + It is usefull calling this routine to pretend file to be deleted, + for ex. when we have UDFCleanUp__() or smth. like this in progress, + but we want to create file with the same name. + */ +OSSTATUS +UDFPretendFileDeleted__( + IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo + ) +{ + AdPrint(("UDFPretendFileDeleted__:\n")); + + NTSTATUS RC; + PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); + if(!hDirNdx) return STATUS_CANNOT_DELETE; + PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); + if(!DirNdx) return STATUS_CANNOT_DELETE; + + + // we can't hide file that is not marked as deleted + RC = UDFDoesOSAllowFilePretendDeleted__(FileInfo); + if(!NT_SUCCESS(RC)) + return RC; + + AdPrint(("UDFPretendFileDeleted__: set UDF_FI_FLAG_FI_INTERNAL\n")); + + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; + if(DirNdx->FName.Buffer) { + MyFreePool__(DirNdx->FName.Buffer); + DirNdx->FName.Buffer = NULL; + DirNdx->FName.Length = + DirNdx->FName.MaximumLength = 0; + } + return STATUS_SUCCESS; +} // end UDFPretendFileDeleted__() +#endif //UDF_READ_ONLY_BUILD diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf_info.dep b/reactos/drivers/filesystems/udfs/udf_info/udf_info.dep new file mode 100644 index 00000000000..3da145a5060 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf_info.dep @@ -0,0 +1,34 @@ +#//////////////////////////////////////////////////////////////////// +#// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +#// All rights reserved +#//////////////////////////////////////////////////////////////////// +# Dependency File, included by udf_info.mak + +#!IF "$(UDFINFO_DEPENDENCES)" == "" +#UDFINFO_DEPENDENCES=\ +# $(CDRW_DEPENDENCES)\ +# "$(UDF_INFO_PATH)\Udf_info.h"\ +# "$(UDF_INFO_PATH)\Udf_rel.h" +#!ENDIF + +$(UDF_INFO_PATH)\alloc.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\dirtree.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\extent.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\mount.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\phys_eject.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\physical.cpp : \ + $(UDFINFO_DEPENDENCES) + +$(UDF_INFO_PATH)\udf_info.cpp : \ + $(UDFINFO_DEPENDENCES) + diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf_info.h b/reactos/drivers/filesystems/udfs/udf_info/udf_info.h new file mode 100644 index 00000000000..2ee29a02e9e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf_info.h @@ -0,0 +1,1337 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __UDF_STRUCT_SUPPORT_H__ +#define __UDF_STRUCT_SUPPORT_H__ + +#include "Ecma_167.h" +#include "osta_misc.h" +#include "udf_rel.h" +#include "..\wcache.h" + +// memory re-allocation (returns new buffer size) +uint32 UDFMemRealloc(IN int8* OldBuff, // old buffer + IN uint32 OldLength, // old buffer size + OUT int8** NewBuff, // address to store new pointer + IN uint32 NewLength); // required size +// convert offset in extent to Lba & calculate block parameters +// it also returns pointer to last valid entry & flags +uint32 +UDFExtentOffsetToLba(IN PVCB Vcb, + IN PEXTENT_AD Extent, // Extent array + IN int64 Offset, // offset in extent + OUT uint32* SectorOffset, + OUT uint32* AvailLength, // available data in this block + OUT uint32* Flags, + OUT uint32* Index); + +// locate frag containing specified Lba in extent +ULONG +UDFLocateLbaInExtent( + IN PVCB Vcb, + IN PEXTENT_MAP Extent, // Extent array + IN lba_t lba + ); + +// see udf_rel.h +//#define LBA_OUT_OF_EXTENT ((LONG)(-1)) +//#define LBA_NOT_ALLOCATED ((LONG)(-2)) + +// read data at any offset from extent +OSSTATUS UDFReadExtent(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT int8* Buffer, + OUT uint32* ReadBytes); +// builds mapping for specified amount of data at any offset from specified extent. +OSSTATUS +UDFReadExtentLocation(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent to start SubExtent from + OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array + IN OUT uint32* _SubExtInfoSz, // IN: maximum number fragments to get + // OUT: actually obtained fragments + OUT int64* _NextOffset // offset, caller can start from to continue + ); +// calculate total length of extent +int64 UDFGetExtentLength(IN PEXTENT_MAP Extent); // Extent array +// convert compressed Unicode to standard +void +__fastcall UDFDecompressUnicode(IN OUT PUNICODE_STRING UName, + IN uint8* CS0, + IN uint32 Length, + OUT uint16* valueCRC); +// calculate hashes for directory search +uint8 UDFBuildHashEntry(IN PVCB Vcb, + IN PUNICODE_STRING Name, + OUT PHASH_ENTRY hashes, + IN uint8 Mask); + +#define HASH_POSIX 0x01 +#define HASH_ULFN 0x02 +#define HASH_DOS 0x04 +#define HASH_ALL 0x07 +#define HASH_KEEP_NAME 0x08 // keep DOS '.' and '..' intact + +// get dirindex's frame +PDIR_INDEX_ITEM UDFDirIndexGetFrame(IN PDIR_INDEX_HDR hDirNdx, + IN uint32 Frame, + OUT uint32* FrameLen, + OUT uint_di* Index, + IN uint_di Rel); +// release DirIndex +void UDFDirIndexFree(PDIR_INDEX_HDR hDirNdx); +// grow DirIndex +OSSTATUS UDFDirIndexGrow(IN PDIR_INDEX_HDR* _hDirNdx, + IN uint_di d); +// truncate DirIndex +OSSTATUS UDFDirIndexTrunc(IN PDIR_INDEX_HDR* _hDirNdx, + IN uint_di d); +// init variables for scan (using knowledge about internal structure) +BOOLEAN UDFDirIndexInitScan(IN PUDF_FILE_INFO DirInfo, // + OUT PUDF_DIR_SCAN_CONTEXT Context, + IN uint_di Index); +// +PDIR_INDEX_ITEM UDFDirIndexScan(PUDF_DIR_SCAN_CONTEXT Context, + PUDF_FILE_INFO* _FileInfo); +// build directory index +OSSTATUS UDFIndexDirectory(IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo); +// search for specified file in specified directory & +// returns corresponding offset in extent if found. +OSSTATUS UDFFindFile(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + IN PUNICODE_STRING Name, + IN PUDF_FILE_INFO DirInfo, + IN OUT uint_di* Index); + +__inline OSSTATUS UDFFindFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN PUNICODE_STRING Name, + IN PUDF_FILE_INFO DirInfo) +{ + if(!DirInfo->Dloc->DirIndex) + return STATUS_NOT_A_DIRECTORY; + uint_di i=0; + return UDFFindFile(Vcb, IgnoreCase, TRUE, Name, DirInfo, &i); +} + +// calculate file mapping length (in bytes) including ZERO-terminator +uint32 UDFGetMappingLength(IN PEXTENT_MAP Extent); +// merge 2 sequencial file mappings +PEXTENT_MAP +__fastcall UDFMergeMappings(IN PEXTENT_MAP Extent, + IN PEXTENT_MAP Extent2); +// build file mapping according to ShortAllocDesc (SHORT_AD) array +PEXTENT_MAP UDFShortAllocDescToMapping(IN PVCB Vcb, + IN uint32 PartNum, + IN PLONG_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc); +// build file mapping according to LongAllocDesc (LONG_AD) array +PEXTENT_MAP UDFLongAllocDescToMapping(IN PVCB Vcb, + IN PLONG_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc); +// build file mapping according to ExtendedAllocDesc (EXT_AD) array +PEXTENT_MAP UDFExtAllocDescToMapping(IN PVCB Vcb, + IN PLONG_AD AllocDesc, + IN uint32 AllocDescLength, + IN uint32 SubCallCount, + OUT PEXTENT_INFO AllocLoc); +// build file mapping according to (Extended)FileEntry +PEXTENT_MAP UDFReadMappingFromXEntry(IN PVCB Vcb, + IN uint32 PartNum, + IN tag* XEntry, + IN OUT uint32* Offset, + OUT PEXTENT_INFO AllocLoc); +// read FileEntry described in FileIdentDesc +OSSTATUS UDFReadFileEntry(IN PVCB Vcb, +// IN PFILE_IDENT_DESC FileDesc, + IN long_ad* Icb, + IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry + IN OUT uint16* Ident); +// scan FileSet sequence & return last valid FileSet +OSSTATUS UDFFindLastFileSet(IN PVCB Vcb, + IN lb_addr *Addr, // Addr for the 1st FileSet + IN OUT PFILE_SET_DESC FileSetDesc); +// read all sparing tables & stores them in contiguos memory +OSSTATUS UDFLoadSparingTable(IN PVCB Vcb, + IN PSPARABLE_PARTITION_MAP PartMap); +// build mapping for extent +PEXTENT_MAP +__fastcall UDFExtentToMapping_(IN PEXTENT_AD Extent +#ifdef UDF_TRACK_EXTENT_TO_MAPPING + ,IN ULONG src, + IN ULONG line +#endif //UDF_TRACK_EXTENT_TO_MAPPING + ); + +#ifdef UDF_TRACK_EXTENT_TO_MAPPING + #define UDFExtentToMapping(e) UDFExtentToMapping_(e, UDF_BUG_CHECK_ID, __LINE__) +#else //UDF_TRACK_EXTENT_TO_MAPPING + #define UDFExtentToMapping(e) UDFExtentToMapping_(e) +#endif //UDF_TRACK_EXTENT_TO_MAPPING + +// This routine remaps sectors from bad packet +OSSTATUS +__fastcall UDFRemapPacket(IN PVCB Vcb, + IN uint32 Lba, + IN BOOLEAN RemapSpared); + +// This routine releases sector mapping when entire packet is marked as free +OSSTATUS +__fastcall UDFUnmapRange(IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BCount); + +// return physical address for relocated sector +uint32 +__fastcall UDFRelocateSector(IN PVCB Vcb, + IN uint32 Lba); +// check +BOOLEAN +__fastcall UDFAreSectorsRelocated(IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BlockCount); +// build mapping for relocated extent +PEXTENT_MAP +__fastcall UDFRelocateSectors(IN PVCB Vcb, + IN uint32 Lba, + IN uint32 BlockCount); +// check for presence of given char among specified ones +BOOLEAN UDFUnicodeInString(IN uint8* string, + IN WCHAR ch); // Unicode char to search for. +// validate char +BOOLEAN +__fastcall UDFIsIllegalChar(IN WCHAR ch); +// translate udfName to dosName using OSTA compliant. +#define UDFDOSName__(Vcb, DosName, UdfName, FileInfo) \ + UDFDOSName(Vcb, DosName, UdfName, (FileInfo) && ((FileInfo)->Index < 2)); + +void +__fastcall UDFDOSName(IN PVCB Vcb, + IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact); + +void +__fastcall UDFDOSName201(IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact); + +void +__fastcall UDFDOSName200(IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact, + IN BOOLEAN Mode150); + +void +__fastcall UDFDOSName100(IN OUT PUNICODE_STRING DosName, + IN PUNICODE_STRING UdfName, + IN BOOLEAN KeepIntact); + +// return length of bit-chain starting from Offs bit +#ifdef _X86_ +uint32 +__stdcall +UDFGetBitmapLen( +#else // NO X86 optimization , use generic C/C++ +uint32 UDFGetBitmapLen( +#endif // _X86_ + uint32* Bitmap, + uint32 Offs, + uint32 Lim); +// scan disc free space bitmap for minimal suitable extent +uint32 UDFFindMinSuitableExtent(IN PVCB Vcb, + IN uint32 Length, // in blocks + IN uint32 SearchStart, + IN uint32 SearchLim, + OUT uint32* MaxExtLen, + IN uint8 AllocFlags); + +#ifdef UDF_CHECK_DISK_ALLOCATION +// mark space described by Mapping as Used/Freed (optionaly) +void UDFCheckSpaceAllocation_(IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ); + +#ifdef UDF_TRACK_ONDISK_ALLOCATION +#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) \ + UDFCheckSpaceAllocation_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__); +#else //UDF_TRACK_ONDISK_ALLOCATION +#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) \ + UDFCheckSpaceAllocation_(Vcb, Map, asXXX); +#endif //UDF_TRACK_ONDISK_ALLOCATION +#else // UDF_CHECK_DISK_ALLOCATION +#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) {;} +#endif //UDF_CHECK_DISK_ALLOCATION + +// mark space described by Mapping as Used/Freed (optionaly) +// this routine doesn't acquire any resource +void +UDFMarkSpaceAsXXXNoProtect_( + IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ); + +#ifdef UDF_TRACK_ONDISK_ALLOCATION +#define UDFMarkSpaceAsXXXNoProtect(Vcb, FileInfo, Map, asXXX) \ + UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__); +#else //UDF_TRACK_ONDISK_ALLOCATION +#define UDFMarkSpaceAsXXXNoProtect(Vcb, FileInfo, Map, asXXX) \ + UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX); +#endif //UDF_TRACK_ONDISK_ALLOCATION + + +// mark space described by Mapping as Used/Freed (optionaly) +void UDFMarkSpaceAsXXX_(IN PVCB Vcb, + IN PEXTENT_MAP Map, + IN uint32 asXXX +#ifdef UDF_TRACK_ONDISK_ALLOCATION + ,IN uint32 FE_lba, + IN uint32 BugCheckId, + IN uint32 Line +#endif //UDF_TRACK_ONDISK_ALLOCATION + ); + +#ifdef UDF_TRACK_ONDISK_ALLOCATION +#define UDFMarkSpaceAsXXX(Vcb, FileInfo, Map, asXXX) \ + UDFMarkSpaceAsXXX_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__); +#else //UDF_TRACK_ONDISK_ALLOCATION +#define UDFMarkSpaceAsXXX(Vcb, FileInfo, Map, asXXX) \ + UDFMarkSpaceAsXXX_(Vcb, Map, asXXX); +#endif //UDF_TRACK_ONDISK_ALLOCATION + +#define AS_FREE 0x00 +#define AS_USED 0x01 +#define AS_DISCARDED 0x02 +#define AS_BAD 0x04 + +// build mapping for Length bytes in FreeSpace +OSSTATUS UDFAllocFreeExtent_(IN PVCB Vcb, + IN int64 Length, + IN uint32 SearchStart, + IN uint32 SearchLim, + OUT PEXTENT_INFO Extent, + IN uint8 AllocFlags +#ifdef UDF_TRACK_ALLOC_FREE_EXTENT + ,IN uint32 src, + IN uint32 line +#endif //UDF_TRACK_ALLOC_FREE_EXTENT + ); + +#ifdef UDF_TRACK_ALLOC_FREE_EXTENT +#define UDFAllocFreeExtent(v, l, ss, sl, e, af) UDFAllocFreeExtent_(v, l, ss, sl, e, af, UDF_BUG_CHECK_ID, __LINE__) +#else //UDF_TRACK_ALLOC_FREE_EXTENT +#define UDFAllocFreeExtent(v, l, ss, sl, e, af) UDFAllocFreeExtent_(v, l, ss, sl, e, af) +#endif //UDF_TRACK_ALLOC_FREE_EXTENT +// + +uint32 __fastcall +UDFGetPartFreeSpace(IN PVCB Vcb, + IN uint32 partNum); + +#define UDF_PREALLOC_CLASS_FE 0x00 +#define UDF_PREALLOC_CLASS_DIR 0x01 + +// try to find cached allocation +OSSTATUS +UDFGetCachedAllocation( + IN PVCB Vcb, + IN uint32 ParentLocation, + OUT PEXTENT_INFO Ext, + OUT uint32* Items, // optional + IN uint32 AllocClass + ); +// put released pre-allocation to cache +OSSTATUS +UDFStoreCachedAllocation( + IN PVCB Vcb, + IN uint32 ParentLocation, + IN PEXTENT_INFO Ext, + IN uint32 Items, + IN uint32 AllocClass + ); +// discard all cached allocations +OSSTATUS +UDFFlushAllCachedAllocations( + IN PVCB Vcb, + IN uint32 AllocClass + ); +// allocate space for FE +OSSTATUS UDFAllocateFESpace(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN uint32 PartNum, + IN PEXTENT_INFO FEExtInfo, + IN uint32 Len); +#ifndef UDF_READ_ONLY_BUILD +// free space FE's allocation +void UDFFreeFESpace(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PEXTENT_INFO FEExtInfo); +#endif //UDF_READ_ONLY_BUILD + +#define FLUSH_FE_KEEP FALSE +#define FLUSH_FE_FOR_DEL TRUE + +// flush FE charge +void UDFFlushFESpace(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc, + IN BOOLEAN Discard = FLUSH_FE_KEEP); +// discard file allocation +void UDFFreeFileAllocation(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUDF_FILE_INFO FileInfo); +// convert physical address to logical in specified partition +uint32 UDFPhysLbaToPart(IN PVCB Vcb, + IN uint32 PartNum, + IN uint32 Addr); +/*#define UDFPhysLbaToPart(Vcb, PartNum, Addr) \ + ((Addr - Vcb->Partitions[PartNum].PartitionRoot) >> Vcb->LB2B_Bits)*/ +// initialize Tag structure. +void UDFSetUpTag(IN PVCB Vcb, + IN tag* Tag, + IN uint16 DataLen, + IN uint32 TagLoc); +// build content for AllocDesc sequence for specified extent +OSSTATUS UDFBuildShortAllocDescs(IN PVCB Vcb, + IN uint32 PartNum, + OUT int8** Buff, // data for AllocLoc + IN uint32 InitSz, + IN OUT PUDF_FILE_INFO FileInfo); +// build data for AllocDesc sequence for specified +OSSTATUS UDFBuildLongAllocDescs(IN PVCB Vcb, + IN uint32 PartNum, + OUT int8** Buff, // data for AllocLoc + IN uint32 InitSz, + IN OUT PUDF_FILE_INFO FileInfo); +// builds FileEntry & associated AllocDescs for specified extent. +OSSTATUS UDFBuildFileEntry(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum, + IN uint16 AllocMode, // short/long/ext/in-icb + IN uint32 ExtAttrSz, + IN BOOLEAN Extended/*, + OUT PFILE_ENTRY* FEBuff, + OUT uint32* FELen, + OUT PEXTENT_INFO FEExtInfo*/); +// find partition containing given physical sector +uint32 +__fastcall UDFGetPartNumByPhysLba(IN PVCB Vcb, + IN uint32 Lba); +// add given bitmap to existing one +#define UDF_FSPACE_BM 0x00 +#define UDF_ZSPACE_BM 0x01 + +OSSTATUS UDFAddXSpaceBitmap(IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD bm, + IN ULONG bm_type); +// subtract given Bitmap to existing one +OSSTATUS UDFDelXSpaceBitmap(IN PVCB Vcb, + IN uint32 PartNum, + IN PSHORT_AD bm); +// build FreeSpaceBitmap (internal) according to media parameters & input data +OSSTATUS UDFBuildFreeSpaceBitmap(IN PVCB Vcb, + IN uint32 PartNdx, + IN PPARTITION_HEADER_DESC phd, + IN uint32 Lba); +// fill ExtentInfo for specified FileEntry +OSSTATUS UDFLoadExtInfo(IN PVCB Vcb, + IN PFILE_ENTRY fe, + IN PLONG_AD fe_loc, + IN OUT PEXTENT_INFO FExtInfo, + IN OUT PEXTENT_INFO AExtInfo); +// convert standard Unicode to compressed +void +__fastcall UDFCompressUnicode(IN PUNICODE_STRING UName, + IN OUT uint8** _CS0, + IN OUT uint32* Length); +// build FileIdent for specified FileEntry. +OSSTATUS UDFBuildFileIdent(IN PVCB Vcb, + IN PUNICODE_STRING fn, + IN PLONG_AD FileEntryIcb, // virtual address of FileEntry + IN uint32 ImpUseLen, + OUT PFILE_IDENT_DESC* _FileId, + OUT uint32* FileIdLen); +// rebuild mapping on write attempts to Alloc-Not-Rec area. +OSSTATUS UDFMarkAllocatedAsRecorded(IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo); // Extent array +// rebuild mapping on write attempts to Not-Alloc-Not-Rec area +OSSTATUS UDFMarkNotAllocatedAsAllocated(IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo); // Extent array +OSSTATUS UDFMarkAllocatedAsNotXXX(IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo, // Extent array + IN BOOLEAN Deallocate); +#ifdef DBG +__inline OSSTATUS UDFMarkAllocatedAsNotAllocated(IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo) +{ + return UDFMarkAllocatedAsNotXXX(Vcb, Offset, Length, ExtInfo, TRUE); +} +#else +#define UDFMarkAllocatedAsNotAllocated(Vcb, Off, Len, Ext) \ + UDFMarkAllocatedAsNotXXX(Vcb, Off, Len, Ext, TRUE) +#endif //DBG + +#ifdef DBG +__inline OSSTATUS UDFMarkRecordedAsAllocated(IN PVCB Vcb, + IN int64 Offset, + IN uint32 Length, + IN PEXTENT_INFO ExtInfo) +{ + return UDFMarkAllocatedAsNotXXX(Vcb, Offset, Length, ExtInfo, FALSE); +} +#else +#define UDFMarkRecordedAsAllocated(Vcb, Off, Len, Ext) \ + UDFMarkAllocatedAsNotXXX(Vcb, Off, Len, Ext, FALSE) +#endif //DBG +// write data at any offset from specified extent. +OSSTATUS UDFWriteExtent(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + IN int8* Buffer, + OUT uint32* WrittenBytes); + +// deallocate/zero data at any offset from specified extent. +OSSTATUS UDFZeroExtent(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Deallocate, // deallocate frag or just mark as unrecorded + IN BOOLEAN Direct, // setting this flag delays flushing of given + // data to indefinite term + OUT uint32* WrittenBytes); + +#define UDFZeroExtent__(Vcb, Ext, Off, Len, Dir, WB) \ + UDFZeroExtent(Vcb, Ext, Off, Len, FALSE, Dir, WB) + +#define UDFSparseExtent__(Vcb, Ext, Off, Len, Dir, WB) \ + UDFZeroExtent(Vcb, Ext, Off, Len, TRUE, Dir, WB) + +uint32 +__fastcall UDFPartStart(PVCB Vcb, + uint32 PartNum); +uint32 +__fastcall UDFPartEnd(PVCB Vcb, + uint32 PartNum); +// resize extent & associated mapping +OSSTATUS UDFResizeExtent(IN PVCB Vcb, + IN uint32 PartNum, + IN int64 Length, + IN BOOLEAN AlwaysInIcb, // must be TRUE for AllocDescs + OUT PEXTENT_INFO ExtInfo); +// (re)build AllocDescs data & resize associated extent +OSSTATUS UDFBuildAllocDescs(IN PVCB Vcb, + IN uint32 PartNum, + IN OUT PUDF_FILE_INFO FileInfo, + OUT int8** AllocData); +// set informationLength field in (Ext)FileEntry +void UDFSetFileSize(IN PUDF_FILE_INFO FileInfo, + IN int64 Size); +// sync cached FileSize from DirNdx and actual FileSize from FE +void UDFSetFileSizeInDirNdx(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64* ASize); +// get informationLength field in (Ext)FileEntry +int64 UDFGetFileSize(IN PUDF_FILE_INFO FileInfo); +// +int64 UDFGetFileSizeFromDirNdx(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +// set lengthAllocDesc field in (Ext)FileEntry +void UDFSetAllocDescLen(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +// change fileLinkCount field in (Ext)FileEntry +void UDFChangeFileLinkCount(IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN Increase); +#define UDFIncFileLinkCount(fi) UDFChangeFileLinkCount(fi, TRUE) +#define UDFDecFileLinkCount(fi) UDFChangeFileLinkCount(fi, FALSE) +// ee +void UDFSetEntityID_imp_(IN EntityID* eID, + IN uint8* Str, + IN uint32 Len); + +// get fileLinkCount field from (Ext)FileEntry +uint16 UDFGetFileLinkCount(IN PUDF_FILE_INFO FileInfo); +#ifdef UDF_CHECK_UTIL +// set fileLinkCount field in (Ext)FileEntry +void +UDFSetFileLinkCount( + IN PUDF_FILE_INFO FileInfo, + uint16 LinkCount + ); +#endif //UDF_CHECK_UTIL + +#define UDFSetEntityID_imp(eID, Str) \ + UDFSetEntityID_imp_(eID, (uint8*)(Str), sizeof(Str)); +// +void UDFReadEntityID_Domain(PVCB Vcb, + EntityID* eID); +// get lengthExtendedAttr field in (Ext)FileEntry +uint32 UDFGetFileEALength(IN PUDF_FILE_INFO FileInfo); +// set UniqueID field in (Ext)FileEntry +void UDFSetFileUID(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +// get UniqueID field in (Ext)FileEntry +int64 UDFGetFileUID(IN PUDF_FILE_INFO FileInfo); +// change counters in LVID +void UDFChangeFileCounter(IN PVCB Vcb, + IN BOOLEAN FileCounter, + IN BOOLEAN Increase); +#define UDFIncFileCounter(Vcb) UDFChangeFileCounter(Vcb, TRUE, TRUE); +#define UDFDecFileCounter(Vcb) UDFChangeFileCounter(Vcb, TRUE, FALSE); +#define UDFIncDirCounter(Vcb) UDFChangeFileCounter(Vcb, FALSE, TRUE); +#define UDFDecDirCounter(Vcb) UDFChangeFileCounter(Vcb, FALSE, FALSE); +// write to file +OSSTATUS UDFWriteFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, + IN uint32 Length, + IN BOOLEAN Direct, + IN int8* Buffer, + OUT uint32* WrittenBytes); +// mark file as deleted & decrease file link counter. +OSSTATUS UDFUnlinkFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN BOOLEAN FreeSpace); +// delete all files in directory (FreeSpace = TRUE) +OSSTATUS UDFUnlinkAllFilesInDir(IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo); +// init UDF_FILE_INFO structure for specifiend file +OSSTATUS UDFOpenFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + IN PUNICODE_STRING fn, + IN PUDF_FILE_INFO DirInfo, + OUT PUDF_FILE_INFO* _FileInfo, + IN uint_di* IndexToOpen); +// init UDF_FILE_INFO structure for root directory +OSSTATUS UDFOpenRootFile__(IN PVCB Vcb, + IN lb_addr* RootLoc, + OUT PUDF_FILE_INFO FileInfo); +// free all memory blocks referenced by given FileInfo +uint32 UDFCleanUpFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +#define UDF_FREE_NOTHING 0x00 +#define UDF_FREE_FILEINFO 0x01 +#define UDF_FREE_DLOC 0x02 +// create zero-sized file +OSSTATUS UDFCreateFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN PUNICODE_STRING fn, + IN uint32 ExtAttrSz, + IN uint32 ImpUseLen, + IN BOOLEAN Extended, + IN BOOLEAN CreateNew, + IN OUT PUDF_FILE_INFO DirInfo, + OUT PUDF_FILE_INFO* _FileInfo); +// read data from file described with FileInfo +/* + This routine reads data from file described by FileInfo + */ +__inline +OSSTATUS UDFReadFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT int8* Buffer, + OUT uint32* ReadBytes) +{ + ValidateFileInfo(FileInfo); + + return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes); +} // end UDFReadFile__()*/ + +/* + This routine reads data from file described by FileInfo + */ +__inline +OSSTATUS UDFReadFileLocation__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent to start SubExtent from + OUT PEXTENT_MAP* SubExtInfo, // SubExtent mapping array + IN OUT uint32* SubExtInfoSz, // IN: maximum number fragments to get + // OUT: actually obtained fragments + OUT int64* NextOffset // offset, caller can start from to continue + ) +{ + ValidateFileInfo(FileInfo); + + return UDFReadExtentLocation(Vcb, &(FileInfo->Dloc->DataLoc), Offset, SubExtInfo, SubExtInfoSz, NextOffset); +} // end UDFReadFile__()*/ + +/* +#define UDFReadFile__(Vcb, FileInfo, Offset, Length, Direct, Buffer, ReadBytes) \ + (UDFReadExtent(Vcb, &((FileInfo)->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes)) +*/ + +// zero data in file described by FileInfo +__inline +OSSTATUS UDFZeroFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT uint32* ReadBytes); +// make sparse area in file described by FileInfo +__inline +OSSTATUS UDFSparseFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN Direct, + OUT uint32* ReadBytes); +// pad sector tail with zeros +OSSTATUS UDFPadLastSector(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo); +// update AllocDesc sequence, FileIdent & FileEntry +OSSTATUS UDFCloseFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +// load specified bitmap. +OSSTATUS UDFPrepareXSpaceBitmap(IN PVCB Vcb, + IN OUT PSHORT_AD XSpaceBitmap, + IN OUT PEXTENT_INFO XSBMExtInfo, + IN OUT int8** XSBM, + IN OUT uint32* XSl); +// update Freed & Unallocated space bitmaps +OSSTATUS UDFUpdateXSpaceBitmaps(IN PVCB Vcb, + IN uint32 PartNum, + IN PPARTITION_HEADER_DESC phd); // partition header pointing to Bitmaps +// update Partition Desc & associated data structures +OSSTATUS UDFUpdatePartDesc(PVCB Vcb, + int8* Buf); +// update Logical volume integrity descriptor +OSSTATUS UDFUpdateLogicalVolInt(PVCB Vcb, + BOOLEAN Close); +// blank Unalloc Space Desc +OSSTATUS UDFUpdateUSpaceDesc(IN PVCB Vcb, + int8* Buf); +// update Volume Descriptor Sequence +OSSTATUS UDFUpdateVDS(IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + IN uint32 flags); +// rebuild & flushes all system areas +OSSTATUS UDFUmount__(IN PVCB Vcb); +// move file from DirInfo1 to DirInfo2 & renames it to fn +OSSTATUS UDFRenameMoveFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN OUT BOOLEAN* Replace, // replace if destination file exists + IN PUNICODE_STRING fn, // destination + // IN uint32 ExtAttrSz, + IN OUT PUDF_FILE_INFO DirInfo1, + IN OUT PUDF_FILE_INFO DirInfo2, + IN OUT PUDF_FILE_INFO FileInfo); // source (opened) +// change file size (on disc) +OSSTATUS UDFResizeFile__(IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo, + IN int64 NewLength); +// transform zero-sized file to directory +OSSTATUS UDFRecordDirectory__(IN PVCB Vcb, + IN OUT PUDF_FILE_INFO DirInfo); // source (opened) +// remove all DELETED entries from Dir & resize it. +#ifndef UDF_READ_ONLY_BUILD +OSSTATUS UDFPackDirectory__(IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo); // source (opened) +// rebuild tags for all entries from Dir. +OSSTATUS +UDFReTagDirectory(IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo); // source (opened) +#endif //UDF_READ_ONLY_BUILD +// load VAT. +OSSTATUS UDFLoadVAT(IN PVCB Vcb, + IN uint32 PartNdx); +// get volume free space +int64 +__fastcall UDFGetFreeSpace(IN PVCB Vcb); +// get volume total space +int64 +__fastcall UDFGetTotalSpace(IN PVCB Vcb); +// get DirIndex for specified FileInfo +PDIR_INDEX_HDR UDFGetDirIndexByFileInfo(IN PUDF_FILE_INFO FileInfo); +// check if the file has been found is deleted +/*BOOLEAN UDFIsDeleted(IN PDIR_INDEX_ITEM DirNdx);*/ +#define UDFIsDeleted(DirNdx) \ + (((DirNdx)->FileCharacteristics & FILE_DELETED) ? TRUE : FALSE) +// check Directory flag +/*BOOLEAN UDFIsADirectory(IN PUDF_FILE_INFO FileInfo);*/ +#define UDFIsADirectory(FileInfo) \ + (((FileInfo) && ((FileInfo)->Dloc) && ((FileInfo)->Dloc->DirIndex || ((FileInfo)->FileIdent && ((FileInfo)->FileIdent->fileCharacteristics & FILE_DIRECTORY)))) ? TRUE : FALSE) +// calculate actual allocation size +/*int64 UDFGetFileAllocationSize(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo);*/ +#define UDFGetFileAllocationSize(Vcb, FileInfo) \ + (((FileInfo)->Dloc->DataLoc.Mapping) ? UDFGetExtentLength((FileInfo)->Dloc->DataLoc.Mapping) : Vcb->LBlockSize) +// check if the directory is empty +BOOLEAN UDFIsDirEmpty(IN PDIR_INDEX_HDR hCurDirNdx); +// flush FE +OSSTATUS UDFFlushFE(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum); +// flush FI +OSSTATUS UDFFlushFI(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint32 PartNum); +// flush all metadata & update counters +OSSTATUS UDFFlushFile__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN ULONG FlushFlags = 0); +// check if the file is flushed +#define UDFIsFlushed(FI) \ + ( FI && \ + !(FI->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) && \ + !(FI->Dloc->DataLoc.Modified) && \ + !(FI->Dloc->AllocLoc.Modified) &&\ + !(FI->Dloc->FELoc.Modified) && \ + !(UDFGetDirIndexByFileInfo(FI)[FI->Index].FI_Flags & UDF_FI_FLAG_FI_MODIFIED) ) +// compare opened directories +BOOLEAN UDFCompareFileInfo(IN PUDF_FILE_INFO f1, + IN PUDF_FILE_INFO f2); +// pack mappings +void +__fastcall UDFPackMapping(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo); // Extent array +// check if all the data is in cache. +BOOLEAN UDFIsExtentCached(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, // Extent array + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN ForWrite); +/*BOOLEAN UDFIsFileCached__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN int64 Offset, // offset in extent + IN uint32 Length, + IN BOOLEAN ForWrite);*/ +#define UDFIsFileCached__(Vcb, FileInfo, Offset, Length, ForWrite) \ + (UDFIsExtentCached(Vcb, &((FileInfo)->Dloc->DataLoc), Offset, Length, ForWrite)) +// check if specified sector belongs to a file +ULONG UDFIsBlockAllocated(IN void* _Vcb, + IN uint32 Lba); +// record VolIdent +OSSTATUS UDFUpdateVolIdent(IN PVCB Vcb, + IN UDF_VDS_RECORD Lba, + IN PUNICODE_STRING VolIdent); +// calculate checksum for unicode string (for DOS-names) +uint16 +__fastcall UDFUnicodeCksum(PWCHAR s, + uint32 n); +//#define UDFUnicodeCksum(s,n) UDFCrc((uint8*)(s), (n)*sizeof(WCHAR)) +// +uint16 +__fastcall +UDFUnicodeCksum150(PWCHAR s, + uint32 n); + +uint32 +__fastcall crc32(IN uint8* s, + IN uint32 len); +// calculate a 16-bit CRC checksum using ITU-T V.41 polynomial +uint16 +__fastcall UDFCrc(IN uint8* Data, + IN uint32 Size); +// read the first block of a tagged descriptor & check it +OSSTATUS UDFReadTagged(IN PVCB Vcb, + IN int8* Buf, + IN uint32 Block, + IN uint32 Location, + OUT uint16 *Ident); +// get physycal Lba for partition-relative addr +uint32 +__fastcall UDFPartLbaToPhys(IN PVCB Vcb, + IN lb_addr* Addr); +// look for Anchor(s) at all possible locations +lba_t UDFFindAnchor(PVCB Vcb); // Volume control block +// look for Volume recognition sequence +uint32 UDFFindVRS(PVCB Vcb); +// process Primary volume descriptor +void UDFLoadPVolDesc(PVCB Vcb, + int8* Buf); // pointer to buffer containing PVD +// +#define UDFGetLVIDiUse(Vcb) \ + ( ((Vcb) && (Vcb)->LVid) ? \ + ( (LogicalVolIntegrityDescImpUse*) \ + ( ((int8*)(Vcb->LVid+1)) + \ + Vcb->LVid->numOfPartitions*2*sizeof(uint32))) \ + : NULL) + +// load Logical volume integrity descriptor +OSSTATUS UDFLoadLogicalVolInt(PDEVICE_OBJECT DeviceObject, + PVCB Vcb, + extent_ad loc); +// load Logical volume descriptor +OSSTATUS UDFLoadLogicalVol(PDEVICE_OBJECT DeviceObject, + PVCB Vcb, + int8* Buf, + lb_addr *fileset); +// process Partition descriptor +OSSTATUS UDFLoadPartDesc(PVCB Vcb, + int8* Buf); +// scan VDS & fill special array +OSSTATUS UDFReadVDS(IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + IN PUDF_VDS_RECORD vds, + IN int8* Buf); +// process a main/reserve volume descriptor sequence. +OSSTATUS UDFProcessSequence(IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + OUT lb_addr *fileset); +// Verifies a main/reserve volume descriptor sequence. +OSSTATUS UDFVerifySequence(IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + IN uint32 block, + IN uint32 lastblock, + OUT lb_addr *fileset); +// remember some useful info about FileSet & RootDir location +void UDFLoadFileset(IN PVCB Vcb, + IN PFILE_SET_DESC fset, + OUT lb_addr *root, + OUT lb_addr *sysstream); +// load partition info +OSSTATUS UDFLoadPartition(IN PDEVICE_OBJECT DeviceObject, + IN PVCB Vcb, + OUT lb_addr *fileset); +// check if this is an UDF-formatted disk +OSSTATUS UDFGetDiskInfoAndVerify(IN PDEVICE_OBJECT DeviceObject, // the target device object + IN PVCB Vcb); // Volume control block from this DevObj +// create hard link for the file +OSSTATUS UDFHardLinkFile__(IN PVCB Vcb, + IN BOOLEAN IgnoreCase, + IN OUT BOOLEAN* Replace, // replace if destination file exists + IN PUNICODE_STRING fn, // destination + IN OUT PUDF_FILE_INFO DirInfo1, + IN OUT PUDF_FILE_INFO DirInfo2, + IN OUT PUDF_FILE_INFO FileInfo); // source (opened) +// +LONG UDFFindDloc(IN PVCB Vcb, + IN uint32 Lba); +// +LONG UDFFindFreeDloc(IN PVCB Vcb, + IN uint32 Lba); +// +OSSTATUS UDFAcquireDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc); +// +OSSTATUS UDFReleaseDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc); +// +OSSTATUS UDFStoreDloc(IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN uint32 Lba); +// +OSSTATUS UDFRemoveDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc); +// +OSSTATUS UDFUnlinkDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc); +// +void UDFFreeDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc); +// +void UDFRelocateDloc(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc, + IN uint32 NewLba); +// +void UDFReleaseDlocList(IN PVCB Vcb); +// +PUDF_FILE_INFO UDFLocateParallelFI(PUDF_FILE_INFO di, // parent FileInfo + uint_di i, // Index + PUDF_FILE_INFO fi); +// +PUDF_FILE_INFO UDFLocateAnyParallelFI(PUDF_FILE_INFO fi); // FileInfo to start search from +// +void UDFInsertLinkedFile(PUDF_FILE_INFO fi, // FileInfo to be added to chain + PUDF_FILE_INFO fi2); // any FileInfo fro the chain +// +OSSTATUS UDFCreateRootFile__(IN PVCB Vcb, + // IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB + IN uint32 PartNum, + IN uint32 ExtAttrSz, + IN uint32 ImpUseLen, + IN BOOLEAN Extended, + OUT PUDF_FILE_INFO* _FileInfo); +// try to create StreamDirectory associated with given file +OSSTATUS UDFCreateStreamDir__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, // file containing stream-dir + OUT PUDF_FILE_INFO* _SDirInfo); +// +OSSTATUS UDFOpenStreamDir__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, // file containing stream-dir + OUT PUDF_FILE_INFO* _SDirInfo); +// +#define UDFIsAStreamDir(FI) ((FI) && ((FI)->Dloc) && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR)) +// +#define UDFHasAStreamDir(FI) ((FI) && ((FI)->Dloc) && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_HAS_SDIR)) +// +#define UDFIsAStream(FI) ((FI) && UDFIsAStreamDir((FI)->ParentFile)) +// +#define UDFIsSDirDeleted(FI) ((FI) && (FI)->Dloc && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_IS_DEL_SDIR)) +// Record updated VAT (if updated) +OSSTATUS UDFRecordVAT(IN PVCB Vcb); +// +OSSTATUS UDFModifyVAT(IN PVCB Vcb, + IN uint32 Lba, + IN uint32 Length); +// +OSSTATUS UDFUpdateVAT(IN void* _Vcb, + IN uint32 Lba, + IN uint32* RelocTab, + IN uint32 BCount); +// +OSSTATUS +__fastcall UDFUnPackMapping(IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo); // Extent array +// +OSSTATUS UDFConvertFEToNonInICB(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo, + IN uint8 NewAllocMode); +// +OSSTATUS UDFConvertFEToExtended(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); +// +#define UDFGetPartNumByPartNdx(Vcb, pi) (Vcb->Partitions[pi].PartitionNum) +// +uint32 +__fastcall UDFPartLen(PVCB Vcb, + uint32 PartNum); +// +OSSTATUS UDFPretendFileDeleted__(IN PVCB Vcb, + IN PUDF_FILE_INFO FileInfo); + +#define UDFStreamsSupported(Vcb) \ + (Vcb->maxUDFWriteRev >= 0x0200) + +#define UDFNtAclSupported(Vcb) \ + (Vcb->maxUDFWriteRev >= 0x0200) + +#define UDFReferenceFile__(fi) \ +{ \ + UDFInterlockedIncrement((PLONG)&((fi)->RefCount)); \ + UDFInterlockedIncrement((PLONG)&((fi)->Dloc->LinkRefCount)); \ + if((fi)->ParentFile) { \ + UDFInterlockedIncrement((PLONG)&((fi)->ParentFile->OpenCount)); \ + } \ +} + +#define UDFReferenceFileEx__(fi,i) \ +{ \ + UDFInterlockedExchangeAdd((PLONG)&((fi)->RefCount),i); \ + UDFInterlockedExchangeAdd((PLONG)&((fi)->Dloc->LinkRefCount),i); \ + if((fi)->ParentFile) { \ + UDFInterlockedExchangeAdd((PLONG)&((fi)->ParentFile->OpenCount),i); \ + } \ +} + +#define UDFDereferenceFile__(fi) \ +{ \ + UDFInterlockedDecrement((PLONG)&((fi)->RefCount)); \ + UDFInterlockedDecrement((PLONG)&((fi)->Dloc->LinkRefCount)); \ + if((fi)->ParentFile) { \ + UDFInterlockedDecrement((PLONG)&((fi)->ParentFile->OpenCount)); \ + } \ +} + +#define UDFIsDirEmpty__(fi) UDFIsDirEmpty((fi)->Dloc->DirIndex) +#define UDFIsDirOpened__(fi) (fi->OpenCount) + +#define UDFSetFileAllocMode__(fi, mode) \ +{ \ + (fi)->Dloc->DataLoc.Flags = \ + ((fi)->Dloc->DataLoc.Flags & ~EXTENT_FLAG_ALLOC_MASK) | (mode & EXTENT_FLAG_ALLOC_MASK); \ +} + +#define UDFGetFileAllocMode__(fi) ((fi)->Dloc->DataLoc.Flags & EXTENT_FLAG_ALLOC_MASK) + +#define UDFGetFileICBAllocMode__(fi) (((PFILE_ENTRY)((fi)->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) + +#ifndef UDF_LIMIT_DIR_SIZE // release +#define UDF_DIR_INDEX_FRAME_SH 9 +#else // demo +#define UDF_DIR_INDEX_FRAME_SH 7 +#endif + +#define UDF_DIR_INDEX_FRAME ((uint_di)(1 << UDF_DIR_INDEX_FRAME_SH)) + +#define UDF_DIR_INDEX_FRAME_GRAN (32) +#define UDF_DIR_INDEX_FRAME_GRAN_MASK (UDF_DIR_INDEX_FRAME_GRAN-1) +#define AlignDirIndex(n) ((n+UDF_DIR_INDEX_FRAME_GRAN_MASK) & ~(UDF_DIR_INDEX_FRAME_GRAN_MASK)) + +#if defined _X86_ && !defined UDF_LIMIT_DIR_SIZE + +PDIR_INDEX_ITEM +__fastcall +UDFDirIndex( + IN PDIR_INDEX_HDR hDirNdx, + IN uint32 i + ); + +#else // NO X86 optimization , use generic C/C++ +__inline PDIR_INDEX_ITEM UDFDirIndex(IN PDIR_INDEX_HDR hDirNdx, + IN uint_di i) +{ +#ifdef UDF_LIMIT_DIR_SIZE + if( hDirNdx && (i < hDirNdx->LastFrameCount)) + return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[0])[i] ); +#else //UDF_LIMIT_DIR_SIZE + uint_di j, k; + if( hDirNdx && + ((j = (i >> UDF_DIR_INDEX_FRAME_SH)) < (k = hDirNdx->FrameCount) ) && + ((i = (i & (UDF_DIR_INDEX_FRAME-1))) < ((j < (k-1)) ? UDF_DIR_INDEX_FRAME : hDirNdx->LastFrameCount)) ) + return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[j])[i] ); +#endif // UDF_LIMIT_DIR_SIZE + return NULL; +} +#endif // _X86_ + +#define UDFDirIndexGetLastIndex(di) ((((di)->FrameCount - 1) << UDF_DIR_INDEX_FRAME_SH) + (di)->LastFrameCount) + +// arr - bit array, bit - number of bit +#ifdef _X86_ + +#ifdef _CONSOLE +#define CheckAddr(addr) {ASSERT((uint32)(addr) > 0x1000);} +#else +#define CheckAddr(addr) {ASSERT((uint32)(addr) & 0x80000000);} +#endif + +#define UDFGetBit(arr, bit) UDFGetBit__((uint32*)(arr), bit) + +BOOLEAN +__fastcall +UDFGetBit__( + IN uint32* arr, + IN uint32 bit + ); + +#define UDFSetBit(arr, bit) UDFSetBit__((uint32*)(arr), bit) + +void +__fastcall +UDFSetBit__( + IN uint32* arr, + IN uint32 bit + ); + +#define UDFSetBits(arr, bit, bc) UDFSetBits__((uint32*)(arr), bit, bc) + +void +UDFSetBits__( + IN uint32* arr, + IN uint32 bit, + IN uint32 bc + ); + +#define UDFClrBit(arr, bit) UDFClrBit__((uint32*)(arr), bit) + +void +__fastcall +UDFClrBit__( + IN uint32* arr, + IN uint32 bit + ); + +#define UDFClrBits(arr, bit, bc) UDFClrBits__((uint32*)(arr), bit, bc) + +void +UDFClrBits__( + IN uint32* arr, + IN uint32 bit, + IN uint32 bc + ); + +#else // NO X86 optimization , use generic C/C++ + +#define UDFGetBit(arr, bit) ( (BOOLEAN) ( ((((uint32*)(arr))[(bit)>>5]) >> ((bit)&31)) &1 ) ) +#define UDFSetBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31)) ) +#define UDFClrBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) &= (~(((uint32)1) << ((bit)&31))) ) + +#define UDFSetBits(arr, bit, bc) \ +{uint32 j; \ + for(j=0;jFSBM_Bitmap_owners[i] = 0; + #define UDFSetUsedBitOwner(Vcb, i, o) (Vcb)->FSBM_Bitmap_owners[i] = o; + #define UDFGetUsedBitOwner(Vcb, i) ((Vcb)->FSBM_Bitmap_owners[i]) + #define UDFCheckUsedBitOwner(Vcb, i, o) { \ + ASSERT(i<(Vcb)->FSBM_BitCount); \ + if((Vcb)->FSBM_Bitmap_owners[i] != -1) { \ + ASSERT((Vcb)->FSBM_Bitmap_owners[i] == o); \ + } else { \ + ASSERT((Vcb)->FSBM_Bitmap_owners[i] != 0); \ + (Vcb)->FSBM_Bitmap_owners[i] = o; \ + } \ + } + #define UDFCheckFreeBitOwner(Vcb, i) ASSERT((Vcb)->FSBM_Bitmap_owners[i] == 0); + #else + #define UDFSetFreeBitOwner(Vcb, i) + #define UDFSetUsedBitOwner(Vcb, i, o) + #define UDFCheckUsedBitOwner(Vcb, i, o) + #define UDFCheckFreeBitOwner(Vcb, i) + #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS +#else + #define UDFSetFreeBitOwner(Vcb, i) + #define UDFSetUsedBitOwner(Vcb, i, o) + #define UDFCheckUsedBitOwner(Vcb, i, o) + #define UDFCheckFreeBitOwner(Vcb, i) +#endif //UDF_DBG + +#ifdef UDF_TRACK_FS_STRUCTURES +extern +VOID +UDFRegisterFsStructure( + PVCB Vcb, + uint32 Lba, + uint32 Length // sectors + ); +#else //UDF_TRACK_FS_STRUCTURES +#define UDFRegisterFsStructure(Vcb, Lba, Length) {NOTHING;} +#endif //UDF_TRACK_FS_STRUCTURES + +extern const char hexChar[]; + +#define UDF_MAX_VERIFY_CACHE (8*1024*1024/2048) +#define UDF_VERIFY_CACHE_LOW (4*1024*1024/2048) +#define UDF_VERIFY_CACHE_GRAN (512*1024/2048) +#define UDF_SYS_CACHE_STOP_THR (10*1024*1024/2048) + +OSSTATUS +UDFVInit( + IN PVCB Vcb + ); + +VOID +UDFVRelease( + IN PVCB Vcb + ); + +#define PH_FORGET_VERIFIED 0x00800000 +#define PH_READ_VERIFY_CACHE 0x00400000 +#define PH_KEEP_VERIFY_CACHE 0x00200000 + +OSSTATUS +UDFVWrite( + IN PVCB Vcb, + IN void* Buffer, // Target buffer + IN uint32 BCount, + IN uint32 LBA, +// OUT uint32* WrittenBytes, + IN uint32 Flags + ); + +OSSTATUS +UDFVRead( + IN PVCB Vcb, + IN void* Buffer, // Target buffer + IN uint32 BCount, + IN uint32 LBA, +// OUT uint32* ReadBytes, + IN uint32 Flags + ); + +OSSTATUS +UDFVForget( + IN PVCB Vcb, + IN uint32 BCount, + IN uint32 LBA, + IN uint32 Flags + ); + +#define UFD_VERIFY_FLAG_FORCE 0x01 +#define UFD_VERIFY_FLAG_WAIT 0x02 +#define UFD_VERIFY_FLAG_BG 0x04 +#define UFD_VERIFY_FLAG_LOCKED 0x10 + +VOID +UDFVVerify( + IN PVCB Vcb, + IN ULONG Flags + ); + +VOID +UDFVFlush( + IN PVCB Vcb + ); + +__inline +BOOLEAN +__fastcall UDFVIsStored( + IN PVCB Vcb, + IN lba_t lba + ) +{ + if(!Vcb->VerifyCtx.VInited) + return FALSE; + return UDFGetBit(Vcb->VerifyCtx.StoredBitMap, lba); +} // end UDFVIsStored() + +BOOLEAN +__fastcall +UDFCheckArea( + IN PVCB Vcb, + IN lba_t LBA, + IN uint32 BCount + ); + +#endif // __UDF_STRUCT_SUPPORT_H__ diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf_info.mak b/reactos/drivers/filesystems/udfs/udf_info/udf_info.mak new file mode 100644 index 00000000000..aed73223bc3 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf_info.mak @@ -0,0 +1,69 @@ +#//////////////////////////////////////////////////////////////////// +#// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +#// All rights reserved +#//////////////////////////////////////////////////////////////////// +# Include make file + +#!MESSAGE Including UDF_INFO... + +!IF "$(UDF_INFO_CFG)" == "SRC" + +#!MESSAGE SRC... + +!IF "$(UDF_INFO_PATH)" == "" +!MESSAGE Defaulting UDF_INFO path +UDF_INFO_PATH=. +!ENDIF + +UDF_INFO_OBJS= \ + "$(INTDIR)\alloc.obj" \ + "$(INTDIR)\extent.obj" \ + "$(INTDIR)\dirtree.obj" \ + "$(INTDIR)\mount.obj" \ + "$(INTDIR)\phys_eject.obj" \ + "$(INTDIR)\physical.obj" \ + "$(INTDIR)\remap.obj" \ + "$(INTDIR)\udf_info.obj" + +!ELSEIF "$(UDF_INFO_CFG)" == "MAKE" + +#!MESSAGE MAKE... +# Explain how to make UDF_INFO sources +!IF "$(xCFG)" == "UDF - NT4 Release" || "$(xCFG)" == "UDF - NT4 Debug" + +.IGNORE: + +REL_PATH=$(UDF_INFO_PATH) +SRC_EXT=cpp + +#!MESSAGE :: $(REL_PATH)\alloc.$(SRC_EXT) :: + +SRC=alloc +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=dirtree +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=extent +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=mount +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=phys_eject +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=physical +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=remap +!INCLUDE $(UDF_INFO_PATH)\build.mak + +SRC=udf_info +!INCLUDE $(UDF_INFO_PATH)\build.mak + + +!ENDIF + + +!ENDIF diff --git a/reactos/drivers/filesystems/udfs/udf_info/udf_rel.h b/reactos/drivers/filesystems/udfs/udf_info/udf_rel.h new file mode 100644 index 00000000000..6bc8080d6a9 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udf_info/udf_rel.h @@ -0,0 +1,555 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module Name: udf_rel.h + + Abstract: + + Contains udf related structures. + + Environment: + + Both kernel and user mode + +*/ + +#ifndef _UDF_REL_H_ +#define _UDF_REL_H_ + +#include "Include\platform.h" +#include "Ecma_167.h" + +#ifdef UDF_LIMIT_DIR_SIZE +typedef uint8 uint_di; +#else //UDF_LIMIT_DIR_SIZE +typedef uint32 uint_di; +#endif //UDF_LIMIT_DIR_SIZE + +typedef struct _UDFTrackMap { + uint32 FirstLba; + uint32 LastLba; + uint32 NWA; + uint32 PacketSize; + uint32 Session; + uint8 TrackParam; + uint8 DataParam; + uint8 NWA_V; + + uint8 Flags; +#define TrackMap_AllowCopyBit_variated 0x01 +#define TrackMap_CopyBit_variated 0x02 +#define TrackMap_Try_variation 0x04 +#define TrackMap_Use_variation 0x08 +#define TrackMap_FixFPAddressing 0x10 +#define TrackMap_FixMRWAddressing 0x20 + + // are used only if FixFPAddressing is enabled + uint32 TrackFPOffset; + uint32 PacketFPOffset; + +} UDFTrackMap, *PUDFTrackMap; + +typedef struct _UDFSparingData +{ + uint32 SparingLocation; + uint16 SparingPLength; +} UDFSparingData, *PUDFSparingData; + +#define PACK_MAPPING_THRESHOLD (sizeof(EXTENT_MAP)*8) + +typedef struct _EXTENT_INFO { + uint32 Offset; + PEXTENT_MAP Mapping; + int64 Length; // user data + BOOLEAN Modified; // mapping + UCHAR Flags; +/* + UCHAR Reserved[2]; + PVOID Cache; +*/ +} EXTENT_INFO, *PEXTENT_INFO; + +#define EXTENT_FLAG_ALLOC_STD 0x00 +#define EXTENT_FLAG_ALLOC_SEQUENTIAL 0x01 +#define EXTENT_FLAG_ALLOC_MASK 0x03 +#define EXTENT_FLAG_PREALLOCATED 0x80 +#define EXTENT_FLAG_CUT_PREALLOCATED 0x40 +#define EXTENT_FLAG_VERIFY 0x20 +#define EXTENT_FLAG_2K_COMPAT 0x10 + +typedef struct _UDFPartMap +{ + uint32 UspaceBitmap; // Lba + uint32 FspaceBitmap; // Lba + uint32 AccessType; + uint32 PartitionRoot; + uint32 PartitionLen; + uint16 PartitionType; + uint16 PartitionNum; + uint16 VolumeSeqNum; +} UDFPartMap, *PUDFPartMap; + + +#define VDS_POS_PRIMARY_VOL_DESC 0 +#define VDS_POS_UNALLOC_SPACE_DESC 1 +#define VDS_POS_LOGICAL_VOL_DESC 2 +#define VDS_POS_PARTITION_DESC 3 +#define VDS_POS_IMP_USE_VOL_DESC 4 +#define VDS_POS_VOL_DESC_PTR 5 +#define VDS_POS_TERMINATING_DESC 6 +#define VDS_POS_RECURSION_COUNTER 7 +#define VDS_POS_LENGTH 8 + +typedef struct _UDF_VDS_RECORD { + uint32 block; + uint32 volDescSeqNum; +} UDF_VDS_RECORD, *PUDF_VDS_RECORD; + +#define VRS_NSR02_FOUND 0x0001 +#define VRS_NSR03_FOUND 0x0002 +#define VRS_ISO9660_FOUND 0x0004 + +#define EXTENT_MAP_GRAN (8*sizeof(LONG_AD)) +#define DIR_INDEX_MAP_GRAN (8*sizeof(DIR_INDEX)) +#define SHORT_AD_GRAN (8*sizeof(SHORT_AD)) +#define RELOC_MAP_GRAN (8*sizeof(EXT_RELOCATION_ENTRY)) +#define ALLOC_DESC_MAX_RECURSE 256 + +struct _UDF_FILE_INFO; +struct _DIR_INDEX_ITEM; + +#define UDF_DIR_INDEX_MT PagedPool +#define UDF_FILENAME_MT PagedPool + +typedef struct _HASH_ENTRY { + uint32 hDos; // hash for Dos-name + uint32 hLfn; // hash for Upcased Lfn + uint32 hPosix; // hash for Posix Lfn +} HASH_ENTRY, *PHASH_ENTRY; + +typedef struct _DIR_INDEX_HDR { + uint_di FirstFree; + uint_di LastUsed; + uint_di FrameCount; + uint_di LastFrameCount; // in items + uint_di DelCount; + EXTENT_INFO FECharge; // file entry charge + EXTENT_INFO FEChargeSDir; // file entry charge for streams + ULONG DIFlags; +// struct _DIR_INDEX_ITEM* FrameList[0]; +} DIR_INDEX_HDR, *PDIR_INDEX_HDR; + +// Initial location of directory data extent in IN_ICB +#define UDF_DI_FLAG_INIT_IN_ICB (0x01) + +/** + This is an entry of file list. Each directory has such a list + for fast search & modification. This structure was introduced + because on-disk equivalents have variable sizes & record + formats. +*/ +typedef struct _DIR_INDEX_ITEM { + // FSD-specific data +/** + Specifies the position of corresponding FileIdent inside the + directory (on-disk). +*/ + uint32 Offset; // File Ident offset in extent +/** + Specifies on-disk size of FileIdent. 0 value of this field + means that given entry has no on-disk representation (ex. - + pointer to the directory itself). In this case #Offset + value must be also 0. +*/ + uint32 Length; // Its length +/** + Points to file name in UnicodeString format. NULL value of + this field is treated as list terminator. +*/ + UNICODE_STRING FName; // Filename +/** + Specifies on-disk location of FileEntry associated with the + given file. This value should be used for unopened files. +*/ + lb_addr FileEntryLoc; // pointer to FileEntry +/** + Cached value from FileIdent (see #FILE_IDENT_DESC) +*/ + uint8 FileCharacteristics; +/** + Set of flags. This is intended for internal use. + Valid flags: + - #UDF_FI_FLAG_FI_MODIFIED\n + Presence of this bit means that given FileIdent was modified + & should be flushed. + - #UDF_FI_FLAG_SYS_ATTR\n + Presence of this bit means that given entry of file list + contains valid file attributes & times in NT-specific format. + - #UDF_FI_FLAG_FI_INTERNAL\n + Presence of this bit means that given entry represents the + file used for internal FS purposes & must be invisible. + - #UDF_FI_FLAG_LINKED\n + Presence of this bit means that related FileEntry has more + than one FileIdent. It happends when we use HardLinks. +*/ + uint8 FI_Flags; // FileIdent-related flags +/** + Points to FileInfo structure for opened files. This field + must be NULL if the file is not opened. +*/ + struct _UDF_FILE_INFO* FileInfo; // associated FileInfo (if opened) + // search hashes + HASH_ENTRY hashes; + // attributes (System-specific format) + uint32 SysAttr; + int64 CreationTime; + int64 LastWriteTime; + int64 LastAccessTime; + int64 ChangeTime; + int64 FileSize; + int64 AllocationSize; +} DIR_INDEX_ITEM, *PDIR_INDEX_ITEM; +/// FileIdent was modified & should be flushed. +#define UDF_FI_FLAG_FI_MODIFIED (0x01) +/// Given entry of file list contains valid file attributes & times in NT-specific format. +#define UDF_FI_FLAG_SYS_ATTR (0x02)// cached flags in system-specific format +/// Given entry represents the file used for internal FS purposes & must be invisible +#define UDF_FI_FLAG_FI_INTERNAL (0x04) +/// Related FileEntry has more than one FileIdent. It happends when we use HardLinks. +#define UDF_FI_FLAG_LINKED (0x08) + +#define UDF_FI_FLAG_DOS (0x10)// Lfn-style name is equal to DOS-style (case insensetive) +#define UDF_FI_FLAG_KEEP_NAME (0x20) + +#define UDF_DATALOC_INFO_MT PagedPool + +/** + This structure describes actual data location. It is an + analogue (and a pair in this implementation) of NTRequiredFcb + structure. + + UDF FSD keeps list of all Dloc structures & their on-disk + representations. Before allocating new Dloc for newly opened + file the FSD checks if the Dloc with the same Lba is already + in memory. If it is so the initiator receive pointer to + existing structure instead of allocating new. This allows to + handle HardLiks properly. When all references to given Dloc + has gone it is released. In case of file deletion the + association between Dloc & Lba is discarded, but Dloc is not + released untill UDFCleanUpFile__() is called. This prevents + interference between deleted files & newly created ones in + case of equal Lba of deleted & created FileEntries. + +*/ + +typedef struct _UDF_DATALOC_INFO { + +/** + NT-specific field. As soon as NT supports HardLink concept it + has own structure describing the file's actual data. +*/ + struct _UDFNTRequiredFCB* CommonFcb; // pointer to corresponding NtReqFcb +/** + Describes on-disk location of user data. If the file is + recorded using IN_ICB method this structure points to the + same LBA as #FELoc, but with non-zero offset inside logical + block +*/ + EXTENT_INFO DataLoc; // user data +/** + Describes on-disk location of allocation descriptors. They + are part of metadata associated with given file If this + structure is not initialized UDF assumes that no allocation + descriptors recorded for this file. Usually this structure + points to the same LBA as #FELoc, but with non-zero offset + inside logical block. The only exception is for files + recorded using IN_ICB method (see above). In such a case this + structure must be zero-filled +*/ + + EXTENT_INFO AllocLoc; // allocation descriptors (if any) +/** + Describes on-disk location the FileEntry. This is on-disk + metadata block describing file location. +*/ + EXTENT_INFO FELoc; // file entry location +/** + Pointer to cached FileEntry. This field mush be valid untill + all file instances are cleaned up (see UDFCleanUpFile__() and + #LinkRefCount). +*/ + tag* FileEntry; // file entry data + uint32 FileEntryLen; +/** + Set of flags. This is intended for internal use. + Valid flags: + - #UDF_FE_FLAG_FE_MODIFIED\n + Presence of this bit means that given FileEntry was modified & + should be flushed + - #UDF_FE_FLAG_HAS_SDIR\n + Presence of this bit means that given FileEntry has an associated + Stream Dir. + - #UDF_FE_FLAG_IS_SDIR\n + Presence of this bit means that given FileEntry represents a Stream Dir. +*/ + uint32 FE_Flags; // FileEntry flags +/** + Counter of currently opened directory tree instances (files) + pointing to given data. It is introduced because UDF supports + HardLink concept. UDF_DATALOC_INFO structure should not be + released untill this field reaches zero. +*/ + uint32 LinkRefCount; +/** + Points to the list of files referenced by the given file. + This field is used for directories only. Otherwise its value + should be NULL. +*/ + PDIR_INDEX_HDR DirIndex; // for Directory objects only + struct _UDF_FILE_INFO* LinkedFileInfo; +/** + Points to the FileInfo describing the StreamDirectory + associated with the given file. If the file has no associated + StreamDirectory this field must bu NULL. +*/ + struct _UDF_FILE_INFO* SDirInfo; +} UDF_DATALOC_INFO, *PUDF_DATALOC_INFO; + +/// Was modified & should be flushed +#define UDF_FE_FLAG_FE_MODIFIED (0x01) +/// File contains Stream Dir +#define UDF_FE_FLAG_HAS_SDIR (0x02) +/// File is a StreamDir +#define UDF_FE_FLAG_IS_SDIR (0x04) +/// Dir was modified & should be packed +#define UDF_FE_FLAG_DIR_MODIFIED (0x08) +/// File contains pointer to Deleted Stream Dir +#define UDF_FE_FLAG_HAS_DEL_SDIR (0x10) +/// File is Deleted Stream Dir +#define UDF_FE_FLAG_IS_DEL_SDIR (0x20) +/// Dloc is being initialized, don't touch it now +#define UDF_FE_FLAG_UNDER_INIT (0x40) + + +#define UDF_FILE_INFO_MT PagedPool + + +/** + This structure describes file location in the directory + tree.. It is an analogue (and a pair in this implementation) + of Fcb structure. +*/ +typedef struct _UDF_FILE_INFO { +#ifdef VALIDATE_STRUCTURES +/** + Used for debug purposes. Each valid FileInfo structure has + IntegrityTag set to zero. If the routine receives FileInfo + with invalid IntegrityTag value the break occures. +*/ + uint32 IntegrityTag; +#endif +/** + Points to the NT structure describing file instance in the + directory tree. Each file opened by NT has Fcb structure & + associated FileInfo. If the file is opened by UDF FSD for + internal use this field may be NULL. Each Fcb has a back + pointer to FileInfo, so both structures are accessable. +*/ + struct _UDFFileControlBlock* Fcb; // pointer to corresponding Fcb (null if absent) +/** + Points to the structure describing actual data location & + file attributes. See #UDF_DATALOC_INFO for more information. +*/ + PUDF_DATALOC_INFO Dloc; // actual data location descriptor +/** + Pointer to cached FileIdent. This field mush be valid untill + the file is cleaned up (see UDFCleanUpFile__()). +*/ + PFILE_IDENT_DESC FileIdent; // file ident data +/** + Length of the buffer allocated for FileIdent. +*/ + uint32 FileIdentLen; +/** + Points to FileInfo structure of the Parent Directory. If the + file has no parent directory this field must be NULL. +*/ + struct _UDF_FILE_INFO* ParentFile; // parent (directory) if any +/** + Number of entry in the DirIndex of the parent directory. It + is used for fast access & modification of the parent. + FileInfo with index equal to 0 usually describes the + directory itself (file name is '.' & the parent is given + directory itself). FileInfo with index equal to 1 usually + describes the parent (file name is '..'). Otherwise FileInfo + describes a plain file or directory. If the file has no + parent this field must be 0. +*/ + uint_di Index; // index in parent directory +/** + Counter of open operations. Each routine opening the file + increments this counter, each routine closing the file - + decrements. The FileInfo structure can't be released untill + this counter reachs zero. +*/ + uint32 RefCount; // number of references +/** + Counter of open operations performed for subsequent files. + Each routine opening the file increments this counter in + parent FileInfo structure, each routine closing the file - + decrements. The FileInfo structure can't be released untill + this counter reachs zero. +*/ + uint32 OpenCount; // number of opened files in Dir + struct _UDF_FILE_INFO* NextLinkedFile; // + struct _UDF_FILE_INFO* PrevLinkedFile; // + + struct _FE_LIST_ENTRY* ListPtr; +} UDF_FILE_INFO, *PUDF_FILE_INFO; + +typedef struct _FE_LIST_ENTRY { + PUDF_FILE_INFO FileInfo; + ULONG EntryRefCount; +} FE_LIST_ENTRY, *PFE_LIST_ENTRY; + +#define DOS_NAME_LEN 8 +#define DOS_EXT_LEN 3 +#define ILLEGAL_CHAR_MARK 0x005F +#define UNICODE_CRC_MARK 0x0023 +#define UNICODE_PERIOD 0x002E +#define UNICODE_SPACE 0x0020 + +#define LBA_OUT_OF_EXTENT ((LONG)(-1)) +#define LBA_NOT_ALLOCATED ((LONG)(-2)) + +typedef struct _EXT_RELOCATION_ENTRY { + uint32 extLength; + uint32 extLocation; + uint32 extRedir; +} EXT_RELOCATION_ENTRY, *PEXT_RELOCATION_ENTRY; + +typedef struct _UDF_DATALOC_INDEX { + uint32 Lba; + PUDF_DATALOC_INFO Dloc; +} UDF_DATALOC_INDEX, *PUDF_DATALOC_INDEX; + +typedef struct _UDF_DIR_SCAN_CONTEXT { + PUDF_FILE_INFO DirInfo; + PDIR_INDEX_HDR hDirNdx; + PDIR_INDEX_ITEM DirNdx; + uint32 frame; + uint_di j; + uint32 d; + uint_di i; +} UDF_DIR_SCAN_CONTEXT, *PUDF_DIR_SCAN_CONTEXT; + +typedef EXT_RELOCATION_ENTRY EXT_RELOC_MAP; +typedef PEXT_RELOCATION_ENTRY PEXT_RELOC_MAP; + +typedef struct _UDF_ALLOCATION_CACHE_ITEM { + lba_t ParentLocation; + uint32 Items; + EXTENT_INFO Ext; +} UDF_ALLOCATION_CACHE_ITEM, *PUDF_ALLOCATION_CACHE_ITEM; + +/* +#define MEM_DIR_HDR_TAG (ULONG)"DirHdr" +#define MEM_DIR_NDX_TAG (ULONG)"DirNdx" +#define MEM_DLOC_NDX_TAG (ULONG)"DlocNdx" +#define MEM_DLOC_INF_TAG (ULONG)"DlocInf" +#define MEM_FNAME_TAG (ULONG)"FName" +#define MEM_FNAME16_TAG (ULONG)"FName16" +#define MEM_FNAMECPY_TAG (ULONG)"FNameC" +#define MEM_FE_TAG (ULONG)"FE" +#define MEM_XFE_TAG (ULONG)"xFE" +#define MEM_FID_TAG (ULONG)"FID" +#define MEM_FINF_TAG (ULONG)"FInf" +#define MEM_VATFINF_TAG (ULONG)"FInfVat" +#define MEM_SDFINF_TAG (ULONG)"SDirFInf" +#define MEM_EXTMAP_TAG (ULONG)"ExtMap" +#define MEM_ALLOCDESC_TAG (ULONG)"AllocDesc" +#define MEM_SHAD_TAG (ULONG)"SHAD" +#define MEM_LNGAD_TAG (ULONG)"LNGAD" +*/ + +#define MEM_DIR_HDR_TAG 'DirH' +#define MEM_DIR_NDX_TAG 'DirN' +#define MEM_DLOC_NDX_TAG 'Dloc' +#define MEM_DLOC_INF_TAG 'Dloc' +#define MEM_FNAME_TAG 'FNam' +#define MEM_FNAME16_TAG 'FNam' +#define MEM_FNAMECPY_TAG 'FNam' +#define MEM_FE_TAG 'FE' +#define MEM_XFE_TAG 'xFE"' +#define MEM_FID_TAG 'FID' +#define MEM_FINF_TAG 'FInf' +#define MEM_VATFINF_TAG 'FInf' +#define MEM_SDFINF_TAG 'SDir' +#define MEM_EXTMAP_TAG 'ExtM' +#define MEM_ALLOCDESC_TAG 'Allo' +#define MEM_SHAD_TAG 'SHAD' +#define MEM_LNGAD_TAG 'LNGA' +#define MEM_ALLOC_CACHE_TAG 'hcCA' + +#define UDF_DEFAULT_LAST_LBA_CD 276159 +#define UDF_DEFAULT_LAST_LBA_DVD 0x23053f +#define UDF_DEFAULT_FE_CHARGE 128 +#define UDF_DEFAULT_FE_CHARGE_SDIR 1 +#define UDF_WRITE_MAX_RETRY 4 +#define UDF_READ_MAX_RETRY 4 +#define UDF_READY_MAX_RETRY 5 + +#define ICB_FLAG_AD_DEFAULT_ALLOC_MODE (UCHAR)(0xff) + +#define UDF_INVALID_LINK_COUNT 0xffff +#define UDF_MAX_LINK_COUNT 0x7fff + +#define UDF_MAX_EXTENT_LENGTH (UDF_EXTENT_LENGTH_MASK & ~(2048-1)) + +#define UDF_MAX_READ_REVISION 0x0260 +#define UDF_MAX_WRITE_REVISION 0x0201 + +#define UDF_MAX_LVID_CHAIN_LENGTH 1024 +#define UDF_LVID_TTL 1024 + +#define UDF_NO_EXTENT_MAP ((PEXTENT_MAP)0xffffffff) + +#define UDF_FLUSH_FLAGS_LITE (0x80000000) + +#if defined UDF_DBG || defined _CONSOLE +//#define UDF_CHECK_DISK_ALLOCATION + +//#define UDF_TRACK_ONDISK_ALLOCATION + +//#define UDF_TRACK_ONDISK_ALLOCATION_OWNERS +//#define UDF_TRACK_ONDISK_ALLOCATION_OWNERS_INTERNAL + +//#define UDF_TRACK_EXTENT_TO_MAPPING + +//#define UDF_TRACK_ALLOC_FREE_EXTENT + +//#define UDF_CHECK_EXTENT_SIZE_ALIGNMENT + +// dependences: + +#ifdef UDF_TRACK_ALLOC_FREE_EXTENT + #define UDF_TRACK_EXTENT_TO_MAPPING +#endif //UDF_TRACK_ALLOC_FREE_EXTENT + +#endif //UDF_DBG + +typedef struct _UDF_VERIFY_CTX { + uint8* StoredBitMap; + ULONG ItemCount; + LIST_ENTRY vrfList; + ERESOURCE VerifyLock; + KEVENT vrfEvent; + uint32 WaiterCount; + uint32 QueuedCount; + BOOLEAN VInited; +} UDF_VERIFY_CTX, *PUDF_VERIFY_CTX; + +#endif /* _UDF_REL_H_ */ diff --git a/reactos/drivers/filesystems/udfs/udffs.h b/reactos/drivers/filesystems/udfs/udffs.h new file mode 100644 index 00000000000..e5c0889b8fd --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udffs.h @@ -0,0 +1,384 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: UDF.h +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the UDF file system driver. +* +*************************************************************************/ + +#ifndef _UDF_UDF_H_ +#define _UDF_UDF_H_ + +/**************** OPTIONS *****************/ + +//#define UDF_TRACK_UNICODE_STR + +//#define DEMO + +//#define UDF_LIMIT_NAME_LEN + +//#define UDF_LIMIT_DIR_SIZE + +#ifdef UDF_LIMIT_NAME_LEN + #define UDF_X_NAME_LEN (20) + #define UDF_X_PATH_LEN (25) +#else //UDF_LIMIT_NAME_LEN + #define UDF_X_NAME_LEN UDF_NAME_LEN + #define UDF_X_PATH_LEN UDF_PATH_LEN +#endif //UDF_LIMIT_NAME_LEN + +#define IFS_40 +//#define PRETEND_NTFS + +//#define UDF_ASYNC_IO + +//#define UDF_ENABLE_SECURITY + +#define UDF_HANDLE_EAS + +#define UDF_HDD_SUPPORT + +#define UDF_ALLOW_FRAG_AD + +#ifndef UDF_LIMIT_DIR_SIZE + #define UDF_DEFAULT_DIR_PACK_THRESHOLD (128) +#else // UDF_LIMIT_DIR_SIZE + #define UDF_DEFAULT_DIR_PACK_THRESHOLD (16) +#endif // UDF_LIMIT_DIR_SIZE + +#ifdef DEMO + #define UDF_DEMO_VOLUME_LABEL L"UDF Demo" +#endif //DEMO + +#define UDF_DEFAULT_READAHEAD_GRAN 0x10000 +#define UDF_DEFAULT_SPARSE_THRESHOLD (256*PACKETSIZE_UDF) + +#define ALLOW_SPARSE + +#define UDF_PACK_DIRS + +#define MOUNT_ERR_THRESHOLD 256 + +#define UDF_VALID_FILE_ATTRIBUTES \ + (FILE_ATTRIBUTE_READONLY | \ + FILE_ATTRIBUTE_HIDDEN | \ + FILE_ATTRIBUTE_SYSTEM | \ + FILE_ATTRIBUTE_DIRECTORY | \ + FILE_ATTRIBUTE_ARCHIVE | \ + /*FILE_ATTRIBUTE_DEVICE | */ \ + FILE_ATTRIBUTE_NORMAL | \ + FILE_ATTRIBUTE_TEMPORARY | \ + FILE_ATTRIBUTE_SPARSE_FILE) + +//#define UDF_DISABLE_SYSTEM_CACHE_MANAGER + +//#define UDF_CDRW_EMULATION_ON_ROM + +#define UDF_DELAYED_CLOSE + +#ifdef UDF_DELAYED_CLOSE +#define UDF_FE_ALLOCATION_CHARGE +#endif //UDF_DELAYED_CLOSE + +#define UDF_ALLOW_RENAME_MOVE + +#define UDF_ALLOW_HARD_LINKS + +#ifdef UDF_ALLOW_HARD_LINKS +//#define UDF_ALLOW_LINKS_TO_STREAMS +#endif //UDF_ALLOW_HARD_LINKS + +//#define UDF_ALLOW_PRETEND_DELETED + +#define UDF_DEFAULT_BM_FLUSH_TIMEOUT 16 // seconds +#define UDF_DEFAULT_TREE_FLUSH_TIMEOUT 5 // seconds + +#define UDF_DEFAULT_FSP_THREAD_PER_CPU (4) +#define UDF_FSP_THREAD_PER_CPU (Vcb->ThreadsPerCpu) +#define FSP_PER_DEVICE_THRESHOLD (UDFGlobalData.CPU_Count*UDF_FSP_THREAD_PER_CPU) + +/************* END OF OPTIONS **************/ + +// some constant definitions +#define UDF_PANIC_IDENTIFIER (0x86427531) + +// Common include files - should be in the include dir of the MS supplied IFS Kit +#ifndef _CONSOLE +extern "C" { +#pragma pack(push, 8) +#include "ntifs.h" +#include "ntifs_ex.h" +#pragma pack(pop) +} +#endif //_CONSOLE + +#include + +#include "..\Include\check_env.h" + +#define PEXTENDED_IO_STACK_LOCATION PIO_STACK_LOCATION + +#ifndef NDEBUG +#define UDF_DBG +#endif + +#define VALIDATE_STRUCTURES +// the following include files should be in the inc sub-dir associated with this driver + +#define OS_SUCCESS(a) NT_SUCCESS(a) +#define OSSTATUS NTSTATUS + +#ifndef _CONSOLE +#include "ntdddisk.h" +#include +#include "..\include\crossnt\crossnt.h" +#endif //_CONSOLE + +#include +#include +#include +//#include "ecma_167.h" +//#include "osta_misc.h" +#include "wcache.h" +#include "..\CDRW\cdrw_usr.h" + +#include "..\Include\regtools.h" + +#ifdef _CONSOLE +#include "udf_info\udf_rel.h" +#include "..\include\udf_common.h" +#else +#include "struct.h" +#endif //_CONSOLE + +// global variables - minimize these +extern UDFData UDFGlobalData; + +#ifndef _CONSOLE +#include "env_spec.h" +#include "DLDetect.h" +#include "Udf_dbg.h" +#else +#include "..\include\env_spec_w32.h" +#endif //_CONSOLE + +#include "sys_spec.h" + +#include "Udf_info\Udf_info.h" + +#ifndef _CONSOLE +#include "protos.h" +#endif //_CONSOLE + +#include "..\Include\phys_lib.h" +#include "errmsg.h" +//#include "..\Include\tools.h" +#include "Include\protect.h" +#include "udfpubl.h" +//#include "ntifs.h" +#include "mem.h" +#include "..\Include\key_lib.h" + +extern CCHAR DefLetter[]; + +// try-finally simulation +#define try_return(S) { S; goto try_exit; } +#define try_return1(S) { S; goto try_exit1; } +#define try_return2(S) { S; goto try_exit2; } + +// some global (helpful) macros +#define UDFSetFlag(Flag, Value) ((Flag) |= (Value)) +#define UDFClearFlag(Flag, Value) ((Flag) &= ~(Value)) + +#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG)(OFFSET) - (ULONG)(BASE))) + +#define UDFQuadAlign(Value) ((((uint32)(Value)) + 7) & 0xfffffff8) + +// to perform a bug-check (panic), the following macro is used +#define UDFPanic(arg1, arg2, arg3) \ + (KeBugCheckEx(UDF_PANIC_IDENTIFIER, UDF_BUG_CHECK_ID | __LINE__, (uint32)(arg1), (uint32)(arg2), (uint32)(arg3))) +// small check for illegal open mode (desired access) if volume is +// read only (on standard CD-ROM device or another like this) +#define UdfIllegalFcbAccess(Vcb,DesiredAccess) (( \ + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && \ + (FlagOn( (DesiredAccess), \ + FILE_WRITE_DATA | \ + FILE_ADD_FILE | \ + FILE_APPEND_DATA | \ + FILE_ADD_SUBDIRECTORY | \ + FILE_WRITE_EA | \ + FILE_DELETE_CHILD | \ + FILE_WRITE_ATTRIBUTES | \ + DELETE | \ + WRITE_OWNER | \ + WRITE_DAC )) \ + ) || ( \ + !(Vcb->WriteSecurity) && \ + (FlagOn( (DesiredAccess), \ + WRITE_OWNER | \ + 0 /*WRITE_DAC*/ )) \ +)) + + +// +#if !defined(UDF_DBG) && !defined(PRINT_ALWAYS) + +#ifndef _CONSOLE +#define UDFAcquireResourceExclusive(Resource,CanWait) \ + (ExAcquireResourceExclusiveLite((Resource),(CanWait))) +#define UDFAcquireResourceShared(Resource,CanWait) \ + (ExAcquireResourceSharedLite((Resource),(CanWait))) +// a convenient macro (must be invoked in the context of the thread that acquired the resource) +#define UDFReleaseResource(Resource) \ + (ExReleaseResourceForThreadLite((Resource), ExGetCurrentResourceThread())) +#define UDFDeleteResource(Resource) \ + (ExDeleteResourceLite((Resource))) +#define UDFConvertExclusiveToSharedLite(Resource) \ + (ExConvertExclusiveToSharedLite((Resource))) +#define UDFInitializeResourceLite(Resource) \ + (ExInitializeResourceLite((Resource))) +#define UDFAcquireSharedStarveExclusive(Resource,CanWait) \ + (ExAcquireSharedStarveExclusive((Resource),(CanWait))) +#define UDFAcquireSharedWaitForExclusive(Resource,CanWait) \ + (ExAcquireSharedWaitForExclusive((Resource),(CanWait))) + +#define UDFInterlockedIncrement(addr) \ + (InterlockedIncrement((addr))) +#define UDFInterlockedDecrement(addr) \ + (InterlockedDecrement((addr))) +#define UDFInterlockedExchangeAdd(addr,i) \ + (InterlockedExchangeAdd((addr),(i))) + +#endif //_CONSOLE + +#define UDF_CHECK_PAGING_IO_RESOURCE(NTReqFCB) +#define UDF_CHECK_EXVCB_RESOURCE(Vcb) +#define UDF_CHECK_BITMAP_RESOURCE(Vcb) + + +#else //UDF_DBG + +#ifndef _CONSOLE +#define UDFAcquireResourceExclusive(Resource,CanWait) \ + (UDFDebugAcquireResourceExclusiveLite((Resource),(CanWait),UDF_BUG_CHECK_ID,__LINE__)) + +#define UDFAcquireResourceShared(Resource,CanWait) \ + (UDFDebugAcquireResourceSharedLite((Resource),(CanWait),UDF_BUG_CHECK_ID,__LINE__)) +// a convenient macro (must be invoked in the context of the thread that acquired the resource) +#define UDFReleaseResource(Resource) \ + (UDFDebugReleaseResourceForThreadLite((Resource), ExGetCurrentResourceThread(),UDF_BUG_CHECK_ID,__LINE__)) + +#define UDFDeleteResource(Resource) \ + (UDFDebugDeleteResource((Resource), ExGetCurrentResourceThread(),UDF_BUG_CHECK_ID,__LINE__)) +#define UDFConvertExclusiveToSharedLite(Resource) \ + (UDFDebugConvertExclusiveToSharedLite((Resource), ExGetCurrentResourceThread(),UDF_BUG_CHECK_ID,__LINE__)) +#define UDFInitializeResourceLite(Resource) \ + (UDFDebugInitializeResourceLite((Resource), ExGetCurrentResourceThread(),UDF_BUG_CHECK_ID,__LINE__)) +#define UDFAcquireSharedStarveExclusive(Resource,CanWait) \ + (UDFDebugAcquireSharedStarveExclusive((Resource), (CanWait), UDF_BUG_CHECK_ID,__LINE__)) +#define UDFAcquireSharedWaitForExclusive(Resource,CanWait) \ + (UDFDebugAcquireSharedWaitForExclusive((Resource), (CanWait), UDF_BUG_CHECK_ID,__LINE__)) + +#define UDFInterlockedIncrement(addr) \ + (UDFDebugInterlockedIncrement((addr), UDF_BUG_CHECK_ID,__LINE__)) +#define UDFInterlockedDecrement(addr) \ + (UDFDebugInterlockedDecrement((addr), UDF_BUG_CHECK_ID,__LINE__)) +#define UDFInterlockedExchangeAdd(addr,i) \ + (UDFDebugInterlockedExchangeAdd((addr),(i), UDF_BUG_CHECK_ID,__LINE__)) + +#endif //_CONSOLE + +#define UDF_CHECK_PAGING_IO_RESOURCE(NTReqFCB) \ + ASSERT(!ExIsResourceAcquiredExclusiveLite(&(NTReqFCB->PagingIoResource))); \ + ASSERT(!ExIsResourceAcquiredSharedLite(&(NTReqFCB->PagingIoResource))); + +#define UDF_CHECK_EXVCB_RESOURCE(Vcb) \ + ASSERT( ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) ); + +#define UDF_CHECK_BITMAP_RESOURCE(Vcb) +/* \ + ASSERT( (ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) || \ + ExIsResourceAcquiredSharedLite(&(Vcb->VCBResource))) ); \ + ASSERT(ExIsResourceAcquiredExclusiveLite(&(Vcb->BitMapResource1))); \ +*/ +#endif //UDF_DBG + +#define UDFRaiseStatus(IC,S) { \ + (IC)->SavedExceptionCode = (S); \ + ExRaiseStatus( (S) ); \ +} + +#define UDFNormalizeAndRaiseStatus(IC,S) { \ + (IC)->SavedExceptionCode = FsRtlNormalizeNtstatus((S),STATUS_UNEXPECTED_IO_ERROR); \ + ExRaiseStatus( (IC)->SavedExceptionCode ); \ +} + +#define UDFIsRawDevice(RC) ( \ + ((RC) == STATUS_DEVICE_NOT_READY) || \ + ((RC) == STATUS_NO_MEDIA_IN_DEVICE) \ +) + + +// each file has a unique bug-check identifier associated with it. +// Here is a list of constant definitions for these identifiers +#define UDF_FILE_INIT (0x00000001) +#define UDF_FILE_FILTER (0x00000002) +#define UDF_FILE_CREATE (0x00000003) +#define UDF_FILE_CLEANUP (0x00000004) +#define UDF_FILE_CLOSE (0x00000005) +#define UDF_FILE_READ (0x00000006) +#define UDF_FILE_WRITE (0x00000007) +#define UDF_FILE_INFORMATION (0x00000008) +#define UDF_FILE_FLUSH (0x00000009) +#define UDF_FILE_VOL_INFORMATION (0x0000000A) +#define UDF_FILE_DIR_CONTROL (0x0000000B) +#define UDF_FILE_FILE_CONTROL (0x0000000C) +#define UDF_FILE_DEVICE_CONTROL (0x0000000D) +#define UDF_FILE_SHUTDOWN (0x0000000E) +#define UDF_FILE_LOCK_CONTROL (0x0000000F) +#define UDF_FILE_SECURITY (0x00000010) +#define UDF_FILE_EXT_ATTR (0x00000011) +#define UDF_FILE_MISC (0x00000012) +#define UDF_FILE_FAST_IO (0x00000013) +#define UDF_FILE_FS_CONTROL (0x00000014) +#define UDF_FILE_PHYSICAL (0x00000015) +#define UDF_FILE_PNP (0x00000016) +#define UDF_FILE_VERIFY_FS_CONTROL (0x00000017) +#define UDF_FILE_ENV_SPEC (0x00000018) +#define UDF_FILE_SYS_SPEC (0x00000019) +#define UDF_FILE_PHYS_EJECT (0x0000001A) + +#define UDF_FILE_DLD (0x00000200) +#define UDF_FILE_MEM (0x00000201) +#define UDF_FILE_MEMH (0x00000202) +#define UDF_FILE_WCACHE (0x00000203) + +#define UDF_FILE_UDF_INFO (0x00000100) +#define UDF_FILE_UDF_INFO_ALLOC (0x00000101) +#define UDF_FILE_UDF_INFO_DIR (0x00000102) +#define UDF_FILE_UDF_INFO_MOUNT (0x00000103) +#define UDF_FILE_UDF_INFO_EXTENT (0x00000104) +#define UDF_FILE_UDF_INFO_REMAP (0x00000105) +//#define UDF_FILE_UDF_INFO_ (0x0000010x) + +#define UDF_FILE_PROTECT (0x00000300) +//#define UDF_FILE_PROTECT_ (0x0000030x) + +#define SystemAllocatePool(hernya,size) ExAllocatePoolWithTag(hernya, size, 'Snwd') +#define SystemFreePool(addr) ExFreePool((PVOID)(addr)) + +//Device names + +#include "../Include/udf_reg.h" + +#include + +#endif // _UDF_UDF_H_ + diff --git a/reactos/drivers/filesystems/udfs/udffs.rc b/reactos/drivers/filesystems/udfs/udffs.rc new file mode 100644 index 00000000000..9b539ab5e32 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udffs.rc @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +//+------------------------------------------------------------------------- +// +// File: udffs.rc +// +//-------------------------------------------------------------------------- + +#if 0 + +#include + +#include + +#include "../include/common.rc" + +#undef VERSION +#define VERSION VER_STR_UDFFS +#define VER_FILEVERSION_STR VER_STR_UDFFS +#define VER_FILEVERSION VER_BIN_UDFFS +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR VER_PRODUCTNAME_STR " File System Driver" +#define VER_INTERNALNAME_STR "dwudf.sys\0" +#define VER_ORIGINALFILENAME_STR "dwudf.sys" +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION VER_BIN_PRODUCT +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR VER_STR_PRODUCT +#undef VER_LEGALTRADEMARKS_STR + +#define VER_LANGNEUTRAL + +#include "common.ver" + +#endif + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "UDF File System Driver" +#define REACTOS_STR_INTERNAL_NAME "dwudf" +#define REACTOS_STR_ORIGINAL_FILENAME "dwudf.sys" +#include diff --git a/reactos/drivers/filesystems/udfs/udfinit.cpp b/reactos/drivers/filesystems/udfs/udfinit.cpp new file mode 100644 index 00000000000..c06cd0ad743 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udfinit.cpp @@ -0,0 +1,1421 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: UDFinit.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* This file contains the initialization code for the kernel mode +* UDF FSD module. The DriverEntry() routine is called by the I/O +* sub-system to initialize the FSD. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_INIT + +// global variables are declared here +UDFData UDFGlobalData; + +#ifdef EVALUATION_TIME_LIMIT + +ULONG PresentDateMask = 0; +BOOLEAN TrialEndOnStart = FALSE; + +#define UDF_MD5Init UDF_MD5Init2 +#define UDF_MD5Update UDF_MD5Update2 +#define UDF_MD5Pad UDF_MD5Pad2 +#define UDF_MD5Final UDF_MD5Final2 +#define UDF_MD5End UDF_MD5End2 +#define UDF_MD5Transform UDF_MD5Transform2 +#define UDF_Encode UDF_Encode2 +#define UDF_Decode UDF_Decode2 +#define PADDING PADDING2 + +#define ROTATE_LEFT ROTATE_LEFT2 +#define FF FF2 +#define GG GG2 +#define HH HH2 +#define II II2 + +#define UDF_MD5Transform_dwords UDF_MD5Transform_dwords2 +#define UDF_MD5Transform_idx UDF_MD5Transform_idx2 +#define UDF_MD5Transform_Sxx UDF_MD5Transform_Sxx2 +#define UDF_MD5Rotate UDF_MD5Rotate2 + +#include "..\Include\md5.h" +#include "..\Include\md5c.c" + +#define UDF_FibonachiNum UDF_FibonachiNum2 +#define XPEHb XPEHb2 +#define UDF_build_long_key UDF_build_long_key2 +#define UDF_build_hash_by_key UDF_build_hash_by_key2 + +#include "..\Include\key_lib.h" +#include "..\Include\key_lib.cpp" + +extern ULONG UDFNumberOfKeys; +extern PCHAR pUDFLongKey; +extern PUDF_KEY_LIST pUDFKeyList; +extern PUCHAR pRegKeyName0; + +#include "..\Include\protect.h" +#define INCLUDE_XOR_DECL_ONLY +#include "..\Include\protect.h" +#undef INCLUDE_XOR_DECL_ONLY + +#endif //EVALUATION_TIME_LIMIT + +#define KD_PREFIX + +struct UDF_MEDIA_CLASS_NAMES UDFMediaClassName[] = { + {MediaUnknown, REG_DEFAULT_UNKNOWN}, + {MediaHdd , REG_DEFAULT_HDD}, + {MediaCdr , REG_DEFAULT_CDR}, + {MediaCdrw , REG_DEFAULT_CDRW}, + {MediaCdrom , REG_DEFAULT_CDROM}, + {MediaZip , REG_DEFAULT_ZIP}, + {MediaFloppy , REG_DEFAULT_FLOPPY}, + {MediaDvdr , REG_DEFAULT_DVDR}, + {MediaDvdrw , REG_DEFAULT_DVDRW} +}; +/* +ULONG MajorVersion = 0; +ULONG MinorVersion = 0; +ULONG BuildNumber = 0; +*/ +ULONG FsRegistered = FALSE; + +WORK_QUEUE_ITEM RemountWorkQueueItem; + +//ptrFsRtlNotifyVolumeEvent FsRtlNotifyVolumeEvent = NULL; + +HANDLE FsNotification_ThreadId = (HANDLE)(-1); + +NTSTATUS +UDFCreateFsDeviceObject( + PCWSTR FsDeviceName, + PDRIVER_OBJECT DriverObject, + DEVICE_TYPE DeviceType, + PDEVICE_OBJECT *DeviceObject); + +NTSTATUS +UDFDismountDevice( + PUNICODE_STRING unicodeCdRomDeviceName); + +VOID +UDFRemountAll( + IN PVOID Context); + +/************************************************************************* +* +* Function: DriverEntry() +* +* Description: +* This routine is the standard entry point for all kernel mode drivers. +* The routine is invoked at IRQL PASSIVE_LEVEL in the context of a +* system worker thread. +* All FSD specific data structures etc. are initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded). +* +*************************************************************************/ +NTSTATUS +NTAPI +DriverEntry( + PDRIVER_OBJECT DriverObject, // created by the I/O sub-system + PUNICODE_STRING RegistryPath // path to the registry key + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + UNICODE_STRING DriverDeviceName; + UNICODE_STRING unicodeDeviceName; +// BOOLEAN RegisteredShutdown = FALSE; + BOOLEAN InternalMMInitialized = FALSE; +// BOOLEAN DLDetectInitialized = FALSE; +// ULONG CdRomNumber; +// CCHAR deviceNameBuffer[MAXIMUM_FILENAME_LENGTH]; +// ANSI_STRING deviceName; +// UNICODE_STRING unicodeCdRomDeviceName; + PUDFFS_DEV_EXTENSION FSDevExt; + HKEY hUdfRootKey; +#ifdef EVALUATION_TIME_LIMIT + WCHAR RegPath[128]; + WCHAR RegKeyName[64]; + CHAR LicenseKey[16+1]; + ULONG iVer; + + ULONG i, j; + int checksum[4] = {0,0,0,0}; +#else + LARGE_INTEGER delay; +#endif //EVALUATION_TIME_LIMIT + +// KdPrint(("UDF: Entered " VER_STR_PRODUCT_NAME " UDF DriverEntry \n")); +// KdPrint((KD_PREFIX "Build " VER_STR_PRODUCT "\n")); + +#ifdef EVALUATION_TIME_LIMIT + BrutePoint(); +#endif //EVALUATION_TIME_LIMIT + + _SEH2_TRY { + _SEH2_TRY { + +#ifdef EVALUATION_TIME_LIMIT + LARGE_INTEGER cTime; +#endif //EVALUATION_TIME_LIMIT + +/* + CrNtInit(DriverObject, RegistryPath); + + //PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL); + KdPrint(("UDF: OS Version Major: %x, Minor: %x, Build number: %d\n", + MajorVersion, MinorVersion, BuildNumber)); +*/ +#ifdef __REACTOS__ + KdPrint(("UDF Init: OS should be ReactOS\n")); +#endif + + // initialize the global data structure + RtlZeroMemory(&UDFGlobalData, sizeof(UDFGlobalData)); + + // initialize some required fields + UDFGlobalData.NodeIdentifier.NodeType = UDF_NODE_TYPE_GLOBAL_DATA; + UDFGlobalData.NodeIdentifier.NodeSize = sizeof(UDFGlobalData); + +#ifdef EVALUATION_TIME_LIMIT + + KeQuerySystemTime((PLARGE_INTEGER)&cTime); + + { + uint64 t, t2; + t = cTime.QuadPart / 100; + t /= 60; + t /= 200*120*24; + t /= 250; + t2 = (int32)t; + KdPrint((KD_PREFIX "t2 = %x\n", t2)); + if(t2-TIME_JAN_1_2003 > UDF_MAX_DATE || + t2-TIME_JAN_1_2003 < UDF_MIN_DATE) { + KdPrint((KD_PREFIX "Ssytem time is out of range: %x <= %x <= %x\n", + UDF_MIN_DATE, (uint32)t2-TIME_JAN_1_2003, UDF_MAX_DATE)); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + } + + if(UDFGetTrialEnd(&iVer)) { + TrialEndOnStart = TRUE; + KdPrint((KD_PREFIX "Eval time expired some time ago\n")); + UDFGlobalData.UDFFlags = (UDFGlobalData.UDFFlags & ~UDF_DATA_FLAGS_UNREGISTERED) + UDF_DATA_FLAGS_UNREGISTERED; + } + cTime.QuadPart /= (10*1000*1000); + cTime.QuadPart /= (60*60*24); + + KdPrint((KD_PREFIX "cTime = %x, jTime = %x\n", cTime.LowPart, TIME_JAN_1_2003)); + if(cTime.QuadPart < TIME_JAN_1_2003) { + KdPrint((KD_PREFIX "System time %x < TIME_JAN_1_2003\n", cTime.LowPart)); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + cTime.LowPart -= TIME_JAN_1_2003; + KdPrint(("cTime = %x\n", cTime.LowPart)); + + if(!UDFGetInstallVersion((PULONG)&iVer) || + !UDFGetInstallTime((PULONG)&cTime.HighPart)) { + KdPrint((KD_PREFIX "UDFGetInstallTime() or UDFGetInstallVersion() failed\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } else { + KdPrint((KD_PREFIX "cTime = %x, iTime = %x\n", cTime.LowPart, cTime.HighPart)); + if(iVer > UDF_CURRENT_BUILD) { + KdPrint(("Init: Detected newer build (0)\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + if((ULONG)cTime.LowPart < (ULONG)cTime.HighPart) { + KdPrint(("Eval time expired: current (%x) < install (%x)\n", + cTime.LowPart, cTime.HighPart)); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + if((ULONG)cTime.LowPart > (ULONG)cTime.HighPart + EVALUATION_TERM) { + KdPrint(("Eval time expired above EVALUATION_TERM\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + if((cTime.HighPart >> 16) & 0x8000) { + KdPrint(("Eval time expired (negative install time)\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + } + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + WCHAR s[16]; + ULONG type, sz; + ULONG d; + PVOID pdata; + + KdPrint(("Init: unregistered (3). Write BIAKAs to Registry\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + + // End of trial + d = 1 ^ XOR_VAR(TrialEnd, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_TRIAL_REG_KEY_NAME(RegPath, 0); + GET_TRIAL_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(TRIAL, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + d = 1 ^ XOR_VAR(TrialEnd, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_TRIAL_REG_KEY_NAME(RegPath, 1); + GET_TRIAL_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(TRIAL, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + // Install Date + if(!TrialEndOnStart) { + d = UDFGlobalData.iTime ^ XOR_VAR(Date, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_DATE_REG_KEY_NAME(RegPath, 0); + GET_DATE_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(DATE, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(DATE, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(DATE, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + if(!(PresentDateMask & (1 << 0))) { + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } + d = UDFGlobalData.iTime ^ XOR_VAR(Date, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_DATE_REG_KEY_NAME(RegPath, 1); + GET_DATE_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(DATE, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(DATE, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(DATE, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + if(!(PresentDateMask & (1 << 1))) { + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } + } + // Highest version + d = UDFGlobalData.iVer ^ XOR_VAR(Version, 0); + swprintf(s, L"0x%8.8x\0", d); + GET_VERSION_REG_KEY_NAME(RegPath, 0); + GET_VERSION_REG_VAL_NAME(RegKeyName, 0); + type = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(VERSION, 0) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + d = UDFGlobalData.iVer ^ XOR_VAR(Version, 1); + swprintf(s, L"0x%8.8x\0", d); + GET_VERSION_REG_KEY_NAME(RegPath, 1); + GET_VERSION_REG_VAL_NAME(RegKeyName, 1); + type = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? REG_SZ : REG_DWORD; + pdata = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? (PVOID)s : (PVOID)&d; + sz = GET_XXX_REG_VAL_TYPE(VERSION, 1) ? (10+1+1)*sizeof(WCHAR) : sizeof(d); + KdPrint(("%ws\n %ws\n", RegPath, RegKeyName)); + RC = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegPath, RegKeyName, + type, pdata, sz ); + KdPrint(("status %#x\n", RC)); + } +#endif //EVALUATION_TIME_LIMIT + + // initialize the global data resource and remember the fact that + // the resource has been initialized + RC = UDFInitializeResourceLite(&(UDFGlobalData.GlobalDataResource)); + ASSERT(NT_SUCCESS(RC)); + UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED); + + RC = UDFInitializeResourceLite(&(UDFGlobalData.DelayedCloseResource)); + ASSERT(NT_SUCCESS(RC)); +// UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED); + + // keep a ptr to the driver object sent to us by the I/O Mgr + UDFGlobalData.DriverObject = DriverObject; + + //SeEnableAccessToExports(); + + // initialize the mounted logical volume list head + InitializeListHead(&(UDFGlobalData.VCBQueue)); + + KdPrint(("UDF: Init memory manager\n")); + // Initialize internal memory management + if(!MyAllocInit()) { + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + InternalMMInitialized = TRUE; + +#ifdef USE_DLD + // Initialize Deadlock Detector + DLDInit(1280); + DLDetectInitialized = TRUE; +#endif + // before we proceed with any more initialization, read in + // user supplied configurable values ... + + // Save RegistryPath + RtlCopyMemory(&(UDFGlobalData.SavedRegPath), RegistryPath, sizeof(UNICODE_STRING)); + + UDFGlobalData.SavedRegPath.Buffer = (PWSTR)MyAllocatePool__(NonPagedPool, RegistryPath->Length + 2); + if(!UDFGlobalData.SavedRegPath.Buffer) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + RtlCopyMemory(UDFGlobalData.SavedRegPath.Buffer, RegistryPath->Buffer, RegistryPath->Length + 2); + + RegTGetKeyHandle(NULL, UDFGlobalData.SavedRegPath.Buffer, &hUdfRootKey); + + UDFGlobalData.UnicodeStrRoot.Buffer = L"\\"; //(PWCHAR)&(UDFGlobalData.UnicodeStrRootBuffer); + UDFGlobalData.UnicodeStrRoot.Length = sizeof(WCHAR); + UDFGlobalData.UnicodeStrRoot.MaximumLength = 2*sizeof(WCHAR); + + UDFGlobalData.UnicodeStrSDir.Buffer = L":"; + UDFGlobalData.UnicodeStrSDir.Length = sizeof(WCHAR); + UDFGlobalData.UnicodeStrSDir.MaximumLength = 2*sizeof(WCHAR); + + UDFGlobalData.AclName.Buffer = UDF_SN_NT_ACL; + UDFGlobalData.AclName.Length = + (UDFGlobalData.AclName.MaximumLength = sizeof(UDF_SN_NT_ACL)) - sizeof(WCHAR); + + KdPrint(("UDF: Init delayed close queues\n")); +#ifdef UDF_DELAYED_CLOSE + InitializeListHead( &UDFGlobalData.DelayedCloseQueue ); + InitializeListHead( &UDFGlobalData.DirDelayedCloseQueue ); + + ExInitializeWorkItem( &UDFGlobalData.CloseItem, + (PWORKER_THREAD_ROUTINE) UDFDelayedClose, + NULL ); + + UDFGlobalData.DelayedCloseCount = 0; + UDFGlobalData.DirDelayedCloseCount = 0; +#endif //UDF_DELAYED_CLOSE + + // we should have the registry data (if any), allocate zone memory ... + // This is an example of when FSD implementations __try to pre-allocate + // some fixed amount of memory to avoid internal fragmentation and/or waiting + // later during run-time ... + + UDFGlobalData.DefaultZoneSizeInNumStructs=10; + + KdPrint(("UDF: Init zones\n")); + if (!NT_SUCCESS(RC = UDFInitializeZones())) + try_return(RC); + + KdPrint(("UDF: Init pointers\n")); + // initialize the IRP major function table, and the fast I/O table + UDFInitializeFunctionPointers(DriverObject); + + UDFGlobalData.CPU_Count = KeNumberProcessors; +#ifdef EVALUATION_TIME_LIMIT + UDFGlobalData.Saved_j = 4; +#endif //EVALUATION_TIME_LIMIT + + // create a device object representing the driver itself + // so that requests can be targeted to the driver ... + // e.g. for a disk-based FSD, "mount" requests will be sent to + // this device object by the I/O Manager.\ + // For a redirector/server, you may have applications + // send "special" IOCTL's using this device object ... + + RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME); + + KdPrint(("UDF: Create Driver dev obj\n")); + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + sizeof(UDFFS_DEV_EXTENSION), // don't need an extension for this object + &DriverDeviceName, // name - can be used to "open" the driver + // see the book for alternate choices + FILE_DEVICE_CD_ROM_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + &(UDFGlobalData.UDFDeviceObject)))) { + // failed to create a device object, leave ... + try_return(RC); + } + + FSDevExt = (PUDFFS_DEV_EXTENSION)((UDFGlobalData.UDFDeviceObject)->DeviceExtension); + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(FSDevExt, sizeof(UDFFS_DEV_EXTENSION)); + + // Initialize the signature fields + FSDevExt->NodeIdentifier.NodeType = UDF_NODE_TYPE_UDFFS_DRVOBJ; + FSDevExt->NodeIdentifier.NodeSize = sizeof(UDFFS_DEV_EXTENSION); + + RtlInitUnicodeString(&unicodeDeviceName, UDF_DOS_FS_NAME); + IoCreateSymbolicLink(&unicodeDeviceName, &DriverDeviceName); + + KdPrint(("UDF: Create CD dev obj\n")); + if (!NT_SUCCESS(RC = UDFCreateFsDeviceObject(UDF_FS_NAME_CD, + DriverObject, + FILE_DEVICE_CD_ROM_FILE_SYSTEM, + &(UDFGlobalData.UDFDeviceObject_CD)))) { + // failed to create a device object, leave ... + try_return(RC); + } +#ifdef UDF_HDD_SUPPORT + KdPrint(("UDF: Create HDD dev obj\n")); + if (!NT_SUCCESS(RC = UDFCreateFsDeviceObject(UDF_FS_NAME_HDD, + DriverObject, + FILE_DEVICE_DISK_FILE_SYSTEM, + &(UDFGlobalData.UDFDeviceObject_HDD)))) { + // failed to create a device object, leave ... + try_return(RC); + } +#endif //UDF_HDD_SUPPORT + +/* RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME_OTHER); + + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + 0, // don't need an extension for this object + &DriverDeviceName, // name - can be used to "open" the driver + // see the book for alternate choices + FILE_DEVICE_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + &(UDFGlobalData.UDFDeviceObject_OTHER)))) { + // failed to create a device object, leave ... + try_return(RC); + } + // register the driver with the I/O Manager, pretend as if this is + // a physical disk based FSD (or in order words, this FSD manages + // logical volumes residing on physical disk drives) + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_OTHER); + + RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME_TAPE); + + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + 0, // don't need an extension for this object + &DriverDeviceName, // name - can be used to "open" the driver + // see the book for alternate choices + FILE_DEVICE_TAPE_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + &(UDFGlobalData.UDFDeviceObject_TAPE)))) { + // failed to create a device object, leave ... + try_return(RC); + } + // register the driver with the I/O Manager, pretend as if this is + // a physical disk based FSD (or in order words, this FSD manages + // logical volumes residing on physical disk drives) + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_TAPE); +*/ + + if (UDFGlobalData.UDFDeviceObject_CD) { + KdPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for CD\n")); + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_CD); + } +#ifdef UDF_HDD_SUPPORT + if (UDFGlobalData.UDFDeviceObject_HDD) { + KdPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for HDD\n")); + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD); + } +#endif // UDF_HDD_SUPPORT + FsRegistered = TRUE; + + KdPrint(("UDF: IoRegisterFsRegistrationChange()\n")); + IoRegisterFsRegistrationChange( DriverObject, (PDRIVER_FS_NOTIFICATION)UDFFsNotification ); + +// delay.QuadPart = -10000000; +// KeDelayExecutionThread(KernelMode, FALSE, &delay); //10 microseconds + +#ifdef EVALUATION_TIME_LIMIT + // Build Registry Value name for License Key + for(i=0; i> 16)); + } + RegKeyName[i] = 0; + +// RtlZeroMemory(UDFGlobalData.LicenseKeyW, sizeof(UDFGlobalData.LicenseKeyW)); + RegTGetStringValue(hUdfRootKey, NULL, + RegKeyName, UDFGlobalData.LicenseKeyW, (16+1)*sizeof(WCHAR)); +// UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; +// } + RegTCloseKeyHandle(hUdfRootKey); + + UDFGlobalData.LicenseKeyW[16] = 0; + // convert WCHAR Key to CHAR key + for(i=0; i<16; i++) { + LicenseKey[i] = (UCHAR)(UDFGlobalData.LicenseKeyW[i]); + } + + // build hash + UDF_build_hash_by_key(pUDFLongKey, UDF_LONG_KEY_SIZE, (PCHAR)&(UDFGlobalData.CurrentKeyHash), LicenseKey); + // check if it is correct + for(i=0; iMajorFunction[IRP_MJ_CREATE] = UDFCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = UDFClose; + DriverObject->MajorFunction[IRP_MJ_READ] = UDFRead; +#ifndef UDF_READ_ONLY_BUILD + DriverObject->MajorFunction[IRP_MJ_WRITE] = UDFWrite; +#endif //UDF_READ_ONLY_BUILD + + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = UDFFileInfo; +#ifndef UDF_READ_ONLY_BUILD + DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = UDFFileInfo; +#endif //UDF_READ_ONLY_BUILD + +#ifndef UDF_READ_ONLY_BUILD + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = UDFFlush; +#endif //UDF_READ_ONLY_BUILD + // To implement support for querying and modifying volume attributes + // (volume information query/set operations), enable initialization + // of the following two function pointers and then implement the supporting + // functions. + DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = UDFQueryVolInfo; +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO + DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = UDFSetVolInfo; +#endif //DEMO +#endif //UDF_READ_ONLY_BUILD + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = UDFDirControl; + // To implement support for file system IOCTL calls, enable initialization + // of the following function pointer and implement appropriate support. + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = UDFFSControl; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = UDFDeviceControl; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = UDFShutdown; + // For byte-range lock support, enable initialization of the following + // function pointer and implement appropriate support. + DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = UDFLockControl; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UDFCleanup; +#ifdef UDF_HANDLE_EAS + DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = UDFQuerySetEA; +#ifndef UDF_READ_ONLY_BUILD + DriverObject->MajorFunction[IRP_MJ_SET_EA] = UDFQuerySetEA; +#endif //UDF_READ_ONLY_BUILD +#endif //UDF_HANDLE_EAS + // If the FSD supports security attributes, we should provide appropriate + // dispatch entry points and initialize the function pointers as given below. + +#ifdef UDF_ENABLE_SECURITY + DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = UDFGetSecurity; +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO + DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = UDFSetSecurity; +#endif //DEMO +#endif //UDF_READ_ONLY_BUILD +#endif //UDF_ENABLE_SECURITY + +// if(MajorVersion >= 0x05) { + // w2k and higher +// DriverObject->MajorFunction[IRP_MJ_PNP] = UDFPnp; +// } + + // Now, it is time to initialize the fast-io stuff ... + PtrFastIoDispatch = DriverObject->FastIoDispatch = &(UDFGlobalData.UDFFastIoDispatch); + + // initialize the global fast-io structure + // NOTE: The fast-io structure has undergone a substantial revision + // in Windows NT Version 4.0. The structure has been extensively expanded. + // Therefore, if the driver needs to work on both V3.51 and V4.0+, + // we will have to be able to distinguish between the two versions at compile time. + + RtlZeroMemory(PtrFastIoDispatch, sizeof(FAST_IO_DISPATCH)); + + PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); + PtrFastIoDispatch->FastIoCheckIfPossible = UDFFastIoCheckIfPossible; + PtrFastIoDispatch->FastIoRead = FsRtlCopyRead; +#ifndef UDF_READ_ONLY_BUILD + PtrFastIoDispatch->FastIoWrite = UDFFastIoCopyWrite /*FsRtlCopyWrite*/; +#endif //UDF_READ_ONLY_BUILD + PtrFastIoDispatch->FastIoQueryBasicInfo = UDFFastIoQueryBasicInfo; + PtrFastIoDispatch->FastIoQueryStandardInfo = UDFFastIoQueryStdInfo; + PtrFastIoDispatch->FastIoLock = UDFFastLock; // Lock + PtrFastIoDispatch->FastIoUnlockSingle = UDFFastUnlockSingle; // UnlockSingle + PtrFastIoDispatch->FastIoUnlockAll = UDFFastUnlockAll; // UnlockAll + PtrFastIoDispatch->FastIoUnlockAllByKey = (unsigned char (__stdcall *)(struct _FILE_OBJECT *, + PVOID ,unsigned long,struct _IO_STATUS_BLOCK *,struct _DEVICE_OBJECT *))UDFFastUnlockAllByKey; // UnlockAllByKey + + PtrFastIoDispatch->AcquireFileForNtCreateSection = UDFFastIoAcqCreateSec; + PtrFastIoDispatch->ReleaseFileForNtCreateSection = UDFFastIoRelCreateSec; + +// PtrFastIoDispatch->FastIoDeviceControl = UDFFastIoDeviceControl; + + // the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + + PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = UDFFastIoQueryNetInfo; + + PtrFastIoDispatch->AcquireForModWrite = UDFFastIoAcqModWrite; + PtrFastIoDispatch->ReleaseForModWrite = UDFFastIoRelModWrite; + PtrFastIoDispatch->AcquireForCcFlush = UDFFastIoAcqCcFlush; + PtrFastIoDispatch->ReleaseForCcFlush = UDFFastIoRelCcFlush; + +/* // MDL functionality + + PtrFastIoDispatch->MdlRead = UDFFastIoMdlRead; + PtrFastIoDispatch->MdlReadComplete = UDFFastIoMdlReadComplete; + PtrFastIoDispatch->PrepareMdlWrite = UDFFastIoPrepareMdlWrite; + PtrFastIoDispatch->MdlWriteComplete = UDFFastIoMdlWriteComplete;*/ + + // this FSD does not support compressed read/write functionality, + // NTFS does, and if we design a FSD that can provide such functionality, + // we should consider initializing the fast io entry points for reading + // and/or writing compressed data ... +#endif // (_WIN32_WINNT >= 0x0400) + + // last but not least, initialize the Cache Manager callback functions + // which are used in CcInitializeCacheMap() + + UDFGlobalData.CacheMgrCallBacks.AcquireForLazyWrite = UDFAcqLazyWrite; + UDFGlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = UDFRelLazyWrite; + UDFGlobalData.CacheMgrCallBacks.AcquireForReadAhead = UDFAcqReadAhead; + UDFGlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = UDFRelReadAhead; + + DriverObject->DriverUnload = UDFDriverUnload; + + return; +} // end UDFInitializeFunctionPointers() + +NTSTATUS +UDFCreateFsDeviceObject( + PCWSTR FsDeviceName, + PDRIVER_OBJECT DriverObject, + DEVICE_TYPE DeviceType, + PDEVICE_OBJECT *DeviceObject + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + UNICODE_STRING DriverDeviceName; + PUDFFS_DEV_EXTENSION FSDevExt; + RtlInitUnicodeString(&DriverDeviceName, FsDeviceName); + *DeviceObject = NULL; + + KdPrint(("UDFCreateFsDeviceObject: create dev\n")); + + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + sizeof(UDFFS_DEV_EXTENSION), // don't need an extension for this object + &DriverDeviceName, // name - can be used to "open" the driver + // see the book for alternate choices + DeviceType, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + DeviceObject))) { + // failed to create a device object, leave ... + return(RC); + } + FSDevExt = (PUDFFS_DEV_EXTENSION)((*DeviceObject)->DeviceExtension); + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(FSDevExt, sizeof(UDFFS_DEV_EXTENSION)); + + // Initialize the signature fields + FSDevExt->NodeIdentifier.NodeType = UDF_NODE_TYPE_UDFFS_DEVOBJ; + FSDevExt->NodeIdentifier.NodeSize = sizeof(UDFFS_DEV_EXTENSION); + // register the driver with the I/O Manager, pretend as if this is + // a physical disk based FSD (or in order words, this FSD manages + // logical volumes residing on physical disk drives) +/* KdPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem()\n")); + IoRegisterFileSystem(*DeviceObject);*/ + return(RC); +} // end UDFCreateFsDeviceObject() + + +NTSTATUS +UDFDismountDevice( + PUNICODE_STRING unicodeCdRomDeviceName + ) +{ + NTSTATUS RC; + IO_STATUS_BLOCK IoStatus; + HANDLE NtFileHandle = (HANDLE)-1; + OBJECT_ATTRIBUTES ObjectAttributes; + NOTIFY_MEDIA_CHANGE_USER_IN buffer = { 0 }; + PFILE_FS_ATTRIBUTE_INFORMATION Buffer; + + _SEH2_TRY { + + Buffer = (PFILE_FS_ATTRIBUTE_INFORMATION)MyAllocatePool__(NonPagedPool,sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+2*sizeof(UDF_FS_TITLE_DVDRAM)); + if (!Buffer) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + + InitializeObjectAttributes ( &ObjectAttributes, + unicodeCdRomDeviceName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + KdPrint(("\n*** UDFDismountDevice: Create\n")); + RC = ZwCreateFile( &NtFileHandle, + GENERIC_READ, + &ObjectAttributes, + &IoStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 ); + + + if (!NT_SUCCESS(RC)) try_return(RC); + + KdPrint(("\n*** UDFDismountDevice: QueryVolInfo\n")); + RC = ZwQueryVolumeInformationFile( NtFileHandle, + &IoStatus, + Buffer, + sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+2*sizeof(UDF_FS_TITLE_DVDRAM), + FileFsAttributeInformation); + +#define UDF_CHECK_FS_NAME(name) \ + (Buffer->FileSystemNameLength+sizeof(WCHAR) == sizeof(name) && \ + DbgCompareMemory(&Buffer->FileSystemName[0],name , sizeof(name)) == sizeof(name)) + + if (NT_SUCCESS(RC) && + (UDF_CHECK_FS_NAME(UDF_FS_TITLE_CDR) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_CDRW) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_DVDR) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_DVDRW) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_DVDpR) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_DVDpRW) || + UDF_CHECK_FS_NAME(UDF_FS_TITLE_DVDRAM) )) try_return(STATUS_SUCCESS); + + KdPrint(("\n*** UDFDismountDevice: LockVolume\n")); + RC = ZwFsControlFile(NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FSCTL_LOCK_VOLUME, + NULL, + NULL, + NULL, + NULL); + + if (!NT_SUCCESS(RC)) try_return(RC); + + KdPrint(("\n*** UDFDismountDevice: DismountVolume\n")); + RC = ZwFsControlFile(NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FSCTL_DISMOUNT_VOLUME, + NULL, + NULL, + NULL, + NULL); + + if (!NT_SUCCESS(RC)) try_return(RC); + + KdPrint(("\n*** UDFDismountDevice: NotifyMediaChange\n")); + RC = ZwDeviceIoControlFile(NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + IOCTL_CDRW_NOTIFY_MEDIA_CHANGE, + &buffer, + sizeof(buffer), + &buffer, + sizeof(buffer)); + + if (!NT_SUCCESS(RC)) try_return(RC); + + + KdPrint(("\n*** UDFDismountDevice: UnlockVolume\n")); + RC = ZwFsControlFile(NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FSCTL_UNLOCK_VOLUME, + NULL, + NULL, + NULL, + NULL); + + KdPrint(("\n*** UDFDismountDevice: Close\n")); + ZwClose( NtFileHandle ); + + NtFileHandle = (HANDLE)-1; + + KdPrint(("\n*** UDFDismountDevice: Create 2\n")); + RC = ZwCreateFile( &NtFileHandle, + GENERIC_READ, + &ObjectAttributes, + &IoStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 ); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if (Buffer) MyFreePool__(Buffer); + if (NtFileHandle != (HANDLE)-1) ZwClose( NtFileHandle ); + } _SEH2_END; + + KdPrint(("\n*** UDFDismountDevice: RC=%x\n",RC)); + return RC; +} + + +VOID +NTAPI +UDFFsNotification( + IN PDEVICE_OBJECT DeviceObject, + IN BOOLEAN FsActive + ) + +/* + +Routine Description: + + This routine is invoked whenever a file system has either registered or + unregistered itself as an active file system. + + For the former case, this routine creates a device object and attaches it + to the specified file system's device object. This allows this driver + to filter all requests to that file system. + + For the latter case, this file system's device object is located, + detached, and deleted. This removes this file system as a filter for + the specified file system. + +Arguments: + + DeviceObject - Pointer to the file system's device object. + + FsActive - bolean indicating whether the file system has registered + (TRUE) or unregistered (FALSE) itself as an active file system. + +Return Value: + + None. + +*/ + +{ + // Begin by determine whether or not the file system is a cdrom-based file + // system. If not, then this driver is not concerned with it. + if (!FsRegistered || + DeviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) { + return; + } + + // Begin by determining whether this file system is registering or + // unregistering as an active file system. + if (FsActive + && UDFGlobalData.UDFDeviceObject_CD != DeviceObject +#ifdef UDF_HDD_SUPPORT + && UDFGlobalData.UDFDeviceObject_HDD != DeviceObject +#endif // UDF_HDD_SUPPORT + ) { + KdPrint(("\n*** UDFFSNotification \n\n")); + + // Acquire GlobalDataResource + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + + if(FsNotification_ThreadId != PsGetCurrentThreadId()) { + + FsNotification_ThreadId = PsGetCurrentThreadId(); + + IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject_CD); + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_CD); + +#ifdef UDF_HDD_SUPPORT + IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD); + IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD); +#endif // UDF_HDD_SUPPORT + + FsNotification_ThreadId = (HANDLE)(-1); + + } else { + KdPrint(("\n*** recursive UDFFSNotification call,\n can't become top-level UDF FSD \n\n")); + } + + // Release the global resource. + UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); + + + } +} +/*VOID +UDFRemountAll( + IN PVOID Context + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + ULONG CdRomNumber; + CCHAR deviceNameBuffer[MAXIMUM_FILENAME_LENGTH]; + ANSI_STRING deviceName; + UNICODE_STRING unicodeCdRomDeviceName; + LARGE_INTEGER delay; + +/* delay.QuadPart = -80*10000000; + KeDelayExecutionThread(KernelMode, FALSE, &delay); //10 seconds*/ + +/* for(CdRomNumber = 0;true;CdRomNumber++) { + sprintf(deviceNameBuffer, "\\Device\\CdRom%d", CdRomNumber); + KdPrint(( "UDF: UDFRemountAll : dismount %s\n", deviceNameBuffer)); + RtlInitString(&deviceName, deviceNameBuffer); + RC = RtlAnsiStringToUnicodeString(&unicodeCdRomDeviceName, &deviceName, TRUE); + + if (!NT_SUCCESS(RC)) { + RtlFreeUnicodeString(&unicodeCdRomDeviceName); + break; + } + + RC = UDFDismountDevice(&unicodeCdRomDeviceName); + RtlFreeUnicodeString(&unicodeCdRomDeviceName); + + if (!NT_SUCCESS(RC)) break; + } +}*/ + + +#ifdef EVALUATION_TIME_LIMIT + +BOOLEAN +UDFGetInstallVersion( + PULONG iVer + ) +{ + WCHAR RegPath[128]; + WCHAR RegVal[64]; + WCHAR Str[32]; + ULONG i, j; + ULONG a, v; + ULONG type; + ULONG sz; + + KdPrint((KD_PREFIX "UDFGetInstallVersion:\n")); + + (*iVer) = UDF_CURRENT_BUILD; + for(j=0; j= 'a' && Str[i] <= 'f') { + a = 10 + Str[i] - 'a'; + } else { + a = Str[i] - '0'; + } + KdPrint((KD_PREFIX "val: %x\n", a)); + v *= 16; + v += a; + } +de_xor: + switch(j) { + case 0: v ^= XOR_VAR(Version, 0); break; + case 1: v ^= XOR_VAR(Version, 1); break; + } + if(v & 0x80000000) + continue; + if((*iVer) == -1 || (*iVer) < v) { + (*iVer) = v; + } + UDFGlobalData.iVer = (*iVer); + } + } + UDFGlobalData.iVer = (*iVer); +/* if(UDFGlobalData.iVer == -1) + return FALSE;*/ + KdPrint((KD_PREFIX "ret val: %x\n", *iVer)); + if((*iVer) > UDF_CURRENT_BUILD) { + return FALSE; + } + return TRUE; +} // end UDFGetInstallVersion() + +BOOLEAN +UDFGetInstallTime( + PULONG iTime + ) +{ + WCHAR RegPath[128]; + WCHAR RegVal[64]; + WCHAR Str[32]; + ULONG i, j; + ULONG a, v; + ULONG type; + ULONG sz; + + KdPrint((KD_PREFIX "UDFGetInstallTime:\n")); + + (*iTime) = -1; + for(j=0; j= 'a' && Str[i] <= 'f') { + a = 10 + Str[i] - 'a'; + } else { + a = Str[i] - '0'; + } + KdPrint((KD_PREFIX "val: %x\n", a)); + v *= 16; + v += a; + } +de_xor: + switch(j) { + case 0: v ^= XOR_VAR(Date, 0); break; + case 1: v ^= XOR_VAR(Date, 1); break; + } + PresentDateMask |= 0x00000001 << j; + if(v & 0x80000000) + continue; + if((*iTime) == -1 || (*iTime) < v) { + (*iTime) = v; + } + UDFGlobalData.iTime = (*iTime); + } + } + UDFGlobalData.iTime = (*iTime); + if(UDFGlobalData.iTime == -1) { + + LARGE_INTEGER cTime; + KeQuerySystemTime((PLARGE_INTEGER)&cTime); + + cTime.QuadPart /= (10*1000*1000); + cTime.QuadPart /= (60*60*24); + + KdPrint((KD_PREFIX "cTime = %x, jTime = %x\n", cTime.LowPart, TIME_JAN_1_2003)); + if(cTime.QuadPart < TIME_JAN_1_2003) { + KdPrint((KD_PREFIX "Eval time expired (1)\n")); + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_UNREGISTERED; + } + cTime.LowPart -= TIME_JAN_1_2003; + KdPrint(("cTime = %x\n", cTime.LowPart)); + + UDFGlobalData.iTime = (*iTime) = cTime.LowPart; + return FALSE; + } + UDFGlobalData.iTime = (*iTime); + KdPrint((KD_PREFIX "ret val: %x\n", *iTime)); + return TRUE; +} // end UDFGetInstallTime() + +BOOLEAN +UDFGetTrialEnd( + PULONG iTrial + ) +{ + WCHAR RegPath[128]; + WCHAR RegVal[64]; + WCHAR Str[32]; + ULONG i, j; + ULONG a, v; + ULONG type; + ULONG sz; + + KdPrint((KD_PREFIX "UDFGetTrialEnd:\n")); + + (*iTrial) = 0; + for(j=0; j= 'a' && Str[i] <= 'f') { + a = 10 + Str[i] - 'a'; + } else { + a = Str[i] - '0'; + } + KdPrint((KD_PREFIX "val: %x\n", a)); + v *= 16; + v += a; + } +de_xor: + switch(j) { + case 0: v ^= XOR_VAR(TrialEnd, 0); break; + case 1: v ^= XOR_VAR(TrialEnd, 1); break; + } + if((*iTrial) < v) { + (*iTrial) = v; + } + if(UDFGlobalData.iTrial = (*iTrial)) { + return TRUE; + } + } + } + return FALSE; +} // end UDFGetTrialEnd() + +#endif //EVALUATION_TRIAL_LIMIT + + + diff --git a/reactos/drivers/filesystems/udfs/udfpubl.h b/reactos/drivers/filesystems/udfs/udfpubl.h new file mode 100644 index 00000000000..615b5425cf0 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/udfpubl.h @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + +Module Name: + + udfpubl.h + +Abstract: + + This file defines the interface between UDFFS driver & user + applications | drivers. + +Environment: + + NT kernel mode or Win32 app + */ + +#ifndef __UDF_PUBL_H__ +#define __UDF_PUBL_H__ + +#pragma pack(push, 8) + +#ifndef CTL_CODE +#include "winioctl.h" +#endif + +#ifndef IOCTL_UDFFS_BASE +#define IOCTL_UDFFS_BASE 0x00000911 +#endif + +#ifndef IOCTL_UDF_DISABLE_DRIVER +#define IOCTL_UDF_DISABLE_DRIVER CTL_CODE(IOCTL_UDFFS_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_ENABLE_DRIVER CTL_CODE(IOCTL_UDFFS_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_INVALIDATE_VOLUMES CTL_CODE(IOCTL_UDFFS_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_GET_RETRIEVAL_POINTERS CTL_CODE(IOCTL_UDFFS_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_GET_FILE_ALLOCATION_MODE CTL_CODE(IOCTL_UDFFS_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_SET_FILE_ALLOCATION_MODE CTL_CODE(IOCTL_UDFFS_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_LOCK_VOLUME_BY_PID CTL_CODE(IOCTL_UDFFS_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_UNLOCK_VOLUME_BY_PID CTL_CODE(IOCTL_UDFFS_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_SEND_LICENSE_KEY CTL_CODE(IOCTL_UDFFS_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS CTL_CODE(IOCTL_UDFFS_BASE, 0x000a, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_UDF_GET_VERSION CTL_CODE(IOCTL_UDFFS_BASE, 0x000b, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_UDF_SET_NOTIFICATION_EVENT CTL_CODE(IOCTL_UDFFS_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_UDF_IS_VOLUME_JUST_MOUNTED CTL_CODE(IOCTL_UDFFS_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_UDF_REGISTER_AUTOFORMAT CTL_CODE(IOCTL_UDFFS_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_UDF_SET_OPTIONS CTL_CODE(IOCTL_UDFFS_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct _UDF_GET_FILE_ALLOCATION_MODE_OUT { + + CHAR AllocMode; // see definition of ICB_FLAG_AD_XXX in Ecma_167.h + +} UDF_GET_FILE_ALLOCATION_MODE_OUT, *PUDF_GET_FILE_ALLOCATION_MODE_OUT; + +// setting default AllocMode +//#define ICB_FLAG_AD_DEFAULT_ALLOC_MODE (UCHAR)(0xff) + +typedef UDF_GET_FILE_ALLOCATION_MODE_OUT UDF_SET_FILE_ALLOCATION_MODE_IN; +typedef PUDF_GET_FILE_ALLOCATION_MODE_OUT PUDF_SET_FILE_ALLOCATION_MODE_IN; + +/*typedef struct _RETRIEVAL_POINTERS_BUFFER { + int a; +} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER; +*/ +typedef struct _UDF_LOCK_VOLUME_BY_PID_IN { + ULONG PID; // -1 for current process +} UDF_LOCK_VOLUME_BY_PID_IN, *PUDF_LOCK_VOLUME_BY_PID_IN; + +typedef UDF_LOCK_VOLUME_BY_PID_IN UDF_UNLOCK_VOLUME_BY_PID_IN; +typedef PUDF_LOCK_VOLUME_BY_PID_IN PUDF_UNLOCK_VOLUME_BY_PID_IN; + +#define UDF_DOS_FS_NAME L"\\DosDevices\\DwUdf" +#define UDF_WIN_FS_NAME "\\\\.\\DwUdf" + +#define UDF_ISO_STREAM_NAME "UdfIsoBridgeStructure" +#define UDF_ISO_STREAM_NAME_W L"UdfIsoBridgeStructure" + +#define UDF_CONFIG_STREAM_NAME "DvdWriteNow.cfg" +#define UDF_CONFIG_STREAM_NAME_W L"DvdWriteNow.cfg" + +#ifdef FSCTL_GET_RETRIEVAL_POINTERS + +typedef struct _UDF_GET_SPEC_RETRIEVAL_POINTERS_IN { + STARTING_VCN_INPUT_BUFFER Standard; + ULONG Special; +} UDF_GET_SPEC_RETRIEVAL_POINTERS_IN, *PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN; + +#endif //FSCTL_GET_RETRIEVAL_POINTERS + +typedef struct _UDF_GET_VERSION_OUT { + struct { + ULONG Length; + ULONG DriverVersionMj; + ULONG DriverVersionMn; + ULONG DriverVersionBuild; + } header; + ULONG FSVersionMj; + ULONG FSVersionMn; + ULONG FSFlags; + ULONG FSCompatFlags; + ULONG FSCfgVersion; +} UDF_GET_VERSION_OUT, *PUDF_GET_VERSION_OUT; + +#define UDF_USER_FS_FLAGS_RO 0x0001 +#define UDF_USER_FS_FLAGS_RAW 0x0002 +#define UDF_USER_FS_FLAGS_OUR_DRIVER 0x0004 +#define UDF_USER_FS_FLAGS_FP 0x0008 +#define UDF_USER_FS_FLAGS_MEDIA_RO 0x0010 +#define UDF_USER_FS_FLAGS_SOFT_RO 0x0020 +#define UDF_USER_FS_FLAGS_HW_RO 0x0040 +#define UDF_USER_FS_FLAGS_MEDIA_DEFECT_RO 0x0080 +#define UDF_USER_FS_FLAGS_PART_RO 0x0100 // partition is r/o +#define UDF_USER_FS_FLAGS_NEW_FS_RO 0x0200 + +#endif //IOCTL_UDF_DISABLE_DRIVER + +#define UDF_PART_DAMAGED_RW (0x00) +#define UDF_PART_DAMAGED_RO (0x01) +#define UDF_PART_DAMAGED_NO (0x02) + +typedef struct _UDF_SET_OPTIONS_IN { + struct { + ULONG HdrLength; + ULONG Flags; + } header; + UCHAR Data[1]; +} UDF_SET_OPTIONS_IN, *PUDF_SET_OPTIONS_IN; + +#define UDF_SET_OPTIONS_FLAG_TEMPORARY 0x00 +#define UDF_SET_OPTIONS_FLAG_DISK 0x01 +#define UDF_SET_OPTIONS_FLAG_DRIVE 0x02 +#define UDF_SET_OPTIONS_FLAG_GLOBAL 0x03 +#define UDF_SET_OPTIONS_FLAG_MASK 0x03 + +#pragma pack(pop) + +#endif //__UDF_PUBL_H__ diff --git a/reactos/drivers/filesystems/udfs/unload.cpp b/reactos/drivers/filesystems/udfs/unload.cpp new file mode 100644 index 00000000000..6af43fc39ef --- /dev/null +++ b/reactos/drivers/filesystems/udfs/unload.cpp @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udffs.h" + +VOID +NTAPI +UDFDriverUnload( + IN PDRIVER_OBJECT DriverObject + ) +{ +// UNICODE_STRING uniWin32NameString; + LARGE_INTEGER delay; + + // + // All *THIS* driver needs to do is to delete the device object and the + // symbolic link between our device name and the Win32 visible name. + // + // Almost every other driver ever written would need to do a + // significant amount of work here deallocating stuff. + // + + KdPrint( ("UDF: Unloading!!\n") ); + + // prevent mount oparations + UDFGlobalData.UDFFlags |= UDF_DATA_FLAGS_BEING_UNLOADED; + + // wait for all volumes to be dismounted + delay.QuadPart = 10*1000*1000*10; + while(TRUE) { + KdPrint(("Poll...\n")); + KeDelayExecutionThread(KernelMode, FALSE, &delay); + } + + // Create counted string version of our Win32 device name. + + +// RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); + + + // Delete the link from our device name to a name in the Win32 namespace. + + +// IoDeleteSymbolicLink( &uniWin32NameString ); + + + // Finally delete our device object + + +// IoDeleteDevice( DriverObject->DeviceObject ); +} diff --git a/reactos/drivers/filesystems/udfs/verfysup.cpp b/reactos/drivers/filesystems/udfs/verfysup.cpp new file mode 100644 index 00000000000..0b901f97fda --- /dev/null +++ b/reactos/drivers/filesystems/udfs/verfysup.cpp @@ -0,0 +1,980 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/* + + Module Name: VerfySup.cpp + + Abstract: + + This module implements the UDF verification routines. + + Environment: + + Kernel mode only + +*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_VERIFY_FS_CONTROL + +/* +Routine Description: + This routine checks that the current Vcb is valid and currently mounted + on the device. It will raise on an error condition. + We check whether the volume needs verification and the current state + of the Vcb. +Arguments: + + Vcb - This is the volume to verify. +*/ + +NTSTATUS +UDFVerifyVcb( + IN PtrUDFIrpContext IrpContext, + IN PVCB Vcb + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + IO_STATUS_BLOCK Iosb; + ULONG MediaChangeCount = 0; + BOOLEAN Nop = TRUE; + BOOLEAN UnsafeIoctl = (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL) ? TRUE : FALSE; + + KdPrint(("UDFVerifyVCB: Modified=%d\n", Vcb->Modified)); + // Fail immediately if the volume is in the progress of being dismounted + // or has been marked invalid. + if (Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) { + return STATUS_FILE_INVALID; + } + + // If the media is removable and the verify volume flag in the + // device object is not set then we want to ping the device + // to see if it needs to be verified + if ( (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) && + !(Vcb->Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) && + (!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) || UnsafeIoctl) ) { + KdPrint(("UDFVerifyVCB: UnsafeIoctl=%d, locked=%d\n", UnsafeIoctl, (Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) ? 0 : 1)); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_UNSAFE_IOCTL; + RC = UDFTSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY, + Vcb, + NULL,0, + &MediaChangeCount,sizeof(ULONG), + FALSE,&Iosb ); + + // Be safe about the count in case the driver didn't fill it in + if (Iosb.Information != sizeof(ULONG)) MediaChangeCount = 0; + KdPrint((" MediaChangeCount %d -> %d\n", Vcb->MediaChangeCount, MediaChangeCount)); + + // If the volume is now an empty device, or we have receieved a + // bare STATUS_VERIFY_REQUIRED (various hardware conditions such + // as bus resets, etc., will trigger this in the drivers), or the + // media change count has moved since we last inspected the device, + // then mark the volume to be verified. + + if ( (RC == STATUS_VERIFY_REQUIRED) || + (UDFIsRawDevice(RC) && (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) || + (NT_SUCCESS(RC) && (Vcb->MediaChangeCount != MediaChangeCount)) || + UnsafeIoctl) { + + KdPrint((" set DO_VERIFY_VOLUME\n")); + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + + // If the volume is not mounted and we got a media change count, + // update the Vcb so we do not trigger a verify again at this + // count value. If the verify->mount path detects that the media + // has actually changed and this Vcb is valid again, this will have + // done nothing. We are already synchronized since the caller has + // the Vcb. + if (!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && + NT_SUCCESS(RC) ) { + Vcb->MediaChangeCount = MediaChangeCount; + } + + } else if (!NT_SUCCESS(RC)) { +// Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + KdPrint((" UDFNormalizeAndRaiseStatus(%x)\n", RC)); + UDFNormalizeAndRaiseStatus(IrpContext,RC); + ASSERT(Nop); + } + } + + KdPrint(("UDFVerifyVCB: Modified=%d\n", Vcb->Modified)); + // The Vcb may be mounted but the underlying real device may need to be verified. + // If it does then we'll set the Iosb in the irp to be our real device + if (Vcb->Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) { + + KdPrint((" DO_VERIFY_VOLUME -> IoSetHardErrorOrVerifyDevice()\n")); + IoSetHardErrorOrVerifyDevice( IrpContext->Irp, + Vcb->Vpb->RealDevice ); + + RC = STATUS_VERIFY_REQUIRED; + KdPrint((" UDFRaiseStatus()\n")); + UDFRaiseStatus(IrpContext, RC); + ASSERT(Nop); + } + + KdPrint(("UDFVerifyVCB: Modified=%d\n", Vcb->Modified)); + if (!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + KdPrint((" !UDF_VCB_FLAGS_VOLUME_MOUNTED -> IoSetHardErrorOrVerifyDevice()\n")); + Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; + IoSetHardErrorOrVerifyDevice( IrpContext->Irp, Vcb->Vpb->RealDevice ); + RC = STATUS_WRONG_VOLUME; + KdPrint((" UDFRaiseStatus()\n")); + UDFRaiseStatus(IrpContext, RC); +// UDFRaiseStatus(IrpContext, STATUS_UNRECOGNIZED_VOLUME); + ASSERT(Nop); + } + if ((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED)) { + KdPrint((" UDF_VCB_FLAGS_BEING_DISMOUNTED\n")); + RC = STATUS_FILE_INVALID; + UDFRaiseStatus( IrpContext, RC ); + ASSERT(Nop); + } + KdPrint(("UDFVerifyVcb: RC = %x\n", RC)); + + return RC; +} // end UDFVerifyVcb() + +/* + +Routine Description: + This routine performs the verify volume operation. It is responsible for + either completing of enqueuing the input Irp. + +Arguments: + Irp - Supplies the Irp to process + +Return Value: + + NTSTATUS - The return status for the operation + +--*/ +NTSTATUS +UDFVerifyVolume( + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb; + PVCB Vcb = (PVCB)IrpSp->Parameters.VerifyVolume.DeviceObject->DeviceExtension; + PVCB NewVcb = NULL; + IO_STATUS_BLOCK Iosb; + ULONG MediaChangeCount = 0; + NTSTATUS RC; + ULONG Mode; + BOOLEAN UnsafeIoctl = (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL) ? TRUE : FALSE; + + // Update the real device in the IrpContext from the Vpb. There was no available + // file object when the IrpContext was created. + // IrpContext->RealDevice = Vpb->RealDevice; + KdPrint(("UDFVerifyVolume:\n")); + + // Acquire shared global access, the termination handler for the + // following try statement will free the access. + + UDFAcquireResourceShared(&(UDFGlobalData.GlobalDataResource),TRUE); + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + + _SEH2_TRY { + + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + // Check if the real device still needs to be verified. If it doesn't + // then obviously someone beat us here and already did the work + // so complete the verify irp with success. Otherwise reenable + // the real device and get to work. + if( !(Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) && + ((Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) && !UnsafeIoctl) ) { + KdPrint(("UDFVerifyVolume: STATUS_SUCCESS (1)\n")); + try_return(RC = STATUS_SUCCESS); + } + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_UNSAFE_IOCTL; + // Verify that there is a disk here. + RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY, + Vcb->TargetDeviceObject, + NULL,0, + &MediaChangeCount,sizeof(ULONG), + TRUE,&Iosb ); + + if(!NT_SUCCESS( RC )) { + // If we will allow a raw mount then return WRONG_VOLUME to + // allow the volume to be mounted by raw. + if(FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) { + KdPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (1)\n")); + RC = STATUS_WRONG_VOLUME; + } + + if(UDFIsRawDevice(RC)) { + KdPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (2)\n")); + RC = STATUS_WRONG_VOLUME; + } + try_return( RC ); + } + + if(Iosb.Information != sizeof(ULONG)) { + // Be safe about the count in case the driver didn't fill it in + MediaChangeCount = 0; + } + + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + KdPrint(("UDFVerifyVolume: MediaChangeCount=%x, Vcb->MediaChangeCount=%x, UnsafeIoctl=%x\n", + MediaChangeCount, Vcb->MediaChangeCount, UnsafeIoctl)); + // Verify that the device actually saw a change. If the driver does not + // support the MCC, then we must verify the volume in any case. + if(MediaChangeCount == 0 || + (Vcb->MediaChangeCount != MediaChangeCount) || + UnsafeIoctl ) { + + KdPrint(("UDFVerifyVolume: compare\n")); + + NewVcb = (PVCB)MyAllocatePool__(NonPagedPool,sizeof(VCB)); + if(!NewVcb) + try_return(RC=STATUS_INSUFFICIENT_RESOURCES); + RtlZeroMemory(NewVcb,sizeof(VCB)); + + NewVcb->TargetDeviceObject = Vcb->TargetDeviceObject; + NewVcb->Vpb = Vpb; + + // Set the removable media flag based on the real device's + // characteristics + if(Vpb->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) { + UDFSetFlag( NewVcb->VCBFlags, UDF_VCB_FLAGS_REMOVABLE_MEDIA ); + } + + RC = UDFGetDiskInfo(NewVcb->TargetDeviceObject,NewVcb); + if(!NT_SUCCESS(RC)) try_return(RC); + // Prevent modification attempts durring Verify + NewVcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY | + UDF_VCB_FLAGS_MEDIA_READ_ONLY; + // Compare physical parameters (phase 1) + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + RC = UDFCompareVcb(Vcb,NewVcb, TRUE); + if(!NT_SUCCESS(RC)) try_return(RC); + + if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + Vcb->MountPhErrorCount > MOUNT_ERR_THRESHOLD ) { + KdPrint(("UDFVerifyVolume: it was very BAD volume. Do not perform Logical check\n")); + goto skip_logical_check; + } + // Initialize internal cache + // in *** READ ONLY *** mode + Mode = WCACHE_MODE_ROM; + + RC = WCacheInit__(&(NewVcb->FastCache), + UDFGlobalData.WCacheMaxFrames, + UDFGlobalData.WCacheMaxBlocks, + NewVcb->WriteBlockSize, + 5, NewVcb->BlockSizeBits, + UDFGlobalData.WCacheBlocksPerFrameSh, + 0/*NewVcb->FirstLBA*/, NewVcb->LastPossibleLBA, Mode, + /*WCACHE_CACHE_WHOLE_PACKET*/ 0 | + (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) | + WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS, // speed up mount on bad disks + UDFGlobalData.WCacheFramesToKeepFree, + UDFTWrite, UDFTRead, +#ifdef UDF_ASYNC_IO + UDFTWriteAsync, UDFTReadAsync, +#else //UDF_ASYNC_IO + NULL, NULL, +#endif //UDF_ASYNC_IO + UDFIsBlockAllocated, UDFUpdateVAT, + UDFWCacheErrorHandler); + if(!NT_SUCCESS(RC)) try_return(RC); + + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + RC = UDFGetDiskInfoAndVerify(NewVcb->TargetDeviceObject,NewVcb); + KdPrint((" NewVcb->NSRDesc=%x\n", NewVcb->NSRDesc)); + if(!NT_SUCCESS(RC)) { + if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + (NewVcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && + !(NewVcb->NSRDesc & VRS_ISO9660_FOUND)) { + KdPrint(("UDFVerifyVolume: both are RAW -> remount\n", Vcb->Modified)); + RC = STATUS_SUCCESS; + goto skip_logical_check; + } + if(RC == STATUS_UNRECOGNIZED_VOLUME) { + try_return(RC = STATUS_WRONG_VOLUME); + } + try_return(RC); + } + + WCacheChFlags__(&(Vcb->FastCache), + WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet + WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS); // let user retry request on Bad Blocks + + NewVcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED; + // Compare logical parameters (phase 2) + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + RC = UDFCompareVcb(Vcb,NewVcb, FALSE); + if(!NT_SUCCESS(RC)) try_return(RC); + // We have unitialized WCache, so it is better to + // force MOUNT_VOLUME call + if(!WCacheIsInitialized__(&(Vcb->FastCache))) + try_return(RC = STATUS_WRONG_VOLUME); + +skip_logical_check:; + + } + + KdPrint(("UDFVerifyVolume: compared\n")); + KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified)); + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED)) { + KdPrint(("UDFVerifyVolume: set UDF_VCB_FLAGS_VOLUME_MOUNTED\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->SoftEjectReq = FALSE; + } + UDFClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME ); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + // Update the media change count to note that we have verified the volume + // at this value + Vcb->MediaChangeCount = MediaChangeCount; + + // If we got the wrong volume, mark the Vcb as not mounted. + if(RC == STATUS_WRONG_VOLUME) { + KdPrint(("UDFVerifyVolume: clear UDF_VCB_FLAGS_VOLUME_MOUNTED\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; +// ASSERT(!(Vcb->EjectWaiter)); + if(Vcb->EjectWaiter) { + UDFReleaseResource(&(Vcb->VCBResource)); + UDFStopEjectWaiter(Vcb); + UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE); + } + } else + if(NT_SUCCESS(RC) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)){ + BOOLEAN CacheInitialized = FALSE; + KdPrint((" !!! VerifyVolume - QUICK REMOUNT !!!\n")); + // Initialize internal cache + CacheInitialized = WCacheIsInitialized__(&(Vcb->FastCache)); + if(!CacheInitialized) { + Mode = WCACHE_MODE_ROM; + RC = WCacheInit__(&(Vcb->FastCache), + Vcb->WCacheMaxFrames, + Vcb->WCacheMaxBlocks, + Vcb->WriteBlockSize, + 5, Vcb->BlockSizeBits, + Vcb->WCacheBlocksPerFrameSh, + 0/*Vcb->FirstLBA*/, Vcb->LastPossibleLBA, Mode, + /*WCACHE_CACHE_WHOLE_PACKET*/ 0 | + (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) | + (Vcb->CacheChainedIo ? WCACHE_CHAINED_IO : 0), + Vcb->WCacheFramesToKeepFree, +// UDFTWrite, UDFTRead, + UDFTWriteVerify, UDFTReadVerify, +#ifdef UDF_ASYNC_IO + UDFTWriteAsync, UDFTReadAsync, +#else //UDF_ASYNC_IO + NULL, NULL, +#endif //UDF_ASYNC_IO + UDFIsBlockAllocated, UDFUpdateVAT, + UDFWCacheErrorHandler); + } + if(NT_SUCCESS(RC)) { + if(!Vcb->VerifyCtx.VInited) { + RC = UDFVInit(Vcb); + } + } + if(NT_SUCCESS(RC)) { + + if(!CacheInitialized) { + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) { + if(!Vcb->CDR_Mode) { + if((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) || + CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) { + KdPrint(("UDFMountVolume: RAM mode\n")); + Mode = WCACHE_MODE_RAM; + } else { + KdPrint(("UDFMountVolume: RW mode\n")); + Mode = WCACHE_MODE_RW; + } + /* if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) { + } else { + Vcb->WriteSecurity = TRUE; + }*/ + } else { + Mode = WCACHE_MODE_R; + } + } + WCacheSetMode__(&(Vcb->FastCache), Mode); + + WCacheChFlags__(&(Vcb->FastCache), + WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet + WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS); // let user retry request on Bad Blocks + } + // we can't record ACL on old format disks + if(!UDFNtAclSupported(Vcb)) { + Vcb->WriteSecurity = FALSE; + Vcb->UseExtendedFE = FALSE; + } + KdPrint(("UDFVerifyVolume: try start EjectWaiter\n")); + RC = UDFStartEjectWaiter(Vcb); + if(!NT_SUCCESS(RC)) { + KdPrint(("UDFVerifyVolume: start EjectWaiter failed\n")); + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; + Vcb->WriteSecurity = FALSE; + } + } + } + + if(NewVcb) { + // Release internal cache + KdPrint(("UDFVerifyVolume: delete NewVcb\n")); + WCacheFlushAll__(&(NewVcb->FastCache),NewVcb); + WCacheRelease__(&(NewVcb->FastCache)); + + ASSERT(!(NewVcb->EjectWaiter)); + // Waiter thread should be already stopped + // if MediaChangeCount have changed + ASSERT(!(Vcb->EjectWaiter)); + + UDFCleanupVCB(NewVcb); + MyFreePool__(NewVcb); + } + UDFReleaseResource(&(Vcb->VCBResource)); + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + } _SEH2_END; + + // Complete the request if no exception. + Irp->IoStatus.Information = 0; + + Irp->IoStatus.Status = RC; + IoCompleteRequest(Irp,IO_DISK_INCREMENT); + + KdPrint(("UDFVerifyVolume: RC = %x\n", RC)); + + return RC; +} // end UDFVerifyVolume () + +/* +Routine Description: + + This routines performs an IoVerifyVolume operation and takes the + appropriate action. If the verify is successful then we send the originating + Irp off to an Ex Worker Thread. This routine is called from the exception handler. + No file system resources are held when this routine is called. + +Arguments: + + Irp - The irp to send off after all is well and done. + Device - The real device needing verification. + +*/ +NTSTATUS +UDFPerformVerify( + IN PtrUDFIrpContext IrpContext, + IN PIRP Irp, + IN PDEVICE_OBJECT DeviceToVerify + ) +{ + + PVCB Vcb; + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp; + + KdPrint(("UDFPerformVerify:\n")); + if(!IrpContext) return STATUS_INVALID_PARAMETER; + if(!Irp) return STATUS_INVALID_PARAMETER; + + // Check if this Irp has a status of Verify required and if it does + // then call the I/O system to do a verify. + // + // Skip the IoVerifyVolume if this is a mount or verify request + // itself. Trying a recursive mount will cause a deadlock with + // the DeviceObject->DeviceLock. + if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && + ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) || + (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) { + + return UDFPostRequest(IrpContext, Irp); + } + + // Extract a pointer to the Vcb from the VolumeDeviceObject. + // Note that since we have specifically excluded mount, + // requests, we know that IrpSp->DeviceObject is indeed a + // volume device object. + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + Vcb = (PVCB)IrpSp->DeviceObject->DeviceExtension; + + KdPrint(("UDFPerformVerify: check\n")); + // Check if the volume still thinks it needs to be verified, + // if it doesn't then we can skip doing a verify because someone + // else beat us to it. + _SEH2_TRY { + + if (DeviceToVerify->Flags & DO_VERIFY_VOLUME) { + + // If the IopMount in IoVerifyVolume did something, and + // this is an absolute open, force a reparse. + RC = IoVerifyVolume( DeviceToVerify, FALSE ); + + // Bug? +/* if (UDFIsRawDevice(RC)) { + RC = STATUS_WRONG_VOLUME; + }*/ + + // If the verify operation completed it will return + // either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. + if (RC == STATUS_SUCCESS) { + IrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_EXCEPTION; + } + // If UDFVerifyVolume encountered an error during + // processing, it will return that error. If we got + // STATUS_WRONG_VOLUME from the verify, and our volume + // is now mounted, commute the status to STATUS_SUCCESS. + if ((RC == STATUS_WRONG_VOLUME) && + (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) { + RC = STATUS_SUCCESS; + } + + // Do a quick unprotected check here. The routine will do + // a safe check. After here we can release the resource. + // Note that if the volume really went away, we will be taking + // the Reparse path. + + // If the device might need to go away then call our dismount routine. + if ( (!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) || + (Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED)) && + (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE) ) + { + KdPrint(("UDFPerformVerify: UDFCheckForDismount\n")); + UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); + UDFCheckForDismount( IrpContext, Vcb, FALSE ); + UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); + } + + // If this is a create and the verify succeeded then complete the + // request with a REPARSE status. + if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && + (IrpSp->FileObject->RelatedFileObject == NULL) && + ((RC == STATUS_SUCCESS) || (RC == STATUS_WRONG_VOLUME)) ) { + + KdPrint(("UDFPerformVerify: IO_REMOUNT\n")); + + Irp->IoStatus.Information = IO_REMOUNT; + + Irp->IoStatus.Status = STATUS_REPARSE; + IoCompleteRequest(Irp,IO_DISK_INCREMENT); + + UDFReleaseIrpContext(IrpContext); + + RC = STATUS_REPARSE; + Irp = NULL; + IrpContext = NULL; + + // If there is still an error to process then call the Io system + // for a popup. + } else if ((Irp != NULL) && !NT_SUCCESS( RC )) { + + KdPrint(("UDFPerformVerify: check IoIsErrorUserInduced\n")); + // Fill in the device object if required. + if (IoIsErrorUserInduced( RC ) ) { + IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify ); + } + KdPrint(("UDFPerformVerify: UDFNormalizeAndRaiseStatus\n")); + UDFNormalizeAndRaiseStatus( IrpContext, RC ); + } + } + + // If there is still an Irp, send it off to an Ex Worker thread. + if (IrpContext != NULL) { + + RC = UDFPostRequest( IrpContext, Irp ); + } + + } _SEH2_EXCEPT(UDFExceptionFilter( IrpContext, _SEH2_GetExceptionInformation())) { + // We had some trouble trying to perform the verify or raised + // an error ourselves. So we'll abort the I/O request with + // the error status that we get back from the execption code. + RC = UDFExceptionHandler( IrpContext, Irp); + } _SEH2_END; + + KdPrint(("UDFPerformVerify: RC = %x\n", RC)); + + return RC; + +} // end UDFPerformVerify() + +/* + +Routine Description: + + This routine is called to check if a volume is ready for dismount. This + occurs when only file system references are left on the volume. + + If the dismount is not currently underway and the user reference count + has gone to zero then we can begin the dismount. + + If the dismount is in progress and there are no references left on the + volume (we check the Vpb for outstanding references as well to catch + any create calls dispatched to the file system) then we can delete + the Vcb. + +Arguments: + + Vcb - Vcb for the volume to try to dismount. + +*/ +BOOLEAN +UDFCheckForDismount( + IN PtrUDFIrpContext IrpContext, + IN PVCB Vcb, + IN BOOLEAN _VcbAcquired + ) +{ + BOOLEAN VcbPresent = TRUE; + KIRQL SavedIrql; + BOOLEAN VcbAcquired; + ULONG ResidualReferenceCount; + + KdPrint(("UDFCheckForDismount:\n")); + if(!Vcb) return FALSE; + + // GlobalDataResource is already acquired + if(!_VcbAcquired) { + VcbAcquired = UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE/*FALSE*/ ); + if(!VcbAcquired) + return TRUE; + } else { + VcbAcquired = TRUE; + } + + if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && + (IrpContext->TargetDeviceObject == Vcb->TargetDeviceObject)) { + + ResidualReferenceCount = 2; + + } else { + + ResidualReferenceCount = 1; + } + + // If the dismount is not already underway then check if the + // user reference count has gone to zero. If so start the teardown + // on the Vcb. + if (!(Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED)) { + if (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE) { + VcbPresent = UDFDismountVcb(Vcb, VcbAcquired); + } + VcbAcquired = VcbAcquired && VcbPresent; + + // If the teardown is underway and there are absolutely no references + // remaining then delete the Vcb. References here include the + // references in the Vcb and Vpb. + } else if (!(Vcb->VCBOpenCount)) { + + IoAcquireVpbSpinLock( &SavedIrql ); + // If there are no file objects and no reference counts in the + // Vpb we can delete the Vcb. Don't forget that we have the + // last reference in the Vpb. + if (Vcb->Vpb->ReferenceCount <= ResidualReferenceCount) { + + IoReleaseVpbSpinLock( SavedIrql ); + if(VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + UDFStopEjectWaiter(Vcb); + UDFReleaseVCB(Vcb); + VcbAcquired = + VcbPresent = FALSE; + + } else { + + IoReleaseVpbSpinLock( SavedIrql ); + } + } + + // Release any resources still acquired. + if (!_VcbAcquired && VcbAcquired) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + + return VcbPresent; +} // end UDFCheckForDismount() + + +/* + +Routine Description: + + This routine is called when all of the user references to a volume are + gone. We will initiate all of the teardown any system resources. + + If all of the references to this volume are gone at the end of this routine + then we will complete the teardown of this Vcb and mark the current Vpb + as not mounted. Otherwise we will allocated a new Vpb for this device + and keep the current Vpb attached to the Vcb. + +Arguments: + + Vcb - Vcb for the volume to dismount. + +Return Value: + + BOOLEAN - TRUE if we didn't delete the Vcb, FALSE otherwise. + +*/ +BOOLEAN +UDFDismountVcb( + IN PVCB Vcb, + IN BOOLEAN VcbAcquired + ) +{ + + PVPB OldVpb; + PVPB NewVpb; + BOOLEAN VcbPresent = TRUE; + KIRQL SavedIrql; + + BOOLEAN FinalReference; + + KdPrint(("UDFDismountVcb:\n")); + // We should only take this path once. + ASSERT( !(Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) ); + + // Mark the Vcb as DismountInProgress. + Vcb->VCBFlags |= UDF_VCB_FLAGS_BEING_DISMOUNTED; + + // Allocate a new Vpb in case we will need it. + NewVpb = (PVPB)DbgAllocatePoolWithTag( NonPagedPool, sizeof( VPB ), 'bpvU' ); + if(!NewVpb) { + Vcb->VCBFlags &= ~UDF_VCB_FLAGS_BEING_DISMOUNTED; + return TRUE; + } + + RtlZeroMemory( NewVpb, sizeof(VPB) ); + + OldVpb = Vcb->Vpb; + + // Remove the mount volume reference. + UDFCloseResidual(Vcb); + // the only residual reference is cleaned above + + // Acquire the Vpb spinlock to check for Vpb references. + IoAcquireVpbSpinLock(&SavedIrql); + + // Remember if this is the last reference on this Vcb. We incremented + // the count on the Vpb earlier so we get one last crack it. If our + // reference has gone to zero but the vpb reference count is greater + // than zero then the Io system will be responsible for deleting the + // Vpb. + FinalReference = (BOOLEAN)(OldVpb->ReferenceCount == 1); + + // There is a reference count in the Vpb and in the Vcb. We have + // incremented the reference count in the Vpb to make sure that + // we have last crack at it. If this is a failed mount then we + // want to return the Vpb to the IO system to use for the next + // mount request. + if (OldVpb->RealDevice->Vpb == OldVpb) { + + // If not the final reference then swap out the Vpb. + if (!FinalReference) { + + NewVpb->Type = IO_TYPE_VPB; + NewVpb->Size = sizeof( VPB ); + NewVpb->RealDevice = OldVpb->RealDevice; + + NewVpb->RealDevice->Vpb = NewVpb; + + NewVpb = NULL; + IoReleaseVpbSpinLock(SavedIrql); + // We want to leave the Vpb for the IO system. Mark it + // as being not mounted. Go ahead and delete the Vcb as + // well. + } else { + + // Make sure to remove the last reference on the Vpb. + + OldVpb->ReferenceCount--; + + OldVpb->DeviceObject = NULL; + Vcb->Vpb->Flags &= ~VPB_MOUNTED; + + // Clear the Vpb flag so we know not to delete it. + Vcb->Vpb = NULL; + + IoReleaseVpbSpinLock(SavedIrql); + if(VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + UDFStopEjectWaiter(Vcb); + UDFReleaseVCB(Vcb); + VcbPresent = FALSE; + } + + // Someone has already swapped in a new Vpb. If this is the final reference + // then the file system is responsible for deleting the Vpb. + } else if (FinalReference) { + + // Make sure to remove the last reference on the Vpb. + OldVpb->ReferenceCount--; + + IoReleaseVpbSpinLock( SavedIrql ); + if(VcbAcquired) + UDFReleaseResource(&(Vcb->VCBResource)); + UDFStopEjectWaiter(Vcb); + UDFReleaseVCB(Vcb); + VcbPresent = FALSE; + + // The current Vpb is no longer the Vpb for the device (the IO system + // has already allocated a new one). We leave our reference in the + // Vpb and will be responsible for deleting it at a later time. + } else { + + OldVpb->DeviceObject = NULL; + Vcb->Vpb->Flags &= ~VPB_MOUNTED; + + IoReleaseVpbSpinLock( SavedIrql ); + } + + // Deallocate the new Vpb if we don't need it. + if (NewVpb != NULL) { + DbgFreePool( NewVpb ); + } + + // Let our caller know whether the Vcb is still present. + return VcbPresent; +} // end UDFDismountVcb() + + +NTSTATUS +UDFCompareVcb( + IN PVCB OldVcb, + IN PVCB NewVcb, + IN BOOLEAN PhysicalOnly + ) +{ + NTSTATUS RC; + UDF_FILE_INFO RootFileInfo; + BOOLEAN SimpleLogicalCheck = FALSE; + + KdPrint(("UDFCompareVcb:\n")); + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_BEING_UNLOADED) { + KdPrint((" WRONG_VOLUME\n")); + return STATUS_WRONG_VOLUME; + } + +#define VCB_NE(x) (OldVcb->x != NewVcb->x) + + // compare physical parameters + if(PhysicalOnly) { + KdPrint((" PhysicalOnly\n")); + if(VCB_NE(FirstLBA) || + VCB_NE(LastLBA) || + VCB_NE(FirstTrackNum) || + VCB_NE(LastTrackNum) || + VCB_NE(NWA) || + VCB_NE(LastPossibleLBA) || + VCB_NE(PhSerialNumber) || + VCB_NE(PhErasable) || + VCB_NE(PhDiskType) || + VCB_NE(MediaClassEx) || + + /* We cannot compare these flags, because NewVcb is in unconditional ReadOnly */ + + /*((OldVcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) != (NewVcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) || + ((OldVcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) != (NewVcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) ||*/ + + VCB_NE(TargetDeviceObject) || + // VCB_NE(xxx) || + // VCB_NE(xxx) || + VCB_NE(LastSession) ) { + + KdPrint((" WRONG_VOLUME (2)\n")); + return STATUS_WRONG_VOLUME; + } + // Note, MRWStatus can change while media is mounted (stoppped/in-progress/complete) + // We can compare only (Vcb->MRWStatus == 0) values + if((OldVcb->MRWStatus == 0) != (NewVcb->MRWStatus == 0)) { + KdPrint((" WRONG_VOLUME (4), missmatch MRW status\n")); + } + for(uint32 i=OldVcb->FirstTrackNum; i<=OldVcb->LastTrackNum; i++) { + if(VCB_NE(TrackMap[i].FirstLba) || + VCB_NE(TrackMap[i].LastLba) || + VCB_NE(TrackMap[i].PacketSize) || + VCB_NE(TrackMap[i].TrackParam) || + VCB_NE(TrackMap[i].DataParam) || + VCB_NE(TrackMap[i].NWA_V) ) { + KdPrint((" WRONG_VOLUME (3), missmatch trk %d\n", i)); + return STATUS_WRONG_VOLUME; + } + } + KdPrint((" Vcb compare Ok\n")); + return STATUS_SUCCESS; + } + + // Something is nasty!!! We perform verify for not flushed volume + // This should never happen, but some devices/buses and their drivers + // can lead us to such condition. For example with help of RESET. + // Now, we hope, that nobody changed media. + // We shall make simplified logical structure check + if(OldVcb->Modified) { + KdPrint((" Vcb SIMPLE compare on !!!MODIFIED!!! volume\n")); + ASSERT(FALSE); + SimpleLogicalCheck = TRUE; + } + + // compare logical structure + if(!SimpleLogicalCheck && (OldVcb->InitVatCount != NewVcb->InitVatCount)) { + KdPrint((" InitVatCount %d != %d \n", OldVcb->InitVatCount, NewVcb->InitVatCount)); + return STATUS_WRONG_VOLUME; + } + + // Compare volume creation time + if(OldVcb->VolCreationTime != NewVcb->VolCreationTime) { + KdPrint((" VolCreationTime %I64x != %I64x \n", OldVcb->VolCreationTime, NewVcb->VolCreationTime)); + return STATUS_WRONG_VOLUME; + } + // Compare serial numbers + if(OldVcb->SerialNumber != NewVcb->SerialNumber) { + KdPrint((" SerialNumber %x != %x \n", OldVcb->SerialNumber, NewVcb->SerialNumber)); + return STATUS_WRONG_VOLUME; + } + // Compare volume idents + if(!SimpleLogicalCheck && + RtlCompareUnicodeString(&(OldVcb->VolIdent),&(NewVcb->VolIdent),FALSE)) { + KdPrint((" VolIdent missmatch \n")); + return STATUS_WRONG_VOLUME; + } + if(SimpleLogicalCheck) { + // do not touch RootDir. It can be partially recorded + KdPrint((" SimpleLogicalCheck Ok\n")); + return STATUS_SUCCESS; + } + + RC = UDFOpenRootFile__(NewVcb, &(NewVcb->RootLbAddr), &RootFileInfo); + if(!NT_SUCCESS(RC)) { + KdPrint((" Can't open root file, status %x\n", RC)); + UDFCleanUpFile__(NewVcb, &RootFileInfo); + return STATUS_WRONG_VOLUME; + } + // perform exhaustive check + if(!(OldVcb->RootDirFCB)) { + KdPrint((" !(OldVcb->RootDirFCB)\n")); +wr_vol: + UDFCloseFile__(NewVcb, &RootFileInfo); + UDFCleanUpFile__(NewVcb, &RootFileInfo); + return STATUS_WRONG_VOLUME; + } + + if(!UDFCompareFileInfo(&RootFileInfo, OldVcb->RootDirFCB->FileInfo)) { + KdPrint((" !UDFCompareFileInfo\n")); + goto wr_vol; + } + UDFCloseFile__(NewVcb, &RootFileInfo); + UDFCleanUpFile__(NewVcb, &RootFileInfo); + + KdPrint(("UDFCompareVcb: Ok\n")); + return STATUS_SUCCESS; + +#undef VCB_NE + +} // end UDFCompareVcb() + diff --git a/reactos/drivers/filesystems/udfs/volinfo.cpp b/reactos/drivers/filesystems/udfs/volinfo.cpp new file mode 100644 index 00000000000..9657a5ddccb --- /dev/null +++ b/reactos/drivers/filesystems/udfs/volinfo.cpp @@ -0,0 +1,830 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/*++ + +Module Name: + + VolInfo.cpp + +Abstract: + + This module implements the volume information routines for UDF called by + the dispatch driver. + +--*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_VOL_INFORMATION + +#ifdef DEMO +PWCHAR DemoVolIdent = UDF_DEMO_VOLUME_LABEL; +#endif // DEMO + +// Local support routines +NTSTATUS +UDFQueryFsVolumeInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_VOLUME_INFORMATION Buffer, + IN OUT PULONG Length + ); + +NTSTATUS +UDFQueryFsSizeInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_SIZE_INFORMATION Buffer, + IN OUT PULONG Length + ); + +NTSTATUS +UDFQueryFsFullSizeInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, + IN OUT PULONG Length + ); + +NTSTATUS +UDFQueryFsDeviceInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_DEVICE_INFORMATION Buffer, + IN OUT PULONG Length + ); + +NTSTATUS +UDFQueryFsAttributeInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, + IN OUT PULONG Length + ); + +NTSTATUS +UDFSetLabelInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_LABEL_INFORMATION Buffer, + IN OUT PULONG Length); + +/* + This is the routine for querying volume information + +Arguments: + + Irp - Supplies the Irp being processed + +Return Value: + + NTSTATUS - The return status for the operation + + */ +NTSTATUS +NTAPI +UDFQueryVolInfo( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFQueryVolInfo: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp); + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFQueryVolInfo() + +/* + This is the common routine for querying volume information called by both + the fsd and fsp threads. + +Arguments: + + Irp - Supplies the Irp being processed + +Return Value: + + NTSTATUS - The return status for the operation + + */ +NTSTATUS +UDFCommonQueryVolInfo( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_INVALID_PARAMETER; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + ULONG Length; + BOOLEAN CanWait = FALSE; + PVCB Vcb; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + PFILE_OBJECT FileObject = NULL; +// PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + _SEH2_TRY { + + KdPrint(("UDFCommonQueryVolInfo: \n")); + + ASSERT(PtrIrpContext); + ASSERT(Irp); + + PAGED_CODE(); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + + Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); + ASSERT(Vcb); + //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + // Reference our input parameters to make things easier + Length = IrpSp->Parameters.QueryVolume.Length; + // Acquire the Vcb for this volume. + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); +#ifdef UDF_ENABLE_SECURITY + RC = IoCheckFunctionAccess( + Ccb->PreviouslyGrantedAccess, + PtrIrpContext->MajorFunction, + PtrIrpContext->MinorFunction, + 0, + NULL, + &(IrpSp->Parameters.QueryVolume.FsInformationClass)); + if(!NT_SUCCESS(RC)) { + try_return(RC); + } +#endif //UDF_ENABLE_SECURITY + switch (IrpSp->Parameters.QueryVolume.FsInformationClass) { + + case FileFsVolumeInformation: + + // This is the only routine we need the Vcb shared because of + // copying the volume label. All other routines copy fields that + // cannot change or are just manifest constants. + UDFFlushTryBreak(Vcb); + if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { + PostRequest = TRUE; + try_return (RC = STATUS_PENDING); + } + AcquiredVCB = TRUE; + + RC = UDFQueryFsVolumeInfo( PtrIrpContext, Vcb, (PFILE_FS_VOLUME_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + break; + + case FileFsSizeInformation: + + RC = UDFQueryFsSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + break; + + case FileFsDeviceInformation: + + RC = UDFQueryFsDeviceInfo( PtrIrpContext, Vcb, (PFILE_FS_DEVICE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + break; + + case FileFsAttributeInformation: + + RC = UDFQueryFsAttributeInfo( PtrIrpContext, Vcb, (PFILE_FS_ATTRIBUTE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + break; + + case FileFsFullSizeInformation: + + RC = UDFQueryFsFullSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_FULL_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + break; + + default: + + RC = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + break; + + } + + // Set the information field to the number of bytes actually filled in + Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if (AcquiredVCB) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVCB = FALSE; + } + + // Post IRP if required + if (PostRequest) { + + // Since, the I/O Manager gave us a system buffer, we do not + // need to "lock" anything. + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else + if(!_SEH2_AbnormalTermination()) { + + Irp->IoStatus.Status = RC; + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } // can we complete the IRP ? + + } _SEH2_END; + + return RC; +} // end UDFCommonQueryVolInfo() + + +// Local support routine + +/* + This routine implements the query volume info call + +Arguments: + + Vcb - Vcb for this volume. + Buffer - Supplies a pointer to the output buffer where the information + is to be returned + Length - Supplies the length of the buffer in byte. This variable + upon return recieves the remaining bytes free in the buffer + */ +NTSTATUS +UDFQueryFsVolumeInfo( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_VOLUME_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + ULONG BytesToCopy; + NTSTATUS Status; + + PAGED_CODE(); + + KdPrint((" UDFQueryFsVolumeInfo: \n")); + // Fill in the data from the Vcb. + Buffer->VolumeCreationTime.QuadPart = Vcb->VolCreationTime; +#ifndef DEMO // release + Buffer->VolumeSerialNumber = Vcb->PhSerialNumber; +#else // DEMO + Buffer->VolumeSerialNumber = 0xDE1770; +#endif // DEMO + KdPrint((" SN %x\n", Vcb->PhSerialNumber)); + + Buffer->SupportsObjects = FALSE; + + *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] ); + + // Check if the buffer we're given is long enough + if (*Length >= (ULONG) Vcb->VolIdent.Length) { +#ifndef DEMO // release + BytesToCopy = Vcb->VolIdent.Length; +#else // DEMO + BytesToCopy = sizeof(UDF_DEMO_VOLUME_LABEL) - sizeof(WCHAR); +#endif // DEMO + Status = STATUS_SUCCESS; + } else { + BytesToCopy = *Length; + Status = STATUS_BUFFER_OVERFLOW; + } + // Copy over what we can of the volume label, and adjust *Length + Buffer->VolumeLabelLength = BytesToCopy; + + if (BytesToCopy) +#ifndef DEMO // release + RtlCopyMemory( &(Buffer->VolumeLabel[0]), Vcb->VolIdent.Buffer, BytesToCopy ); +#else // DEMO + RtlCopyMemory( &(Buffer->VolumeLabel[0]), DemoVolIdent, BytesToCopy ); +#endif // DEMO + *Length -= BytesToCopy; + + return Status; +} // end UDFQueryFsVolumeInfo() + +/* + This routine implements the query volume size call. + +Arguments: + + Vcb - Vcb for this volume. + Buffer - Supplies a pointer to the output buffer where the information + is to be returned + Length - Supplies the length of the buffer in byte. This variable + upon return recieves the remaining bytes free in the buffer + */ +NTSTATUS +UDFQueryFsSizeInfo( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_SIZE_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + PAGED_CODE(); + + KdPrint((" UDFQueryFsSizeInfo: \n")); + // Fill in the output buffer. + if(Vcb->BitmapModified) { + Vcb->TotalAllocUnits = + Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); + Vcb->FreeAllocUnits = + Buffer->AvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); + Vcb->BitmapModified = FALSE; + } else { + Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; + Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; + } + Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128); + if(!Buffer->TotalAllocationUnits.QuadPart) + Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); + Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; + if(!Buffer->SectorsPerAllocationUnit) + Buffer->SectorsPerAllocationUnit = 1; + Buffer->BytesPerSector = Vcb->BlockSize; + if(!Buffer->BytesPerSector) + Buffer->BytesPerSector = 2048; + + KdPrint((" Space: Total %I64x, Free %I64x\n", + Buffer->TotalAllocationUnits.QuadPart, + Buffer->AvailableAllocationUnits.QuadPart)); + + // Adjust the length variable + *Length -= sizeof( FILE_FS_SIZE_INFORMATION ); + return STATUS_SUCCESS; +} // UDFQueryFsSizeInfo() + +/* + This routine implements the query volume full size call. + +Arguments: + + Vcb - Vcb for this volume. + Buffer - Supplies a pointer to the output buffer where the information + is to be returned + Length - Supplies the length of the buffer in byte. This variable + upon return recieves the remaining bytes free in the buffer + */ +NTSTATUS +UDFQueryFsFullSizeInfo( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + PAGED_CODE(); + + KdPrint((" UDFQueryFsFullSizeInfo: \n")); + // Fill in the output buffer. + if(Vcb->BitmapModified) { + Vcb->TotalAllocUnits = + Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); + Vcb->FreeAllocUnits = + Buffer->CallerAvailableAllocationUnits.QuadPart = + Buffer->ActualAvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); + Vcb->BitmapModified = FALSE; + } else { + Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; + Buffer->CallerAvailableAllocationUnits.QuadPart = + Buffer->ActualAvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; + } + if(!Buffer->TotalAllocationUnits.QuadPart) + Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); + Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; + if(!Buffer->SectorsPerAllocationUnit) + Buffer->SectorsPerAllocationUnit = 1; + Buffer->BytesPerSector = Vcb->BlockSize; + if(!Buffer->BytesPerSector) + Buffer->BytesPerSector = 2048; + + KdPrint((" Space: Total %I64x, Free %I64x\n", + Buffer->TotalAllocationUnits.QuadPart, + Buffer->ActualAvailableAllocationUnits.QuadPart)); + + // Adjust the length variable + *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION ); + return STATUS_SUCCESS; +} // UDFQueryFsSizeInfo() + +/* + This routine implements the query volume device call. + +Arguments: + + Vcb - Vcb for this volume. + Buffer - Supplies a pointer to the output buffer where the information + is to be returned + Length - Supplies the length of the buffer in byte. This variable + upon return recieves the remaining bytes free in the buffer + */ +NTSTATUS +UDFQueryFsDeviceInfo( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_DEVICE_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + PAGED_CODE(); + + KdPrint((" UDFQueryFsDeviceInfo: \n")); + // Update the output buffer. + ASSERT(! (Vcb->TargetDeviceObject->Characteristics & (FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA))); + Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics & ~(FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA); + Buffer->DeviceType = Vcb->TargetDeviceObject->DeviceType; + KdPrint((" Characteristics %x, DeviceType %x\n", Buffer->Characteristics, Buffer->DeviceType)); + // Adjust the length variable + *Length -= sizeof( FILE_FS_DEVICE_INFORMATION ); + return STATUS_SUCCESS; +} // end UDFQueryFsDeviceInfo() + +/* + This routine implements the query volume attribute call. + +Arguments: + + Vcb - Vcb for this volume. + Buffer - Supplies a pointer to the output buffer where the information + is to be returned + Length - Supplies the length of the buffer in byte. This variable + upon return recieves the remaining bytes free in the buffer + */ +NTSTATUS +UDFQueryFsAttributeInfo( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + ULONG BytesToCopy; + + NTSTATUS Status = STATUS_SUCCESS; + PWCHAR FsTypeTitle; + ULONG FsTypeTitleLen; + + PAGED_CODE(); + + KdPrint((" UDFQueryFsAttributeInfo: \n")); + // Fill out the fixed portion of the buffer. + Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | + FILE_CASE_PRESERVED_NAMES | + (UDFStreamsSupported(Vcb) ? FILE_NAMED_STREAMS : 0) | +#ifdef ALLOW_SPARSE + FILE_SUPPORTS_SPARSE_FILES | +#endif //ALLOW_SPARSE +#ifdef UDF_ENABLE_SECURITY + (UDFNtAclSupported(Vcb) ? FILE_PERSISTENT_ACLS : 0) | +#endif //UDF_ENABLE_SECURITY + ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ? FILE_READ_ONLY_VOLUME : 0) | + + FILE_UNICODE_ON_DISK; + + Buffer->MaximumComponentNameLength = UDF_X_NAME_LEN-1; + + *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ); + // Make sure we can copy full unicode characters. + *Length &= ~1; + // Determine how much of the file system name will fit. + +#define UDFSetFsTitle(tit) \ + FsTypeTitle = UDF_FS_TITLE_##tit; \ + FsTypeTitleLen = sizeof(UDF_FS_TITLE_##tit) - sizeof(WCHAR); + + switch(Vcb->TargetDeviceObject->DeviceType) { + case FILE_DEVICE_CD_ROM: { + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + if(!Vcb->LastLBA) { + UDFSetFsTitle(BLANK); + } else { + UDFSetFsTitle(UNKNOWN); + } + } else + if(Vcb->CDR_Mode) { + if(Vcb->MediaClassEx == CdMediaClass_DVDR || + Vcb->MediaClassEx == CdMediaClass_DVDRW || + Vcb->MediaClassEx == CdMediaClass_DVDRAM) { + UDFSetFsTitle(DVDR); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDpR || + Vcb->MediaClassEx == CdMediaClass_DVDpRW) { + UDFSetFsTitle(DVDpR); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDROM) { + UDFSetFsTitle(DVDROM); + } else + if(Vcb->MediaClassEx == CdMediaClass_CDROM) { + UDFSetFsTitle(CDROM); + } else { + UDFSetFsTitle(CDR); + } + } else { + if(Vcb->MediaClassEx == CdMediaClass_DVDROM || + Vcb->MediaClassEx == CdMediaClass_DVDR || + Vcb->MediaClassEx == CdMediaClass_DVDpR) { + UDFSetFsTitle(DVDROM); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDR) { + UDFSetFsTitle(DVDR); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { + UDFSetFsTitle(DVDRW); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) { + UDFSetFsTitle(DVDpRW); + } else + if(Vcb->MediaClassEx == CdMediaClass_DVDRAM) { + UDFSetFsTitle(DVDRAM); + } else + if(Vcb->MediaClassEx == CdMediaClass_CDROM) { + UDFSetFsTitle(CDROM); + } else { + UDFSetFsTitle(CDRW); + } + } + break; + } + default: { + UDFSetFsTitle(HDD); + break; + } + } + +#undef UDFSetFsTitle + + if (*Length >= FsTypeTitleLen) { + BytesToCopy = FsTypeTitleLen; + } else { + BytesToCopy = *Length; + Status = STATUS_BUFFER_OVERFLOW; + } + + *Length -= BytesToCopy; + // Do the file system name. + Buffer->FileSystemNameLength = BytesToCopy; + RtlCopyMemory( &Buffer->FileSystemName[0], FsTypeTitle, BytesToCopy ); + // And return to our caller + return Status; +} // end UDFQueryFsAttributeInfo() + + +#ifndef UDF_READ_ONLY_BUILD +#ifndef DEMO // release + +NTSTATUS +NTAPI +UDFSetVolInfo( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + KdPrint(("UDFSetVolInfo: \n")); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = UDFCommonSetVolInfo(PtrIrpContext, Irp); + + } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFSetVolInfo() + + +/* + This is the common routine for setting volume information called by both + the fsd and fsp threads. + */ +NTSTATUS +UDFCommonSetVolInfo( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp + ) +{ + NTSTATUS RC = STATUS_INVALID_PARAMETER; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + ULONG Length; + BOOLEAN CanWait = FALSE; + PVCB Vcb; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + PFILE_OBJECT FileObject = NULL; +// PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + + _SEH2_TRY { + + KdPrint(("UDFCommonSetVolInfo: \n")); + ASSERT(PtrIrpContext); + ASSERT(Irp); + + PAGED_CODE(); + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // Get the FCB and CCB pointers. + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + + if(Ccb && Ccb->Fcb && (Ccb->Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { + KdPrint((" Can't change Label on Non-volume object\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + + Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); + ASSERT(Vcb); + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + // Reference our input parameters to make things easier + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { + KdPrint((" Can't change Label on blank volume ;)\n")); + try_return(RC = STATUS_ACCESS_DENIED); + } + + Length = IrpSp->Parameters.SetVolume.Length; + // Acquire the Vcb for this volume. + CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { + PostRequest = TRUE; + try_return (RC = STATUS_PENDING); + } + AcquiredVCB = TRUE; +#ifdef UDF_ENABLE_SECURITY + RC = IoCheckFunctionAccess( + Ccb->PreviouslyGrantedAccess, + PtrIrpContext->MajorFunction, + PtrIrpContext->MinorFunction, + 0, + NULL, + &(IrpSp->Parameters.SetVolume.FsInformationClass)); + if(!NT_SUCCESS(RC)) { + try_return(RC); + } +#endif //UDF_ENABLE_SECURITY + switch (IrpSp->Parameters.SetVolume.FsInformationClass) { + + case FileFsLabelInformation: + + RC = UDFSetLabelInfo( PtrIrpContext, Vcb, (PFILE_FS_LABEL_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); + Irp->IoStatus.Information = 0; + break; + + default: + + RC = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + break; + + } + + // Set the information field to the number of bytes actually filled in + Irp->IoStatus.Information = IrpSp->Parameters.SetVolume.Length - Length; + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if (AcquiredVCB) { + UDFReleaseResource(&(Vcb->VCBResource)); + AcquiredVCB = FALSE; + } + + // Post IRP if required + if (PostRequest) { + + // Since, the I/O Manager gave us a system buffer, we do not + // need to "lock" anything. + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else { + + // Can complete the IRP here if no exception was encountered + if (!_SEH2_AbnormalTermination()) { + Irp->IoStatus.Status = RC; + + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + + } _SEH2_END; + + return RC; +} // end UDFCommonSetVolInfo() + +/* + This sets Volume Label + */ +NTSTATUS +UDFSetLabelInfo ( + IN PtrUDFIrpContext PtrIrpContext, + IN PVCB Vcb, + IN PFILE_FS_LABEL_INFORMATION Buffer, + IN OUT PULONG Length + ) +{ + PAGED_CODE(); + + KdPrint((" UDFSetLabelInfo: \n")); + if(Buffer->VolumeLabelLength > UDF_VOL_LABEL_LEN*sizeof(WCHAR)) { + // Too long Volume Label... NT doesn't like it + KdPrint((" UDFSetLabelInfo: STATUS_INVALID_VOLUME_LABEL\n")); + return STATUS_INVALID_VOLUME_LABEL; + } + + if(Vcb->VolIdent.Buffer) MyFreePool__(Vcb->VolIdent.Buffer); + Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Buffer->VolumeLabelLength+sizeof(WCHAR)); + if(!Vcb->VolIdent.Buffer) return STATUS_INSUFFICIENT_RESOURCES; + + Vcb->VolIdent.Length = (USHORT)Buffer->VolumeLabelLength; + Vcb->VolIdent.MaximumLength = (USHORT)Buffer->VolumeLabelLength+sizeof(WCHAR); + RtlCopyMemory(Vcb->VolIdent.Buffer, &(Buffer->VolumeLabel), Buffer->VolumeLabelLength); + Vcb->VolIdent.Buffer[Buffer->VolumeLabelLength/sizeof(WCHAR)] = 0; + UDFSetModified(Vcb); + + KdPrint((" UDFSetLabelInfo: OK\n")); + return STATUS_SUCCESS; +} // end UDFSetLabelInfo () + +#endif // DEMO +#endif //UDF_READ_ONLY_BUILD diff --git a/reactos/drivers/filesystems/udfs/wcache.cpp b/reactos/drivers/filesystems/udfs/wcache.cpp new file mode 100644 index 00000000000..be686ab7693 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/wcache.cpp @@ -0,0 +1,10 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_WCACHE + +#include "..\Include\Wcache_lib.cpp" diff --git a/reactos/drivers/filesystems/udfs/wcache.h b/reactos/drivers/filesystems/udfs/wcache.h new file mode 100644 index 00000000000..f064f627e83 --- /dev/null +++ b/reactos/drivers/filesystems/udfs/wcache.h @@ -0,0 +1,11 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// + +#ifndef __CDRW_WCACHE_H__ +#define __CDRW_WCACHE_H__ + +#include "..\Include\Wcache_lib.h" + +#endif // __CDRW_WCACHE_H__ diff --git a/reactos/drivers/filesystems/udfs/write.cpp b/reactos/drivers/filesystems/udfs/write.cpp new file mode 100644 index 00000000000..01964f1803e --- /dev/null +++ b/reactos/drivers/filesystems/udfs/write.cpp @@ -0,0 +1,1242 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +//////////////////////////////////////////////////////////////////// +/************************************************************************* +* +* File: Write.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Write" dispatch entry point. +* +*************************************************************************/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_WRITE + +#ifndef UDF_READ_ONLY_BUILD + +/************************************************************************* +* +* Function: UDFWrite() +* +* Description: +* The I/O Manager will invoke this routine to handle a write +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +NTAPI +UDFWrite( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp // I/O Request Packet + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrUDFIrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + TmPrint(("UDFWrite: , thrd:%8.8x\n",PsGetCurrentThread())); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = UDFIsIrpTopLevel(Irp); + ASSERT(!UDFIsFSDevObj(DeviceObject)); + + _SEH2_TRY { + + // get an IRP context structure and issue the request + PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); + if(PtrIrpContext) { + + RC = UDFCommonWrite(PtrIrpContext, Irp); + + } else { + RC = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + // complete the IRP + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + + } _SEH2_EXCEPT (UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { + + RC = UDFExceptionHandler(PtrIrpContext, Irp); + + UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); + } _SEH2_END; + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} // end UDFWrite() + + +/************************************************************************* +* +* Function: UDFCommonWrite() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFCommonWrite( + PtrUDFIrpContext PtrIrpContext, + PIRP Irp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = NULL; + LARGE_INTEGER ByteOffset; + ULONG WriteLength = 0, TruncatedLength = 0; + ULONG NumberBytesWritten = 0; + PFILE_OBJECT FileObject = NULL; + PtrUDFFCB Fcb = NULL; + PtrUDFCCB Ccb = NULL; + PVCB Vcb = NULL; + PtrUDFNTRequiredFCB NtReqFcb = NULL; + PERESOURCE PtrResourceAcquired = NULL; + PERESOURCE PtrResourceAcquired2 = NULL; + PVOID SystemBuffer = NULL; +// PVOID TmpBuffer = NULL; +// uint32 KeyValue = 0; + PIRP TopIrp; + + LONGLONG ASize; + LONGLONG OldVDL; + + ULONG Res1Acq = 0; + ULONG Res2Acq = 0; + + BOOLEAN CacheLocked = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + BOOLEAN IsThisADeferredWrite = FALSE; + BOOLEAN WriteToEOF = FALSE; + BOOLEAN Resized = FALSE; + BOOLEAN RecursiveWriteThrough = FALSE; + BOOLEAN WriteFileSizeToDirNdx = FALSE; + BOOLEAN ZeroBlock = FALSE; + BOOLEAN VcbAcquired = FALSE; + BOOLEAN ZeroBlockDone = FALSE; + + TmPrint(("UDFCommonWrite: irp %x\n", Irp)); + + _SEH2_TRY { + + + TopIrp = IoGetTopLevelIrp(); + + switch((ULONG)TopIrp) { + case FSRTL_FSP_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); + break; + case FSRTL_CACHE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); + break; + case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: + KdPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n")); + break; + case FSRTL_FAST_IO_TOP_LEVEL_IRP: + KdPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n")); + BrutePoint(); + break; + case NULL: + KdPrint((" NULL TOP_LEVEL_IRP\n")); + break; + default: + if(TopIrp == Irp) { + KdPrint((" TOP_LEVEL_IRP\n")); + } else { + KdPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); + } + break; + } + + // First, get a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpSp); + MmPrint((" Enter Irp, MDL=%x\n", Irp->MdlAddress)); + if(Irp->MdlAddress) { + UDFTouch(Irp->MdlAddress); + } + + FileObject = IrpSp->FileObject; + ASSERT(FileObject); + + // If this happens to be a MDL write complete request, then + // allocated MDL can be freed. This may cause a recursive write + // back into the FSD. + if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + UDFMdlComplete(PtrIrpContext, Irp, IrpSp, FALSE); + // The IRP has been completed. + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post the request + if (IrpSp->MinorFunction & IRP_MN_DPC) { + try_return(RC = STATUS_PENDING); + } + + // Get the FCB and CCB pointers + Ccb = (PtrUDFCCB)(FileObject->FsContext2); + ASSERT(Ccb); + Fcb = Ccb->Fcb; + ASSERT(Fcb); + Vcb = Fcb->Vcb; + + if(Fcb->FCBFlags & UDF_FCB_DELETED) { + ASSERT(FALSE); + try_return(RC = STATUS_TOO_LATE); + } + + // is this operation allowed ? + if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { + try_return(RC = STATUS_ACCESS_DENIED); + } + Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; + +#ifdef EVALUATION_TIME_LIMIT + // License Key check + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + try_return(RC = STATUS_ACCESS_DENIED); + } +#endif //EVALUATION_TIME_LIMIT + + // Disk based file systems might decide to verify the logical volume + // (if required and only if removable media are supported) at this time + // As soon as Tray is locked, we needn't call UDFVerifyVcb() + + ByteOffset = IrpSp->Parameters.Write.ByteOffset; + + CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; + PagingIo = (Irp->Flags & IRP_PAGING_IO) ? TRUE : FALSE; + NonBufferedIo = (Irp->Flags & IRP_NOCACHE) ? TRUE : FALSE; + SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE; + KdPrint((" Flags: %s; %s; %s; %s; Irp(W): %8.8x\n", + CanWait ? "Wt" : "nw", PagingIo ? "Pg" : "np", + NonBufferedIo ? "NBuf" : "buff", SynchronousIo ? "Snc" : "Asc", + Irp->Flags)); + + NtReqFcb = Fcb->NTRequiredFCB; + + Res1Acq = UDFIsResourceAcquired(&(NtReqFcb->MainResource)); + if(!Res1Acq) { + Res1Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES1_ACQ; + } + Res2Acq = UDFIsResourceAcquired(&(NtReqFcb->PagingIoResource)); + if(!Res2Acq) { + Res2Acq = PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_RES2_ACQ; + } + + if(!NonBufferedIo && + (Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { + if((Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) && + UDFIsAStream(Fcb->FileInfo)) { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_STREAM_WRITE, + FILE_ACTION_MODIFIED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS, + FILE_ACTION_MODIFIED); + } + } + + // Get some of the parameters supplied to us + WriteLength = IrpSp->Parameters.Write.Length; + if (WriteLength == 0) { + // a 0 byte write can be immediately succeeded + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { + // NT expects changing CurrentByteOffset to zero in this case + FileObject->CurrentByteOffset.QuadPart = 0; + } + try_return(RC); + } + + // If this is the normal file we have to check for + // write access according to the current state of the file locks. + if (!PagingIo && + !FsRtlCheckLockForWriteAccess( &(NtReqFcb->FileLock), Irp) ) { + try_return( RC = STATUS_FILE_LOCK_CONFLICT ); + } + + // ********** + // Is this a write of the volume itself ? + // ********** + if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { + // Yup, we need to send this on to the disk driver after + // validation of the offset and length. + Vcb = (PVCB)(Fcb); + if(!CanWait) + try_return(RC = STATUS_PENDING); + // I dislike the idea of writing to not locked media + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED)) { + try_return(RC = STATUS_ACCESS_DENIED); + } + + if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { + + KdPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); + PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED; + + if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { + UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); + } +#ifdef UDF_DELAYED_CLOSE + UDFCloseAllDelayed(Vcb); +#endif //UDF_DELAYED_CLOSE + + } + + // Acquire the volume resource exclusive + UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); + PtrResourceAcquired = &(Vcb->VCBResource); + + // I dislike the idea of writing to mounted media too, but M$ has another point of view... + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) { + // flush system cache + UDFFlushLogicalVolume(NULL, NULL, Vcb, 0); + } +#ifdef _MSC_VER +/* FIXME */ + if(PagingIo) { + CollectStatistics(Vcb, MetaDataWrites); + CollectStatisticsEx(Vcb, MetaDataWriteBytes, NumberBytesWritten); + } +#endif + // Forward the request to the lower level driver + // Lock the callers buffer + if (!NT_SUCCESS(RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, WriteLength))) { + try_return(RC); + } + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) + try_return(RC = STATUS_INVALID_USER_BUFFER); + // Indicate, that volume contents can change after this operation + // This flag will force VerifyVolume in future + KdPrint((" set UnsafeIoctl\n")); + Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL; + // Make sure, that volume will never be quick-remounted + // It is very important for ChkUdf utility. + Vcb->SerialNumber--; + // Perform actual Write + RC = UDFTWrite(Vcb, SystemBuffer, WriteLength, + (ULONG)(ByteOffset.QuadPart >> Vcb->BlockSizeBits), + &NumberBytesWritten); + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + try_return(RC); + } + + if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) { + try_return(RC = STATUS_ACCESS_DENIED); + } + + // back pressure for very smart and fast system cache ;) + if(!NonBufferedIo) { + // cached IO + if(Vcb->VerifyCtx.QueuedCount || + Vcb->VerifyCtx.ItemCount >= UDF_MAX_VERIFY_CACHE) { + UDFVVerify(Vcb, UFD_VERIFY_FLAG_WAIT); + } + } else { + if(Vcb->VerifyCtx.ItemCount > UDF_SYS_CACHE_STOP_THR) { + UDFVVerify(Vcb, UFD_VERIFY_FLAG_WAIT); + } + } + + // The FSD (if it is a "nice" FSD) should check whether it is + // convenient to allow the write to proceed by utilizing the + // CcCanIWrite() function call. If it is not convenient to perform + // the write at this time, we should defer the request for a while. + // The check should not however be performed for non-cached write + // operations. To determine whether we are retrying the operation + // or now, use Flags in the IrpContext structure we have created + + IsThisADeferredWrite = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE; + + if (!NonBufferedIo) { + MmPrint((" CcCanIWrite()\n")); + if (!CcCanIWrite(FileObject, WriteLength, CanWait, IsThisADeferredWrite)) { + // Cache Manager and/or the VMM does not want us to perform + // the write at this time. Post the request. + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_DEFERRED_WRITE; + KdPrint(("UDFCommonWrite: Defer write\n")); + MmPrint((" CcDeferWrite()\n")); + CcDeferWrite(FileObject, UDFDeferredWriteCallBack, PtrIrpContext, Irp, WriteLength, IsThisADeferredWrite); + try_return(RC = STATUS_PENDING); + } + } + + // If the write request is directed to a page file, + // send the request directly to the disk + if (Fcb->FCBFlags & UDF_FCB_PAGE_FILE) { + NonBufferedIo = TRUE; + } + + // We can continue. Check whether this write operation is targeted + // to a directory object in which case the UDF FSD will disallow + // the write request. + if (Fcb->FCBFlags & UDF_FCB_DIRECTORY) { + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + + // Validate start offset and length supplied. + // Here is a special check that determines whether the caller wishes to + // begin the write at current end-of-file (whatever the value of that + // offset might be) + if(ByteOffset.HighPart == (LONG)0xFFFFFFFF) { + if(ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) { + WriteToEOF = TRUE; + ByteOffset = NtReqFcb->CommonFCBHeader.FileSize; + } else + if(ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) { + ByteOffset = FileObject->CurrentByteOffset; + } + } + + // Check if this volume has already been shut down. If it has, fail + // this write request. + if (Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN) { + try_return(RC = STATUS_TOO_LATE); + } + +#ifdef EVALUATION_TIME_LIMIT + // License Key check + if(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_UNREGISTERED) { + Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; + try_return(RC = STATUS_ACCESS_DENIED); + } +#endif //EVALUATION_TIME_LIMIT + + // Paging I/O write operations are special. If paging i/o write + // requests begin beyond end-of-file, the request should be no-oped + // If paging i/o + // requests extend beyond current end of file, they should be truncated + // to current end-of-file. + if(PagingIo && (WriteToEOF || ((ByteOffset.QuadPart + WriteLength) > NtReqFcb->CommonFCBHeader.FileSize.QuadPart))) { + if (ByteOffset.QuadPart > NtReqFcb->CommonFCBHeader.FileSize.QuadPart) { + TruncatedLength = 0; + } else { + TruncatedLength = (ULONG)(NtReqFcb->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); + } + if(!TruncatedLength) try_return(RC = STATUS_SUCCESS); + } else { + TruncatedLength = WriteLength; + } + +#ifdef _MSC_VER +/* FIXME */ + if(PagingIo) { + CollectStatistics(Vcb, UserFileWrites); + CollectStatisticsEx(Vcb, UserFileWriteBytes, NumberBytesWritten); + } +#endif + + // There are certain complications that arise when the same file stream + // has been opened for cached and non-cached access. The FSD is then + // responsible for maintaining a consistent view of the data seen by + // the caller. + // If this happens to be a non-buffered I/O, we should __try to flush the + // cached data (if some other file object has already initiated caching + // on the file stream). We should also __try to purge the cached + // information though the purge will probably fail if the file has been + // mapped into some process' virtual address space + // WARNING !!! we should not flush data beyond valid data length + if ( NonBufferedIo && + !PagingIo && + NtReqFcb->SectionObject.DataSectionObject && + TruncatedLength && + (ByteOffset.QuadPart < NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) { + + if(!Res1Acq) { + // Try to acquire the FCB MainResource exclusively + if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + PtrResourceAcquired = &(NtReqFcb->MainResource); + } + + if(!Res2Acq) { + // We hold PagingIo shared around the flush to fix a + // cache coherency problem. + UDFAcquireSharedStarveExclusive(&(NtReqFcb->PagingIoResource), TRUE ); + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + + // Flush and then attempt to purge the cache + if((ByteOffset.QuadPart + TruncatedLength) > NtReqFcb->CommonFCBHeader.FileSize.QuadPart) { + NumberBytesWritten = TruncatedLength; + } else { + NumberBytesWritten = (ULONG)(NtReqFcb->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); + } + + MmPrint((" CcFlushCache()\n")); + CcFlushCache(&(NtReqFcb->SectionObject), &ByteOffset, NumberBytesWritten, &(Irp->IoStatus)); + + if(PtrResourceAcquired2) { + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + PtrResourceAcquired2 = NULL; + } + // If the flush failed, return error to the caller + if (!NT_SUCCESS(RC = Irp->IoStatus.Status)) { + NumberBytesWritten = 0; + try_return(RC); + } + + if(!Res2Acq) { + // Acquiring and immediately dropping the resource serializes + // us behind any other writes taking place (either from the + // lazy writer or modified page writer). + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE ); + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + } + + // Attempt the purge and ignore the return code + MmPrint((" CcPurgeCacheSection()\n")); + CcPurgeCacheSection(&(NtReqFcb->SectionObject), &ByteOffset, + NumberBytesWritten, FALSE); + NumberBytesWritten = 0; + // We are finished with our flushing and purging + if(PtrResourceAcquired) { + UDFReleaseResource(PtrResourceAcquired); + PtrResourceAcquired = NULL; + } + } + + // Determine if we were called by the lazywriter. + // We reuse 'IsThisADeferredWrite' here to decrease stack usage + IsThisADeferredWrite = (NtReqFcb->LazyWriterThreadID == (uint32)PsGetCurrentThread()); + + // Acquire the appropriate FCB resource + if(PagingIo) { + // PagingIoResource is already acquired exclusive + // on LazyWrite condition (see UDFAcqLazyWrite()) + ASSERT(NonBufferedIo); + if(!IsThisADeferredWrite) { + if(!Res2Acq) { + // Try to acquire the FCB PagingIoResource exclusive + if(!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + } + } else { + // Try to acquire the FCB MainResource shared + if(NonBufferedIo) { + if(!Res2Acq) { + if(!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { + //if(!UDFAcquireSharedWaitForExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + } else { + if(!Res1Acq) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + //if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + PtrResourceAcquired = &(NtReqFcb->MainResource); + } + } + // Remember the resource that was acquired + } + + // Set the flag indicating if Fast I/O is possible + NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); +/* if(NtReqFcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible) { + NtReqFcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable; + }*/ + + if ( (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) && + (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL)) { + + // This clause determines if the top level request was + // in the FastIo path. + if ((ULONG)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG) { + + PIO_STACK_LOCATION IrpStack; + ASSERT( TopIrp->Type == IO_TYPE_IRP ); + IrpStack = IoGetCurrentIrpStackLocation(TopIrp); + + // Finally this routine detects if the Top irp was a + // write to this file and thus we are the writethrough. + if ((IrpStack->MajorFunction == IRP_MJ_WRITE) && + (IrpStack->FileObject->FsContext == FileObject->FsContext)) { + + RecursiveWriteThrough = TRUE; + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_WRITE_THROUGH; + } + } + } + + // Here is the deal with ValidDataLength and FileSize: + // + // Rule 1: PagingIo is never allowed to extend file size. + // + // Rule 2: Only the top level requestor may extend Valid + // Data Length. This may be paging IO, as when a + // a user maps a file, but will never be as a result + // of cache lazy writer writes since they are not the + // top level request. + // + // Rule 3: If, using Rules 1 and 2, we decide we must extend + // file size or valid data, we take the Fcb exclusive. + + // Check whether the current request will extend the file size, + // or the valid data length (if the FSD supports the concept of a + // valid data length associated with the file stream). In either case, + // inform the Cache Manager at this time using CcSetFileSizes() about + // the new file length. Note that real FSD implementations will have to + // first allocate enough on-disk space at this point (before they + // inform the Cache Manager about the new size) to ensure that the write + // will subsequently not fail due to lack of disk space. + + OldVDL = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart; + ZeroBlock = (ByteOffset.QuadPart > OldVDL); + + if (!PagingIo && + !RecursiveWriteThrough && + !IsThisADeferredWrite) { + + BOOLEAN ExtendFS; + + ExtendFS = (ByteOffset.QuadPart + TruncatedLength > NtReqFcb->CommonFCBHeader.FileSize.QuadPart); + + if( WriteToEOF || ZeroBlock || ExtendFS) { + // we are extending the file; + + if(!CanWait) + try_return(RC = STATUS_PENDING); +// CanWait = TRUE; + // Release any resources acquired above ... + if (PtrResourceAcquired2) { + UDFReleaseResource(PtrResourceAcquired2); + PtrResourceAcquired2 = NULL; + } + if (PtrResourceAcquired) { + UDFReleaseResource(PtrResourceAcquired); + PtrResourceAcquired = NULL; + } + if(!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + VcbAcquired = TRUE; + if(!Res1Acq) { + // Try to acquire the FCB MainResource exclusively + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + PtrResourceAcquired = &(NtReqFcb->MainResource); + } + + if(!Res2Acq) { + // allocate space... + AdPrint((" Try to acquire PagingIoRes\n")); + UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), TRUE ); + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + AdPrint((" PagingIoRes Ok, Resizing...\n")); + + if(ExtendFS) { + RC = UDFResizeFile__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart + TruncatedLength); + + if(!NT_SUCCESS(RC)) { + if(PtrResourceAcquired2) { + UDFReleaseResource(&(NtReqFcb->PagingIoResource)); + PtrResourceAcquired2 = NULL; + } + try_return(RC); + } + Resized = TRUE; + // ... and inform the Cache Manager about it + NtReqFcb->CommonFCBHeader.FileSize.QuadPart = ByteOffset.QuadPart + TruncatedLength; + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); + if(!Vcb->LowFreeSpace) { + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart += (PAGE_SIZE*9-1); + } else { + NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart += (PAGE_SIZE-1); + } + NtReqFcb->CommonFCBHeader.AllocationSize.LowPart &= ~(PAGE_SIZE-1); + } + + KdPrint(("UDFCommonWrite: Set size %x (alloc size %x)\n", ByteOffset.LowPart + TruncatedLength, NtReqFcb->CommonFCBHeader.AllocationSize.LowPart)); + if (CcIsFileCached(FileObject)) { + if(ExtendFS) { + MmPrint((" CcSetFileSizes()\n")); + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + } + // Attempt to Zero newly added fragment + // and ignore the return code + // This should be done to inform cache manager + // that given extent has no cached data + // (Otherwise, CM sometimes thinks that it has) + if(ZeroBlock) { + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + ThPrint((" UDFZeroDataEx(1)\n")); + UDFZeroDataEx(NtReqFcb, + OldVDL, + /*ByteOffset.QuadPart*/ NtReqFcb->CommonFCBHeader.FileSize.QuadPart - OldVDL, + CanWait, Vcb, FileObject); +#ifdef UDF_DBG + ZeroBlockDone = TRUE; +#endif //UDF_DBG + } + } + if (PtrResourceAcquired2) { + UDFReleaseResource(PtrResourceAcquired2); + PtrResourceAcquired2 = NULL; + } + + // Inform any pending IRPs (notify change directory). + if(UDFIsAStream(Fcb->FileInfo)) { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_STREAM_SIZE, + FILE_ACTION_MODIFIED_STREAM); + } else { + UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, + FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + } + } + + } + +#ifdef UDF_DISABLE_SYSTEM_CACHE_MANAGER + NonBufferedIo = TRUE; +#endif + if(Fcb && Fcb->FileInfo && Fcb->FileInfo->Dloc) { + AdPrint(("UDFCommonWrite: DataLoc %x, Mapping %x\n", Fcb->FileInfo->Dloc->DataLoc, Fcb->FileInfo->Dloc->DataLoc.Mapping)); + } + + // Branch here for cached vs non-cached I/O + if (!NonBufferedIo) { + + // The caller wishes to perform cached I/O. Initiate caching if + // this is the first cached I/O operation using this file object + if (!FileObject->PrivateCacheMap) { + // This is the first cached I/O operation. You must ensure + // that the FCB Common FCB Header contains valid sizes at this time + KdPrint(("UDFCommonWrite: Init system cache\n")); + MmPrint((" CcInitializeCacheMap()\n")); + CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)(&(NtReqFcb->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(UDFGlobalData.CacheMgrCallBacks), // callbacks + NtReqFcb); // The context used in callbacks + MmPrint((" CcSetReadAheadGranularity()\n")); + CcSetReadAheadGranularity(FileObject, Vcb->SystemCacheGran); + + } + + if(ZeroBlock && !ZeroBlockDone) { + ThPrint((" UDFZeroDataEx(2)\n")); + UDFZeroDataEx(NtReqFcb, + OldVDL, + /*ByteOffset.QuadPart*/ ByteOffset.QuadPart + TruncatedLength - OldVDL, + CanWait, Vcb, FileObject); + if(ByteOffset.LowPart & (PAGE_SIZE-1)) { + } + } + + WriteFileSizeToDirNdx = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_WRITE_THROUGH) ? + TRUE : FALSE; + // Check and see if this request requires a MDL returned to the caller + if (IrpSp->MinorFunction & IRP_MN_MDL) { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + MmPrint((" CcPrepareMdlWrite()\n")); +// CcPrepareMdlWrite(FileObject, &ByteOffset, TruncatedLength, &(Irp->MdlAddress), &(Irp->IoStatus)); +// NumberBytesWritten = Irp->IoStatus.Information; +// RC = Irp->IoStatus.Status; + + NumberBytesWritten = 0; + RC = STATUS_INVALID_PARAMETER; + + try_return(RC); + } + + if(NtReqFcb->SectionObject.DataSectionObject && + TruncatedLength >= 0x10000 && + ByteOffset.LowPart && + !(ByteOffset.LowPart & 0x00ffffff)) { + + //if(WinVer_Id() < WinVer_2k) { + //LARGE_INTEGER flush_offs; + //flush_offs.QuadPart = ByteOffset.QuadPart - 0x100*0x10000; + MmPrint((" CcFlushCache() 16Mb\n")); + //CcFlushCache(&(NtReqFcb->SectionObject), &ByteOffset, 0x100*0x10000, &(Irp->IoStatus)); + + // there was a nice idea: flush just previous part. But it doesn't work + CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &(Irp->IoStatus)); + //} + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + // First though, we need a buffer pointer (address) that is valid + + // We needn't call CcZeroData 'cause udf_info.cpp will care about it + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) + try_return(RC = STATUS_INVALID_USER_BUFFER); + ASSERT(SystemBuffer); + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + PerfPrint(("UDFCommonWrite: CcCopyWrite %x bytes at %x\n", TruncatedLength, ByteOffset.LowPart)); + MmPrint((" CcCopyWrite()\n")); + if(!CcCopyWrite(FileObject, &(ByteOffset), TruncatedLength, CanWait, SystemBuffer)) { + // The caller was not prepared to block and data is not immediately + // available in the system cache + // Mark Irp Pending ... + try_return(RC = STATUS_PENDING); + } + + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + // We have the data + RC = STATUS_SUCCESS; + NumberBytesWritten = TruncatedLength; + + try_return(RC); + + } else { + + MmPrint((" Write NonBufferedIo\n")); + + // We needn't call CcZeroData here (like in Fat driver) + // 'cause we've already done it above + // (see call to UDFZeroDataEx() ) + if (!RecursiveWriteThrough && + !IsThisADeferredWrite && + (OldVDL < ByteOffset.QuadPart)) { +#ifdef UDF_DBG + ASSERT(!ZeroBlockDone); +#endif //UDF_DBG + UDFZeroDataEx(NtReqFcb, + OldVDL, + /*ByteOffset.QuadPart*/ ByteOffset.QuadPart - OldVDL, + CanWait, Vcb, FileObject); + } + if(OldVDL < (ByteOffset.QuadPart + TruncatedLength)) { + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = ByteOffset.QuadPart + TruncatedLength; + } + +#if 1 + if((ULONG)TopIrp == FSRTL_MOD_WRITE_TOP_LEVEL_IRP) { + KdPrint(("FSRTL_MOD_WRITE_TOP_LEVEL_IRP => CanWait\n")); + CanWait = TRUE; + } else + if((ULONG)TopIrp == FSRTL_CACHE_TOP_LEVEL_IRP) { + KdPrint(("FSRTL_CACHE_TOP_LEVEL_IRP => CanWait\n")); + CanWait = TRUE; + } + + if(NtReqFcb->AcqSectionCount || NtReqFcb->AcqFlushCount) { + MmPrint((" AcqCount (%d/%d)=> CanWait ?\n", NtReqFcb->AcqSectionCount, NtReqFcb->AcqFlushCount)); + CanWait = TRUE; + } else + {} +/* if((TopIrp != Irp)) { + KdPrint(("(TopIrp != Irp) => CanWait\n")); + CanWait = TRUE; + } else*/ +#endif + if(KeGetCurrentIrql() > PASSIVE_LEVEL) { + MmPrint((" !PASSIVE_LEVEL\n")); + CanWait = FALSE; + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FORCED_POST; + } + // Successful check will cause WCache lock + if(!CanWait && UDFIsFileCached__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, TRUE)) { + KdPrint(("UDFCommonWrite: Cached => CanWait\n")); + CacheLocked = TRUE; + CanWait = TRUE; + } + // Send the request to lower level drivers + if(!CanWait) { + KdPrint(("UDFCommonWrite: Post physical write %x bytes at %x\n", TruncatedLength, ByteOffset.LowPart)); + + try_return(RC = STATUS_PENDING); + } + + if(!Res2Acq) { + if(UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource))) { + PtrResourceAcquired2 = &(NtReqFcb->PagingIoResource); + } + } + + PerfPrint(("UDFCommonWrite: Physical write %x bytes at %x\n", TruncatedLength, ByteOffset.LowPart)); + + // Lock the callers buffer + if (!NT_SUCCESS(RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, TruncatedLength))) { + try_return(RC); + } + + SystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp); + if(!SystemBuffer) { + try_return(RC = STATUS_INVALID_USER_BUFFER); + } + NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + RC = UDFWriteFile__(Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, + CacheLocked, (PCHAR)SystemBuffer, &NumberBytesWritten); + + UDFUnlockCallersBuffer(PtrIrpContext, Irp, SystemBuffer); + +#ifdef _MSC_VER +/* FIXME */ + if(PagingIo) { + CollectStatistics(Vcb, UserDiskWrites); + } else { + CollectStatistics2(Vcb, NonCachedDiskWrites); + } +#endif + WriteFileSizeToDirNdx = TRUE; + + try_return(RC); + } + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + if(CacheLocked) { + WCacheEODirect__(&(Vcb->FastCache), Vcb); + } + + // Release any resources acquired here ... + if(PtrResourceAcquired2) { + UDFReleaseResource(PtrResourceAcquired2); + } + if(PtrResourceAcquired) { + if(NtReqFcb && + (PtrResourceAcquired == + &(NtReqFcb->MainResource))) { + UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); + } + UDFReleaseResource(PtrResourceAcquired); + } + if(VcbAcquired) { + UDFReleaseResource(&(Vcb->VCBResource)); + } + + // Post IRP if required + if(RC == STATUS_PENDING) { + + // Lock the callers buffer here. Then invoke a common routine to + // perform the post operation. + if (!(IrpSp->MinorFunction & IRP_MN_MDL)) { + RC = UDFLockCallersBuffer(PtrIrpContext, Irp, FALSE, WriteLength); + ASSERT(NT_SUCCESS(RC)); + } + if(PagingIo) { + if(Res1Acq) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES1_ACQ; + } + if(Res2Acq) { + PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_RES2_ACQ; + } + } + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = UDFPostRequest(PtrIrpContext, Irp); + + } else { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { + FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + NumberBytesWritten; + } + // If the write completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a write was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) { + Ccb->CCBFlags |= UDF_CCB_MODIFIED; + // If the file size was changed, set a flag in the FCB indicating that + // this occurred. + FileObject->Flags |= FO_FILE_MODIFIED; + if(Resized) { + if(!WriteFileSizeToDirNdx) { + FileObject->Flags |= FO_FILE_SIZE_CHANGED; + } else { + ASize = UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); + UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &ASize); + } + } + // Update ValidDataLength + if(!IsThisADeferredWrite && + NtReqFcb) { + if(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart < (ByteOffset.QuadPart + NumberBytesWritten)) { + + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = + min(NtReqFcb->CommonFCBHeader.FileSize.QuadPart, + ByteOffset.QuadPart + NumberBytesWritten); + } + } + } + + // If the request failed, and we had done some nasty stuff like + // extending the file size (including informing the Cache Manager + // about the new file size), and allocating on-disk space etc., undo + // it at this time. + + // Can complete the IRP here if no exception was encountered + if(!_SEH2_AbnormalTermination() && + Irp) { + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = NumberBytesWritten; + // complete the IRP + MmPrint((" Complete Irp, MDL=%x\n", Irp->MdlAddress)); + if(Irp->MdlAddress) { + UDFTouch(Irp->MdlAddress); + } + IoCompleteRequest(Irp, IO_DISK_INCREMENT); + } + // Free up the Irp Context + UDFReleaseIrpContext(PtrIrpContext); + + } // can we complete the IRP ? + } _SEH2_END; // end of "__finally" processing + + KdPrint(("\n")); + return(RC); +} // end UDFCommonWrite() + +/************************************************************************* +* +* Function: UDFDeferredWriteCallBack() +* +* Description: +* Invoked by the cache manager in the context of a worker thread. +* Typically, you can simply post the request at this point (just +* as you would have if the original request could not block) to +* perform the write in the context of a system worker thread. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +NTAPI +UDFDeferredWriteCallBack( + IN PVOID Context1, // Should be PtrIrpContext + IN PVOID Context2 // Should be Irp + ) +{ + KdPrint(("UDFDeferredWriteCallBack\n")); + // We should typically simply post the request to our internal + // queue of posted requests (just as we would if the original write + // could not be completed because the caller could not block). + // Once we post the request, return from this routine. The write + // will then be retried in the context of a system worker thread + UDFPostRequest((PtrUDFIrpContext)Context1, (PIRP)Context2); + +} // end UDFDeferredWriteCallBack() + +/************************************************************************* +* +*************************************************************************/ + +#define USE_CcCopyWrite_TO_ZERO + +VOID +UDFPurgeCacheEx_( + PtrUDFNTRequiredFCB NtReqFcb, + LONGLONG Offset, + LONGLONG Length, +//#ifndef ALLOW_SPARSE + BOOLEAN CanWait, +//#endif //ALLOW_SPARSE + PVCB Vcb, + PFILE_OBJECT FileObject + ) +{ + ULONG Off_l; +#ifdef USE_CcCopyWrite_TO_ZERO + ULONG PgLen; +#endif //USE_CcCopyWrite_TO_ZERO + + // We'll just purge cache section here, + // without call to CcZeroData() + // 'cause udf_info.cpp will care about it + +#define PURGE_BLOCK_SZ 0x10000000 + + // NOTE: if FS engine doesn't suport + // sparse/unrecorded areas, CcZeroData must be called + // In this case we'll see some recursive WRITE requests + + _SEH2_TRY { + MmPrint((" UDFPurgeCacheEx_(): Offs: %I64x, ", Offset)); + MmPrint((" Len: %lx\n", Length)); + SECTION_OBJECT_POINTERS* SectionObject = &(NtReqFcb->SectionObject); + if(Length) { + LONGLONG Offset0, OffsetX, VDL; + + Offset0 = Offset; + if((Off_l = ((ULONG)Offset0 & (PAGE_SIZE-1)))) { + // Offset, Offset0 + // v + // ...|dddddddddddd00000|.... + // |<- Off_l ->| +#ifndef USE_CcCopyWrite_TO_ZERO + *((PULONG)&Offset0) &= ~(PAGE_SIZE-1); + MmPrint((" CcFlushCache(s) Offs %I64x, Len %x\n", Offset0, Off_l)); + CcFlushCache( SectionObject, (PLARGE_INTEGER)&Offset0, Off_l, NULL ); +#else //USE_CcCopyWrite_TO_ZERO + // ...|ddddd000000000000|.... + // |<- PgLen ->| + PgLen = PAGE_SIZE - Off_l; /*(*((PULONG)&Offset) & (PAGE_SIZE-1))*/ + // + if(PgLen > Length) + PgLen = (ULONG)Length; + + MmPrint((" ZeroCache (CcWrite) Offs %I64x, Len %x\n", Offset, PgLen)); +#ifdef DBG + if(FileObject && Vcb) { + + ASSERT(CanWait); +#endif //DBG + if (PgLen) { + if (SectionObject->SharedCacheMap) { + CcCopyWrite(FileObject, (PLARGE_INTEGER)&Offset, PgLen, TRUE || CanWait, Vcb->ZBuffer); + } + Offset += PgLen; + Length -= PgLen; + } +#ifdef DBG + } else { + MmPrint((" Can't use CcWrite to zero cache\n")); + } +#endif //DBG +#endif //USE_CcCopyWrite_TO_ZERO + } + VDL = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart; + OffsetX = Offset+Length; + if((Off_l = ((ULONG)OffsetX & (PAGE_SIZE-1)))) { + + if(OffsetX < VDL) { +#ifndef USE_CcCopyWrite_TO_ZERO + Off_l = ( (ULONG)(VDL-OffsetX) > PAGE_SIZE ) ? + (PAGE_SIZE - Off_l) : + ((ULONG)(VDL-OffsetX)); + *((PULONG)&OffsetX) &= ~(PAGE_SIZE-1); + MmPrint((" CcFlushCache(e) Offs %I64x, Len %x\n", OffsetX, Off_l)); + CcFlushCache( SectionObject, (PLARGE_INTEGER)&OffsetX, Off_l, NULL ); +#else //USE_CcCopyWrite_TO_ZERO + if(VDL - OffsetX > PAGE_SIZE) { + PgLen = (ULONG)OffsetX & ~(PAGE_SIZE-1); + } else { + PgLen = (ULONG)(VDL - OffsetX) & ~(PAGE_SIZE-1); + } + // ...|000000000000ddddd|.... + // |<- PgLen ->| + MmPrint((" ZeroCache (CcWrite - 2) Offs %I64x, Len %x\n", OffsetX, PgLen)); +#ifdef DBG + if(FileObject && Vcb) { + ASSERT(CanWait); +#endif //DBG + if (SectionObject->SharedCacheMap) { + CcCopyWrite(FileObject, (PLARGE_INTEGER)&OffsetX, PgLen, TRUE || CanWait, Vcb->ZBuffer); + } + Length -= PgLen; +#ifdef DBG + } else { + MmPrint((" Can't use CcWrite to zero cache (2)\n")); + } +#endif //DBG +#endif //USE_CcCopyWrite_TO_ZERO + } + } +#ifndef USE_CcCopyWrite_TO_ZERO + do +#else //USE_CcCopyWrite_TO_ZERO + while(Length) +#endif //USE_CcCopyWrite_TO_ZERO + { + MmPrint((" CcPurgeCacheSection()\n")); + if(PURGE_BLOCK_SZ > Length) { + CcPurgeCacheSection(SectionObject, (PLARGE_INTEGER)&Offset, + (ULONG)Length, FALSE); + /* + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart += Length; + ASSERT(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart <= + NtReqFcb->CommonFCBHeader.FileSize.QuadPart); + MmPrint((" CcFlushCache()\n")); + CcFlushCache( SectionObject, (PLARGE_INTEGER)&Offset, (ULONG)Length, NULL ); + */ +#ifndef ALLOW_SPARSE + // UDFZeroFile__( +#endif //ALLOW_SPARSE + break; + } else { + CcPurgeCacheSection(SectionObject, (PLARGE_INTEGER)&Offset, + PURGE_BLOCK_SZ, FALSE); + /* + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart += PURGE_BLOCK_SZ; + ASSERT(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart <= + NtReqFcb->CommonFCBHeader.FileSize.QuadPart); + MmPrint((" CcFlushCache()\n")); + CcFlushCache( SectionObject, (PLARGE_INTEGER)&Offset, (ULONG)Length, NULL ); + */ +#ifndef ALLOW_SPARSE + // UDFZeroFile__( +#endif //ALLOW_SPARSE + Length -= PURGE_BLOCK_SZ; + Offset += PURGE_BLOCK_SZ; + } + } +#ifndef USE_CcCopyWrite_TO_ZERO + while(Length); +#endif //USE_CcCopyWrite_TO_ZERO + if(VDL < Offset) + NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = Offset; + } + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +} // end UDFPurgeCacheEx_() + +#endif //UDF_READ_ONLY_BUILD