1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7  Module Name: Phys_lib.cpp
8 
9  Execution: Kernel mode only
10 
11  Description:
12 
13    Contains code that implement read/write operations for physical device
14 */
15 
16 #include "phys_lib.h"
17 
18 static const char Signature [16] = {CDRW_SIGNATURE_v1};
19 
20 // Local functions:
21 
22 OSSTATUS
23 UDFSetSpeeds(
24     IN PVCB Vcb
25     );
26 
27 NTSTATUS
28 UDFSetCaching(
29     IN PVCB Vcb
30     );
31 
32 OSSTATUS
33 UDFRecoverFromError(
34     IN PVCB Vcb,
35     IN BOOLEAN WriteOp,
36     IN OSSTATUS status,
37     IN uint32 Lba,
38     IN uint32 BCount,
39  IN OUT uint32* retry);
40 
41 #ifdef _BROWSE_UDF_
42 
43 uint32
44 UDFFixFPAddress(
45     IN PVCB           Vcb,               // Volume control block from this DevObj
46     IN uint32         Lba
47     );
48 
49 #endif //_BROWSE_UDF_
50 
51 NTSTATUS
UDFSyncCache(IN PVCB Vcb)52 UDFSyncCache(
53     IN PVCB Vcb
54     )
55 {
56     UDFPrint(("UDFSyncCache:\n"));
57     OSSTATUS RC;
58     RC = UDFPhSendIOCTL( IOCTL_CDRW_SYNC_CACHE, Vcb->TargetDeviceObject,
59                     NULL,0, NULL,0, FALSE, NULL);
60     if(OS_SUCCESS(RC)) {
61         // clear LAST_WRITE flag
62         Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
63     }
64     return RC;
65 } // end UDFSyncCache()
66 
67 
68 OSSTATUS
UDFReallocTrackMap(IN PVCB Vcb,IN uint32 TrackNum)69 UDFReallocTrackMap(
70     IN PVCB Vcb,
71     IN uint32 TrackNum
72     )
73 {
74 #ifdef _BROWSE_UDF_
75     if(Vcb->TrackMap) {
76         MyFreePool__(Vcb->TrackMap);
77         Vcb->TrackMap = NULL;
78     }
79     Vcb->TrackMap = (PUDFTrackMap)
80         MyAllocatePool__(NonPagedPool, TrackNum*sizeof(UDFTrackMap));
81     if(!Vcb->TrackMap) {
82         return STATUS_INSUFFICIENT_RESOURCES;
83     }
84 #endif //_BROWSE_UDF_
85     RtlZeroMemory(Vcb->TrackMap,TrackNum*sizeof(UDFTrackMap));
86     return STATUS_SUCCESS;
87 } // end UDFReallocTrackMap()
88 
89 #ifdef _BROWSE_UDF_
90 
91 
92 OSSTATUS
93 __fastcall
UDFTIOVerify(IN void * _Vcb,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T IOBytes,IN uint32 Flags)94 UDFTIOVerify(
95     IN void* _Vcb,
96     IN void* Buffer,     // Target buffer
97     IN SIZE_T Length,
98     IN uint32 LBA,
99     OUT PSIZE_T IOBytes,
100     IN uint32 Flags
101     )
102 {
103     OSSTATUS RC = STATUS_SUCCESS;
104     uint32 i, j;
105     SIZE_T mask;
106     uint32 lba0, len, lba1;
107     PUCHAR tmp_buff;
108     PUCHAR p;
109     PCHAR cached_block;
110     SIZE_T tmp_wb;
111     BOOLEAN need_remap;
112     OSSTATUS final_RC = STATUS_SUCCESS;
113     BOOLEAN zero;
114     BOOLEAN non_zero;
115     BOOLEAN packet_ok;
116     BOOLEAN free_tmp = FALSE;
117     BOOLEAN single_packet = FALSE;
118 
119 #define Vcb ((PVCB)_Vcb)
120     // ATTENTION! Do not touch bad block bitmap here, since it describes PHYSICAL addresses WITHOUT remapping,
121     // while here we work with LOGICAL addresses
122 
123     if(Vcb->VerifyCtx.ItemCount > UDF_MAX_VERIFY_CACHE) {
124         UDFVVerify(Vcb, 0/*UFD_VERIFY_FLAG_WAIT*/);
125     }
126 
127     UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
128     Flags |= PH_IO_LOCKED;
129 
130     tmp_wb = (SIZE_T)_Vcb;
131     if(Flags & PH_EX_WRITE) {
132         UDFPrint(("IO-Write-Verify\n"));
133         RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_VCB_IN_RETLEN);
134     } else {
135         UDFPrint(("IO-Read-Verify\n"));
136         RC = UDFTRead(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_VCB_IN_RETLEN);
137     }
138     (*IOBytes) = tmp_wb;
139 
140     switch(RC) {
141     default:
142         UDFReleaseResource(&(Vcb->IoResource));
143         return RC;
144     case STATUS_FT_WRITE_RECOVERY:
145     case STATUS_DEVICE_DATA_ERROR:
146     case STATUS_IO_DEVICE_ERROR:
147         break;
148         /* FALL THROUGH */
149     } // end switch(RC)
150 
151     if(!Vcb->SparingCount ||
152        !Vcb->SparingCountFree ||
153        Vcb->CDR_Mode) {
154         UDFPrint(("Can't remap\n"));
155         UDFReleaseResource(&(Vcb->IoResource));
156         return RC;
157     }
158 
159     if(Flags & PH_EX_WRITE) {
160         UDFPrint(("Write failed, try relocation\n"));
161     } else {
162         if(Vcb->Modified) {
163             UDFPrint(("Read failed, try relocation\n"));
164         } else {
165             UDFPrint(("no remap on not modified volume\n"));
166             UDFReleaseResource(&(Vcb->IoResource));
167             return RC;
168         }
169     }
170     if(Flags & PH_LOCK_CACHE) {
171         UDFReleaseResource(&(Vcb->IoResource));
172         WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
173         UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
174     }
175 
176     Flags &= ~PH_KEEP_VERIFY_CACHE;
177 
178     // NOTE: SparingBlockSize may be not equal to PacketSize
179     // perform recovery
180     mask = Vcb->SparingBlockSize-1;
181     lba0 = LBA & ~mask;
182     len = ((LBA+(Length>>Vcb->BlockSizeBits)+mask) & ~mask) - lba0;
183     j=0;
184     if((lba0 == LBA) && (len == mask+1) && (len == (Length>>Vcb->BlockSizeBits))) {
185         single_packet = TRUE;
186         tmp_buff = NULL;
187     } else {
188         tmp_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Vcb->SparingBlockSize << Vcb->BlockSizeBits, 'bNWD');
189         if(!tmp_buff) {
190             UDFPrint(("  can't alloc tmp\n"));
191             UDFReleaseResource(&(Vcb->IoResource));
192             return STATUS_DEVICE_DATA_ERROR;
193         }
194         free_tmp = TRUE;
195     }
196 
197     for(i=0; i<len; i++) {
198         if(!Vcb->SparingCountFree) {
199             UDFPrint(("  no more free spare blocks, abort verification\n"));
200             break;
201         }
202         UDFPrint(("  read LBA %x (%x)\n", lba0+i, j));
203         if(!j) {
204             need_remap = FALSE;
205             lba1 = lba0+i;
206             non_zero = FALSE;
207             if(single_packet) {
208                 // single packet requested
209                 tmp_buff = (PUCHAR)Buffer;
210                 if(Flags & PH_EX_WRITE) {
211                     UDFPrint(("  remap single write\n"));
212                     UDFPrint(("  try del from verify cache @ %x, %x\n", lba0, len));
213                     UDFVForget(Vcb, len, UDFRelocateSector(Vcb, lba0), 0);
214                     goto do_remap;
215                 } else {
216                     UDFPrint(("  recover and remap single read\n"));
217                 }
218             }
219         }
220         p = tmp_buff+(j<<Vcb->BlockSizeBits);
221         // not cached, try to read
222         // prepare for error, if block cannot be read, assume it is zero-filled
223         RtlZeroMemory(p, Vcb->BlockSize);
224 
225         // check if block valid
226         if(Vcb->BSBM_Bitmap) {
227             if(UDFGetBit((uint32*)(Vcb->BSBM_Bitmap), UDFRelocateSector(Vcb, lba0+i))) {
228                 UDFPrint(("  remap: known BB @ %x, mapped to %x\n", lba0+i, UDFRelocateSector(Vcb, lba0+i)));
229                 need_remap = TRUE;
230             }
231         }
232         zero = FALSE;
233         if(Vcb->FSBM_Bitmap) {
234             if(UDFGetFreeBit((uint32*)(Vcb->FSBM_Bitmap), lba0+i)) {
235                 UDFPrint(("  unused @ %x\n", lba0+i));
236                 zero = TRUE;
237             }
238         }
239         if(!zero && Vcb->ZSBM_Bitmap) {
240             if(UDFGetZeroBit((uint32*)(Vcb->ZSBM_Bitmap), lba0+i)) {
241                 UDFPrint(("  unused @ %x (Z)\n", lba0+i));
242                 zero = TRUE;
243             }
244         }
245         non_zero |= !zero;
246 
247         if(!j) {
248             packet_ok = FALSE;
249             if(!single_packet) {
250                 // try to read entire packet, this returs error more often then sequential reading of all blocks one by one
251                 tmp_wb = (SIZE_T)_Vcb;
252                 RC = UDFTRead(_Vcb, p, Vcb->SparingBlockSize << Vcb->BlockSizeBits, lba0+i, &tmp_wb,
253                               Flags | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN);
254             } else {
255                 // Note: we get here ONLY if original request failed
256                 // do not retry if it was single-packet request
257                 RC = STATUS_UNSUCCESSFUL;
258             }
259             if(RC == STATUS_SUCCESS) {
260                 UDFPrint(("  packet ok @ %x\n", lba0+i));
261                 packet_ok = TRUE;
262                 i += Vcb->SparingBlockSize-1;
263                 continue;
264             } else {
265                 need_remap = TRUE;
266             }
267         }
268 
269         if(!zero) {
270             if(WCacheIsCached__(&(Vcb->FastCache), lba0+i, 1)) {
271                 // even if block is cached, we have to verify if it is readable
272                 if(!packet_ok && !UDFVIsStored(Vcb, lba0+i)) {
273 
274                     tmp_wb = (SIZE_T)_Vcb;
275                     RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb,
276                                   Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN);
277                     if(!OS_SUCCESS(RC)) {
278                         UDFPrint(("  Found BB @ %x\n", lba0+i));
279                     }
280 
281                 }
282                 RC = WCacheDirect__(&(Vcb->FastCache), _Vcb, lba0+i, FALSE, &cached_block, TRUE/* cached only */);
283             } else {
284                 cached_block = NULL;
285                 if(!packet_ok) {
286                     RC = STATUS_UNSUCCESSFUL;
287                 } else {
288                     RC = STATUS_SUCCESS;
289                 }
290             }
291             if(OS_SUCCESS(RC)) {
292                 // cached or successfully read
293                 if(cached_block) {
294                     // we can get from cache the most fresh data
295                     RtlCopyMemory(p, cached_block, Vcb->BlockSize);
296                 }
297 
298             } else {
299                 if(!UDFVIsStored(Vcb, lba0+i)) {
300                     tmp_wb = (SIZE_T)_Vcb;
301                     RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb,
302                                   Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN);
303                 } else {
304                     // get it from verify-cache
305                     RC = STATUS_UNSUCCESSFUL;
306                 }
307                 if(!OS_SUCCESS(RC)) {
308 /*
309                     UDFPrint(("  retry @ %x\n", lba0+i));
310                     tmp_wb = (uint32)_Vcb;
311                     RC = UDFTRead(_Vcb, p, Vcb->BlockSize, lba0+i, &tmp_wb,
312                                   Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN);
313 */
314                     UDFPrint(("  try get from verify cache @ %x\n", lba0+i));
315                     RC = UDFVRead(Vcb, p, 1, UDFRelocateSector(Vcb, lba0+i),
316                                   Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
317                     need_remap = TRUE;
318                 }
319             }
320         } else {
321             RtlZeroMemory(p, Vcb->BlockSize);
322         }
323         if(!packet_ok) {
324             UDFPrint(("  try del from verify cache @ %x\n", lba0+i));
325             RC = UDFVForget(Vcb, 1, UDFRelocateSector(Vcb, lba0+i), 0);
326         }
327 
328         if(!packet_ok || need_remap) {
329             UDFPrint(("  block in bad packet @ %x\n", lba0+i));
330             if(Vcb->BSBM_Bitmap) {
331                 UDFSetBit(Vcb->BSBM_Bitmap, lba0+i);
332             }
333             if(Vcb->FSBM_Bitmap) {
334                 UDFSetUsedBit(Vcb->FSBM_Bitmap, lba0+i);
335             }
336         }
337 
338         j++;
339         if(j >= Vcb->SparingBlockSize) {
340             // remap this packet
341             if(need_remap) {
342                 ASSERT(!packet_ok);
343                 if(!non_zero) {
344                     UDFPrint(("  forget Z packet @ %x\n", lba1));
345                     UDFUnmapRange(Vcb, lba1, Vcb->SparingBlockSize);
346                     RC = STATUS_SUCCESS;
347                 } else {
348 do_remap:
349                     for(j=0; j<3; j++) {
350                         UDFPrint(("  remap packet @ %x\n", lba1));
351                         RC = UDFRemapPacket(Vcb, lba1, FALSE);
352                         if(!OS_SUCCESS(RC)) {
353                             if(RC == STATUS_SHARING_VIOLATION) {
354                                 UDFPrint(("  remap2\n"));
355                                 // remapped location have died
356                                 RC = UDFRemapPacket(Vcb, lba1, TRUE);
357                             }
358                             if(!OS_SUCCESS(RC)) {
359                                 // packet cannot be remapped :(
360                                 RC = STATUS_DEVICE_DATA_ERROR;
361                             }
362                         }
363                         UDFPrint(("  remap status %x\n", RC));
364                         if(OS_SUCCESS(RC)) {
365                             // write to remapped area
366                             tmp_wb = (SIZE_T)_Vcb;
367                             RC = UDFTWrite(_Vcb, tmp_buff, Vcb->SparingBlockSize << Vcb->BlockSizeBits, lba1, &tmp_wb,
368                                           Flags | PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER | PH_VCB_IN_RETLEN);
369                             UDFPrint(("  write status %x\n", RC));
370                             if(RC != STATUS_SUCCESS) {
371                                 // will be remapped
372                                 UDFPrint(("  retry remap\n"));
373 
374                                 // Note: when remap of already remapped block is requested, verify of
375                                 // entire sparing are will be performed.
376 
377                             } else {
378                                 UDFPrint(("  remap OK\n"));
379                                 break;
380                             }
381                         } else {
382                             UDFPrint(("  failed remap\n"));
383                             break;
384                         }
385                     } // for
386                 }
387                 if(!OS_SUCCESS(RC) && !OS_SUCCESS(final_RC)) {
388                     final_RC = RC;
389                 }
390             } else {
391                 UDFPrint(("  NO remap for @ %x\n", (lba0+i) & ~mask));
392             }
393             j=0;
394         }
395     }
396     if(free_tmp) {
397         DbgFreePool(tmp_buff);
398     }
399 
400     tmp_wb = (SIZE_T)_Vcb;
401     if(Flags & PH_EX_WRITE) {
402         UDFPrint(("IO-Write-Verify (2)\n"));
403         //RC = UDFTWrite(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN);
404     } else {
405         UDFPrint(("IO-Read-Verify (2)\n"));
406         RC = UDFTRead(_Vcb, Buffer, Length, LBA, &tmp_wb, Flags | PH_FORGET_VERIFIED | PH_VCB_IN_RETLEN);
407     }
408     (*IOBytes) = tmp_wb;
409     UDFPrint(("Final %x\n", RC));
410 
411     UDFReleaseResource(&(Vcb->IoResource));
412     if(Flags & PH_LOCK_CACHE) {
413         WCacheEODirect__(&(Vcb->FastCache), Vcb);
414     }
415 
416     return RC;
417 } // end UDFTIOVerify()
418 
419 OSSTATUS
UDFTWriteVerify(IN void * _Vcb,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T WrittenBytes,IN uint32 Flags)420 UDFTWriteVerify(
421     IN void* _Vcb,
422     IN void* Buffer,     // Target buffer
423     IN SIZE_T Length,
424     IN uint32 LBA,
425     OUT PSIZE_T WrittenBytes,
426     IN uint32 Flags
427     )
428 {
429     return UDFTIOVerify(_Vcb, Buffer, Length, LBA, WrittenBytes, Flags | PH_VCB_IN_RETLEN | PH_EX_WRITE | PH_KEEP_VERIFY_CACHE);
430 } // end UDFTWriteVerify()
431 
432 OSSTATUS
UDFTReadVerify(IN void * _Vcb,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T ReadBytes,IN uint32 Flags)433 UDFTReadVerify(
434     IN void* _Vcb,
435     IN void* Buffer,     // Target buffer
436     IN SIZE_T Length,
437     IN uint32 LBA,
438     OUT PSIZE_T ReadBytes,
439     IN uint32 Flags
440     )
441 {
442     return UDFTIOVerify(_Vcb, Buffer, Length, LBA, ReadBytes, Flags | PH_VCB_IN_RETLEN | PH_KEEP_VERIFY_CACHE);
443 } // end UDFTReadVerify()
444 #endif //_BROWSE_UDF_
445 
446 /*
447     This routine performs low-level write
448 
449     ATTENTION! When we are in Variable-Packet mode (CDR_Mode = TRUE)
450     LBA is ignored and assumed to be equal to NWA by CD-R(W) driver
451  */
452 OSSTATUS
UDFTWrite(IN void * _Vcb,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T WrittenBytes,IN uint32 Flags)453 UDFTWrite(
454     IN void* _Vcb,
455     IN void* Buffer,     // Target buffer
456     IN SIZE_T Length,
457     IN uint32 LBA,
458     OUT PSIZE_T WrittenBytes,
459     IN uint32 Flags
460     )
461 {
462 #ifndef UDF_READ_ONLY_BUILD
463 #define Vcb ((PVCB)_Vcb)
464 
465 #ifdef _BROWSE_UDF_
466     PEXTENT_MAP RelocExtent;
467     PEXTENT_MAP RelocExtent_saved = NULL;
468 #endif //_BROWSE_UDF_
469     uint32 retry;
470     BOOLEAN res_acq = FALSE;
471 
472     OSSTATUS RC = STATUS_SUCCESS;
473     uint32 rLba;
474     uint32 BCount;
475     uint32 i;
476 
477 #ifdef DBG
478     //ASSERT(!(LBA & (32-1)));
479 #endif //DBG
480 
481     (*WrittenBytes) = 0;
482     BCount = Length>>Vcb->BlockSizeBits;
483 
484     UDFPrint(("TWrite %x (%x)\n", LBA, BCount));
485 #ifdef _BROWSE_UDF_
486     if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD) {
487         UDFPrint(("DEAD\n"));
488         return STATUS_NO_SUCH_DEVICE;
489     }
490 
491     Vcb->VCBFlags |= (UDF_VCB_SKIP_EJECT_CHECK | UDF_VCB_LAST_WRITE);
492     if(!Vcb->CDR_Mode) {
493         RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount);
494         if(!RelocExtent) {
495             UDFPrint(("can't relocate\n"));
496             return STATUS_INSUFFICIENT_RESOURCES;
497         }
498         rLba = LBA;
499     } else {
500         RelocExtent = UDF_NO_EXTENT_MAP;
501         rLba = Vcb->NWA;
502     }
503 #else //_BROWSE_UDF_
504     rLba = LBA;
505 #endif //_BROWSE_UDF_
506 
507 #ifdef DBG
508     //ASSERT(!(rLba & (32-1)));
509 #endif //DBG
510 
511     _SEH2_TRY {
512 #ifdef _BROWSE_UDF_
513 
514         if(!(Flags & PH_IO_LOCKED)) {
515             UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
516             res_acq = TRUE;
517         }
518 
519         if(RelocExtent == UDF_NO_EXTENT_MAP) {
520 #endif //_BROWSE_UDF_
521             retry = UDF_WRITE_MAX_RETRY;
522 retry_1:
523             RC = UDFPrepareForWriteOperation(Vcb, rLba, BCount);
524             if(!OS_SUCCESS(RC)) {
525                 UDFPrint(("prepare failed\n"));
526                 try_return(RC);
527             }
528             if(Flags & PH_VCB_IN_RETLEN) {
529                 (*WrittenBytes) = (ULONG_PTR)Vcb;
530             }
531             RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Buffer, Length,
532                        ((uint64)rLba) << Vcb->BlockSizeBits, WrittenBytes, Flags);
533 #ifdef _BROWSE_UDF_
534             Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
535 #endif //_BROWSE_UDF_
536             if(!OS_SUCCESS(RC) &&
537                 OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, rLba, BCount, &retry)) )
538                 goto retry_1;
539             UDFUpdateNWA((PVCB)_Vcb, rLba, BCount, RC);
540             try_return(RC);
541 #ifdef _BROWSE_UDF_
542         }
543         // write according to relocation table
544         RelocExtent_saved = RelocExtent;
545         for(i=0; RelocExtent->extLength; i++, RelocExtent++) {
546             SIZE_T _WrittenBytes;
547             rLba = RelocExtent->extLocation;
548             BCount = RelocExtent->extLength>>Vcb->BlockSizeBits;
549             retry = UDF_WRITE_MAX_RETRY;
550 retry_2:
551             RC = UDFPrepareForWriteOperation(Vcb, rLba, BCount);
552             if(!OS_SUCCESS(RC)) {
553                 UDFPrint(("prepare failed (2)\n"));
554                 break;
555             }
556             if(Flags & PH_VCB_IN_RETLEN) {
557                 _WrittenBytes = (ULONG_PTR)Vcb;
558             }
559             RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength,
560                        ((uint64)rLba) << Vcb->BlockSizeBits, &_WrittenBytes, Flags);
561             Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
562             if(!OS_SUCCESS(RC) &&
563                 OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, rLba, BCount, &retry)) )
564                 goto retry_2;
565             UDFUpdateNWA((PVCB)_Vcb, rLba, BCount, RC);
566             LBA += BCount;
567             (*WrittenBytes) += _WrittenBytes;
568             if(!OS_SUCCESS(RC)) break;
569             *((uint32*)&Buffer) += RelocExtent->extLength;
570         }
571 #endif //_BROWSE_UDF_
572 try_exit: NOTHING;
573     } _SEH2_FINALLY {
574         if(res_acq) {
575             UDFReleaseResource(&(Vcb->IoResource));
576         }
577 #ifdef _BROWSE_UDF_
578         if(RelocExtent_saved) {
579             MyFreePool__(RelocExtent_saved);
580         }
581 #endif //_BROWSE_UDF_
582     } _SEH2_END;
583     UDFPrint(("TWrite: %x\n", RC));
584     return RC;
585 
586 #undef Vcb
587 #else //UDF_READ_ONLY_BUILD
588     return STATUS_ACCESS_DENIED;
589 #endif //UDF_READ_ONLY_BUILD
590 } // end UDFTWrite()
591 
592 /*
593     This routine performs low-level read
594  */
595 OSSTATUS
UDFTRead(IN void * _Vcb,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T ReadBytes,IN uint32 Flags)596 UDFTRead(
597     IN void* _Vcb,
598     IN void* Buffer,     // Target buffer
599     IN SIZE_T Length,
600     IN uint32 LBA,
601     OUT PSIZE_T ReadBytes,
602     IN uint32 Flags
603     )
604 {
605     uint32 rLba;
606     OSSTATUS RC = STATUS_SUCCESS;
607     uint32 retry;
608     PVCB Vcb = (PVCB)_Vcb;
609     uint32 BCount = Length >> Vcb->BlockSizeBits;
610     uint32 i;
611 #ifdef _BROWSE_UDF_
612     PEXTENT_MAP RelocExtent;
613     PEXTENT_MAP RelocExtent_saved = NULL;
614     BOOLEAN res_acq = FALSE;
615 //    LARGE_INTEGER delay;
616     Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
617 
618     ASSERT(Buffer);
619 
620     (*ReadBytes) = 0;
621 
622     if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD)
623         return STATUS_NO_SUCH_DEVICE;
624 
625     RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount);
626     if(!RelocExtent) return STATUS_INSUFFICIENT_RESOURCES;
627 
628     _SEH2_TRY {
629 
630         if(!(Flags & PH_IO_LOCKED)) {
631             UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
632             res_acq = TRUE;
633         }
634 
635         if(RelocExtent == UDF_NO_EXTENT_MAP) {
636             rLba = LBA;
637             if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) {
638                 RtlZeroMemory(Buffer, Length);
639                 try_return(RC = STATUS_SUCCESS);
640             }
641             retry = UDF_WRITE_MAX_RETRY;
642 retry_1:
643             RC = UDFPrepareForReadOperation(Vcb, rLba, Length >> Vcb->BlockSizeBits);
644             if(!OS_SUCCESS(RC)) try_return(RC);
645             rLba = UDFFixFPAddress(Vcb, rLba);
646 #else
647             rLba = LBA;
648             retry = UDF_WRITE_MAX_RETRY;
649 retry_1:
650             RC = UDFPrepareForReadOperation(Vcb, rLba, Length >> Vcb->BlockSizeBits);
651             if(!OS_SUCCESS(RC)) return RC; // this is for !_BROWSE_UDF only
652 #endif //_BROWSE_UDF_
653             if(Flags & PH_VCB_IN_RETLEN) {
654                 (*ReadBytes) = (SIZE_T)Vcb;
655             }
656             RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Length,
657                        ((uint64)rLba) << Vcb->BlockSizeBits, ReadBytes, Flags);
658             Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
659 #ifdef _BROWSE_UDF_
660             Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
661 #endif //_BROWSE_UDF_
662             if(!OS_SUCCESS(RC) &&
663                 OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) {
664                 if(RC != STATUS_BUFFER_ALL_ZEROS) {
665                     goto retry_1;
666                 }
667                 RtlZeroMemory(Buffer, Length);
668                 (*ReadBytes) = Length;
669                 RC = STATUS_SUCCESS;
670             }
671 #ifdef _BROWSE_UDF_
672             try_return(RC);
673         }
674         // read according to relocation table
675         RelocExtent_saved = RelocExtent;
676         for(i=0; RelocExtent->extLength; i++, RelocExtent++) {
677             SIZE_T _ReadBytes;
678             rLba = RelocExtent->extLocation;
679             if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) {
680                 RtlZeroMemory(Buffer, _ReadBytes = RelocExtent->extLength);
681                 RC = STATUS_SUCCESS;
682                 goto TR_continue;
683             }
684             BCount = RelocExtent->extLength>>Vcb->BlockSizeBits;
685             retry = UDF_WRITE_MAX_RETRY;
686 retry_2:
687             RC = UDFPrepareForReadOperation(Vcb, rLba, RelocExtent->extLength >> Vcb->BlockSizeBits);
688             if(!OS_SUCCESS(RC)) break;
689             rLba = UDFFixFPAddress(Vcb, rLba);
690             if(Flags & PH_VCB_IN_RETLEN) {
691                 _ReadBytes = (SIZE_T)Vcb;
692             }
693             RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength,
694                        ((uint64)rLba) << Vcb->BlockSizeBits, &_ReadBytes, Flags);
695             Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
696             Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
697             if(!OS_SUCCESS(RC) &&
698                 OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) ) {
699                 if(RC != STATUS_BUFFER_ALL_ZEROS) {
700                     goto retry_2;
701                 }
702                 RtlZeroMemory(Buffer, RelocExtent->extLength);
703                 _ReadBytes = RelocExtent->extLength;
704                 RC = STATUS_SUCCESS;
705             }
706 TR_continue:
707             (*ReadBytes) += _ReadBytes;
708             if(!OS_SUCCESS(RC)) break;
709             *((uint32*)&Buffer) += RelocExtent->extLength;
710         }
711 try_exit: NOTHING;
712     } _SEH2_FINALLY {
713         if(res_acq) {
714             UDFReleaseResource(&(Vcb->IoResource));
715         }
716         if(RelocExtent_saved) {
717             MyFreePool__(RelocExtent_saved);
718         }
719     } _SEH2_END;
720 #endif //_BROWSE_UDF_
721     return RC;
722 } // end UDFTRead()
723 
724 #ifdef UDF_ASYNC_IO
725 /*
726     This routine performs asynchronous low-level read
727     Is not used now.
728  */
729 OSSTATUS
UDFTReadAsync(IN void * _Vcb,IN void * _WContext,IN void * Buffer,IN SIZE_T Length,IN uint32 LBA,OUT PSIZE_T ReadBytes)730 UDFTReadAsync(
731     IN void* _Vcb,
732     IN void* _WContext,
733     IN void* Buffer,     // Target buffer
734     IN SIZE_T Length,
735     IN uint32 LBA,
736     OUT PSIZE_T ReadBytes
737     )
738 {
739     PEXTENT_MAP RelocExtent;
740     PEXTENT_MAP RelocExtent_saved;
741     OSSTATUS RC = STATUS_SUCCESS;
742 //    LARGE_INTEGER delay;
743     uint32 retry = UDF_READ_MAX_RETRY;
744     PVCB Vcb = (PVCB)_Vcb;
745     Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
746     uint32 rLba;
747     uint32 BCount;
748 
749     ASSERT(Buffer);
750 
751     (*ReadBytes) = 0;
752 
753     RelocExtent = UDFRelocateSectors(Vcb, LBA, BCount = Length >> Vcb->BlockSizeBits);
754     if(!RelocExtent) return STATUS_INSUFFICIENT_RESOURCES;
755     if(RelocExtent == UDF_NO_EXTENT_MAP) {
756         rLba = LBA;
757         if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) {
758             RtlZeroMemory(Buffer, Length);
759             return STATUS_SUCCESS;
760         }
761 retry_1:
762         RC = UDFPrepareForReadOperation(Vcb, rLba, BCount);
763         if(!OS_SUCCESS(RC)) return RC;
764         rLba = UDFFixFPAddress(Vcb, rLba);
765         RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Length,
766                    ((uint64)rLba) << Vcb->BlockSizeBits, ReadBytes, 0);
767         Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
768         Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
769         if(!OS_SUCCESS(RC) &&
770             OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) )
771             goto retry_1;
772         return RC;
773     }
774     // read according to relocation table
775     RelocExtent_saved = RelocExtent;
776     for(uint32 i=0; RelocExtent->extLength; i++, RelocExtent++) {
777         SIZE_T _ReadBytes;
778         rLba = RelocExtent->extLocation;
779         if(rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) {
780             RtlZeroMemory(Buffer, _ReadBytes = RelocExtent->extLength);
781             RC = STATUS_SUCCESS;
782             goto TR_continue;
783         }
784         BCount = RelocExtent->extLength>>Vcb->BlockSizeBits;
785 retry_2:
786         RC = UDFPrepareForReadOperation(Vcb, rLba, RelocExtent->extLength >> Vcb->BlockSizeBits);
787         if(!OS_SUCCESS(RC)) break;
788         rLba = UDFFixFPAddress(Vcb, rLba);
789         RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, RelocExtent->extLength,
790                    ((uint64)rLba) << Vcb->BlockSizeBits, &_ReadBytes, 0);
791         Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
792         Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
793         if(!OS_SUCCESS(RC) &&
794             OS_SUCCESS(RC = UDFRecoverFromError(Vcb, FALSE, RC, rLba, BCount, &retry)) )
795             goto retry_2;
796 TR_continue:
797         (*ReadBytes) += _ReadBytes;
798         if(!OS_SUCCESS(RC)) break;
799         *((uint32*)&Buffer) += RelocExtent->extLength;
800     }
801     MyFreePool__(RelocExtent_saved);
802     return RC;
803 } // end UDFTReadAsync()
804 
805 #endif //UDF_ASYNC_IO
806 
807 /*
808 
809  */
810 NTSTATUS
UDFSetMRWMode(IN PVCB Vcb)811 UDFSetMRWMode(
812     IN PVCB Vcb
813     )
814 {
815     GET_MRW_MODE_USER_OUT MRWPage;
816     OSSTATUS RC;
817 
818     if(Vcb->MediaClassEx != CdMediaClass_CDRW)
819         return STATUS_SUCCESS;
820 //#ifdef _BROWSE_UDF_
821     if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM)
822         return STATUS_SUCCESS;
823 //#endif //_BROWSE_UDF_
824 
825     if(!Vcb->MRWStatus) {
826         UDFPrint(("Non-MRW disk. Skip setting MRW_MODE\n"));
827         return STATUS_SUCCESS;
828     }
829     UDFPrint(("try set MRW_MODE\n"));
830     RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MRW_MODE, Vcb->TargetDeviceObject,
831                     NULL,0,
832                     (PVOID)&MRWPage,sizeof(MRWPage),
833                     FALSE, NULL);
834     if(!NT_SUCCESS(RC)) {
835         return RC;
836     }
837     UDFPrint(("GET_MRW_MODE ok (current %x)\n", MRWPage.AddressMode));
838     MRWPage.AddressMode = Vcb->MRWStatus ? 0 : MrwPage_use_GAA;
839     UDFPrint(("SET_MRW_MODE %x\n", MRWPage.AddressMode));
840     RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_MRW_MODE, Vcb->TargetDeviceObject,
841                     (PVOID)&MRWPage,sizeof(MRWPage),
842                     NULL,0,
843                     FALSE, NULL);
844     UDFPrint(("SET_MRW_MODE status %x\n", RC));
845 
846     return STATUS_SUCCESS;
847 } // end UDFSetMRWMode()
848 
849 OSSTATUS
UDFDoOPC(IN PVCB Vcb)850 UDFDoOPC(
851     IN PVCB Vcb
852     )
853 {
854     OSSTATUS RC;
855     if(Vcb->OPCNum && !Vcb->OPCDone) {
856         UDFPrint(("UDFDoOPC\n"));
857         if(!Vcb->OPCh) {
858             Vcb->OPCh =
859                 (PSEND_OPC_INFO_HEADER_USER_IN)MyAllocatePool__(NonPagedPool,
860                     sizeof(SEND_OPC_INFO_HEADER_USER_IN) );
861         }
862         if(!Vcb->OPCh)
863             return STATUS_INSUFFICIENT_RESOURCES;
864         Vcb->OPCh->DoOpc = TRUE;
865         Vcb->OPCh->OpcBlocksNumber = 0;
866         RC = UDFPhSendIOCTL(IOCTL_CDRW_SEND_OPC_INFO, Vcb->TargetDeviceObject,
867                         (void*)(Vcb->OPCh),sizeof(SEND_OPC_INFO_HEADER_USER_IN),
868                         NULL,0,
869                         FALSE, NULL);
870         if(!OS_SUCCESS(RC)) {
871             UDFPrint(("UDFDoOPC failed\n"));
872             Vcb->OPCNum = 0;
873 //            Vcb->VCBFlags |= UDF_VCB_FLAGS_OPC_FAILED;
874         }
875         Vcb->OPCDone = TRUE;
876     }
877     return RC;
878 } // end UDFDoOPC()
879 
880 /*
881     This routine performs media-type dependent preparations
882     for write operation.
883 
884     For CDR/RW it sets WriteParameters according to track parameters,
885     in some cases issues SYNC_CACHE command.
886     It can also send OPC info if requered.
887     If write-requested block is located beyond last formatted LBA
888     on incompletely formatted DVD media, this routine performs
889     all neccessary formatting operations in order to satisfy
890     subsequent write request.
891  */
892 OSSTATUS
UDFPrepareForWriteOperation(IN PVCB Vcb,IN uint32 Lba,IN uint32 BCount)893 UDFPrepareForWriteOperation(
894     IN PVCB Vcb,
895     IN uint32 Lba,
896     IN uint32 BCount
897     )
898 {
899 #ifndef UDF_READ_ONLY_BUILD
900 #ifdef UDF_FORMAT_MEDIA
901     PUDFFmtState            fms = Vcb->fms;
902 #else
903   #define fms FALSE
904 #endif //UDF_FORMAT_MEDIA
905 
906 #ifdef _UDF_STRUCTURES_H_
907     if(Vcb->BSBM_Bitmap) {
908         ULONG i;
909         for(i=0; i<BCount; i++) {
910             if(UDFGetBit((uint32*)(Vcb->BSBM_Bitmap), Lba+i)) {
911                 UDFPrint(("W: Known BB @ %#x\n", Lba));
912                 //return STATUS_FT_WRITE_RECOVERY; // this shall not be treated as error and
913                                                    // we shall get IO request to BAD block
914                 return STATUS_DEVICE_DATA_ERROR;
915             }
916         }
917     }
918 #endif //_UDF_STRUCTURES_H_
919 
920     Vcb->VCBFlags |= UDF_VCB_LAST_WRITE;
921 
922     if(
923 #ifdef _BROWSE_UDF_
924        (((Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
925        !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||
926         (Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
927         && !fms
928         ) ||
929 #endif //_BROWSE_UDF_
930 #ifdef UDF_FORMAT_MEDIA
931         (fms && fms->SkipPrepareW) ||
932 #endif //UDF_FORMAT_MEDIA
933        !(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)
934        ) {
935         UDFPrint(("Skip prepare for Write @%x\n", Lba));
936         return STATUS_SUCCESS;
937     }
938 
939     // check if the device requires OPC before each write operation
940     UDFDoOPC(Vcb);
941 
942     if(Vcb->SyncCacheState == SYNC_CACHE_RECOVERY_ATTEMPT) {
943         Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_RETRY;
944     } else {
945         Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_NONE;
946     }
947     if(Vcb->LastModifiedTrack &&
948        (Vcb->TrackMap[Vcb->LastModifiedTrack].FirstLba <= Lba) &&
949        (Vcb->TrackMap[Vcb->LastModifiedTrack].LastLba >= Lba) &&
950        !( (Vcb->MediaClassEx == CdMediaClass_DVDRW ||
951            Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
952            Vcb->MediaClassEx == CdMediaClass_DVDRAM ||
953            Vcb->MRWStatus == DiscInfo_BGF_Interrupted ||
954            Vcb->MRWStatus == DiscInfo_BGF_InProgress) && (Lba > Vcb->LastLBA))
955       ) {
956         // Ok, we needn't change Write Parameters
957 //        if(Vcb->TrackMap[Vcb->LastModifiedTrack].Flags & TrackMap_Try_variation)
958 //            Vcb->TrackMap[Vcb->LastModifiedTrack].Flags |= TrackMap_Use_variation;
959         UDFPrint(("Skip prepare for Write (2) @%x\n", Lba));
960         return STATUS_SUCCESS;
961     }
962 
963     UDFSetMRWMode(Vcb);
964 
965     if(!UDFIsWriteParamsReq(Vcb)) {
966 #ifdef UDF_FORMAT_MEDIA
967         if(fms) {
968             return STATUS_SUCCESS;
969         }
970 #endif //UDF_FORMAT_MEDIA
971     }
972 
973     for(uint32 i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) {
974         if((Vcb->TrackMap[i].FirstLba > Lba) ||
975            (Vcb->TrackMap[i].LastLba < Lba)) {
976             //UDFPrint(("not in track %d\n"));
977             continue;
978         }
979         OSSTATUS RC;
980         PGET_WRITE_MODE_USER_OUT WParams;
981 
982         if(!UDFIsWriteParamsReq(Vcb)) {
983             RC = STATUS_SUCCESS;
984             goto check_dvd_bg_format;
985         }
986 
987         if(!Vcb->WParams) {
988             Vcb->WParams =
989                 (PGET_WRITE_MODE_USER_OUT)MyAllocatePool__(NonPagedPool, 512);
990         }
991         if(!(WParams = Vcb->WParams)) {
992             UDFPrint(("!WParams\n"));
993             return STATUS_INSUFFICIENT_RESOURCES;
994         }
995 
996         RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_WRITE_MODE, Vcb->TargetDeviceObject,
997                         NULL,0,
998                         (void*)(Vcb->WParams),sizeof(GET_WRITE_MODE_USER_OUT),
999                         FALSE, NULL);
1000         if(!OS_SUCCESS(RC)) {
1001 #ifdef UDF_FORMAT_MEDIA
1002             if(fms) {
1003                 fms->SkipPrepareW = 1;
1004                 MyFreePool__(WParams);
1005                 return STATUS_SUCCESS;
1006             }
1007 #endif //UDF_FORMAT_MEDIA
1008             UDFPrint(("!get WParams\n"));
1009             return RC;
1010         }
1011         // clear unnecassary flags
1012         WParams->Byte2.Flags &= ~WParam_TestWrite;
1013         WParams->Byte2.Flags &= ~WParam_WType_Mask;
1014         // select packet writing
1015         WParams->Byte2.Flags |= WParam_WType_Packet;
1016 
1017         WParams->Byte3.Flags &= ~(WParam_TrkMode_Mask |
1018                                   WParam_TrkMode_AllowCpy |
1019                                   WParam_Copy);
1020         WParams->Byte3.Flags |= Vcb->TrackMap[i].TrackParam &
1021                                  (WParam_TrkMode_Mask |
1022                                   WParam_TrkMode_AllowCpy |
1023                                   WParam_Copy);
1024 
1025         // set packet type (VP/FP)
1026 //        if(opt_partition == PT_VAT15 ||
1027 //           opt_blank_vat15)
1028         if(WParams->Byte2.Flags & WParam_LS_V) {
1029             WParams->LinkSize = 7;
1030         }
1031 
1032         if(Vcb->TrackMap[i].DataParam & TrkInfo_Packet) {
1033             if((Vcb->TrackMap[i].DataParam & TrkInfo_FP) &&
1034                 !Vcb->CDR_Mode) {
1035                 WParams->Byte3.Flags |= WParam_FP;
1036             } else {
1037                 WParams->Byte3.Flags &= ~WParam_FP;
1038             }
1039         } else {
1040             if(!Vcb->CDR_Mode) {
1041                 WParams->Byte3.Flags |= WParam_FP;
1042             } else {
1043                 WParams->Byte3.Flags &= ~WParam_FP;
1044             }
1045         }
1046 
1047         // select multisession mode
1048         WParams->Byte3.Flags &= ~WParam_MultiSes_Mask;
1049         if((Vcb->DiscStat & DiscInfo_Disk_Mask) == DiscInfo_Disk_Appendable) {
1050             WParams->Byte3.Flags |= WParam_Multises_Multi;
1051         } else
1052         if(Vcb->LastSession > 1) {
1053             WParams->Byte3.Flags |= WParam_Multises_Final;
1054         } else {
1055             WParams->Byte3.Flags |= WParam_Multises_None;
1056         }
1057         // set sector mode (Mode1/XA)
1058         WParams->Byte4.Flags &= ~WParam_BlkType_Mask;
1059         if((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask) == TrkInfo_Dat_XA) {
1060             // XA Mode2
1061             WParams->Byte4.Flags |= WParam_BlkType_M2XAF1_2048;
1062             WParams->SesFmt = WParam_SesFmt_CdRomXa;
1063         } else if((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask) == TrkInfo_Dat_Mode1) {
1064             // Mode1
1065             WParams->Byte4.Flags |= WParam_BlkType_M1_2048;
1066             WParams->SesFmt = WParam_SesFmt_CdRom;
1067         } else {
1068 #ifdef UDF_FORMAT_MEDIA
1069             if(fms) {
1070                 fms->SkipPrepareW = 1;
1071                 MyFreePool__(WParams);
1072                 return STATUS_SUCCESS;
1073             }
1074 #endif //UDF_FORMAT_MEDIA
1075             UDFPrint(("  inv sector mode\n"));
1076             return STATUS_INVALID_PARAMETER;
1077         }
1078         // set packet size
1079         *((uint32*)&(WParams->PacketSize)) = BCount;
1080         *((uint32*)&(WParams->SubHeader)) = 0;
1081         // set additional flags for VP
1082 
1083         if(Vcb->CDR_Mode) {
1084 //        if(opt_partition == PT_VAT15)
1085             WParams->SubHeader.Params.Params1.SubMode = WParam_SubHdr_SubMode1;
1086         }
1087         WParams->PageLength = sizeof(GET_WRITE_MODE_USER_OUT)-2;
1088         WParams->PageCode = MODE_PAGE_WRITE_PARAMS;
1089         // apply write parameters
1090         RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_WRITE_MODE, Vcb->TargetDeviceObject,
1091                         (void*)WParams,sizeof(SET_WRITE_MODE_USER_IN),
1092                         NULL,0,FALSE,NULL);
1093 
1094 #ifdef UDF_FORMAT_MEDIA
1095         if(fms) {
1096             if(!NT_SUCCESS(RC)) {
1097                 fms->SkipPrepareW = 1;
1098                 MyFreePool__(WParams);
1099                 return STATUS_SUCCESS;
1100             }
1101 
1102             RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_WRITE_MODE, Vcb->TargetDeviceObject,
1103                             NULL,0,
1104                             (PVOID)WParams,sizeof(GET_WRITE_MODE_USER_OUT),
1105                             FALSE, NULL);
1106             if(!NT_SUCCESS(RC)) {
1107                 MyFreePool__(WParams);
1108                 return RC;
1109             }
1110 
1111             if(fms->opt_partition == PT_VAT15 ||
1112                fms->opt_blank_vat15) {
1113                 if(WParams->Byte3.Flags & WParam_FP) {
1114                     MyFreePool__(WParams);
1115                     return STATUS_INVALID_DEVICE_STATE;
1116                 }
1117             } else {
1118                 if(!(WParams->Byte3.Flags & WParam_FP)) {
1119                     MyFreePool__(WParams);
1120                     return STATUS_INVALID_DEVICE_STATE;
1121                 }
1122             }
1123         }
1124 #endif //UDF_FORMAT_MEDIA
1125 
1126         // switch to random access mode
1127         ((PSET_RANDOM_ACCESS_USER_IN)WParams)->RandomAccessMode = Vcb->CDR_Mode ? FALSE : TRUE;
1128 //        ((PSET_RANDOM_ACCESS_USER_IN)WParams)->RandomAccessMode = (opt_partition != PT_VAT15) ? TRUE : FALSE;
1129         RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_RANDOM_ACCESS, Vcb->TargetDeviceObject,
1130                         (void*)WParams,sizeof(SET_RANDOM_ACCESS_USER_IN),
1131                         NULL,0,FALSE, NULL);
1132 
1133 check_dvd_bg_format:
1134 
1135         UDFPrint(("  check BGF\n"));
1136         if(!Vcb->CDR_Mode) {
1137             if(OS_SUCCESS(RC)) {
1138                 Vcb->LastModifiedTrack = i;
1139                 if(!(Vcb->TrackMap[i].Flags & TrackMap_Use_variation)) {
1140                     if(Vcb->TrackMap[i].Flags & TrackMap_Try_variation) {
1141                         Vcb->TrackMap[i].Flags |= TrackMap_Use_variation;
1142                     } else {
1143                         Vcb->TrackMap[i].Flags |= TrackMap_Try_variation;
1144                     }
1145                 }
1146             }
1147         } else {
1148             Vcb->LastModifiedTrack = 0;
1149         }
1150 //        fms->SkipPrepareW = 1;
1151 
1152 
1153         if((Vcb->MediaClassEx == CdMediaClass_DVDRW ||
1154             Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
1155             Vcb->MediaClassEx == CdMediaClass_DVDRAM ||
1156             Vcb->MRWStatus == DiscInfo_BGF_Interrupted )
1157                  && (Lba > Vcb->LastLBA)) {
1158 
1159             ULONG fLba;
1160             SIZE_T WrittenBytes;
1161             ULONG PSz = BCount << Vcb->BlockSizeBits;
1162 #ifdef _BROWSE_UDF_
1163             ULONG retry;
1164 #endif //_BROWSE_UDF_
1165             PFORMAT_CDRW_PARAMETERS_USER_IN ForBuf;
1166 
1167             ASSERT((Vcb->LastLBA+1) == Vcb->NWA);
1168 
1169             if(Lba+BCount <= (Vcb->LastLBA+1) ) {
1170                 UDFPrint(("DVD cont. fmt, LBA+BCount<=NWA, exiting\n"));
1171                 return STATUS_SUCCESS;
1172             }
1173             if((Vcb->MRWStatus != DiscInfo_BGF_Interrupted) &&
1174                (Lba <= (Vcb->LastLBA+1)) ) {
1175                 UDFPrint(("!PausedBGF + DVD cont. fmt, LBA<=NWA, exiting\n"));
1176                 return STATUS_SUCCESS;
1177             }
1178 
1179             if(Vcb->MRWStatus == DiscInfo_BGF_Interrupted) {
1180                 // This code also can restart background MRW formatting
1181                 UDFPrint(("DVD cont. fmt, LastLBA %x, Lba %x\n", Vcb->LastLBA, Lba));
1182 
1183                 ForBuf = (PFORMAT_CDRW_PARAMETERS_USER_IN)DbgAllocatePoolWithTag(NonPagedPool, sizeof(FORMAT_CDRW_PARAMETERS_USER_IN), 'zNWD');
1184                 if(ForBuf) {
1185                     RtlZeroMemory(ForBuf, sizeof(FORMAT_CDRW_PARAMETERS_USER_IN));
1186                     ForBuf->Flags.FlagsEx = FORMAT_UNIT_RESTART_MRW;
1187                     ForBuf->BlockCount = 0xffffffff;
1188 
1189                     RC = UDFPhSendIOCTL(IOCTL_CDRW_FORMAT_UNIT, Vcb->TargetDeviceObject,
1190                             ForBuf,sizeof(FORMAT_CDRW_PARAMETERS_USER_IN),
1191                             NULL,0,FALSE, NULL);
1192                     DbgFreePool(ForBuf);
1193                     if(OS_SUCCESS(RC)) {
1194                         UDFPrint(("BGFormat restarted Interrupted->InProgress\n"));
1195                         Vcb->MRWStatus = DiscInfo_BGF_InProgress;
1196                     } else {
1197                         PGET_LAST_ERROR_USER_OUT Error = NULL;
1198                         if(!Vcb->Error) {
1199                             Vcb->Error = (PGET_LAST_ERROR_USER_OUT)
1200                                             MyAllocatePool__(NonPagedPool, sizeof(GET_LAST_ERROR_USER_OUT));
1201                         }
1202                         Error = Vcb->Error;
1203                         if(Error) {
1204                             UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject,
1205                                             NULL,0,
1206                                             Error,sizeof(GET_LAST_ERROR_USER_OUT),
1207                                             TRUE,NULL);
1208                             UDFPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n",
1209                                      Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError));
1210                             // check for Long Write In Progress
1211                             if( (Error->SenseKey == SCSI_SENSE_NOT_READY) &&
1212                                 (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
1213                                  ((Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS) ||
1214                                   (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) ) {
1215                                 RC = STATUS_SUCCESS;
1216                                 UDFPrint(("Seems, BGFormat already restarted\n"));
1217                                 Vcb->MRWStatus = DiscInfo_BGF_InProgress;
1218                             }
1219                         }
1220                     }
1221                 }
1222             } else {
1223                 RC = STATUS_SUCCESS;
1224             }
1225 
1226             UDFPrint(("DVD cont. write, LastLBA %x, Lba %x\n", Vcb->LastLBA, Lba));
1227 
1228             ASSERT(Vcb->MediaClassEx == CdMediaClass_DVDRW);
1229             if(!Vcb->fZBuffer) {
1230                 Vcb->fZBuffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, PSz, 'zNWD');
1231                 RtlZeroMemory(Vcb->fZBuffer, PSz);
1232                 Vcb->fZBufferSize = PSz;
1233             } else
1234             if(Vcb->fZBufferSize < PSz) {
1235                 PSz = Vcb->fZBufferSize;
1236             }
1237             if(!Vcb->fZBuffer) {
1238                 BrutePoint();
1239                 RC = STATUS_INSUFFICIENT_RESOURCES;
1240             } else {
1241                 for(fLba = Vcb->NWA; fLba < Lba; fLba+=BCount) {
1242 #ifdef _BROWSE_UDF_
1243                     retry = UDF_WRITE_MAX_RETRY;
1244 retry_1:
1245 #endif //_BROWSE_UDF_
1246                     RC = UDFPhWriteVerifySynchronous(Vcb->TargetDeviceObject, Vcb->fZBuffer, PSz,
1247                            ((uint64)fLba) << Vcb->BlockSizeBits, &WrittenBytes, PH_TMP_BUFFER);
1248                     Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
1249                     UDFPrint(("Fmt status: %x\n", RC));
1250 #ifdef _BROWSE_UDF_
1251                     if(!OS_SUCCESS(RC) &&
1252                         OS_SUCCESS(RC = UDFRecoverFromError(Vcb, TRUE, RC, fLba, BCount, &retry)) ) {
1253                         goto retry_1;
1254                         UDFPrint(("Fmt retry\n"));
1255                     }
1256 #endif //_BROWSE_UDF_
1257                     if(!OS_SUCCESS(RC)) {
1258                         BrutePoint();
1259                         UDFPrint(("Fmt break on ERROR\n"));
1260                         break;
1261                     }
1262                     UDFUpdateNWA(Vcb, fLba, BCount, RC);
1263                 }
1264             }
1265         } else {
1266             UDFPrint(("  no special processing\n"));
1267         }
1268 
1269         return RC;
1270     }
1271 #endif //UDF_READ_ONLY_BUILD
1272     UDFPrint(("  no suitable track!\n"));
1273     return STATUS_INVALID_PARAMETER;
1274 } // end UDFPrepareForWriteOperation()
1275 
1276 //#ifdef _BROWSE_UDF_
1277 /*
1278     This routine tries to recover from hardware error
1279     Return: STATUS_SUCCESS - retry requst
1280             STATUS_XXX - unrecoverable error
1281  */
1282 OSSTATUS
UDFRecoverFromError(IN PVCB Vcb,IN BOOLEAN WriteOp,IN OSSTATUS status,IN uint32 Lba,IN uint32 BCount,IN OUT uint32 * retry)1283 UDFRecoverFromError(
1284     IN PVCB Vcb,
1285     IN BOOLEAN WriteOp,
1286     IN OSSTATUS status,
1287     IN uint32 Lba,
1288     IN uint32 BCount,
1289  IN OUT uint32* retry
1290     )
1291 {
1292     PGET_LAST_ERROR_USER_OUT Error = NULL;
1293     LARGE_INTEGER delay;
1294 //    OSSTATUS RC;
1295     uint32 i;
1296     BOOLEAN UpdateBB = FALSE;
1297 
1298     if(!(*retry) ||
1299        !(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) ||
1300         (Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM))
1301         return status;
1302     (*retry)--;
1303     // allocate tmp buffer
1304     _SEH2_TRY {
1305         if(!Vcb->Error) {
1306             if(!(Vcb->Error = (PGET_LAST_ERROR_USER_OUT)
1307                             MyAllocatePool__(NonPagedPool, sizeof(GET_LAST_ERROR_USER_OUT))))
1308                 try_return(status);
1309         }
1310         if(status == STATUS_NO_SUCH_DEVICE) {
1311             UDFPrint(("Error recovery: STATUS_NO_SUCH_DEVICE, die.....\n"));
1312             Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL | UDF_VCB_FLAGS_DEAD;
1313             try_return(status);
1314         }
1315 
1316 #ifdef _UDF_STRUCTURES_H_
1317         if(status == STATUS_NO_MEDIA_IN_DEVICE && !Vcb->EjectWaiter) {
1318             UDFPrint(("Error recovery: STATUS_NO_MEDIA_IN_DEVICE, prevent further remount.....\n"));
1319             // Make sure, that volume will never be quick-remounted
1320             // It is very important for ChkUdf utility and
1321             // some CD-recording libraries
1322             Vcb->SerialNumber--;
1323             try_return(status);
1324         }
1325 #endif //_UDF_STRUCTURES_H_
1326 
1327         Error = Vcb->Error;
1328         UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject,
1329                         NULL,0,
1330                         Error,sizeof(GET_LAST_ERROR_USER_OUT),
1331                         TRUE,NULL);
1332         UDFPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n",
1333                  Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError));
1334         // check for Long Write In Progress
1335         if( ((Error->SenseKey == SCSI_SENSE_NOT_READY) &&
1336              (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
1337              (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS)) ) {
1338             // we should wait...
1339             if(WriteOp) {
1340                 if((*retry) == UDF_WRITE_MAX_RETRY-1) {
1341                     UDFPrint(("Error recovery: reserve retry count for write retries\n"));
1342                     (*retry) = UDF_WRITE_MAX_RETRY*3;
1343                 } else
1344                 if((*retry) == UDF_WRITE_MAX_RETRY) {
1345                     UDFPrint(("Error recovery: jump over UDF_WRITE_MAX_RETRY\n"));
1346                     (*retry)--;
1347                 }
1348                 delay.QuadPart = -500000; // 0.05 sec
1349                 KeDelayExecutionThread(KernelMode, FALSE, &delay);
1350                 if(WriteOp && ((*retry) > UDF_WRITE_MAX_RETRY-1)) {
1351                     UDFPrint(("Error recovery: simple write retry with delay\n"));
1352                     try_return(status = STATUS_SUCCESS);
1353                 }
1354             } else {
1355                 delay.QuadPart = -500000; // 0.05 sec
1356                 KeDelayExecutionThread(KernelMode, FALSE, &delay);
1357                 if((*retry) == UDF_WRITE_MAX_RETRY-1) {
1358                     UDFPrint(("Error recovery: retry read after small delay\n"));
1359                     try_return(status = STATUS_SUCCESS);
1360                 }
1361             }
1362             UDFPrint(("Error recovery: sync cache\n"));
1363             // ...flush device cache...
1364             UDFSyncCache(Vcb);
1365             // wait again & retry
1366             delay.QuadPart = -1000000; // 0.1 sec
1367             KeDelayExecutionThread(KernelMode, FALSE, &delay);
1368 #ifdef _UDF_STRUCTURES_H_
1369             if(Vcb->BGWriters) (*retry)++;
1370 #endif //_UDF_STRUCTURES_H_
1371             try_return(status = STATUS_SUCCESS);
1372         } else
1373         // check for Long Write In Progress
1374         if((Error->SenseKey == SCSI_SENSE_NOT_READY) &&
1375            (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
1376           ((Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS) ||
1377            (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) ||
1378            (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_OPERATION_IN_PROGRESS) ) ) {
1379             // we should wait & retry
1380             UDFPrint(("Error recovery: op. in progress, waiting 0.3 sec\n"));
1381             delay.QuadPart = -3000000; // 0.3 sec
1382             KeDelayExecutionThread(KernelMode, FALSE, &delay);
1383 #ifdef _UDF_STRUCTURES_H_
1384             if(Vcb->BGWriters) (*retry)++;
1385 #endif //_UDF_STRUCTURES_H_
1386             Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_ATTEMPT;
1387             try_return(status = STATUS_SUCCESS);
1388         } else
1389         // check for non empty cache special case
1390         if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
1391            (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_CMD_SEQUENCE)) {
1392             // we should wait & retry
1393             if(!WriteOp) {
1394                 UDFPrint(("Error recovery: invalid command sequence on read\n"));
1395                 delay.QuadPart = -1000000; // 0.1 sec
1396                 KeDelayExecutionThread(KernelMode, FALSE, &delay);
1397                 UDFPrint(("Error recovery: sync cache\n"));
1398                 // ...flush device cache...
1399                 UDFSyncCache(Vcb);
1400                 // wait again & retry
1401                 delay.QuadPart = -1000000; // 0.1 sec
1402                 KeDelayExecutionThread(KernelMode, FALSE, &delay);
1403 #ifdef _UDF_STRUCTURES_H_
1404                 if(Vcb->BGWriters) (*retry)++;
1405 #endif //_UDF_STRUCTURES_H_
1406                 try_return(status = STATUS_SUCCESS);
1407             }
1408             goto reinit_sector_mode;
1409         } else
1410         // check for Bus Reset (sometimes it happends...)
1411         if((Error->SenseKey == SCSI_SENSE_UNIT_ATTENTION) &&
1412            (Error->AdditionalSenseCode == SCSI_ADSENSE_BUS_RESET) ) {
1413             // we should wait
1414             UDFPrint(("Error recovery: bus reset...\n"));
1415             Vcb->MediaChangeCount = Error->MediaChangeCount;
1416             delay.QuadPart = -1000000; // 0.1 sec
1417             KeDelayExecutionThread(KernelMode, FALSE, &delay);
1418             // reset driver
1419             UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
1420             delay.QuadPart = -1000000; // 0.1 sec
1421             KeDelayExecutionThread(KernelMode, FALSE, &delay);
1422             // lock it
1423 /*            ((PPREVENT_MEDIA_REMOVAL_USER_IN)(Error))->PreventMediaRemoval = TRUE;
1424             UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
1425                                  Vcb->TargetDeviceObject,
1426                                  Error,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
1427                                  NULL,0,
1428                                  FALSE,NULL);
1429             delay.QuadPart = -1000000; // 0.1 sec
1430             KeDelayExecutionThread(KernelMode, FALSE, &delay);*/
1431 
1432             // reinit write mode the following is performed inside UDFResetDeviceDriver()
1433             //Vcb->LastModifiedTrack = 0;
1434             //Vcb->OPCDone = FALSE;
1435 
1436 reinit_sector_mode:
1437             // reinit sector mode
1438             Vcb->LastModifiedTrack = 0;
1439             UDFPrepareForWriteOperation(Vcb, Lba, BCount);
1440             try_return(status = STATUS_SUCCESS);
1441         } else
1442         // check for Illegal Sector Mode.
1443         // We can get this error 'cause of 2 reasons:
1444         // a) Bus reset occured. We should reinit
1445         // b) CopyProtection settings missmatch
1446         // c) preblems with DNA of firmware developer, some TEACs fall into such state
1447         //    after failed streaming read
1448         if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
1449            (Error->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK)) {
1450 bad_rw_seek_recovery:
1451             if(WriteOp) {
1452 
1453                 if((*retry) <= 1) {
1454                     // Variate CopyProtection...
1455                     for(i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) {
1456                         if((Vcb->TrackMap[i].FirstLba > Lba) ||
1457                            (Vcb->TrackMap[i].LastLba < Lba))
1458                             continue;
1459     /*                    if(Vcb->TrackMap[i].Flags & TrackMap_CopyBit_variated)
1460                             // Last chance....
1461                             goto reinit_sector_mode;*/
1462 
1463                         // check if we have successuflly completed WriteOp
1464                         // using Variation.
1465                         // We should not variate these bits again in this case.
1466                         if(Vcb->TrackMap[i].Flags & TrackMap_Use_variation)
1467                             break;
1468                         Vcb->TrackMap[i].Flags &= ~TrackMap_Try_variation;
1469     /*                    if((Vcb->TrackMap[i].Flags & TrackMap_Try_variation) &&
1470                            (Vcb->TrackMap[i].Flags & (TrackMap_AllowCopyBit_variated |
1471                                                       TrackMap_CopyBit_variated)))
1472                             break;*/
1473     /*                    if(Vcb->TrackMap[i].Flags & TrackMap_Use_variation)
1474                             break;*/
1475                         Vcb->TrackMap[i].Flags |= TrackMap_Try_variation;
1476                         // Try variation.
1477                         if(!(Vcb->TrackMap[i].Flags ^= TrackMap_AllowCopyBit_variated))
1478                             Vcb->TrackMap[i].Flags ^= TrackMap_CopyBit_variated;
1479                         if(Vcb->TrackMap[i].Flags & (TrackMap_AllowCopyBit_variated |
1480                                                      TrackMap_CopyBit_variated) ) {
1481                             (*retry) = 1;
1482                         } else {
1483                             Vcb->TrackMap[i].Flags &= ~TrackMap_Try_variation;
1484                         }
1485                         // reinit sector mode
1486                         Vcb->LastModifiedTrack = 0;
1487                         UDFPrepareForWriteOperation(Vcb, Lba, BCount);
1488                         break;
1489                     }
1490                 } else {
1491                     // Reinit...
1492 //reinit_sector_mode:
1493                     // we should wait
1494                     delay.QuadPart = -1000000; // 0.1 sec
1495                     KeDelayExecutionThread(KernelMode, FALSE, &delay);
1496                     // reinit sector mode
1497                     goto reinit_sector_mode;
1498 /*
1499                     Vcb->LastModifiedTrack = 0;
1500                     UDFPrepareForWriteOperation(Vcb, Lba, BCount);
1501                     try_return(status = STATUS_SUCCESS);
1502 */
1503                 }
1504             } else
1505             if((Vcb->CompatFlags & UDF_VCB_IC_BAD_RW_SEEK) &&
1506                (Vcb->IncrementalSeekState != INCREMENTAL_SEEK_DONE)) {
1507                 UDFPrint(("Using incremental seek workaround...\n"));
1508                 Vcb->IncrementalSeekState = INCREMENTAL_SEEK_WORKAROUND;
1509                 try_return(status = STATUS_SUCCESS);
1510             } else {
1511                 UDFPrint(("Seems to be BB @ %x\n", Lba));
1512                 UpdateBB = TRUE;
1513             }
1514         } else
1515         if((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
1516            (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_SESSION_MODE)) {
1517             if(WriteOp &&
1518                (Vcb->SavedFeatures & CDRW_FEATURE_STREAMING) &&
1519                Lba+BCount <= Vcb->LastLBA+1) {
1520                 UDFPrint(("bad Session in streaming mode. Lba %x, try fix-up\n", Lba));
1521                 // ...flush device cache...
1522                 UDFSyncCache(Vcb);
1523                 // we should wait
1524                 delay.QuadPart = -10000000; // 1 sec
1525                 KeDelayExecutionThread(KernelMode, FALSE, &delay);
1526                 try_return(status = STATUS_SUCCESS);
1527             }
1528         } else
1529         if((Error->LastError == CDRW_ERR_WRITE_IN_PROGRESS_BUSY) ||
1530            (status == STATUS_DEVICE_BUSY)) {
1531             delay.QuadPart = -5000000; // 0.5 sec
1532             UDFPrint(("CDRW_ERR_WRITE_IN_PROGRESS_BUSY || STATUS_DEVICE_BUSY\n"));
1533             KeDelayExecutionThread(KernelMode, FALSE, &delay);
1534 #ifdef _UDF_STRUCTURES_H_
1535             if(Vcb->BGWriters) (*retry)++;
1536 #endif //_UDF_STRUCTURES_H_
1537             try_return(status = STATUS_SUCCESS);
1538         } else
1539         // some devices (SONY) return such a strange sequence....
1540         if( ((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
1541              (Error->AdditionalSenseCode == SCSI_ADSENSE_INVALID_CDB)) &&
1542               WriteOp) {
1543             // reinit write mode
1544             Vcb->LastModifiedTrack = 0;
1545             UDFPrepareForWriteOperation(Vcb, Lba, BCount);
1546             try_return(status = STATUS_SUCCESS);
1547         } else
1548         // No seek on Read... to morgue, I'm afraid
1549         if((Error->SenseKey == SCSI_SENSE_MEDIUM_ERROR) /*&&
1550            ((Error->AdditionalSenseCode == SCSI_ADSENSE_CD_READ_ERROR) ||
1551             (Error->AdditionalSenseCode == SCSI_ADSENSE_NO_SENSE) ||
1552             (Error->AdditionalSenseCode == SCSI_ADSENSE_FORMAT_CORRUPTED) ||
1553             (Error->AdditionalSenseCode == SCSI_ADSENSE_SEEK_ERROR))*/ &&
1554            !WriteOp) {
1555             if(Error->AdditionalSenseCode == SCSI_ADSENSE_SEEK_ERROR) {
1556                 UDFPrint(("Seek error\n"));
1557                 if(Vcb->CompatFlags & UDF_VCB_IC_BAD_RW_SEEK) {
1558                     UDFPrint(("try recovery\n"));
1559                     goto bad_rw_seek_recovery;
1560                 }
1561                 UDFPrint(("map error to STATUS_NONEXISTENT_SECTOR\n"));
1562                 status = STATUS_NONEXISTENT_SECTOR;
1563             }
1564             UDFPrint(("Seems to be BB @ %x (read 2)\n", Lba));
1565             UpdateBB = TRUE;
1566         } else
1567         // handle invalid block address
1568         if( ((Error->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
1569              (Error->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_BLOCK)) ) {
1570             if(!WriteOp &&
1571                (Vcb->SavedFeatures & CDRW_FEATURE_STREAMING) &&
1572                Lba+BCount <= Vcb->LastLBA+1) {
1573                 UDFPrint(("bad LBA %x in streaming mode, try fix-up\n", Lba));
1574                 // ...flush device cache...
1575                 UDFSyncCache(Vcb);
1576                 try_return(status = STATUS_SUCCESS);
1577             }
1578 
1579             if((Lba+BCount >= Vcb->LastLBA) &&
1580                (Vcb->MRWStatus == DiscInfo_BGF_Interrupted)) {
1581                 UDFPrint(("stupid drive, cannot read beyond formatted area on DiscInfo_BGF_Interrupted\n"));
1582                 UpdateBB = FALSE;
1583                 try_return(status = STATUS_BUFFER_ALL_ZEROS);
1584             }
1585             // prevent Bad Block Bitmap modification
1586         }
1587 
1588 try_exit: NOTHING;
1589 
1590     } _SEH2_FINALLY {
1591 #ifdef UDF_DBG
1592         if(OS_SUCCESS(status)) {
1593             UDFPrint(("Retry\n"));
1594         }
1595 #endif //UDF_DBG
1596     } _SEH2_END;
1597     if(!OS_SUCCESS(status)) {
1598         if((Vcb->MountPhErrorCount != (ULONG)-1) &&
1599            (Vcb->MountPhErrorCount < 0x7fffffff)) {
1600             Vcb->MountPhErrorCount++;
1601         }
1602 //#ifdef _UDF_STRUCTURES_H_
1603         if(UpdateBB && (BCount == 1)) {
1604             uint32* bm;
1605             if(!(bm = (uint32*)(Vcb->BSBM_Bitmap))) {
1606                 bm = (uint32*)(Vcb->BSBM_Bitmap = (int8*)DbgAllocatePoolWithTag(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3), 'mNWD' ));
1607                 if(bm) {
1608                     RtlZeroMemory(bm, i);
1609                 } else {
1610                     UDFPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA));
1611                 }
1612             }
1613             if(bm) {
1614                 UDFSetBit(bm, Lba);
1615                 UDFPrint(("Set BB @ %#x\n", Lba));
1616             }
1617 #ifdef _BROWSE_UDF_
1618             bm = (uint32*)(Vcb->FSBM_Bitmap);
1619             if(bm) {
1620                 UDFSetUsedBit(bm, Lba);
1621                 UDFPrint(("Set BB @ %#x as used\n", Lba));
1622             }
1623 #endif //_BROWSE_UDF_
1624         }
1625 //#endif //_UDF_STRUCTURES_H_
1626     }
1627     return status;
1628 } // end UDFRecoverFromError()
1629 
1630 //#endif //_BROWSE_UDF_
1631 /*
1632     This routine attempts to read disk layout using ReadDisk/Track info cmd
1633  */
1634 OSSTATUS
UDFReadDiscTrackInfo(PDEVICE_OBJECT DeviceObject,PVCB Vcb)1635 UDFReadDiscTrackInfo(
1636     PDEVICE_OBJECT    DeviceObject,      // the target device object
1637     PVCB              Vcb                // Volume Control Block for ^ DevObj
1638     )
1639 {
1640     OSSTATUS                    RC = STATUS_SUCCESS;
1641     PDISC_INFO_BLOCK_USER_OUT   DiscInfo = (PDISC_INFO_BLOCK_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(DISC_INFO_BLOCK_USER_OUT) );
1642     PTRACK_INFO_BLOCK_USER_OUT  TrackInfoOut = (PTRACK_INFO_BLOCK_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(TRACK_INFO_BLOCK_USER_OUT) );
1643     PTRACK_INFO_BLOCK_USER_IN   TrackInfoIn = (PTRACK_INFO_BLOCK_USER_IN)TrackInfoOut;
1644     READ_CAPACITY_USER_OUT      CapacityBuffer;
1645     LONG                        TrackNumber;
1646     BOOLEAN                     NotFP = FALSE;
1647     BOOLEAN                     ForceFP = FALSE;
1648     BOOLEAN                     PacketTrack = FALSE;
1649     BOOLEAN                     MRWRetry = FALSE;
1650 //    BOOLEAN                     ReadCapacityOk = FALSE;
1651 #ifdef UDF_FORMAT_MEDIA
1652     PUDFFmtState            fms = Vcb->fms;
1653 #endif
1654 
1655     _SEH2_TRY {
1656         if(!DiscInfo || !TrackInfoOut)
1657             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1658 
1659 MRWRetry_label:
1660 
1661         RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_DISC_INFO, DeviceObject,
1662                 NULL, 0,
1663                 DiscInfo,sizeof(DISC_INFO_BLOCK_USER_OUT), TRUE, NULL);
1664         if(!OS_SUCCESS(RC)) {
1665             UDFPrint(("ReadDiskInfo failed. Use default.\n"));
1666             if(Vcb->MediaClassEx == CdMediaClass_DVDRW ||
1667                 Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
1668                 Vcb->MediaClassEx == CdMediaClass_DVDRAM) {
1669                 Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD;
1670             } else
1671             if(Vcb->MediaClassEx == CdMediaClass_BDRE) {
1672                 Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_BD;
1673             } else {
1674                 Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_FP_CD;
1675             }
1676             try_return(RC);
1677         }
1678 #ifdef UDF_FORMAT_MEDIA
1679         if(fms && fms->opt_disk_info) {
1680             UserPrint(("ReadDiskInfo OK\n"));
1681         }
1682 #endif //UDF_FORMAT_MEDIA
1683 
1684         RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_CAPACITY, DeviceObject,
1685                 NULL, 0,
1686                 &CapacityBuffer,sizeof(READ_CAPACITY_USER_OUT), TRUE, NULL);
1687         if(!OS_SUCCESS(RC)) {
1688             UDFPrint(("ReadCapacity failed.\n"));
1689             if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
1690                 Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD;
1691             }
1692         } else {
1693             UDFPrint(("ReadCapacity ok.\n"));
1694             UDFPrint(("Last possible LBA %#x.\n", CapacityBuffer.LogicalBlockAddress));
1695             if(!(CapacityBuffer.LogicalBlockAddress  & 0xc0000000) &&
1696                 (CapacityBuffer.LogicalBlockAddress != 0x7fffffff)) {
1697                 // good value from ReadCapacity
1698                 UDFPrint(("Update Last possible LBA %#x.\n", CapacityBuffer.LogicalBlockAddress));
1699                 Vcb->LastPossibleLBA = CapacityBuffer.LogicalBlockAddress;
1700 //                ReadCapacityOk = TRUE;
1701 #ifdef UDF_FORMAT_MEDIA
1702                 if(fms && fms->opt_disk_info) {
1703                     UserPrint(("ReadCapacity OK\n"));
1704                 }
1705 #endif //UDF_FORMAT_MEDIA
1706             }
1707         }
1708 
1709 #ifdef _CONSOLE
1710         Vcb->PhDeviceType = FILE_DEVICE_CD_ROM;
1711 #endif //_CONSOLE
1712         Vcb->PhSerialNumber = *((uint32*)&(DiscInfo->DiskId));
1713         Vcb->PhErasable = DiscInfo->DiscStat.Flags & DiscInfo_Disk_Erasable;
1714         Vcb->PhDiskType = DiscInfo->DiskType;
1715         // save OPC info
1716         if(DiscInfo->OPCNum)
1717             Vcb->OPCNum = DiscInfo->OPCNum;
1718         UDFPrint(("DiskInfo: SN %x, OPCn %x(%x), Stat %x, Flg: %x\n",
1719             Vcb->PhSerialNumber, Vcb->OPCNum, DiscInfo->OPCNum, DiscInfo->DiscStat.Flags, DiscInfo->Flags.Flags));
1720 #ifdef UDF_FORMAT_MEDIA
1721         if(fms && fms->opt_disk_info) {
1722             UserPrint(("Media type: "));
1723             switch(Vcb->MediaClassEx) {
1724             case CdMediaClass_CDROM     : UserPrint(("CD-ROM     \n")); break;
1725             case CdMediaClass_CDR       : UserPrint(("CD-R       \n")); break;
1726             case CdMediaClass_CDRW      : UserPrint(("CD-RW      \n")); break;
1727             case CdMediaClass_DVDROM    : UserPrint(("DVD-ROM    \n")); break;
1728             case CdMediaClass_DVDRAM    : UserPrint(("DVD-RAM    \n")); break;
1729             case CdMediaClass_DVDR      : UserPrint(("DVD-R      \n")); break;
1730             case CdMediaClass_DVDRW     : UserPrint(("DVD-RW     \n")); break;
1731             case CdMediaClass_DVDpR     : UserPrint(("DVD+R      \n")); break;
1732             case CdMediaClass_DVDpRW    : UserPrint(("DVD+RW     \n")); break;
1733             case CdMediaClass_DDCDROM   : UserPrint(("DDCD-ROM   \n")); break;
1734             case CdMediaClass_DDCDR     : UserPrint(("DDCD-R     \n")); break;
1735             case CdMediaClass_DDCDRW    : UserPrint(("DDCD-RW    \n")); break;
1736             case CdMediaClass_BDROM     : UserPrint(("BD-ROM     \n")); break;
1737             case CdMediaClass_BDRE      : UserPrint(("BD-RE      \n")); break;
1738             case CdMediaClass_BDR       : UserPrint(("BD-R       \n")); break;
1739             case CdMediaClass_HD_DVDROM : UserPrint(("HD DVD-ROM \n")); break;
1740             case CdMediaClass_HD_DVDRAM : UserPrint(("HD DVD-RAM \n")); break;
1741             case CdMediaClass_HD_DVDR   : UserPrint(("HD DVD-R   \n")); break;
1742             case CdMediaClass_HD_DVDRW  : UserPrint(("HD DVD-RW  \n")); break;
1743             default: UserPrint(("Unknown\n")); break;
1744             }
1745             UserPrint(("SN %#x, OPCn %#x\n",
1746                 Vcb->PhSerialNumber, Vcb->OPCNum, DiscInfo->OPCNum));
1747             UserPrint(("Disk State: "));
1748             switch(DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) {
1749             case DiscInfo_Disk_Empty:
1750                 UserPrint(("Empty\n"));
1751                 break;
1752             case DiscInfo_Disk_Appendable:
1753                 UserPrint(("Appendable\n"));
1754                 break;
1755             case DiscInfo_Disk_Complete:
1756                 UserPrint(("Complete\n"));
1757                 break;
1758             case DiscInfo_Disk_OtherRW:
1759                 UserPrint(("RW in unknown state\n"));
1760                 break;
1761             }
1762             UserPrint(("Last Session State: "));
1763             switch(DiscInfo->DiscStat.Flags & DiscInfo_Ses_Mask) {
1764             case DiscInfo_Ses_Empty:
1765                 UserPrint(("Empty\n"));
1766                 break;
1767             case DiscInfo_Ses_Incomplete:
1768                 UserPrint(("Incomplete\n"));
1769                 break;
1770             case DiscInfo_Ses_Complete:
1771                 UserPrint(("Complete\n"));
1772                 break;
1773             default:
1774                 UserPrint(("unknown state\n"));
1775                 break;
1776             }
1777             UserPrint(("Erasable: %s\n",
1778                 (DiscInfo->DiscStat.Flags & DiscInfo_Disk_Erasable) ? "yes" : "no"
1779                 ));
1780         }
1781 #endif //UDF_FORMAT_MEDIA
1782         // Save disk status
1783         Vcb->DiscStat = DiscInfo->DiscStat.Flags;
1784         if((DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty) {
1785             UDFPrint(("Blank\n"));
1786             Vcb->BlankCD = TRUE;
1787         }
1788         if( (DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty ||
1789             (DiscInfo->DiscStat.Flags & DiscInfo_Ses_Mask) == DiscInfo_Ses_Incomplete) {
1790             // we shall mount empty disk to make it possible for
1791             // external applications to perform format operation
1792             // or something like this
1793             UDFPrint(("Try RAW_MOUNT\n"));
1794             Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
1795             PacketTrack = TRUE;
1796         }
1797 
1798 #ifndef _BROWSE_UDF_
1799         // If drive returned reasonable value from ReadCapacity, do not use
1800         // last LeadIn/LeadOut
1801         if(Vcb->MediaClassEx != CdMediaClass_DVDpRW &&
1802            !ReadCapacityOk) {
1803             // +RW returns bad value
1804             UDFPrint(("+RW returns bad value\n"));
1805             Vcb->LastPossibleLBA = (DiscInfo->LastSesLeadOutLBA & 0x80000000) ?
1806                 0 : DiscInfo->LastSesLeadOutLBA;
1807             if(!(DiscInfo->LastSesLeadInLBA & 0x80000000)) {
1808                 Vcb->LastPossibleLBA = max(DiscInfo->LastSesLeadInLBA, Vcb->LastPossibleLBA);
1809             }
1810         }
1811 #endif // _BROWSE_UDF_
1812         if((DiscInfo->Flags.Flags & DiscInfo_BGF_Mask) != 0) {
1813             UDFPrint(("ForceFP + MRW\n"));
1814             ForceFP = TRUE;
1815             Vcb->MRWStatus = DiscInfo->Flags.Flags & DiscInfo_BGF_Mask;
1816             // update addressing mode
1817             if(!MRWRetry) {
1818                 UDFSetMRWMode(Vcb);
1819                 MRWRetry = TRUE;
1820                 goto MRWRetry_label;
1821             }
1822         }
1823         UDFPrint(("MRW state %x\n", Vcb->MRWStatus));
1824         if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
1825             if(Vcb->PhMediaCapFlags & CdCapFlags_RandomWritable) {
1826                 UDFPrint(("DVD-RW Rewritable\n"));
1827                 ForceFP = TRUE;
1828             } else
1829             if((DiscInfo->DiscStat.Flags & DiscInfo_Disk_Mask) == DiscInfo_Disk_Empty) {
1830                 UDFPrint(("Blank DVD-RW\n"));
1831                 ForceFP = TRUE;
1832             } else {
1833                 UDFPrint(("DVD-RW Sequential\n"));
1834                 NotFP = TRUE;
1835             }
1836         } else
1837         if(CdrwIsDvdOverwritable(Vcb->MediaClassEx)) {
1838             UDFPrint(("force Rewritable (2)\n"));
1839             ForceFP = TRUE;
1840         }
1841         // We have incomplete last session, so process each track from last to first
1842 //            Vcb->LastPossibleLBA = DiscInfo->LastSesLeadInLBA;
1843 
1844         Vcb->LastSession   = DiscInfo->Status.NumOfSes;
1845         Vcb->LastTrackNum  = DiscInfo->Status.LastTrackNumLastSes;
1846         Vcb->FirstTrackNum = DiscInfo->FirstTrackNum;
1847         // some devices report LastTrackNum=0 for full disks
1848         Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum);
1849         if(!Vcb->LastTrackNum) {
1850             UDFPrint(("Try read 1st track...\n"));
1851             Vcb->LastTrackNum = 1;
1852         }
1853         UDFPrint(("DiskInfo: 1st trk %x, last trk %x\n", Vcb->FirstTrackNum, Vcb->LastTrackNum));
1854 #ifdef UDF_FORMAT_MEDIA
1855         if(fms && fms->opt_disk_info) {
1856             UserPrint(("First track: %d\n"
1857                        "Last track:  %d\n", Vcb->FirstTrackNum, Vcb->LastTrackNum));
1858             UserPrint(("------------------------------------------\n"));
1859         }
1860 #endif //UDF_FORMAT_MEDIA
1861 
1862         RC = UDFReallocTrackMap(Vcb, Vcb->LastTrackNum+1);
1863         if(!OS_SUCCESS(RC))
1864             try_return(RC);
1865 
1866         // Get last LBA from invisible track (if any)
1867         RtlZeroMemory(TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT));
1868 
1869         TrackInfoIn->LBA_TrkNum = 0; // invisible track
1870         TrackInfoIn->Track = TRUE;
1871 
1872         RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_TRACK_INFO, DeviceObject,
1873                 TrackInfoIn, sizeof(TRACK_INFO_BLOCK_USER_IN),
1874                 TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT), TRUE, NULL);
1875         if(OS_SUCCESS(RC)) {
1876             if((Vcb->LastTrackNum < TrackInfoOut->TrackNum) &&
1877                 TrackInfoOut->TrackLength &&
1878                (TrackInfoOut->TrackStartLBA != TrackInfoOut->NextWriteLBA)) {
1879                 Vcb->LastTrackNum = TrackInfoOut->TrackNum;
1880                 if(!(TrackInfoOut->NextWriteLBA & 0x80000000))
1881                     Vcb->NWA = TrackInfoOut->NextWriteLBA;
1882                 if(TrackInfoOut->TrackLength > 1) {
1883                     Vcb->LastPossibleLBA =
1884                         TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0);
1885                     UDFPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA));
1886                 }
1887             }
1888 
1889             UDFPrint(("Ses %d, Track %d (%x, len %x) PckSize %x: \n"
1890                      "  NWA: %x (%s)  DatType:%x, %s %s %s %s TrkType:%x %s %s\n"
1891                      "  LRA: %x (%s)  RC_LBA:%x\n",
1892                 TrackInfoOut->SesNum,
1893                 0,
1894                 TrackInfoOut->TrackStartLBA,
1895                 TrackInfoOut->TrackLength,
1896                 TrackInfoOut->FixPacketSize,
1897 
1898                 TrackInfoOut->NextWriteLBA,
1899                 TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv",
1900                 TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask,
1901                 (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "",
1902                 (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "",
1903                 (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "",
1904                 (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "",
1905 
1906                 TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask,
1907                 (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "",
1908                 (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "",
1909 
1910                 TrackInfoOut->LastRecordedAddr,
1911                 (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv",
1912 
1913                 TrackInfoOut->ReadCompatLBA
1914                 ));
1915 #ifdef UDF_FORMAT_MEDIA
1916             if(fms && fms->opt_disk_info) {
1917                 UserPrint(("Invisible track: \n"));
1918                 UserPrint(("  Ses %d, Track %d (%x, len %x) PckSize %x: \n"
1919                            "    NWA: %x (%s)  DatType:%x, %s %s %s %s TrkType:%x %s %s\n"
1920                            "    LRA: %x (%s)  RC_LBA:%x\n",
1921                     TrackInfoOut->SesNum,
1922                     0,
1923                     TrackInfoOut->TrackStartLBA,
1924                     TrackInfoOut->TrackLength,
1925                     TrackInfoOut->FixPacketSize,
1926 
1927                     TrackInfoOut->NextWriteLBA,
1928                     TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv",
1929                     TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask,
1930                     (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "",
1931                     (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "",
1932                     (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "",
1933                     (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "",
1934 
1935                     TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask,
1936                     (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "",
1937                     (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "",
1938 
1939                     TrackInfoOut->LastRecordedAddr,
1940                     (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv",
1941 
1942                     TrackInfoOut->ReadCompatLBA
1943                     ));
1944             }
1945 #endif //UDF_FORMAT_MEDIA
1946 
1947         }
1948 
1949         for (TrackNumber=(LONG)DiscInfo->FirstTrackNum;TrackNumber <= (LONG)Vcb->LastTrackNum;TrackNumber++) {
1950 
1951             RtlZeroMemory(TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT));
1952             TrackInfoIn->LBA_TrkNum = TrackNumber;
1953             TrackInfoIn->Track = TRUE;
1954 
1955             RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_TRACK_INFO, DeviceObject,
1956                     TrackInfoIn, sizeof(TRACK_INFO_BLOCK_USER_IN),
1957                     TrackInfoOut,sizeof(TRACK_INFO_BLOCK_USER_OUT), TRUE, NULL);
1958             // fill sector type map
1959             if(TrackInfoOut->TrackStartLBA & 0x80000000) {
1960                 UDFPrint(("TrkInfo: Bad FirstLba (%x), change to %x\n", TrackInfoOut->TrackStartLBA, 0));
1961                 Vcb->TrackMap[TrackNumber].FirstLba = 0;
1962             } else {
1963                 Vcb->TrackMap[TrackNumber].FirstLba = TrackInfoOut->TrackStartLBA;
1964             }
1965             if(TrackInfoOut->TrackLength & 0x80000000) {
1966                 UDFPrint(("TrkInfo: Bad TrackLength (%x), change to %x\n", TrackInfoOut->TrackLength,
1967                     Vcb->LastPossibleLBA - Vcb->TrackMap[TrackNumber].FirstLba + 1));
1968                 TrackInfoOut->TrackLength = Vcb->LastPossibleLBA - Vcb->TrackMap[TrackNumber].FirstLba + 1;
1969             }
1970             Vcb->TrackMap[TrackNumber].LastLba = TrackInfoOut->TrackStartLBA +
1971                                                  TrackInfoOut->TrackLength -
1972                                             (TrackInfoOut->TrackLength ? 1 : 0);
1973 
1974             Vcb->TrackMap[TrackNumber].TrackParam = TrackInfoOut->TrackParam.Flags;
1975             Vcb->TrackMap[TrackNumber].DataParam = TrackInfoOut->DataParam.Flags;
1976             Vcb->TrackMap[TrackNumber].NWA_V = TrackInfoOut->NWA_V;
1977             if((TrackInfoOut->NextWriteLBA & 0x80000000) ||
1978                (TrackInfoOut->NextWriteLBA < TrackInfoOut->TrackStartLBA)) {
1979                 if(!(Vcb->TrackMap[TrackNumber].LastLba & 0x8000000)) {
1980                     UDFPrint(("TrkInfo: set NWA to LastLba (%x)\n", Vcb->TrackMap[TrackNumber].LastLba));
1981                     Vcb->TrackMap[TrackNumber].NWA =
1982                         Vcb->TrackMap[TrackNumber].LastLba;
1983                 } else {
1984                     UDFPrint(("TrkInfo: set NWA to INV (1)\n"));
1985                     Vcb->TrackMap[TrackNumber].NWA = 0;
1986                     Vcb->TrackMap[TrackNumber].NWA_V = 0;
1987                 }
1988             } else {
1989                 if(!(TrackInfoOut->NextWriteLBA & 0x80000000)) {
1990                     UDFPrint(("TrkInfo: Good NWA (%x)\n", TrackInfoOut->NextWriteLBA));
1991                     Vcb->TrackMap[TrackNumber].NWA =
1992                         TrackInfoOut->NextWriteLBA;
1993                 } else {
1994                     UDFPrint(("TrkInfo: set NWA to INV (2)\n"));
1995                     Vcb->TrackMap[TrackNumber].NWA = 0;
1996                     Vcb->TrackMap[TrackNumber].NWA_V = 0;
1997                 }
1998             }
1999             Vcb->TrackMap[TrackNumber].Session = TrackInfoOut->SesNum;
2000             // for FP tracks we shall get PacketSize from returned info
2001             // otherwise set to default UDF value (0x20)
2002             if(NotFP) {
2003                 UDFPrint(("Apply NotFP\n"));
2004                 Vcb->TrackMap[TrackNumber].DataParam &= ~TrkInfo_FP;
2005 #ifdef DBG
2006                 TrackInfoOut->DataParam.Flags &= ~TrkInfo_FP;
2007 #endif //DBG
2008             } else
2009             if(ForceFP) {
2010                 UDFPrint(("Apply ForceFP\n"));
2011                 PacketTrack = TRUE;
2012                 Vcb->TrackMap[TrackNumber].DataParam |= TrkInfo_FP;
2013 #ifdef DBG
2014                 TrackInfoOut->DataParam.Flags |= TrkInfo_FP;
2015 #endif //DBG
2016             }
2017             if(Vcb->TrackMap[TrackNumber].DataParam & TrkInfo_FP) {
2018                 Vcb->TrackMap[TrackNumber].PacketSize = TrackInfoOut->FixPacketSize;
2019                 Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
2020                 Vcb->FP_disc = TRUE;
2021             } else {
2022                 Vcb->TrackMap[TrackNumber].PacketSize = PACKETSIZE_UDF;
2023             }
2024             // presence of Damaged track means, that we should mount this disk in RAW mode
2025             if(Vcb->TrackMap[TrackNumber].TrackParam & TrkInfo_Damage) {
2026                 UDFPrint(("TrkInfo_Damage, Try RAW_MOUNT\n"));
2027                 Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
2028             }
2029             // presence of track with Unknown data type means, that we should mount
2030             // this disk in RAW mode
2031             if((TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask) == TrkInfo_Trk_unknown) {
2032                 UDFPrint(("Unknown DatType, Try RAW_MOUNT\n"));
2033                 Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
2034             }
2035 
2036             PacketTrack |= ((TrackInfoOut->DataParam.Flags & TrkInfo_Packet) != 0);
2037 
2038             UDFPrint(("Ses %d, Track %d (%x - %x) PckSize %x: \n"
2039                      "  NWA: %x (%s)  DatType:%x, %s %s %s %s TrkType:%x %s %s\n"
2040                      "  LRA: %x (%s)  RC_LBA:%x\n",
2041                 TrackInfoOut->SesNum,
2042                 TrackNumber,
2043                 Vcb->TrackMap[TrackNumber].FirstLba,
2044                 Vcb->TrackMap[TrackNumber].LastLba,
2045                 TrackInfoOut->FixPacketSize,
2046 
2047                 TrackInfoOut->NextWriteLBA,
2048                 TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv",
2049                 TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask,
2050                 (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "",
2051                 (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "",
2052                 (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "",
2053                 (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "",
2054 
2055                 TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask,
2056                 (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "",
2057                 (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "",
2058 
2059                 TrackInfoOut->LastRecordedAddr,
2060                 (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv",
2061 
2062                 TrackInfoOut->ReadCompatLBA
2063                 ));
2064 #ifdef UDF_FORMAT_MEDIA
2065             if(fms && fms->opt_disk_info) {
2066                 UserPrint(("Track %d: \n", TrackNumber));
2067                 UserPrint(("  Ses %d, Track %d (%x, len %x) PckSize %x: \n"
2068                            "    NWA: %x (%s)  DatType:%x, %s %s %s %s TrkType:%x %s %s\n"
2069                            "    LRA: %x (%s)  RC_LBA:%x\n",
2070                     TrackInfoOut->SesNum,
2071                     TrackNumber,
2072                     TrackInfoOut->TrackStartLBA,
2073                     TrackInfoOut->TrackLength,
2074                     TrackInfoOut->FixPacketSize,
2075 
2076                     TrackInfoOut->NextWriteLBA,
2077                     TrackInfoOut->NWA_V & TrkInfo_NWA_V ? "vld" : "inv",
2078                     TrackInfoOut->DataParam.Flags & TrkInfo_Dat_Mask,
2079                     (TrackInfoOut->DataParam.Flags & TrkInfo_Packet) ? "Pck" : "",
2080                     (TrackInfoOut->DataParam.Flags & TrkInfo_FP) ? "FP" : "",
2081                     (TrackInfoOut->DataParam.Flags & TrkInfo_Blank) ? "Blank" : "",
2082                     (TrackInfoOut->DataParam.Flags & TrkInfo_RT) ? "RT" : "",
2083 
2084                     TrackInfoOut->TrackParam.Flags & TrkInfo_Trk_Mask,
2085                     (TrackInfoOut->TrackParam.Flags & TrkInfo_Copy) ? "Cpy" : "",
2086                     (TrackInfoOut->TrackParam.Flags & TrkInfo_Damage) ? "Damage" : "",
2087 
2088                     TrackInfoOut->LastRecordedAddr,
2089                     (TrackInfoOut->NWA_V & TrkInfo_LRA_V) ? "vld" : "inv",
2090 
2091                     TrackInfoOut->ReadCompatLBA
2092                     ));
2093             }
2094 #endif //UDF_FORMAT_MEDIA
2095 
2096             if(TrackNumber == DiscInfo->FirstTrackNum) {
2097                 if(!(Vcb->TrackMap[TrackNumber].FirstLba & 0x80000000)) {
2098                     UDFPrint(("TrkInfo: Update FirstLBA (%x)\n", Vcb->TrackMap[TrackNumber].FirstLba));
2099                     Vcb->FirstLBA = Vcb->TrackMap[TrackNumber].FirstLba;
2100                 }
2101             }
2102             if((TrackInfoOut->SesNum == Vcb->LastSession) && !Vcb->FirstTrackNumLastSes) {
2103                 if(!(Vcb->TrackMap[TrackNumber].FirstLba & 0x80000000)) {
2104                     UDFPrint(("TrkInfo: Update FirstLBALastSes (%x)\n", Vcb->TrackMap[TrackNumber].FirstLba));
2105                     Vcb->FirstLBALastSes = Vcb->TrackMap[TrackNumber].FirstLba;
2106                 }
2107                 Vcb->FirstTrackNumLastSes = TrackNumber;
2108             }
2109         }
2110 
2111         if(!(TrackInfoOut->NextWriteLBA & 0x80000000) &&
2112            !(TrackInfoOut->TrackLength  & 0x80000000) &&
2113             (Vcb->NWA < TrackInfoOut->NextWriteLBA)
2114            ) {
2115             UDFPrint((" set NWA to %x\n", TrackInfoOut->NextWriteLBA));
2116             if(Vcb->MediaClassEx != CdMediaClass_DVDpRW) {
2117                 Vcb->NWA = TrackInfoOut->NextWriteLBA;
2118             } else {
2119                 Vcb->NWA =
2120                     TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0);
2121             }
2122         }
2123         if(Vcb->MediaClassEx != CdMediaClass_DVDpRW &&
2124            !(TrackInfoOut->TrackLength & 0x80000000) &&
2125            TrackInfoOut->TrackLength > 1) {
2126             Vcb->LastPossibleLBA =
2127                 TrackInfoOut->TrackStartLBA + TrackInfoOut->TrackLength - (TrackInfoOut->TrackLength ? 1 : 0);
2128             UDFPrint((" set LastPossibleLBA=%x\n", Vcb->LastPossibleLBA));
2129         }
2130         TrackNumber = Vcb->LastTrackNum;
2131         // quick formatted +RW returns bogus value
2132         if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) {
2133             UDFPrint((" check quick formatted +RW\n"));
2134             if(Vcb->TrackMap[TrackNumber].LastLba &&
2135                !(Vcb->TrackMap[TrackNumber].LastLba & 0x80000000) &&
2136                Vcb->TrackMap[TrackNumber].LastLba < Vcb->LastPossibleLBA /*&&
2137                Vcb->TrackMap[TrackNumber].LastLba != Vcb->LastPossibleLBA*/
2138                ) {
2139                 UDFPrint((" track LastLBA %x != LastPossibleLBA %x, verify\n",
2140                     Vcb->TrackMap[TrackNumber].LastLba, Vcb->LastPossibleLBA));
2141 
2142                 if(Vcb->MRWStatus == DiscInfo_BGF_Complete) {
2143                     UDFPrint((" complete MRW state\n"));
2144 #ifdef _BROWSE_UDF_
2145                     Vcb->LastPossibleLBA =
2146                     Vcb->NWA =
2147                     Vcb->LastLBA =
2148                     Vcb->TrackMap[TrackNumber].LastLba;
2149                     goto valid_track_length;
2150 #endif // _BROWSE_UDF_
2151                 } else
2152                 if(Vcb->MRWStatus) {
2153                     uint8* buff;
2154                     SIZE_T ReadBytes;
2155 
2156                     UDFPrint((" MRW state %x\n", Vcb->MRWStatus));
2157 
2158                     buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' );
2159                     if(buff) {
2160                         RC = UDFTRead(Vcb,
2161                                        buff,
2162                                        Vcb->WriteBlockSize,
2163                                        Vcb->TrackMap[TrackNumber].LastLba+1,
2164                                        &ReadBytes,
2165                                        PH_TMP_BUFFER);
2166                         DbgFreePool(buff);
2167                         if(!OS_SUCCESS(RC)) {
2168                             UDFPrint((" Can't read beyond track LastLBA (%x)\n", Vcb->TrackMap[TrackNumber].LastLba+1));
2169                             Vcb->LastLBA = Vcb->TrackMap[TrackNumber].LastLba;
2170                             Vcb->NWA = Vcb->LastLBA+1;
2171                             Vcb->TrackMap[TrackNumber].NWA_V = 1;
2172                             Vcb->TrackMap[TrackNumber].NWA = Vcb->NWA;
2173                             Vcb->TrackMap[TrackNumber].LastLba = Vcb->LastPossibleLBA;
2174                             RC = STATUS_SUCCESS;
2175                             goto valid_track_length;
2176                         }
2177                     }
2178                 }
2179             }
2180             UDFPrint((" set track LastLBA %x\n", Vcb->LastPossibleLBA));
2181             Vcb->NWA =
2182             Vcb->LastLBA =
2183             Vcb->TrackMap[TrackNumber].LastLba =
2184                 Vcb->LastPossibleLBA;
2185         }
2186 valid_track_length:
2187         // Test for last empty session
2188         if((Vcb->TrackMap[TrackNumber].Session !=
2189             Vcb->TrackMap[TrackNumber-1].Session) &&
2190            (Vcb->LastSession > 1)) {
2191             // Note: some devices return negative track length
2192             if((Vcb->TrackMap[TrackNumber].LastLba <=
2193                 Vcb->TrackMap[TrackNumber].FirstLba) ||
2194                (Vcb->TrackMap[TrackNumber].FirstLba ==
2195                 Vcb->TrackMap[TrackNumber].NWA)) {
2196                 // empty last session...
2197                 Vcb->LastTrackNum--;
2198 //                TrackNumber--;
2199 /*                for(SesNum = Vcb->TrackMap[TrackNumber].Session;
2200                     Vcb->TrackMap[TrackNumber].Session == SesNum;
2201                     TrackNumber--) {
2202                 }*/
2203                 if(TrackNumber>1)
2204                     Vcb->LastSession = Vcb->TrackMap[TrackNumber-1].Session;
2205             }
2206         }
2207 
2208         TrackNumber = Vcb->LastTrackNum;
2209 #ifdef _BROWSE_UDF_
2210         Vcb->LastLBA = min(Vcb->TrackMap[TrackNumber].LastLba, Vcb->TrackMap[TrackNumber].NWA);
2211 #endif //_BROWSE_UDF_
2212 
2213         if(Vcb->TrackMap[TrackNumber].NWA_V & TrkInfo_NWA_V) {
2214             UDFPrint((" NWA ok, set LastLBA to min(Last %x, NWA %x\n",
2215                 Vcb->TrackMap[TrackNumber].LastLba,
2216                 Vcb->TrackMap[TrackNumber].NWA));
2217             Vcb->LastLBA = min(Vcb->TrackMap[TrackNumber].LastLba, Vcb->TrackMap[TrackNumber].NWA);
2218         } else {
2219             UDFPrint((" no NWA, set LastLBA to Last %x\n", Vcb->TrackMap[TrackNumber].LastLba));
2220             Vcb->LastLBA = Vcb->TrackMap[TrackNumber].LastLba;
2221         }
2222 
2223         Vcb->VCBFlags |= UDF_VCB_FLAGS_TRACKMAP;
2224         if(!PacketTrack && Vcb->MediaClassEx != CdMediaClass_DVDRAM ) {
2225             UDFPrint((" disable Raw mount\n"));
2226             Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
2227         }
2228 
2229 try_exit:    NOTHING;
2230 
2231     } _SEH2_FINALLY {
2232         if(DiscInfo) MyFreePool__(DiscInfo);
2233         if(TrackInfoOut) MyFreePool__(TrackInfoOut);
2234     } _SEH2_END;
2235 
2236     return RC;
2237 } // end UDFReadDiscTrackInfo()
2238 
2239 /*
2240     This routine attempts to read disk layout using ReadFullTOC cmd
2241  */
2242 OSSTATUS
UDFReadAndProcessFullToc(PDEVICE_OBJECT DeviceObject,PVCB Vcb)2243 UDFReadAndProcessFullToc(
2244     PDEVICE_OBJECT DeviceObject, // the target device object
2245     PVCB           Vcb
2246     )
2247 {
2248     OSSTATUS                RC = STATUS_SUCCESS;
2249     PREAD_FULL_TOC_USER_OUT toc = (PREAD_FULL_TOC_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(READ_FULL_TOC_USER_OUT) );
2250     uint32 index;
2251     uint8 POINT;
2252     uint8 CurTrack = 0;
2253     uint32 LastLeadOut = 0;
2254 //    BOOLEAN IsMRW = FALSE;
2255 
2256     UDFPrint(("UDFReadAndProcessFullToc\n"));
2257 
2258     if(!toc) return STATUS_INSUFFICIENT_RESOURCES;
2259     Vcb->FirstTrackNum = 0xFF;
2260 
2261     RtlZeroMemory(toc,sizeof(READ_FULL_TOC_USER_OUT));
2262 
2263     RC = UDFPhSendIOCTL(IOCTL_CDRW_READ_FULL_TOC,DeviceObject,
2264         NULL,0,
2265         toc,sizeof(READ_FULL_TOC_USER_OUT),
2266         TRUE,NULL);
2267 
2268     if(!OS_SUCCESS(RC)) {
2269 
2270         MyFreePool__(toc);
2271         return RC;
2272     }
2273 
2274 #ifdef _CONSOLE
2275     Vcb->PhDeviceType = FILE_DEVICE_CD_ROM;
2276 #endif //_CONSOLE
2277     Vcb->LastSession = toc->Sessions.Last_TrackSes;
2278 
2279     RC = UDFReallocTrackMap(Vcb, 0x100);
2280     if(!OS_SUCCESS(RC)) {
2281         MyFreePool__(toc);
2282         return RC;
2283     }
2284 
2285     // get LastPossibleLBA
2286 
2287     // Note: some drives return Full TOC items unordered.
2288     // So, LeadOut position may come before Track definition.
2289     // In order to handle such situation, we must initialize
2290     // CurTrack when First or Last Track descriptor comes
2291     for (index=0;(index<MAXIMUM_NUMBER_OF_SESSIONS);index++) {
2292 /*        if((toc->SessionData[index].Adr == TOC_ADR_TrackInfo) &&
2293            ((toc->SessionData[index].Control == TOC_CTL_MRWTrackInfo) || (toc->SessionData[index].Control == TOC_CTL_MRWLastSes))) {
2294             IsMRW = TRUE;
2295         }*/
2296         if(toc->SessionData[index].Adr == 1) {
2297             switch (POINT = toc->SessionData[index].POINT) {
2298             case POINT_FirstTrackNum: {
2299                 Vcb->FirstTrackNum = toc->SessionData[index].Params.FirstTrackNum.FirstTrackNum;
2300                 if(!CurTrack)
2301                     CurTrack = (uint8)(Vcb->FirstTrackNum);
2302                 break;
2303                 }
2304             case POINT_LastTrackNum: {
2305                 Vcb->LastTrackNum = toc->SessionData[index].Params.LastTrackNum.LastTrackNum;
2306                 if(CurTrack < Vcb->LastTrackNum)
2307                     CurTrack = (uint8)(Vcb->FirstTrackNum);
2308                 break;
2309                 }
2310             case POINT_StartPositionOfLeadOut: {
2311 #define TempMSF toc->SessionData[index].Params.StartPositionOfLeadOut.MSF
2312                 Vcb->TrackMap[CurTrack].LastLba = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]);
2313                 LastLeadOut = max(LastLeadOut, Vcb->TrackMap[CurTrack].LastLba);
2314 #undef TempMSF
2315                 break;
2316                 }
2317             default: {
2318                 if( (Vcb->FirstTrackNum != 0x0FF) &&
2319                      (toc->SessionData[index].POINT == Vcb->FirstTrackNum) ) {
2320 #define TempMSF toc->SessionData[index].Params.StartPositionOfTrack.MSF
2321                     Vcb->FirstLBA = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]);
2322                     if(Vcb->FirstLBA & 0x80000000) {
2323                         Vcb->FirstLBA = 0;
2324                     }
2325 #undef TempMSF
2326                 }
2327                 break;
2328                 }
2329             }
2330             if((POINT >= POINT_StartPositionOfTrack_Min) &&
2331                (POINT <= POINT_StartPositionOfTrack_Max)) {
2332 #define TempMSF toc->SessionData[index].Params.StartPositionOfTrack.MSF
2333                 Vcb->TrackMap[POINT].FirstLba = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2])-1;
2334                 if(Vcb->TrackMap[POINT].FirstLba & 0x80000000) {
2335                     if(POINT == 1) {
2336                         Vcb->TrackMap[POINT].FirstLba = 0;
2337                     } else {
2338                         if(Vcb->TrackMap[POINT-1].LastLba) {
2339                             Vcb->TrackMap[POINT].FirstLba = Vcb->TrackMap[POINT-1].LastLba+1;
2340                         }
2341                     }
2342                 }
2343 #undef TempMSF
2344                 if(POINT > POINT_StartPositionOfTrack_Min) {
2345                     Vcb->TrackMap[POINT-1].LastLba = Vcb->TrackMap[POINT].FirstLba-1;
2346                 }
2347                 CurTrack = POINT;
2348             }
2349         } else
2350         if(toc->SessionData[index].Adr == 5) {
2351             switch (POINT = toc->SessionData[index].POINT) {
2352             case POINT_StartPositionOfNextProgramArea: {
2353 #define TempMSF toc->SessionData[index].Params.StartPositionOfNextProgramArea.MaxLeadOut_MSF
2354                 Vcb->LastPossibleLBA = MSF_TO_LBA(TempMSF[0],TempMSF[1],TempMSF[2]);
2355 #undef TempMSF
2356                 break;
2357                 }
2358             default: {
2359                 break;
2360                 }
2361             }
2362         }
2363 
2364     }
2365 
2366 /*    if(!IsMRW) {
2367         UDFPrint(("No MRW\n"));
2368         Vcb->CompatFlags &= ~UDF_VCB_IC_MRW_ADDR_PROBLEM;
2369     }*/
2370 //        Vcb->CompatFlags &= ~UDF_VCB_IC_MRW_ADDR_PROBLEM;
2371     // some devices report LastTrackNum=0 for full disks
2372     Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum);
2373     Vcb->TrackMap[Vcb->LastTrackNum].LastLba = max(LastLeadOut, Vcb->TrackMap[Vcb->LastTrackNum].LastLba);
2374 
2375     Vcb->LastLBA = Vcb->TrackMap[Vcb->LastTrackNum].LastLba;
2376 
2377     MyFreePool__(toc);
2378 //    Vcb->LastLBA=PacketVariable2Fixed(Vcb->LastLBA)-2;
2379     return STATUS_SUCCESS;
2380 } // end UDFReadAndProcessFullToc()
2381 
2382 /*
2383     use standard way to determine disk layout (ReadTOC cmd)
2384  */
2385 OSSTATUS
UDFUseStandard(PDEVICE_OBJECT DeviceObject,PVCB Vcb)2386 UDFUseStandard(
2387     PDEVICE_OBJECT DeviceObject, // the target device object
2388     PVCB           Vcb           // Volume control block from this DevObj
2389     )
2390 {
2391     OSSTATUS                RC = STATUS_SUCCESS;
2392     PREAD_TOC_USER_OUT      toc = (PREAD_TOC_USER_OUT)MyAllocatePool__(NonPagedPool,max(Vcb->BlockSize, sizeof(READ_TOC_USER_OUT)) );
2393     PGET_LAST_SESSION_USER_OUT LastSes = (PGET_LAST_SESSION_USER_OUT)MyAllocatePool__(NonPagedPool,sizeof(GET_LAST_SESSION_USER_OUT) );
2394     uint32                  LocalTrackCount;
2395 //    uint32                  LocalTocLength;
2396     uint32                  TocEntry;
2397 #ifdef _BROWSE_UDF_
2398     uint32                  OldTrkNum;
2399     uint32                  TrkNum;
2400     SIZE_T                  ReadBytes, i, len;
2401 #endif //_BROWSE_UDF_
2402 #ifdef UDF_FORMAT_MEDIA
2403     PUDFFmtState            fms = Vcb->fms;
2404 #else
2405   #define fms FALSE
2406 #endif //UDF_FORMAT_MEDIA
2407 
2408     UDFPrint(("UDFUseStandard\n"));
2409 
2410     _SEH2_TRY {
2411 
2412         if(!toc || !LastSes) {
2413             try_return (RC = STATUS_INSUFFICIENT_RESOURCES);
2414         }
2415         RtlZeroMemory(toc,sizeof(READ_TOC_TOC));
2416 
2417         Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_STD;
2418 
2419         RC = UDFPhSendIOCTL(IOCTL_CDROM_READ_TOC,DeviceObject,
2420             toc,sizeof(READ_TOC_USER_OUT),
2421             toc,sizeof(READ_TOC_USER_OUT),
2422             TRUE,NULL );
2423 
2424         if((RC == STATUS_DEVICE_NOT_READY) || (RC == STATUS_NO_MEDIA_IN_DEVICE)) {
2425             try_return(RC);
2426         }
2427 #ifdef UDF_FORMAT_MEDIA
2428         if(fms->opt_media == MT_none) {
2429             try_return(RC = STATUS_NO_MEDIA_IN_DEVICE);
2430         }
2431 #endif //UDF_FORMAT_MEDIA
2432 
2433         // If even standard read toc does not work, then use default values
2434         if(!OS_SUCCESS(RC)) {
2435 
2436             RC = UDFReallocTrackMap(Vcb, 2);
2437             if(!OS_SUCCESS(RC)) {
2438                 try_return(RC);
2439             }
2440 
2441             Vcb->LastSession=1;
2442             Vcb->FirstTrackNum=1;
2443 //            Vcb->FirstLBA=0;
2444             Vcb->LastTrackNum=1;
2445             Vcb->TrackMap[1].FirstLba = Vcb->FirstLBA;
2446             Vcb->TrackMap[1].LastLba = Vcb->LastLBA;
2447             Vcb->TrackMap[1].PacketSize = PACKETSIZE_UDF;
2448 #ifdef UDF_FORMAT_MEDIA
2449             if(!fms) {
2450 #endif //UDF_FORMAT_MEDIA
2451 
2452 #ifdef _BROWSE_UDF_
2453 #ifdef UDF_HDD_SUPPORT
2454                 if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) {
2455                     try_return(RC = STATUS_SUCCESS);
2456                 }
2457 #endif //UDF_HDD_SUPPORT
2458 #endif //_BROWSE_UDF_
2459 
2460 #ifdef UDF_FORMAT_MEDIA
2461             } else {
2462 
2463                 if(fms->opt_media == MT_HD) {
2464                     Vcb->LastPossibleLBA = Vcb->LastLBA;
2465                     try_return(RC = STATUS_SUCCESS);
2466                 }
2467             }
2468 #endif //UDF_FORMAT_MEDIA
2469             Vcb->LastPossibleLBA = max(Vcb->LastLBA, DEFAULT_LAST_LBA_FP_CD);
2470             Vcb->TrackMap[1].DataParam = TrkInfo_Dat_XA | TrkInfo_FP | TrkInfo_Packet;
2471             Vcb->TrackMap[1].TrackParam = TrkInfo_Trk_XA;
2472             Vcb->TrackMap[1].NWA = 0xffffffff;
2473             Vcb->NWA = DEFAULT_LAST_LBA_FP_CD + 7 + 1;
2474             try_return(RC = STATUS_SUCCESS);
2475         }
2476 
2477 #ifdef _CONSOLE
2478         Vcb->PhDeviceType = FILE_DEVICE_CD_ROM;
2479 #endif //_CONSOLE
2480 
2481         LocalTrackCount = toc->Tracks.Last_TrackSes - toc->Tracks.First_TrackSes + 1;
2482 //        LocalTocLength = PtrOffset( toc, &(toc->TrackData[LocalTrackCount + 1]) );  /* FIXME ReactOS Assume PtrOffset is not changing it's arguments? */
2483 
2484         // Get out if there is an immediate problem with the TOC.
2485         if(toc->Tracks.First_TrackSes > toc->Tracks.Last_TrackSes) {
2486             try_return(RC = STATUS_DISK_CORRUPT_ERROR);
2487         }
2488 
2489 #ifdef _BROWSE_UDF_
2490         Vcb->LastTrackNum=toc->Tracks.Last_TrackSes;
2491         Vcb->FirstTrackNum=toc->Tracks.First_TrackSes;
2492         // some devices report LastTrackNum=0 for full disks
2493         Vcb->LastTrackNum = max(Vcb->LastTrackNum, Vcb->FirstTrackNum);
2494 
2495         RC = UDFReallocTrackMap(Vcb, MAXIMUM_NUMBER_OF_TRACKS+1);
2496 /*        if(Vcb->TrackMap) {
2497             MyFreePool__(Vcb->TrackMap);
2498             Vcb->TrackMap = NULL;
2499         }
2500         Vcb->TrackMap = (PUDFTrackMap)
2501             MyAllocatePool__(NonPagedPool, (MAXIMUM_NUMBER_OF_TRACKS+1)*sizeof(UDFTrackMap));
2502         if(!Vcb->TrackMap) {
2503             MyFreePool__(toc);
2504             return STATUS_INSUFFICIENT_RESOURCES;
2505         }
2506         RtlZeroMemory(Vcb->TrackMap,(MAXIMUM_NUMBER_OF_TRACKS+1)*sizeof(UDFTrackMap));
2507 */
2508         if(!OS_SUCCESS(RC)) {
2509             BrutePoint();
2510             try_return(RC);
2511         }
2512         // find 1st and last session
2513         RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_LAST_SESSION,DeviceObject,
2514             LastSes,sizeof(GET_LAST_SESSION_USER_OUT),
2515             LastSes,sizeof(GET_LAST_SESSION_USER_OUT),
2516             TRUE,NULL );
2517 
2518         if(OS_SUCCESS(RC)) {
2519             TrkNum = LastSes->LastSes_1stTrack.TrackNum;
2520             Vcb->LastSession = LastSes->Sessions.First_TrackSes;
2521             for(TocEntry=0;TocEntry<LocalTrackCount + 1;TocEntry++) {
2522                 if(toc->TrackData[TocEntry].TrackNum == TrkNum) {
2523                     Vcb->TrackMap[TrkNum].Session = Vcb->LastSession;
2524                 }
2525             }
2526         }
2527 
2528         OldTrkNum = 0;
2529         // Scan toc for first & last LBA
2530         for(TocEntry=0;TocEntry<LocalTrackCount + 1;TocEntry++) {
2531 #define TempMSF toc->TrackData[TocEntry].LBA
2532             TrkNum = toc->TrackData[TocEntry].TrackNum;
2533 #ifdef UDF_DBG
2534             if (TrkNum >= MAXIMUM_NUMBER_OF_TRACKS &&
2535                 TrkNum != TOC_LastTrack_ID) {
2536                 UDFPrint(("UDFUseStandard: Array out of bounds\n"));
2537                 BrutePoint();
2538                 try_return(RC = STATUS_SUCCESS);
2539             }
2540             UDFPrint(("Track N %d (0x%x) first LBA %ld (%lx) \n",TrkNum,TrkNum,
2541                 MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]),
2542                 MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3])));
2543 #endif // UDF_DBG
2544             if(Vcb->FirstTrackNum == TrkNum) {
2545                 Vcb->FirstLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]);
2546                 if(Vcb->FirstLBA & 0x80000000) {
2547                     Vcb->FirstLBA = 0;
2548                 }
2549             }
2550             if(TOC_LastTrack_ID   == TrkNum) {
2551                 Vcb->LastLBA  = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3])-1;
2552                 Vcb->TrackMap[OldTrkNum].LastLba = Vcb->LastLBA-1;
2553                 UDFPrint(("UDFUseStandard: Last track entry, break TOC scan\n"));
2554 //                continue;
2555                 break;
2556             } else {
2557                 Vcb->TrackMap[TrkNum].FirstLba = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]);
2558                 if(Vcb->TrackMap[TrkNum].FirstLba & 0x80000000)
2559                     Vcb->TrackMap[TrkNum].FirstLba = 0;
2560                 if(TrkNum) {
2561                     if (TOC_LastTrack_ID == OldTrkNum) {
2562                         UDFPrint(("UDFUseStandard: Wrong previous track number\n"));
2563                         BrutePoint();
2564                     } else {
2565                         Vcb->TrackMap[OldTrkNum].LastLba = Vcb->TrackMap[TrkNum].FirstLba-1;
2566                     }
2567                 }
2568             }
2569             // check track type
2570             switch(toc->TrackData[TocEntry].Control & TocControl_TrkMode_Mask) {
2571             case TocControl_TrkMode_Data:
2572             case TocControl_TrkMode_IncrData:
2573                 Vcb->TrackMap[TrkNum].DataParam = TrkInfo_Dat_XA;
2574                 Vcb->TrackMap[TrkNum].TrackParam = TrkInfo_Trk_XA;
2575                 break;
2576             default:
2577                 Vcb->TrackMap[TrkNum].DataParam = TrkInfo_Dat_unknown;
2578                 Vcb->TrackMap[TrkNum].TrackParam = TrkInfo_Trk_unknown;
2579             }
2580             OldTrkNum = TrkNum;
2581 #undef TempMSF
2582         }
2583 
2584         TrkNum = Vcb->LastTrackNum;
2585         RC = STATUS_SUCCESS;
2586         // find last _valid_ track
2587         for(;TrkNum;TrkNum--) {
2588             if((Vcb->TrackMap[TrkNum].DataParam  != TrkInfo_Dat_unknown) &&
2589                (Vcb->TrackMap[TrkNum].TrackParam != TrkInfo_Trk_unknown)) {
2590                 RC = STATUS_UNSUCCESSFUL;
2591                 Vcb->LastTrackNum = TrkNum;
2592                 break;
2593             }
2594         }
2595         // no valid tracks...
2596         if(!TrkNum) {
2597             UDFPrint(("UDFUseStandard: no valid tracks...\n"));
2598             try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
2599         }
2600         i = 0;
2601 
2602         // Check for last VP track. Some last sectors may belong to Link-data &
2603         // be unreadable. We should forget about them, because UDF needs
2604         // last _readable_ sector.
2605         while(!OS_SUCCESS(RC) && (i<8)) {
2606             RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, (int8*)toc, Vcb->BlockSize,
2607                        ((uint64)(Vcb->TrackMap[TrkNum].LastLba-i)) << Vcb->BlockSizeBits, &ReadBytes, PH_TMP_BUFFER);
2608             i++;
2609         }
2610         if(OS_SUCCESS(RC)) {
2611             Vcb->LastLBA = Vcb->TrackMap[TrkNum].LastLba-i+1;
2612 /*            if(i) {
2613                 Vcb->TrackMap[TrkNum].PacketSize = PACKETSIZE_UDF;
2614                 Vcb->TrackMap[TrkNum].;
2615             }*/
2616         } else {
2617 
2618             // Check for FP track. READ_TOC reports actual track length, but
2619             // Link-data is hidden & unreadable for us. So, available track
2620             // length may be less than actual. Here we assume that Packet-size
2621             // is PACKETSIZE_UDF.
2622             i = 0;
2623             len = Vcb->TrackMap[TrkNum].LastLba - Vcb->TrackMap[TrkNum].FirstLba + 1;
2624             len = (uint32)(((int64)len*PACKETSIZE_UDF) / (PACKETSIZE_UDF+7));
2625 
2626             while(!OS_SUCCESS(RC) && (i<9)) {
2627                 RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, (int8*)toc, Vcb->BlockSize,
2628                            ((uint64)(Vcb->TrackMap[TrkNum].FirstLba-i+len)) << Vcb->BlockSizeBits, &ReadBytes, PH_TMP_BUFFER);
2629                 i++;
2630             }
2631             if(OS_SUCCESS(RC)) {
2632                 Vcb->LastLBA =
2633                 Vcb->TrackMap[TrkNum].LastLba = Vcb->TrackMap[TrkNum].FirstLba-i+len+1;
2634                 Vcb->TrackMap[TrkNum].PacketSize = PACKETSIZE_UDF;
2635 //                Vcb->TrackMap[TrkNum].;
2636             } else
2637             if(RC == STATUS_INVALID_DEVICE_REQUEST) {
2638                 // wrap return code from Audio-disk
2639                 RC = STATUS_SUCCESS;
2640             }
2641         }
2642 
2643 #ifdef UDF_CDRW_EMULATION_ON_ROM
2644         Vcb->LastPossibleLBA = Vcb->LastLBA+7+1+1024;
2645         Vcb->NWA = Vcb->LastLBA+7+1;
2646 #else
2647         Vcb->LastPossibleLBA =
2648         Vcb->NWA = Vcb->LastLBA+7+1;
2649 #endif //UDF_CDRW_EMULATION_ON_ROM
2650 
2651 #else //_BROWSE_UDF_
2652 
2653         Vcb->FirstTrackNum=toc->Tracks.Last_TrackSes;
2654         Vcb->LastTrackNum=toc->Tracks.First_TrackSes;
2655 
2656         // Scan toc for first & last LBA
2657         for(TocEntry=0;TocEntry<LocalTrackCount + 1;TocEntry++) {
2658 #define TempMSF toc->TrackData[TocEntry].LBA
2659             if(Vcb->FirstTrackNum == toc->TrackData[TocEntry].TrackNum) {
2660                 Vcb->FirstLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3]);
2661                 if(Vcb->FirstLBA & 0x80000000) {
2662                     Vcb->FirstLBA = 0;
2663                 }
2664             }
2665             if(TOC_LastTrack_ID   == toc->TrackData[TocEntry].TrackNum) {
2666                 Vcb->LastLBA = MSF_TO_LBA(TempMSF[1],TempMSF[2],TempMSF[3])-1;
2667             }
2668 #undef TempMSF
2669         }
2670 
2671 //        Vcb->LastLBA=PacketVariable2Fixed(Vcb->LastLBA)-2;
2672         Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_FP_CD;
2673 #endif //_BROWSE_UDF_
2674 try_exit: NOTHING;
2675     } _SEH2_FINALLY {
2676         if(toc) MyFreePool__(toc);
2677         if(LastSes) MyFreePool__(LastSes);
2678     } _SEH2_END;
2679 
2680     return RC;
2681 } // end UDFUseStandard()
2682 
2683 /*
2684     Get block size (for read operation)
2685  */
2686 OSSTATUS
UDFGetBlockSize(IN PDEVICE_OBJECT DeviceObject,IN PVCB Vcb)2687 UDFGetBlockSize(
2688     IN PDEVICE_OBJECT DeviceObject,      // the target device object
2689     IN PVCB           Vcb                // Volume control block from this DevObj
2690     )
2691 {
2692     OSSTATUS        RC = STATUS_SUCCESS;
2693     PDISK_GEOMETRY  DiskGeometry = (PDISK_GEOMETRY)MyAllocatePool__(NonPagedPool,sizeof(DISK_GEOMETRY));
2694     PPARTITION_INFORMATION  PartitionInfo = (PPARTITION_INFORMATION)MyAllocatePool__(NonPagedPool,sizeof(PARTITION_INFORMATION)*2);
2695 #ifdef UDF_FORMAT_MEDIA
2696     PUDFFmtState            fms = Vcb->fms;
2697 #else
2698   #define fms FALSE
2699 #endif //UDF_FORMAT_MEDIA
2700 
2701     if(!DiskGeometry || !PartitionInfo)
2702         try_return (RC = STATUS_INSUFFICIENT_RESOURCES);
2703 
2704 #ifdef _BROWSE_UDF_
2705 
2706 #ifdef UDF_HDD_SUPPORT
2707     if(!fms) {
2708         if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) {
2709             UDFPrint(("UDFGetBlockSize: HDD\n"));
2710             RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY,DeviceObject,
2711                 0,NULL,
2712                 DiskGeometry,sizeof(DISK_GEOMETRY),
2713                 TRUE,NULL );
2714             Vcb->BlockSize = (OS_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 512;
2715             if(!NT_SUCCESS(RC))
2716                 try_return(RC);
2717             RC = UDFPhSendIOCTL(IOCTL_DISK_GET_PARTITION_INFO,DeviceObject,
2718                 0,NULL,
2719                 PartitionInfo,sizeof(PARTITION_INFORMATION),
2720                 TRUE,NULL );
2721             if(!NT_SUCCESS(RC)) {
2722                 UDFPrint(("UDFGetBlockSize: IOCTL_DISK_GET_PARTITION_INFO failed\n"));
2723                 if(RC == STATUS_INVALID_DEVICE_REQUEST) /* ReactOS Code Change (was =) */
2724                     RC = STATUS_UNRECOGNIZED_VOLUME;
2725                 try_return(RC);
2726             }
2727             if(PartitionInfo->PartitionType != PARTITION_IFS) {
2728                 UDFPrint(("UDFGetBlockSize: PartitionInfo->PartitionType != PARTITION_IFS\n"));
2729                 try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
2730             }
2731         } else {
2732 #endif //UDF_HDD_SUPPORT
2733             RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,DeviceObject,
2734                 DiskGeometry,sizeof(DISK_GEOMETRY),
2735                 DiskGeometry,sizeof(DISK_GEOMETRY),
2736                 TRUE,NULL );
2737 
2738             if(RC == STATUS_DEVICE_NOT_READY) {
2739                 // probably, the device is really busy, may be by CD/DVD recording
2740                 UserPrint(("  busy (0)\n"));
2741                 try_return(RC);
2742             }
2743 
2744             Vcb->BlockSize = (OS_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 2048;
2745 #ifdef UDF_HDD_SUPPORT
2746         }
2747     }
2748 #endif //UDF_HDD_SUPPORT
2749 
2750 #endif //_BROWSE_UDF_
2751 
2752 #ifdef UDF_FORMAT_MEDIA
2753     if(fms) {
2754         RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,DeviceObject,
2755             DiskGeometry,sizeof(DISK_GEOMETRY),
2756             DiskGeometry,sizeof(DISK_GEOMETRY),
2757             FALSE, NULL );
2758 
2759         if(!NT_SUCCESS(RC)) {
2760             RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY,DeviceObject,
2761                 DiskGeometry,sizeof(DISK_GEOMETRY),
2762                 DiskGeometry,sizeof(DISK_GEOMETRY),
2763                 FALSE, NULL );
2764             if(NT_SUCCESS(RC)) {
2765                 fms->opt_media = MT_HD;
2766                 RC = UDFPhSendIOCTL(IOCTL_DISK_GET_PARTITION_INFO,DeviceObject,
2767                     NULL,0,
2768                     PartitionInfo,sizeof(PARTITION_INFORMATION)*2,
2769                     FALSE, NULL );
2770                 if(!NT_SUCCESS(RC)) {
2771                     LONG HiOffs=0;
2772                     RC = SetFilePointer(DeviceObject->h,0,&HiOffs,FILE_END);
2773                 }
2774             }
2775         }
2776 
2777         if(RC == STATUS_DEVICE_NOT_READY) {
2778             // probably, the device is really busy, may be by CD/DVD recording
2779             UserPrint(("  busy\n"));
2780             try_return(RC );
2781         }
2782 
2783         Vcb->BlockSize = (NT_SUCCESS(RC)) ? DiskGeometry->BytesPerSector : 2048;
2784     }
2785 #endif //UDF_FORMAT_MEDIA
2786 
2787     // Block size must be an even multiple of 512
2788     switch (Vcb->BlockSize) {
2789         case 2048: Vcb->BlockSizeBits = 11; break;
2790 #ifdef UDF_HDD_SUPPORT
2791         case 512:  Vcb->BlockSizeBits = 9; break;
2792         case 1024: Vcb->BlockSizeBits = 10; break;
2793         case 4096: Vcb->BlockSizeBits = 12; break;
2794         case 8192: Vcb->BlockSizeBits = 13; break;
2795 #endif //UDF_HDD_SUPPORT
2796         default:
2797         {
2798             UserPrint(("UDF: Bad block size (%ld)\n", Vcb->BlockSize));
2799             try_return(RC = STATUS_UNSUCCESSFUL);
2800         }
2801     }
2802 
2803 #ifdef UDF_HDD_SUPPORT
2804     if(
2805 #ifdef _BROWSE_UDF_
2806         (!fms && (UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK))
2807                          ||
2808 #endif //_BROWSE_UDF_
2809 #ifdef UDF_FORMAT_MEDIA
2810         (fms && fms->opt_media == MT_HD)
2811                          ||
2812 #endif //UDF_FORMAT_MEDIA
2813          FALSE ) {
2814 
2815 #ifdef UDF_FORMAT_MEDIA
2816         if(fms && !NT_SUCCESS(RC))
2817             try_return(STATUS_UNSUCCESSFUL);
2818 #endif //UDF_FORMAT_MEDIA
2819 
2820         Vcb->FirstLBA=0;//(ULONG)(PartitionInfo->StartingOffset.QuadPart >> Vcb->BlockSizeBits);
2821         Vcb->LastPossibleLBA =
2822         Vcb->LastLBA = (uint32)(PartitionInfo->PartitionLength.QuadPart >> Vcb->BlockSizeBits)/* + Vcb->FirstLBA*/ - 1;
2823     } else {
2824 #endif //UDF_HDD_SUPPORT
2825         Vcb->FirstLBA=0;
2826         if(OS_SUCCESS(RC)) {
2827             Vcb->LastLBA = (uint32)(DiskGeometry->Cylinders.QuadPart *
2828                                     DiskGeometry->TracksPerCylinder *
2829                                     DiskGeometry->SectorsPerTrack - 1);
2830             if(Vcb->LastLBA == 0x7fffffff) {
2831                 Vcb->LastLBA = UDFIsDvdMedia(Vcb) ? DEFAULT_LAST_LBA_DVD : DEFAULT_LAST_LBA_FP_CD;
2832             }
2833         } else {
2834             Vcb->LastLBA = UDFIsDvdMedia(Vcb) ? DEFAULT_LAST_LBA_DVD : DEFAULT_LAST_LBA_FP_CD;
2835         }
2836         Vcb->LastPossibleLBA = Vcb->LastLBA;
2837 #ifdef UDF_HDD_SUPPORT
2838     }
2839 #endif //UDF_HDD_SUPPORT
2840 
2841 #ifdef _BROWSE_UDF_
2842 //    if(UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) {
2843         Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize;
2844 //    } else {
2845 //        Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize;
2846 //    }
2847 #else //_BROWSE_UDF_
2848     if(fms->opt_media == MT_HD) {
2849         Vcb->WriteBlockSize = Vcb->BlockSize;
2850     } else {
2851         Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize;
2852     }
2853 #endif //_BROWSE_UDF_
2854 
2855     RC = STATUS_SUCCESS;
2856 
2857 try_exit:   NOTHING;
2858 
2859     UDFPrint(("UDFGetBlockSize:\nBlock size is %x, Block size bits %x, Last LBA is %x\n",
2860               Vcb->BlockSize, Vcb->BlockSizeBits, Vcb->LastLBA));
2861 
2862     MyFreePool__(PartitionInfo);
2863     MyFreePool__(DiskGeometry);
2864     return RC;
2865 
2866 } // end UDFGetBlockSize()
2867 
2868 #ifdef _BROWSE_UDF_
2869 
2870 OSSTATUS
UDFCheckTrackFPAddressing(IN PVCB Vcb,IN ULONG TrackNum)2871 UDFCheckTrackFPAddressing(
2872 //    IN PDEVICE_OBJECT DeviceObject,      // the target device object
2873     IN PVCB           Vcb,               // Volume control block from this DevObj
2874     IN ULONG          TrackNum
2875     )
2876 {
2877     OSSTATUS RC = STATUS_SUCCESS;
2878 //    OSSTATUS RC2 = STATUS_UNSUCCESSFUL;
2879     uint32 lba=0;
2880     uint32 i;
2881     uint8* Buffer;
2882 //    SIZE_T ReadBytes;
2883 
2884     uint8  user_data;
2885 
2886     ULONG FirstChunkLen = 0;
2887 
2888     ULONG NextChunkLen = 0;
2889     ULONG NextChunkLenCount = 0;
2890 
2891     ULONG NextChunkLenOth = 0;
2892     ULONG NextChunkLenOthCount = 0;
2893 //    ULONG MRW_Offset = 0;
2894 
2895     PLL_READ_USER_IN pLLR_in;
2896     PCD_SECTOR_HEADER pHdr;
2897 /*    uint8 cMSF[3] = {0,2,0};
2898     uint8 cMSF1[3] = {0,2,1};*/
2899 
2900 
2901     if(!Vcb->TrackMap) {
2902         Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM;
2903         return STATUS_SUCCESS;
2904     }
2905 
2906     Buffer = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, max(Vcb->BlockSize,
2907                                                      sizeof(LL_READ_USER_IN)+16), 'pNWD');
2908     if(!Buffer)
2909         return STATUS_INSUFFICIENT_RESOURCES;
2910     pLLR_in = (PLL_READ_USER_IN)Buffer;
2911     pHdr = (PCD_SECTOR_HEADER)(Buffer+sizeof(LL_READ_USER_IN));
2912 
2913 /*    if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM) {
2914         MRW_Offset = (MRW_DMA_OFFSET/32)*39;
2915     }*/
2916 
2917     user_data = 0;
2918     for(i=0; i<=0x200; i++) {
2919 
2920         RtlZeroMemory(pLLR_in, sizeof(pLLR_in)+16);
2921         pLLR_in->ExpectedBlkType = ReadCd_BlkType_Any;
2922         pLLR_in->LBA = i;
2923         pLLR_in->NumOfBlocks = 1;
2924         pLLR_in->Flags.Flags = ReadCd_Header_Hdr;
2925 //        pLLR_in->UseMFS = FALSE; // already zero
2926 //        MOV_MSF(pLLR_in->Starting_MSF, cMSF);
2927 //        MOV_MSF(pLLR_in->Ending_MSF, cMSF1);
2928         RtlZeroMemory(pHdr, sizeof(CD_SECTOR_HEADER));
2929         RC = UDFPhSendIOCTL(IOCTL_CDRW_LL_READ, Vcb->TargetDeviceObject,
2930             pLLR_in, sizeof(LL_READ_USER_IN),
2931             pHdr, sizeof(CD_SECTOR_HEADER),
2932             TRUE, NULL );
2933 
2934 /*        RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, Buffer, Vcb->BlockSize,
2935                    ((uint64)(i+MRW_Offset)) << Vcb->BlockSizeBits, &ReadBytes, 0);*/
2936 
2937         // skip unreadable
2938         if(!OS_SUCCESS(RC)) {
2939             UDFPrint(("  Read error at lba %x\n", i));
2940             continue;
2941         }
2942 
2943         // skip strange (damaged ?) blocks
2944         if((pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask) != WParam_SubHdr_Mode1 &&
2945            (pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask) != WParam_SubHdr_Mode2) {
2946             UDFPrint(("  Unexpected data type (%x) at lba %x\n", pHdr->Mode.Flags & WParam_SubHdr_Mode_Mask, i));
2947             continue;
2948         }
2949 
2950         if((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) == WParam_SubHdr_Format_UserData &&
2951             !user_data) {
2952             lba = i;
2953         }
2954 
2955 /*        if(OS_SUCCESS(RC) && !OS_SUCCESS(RC2)) {
2956             lba = i;
2957         }*/
2958 
2959         if((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) != WParam_SubHdr_Format_UserData &&
2960             user_data) {
2961 //        if(!OS_SUCCESS(RC) && OS_SUCCESS(RC2)) {
2962             UDFPrint(("  %x - %x (%x sectors)\n", lba, i-1, i-lba));
2963             if(!FirstChunkLen) {
2964                 FirstChunkLen = i-lba;
2965             } else {
2966                 if(!NextChunkLen) {
2967                     NextChunkLen = i-lba;
2968                     NextChunkLenCount++;
2969                 } else {
2970                     if(NextChunkLen == i-lba) {
2971                         NextChunkLenCount++;
2972                     } else {
2973                         if((NextChunkLenOth+1) % (NextChunkLen+1)) {
2974                             NextChunkLenOth = i-lba;
2975                             NextChunkLenOthCount++;
2976                         } else {
2977                             NextChunkLenCount++;
2978                         }
2979                     }
2980                 }
2981             }
2982         }
2983         user_data = ((pHdr->Mode.Flags & WParam_SubHdr_Format_Mask) == WParam_SubHdr_Format_UserData);
2984 //        RC2 = RC;
2985     }
2986 
2987     DbgFreePool(Buffer);
2988 
2989     if(!NextChunkLenCount && !NextChunkLenOthCount) {
2990         Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM;
2991         return STATUS_SUCCESS;
2992     }
2993     if(NextChunkLenOthCount > NextChunkLenCount) {
2994         NextChunkLen = NextChunkLenOth;
2995     }
2996     if(NextChunkLen > PACKETSIZE_UDF+7) {
2997         Vcb->CompatFlags &= ~UDF_VCB_IC_FP_ADDR_PROBLEM;
2998         return STATUS_SUCCESS;
2999     }
3000     Vcb->TrackMap[TrackNum].DataParam &= ~TrkInfo_Dat_Mask;
3001     Vcb->TrackMap[TrackNum].DataParam |= TrkInfo_Dat_XA;
3002     Vcb->TrackMap[TrackNum].Flags |= TrackMap_FixFPAddressing;
3003     Vcb->TrackMap[TrackNum].PacketSize = 1;
3004     while(NextChunkLen >> Vcb->TrackMap[TrackNum].PacketSize) {
3005         Vcb->TrackMap[TrackNum].PacketSize++;
3006     }
3007     Vcb->TrackMap[TrackNum].PacketSize = 1 << (Vcb->TrackMap[TrackNum].PacketSize-1);
3008     Vcb->TrackMap[TrackNum].TrackFPOffset = NextChunkLen - FirstChunkLen;  // !!!!!
3009     Vcb->TrackMap[TrackNum].PacketFPOffset = Vcb->TrackMap[TrackNum].TrackFPOffset;//0;//NextChunkLenOth - FirstChunkLen;
3010     Vcb->TrackMap[TrackNum].LastLba = (Vcb->TrackMap[TrackNum].LastLba*Vcb->TrackMap[TrackNum].PacketSize) /
3011            (Vcb->TrackMap[TrackNum].PacketSize + 7);
3012 
3013     return STATUS_SUCCESS;
3014 } // end UDFCheckTrackFPAddressing()
3015 
3016 uint32
UDFFixFPAddress(IN PVCB Vcb,IN uint32 Lba)3017 UDFFixFPAddress(
3018     IN PVCB           Vcb,               // Volume control block from this DevObj
3019     IN uint32         Lba
3020     )
3021 {
3022     uint32 i = Vcb->LastReadTrack;
3023     uint32 pk;
3024     uint32 rel;
3025 
3026 //    if(Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM) {
3027     if(Vcb->TrackMap[i].Flags & TrackMap_FixMRWAddressing) {
3028         pk = Lba / MRW_DA_SIZE;
3029         rel = Lba % MRW_DA_SIZE;
3030         Lba = pk*MRW_DMA_SEGMENT_SIZE + rel;
3031         Lba += MRW_DMA_OFFSET;
3032     }
3033     if(Vcb->TrackMap[i].Flags & TrackMap_FixFPAddressing) {
3034         if(Lba < 0x20)
3035             return Lba;
3036         pk = Lba / Vcb->TrackMap[i].PacketSize;
3037         rel = Lba % Vcb->TrackMap[i].PacketSize;
3038         UDFPrint(("FixFPAddr: %x -> %x\n", Lba, pk*(Vcb->TrackMap[i].PacketSize+7) + rel));
3039         return pk*(Vcb->TrackMap[i].PacketSize+7) + rel /*- Vcb->TrackMap[i].PacketFPOffset*/;
3040     }
3041     return Lba;
3042 } // end UDFFixFPAddress()
3043 
3044 #endif //_BROWSE_UDF_
3045 
3046 /*
3047     detect device driver & try to read disk layout (use all methods)
3048  */
3049 OSSTATUS
UDFGetDiskInfo(IN PDEVICE_OBJECT DeviceObject,IN PVCB Vcb)3050 UDFGetDiskInfo(
3051     IN PDEVICE_OBJECT DeviceObject,      // the target device object
3052     IN PVCB           Vcb                // Volume control block from this DevObj
3053     )
3054 {
3055     OSSTATUS        RC = STATUS_UNRECOGNIZED_VOLUME;
3056     int8*           ioBuf = (int8*)MyAllocatePool__(NonPagedPool,4096);
3057     uint8 MediaType;
3058     PLUN_WRITE_PERF_DESC_USER WPerfDesc;
3059     uint32 i;
3060 //    BOOLEAN MRW_problem = FALSE;
3061     uint32 SavedFeatures = 0;
3062 #ifdef UDF_FORMAT_MEDIA
3063     PUDFFmtState            fms = Vcb->fms;
3064 #else
3065   #define fms FALSE
3066 #endif //UDF_FORMAT_MEDIA
3067 
3068     UDFPrint(("UDFGetDiskInfo\n"));
3069 
3070     if(!ioBuf) {
3071         return STATUS_INSUFFICIENT_RESOURCES;
3072     }
3073 
3074     _SEH2_TRY {
3075         RC = UDFGetBlockSize(DeviceObject, Vcb);
3076         if(!OS_SUCCESS(RC)) try_return(RC);
3077 
3078 
3079         // Get lower driver signature
3080         RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_SIGNATURE,DeviceObject,
3081             ioBuf,sizeof(GET_SIGNATURE_USER_OUT),
3082             ioBuf,sizeof(GET_SIGNATURE_USER_OUT),
3083             TRUE,NULL);
3084 
3085         if(!OS_SUCCESS(RC)) {
3086 
3087             RC = UDFUseStandard(DeviceObject, Vcb);
3088 #ifdef _BROWSE_UDF_
3089             if(!NT_SUCCESS(RC) || fms)
3090                 try_return(RC);
3091 
3092             // assume Device Recordable for now
3093             goto GetSignatureFailed;
3094 #endif //_BROWSE_UDF_
3095         }
3096 
3097         UDFPrint(("UDF: Signature of low driver is : %s \n",
3098             ((PGET_SIGNATURE_USER_OUT)(ioBuf))->VendorId));
3099 
3100         if(!strncmp( (const char *)(&( ((PGET_SIGNATURE_USER_OUT)(ioBuf))->VendorId[0]) ),
3101             Signature,strlen(Signature) )) {
3102             UDFPrint(("UDF: *****************************************\n"));
3103             UDFPrint(("UDF: ********* Our Device Driver Found ******\n"));
3104             UDFPrint(("UDF: *****************************************\n"));
3105 
3106             (Vcb->VCBFlags) |= UDF_VCB_FLAGS_OUR_DEVICE_DRIVER;
3107 #ifndef _BROWSE_UDF_
3108             // reset driver
3109 #ifdef UDF_FORMAT_MEDIA
3110             if(!fms->opt_probe) {
3111 #endif //UDF_FORMAT_MEDIA
3112                 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
3113                 // lock it
3114                 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(ioBuf))->PreventMediaRemoval = TRUE;
3115                 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
3116                                      DeviceObject,
3117                                      ioBuf,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
3118                                      NULL,0,
3119                                      FALSE, NULL);
3120 #ifdef UDF_FORMAT_MEDIA
3121             }
3122 #endif //UDF_FORMAT_MEDIA
3123 #endif //_BROWSE_UDF_
3124 //#else //_BROWSE_UDF_
3125             // get device features
3126             UDFPhSendIOCTL( IOCTL_CDRW_GET_DEVICE_INFO,
3127                                  DeviceObject,
3128                                  NULL,0,
3129                                  ioBuf,sizeof(GET_DEVICE_INFO_USER_OUT),
3130                                  FALSE,NULL);
3131 
3132             Vcb->SavedFeatures =
3133                 SavedFeatures = ((PGET_DEVICE_INFO_USER_OUT)ioBuf)->Features;
3134             if(!(SavedFeatures & CDRW_FEATURE_SYNC_ON_WRITE)) {
3135                 UDFPrint(("UDFGetDiskInfo: UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE\n"));
3136                 Vcb->CompatFlags |= UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE;
3137             }
3138             if(!(SavedFeatures & CDRW_FEATURE_FORCE_SYNC_BEFORE_READ)) {
3139                 UDFPrint(("UDFGetDiskInfo: UDF_VCB_IC_SYNCCACHE_BEFORE_READ\n"));
3140                 Vcb->CompatFlags |= UDF_VCB_IC_SYNCCACHE_BEFORE_READ;
3141             }
3142             if(SavedFeatures & CDRW_FEATURE_BAD_RW_SEEK) {
3143                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_BAD_RW_SEEK\n"));
3144                 Vcb->CompatFlags |= UDF_VCB_IC_BAD_RW_SEEK;
3145             }
3146             // we must check if this is FP-formatted disk in old devices
3147             // independently of MediaType they report
3148             if(SavedFeatures & CDRW_FEATURE_FP_ADDRESSING_PROBLEM) {
3149                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FP_ADDRESSING_PROBLEM ?\n"));
3150                 Vcb->CompatFlags |= UDF_VCB_IC_FP_ADDR_PROBLEM;
3151             }
3152             if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) {
3153                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM ?\n"));
3154             }
3155             if(SavedFeatures & CDRW_FEATURE_FORCE_SYNC_ON_WRITE) {
3156                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FORCE_SYNC_ON_WRITE\n"));
3157                 Vcb->VCBFlags |= UDF_VCB_FLAGS_FORCE_SYNC_CACHE;
3158             }
3159             if(SavedFeatures & CDRW_FEATURE_BAD_DVD_LAST_LBA) {
3160                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_BAD_DVD_LAST_LBA\n"));
3161                 Vcb->CompatFlags |= UDF_VCB_IC_BAD_DVD_LAST_LBA;
3162             }
3163             if(SavedFeatures & CDRW_FEATURE_STREAMING) {
3164                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_STREAMING\n"));
3165             }
3166             if(SavedFeatures & CDRW_FEATURE_OPC) {
3167                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_OPC -> assume OPCNum=1\n"));
3168                 Vcb->OPCNum = 1;
3169             }
3170 #ifdef UDF_FORMAT_MEDIA
3171             if(SavedFeatures & CDRW_FEATURE_FULL_BLANK_ON_FORMAT) {
3172                 UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_FULL_BLANK_ON_FORMAT\n"));
3173                 if((fms->opt_probe || fms->opt_smart_f)/* &&
3174                    (fms->format_media && fms->blank_media*/) {
3175                     UDFPrint(("UDFGetDiskInfo: force Full Erase\n"));
3176                     fms->opt_qblank = FALSE;
3177                 }
3178             }
3179 #endif //UDF_FORMAT_MEDIA
3180 #ifdef _BROWSE_UDF_
3181             // get device buffer size
3182             RC = UDFPhSendIOCTL( IOCTL_CDRW_BUFFER_CAPACITY,
3183                                  DeviceObject,
3184                                  NULL,0,
3185                                  ioBuf,sizeof(BUFFER_CAPACITY_BLOCK_USER_OUT),
3186                                  FALSE,NULL);
3187             if(NT_SUCCESS(RC)) {
3188                 Vcb->CdrwBufferSize = ((PBUFFER_CAPACITY_BLOCK_USER_OUT)ioBuf)->BufferLength;
3189             } else {
3190                 Vcb->CdrwBufferSize = 0;
3191             }
3192             UDFPrint(("UDFGetDiskInfo: CdrwBufferSize = %dKb\n", Vcb->CdrwBufferSize / 1024));
3193             Vcb->CdrwBufferSizeCounter = 0;
3194 #endif //_BROWSE_UDF_
3195             // get media type
3196             RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MEDIA_TYPE,DeviceObject,
3197                     NULL,0,ioBuf,sizeof(GET_MEDIA_TYPE_USER_OUT),
3198                     FALSE, NULL);
3199             if(!OS_SUCCESS(RC)) goto Try_FullToc;
3200             Vcb->MediaType =
3201             MediaType = ((PGET_MEDIA_TYPE_USER_OUT)ioBuf)->MediaType;
3202             UDFPrint(("UDFGetDiskInfo: MediaType %x\n", MediaType));
3203 
3204 #ifndef UDF_FORMAT_MEDIA
3205             // we shall ignore audio-disks
3206             switch(MediaType) {
3207             case MediaType_120mm_CDROM_AudioOnly:
3208             case MediaType_80mm_CDROM_AudioOnly:
3209             case MediaType_120mm_CDR_AudioOnly:
3210             case MediaType_80mm_CDR_AudioOnly:
3211             case MediaType_120mm_CDRW_AudioOnly:
3212             case MediaType_80mm_CDRW_AudioOnly:
3213 //            case :
3214                 UDFPrint(("UDFGetDiskInfo: we shall ignore audio-disks...\n"));
3215                 try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
3216             }
3217 #endif //UDF_FORMAT_MEDIA
3218 
3219             UDFPrint(("UDFGetDiskInfo: Check DVD-disks...\n"));
3220             RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_MEDIA_TYPE_EX,DeviceObject,
3221                     NULL,0,ioBuf,sizeof(GET_MEDIA_TYPE_EX_USER_OUT),
3222                     FALSE, NULL);
3223             if(!OS_SUCCESS(RC)) goto Try_FullToc;
3224             Vcb->MediaClassEx =
3225             MediaType = (((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->MediaClass);
3226             UDFPrint(("UDFGetDiskInfo: MediaClassEx %x\n", MediaType));
3227 
3228 #ifdef _BROWSE_UDF_
3229             if(!fms) {
3230 
3231                 switch(MediaType) {
3232 
3233                 case CdMediaClass_CDR:
3234                 case CdMediaClass_DVDR:
3235                 case CdMediaClass_DVDpR:
3236                 case CdMediaClass_HD_DVDR:
3237                 case CdMediaClass_BDR:
3238                     UDFPrint(("UDFGetDiskInfo: MediaClass R\n"));
3239                     Vcb->MediaType = MediaType_UnknownSize_CDR;
3240                     break;
3241                 case CdMediaClass_CDRW:
3242 
3243                     if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) {
3244                         UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on CD-RW\n"));
3245                         Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM;
3246                     }
3247 
3248                 case CdMediaClass_DVDRW:
3249                 case CdMediaClass_DVDpRW:
3250                 case CdMediaClass_DVDRAM:
3251                 case CdMediaClass_HD_DVDRW:
3252                 case CdMediaClass_HD_DVDRAM:
3253                 case CdMediaClass_BDRE:
3254                     UDFPrint(("UDFGetDiskInfo: MediaClass RW\n"));
3255                     Vcb->MediaType = MediaType_UnknownSize_CDRW;
3256                     break;
3257                 case CdMediaClass_CDROM:
3258                 case CdMediaClass_DVDROM:
3259                 case CdMediaClass_HD_DVDROM:
3260                 case CdMediaClass_BDROM:
3261                     UDFPrint(("UDFGetDiskInfo: MediaClass ROM\n"));
3262                     Vcb->MediaType = MediaType_Unknown;
3263     //                    Vcb->MediaType = MediaType_UnknownSize_CDROM;
3264                     break;
3265                 default:
3266                     UDFPrint(("UDFGetDiskInfo: MediaClass Unknown\n"));
3267                     Vcb->MediaType = MediaType_Unknown;
3268                     break;
3269                 }
3270                 MediaType = Vcb->MediaType;
3271 
3272             }
3273 #endif //_BROWSE_UDF_
3274 
3275 #ifdef UDF_FORMAT_MEDIA
3276 
3277             if(fms) {
3278 
3279                 switch(MediaType) {
3280                 case CdMediaClass_CDR:
3281                     UDFPrint(("CdMediaClass_CDR\n"));
3282                     MediaType = MediaType_UnknownSize_CDR;
3283                     if(fms->opt_media == MT_AUTO)
3284                         fms->opt_media = MT_CDR;
3285                     break;
3286                 case CdMediaClass_DVDR:
3287                     UDFPrint(("CdMediaClass_DVDR -> MediaType_UnknownSize_CDR\n"));
3288                     MediaType = MediaType_UnknownSize_CDR;
3289                     if(fms->opt_media == MT_AUTO)
3290                         fms->opt_media = MT_DVDR;
3291                     break;
3292                 case CdMediaClass_DVDpR:
3293                     UDFPrint(("CdMediaClass_DVDpR -> MediaType_UnknownSize_CDR\n"));
3294                     MediaType = MediaType_UnknownSize_CDR;
3295                     if(fms->opt_media == MT_AUTO)
3296                         fms->opt_media = MT_DVDpR;
3297                     break;
3298                 case CdMediaClass_HD_DVDR:
3299                     UDFPrint(("CdMediaClass_HD_DVDR -> MediaType_UnknownSize_CDR\n"));
3300                     MediaType = MediaType_UnknownSize_CDR;
3301                     if(fms->opt_media == MT_AUTO)
3302                         fms->opt_media = MT_DVDR;
3303                     break;
3304                 case CdMediaClass_BDR:
3305                     UDFPrint(("CdMediaClass_BDR -> MediaType_UnknownSize_CDR\n"));
3306                     MediaType = MediaType_UnknownSize_CDR;
3307                     if(fms->opt_media == MT_AUTO)
3308                         fms->opt_media = MT_DVDR;
3309                     break;
3310                 case CdMediaClass_CDRW:
3311                     UDFPrint(("CdMediaClass_CDRW\n"));
3312                     MediaType = MediaType_UnknownSize_CDRW;
3313                     if(fms->opt_media == MT_AUTO)
3314                         fms->opt_media = MT_CDRW;
3315                     if(SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) {
3316                         UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on CD-RW\n"));
3317                         Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM;
3318                     }
3319                     break;
3320                 case CdMediaClass_DVDRW:
3321                     UDFPrint(("  CdMediaClass_DVDRW -> MediaType_UnknownSize_CDRW\n"));
3322                     if(fms->opt_media == MT_AUTO)
3323                         fms->opt_media = MT_DVDRW;
3324                     MediaType = MediaType_UnknownSize_CDRW;
3325                     break;
3326                 case CdMediaClass_DVDpRW:
3327                     UDFPrint(("  CdMediaClass_DVDpRW -> MediaType_UnknownSize_CDRW\n"));
3328                     if(fms->opt_media == MT_AUTO)
3329                         fms->opt_media = MT_DVDpRW;
3330                     MediaType = MediaType_UnknownSize_CDRW;
3331                     break;
3332                 case CdMediaClass_DVDRAM:
3333                     UDFPrint(("  CdMediaClass_DVDRAM -> MediaType_UnknownSize_CDRW\n"));
3334                     if(fms->opt_media == MT_AUTO)
3335                         fms->opt_media = MT_DVDRAM;
3336                     MediaType = MediaType_UnknownSize_CDRW;
3337                     break;
3338                 case CdMediaClass_HD_DVDRW:
3339                     UDFPrint(("  CdMediaClass_HD_DVDRW -> MediaType_UnknownSize_CDRW\n"));
3340                     if(fms->opt_media == MT_AUTO)
3341                         fms->opt_media = MT_DVDRW;
3342                     MediaType = MediaType_UnknownSize_CDRW;
3343                     break;
3344                 case CdMediaClass_HD_DVDRAM:
3345                     UDFPrint(("  CdMediaClass_HD_DVDRAM -> MediaType_UnknownSize_CDRW\n"));
3346                     if(fms->opt_media == MT_AUTO)
3347                         fms->opt_media = MT_DVDRAM;
3348                     MediaType = MediaType_UnknownSize_CDRW;
3349                     break;
3350                 case CdMediaClass_BDRE:
3351                     UDFPrint(("  CdMediaClass_BDRE -> MediaType_UnknownSize_CDRW\n"));
3352                     if(fms->opt_media == MT_AUTO)
3353                         fms->opt_media = MT_DVDRW;
3354                     MediaType = MediaType_UnknownSize_CDRW;
3355                     break;
3356                 case CdMediaClass_NoDiscPresent:
3357                     UDFPrint(("  CdMediaClass_NoDiscPresent -> MediaType_NoDiscPresent\n"));
3358                     MediaType = MediaType_NoDiscPresent;
3359                     fms->opt_media = MT_none;
3360                     break;
3361                 case CdMediaClass_DoorOpen:
3362                     UDFPrint(("  CdMediaClass_DoorOpen -> MediaType_DoorOpen\n"));
3363                     MediaType = MediaType_DoorOpen;
3364                     fms->opt_media = MT_none;
3365                     break;
3366                 default:
3367                     UDFPrint(("  MediaType_Unknown\n"));
3368                     MediaType = MediaType_Unknown;
3369                     break;
3370                 }
3371                 if(!apply_force_r(fms)) {
3372                     my_exit(fms, MKUDF_CANT_APPLY_R);
3373                 }
3374             }
3375 
3376 #endif //UDF_FORMAT_MEDIA
3377 
3378             Vcb->DVD_Mode = (((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->MediaClassEx == CdMediaClassEx_DVD);
3379             Vcb->PhMediaCapFlags = ((PGET_MEDIA_TYPE_EX_USER_OUT)ioBuf)->CapFlags;
3380             Vcb->WriteParamsReq = (Vcb->PhMediaCapFlags & CdCapFlags_WriteParamsReq) ? TRUE : FALSE;
3381             if(Vcb->DVD_Mode &&
3382                 !(Vcb->PhMediaCapFlags & CdCapFlags_RandomWritable)) {
3383                 UDFPrint(("UDFGetDiskInfo: DVD && !CdCapFlags_RandomWritable\n"));
3384                 UDFPrint(("  Read-only volume\n"));
3385 //                BrutePoint();
3386 #ifndef UDF_CDRW_EMULATION_ON_ROM
3387                 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
3388 #endif
3389             }
3390 #ifdef UDF_FORMAT_MEDIA
3391             if(fms) {
3392                 if((MediaType == MediaType_NoDiscPresent) ||
3393                    (MediaType == MediaType_DoorOpen)) {
3394                     UserPrint(("No media in device\n"));
3395                     my_exit(fms, MKUDF_NO_MEDIA_IN_DEVICE);
3396                 }
3397             }
3398 #endif //UDF_FORMAT_MEDIA
3399             if(!Vcb->WriteParamsReq) {
3400                 UDFPrint(("UDFGetDiskInfo: do not use WriteParams\n"));
3401             }
3402             if(Vcb->PhMediaCapFlags & CdCapFlags_Cav) {
3403                 UDFPrint(("UDFGetDiskInfo: Use CAV (1)\n"));
3404                 Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_CAV;
3405             }
3406 
3407 #ifdef _BROWSE_UDF_
3408             if(!fms) {
3409                 // check if this device is capable to write on such media
3410                 if(UDFIsDvdMedia(Vcb)) {
3411                     //RC =
3412                     UDFPrint(("UDFGetDiskInfo: update defaulted LastLBA\n"));
3413                     UDFGetBlockSize(DeviceObject,Vcb);
3414                     //if(!OS_SUCCESS(RC)) goto Try_FullToc;
3415                 } else {
3416                     if((SavedFeatures & CDRW_FEATURE_MRW_ADDRESSING_PROBLEM) &&
3417                        (SavedFeatures & UDF_VCB_IC_FP_ADDR_PROBLEM)) {
3418                         UDFPrint(("UDFGetDiskInfo: CDRW_FEATURE_MRW_ADDRESSING_PROBLEM on old CD-ROM\n"));
3419                         Vcb->CompatFlags |= UDF_VCB_IC_MRW_ADDR_PROBLEM;
3420                     }
3421                 }
3422             }
3423 #endif //_BROWSE_UDF_
3424 
3425 /*#ifdef UDF_FORMAT_MEDIA
3426             if(fms) {
3427                 if(MediaType == CdMediaClass_DVDRW) {
3428                     UserPrint(("Not empty media. Erase required.\n"));
3429                     my_exit(fms, MKUDF_BLANK_FORMAT_REQUIRED);
3430                 }
3431             }
3432 #endif //UDF_FORMAT_MEDIA*/
3433 
3434 #define cap ((PGET_CAPABILITIES_3_USER_OUT)ioBuf)
3435             // get device capabilities
3436             RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_CAPABILITIES,DeviceObject,
3437                     NULL,0,ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT),
3438                     FALSE, NULL);
3439             if(!OS_SUCCESS(RC)) goto Try_FullToc;
3440 
3441             // check if this device is capable to write on such media
3442             RC = UDFPhSendIOCTL(IOCTL_DISK_IS_WRITABLE,DeviceObject,
3443                     NULL,0,NULL,0,FALSE, NULL);
3444             if(RC != STATUS_SUCCESS) {
3445                 UDFPrint(("IS_WRITABLE - false, doing additional check...\n"));
3446                 if( ((MediaType >= MediaType_UnknownSize_CDRW) && !(cap->WriteCap & DevCap_write_cd_rw)) ||
3447                     ((MediaType >= MediaType_UnknownSize_CDR) && !(cap->WriteCap & DevCap_write_cd_r)) ||
3448                      (MediaType < MediaType_UnknownSize_CDR) ) {
3449                     UserPrint(("Hardware Read-only volume\n"));
3450 #ifndef UDF_CDRW_EMULATION_ON_ROM
3451                     Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
3452 #endif  //UDF_CDRW_EMULATION_ON_ROM
3453 #ifdef UDF_FORMAT_MEDIA
3454                     if(fms && !fms->opt_read_iso)
3455                         my_exit(fms, MKUDF_HW_READ_ONLY);
3456 #endif //UDF_FORMAT_MEDIA
3457                 }
3458             } else {
3459                 UDFPrint(("Writable disk\n"));
3460             }
3461             Vcb->MaxWriteSpeed = cap->MaximumWriteSpeedSupported;
3462             Vcb->MaxReadSpeed  = cap->MaximumSpeedSupported;
3463             if(cap->PageLength >= (sizeof(GET_CAPABILITIES_3_USER_OUT)-2)) {
3464                 Vcb->CurSpeed = max(cap->CurrentSpeed, cap->CurrentWriteSpeed3);
3465                 if(cap->LunWPerfDescriptorCount && cap->LunWPerfDescriptorCount != 0xffff) {
3466                     ULONG n;
3467                     UDFPrint(("Write performance descriptor(s) found: %x\n", cap->LunWPerfDescriptorCount));
3468                     n = (4096 - sizeof(GET_CAPABILITIES_3_USER_OUT)) / sizeof(LUN_WRITE_PERF_DESC_USER);
3469                     n = min(n, cap->LunWPerfDescriptorCount);
3470                     // get device capabilities
3471                     RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_CAPABILITIES,DeviceObject,
3472                             ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT)+n*sizeof(LUN_WRITE_PERF_DESC_USER),
3473                             ioBuf,sizeof(GET_CAPABILITIES_3_USER_OUT)+n*sizeof(LUN_WRITE_PERF_DESC_USER),
3474                             TRUE,NULL);
3475                     if(OS_SUCCESS(RC)) {
3476                         WPerfDesc = (PLUN_WRITE_PERF_DESC_USER)(ioBuf + sizeof(GET_CAPABILITIES_3_USER_OUT));
3477                         n = FALSE;
3478                         for(i = 0; i<n; i++) {
3479                             if((WPerfDesc[i].RotationControl & LunWPerf_RotCtrl_Mask) == LunWPerf_RotCtrl_CAV) {
3480                                 Vcb->VCBFlags |= UDF_VCB_FLAGS_USE_CAV;
3481                                 if(!n) {
3482                                     Vcb->CurSpeed = WPerfDesc[i].WriteSpeedSupported;
3483                                     n = TRUE;
3484                                     UDFPrint(("Use CAV\n"));
3485                                 } else {
3486                                     Vcb->CurSpeed = max(WPerfDesc[i].WriteSpeedSupported, Vcb->CurSpeed);
3487                                 }
3488                                 UDFPrint(("supports speed %dX\n", Vcb->CurSpeed/176));
3489                                 //break;
3490                             }
3491                         }
3492                         if(n) {
3493                             UDFPrint(("Set r/w speeds to %dX\n", Vcb->CurSpeed/176));
3494                             Vcb->MaxWriteSpeed =
3495                             Vcb->MaxReadSpeed  = Vcb->CurSpeed;
3496                         }
3497                     }
3498                 }
3499             } else {
3500                 Vcb->CurSpeed = max(cap->CurrentSpeed, cap->CurrentWriteSpeed);
3501             }
3502             UDFPrint((" Speeds r/w %dX/%dX\n", Vcb->CurSpeed/176, cap->CurrentWriteSpeed/176));
3503 
3504             if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) {
3505                 // limit both read & write speed to last write speed for CAV mode
3506                 // some drives damage data when speed is adjusted during recording process
3507                 // even in packet mode
3508                 UDFSetSpeeds(Vcb);
3509             }
3510             UDFSetCaching(Vcb);
3511 
3512 #undef cap
3513 #ifdef UDF_FORMAT_MEDIA
3514             if(fms) {
3515                 if( (fms->auto_media || (fms->opt_media == MT_AUTO)) &&
3516                        (fms->opt_media < MT_DVDR) ) {
3517                     if(MediaType < MediaType_UnknownSize_CDRW) {
3518                         fms->opt_media = MT_CDR;
3519                     } else {
3520                         fms->opt_media = MT_CDRW;
3521                     }
3522                 }
3523                 if(!apply_force_r(fms)) {
3524                     my_exit(fms, MKUDF_CANT_APPLY_R);
3525                 }
3526             }
3527 #endif //UDF_FORMAT_MEDIA
3528             RC = UDFReadDiscTrackInfo(DeviceObject, Vcb);
3529 
3530             if(!OS_SUCCESS(RC)) {
3531                 // may be we have a CD-ROM device
3532 Try_FullToc:
3533                 UDFPrint(("Hardware Read-only volume (2)\n"));
3534 //                BrutePoint();
3535 #ifndef UDF_CDRW_EMULATION_ON_ROM
3536                 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
3537 #endif
3538 
3539                 RC = UDFReadAndProcessFullToc(DeviceObject, Vcb);
3540 
3541                 if(!OS_SUCCESS(RC)) {
3542                     RC = UDFUseStandard(DeviceObject,Vcb);
3543                     if(!OS_SUCCESS(RC)) try_return(RC);
3544                 }
3545 
3546             }
3547         } else {
3548 #ifdef _BROWSE_UDF_
3549 GetSignatureFailed:
3550 #endif
3551             RC = UDFUseStandard(DeviceObject, Vcb);
3552             if(!OS_SUCCESS(RC)) try_return(RC);
3553         }
3554 
3555 try_exit:   NOTHING;
3556 
3557     } _SEH2_FINALLY {
3558 
3559         if(ioBuf) MyFreePool__(ioBuf);
3560 
3561         if(UDFIsDvdMedia(Vcb) &&
3562            (Vcb->CompatFlags & UDF_VCB_IC_BAD_DVD_LAST_LBA) &&
3563            (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) &&
3564             Vcb->LastLBA &&
3565            (Vcb->LastLBA < DEFAULT_LAST_LBA_DVD)) {
3566             UDFPrint(("UDF: Bad DVD last LBA %x, fixup!\n", Vcb->LastLBA));
3567             Vcb->LastLBA = DEFAULT_LAST_LBA_DVD;
3568             Vcb->NWA = 0;
3569         }
3570 
3571 
3572         if(UDFIsDvdMedia(Vcb) && !Vcb->FirstLBA && !Vcb->LastPossibleLBA) {
3573             UDFPrint(("UDF: Empty DVD. Use bogus values for now\n"));
3574             Vcb->LastPossibleLBA = DEFAULT_LAST_LBA_DVD;
3575             Vcb->LastLBA = 0;
3576         }
3577 
3578         if((Vcb->LastPossibleLBA & 0x80000000) || (Vcb->LastPossibleLBA < Vcb->LastLBA)) {
3579             UDFPrint(("UDF: bad LastPossibleLBA %x -> %x\n", Vcb->LastPossibleLBA, Vcb->LastLBA));
3580             Vcb->LastPossibleLBA = Vcb->LastLBA;
3581         }
3582         if(!Vcb->WriteBlockSize)
3583             Vcb->WriteBlockSize = PACKETSIZE_UDF*Vcb->BlockSize;
3584 
3585 #ifdef _BROWSE_UDF_
3586         if(Vcb->TrackMap) {
3587             if(Vcb->TrackMap[Vcb->LastTrackNum].LastLba > Vcb->NWA) {
3588                 if(Vcb->NWA) {
3589                     if(Vcb->TrackMap[Vcb->LastTrackNum].DataParam & TrkInfo_FP) {
3590                         Vcb->LastLBA = Vcb->NWA-1;
3591                     } else {
3592                         Vcb->LastLBA = Vcb->NWA-7-1;
3593                     }
3594                 }
3595             } else {
3596                 if((Vcb->LastTrackNum > 1) &&
3597                    (Vcb->TrackMap[Vcb->LastTrackNum-1].FirstLba >= Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) {
3598                     Vcb->LastLBA = Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba;
3599                 }
3600             }
3601         }
3602 
3603         for(i=0; i<32; i++) {
3604             if(!(Vcb->LastPossibleLBA >> i))
3605                 break;
3606         }
3607         if(i > 20) {
3608             Vcb->WCacheBlocksPerFrameSh = max(Vcb->WCacheBlocksPerFrameSh, (2*i)/5+2);
3609             Vcb->WCacheBlocksPerFrameSh = min(Vcb->WCacheBlocksPerFrameSh, 16);
3610         }
3611 
3612         if(Vcb->CompatFlags & UDF_VCB_IC_FP_ADDR_PROBLEM) {
3613             // Check first 0x200 blocks
3614             UDFCheckTrackFPAddressing(Vcb, Vcb->FirstTrackNum);
3615             // if we really have such a problem, fix LastLBA
3616             if(Vcb->CompatFlags & UDF_VCB_IC_FP_ADDR_PROBLEM) {
3617                 UDFPrint(("UDF: Fix LastLBA: %x -> %x\n", Vcb->LastLBA, (Vcb->LastLBA*32) / 39));
3618                 Vcb->LastLBA = (Vcb->LastLBA*32) / 39;
3619             }
3620         }
3621 #endif //_BROWSE_UDF_
3622 
3623         if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) {
3624             if(!Vcb->BlankCD && Vcb->MediaType != MediaType_UnknownSize_CDRW) {
3625                 UDFPrint(("UDFGetDiskInfo: R/O+!Blank+!RW -> !RAW\n"));
3626                 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
3627             } else {
3628                 UDFPrint(("UDFGetDiskInfo: Blank or RW\n"));
3629             }
3630         }
3631 
3632         UDFPrint(("UDF: ------------------------------------------\n"));
3633         UDFPrint(("UDF: Media characteristics\n"));
3634         UDFPrint(("UDF: Last session: %d\n",Vcb->LastSession));
3635         UDFPrint(("UDF: First track in first session: %d\n",Vcb->FirstTrackNum));
3636         UDFPrint(("UDF: First track in last session: %d\n",Vcb->FirstTrackNumLastSes));
3637         UDFPrint(("UDF: Last track in last session: %d\n",Vcb->LastTrackNum));
3638         UDFPrint(("UDF: First LBA in first session: %x\n",Vcb->FirstLBA));
3639         UDFPrint(("UDF: First LBA in last session: %x\n",Vcb->FirstLBALastSes));
3640         UDFPrint(("UDF: Last LBA in last session: %x\n",Vcb->LastLBA));
3641         UDFPrint(("UDF: First writable LBA (NWA) in last session: %x\n",Vcb->NWA));
3642         UDFPrint(("UDF: Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA));
3643         UDFPrint(("UDF: blocks per frame: %x\n",1 << Vcb->WCacheBlocksPerFrameSh));
3644         UDFPrint(("UDF: Flags: %s%s\n",
3645                  Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK ? "RAW " : "",
3646                  Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY ? "R/O " : "WR "
3647                  ));
3648         UDFPrint(("UDF: ------------------------------------------\n"));
3649 
3650 #ifdef UDF_FORMAT_MEDIA
3651         if(fms && fms->opt_disk_info) {
3652             UserPrint(("------------------------------------------\n"));
3653             UserPrint(("Media characteristics:\n"));
3654             UserPrint(("  First writable LBA (NWA) in last session: %x\n",Vcb->NWA));
3655             UserPrint(("  Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA));
3656             UserPrint(("------------------------------------------\n"));
3657         }
3658 #endif //UDF_FORMAT_MEDIA
3659 
3660     } _SEH2_END;
3661 
3662     UDFPrint(("UDFGetDiskInfo: %x\n", RC));
3663     return(RC);
3664 
3665 } // end UDFGetDiskInfo()
3666 
3667 //#ifdef _BROWSE_UDF_
3668 
3669 OSSTATUS
UDFPrepareForReadOperation(IN PVCB Vcb,IN uint32 Lba,IN uint32 BCount)3670 UDFPrepareForReadOperation(
3671     IN PVCB Vcb,
3672     IN uint32 Lba,
3673     IN uint32 BCount
3674     )
3675 {
3676     if( (Vcb->FsDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) ) {
3677         Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
3678         return STATUS_SUCCESS;
3679     }
3680     uint32 i = Vcb->LastReadTrack;
3681     BOOLEAN speed_changed = FALSE;
3682 #ifdef _BROWSE_UDF_
3683     PUCHAR tmp;
3684     OSSTATUS RC;
3685     SIZE_T ReadBytes;
3686 #endif //_BROWSE_UDF_
3687 
3688 #ifdef _UDF_STRUCTURES_H_
3689     if(Vcb->BSBM_Bitmap) {
3690         ULONG i;
3691         for(i=0; i<BCount; i++) {
3692             if(UDFGetBit((uint32*)(Vcb->BSBM_Bitmap), Lba+i)) {
3693                 UDFPrint(("R: Known BB @ %#x\n", Lba));
3694                 //return STATUS_FT_WRITE_RECOVERY; // this shall not be treated as error and
3695                                                    // we shall get IO request to BAD block
3696                 return STATUS_DEVICE_DATA_ERROR;
3697             }
3698         }
3699     }
3700 #endif //_UDF_STRUCTURES_H_
3701 
3702     if(!UDFIsDvdMedia(Vcb) &&
3703         (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) &&
3704        !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) &&
3705        !(Vcb->CompatFlags & UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE)){
3706 
3707 //        OSSTATUS RC;
3708 
3709         RC = UDFSyncCache(Vcb);
3710     }
3711     if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) &&
3712        !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) &&
3713 #ifndef UDF_FORMAT_MEDIA
3714         (Vcb->CompatFlags & UDF_VCB_IC_SYNCCACHE_BEFORE_READ) &&
3715 #endif //UDF_FORMAT_MEDIA
3716         TRUE)
3717     {
3718 //        OSSTATUS RC;
3719         UDFSyncCache(Vcb);
3720     }
3721 
3722 #ifdef _BROWSE_UDF_
3723     if(!UDFIsDvdMedia(Vcb)) {
3724         // limit read speed after write operation
3725         // to avoid performance degrade durring speed-up/down
3726         // on read/write mode switching
3727         if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) {
3728             // limit both read & write speed to last write speed for CAV mode
3729             // some drives damage data when speed is adjusted during recording process
3730             // even in packet mode
3731             if(Vcb->CurSpeed != Vcb->MaxWriteSpeed ||
3732                Vcb->CurSpeed != Vcb->MaxReadSpeed) {
3733                 Vcb->CurSpeed = Vcb->MaxWriteSpeed;
3734                 speed_changed = TRUE;
3735             }
3736         } else
3737         if(Vcb->VCBFlags & UDF_VCB_LAST_WRITE) {
3738             // limit read speed to last write speed
3739             if(Vcb->CurSpeed > Vcb->MaxWriteSpeed) {
3740                 Vcb->CurSpeed = Vcb->MaxWriteSpeed;
3741                 speed_changed = TRUE;
3742             }
3743         } else
3744         if(Vcb->CurSpeed < Vcb->MaxReadSpeed ) {
3745             // increment read speed (+1X)
3746             Vcb->CurSpeed += 176/1;
3747             speed_changed = TRUE;
3748         }
3749 
3750         if(Vcb->CurSpeed > Vcb->MaxReadSpeed) {
3751             Vcb->CurSpeed = Vcb->MaxReadSpeed;
3752         }
3753         // send speed limits to drive
3754         if(speed_changed) {
3755             RtlZeroMemory(&(Vcb->SpeedBuf), sizeof(SET_CD_SPEED_EX_USER_IN));
3756             Vcb->SpeedBuf.ReadSpeed  = Vcb->CurSpeed;
3757             Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed;
3758             if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) {
3759                 Vcb->SpeedBuf.RotCtrl = CdSpeed_RotCtrl_CAV;
3760             }
3761             UDFPrint(("    UDFPrepareForReadOperation: set speed to %s %dX/%dX\n",
3762                 (Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) ? "CAV" : "CLV",
3763                 Vcb->SpeedBuf.ReadSpeed,
3764                 Vcb->SpeedBuf.WriteSpeed));
3765             UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED,
3766                                 Vcb->TargetDeviceObject,
3767                                 &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_EX_USER_IN),
3768                                 NULL,0,TRUE,NULL);
3769         }
3770     }
3771 
3772     if(UDFIsDvdMedia(Vcb))
3773         return STATUS_SUCCESS;
3774 
3775     if(Vcb->LastReadTrack &&
3776        ((Vcb->TrackMap[i].FirstLba <= Lba) || (Vcb->TrackMap[i].FirstLba & 0x80000000)) &&
3777        (Vcb->TrackMap[i].LastLba >= Lba)) {
3778 check_for_data_track:
3779         // check track mode (Mode1/XA)
3780         switch((Vcb->TrackMap[i].DataParam & TrkInfo_Dat_Mask)) {
3781         case TrkInfo_Dat_Mode1: // Mode1
3782         case TrkInfo_Dat_XA:    // XA Mode2
3783         case TrkInfo_Dat_Unknown: // for some stupid irons
3784             UDFSetMRWMode(Vcb);
3785             break;
3786         default:
3787             Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE;
3788             return STATUS_INVALID_PARAMETER;
3789         }
3790     } else {
3791         for(i=Vcb->FirstTrackNum; i<=Vcb->LastTrackNum; i++) {
3792             if(((Vcb->TrackMap[i].FirstLba > Lba) && !(Vcb->TrackMap[i].FirstLba & 0x80000000)) ||
3793                (Vcb->TrackMap[i].LastLba < Lba))
3794                 continue;
3795             Vcb->LastReadTrack = i;
3796             goto check_for_data_track;
3797         }
3798         Vcb->LastReadTrack = 0;
3799     }
3800     if(Vcb->IncrementalSeekState != INCREMENTAL_SEEK_WORKAROUND) {
3801         Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE;
3802         return STATUS_SUCCESS;
3803     }
3804     UDFPrint(("    UDFPrepareForReadOperation: seek workaround...\n"));
3805     Vcb->IncrementalSeekState = INCREMENTAL_SEEK_DONE;
3806 
3807     tmp = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Vcb->BlockSize, 'bNWD');
3808     if(!tmp) {
3809         Vcb->IncrementalSeekState = INCREMENTAL_SEEK_NONE;
3810         return STATUS_INSUFFICIENT_RESOURCES;
3811     }
3812     for(i=0x1000; i<=Lba; i+=0x1000) {
3813         RC = UDFPhReadSynchronous(Vcb->TargetDeviceObject, tmp, Vcb->BlockSize,
3814                    ((uint64)UDFFixFPAddress(Vcb,i)) << Vcb->BlockSizeBits, &ReadBytes, 0);
3815         UDFPrint(("    seek workaround, LBA %x, status %x\n", i, RC));
3816     }
3817     DbgFreePool(tmp);
3818 #endif //_BROWSE_UDF_
3819 
3820     return STATUS_SUCCESS;
3821 } // end UDFPrepareForReadOperation()
3822 
3823 //#endif //_BROWSE_UDF_
3824 
3825 void
UDFUpdateNWA(PVCB Vcb,uint32 LBA,uint32 BCount,OSSTATUS RC)3826 UDFUpdateNWA(
3827     PVCB Vcb,
3828     uint32 LBA,  // physical
3829     uint32 BCount,
3830     OSSTATUS RC
3831     )
3832 {
3833 #ifndef UDF_READ_ONLY_BUILD
3834 #ifdef _BROWSE_UDF_
3835     if(!OS_SUCCESS(RC)) {
3836         return;
3837     }
3838     if(!Vcb->CDR_Mode) {
3839 
3840         if((Vcb->MediaClassEx == CdMediaClass_DVDRW ||
3841             Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
3842             Vcb->MediaClassEx == CdMediaClass_DVDRAM ||
3843             Vcb->MRWStatus == DiscInfo_BGF_Interrupted ||
3844             Vcb->MRWStatus == DiscInfo_BGF_InProgress)
3845               && (LBA+BCount-1) > Vcb->LastLBA) {
3846             ASSERT(Vcb->NWA > Vcb->LastLBA);
3847             Vcb->NWA = LBA+BCount;
3848             Vcb->LastLBA = Vcb->NWA-1;
3849         }
3850         if(Vcb->VCBFlags & UDF_VCB_FLAGS_FORCE_SYNC_CACHE)
3851             goto sync_cache;
3852 /*        if(Vcb->CdrwBufferSize) {
3853             Vcb->CdrwBufferSizeCounter += BCount * 2048;
3854             if(Vcb->CdrwBufferSizeCounter >= Vcb->CdrwBufferSize + 2*2048) {
3855                 UDFPrint(("    UDFUpdateNWA: buffer is full, sync...\n"));
3856                 Vcb->CdrwBufferSizeCounter = 0;
3857                 goto sync_cache;
3858             }
3859         }*/
3860         if(Vcb->SyncCacheState == SYNC_CACHE_RECOVERY_RETRY) {
3861             Vcb->VCBFlags |= UDF_VCB_FLAGS_FORCE_SYNC_CACHE;
3862         }
3863         Vcb->SyncCacheState = SYNC_CACHE_RECOVERY_NONE;
3864         return;
3865     }
3866     if(Vcb->LastLBA < (LBA+BCount))
3867         Vcb->LastLBA = LBA+BCount;
3868     if(Vcb->NWA)
3869         Vcb->NWA+=BCount+7;
3870 sync_cache:
3871     if(!(Vcb->CompatFlags & UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE)) {
3872         UDFPrint(("    UDFUpdateNWA: syncing...\n"));
3873         RC = UDFSyncCache(Vcb);
3874     }
3875 #endif //_BROWSE_UDF_
3876 #endif //UDF_READ_ONLY_BUILD
3877 } // end UDFUpdateNWA()
3878 
3879 
3880 /*
3881     This routine reads physical sectors
3882  */
3883 /*OSSTATUS
3884 UDFReadSectors(
3885     IN PVCB Vcb,
3886     IN BOOLEAN Translate,       // Translate Logical to Physical
3887     IN uint32 Lba,
3888     IN uint32 BCount,
3889     OUT int8* Buffer,
3890     OUT PSIZE_T ReadBytes
3891     )
3892 {
3893 
3894     if(Vcb->FastCache.ReadProc && (KeGetCurrentIrql() < DISPATCH_LEVEL)) {
3895         return WCacheReadBlocks__(&(Vcb->FastCache), Vcb, Buffer, Lba, BCount, ReadBytes);
3896     }
3897     return UDFTRead(Vcb, Buffer, BCount*Vcb->BlockSize, Lba, ReadBytes);
3898 } // end UDFReadSectors()*/
3899 
3900 #ifdef _BROWSE_UDF_
3901 
3902 /*
3903     This routine reads physical sectors
3904  */
3905 OSSTATUS
UDFReadInSector(IN PVCB Vcb,IN BOOLEAN Translate,IN uint32 Lba,IN uint32 i,IN uint32 l,IN BOOLEAN Direct,OUT int8 * Buffer,OUT PSIZE_T ReadBytes)3906 UDFReadInSector(
3907     IN PVCB Vcb,
3908     IN BOOLEAN Translate,       // Translate Logical to Physical
3909     IN uint32 Lba,
3910     IN uint32 i,                 // offset in sector
3911     IN uint32 l,                 // transfer length
3912     IN BOOLEAN Direct,          // Disable access to non-cached data
3913     OUT int8* Buffer,
3914     OUT PSIZE_T ReadBytes
3915     )
3916 {
3917     int8* tmp_buff;
3918     OSSTATUS status;
3919     SIZE_T _ReadBytes;
3920 
3921     (*ReadBytes) = 0;
3922     if(WCacheIsInitialized__(&(Vcb->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) {
3923         status = WCacheDirect__(&(Vcb->FastCache), Vcb, Lba, FALSE, &tmp_buff, Direct);
3924         if(OS_SUCCESS(status)) {
3925             (*ReadBytes) += l;
3926             RtlCopyMemory(Buffer, tmp_buff+i, l);
3927         }
3928         if(!Direct) WCacheEODirect__(&(Vcb->FastCache), Vcb);
3929     } else {
3930         if(Direct) {
3931             return STATUS_INVALID_PARAMETER;
3932         }
3933         tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, Vcb->BlockSize);
3934         if(!tmp_buff) return STATUS_INSUFFICIENT_RESOURCES;
3935         status = UDFReadSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &_ReadBytes);
3936         if(OS_SUCCESS(status)) {
3937             (*ReadBytes) += l;
3938             RtlCopyMemory(Buffer, tmp_buff+i, l);
3939         }
3940         MyFreePool__(tmp_buff);
3941     }
3942     return status;
3943 } // end UDFReadInSector()
3944 
3945 /*
3946     This routine reads data of unaligned offset & length
3947  */
3948 OSSTATUS
UDFReadData(IN PVCB Vcb,IN BOOLEAN Translate,IN int64 Offset,IN uint32 Length,IN BOOLEAN Direct,OUT int8 * Buffer,OUT PSIZE_T ReadBytes)3949 UDFReadData(
3950     IN PVCB Vcb,
3951     IN BOOLEAN Translate,       // Translate Logical to Physical
3952     IN int64 Offset,
3953     IN uint32 Length,
3954     IN BOOLEAN Direct,          // Disable access to non-cached data
3955     OUT int8* Buffer,
3956     OUT PSIZE_T ReadBytes
3957     )
3958 {
3959     uint32 i, l, Lba, BS=Vcb->BlockSize;
3960     uint32 BSh=Vcb->BlockSizeBits;
3961     OSSTATUS status;
3962     SIZE_T _ReadBytes = 0;
3963     Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
3964     uint32 to_read;
3965 
3966     (*ReadBytes) = 0;
3967     if(!Length) return STATUS_SUCCESS;
3968     if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD)
3969         return STATUS_NO_SUCH_DEVICE;
3970     // read tail of the 1st sector if Offset is not sector_size-aligned
3971     Lba = (uint32)(Offset >> BSh);
3972     if((i = (uint32)(Offset & (BS-1)))) {
3973         l = (BS - i) < Length ?
3974             (BS - i) : Length;
3975         // here we use 'ReadBytes' 'cause now it's set to zero
3976         status = UDFReadInSector(Vcb, Translate, Lba, i, l, Direct, Buffer, ReadBytes);
3977         if(!OS_SUCCESS(status)) return status;
3978         if(!(Length = Length - l)) return STATUS_SUCCESS;
3979         Lba ++;
3980         Buffer += l;
3981     }
3982     // read sector_size-aligned part
3983     i = Length >> BSh;
3984     while(i) {
3985         to_read = min(i, 64);
3986         status = UDFReadSectors(Vcb, Translate, Lba, to_read, Direct, Buffer, &_ReadBytes);
3987         (*ReadBytes) += _ReadBytes;
3988         if(!OS_SUCCESS(status)) {
3989             return status;
3990         }
3991         Buffer += to_read<<BSh;
3992         Length -= to_read<<BSh;
3993         Lba += to_read;
3994         i -= to_read;
3995     }
3996     // read head of the last sector
3997     if(!Length) return STATUS_SUCCESS;
3998     status = UDFReadInSector(Vcb, Translate, Lba, 0, Length, Direct, Buffer, &_ReadBytes);
3999     (*ReadBytes) += _ReadBytes;
4000 
4001     return status;
4002 } // end UDFReadData()
4003 
4004 #endif //_BROWSE_UDF_
4005 
4006 #ifndef UDF_READ_ONLY_BUILD
4007 /*
4008     This routine writes physical sectors. This routine supposes Lba & Length
4009     alignment on WriteBlock (packet) size.
4010  */
4011 OSSTATUS
UDFWriteSectors(IN PVCB Vcb,IN BOOLEAN Translate,IN uint32 Lba,IN uint32 BCount,IN BOOLEAN Direct,IN int8 * Buffer,OUT PSIZE_T WrittenBytes)4012 UDFWriteSectors(
4013     IN PVCB Vcb,
4014     IN BOOLEAN Translate,       // Translate Logical to Physical
4015     IN uint32 Lba,
4016     IN uint32 BCount,
4017     IN BOOLEAN Direct,          // Disable access to non-cached data
4018     IN int8* Buffer,
4019     OUT PSIZE_T WrittenBytes
4020     )
4021 {
4022     OSSTATUS status;
4023 
4024 #ifdef _BROWSE_UDF_
4025     if(!Vcb->Modified || (Vcb->IntegrityType == INTEGRITY_TYPE_CLOSE)) {
4026         UDFSetModified(Vcb);
4027         if(Vcb->LVid && !Direct) {
4028             status = UDFUpdateLogicalVolInt(Vcb,FALSE);
4029         }
4030     }
4031 
4032     if(Vcb->CDR_Mode) {
4033         if(Vcb->LastLBA < Lba+BCount-1)
4034             Vcb->LastLBA = Lba+BCount-1;
4035     }
4036 #endif //_BROWSE_UDF_
4037 
4038     if(Vcb->FastCache.WriteProc && (KeGetCurrentIrql() < DISPATCH_LEVEL)) {
4039         status = WCacheWriteBlocks__(&(Vcb->FastCache), Vcb, Buffer, Lba, BCount, WrittenBytes, Direct);
4040         ASSERT(OS_SUCCESS(status));
4041 #ifdef _BROWSE_UDF_
4042         UDFClrZeroBits(Vcb->ZSBM_Bitmap, Lba, BCount);
4043 #endif //_BROWSE_UDF_
4044         return status;
4045     }
4046 /*    void* buffer;
4047     OSSTATUS status;
4048     SIZE_T _ReadBytes;
4049     (*WrittenBytes) = 0;
4050     buffer = DbgAllocatePool(NonPagedPool, Vcb->WriteBlockSize);
4051     if(!buffer) return STATUS_INSUFFICIENT_RESOURCES;
4052     status = UDFTRead(Vcb, Buffer, BCount<<Vcb->BlockSizeBits, (Lba&~(Vcb->WriteBlockSize-1), _WrittenBytes);*/
4053 #ifdef UDF_DBG
4054     status = UDFTWrite(Vcb, Buffer, BCount<<Vcb->BlockSizeBits, Lba, WrittenBytes);
4055     ASSERT(OS_SUCCESS(status));
4056     return status;
4057 #else // UDF_DBG
4058     return UDFTWrite(Vcb, Buffer, BCount<<Vcb->BlockSizeBits, Lba, WrittenBytes);
4059 #endif // UDF_DBG
4060 } // end UDFWriteSectors()
4061 
4062 OSSTATUS
UDFWriteInSector(IN PVCB Vcb,IN BOOLEAN Translate,IN uint32 Lba,IN uint32 i,IN uint32 l,IN BOOLEAN Direct,OUT int8 * Buffer,OUT PSIZE_T WrittenBytes)4063 UDFWriteInSector(
4064     IN PVCB Vcb,
4065     IN BOOLEAN Translate,       // Translate Logical to Physical
4066     IN uint32 Lba,
4067     IN uint32 i,                 // offset in sector
4068     IN uint32 l,                 // transfer length
4069     IN BOOLEAN Direct,          // Disable access to non-cached data
4070     OUT int8* Buffer,
4071     OUT PSIZE_T WrittenBytes
4072     )
4073 {
4074     int8* tmp_buff;
4075     OSSTATUS status;
4076 #ifdef _BROWSE_UDF_
4077     SIZE_T _WrittenBytes;
4078     SIZE_T ReadBytes;
4079 
4080     if(!Vcb->Modified) {
4081         UDFSetModified(Vcb);
4082         if(Vcb->LVid)
4083             status = UDFUpdateLogicalVolInt(Vcb,FALSE);
4084     }
4085 
4086     if(Vcb->CDR_Mode) {
4087         if(Vcb->LastLBA < Lba)
4088             Vcb->LastLBA = Lba;
4089     }
4090 #endif //_BROWSE_UDF_
4091 
4092     (*WrittenBytes) = 0;
4093 #ifdef _BROWSE_UDF_
4094     if(WCacheIsInitialized__(&(Vcb->FastCache)) && (KeGetCurrentIrql() < DISPATCH_LEVEL)) {
4095 #endif //_BROWSE_UDF_
4096         status = WCacheDirect__(&(Vcb->FastCache), Vcb, Lba, TRUE, &tmp_buff, Direct);
4097         if(OS_SUCCESS(status)) {
4098 #ifdef _BROWSE_UDF_
4099             UDFClrZeroBit(Vcb->ZSBM_Bitmap, Lba);
4100 #endif //_BROWSE_UDF_
4101             (*WrittenBytes) += l;
4102             RtlCopyMemory(tmp_buff+i, Buffer, l);
4103         }
4104         if(!Direct) WCacheEODirect__(&(Vcb->FastCache), Vcb);
4105 #ifdef _BROWSE_UDF_
4106     } else {
4107         // If Direct = TRUE we should never get here, but...
4108         if(Direct) {
4109             BrutePoint();
4110             return STATUS_INVALID_PARAMETER;
4111         }
4112         tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, Vcb->BlockSize);
4113         if(!tmp_buff) {
4114             BrutePoint();
4115             return STATUS_INSUFFICIENT_RESOURCES;
4116         }
4117         // read packet
4118         status = UDFReadSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &ReadBytes);
4119         if(!OS_SUCCESS(status)) goto EO_WrSctD;
4120         // modify packet
4121         RtlCopyMemory(tmp_buff+i, Buffer, l);
4122         // write modified packet
4123         status = UDFWriteSectors(Vcb, Translate, Lba, 1, FALSE, tmp_buff, &_WrittenBytes);
4124         if(OS_SUCCESS(status))
4125             (*WrittenBytes) += l;
4126 EO_WrSctD:
4127         MyFreePool__(tmp_buff);
4128     }
4129     ASSERT(OS_SUCCESS(status));
4130     if(!OS_SUCCESS(status)) {
4131         UDFPrint(("UDFWriteInSector() for LBA %x failed\n", Lba));
4132     }
4133 #endif //_BROWSE_UDF_
4134     return status;
4135 } // end UDFWriteInSector()
4136 
4137 /*
4138     This routine writes data at unaligned offset & length
4139  */
4140 OSSTATUS
UDFWriteData(IN PVCB Vcb,IN BOOLEAN Translate,IN int64 Offset,IN SIZE_T Length,IN BOOLEAN Direct,IN int8 * Buffer,OUT PSIZE_T WrittenBytes)4141 UDFWriteData(
4142     IN PVCB Vcb,
4143     IN BOOLEAN Translate,      // Translate Logical to Physical
4144     IN int64 Offset,
4145     IN SIZE_T Length,
4146     IN BOOLEAN Direct,         // setting this flag delays flushing of given
4147                                // data to indefinite term
4148     IN int8* Buffer,
4149     OUT PSIZE_T WrittenBytes
4150     )
4151 {
4152     uint32 i, l, Lba, BS=Vcb->BlockSize;
4153     uint32 BSh=Vcb->BlockSizeBits;
4154     OSSTATUS status;
4155     SIZE_T _WrittenBytes;
4156     Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
4157 
4158     (*WrittenBytes) = 0;
4159     if(!Length) return STATUS_SUCCESS;
4160     if(Vcb->VCBFlags & UDF_VCB_FLAGS_DEAD)
4161         return STATUS_NO_SUCH_DEVICE;
4162     // write tail of the 1st sector if Offset is not sector_size-aligned
4163     Lba = (uint32)(Offset >> BSh);
4164     if((i = ((uint32)Offset & (BS-1)))) {
4165         l = (BS - i) < Length ?
4166             (BS - i) : Length;
4167         status = UDFWriteInSector(Vcb, Translate, Lba, i, l, Direct, Buffer, WrittenBytes);
4168         if(!OS_SUCCESS(status)) return status;
4169         if(!(Length = Length - l)) return STATUS_SUCCESS;
4170         Lba ++;
4171         Buffer += l;
4172     }
4173     // write sector_size-aligned part
4174     i = Length >> BSh;
4175     if(i) {
4176         status = UDFWriteSectors(Vcb, Translate, Lba, i, Direct, Buffer, &_WrittenBytes);
4177         (*WrittenBytes) += _WrittenBytes;
4178         if(!OS_SUCCESS(status)) return status;
4179         l = i<<BSh;
4180 #ifdef _BROWSE_UDF_
4181         UDFClrZeroBits(Vcb->ZSBM_Bitmap, Lba, i);
4182 #endif //_BROWSE_UDF_
4183         if(!(Length = Length - l)) return STATUS_SUCCESS;
4184         Lba += i;
4185         Buffer += l;
4186     }
4187     status = UDFWriteInSector(Vcb, Translate, Lba, 0, Length, Direct, Buffer, &_WrittenBytes);
4188     (*WrittenBytes) += _WrittenBytes;
4189 #ifdef _BROWSE_UDF_
4190     UDFClrZeroBit(Vcb->ZSBM_Bitmap, Lba);
4191 #endif //_BROWSE_UDF_
4192 
4193     return status;
4194 } // end UDFWriteData()
4195 
4196 #endif //UDF_READ_ONLY_BUILD
4197 
4198 OSSTATUS
UDFResetDeviceDriver(IN PVCB Vcb,IN PDEVICE_OBJECT TargetDeviceObject,IN BOOLEAN Unlock)4199 UDFResetDeviceDriver(
4200     IN PVCB Vcb,
4201     IN PDEVICE_OBJECT TargetDeviceObject,
4202     IN BOOLEAN Unlock
4203     )
4204 {
4205     PCDRW_RESET_DRIVER_USER_IN tmp = (PCDRW_RESET_DRIVER_USER_IN)
4206         MyAllocatePool__(NonPagedPool, sizeof(CDRW_RESET_DRIVER_USER_IN));
4207     OSSTATUS RC;
4208     if(!tmp)
4209         return STATUS_INSUFFICIENT_RESOURCES;
4210     RtlZeroMemory(tmp, sizeof(CDRW_RESET_DRIVER_USER_IN));
4211     tmp->UnlockTray = (Unlock ? 1 : 0);
4212     tmp->MagicWord = 0x3a6 | (Unlock ? 1 : 0);
4213     RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_DRIVER_EX, TargetDeviceObject,
4214         tmp, sizeof(CDRW_RESET_DRIVER_USER_IN), NULL, 0, TRUE,NULL);
4215     if(Vcb) {
4216         Vcb->LastReadTrack = 0;
4217         Vcb->LastModifiedTrack = 0;
4218         Vcb->OPCDone = FALSE;
4219         if((Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) &&
4220            Vcb->TargetDeviceObject) {
4221             // limit both read & write speed to last write speed for CAV mode
4222             // some drives damage data when speed is adjusted during recording process
4223             // even in packet mode
4224             UDFSetSpeeds(Vcb);
4225         }
4226         UDFSetCaching(Vcb);
4227     }
4228 
4229     MyFreePool__(tmp);
4230     return RC;
4231 } // end UDFResetDeviceDriver()
4232 
4233 OSSTATUS
UDFSetSpeeds(IN PVCB Vcb)4234 UDFSetSpeeds(
4235     IN PVCB Vcb
4236     )
4237 {
4238     OSSTATUS RC;
4239 
4240     RtlZeroMemory(&(Vcb->SpeedBuf), sizeof(SET_CD_SPEED_EX_USER_IN));
4241     if(Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) {
4242         Vcb->SpeedBuf.RotCtrl = CdSpeed_RotCtrl_CAV;
4243         Vcb->CurSpeed =
4244         Vcb->SpeedBuf.ReadSpeed =
4245         Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed;
4246     } else {
4247         Vcb->SpeedBuf.ReadSpeed  = Vcb->CurSpeed;
4248         Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed;
4249     }
4250     UDFPrint(("    UDFSetSpeeds: set speed to %s %dX/%dX\n",
4251         (Vcb->VCBFlags & UDF_VCB_FLAGS_USE_CAV) ? "CAV" : "CLV",
4252         Vcb->SpeedBuf.ReadSpeed / 176,
4253         Vcb->SpeedBuf.WriteSpeed / 176));
4254     RC = UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED,
4255                         Vcb->TargetDeviceObject,
4256                         &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_EX_USER_IN),
4257                         NULL,0,TRUE,NULL);
4258     UDFPrint(("UDFSetSpeeds: %x\n", RC));
4259     return RC;
4260 } // end UDFSetSpeeds()
4261 
4262 NTSTATUS
UDFSetCaching(IN PVCB Vcb)4263 UDFSetCaching(
4264     IN PVCB Vcb
4265     )
4266 {
4267 #pragma pack(push,1)
4268     struct {
4269         MODE_PARAMETER_HEADER    Header;
4270         MODE_CACHING_PAGE        Data;
4271         CHAR Padding [16];
4272     } CachingPage;
4273 
4274     struct {
4275         MODE_PARAMETER_HEADER         Header;
4276         MODE_READ_WRITE_RECOVERY_PAGE Data;
4277         CHAR Padding [16];
4278     } RecoveryPage;
4279 #ifdef _MSC_VER
4280 #pragma pack(pop,1)
4281 #else
4282 #pragma pack(pop)
4283 #endif
4284 
4285     MODE_SENSE_USER_IN ModeSenseCtl;
4286     OSSTATUS RC;
4287 
4288     UDFPrint(("UDFSetCaching:\n"));
4289 
4290     ModeSenseCtl.PageCode.Byte = MODE_PAGE_ERROR_RECOVERY;
4291     RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SENSE, Vcb->TargetDeviceObject,
4292                     &ModeSenseCtl,sizeof(ModeSenseCtl),
4293                     (PVOID)&RecoveryPage,sizeof(RecoveryPage),
4294                     FALSE, NULL);
4295     if(OS_SUCCESS(RC)) {
4296         UDFPrint(("  Error recovery page:\n"
4297             "PageCode         %d\n"
4298             "PageLength       %d\n"
4299 
4300             "DCRBit %d\n"
4301             "DTEBit %d\n"
4302             "PERBit %d\n"
4303             "EERBit %d\n"
4304             "RCBit  %d\n"
4305             "TBBit  %d\n"
4306             "ARRE   %d\n"
4307             "AWRE   %d\n"
4308 
4309             "ReadRetryCount %d\n"
4310             "CorrectionSpan %d\n"
4311             "HeadOffsetCount %d\n"
4312             "DataStrobOffsetCount %d\n"
4313 
4314             "ErrorRecoveryParam2.Fields.EMCDR %d\n"
4315 
4316             "WriteRetryCount %d\n",
4317 
4318             RecoveryPage.Data.PageCode,
4319             RecoveryPage.Data.PageLength,
4320 
4321             RecoveryPage.Data.ErrorRecoveryParam.Fields.DCRBit,
4322             RecoveryPage.Data.ErrorRecoveryParam.Fields.DTEBit,
4323             RecoveryPage.Data.ErrorRecoveryParam.Fields.PERBit,
4324             RecoveryPage.Data.ErrorRecoveryParam.Fields.EERBit,
4325             RecoveryPage.Data.ErrorRecoveryParam.Fields.RCBit,
4326             RecoveryPage.Data.ErrorRecoveryParam.Fields.TBBit,
4327             RecoveryPage.Data.ErrorRecoveryParam.Fields.ARRE,
4328             RecoveryPage.Data.ErrorRecoveryParam.Fields.AWRE,
4329 
4330             RecoveryPage.Data.ReadRetryCount,
4331             RecoveryPage.Data.CorrectionSpan,
4332             RecoveryPage.Data.HeadOffsetCount,
4333             RecoveryPage.Data.DataStrobOffsetCount,
4334 
4335             RecoveryPage.Data.ErrorRecoveryParam2.Fields.EMCDR,
4336 
4337             RecoveryPage.Data.WriteRetryCount
4338 
4339         ));
4340     }
4341 
4342     ModeSenseCtl.PageCode.Byte = MODE_PAGE_CACHING;
4343     RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SENSE, Vcb->TargetDeviceObject,
4344                     &ModeSenseCtl,sizeof(ModeSenseCtl),
4345                     (PVOID)&CachingPage,sizeof(CachingPage),
4346                     FALSE, NULL);
4347     if(!OS_SUCCESS(RC)) {
4348         return RC;
4349     }
4350 
4351     UDFPrint(("  Caching page:\n"
4352         "PageCode         %d\n"
4353         "PageLength       %d\n"
4354         "ReadDisableCache %d\n"
4355         "MultiplicationFactor %d\n"
4356         "WriteCacheEnable %d\n"
4357         "WriteRetensionPriority %d\n"
4358         "ReadRetensionPriority  %d\n",
4359 
4360         CachingPage.Data.PageCode,
4361         CachingPage.Data.PageLength,
4362         CachingPage.Data.ReadDisableCache,
4363         CachingPage.Data.MultiplicationFactor,
4364         CachingPage.Data.WriteCacheEnable,
4365         CachingPage.Data.WriteRetensionPriority,
4366         CachingPage.Data.ReadRetensionPriority
4367     ));
4368 
4369     RtlZeroMemory(&CachingPage.Header, sizeof(CachingPage.Header));
4370     CachingPage.Data.PageCode = MODE_PAGE_CACHING;
4371     CachingPage.Data.PageSavable = 0;
4372     if( CachingPage.Data.ReadDisableCache ||
4373        !CachingPage.Data.WriteCacheEnable) {
4374         CachingPage.Data.ReadDisableCache = 0;
4375         CachingPage.Data.WriteCacheEnable = 1;
4376         RC = UDFPhSendIOCTL(IOCTL_CDRW_MODE_SELECT, Vcb->TargetDeviceObject,
4377                         (PVOID)&CachingPage,sizeof(CachingPage.Header) + 2 + CachingPage.Data.PageLength,
4378                         NULL,0,
4379                         FALSE, NULL);
4380     } else {
4381         RC = STATUS_SUCCESS;
4382     }
4383     UDFPrint(("UDFSetCaching: %x\n", RC));
4384     return RC;
4385 } // end UDFSetCaching()
4386