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:
8 
9    remap.cpp
10 
11         Abstract:
12 
13    This file contains filesystem-specific routines
14    responsible for disk space management
15 
16 */
17 
18 #include "udf.h"
19 
20 #define         UDF_BUG_CHECK_ID                UDF_FILE_UDF_INFO_REMAP
21 
22 typedef struct _UDF_VERIFY_ITEM {
23     lba_t      lba;
24     ULONG      crc;
25     PUCHAR     Buffer;
26     LIST_ENTRY vrfList;
27     BOOLEAN    queued;
28 } UDF_VERIFY_ITEM, *PUDF_VERIFY_ITEM;
29 
30 typedef struct _UDF_VERIFY_REQ_RANGE {
31     lba_t      lba;
32     uint32     BCount;
33 } UDF_VERIFY_REQ_RANGE, *PUDF_VERIFY_REQ_RANGE;
34 
35 #define MAX_VREQ_RANGES  128
36 
37 typedef struct _UDF_VERIFY_REQ {
38     PVCB       Vcb;
39     PUCHAR     Buffer;
40     ULONG      nReq;
41     UDF_VERIFY_REQ_RANGE vr[MAX_VREQ_RANGES];
42 #ifndef _CONSOLE
43     WORK_QUEUE_ITEM VerifyItem;
44 #endif
45 } UDF_VERIFY_REQ, *PUDF_VERIFY_REQ;
46 
47 VOID
48 UDFVRemoveBlock(
49     PUDF_VERIFY_CTX VerifyCtx,
50     PUDF_VERIFY_ITEM vItem
51     );
52 
53 OSSTATUS
UDFVInit(IN PVCB Vcb)54 UDFVInit(
55     IN PVCB Vcb
56     )
57 {
58     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
59     uint32 i;
60     OSSTATUS status = STATUS_SUCCESS;
61     BOOLEAN res_inited = FALSE;
62 
63     if(VerifyCtx->VInited) {
64         UDFPrint(("Already inited\n"));
65         return STATUS_SUCCESS;
66     }
67 
68     _SEH2_TRY {
69         RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX));
70         if(!Vcb->VerifyOnWrite) {
71             UDFPrint(("Verify is disabled\n"));
72             return STATUS_SUCCESS;
73         }
74         if(Vcb->CDR_Mode) {
75             UDFPrint(("Verify is not intended for CD/DVD-R\n"));
76             return STATUS_SUCCESS;
77         }
78         if(!OS_SUCCESS(status = ExInitializeResourceLite(&(VerifyCtx->VerifyLock)))) {
79             try_return(status);
80         }
81         res_inited = TRUE;
82         VerifyCtx->ItemCount = 0;
83         VerifyCtx->StoredBitMap = (uint8*)DbgAllocatePoolWithTag(PagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3), 'mNWD' );
84         if(VerifyCtx->StoredBitMap) {
85             RtlZeroMemory(VerifyCtx->StoredBitMap, i);
86         } else {
87             UDFPrint(("Can't alloc verify bitmap for %x blocks\n", Vcb->LastPossibleLBA));
88             try_return(status = STATUS_INSUFFICIENT_RESOURCES);
89         }
90         InitializeListHead(&(VerifyCtx->vrfList));
91         KeInitializeEvent(&(VerifyCtx->vrfEvent), SynchronizationEvent, FALSE);
92         VerifyCtx->WaiterCount = 0;
93         VerifyCtx->VInited = TRUE;
94 
95 try_exit: NOTHING;
96 
97     } _SEH2_FINALLY {
98 
99         if(!OS_SUCCESS(status)) {
100             if(res_inited) {
101                 ExDeleteResourceLite(&(VerifyCtx->VerifyLock));
102             }
103         }
104     } _SEH2_END;
105     return status;
106 } // end UDFVInit()
107 
108 VOID
UDFVWaitQueued(PUDF_VERIFY_CTX VerifyCtx)109 UDFVWaitQueued(
110     PUDF_VERIFY_CTX VerifyCtx
111     )
112 {
113     ULONG w;
114 
115     while(VerifyCtx->QueuedCount) {
116         UDFPrint(("UDFVWaitQueued: wait for completion (%d)\n", VerifyCtx->QueuedCount));
117         w = InterlockedIncrement((PLONG)&(VerifyCtx->WaiterCount));
118         UDFPrint(("  %d waiters\n", w));
119         DbgWaitForSingleObject(&(VerifyCtx->vrfEvent), NULL);
120         if((w = InterlockedDecrement((PLONG)&(VerifyCtx->WaiterCount)))) {
121             UDFPrint(("  still %d waiters, q %d\n", w, VerifyCtx->QueuedCount));
122             if(!VerifyCtx->QueuedCount) {
123                 UDFPrint(("  pulse event\n", w));
124                 KeSetEvent(&(VerifyCtx->vrfEvent), 0, FALSE);
125             }
126         }
127     }
128     return;
129 } // end UDFVWaitQueued()
130 
131 VOID
UDFVRelease(IN PVCB Vcb)132 UDFVRelease(
133     IN PVCB Vcb
134     )
135 {
136     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
137     PLIST_ENTRY Link;
138     PUDF_VERIFY_ITEM vItem;
139 
140     if(!VerifyCtx->VInited) {
141         return;
142     }
143 
144     UDFPrint(("UDFVRelease: wait for completion\n"));
145     UDFVWaitQueued(VerifyCtx);
146 
147     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
148 
149     Link = VerifyCtx->vrfList.Flink;
150 
151     while(Link != &(VerifyCtx->vrfList)) {
152         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
153         Link = Link->Flink;
154         //DbgFreePool(vItem);
155         UDFVRemoveBlock(VerifyCtx, vItem);
156     }
157     VerifyCtx->VInited = FALSE;
158 
159     UDFReleaseResource(&(VerifyCtx->VerifyLock));
160 
161     ExDeleteResourceLite(&(VerifyCtx->VerifyLock));
162     DbgFreePool(VerifyCtx->StoredBitMap);
163 
164     RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX));
165 
166     return;
167 } // end UDFVRelease()
168 
169 PUDF_VERIFY_ITEM
UDFVStoreBlock(IN PVCB Vcb,IN uint32 LBA,IN PVOID Buffer,PLIST_ENTRY Link)170 UDFVStoreBlock(
171     IN PVCB Vcb,
172     IN uint32 LBA,
173     IN PVOID Buffer,
174     PLIST_ENTRY Link
175     )
176 {
177     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
178     PUDF_VERIFY_ITEM vItem;
179 
180     UDFPrint(("v-add %x\n", LBA));
181 
182     vItem = (PUDF_VERIFY_ITEM)DbgAllocatePoolWithTag(PagedPool, sizeof(UDF_VERIFY_ITEM)+Vcb->BlockSize, 'bvWD');
183     if(!vItem)
184         return NULL;
185     RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize);
186     vItem->lba = LBA;
187     vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize);
188     vItem->Buffer = (PUCHAR)(vItem+1);
189     vItem->queued = FALSE;
190     InitializeListHead(&(vItem->vrfList));
191     InsertTailList(Link, &(vItem->vrfList));
192     UDFSetBit(VerifyCtx->StoredBitMap, LBA);
193     VerifyCtx->ItemCount++;
194     return vItem;
195 } // end UDFVStoreBlock()
196 
197 VOID
UDFVUpdateBlock(IN PVCB Vcb,IN PVOID Buffer,PUDF_VERIFY_ITEM vItem)198 UDFVUpdateBlock(
199     IN PVCB Vcb,
200     IN PVOID Buffer,
201     PUDF_VERIFY_ITEM vItem
202     )
203 {
204     UDFPrint(("v-upd %x\n", vItem->lba));
205     RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize);
206     vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize);
207     return;
208 } // end UDFVUpdateBlock()
209 
210 VOID
UDFVRemoveBlock(PUDF_VERIFY_CTX VerifyCtx,PUDF_VERIFY_ITEM vItem)211 UDFVRemoveBlock(
212     PUDF_VERIFY_CTX VerifyCtx,
213     PUDF_VERIFY_ITEM vItem
214     )
215 {
216     UDFPrint(("v-del %x\n", vItem->lba));
217     UDFClrBit(VerifyCtx->StoredBitMap, vItem->lba);
218     RemoveEntryList(&(vItem->vrfList));
219     VerifyCtx->ItemCount--;
220     DbgFreePool(vItem);
221     return;
222 } // end UDFVUpdateBlock()
223 
224 OSSTATUS
UDFVWrite(IN PVCB Vcb,IN void * Buffer,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)225 UDFVWrite(
226     IN PVCB Vcb,
227     IN void* Buffer,     // Target buffer
228     IN uint32 BCount,
229     IN uint32 LBA,
230 //    OUT PSIZE_T WrittenBytes,
231     IN uint32 Flags
232     )
233 {
234     PLIST_ENTRY Link;
235     PUDF_VERIFY_ITEM vItem;
236     //PUDF_VERIFY_ITEM vItem1;
237     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
238     ULONG i;
239     ULONG n;
240     //uint32 prev_lba;
241 
242     if(!VerifyCtx->VInited) {
243         return STATUS_SUCCESS;
244     }
245 
246     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
247 
248     for(i=0, n=0; i<BCount; i++) {
249         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
250             // some blocks are remembered
251             n++;
252         }
253     }
254 
255     if(n == BCount) {
256         // update all blocks
257         n = 0;
258         Link = VerifyCtx->vrfList.Blink;
259         while(Link != &(VerifyCtx->vrfList)) {
260             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
261             Link = Link->Blink;
262             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
263                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba));
264                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+(vItem->lba-LBA)*Vcb->BlockSize, vItem);
265                 n++;
266                 if(n == BCount) {
267                     // all updated
268                     break;
269                 }
270             }
271         }
272     } else
273     if(n) {
274 #if 0
275         // find remembered blocks (the 1st one)
276         Link = VerifyCtx->vrfList.Blink;
277         while(Link != &(VerifyCtx->vrfList)) {
278             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
279             Link = Link->Blink;
280             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
281                 //UDFVRemoveBlock(VerifyCtx, vItem);
282                 break;
283             }
284         }
285 
286         // check if contiguous
287         i=1;
288         prev_lba = vItem->lba;
289         vItem1 = vItem;
290         Link = Link->Blink;
291         while((i < n) && (Link != &(VerifyCtx->vrfList))) {
292             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
293             Link = Link->Blink;
294             if(vItem->lba > LBA || vItem->lba >= LBA+BCount) {
295                 // end
296                 break;
297             }
298             if(vItem->lba < prev_lba) {
299                 // not sorted
300                 break;
301             }
302             prev_lba = vItem->lba;
303             i++;
304         }
305 
306         if(i == n) {
307             // cont
308         } else {
309             // drop all and add again
310         }
311 
312         vItem1 = vItem;
313         for(i=0; i<BCount; i++) {
314             if(vItem->lba == LBA+i) {
315                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
316                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem);
317                 continue;
318             }
319             if(vItem1->lba == LBA+i) {
320                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
321                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem1);
322                 continue;
323             }
324             if(vItem1->lba > LBA+i) {
325                 // just insert this block
326                 ASSERT(!UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
327                 UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(vItem1->vrfList));
328             } else {
329                 vItem = CONTAINING_RECORD( vItem->vrfList.Blink, UDF_VERIFY_ITEM, vrfList );
330             }
331         }
332 #else
333         Link = VerifyCtx->vrfList.Blink;
334         i=0;
335         while(Link != &(VerifyCtx->vrfList)) {
336             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
337             Link = Link->Blink;
338             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
339                 UDFVRemoveBlock(VerifyCtx, vItem);
340                 i++;
341                 if(i == n) {
342                     // all killed
343                     break;
344                 }
345             }
346         }
347         goto remember_all;
348 #endif
349 
350     } else {
351 remember_all:
352         // remember all blocks
353         for(i=0; i<BCount; i++) {
354             ASSERT(!UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
355             UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(VerifyCtx->vrfList));
356         }
357     }
358 
359     if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE) {
360         UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED);
361     }
362 
363     UDFReleaseResource(&(VerifyCtx->VerifyLock));
364 
365     if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE*2) {
366         //UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED);
367         // TODO: make some delay
368     }
369 
370     return STATUS_SUCCESS;
371 
372 } // end UDFVWrite()
373 
374 OSSTATUS
UDFVRead(IN PVCB Vcb,IN void * Buffer,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)375 UDFVRead(
376     IN PVCB Vcb,
377     IN void* Buffer,     // Target buffer
378     IN uint32 BCount,
379     IN uint32 LBA,
380 //    OUT uint32* ReadBytes,
381     IN uint32 Flags
382     )
383 {
384     PLIST_ENTRY Link;
385     PUDF_VERIFY_ITEM vItem;
386     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
387     ULONG crc;
388     ULONG i;
389     ULONG n;
390     OSSTATUS status = STATUS_SUCCESS;
391     uint32* bm;
392 
393     if(!VerifyCtx->VInited) {
394         return STATUS_SUCCESS;
395         //return STATUS_UNSUCCESSFUL;
396     }
397 
398     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
399 
400     for(i=0, n=0; i<BCount; i++) {
401         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
402             // some blocks are remembered
403             n++;
404         }
405     }
406 
407     if(!n) {
408         // no blocks are remembered
409         UDFReleaseResource(&(VerifyCtx->VerifyLock));
410         return STATUS_SUCCESS;
411     }
412 
413     Link = VerifyCtx->vrfList.Flink;
414     i=0;
415     while(Link != &(VerifyCtx->vrfList)) {
416         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
417         Link = Link->Flink;
418         if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
419             ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba));
420             i++;
421             if(!(Flags & PH_READ_VERIFY_CACHE)) {
422                 crc = crc32((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, Vcb->BlockSize);
423                 if(vItem->crc != crc) {
424                     UDFPrint(("UDFVRead: stored %x != %x\n", vItem->crc, crc));
425                     RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize);
426                     status = STATUS_FT_WRITE_RECOVERY;
427 
428                     if(!(bm = (uint32*)(Vcb->BSBM_Bitmap))) {
429                         crc = (Vcb->LastPossibleLBA+1+7) >> 3; // reuse 'crc' variable
430                         bm = (uint32*)(Vcb->BSBM_Bitmap = (int8*)DbgAllocatePoolWithTag(NonPagedPool, crc, 'mNWD' ));
431                         if(bm) {
432                             RtlZeroMemory(bm, crc);
433                         } else {
434                             UDFPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA));
435                         }
436                     }
437                     if(bm) {
438                         UDFSetBit(bm, vItem->lba);
439                         UDFPrint(("Set BB @ %#x\n", vItem->lba));
440                     }
441 #ifdef _BROWSE_UDF_
442                     bm = (uint32*)(Vcb->FSBM_Bitmap);
443                     if(bm) {
444                         UDFSetUsedBit(bm, vItem->lba);
445                         UDFPrint(("Set BB @ %#x as used\n", vItem->lba));
446                     }
447 #endif //_BROWSE_UDF_
448                 } else {
449                     // ok
450                 }
451             } else {
452                 UDFPrint(("UDFVRead: get cached @ %x\n", vItem->lba));
453                 RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize);
454             }
455             if(i >= n) {
456                 // no more blocks expected
457                 break;
458             }
459         }
460     }
461 
462     if((status == STATUS_SUCCESS && !(Flags & PH_KEEP_VERIFY_CACHE)) || (Flags & PH_FORGET_VERIFIED)) {
463         // ok, forget this, no errors found
464         Link = VerifyCtx->vrfList.Flink;
465         i = 0;
466         while(Link != &(VerifyCtx->vrfList)) {
467             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
468             Link = Link->Flink;
469             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
470                 i++;
471                 UDFVRemoveBlock(VerifyCtx, vItem);
472                 if(i >= n) {
473                     // no more blocks expected
474                     break;
475                 }
476             }
477         }
478     }
479 
480     UDFReleaseResource(&(VerifyCtx->VerifyLock));
481     return status;
482 
483 } // end UDFVRead()
484 
485 OSSTATUS
UDFVForget(IN PVCB Vcb,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)486 UDFVForget(
487     IN PVCB Vcb,
488     IN uint32 BCount,
489     IN uint32 LBA,
490     IN uint32 Flags
491     )
492 {
493     PLIST_ENTRY Link;
494     PUDF_VERIFY_ITEM vItem;
495     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
496     ULONG i;
497     ULONG n;
498     OSSTATUS status = STATUS_SUCCESS;
499 
500     if(!VerifyCtx->VInited) {
501         return STATUS_UNSUCCESSFUL;
502     }
503 
504     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
505 
506     for(i=0, n=0; i<BCount; i++) {
507         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
508             // some blocks are remembered
509             n++;
510         }
511     }
512 
513     if(!n) {
514         // no blocks are remembered
515         UDFReleaseResource(&(VerifyCtx->VerifyLock));
516         return STATUS_SUCCESS;
517     }
518 
519     Link = VerifyCtx->vrfList.Flink;
520     i = 0;
521     while(Link != &(VerifyCtx->vrfList)) {
522         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
523         Link = Link->Flink;
524         if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
525             i++;
526             UDFVRemoveBlock(VerifyCtx, vItem);
527             if(i >= n) {
528                 // no more blocks expected
529                 break;
530             }
531         }
532     }
533 
534     UDFReleaseResource(&(VerifyCtx->VerifyLock));
535     return status;
536 
537 } // end UDFVForget()
538 
539 VOID
540 NTAPI
UDFVWorkItem(PVOID Context)541 UDFVWorkItem(
542     PVOID Context
543     )
544 {
545     PUDF_VERIFY_REQ VerifyReq = (PUDF_VERIFY_REQ)Context;
546     PVCB Vcb = VerifyReq->Vcb;
547     SIZE_T ReadBytes;
548 //    OSSTATUS RC;
549     ULONG i;
550 
551     ReadBytes = (SIZE_T)Vcb;
552 #if 1
553     if(Vcb->SparingCountFree) {
554         WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
555         for(i=0; i<VerifyReq->nReq; i++) {
556             UDFTIOVerify(Vcb,
557                          VerifyReq->Buffer,     // Target buffer
558                          VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
559                          VerifyReq->vr[i].lba,
560                          &ReadBytes,
561                          PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
562         }
563         WCacheEODirect__(&(Vcb->FastCache), Vcb);
564     } else {
565         for(i=0; i<VerifyReq->nReq; i++) {
566             UDFPrint(("!!! No more space for remap !!!\n"));
567             UDFPrint(("  try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
568             UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
569                      PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
570         }
571     }
572 #else
573     for(i=0; i<VerifyReq->nReq; i++) {
574         if(Vcb->SparingCountFree) {
575             WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
576             RC = UDFTIOVerify(Vcb,
577                            VerifyReq->Buffer,     // Target buffer
578                            VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
579                            VerifyReq->vr[i].lba,
580                            &ReadBytes,
581                            PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
582             WCacheEODirect__(&(Vcb->FastCache), Vcb);
583         } else {
584             UDFPrint(("!!! No more space for remap !!!\n"));
585             UDFPrint(("  try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
586             RC = UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
587                           PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
588         }
589     }
590 #endif
591     DbgFreePool(VerifyReq->Buffer);
592     DbgFreePool(VerifyReq);
593     InterlockedDecrement((PLONG)&(Vcb->VerifyCtx.QueuedCount));
594     UDFPrint(("  QueuedCount = %d\n", Vcb->VerifyCtx.QueuedCount));
595     UDFPrint(("  Setting event...\n"));
596     KeSetEvent(&(Vcb->VerifyCtx.vrfEvent), 0, FALSE);
597     return;
598 } // end UDFVWorkItem()
599 
600 VOID
UDFVVerify(IN PVCB Vcb,IN ULONG Flags)601 UDFVVerify(
602     IN PVCB Vcb,
603     IN ULONG Flags
604     )
605 {
606     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
607     PLIST_ENTRY Link;
608     PUDF_VERIFY_ITEM vItem;
609     PUDF_VERIFY_REQ VerifyReq = NULL;
610     ULONG len, max_len=0;
611     lba_t prev_lba;
612     //PUCHAR tmp_buff;
613     ULONG i;
614     BOOLEAN do_vrf = FALSE;
615 
616     if(!VerifyCtx->VInited) {
617         return;
618     }
619     if(VerifyCtx->QueuedCount) {
620         if(Flags & UFD_VERIFY_FLAG_WAIT) {
621             UDFPrint(("  wait for verify flush\n"));
622             goto wait;
623         }
624         UDFPrint(("  verify flush already queued\n"));
625         return;
626     }
627 
628     if(!(Flags & (UFD_VERIFY_FLAG_FORCE | UFD_VERIFY_FLAG_BG))) {
629         if(VerifyCtx->ItemCount < UDF_MAX_VERIFY_CACHE) {
630             return;
631         }
632 
633     }
634     if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
635         UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
636     }
637 
638     if(Flags & UFD_VERIFY_FLAG_FORCE) {
639         i = VerifyCtx->ItemCount;
640     } else {
641         if(VerifyCtx->ItemCount >= UDF_MAX_VERIFY_CACHE) {
642             i = VerifyCtx->ItemCount - UDF_VERIFY_CACHE_LOW;
643         } else {
644             i = min(UDF_VERIFY_CACHE_GRAN, VerifyCtx->ItemCount);
645         }
646     }
647 
648     Link = VerifyCtx->vrfList.Flink;
649     prev_lba = -2;
650     len = 0;
651 
652     while(i) {
653         ASSERT(Link != &(VerifyCtx->vrfList));
654 /*
655         if(Link == &(VerifyCtx->vrfList)) {
656             if(!len)
657                 break;
658             i=1;
659             goto queue_req;
660         }
661 */
662         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
663         Link = Link->Flink;
664 
665         //
666         if(!vItem->queued && (prev_lba+len == vItem->lba)) {
667             vItem->queued = TRUE;
668             len++;
669         } else {
670             if(len) {
671                 do_vrf = TRUE;
672             } else {
673                 len = 1;
674                 prev_lba = vItem->lba;
675             }
676         }
677         if((i == 1) && len) {
678             do_vrf = TRUE;
679         }
680         if(len >= 0x100) {
681             do_vrf = TRUE;
682         }
683         if(do_vrf) {
684 //queue_req:
685             if(!VerifyReq) {
686                 VerifyReq = (PUDF_VERIFY_REQ)DbgAllocatePoolWithTag(NonPagedPool, sizeof(UDF_VERIFY_REQ), 'bNWD');
687                 if(VerifyReq) {
688                     RtlZeroMemory(VerifyReq, sizeof(UDF_VERIFY_REQ));
689                     VerifyReq->Vcb    = Vcb;
690                 }
691             }
692             if(VerifyReq) {
693 
694                 VerifyReq->vr[VerifyReq->nReq].lba    = prev_lba;
695                 VerifyReq->vr[VerifyReq->nReq].BCount = len;
696                 VerifyReq->nReq++;
697                 if(max_len < len) {
698                     max_len = len;
699                 }
700 
701                 if((VerifyReq->nReq >= MAX_VREQ_RANGES) || (i == 1)) {
702 
703                     VerifyReq->Buffer = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, max_len * Vcb->BlockSize, 'bNWD');
704                     if(VerifyReq->Buffer) {
705                         InterlockedIncrement((PLONG)&(VerifyCtx->QueuedCount));
706 #ifndef _CONSOLE
707                         ExInitializeWorkItem( &(VerifyReq->VerifyItem),
708                                               UDFVWorkItem,
709                                               VerifyReq );
710                         ExQueueWorkItem( &(VerifyReq->VerifyItem), CriticalWorkQueue );
711 #else
712                         UDFVWorkItem(VerifyReq);
713 #endif
714                     } else {
715                         DbgFreePool(VerifyReq);
716                     }
717                     VerifyReq = NULL;
718                     max_len = 0;
719                 } else {
720                 }
721             }
722             len = 1;
723             prev_lba = vItem->lba;
724             do_vrf = FALSE;
725         }
726         i--;
727     }
728 
729     if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
730         UDFReleaseResource(&(VerifyCtx->VerifyLock));
731     }
732     if(Flags & UFD_VERIFY_FLAG_WAIT) {
733 wait:
734         UDFPrint(("UDFVVerify: wait for completion\n"));
735         UDFVWaitQueued(VerifyCtx);
736     }
737 
738     return;
739 } // end UDFVVerify()
740 
741 VOID
UDFVFlush(IN PVCB Vcb)742 UDFVFlush(
743     IN PVCB Vcb
744     )
745 {
746     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
747 
748     if(!VerifyCtx->VInited) {
749         return;
750     }
751 
752     UDFPrint(("UDFVFlush: wait for completion\n"));
753     UDFVWaitQueued(VerifyCtx);
754 
755     UDFVVerify(Vcb, UFD_VERIFY_FLAG_FORCE);
756 
757     UDFPrint(("UDFVFlush: wait for completion (2)\n"));
758     UDFVWaitQueued(VerifyCtx);
759 } // end UDFVFlush()
760 
761 BOOLEAN
762 __fastcall
UDFCheckArea(IN PVCB Vcb,IN lba_t LBA,IN uint32 BCount)763 UDFCheckArea(
764     IN PVCB Vcb,
765     IN lba_t LBA,
766     IN uint32 BCount
767     )
768 {
769     uint8* buff;
770     OSSTATUS RC;
771     SIZE_T ReadBytes;
772     uint32 i, d;
773     BOOLEAN ext_ok = TRUE;
774     EXTENT_MAP Map[2];
775     uint32 PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
776 
777     buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' );
778     if(buff) {
779         for(i=0; i<BCount; i+=d) {
780             if(!((LBA+i) & (PS-1)) &&
781                (i+PS <= BCount)) {
782                 d = PS;
783             } else {
784                 d = 1;
785             }
786             RC = UDFTRead(Vcb,
787                            buff,
788                            d << Vcb->BlockSizeBits,
789                            LBA+i,
790                            &ReadBytes,
791                            PH_TMP_BUFFER);
792 
793             if(RC != STATUS_SUCCESS) {
794                 Map[0].extLocation = LBA+i;
795                 Map[0].extLength = d << Vcb->BlockSizeBits;
796                 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(Map[0]), AS_DISCARDED | AS_BAD); // free
797                 ext_ok = FALSE;
798             }
799         }
800         DbgFreePool(buff);
801     }
802     return ext_ok;
803 } // end UDFCheckArea()
804 
805 /*
806     This routine remaps sectors from bad packet
807  */
808 OSSTATUS
809 __fastcall
UDFRemapPacket(IN PVCB Vcb,IN uint32 Lba,IN BOOLEAN RemapSpared)810 UDFRemapPacket(
811     IN PVCB Vcb,
812     IN uint32 Lba,
813     IN BOOLEAN RemapSpared
814     )
815 {
816     uint32 i, max, BS, orig;
817     PSPARING_MAP Map;
818     BOOLEAN verified = FALSE;
819 
820     if(Vcb->SparingTable) {
821 
822         max = Vcb->SparingCount;
823         BS = Vcb->SparingBlockSize;
824 
825         // use sparing table for relocation
826         if(Vcb->SparingCountFree == (ULONG)-1) {
827             UDFPrint(("calculate free spare areas\n"));
828 re_check:
829             UDFPrint(("verify spare area\n"));
830             Vcb->SparingCountFree = 0;
831             Map = Vcb->SparingTable;
832             for(i=0;i<max;i++,Map++) {
833                 if(Map->origLocation == SPARING_LOC_AVAILABLE) {
834                     if(UDFCheckArea(Vcb, Map->mappedLocation, BS)) {
835                         Vcb->SparingCountFree++;
836                     } else {
837                         UDFPrint(("initial check: bad spare block @ %x\n", Map->mappedLocation));
838                         Map->origLocation = SPARING_LOC_CORRUPTED;
839                         Vcb->SparingTableModified = TRUE;
840                     }
841                 }
842             }
843         }
844         if(!Vcb->SparingCountFree) {
845             UDFPrint(("sparing table full\n"));
846             return STATUS_DISK_FULL;
847         }
848 
849         Map = Vcb->SparingTable;
850         Lba &= ~(BS-1);
851         for(i=0;i<max;i++,Map++) {
852             orig = Map->origLocation;
853             if(Lba == (orig & ~(BS-1)) ) {
854                 // already remapped
855 
856                 UDFPrint(("remap remapped: bad spare block @ %x\n", Map->mappedLocation));
857                 if(!verified) {
858                     verified = TRUE;
859                     goto re_check;
860                 }
861 
862                 if(!RemapSpared) {
863                     return STATUS_SHARING_VIOLATION;
864                 } else {
865                     // look for another remap area
866                     Map->origLocation = SPARING_LOC_CORRUPTED;
867                     Vcb->SparingTableModified = TRUE;
868                     Vcb->SparingCountFree--;
869                     break;
870                 }
871             }
872         }
873         Map = Vcb->SparingTable;
874         for(i=0;i<max;i++,Map++) {
875             if(Map->origLocation == SPARING_LOC_AVAILABLE) {
876                 UDFPrint(("remap %x -> %x\n", Lba, Map->mappedLocation));
877                 Map->origLocation = Lba;
878                 Vcb->SparingTableModified = TRUE;
879                 Vcb->SparingCountFree--;
880                 return STATUS_SUCCESS;
881             }
882         }
883         UDFPrint(("sparing table full\n"));
884         return STATUS_DISK_FULL;
885     }
886     return STATUS_UNSUCCESSFUL;
887 } // end UDFRemapPacket()
888 
889 /*
890     This routine releases sector mapping when entire packet is marked as free
891  */
892 OSSTATUS
893 __fastcall
UDFUnmapRange(IN PVCB Vcb,IN uint32 Lba,IN uint32 BCount)894 UDFUnmapRange(
895     IN PVCB Vcb,
896     IN uint32 Lba,
897     IN uint32 BCount
898     )
899 {
900     uint32 i, max, BS, orig;
901     PSPARING_MAP Map;
902 
903     if(Vcb->SparingTable) {
904         // use sparing table for relocation
905 
906         max = Vcb->SparingCount;
907         BS = Vcb->SparingBlockSize;
908         Map = Vcb->SparingTable;
909         for(i=0;i<max;i++,Map++) {
910             orig = Map->origLocation;
911             switch(orig) {
912             case SPARING_LOC_AVAILABLE:
913             case SPARING_LOC_CORRUPTED:
914                 continue;
915             }
916             if(orig >= Lba &&
917               (orig+BS) <= (Lba+BCount)) {
918                 // unmap
919                 UDFPrint(("unmap %x -> %x\n", orig, Map->mappedLocation));
920                 Map->origLocation = SPARING_LOC_AVAILABLE;
921                 Vcb->SparingTableModified = TRUE;
922                 Vcb->SparingCountFree++;
923             }
924         }
925     }
926     return STATUS_SUCCESS;
927 } // end UDFUnmapRange()
928 
929 /*
930     This routine returns physical address for relocated sector
931  */
932 uint32
933 __fastcall
UDFRelocateSector(IN PVCB Vcb,IN uint32 Lba)934 UDFRelocateSector(
935     IN PVCB Vcb,
936     IN uint32 Lba
937     )
938 {
939     uint32 i, max, BS, orig;
940 
941     if(Vcb->SparingTable) {
942         // use sparing table for relocation
943         uint32 _Lba;
944         PSPARING_MAP Map = Vcb->SparingTable;
945 
946         max = Vcb->SparingCount;
947         BS = Vcb->SparingBlockSize;
948         _Lba = Lba & ~(BS-1);
949         for(i=0;i<max;i++,Map++) {
950             orig = Map->origLocation;
951             if(_Lba == (orig & ~(BS-1)) ) {
952             //if( (Lba >= (orig = Map->origLocation)) && (Lba < orig + BS) ) {
953                 return Map->mappedLocation + Lba - orig;
954             }
955         }
956     } else if(Vcb->Vat) {
957         // use VAT for relocation
958         uint32* Map = Vcb->Vat;
959         uint32 root;
960         // check if given Lba lays in the partition covered by VAT
961         if(Lba >= Vcb->NWA)
962             return Vcb->NWA;
963         if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
964             return Lba;
965         Map = &(Vcb->Vat[(i = Lba - root)]);
966         if((i < Vcb->VatCount) && (i=(*Map)) ) {
967             if(i != UDF_VAT_FREE_ENTRY) {
968                 return i + root;
969             } else {
970                 return 0x7fffffff;
971             }
972         }
973     }
974     return Lba;
975 } // end UDFRelocateSector()
976 
977 /*
978     This routine checks if the extent specified requires relocation
979  */
980 BOOLEAN
981 __fastcall
UDFAreSectorsRelocated(IN PVCB Vcb,IN uint32 Lba,IN uint32 BlockCount)982 UDFAreSectorsRelocated(
983     IN PVCB Vcb,
984     IN uint32 Lba,
985     IN uint32 BlockCount
986     )
987 {
988 
989     if(Vcb->SparingTable) {
990         // use sparing table for relocation
991         uint32 i, BS, orig;
992         BS = Vcb->SparingBlockSize;
993         PSPARING_MAP Map;
994 
995         Map = Vcb->SparingTable;
996         for(i=0;i<Vcb->SparingCount;i++,Map++) {
997             if( ((Lba >= (orig = Map->origLocation)) && (Lba < orig + BS)) ||
998                 ((Lba+BlockCount-1 >= orig) && (Lba+BlockCount-1 < orig + BS)) ||
999                 ((orig >= Lba) && (orig < Lba+BlockCount)) ||
1000                 ((orig+BS >= Lba) && (orig+BS < Lba+BlockCount)) ) {
1001                 return TRUE;
1002             }
1003         }
1004     } else if(Vcb->Vat) {
1005         // use VAT for relocation
1006         uint32 i, root, j;
1007         uint32* Map;
1008         if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
1009             return FALSE;
1010         if(Lba+BlockCount >= Vcb->NWA)
1011             return TRUE;
1012         Map = &(Vcb->Vat[Lba-root/*+i*/]);
1013         for(i=0; i<BlockCount; i++, Map++) {
1014             if((j = (*Map)) &&
1015                (j != Lba-root+i) &&
1016                ((j != UDF_VAT_FREE_ENTRY) || ((Lba+i) < Vcb->LastLBA)))
1017                 return TRUE;
1018         }
1019     }
1020     return FALSE;
1021 } // end UDFAreSectorsRelocated()
1022 
1023 /*
1024     This routine builds mapping for relocated extent
1025     If relocation is not required (-1) will be returned
1026  */
1027 PEXTENT_MAP
1028 __fastcall
UDFRelocateSectors(IN PVCB Vcb,IN uint32 Lba,IN uint32 BlockCount)1029 UDFRelocateSectors(
1030     IN PVCB Vcb,
1031     IN uint32 Lba,
1032     IN uint32 BlockCount
1033     )
1034 {
1035     if(!UDFAreSectorsRelocated(Vcb, Lba, BlockCount)) return UDF_NO_EXTENT_MAP;
1036 
1037     PEXTENT_MAP Extent=NULL, Extent2;
1038     uint32 NewLba, LastLba, j, i;
1039     EXTENT_AD locExt;
1040 
1041     LastLba = UDFRelocateSector(Vcb, Lba);
1042     for(i=0, j=1; i<BlockCount; i++, j++) {
1043         // create new entry if the extent in not contigous
1044         if( ((NewLba = UDFRelocateSector(Vcb, Lba+i+1)) != (LastLba+1)) ||
1045             (i==(BlockCount-1)) ) {
1046             locExt.extLength = j << Vcb->BlockSizeBits;
1047             locExt.extLocation = LastLba-j+1;
1048             Extent2 = UDFExtentToMapping(&locExt);
1049             if(!Extent) {
1050                 Extent = Extent2;
1051             } else {
1052                 Extent = UDFMergeMappings(Extent, Extent2);
1053                 MyFreePool__(Extent2);
1054             }
1055             if(!Extent) return NULL;
1056             j = 0;
1057         }
1058         LastLba = NewLba;
1059     }
1060     return Extent;
1061 } // end UDFRelocateSectors()
1062 
1063