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_eject.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 "udf.h"
17 // define the file specific bug-check id
18 #define UDF_BUG_CHECK_ID UDF_FILE_PHYS_EJECT
19
20 extern void
21 UDFKeyWaiter(
22 IN void* Context
23 );
24
25 /*
26 This routine checks for User Eject request & initiates Dismount
27 */
28 void
29 NTAPI
UDFEjectReqWaiter(IN void * Context)30 UDFEjectReqWaiter(
31 IN void* Context
32 )
33 {
34 PUDFEjectWaitContext WC = (PUDFEjectWaitContext)Context;
35 PVCB Vcb;
36 OSSTATUS RC = STATUS_SUCCESS;
37 OSSTATUS WRC;
38 LARGE_INTEGER delay;
39 LARGE_INTEGER time;
40 BOOLEAN UseEvent = TRUE;
41 uint32 d;
42 BOOLEAN FlushWCache = FALSE;
43 IO_STATUS_BLOCK IoStatus;
44 BOOLEAN VcbAcquired;
45 BOOLEAN AllFlushed;
46 PDEVICE_OBJECT TargetDevObj;
47 uint32 BM_FlushPriod;
48 uint32 Tree_FlushPriod;
49 uint32 SkipCount = 0;
50 uint32 SkipEjectCount = 0;
51 uint32 flags = 0;
52 uint32 flush_stat = 0;
53 BOOLEAN UseEject = TRUE;
54 BOOLEAN MediaLoss = FALSE;
55
56 BOOLEAN SkipEject = FALSE;
57 BOOLEAN SkipFlush = FALSE;
58
59 // BOOLEAN FlushAndEject = FALSE;
60
61 UDFPrint((" UDFEjectReqWaiter: start\n"));
62 uint8 supported_evt_classes = 0;
63 uint32 i, j;
64 uint8 evt_type;
65 BOOLEAN OldLowFreeSpace = FALSE;
66 uint32 space_check_counter = 0x7fffffff;
67 PGET_LAST_ERROR_USER_OUT Error = NULL;
68
69 // Drain out Event Queue
70 Vcb = WC->Vcb;
71 TargetDevObj = Vcb->TargetDeviceObject;
72 UseEvent = Vcb->UseEvent;
73 if(UseEvent) {
74 supported_evt_classes = EventStat_Class_Media;
75 } else {
76 UDFPrint((" Eject Button ignored\n"));
77 }
78 for(j=0; j<4; j++) {
79 UDFPrint((" Reading events... (0)\n"));
80 if(supported_evt_classes) {
81 for(i=1; i<=EventRetStat_Class_Mask;i++) {
82 evt_type = (((UCHAR)1) << i);
83 if( !(supported_evt_classes & evt_type) )
84 continue;
85 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
86 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type;
87
88 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_EVENT,
89 TargetDevObj,
90 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
91 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
92 FALSE,NULL);
93
94 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
95 UseEvent = FALSE;
96 break;
97 }
98 if(RC == STATUS_NO_SUCH_DEVICE)
99 break;
100 if(OS_SUCCESS(RC)) {
101 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses;
102 }
103 }
104 }
105 if(!UseEvent)
106 break;
107 if(RC == STATUS_NO_SUCH_DEVICE)
108 break;
109 }
110 supported_evt_classes = 0;
111
112 // Wait for events
113 while(TRUE) {
114 _SEH2_TRY {
115
116 VcbAcquired = FALSE;
117 delay.QuadPart = -10000000; // 1.0 sec
118 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
119 if(WRC == STATUS_SUCCESS) {
120 stop_waiter:
121 // if(!
122 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);//) {
123 /* delay.QuadPart = -1000000; // 0.1 sec
124 KeDelayExecutionThread(KernelMode, FALSE, &delay);
125 try_return(RC);*/
126 // }
127 Vcb->EjectWaiter = NULL;
128 UDFReleaseResource(&(Vcb->VCBResource));
129
130 KeSetEvent(WC->WaiterStopped, 0, FALSE);
131 MyFreePool__(WC);
132 WC = NULL;
133 UDFPrint((" UDFEjectReqWaiter: exit 3\n"));
134 return;
135 }
136 BM_FlushPriod = Vcb->BM_FlushPriod;
137 Tree_FlushPriod = Vcb->Tree_FlushPriod;
138
139 // check if we approaching end of disk
140 if(space_check_counter > 2) {
141 // update FreeAllocUnits if it is necessary
142 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && Vcb->Modified) {
143 Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb);
144 }
145 // update LowFreeSpace flag
146 Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128);
147 if(Vcb->LowFreeSpace && !OldLowFreeSpace) {
148 // initiate Flush process if we crossed LowFreeSpace boundary
149 Vcb->Tree_FlushTime = Tree_FlushPriod+1;
150 Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK;
151 }
152 OldLowFreeSpace = Vcb->LowFreeSpace;
153 space_check_counter = 0;
154 }
155 space_check_counter++;
156
157 if(Vcb->VCBFlags & UDF_VCB_SKIP_EJECT_CHECK) {
158 SkipCount++;
159 SkipEjectCount++;
160 SkipEject = (SkipEjectCount <= Vcb->SkipEjectCountLimit);
161 SkipFlush = (SkipEjectCount <= Vcb->SkipCountLimit);
162 if(SkipEject || SkipFlush) {
163 Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK;
164 }
165 } else {
166 SkipEject = FALSE;
167 SkipFlush = FALSE;
168 }
169
170 if(WC->SoftEjectReq) {
171 SkipEject = FALSE;
172 SkipFlush = FALSE;
173 }
174
175 if(SkipFlush) {
176 Vcb->BM_FlushTime =
177 Vcb->Tree_FlushTime = 0;
178 } else {
179 SkipCount = 0;
180 }
181 if(!SkipEject) {
182 SkipEjectCount = 0;
183 }
184
185 if(SkipEject && SkipFlush) {
186 wait_eject:
187 delay.QuadPart = -10000000; // 1.0 sec
188 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
189 if(WRC == STATUS_SUCCESS) {
190 goto stop_waiter;
191 }
192 try_return(RC);
193 }
194
195 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) {
196 goto wait_eject;
197 }
198
199 // check if the door is still locked
200 if(!SkipEject &&
201 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) &&
202 (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) {
203
204 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
205 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_CAPABILITIES,
206 TargetDevObj,
207 NULL,0,
208 &(WC->DevCap),sizeof(GET_CAPABILITIES_USER_OUT),
209 FALSE,NULL);
210
211 Error = &(WC->Error);
212 UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject,
213 NULL,0,
214 Error,sizeof(GET_LAST_ERROR_USER_OUT),
215 TRUE,NULL);
216 UDFReleaseResource(&(Vcb->IoResource));
217 UDFPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n",
218 Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError));
219 // check for Long Write In Progress
220 if( ((Error->SenseKey == SCSI_SENSE_NOT_READY) &&
221 (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
222 (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS ||
223 Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) ) {
224 if((!Vcb->Modified &&
225 !(Vcb->VCBFlags & UDF_VCB_LAST_WRITE))
226 ||
227 (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL)) {
228 // we should forget about this disk...
229 UDFPrint((" LAST_WRITE %x\n", !!(Vcb->VCBFlags & UDF_VCB_LAST_WRITE)));
230 UDFPrint((" UDF_VCB_FLAGS_UNSAFE_IOCTL %x\n", !!(Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL)));
231 UDFPrint((" UDFEjectReqWaiter: Unexpected write-in-progress on !Modified volume\n"));
232 //ASSERT(FALSE);
233 Vcb->ForgetVolume = TRUE;
234 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY | UDF_VCB_FLAGS_MEDIA_READ_ONLY;
235 MediaLoss = TRUE;
236 goto device_failure;
237 }
238 }
239 if( OS_SUCCESS(RC) &&
240 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) &&
241 !(WC->DevCap.Capabilities2 & DevCap_lock_state)) {
242 // probably bus reset or power failure occured
243 // re-lock tray
244 UDFPrint((" UDFEjectReqWaiter: Unexpected tray unlock encountered. Try to re-lock\n"));
245
246 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
247 VcbAcquired = TRUE;
248
249 /* UDFResetDeviceDriver(Vcb, TargetDevObj, FALSE);
250 delay.QuadPart = -1000000; // 0.1 sec
251 KeDelayExecutionThread(KernelMode, FALSE, &delay);*/
252 // lock it
253 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&(WC->DevCap)))->PreventMediaRemoval = TRUE;
254 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
255 TargetDevObj,
256 &(WC->DevCap),sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
257 NULL,0,
258 FALSE,NULL);
259 delay.QuadPart = -1000000; // 0.1 sec
260 KeDelayExecutionThread(KernelMode, FALSE, &delay);
261 // force write mode re-initialization
262 Vcb->LastModifiedTrack = 0;
263 // try_return(RC);
264 }
265 }
266
267 UDFVVerify(Vcb, 0 /* partial verify */);
268
269 if(!SkipFlush &&
270 !(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
271 (BM_FlushPriod || Tree_FlushPriod)) {
272 KeQuerySystemTime(&delay);
273 d = (uint32)((delay.QuadPart - time.QuadPart) / 10000000);
274 time = delay;
275 Vcb->BM_FlushTime += d;
276 Vcb->Tree_FlushTime += d;
277
278 if(!Vcb->CDR_Mode) {
279
280 AllFlushed = FALSE;
281
282 UDFPrint((" SkipCount=%x, SkipCountLimit=%x\n",
283 SkipCount,
284 Vcb->SkipCountLimit));
285
286 if( Tree_FlushPriod &&
287 (Tree_FlushPriod < Vcb->Tree_FlushTime)) {
288
289 UDFPrint((" Tree_FlushPriod %I64x, Vcb->Tree_FlushTime %I64x\n",
290 Tree_FlushPriod,
291 Vcb->Tree_FlushTime));
292
293 // do not touch unchanged volume
294 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ||
295 !Vcb->Modified)
296 goto skip_BM_flush;
297
298 // Acquire Vcb resource
299 if(!VcbAcquired) {
300 if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FALSE)) {
301 delay.QuadPart = -10000000; // 1.0 sec
302 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
303 if(WRC == STATUS_SUCCESS) {
304 goto stop_waiter;
305 }
306 try_return(RC);
307 }
308 VcbAcquired = TRUE;
309 }
310
311 UDFPrint(("UDF: Flushing Directory Tree....\n"));
312 if( BM_FlushPriod &&
313 (BM_FlushPriod < Vcb->BM_FlushTime)) {
314 UDFPrint((" full flush\n"));
315 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE);
316 } else {
317 UDFPrint((" light flush\n"));
318 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE | UDF_FLUSH_FLAGS_LITE);
319 }
320 if(flush_stat & UDF_FLUSH_FLAGS_INTERRUPTED)
321 try_return(RC);
322 FlushWCache = TRUE;
323 UDFVVerify(Vcb, UFD_VERIFY_FLAG_BG /* partial verify */);
324 //UDFVFlush(Vcb);
325 skip_BM_flush:
326 Vcb->Tree_FlushTime = 0;
327 }
328 if( BM_FlushPriod &&
329 (BM_FlushPriod < Vcb->BM_FlushTime)) {
330
331 UDFPrint((" BM_FlushPriod %I64x, Vcb->BM_FlushTime %I64x\n",
332 BM_FlushPriod,
333 Vcb->BM_FlushTime));
334
335
336 // do not touch unchanged volume
337 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)
338 goto skip_BM_flush2;
339 if(!Vcb->Modified)
340 goto skip_BM_flush2;
341
342 if(!VcbAcquired) {
343 if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FlushWCache /*|| FALSE*/)) {
344 delay.QuadPart = -10000000; // 1.0 sec
345 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
346 if(WRC == STATUS_SUCCESS) {
347 goto stop_waiter;
348 }
349 try_return(RC);
350 }
351 VcbAcquired = TRUE;
352 }
353
354 UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
355 // UDF_CHECK_BITMAP_RESOURCE(Vcb);
356
357 if(Vcb->FSBM_ByteCount != RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) {
358 flags |= 1;
359 }
360 /* if(FlushWCache) {
361 AllFlushed = TRUE;
362 }*/
363 AllFlushed =
364 FlushWCache = TRUE;
365 #ifndef UDF_READ_ONLY_BUILD
366 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE);
367 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR);
368
369 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent));
370 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent));
371
372 if(Vcb->VerifyOnWrite) {
373 UDFPrint(("UDF: Flushing cache for verify\n"));
374 //WCacheFlushAll__(&(Vcb->FastCache), Vcb);
375 WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA);
376 UDFVFlush(Vcb);
377 }
378 #ifdef UDF_DBG
379 UDFPrint(("UDF: Flushing Free Space Bitmap....\n"));
380
381 // if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent))))
382 // UDFPrint(("Error updating VolIdent\n"));
383 if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags)))
384 UDFPrint(("Error updating Main VDS\n"));
385 if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags)))
386 UDFPrint(("Error updating Reserve VDS\n"));
387 #else
388 UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags);
389 UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags);
390 #endif // UDF_DBG
391 // Update Integrity Desc if any
392 if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) {
393 UDFUpdateLogicalVolInt(Vcb, TRUE);
394 }
395 if(flags & 1) {
396 RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount);
397 }
398 #endif //UDF_READ_ONLY_BUILD
399 UDFPreClrModified(Vcb);
400 UDFReleaseResource(&(Vcb->BitMapResource1));
401 skip_BM_flush2:
402 Vcb->BM_FlushTime = 0;
403 }
404 if(FlushWCache) {
405 FlushWCache = FALSE;
406 WCacheFlushAll__(&(Vcb->FastCache), Vcb);
407 }
408
409 if(AllFlushed) {
410 //Vcb->Modified = FALSE;
411 UDFClrModified(Vcb);
412 }
413
414 if(VcbAcquired) {
415 VcbAcquired = FALSE;
416 UDFReleaseResource(&(Vcb->VCBResource));
417 }
418 if(!Vcb->Tree_FlushTime &&
419 !Vcb->BM_FlushTime)
420 SkipCount = 0;
421 }
422 } else {
423 //SkipCount = 0;
424 }
425
426 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA))
427 try_return(RC);
428
429 UDFPrint((" UDFEjectReqWaiter: check removable media\n"));
430 if(!WC->SoftEjectReq && SkipEject) {
431 try_return(RC);
432 }
433
434 if(!WC->SoftEjectReq) {
435
436 if(!UseEvent) {
437 UDFPrint((" Eject Button ignored\n"));
438 try_return(RC);
439 }
440
441 /* if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) &&
442 !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) ){
443 // delay.QuadPart = -100000; // 0.01 sec
444 // KeDelayExecutionThread(KernelMode, FALSE, &delay);
445 OSSTATUS RC;
446
447 UDFPrint((" Sync cache before GET_EVENT\n"));
448 RC = UDFSyncCache(Vcb);
449 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
450 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_SYNC_CACHE;
451 }
452
453 // delay.QuadPart = -300000; // 0.03 sec
454 // KeDelayExecutionThread(KernelMode, FALSE, &delay);
455 Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
456 }*/
457
458 ASSERT(sizeof(TEST_UNIT_READY_USER_OUT) <= sizeof(GET_EVENT_USER_OUT));
459
460 RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY,
461 Vcb,
462 NULL,0,
463 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT),
464 FALSE,NULL);
465
466 if(RC != STATUS_SUCCESS &&
467 RC != STATUS_DATA_OVERRUN) {
468 if(RC == STATUS_NO_SUCH_DEVICE) {
469 UDFPrint((" Device loss\n"));
470 goto device_failure;
471 }
472 if(RC == STATUS_NO_MEDIA_IN_DEVICE) {
473 UDFPrint((" Media loss\n"));
474 goto media_loss;
475 }
476 }
477 UDFPrint((" Reading events...\n"));
478 if(supported_evt_classes) {
479 for(i=1; i<=EventRetStat_Class_Mask;i++) {
480 evt_type = (((UCHAR)1) << i);
481 if( !(supported_evt_classes & evt_type) )
482 continue;
483 /*
484 if( evt_type == EventStat_Class_Media )
485 continue;
486 if( evt_type == EventStat_Class_ExternalReq )
487 continue;
488 */
489 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
490 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type;
491
492 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
493 Vcb,
494 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
495 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
496 FALSE,NULL);
497
498 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
499 supported_evt_classes &= ~evt_type;
500 continue;
501 }
502 if(RC == STATUS_NO_SUCH_DEVICE) {
503 UDFPrint((" Device loss (2)\n"));
504 goto device_failure;
505 }
506 if(!OS_SUCCESS(RC)) {
507 continue;
508 }
509
510 if(WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_NEA) {
511 continue;
512 }
513 if( evt_type == EventStat_Class_Media ) {
514 UDFPrint((" EventStat_Class_Media:\n"));
515 if((WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_Class_Mask) !=
516 EventRetStat_Class_Media) {
517 continue;
518 }
519 retry_media_presence_check:
520 if(!(WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_Present) ||
521 (WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_DoorOpen)) {
522 // something wrong....
523 RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY,
524 Vcb,
525 NULL,0,
526 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT),
527 FALSE,NULL);
528
529 if(RC == STATUS_SUCCESS ||
530 RC == STATUS_DATA_OVERRUN) {
531 UDFPrint((" Buggy GET_EVENT media presence flag %x\n",
532 WC->EjectReqBuffer.MediaChange.Byte1));
533 WC->EjectReqBuffer.MediaChange.Byte1.Flags |= EventStat_MediaStat_Present;
534 WC->EjectReqBuffer.MediaChange.Byte1.Flags &= ~EventStat_MediaStat_DoorOpen;
535 goto retry_media_presence_check;
536 }
537 media_loss:
538 UDFPrint((" Unexpected media loss. Check device status\n"));
539 UseEject = FALSE;
540 MediaLoss = TRUE;
541 } else
542 // check if eject request occured
543 if( (WC->EjectReqBuffer.MediaChange.Byte0.Flags & EventStat_MediaEvent_Mask) !=
544 EventStat_MediaEvent_EjectReq ) {
545 continue;
546 }
547 UDFPrint((" eject requested\n"));
548 WC->SoftEjectReq = TRUE;
549 break;
550 }
551 if( evt_type == EventStat_Class_ExternalReq ) {
552 UDFPrint((" EventStat_Class_ExternalReq:\n"));
553 if((WC->EjectReqBuffer.ExternalReq.Header.Flags.Flags & EventRetStat_Class_Mask) !=
554 EventRetStat_Class_ExternReq)
555 continue;
556 switch(WC->EjectReqBuffer.ExternalReq.Byte0.Flags & EventStat_ExtrnReqEvent_Mask) {
557 case EventStat_ExtrnReqEvent_KeyDown:
558 case EventStat_ExtrnReqEvent_KeyUp:
559 case EventStat_ExtrnReqEvent_ExtrnReq:
560 UDFPrint((" eject requested (%x)\n", WC->EjectReqBuffer.ExternalReq.Byte0.Flags));
561 WC->SoftEjectReq = TRUE;
562 break;
563 }
564 continue;
565 }
566 }
567 if(!supported_evt_classes) {
568 UseEvent = FALSE;
569 }
570 if(!WC->SoftEjectReq) {
571 try_return(RC);
572 }
573 } else {
574
575 UDFPrint((" Reading Media Event...\n"));
576 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
577 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_Media;
578
579 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
580 Vcb,
581 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
582 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
583 FALSE,NULL);
584
585 if(!OS_SUCCESS(RC)) {
586 if(RC == STATUS_NO_SUCH_DEVICE)
587 goto device_failure;
588 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
589 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_ExternalReq;
590
591 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
592 Vcb,
593 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
594 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
595 FALSE,NULL);
596
597 if(RC == STATUS_NO_SUCH_DEVICE)
598 goto device_failure;
599 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
600 UseEvent = FALSE;
601 }
602 try_return(RC);
603 }
604 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses;
605 try_return(RC);
606 }
607 }
608 // FlushAndEject = TRUE;
609 device_failure:
610 // Ok. Lets flush all we have in memory, dismount volume & eject disc
611 // Acquire Vcb resource
612 Vcb->SoftEjectReq = TRUE;
613
614 UDFPrint((" UDFEjectReqWaiter: ejecting...\n"));
615 #ifdef UDF_DELAYED_CLOSE
616 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
617 UDFPrint((" UDFEjectReqWaiter: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
618 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
619 UDFReleaseResource(&(Vcb->VCBResource));
620 #endif //UDF_DELAYED_CLOSE
621
622 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllSystemDelayedInDir\n"));
623 RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
624 ASSERT(OS_SUCCESS(RC));
625 #ifdef UDF_DELAYED_CLOSE
626 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllDelayed\n"));
627 UDFCloseAllDelayed(Vcb);
628 //ASSERT(OS_SUCCESS(RC));
629 #endif //UDF_DELAYED_CLOSE
630
631 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
632
633 UDFPrint((" UDFEjectReqWaiter: UDFDoDismountSequence\n"));
634 UDFDoDismountSequence(Vcb, (PPREVENT_MEDIA_REMOVAL_USER_IN)&(WC->EjectReqBuffer), UseEject);
635 if (MediaLoss) {
636 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
637 Vcb->WriteSecurity = FALSE;
638 }
639 Vcb->EjectWaiter = NULL;
640 Vcb->SoftEjectReq = FALSE;
641 UDFReleaseResource(&(Vcb->VCBResource));
642
643 UDFPrint((" UDFEjectReqWaiter: set WaiterStopped\n"));
644 KeSetEvent(WC->WaiterStopped, 0, FALSE);
645 MyFreePool__(WC);
646 WC = NULL;
647
648 UDFPrint((" UDFEjectReqWaiter: exit 1\n"));
649 return;
650
651 try_exit: NOTHING;
652 } _SEH2_FINALLY {
653
654 if(VcbAcquired) {
655 VcbAcquired = FALSE;
656 UDFReleaseResource(&(Vcb->VCBResource));
657 }
658
659 /* if(WC) {
660 delay.QuadPart = -10000000; // 1.0 sec
661 WRC = KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, &delay);
662 if(WRC == STATUS_SUCCESS) {
663 goto stop_waiter;
664 }
665 }*/
666 } _SEH2_END;
667 }
668 // Simply make compiler happy
669 return;
670 } // end UDFEjectReqWaiter()
671
672 void
UDFStopEjectWaiter(PVCB Vcb)673 UDFStopEjectWaiter(PVCB Vcb) {
674
675 UDFPrint((" UDFStopEjectWaiter: try\n"));
676 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
677 _SEH2_TRY {
678 if(Vcb->EjectWaiter) {
679 UDFPrint((" UDFStopEjectWaiter: set flag\n"));
680 KeSetEvent( &(Vcb->EjectWaiter->StopReq), 0, FALSE );
681 } else {
682 // return;
683 }
684 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
685 BrutePoint();
686 } _SEH2_END;
687 UDFReleaseResource(&(Vcb->VCBResource));
688
689 _SEH2_TRY {
690 if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT) {
691 UDFPrint((" UDFStopEjectWaiter: wait\n"));
692 KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL);
693 }
694 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT;
695 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
696 BrutePoint();
697 } _SEH2_END;
698 ASSERT(!Vcb->EjectWaiter);
699 UDFPrint((" UDFStopEjectWaiter: exit\n"));
700
701 } // end UDFStopEjectWaiter()
702
703 OSSTATUS
UDFDoDismountSequence(IN PVCB Vcb,IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf,IN BOOLEAN Eject)704 UDFDoDismountSequence(
705 IN PVCB Vcb,
706 IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf,
707 IN BOOLEAN Eject
708 )
709 {
710 LARGE_INTEGER delay;
711 // OSSTATUS RC;
712 ULONG i;
713
714 // flush system cache
715 UDFFlushLogicalVolume(NULL, NULL, Vcb, 0);
716 UDFPrint(("UDFDoDismountSequence:\n"));
717
718 delay.QuadPart = -1000000; // 0.1 sec
719 KeDelayExecutionThread(KernelMode, FALSE, &delay);
720 // wait for completion of all backgroung writes
721 while(Vcb->BGWriters) {
722 delay.QuadPart = -5000000; // 0.5 sec
723 KeDelayExecutionThread(KernelMode, FALSE, &delay);
724 }
725 // release WCache
726 WCacheRelease__(&(Vcb->FastCache));
727
728 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
729
730 // unlock media, drop our own Locks
731 if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
732 UDFPrint((" cleanup tray-lock (%d+2):\n", Vcb->MediaLockCount));
733 for(i=0; i<Vcb->MediaLockCount+2; i++) {
734 Buf->PreventMediaRemoval = FALSE;
735 UDFPhSendIOCTL(IOCTL_STORAGE_MEDIA_REMOVAL,
736 Vcb->TargetDeviceObject,
737 Buf,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
738 NULL,0,
739 FALSE,NULL);
740 KeDelayExecutionThread(KernelMode, FALSE, &delay);
741 }
742 delay.QuadPart = -2000000; // 0.2 sec
743 }
744
745 if(!Vcb->ForgetVolume) {
746
747 if(!UDFIsDvdMedia(Vcb)) {
748 // send speed limits to drive
749 UDFPrint((" Restore drive speed on dismount\n"));
750 Vcb->SpeedBuf.ReadSpeed = Vcb->MaxReadSpeed;
751 Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed;
752 UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED,
753 Vcb->TargetDeviceObject,
754 &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_USER_IN),
755 NULL,0,TRUE,NULL);
756 }
757
758 if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) {
759 CLOSE_TRK_SES_USER_IN CBuff;
760
761 // reset driver
762 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
763 delay.QuadPart = -2000000; // 0.2 sec
764 KeDelayExecutionThread(KernelMode, FALSE, &delay);
765
766 memset(&CBuff,0,sizeof(CLOSE_TRK_SES_USER_IN));
767 // stop BG format
768 if(Vcb->MRWStatus) {
769 UDFPrint((" Stop background formatting\n"));
770
771 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed;
772 CBuff.Byte2.Flags = CloseTrkSes_Ses;
773 CBuff.TrackNum = 1;
774
775 UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES,
776 Vcb->TargetDeviceObject,
777 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
778 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
779 FALSE, NULL );
780 /* } else
781 if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
782 UDFPrint((" Close BG-formatted track\n"));
783
784 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed;
785 CBuff.Byte2.Flags = CloseTrkSes_Trk;
786 CBuff.TrackNum = 1;
787
788 RC = UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES,
789 Vcb->TargetDeviceObject,
790 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
791 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
792 FALSE, NULL );
793 */
794 }
795 // reset driver
796 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
797 delay.QuadPart = -1000000; // 0.1 sec
798 KeDelayExecutionThread(KernelMode, FALSE, &delay);
799 }
800 // eject media
801 if(Eject &&
802 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) {
803
804 UDFPhSendIOCTL(IOCTL_STORAGE_EJECT_MEDIA,
805 Vcb->TargetDeviceObject,
806 NULL,0,
807 NULL,0,
808 FALSE,NULL);
809 }
810 // notify media change
811 /* if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) {
812 ((PNOTIFY_MEDIA_CHANGE_USER_IN)Buf)->Autorun = FALSE;
813 RC = UDFPhSendIOCTL(IOCTL_CDRW_NOTIFY_MEDIA_CHANGE,
814 Vcb->TargetDeviceObject,
815 Buf,sizeof(NOTIFY_MEDIA_CHANGE_USER_IN),
816 NULL,0,
817 FALSE,NULL);
818 }*/
819 }
820 UDFReleaseResource(&(Vcb->IoResource));
821 // unregister shutdown notification
822 if(Vcb->ShutdownRegistered) {
823 IoUnregisterShutdownNotification(Vcb->VCBDeviceObject);
824 Vcb->ShutdownRegistered = FALSE;
825 }
826 // allow media change checks (this will lead to dismount)
827 // ... and make it Read-Only... :-\~
828 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED;
829
830 // Return back XP CD Burner Volume
831 /*
832 if (Vcb->CDBurnerVolumeValid) {
833 RtlWriteRegistryValue(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL,
834 REG_CD_BURNER_KEY_NAME,REG_CD_BURNER_VOLUME_NAME,
835 REG_SZ,(PVOID)&(Vcb->CDBurnerVolume),sizeof(Vcb->CDBurnerVolume));
836 ExFreePool(Vcb->CDBurnerVolume.Buffer);
837 }
838 */
839 UDFPrint((" set UnsafeIoctl\n"));
840 Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL;
841
842 return STATUS_SUCCESS;
843 } // end UDFDoDismountSequence()
844
845