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    extent.cpp
10 
11         Abstract:
12 
13    This file contains filesystem-specific routines
14    responsible for extent & mapping management
15 
16 */
17 
18 #include "udf.h"
19 
20 #define         UDF_BUG_CHECK_ID                UDF_FILE_UDF_INFO_EXTENT
21 
22 /*
23     This routine converts offset in extent to Lba & returns offset in the 1st
24     sector & bytes before end of block.
25     Here we assume no references to AllocDescs
26  */
27 uint32
UDFExtentOffsetToLba(IN PVCB Vcb,IN PEXTENT_MAP Extent,IN int64 Offset,OUT uint32 * SectorOffset,OUT PSIZE_T AvailLength,OUT uint32 * Flags,OUT uint32 * Index)28 UDFExtentOffsetToLba(
29     IN PVCB Vcb,
30     IN PEXTENT_MAP Extent,   // Extent array
31     IN int64 Offset,      // offset in extent
32     OUT uint32* SectorOffset,
33     OUT PSIZE_T AvailLength,  // available data in this block
34     OUT uint32* Flags,
35     OUT uint32* Index
36     )
37 {
38     uint32 j=0, l, d, BSh = Vcb->BlockSizeBits;
39     uint32 Offs;
40     uint32 i=0, BOffset; // block nums
41 
42     BOffset = (uint32)(Offset >> BSh);
43     // scan extent table for suitable range (frag)
44     ExtPrint(("ExtLen %x\n", Extent->extLength));
45     while(i+(d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)) >> BSh) <= BOffset) {
46 
47         if(!l) {
48             if(Index) (*Index) = j-1;
49             if(Flags) {
50                 Extent--;
51                 (*Flags) = (Extent->extLength >> 30);
52             }
53             return LBA_OUT_OF_EXTENT;
54         }
55         if(!d)
56             break;
57         i += d; //frag offset
58         j++; // frag index
59         Extent++;
60     }
61     BOffset -= i;
62     Offs = (*((uint32*)&Offset)) - (i << BSh); // offset in frag
63 
64     if(SectorOffset)
65         (*SectorOffset) = Offs & (Vcb->BlockSize-1);// offset in 1st Lba
66     if(AvailLength)
67         (*AvailLength) = l - Offs;// bytes to EO frag
68     if(Flags)
69         (*Flags) = (Extent->extLength >> 30);
70     if(Index)
71         (*Index) = j;
72 
73     ASSERT(((Extent->extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation);
74 
75     return Extent->extLocation + BOffset;// 1st Lba
76 } // end UDFExtentOffsetToLba()
77 
78 uint32
UDFNextExtentToLba(IN PVCB Vcb,IN PEXTENT_MAP Extent,OUT PSIZE_T AvailLength,OUT uint32 * Flags,OUT uint32 * Index)79 UDFNextExtentToLba(
80     IN PVCB Vcb,
81     IN PEXTENT_MAP Extent,   // Extent array
82     OUT PSIZE_T AvailLength,  // available data in this block
83     OUT uint32* Flags,
84     OUT uint32* Index
85     )
86 {
87 //    uint32 Lba;
88 
89     uint32 l;
90 //    uint32 d;
91 
92     // scan extent table for suitable range (frag)
93 //    d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK));
94     l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK);
95 
96     if(!l) {
97         (*Index) = -1;
98         Extent--;
99         (*Flags) = (Extent->extLength >> 30);
100         return LBA_OUT_OF_EXTENT;
101     }
102 
103     (*Index) = 0;
104     (*AvailLength) = l;// bytes to EO frag
105     (*Flags) = (Extent->extLength >> 30);
106 
107     ASSERT(((*Flags) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation);
108 
109     return Extent->extLocation;// 1st Lba
110 } // end UDFNextExtentToLba()
111 
112 /*
113     This routine locates frag containing specified Lba in extent
114  */
115 ULONG
UDFLocateLbaInExtent(IN PVCB Vcb,IN PEXTENT_MAP Extent,IN lba_t lba)116 UDFLocateLbaInExtent(
117     IN PVCB Vcb,
118     IN PEXTENT_MAP Extent,   // Extent array
119     IN lba_t lba
120     )
121 {
122     uint32 l, BSh = Vcb->BlockSizeBits;
123     uint32 i=0;
124 
125     while((l = ((Extent->extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) {
126 
127         if(Extent->extLocation   >= lba &&
128            Extent->extLocation+l <  lba) {
129             return i;
130         }
131         i++; //frag offset
132         Extent++;
133     }
134     return LBA_OUT_OF_EXTENT;// index of item in extent, containing out Lba
135 } // end UDFLocateLbaInExtent()
136 
137 /*
138     This routine calculates total length of specified extent.
139     Here we assume no references to AllocDescs
140  */
141 int64
UDFGetExtentLength(IN PEXTENT_MAP Extent)142 UDFGetExtentLength(
143     IN PEXTENT_MAP Extent   // Extent array
144     )
145 {
146     if(!Extent) return 0;
147     int64 i=0;
148 
149 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
150 
151     __asm push  ebx
152     __asm push  ecx
153     __asm push  esi
154 
155     __asm lea   ebx,i
156     __asm mov   esi,Extent
157     __asm xor   ecx,ecx
158 While_1:
159     __asm mov   eax,[esi+ecx*8]  // Extent[j].extLength
160     __asm and   eax,UDF_EXTENT_LENGTH_MASK
161     __asm jz    EO_While
162     __asm add   [ebx],eax
163     __asm adc   [ebx+4],0
164     __asm inc   ecx
165     __asm jmp   While_1
166 EO_While:;
167     __asm pop   esi
168     __asm pop   ecx
169     __asm pop   ebx
170 
171 #else   // NO X86 optimization , use generic C/C++
172 
173     while(Extent->extLength) {
174         i += (Extent->extLength & UDF_EXTENT_LENGTH_MASK);
175         Extent++;
176     }
177 
178 #endif // _X86_
179 
180     return i;
181 } // UDFGetExtentLength()
182 
183 /*
184     This routine appends Zero-terminator to single Extent-entry.
185     Such operation makes it compatible with other internal routines
186  */
187 PEXTENT_MAP
188 __fastcall
UDFExtentToMapping_(IN PEXTENT_AD Extent,IN ULONG src,IN ULONG line)189 UDFExtentToMapping_(
190     IN PEXTENT_AD Extent
191 #ifdef UDF_TRACK_EXTENT_TO_MAPPING
192    ,IN ULONG src,
193     IN ULONG line
194 #endif //UDF_TRACK_EXTENT_TO_MAPPING
195     )
196 {
197     PEXTENT_MAP Map;
198 
199 #ifdef UDF_TRACK_EXTENT_TO_MAPPING
200 #define UDF_EXT_MAP_MULT 4
201 #else //UDF_TRACK_EXTENT_TO_MAPPING
202 #define UDF_EXT_MAP_MULT 2
203 #endif //UDF_TRACK_EXTENT_TO_MAPPING
204 
205     Map = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDF_EXT_MAP_MULT *
206                                                        sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
207     if(!Map) return NULL;
208     RtlZeroMemory((int8*)(Map+1), sizeof(EXTENT_MAP));
209     Map[0].extLength = Extent->extLength;
210     Map[0].extLocation = Extent->extLocation;
211 #ifdef UDF_TRACK_EXTENT_TO_MAPPING
212     Map[2].extLength = src;
213     Map[2].extLocation = line;
214 #endif //UDF_TRACK_EXTENT_TO_MAPPING
215     return Map;
216 } // end UDFExtentToMapping()
217 
218 /*
219     This routine calculates file mapping length (in bytes) including
220     ZERO-terminator
221  */
222 uint32
UDFGetMappingLength(IN PEXTENT_MAP Extent)223 UDFGetMappingLength(
224     IN PEXTENT_MAP Extent
225     )
226 {
227     if(!Extent) return 0;
228     uint32 i=0;
229 
230 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
231     __asm push  ebx
232 
233     __asm mov   ebx,Extent
234     __asm xor   eax,eax
235 While_1:
236     __asm mov   ecx,[ebx+eax*8]
237     __asm jecxz EO_While
238     __asm inc   eax
239     __asm jmp   While_1
240 EO_While:
241     __asm inc   eax
242     __asm shl   eax,3
243     __asm mov   i,eax
244 
245     __asm pop   ebx
246 
247 #else   // NO X86 optimization , use generic C/C++
248 
249     while(Extent->extLength) {
250         i++;
251         Extent++;
252     }
253     i++;
254     i*=sizeof(EXTENT_MAP);
255 
256 #endif // _X86_
257 
258     return i; //  i*sizeof(EXTENT_MAP)
259 } // end UDFGetMappingLength()
260 
261 /*
262     This routine merges 2 sequencial file mappings
263  */
264 PEXTENT_MAP
265 __fastcall
UDFMergeMappings(IN PEXTENT_MAP Extent,IN PEXTENT_MAP Extent2)266 UDFMergeMappings(
267     IN PEXTENT_MAP Extent,
268     IN PEXTENT_MAP Extent2
269     )
270 {
271     PEXTENT_MAP NewExt;
272     uint32 len, len2;
273 
274     len = UDFGetMappingLength(Extent);
275     len2 = UDFGetMappingLength(Extent2);
276     ASSERT(len2 && len);
277     if(!len2) {
278         return Extent;
279     }
280     if(MyReallocPool__((int8*)Extent, len, (int8**)(&NewExt), len+len2-sizeof(EXTENT_MAP))) {
281         RtlCopyMemory(((int8*)NewExt)+len-sizeof(EXTENT_MAP), (int8*)Extent2, len2);
282     } else {
283         ExtPrint(("UDFMergeMappings failed\n"));
284         BrutePoint();
285     }
286     return NewExt;
287 } // end UDFMergeMappings()
288 
289 /*
290     This routine builds file mapping according to ShortAllocDesc (SHORT_AD)
291     array
292  */
293 PEXTENT_MAP
UDFShortAllocDescToMapping(IN PVCB Vcb,IN uint32 PartNum,IN PSHORT_AD AllocDesc,IN uint32 AllocDescLength,IN uint32 SubCallCount,OUT PEXTENT_INFO AllocLoc)294 UDFShortAllocDescToMapping(
295     IN PVCB Vcb,
296     IN uint32 PartNum,
297     IN PSHORT_AD AllocDesc,
298     IN uint32 AllocDescLength,
299     IN uint32 SubCallCount,
300     OUT PEXTENT_INFO AllocLoc
301     )
302 {
303     uint32 i, lim, l, len, type;
304 //    uint32 BSh;
305     PEXTENT_MAP Extent, Extent2, AllocMap;
306     EXTENT_AD AllocExt;
307     PALLOC_EXT_DESC NextAllocDesc;
308     lb_addr locAddr;
309     SIZE_T ReadBytes;
310     EXTENT_INFO NextAllocLoc;
311     BOOLEAN w2k_compat = FALSE;
312 
313     ExtPrint(("UDFShortAllocDescToMapping: len=%x\n", AllocDescLength));
314 
315     if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
316 
317     locAddr.partitionReferenceNum = (uint16)PartNum;
318 //    BSh = Vcb->BlockSizeBits;
319     l = ((lim = (AllocDescLength/sizeof(SHORT_AD))) + 1 ) * sizeof(EXTENT_AD);
320     Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
321     if(!Extent) return NULL;
322 
323     NextAllocLoc.Offset = 0;
324 
325     for(i=0;i<lim;i++) {
326         type = AllocDesc[i].extLength >> 30;
327         len  = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
328         ExtPrint(("ShExt: type %x, loc %x, len %x\n", type, AllocDesc[i].extPosition, len));
329         if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
330             // read next frag of allocation descriptors if encountered
331             if(len < sizeof(ALLOC_EXT_DESC)) {
332                 MyFreePool__(Extent);
333                 return NULL;
334             }
335             NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
336             if(!NextAllocDesc) {
337                 MyFreePool__(Extent);
338                 return NULL;
339             }
340             // record information about this frag
341             locAddr.logicalBlockNum = AllocDesc[i].extPosition;
342             AllocExt.extLength = len;
343             AllocExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr);
344             if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
345                 UDFPrint(("bad address\n"));
346                 MyFreePool__(NextAllocDesc);
347                 MyFreePool__(Extent);
348                 return NULL;
349             }
350             NextAllocLoc.Mapping =
351             AllocMap = UDFExtentToMapping(&AllocExt);
352             NextAllocLoc.Length = len;
353             if(!AllocMap) {
354                 MyFreePool__(NextAllocDesc);
355                 MyFreePool__(Extent);
356                 return NULL;
357             }
358             AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
359             if(!AllocLoc->Mapping ||
360             // read this frag
361                !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
362                                 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
363             {
364                 MyFreePool__(AllocMap);
365                 MyFreePool__(NextAllocDesc);
366                 MyFreePool__(Extent);
367                 return NULL;
368             }
369             MyFreePool__(AllocMap);
370             // check integrity
371             if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
372                (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
373                 UDFPrint(("Integrity check failed\n"));
374                 UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
375                 UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
376                 UDFPrint(("len = %x\n", len));
377                 MyFreePool__(NextAllocDesc);
378                 MyFreePool__(Extent);
379                 return NULL;
380             }
381             // perform recursive call to obtain mapping
382             NextAllocLoc.Flags = 0;
383             Extent2 = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)(NextAllocDesc+1),
384                                       NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
385             if(!Extent2) {
386                 MyFreePool__(NextAllocDesc);
387                 MyFreePool__(Extent);
388                 return NULL;
389             }
390             UDFCheckSpaceAllocation(Vcb, 0, Extent2, AS_USED); // check if used
391             // and merge this 2 mappings into 1
392             Extent[i].extLength = 0;
393             Extent[i].extLocation = 0;
394             Extent = UDFMergeMappings(Extent, Extent2);
395 
396             if(NextAllocLoc.Flags & EXTENT_FLAG_2K_COMPAT) {
397                 ExtPrint(("w2k-compat\n"));
398                 AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
399             }
400 
401             MyFreePool__(Extent2);
402             return Extent;
403         }
404         //
405 #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
406         ASSERT(!(len & (Vcb->LBlockSize-1) ));
407 #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
408         if(len & (Vcb->LBlockSize-1)) {
409             w2k_compat = TRUE;
410         }
411         Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1);
412         locAddr.logicalBlockNum = AllocDesc[i].extPosition;
413         // Note: for compatibility Adaptec DirectCD we check 'len' here
414         //       That strange implementation records bogus extLocation in terminal entries
415         if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
416             Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr);
417             if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
418                 UDFPrint(("bad address (2)\n"));
419                 MyFreePool__(Extent);
420                 return NULL;
421             }
422         } else {
423             Extent[i].extLocation = 0;
424         }
425         if(!len) {
426             // some UDF implementations set strange AllocDesc sequence length,
427             // but terminates it with zeros in proper place, so handle
428             // this case
429             ASSERT(i>=(lim-1));
430             ASSERT(!Extent[i].extLength);
431             Extent[i].extLocation = 0;
432             if(/*!SubCallCount &&*/ w2k_compat) {
433                 ExtPrint(("w2k-compat\n"));
434                 AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
435             }
436             return Extent;
437         }
438         Extent[i].extLength |= (type << 30);
439     }
440     // set terminator
441     Extent[i].extLength = 0;
442     Extent[i].extLocation = 0;
443 
444     if(/*!SubCallCount &&*/ w2k_compat) {
445         ExtPrint(("w2k-compat\n"));
446         AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
447     }
448 
449     return Extent;
450 } // end UDFShortAllocDescToMapping()
451 
452 /*
453     This routine builds file mapping according to LongAllocDesc (LONG_AD)
454     array
455  */
456 PEXTENT_MAP
UDFLongAllocDescToMapping(IN PVCB Vcb,IN PLONG_AD AllocDesc,IN uint32 AllocDescLength,IN uint32 SubCallCount,OUT PEXTENT_INFO AllocLoc)457 UDFLongAllocDescToMapping(
458     IN PVCB Vcb,
459     IN PLONG_AD AllocDesc,
460     IN uint32 AllocDescLength,
461     IN uint32 SubCallCount,
462     OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
463     )
464 {
465     uint32 i, lim, l, len, type;
466 //    uint32 BSh;
467     PEXTENT_MAP Extent, Extent2, AllocMap;
468     EXTENT_AD AllocExt;
469     PALLOC_EXT_DESC NextAllocDesc;
470     SIZE_T ReadBytes;
471     EXTENT_INFO NextAllocLoc;
472 
473     ExtPrint(("UDFLongAllocDescToMapping: len=%x\n", AllocDescLength));
474 
475     if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
476 
477 //    BSh = Vcb->BlockSizeBits;
478     l = ((lim = (AllocDescLength/sizeof(LONG_AD))) + 1 ) * sizeof(EXTENT_AD);
479     Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
480     if(!Extent) return NULL;
481 
482     NextAllocLoc.Offset = 0;
483 
484     for(i=0;i<lim;i++) {
485         type = AllocDesc[i].extLength >> 30;
486         len  = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
487         ExtPrint(("LnExt: type %x, loc %x (%x:%x), len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)),
488             AllocDesc[i].extLocation.partitionReferenceNum, AllocDesc[i].extLocation.logicalBlockNum,
489             len));
490         if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
491             // read next frag of allocation descriptors if encountered
492             if(len < sizeof(ALLOC_EXT_DESC)) {
493                 MyFreePool__(Extent);
494                 return NULL;
495             }
496             NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
497             if(!NextAllocDesc) {
498                 MyFreePool__(Extent);
499                 return NULL;
500             }
501             // record information about this frag
502             AllocExt.extLength = len;
503             AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
504             if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
505                 UDFPrint(("bad address\n"));
506                 MyFreePool__(NextAllocDesc);
507                 MyFreePool__(Extent);
508                 return NULL;
509             }
510             NextAllocLoc.Mapping =
511             AllocMap = UDFExtentToMapping(&AllocExt);
512             NextAllocLoc.Length = len;
513             if(!AllocMap) {
514                 MyFreePool__(NextAllocDesc);
515                 MyFreePool__(Extent);
516                 return NULL;
517             }
518             AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
519             if(!AllocLoc->Mapping ||
520             // read this frag
521                !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
522                                 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
523             {
524                 MyFreePool__(AllocMap);
525                 MyFreePool__(NextAllocDesc);
526                 MyFreePool__(Extent);
527                 return NULL;
528             }
529             MyFreePool__(AllocMap);
530             // check integrity
531             if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
532                (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
533                 UDFPrint(("Integrity check failed\n"));
534                 UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
535                 UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
536                 UDFPrint(("len = %x\n", len));
537                 MyFreePool__(NextAllocDesc);
538                 MyFreePool__(Extent);
539                 return NULL;
540             }
541             // perform recursive call to obtain mapping
542             Extent2 = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)(NextAllocDesc+1),
543                                       NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
544             if(!Extent2) {
545                 MyFreePool__(NextAllocDesc);
546                 MyFreePool__(Extent);
547                 return NULL;
548             }
549             // and merge this 2 mappings into 1
550             Extent[i].extLength = 0;
551             Extent[i].extLocation = 0;
552             Extent = UDFMergeMappings(Extent, Extent2);
553             MyFreePool__(Extent2);
554             return Extent;
555         }
556         //
557         Extent[i].extLength = len;
558 #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
559         ASSERT(!(len & (Vcb->LBlockSize-1) ));
560 #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
561         Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1);
562         // Note: for compatibility Adaptec DirectCD we check 'len' here
563         //       That strange implementation records bogus extLocation in terminal entries
564         if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
565             Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
566             if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
567                 UDFPrint(("bad address (2)\n"));
568                 MyFreePool__(Extent);
569                 return NULL;
570             }
571         } else {
572             Extent[i].extLocation = 0;
573         }
574         if(!len) {
575             // some UDF implementations set strange AllocDesc sequence length,
576             // but terminates it with zeros in proper place, so handle
577             // this case
578             Extent[i].extLocation = 0;
579             return Extent;
580         }
581         Extent[i].extLength |= (type << 30);
582     }
583     // set terminator
584     Extent[i].extLength = 0;
585     Extent[i].extLocation = 0;
586 
587     return Extent;
588 } // end UDFLongAllocDescToMapping()
589 
590 /*
591     This routine builds file mapping according to ExtendedAllocDesc (EXT_AD)
592     array
593  */
594 PEXTENT_MAP
UDFExtAllocDescToMapping(IN PVCB Vcb,IN PEXT_AD AllocDesc,IN uint32 AllocDescLength,IN uint32 SubCallCount,OUT PEXTENT_INFO AllocLoc)595 UDFExtAllocDescToMapping(
596     IN PVCB Vcb,
597     IN PEXT_AD AllocDesc,
598     IN uint32 AllocDescLength,
599     IN uint32 SubCallCount,
600     OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
601     )
602 {
603     uint32 i, lim, l, len, type;
604 //    uint32 BSh;
605     PEXTENT_MAP Extent, Extent2, AllocMap;
606     EXTENT_AD AllocExt;
607     PALLOC_EXT_DESC NextAllocDesc;
608     SIZE_T ReadBytes;
609     EXTENT_INFO NextAllocLoc;
610 
611     ExtPrint(("UDFExtAllocDescToMapping: len=%x\n", AllocDescLength));
612 
613     if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
614 
615 //    BSh = Vcb->BlockSizeBits;
616     l = ((lim = (AllocDescLength/sizeof(EXT_AD))) + 1 ) * sizeof(EXTENT_AD);
617     Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
618     if(!Extent) return NULL;
619 
620     NextAllocLoc.Offset = 0;
621 
622     for(i=0;i<lim;i++) {
623         type = AllocDesc[i].extLength >> 30;
624         len  = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
625         ExtPrint(("ExExt: type %x, loc %x, len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), len));
626         if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
627             // read next frag of allocation descriptors if encountered
628             if(len < sizeof(ALLOC_EXT_DESC)) {
629                 MyFreePool__(Extent);
630                 return NULL;
631             }
632             NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
633             if(!NextAllocDesc) {
634                 MyFreePool__(Extent);
635                 return NULL;
636             }
637             // record information about this frag
638             AllocExt.extLength = len;
639             AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
640             if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
641                 UDFPrint(("bad address\n"));
642                 MyFreePool__(NextAllocDesc);
643                 MyFreePool__(Extent);
644                 return NULL;
645             }
646             NextAllocLoc.Mapping =
647             AllocMap = UDFExtentToMapping(&AllocExt);
648             NextAllocLoc.Length = len;
649             if(!AllocMap) {
650                 MyFreePool__(NextAllocDesc);
651                 MyFreePool__(Extent);
652                 return NULL;
653             }
654             AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
655             if(!AllocLoc->Mapping ||
656             // read this frag
657                !OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
658                                 0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
659             {
660                 MyFreePool__(AllocMap);
661                 MyFreePool__(NextAllocDesc);
662                 MyFreePool__(Extent);
663                 return NULL;
664             }
665             MyFreePool__(AllocMap);
666             // check integrity
667             if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
668                (NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
669                 UDFPrint(("Integrity check failed\n"));
670                 MyFreePool__(NextAllocDesc);
671                 MyFreePool__(Extent);
672                 return NULL;
673             }
674             // perform recursive call to obtain mapping
675             Extent2 = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)(NextAllocDesc+1),
676                                       NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
677             if(!Extent2) {
678                 MyFreePool__(NextAllocDesc);
679                 MyFreePool__(Extent);
680                 return NULL;
681             }
682             // and merge this 2 mappings into 1
683             Extent[i].extLength = 0;
684             Extent[i].extLocation = 0;
685             Extent = UDFMergeMappings(Extent, Extent2);
686             MyFreePool__(Extent2);
687             return Extent;
688         }
689 /*        if((AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK) > // Uncomment!!!
690            (AllocDesc[i].recordedLength & UDF_EXTENT_LENGTH_MASK)) {
691             Extent[i].extLength = AllocDesc[i].recordedLength;
692             Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
693         }*/
694         Extent[i].extLength = len;
695 #ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
696         ASSERT(!(len & (Vcb->LBlockSize-1) ));
697 #endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
698         // Note: for compatibility Adaptec DirectCD we check 'len' here
699         //       That strange implementation records bogus extLocation in terminal entries
700         if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
701             Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
702             if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
703                 UDFPrint(("bad address (2)\n"));
704                 MyFreePool__(Extent);
705                 return NULL;
706             }
707         } else {
708             Extent[i].extLocation = 0;
709         }
710         if(!len) {
711             // some UDF implementations set strange AllocDesc sequence length,
712             // but terminates it with zeros in proper place, so handle
713             // this case
714             Extent[i].extLocation = 0;
715             return Extent;
716         }
717         Extent[i].extLength |= (type << 30);
718     }
719     // set terminator
720     Extent[i].extLength = 0;
721     Extent[i].extLocation = 0;
722 
723     return Extent;
724 } // end UDFExtAllocDescToMapping()
725 
726 
727 /*
728     This routine builds FileMapping according to given FileEntry
729     Return:    pointer to EXTENT_MAP array
730             or offset inside FileEntry (negative)
731                when ICB_FLAG_AD_IN_ICB encountered
732             of NULL if an error occured
733  */
734 PEXTENT_MAP
UDFReadMappingFromXEntry(IN PVCB Vcb,IN uint32 PartNum,IN tag * XEntry,IN OUT uint32 * Offset,OUT PEXTENT_INFO AllocLoc)735 UDFReadMappingFromXEntry(
736     IN PVCB Vcb,
737     IN uint32 PartNum,
738     IN tag* XEntry,
739     IN OUT uint32* Offset,
740     OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
741     )
742 {
743     PEXTENT_AD Extent;
744     uint16 AllocMode;
745     int8* AllocDescs;
746     uint32 len;
747 //    EntityID* eID;  // for compatibility with Adaptec DirectCD
748 
749     Extent = NULL;
750     (*Offset) = 0;
751 
752 
753     if(XEntry->tagIdent == TID_FILE_ENTRY) {
754 //        UDFPrint(("Standard FileEntry\n"));
755         PFILE_ENTRY FileEntry = (PFILE_ENTRY)XEntry;
756         ExtPrint(("Standard FileEntry\n"));
757 
758         AllocDescs = (int8*)(((int8*)(FileEntry+1))+(FileEntry->lengthExtendedAttr));
759         len = FileEntry->lengthAllocDescs;
760         AllocLoc->Offset = sizeof(FILE_ENTRY) + FileEntry->lengthExtendedAttr;
761 //        eID = &(FileEntry->impIdent);
762 
763         AllocMode = FileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK;
764 
765     } else if(XEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) {
766 //        UDFPrint(("Extended FileEntry\n"));
767         ExtPrint(("Extended FileEntry\n"));
768         PEXTENDED_FILE_ENTRY ExFileEntry = (PEXTENDED_FILE_ENTRY)XEntry;
769 
770         AllocDescs = (((int8*)(ExFileEntry+1))+(ExFileEntry->lengthExtendedAttr));
771         len = ExFileEntry->lengthAllocDescs;
772         AllocLoc->Offset = sizeof(EXTENDED_FILE_ENTRY) + ExFileEntry->lengthExtendedAttr;
773 //        eID = &(FileEntry->impIdent);
774 
775         AllocMode = ExFileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK;
776 
777     } else {
778         return NULL;
779     }
780 
781     // for compatibility with Adaptec DirectCD
782 //    if(!(Vcb->UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT))
783 
784     AllocLoc->Length=len;
785     AllocLoc->Flags |= EXTENT_FLAG_VERIFY; // for metadata
786 
787     switch (AllocMode) {
788     case ICB_FLAG_AD_SHORT: {
789         Extent = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)AllocDescs, len, 0, AllocLoc);
790         break;
791     }
792     case ICB_FLAG_AD_LONG: {
793         Extent = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)AllocDescs, len, 0, AllocLoc);
794         break;
795     }
796     case ICB_FLAG_AD_EXTENDED: {
797         Extent = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)AllocDescs, len, 0, AllocLoc);
798         break;
799     }
800     default : {  // case ICB_FLAG_AD_IN_ICB
801         Extent = NULL;
802         *Offset = (uintptr_t)AllocDescs - (uintptr_t)XEntry;
803         AllocLoc->Offset=0;
804         AllocLoc->Length=0;
805         if(AllocLoc->Mapping) MyFreePool__(AllocLoc->Mapping);
806         AllocLoc->Mapping=NULL;
807         break;
808     }
809     }
810 
811     ExtPrint(("UDFReadMappingFromXEntry: mode %x, loc %x, len %x\n", AllocMode,
812         AllocLoc->Mapping ? AllocLoc->Mapping[0].extLocation : -1, len));
813 
814     UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
815 
816     return Extent;
817 }// end UDFReadMappingFromXEntry()
818 
819 #ifndef UDF_READ_ONLY_BUILD
820 /*
821     This routine builds data for AllocDesc sequence for specified
822     extent
823  */
824 OSSTATUS
UDFBuildShortAllocDescs(IN PVCB Vcb,IN uint32 PartNum,OUT int8 ** Buff,IN uint32 InitSz,IN OUT PUDF_FILE_INFO FileInfo)825 UDFBuildShortAllocDescs(
826     IN PVCB Vcb,
827     IN uint32 PartNum,
828     OUT int8** Buff,  // data for AllocLoc
829     IN uint32 InitSz,
830  IN OUT PUDF_FILE_INFO FileInfo
831     )
832 {
833     uint32 i, j;
834     uint32 len=0;
835     PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
836     PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
837     PSHORT_AD Alloc;
838     uint32 NewLen;
839     OSSTATUS status;
840     uint32 ph_len=0; // in general, this should be uint64,
841                      // but we need its lower part only
842 #ifdef UDF_ALLOW_FRAG_AD
843     uint32 ts, ac, len2;
844     uint32 LBS = Vcb->LBlockSize;
845     uint32 LBSh = Vcb->BlockSizeBits;
846     uint32 TagLen = 0;
847     tag* Tag = NULL;
848     PSHORT_AD saved_Alloc;
849     uint32 TagLoc, prevTagLoc;
850     uint32 BufOffs;
851     uint32 ExtOffs;
852     uint32 saved_NewLen;
853 #endif //UDF_ALLOW_FRAG_AD
854 
855     ValidateFileInfo(FileInfo);
856     ExtPrint(("UDFBuildShortAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
857     // calculate length
858     for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) {
859         ExtPrint(("bShExt: type %x, loc %x, len %x\n",
860             Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK));
861     }
862     Alloc = (PSHORT_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(SHORT_AD), MEM_SHAD_TAG);
863     if(!Alloc) {
864         BrutePoint();
865         return STATUS_INSUFFICIENT_RESOURCES;
866     }
867     // fill contiguous AllocDesc buffer (decribing UserData)
868     for(i=0;i<len;i++) {
869         Alloc[i].extLength = Extent[i].extLength;
870         Alloc[i].extPosition = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
871     }
872     if((Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) {
873         Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) &
874                                 (Vcb->LBlockSize-1);
875         ExtPrint(("bShExt: cut tail -> %x\n",
876             Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK));
877     }
878     Alloc[i].extLength =
879     Alloc[i].extPosition = 0;
880     j = len*sizeof(SHORT_AD); // required space
881     len = (InitSz & ~(sizeof(SHORT_AD)-1)); // space available in 1st block
882     ASSERT(len == InitSz);
883 
884     // Ok. Let's init AllocLoc
885     if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
886         FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
887         if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
888             BrutePoint();
889             MyFreePool__(Alloc);
890             return STATUS_INSUFFICIENT_RESOURCES;
891         }
892         // allocation descriptors are located in the same sector as FileEntry
893         // (at least their 1st part), just after it
894         FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
895         FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
896         FileInfo->Dloc->AllocLoc.Length = 0;
897         // set terminator
898         FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
899         FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
900     }
901 
902     if(j <= len) {
903         // we needn't allocating additional blocks to store AllocDescs
904         AdPrint(("in-ICB AllocDescs, j=%x\n",j));
905         RtlCopyMemory(*Buff, (int8*)Alloc, j);
906         NewLen = j;
907         MyFreePool__(Alloc);
908     } else {
909 #ifndef UDF_ALLOW_FRAG_AD
910         AdPrint(("  DISK_FULL\n"));
911         return STATUS_DISK_FULL;
912 #else //UDF_ALLOW_FRAG_AD
913         AdPrint(("multi-block AllocDescs, j=%x\n",j));
914         BufOffs = 0;
915         TagLoc = prevTagLoc = 0;
916         // calculate the space available for SHORT_ADs in each block
917         ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(SHORT_AD))) & ~(sizeof(SHORT_AD)-1);
918         len2 = len;
919         // tail size
920         ts = InitSz - len2;
921         len -= sizeof(SHORT_AD);
922         // calculate actual AllocSequence length (in bytes)
923         NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(SHORT_AD);
924         MyFreePool__(*Buff);
925         (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_SHAD_TAG);
926         if(!(*Buff)) {
927             status = STATUS_INSUFFICIENT_RESOURCES;
928             UDFPrint(("UDFResizeExtent() failed (%x)\n",status));
929             BrutePoint();
930             goto sh_alloc_err;
931         }
932         if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
933             status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
934             if(!OS_SUCCESS(status)) {
935                 UDFPrint(("UDFResizeExtent(2) failed (%x)\n",status));
936                 BrutePoint();
937 sh_alloc_err:
938                 MyFreePool__(Alloc);
939                 return status;
940             }
941         }
942         ExtOffs = AllocExtent->Offset;
943         RtlZeroMemory(*Buff, NewLen);
944         saved_NewLen = NewLen;
945         NewLen = 0; // recorded length
946         saved_Alloc = Alloc;
947         // fill buffer sector by sector (adding links at the end of each one)
948         while(TRUE) {
949 
950             // j - remained AllocDescs length (in bytes)
951             // len - bytes available for AllocDescs in current block
952             // ac - bytes available for AllocDescs in each block
953 
954             // leave space for terminator or pointer to next part of sequence
955             if(j == len2) {
956                 // if we have only 1 SHORT_AD that we can fit in last sector
957                 // we shall do it instead of recording link & allocating new block
958                 len =
959                 TagLen = len2;
960             }
961             ASSERT(saved_NewLen >= (BufOffs + len));
962             RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
963             Alloc = (PSHORT_AD)((int8*)Alloc + len);
964             j -= len;
965             BufOffs += len;
966             if(Tag) {
967                 // Set up Tag for AllocDesc
968                 Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
969                 UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
970                 prevTagLoc = TagLoc;
971             }
972             if(!j) {
973                 // terminate loop
974                 NewLen = BufOffs;
975                 break;
976             }
977             len = ac;
978             if(j <= (len + sizeof(SHORT_AD)))
979                 len = j - sizeof(SHORT_AD);
980             len2 = len + sizeof(SHORT_AD);
981             // we have more than 1 SHORT_AD that we can't fit in current block
982             // so we shall set up pointer to the next block
983             ((PSHORT_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 |
984                 (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
985             ((PSHORT_AD)((*Buff)+BufOffs))->extPosition = TagLoc =
986                 UDFPhysLbaToPart(Vcb, PartNum,
987                     UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping,
988                         ExtOffs+BufOffs+sizeof(SHORT_AD)+ts,
989                         NULL, NULL, NULL, NULL) );
990             // reflect additional (link) block & LBlock tail (if any)
991             BufOffs += ts+sizeof(SHORT_AD);
992             // init AllocDesc
993             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
994             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
995             Tag = (tag*)((*Buff)+BufOffs);
996             TagLen = len2;
997             ts = LBS-len2-sizeof(ALLOC_EXT_DESC);
998             BufOffs += sizeof(ALLOC_EXT_DESC);
999         }
1000         MyFreePool__(saved_Alloc);
1001 #endif //UDF_ALLOW_FRAG_AD
1002     }
1003     status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
1004     return status;
1005 } // end UDFBuildShortAllocDescs()
1006 
1007 /*
1008     This routine builds data for AllocDesc sequence for specified
1009     extent
1010  */
1011 OSSTATUS
UDFBuildLongAllocDescs(IN PVCB Vcb,IN uint32 PartNum,OUT int8 ** Buff,IN uint32 InitSz,IN OUT PUDF_FILE_INFO FileInfo)1012 UDFBuildLongAllocDescs(
1013     IN PVCB Vcb,
1014     IN uint32 PartNum,
1015     OUT int8** Buff,  // data for AllocLoc
1016     IN uint32 InitSz,
1017  IN OUT PUDF_FILE_INFO FileInfo
1018     )
1019 {
1020     uint32 i, j;
1021     uint32 len=0;
1022     PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
1023     PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
1024     PLONG_AD Alloc;
1025     uint32 NewLen;
1026     OSSTATUS status;
1027     uint32 ph_len=0; // in general, this should be uint64,
1028                      // but we need its lower part only
1029 #ifdef UDF_ALLOW_FRAG_AD
1030     uint32 ac, len2, ts;
1031     uint32 TagLoc, prevTagLoc;
1032     uint32 LBS = Vcb->LBlockSize;
1033     uint32 LBSh = Vcb->BlockSizeBits;
1034     uint32 BufOffs;
1035     uint32 ExtOffs = AllocExtent->Offset;
1036     PLONG_AD saved_Alloc;
1037     uint32 TagLen = 0;
1038     tag* Tag = NULL;
1039 #endif //UDF_ALLOW_FRAG_AD
1040 
1041     ValidateFileInfo(FileInfo);
1042     ExtPrint(("UDFBuildLongAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
1043     // calculate length
1044     //for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i);
1045     for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) {
1046         ExtPrint(("bLnExt: type %x, loc %x, len %x\n",
1047             Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK));
1048     }
1049     Alloc = (PLONG_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(LONG_AD), MEM_LNGAD_TAG);
1050     if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES;
1051     // fill contiguous AllocDesc buffer (decribing UserData)
1052     for(i=0;i<len;i++) {
1053         Alloc[i].extLength = Extent[i].extLength;
1054         Alloc[i].extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
1055         Alloc[i].extLocation.partitionReferenceNum = (uint16)PartNum;
1056         RtlZeroMemory(&(Alloc[i].impUse), sizeof(Alloc[i].impUse));
1057     }
1058     if((Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) {
1059         Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) &
1060                                 (Vcb->LBlockSize-1);
1061         ExtPrint(("bLnExt: cut tail -> %x\n",
1062             Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK));
1063     }
1064     RtlZeroMemory(&(Alloc[i]), sizeof(LONG_AD));
1065     j = len*sizeof(LONG_AD); // required space
1066     len = (InitSz & ~(sizeof(LONG_AD)-1)); // space available in 1st block
1067     ASSERT(len == InitSz);
1068 
1069     // Ok. Let's init AllocLoc
1070     if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
1071         FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
1072         if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
1073             MyFreePool__(Alloc);
1074             return STATUS_INSUFFICIENT_RESOURCES;
1075         }
1076         // allocation descriptors are located in the same sector as FileEntry
1077         // (at least their 1st part), just after it
1078         FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
1079         FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
1080         FileInfo->Dloc->AllocLoc.Length = 0;
1081         // set terminator
1082         FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
1083         FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
1084     }
1085 
1086     if(j <= len) {
1087         // we needn't allocating additional blocks to store AllocDescs
1088         RtlCopyMemory(*Buff, (int8*)Alloc, j);
1089         NewLen = j;
1090         MyFreePool__(Alloc);
1091     } else {
1092 #ifndef UDF_ALLOW_FRAG_AD
1093         AdPrint(("  DISK_FULL\n"));
1094         return STATUS_DISK_FULL;
1095 #else //UDF_ALLOW_FRAG_AD
1096         BufOffs = 0;
1097         TagLoc = prevTagLoc = 0;
1098         // calculate the space available for LONG_ADs in each block
1099         ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(LONG_AD))) & ~(sizeof(LONG_AD)-1);
1100         len2 = len;
1101         // tail size
1102         ts = InitSz - len2;
1103         len -= sizeof(LONG_AD);
1104         // calculate actual AllocSequence length (in LBlocks)
1105         NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(LONG_AD);
1106         MyFreePool__(*Buff);
1107         (*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_LNGAD_TAG);
1108         if(!(*Buff)) {
1109             status = STATUS_INSUFFICIENT_RESOURCES;
1110             goto lad_alloc_err;
1111         }
1112         if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
1113             status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
1114             if(!OS_SUCCESS(status)) {
1115 lad_alloc_err:
1116                 MyFreePool__(Alloc);
1117                 return status;
1118             }
1119         }
1120         ExtOffs = AllocExtent->Offset;
1121         RtlZeroMemory(*Buff, NewLen);
1122         NewLen = 0; // recorded length
1123         saved_Alloc = Alloc;
1124         len2 = len+sizeof(LONG_AD);
1125         // fill buffer sector by sector (adding links at the end of each one)
1126         while(TRUE) {
1127 
1128             // j - remained AllocDescs length (in bytes)
1129             // len - bytes available for in AllocDescs each block
1130 
1131             // leave space for terminator or pointer to next part of sequence
1132             if(j == len2) {
1133                 // if we have only 1 LONG_AD that we can fit in last sector
1134                 // we shall do it instead of recording link & allocating new block
1135                 len =
1136                 TagLen = len2;
1137             }
1138             RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
1139             Alloc = (PLONG_AD)((int8*)Alloc + len);
1140             j -= len;
1141             BufOffs += len;
1142             if(Tag) {
1143                 // Set up Tag for AllocDesc
1144                 Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
1145                 UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
1146                 prevTagLoc = TagLoc;
1147             }
1148             if(!j) {
1149                 // terminate loop
1150                 NewLen = BufOffs;
1151                 break;
1152             }
1153             len = ac;
1154             if(j <= (len + sizeof(LONG_AD)))
1155                 len = j - sizeof(LONG_AD);
1156             len2 = len+sizeof(LONG_AD);
1157             // we have more than 1 LONG_AD that we can't fit in current block
1158             // so we shall set up pointer to the next block
1159             ((PLONG_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 |
1160                 (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
1161             ((PLONG_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc =
1162                 UDFPhysLbaToPart(Vcb, PartNum,
1163                     UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping,
1164                         ExtOffs+BufOffs+sizeof(LONG_AD)+ts,
1165                         NULL, NULL, NULL, NULL) );
1166             ((PLONG_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum;
1167             // reflect additional (link) block & LBlock tail (if any)
1168             BufOffs += ts+sizeof(LONG_AD);
1169             // init AllocDesc
1170             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
1171             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
1172             Tag = (tag*)((*Buff)+BufOffs);
1173             TagLen = len2;
1174             ts = LBS-len2-sizeof(ALLOC_EXT_DESC);
1175             BufOffs += sizeof(ALLOC_EXT_DESC);
1176         }
1177         MyFreePool__(saved_Alloc);
1178 #endif //UDF_ALLOW_FRAG_AD
1179     }
1180     status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
1181     return status;
1182 } // end UDFBuildLongAllocDescs()
1183 
1184 /*
1185     This routine builds data for AllocDesc sequence for specified
1186     extent
1187  */
1188 /*OSSTATUS
1189 UDFBuildExtAllocDescs(
1190     IN PVCB Vcb,
1191     IN uint32 PartNum,
1192     OUT int8** Buff,  // data for AllocLoc
1193     IN uint32 InitSz,
1194  IN OUT PUDF_FILE_INFO FileInfo
1195     )
1196 {
1197     uint32 i, j;
1198     uint32 len=0, ac, len2;
1199     uint32 TagLoc, prevTagLoc;
1200     uint32 LBS = Vcb->LBlockSize;
1201     uint32 LBSh = Vcb->BlockSizeBits;
1202     PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
1203     PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
1204     PEXT_AD Alloc, saved_Alloc;
1205     uint32 BufOffs;
1206     uint32 ExtOffs = AllocExtent->Offset;
1207     uint32 NewLen;
1208     OSSTATUS status;
1209     uint32 TagLen = 0;
1210     tag* Tag = NULL;
1211 
1212     ValidateFileInfo(FileInfo);
1213     // calculate length
1214     for(len=0; Extent[len].extLength; len++);
1215     Alloc = (PEXT_AD)MyAllocatePool__(NonPagedPool, (len+1)*sizeof(EXT_AD));
1216     if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES;
1217     // fill contiguous AllocDesc buffer (decribing UserData)
1218     for(i=0;i<len;i++) {
1219         Alloc[i].extLength =
1220         Alloc[i].recordedLength =
1221         Alloc[i].informationLength = Extent[i].extLength;
1222         Alloc[i].extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
1223         Alloc[i].extLocation.partitionReferenceNum = (uint16)PartNum;
1224     }
1225     RtlZeroMemory(&(Alloc[i]), sizeof(EXT_AD));
1226     j = len*sizeof(EXT_AD); // required space
1227     len = InitSz;            // space available in 1st block
1228 
1229     // Ok. Let's init AllocLoc
1230     if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
1231         FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, 2 * sizeof(EXTENT_MAP));
1232         if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
1233             MyFreePool__(Alloc);
1234             return STATUS_INSUFFICIENT_RESOURCES;
1235         }
1236         // allocation descriptors are located in the same sector as FileEntry
1237         // (at least their 1st part), just after it
1238         FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
1239         FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
1240         FileInfo->Dloc->AllocLoc.Length = 0;
1241         // set terminator
1242         FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
1243         FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
1244     }
1245 
1246     if(j <= len) {
1247         // we needn't allocating additional blocks to store AllocDescs
1248         RtlCopyMemory(*Buff, (int8*)Alloc, j);
1249         NewLen = j;
1250         MyFreePool__(Alloc);
1251     } else {
1252         BufOffs = 0;
1253         TagLoc = prevTagLoc = 0;
1254         // calculate the space available for EXT_ADs in each block
1255         ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(EXT_AD))) & ~(sizeof(EXT_AD)-1);
1256         // calculate actual AllocSequence length (in LBlocks)
1257         len -= sizeof(EXT_AD);
1258         NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + len + sizeof(EXT_AD);
1259         MyFreePool__(*Buff);
1260         (*Buff) = (int8*)MyAllocatePool__(NonPagedPool, NewLen);
1261         if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
1262             status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
1263             if(!OS_SUCCESS(status)) {
1264                 MyFreePool__(Alloc);
1265                 return status;
1266             }
1267         }
1268         RtlZeroMemory(*Buff, NewLen);
1269         NewLen = 0; // recorded length
1270         saved_Alloc = Alloc;
1271         len2 = len + sizeof(EXT_AD);
1272         // fill buffer sector by sector (adding links at the end of each one)
1273         while(TRUE) {
1274 
1275             // j - remained AllocDescs length (in bytes)
1276             // len - bytes available for in AllocDescs each block
1277 
1278             // leave space for terminator or pointer to next part of sequence
1279             if(j == len2) {
1280                 // if we have only 1 EXT_AD that we can fit in last sector
1281                 // we shall do it instead of recording link & allocating new block
1282                 len =
1283                 TagLen = len2;
1284             }
1285             RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
1286             Alloc = (PEXT_AD)((int8*)Alloc + len);
1287             j -= len;
1288             BufOffs += len;
1289             if(Tag) {
1290                 // Set up Tag for AllocDesc
1291                 Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
1292                 UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
1293                 prevTagLoc = TagLoc;
1294             }
1295             if(!j) {
1296                 // terminate loop
1297                 NewLen = BufOffs;
1298                 break;
1299             }
1300             len = ac;
1301             if(j <= (len + sizeof(EXT_AD)))
1302                 len = j - sizeof(EXT_AD);
1303             len2 = len + sizeof(EXT_AD);
1304             // we have more than 1 EXT_AD that we can't fit in current block
1305             // so we shall set up pointer to the next block
1306             ((PEXT_AD)((*Buff)+BufOffs))->extLength =
1307             ((PEXT_AD)((*Buff)+BufOffs))->recordedLength = LBS;
1308             ((PEXT_AD)((*Buff)+BufOffs))->informationLength = len2 |
1309                 (((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
1310             ((PEXT_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc =
1311                 UDFPhysLbaToPart(Vcb, PartNum,
1312                     UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs + BufOffs + 2*sizeof(EXT_AD)-1, NULL, NULL, NULL, NULL) );
1313             ((PEXT_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum;
1314             BufOffs = (BufOffs + 2*sizeof(EXT_AD) - 1) & ~(sizeof(EXT_AD)-1) ;
1315             // init AllocDesc
1316             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
1317             ( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
1318             Tag = (tag*)((*Buff)+BufOffs);
1319             TagLen = len2;
1320             BufOffs += sizeof(ALLOC_EXT_DESC);
1321         }
1322         MyFreePool__(saved_Alloc);
1323     }
1324     status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
1325     return status;
1326 } // end UDFBuildExtAllocDescs()*/
1327 
1328 void
UDFDiscardFESpace(IN PVCB Vcb,IN PEXTENT_MAP Mapping,IN uint32 lim)1329 UDFDiscardFESpace(
1330     IN PVCB Vcb,
1331     IN PEXTENT_MAP Mapping,
1332     IN uint32 lim
1333     )
1334 {
1335 #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
1336     PEXTENT_MAP Mapping2;
1337     uint32 i;
1338 
1339     UDFPrint(("  DiscardFESpace\n"));
1340     Mapping2 = Mapping;
1341     for(i=0;i<lim;i++, Mapping++) {
1342         // we should not discard allocated FEs
1343         if( (Mapping->extLength >> 30) == EXTENT_RECORDED_ALLOCATED) {
1344             UDFPrint(("  used @ %x\n", Mapping->extLocation));
1345             Mapping->extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
1346             Mapping->extLocation = 0;
1347         } else {
1348             UDFPrint(("  free @ %x\n", Mapping->extLocation));
1349         }
1350     }
1351     UDFMarkSpaceAsXXX(Vcb, 0, Mapping2, AS_DISCARDED);
1352 
1353     MyFreePool__(Mapping2);
1354 #else // UDF_FE_ALLOCATION_CHARGE
1355     ASSERT(!Dloc->DirIndex->FECharge.Mapping);
1356     return;
1357 #endif // UDF_FE_ALLOCATION_CHARGE
1358 } // end UDFDiscardFESpace()
1359 
1360 OSSTATUS
UDFInitAllocationCache(IN PVCB Vcb,IN uint32 AllocClass,OUT PUDF_ALLOCATION_CACHE_ITEM * _AllocCache,OUT uint32 * _lim,IN BOOLEAN Init)1361 UDFInitAllocationCache(
1362     IN PVCB Vcb,
1363     IN uint32 AllocClass,
1364    OUT PUDF_ALLOCATION_CACHE_ITEM* _AllocCache,
1365    OUT uint32* _lim,
1366     IN BOOLEAN Init
1367     )
1368 {
1369     PUDF_ALLOCATION_CACHE_ITEM AllocCache;
1370     PUDF_ALLOCATION_CACHE_ITEM* pAllocCache;
1371     uint32 i, lim;
1372     uint32* plim;
1373 
1374     switch(AllocClass) {
1375     case UDF_PREALLOC_CLASS_FE:
1376         UDFPrint(("AllocationCache FE:\n"));
1377         pAllocCache = &(Vcb->FEChargeCache);
1378         plim = &(Vcb->FEChargeCacheMaxSize);
1379         lim = 32;
1380         break;
1381     case UDF_PREALLOC_CLASS_DIR:
1382         UDFPrint(("AllocationCache DIR:\n"));
1383         pAllocCache = &(Vcb->PreallocCache);
1384         plim = &(Vcb->PreallocCacheMaxSize);
1385         lim = 32;
1386         break;
1387     default:
1388         return STATUS_INVALID_PARAMETER;
1389     }
1390     if(!(*plim)) {
1391         if(!Init) {
1392             return STATUS_UNSUCCESSFUL;
1393         }
1394         (*pAllocCache) = AllocCache =
1395                   (PUDF_ALLOCATION_CACHE_ITEM)
1396                   MyAllocatePoolTag__(NonPagedPool , sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim,
1397                                       MEM_ALLOC_CACHE_TAG);
1398         if(!AllocCache) {
1399             return STATUS_INSUFFICIENT_RESOURCES;
1400         }
1401         RtlZeroMemory(AllocCache, sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim);
1402         for(i=0; i<lim; i++) {
1403             AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED;
1404         }
1405         (*plim) = lim;
1406     } else {
1407         lim = (*plim);
1408         AllocCache = (*pAllocCache);
1409     }
1410     (*_lim) = lim;
1411     (*_AllocCache) = AllocCache;
1412 
1413     return STATUS_SUCCESS;
1414 } // end UDFInitAllocationCache()
1415 
1416 OSSTATUS
UDFGetCachedAllocation(IN PVCB Vcb,IN uint32 ParentLocation,OUT PEXTENT_INFO Ext,OUT uint32 * Items,IN uint32 AllocClass)1417 UDFGetCachedAllocation(
1418     IN PVCB Vcb,
1419     IN uint32 ParentLocation,
1420    OUT PEXTENT_INFO Ext,
1421    OUT uint32* Items, // optional
1422     IN uint32 AllocClass
1423     )
1424 {
1425     PUDF_ALLOCATION_CACHE_ITEM AllocCache;
1426     uint32 i, lim;
1427     OSSTATUS status;
1428 
1429     UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
1430 
1431     status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE);
1432     if(!OS_SUCCESS(status)) {
1433         UDFReleaseResource(&(Vcb->PreallocResource));
1434         return status;
1435     }
1436     UDFPrint(("Get AllocationCache for %x\n", ParentLocation));
1437 
1438     for(i=0; i<lim; i++) {
1439         if(AllocCache[i].ParentLocation == ParentLocation) {
1440             (*Ext) = AllocCache[i].Ext;
1441             AdPrint(("    map %x (%x)\n", Ext->Mapping, i));
1442             if(Items) {
1443                 (*Items) = AllocCache[i].Items;
1444             }
1445             RtlZeroMemory(&(AllocCache[i]), sizeof(AllocCache[i]));
1446             AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED;
1447             UDFReleaseResource(&(Vcb->PreallocResource));
1448             return STATUS_SUCCESS;
1449         }
1450     }
1451     AdPrint(("    no map\n"));
1452     UDFReleaseResource(&(Vcb->PreallocResource));
1453     return STATUS_UNSUCCESSFUL;
1454 } // end UDFGetCachedAllocation()
1455 
1456 OSSTATUS
UDFStoreCachedAllocation(IN PVCB Vcb,IN uint32 ParentLocation,IN PEXTENT_INFO Ext,IN uint32 Items,IN uint32 AllocClass)1457 UDFStoreCachedAllocation(
1458     IN PVCB Vcb,
1459     IN uint32 ParentLocation,
1460     IN PEXTENT_INFO Ext,
1461     IN uint32 Items,
1462     IN uint32 AllocClass
1463     )
1464 {
1465     PUDF_ALLOCATION_CACHE_ITEM AllocCache;
1466     uint32 i, lim;
1467     OSSTATUS status;
1468 
1469     UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
1470 
1471     status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, TRUE);
1472     if(!OS_SUCCESS(status)) {
1473         UDFReleaseResource(&(Vcb->PreallocResource));
1474         return status;
1475     }
1476     UDFPrint(("Store AllocationCache for %x, map %x\n", ParentLocation, Ext->Mapping));
1477 
1478     for(i=0; i<lim; i++) {
1479         if(AllocCache[i].ParentLocation == LBA_NOT_ALLOCATED) {
1480             AdPrint(("    stored in %x\n", i));
1481             AllocCache[i].Ext = (*Ext);
1482             AllocCache[i].Items = Items;
1483             AllocCache[i].ParentLocation = ParentLocation;
1484             UDFReleaseResource(&(Vcb->PreallocResource));
1485             return STATUS_SUCCESS;
1486         }
1487     }
1488     //
1489     AdPrint(("    drop map %x (%x)\n", AllocCache[lim-1].Ext.Mapping, lim-1));
1490     switch(AllocClass) {
1491     case UDF_PREALLOC_CLASS_FE:
1492         UDFDiscardFESpace(Vcb, AllocCache[lim-1].Ext.Mapping, AllocCache[lim-1].Items);
1493         break;
1494     case UDF_PREALLOC_CLASS_DIR:
1495         UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[lim-1].Ext.Mapping, AS_DISCARDED);
1496         break;
1497     }
1498     RtlMoveMemory(&(AllocCache[1]), &(AllocCache[0]), sizeof(UDF_ALLOCATION_CACHE_ITEM)*(lim-1));
1499     AllocCache[0].Ext = (*Ext);
1500     AllocCache[0].Items = Items;
1501     AllocCache[0].ParentLocation = ParentLocation;
1502     AdPrint(("    stored in 0\n"));
1503     UDFReleaseResource(&(Vcb->PreallocResource));
1504     return STATUS_SUCCESS;
1505 } // end UDFStoreCachedAllocation()
1506 
1507 OSSTATUS
UDFFlushAllCachedAllocations(IN PVCB Vcb,IN uint32 AllocClass)1508 UDFFlushAllCachedAllocations(
1509     IN PVCB Vcb,
1510     IN uint32 AllocClass
1511     )
1512 {
1513     PUDF_ALLOCATION_CACHE_ITEM AllocCache;
1514     uint32 i, lim;
1515     OSSTATUS status;
1516 
1517     UDFPrint(("Flush AllocationCache\n"));
1518     UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
1519 
1520     status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE);
1521     if(!OS_SUCCESS(status)) {
1522         UDFReleaseResource(&(Vcb->PreallocResource));
1523         return status;
1524     }
1525 
1526     for(i=0; i<lim; i++) {
1527         if(AllocCache[i].ParentLocation != LBA_NOT_ALLOCATED) {
1528             switch(AllocClass) {
1529             case UDF_PREALLOC_CLASS_FE:
1530                 UDFDiscardFESpace(Vcb, AllocCache[i].Ext.Mapping, AllocCache[i].Items);
1531                 break;
1532             case UDF_PREALLOC_CLASS_DIR:
1533                 UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[i].Ext.Mapping, AS_DISCARDED);
1534                 break;
1535             }
1536         }
1537     }
1538     MyFreePool__(AllocCache);
1539     switch(AllocClass) {
1540     case UDF_PREALLOC_CLASS_FE:
1541         Vcb->FEChargeCache = NULL;
1542         Vcb->FEChargeCacheMaxSize = 0;
1543         break;
1544     case UDF_PREALLOC_CLASS_DIR:
1545         Vcb->PreallocCache = NULL;
1546         Vcb->PreallocCacheMaxSize = 0;
1547         break;
1548     }
1549     UDFReleaseResource(&(Vcb->PreallocResource));
1550     //
1551     return STATUS_SUCCESS;
1552 } // end UDFFlushAllCachedAllocations()
1553 
1554 /*
1555     This routine allocates space for FE of the file being created
1556     If FE-Charge is enabled it reserves an extent & allocates
1557     space in it. It works much faster then usual way both while
1558     allocating & accessing on disk
1559     If FE-Charge is disabled FE may be allocated at any suitable
1560     location
1561  */
1562 OSSTATUS
UDFAllocateFESpace(IN PVCB Vcb,IN PUDF_FILE_INFO DirInfo,IN uint32 PartNum,IN PEXTENT_INFO FEExtInfo,IN uint32 Len)1563 UDFAllocateFESpace(
1564     IN PVCB Vcb,
1565     IN PUDF_FILE_INFO DirInfo,
1566     IN uint32 PartNum,
1567     IN PEXTENT_INFO FEExtInfo,
1568     IN uint32 Len
1569     )
1570 {
1571 #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
1572     OSSTATUS status;
1573     PEXTENT_INFO Ext;
1574     EXTENT_AD Extent;
1575     BOOLEAN retry = FALSE;
1576     uint32 i, lim;
1577 
1578 /*
1579     1. #Dir1#->*File*                ->  Dir1's FECharge
1580     2. #Dir1#->*Dir*                 ->  Dir1's FECharge
1581     3. #Dir1#->*SDir*                ->  Dir1's FECharge
1582     4. Dir1->#SDir#->*Stream*        ->  Dir1's FEChargeSDir
1583     5. Dir1->#File#->*SDir*          ->  Dir1's FEChargeSDir
1584     6. Dir1->#Dir#->*SDir*           ->  (see p.2)
1585     7. Dir1->File->#SDir#->*Stream*  ->  Dir1's FEChargeSDir
1586     8. Dir1->Dir->#SDir#->*Stream*   ->  (see p.4)
1587 
1588 ## ~ DirInfo
1589 ** ~ Object to be created
1590 
1591 */
1592 
1593 //    ASSERT(!FEExtInfo->Mapping);
1594     // check if DirInfo we are called with is a Directory
1595     // (it can be a file with SDir)
1596     if(!DirInfo || !DirInfo->Dloc->DirIndex ||
1597        ((lim = ((DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge)) <= 1))
1598 #endif // UDF_FE_ALLOCATION_CHARGE
1599         return UDFAllocFreeExtent(Vcb, Len,
1600                UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY);
1601 #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
1602 
1603     Ext = &(DirInfo->Dloc->DirIndex->FECharge);
1604 
1605     while(TRUE) {
1606 
1607         if(!Ext->Mapping) {
1608             ULONG p_start;
1609             ULONG p_end;
1610             ULONG fe_loc;
1611             ULONG l1, l2;
1612 
1613             p_start = UDFPartStart(Vcb, PartNum);
1614             p_end   = UDFPartEnd(Vcb, PartNum);
1615             fe_loc  = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
1616 
1617             status = UDFGetCachedAllocation(Vcb, fe_loc, Ext, NULL, UDF_PREALLOC_CLASS_FE);
1618             if(OS_SUCCESS(status)) {
1619                 // do nothing, even do not unpack
1620             } else
1621             if(Vcb->LowFreeSpace) {
1622                 status = UDFAllocFreeExtent(Vcb, Len << Vcb->LBlockSizeBits,p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY);
1623                 if(OS_SUCCESS(status)) {
1624                     UDFPrint(("FE @ %x (1)\n", FEExtInfo->Mapping[0].extLocation ));
1625                 }
1626                 return status;
1627             } else {
1628                 if(fe_loc > p_start + 512*16) {
1629                     l1 = fe_loc - 512*16;
1630                 } else {
1631                     l1 = p_start;
1632                 }
1633                 if(fe_loc + 512*16 < p_end) {
1634                     l2 = fe_loc + 512*16;
1635                 } else {
1636                     l2 = p_end;
1637                 }
1638                 status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, l1, l2, Ext, EXTENT_FLAG_VERIFY);
1639                 if(!OS_SUCCESS(status)) {
1640                     status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, (p_start+fe_loc)/2, (fe_loc+p_end)/2, Ext, EXTENT_FLAG_VERIFY);
1641                 }
1642                 if(!OS_SUCCESS(status)) {
1643                     status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY);
1644                 }
1645                 if(!OS_SUCCESS(status)) {
1646                     status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start+1024, p_end-1024, Ext, EXTENT_FLAG_VERIFY);
1647                 }
1648                 if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY) )) {
1649                     // can't pre-allocate space for multiple FEs. Try single FE
1650                     UDFPrint(("allocate single FE entry\n"));
1651                     status = UDFAllocFreeExtent(Vcb, Len,
1652                            p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY);
1653                     if(OS_SUCCESS(status)) {
1654                         UDFPrint(("FE @ %x (2)\n", FEExtInfo->Mapping[0].extLocation ));
1655                     }
1656                     return status;
1657                 }
1658                 status = UDFUnPackMapping(Vcb, Ext);
1659                 if(!OS_SUCCESS(status)) {
1660                     MyFreePool__(Ext->Mapping);
1661                     Ext->Mapping = NULL;
1662                     return status;
1663                 }
1664             }
1665         }
1666 
1667         for(i=0;i<lim;i++) {
1668             if( (Ext->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ) {
1669                 Ext->Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; // EXTENT_RECORDED_ALLOCATED
1670 
1671                 Extent.extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1672                 Extent.extLocation = Ext->Mapping[i].extLocation;
1673 
1674                 if(Vcb->BSBM_Bitmap) {
1675                     uint32 lba = Ext->Mapping[i].extLocation;
1676                     if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
1677                         UDFPrint(("Remove BB @ %x from FE charge\n", lba));
1678                         Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
1679                         Ext->Mapping[i].extLocation = 0;
1680                         continue;
1681                     }
1682                 }
1683 
1684                 FEExtInfo->Mapping = UDFExtentToMapping(&Extent);
1685                 if(!FEExtInfo->Mapping) {
1686                     ASSERT(!(Ext->Mapping[i].extLength >> 30));
1687                     Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1688                     return STATUS_INSUFFICIENT_RESOURCES;
1689                 }
1690                 UDFPrint(("FE @ %x (3)\n", FEExtInfo->Mapping[0].extLocation ));
1691                 FEExtInfo->Length = Len;
1692                 FEExtInfo->Offset = 0;
1693                 FEExtInfo->Modified = TRUE;
1694                 return STATUS_SUCCESS;
1695             }
1696         }
1697 
1698         if(Vcb->LowFreeSpace) {
1699             status = UDFAllocFreeExtent(Vcb, Len,
1700                    UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY);
1701             if(OS_SUCCESS(status)) {
1702                 UDFPrint(("FE @ %x (4)\n", FEExtInfo->Mapping[0].extLocation ));
1703             }
1704             return status;
1705         }
1706         if(retry)
1707             return STATUS_INSUFFICIENT_RESOURCES;
1708 
1709         // we can get here if there are no free slots in
1710         // preallocated FE charge. So, we should release
1711         // memory and try to allocate space for new FE charge.
1712         MyFreePool__(Ext->Mapping);
1713         Ext->Mapping = NULL;
1714         retry = TRUE;
1715     }
1716     return STATUS_INSUFFICIENT_RESOURCES;
1717 #endif // UDF_FE_ALLOCATION_CHARGE
1718 
1719 } // end UDFAllocateFESpace()
1720 
1721 /*
1722     This routine frees space allocated for FE.
1723  */
1724 void
UDFFreeFESpace(IN PVCB Vcb,IN PUDF_FILE_INFO DirInfo,IN PEXTENT_INFO FEExtInfo)1725 UDFFreeFESpace(
1726     IN PVCB Vcb,
1727     IN PUDF_FILE_INFO DirInfo,
1728     IN PEXTENT_INFO FEExtInfo
1729     )
1730 {
1731 #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
1732     PEXTENT_INFO Ext;
1733     uint32 i, lim, j=-1;
1734     uint32 Lba;
1735 
1736     // check if the DirInfo we are called with is a Directory
1737     // (it can be a file with SDir)
1738     if(DirInfo && DirInfo->Dloc->DirIndex &&
1739        (Ext = &(DirInfo->Dloc->DirIndex->FECharge))->Mapping) {
1740         if(!FEExtInfo->Mapping)
1741             return;
1742         Lba = FEExtInfo->Mapping[0].extLocation;
1743 
1744         lim = (DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge;
1745         for(i=0;i<lim;i++) {
1746             if(Ext->Mapping[i].extLocation == Lba) {
1747                 ASSERT(!(Ext->Mapping[i].extLength >> 30));
1748                 Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1749                 goto clean_caller;
1750             }
1751             if(!Ext->Mapping[i].extLocation) {
1752                 j = i;
1753             }
1754         }
1755         if(j != (ULONG)-1) {
1756             i = j;
1757             Ext->Mapping[i].extLocation = Lba;
1758             Ext->Mapping[i].extLength   = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1759             goto clean_caller;
1760         }
1761     }
1762 #endif // UDF_FE_ALLOCATION_CHARGE
1763     UDFMarkSpaceAsXXX(Vcb, 0, FEExtInfo->Mapping, AS_DISCARDED); // free
1764 clean_caller:
1765     FEExtInfo->Mapping[0].extLocation = 0;
1766     FEExtInfo->Mapping[0].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
1767     return;
1768 } // end UDFFreeFESpace()
1769 #endif //UDF_READ_ONLY_BUILD
1770 
1771 /*
1772     This routine flushes FE-Charge buffer, marks unused blocks as free
1773     in bitmap & releases memory allocated for FE-Charge management
1774  */
1775 void
UDFFlushFESpace(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc,IN BOOLEAN Discard)1776 UDFFlushFESpace(
1777     IN PVCB Vcb,
1778     IN PUDF_DATALOC_INFO Dloc,
1779     IN BOOLEAN Discard
1780     )
1781 {
1782 #ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
1783     PEXTENT_MAP Mapping;
1784     uint32 lim;
1785 
1786     if(!(Mapping = Dloc->DirIndex->FECharge.Mapping))
1787         return;
1788 
1789     lim = (Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge;
1790 
1791     if(!Discard) {
1792         // cache it!
1793         if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb,
1794                                  Dloc->FELoc.Mapping[0].extLocation,
1795                                  &Dloc->DirIndex->FECharge, lim, UDF_PREALLOC_CLASS_FE))) {
1796             Dloc->DirIndex->FECharge.Mapping = NULL;
1797             return;
1798         }
1799     }
1800     Dloc->DirIndex->FECharge.Mapping = NULL;
1801     UDFDiscardFESpace(Vcb, Mapping, lim);
1802 #else // UDF_FE_ALLOCATION_CHARGE
1803     ASSERT(!Dloc->DirIndex->FECharge.Mapping);
1804     return;
1805 #endif // UDF_FE_ALLOCATION_CHARGE
1806 } // end UDFFlushFESpace()
1807 
1808 #ifndef UDF_READ_ONLY_BUILD
1809 /*
1810     This routine rebuilds mapping on write attempts to Alloc-Not-Rec area.
1811     Here we assume that required area lays in a single frag.
1812  */
1813 OSSTATUS
UDFMarkAllocatedAsRecorded(IN PVCB Vcb,IN int64 Offset,IN uint32 Length,IN PEXTENT_INFO ExtInfo)1814 UDFMarkAllocatedAsRecorded(
1815     IN PVCB Vcb,
1816     IN int64 Offset,
1817     IN uint32 Length,
1818     IN PEXTENT_INFO ExtInfo   // Extent array
1819     )
1820 {
1821     uint32 i, len, lba, sLen;
1822     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
1823     PEXTENT_MAP NewExtent;
1824     uint32 BS = Vcb->BlockSize;
1825     uint32 LBS = Vcb->LBlockSize;
1826     uint32 BSh = Vcb->BlockSizeBits;
1827     BOOLEAN TryPack = TRUE;
1828 #ifdef UDF_DBG
1829     int64 check_size;
1830 #endif //UDF_DBG
1831     // I don't know what else comment can be added here.
1832     // Just belive that it works
1833     lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, (Offset & ~((int64)LBS-1)), NULL, NULL, NULL, &i);
1834     if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER;
1835 #ifdef UDF_DBG
1836     check_size = UDFGetExtentLength(ExtInfo->Mapping);
1837     ASSERT(!(check_size & (LBS-1)));
1838 #endif //UDF_DBG
1839     AdPrint(("Alloc->Rec  ExtInfo %x, Extent %x\n", ExtInfo, Extent));
1840     if((Extent[i].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) return STATUS_SUCCESS;
1841     if((Extent[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_INVALID_PARAMETER;
1842     ASSERT((((uint32)Offset) & (LBS-1)) + Length <= (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK));
1843     sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
1844     if((Extent[i].extLocation == lba) && (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK ) >> BSh) == sLen)) {
1845         // xxxxxx ->  RRRRRR
1846         Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1847 //      Extent[i].extLength |= (EXTENT_RECORDED_ALLOCATED << 30); // = 0;
1848         ExtInfo->Modified = TRUE;
1849         if(i &&
1850            ((Extent[i-1].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) &&
1851            (lba == (Extent[i-1].extLocation + ((len = Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) &&
1852            ((len + (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)) <= UDF_MAX_EXTENT_LENGTH) &&
1853            (i == ((UDFGetMappingLength(Extent) / sizeof(EXTENT_MAP)) - 2)) &&
1854            TRUE) {
1855             // make optimization for sequentially written files
1856             Extent[i-1].extLength += Extent[i].extLength;
1857             Extent[i].extLocation = 0;
1858             Extent[i].extLength = 0;
1859         } else {
1860             UDFPackMapping(Vcb, ExtInfo);
1861         }
1862         AdPrint(("Alloc->Rec (1) new %x\n", ExtInfo->Mapping));
1863 #ifdef UDF_DBG
1864         ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
1865 #endif
1866         AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
1867         return STATUS_SUCCESS;
1868     }
1869     if(Extent[i].extLocation < lba) {
1870         if(  (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (lba - Extent[i].extLocation))
1871              > sLen ) {
1872             // xxxxxx ->  xxRRxx
1873             NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP)*2,
1874                                                                MEM_EXTMAP_TAG);
1875             if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1876             Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1877             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1878             RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1879             NewExtent[i].extLocation = Extent[i].extLocation;
1880             NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
1881             NewExtent[i+1].extLength = (Length+BS-1) & ~(BS-1);
1882             NewExtent[i+1].extLocation = lba;
1883             NewExtent[i+2].extLength = Extent[i].extLength - NewExtent[i].extLength - NewExtent[i+1].extLength;
1884             NewExtent[i+2].extLocation = lba + ((Length+BS-1) >> BSh);
1885             ASSERT(!(NewExtent[i].extLength >> 30));
1886             ASSERT(!(NewExtent[i+2].extLength >> 30));
1887             NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1888             NewExtent[i+2].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1889             TryPack = FALSE;
1890             AdPrint(("Alloc->Rec (2) new %x\n", NewExtent));
1891         } else {
1892             // xxxxxx ->  xxRRRR
1893             NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
1894                                                                MEM_EXTMAP_TAG);
1895             if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1896             Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1897             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1898             RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1899             NewExtent[i].extLocation = Extent[i].extLocation;
1900             NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
1901             NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
1902             NewExtent[i+1].extLocation = lba;
1903             ASSERT(!(NewExtent[i].extLength >> 30));
1904             NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1905             AdPrint(("Alloc->Rec (3) new %x\n", NewExtent));
1906         }
1907     } else {
1908         // xxxxxx ->  RRRRxx
1909         NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
1910                                                            MEM_EXTMAP_TAG);
1911         if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1912         Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1913         RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1914         RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1915         NewExtent[i].extLocation = Extent[i].extLocation;
1916         NewExtent[i].extLength = (Length+BS-1) & ~(BS-1);
1917         NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
1918         NewExtent[i+1].extLocation = Extent[i].extLocation + (NewExtent[i].extLength >> BSh);
1919         ASSERT(!(NewExtent[i+1].extLength >> 30));
1920         NewExtent[i+1].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1921         AdPrint(("Alloc->Rec (4) new %x\n", NewExtent));
1922     }
1923 
1924     //ASSERT(check_size == UDFGetExtentLength(Extent));
1925     //ASSERT(!(check_size & (LBS-1)));
1926 
1927     AdPrint(("Free Extent %x (new %x)\n", Extent, NewExtent));
1928     MyFreePool__(Extent);
1929     ExtInfo->Modified = TRUE;
1930     ExtInfo->Mapping = NewExtent;
1931     if(TryPack)
1932         UDFPackMapping(Vcb, ExtInfo);
1933 #ifdef UDF_DBG
1934     ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
1935     ASSERT(!(check_size & (LBS-1)));
1936 #endif
1937 
1938     AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
1939 
1940     return STATUS_SUCCESS;
1941 } // end UDFMarkAllocatedAsRecorded()
1942 
1943 /*
1944     This routine rebuilds mapping on write attempts to Not-Alloc-Not-Rec area.
1945     Here we assume that required area lays in a single frag.
1946  */
1947 OSSTATUS
UDFMarkNotAllocatedAsAllocated(IN PVCB Vcb,IN int64 Offset,IN uint32 Length,IN PEXTENT_INFO ExtInfo)1948 UDFMarkNotAllocatedAsAllocated(
1949     IN PVCB Vcb,
1950     IN int64 Offset,
1951     IN uint32 Length,
1952     IN PEXTENT_INFO ExtInfo   // Extent array
1953     )
1954 {
1955     uint32 i, len, /*lba,*/ d, l, BOffs, j;
1956     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
1957     PEXTENT_MAP NewExtent;
1958 //    uint32 BS = Vcb->BlockSize;
1959     uint32 BSh = Vcb->BlockSizeBits;
1960     OSSTATUS status;
1961     EXTENT_INFO TmpExtInf;
1962     SIZE_T aLen, sLen;
1963     SIZE_T LBS = Vcb->LBlockSize;
1964     // I don't know what else comment can be added here.
1965     // Just belive that it works
1966     /*lba = */
1967 #ifndef ALLOW_SPARSE
1968     BrutePoint();
1969 #endif
1970     AdPrint(("Not->Alloc  ExtInfo %x, Extent %x\n", ExtInfo, Extent));
1971     UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
1972     if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER;
1973     if((Extent[i].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_SUCCESS;
1974 
1975     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
1976     BOffs = (uint32)(Offset >> BSh);
1977     // length of existing Not-Alloc-Not-Rec frag
1978     sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
1979     // required allocation length increment (in bytes)
1980     aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)));
1981 
1982     // try to extend previous frag or allocate space _after_ it to
1983     // avoid backward seeks, if previous frag is not Not-Rec-Not-Alloc
1984     if(i && ((Extent[i-1].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) ) {
1985         status = UDFAllocFreeExtent(Vcb, aLen,
1986                                       Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh),
1987                                       min(UDFPartEnd(Vcb, PartNum), Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) + sLen ),
1988                                       &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
1989         if(status == STATUS_DISK_FULL)
1990             // if there are not enough free blocks after that frag...
1991             goto try_alloc_anywhere;
1992     } else {
1993 try_alloc_anywhere:
1994         // ... try to alloc required disk space anywhere
1995         status = UDFAllocFreeExtent(Vcb, aLen,
1996                                       UDFPartStart(Vcb, PartNum),
1997                                       UDFPartEnd(Vcb, PartNum),
1998                                       &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
1999     }
2000     // check for successfull allocation
2001     if(!OS_SUCCESS(status)) {
2002         AdPrint(("Not->Alloc  no free\n"));
2003         return status;
2004     }
2005     // get number of frags in allocated block
2006     d = (UDFGetMappingLength(TmpExtInf.Mapping) / sizeof(EXTENT_MAP)) - 1;
2007     // calculate number of existing blocks before the frag to be changed
2008     l=0;
2009     for(j=0; j<i; j++) {
2010         l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2011     }
2012     // and now just update mapping...
2013     if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
2014         // xxxxxx ->  RRRRRR
2015         // (d-1) - since we have to raplace last frag of Extent with 1 or more frags of TmpExtInf.Mapping
2016         NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d-1)*sizeof(EXTENT_MAP) );
2017         if(!NewExtent) {
2018             MyFreePool__(TmpExtInf.Mapping);
2019             return STATUS_INSUFFICIENT_RESOURCES;
2020         }
2021         RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2022         RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2023         RtlCopyMemory((int8*)&(NewExtent[i+d]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2024         AdPrint(("Not->Alloc (1) new %x\n", NewExtent));
2025     } else
2026     if(l < BOffs) {
2027         // .ExtLength, BOffs & l are already aligned...
2028         if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
2029             // xxxxxx ->  xxRRxx
2030             NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d+1)*sizeof(EXTENT_MAP) );
2031             if(!NewExtent) {
2032                 MyFreePool__(TmpExtInf.Mapping);
2033                 return STATUS_INSUFFICIENT_RESOURCES;
2034             }
2035             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2036             RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2037             RtlCopyMemory((int8*)&(NewExtent[i+d+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2038             NewExtent[i].extLocation = 0;
2039             NewExtent[i].extLength = (BOffs - l) << BSh;
2040             NewExtent[i+d+1].extLength = Extent[i].extLength - NewExtent[i].extLength - aLen;
2041             NewExtent[i+d+1].extLocation = 0;
2042             NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2043             NewExtent[i+d+1].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2044             AdPrint(("Not->Alloc (2) new %x\n", NewExtent));
2045         } else {
2046             // xxxxxx ->  xxRRRR
2047             NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
2048             if(!NewExtent) {
2049                 MyFreePool__(TmpExtInf.Mapping);
2050                 return STATUS_INSUFFICIENT_RESOURCES;
2051             }
2052             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2053             RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2054             RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2055             NewExtent[i].extLocation = 0;
2056             NewExtent[i].extLength = (BOffs - l) << BSh;
2057             NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2058             AdPrint(("Not->Alloc (3) new %x\n", NewExtent));
2059         }
2060     } else {
2061         // xxxxxx ->  RRRRxx
2062         NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
2063         if(!NewExtent) {
2064             MyFreePool__(TmpExtInf.Mapping);
2065             return STATUS_INSUFFICIENT_RESOURCES;
2066         }
2067         RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2068         RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2069         RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2070         NewExtent[i+d].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
2071         NewExtent[i+d].extLocation = 0;
2072         NewExtent[i+d].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2073         AdPrint(("Not->Alloc (4) new %x\n", NewExtent));
2074     }
2075 
2076     AdPrint(("Free Extent %x, TmpExtInf.Mapping, (new %x)\n", Extent, TmpExtInf.Mapping, NewExtent));
2077     MyFreePool__(Extent);
2078     MyFreePool__(TmpExtInf.Mapping);
2079     ExtInfo->Modified = TRUE;
2080     ExtInfo->Mapping = NewExtent;
2081 
2082     AdPrint(("Not->Alloc: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
2083 
2084     return STATUS_SUCCESS;
2085 } // end UDFMarkNotAllocatedAsAllocated()
2086 
2087 //#if 0
2088 /*
2089     This routine rebuilds mapping on write zero attempts to
2090     Alloc-Not-Rec area.
2091     Here we assume that required area lays in a single frag.
2092  */
2093 OSSTATUS
UDFMarkAllocatedAsNotXXX(IN PVCB Vcb,IN int64 Offset,IN uint32 Length,IN PEXTENT_INFO ExtInfo,IN BOOLEAN Deallocate)2094 UDFMarkAllocatedAsNotXXX(
2095     IN PVCB Vcb,
2096     IN int64 Offset,
2097     IN uint32 Length,
2098     IN PEXTENT_INFO ExtInfo,   // Extent array
2099     IN BOOLEAN Deallocate
2100     )
2101 {
2102     uint32 i, len, /*lba, d,*/ l, BOffs, j;
2103     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2104     PEXTENT_MAP NewExtent;
2105 //    EXTENT_MAP TmpExtent;
2106 //    uint32 BS = Vcb->BlockSize;
2107     uint32 BSh = Vcb->BlockSizeBits;
2108 //    OSSTATUS status;
2109     EXTENT_INFO TmpExtInf;
2110     uint32 aLen, sLen;
2111     uint32 flags;
2112     uint32 target_flags = Deallocate ?
2113                              EXTENT_NOT_RECORDED_NOT_ALLOCATED :
2114                              EXTENT_NOT_RECORDED_ALLOCATED;
2115     SIZE_T LBS = Vcb->LBlockSize;
2116     EXTENT_MAP DeadMapping[2];
2117     // I don't know what else comment can be added here.
2118     // Just belive that it works
2119     /*lba = */
2120 #ifndef ALLOW_SPARSE
2121     if(Deallocate) {
2122         BrutePoint();
2123     }
2124 #endif
2125 
2126     AdPrint(("Alloc->Not ExtInfo %x, Extent %x\n", ExtInfo, Extent));
2127 
2128     DeadMapping[0].extLocation =
2129         UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
2130     if(i == (ULONG)-1) {
2131         BrutePoint();
2132         return STATUS_INVALID_PARAMETER;
2133     }
2134     DeadMapping[0].extLength = Extent[i].extLength;
2135     DeadMapping[1].extLocation =
2136     DeadMapping[1].extLength = 0;
2137     TmpExtInf.Mapping = (PEXTENT_MAP)&DeadMapping;
2138     TmpExtInf.Offset = 0;
2139     TmpExtInf.Length = Extent[i].extLength & UDF_EXTENT_LENGTH_MASK;
2140 
2141     flags = Extent[i].extLength >> 30;
2142     if(flags == target_flags) return STATUS_SUCCESS;
2143 
2144 //    uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
2145     BOffs = (uint32)(Offset >> BSh);
2146     // length of existing Alloc-(Not-)Rec frag (in sectors)
2147     sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
2148     // required deallocation length increment (in bytes)
2149     aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)) );
2150 
2151     l=0;
2152     for(j=0; j<i; j++) {
2153         l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2154     }
2155     flags <<= 30;
2156     if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
2157         // xxxxxx ->  RRRRRR
2158         Extent[i].extLocation = 0;
2159         Extent[i].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) | flags;
2160         NewExtent = Extent;
2161         Extent = NULL;
2162         AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent));
2163     } else
2164     if(l < BOffs) {
2165         // .ExtLength, BOffs & l are already aligned...
2166         if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
2167             // xxxxxx ->  xxRRxx
2168             NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) );
2169             if(!NewExtent) {
2170                 return STATUS_INSUFFICIENT_RESOURCES;
2171             }
2172             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2173             RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2174             NewExtent[i].extLength = (BOffs - l) << BSh;
2175             NewExtent[i].extLength |= flags;
2176             NewExtent[i+1].extLocation = 0;
2177             NewExtent[i+1].extLength = aLen | (target_flags << 30);
2178             NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) -
2179                                        (NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ;
2180             NewExtent[i+2].extLocation = Extent[i].extLocation +
2181                                        (NewExtent[i+2].extLength >> BSh);
2182             NewExtent[i+2].extLength |= flags;
2183             AdPrint(("Alloc->Not (2) new %x\n", NewExtent));
2184         } else {
2185             // xxxxxx ->  xxRRRR
2186             NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2187             if(!NewExtent) {
2188                 return STATUS_INSUFFICIENT_RESOURCES;
2189             }
2190             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2191             RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2192             NewExtent[i].extLength = ((BOffs - l) << BSh) | flags;
2193             NewExtent[i+1].extLocation = 0;
2194             NewExtent[i+1].extLength = aLen | (target_flags << 30);
2195             AdPrint(("Alloc->Not (3) new %x\n", NewExtent));
2196         }
2197     } else {
2198         // xxxxxx ->  RRRRxx
2199         NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2200         if(!NewExtent) {
2201             return STATUS_INSUFFICIENT_RESOURCES;
2202         }
2203         RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2204         RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2205         NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
2206         NewExtent[i+1].extLength |= flags;
2207         NewExtent[i].extLocation = 0;
2208         NewExtent[i].extLength = aLen | (target_flags << 30);
2209         AdPrint(("Alloc->Not (4) new %x\n", NewExtent));
2210     }
2211 
2212     if(Deallocate)
2213         UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free
2214 
2215     ExtInfo->Modified = TRUE;
2216     ExtInfo->Mapping = NewExtent;
2217 
2218     AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
2219 
2220     if(Extent) {
2221         AdPrint(("Alloc->Not kill %x\n", Extent));
2222         MyFreePool__(Extent);
2223     } else {
2224         AdPrint(("Alloc->Not keep %x\n", Extent));
2225     }
2226 
2227     return STATUS_SUCCESS;
2228 } // end UDFMarkAllocatedAsNotXXX()
2229 //#endif //0
2230 
2231 /*
2232     This routine resizes extent & updates associated mapping
2233  */
2234 OSSTATUS
UDFResizeExtent(IN PVCB Vcb,IN uint32 PartNum,IN int64 Length,IN BOOLEAN AlwaysInIcb,OUT PEXTENT_INFO ExtInfo)2235 UDFResizeExtent(
2236     IN PVCB Vcb,
2237     IN uint32 PartNum,
2238     IN int64 Length,          // Required Length
2239     IN BOOLEAN AlwaysInIcb,   // must be TRUE for AllocDescs
2240     OUT PEXTENT_INFO ExtInfo
2241     )
2242 {
2243     uint32 i, flags, lba;
2244     SIZE_T lim;
2245     int64 l;
2246     OSSTATUS status;
2247     EXTENT_INFO TmpExtInf;
2248     EXTENT_MAP  TmpMapping[2];
2249     uint32 s, pe, BSh, PS;
2250     SIZE_T req_s;
2251     SIZE_T LBS = Vcb->LBlockSize;
2252     BSh = Vcb->BlockSizeBits;
2253     PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
2254     uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1));
2255     BOOLEAN Sequential = FALSE;
2256 
2257     ASSERT(PartNum < 3);
2258 
2259     ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length));
2260 
2261     if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) {
2262         AdPrint(("  cut preallocated\n"));
2263     } else
2264     if(ExtInfo->Length == Length) {
2265         return STATUS_SUCCESS;
2266     }
2267     if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2268         MaxGrow &= ~(Vcb->WriteBlockSize-1);
2269         Sequential = TRUE;
2270     }
2271 
2272     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2273     if(ExtInfo->Offset) {
2274         if(ExtInfo->Offset + Length <= LBS) {
2275             ExtPrint(("Resize IN-ICB\n"));
2276             ExtInfo->Length = Length;
2277             return STATUS_SUCCESS;
2278         }
2279         if(!AlwaysInIcb)           // simulate unused 1st sector in extent
2280             ExtInfo->Offset = LBS; // it'll be truncated later
2281         Length += ExtInfo->Offset; // convert to real offset in extent
2282     }
2283     lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i);
2284     if(ExtInfo->Length < Length) {
2285         // increase extent
2286         if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2287                               &TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) {
2288             AdPrint(("Resize found cached(1)\n"));
2289             ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2290             MyFreePool__(TmpExtInf.Mapping);
2291         }
2292         if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) {
2293             // we have enough space inside extent
2294             ExtInfo->Length = Length;
2295             AdPrint(("Resize do nothing (1)\n"));
2296         } else /*if(lba == LBA_OUT_OF_EXTENT)*/ {
2297 
2298             Length -= ExtInfo->Offset;
2299             if(/*Length && l &&*/  (l % MaxGrow) &&
2300                (Length-1)/MaxGrow != (l-1)/MaxGrow) {
2301                 AdPrint(("Crossing MAX_FRAG boundary...\n"));
2302                 int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow;
2303                 status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo);
2304                 if(!OS_SUCCESS(status)) {
2305                     UDFPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status));
2306                     return status;
2307                 }
2308                 l = ExtInfo->Length;
2309                 ASSERT(l == l2);
2310             }
2311             while((Length - l) > MaxGrow) {
2312                 status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2313                 if(!OS_SUCCESS(status)) {
2314                     UDFPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status));
2315                     return status;
2316                 }
2317                 l = ExtInfo->Length;
2318             }
2319             Length += ExtInfo->Offset;
2320             // at first, try to resize existing frag
2321 #ifndef UDF_ALLOW_FRAG_AD
2322             i = UDFGetMappingLength(ExtInfo->Mapping);
2323             if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) {
2324                 // this is very important check since we will not
2325                 // be able to _record_ too long AllocDesc because of
2326                 // some DEMO limitations in UDFBuildXXXAllocDescs()
2327                 AdPrint(("  DISK_FULL\n"));
2328                 return STATUS_DISK_FULL;
2329             }
2330             i /= sizeof(EXTENT_MAP);
2331 #else //UDF_ALLOW_FRAG_AD
2332             i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP);
2333 #endif //UDF_ALLOW_FRAG_AD
2334 #ifdef ALLOW_SPARSE
2335             if(!AlwaysInIcb && !(ExtInfo->Offset) &&
2336                (Length - l >= (Vcb->SparseThreshold << BSh))) {
2337                 // last frag will be Not-Alloc-Not-Rec...
2338                 AdPrint(("Resize sparse (2)\n"));
2339                 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2340                 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2,
2341                                                                    MEM_EXTMAP_TAG);
2342                 if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES;
2343                 TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2344                 TmpExtInf.Mapping[0].extLocation =// 0;
2345                 TmpExtInf.Mapping[1].extLength =
2346                 TmpExtInf.Mapping[1].extLocation = 0;
2347                 l = Length;
2348                 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2349                 MyFreePool__(TmpExtInf.Mapping);
2350             } else
2351 #endif //ALLOW_SPARSE
2352             // allocate some sectors
2353             if(i>1 && !(ExtInfo->Offset)) {
2354                 i-=2;
2355                 // check if Not-Alloc-Not-Rec at the end of mapping
2356                 if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) {
2357                     // do nothing, but jump directly to allocator
2358                 } else
2359                 if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
2360                     AdPrint(("Resize grow sparse (3)\n"));
2361                     ExtInfo->Mapping[i].extLength +=
2362                         (((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ;
2363                     l = Length;
2364                 // check if Alloc-Not-Rec at the end of mapping
2365                 } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) {
2366                     AdPrint(("Resize grow Not-Rec (3)\n"));
2367                     // current length of last frag
2368                     s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2369                     // prefered location of the next frag
2370                     lba = ExtInfo->Mapping[i].extLocation + s;
2371                     pe=UDFPartEnd(Vcb,PartNum);
2372                     // maximum frag length
2373                     if(Sequential) {
2374                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2375                     } else {
2376                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2377                     }
2378                     // required last extent length
2379                     req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2380                                            ((l      + LBS - 1) & ~(LBS-1))   ) >> BSh);
2381                     if(lim > req_s) {
2382                         lim = req_s;
2383                     }
2384                     UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2385 /*                    if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) &&
2386                        ((Length & ~(PS-1)) > (l & ~(PS-1))) &&
2387                        TRUE) {
2388                         status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2389                     }*/
2390                     // how many sectors we should add
2391                     req_s = lim - s;
2392                     ASSERT(req_s);
2393                     if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2394                         s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1));
2395                     }
2396 /*                    for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2397                         s++;
2398                     }*/
2399                     if(s==lim) {
2400                         // we can just increase the last frag
2401                         AdPrint(("Resize grow last Not-Rec (4)\n"));
2402                         ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2403                         l = Length;
2404                         UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2405                     } else {
2406                         // we get here if simple increasing of last frag failed
2407                         // it worth truncating last frag and try to allocate
2408                         // all required data as a single frag
2409 
2410 /*                        if(Sequential && s>=PS) {
2411                             s &= ~(PS-1);
2412                             AdPrint(("Resize grow last Not-Rec (4/2)\n"));
2413                             ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2414                             l += (s << BSh);
2415                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2416                         }*/
2417                         AdPrint(("Resize reloc last Not-Rec (5)\n"));
2418                         TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP),
2419                                                                            MEM_EXTMAP_TAG);
2420                         if(!TmpExtInf.Mapping) {
2421                             UDFPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n"));
2422                             UDFReleaseResource(&(Vcb->BitMapResource1));
2423                             return STATUS_INSUFFICIENT_RESOURCES;
2424                         }
2425                         RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP));
2426                         TmpExtInf.Mapping[i].extLength =
2427                         TmpExtInf.Mapping[i].extLocation = 0;
2428                         TmpExtInf.Offset = ExtInfo->Offset;
2429                         l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2430                         TmpExtInf.Length = l;
2431                         ASSERT(i || !ExtInfo->Offset);
2432                         UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2433                         MyFreePool__(ExtInfo->Mapping);
2434                         (*ExtInfo) = TmpExtInf;
2435                     }
2436                     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2437                     UDFReleaseResource(&(Vcb->BitMapResource1));
2438                 // check if Alloc-Rec
2439                 } else {
2440                     // current length of last frag
2441                     s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2442                     // prefered location of the next frag
2443                     lba = ExtInfo->Mapping[i].extLocation + s;
2444                     pe=UDFPartEnd(Vcb,PartNum);
2445                     // maximum frag length
2446                     if(Sequential) {
2447                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2448                     } else {
2449                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2450                     }
2451                     // required last extent length
2452                     req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2453                                            ((l      + LBS - 1) & ~(LBS-1))   ) >> BSh);
2454                     if(lim > req_s) {
2455                         lim = req_s;
2456                     }
2457 //                    s=0;
2458                     // how many sectors we should add
2459                     req_s = lim - s;
2460                     if(req_s) {
2461                         uint32 d=0;
2462 
2463                         UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2464                         //ASSERT(req_s);
2465                         if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2466                             s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)));
2467                         }
2468     /*                    for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2469                             s++;
2470                         }*/
2471 
2472                         if(s==lim) {
2473                             AdPrint(("Resize grow last Rec (6)\n"));
2474                             // we can just increase last frag
2475                             TmpMapping[0].extLength = req_s << BSh;
2476                             TmpMapping[0].extLocation = lba;
2477                             TmpMapping[1].extLength =
2478                             TmpMapping[1].extLocation = 0;
2479                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2480                             l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2481                             ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2482                         } else if(d) {
2483                             AdPrint(("Resize part-grow last Rec (6)\n"));
2484                             // increase last frag, then alloc rest
2485                             TmpMapping[0].extLength = d << BSh;
2486                             TmpMapping[0].extLocation = lba;
2487                             TmpMapping[1].extLength =
2488                             TmpMapping[1].extLocation = 0;
2489                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2490                             l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2491                             ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2492                         } else {
2493                             AdPrint(("Can't grow last Rec (6)\n"));
2494                         }
2495                         UDFReleaseResource(&(Vcb->BitMapResource1));
2496                     } else {
2497                         AdPrint(("Max frag length reached (6)\n"));
2498                     }
2499                 }
2500             }
2501             if(l < Length) {
2502                 // we get here if simple increasing of the last frag failed
2503                 AdPrint(("Resize add new frag (7)\n"));
2504                 if(l < LBS && Length >= LBS &&
2505                    (ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2506                     AdPrint(("Resize tune for SEQUENTIAL i/o\n"));
2507                 }
2508                 status = UDFAllocFreeExtent(Vcb, Length - l,
2509                                                    UDFPartStart(Vcb, PartNum),
2510                                                    UDFPartEnd(Vcb, PartNum),
2511                                                    &TmpExtInf,
2512                                                    ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
2513                 if(!OS_SUCCESS(status)) {
2514                     UDFPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status));
2515                     return status;
2516                 }
2517                 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2518                 MyFreePool__(TmpExtInf.Mapping);
2519             }
2520             UDFPackMapping(Vcb, ExtInfo);
2521         }
2522     } else
2523     if(Length) {
2524         // decrease extent
2525         AdPrint(("Resize cut (8)\n"));
2526         lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i);
2527         i++;
2528         ASSERT(lba != LBA_OUT_OF_EXTENT);
2529         ASSERT(lba != LBA_NOT_ALLOCATED);
2530         ASSERT(i);
2531         if(ExtInfo->Mapping[i].extLength) {
2532             UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used
2533             if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) {
2534 
2535                 AdPrint(("Resize try save cutted (8)\n"));
2536                 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2537                 s = UDFGetMappingLength(&(ExtInfo->Mapping[i]));
2538 
2539                 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG);
2540                 if(TmpExtInf.Mapping) {
2541                     RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s);
2542                     AdPrint(("Resize save cutted (8)\n"));
2543                     if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2544                                                &TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) {
2545                         ExtInfo->Mapping[i].extLength = 0;
2546                         ExtInfo->Mapping[i].extLocation = 0;
2547                         goto tail_cached;
2548                     }
2549                 }
2550             }
2551             UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2552 tail_cached:;
2553         }
2554         if((lim-1 >= LBS) &&
2555            (flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) {
2556             AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim));
2557             ASSERT(lim);
2558 //            BrutePoint();
2559             EXTENT_MAP ClrMap[2];
2560             ClrMap[0].extLength = lim & ~(LBS-1);
2561             s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK;
2562             ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation +
2563                                    (s >> BSh);
2564             ClrMap[1].extLength =
2565             ClrMap[1].extLocation = 0;
2566             ASSERT((ExtInfo->Mapping[i].extLocation <   ClrMap[0].extLocation) ||
2567                    (ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh))));
2568             UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used
2569             UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free
2570             ExtInfo->Mapping[i-1].extLength = s | (flags << 30);
2571         }
2572 
2573         s = UDFGetMappingLength(ExtInfo->Mapping);
2574         if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) {
2575             // This must never happen on truncate !!!
2576             AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n"));
2577         }
2578         ExtInfo->Mapping[i].extLength =
2579         ExtInfo->Mapping[i].extLocation = 0;
2580     } else {
2581         AdPrint(("Resize zero (9)\n"));
2582         ASSERT(!ExtInfo->Offset);
2583         UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free
2584         s = UDFGetMappingLength(ExtInfo->Mapping);
2585         if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) {
2586             // This must never happen on truncate !!!
2587             AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n"));
2588         }
2589         ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2590         ExtInfo->Mapping[0].extLocation =
2591         ExtInfo->Mapping[1].extLength =
2592         ExtInfo->Mapping[1].extLocation = 0;
2593     }
2594     if(ExtInfo->Offset) {
2595         if(!AlwaysInIcb) {
2596             // remove 1st entry pointing to FileEntry
2597             s = UDFGetMappingLength(ExtInfo->Mapping);
2598             RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP));
2599             if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s,
2600                           (int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) {
2601                 // This must never happen on truncate !!!
2602                 AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n"));
2603             }
2604             Length -= ExtInfo->Offset;
2605             ExtInfo->Offset = 0;
2606         } else {
2607             Length -= ExtInfo->Offset; // back to in-icb
2608         }
2609     }
2610     ExtInfo->Length = Length;
2611     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2612 
2613     for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) {
2614         ExtPrint(("Resized Ext: type %x, loc %x, len %x\n",
2615             ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK));
2616     }
2617 
2618     return STATUS_SUCCESS;
2619 } // end UDFResizeExtent()
2620 
2621 /*
2622     This routine (re)builds AllocDescs data for all allocation modes except
2623     in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for
2624     already allocated user data extent (FileInfo->Dloc->DataLoc).
2625     AllocMode in FileEntry pointed by FileInfo must be already initialized.
2626  */
2627 OSSTATUS
UDFBuildAllocDescs(IN PVCB Vcb,IN uint32 PartNum,IN OUT PUDF_FILE_INFO FileInfo,OUT int8 ** AllocData)2628 UDFBuildAllocDescs(
2629     IN PVCB Vcb,
2630     IN uint32 PartNum,
2631  IN OUT PUDF_FILE_INFO FileInfo,
2632     OUT int8** AllocData
2633     )
2634 {
2635 //    PEXTENT_MAP InMap;
2636 //    uint32 i=0;
2637     int8* Allocs;
2638     uint16 AllocMode;
2639     uint32 InitSz;
2640     OSSTATUS status;
2641 
2642     ValidateFileInfo(FileInfo);
2643     AdPrint(("BuildAllocDesc\n"));
2644     // get space available in the 1st LBlock after FE
2645     InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen;
2646     Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz);
2647     if(!Allocs) {
2648         *AllocData = NULL;
2649         AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz));
2650         return STATUS_INSUFFICIENT_RESOURCES;
2651     }
2652     RtlZeroMemory(Allocs, InitSz);
2653 //    InMap = FileInfo->Dloc->DataLoc.Mapping;
2654     UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used
2655 
2656     // TODO: move data from mapped locations here
2657 
2658     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
2659     switch(AllocMode) {
2660     case ICB_FLAG_AD_IN_ICB: {
2661         MyFreePool__(Allocs);
2662         ASSERT(!FileInfo->Dloc->AllocLoc.Mapping);
2663         Allocs = NULL;
2664         status = STATUS_SUCCESS;
2665         break;
2666     }
2667     case ICB_FLAG_AD_SHORT: {
2668         status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2669         break;
2670     }
2671     case ICB_FLAG_AD_LONG: {
2672         status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2673         break;
2674     }
2675 /*    case ICB_FLAG_AD_EXTENDED: {
2676         status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2677         break;
2678     }*/
2679     default: {
2680         MyFreePool__(Allocs);
2681         Allocs = NULL;
2682         status = STATUS_INVALID_PARAMETER;
2683     }
2684     }
2685 
2686     *AllocData = Allocs;
2687     UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2688 
2689     return status;
2690 } // end UDFBuildAllocDescs()
2691 
2692 /*
2693     This routine discards file's allocation
2694  */
2695 void
UDFFreeFileAllocation(IN PVCB Vcb,IN PUDF_FILE_INFO DirInfo,IN PUDF_FILE_INFO FileInfo)2696 UDFFreeFileAllocation(
2697     IN PVCB Vcb,
2698     IN PUDF_FILE_INFO DirInfo,
2699     IN PUDF_FILE_INFO FileInfo
2700     )
2701 {
2702     if(FileInfo->Dloc->DataLoc.Offset) {
2703         // in-ICB data
2704         if(FileInfo->Dloc->DataLoc.Mapping) {
2705             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2706                    FileInfo->Dloc->DataLoc.Mapping[0].extLocation);
2707             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
2708             FileInfo->Dloc->DataLoc.Mapping[1].extLocation =
2709             FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0;
2710             FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0;
2711             FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2712         }
2713         if(FileInfo->Dloc->AllocLoc.Mapping) {
2714             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2715                    FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2716             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2717             FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2718             FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2719             FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2720             FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2721         }
2722         UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2723     } else {
2724         if(FileInfo->Dloc->AllocLoc.Mapping) {
2725             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2726                    FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2727             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2728             FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2729             FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2730             FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2731             FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2732         }
2733         UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2734         UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
2735     }
2736     FileInfo->Dloc->DataLoc.Modified =
2737     FileInfo->Dloc->AllocLoc.Modified =
2738     FileInfo->Dloc->FELoc.Modified = FALSE;
2739 } // end UDFFreeFileAllocation()
2740 #endif //UDF_READ_ONLY_BUILD
2741 
2742 /*
2743     This routine packs physically sequential extents into single one
2744  */
2745 void
2746 __fastcall
UDFPackMapping(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo)2747 UDFPackMapping(
2748     IN PVCB Vcb,
2749     IN PEXTENT_INFO ExtInfo   // Extent array
2750     )
2751 {
2752     PEXTENT_MAP NewMap, OldMap;
2753     uint32 i, j, l;
2754     uint32 LastLba, LastType, OldLen;
2755     uint32 OldSize, NewSize;
2756 #ifdef UDF_DBG
2757     int64 check_size;
2758 #endif //UDF_DBG
2759 
2760     AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
2761     AdPrint(("  Length %x\n", ExtInfo->Length));
2762 
2763     OldMap = ExtInfo->Mapping;
2764     LastLba = OldMap[0].extLocation;
2765     OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2766     LastType = OldMap[0].extLength >> 30;
2767     OldSize =
2768     NewSize = UDFGetMappingLength(OldMap);
2769 #ifdef UDF_DBG
2770     check_size = UDFGetExtentLength(ExtInfo->Mapping);
2771     ASSERT(!(check_size & (2048-1)));
2772 #endif //UDF_DBG
2773 
2774     l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK;
2775     // calculate required length
2776     for(i=1; OldMap[i].extLength; i++) {
2777         if((LastType == (OldMap[i].extLength >> 30))
2778             &&
2779            ((OldMap[i].extLocation == LastLba + OldLen) ||
2780             (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
2781             &&
2782            (l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
2783             // we can pack two blocks in one
2784             l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2785             NewSize -= sizeof(EXTENT_MAP);
2786         } else {
2787             l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2788         }
2789         LastLba = OldMap[i].extLocation;
2790         LastType = OldMap[i].extLength >> 30;
2791         OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2792     }
2793     // no changes ?
2794     if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) {
2795         if(OldSize == NewSize)
2796             return;
2797         if(NewSize >= PACK_MAPPING_THRESHOLD)
2798             return;
2799     }
2800     AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping));
2801     NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize,
2802                                                        MEM_EXTMAP_TAG);
2803     // can't alloc ?
2804     if(!NewMap) return;
2805     // Ok, lets pack it...
2806     j=0;
2807     NewMap[0] = OldMap[0];
2808     LastLba = OldMap[0].extLocation;
2809     OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2810     LastType = OldMap[0].extLength >> 30;
2811     for(i=1; OldMap[i].extLength; i++) {
2812 
2813         ExtPrint(("oShExt: type %x, loc %x, len %x\n",
2814             OldMap[i].extLength >> 30, OldMap[i].extLocation, OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK));
2815 
2816         if((LastType == (OldMap[i].extLength >> 30))
2817             &&
2818            ((OldMap[i].extLocation == LastLba + OldLen) ||
2819             (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
2820             &&
2821            ((NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK) + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
2822             NewMap[j].extLength += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2823         } else {
2824             j++;
2825             NewMap[j] = OldMap[i];
2826         }
2827 
2828         ExtPrint(("nShExt: type %x, loc %x, len %x\n",
2829             NewMap[j].extLength >> 30, NewMap[j].extLocation, NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK));
2830 
2831         LastLba = OldMap[i].extLocation;
2832         LastType = OldMap[i].extLength >> 30;
2833         OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2834     }
2835     // write terminator
2836     j++;
2837     ASSERT(NewSize == (j+1)*sizeof(EXTENT_MAP));
2838     NewMap[j].extLength =
2839     NewMap[j].extLocation = 0;
2840 
2841 #ifdef UDF_DBG
2842     ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
2843     ASSERT(check_size == UDFGetExtentLength(NewMap));
2844 #endif
2845 
2846     AdPrint(("Pack ExtInfo %x, NewMap %x, OldMap %x\n", ExtInfo, NewMap, OldMap));
2847 
2848     ExtInfo->Mapping = NewMap;
2849     MyFreePool__(OldMap);
2850 
2851     AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
2852     AdPrint(("  Length %x\n", ExtInfo->Length));
2853 } // end UDFPackMapping()
2854 
2855 /*
2856     This routine expands mapping to 'frag-per-LBlock' state
2857  */
2858 OSSTATUS
2859 __fastcall
UDFUnPackMapping(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo)2860 UDFUnPackMapping(
2861     IN PVCB Vcb,
2862     IN PEXTENT_INFO ExtInfo   // Extent array
2863     )
2864 {
2865     PEXTENT_MAP NewMapping;
2866     PEXTENT_MAP Mapping = ExtInfo->Mapping;
2867     uint32 LBS = Vcb->LBlockSize;
2868     uint32 len = (uint32)(UDFGetExtentLength(Mapping) >> Vcb->LBlockSizeBits);
2869     uint32 i,j, type, base, d;
2870     LONG l;
2871 
2872     NewMapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
2873                                                        MEM_EXTMAP_TAG);
2874     if(!NewMapping) return STATUS_INSUFFICIENT_RESOURCES;
2875 
2876     j=0;
2877     d = LBS >> Vcb->BlockSizeBits;
2878     for(i=0; (l = (Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); i++) {
2879         base = Mapping[i].extLocation;
2880         type = Mapping[i].extLength & UDF_EXTENT_FLAG_MASK;
2881         for(; l>=(LONG)LBS; j++) {
2882             NewMapping[j].extLength = LBS | type;
2883             NewMapping[j].extLocation = base;
2884             base+=d;
2885             l-=LBS;
2886         }
2887     }
2888     // record terminator
2889     ASSERT(NewMapping);
2890     RtlZeroMemory(&(NewMapping[j]), sizeof(EXTENT_MAP));
2891     MyFreePool__(Mapping);
2892     ExtInfo->Mapping = NewMapping;
2893 
2894     return STATUS_SUCCESS;
2895 } // end UDFUnPackMapping()
2896 
2897 /*
2898     Relocate a part of extent that starts from relative (inside extent)
2899     block number 'ExtBlock' and has length of 'BC' blocks to continuous
2900     run which starts at block 'Lba'
2901  */
2902 OSSTATUS
UDFRelocateExtent(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN uint32 ExtBlock,IN uint32 Lba,IN uint32 BC)2903 UDFRelocateExtent(
2904     IN PVCB Vcb,
2905     IN PEXTENT_INFO ExtInfo,
2906     IN uint32 ExtBlock,
2907     IN uint32 Lba,
2908     IN uint32 BC
2909     )
2910 {
2911     return STATUS_ACCESS_DENIED;
2912 }
2913 
2914 /*
2915     This routine checks if all the data required is in cache.
2916  */
2917 BOOLEAN
UDFIsExtentCached(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN int64 Offset,IN uint32 Length,IN BOOLEAN ForWrite)2918 UDFIsExtentCached(
2919     IN PVCB Vcb,
2920     IN PEXTENT_INFO ExtInfo,   // Extent array
2921     IN int64 Offset,      // offset in extent
2922     IN uint32 Length,
2923     IN BOOLEAN ForWrite
2924     )
2925 {
2926     BOOLEAN retstat = FALSE;
2927     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2928     SIZE_T to_read;
2929     uint32 Lba, sect_offs, flags, i;
2930 
2931     WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE/*FALSE*//*ForWrite*/);
2932     if(!ExtInfo || !ExtInfo->Mapping) goto EO_IsCached;
2933     if(!Length) {
2934         retstat = TRUE;
2935         goto EO_IsCached;
2936     }
2937 
2938     // prevent reading out of data space
2939     if(Offset > ExtInfo->Length) goto EO_IsCached;
2940     if(Offset+Length > ExtInfo->Length) goto EO_IsCached;
2941     Offset += ExtInfo->Offset;               // used for in-ICB data
2942     // read maximal possible part of each frag of extent
2943     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &i);
2944     while(((LONG)Length) > 0) {
2945         // EOF check
2946         if(Lba == LBA_OUT_OF_EXTENT) goto EO_IsCached;
2947         Extent += (i + 1);
2948         // check for reading tail
2949         to_read = min(to_read, Length);
2950         if(flags == EXTENT_RECORDED_ALLOCATED) {
2951             retstat = UDFIsDataCached(Vcb, Lba, (to_read+sect_offs+Vcb->BlockSize-1)>>Vcb->BlockSizeBits);
2952             if(!retstat) goto EO_IsCached;
2953         } else if(ForWrite) {
2954             goto EO_IsCached;
2955         }
2956         Offset += to_read;
2957         Length -= to_read;
2958         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &i);
2959     }
2960     retstat = TRUE;
2961 EO_IsCached:
2962     if(!retstat) {
2963         WCacheEODirect__(&(Vcb->FastCache), Vcb);
2964     }
2965     return retstat;
2966 } // end UDFIsExtentCached()
2967 
2968 /*
2969     This routine reads cached data only.
2970  */
2971 /*OSSTATUS
2972 UDFReadExtentCached(
2973     IN PVCB Vcb,
2974     IN PEXTENT_INFO ExtInfo,   // Extent array
2975     IN int64 Offset,      // offset in extent
2976     IN uint32 Length,
2977     OUT int8* Buffer,
2978     OUT PSIZE_T ReadBytes
2979     )
2980 {
2981     (*ReadBytes) = 0;
2982     if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
2983 
2984     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2985     uint32 to_read, Lba, sect_offs, flags;
2986     SIZE_T _ReadBytes;
2987     OSSTATUS status;
2988     // prevent reading out of data space
2989     if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
2990     if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
2991     Offset += ExtInfo->Offset;               // used for in-ICB data
2992     // read maximal possible part of each frag of extent
2993     while(((LONG)Length) > 0) {
2994         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, NULL);
2995         // EOF check
2996         if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
2997         // check for reading tail
2998         to_read = (to_read < Length) ?
2999                    to_read : Length;
3000         if(flags == EXTENT_RECORDED_ALLOCATED) {
3001             status = UDFReadDataCached(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Buffer, &_ReadBytes);
3002             (*ReadBytes) += _ReadBytes;
3003         } else {
3004             RtlZeroMemory(Buffer, to_read);
3005             (*ReadBytes) += to_read;
3006             status = STATUS_SUCCESS;
3007         }
3008         if(!OS_SUCCESS(status)) return status;
3009         // prepare for reading next frag...
3010         Buffer += to_read;
3011         Offset += to_read;
3012         Length -= to_read;
3013     }
3014     return STATUS_SUCCESS;
3015 } // end UDFReadExtentCached()*/
3016 
3017 /*
3018     This routine reads data at any offset from specified extent.
3019  */
3020 OSSTATUS
UDFReadExtent(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN int64 Offset,IN SIZE_T Length,IN BOOLEAN Direct,OUT int8 * Buffer,OUT PSIZE_T ReadBytes)3021 UDFReadExtent(
3022     IN PVCB Vcb,
3023     IN PEXTENT_INFO ExtInfo, // Extent array
3024     IN int64 Offset,      // offset in extent
3025     IN SIZE_T Length,
3026     IN BOOLEAN Direct,
3027     OUT int8* Buffer,
3028     OUT PSIZE_T ReadBytes
3029     )
3030 {
3031     (*ReadBytes) = 0;
3032     if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
3033     ASSERT((uintptr_t)Buffer > 0x1000);
3034 
3035     AdPrint(("Read ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3036 
3037     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3038     SIZE_T to_read, _ReadBytes;
3039     uint32 Lba, sect_offs, flags;
3040     uint32 index;
3041     OSSTATUS status;
3042     // prevent reading out of data space
3043     if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
3044     if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
3045     Offset += ExtInfo->Offset;               // used for in-ICB data
3046     // read maximal possible part of each frag of extent
3047     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &index);
3048     _ReadBytes = index;
3049     while(Length) {
3050         // EOF check
3051         if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
3052         Extent += (_ReadBytes + 1);
3053         // check for reading tail
3054         to_read = min(to_read, Length);
3055         if(flags == EXTENT_RECORDED_ALLOCATED) {
3056             status = UDFReadData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Direct, Buffer, &_ReadBytes);
3057             (*ReadBytes) += _ReadBytes;
3058             if(!OS_SUCCESS(status)) return status;
3059         } else {
3060             RtlZeroMemory(Buffer, to_read);
3061             (*ReadBytes) += to_read;
3062         }
3063         // prepare for reading next frag...
3064         Length -= to_read;
3065         if(!Length)
3066             break;
3067         ASSERT(to_read);
3068         Buffer += to_read;
3069 //        Offset += to_read;
3070         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &index);
3071         _ReadBytes = index;
3072         sect_offs = 0;
3073     }
3074     return STATUS_SUCCESS;
3075 } // end UDFReadExtent()
3076 
3077 /*
3078     This routine reads and builds mapping for
3079     specified amount of data at any offset from specified extent.
3080     Size of output buffer is limited by *_SubExtInfoSz
3081  */
3082 OSSTATUS
UDFReadExtentLocation(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN int64 Offset,OUT PEXTENT_MAP * _SubExtInfo,IN OUT uint32 * _SubExtInfoSz,OUT int64 * _NextOffset)3083 UDFReadExtentLocation(
3084     IN PVCB Vcb,
3085     IN PEXTENT_INFO ExtInfo,      // Extent array
3086     IN int64 Offset,              // offset in extent to start SubExtent from
3087     OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array
3088  IN OUT uint32* _SubExtInfoSz,    // IN:  maximum number of fragments to get
3089                                   // OUT: actually obtained fragments
3090     OUT int64* _NextOffset        // offset, caller can start from to continue
3091     )
3092 {
3093     if(!ExtInfo || !ExtInfo->Mapping)
3094         return STATUS_INVALID_PARAMETER;
3095 
3096     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3097     PEXTENT_MAP SubExtInfo;
3098     SIZE_T to_read;
3099     uint32 Lba, sect_offs, flags, Skip_MapEntries;
3100     int32 SubExtInfoSz = *_SubExtInfoSz;
3101     int64 Length;
3102     int64 NextOffset;
3103 //    OSSTATUS status = STATUS_BUFFER_OVERFLOW;
3104 
3105     (*_SubExtInfo) = NULL;
3106     (*_SubExtInfoSz) = 0;
3107     NextOffset = Offset;
3108     // prevent reading out of data space
3109     if(Offset >= ExtInfo->Length)
3110         return STATUS_END_OF_FILE;
3111     Length = ExtInfo->Length - Offset;
3112     Offset += ExtInfo->Offset;               // used for in-ICB data
3113     // read maximal possible part of each frag of extent
3114     SubExtInfo = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , SubExtInfoSz*sizeof(EXTENT_MAP),
3115                                                        MEM_EXTMAP_TAG);
3116     (*_SubExtInfo) = SubExtInfo;
3117     if(!SubExtInfo)
3118         return STATUS_INSUFFICIENT_RESOURCES;
3119 
3120     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &Skip_MapEntries);
3121     while(Length && SubExtInfoSz) {
3122         // EOF check
3123         if(Lba == LBA_OUT_OF_EXTENT) {
3124             BrutePoint();
3125             return STATUS_END_OF_FILE;
3126         }
3127         Extent += (Skip_MapEntries + 1);
3128         // check for reading tail
3129         to_read = (int32)min((int64)to_read, Length);
3130         SubExtInfo->extLength   = to_read;
3131         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3132             SubExtInfo->extLocation = LBA_NOT_ALLOCATED;
3133         } else
3134         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3135             ASSERT(!(Lba & 0x80000000));
3136             SubExtInfo->extLocation = Lba | 0x80000000;
3137         } else {
3138             SubExtInfo->extLocation = Lba;
3139         }
3140         (*_SubExtInfoSz)++;
3141         SubExtInfoSz--;
3142         NextOffset += to_read;
3143         // prepare for reading next frag...
3144         Length -= to_read;
3145         if(!Length) {
3146 //            status = STATUS_SUCCESS;
3147             break;
3148         }
3149         ASSERT(to_read);
3150         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &Skip_MapEntries);
3151         sect_offs = 0;
3152     }
3153     (*_NextOffset) = NextOffset;
3154     return STATUS_SUCCESS;
3155 } // end UDFReadExtentLocation()
3156 
3157 #ifdef _MSC_VER
3158 #pragma warning(push)
3159 #pragma warning(disable:4035)               // re-enable below
3160 #endif
3161 
3162 uint32
UDFGetZeroLength(IN int8 * Buffer,IN uint32 Length)3163 UDFGetZeroLength(
3164     IN int8* Buffer,
3165     IN uint32 Length
3166     )
3167 {
3168     uint32 i;
3169     Length /= sizeof(uint32);
3170     for(i=0; i<Length; i++) {
3171         if( ((uint32*)Buffer)[i] )
3172             break;
3173     }
3174     return Length*sizeof(uint32);
3175 }
3176 
3177 #ifdef _MSC_VER
3178 #pragma warning(pop) // re-enable warning #4035
3179 #endif
3180 
3181 #ifndef UDF_READ_ONLY_BUILD
3182 /*
3183     This routine writes data at any offset to specified extent.
3184  */
3185 OSSTATUS
UDFWriteExtent(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN int64 Offset,IN SIZE_T Length,IN BOOLEAN Direct,IN int8 * Buffer,OUT PSIZE_T WrittenBytes)3186 UDFWriteExtent(
3187     IN PVCB Vcb,
3188     IN PEXTENT_INFO ExtInfo,   // Extent array
3189     IN int64 Offset,        // offset in extent
3190     IN SIZE_T Length,
3191     IN BOOLEAN Direct,         // setting this flag delays flushing of given
3192                                // data to indefinite term
3193     IN int8* Buffer,
3194     OUT PSIZE_T WrittenBytes
3195     )
3196 {
3197     if(!ExtInfo || !ExtInfo->Mapping)
3198         return STATUS_INVALID_PARAMETER;
3199 
3200     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3201     uint32 Lba, sect_offs, flags;
3202     OSSTATUS status;
3203     SIZE_T to_write, _WrittenBytes;
3204     BOOLEAN reread_lba;
3205 //    BOOLEAN already_prepared = FALSE;
3206 //    BOOLEAN prepare = !Buffer;
3207 
3208     AdPrint(("Write ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3209 
3210     Offset += ExtInfo->Offset;               // used for in-ICB data
3211     // write maximal possible part of each frag of extent
3212     while(((LONG)Length) > 0) {
3213         UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3214         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3215         // EOF check
3216         if(Lba == LBA_OUT_OF_EXTENT) {
3217             return STATUS_END_OF_FILE;
3218         }
3219 /*        if((to_write < Length) &&
3220            !Direct && !prepare && !already_prepared) {
3221             // rebuild mapping, allocate space, etc.
3222             // to indicate this, set Buffer to NULL
3223             AdPrint(("UDFWriteExtent: Prepare\n"));
3224             BrutePoint();
3225             _WrittenBytes = 0;
3226             status = UDFWriteExtent(Vcb, ExtInfo, Offset, Length, *//*Direct*//*FALSE, NULL, &_WrittenBytes);
3227             if(!OS_SUCCESS(status)) {
3228                 return status;
3229             }
3230             Extent = ExtInfo->Mapping;
3231             Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3232             already_prepared = TRUE;
3233         }*/
3234         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3235             // here we should allocate space for this extent
3236             if(!OS_SUCCESS(status = UDFMarkNotAllocatedAsAllocated(Vcb, Offset, to_write, ExtInfo)))
3237                 return status;
3238             Extent = ExtInfo->Mapping;
3239             UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3240             Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3241             if(Lba == LBA_OUT_OF_EXTENT) {
3242                 return STATUS_END_OF_FILE;
3243             }
3244             // we have already re-read Lba
3245             reread_lba = FALSE;
3246         } else {
3247             // we may need to re-read Lba if some changes are
3248             // made while converting from Alloc-Not-Rec
3249             reread_lba = TRUE;
3250         }
3251         // check if writing to not recorded allocated
3252         // in this case we must pad blocks with zeros around
3253         // modified area
3254         //
3255         // ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|...
3256         //        .                .
3257         //        .     ||         .
3258         //        .     \/         .
3259         //        .                .
3260         // ...|000ddddd|dddddddd|dd000000|...
3261         //        .                .
3262         //        ^                ^
3263         //        sect_offs        sect_offs+to_write
3264         //        .                .
3265         //        .<-- to_write -->.
3266         //
3267         to_write = min(to_write, Length);
3268         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3269             if(!OS_SUCCESS(status = UDFMarkAllocatedAsRecorded(Vcb, Offset, to_write, ExtInfo)))
3270                 return status;
3271             Extent = ExtInfo->Mapping;
3272             UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3273             if(reread_lba) {
3274                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3275                 to_write = min(to_write, Length);
3276             }
3277             /*
3278               we must fill 1st block with zeros in 1 of 2 cases:
3279                 1) start offset is not aligned on LBlock boundary
3280                       OR
3281                 2) end offset is not aligned on LBlock boundary and lays in
3282                    the same LBlock
3283 
3284               we must fill last block with zeros if both
3285                 1) end offset is not aligned on LBlock boundary
3286                       AND
3287                 2) end offset DOESN'T lay in the 1st LBlock
3288             */
3289 
3290 //            if(!prepare) {
3291                 // pad 1st logical block
3292             if((sect_offs || (sect_offs + to_write < Vcb->LBlockSize) )
3293                                 &&
3294                            !Vcb->CDR_Mode) {
3295                 status = UDFWriteData(Vcb, TRUE,
3296                                       ( ((uint64)Lba) << Vcb->BlockSizeBits),
3297                                       Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
3298                 if(!OS_SUCCESS(status))
3299                     return status;
3300             }
3301             // pad last logical block
3302             if((sect_offs + to_write > Vcb->LBlockSize) &&
3303                (sect_offs + to_write) & (Vcb->LBlockSize - 1)) {
3304                 status = UDFWriteData(Vcb, TRUE,
3305                                       (( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs + to_write) & ~((int64)(Vcb->LBlockSize)-1),
3306                                       Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
3307             }
3308             if(!OS_SUCCESS(status))
3309                 return status;
3310 /*            } else {
3311                 status = STATUS_SUCCESS;
3312             }*/
3313         }
3314         ASSERT(to_write);
3315 //        if(!prepare) {
3316         status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, Direct, Buffer, &_WrittenBytes);
3317         *WrittenBytes += _WrittenBytes;
3318         if(!OS_SUCCESS(status)) return status;
3319 /*        } else {
3320             status = STATUS_SUCCESS;
3321             *WrittenBytes += to_write;
3322         }*/
3323         // prepare for writing next frag...
3324         Buffer += to_write;
3325         Offset += to_write;
3326         Length -= to_write;
3327     }
3328     AdPrint(("Write: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3329     return STATUS_SUCCESS;
3330 } // end UDFWriteExtent()
3331 
3332 //#if 0
3333 /*
3334     This routine zeroes/deallocates data at any offset to specified extent.
3335  */
3336 OSSTATUS
UDFZeroExtent(IN PVCB Vcb,IN PEXTENT_INFO ExtInfo,IN int64 Offset,IN SIZE_T Length,IN BOOLEAN Deallocate,IN BOOLEAN Direct,OUT PSIZE_T WrittenBytes)3337 UDFZeroExtent(
3338     IN PVCB Vcb,
3339     IN PEXTENT_INFO ExtInfo,   // Extent array
3340     IN int64 Offset,           // offset in extent
3341     IN SIZE_T Length,
3342     IN BOOLEAN Deallocate,     // deallocate frag or just mark as unrecorded
3343     IN BOOLEAN Direct,         // setting this flag delays flushing of given
3344                                // data to indefinite term
3345     OUT PSIZE_T WrittenBytes
3346     )
3347 {
3348     if(!ExtInfo || !ExtInfo->Mapping)
3349         return STATUS_INVALID_PARAMETER;
3350 
3351     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3352     uint32 Lba, sect_offs, flags;
3353     OSSTATUS status;
3354     SIZE_T to_write, _WrittenBytes;
3355     SIZE_T LBS = Vcb->LBlockSize;
3356 
3357     AdPrint(("Zero ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3358 
3359     Offset += ExtInfo->Offset;               // used for in-ICB data
3360     // fill/deallocate maximal possible part of each frag of extent
3361     while(((LONG)Length) > 0) {
3362         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3363         // EOF check
3364         if(Lba == LBA_OUT_OF_EXTENT) {
3365             return STATUS_END_OF_FILE;
3366         }
3367         // check for writing tail
3368         to_write = min(to_write, Length);
3369 
3370         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3371             // here we should do nothing
3372             *WrittenBytes += to_write;
3373         } else
3374         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3375             // we should just deallocate this frag
3376             if(Deallocate) {
3377                 if(!OS_SUCCESS(status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, to_write, ExtInfo)))
3378                     return status;
3379             }
3380             Extent = ExtInfo->Mapping;
3381             *WrittenBytes += to_write;
3382         } else {
3383             // fill tail of the 1st Block with ZEROs
3384             if(sect_offs) {
3385                 status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs,
3386                                       min(to_write, LBS-sect_offs),
3387                                       Direct, Vcb->ZBuffer, &_WrittenBytes);
3388                 *WrittenBytes += _WrittenBytes;
3389                 if(!OS_SUCCESS(status))
3390                     return status;
3391                 Offset += _WrittenBytes;
3392                 Length -= _WrittenBytes;
3393                 to_write -= _WrittenBytes;
3394                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3395                 ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
3396                 ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
3397                 ASSERT(!sect_offs);
3398             }
3399             // deallocate Blocks
3400             if(to_write >= LBS) {
3401                 // use 'sect_offs' as length of extent to be deallocated
3402                 sect_offs = to_write & ~(LBS - 1);
3403                 if(Deallocate) {
3404                     status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, sect_offs, ExtInfo);
3405                 } else {
3406                     status = UDFMarkRecordedAsAllocated(Vcb, Offset, sect_offs, ExtInfo);
3407                 }
3408                 if(!OS_SUCCESS(status))
3409                     return status;
3410                 // reload extent mapping
3411                 Extent = ExtInfo->Mapping;
3412                 Offset += sect_offs;
3413                 Length -= sect_offs;
3414                 *WrittenBytes += sect_offs;
3415                 to_write -= sect_offs;
3416                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3417                 ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
3418                 ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
3419                 ASSERT(!sect_offs);
3420             }
3421             // fill beginning of the last Block with ZEROs
3422             if(to_write) {
3423                 status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), to_write, Direct, Vcb->ZBuffer, &_WrittenBytes);
3424                 *WrittenBytes += _WrittenBytes;
3425                 if(!OS_SUCCESS(status))
3426                     return status;
3427                 ASSERT(to_write == _WrittenBytes);
3428             }
3429         }
3430         AdPrint(("Zero... ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3431         // prepare for filling next frag...
3432         Offset += to_write;
3433         Length -= to_write;
3434     }
3435     AdPrint(("Zero: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3436     return STATUS_SUCCESS;
3437 } // end UDFZeroExtent()
3438 //#endif //0
3439 #endif //UDF_READ_ONLY_BUILD
3440