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