[HTTPAPI] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / reactos / drivers / filesystems / udfs / udf_info / extent.cpp
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)
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)
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 KdPrint(("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 KdPrint(("Integrity check failed\n"));
374 KdPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
375 KdPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
376 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("Integrity check failed\n"));
534 KdPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
535 KdPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
536 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 // KdPrint(("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 // KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint((" 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 KdPrint((" used @ %x\n", Mapping->extLocation));
1345 Mapping->extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
1346 Mapping->extLocation = 0;
1347 } else {
1348 KdPrint((" 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 KdPrint(("AllocationCache FE:\n"));
1377 pAllocCache = &(Vcb->FEChargeCache);
1378 plim = &(Vcb->FEChargeCacheMaxSize);
1379 lim = 32;
1380 break;
1381 case UDF_PREALLOC_CLASS_DIR:
1382 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 KdPrint(("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 ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
1864 AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
1865 return STATUS_SUCCESS;
1866 }
1867 if(Extent[i].extLocation < lba) {
1868 if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (lba - Extent[i].extLocation))
1869 > sLen ) {
1870 // xxxxxx -> xxRRxx
1871 NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP)*2,
1872 MEM_EXTMAP_TAG);
1873 if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1874 Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1875 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1876 RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1877 NewExtent[i].extLocation = Extent[i].extLocation;
1878 NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
1879 NewExtent[i+1].extLength = (Length+BS-1) & ~(BS-1);
1880 NewExtent[i+1].extLocation = lba;
1881 NewExtent[i+2].extLength = Extent[i].extLength - NewExtent[i].extLength - NewExtent[i+1].extLength;
1882 NewExtent[i+2].extLocation = lba + ((Length+BS-1) >> BSh);
1883 ASSERT(!(NewExtent[i].extLength >> 30));
1884 ASSERT(!(NewExtent[i+2].extLength >> 30));
1885 NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1886 NewExtent[i+2].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1887 TryPack = FALSE;
1888 AdPrint(("Alloc->Rec (2) new %x\n", NewExtent));
1889 } else {
1890 // xxxxxx -> xxRRRR
1891 NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
1892 MEM_EXTMAP_TAG);
1893 if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1894 Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1895 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1896 RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1897 NewExtent[i].extLocation = Extent[i].extLocation;
1898 NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
1899 NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
1900 NewExtent[i+1].extLocation = lba;
1901 ASSERT(!(NewExtent[i].extLength >> 30));
1902 NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1903 AdPrint(("Alloc->Rec (3) new %x\n", NewExtent));
1904 }
1905 } else {
1906 // xxxxxx -> RRRRxx
1907 NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
1908 MEM_EXTMAP_TAG);
1909 if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
1910 Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
1911 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
1912 RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
1913 NewExtent[i].extLocation = Extent[i].extLocation;
1914 NewExtent[i].extLength = (Length+BS-1) & ~(BS-1);
1915 NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
1916 NewExtent[i+1].extLocation = Extent[i].extLocation + (NewExtent[i].extLength >> BSh);
1917 ASSERT(!(NewExtent[i+1].extLength >> 30));
1918 NewExtent[i+1].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
1919 AdPrint(("Alloc->Rec (4) new %x\n", NewExtent));
1920 }
1921
1922 //ASSERT(check_size == UDFGetExtentLength(Extent));
1923 //ASSERT(!(check_size & (LBS-1)));
1924
1925 AdPrint(("Free Extent %x (new %x)\n", Extent, NewExtent));
1926 MyFreePool__(Extent);
1927 ExtInfo->Modified = TRUE;
1928 ExtInfo->Mapping = NewExtent;
1929 if(TryPack)
1930 UDFPackMapping(Vcb, ExtInfo);
1931 ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
1932 ASSERT(!(check_size & (LBS-1)));
1933
1934 AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
1935
1936 return STATUS_SUCCESS;
1937 } // end UDFMarkAllocatedAsRecorded()
1938
1939 /*
1940 This routine rebuilds mapping on write attempts to Not-Alloc-Not-Rec area.
1941 Here we assume that required area lays in a single frag.
1942 */
1943 OSSTATUS
1944 UDFMarkNotAllocatedAsAllocated(
1945 IN PVCB Vcb,
1946 IN int64 Offset,
1947 IN uint32 Length,
1948 IN PEXTENT_INFO ExtInfo // Extent array
1949 )
1950 {
1951 uint32 i, len, /*lba,*/ d, l, BOffs, j;
1952 PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
1953 PEXTENT_MAP NewExtent;
1954 // uint32 BS = Vcb->BlockSize;
1955 uint32 BSh = Vcb->BlockSizeBits;
1956 OSSTATUS status;
1957 EXTENT_INFO TmpExtInf;
1958 uint32 aLen, sLen;
1959 uint32 LBS = Vcb->LBlockSize;
1960 // I don't know what else comment can be added here.
1961 // Just belive that it works
1962 /*lba = */
1963 #ifndef ALLOW_SPARSE
1964 BrutePoint();
1965 #endif
1966 AdPrint(("Not->Alloc ExtInfo %x, Extent %x\n", ExtInfo, Extent));
1967 UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
1968 if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER;
1969 if((Extent[i].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_SUCCESS;
1970
1971 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
1972 BOffs = (uint32)(Offset >> BSh);
1973 // length of existing Not-Alloc-Not-Rec frag
1974 sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
1975 // required allocation length increment (in bytes)
1976 aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)));
1977
1978 // try to extend previous frag or allocate space _after_ it to
1979 // avoid backward seeks, if previous frag is not Not-Rec-Not-Alloc
1980 if(i && ((Extent[i-1].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) ) {
1981 status = UDFAllocFreeExtent(Vcb, aLen,
1982 Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh),
1983 min(UDFPartEnd(Vcb, PartNum), Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) + sLen ),
1984 &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
1985 if(status == STATUS_DISK_FULL)
1986 // if there are not enough free blocks after that frag...
1987 goto try_alloc_anywhere;
1988 } else {
1989 try_alloc_anywhere:
1990 // ... try to alloc required disk space anywhere
1991 status = UDFAllocFreeExtent(Vcb, aLen,
1992 UDFPartStart(Vcb, PartNum),
1993 UDFPartEnd(Vcb, PartNum),
1994 &TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
1995 }
1996 // check for successfull allocation
1997 if(!OS_SUCCESS(status)) {
1998 AdPrint(("Not->Alloc no free\n"));
1999 return status;
2000 }
2001 // get number of frags in allocated block
2002 d = (UDFGetMappingLength(TmpExtInf.Mapping) / sizeof(EXTENT_MAP)) - 1;
2003 // calculate number of existing blocks before the frag to be changed
2004 l=0;
2005 for(j=0; j<i; j++) {
2006 l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2007 }
2008 // and now just update mapping...
2009 if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
2010 // xxxxxx -> RRRRRR
2011 // (d-1) - since we have to raplace last frag of Extent with 1 or more frags of TmpExtInf.Mapping
2012 NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d-1)*sizeof(EXTENT_MAP) );
2013 if(!NewExtent) {
2014 MyFreePool__(TmpExtInf.Mapping);
2015 return STATUS_INSUFFICIENT_RESOURCES;
2016 }
2017 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2018 RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2019 RtlCopyMemory((int8*)&(NewExtent[i+d]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2020 AdPrint(("Not->Alloc (1) new %x\n", NewExtent));
2021 } else
2022 if(l < BOffs) {
2023 // .ExtLength, BOffs & l are already aligned...
2024 if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
2025 // xxxxxx -> xxRRxx
2026 NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d+1)*sizeof(EXTENT_MAP) );
2027 if(!NewExtent) {
2028 MyFreePool__(TmpExtInf.Mapping);
2029 return STATUS_INSUFFICIENT_RESOURCES;
2030 }
2031 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2032 RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2033 RtlCopyMemory((int8*)&(NewExtent[i+d+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2034 NewExtent[i].extLocation = 0;
2035 NewExtent[i].extLength = (BOffs - l) << BSh;
2036 NewExtent[i+d+1].extLength = Extent[i].extLength - NewExtent[i].extLength - aLen;
2037 NewExtent[i+d+1].extLocation = 0;
2038 NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2039 NewExtent[i+d+1].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2040 AdPrint(("Not->Alloc (2) new %x\n", NewExtent));
2041 } else {
2042 // xxxxxx -> xxRRRR
2043 NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
2044 if(!NewExtent) {
2045 MyFreePool__(TmpExtInf.Mapping);
2046 return STATUS_INSUFFICIENT_RESOURCES;
2047 }
2048 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2049 RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2050 RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2051 NewExtent[i].extLocation = 0;
2052 NewExtent[i].extLength = (BOffs - l) << BSh;
2053 NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2054 AdPrint(("Not->Alloc (3) new %x\n", NewExtent));
2055 }
2056 } else {
2057 // xxxxxx -> RRRRxx
2058 NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
2059 if(!NewExtent) {
2060 MyFreePool__(TmpExtInf.Mapping);
2061 return STATUS_INSUFFICIENT_RESOURCES;
2062 }
2063 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2064 RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
2065 RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2066 NewExtent[i+d].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
2067 NewExtent[i+d].extLocation = 0;
2068 NewExtent[i+d].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2069 AdPrint(("Not->Alloc (4) new %x\n", NewExtent));
2070 }
2071
2072 AdPrint(("Free Extent %x, TmpExtInf.Mapping, (new %x)\n", Extent, TmpExtInf.Mapping, NewExtent));
2073 MyFreePool__(Extent);
2074 MyFreePool__(TmpExtInf.Mapping);
2075 ExtInfo->Modified = TRUE;
2076 ExtInfo->Mapping = NewExtent;
2077
2078 AdPrint(("Not->Alloc: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
2079
2080 return STATUS_SUCCESS;
2081 } // end UDFMarkNotAllocatedAsAllocated()
2082
2083 //#if 0
2084 /*
2085 This routine rebuilds mapping on write zero attempts to
2086 Alloc-Not-Rec area.
2087 Here we assume that required area lays in a single frag.
2088 */
2089 OSSTATUS
2090 UDFMarkAllocatedAsNotXXX(
2091 IN PVCB Vcb,
2092 IN int64 Offset,
2093 IN uint32 Length,
2094 IN PEXTENT_INFO ExtInfo, // Extent array
2095 IN BOOLEAN Deallocate
2096 )
2097 {
2098 uint32 i, len, /*lba, d,*/ l, BOffs, j;
2099 PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
2100 PEXTENT_MAP NewExtent;
2101 // EXTENT_MAP TmpExtent;
2102 // uint32 BS = Vcb->BlockSize;
2103 uint32 BSh = Vcb->BlockSizeBits;
2104 // OSSTATUS status;
2105 EXTENT_INFO TmpExtInf;
2106 uint32 aLen, sLen;
2107 uint32 flags;
2108 uint32 target_flags = Deallocate ?
2109 EXTENT_NOT_RECORDED_NOT_ALLOCATED :
2110 EXTENT_NOT_RECORDED_ALLOCATED;
2111 uint32 LBS = Vcb->LBlockSize;
2112 EXTENT_MAP DeadMapping[2];
2113 // I don't know what else comment can be added here.
2114 // Just belive that it works
2115 /*lba = */
2116 #ifndef ALLOW_SPARSE
2117 if(Deallocate) {
2118 BrutePoint();
2119 }
2120 #endif
2121
2122 AdPrint(("Alloc->Not ExtInfo %x, Extent %x\n", ExtInfo, Extent));
2123
2124 DeadMapping[0].extLocation =
2125 UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
2126 if(i == (ULONG)-1) {
2127 BrutePoint();
2128 return STATUS_INVALID_PARAMETER;
2129 }
2130 DeadMapping[0].extLength = Extent[i].extLength;
2131 DeadMapping[1].extLocation =
2132 DeadMapping[1].extLength = 0;
2133 TmpExtInf.Mapping = (PEXTENT_MAP)&DeadMapping;
2134 TmpExtInf.Offset = 0;
2135 TmpExtInf.Length = Extent[i].extLength & UDF_EXTENT_LENGTH_MASK;
2136
2137 flags = Extent[i].extLength >> 30;
2138 if(flags == target_flags) return STATUS_SUCCESS;
2139
2140 // uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
2141 BOffs = (uint32)(Offset >> BSh);
2142 // length of existing Alloc-(Not-)Rec frag (in sectors)
2143 sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
2144 // required deallocation length increment (in bytes)
2145 aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)) );
2146
2147 l=0;
2148 for(j=0; j<i; j++) {
2149 l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2150 }
2151 flags <<= 30;
2152 if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
2153 // xxxxxx -> RRRRRR
2154 Extent[i].extLocation = 0;
2155 Extent[i].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) | flags;
2156 NewExtent = Extent;
2157 AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent));
2158 } else
2159 if(l < BOffs) {
2160 // .ExtLength, BOffs & l are already aligned...
2161 if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
2162 // xxxxxx -> xxRRxx
2163 NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) );
2164 if(!NewExtent) {
2165 return STATUS_INSUFFICIENT_RESOURCES;
2166 }
2167 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2168 RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2169 NewExtent[i].extLength = (BOffs - l) << BSh;
2170 NewExtent[i].extLength |= flags;
2171 NewExtent[i+1].extLocation = 0;
2172 NewExtent[i+1].extLength = aLen | (target_flags << 30);
2173 NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) -
2174 (NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ;
2175 NewExtent[i+2].extLocation = Extent[i].extLocation +
2176 (NewExtent[i+2].extLength >> BSh);
2177 NewExtent[i+2].extLength |= flags;
2178 AdPrint(("Alloc->Not (2) new %x\n", NewExtent));
2179 } else {
2180 // xxxxxx -> xxRRRR
2181 NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2182 if(!NewExtent) {
2183 return STATUS_INSUFFICIENT_RESOURCES;
2184 }
2185 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2186 RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2187 NewExtent[i].extLength = ((BOffs - l) << BSh) | flags;
2188 NewExtent[i+1].extLocation = 0;
2189 NewExtent[i+1].extLength = aLen | (target_flags << 30);
2190 AdPrint(("Alloc->Not (3) new %x\n", NewExtent));
2191 }
2192 } else {
2193 // xxxxxx -> RRRRxx
2194 NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
2195 if(!NewExtent) {
2196 return STATUS_INSUFFICIENT_RESOURCES;
2197 }
2198 RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
2199 RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
2200 NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
2201 NewExtent[i+1].extLength |= flags;
2202 NewExtent[i].extLocation = 0;
2203 NewExtent[i].extLength = aLen | (target_flags << 30);
2204 AdPrint(("Alloc->Not (4) new %x\n", NewExtent));
2205 }
2206
2207 if(Deallocate)
2208 UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free
2209
2210 if(Extent) {
2211 AdPrint(("Alloc->Not kill %x\n", Extent));
2212 MyFreePool__(Extent);
2213 } else {
2214 AdPrint(("Alloc->Not keep %x\n", Extent));
2215 }
2216 ExtInfo->Modified = TRUE;
2217 ExtInfo->Mapping = NewExtent;
2218 AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
2219
2220 return STATUS_SUCCESS;
2221 } // end UDFMarkAllocatedAsNotXXX()
2222 //#endif //0
2223
2224 /*
2225 This routine resizes extent & updates associated mapping
2226 */
2227 OSSTATUS
2228 UDFResizeExtent(
2229 IN PVCB Vcb,
2230 IN uint32 PartNum,
2231 IN int64 Length, // Required Length
2232 IN BOOLEAN AlwaysInIcb, // must be TRUE for AllocDescs
2233 OUT PEXTENT_INFO ExtInfo
2234 )
2235 {
2236 uint32 i, flags, lba, lim;
2237 int64 l;
2238 OSSTATUS status;
2239 EXTENT_INFO TmpExtInf;
2240 EXTENT_MAP TmpMapping[2];
2241 uint32 s, req_s, pe, BSh, LBS, PS;
2242 LBS = Vcb->LBlockSize;
2243 BSh = Vcb->BlockSizeBits;
2244 PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
2245 uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1));
2246 BOOLEAN Sequential = FALSE;
2247
2248 ASSERT(PartNum < 3);
2249
2250 ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length));
2251
2252 if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) {
2253 AdPrint((" cut preallocated\n"));
2254 } else
2255 if(ExtInfo->Length == Length) {
2256 return STATUS_SUCCESS;
2257 }
2258 if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2259 MaxGrow &= ~(Vcb->WriteBlockSize-1);
2260 Sequential = TRUE;
2261 }
2262
2263 UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2264 if(ExtInfo->Offset) {
2265 if(ExtInfo->Offset + Length <= LBS) {
2266 ExtPrint(("Resize IN-ICB\n"));
2267 ExtInfo->Length = Length;
2268 return STATUS_SUCCESS;
2269 }
2270 if(!AlwaysInIcb) // simulate unused 1st sector in extent
2271 ExtInfo->Offset = LBS; // it'll be truncated later
2272 Length += ExtInfo->Offset; // convert to real offset in extent
2273 }
2274 lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i);
2275 if(ExtInfo->Length < Length) {
2276 // increase extent
2277 if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2278 &TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) {
2279 AdPrint(("Resize found cached(1)\n"));
2280 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2281 MyFreePool__(TmpExtInf.Mapping);
2282 }
2283 if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) {
2284 // we have enough space inside extent
2285 ExtInfo->Length = Length;
2286 AdPrint(("Resize do nothing (1)\n"));
2287 } else /*if(lba == LBA_OUT_OF_EXTENT)*/ {
2288
2289 Length -= ExtInfo->Offset;
2290 if(/*Length && l &&*/ (l % MaxGrow) &&
2291 (Length-1)/MaxGrow != (l-1)/MaxGrow) {
2292 AdPrint(("Crossing MAX_FRAG boundary...\n"));
2293 int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow;
2294 status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo);
2295 if(!OS_SUCCESS(status)) {
2296 KdPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status));
2297 return status;
2298 }
2299 l = ExtInfo->Length;
2300 ASSERT(l == l2);
2301 }
2302 while((Length - l) > MaxGrow) {
2303 status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2304 if(!OS_SUCCESS(status)) {
2305 KdPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status));
2306 return status;
2307 }
2308 l = ExtInfo->Length;
2309 }
2310 Length += ExtInfo->Offset;
2311 // at first, try to resize existing frag
2312 #ifndef UDF_ALLOW_FRAG_AD
2313 i = UDFGetMappingLength(ExtInfo->Mapping);
2314 if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) {
2315 // this is very important check since we will not
2316 // be able to _record_ too long AllocDesc because of
2317 // some DEMO limitations in UDFBuildXXXAllocDescs()
2318 AdPrint((" DISK_FULL\n"));
2319 return STATUS_DISK_FULL;
2320 }
2321 i /= sizeof(EXTENT_MAP);
2322 #else //UDF_ALLOW_FRAG_AD
2323 i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP);
2324 #endif //UDF_ALLOW_FRAG_AD
2325 #ifdef ALLOW_SPARSE
2326 if(!AlwaysInIcb && !(ExtInfo->Offset) &&
2327 (Length - l >= (Vcb->SparseThreshold << BSh))) {
2328 // last frag will be Not-Alloc-Not-Rec...
2329 AdPrint(("Resize sparse (2)\n"));
2330 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2331 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2,
2332 MEM_EXTMAP_TAG);
2333 if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES;
2334 TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2335 TmpExtInf.Mapping[0].extLocation =// 0;
2336 TmpExtInf.Mapping[1].extLength =
2337 TmpExtInf.Mapping[1].extLocation = 0;
2338 l = Length;
2339 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2340 MyFreePool__(TmpExtInf.Mapping);
2341 } else
2342 #endif //ALLOW_SPARSE
2343 // allocate some sectors
2344 if(i>1 && !(ExtInfo->Offset)) {
2345 i-=2;
2346 // check if Not-Alloc-Not-Rec at the end of mapping
2347 if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) {
2348 // do nothing, but jump directly to allocator
2349 } else
2350 if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
2351 AdPrint(("Resize grow sparse (3)\n"));
2352 ExtInfo->Mapping[i].extLength +=
2353 (((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ;
2354 l = Length;
2355 // check if Alloc-Not-Rec at the end of mapping
2356 } else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) {
2357 AdPrint(("Resize grow Not-Rec (3)\n"));
2358 // current length of last frag
2359 s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2360 // prefered location of the next frag
2361 lba = ExtInfo->Mapping[i].extLocation + s;
2362 pe=UDFPartEnd(Vcb,PartNum);
2363 // maximum frag length
2364 if(Sequential) {
2365 lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2366 } else {
2367 lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2368 }
2369 // required last extent length
2370 req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2371 ((l + LBS - 1) & ~(LBS-1)) ) >> BSh);
2372 if(lim > req_s) {
2373 lim = req_s;
2374 }
2375 UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2376 /* if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) &&
2377 ((Length & ~(PS-1)) > (l & ~(PS-1))) &&
2378 TRUE) {
2379 status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
2380 }*/
2381 // how many sectors we should add
2382 req_s = lim - s;
2383 ASSERT(req_s);
2384 if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2385 s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1));
2386 }
2387 /* for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2388 s++;
2389 }*/
2390 if(s==lim) {
2391 // we can just increase the last frag
2392 AdPrint(("Resize grow last Not-Rec (4)\n"));
2393 ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2394 l = Length;
2395 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2396 } else {
2397 // we get here if simple increasing of last frag failed
2398 // it worth truncating last frag and try to allocate
2399 // all required data as a single frag
2400
2401 /* if(Sequential && s>=PS) {
2402 s &= ~(PS-1);
2403 AdPrint(("Resize grow last Not-Rec (4/2)\n"));
2404 ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
2405 l += (s << BSh);
2406 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
2407 }*/
2408 AdPrint(("Resize reloc last Not-Rec (5)\n"));
2409 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP),
2410 MEM_EXTMAP_TAG);
2411 if(!TmpExtInf.Mapping) {
2412 KdPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n"));
2413 UDFReleaseResource(&(Vcb->BitMapResource1));
2414 return STATUS_INSUFFICIENT_RESOURCES;
2415 }
2416 RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP));
2417 TmpExtInf.Mapping[i].extLength =
2418 TmpExtInf.Mapping[i].extLocation = 0;
2419 TmpExtInf.Offset = ExtInfo->Offset;
2420 l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2421 TmpExtInf.Length = l;
2422 ASSERT(i || !ExtInfo->Offset);
2423 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2424 MyFreePool__(ExtInfo->Mapping);
2425 (*ExtInfo) = TmpExtInf;
2426 }
2427 UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2428 UDFReleaseResource(&(Vcb->BitMapResource1));
2429 // check if Alloc-Rec
2430 } else {
2431 // current length of last frag
2432 s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
2433 // prefered location of the next frag
2434 lba = ExtInfo->Mapping[i].extLocation + s;
2435 pe=UDFPartEnd(Vcb,PartNum);
2436 // maximum frag length
2437 if(Sequential) {
2438 lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
2439 } else {
2440 lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
2441 }
2442 // required last extent length
2443 req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
2444 ((l + LBS - 1) & ~(LBS-1)) ) >> BSh);
2445 if(lim > req_s) {
2446 lim = req_s;
2447 }
2448 // s=0;
2449 // how many sectors we should add
2450 req_s = lim - s;
2451 if(req_s) {
2452 uint32 d=0;
2453
2454 UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
2455 //ASSERT(req_s);
2456 if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
2457 s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)));
2458 }
2459 /* for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
2460 s++;
2461 }*/
2462
2463 if(s==lim) {
2464 AdPrint(("Resize grow last Rec (6)\n"));
2465 // we can just increase last frag
2466 TmpMapping[0].extLength = req_s << BSh;
2467 TmpMapping[0].extLocation = lba;
2468 TmpMapping[1].extLength =
2469 TmpMapping[1].extLocation = 0;
2470 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2471 l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2472 ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2473 } else if(d) {
2474 AdPrint(("Resize part-grow last Rec (6)\n"));
2475 // increase last frag, then alloc rest
2476 TmpMapping[0].extLength = d << BSh;
2477 TmpMapping[0].extLocation = lba;
2478 TmpMapping[1].extLength =
2479 TmpMapping[1].extLocation = 0;
2480 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
2481 l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
2482 ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
2483 } else {
2484 AdPrint(("Can't grow last Rec (6)\n"));
2485 }
2486 UDFReleaseResource(&(Vcb->BitMapResource1));
2487 } else {
2488 AdPrint(("Max frag length reached (6)\n"));
2489 }
2490 }
2491 }
2492 if(l < Length) {
2493 // we get here if simple increasing of the last frag failed
2494 AdPrint(("Resize add new frag (7)\n"));
2495 if(l < LBS && Length >= LBS &&
2496 (ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
2497 AdPrint(("Resize tune for SEQUENTIAL i/o\n"));
2498 }
2499 status = UDFAllocFreeExtent(Vcb, Length - l,
2500 UDFPartStart(Vcb, PartNum),
2501 UDFPartEnd(Vcb, PartNum),
2502 &TmpExtInf,
2503 ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
2504 if(!OS_SUCCESS(status)) {
2505 KdPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status));
2506 return status;
2507 }
2508 ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
2509 MyFreePool__(TmpExtInf.Mapping);
2510 }
2511 UDFPackMapping(Vcb, ExtInfo);
2512 }
2513 } else
2514 if(Length) {
2515 // decrease extent
2516 AdPrint(("Resize cut (8)\n"));
2517 lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i);
2518 i++;
2519 ASSERT(lba != LBA_OUT_OF_EXTENT);
2520 ASSERT(lba != LBA_NOT_ALLOCATED);
2521 ASSERT(i);
2522 if(ExtInfo->Mapping[i].extLength) {
2523 UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used
2524 if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) {
2525
2526 AdPrint(("Resize try save cutted (8)\n"));
2527 RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
2528 s = UDFGetMappingLength(&(ExtInfo->Mapping[i]));
2529
2530 TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG);
2531 if(TmpExtInf.Mapping) {
2532 RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s);
2533 AdPrint(("Resize save cutted (8)\n"));
2534 if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
2535 &TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) {
2536 ExtInfo->Mapping[i].extLength = 0;
2537 ExtInfo->Mapping[i].extLocation = 0;
2538 goto tail_cached;
2539 }
2540 }
2541 }
2542 UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
2543 tail_cached:;
2544 }
2545 if((lim-1 >= LBS) &&
2546 (flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) {
2547 AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim));
2548 ASSERT(lim);
2549 // BrutePoint();
2550 EXTENT_MAP ClrMap[2];
2551 ClrMap[0].extLength = lim & ~(LBS-1);
2552 s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK;
2553 ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation +
2554 (s >> BSh);
2555 ClrMap[1].extLength =
2556 ClrMap[1].extLocation = 0;
2557 ASSERT((ExtInfo->Mapping[i].extLocation < ClrMap[0].extLocation) ||
2558 (ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh))));
2559 UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used
2560 UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free
2561 ExtInfo->Mapping[i-1].extLength = s | (flags << 30);
2562 }
2563
2564 s = UDFGetMappingLength(ExtInfo->Mapping);
2565 if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) {
2566 // This must never happen on truncate !!!
2567 AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n"));
2568 }
2569 ExtInfo->Mapping[i].extLength =
2570 ExtInfo->Mapping[i].extLocation = 0;
2571 } else {
2572 AdPrint(("Resize zero (9)\n"));
2573 ASSERT(!ExtInfo->Offset);
2574 UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free
2575 s = UDFGetMappingLength(ExtInfo->Mapping);
2576 if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) {
2577 // This must never happen on truncate !!!
2578 AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n"));
2579 }
2580 ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
2581 ExtInfo->Mapping[0].extLocation =
2582 ExtInfo->Mapping[1].extLength =
2583 ExtInfo->Mapping[1].extLocation = 0;
2584 }
2585 if(ExtInfo->Offset) {
2586 if(!AlwaysInIcb) {
2587 // remove 1st entry pointing to FileEntry
2588 s = UDFGetMappingLength(ExtInfo->Mapping);
2589 RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP));
2590 if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s,
2591 (int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) {
2592 // This must never happen on truncate !!!
2593 AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n"));
2594 }
2595 Length -= ExtInfo->Offset;
2596 ExtInfo->Offset = 0;
2597 } else {
2598 Length -= ExtInfo->Offset; // back to in-icb
2599 }
2600 }
2601 ExtInfo->Length = Length;
2602 UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
2603
2604 for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) {
2605 ExtPrint(("Resized Ext: type %x, loc %x, len %x\n",
2606 ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK));
2607 }
2608
2609 return STATUS_SUCCESS;
2610 } // end UDFResizeExtent()
2611
2612 /*
2613 This routine (re)builds AllocDescs data for all allocation modes except
2614 in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for
2615 already allocated user data extent (FileInfo->Dloc->DataLoc).
2616 AllocMode in FileEntry pointed by FileInfo must be already initialized.
2617 */
2618 OSSTATUS
2619 UDFBuildAllocDescs(
2620 IN PVCB Vcb,
2621 IN uint32 PartNum,
2622 IN OUT PUDF_FILE_INFO FileInfo,
2623 OUT int8** AllocData
2624 )
2625 {
2626 // PEXTENT_MAP InMap;
2627 // uint32 i=0;
2628 int8* Allocs;
2629 uint16 AllocMode;
2630 uint32 InitSz;
2631 OSSTATUS status;
2632
2633 ValidateFileInfo(FileInfo);
2634 AdPrint(("BuildAllocDesc\n"));
2635 // get space available in the 1st LBlock after FE
2636 InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen;
2637 Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz);
2638 if(!Allocs) {
2639 AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz));
2640 return STATUS_INSUFFICIENT_RESOURCES;
2641 }
2642 RtlZeroMemory(Allocs, InitSz);
2643 // InMap = FileInfo->Dloc->DataLoc.Mapping;
2644 UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used
2645
2646 // TODO: move data from mapped locations here
2647
2648 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
2649 switch(AllocMode) {
2650 case ICB_FLAG_AD_IN_ICB: {
2651 MyFreePool__(Allocs);
2652 ASSERT(!FileInfo->Dloc->AllocLoc.Mapping);
2653 Allocs = NULL;
2654 status = STATUS_SUCCESS;
2655 break;
2656 }
2657 case ICB_FLAG_AD_SHORT: {
2658 status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2659 break;
2660 }
2661 case ICB_FLAG_AD_LONG: {
2662 status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2663 break;
2664 }
2665 /* case ICB_FLAG_AD_EXTENDED: {
2666 status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
2667 break;
2668 }*/
2669 default: {
2670 MyFreePool__(Allocs);
2671 Allocs = NULL;
2672 status = STATUS_INVALID_PARAMETER;
2673 }
2674 }
2675
2676 *AllocData = Allocs;
2677 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2678
2679 return status;
2680 } // end UDFBuildAllocDescs()
2681
2682 /*
2683 This routine discards file's allocation
2684 */
2685 void
2686 UDFFreeFileAllocation(
2687 IN PVCB Vcb,
2688 IN PUDF_FILE_INFO DirInfo,
2689 IN PUDF_FILE_INFO FileInfo
2690 )
2691 {
2692 if(FileInfo->Dloc->DataLoc.Offset) {
2693 // in-ICB data
2694 if(FileInfo->Dloc->DataLoc.Mapping) {
2695 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2696 FileInfo->Dloc->DataLoc.Mapping[0].extLocation);
2697 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
2698 FileInfo->Dloc->DataLoc.Mapping[1].extLocation =
2699 FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0;
2700 FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0;
2701 FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2702 }
2703 if(FileInfo->Dloc->AllocLoc.Mapping) {
2704 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2705 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2706 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2707 FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2708 FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2709 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2710 FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2711 }
2712 UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2713 } else {
2714 if(FileInfo->Dloc->AllocLoc.Mapping) {
2715 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
2716 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
2717 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
2718 FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
2719 FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
2720 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
2721 FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
2722 }
2723 UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2724 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
2725 }
2726 FileInfo->Dloc->DataLoc.Modified =
2727 FileInfo->Dloc->AllocLoc.Modified =
2728 FileInfo->Dloc->FELoc.Modified = FALSE;
2729 } // end UDFFreeFileAllocation()
2730 #endif //UDF_READ_ONLY_BUILD
2731
2732 /*
2733 This routine packs physically sequential extents into single one
2734 */
2735 void
2736 __fastcall
2737 UDFPackMapping(
2738 IN PVCB Vcb,
2739 IN PEXTENT_INFO ExtInfo // Extent array
2740 )
2741 {
2742 PEXTENT_MAP NewMap, OldMap;
2743 uint32 i, j, l;
2744 uint32 LastLba, LastType, OldLen;
2745 uint32 OldSize, NewSize;
2746 #ifdef UDF_DBG
2747 int64 check_size;
2748 #endif //UDF_DBG
2749
2750 AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
2751 AdPrint((" Length %x\n", ExtInfo->Length));
2752
2753 OldMap = ExtInfo->Mapping;
2754 LastLba = OldMap[0].extLocation;
2755 OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2756 LastType = OldMap[0].extLength >> 30;
2757 OldSize =
2758 NewSize = UDFGetMappingLength(OldMap);
2759 #ifdef UDF_DBG
2760 check_size = UDFGetExtentLength(ExtInfo->Mapping);
2761 ASSERT(!(check_size & (2048-1)));
2762 #endif //UDF_DBG
2763
2764 l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK;
2765 // calculate required length
2766 for(i=1; OldMap[i].extLength; i++) {
2767 if((LastType == (OldMap[i].extLength >> 30))
2768 &&
2769 ((OldMap[i].extLocation == LastLba + OldLen) ||
2770 (!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
2771 &&
2772 (l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
2773 // we can pack two blocks in one
2774 l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2775 NewSize -= sizeof(EXTENT_MAP);
2776 } else {
2777 l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
2778 }
2779 LastLba = OldMap[i].extLocation;
2780 LastType = OldMap[i].extLength >> 30;
2781 OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
2782 }
2783 // no changes ?
2784 if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) {
2785 if(OldSize == NewSize)
2786 return;
2787 if(NewSize >= PACK_MAPPING_THRESHOLD)
2788 return;
2789 }
2790 AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping));
2791 NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize,
2792 MEM_EXTMAP_TAG);
2793 // can't alloc ?
2794 if(!NewMap) return;
2795 // Ok, lets pack it...
2796 j=0;
2797 NewMap[0] = OldMap[0