reactos/drivers/filesystems/udfs/Include/phys_lib.cpp
2021-06-11 15:33:08 +03:00

4386 lines
165 KiB
C++

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*
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
)
{
UDFPrint(("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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T IOBytes,
IN uint32 Flags
)
{
OSSTATUS RC = STATUS_SUCCESS;
uint32 i, j;
SIZE_T mask;
uint32 lba0, len, lba1;
PUCHAR tmp_buff;
PUCHAR p;
PCHAR cached_block;
SIZE_T 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 = (SIZE_T)_Vcb;
if(Flags & PH_EX_WRITE) {
UDFPrint(("IO-Write-Verify\n"));
RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_VCB_IN_RETLEN);
} else {
UDFPrint(("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) {
UDFPrint(("Can't remap\n"));
UDFReleaseResource(&(Vcb->IoResource));
return RC;
}
if(Flags & PH_EX_WRITE) {
UDFPrint(("Write failed, try relocation\n"));
} else {
if(Vcb->Modified) {
UDFPrint(("Read failed, try relocation\n"));
} else {
UDFPrint(("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) {
UDFPrint((" can't alloc tmp\n"));
UDFReleaseResource(&(Vcb->IoResource));
return STATUS_DEVICE_DATA_ERROR;
}
free_tmp = TRUE;
}
for(i=0; i<len; i++) {
if(!Vcb->SparingCountFree) {
UDFPrint((" no more free spare blocks, abort verification\n"));
break;
}
UDFPrint((" 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) {
UDFPrint((" remap single write\n"));
UDFPrint((" try del from verify cache @ %x, %x\n", lba0, len));
UDFVForget(Vcb, len, UDFRelocateSector(Vcb, lba0), 0);
goto do_remap;
} else {
UDFPrint((" recover and remap single read\n"));
}
}
}
p = tmp_buff+(j<<Vcb->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))) {
UDFPrint((" 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)) {
UDFPrint((" unused @ %x\n", lba0+i));
zero = TRUE;
}
}
if(!zero && Vcb->ZSBM_Bitmap) {
if(UDFGetZeroBit((uint32*)(Vcb->ZSBM_Bitmap), lba0+i)) {
UDFPrint((" 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 = (SIZE_T)_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) {
UDFPrint((" 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 = (SIZE_T)_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)) {
UDFPrint((" 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 = (SIZE_T)_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)) {
/*
UDFPrint((" 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);
*/
UDFPrint((" 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) {
UDFPrint((" try del from verify cache @ %x\n", lba0+i));
RC = UDFVForget(Vcb, 1, UDFRelocateSector(Vcb, lba0+i), 0);
}
if(!packet_ok || need_remap) {
UDFPrint((" 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) {
UDFPrint((" forget Z packet @ %x\n", lba1));
UDFUnmapRange(Vcb, lba1, Vcb->SparingBlockSize);
RC = STATUS_SUCCESS;
} else {
do_remap:
for(j=0; j<3; j++) {
UDFPrint((" remap packet @ %x\n", lba1));
RC = UDFRemapPacket(Vcb, lba1, FALSE);
if(!OS_SUCCESS(RC)) {
if(RC == STATUS_SHARING_VIOLATION) {
UDFPrint((" remap2\n"));
// remapped location have died
RC = UDFRemapPacket(Vcb, lba1, TRUE);
}
if(!OS_SUCCESS(RC)) {
// packet cannot be remapped :(
RC = STATUS_DEVICE_DATA_ERROR;
}
}
UDFPrint((" remap status %x\n", RC));
if(OS_SUCCESS(RC)) {
// write to remapped area
tmp_wb = (SIZE_T)_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);
UDFPrint((" write status %x\n", RC));
if(RC != STATUS_SUCCESS) {
// will be remapped
UDFPrint((" retry remap\n"));
// Note: when remap of already remapped block is requested, verify of
// entire sparing are will be performed.
} else {
UDFPrint((" remap OK\n"));
break;
}
} else {
UDFPrint((" failed remap\n"));
break;
}
} // for
}
if(!OS_SUCCESS(RC) && !OS_SUCCESS(final_RC)) {
final_RC = RC;
}
} else {
UDFPrint((" NO remap for @ %x\n", (lba0+i) & ~mask));
}
j=0;
}
}
if(free_tmp) {
DbgFreePool(tmp_buff);
}
tmp_wb = (SIZE_T)_Vcb;
if(Flags & PH_EX_WRITE) {
UDFPrint(("IO-Write-Verify (2)\n"));
//RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN);
} else {
UDFPrint(("IO-Read-Verify (2)\n"));
RC = UDFTRead(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN);
}
(*IOBytes) = tmp_wb;
UDFPrint(("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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T 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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T 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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T 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;
UDFPrint(("TWrite %x (%x)\n", LBA, BCount));
#ifdef _BROWSE_UDF_
if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) {
UDFPrint(("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) {
UDFPrint(("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)) {
UDFPrint(("prepare failed\n"));
try_return(RC);
}
if(Flags & PH_VCB_IN_RETLEN) {
(*WrittenBytes) = (ULONG_PTR)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++) {
SIZE_T _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)) {
UDFPrint(("prepare failed (2)\n"));
break;
}
if(Flags & PH_VCB_IN_RETLEN) {
_WrittenBytes = (ULONG_PTR)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;
UDFPrint(("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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T 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) = (SIZE_T)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++) {
SIZE_T _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 = (SIZE_T)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 SIZE_T Length,
IN uint32 LBA,
OUT PSIZE_T 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++) {
SIZE_T _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) {
UDFPrint(("Non-MRW disk. Skip setting MRW_MODE\n"));
return STATUS_SUCCESS;
}
UDFPrint(("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;
}
UDFPrint(("GET_MRW_MODE ok (current %x)\n", MRWPage.AddressMode));
MRWPage.AddressMode = Vcb->MRWStatus ? 0 : MrwPage_use_GAA;
UDFPrint(("SET_MRW_MODE %x\n", MRWPage.AddressMode));
RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_MRW_MODE, Vcb->TargetDeviceObject,
(PVOID)&MRWPage,sizeof(MRWPage),
NULL,0,
FALSE, NULL);
UDFPrint(("SET_MRW_MODE status %x\n", RC));
return STATUS_SUCCESS;
} // end UDFSetMRWMode()
OSSTATUS
UDFDoOPC(
IN PVCB Vcb
)
{
OSSTATUS RC;
if(Vcb->OPCNum && !Vcb->OPCDone) {
UDFPrint(("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)) {
UDFPrint(("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; i<BCount; i++) {
if(UDFGetBit((uint32*)(Vcb->BSBM_Bitmap), Lba+i)) {
UDFPrint(("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)
) {
UDFPrint(("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;
UDFPrint(("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)) {
//UDFPrint(("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)) {
UDFPrint(("!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
UDFPrint(("!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
UDFPrint((" 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:
UDFPrint((" 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;
SIZE_T 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) ) {
UDFPrint(("DVD cont. fmt, LBA+BCount<=NWA, exiting\n"));
return STATUS_SUCCESS;
}
if((Vcb->MRWStatus != DiscInfo_BGF_Interrupted) &&
(Lba <= (Vcb->LastLBA+1)) ) {
UDFPrint(("!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
UDFPrint(("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)) {
UDFPrint(("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);
UDFPrint(("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;
UDFPrint(("Seems, BGFormat already restarted\n"));
Vcb->MRWStatus = DiscInfo_BGF_InProgress;
}
}
}
}
} else {
RC = STATUS_SUCCESS;
}
UDFPrint(("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;
UDFPrint(("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;
UDFPrint(("Fmt retry\n"));
}
#endif //_BROWSE_UDF_
if(!OS_SUCCESS(RC)) {
BrutePoint();
UDFPrint(("Fmt break on ERROR\n"));
break;
}
UDFUpdateNWA(Vcb, fLba, BCount, RC);
}
}
} else {
UDFPrint((" no special processing\n"));
}
return RC;
}
#endif //UDF_READ_ONLY_BUILD
UDFPrint((" 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) {
UDFPrint(("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) {
UDFPrint(("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);
UDFPrint(("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) {
UDFPrint(("Error recovery: reserve retry count for write retries\n"));
(*retry) = UDF_WRITE_MAX_RETRY*3;
} else
if((*retry) == UDF_WRITE_MAX_RETRY) {
UDFPrint(("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)) {
UDFPrint(("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) {
UDFPrint(("Error recovery: retry read after small delay\n"));
try_return(status = STATUS_SUCCESS);
}
}
UDFPrint(("Error recovery: sync cache\n"));
// ...flush device cache...
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
UDFPrint(("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) {
UDFPrint(("Error recovery: invalid command sequence on read\n"));
delay.QuadPart = -1000000; // 0.1 sec
KeDelayExecutionThread(KernelMode, FALSE, &delay);
UDFPrint(("Error recovery: sync cache\n"));
// ...flush device cache...
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
UDFPrint(("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)) {
UDFPrint(("Using incremental seek workaround...\n"));
Vcb->IncrementalSeekState = INCREMENTAL_SEEK_WORKAROUND;
try_return(status = STATUS_SUCCESS);
} else {
UDFPrint(("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) {
UDFPrint(("bad Session in streaming mode. Lba %x, try fix-up\n", Lba));
// ...flush device cache...
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
UDFPrint(("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) {
UDFPrint(("Seek error\n"));
if(Vcb->CompatFlags & UDF_VCB_IC_BAD_RW_SEEK) {
UDFPrint(("try recovery\n"));
goto bad_rw_seek_recovery;
}
UDFPrint(("map error to STATUS_NONEXISTENT_SECTOR\n"));
status = STATUS_NONEXISTENT_SECTOR;
}
UDFPrint(("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) {
UDFPrint(("bad LBA %x in streaming mode, try fix-up\n", Lba));
// ...flush device cache...
UDFSyncCache(Vcb);
try_return(status = STATUS_SUCCESS);
}
if((Lba+BCount >= Vcb->LastLBA) &&
(Vcb->MRWStatus == DiscInfo_BGF_Interrupted)) {
UDFPrint(("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)) {
UDFPrint(("Retry\n"));
}
#endif //UDF_DBG
} _SEH2_END;
if(!OS_SUCCESS(status)) {
if((Vcb->MountPhErrorCount != (ULONG)-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 {
UDFPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA));
}
}
if(bm) {
UDFSetBit(bm, Lba);
UDFPrint(("Set BB @ %#x\n", Lba));
}
#ifdef _BROWSE_UDF_
bm = (uint32*)(Vcb->FSBM_Bitmap);
if(bm) {
UDFSetUsedBit(bm, Lba);
UDFPrint(("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)) {
UDFPrint(("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)) {
UDFPrint(("ReadCapacity failed.\n"));
if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD;
}
} else {
UDFPrint(("ReadCapacity ok.\n"));
UDFPrint(("Last possible LBA %#x.\n", CapacityBuffer.LogicalBlockAddress));
if(!(CapacityBuffer.LogicalBlockAddress & 0xc0000000) &&
(CapacityBuffer.LogicalBlockAddress != 0x7fffffff)) {
// good value from ReadCapacity
UDFPrint(("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;
UDFPrint(("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) {
UDFPrint(("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
UDFPrint(("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
UDFPrint(("+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) {
UDFPrint(("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;
}
}
UDFPrint(("MRW state %x\n", Vcb->MRWStatus));
if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
if(Vcb->PhMediaCapFlags & CdCapFlags_RandomWritable) {
UDFPrint(("DVD-RW Rewritable\n"));
ForceFP = TRUE;
} else
if((DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty) {
UDFPrint(("Blank DVD-RW\n"));
ForceFP = TRUE;
} else {
UDFPrint(("DVD-RW Sequential\n"));
NotFP = TRUE;
}
} else
if(CdrwIsDvdOverwritable(Vcb->MediaClassEx)) {
UDFPrint(("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) {
UDFPrint(("Try read 1st track...\n"));
Vcb->LastTrackNum = 1;
}
UDFPrint(("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);
UDFPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA));
}
}
UDFPrint(("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) {
UDFPrint(("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) {
UDFPrint(("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)) {
UDFPrint(("TrkInfo: set NWA to LastLba (%x)\n", Vcb->TrackMap[TrackNumber].LastLba));
Vcb->TrackMap[TrackNumber].NWA =
Vcb->TrackMap[TrackNumber].LastLba;
} else {
UDFPrint(("TrkInfo: set NWA to INV (1)\n"));
Vcb->TrackMap[TrackNumber].NWA = 0;
Vcb->TrackMap[TrackNumber].NWA_V = 0;
}
} else {
if(!(TrackInfoOut->NextWriteLBA & 0x80000000)) {
UDFPrint(("TrkInfo: Good NWA (%x)\n", TrackInfoOut->NextWriteLBA));
Vcb->TrackMap[TrackNumber].NWA =
TrackInfoOut->NextWriteLBA;
} else {
UDFPrint(("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) {
UDFPrint(("Apply NotFP\n"));
Vcb->TrackMap[TrackNumber].DataParam &= ~TrkInfo_FP;
#ifdef DBG
TrackInfoOut->DataParam.Flags &= ~TrkInfo_FP;
#endif //DBG
} else
if(ForceFP) {
UDFPrint(("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) {
UDFPrint(("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) {
UDFPrint(("Unknown DatType, Try RAW_MOUNT\n"));
Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
}
PacketTrack |= ((TrackInfoOut->DataParam.Flags & TrkInfo_Packet) != 0);
UDFPrint(("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)) {
UDFPrint(("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)) {
UDFPrint(("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)
) {
UDFPrint((" 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);
UDFPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA));
}
TrackNumber = Vcb->LastTrackNum;
// quick formatted +RW returns bogus value
if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
UDFPrint((" 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*/
) {
UDFPrint((" track LastLBA %x != LastPossibleLBA %x, verify\n",
Vcb->TrackMap[TrackNumber].LastLba, Vcb->LastPossibleLBA));
if(Vcb->MRWStatus == DiscInfo_BGF_Complete) {
UDFPrint((" 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;
SIZE_T ReadBytes;
UDFPrint((" 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)) {
UDFPrint((" 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;
}
}
}
}
UDFPrint((" 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) {
UDFPrint((" 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 {
UDFPrint((" 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 ) {
UDFPrint((" 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;
UDFPrint(("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;(index<MAXIMUM_NUMBER_OF_SESSIONS);index++) {
/* if((toc->SessionData[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) {
UDFPrint(("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;
SIZE_T ReadBytes, i, len;
#endif //_BROWSE_UDF_
#ifdef UDF_FORMAT_MEDIA
PUDFFmtState fms = Vcb->fms;
#else
#define fms FALSE
#endif //UDF_FORMAT_MEDIA
UDFPrint(("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]) ); /* FIXME ReactOS Assume PtrOffset is not changing it's arguments? */
// 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;TocEntry<LocalTrackCount + 1;TocEntry++) {
if(toc->TrackData[TocEntry].TrackNum == TrkNum) {
Vcb->TrackMap[TrkNum].Session = Vcb->LastSession;
}
}
}
OldTrkNum = 0;
// Scan toc for first & last LBA
for(TocEntry=0;TocEntry<LocalTrackCount + 1;TocEntry++) {
#define TempMSF toc->TrackData[TocEntry].LBA
TrkNum = toc->TrackData[TocEntry].TrackNum;
#ifdef UDF_DBG
if (TrkNum >= MAXIMUM_NUMBER_OF_TRACKS &&
TrkNum != TOC_LastTrack_ID) {
UDFPrint(("UDFUseStandard: Array out of bounds\n"));
BrutePoint();
try_return(RC = STATUS_SUCCESS);
}
UDFPrint(("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;
UDFPrint(("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) {
UDFPrint(("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) {
UDFPrint(("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;TocEntry<LocalTrackCount + 1;TocEntry++) {
#define TempMSF toc->TrackData[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) {
UDFPrint(("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)) {
UDFPrint(("UDFGetBlockSize: IOCTL_DISK_GET_PARTITION_INFO failed\n"));
if(RC == STATUS_INVALID_DEVICE_REQUEST) /* ReactOS Code Change (was =) */
RC = STATUS_UNRECOGNIZED_VOLUME;
try_return(RC);
}
if(PartitionInfo->PartitionType != PARTITION_IFS) {
UDFPrint(("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;
UDFPrint(("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;
// SIZE_T 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)) {
UDFPrint((" 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) {
UDFPrint((" 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)) {
UDFPrint((" %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;
UDFPrint(("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
UDFPrint(("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_
}
UDFPrint(("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) )) {
UDFPrint(("UDF: *****************************************\n"));
UDFPrint(("UDF: ********* Our Device Driver Found ******\n"));
UDFPrint(("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)) {
UDFPrint(("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)) {
UDFPrint(("UDFGetDiskInfo: UDF_VCB_IC_SYNCCACHE_BEFORE_READ\n"));
Vcb->CompatFlags |= UDF_VCB_IC_SYNCCACHE_BEFORE_READ;
}
if(SavedFeatures & CDRW_FEATURE_BAD_RW_SEEK) {
UDFPrint(("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) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FP_ADDRESSING_PROBLEM ?\n"));
Vcb->CompatFlags |= UDF_VCB_IC_FP_ADDR_PROBLEM;
}
if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM ?\n"));
}
if(SavedFeatures & CDRW_FEATURE_FORCE_SYNC_ON_WRITE) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FORCE_SYNC_ON_WRITE\n"));
Vcb->VCBFlags |= UDF_VCB_FLAGS_FORCE_SYNC_CACHE;
}
if(SavedFeatures & CDRW_FEATURE_BAD_DVD_LAST_LBA) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_BAD_DVD_LAST_LBA\n"));
Vcb->CompatFlags |= UDF_VCB_IC_BAD_DVD_LAST_LBA;
}
if(SavedFeatures & CDRW_FEATURE_STREAMING) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_STREAMING\n"));
}
if(SavedFeatures & CDRW_FEATURE_OPC) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_OPC -> assume OPCNum=1\n"));
Vcb->OPCNum = 1;
}
#ifdef UDF_FORMAT_MEDIA
if(SavedFeatures & CDRW_FEATURE_FULL_BLANK_ON_FORMAT) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FULL_BLANK_ON_FORMAT\n"));
if((fms->opt_probe || fms->opt_smart_f)/* &&
(fms->format_media && fms->blank_media*/) {
UDFPrint(("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;
}
UDFPrint(("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;
UDFPrint(("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 :
UDFPrint(("UDFGetDiskInfo: we shall ignore audio-disks...\n"));
try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
}
#endif //UDF_FORMAT_MEDIA
UDFPrint(("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);
UDFPrint(("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:
UDFPrint(("UDFGetDiskInfo: MediaClass R\n"));
Vcb->MediaType = MediaType_UnknownSize_CDR;
break;
case CdMediaClass_CDRW:
if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) {
UDFPrint(("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:
UDFPrint(("UDFGetDiskInfo: MediaClass RW\n"));
Vcb->MediaType = MediaType_UnknownSize_CDRW;
break;
case CdMediaClass_CDROM:
case CdMediaClass_DVDROM:
case CdMediaClass_HD_DVDROM:
case CdMediaClass_BDROM:
UDFPrint(("UDFGetDiskInfo: MediaClass ROM\n"));
Vcb->MediaType = MediaType_Unknown;
// Vcb->MediaType = MediaType_UnknownSize_CDROM;
break;
default:
UDFPrint(("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:
UDFPrint(("CdMediaClass_CDR\n"));
MediaType = MediaType_UnknownSize_CDR;
if(fms->opt_media == MT_AUTO)
fms->opt_media = MT_CDR;
break;
case CdMediaClass_DVDR:
UDFPrint(("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:
UDFPrint(("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:
UDFPrint(("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:
UDFPrint(("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:
UDFPrint(("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) {
UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on CD-RW\n"));
Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM;
}
break;
case CdMediaClass_DVDRW:
UDFPrint((" 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:
UDFPrint((" 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:
UDFPrint((" 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:
UDFPrint((" 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:
UDFPrint((" 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:
UDFPrint((" 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:
UDFPrint((" CdMediaClass_NoDiscPresent -> MediaType_NoDiscPresent\n"));
MediaType = MediaType_NoDiscPresent;
fms->opt_media = MT_none;
break;
case CdMediaClass_DoorOpen:
UDFPrint((" CdMediaClass_DoorOpen -> MediaType_DoorOpen\n"));
MediaType = MediaType_DoorOpen;
fms->opt_media = MT_none;
break;
default:
UDFPrint((" 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)) {
UDFPrint(("UDFGetDiskInfo: DVD && !CdCapFlags_RandomWritable\n"));
UDFPrint((" 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) {
UDFPrint(("UDFGetDiskInfo: do not use WriteParams\n"));
}
if(Vcb->PhMediaCapFlags & CdCapFlags_Cav) {
UDFPrint(("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 =
UDFPrint(("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)) {
UDFPrint(("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) {
UDFPrint(("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 {
UDFPrint(("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;
UDFPrint(("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; i<n; i++) {
if((WPerfDesc[i].RotationControl & LunWPerf_RotCtrl_Mask) == LunWPerf_RotCtrl_CAV) {
Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_CAV;
if(!n) {
Vcb->CurSpeed = WPerfDesc[i].WriteSpeedSupported;
n = TRUE;
UDFPrint(("Use CAV\n"));
} else {
Vcb->CurSpeed = max(WPerfDesc[i].WriteSpeedSupported, Vcb->CurSpeed);
}
UDFPrint(("supports speed %dX\n", Vcb->CurSpeed/176));
//break;
}
}
if(n) {
UDFPrint(("Set r/w speeds to %dX\n", Vcb->CurSpeed/176));
Vcb->MaxWriteSpeed =
Vcb->MaxReadSpeed = Vcb->CurSpeed;
}
}
}
} else {
Vcb->CurSpeed = max(cap->CurrentSpeed, cap->CurrentWriteSpeed);
}
UDFPrint((" 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:
UDFPrint(("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)) {
UDFPrint(("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) {
UDFPrint(("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)) {
UDFPrint(("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) {
UDFPrint(("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) {
UDFPrint(("UDFGetDiskInfo: R/O+!Blank+!RW -> !RAW\n"));
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
} else {
UDFPrint(("UDFGetDiskInfo: Blank or RW\n"));
}
}
UDFPrint(("UDF: ------------------------------------------\n"));
UDFPrint(("UDF: Media characteristics\n"));
UDFPrint(("UDF: Last session: %d\n",Vcb->LastSession));
UDFPrint(("UDF: First track in first session: %d\n",Vcb->FirstTrackNum));
UDFPrint(("UDF: First track in last session: %d\n",Vcb->FirstTrackNumLastSes));
UDFPrint(("UDF: Last track in last session: %d\n",Vcb->LastTrackNum));
UDFPrint(("UDF: First LBA in first session: %x\n",Vcb->FirstLBA));
UDFPrint(("UDF: First LBA in last session: %x\n",Vcb->FirstLBALastSes));
UDFPrint(("UDF: Last LBA in last session: %x\n",Vcb->LastLBA));
UDFPrint(("UDF: First writable LBA (NWA) in last session: %x\n",Vcb->NWA));
UDFPrint(("UDF: Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA));
UDFPrint(("UDF: blocks per frame: %x\n",1 << Vcb->WCacheBlocksPerFrameSh));
UDFPrint(("UDF: Flags: %s%s\n",
Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK ? "RAW " : "",
Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY ? "R/O " : "WR "
));
UDFPrint(("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;
UDFPrint(("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;
SIZE_T ReadBytes;
#endif //_BROWSE_UDF_
#ifdef _UDF_STRUCTURES_H_
if(Vcb->BSBM_Bitmap) {
ULONG i;
for(i=0; i<BCount; i++) {
if(UDFGetBit((uint32*)(Vcb->BSBM_Bitmap), Lba+i)) {
UDFPrint(("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;
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;
}
UDFPrint((" 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;
}
UDFPrint((" 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);
UDFPrint((" 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) {
UDFPrint((" 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)) {
UDFPrint((" 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 PSIZE_T 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 PSIZE_T ReadBytes
)
{
int8* tmp_buff;
OSSTATUS status;
SIZE_T _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 PSIZE_T ReadBytes
)
{
uint32 i, l, Lba, BS=Vcb->BlockSize;
uint32 BSh=Vcb->BlockSizeBits;
OSSTATUS status;
SIZE_T _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<<BSh;
Length -= to_read<<BSh;
Lba += to_read;
i -= to_read;
}
// read head of the last sector
if(!Length) return STATUS_SUCCESS;
status = UDFReadInSector(Vcb, Translate, Lba, 0, Length, Direct, Buffer, &_ReadBytes);
(*ReadBytes) += _ReadBytes;
return status;
} // end UDFReadData()
#endif //_BROWSE_UDF_
#ifndef UDF_READ_ONLY_BUILD
/*
This routine writes physical sectors. This routine supposes Lba & Length
alignment on WriteBlock (packet) size.
*/
OSSTATUS
UDFWriteSectors(
IN PVCB Vcb,
IN BOOLEAN Translate, // Translate Logical to Physical
IN uint32 Lba,
IN uint32 BCount,
IN BOOLEAN Direct, // Disable access to non-cached data
IN int8* Buffer,
OUT PSIZE_T WrittenBytes
)
{
OSSTATUS status;
#ifdef _BROWSE_UDF_
if(!Vcb->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;
SIZE_T _ReadBytes;
(*WrittenBytes) = 0;
buffer = DbgAllocatePool(NonPagedPool, Vcb->WriteBlockSize);
if(!buffer) return STATUS_INSUFFICIENT_RESOURCES;
status = UDFTRead(Vcb, Buffer, BCount<<Vcb->BlockSizeBits, (Lba&~(Vcb->WriteBlockSize-1), _WrittenBytes);*/
#ifdef UDF_DBG
status = UDFTWrite(Vcb, Buffer, BCount<<Vcb->BlockSizeBits, Lba, WrittenBytes);
ASSERT(OS_SUCCESS(status));
return status;
#else // UDF_DBG
return UDFTWrite(Vcb, Buffer, BCount<<Vcb->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 PSIZE_T WrittenBytes
)
{
int8* tmp_buff;
OSSTATUS status;
#ifdef _BROWSE_UDF_
SIZE_T _WrittenBytes;
SIZE_T 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)) {
UDFPrint(("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 SIZE_T Length,
IN BOOLEAN Direct, // setting this flag delays flushing of given
// data to indefinite term
IN int8* Buffer,
OUT PSIZE_T WrittenBytes
)
{
uint32 i, l, Lba, BS=Vcb->BlockSize;
uint32 BSh=Vcb->BlockSizeBits;
OSSTATUS status;
SIZE_T _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<<BSh;
#ifdef _BROWSE_UDF_
UDFClrZeroBits(Vcb->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;
}
UDFPrint((" 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);
UDFPrint(("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;
#ifdef _MSC_VER
#pragma pack(pop,1)
#else
#pragma pack(pop)
#endif
MODE_SENSE_USER_IN ModeSenseCtl;
OSSTATUS RC;
UDFPrint(("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)) {
UDFPrint((" 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;
}
UDFPrint((" 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;
}
UDFPrint(("UDFSetCaching: %x\n", RC));
return RC;
} // end UDFSetCaching()