mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 23:28:58 +00:00
4386 lines
165 KiB
C++
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()
|