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
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 uint32* 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
79 UDFNextExtentToLba(
80     IN PVCB Vcb,
81     IN PEXTENT_MAP Extent,   // Extent array
82     OUT uint32* 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
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
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
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
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
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
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     uint32 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
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     uint32 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
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     uint32 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
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 = (uint32)AllocDescs - (uint32)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
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
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
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
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
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
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
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
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
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
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
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
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     uint32 aLen, sLen;
1963     uint32 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
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     uint32 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         AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent));
2162     } else
2163     if(l < BOffs) {
2164         // .ExtLength, BOffs & l are already aligned...
2165         if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
2166             // xxxxxx ->  xxRRxx
2167             NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) );
2168             if(!NewExtent) {
2169                 return STATUS_INSUFFICIENT_RESOURCES;
2170             }
2171             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2172             RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2173             NewExtent[i].extLength = (BOffs - l) << BSh;
2174             NewExtent[i].extLength |= flags;
2175             NewExtent[i+1].extLocation = 0;
2176             NewExtent[i+1].extLength = aLen | (target_flags << 30);
2177             NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) -
2178                                        (NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ;
2179             NewExtent[i+2].extLocation = Extent[i].extLocation +
2180                                        (NewExtent[i+2].extLength >> BSh);
2181             NewExtent[i+2].extLength |= flags;
2182             AdPrint(("Alloc->Not (2) new %x\n", NewExtent));
2183         } else {
2184             // xxxxxx ->  xxRRRR
2185             NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2186             if(!NewExtent) {
2187                 return STATUS_INSUFFICIENT_RESOURCES;
2188             }
2189             RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2190             RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2191             NewExtent[i].extLength = ((BOffs - l) << BSh) | flags;
2192             NewExtent[i+1].extLocation = 0;
2193             NewExtent[i+1].extLength = aLen | (target_flags << 30);
2194             AdPrint(("Alloc->Not (3) new %x\n", NewExtent));
2195         }
2196     } else {
2197         // xxxxxx ->  RRRRxx
2198         NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2199         if(!NewExtent) {
2200             return STATUS_INSUFFICIENT_RESOURCES;
2201         }
2202         RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2203         RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2204         NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
2205         NewExtent[i+1].extLength |= flags;
2206         NewExtent[i].extLocation = 0;
2207         NewExtent[i].extLength = aLen | (target_flags << 30);
2208         AdPrint(("Alloc->Not (4) new %x\n", NewExtent));
2209     }
2210 
2211     if(Deallocate)
2212         UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free
2213 
2214     if(Extent) {
2215         AdPrint(("Alloc->Not kill %x\n", Extent));
2216         MyFreePool__(Extent);
2217     } else {
2218         AdPrint(("Alloc->Not keep %x\n", Extent));
2219     }
2220     ExtInfo->Modified = TRUE;
2221     ExtInfo->Mapping = NewExtent;
2222     AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
2223 
2224     return STATUS_SUCCESS;
2225 } // end UDFMarkAllocatedAsNotXXX()
2226 //#endif //0
2227 
2228 /*
2229     This routine resizes extent & updates associated mapping
2230  */
2231 OSSTATUS
2232 UDFResizeExtent(
2233     IN PVCB Vcb,
2234     IN uint32 PartNum,
2235     IN int64 Length,          // Required Length
2236     IN BOOLEAN AlwaysInIcb,   // must be TRUE for AllocDescs
2237     OUT PEXTENT_INFO ExtInfo
2238     )
2239 {
2240     uint32 i, flags, lba, lim;
2241     int64 l;
2242     OSSTATUS status;
2243     EXTENT_INFO TmpExtInf;
2244     EXTENT_MAP  TmpMapping[2];
2245     uint32 s, req_s, pe, BSh, LBS, PS;
2246     LBS = Vcb->LBlockSize;
2247     BSh = Vcb->BlockSizeBits;
2248     PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
2249     uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1));
2250     BOOLEAN Sequential = FALSE;
2251 
2252     ASSERT(PartNum < 3);
2253 
2254     ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length));
2255 
2256     if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) {
2257         AdPrint(("  cut preallocated\n"));
2258     } else
2259     if(ExtInfo->Length == Length) {
2260         return STATUS_SUCCESS;
2261     }
2262     if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2263         MaxGrow &= ~(Vcb->WriteBlockSize-1);
2264         Sequential = TRUE;
2265     }
2266 
2267     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2268     if(ExtInfo->Offset) {
2269         if(ExtInfo->Offset + Length <= LBS) {
2270             ExtPrint(("Resize IN-ICB\n"));
2271             ExtInfo->Length = Length;
2272             return STATUS_SUCCESS;
2273         }
2274         if(!AlwaysInIcb)           // simulate unused 1st sector in extent
2275             ExtInfo->Offset = LBS; // it'll be truncated later
2276         Length += ExtInfo->Offset; // convert to real offset in extent
2277     }
2278     lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i);
2279     if(ExtInfo->Length < Length) {
2280         // increase extent
2281         if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2282                               &TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) {
2283             AdPrint(("Resize found cached(1)\n"));
2284             ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2285             MyFreePool__(TmpExtInf.Mapping);
2286         }
2287         if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) {
2288             // we have enough space inside extent
2289             ExtInfo->Length = Length;
2290             AdPrint(("Resize do nothing (1)\n"));
2291         } else /*if(lba == LBA_OUT_OF_EXTENT)*/ {
2292 
2293             Length -= ExtInfo->Offset;
2294             if(/*Length && l &&*/  (l % MaxGrow) &&
2295                (Length-1)/MaxGrow != (l-1)/MaxGrow) {
2296                 AdPrint(("Crossing MAX_FRAG boundary...\n"));
2297                 int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow;
2298                 status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo);
2299                 if(!OS_SUCCESS(status)) {
2300                     UDFPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status));
2301                     return status;
2302                 }
2303                 l = ExtInfo->Length;
2304                 ASSERT(l == l2);
2305             }
2306             while((Length - l) > MaxGrow) {
2307                 status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2308                 if(!OS_SUCCESS(status)) {
2309                     UDFPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status));
2310                     return status;
2311                 }
2312                 l = ExtInfo->Length;
2313             }
2314             Length += ExtInfo->Offset;
2315             // at first, try to resize existing frag
2316 #ifndef UDF_ALLOW_FRAG_AD
2317             i = UDFGetMappingLength(ExtInfo->Mapping);
2318             if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) {
2319                 // this is very important check since we will not
2320                 // be able to _record_ too long AllocDesc because of
2321                 // some DEMO limitations in UDFBuildXXXAllocDescs()
2322                 AdPrint(("  DISK_FULL\n"));
2323                 return STATUS_DISK_FULL;
2324             }
2325             i /= sizeof(EXTENT_MAP);
2326 #else //UDF_ALLOW_FRAG_AD
2327             i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP);
2328 #endif //UDF_ALLOW_FRAG_AD
2329 #ifdef ALLOW_SPARSE
2330             if(!AlwaysInIcb && !(ExtInfo->Offset) &&
2331                (Length - l >= (Vcb->SparseThreshold << BSh))) {
2332                 // last frag will be Not-Alloc-Not-Rec...
2333                 AdPrint(("Resize sparse (2)\n"));
2334                 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2335                 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2,
2336                                                                    MEM_EXTMAP_TAG);
2337                 if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES;
2338                 TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2339                 TmpExtInf.Mapping[0].extLocation =// 0;
2340                 TmpExtInf.Mapping[1].extLength =
2341                 TmpExtInf.Mapping[1].extLocation = 0;
2342                 l = Length;
2343                 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2344                 MyFreePool__(TmpExtInf.Mapping);
2345             } else
2346 #endif //ALLOW_SPARSE
2347             // allocate some sectors
2348             if(i>1 && !(ExtInfo->Offset)) {
2349                 i-=2;
2350                 // check if Not-Alloc-Not-Rec at the end of mapping
2351                 if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) {
2352                     // do nothing, but jump directly to allocator
2353                 } else
2354                 if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
2355                     AdPrint(("Resize grow sparse (3)\n"));
2356                     ExtInfo->Mapping[i].extLength +=
2357                         (((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ;
2358                     l = Length;
2359                 // check if Alloc-Not-Rec at the end of mapping
2360                 } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) {
2361                     AdPrint(("Resize grow Not-Rec (3)\n"));
2362                     // current length of last frag
2363                     s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2364                     // prefered location of the next frag
2365                     lba = ExtInfo->Mapping[i].extLocation + s;
2366                     pe=UDFPartEnd(Vcb,PartNum);
2367                     // maximum frag length
2368                     if(Sequential) {
2369                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2370                     } else {
2371                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2372                     }
2373                     // required last extent length
2374                     req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2375                                            ((l      + LBS - 1) & ~(LBS-1))   ) >> BSh);
2376                     if(lim > req_s) {
2377                         lim = req_s;
2378                     }
2379                     UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2380 /*                    if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) &&
2381                        ((Length & ~(PS-1)) > (l & ~(PS-1))) &&
2382                        TRUE) {
2383                         status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2384                     }*/
2385                     // how many sectors we should add
2386                     req_s = lim - s;
2387                     ASSERT(req_s);
2388                     if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2389                         s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1));
2390                     }
2391 /*                    for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2392                         s++;
2393                     }*/
2394                     if(s==lim) {
2395                         // we can just increase the last frag
2396                         AdPrint(("Resize grow last Not-Rec (4)\n"));
2397                         ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2398                         l = Length;
2399                         UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2400                     } else {
2401                         // we get here if simple increasing of last frag failed
2402                         // it worth truncating last frag and try to allocate
2403                         // all required data as a single frag
2404 
2405 /*                        if(Sequential && s>=PS) {
2406                             s &= ~(PS-1);
2407                             AdPrint(("Resize grow last Not-Rec (4/2)\n"));
2408                             ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2409                             l += (s << BSh);
2410                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2411                         }*/
2412                         AdPrint(("Resize reloc last Not-Rec (5)\n"));
2413                         TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP),
2414                                                                            MEM_EXTMAP_TAG);
2415                         if(!TmpExtInf.Mapping) {
2416                             UDFPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n"));
2417                             UDFReleaseResource(&(Vcb->BitMapResource1));
2418                             return STATUS_INSUFFICIENT_RESOURCES;
2419                         }
2420                         RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP));
2421                         TmpExtInf.Mapping[i].extLength =
2422                         TmpExtInf.Mapping[i].extLocation = 0;
2423                         TmpExtInf.Offset = ExtInfo->Offset;
2424                         l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2425                         TmpExtInf.Length = l;
2426                         ASSERT(i || !ExtInfo->Offset);
2427                         UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2428                         MyFreePool__(ExtInfo->Mapping);
2429                         (*ExtInfo) = TmpExtInf;
2430                     }
2431                     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2432                     UDFReleaseResource(&(Vcb->BitMapResource1));
2433                 // check if Alloc-Rec
2434                 } else {
2435                     // current length of last frag
2436                     s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2437                     // prefered location of the next frag
2438                     lba = ExtInfo->Mapping[i].extLocation + s;
2439                     pe=UDFPartEnd(Vcb,PartNum);
2440                     // maximum frag length
2441                     if(Sequential) {
2442                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2443                     } else {
2444                         lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2445                     }
2446                     // required last extent length
2447                     req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2448                                            ((l      + LBS - 1) & ~(LBS-1))   ) >> BSh);
2449                     if(lim > req_s) {
2450                         lim = req_s;
2451                     }
2452 //                    s=0;
2453                     // how many sectors we should add
2454                     req_s = lim - s;
2455                     if(req_s) {
2456                         uint32 d=0;
2457 
2458                         UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2459                         //ASSERT(req_s);
2460                         if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2461                             s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)));
2462                         }
2463     /*                    for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2464                             s++;
2465                         }*/
2466 
2467                         if(s==lim) {
2468                             AdPrint(("Resize grow last Rec (6)\n"));
2469                             // we can just increase last frag
2470                             TmpMapping[0].extLength = req_s << BSh;
2471                             TmpMapping[0].extLocation = lba;
2472                             TmpMapping[1].extLength =
2473                             TmpMapping[1].extLocation = 0;
2474                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2475                             l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2476                             ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2477                         } else if(d) {
2478                             AdPrint(("Resize part-grow last Rec (6)\n"));
2479                             // increase last frag, then alloc rest
2480                             TmpMapping[0].extLength = d << BSh;
2481                             TmpMapping[0].extLocation = lba;
2482                             TmpMapping[1].extLength =
2483                             TmpMapping[1].extLocation = 0;
2484                             UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2485                             l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2486                             ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2487                         } else {
2488                             AdPrint(("Can't grow last Rec (6)\n"));
2489                         }
2490                         UDFReleaseResource(&(Vcb->BitMapResource1));
2491                     } else {
2492                         AdPrint(("Max frag length reached (6)\n"));
2493                     }
2494                 }
2495             }
2496             if(l < Length) {
2497                 // we get here if simple increasing of the last frag failed
2498                 AdPrint(("Resize add new frag (7)\n"));
2499                 if(l < LBS && Length >= LBS &&
2500                    (ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2501                     AdPrint(("Resize tune for SEQUENTIAL i/o\n"));
2502                 }
2503                 status = UDFAllocFreeExtent(Vcb, Length - l,
2504                                                    UDFPartStart(Vcb, PartNum),
2505                                                    UDFPartEnd(Vcb, PartNum),
2506                                                    &TmpExtInf,
2507                                                    ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
2508                 if(!OS_SUCCESS(status)) {
2509                     UDFPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status));
2510                     return status;
2511                 }
2512                 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2513                 MyFreePool__(TmpExtInf.Mapping);
2514             }
2515             UDFPackMapping(Vcb, ExtInfo);
2516         }
2517     } else
2518     if(Length) {
2519         // decrease extent
2520         AdPrint(("Resize cut (8)\n"));
2521         lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i);
2522         i++;
2523         ASSERT(lba != LBA_OUT_OF_EXTENT);
2524         ASSERT(lba != LBA_NOT_ALLOCATED);
2525         ASSERT(i);
2526         if(ExtInfo->Mapping[i].extLength) {
2527             UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used
2528             if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) {
2529 
2530                 AdPrint(("Resize try save cutted (8)\n"));
2531                 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2532                 s = UDFGetMappingLength(&(ExtInfo->Mapping[i]));
2533 
2534                 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG);
2535                 if(TmpExtInf.Mapping) {
2536                     RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s);
2537                     AdPrint(("Resize save cutted (8)\n"));
2538                     if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2539                                                &TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) {
2540                         ExtInfo->Mapping[i].extLength = 0;
2541                         ExtInfo->Mapping[i].extLocation = 0;
2542                         goto tail_cached;
2543                     }
2544                 }
2545             }
2546             UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2547 tail_cached:;
2548         }
2549         if((lim-1 >= LBS) &&
2550            (flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) {
2551             AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim));
2552             ASSERT(lim);
2553 //            BrutePoint();
2554             EXTENT_MAP ClrMap[2];
2555             ClrMap[0].extLength = lim & ~(LBS-1);
2556             s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK;
2557             ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation +
2558                                    (s >> BSh);
2559             ClrMap[1].extLength =
2560             ClrMap[1].extLocation = 0;
2561             ASSERT((ExtInfo->Mapping[i].extLocation <   ClrMap[0].extLocation) ||
2562                    (ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh))));
2563             UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used
2564             UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free
2565             ExtInfo->Mapping[i-1].extLength = s | (flags << 30);
2566         }
2567 
2568         s = UDFGetMappingLength(ExtInfo->Mapping);
2569         if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) {
2570             // This must never happen on truncate !!!
2571             AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n"));
2572         }
2573         ExtInfo->Mapping[i].extLength =
2574         ExtInfo->Mapping[i].extLocation = 0;
2575     } else {
2576         AdPrint(("Resize zero (9)\n"));
2577         ASSERT(!ExtInfo->Offset);
2578         UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free
2579         s = UDFGetMappingLength(ExtInfo->Mapping);
2580         if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) {
2581             // This must never happen on truncate !!!
2582             AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n"));
2583         }
2584         ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2585         ExtInfo->Mapping[0].extLocation =
2586         ExtInfo->Mapping[1].extLength =
2587         ExtInfo->Mapping[1].extLocation = 0;
2588     }
2589     if(ExtInfo->Offset) {
2590         if(!AlwaysInIcb) {
2591             // remove 1st entry pointing to FileEntry
2592             s = UDFGetMappingLength(ExtInfo->Mapping);
2593             RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP));
2594             if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s,
2595                           (int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) {
2596                 // This must never happen on truncate !!!
2597                 AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n"));
2598             }
2599             Length -= ExtInfo->Offset;
2600             ExtInfo->Offset = 0;
2601         } else {
2602             Length -= ExtInfo->Offset; // back to in-icb
2603         }
2604     }
2605     ExtInfo->Length = Length;
2606     UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2607 
2608     for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) {
2609         ExtPrint(("Resized Ext: type %x, loc %x, len %x\n",
2610             ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK));
2611     }
2612 
2613     return STATUS_SUCCESS;
2614 } // end UDFResizeExtent()
2615 
2616 /*
2617     This routine (re)builds AllocDescs data for all allocation modes except
2618     in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for
2619     already allocated user data extent (FileInfo->Dloc->DataLoc).
2620     AllocMode in FileEntry pointed by FileInfo must be already initialized.
2621  */
2622 OSSTATUS
2623 UDFBuildAllocDescs(
2624     IN PVCB Vcb,
2625     IN uint32 PartNum,
2626  IN OUT PUDF_FILE_INFO FileInfo,
2627     OUT int8** AllocData
2628     )
2629 {
2630 //    PEXTENT_MAP InMap;
2631 //    uint32 i=0;
2632     int8* Allocs;
2633     uint16 AllocMode;
2634     uint32 InitSz;
2635     OSSTATUS status;
2636 
2637     ValidateFileInfo(FileInfo);
2638     AdPrint(("BuildAllocDesc\n"));
2639     // get space available in the 1st LBlock after FE
2640     InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen;
2641     Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz);
2642     if(!Allocs) {
2643         *AllocData = NULL;
2644         AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz));
2645         return STATUS_INSUFFICIENT_RESOURCES;
2646     }
2647     RtlZeroMemory(Allocs, InitSz);
2648 //    InMap = FileInfo->Dloc->DataLoc.Mapping;
2649     UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used
2650 
2651     // TODO: move data from mapped locations here
2652 
2653     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
2654     switch(AllocMode) {
2655     case ICB_FLAG_AD_IN_ICB: {
2656         MyFreePool__(Allocs);
2657         ASSERT(!FileInfo->Dloc->AllocLoc.Mapping);
2658         Allocs = NULL;
2659         status = STATUS_SUCCESS;
2660         break;
2661     }
2662     case ICB_FLAG_AD_SHORT: {
2663         status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2664         break;
2665     }
2666     case ICB_FLAG_AD_LONG: {
2667         status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2668         break;
2669     }
2670 /*    case ICB_FLAG_AD_EXTENDED: {
2671         status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2672         break;
2673     }*/
2674     default: {
2675         MyFreePool__(Allocs);
2676         Allocs = NULL;
2677         status = STATUS_INVALID_PARAMETER;
2678     }
2679     }
2680 
2681     *AllocData = Allocs;
2682     UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2683 
2684     return status;
2685 } // end UDFBuildAllocDescs()
2686 
2687 /*
2688     This routine discards file's allocation
2689  */
2690 void
2691 UDFFreeFileAllocation(
2692     IN PVCB Vcb,
2693     IN PUDF_FILE_INFO DirInfo,
2694     IN PUDF_FILE_INFO FileInfo
2695     )
2696 {
2697     if(FileInfo->Dloc->DataLoc.Offset) {
2698         // in-ICB data
2699         if(FileInfo->Dloc->DataLoc.Mapping) {
2700             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2701                    FileInfo->Dloc->DataLoc.Mapping[0].extLocation);
2702             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
2703             FileInfo->Dloc->DataLoc.Mapping[1].extLocation =
2704             FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0;
2705             FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0;
2706             FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2707         }
2708         if(FileInfo->Dloc->AllocLoc.Mapping) {
2709             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2710                    FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2711             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2712             FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2713             FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2714             FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2715             FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2716         }
2717         UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2718     } else {
2719         if(FileInfo->Dloc->AllocLoc.Mapping) {
2720             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2721                    FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2722             UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2723             FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2724             FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2725             FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2726             FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2727         }
2728         UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2729         UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
2730     }
2731     FileInfo->Dloc->DataLoc.Modified =
2732     FileInfo->Dloc->AllocLoc.Modified =
2733     FileInfo->Dloc->FELoc.Modified = FALSE;
2734 } // end UDFFreeFileAllocation()
2735 #endif //UDF_READ_ONLY_BUILD
2736 
2737 /*
2738     This routine packs physically sequential extents into single one
2739  */
2740 void
2741 __fastcall
2742 UDFPackMapping(
2743     IN PVCB Vcb,
2744     IN PEXTENT_INFO ExtInfo   // Extent array
2745     )
2746 {
2747     PEXTENT_MAP NewMap, OldMap;
2748     uint32 i, j, l;
2749     uint32 LastLba, LastType, OldLen;
2750     uint32 OldSize, NewSize;
2751 #ifdef UDF_DBG
2752     int64 check_size;
2753 #endif //UDF_DBG
2754 
2755     AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
2756     AdPrint(("  Length %x\n", ExtInfo->Length));
2757 
2758     OldMap = ExtInfo->Mapping;
2759     LastLba = OldMap[0].extLocation;
2760     OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2761     LastType = OldMap[0].extLength >> 30;
2762     OldSize =
2763     NewSize = UDFGetMappingLength(OldMap);
2764 #ifdef UDF_DBG
2765     check_size = UDFGetExtentLength(ExtInfo->Mapping);
2766     ASSERT(!(check_size & (2048-1)));
2767 #endif //UDF_DBG
2768 
2769     l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK;
2770     // calculate required length
2771     for(i=1; OldMap[i].extLength; i++) {
2772         if((LastType == (OldMap[i].extLength >> 30))
2773             &&
2774            ((OldMap[i].extLocation == LastLba + OldLen) ||
2775             (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
2776             &&
2777            (l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
2778             // we can pack two blocks in one
2779             l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2780             NewSize -= sizeof(EXTENT_MAP);
2781         } else {
2782             l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2783         }
2784         LastLba = OldMap[i].extLocation;
2785         LastType = OldMap[i].extLength >> 30;
2786         OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2787     }
2788     // no changes ?
2789     if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) {
2790         if(OldSize == NewSize)
2791             return;
2792         if(NewSize >= PACK_MAPPING_THRESHOLD)
2793             return;
2794     }
2795     AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping));
2796     NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize,
2797                                                        MEM_EXTMAP_TAG);
2798     // can't alloc ?
2799     if(!NewMap) return;
2800     // Ok, lets pack it...
2801     j=0;
2802     NewMap[0] = OldMap[0];
2803     LastLba = OldMap[0].extLocation;
2804     OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2805     LastType = OldMap[0].extLength >> 30;
2806     for(i=1; OldMap[i].extLength; i++) {
2807 
2808         ExtPrint(("oShExt: type %x, loc %x, len %x\n",
2809             OldMap[i].extLength >> 30, OldMap[i].extLocation, OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK));
2810 
2811         if((LastType == (OldMap[i].extLength >> 30))
2812             &&
2813            ((OldMap[i].extLocation == LastLba + OldLen) ||
2814             (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
2815             &&
2816            ((NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK) + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
2817             NewMap[j].extLength += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2818         } else {
2819             j++;
2820             NewMap[j] = OldMap[i];
2821         }
2822 
2823         ExtPrint(("nShExt: type %x, loc %x, len %x\n",
2824             NewMap[j].extLength >> 30, NewMap[j].extLocation, NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK));
2825 
2826         LastLba = OldMap[i].extLocation;
2827         LastType = OldMap[i].extLength >> 30;
2828         OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2829     }
2830     // write terminator
2831     j++;
2832     ASSERT(NewSize == (j+1)*sizeof(EXTENT_MAP));
2833     NewMap[j].extLength =
2834     NewMap[j].extLocation = 0;
2835 
2836 #ifdef UDF_DBG
2837     ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
2838     ASSERT(check_size == UDFGetExtentLength(NewMap));
2839 #endif
2840 
2841     AdPrint(("Pack ExtInfo %x, NewMap %x, OldMap %x\n", ExtInfo, NewMap, OldMap));
2842 
2843     ExtInfo->Mapping = NewMap;
2844     MyFreePool__(OldMap);
2845 
2846     AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
2847     AdPrint(("  Length %x\n", ExtInfo->Length));
2848 } // end UDFPackMapping()
2849 
2850 /*
2851     This routine expands mapping to 'frag-per-LBlock' state
2852  */
2853 OSSTATUS
2854 __fastcall
2855 UDFUnPackMapping(
2856     IN PVCB Vcb,
2857     IN PEXTENT_INFO ExtInfo   // Extent array
2858     )
2859 {
2860     PEXTENT_MAP NewMapping;
2861     PEXTENT_MAP Mapping = ExtInfo->Mapping;
2862     uint32 LBS = Vcb->LBlockSize;
2863     uint32 len = (uint32)(UDFGetExtentLength(Mapping) >> Vcb->LBlockSizeBits);
2864     uint32 i,j, type, base, d;
2865     LONG l;
2866 
2867     NewMapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
2868                                                        MEM_EXTMAP_TAG);
2869     if(!NewMapping) return STATUS_INSUFFICIENT_RESOURCES;
2870 
2871     j=0;
2872     d = LBS >> Vcb->BlockSizeBits;
2873     for(i=0; (l = (Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); i++) {
2874         base = Mapping[i].extLocation;
2875         type = Mapping[i].extLength & UDF_EXTENT_FLAG_MASK;
2876         for(; l>=(LONG)LBS; j++) {
2877             NewMapping[j].extLength = LBS | type;
2878             NewMapping[j].extLocation = base;
2879             base+=d;
2880             l-=LBS;
2881         }
2882     }
2883     // record terminator
2884     ASSERT(NewMapping);
2885     RtlZeroMemory(&(NewMapping[j]), sizeof(EXTENT_MAP));
2886     MyFreePool__(Mapping);
2887     ExtInfo->Mapping = NewMapping;
2888 
2889     return STATUS_SUCCESS;
2890 } // end UDFUnPackMapping()
2891 
2892 /*
2893     Relocate a part of extent that starts from relative (inside extent)
2894     block number 'ExtBlock' and has length of 'BC' blocks to continuous
2895     run which starts at block 'Lba'
2896  */
2897 OSSTATUS
2898 UDFRelocateExtent(
2899     IN PVCB Vcb,
2900     IN PEXTENT_INFO ExtInfo,
2901     IN uint32 ExtBlock,
2902     IN uint32 Lba,
2903     IN uint32 BC
2904     )
2905 {
2906     return STATUS_ACCESS_DENIED;
2907 }
2908 
2909 /*
2910     This routine checks if all the data required is in cache.
2911  */
2912 BOOLEAN
2913 UDFIsExtentCached(
2914     IN PVCB Vcb,
2915     IN PEXTENT_INFO ExtInfo,   // Extent array
2916     IN int64 Offset,      // offset in extent
2917     IN uint32 Length,
2918     IN BOOLEAN ForWrite
2919     )
2920 {
2921     BOOLEAN retstat = FALSE;
2922     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2923     uint32 to_read, Lba, sect_offs, flags, i;
2924 
2925     WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE/*FALSE*//*ForWrite*/);
2926     if(!ExtInfo || !ExtInfo->Mapping) goto EO_IsCached;
2927     if(!Length) {
2928         retstat = TRUE;
2929         goto EO_IsCached;
2930     }
2931 
2932     // prevent reading out of data space
2933     if(Offset > ExtInfo->Length) goto EO_IsCached;
2934     if(Offset+Length > ExtInfo->Length) goto EO_IsCached;
2935     Offset += ExtInfo->Offset;               // used for in-ICB data
2936     // read maximal possible part of each frag of extent
2937     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &i);
2938     while(((LONG)Length) > 0) {
2939         // EOF check
2940         if(Lba == LBA_OUT_OF_EXTENT) goto EO_IsCached;
2941         Extent += (i + 1);
2942         // check for reading tail
2943         to_read = min(to_read, Length);
2944         if(flags == EXTENT_RECORDED_ALLOCATED) {
2945             retstat = UDFIsDataCached(Vcb, Lba, (to_read+sect_offs+Vcb->BlockSize-1)>>Vcb->BlockSizeBits);
2946             if(!retstat) goto EO_IsCached;
2947         } else if(ForWrite) {
2948             goto EO_IsCached;
2949         }
2950         Offset += to_read;
2951         Length -= to_read;
2952         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &i);
2953     }
2954     retstat = TRUE;
2955 EO_IsCached:
2956     if(!retstat) {
2957         WCacheEODirect__(&(Vcb->FastCache), Vcb);
2958     }
2959     return retstat;
2960 } // end UDFIsExtentCached()
2961 
2962 /*
2963     This routine reads cached data only.
2964  */
2965 /*OSSTATUS
2966 UDFReadExtentCached(
2967     IN PVCB Vcb,
2968     IN PEXTENT_INFO ExtInfo,   // Extent array
2969     IN int64 Offset,      // offset in extent
2970     IN uint32 Length,
2971     OUT int8* Buffer,
2972     OUT uint32* ReadBytes
2973     )
2974 {
2975     (*ReadBytes) = 0;
2976     if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
2977 
2978     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2979     uint32 to_read, Lba, sect_offs, flags, _ReadBytes;
2980     OSSTATUS status;
2981     // prevent reading out of data space
2982     if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
2983     if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
2984     Offset += ExtInfo->Offset;               // used for in-ICB data
2985     // read maximal possible part of each frag of extent
2986     while(((LONG)Length) > 0) {
2987         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, NULL);
2988         // EOF check
2989         if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
2990         // check for reading tail
2991         to_read = (to_read < Length) ?
2992                    to_read : Length;
2993         if(flags == EXTENT_RECORDED_ALLOCATED) {
2994             status = UDFReadDataCached(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Buffer, &_ReadBytes);
2995             (*ReadBytes) += _ReadBytes;
2996         } else {
2997             RtlZeroMemory(Buffer, to_read);
2998             (*ReadBytes) += to_read;
2999             status = STATUS_SUCCESS;
3000         }
3001         if(!OS_SUCCESS(status)) return status;
3002         // prepare for reading next frag...
3003         Buffer += to_read;
3004         Offset += to_read;
3005         Length -= to_read;
3006     }
3007     return STATUS_SUCCESS;
3008 } // end UDFReadExtentCached()*/
3009 
3010 /*
3011     This routine reads data at any offset from specified extent.
3012  */
3013 OSSTATUS
3014 UDFReadExtent(
3015     IN PVCB Vcb,
3016     IN PEXTENT_INFO ExtInfo, // Extent array
3017     IN int64 Offset,      // offset in extent
3018     IN uint32 Length,
3019     IN BOOLEAN Direct,
3020     OUT int8* Buffer,
3021     OUT uint32* ReadBytes
3022     )
3023 {
3024     (*ReadBytes) = 0;
3025     if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
3026     ASSERT((uint32)Buffer > 0x1000);
3027 
3028     AdPrint(("Read ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3029 
3030     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3031     uint32 to_read, Lba, sect_offs, flags, _ReadBytes;
3032     OSSTATUS status;
3033     // prevent reading out of data space
3034     if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
3035     if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
3036     Offset += ExtInfo->Offset;               // used for in-ICB data
3037     // read maximal possible part of each frag of extent
3038     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &_ReadBytes);
3039     while(Length) {
3040         // EOF check
3041         if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
3042         Extent += (_ReadBytes + 1);
3043         // check for reading tail
3044         to_read = min(to_read, Length);
3045         if(flags == EXTENT_RECORDED_ALLOCATED) {
3046             status = UDFReadData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Direct, Buffer, &_ReadBytes);
3047             (*ReadBytes) += _ReadBytes;
3048             if(!OS_SUCCESS(status)) return status;
3049         } else {
3050             RtlZeroMemory(Buffer, to_read);
3051             (*ReadBytes) += to_read;
3052         }
3053         // prepare for reading next frag...
3054         Length -= to_read;
3055         if(!Length)
3056             break;
3057         ASSERT(to_read);
3058         Buffer += to_read;
3059 //        Offset += to_read;
3060         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &_ReadBytes);
3061         sect_offs = 0;
3062     }
3063     return STATUS_SUCCESS;
3064 } // end UDFReadExtent()
3065 
3066 /*
3067     This routine reads and builds mapping for
3068     specified amount of data at any offset from specified extent.
3069     Size of output buffer is limited by *_SubExtInfoSz
3070  */
3071 OSSTATUS
3072 UDFReadExtentLocation(
3073     IN PVCB Vcb,
3074     IN PEXTENT_INFO ExtInfo,      // Extent array
3075     IN int64 Offset,              // offset in extent to start SubExtent from
3076     OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array
3077  IN OUT uint32* _SubExtInfoSz,    // IN:  maximum number of fragments to get
3078                                   // OUT: actually obtained fragments
3079     OUT int64* _NextOffset        // offset, caller can start from to continue
3080     )
3081 {
3082     if(!ExtInfo || !ExtInfo->Mapping)
3083         return STATUS_INVALID_PARAMETER;
3084 
3085     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3086     PEXTENT_MAP SubExtInfo;
3087     uint32 to_read, Lba, sect_offs, flags, Skip_MapEntries;
3088     int32 SubExtInfoSz = *_SubExtInfoSz;
3089     int64 Length;
3090     int64 NextOffset;
3091 //    OSSTATUS status = STATUS_BUFFER_OVERFLOW;
3092 
3093     (*_SubExtInfo) = NULL;
3094     (*_SubExtInfoSz) = 0;
3095     NextOffset = Offset;
3096     // prevent reading out of data space
3097     if(Offset >= ExtInfo->Length)
3098         return STATUS_END_OF_FILE;
3099     Length = ExtInfo->Length - Offset;
3100     Offset += ExtInfo->Offset;               // used for in-ICB data
3101     // read maximal possible part of each frag of extent
3102     SubExtInfo = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , SubExtInfoSz*sizeof(EXTENT_MAP),
3103                                                        MEM_EXTMAP_TAG);
3104     (*_SubExtInfo) = SubExtInfo;
3105     if(!SubExtInfo)
3106         return STATUS_INSUFFICIENT_RESOURCES;
3107 
3108     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &Skip_MapEntries);
3109     while(Length && SubExtInfoSz) {
3110         // EOF check
3111         if(Lba == LBA_OUT_OF_EXTENT) {
3112             BrutePoint();
3113             return STATUS_END_OF_FILE;
3114         }
3115         Extent += (Skip_MapEntries + 1);
3116         // check for reading tail
3117         to_read = (int32)min((int64)to_read, Length);
3118         SubExtInfo->extLength   = to_read;
3119         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3120             SubExtInfo->extLocation = LBA_NOT_ALLOCATED;
3121         } else
3122         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3123             ASSERT(!(Lba & 0x80000000));
3124             SubExtInfo->extLocation = Lba | 0x80000000;
3125         } else {
3126             SubExtInfo->extLocation = Lba;
3127         }
3128         (*_SubExtInfoSz)++;
3129         SubExtInfoSz--;
3130         NextOffset += to_read;
3131         // prepare for reading next frag...
3132         Length -= to_read;
3133         if(!Length) {
3134 //            status = STATUS_SUCCESS;
3135             break;
3136         }
3137         ASSERT(to_read);
3138         Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &Skip_MapEntries);
3139         sect_offs = 0;
3140     }
3141     (*_NextOffset) = NextOffset;
3142     return STATUS_SUCCESS;
3143 } // end UDFReadExtentLocation()
3144 
3145 #ifdef _MSC_VER
3146 #pragma warning(push)
3147 #pragma warning(disable:4035)               // re-enable below
3148 #endif
3149 
3150 uint32
3151 UDFGetZeroLength(
3152     IN int8* Buffer,
3153     IN uint32 Length
3154     )
3155 {
3156     uint32 i;
3157     Length /= sizeof(uint32);
3158     for(i=0; i<Length; i++) {
3159         if( ((uint32*)Buffer)[i] )
3160             break;
3161     }
3162     return Length*sizeof(uint32);
3163 }
3164 
3165 #ifdef _MSC_VER
3166 #pragma warning(pop) // re-enable warning #4035
3167 #endif
3168 
3169 #ifndef UDF_READ_ONLY_BUILD
3170 /*
3171     This routine writes data at any offset to specified extent.
3172  */
3173 OSSTATUS
3174 UDFWriteExtent(
3175     IN PVCB Vcb,
3176     IN PEXTENT_INFO ExtInfo,   // Extent array
3177     IN int64 Offset,        // offset in extent
3178     IN uint32 Length,
3179     IN BOOLEAN Direct,         // setting this flag delays flushing of given
3180                                // data to indefinite term
3181     IN int8* Buffer,
3182     OUT uint32* WrittenBytes
3183     )
3184 {
3185     if(!ExtInfo || !ExtInfo->Mapping)
3186         return STATUS_INVALID_PARAMETER;
3187 
3188     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3189     uint32 to_write, Lba, sect_offs, flags;
3190     OSSTATUS status;
3191     uint32 _WrittenBytes;
3192     BOOLEAN reread_lba;
3193 //    BOOLEAN already_prepared = FALSE;
3194 //    BOOLEAN prepare = !Buffer;
3195 
3196     AdPrint(("Write ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3197 
3198     Offset += ExtInfo->Offset;               // used for in-ICB data
3199     // write maximal possible part of each frag of extent
3200     while(((LONG)Length) > 0) {
3201         UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3202         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3203         // EOF check
3204         if(Lba == LBA_OUT_OF_EXTENT) {
3205             return STATUS_END_OF_FILE;
3206         }
3207 /*        if((to_write < Length) &&
3208            !Direct && !prepare && !already_prepared) {
3209             // rebuild mapping, allocate space, etc.
3210             // to indicate this, set Buffer to NULL
3211             AdPrint(("UDFWriteExtent: Prepare\n"));
3212             BrutePoint();
3213             _WrittenBytes = 0;
3214             status = UDFWriteExtent(Vcb, ExtInfo, Offset, Length, *//*Direct*//*FALSE, NULL, &_WrittenBytes);
3215             if(!OS_SUCCESS(status)) {
3216                 return status;
3217             }
3218             Extent = ExtInfo->Mapping;
3219             Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3220             already_prepared = TRUE;
3221         }*/
3222         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3223             // here we should allocate space for this extent
3224             if(!OS_SUCCESS(status = UDFMarkNotAllocatedAsAllocated(Vcb, Offset, to_write, ExtInfo)))
3225                 return status;
3226             Extent = ExtInfo->Mapping;
3227             UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3228             Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3229             if(Lba == LBA_OUT_OF_EXTENT) {
3230                 return STATUS_END_OF_FILE;
3231             }
3232             // we have already re-read Lba
3233             reread_lba = FALSE;
3234         } else {
3235             // we may need to re-read Lba if some changes are
3236             // made while converting from Alloc-Not-Rec
3237             reread_lba = TRUE;
3238         }
3239         // check if writing to not recorded allocated
3240         // in this case we must pad blocks with zeros around
3241         // modified area
3242         //
3243         // ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|...
3244         //        .                .
3245         //        .     ||         .
3246         //        .     \/         .
3247         //        .                .
3248         // ...|000ddddd|dddddddd|dd000000|...
3249         //        .                .
3250         //        ^                ^
3251         //        sect_offs        sect_offs+to_write
3252         //        .                .
3253         //        .<-- to_write -->.
3254         //
3255         to_write = min(to_write, Length);
3256         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3257             if(!OS_SUCCESS(status = UDFMarkAllocatedAsRecorded(Vcb, Offset, to_write, ExtInfo)))
3258                 return status;
3259             Extent = ExtInfo->Mapping;
3260             UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
3261             if(reread_lba) {
3262                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3263                 to_write = min(to_write, Length);
3264             }
3265             /*
3266               we must fill 1st block with zeros in 1 of 2 cases:
3267                 1) start offset is not aligned on LBlock boundary
3268                       OR
3269                 2) end offset is not aligned on LBlock boundary and lays in
3270                    the same LBlock
3271 
3272               we must fill last block with zeros if both
3273                 1) end offset is not aligned on LBlock boundary
3274                       AND
3275                 2) end offset DOESN'T lay in the 1st LBlock
3276             */
3277 
3278 //            if(!prepare) {
3279                 // pad 1st logical block
3280             if((sect_offs || (sect_offs + to_write < Vcb->LBlockSize) )
3281                                 &&
3282                            !Vcb->CDR_Mode) {
3283                 status = UDFWriteData(Vcb, TRUE,
3284                                       ( ((uint64)Lba) << Vcb->BlockSizeBits),
3285                                       Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
3286                 if(!OS_SUCCESS(status))
3287                     return status;
3288             }
3289             // pad last logical block
3290             if((sect_offs + to_write > Vcb->LBlockSize) &&
3291                (sect_offs + to_write) & (Vcb->LBlockSize - 1)) {
3292                 status = UDFWriteData(Vcb, TRUE,
3293                                       (( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs + to_write) & ~((int64)(Vcb->LBlockSize)-1),
3294                                       Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
3295             }
3296             if(!OS_SUCCESS(status))
3297                 return status;
3298 /*            } else {
3299                 status = STATUS_SUCCESS;
3300             }*/
3301         }
3302         ASSERT(to_write);
3303 //        if(!prepare) {
3304         status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, Direct, Buffer, &_WrittenBytes);
3305         *WrittenBytes += _WrittenBytes;
3306         if(!OS_SUCCESS(status)) return status;
3307 /*        } else {
3308             status = STATUS_SUCCESS;
3309             *WrittenBytes += to_write;
3310         }*/
3311         // prepare for writing next frag...
3312         Buffer += to_write;
3313         Offset += to_write;
3314         Length -= to_write;
3315     }
3316     AdPrint(("Write: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3317     return STATUS_SUCCESS;
3318 } // end UDFWriteExtent()
3319 
3320 //#if 0
3321 /*
3322     This routine zeroes/deallocates data at any offset to specified extent.
3323  */
3324 OSSTATUS
3325 UDFZeroExtent(
3326     IN PVCB Vcb,
3327     IN PEXTENT_INFO ExtInfo,   // Extent array
3328     IN int64 Offset,           // offset in extent
3329     IN uint32 Length,
3330     IN BOOLEAN Deallocate,     // deallocate frag or just mark as unrecorded
3331     IN BOOLEAN Direct,         // setting this flag delays flushing of given
3332                                // data to indefinite term
3333     OUT uint32* WrittenBytes
3334     )
3335 {
3336     if(!ExtInfo || !ExtInfo->Mapping)
3337         return STATUS_INVALID_PARAMETER;
3338 
3339     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
3340     uint32 to_write, Lba, sect_offs, flags;
3341     OSSTATUS status;
3342     uint32 _WrittenBytes;
3343     uint32 LBS = Vcb->LBlockSize;
3344 
3345     AdPrint(("Zero ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3346 
3347     Offset += ExtInfo->Offset;               // used for in-ICB data
3348     // fill/deallocate maximal possible part of each frag of extent
3349     while(((LONG)Length) > 0) {
3350         Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3351         // EOF check
3352         if(Lba == LBA_OUT_OF_EXTENT) {
3353             return STATUS_END_OF_FILE;
3354         }
3355         // check for writing tail
3356         to_write = min(to_write, Length);
3357 
3358         if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
3359             // here we should do nothing
3360             *WrittenBytes += to_write;
3361         } else
3362         if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
3363             // we should just deallocate this frag
3364             if(Deallocate) {
3365                 if(!OS_SUCCESS(status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, to_write, ExtInfo)))
3366                     return status;
3367             }
3368             Extent = ExtInfo->Mapping;
3369             *WrittenBytes += to_write;
3370         } else {
3371             // fill tail of the 1st Block with ZEROs
3372             if(sect_offs) {
3373                 status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs,
3374                                       min(to_write, LBS-sect_offs),
3375                                       Direct, Vcb->ZBuffer, &_WrittenBytes);
3376                 *WrittenBytes += _WrittenBytes;
3377                 if(!OS_SUCCESS(status))
3378                     return status;
3379                 Offset += _WrittenBytes;
3380                 Length -= _WrittenBytes;
3381                 to_write -= _WrittenBytes;
3382                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3383                 ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
3384                 ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
3385                 ASSERT(!sect_offs);
3386             }
3387             // deallocate Blocks
3388             if(to_write >= LBS) {
3389                 // use 'sect_offs' as length of extent to be deallocated
3390                 sect_offs = to_write & ~(LBS - 1);
3391                 if(Deallocate) {
3392                     status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, sect_offs, ExtInfo);
3393                 } else {
3394                     status = UDFMarkRecordedAsAllocated(Vcb, Offset, sect_offs, ExtInfo);
3395                 }
3396                 if(!OS_SUCCESS(status))
3397                     return status;
3398                 // reload extent mapping
3399                 Extent = ExtInfo->Mapping;
3400                 Offset += sect_offs;
3401                 Length -= sect_offs;
3402                 *WrittenBytes += sect_offs;
3403                 to_write -= sect_offs;
3404                 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
3405                 ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
3406                 ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
3407                 ASSERT(!sect_offs);
3408             }
3409             // fill beginning of the last Block with ZEROs
3410             if(to_write) {
3411                 status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), to_write, Direct, Vcb->ZBuffer, &_WrittenBytes);
3412                 *WrittenBytes += _WrittenBytes;
3413                 if(!OS_SUCCESS(status))
3414                     return status;
3415                 ASSERT(to_write == _WrittenBytes);
3416             }
3417         }
3418         AdPrint(("Zero... ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3419         // prepare for filling next frag...
3420         Offset += to_write;
3421         Length -= to_write;
3422     }
3423     AdPrint(("Zero: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
3424     return STATUS_SUCCESS;
3425 } // end UDFZeroExtent()
3426 //#endif //0
3427 #endif //UDF_READ_ONLY_BUILD
3428