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    udf_info.cpp
10 
11         Abstract:
12 
13    This file contains filesystem-specific routines
14    for Directory tree & related structures support
15 
16 */
17 
18 #include "udf.h"
19 
20 #ifdef UDF_CHECK_UTIL
21   #include "..\namesup.h"
22 #else
23   #ifdef UDF_BUG_CHECK_ID
24     #undef UDF_BUG_CHECK_ID
25   #endif //UDF_BUG_CHECK_ID
26 #endif //UDF_CHECK_UTIL
27 
28 #define         UDF_BUG_CHECK_ID                UDF_FILE_UDF_INFO_DIR
29 
30 #define         MEM_USDIRHASH_TAG               "USDirHash"
31 
32 #define UDF_DUMP_DIRTREE
33 #ifdef UDF_DUMP_DIRTREE
34 #define DirPrint(x)  UDFPrint(x)
35 #else
36 #define DirPrint(x)  {;}
37 #endif
38 
39 /*
40     This routine initializes DirIndex array
41  */
42 PDIR_INDEX_HDR
43 UDFDirIndexAlloc(
44     IN uint_di i
45     )
46 {
47     uint_di j,k;
48     PDIR_INDEX_HDR hDirNdx;
49     PDIR_INDEX_ITEM* FrameList;
50 
51     if(!i)
52         return NULL;
53 #ifdef UDF_LIMIT_DIR_SIZE
54     if(i>UDF_DIR_INDEX_FRAME)
55         return NULL;
56 #endif //UDF_LIMIT_DIR_SIZE
57 
58     j = i >> UDF_DIR_INDEX_FRAME_SH;
59     i &= (UDF_DIR_INDEX_FRAME-1);
60 
61     hDirNdx = (PDIR_INDEX_HDR)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, sizeof(DIR_INDEX_HDR)+(j+(i!=0))*sizeof(PDIR_INDEX_ITEM), MEM_DIR_HDR_TAG);
62     if(!hDirNdx) return NULL;
63     RtlZeroMemory(hDirNdx, sizeof(DIR_INDEX_HDR));
64 
65     FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
66     for(k=0; k<j; k++, FrameList++) {
67         (*FrameList) = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG);
68         if(!(*FrameList)) {
69 free_hdi:
70             // item pointet by FrameList is NULL, it could not be allocated
71             while(k) {
72                 k--;
73                 FrameList--;
74                 MyFreePool__(*FrameList);
75             }
76             MyFreePool__(hDirNdx);
77             return NULL;
78         }
79         RtlZeroMemory((*FrameList), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM));
80     }
81     if(i) {
82         (*FrameList) = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, AlignDirIndex(i)*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG);
83         if(!(*FrameList))
84             goto free_hdi;
85         RtlZeroMemory((*FrameList), i*sizeof(DIR_INDEX_ITEM));
86     }
87 
88     hDirNdx->FrameCount = j+(i!=0);
89     hDirNdx->LastFrameCount = i ? i : UDF_DIR_INDEX_FRAME;
90 
91     return hDirNdx;
92 } // UDFDirIndexAlloc()
93 
94 /*
95     This routine releases DirIndex array
96  */
97 void
98 UDFDirIndexFree(
99     PDIR_INDEX_HDR hDirNdx
100     )
101 {
102     uint32 k;
103     PDIR_INDEX_ITEM* FrameList;
104 
105     FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
106     if(!hDirNdx) return;
107     for(k=0; k<hDirNdx->FrameCount; k++, FrameList++) {
108         if(*FrameList) MyFreePool__(*FrameList);
109     }
110     MyFreePool__(hDirNdx);
111 } // UDFDirIndexFree();
112 
113 /*
114     This routine grows DirIndex array
115  */
116 OSSTATUS
117 UDFDirIndexGrow(
118     IN PDIR_INDEX_HDR* _hDirNdx,
119     IN uint_di d // increment
120     )
121 {
122     uint_di j,k;
123     PDIR_INDEX_HDR hDirNdx = *_hDirNdx;
124     PDIR_INDEX_ITEM* FrameList;
125 
126     if(d > UDF_DIR_INDEX_FRAME)
127         return STATUS_INVALID_PARAMETER;
128 
129     j = hDirNdx->LastFrameCount+d;
130 
131     if(j > UDF_DIR_INDEX_FRAME) {
132 #ifndef UDF_LIMIT_DIR_SIZE // release
133         // Grow header
134         k = hDirNdx->FrameCount;
135         if(!MyReallocPool__((int8*)hDirNdx, sizeof(DIR_INDEX_HDR) + k*sizeof(PDIR_INDEX_ITEM),
136                        (int8**)(&hDirNdx), sizeof(DIR_INDEX_HDR) + (k+1)*sizeof(PDIR_INDEX_ITEM) ) )
137             return STATUS_INSUFFICIENT_RESOURCES;
138         FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
139         // Grow last frame
140         if(!MyReallocPool__((int8*)(FrameList[k-1]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM),
141                        (int8**)(&(FrameList[k-1])), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM) ) )
142             return STATUS_INSUFFICIENT_RESOURCES;
143         RtlZeroMemory(&(FrameList[k-1][hDirNdx->LastFrameCount]),
144                        (UDF_DIR_INDEX_FRAME-hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM));
145         hDirNdx->LastFrameCount = UDF_DIR_INDEX_FRAME;
146         // Allocate new frame
147         FrameList[k] = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, AlignDirIndex(j-UDF_DIR_INDEX_FRAME)*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG );
148         if(!FrameList[k])
149             return STATUS_INSUFFICIENT_RESOURCES;
150         hDirNdx->FrameCount++;
151         RtlZeroMemory(FrameList[k], (j-UDF_DIR_INDEX_FRAME)*sizeof(DIR_INDEX_ITEM));
152         hDirNdx->LastFrameCount = j-UDF_DIR_INDEX_FRAME;
153         (*_hDirNdx) = hDirNdx;
154 #else   // UDF_LIMIT_DIR_SIZE
155         return STATUS_INSUFFICIENT_RESOURCES;
156 #endif  // UDF_LIMIT_DIR_SIZE
157     } else {
158         k = hDirNdx->FrameCount;
159         FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
160         if(!MyReallocPool__((int8*)(FrameList[k-1]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM),
161                        (int8**)(&(FrameList[k-1])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) )
162             return STATUS_INSUFFICIENT_RESOURCES;
163         RtlZeroMemory(&(FrameList[k-1][hDirNdx->LastFrameCount]),
164                        (j-hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM));
165         hDirNdx->LastFrameCount = j;
166     }
167     return STATUS_SUCCESS;
168 } // end UDFDirIndexGrow()
169 
170 /*
171     Thisd routine truncates DirIndex array
172  */
173 OSSTATUS
174 UDFDirIndexTrunc(
175     IN PDIR_INDEX_HDR* _hDirNdx,
176     IN uint_di d // decrement
177     )
178 {
179     uint_di j,k;
180 
181     if(d > UDF_DIR_INDEX_FRAME) {
182         OSSTATUS status;
183         while(d) {
184             k = (d > UDF_DIR_INDEX_FRAME) ? UDF_DIR_INDEX_FRAME : d;
185             if(!OS_SUCCESS(status = UDFDirIndexTrunc(_hDirNdx, k))) {
186                 return status;
187             }
188             d -= k;
189         }
190         return STATUS_SUCCESS;
191     }
192 
193     PDIR_INDEX_HDR hDirNdx = *_hDirNdx;
194     PDIR_INDEX_ITEM* FrameList;
195 
196     j = UDF_DIR_INDEX_FRAME+hDirNdx->LastFrameCount-d;
197     FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
198     k = hDirNdx->FrameCount-1;
199 
200     if(j <= UDF_DIR_INDEX_FRAME) {
201         // free last frame
202         if(!k && (j < 2)) {
203             // someone tries to trunc. residual entries...
204             return STATUS_INVALID_PARAMETER;
205         }
206         MyFreePool__(FrameList[k]);
207         FrameList[k] = NULL;
208         hDirNdx->LastFrameCount = UDF_DIR_INDEX_FRAME;
209         hDirNdx->FrameCount--;
210         // Truncate new last frame
211         if(!MyReallocPool__((int8*)(FrameList[k-1]), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM),
212                        (int8**)(&(FrameList[k-1])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) )
213             return STATUS_INSUFFICIENT_RESOURCES;
214         hDirNdx->LastFrameCount = j;
215         // Truncate header
216         if(!MyReallocPool__((int8*)hDirNdx, sizeof(DIR_INDEX_HDR) + (k+1)*sizeof(PDIR_INDEX_ITEM),
217                        (int8**)(&hDirNdx), sizeof(DIR_INDEX_HDR) + k*sizeof(PDIR_INDEX_ITEM) ) )
218             return STATUS_INSUFFICIENT_RESOURCES;
219 
220         (*_hDirNdx) = hDirNdx;
221 
222     } else {
223 
224         j -= UDF_DIR_INDEX_FRAME;
225         if(!k && (j < 2)) {
226             // someone tries to trunc. residual entries...
227             return STATUS_INVALID_PARAMETER;
228         }
229 
230         if(!MyReallocPool__((int8*)(FrameList[k]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM),
231                        (int8**)(&(FrameList[k])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) )
232             return STATUS_INSUFFICIENT_RESOURCES;
233         hDirNdx->LastFrameCount = j;
234     }
235     return STATUS_SUCCESS;
236 } // end UDFDirIndexTrunc()
237 
238 #if defined _X86_ && !defined UDF_LIMIT_DIR_SIZE
239 #ifdef _MSC_VER
240 #pragma warning(disable:4035)               // re-enable below
241 #endif
242 /*
243     This routine returns pointer to DirIndex item with index i.
244  */
245 #if defined(_MSC_VER) && !defined(__clang__)
246 __declspec (naked)
247 #endif
248 PDIR_INDEX_ITEM
249 __fastcall
250 UDFDirIndex(
251     IN PDIR_INDEX_HDR hDirNdx, // ECX
252     IN uint32 i                // EDX
253     )
254 {
255 #if defined(_MSC_VER) && !defined(__clang__)
256     __asm {
257         push ebx
258         push ecx
259         push edx
260 
261 //        mov  ebx,hDirNdx
262         mov  ebx,ecx
263         mov  ecx,edx
264         or   ebx,ebx
265         jz   EO_udi_err
266 
267         mov  eax,ecx
268         shr  ecx,UDF_DIR_INDEX_FRAME_SH           ; ecx = j
269         mov  edx,[ebx]hDirNdx.FrameCount          ; edx = k
270         cmp  ecx,edx
271         jae  EO_udi_err
272 
273         and  eax,(1 shl UDF_DIR_INDEX_FRAME_SH)-1 ; eax = i
274         dec  edx
275         cmp  ecx,edx
276         jb   No_check
277 
278         cmp  eax,[ebx].LastFrameCount
279         jae  EO_udi_err
280 No_check:
281         add  ebx,size DIR_INDEX_HDR      ; ((PDIR_INDEX_ITEM*)(hDirNdx+1))...
282         mov  ebx,[ebx+ecx*4]             ; ...[j]...
283         mov  edx,size DIR_INDEX_ITEM
284         mul  edx                         ; ...[i]...
285         add  eax,ebx                     ; &(...)
286         jmp  udi_OK
287 EO_udi_err:
288         xor  eax,eax
289 udi_OK:
290         pop  edx
291         pop  ecx
292         pop  ebx
293 
294         ret
295     }
296 #else
297     /* FIXME ReactOS */
298     uint_di j, k;
299     if( hDirNdx &&
300         ((j = (i >> UDF_DIR_INDEX_FRAME_SH)) < (k = hDirNdx->FrameCount) ) &&
301         ((i = (i & (UDF_DIR_INDEX_FRAME-1))) < ((j < (k-1)) ? UDF_DIR_INDEX_FRAME : hDirNdx->LastFrameCount)) )
302         return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[j])[i] );
303     return NULL;
304 #endif
305 }
306 #ifdef _MSC_VER
307 #pragma warning(default:4035)
308 #endif
309 #endif // _X86_
310 
311 /*
312     This routine returns pointer to DirIndex'es frame & index inside it
313     according to start Index parameter. It also initializes scan parameters
314  */
315 PDIR_INDEX_ITEM
316 UDFDirIndexGetFrame(
317     IN PDIR_INDEX_HDR hDirNdx,
318     IN uint32 Frame,
319    OUT uint32* FrameLen,
320    OUT uint_di* Index,
321     IN uint_di Rel
322     )
323 {
324     if(Frame >= hDirNdx->FrameCount)
325         return NULL;
326     if(Index) {
327 #ifdef UDF_LIMIT_DIR_SIZE
328         (*Index) = Rel;
329 //    if(FrameLen)
330         (*FrameLen) = hDirNdx->LastFrameCount;
331 #else //UDF_LIMIT_DIR_SIZE
332         (*Index) = Frame*UDF_DIR_INDEX_FRAME+Rel;
333 //    if(FrameLen)
334         (*FrameLen) = (Frame < (hDirNdx->FrameCount-1)) ? UDF_DIR_INDEX_FRAME :
335                                                           hDirNdx->LastFrameCount;
336 #endif //UDF_LIMIT_DIR_SIZE
337     }
338     return ((PDIR_INDEX_ITEM*)(hDirNdx+1))[Frame]+Rel;
339 } // end UDFDirIndexGetFrame()
340 
341 /*
342     This routine initializes indexes for optimized DirIndex scan
343     according to start Index parameter
344  */
345 
346 BOOLEAN
347 UDFDirIndexInitScan(
348     IN PUDF_FILE_INFO DirInfo,   //
349    OUT PUDF_DIR_SCAN_CONTEXT Context,
350     IN uint_di Index
351     )
352 {
353     Context->DirInfo = DirInfo;
354     Context->hDirNdx = DirInfo->Dloc->DirIndex;
355     if( (Context->frame = (Index >> UDF_DIR_INDEX_FRAME_SH)) >=
356                                                  Context->hDirNdx->FrameCount) {
357         return FALSE;
358     }
359     if( (Context->j = Index & (UDF_DIR_INDEX_FRAME-1)) >=
360                ((Context->frame < (Context->hDirNdx->FrameCount-1))
361                                     ?
362                                  UDF_DIR_INDEX_FRAME : Context->hDirNdx->LastFrameCount) ) {
363         return FALSE;
364     }
365     Context->DirNdx = UDFDirIndexGetFrame(Context->hDirNdx,
366                                           Context->frame,
367                                           &(Context->d),
368                                           &(Context->i),
369                                           Context->j);
370     Context->i--;
371     Context->j--;
372     Context->DirNdx--;
373 
374     return TRUE;
375 } // end UDFDirIndexInitScan()
376 
377 PDIR_INDEX_ITEM
378 UDFDirIndexScan(
379     PUDF_DIR_SCAN_CONTEXT Context,
380     PUDF_FILE_INFO* _FileInfo
381     )
382 {
383     PUDF_FILE_INFO FileInfo;
384     PUDF_FILE_INFO ParFileInfo;
385 
386     Context->i++;
387     Context->j++;
388     Context->DirNdx++;
389 
390     if(Context->j >= Context->d) {
391         Context->j=0;
392         Context->frame++;
393         Context->DirNdx = UDFDirIndexGetFrame(Context->hDirNdx,
394                                               Context->frame,
395                                               &(Context->d),
396                                               &(Context->i),
397                                               Context->j);
398     }
399     if(!Context->DirNdx) {
400         if(_FileInfo)
401             (*_FileInfo) = NULL;
402         return NULL;
403     }
404 
405     if(_FileInfo) {
406         if((FileInfo = Context->DirNdx->FileInfo)) {
407             if(FileInfo->ParentFile != Context->DirInfo) {
408                 ParFileInfo = UDFLocateParallelFI(Context->DirInfo,
409                                                   Context->i,
410                                                   FileInfo);
411 #ifdef UDF_DBG
412                 if(ParFileInfo->ParentFile != Context->DirInfo) {
413                     BrutePoint();
414                 }
415 #endif // UDF_DBG
416                 FileInfo = ParFileInfo;
417             }
418         }
419         (*_FileInfo) = FileInfo;
420     }
421 
422     return (Context->DirNdx);
423 } // end UDFDirIndexScan()
424 
425 /*
426     This routine calculates hashes for directory search
427  */
428 uint8
429 UDFBuildHashEntry(
430     IN PVCB Vcb,
431     IN PUNICODE_STRING Name,
432    OUT PHASH_ENTRY hashes,
433     IN uint8 Mask
434     )
435 {
436     UNICODE_STRING UName;
437     WCHAR ShortNameBuffer[13];
438     uint8 RetFlags = 0;
439 
440     if(!Name->Buffer) return 0;
441 
442     if(Mask & HASH_POSIX)
443         hashes->hPosix = crc32((uint8*)(Name->Buffer), Name->Length);
444 
445     if(Mask & HASH_ULFN) {
446 /*        if(OS_SUCCESS(MyInitUnicodeString(&UName, L"")) &&
447            OS_SUCCESS(MyAppendUnicodeStringToStringTag(&UName, Name, MEM_USDIRHASH_TAG))) {*/
448         if(OS_SUCCESS(MyCloneUnicodeString(&UName, Name))) {
449             RtlUpcaseUnicodeString(&UName, &UName, FALSE);
450     /*        if(!RtlCompareUnicodeString(Name, &UName, FALSE)) {
451                 RetFlags |= UDF_FI_FLAG_LFN;
452             }*/
453             hashes->hLfn = crc32((uint8*)(UName.Buffer), UName.Length);
454         } else {
455             BrutePoint();
456         }
457         MyFreePool__(UName.Buffer);
458     }
459 
460     if(Mask & HASH_DOS) {
461         UName.Buffer = (PWCHAR)(&ShortNameBuffer);
462         UName.MaximumLength = 13*sizeof(WCHAR);
463         UDFDOSName(Vcb, &UName, Name, (Mask & HASH_KEEP_NAME) ? TRUE : FALSE);
464         if(!RtlCompareUnicodeString(Name, &UName, TRUE)) {
465             RetFlags |= UDF_FI_FLAG_DOS;
466         }
467         hashes->hDos = crc32((uint8*)(UName.Buffer), UName.Length);
468     }
469     return RetFlags;
470 } // UDFBuildHashEntry()
471 
472 #ifdef UDF_CHECK_UTIL
473 uint32
474 UDFFindNextFI(
475     IN int8* buff,
476     IN uint32 prevOffset,
477     IN uint32 Length
478     )
479 {
480     PFILE_IDENT_DESC FileId;
481     while(prevOffset+sizeof(FILE_IDENT_DESC) < Length) {
482         prevOffset++;
483         FileId = (PFILE_IDENT_DESC)(buff+prevOffset);
484         if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC)
485             continue;
486         if(FileId->descTag.descVersion != 2 && FileId->descTag.descVersion != 3)
487             continue;
488         if(FileId->fileVersionNum != 1)
489             continue;
490         if(FileId->fileCharacteristics & (~0x1f))
491             continue;
492         if(prevOffset + ((FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3))) <= Length) {
493             UDFPrint(("UDFFindNextFI OK: %x\n", prevOffset));
494             return prevOffset;
495         }
496     }
497     return 0;
498 } // end UDFFindNextFI()
499 #else //UDF_CHECK_UTIL
500 #define UDFFindNextFI(a,b,c)  0
501 #endif //UDF_CHECK_UTIL
502 
503 /*
504     This routine scans directory extent & builds index table for FileIdents
505  */
506 OSSTATUS
507 UDFIndexDirectory(
508     IN PVCB Vcb,
509  IN OUT PUDF_FILE_INFO FileInfo
510     )
511 {
512     PDIR_INDEX_HDR hDirNdx;
513     PDIR_INDEX_ITEM DirNdx;
514     PFILE_IDENT_DESC FileId;
515     uint32 Offset = 0;
516 //    uint32 prevOffset = 0;
517     uint_di Count = 0;
518     OSSTATUS status;
519     int8* buff;
520     PEXTENT_INFO ExtInfo;  // Extent array for directory
521     uint16 PartNum;
522     SIZE_T ReadBytes;
523     uint16 valueCRC;
524 
525     if(!FileInfo) return STATUS_INVALID_PARAMETER;
526     ValidateFileInfo(FileInfo);
527 
528     ExtInfo = &(FileInfo->Dloc->DataLoc);
529     FileInfo->Dloc->DirIndex = NULL;
530     UDFPrint(("UDF: scaning directory\n"));
531     // allocate buffer for the whole directory
532     ASSERT((uint32)(ExtInfo->Length));
533     if(!ExtInfo->Length)
534         return STATUS_FILE_CORRUPT_ERROR;
535     buff = (int8*)DbgAllocatePool(PagedPool, (uint32)(ExtInfo->Length));
536     if(!buff)
537         return STATUS_INSUFFICIENT_RESOURCES;
538 
539     ExtInfo->Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
540 
541     // read FileIdents
542     status = UDFReadExtent(Vcb, ExtInfo, 0, (uint32)(ExtInfo->Length), FALSE, buff, &ReadBytes);
543     if(!OS_SUCCESS(status)) {
544         DbgFreePool(buff);
545         return status;
546     }
547     // scan Dir to get entry counter
548     FileId = (PFILE_IDENT_DESC)buff;
549     DirPrint(("  ExtInfo->Length %x\n", ExtInfo->Length));
550 //    prevOffset = 0;
551     while(Offset<ExtInfo->Length) {
552         DirPrint(("  Offset %x\n", Offset));
553         if(!FileId->descTag.tagIdent) {
554             DirPrint(("  term item\n"));
555             break;
556         }
557         if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC) {
558             DirPrint(("  Inv. tag %x\n", FileId->descTag.tagIdent));
559             Offset = UDFFindNextFI(buff, prevOffset, (ULONG)(ExtInfo->Length));
560             if(!Offset) {
561                 DirPrint(("  can't find next\n"));
562                 break;
563             } else {
564                 DirPrint(("  found next offs %x\n", Offset));
565                 FileId = (PFILE_IDENT_DESC)((buff)+Offset);
566             }
567         }
568         if(((ULONG)Offset & (Vcb->LBlockSize-1)) > (Vcb->LBlockSize-sizeof(FILE_IDENT_DESC))) {
569             DirPrint(("  badly aligned\n", Offset));
570             if(Vcb->Modified) {
571                 DirPrint(("  queue repack request\n"));
572                 FileInfo->Dloc->DirIndex->DelCount = Vcb->PackDirThreshold+1;
573             }
574         }
575 //        prevOffset = Offset;
576         Offset += (FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3));
577         FileId = (PFILE_IDENT_DESC)((buff)+Offset);
578         Count++;
579         if(Offset+sizeof(FILE_IDENT_DESC) > ExtInfo->Length) {
580             if(Offset != ExtInfo->Length) {
581                 UDFPrint(("  Trash at the end of Dir\n"));
582             }
583 //            BrutePoint();
584             break;
585         }
586     }
587     DirPrint(("  final Offset %x\n", Offset));
588     if(Offset > ExtInfo->Length) {
589         BrutePoint();
590         UDFPrint(("  Unexpected end of Dir\n"));
591         DbgFreePool(buff);
592         return STATUS_FILE_CORRUPT_ERROR;
593     }
594     // allocate buffer for directory index & zero it
595     DirPrint(("  Count %x\n", Count));
596     hDirNdx = UDFDirIndexAlloc(Count+1);
597     if(!hDirNdx) {
598         DbgFreePool(buff);
599         return STATUS_INSUFFICIENT_RESOURCES;
600     }
601 
602     Offset = Count = 0;
603     hDirNdx->DIFlags |= (ExtInfo->Offset ? UDF_DI_FLAG_INIT_IN_ICB : 0);
604     // add entry pointing to the directory itself
605     DirNdx = UDFDirIndex(hDirNdx,0);
606     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
607     DirNdx->FileEntryLoc.partitionReferenceNum = PartNum =
608         (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
609     ASSERT(PartNum != -1);
610     DirNdx->FileEntryLoc.logicalBlockNum =
611         UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
612     if(DirNdx->FileEntryLoc.logicalBlockNum == (ULONG)-1) {
613         DirPrint(("  err: FileEntryLoc=-1\n"));
614         DbgFreePool(buff);
615         UDFDirIndexFree(hDirNdx);
616         return STATUS_FILE_CORRUPT_ERROR;
617     }
618     DirNdx->FileCharacteristics = (FileInfo->FileIdent) ?
619                          FileInfo->FileIdent->fileCharacteristics :
620                          FILE_DIRECTORY;
621 //    DirNdx->Offset = 0;
622 //    DirNdx->Length = 0;
623     RtlInitUnicodeString(&DirNdx->FName, L".");
624     DirNdx->FileInfo = FileInfo;
625     DirNdx->FI_Flags |= UDF_FI_FLAG_KEEP_NAME;
626     DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes),
627         HASH_ALL | HASH_KEEP_NAME);
628     Count++;
629     FileId = (PFILE_IDENT_DESC)buff;
630     status = STATUS_SUCCESS;
631 //    prevOffset = 0;
632     while((Offset<ExtInfo->Length) && FileId->descTag.tagIdent) {
633         // add new entry to index list
634         if(FileId->descTag.tagIdent != TID_FILE_IDENT_DESC) {
635             UDFPrint(("  Invalid tagIdent %x (expected %x) offst %x\n", FileId->descTag.tagIdent, TID_FILE_IDENT_DESC, Offset));
636             DirPrint(("    FileId: filen %x, iulen %x, charact %x\n",
637                 FileId->lengthFileIdent, FileId->lengthOfImpUse, FileId->fileCharacteristics));
638             DirPrint(("    loc: @%x\n", UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, NULL)));
639             KdDump(FileId, sizeof(FileId->descTag));
640             Offset = UDFFindNextFI(buff, prevOffset, (ULONG)(ExtInfo->Length));
641             if(!Offset) {
642                 DbgFreePool(buff);
643                 UDFDirIndexFree(hDirNdx);
644                 return STATUS_FILE_CORRUPT_ERROR;
645             } else {
646                 DirPrint(("  found next offs %x\n", Offset));
647                 FileId = (PFILE_IDENT_DESC)((buff)+Offset);
648             }
649         }
650         DirNdx = UDFDirIndex(hDirNdx,Count);
651         // allocate buffer & fill it with decompressed unicode filename
652         if(FileId->fileCharacteristics & FILE_DELETED) {
653             DirPrint(("  FILE_DELETED\n"));
654             hDirNdx->DelCount++;
655         }
656         DirPrint(("  FileId: offs %x, filen %x, iulen %x\n", Offset, FileId->lengthFileIdent, FileId->lengthOfImpUse));
657         DirNdx->Length = (FileId->lengthFileIdent + FileId->lengthOfImpUse + sizeof(FILE_IDENT_DESC) + 3) & (~((uint32)3));
658         DirPrint(("  DirNdx: Length %x, Charact %x\n", DirNdx->Length, FileId->fileCharacteristics));
659         if(FileId->fileCharacteristics & FILE_PARENT) {
660             DirPrint(("  parent\n"));
661             // init 'parent' entry
662             // '..' points to Parent Object (if any),
663             // otherwise it points to the Dir itself
664             RtlInitUnicodeString(&DirNdx->FName, L"..");
665             DirNdx->FileInfo = (FileInfo->ParentFile) ?
666                                       FileInfo->ParentFile : FileInfo;
667             DirNdx->FI_Flags |= UDF_FI_FLAG_KEEP_NAME;
668             DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL | HASH_KEEP_NAME);
669         } else {
670             // init plain file/dir entry
671             ASSERT( (Offset+sizeof(FILE_IDENT_DESC)+FileId->lengthOfImpUse+FileId->lengthFileIdent) <=
672                     ExtInfo->Length );
673             UDFDecompressUnicode(&(DirNdx->FName),
674                              ((uint8*)(FileId+1)) + (FileId->lengthOfImpUse),
675                              FileId->lengthFileIdent,
676                              &valueCRC);
677             UDFNormalizeFileName(&(DirNdx->FName), valueCRC);
678             DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
679         }
680         if((FileId->fileCharacteristics & FILE_METADATA)
681                        ||
682               !DirNdx->FName.Buffer
683                        ||
684            ((DirNdx->FName.Length >= sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) &&
685             (RtlCompareMemory(DirNdx->FName.Buffer, UDF_RESERVED_NAME_HDR, sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) == sizeof(UDF_RESERVED_NAME_HDR)-sizeof(WCHAR)) )) {
686             DirPrint(("  metadata\n"));
687             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
688         }
689 #if 0
690         UDFPrint(("%ws\n", DirNdx->FName.Buffer));
691 #endif
692         DirPrint(("%ws\n", DirNdx->FName.Buffer));
693         // remember FileEntry location...
694         DirNdx->FileEntryLoc = FileId->icb.extLocation;
695         // ... and some file characteristics
696         DirNdx->FileCharacteristics = FileId->fileCharacteristics;
697         DirNdx->Offset = Offset;
698 #ifdef UDF_CHECK_DISK_ALLOCATION
699         if(!(FileId->fileCharacteristics & FILE_DELETED) &&
700             (UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) != LBA_OUT_OF_EXTENT) &&
701              UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) )) {
702 
703             AdPrint(("Ref to Discarded block %x\n",UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) ));
704             BrutePoint();
705             FileId->fileCharacteristics |= FILE_DELETED;
706         } else
707         if(UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) == LBA_OUT_OF_EXTENT) {
708             AdPrint(("Ref to Invalid block %x\n", UDFPartLbaToPhys(Vcb, &(DirNdx->FileEntryLoc)) ));
709             BrutePoint();
710             FileId->fileCharacteristics |= FILE_DELETED;
711         }
712 #endif // UDF_CHECK_DISK_ALLOCATION
713 //        prevOffset = Offset;
714         Offset += DirNdx->Length;
715         FileId = (PFILE_IDENT_DESC)(((int8*)FileId)+DirNdx->Length);
716         Count++;
717         if(Offset+sizeof(FILE_IDENT_DESC) > ExtInfo->Length) {
718             if(Offset != ExtInfo->Length) {
719                 UDFPrint(("  Trash at the end of Dir (2)\n"));
720             }
721 //            BrutePoint();
722             break;
723         }
724     } // while()
725     // we needn't writing terminator 'cause the buffer is already zero-filled
726     DbgFreePool(buff);
727     if(Count < 2) {
728         UDFDirIndexFree(hDirNdx);
729         UDFPrint(("  Directory too short\n"));
730         return STATUS_FILE_CORRUPT_ERROR;
731     }
732     // store index
733     FileInfo->Dloc->DirIndex = hDirNdx;
734     return status;
735 } // end UDFIndexDirectory()
736 
737 #ifndef UDF_READ_ONLY_BUILD
738 /*
739     This routine removes all DELETED entries from Dir & resizes it.
740     It must be called before closing, no files sould be opened.
741  */
742 OSSTATUS
743 UDFPackDirectory__(
744     IN PVCB Vcb,
745  IN OUT PUDF_FILE_INFO FileInfo   // source (opened)
746     )
747 {
748 #ifdef UDF_PACK_DIRS
749     uint32 d, LBS;
750     uint_di i, j;
751     uint32 IUl, FIl, l;
752     uint32 DataLocOffset;
753     uint32 Offset, curOffset;
754     int8* Buf;
755     OSSTATUS status;
756     SIZE_T ReadBytes;
757     int8* storedFI;
758     PUDF_FILE_INFO curFileInfo;
759     PDIR_INDEX_ITEM DirNdx, DirNdx2;
760     UDF_DIR_SCAN_CONTEXT ScanContext;
761     uint_di dc=0;
762     uint16 PartNum;
763 #endif //UDF_PACK_DIRS
764 
765     ValidateFileInfo(FileInfo);
766     PDIR_INDEX_HDR hDirNdx = FileInfo->Dloc->DirIndex;
767     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
768 #ifndef UDF_PACK_DIRS
769     return STATUS_SUCCESS;
770 #else // UDF_PACK_DIRS
771 
772     // do not pack dirs on unchanged disks
773     if(!Vcb->Modified)
774         return STATUS_SUCCESS;
775     // start packing
776     LBS = Vcb->LBlockSize;
777     Buf = (int8*)DbgAllocatePool(PagedPool, LBS*2);
778     if(!Buf) return STATUS_INSUFFICIENT_RESOURCES;
779     // we shall never touch 1st entry 'cause it can't be deleted
780     Offset = UDFDirIndex(hDirNdx,2)->Offset;
781     DataLocOffset = FileInfo->Dloc->DataLoc.Offset;
782 
783     i=j=2;
784 
785     if(!UDFDirIndexInitScan(FileInfo, &ScanContext, i)) {
786         DbgFreePool(Buf);
787         return STATUS_SUCCESS;
788     }
789 
790     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
791     PartNum = (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
792     ASSERT(PartNum != -1);
793 
794     while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
795 
796         if(UDFIsDeleted(DirNdx))
797             dc++;
798 
799         if(!UDFIsDeleted(DirNdx) ||
800              DirNdx->FileInfo) {
801             // move down valid entry
802             status = UDFReadFile__(Vcb, FileInfo, curOffset = DirNdx->Offset,
803                                                           l = DirNdx->Length, FALSE, Buf, &ReadBytes);
804             if(!OS_SUCCESS(status)) {
805                 DbgFreePool(Buf);
806                 return status;
807             }
808             // remove ImpUse field
809             IUl = ((PFILE_IDENT_DESC)Buf)->lengthOfImpUse;
810             curFileInfo = DirNdx->FileInfo;
811             // align next entry
812             if((d = LBS - ((curOffset + (l - IUl) + DataLocOffset) & (LBS-1)) ) < sizeof(FILE_IDENT_DESC)) {
813 
814                 // insufficient space at the end of last sector for
815                 // next FileIdent's tag. fill it with ImpUse data
816 
817                 // generally, all data should be DWORD-aligned, but if it is not so
818                 // this opearation will help us to avoid glitches
819                 d = (d+3) & ~(3);
820                 if(d != IUl) {
821                     l = l + d - IUl;
822                     FIl = ((PFILE_IDENT_DESC)Buf)->lengthFileIdent;
823                     // copy filename to upper addr
824                     RtlMoveMemory(Buf+sizeof(FILE_IDENT_DESC)+d,
825                                   Buf+sizeof(FILE_IDENT_DESC)+IUl, FIl);
826                     RtlZeroMemory(Buf+sizeof(FILE_IDENT_DESC), d);
827                     ((PFILE_IDENT_DESC)Buf)->lengthOfImpUse = (uint16)d;
828 
829                     if(curFileInfo && curFileInfo->FileIdent) {
830                         // update stored FI if any
831                         if(!MyReallocPool__((int8*)(curFileInfo->FileIdent), l,
832                                      (int8**)&(curFileInfo->FileIdent), (l+IUl-d) )) {
833                             DbgFreePool(Buf);
834                             return STATUS_INSUFFICIENT_RESOURCES;
835                         }
836                         storedFI = (int8*)(curFileInfo->FileIdent);
837                         RtlMoveMemory(storedFI+sizeof(FILE_IDENT_DESC)+d,
838                                       storedFI+sizeof(FILE_IDENT_DESC)+IUl, FIl);
839                         RtlZeroMemory(storedFI+sizeof(FILE_IDENT_DESC), d);
840                         ((PFILE_IDENT_DESC)storedFI)->lengthOfImpUse = (uint16)d;
841                         FileInfo->Dloc->FELoc.Modified = TRUE;
842                         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
843                     }
844                 }
845             } else {
846                 d = 0;
847             }
848             // write modified to new addr
849             if((d != IUl) ||
850                (curOffset != Offset)) {
851 
852                 UDFSetUpTag(Vcb, (tag*)Buf, (uint16)l,
853                           UDFPhysLbaToPart(Vcb, PartNum,
854                                      UDFExtentOffsetToLba(Vcb, FileInfo->Dloc->DataLoc.Mapping,
855                                                 Offset, NULL, NULL, NULL, NULL)));
856 
857                 status = UDFWriteFile__(Vcb, FileInfo, Offset, l, FALSE, Buf, &ReadBytes);
858                 if(!OS_SUCCESS(status)) {
859                     DbgFreePool(Buf);
860                     return status;
861                 }
862             }
863             DirNdx2 = UDFDirIndex(hDirNdx, j);
864             *DirNdx2 = *DirNdx;
865             DirNdx2->Offset = Offset;
866             DirNdx2->Length = l;
867             if(curFileInfo) {
868                 curFileInfo->Index = j;
869                 DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
870             }
871             Offset += l;
872             j++;
873         }
874     }
875     // resize DirIndex
876     DbgFreePool(Buf);
877     if(dc) {
878         if(!OS_SUCCESS(status = UDFDirIndexTrunc(&(FileInfo->Dloc->DirIndex), dc))) {
879             return status;
880         }
881     }
882     // terminator is set by UDFDirIndexTrunc()
883     FileInfo->Dloc->DirIndex->DelCount = 0;
884     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
885 
886     // now Offset points to EOF. Let's truncate directory
887     return UDFResizeFile__(Vcb, FileInfo, Offset);
888 #endif // UDF_PACK_DIRS
889 } // end UDFPackDirectory__()
890 
891 /*
892     This routine rebuilds tags for all entries from Dir.
893  */
894 OSSTATUS
895 UDFReTagDirectory(
896     IN PVCB Vcb,
897  IN OUT PUDF_FILE_INFO FileInfo   // source (opened)
898     )
899 {
900     uint32 l;
901     uint32 Offset;
902     int8* Buf;
903     OSSTATUS status;
904     SIZE_T ReadBytes;
905     PUDF_FILE_INFO curFileInfo;
906     PDIR_INDEX_ITEM DirNdx;
907     UDF_DIR_SCAN_CONTEXT ScanContext;
908     uint16 PartNum;
909 
910     ValidateFileInfo(FileInfo);
911     PDIR_INDEX_HDR hDirNdx = FileInfo->Dloc->DirIndex;
912     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
913 
914     // do not pack dirs on unchanged disks
915     if(!Vcb->Modified)
916         return STATUS_SUCCESS;
917 
918     if( ((hDirNdx->DIFlags & UDF_DI_FLAG_INIT_IN_ICB) ? TRUE : FALSE) ==
919         ((FileInfo->Dloc->DataLoc.Offset) ? TRUE : FALSE) ) {
920         return STATUS_SUCCESS;
921     }
922 
923     // start packing
924     Buf = (int8*)DbgAllocatePool(PagedPool, Vcb->LBlockSize*2);
925     if(!Buf) return STATUS_INSUFFICIENT_RESOURCES;
926 
927     Offset = UDFDirIndex(hDirNdx,1)->Offset;
928 
929     if(!UDFDirIndexInitScan(FileInfo, &ScanContext, 1)) {
930         DbgFreePool(Buf);
931         return STATUS_SUCCESS;
932     }
933 
934     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
935     PartNum = (uint16)UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
936     ASSERT(PartNum != -1);
937 
938     while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
939 
940         status = UDFReadFile__(Vcb, FileInfo, Offset = DirNdx->Offset,
941                                                    l = DirNdx->Length, FALSE, Buf, &ReadBytes);
942         if(!OS_SUCCESS(status)) {
943             DbgFreePool(Buf);
944             return status;
945         }
946         curFileInfo = DirNdx->FileInfo;
947         // write modified
948         UDFSetUpTag(Vcb, (tag*)Buf, (uint16)l,
949                   UDFPhysLbaToPart(Vcb, PartNum,
950                              UDFExtentOffsetToLba(Vcb, FileInfo->Dloc->DataLoc.Mapping,
951                                         Offset, NULL, NULL, NULL, NULL)));
952 
953         if(curFileInfo && curFileInfo->FileIdent) {
954             FileInfo->Dloc->FELoc.Modified = TRUE;
955             FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
956         }
957 
958         status = UDFWriteFile__(Vcb, FileInfo, Offset, l, FALSE, Buf, &ReadBytes);
959         if(!OS_SUCCESS(status)) {
960             DbgFreePool(Buf);
961             return status;
962         }
963         if(curFileInfo) {
964             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
965         }
966     }
967     // resize DirIndex
968     DbgFreePool(Buf);
969 
970     hDirNdx->DIFlags &= ~UDF_DI_FLAG_INIT_IN_ICB;
971     hDirNdx->DIFlags |= (FileInfo->Dloc->DataLoc.Offset ? UDF_DI_FLAG_INIT_IN_ICB : 0);
972     return status;
973 
974 } // end UDFReTagDirectory()
975 #endif //UDF_READ_ONLY_BUILD
976 
977 /*
978     This routine performs search for specified file in specified directory &
979     returns corresponding offset in extent if found.
980  */
981 OSSTATUS
982 UDFFindFile(
983     IN PVCB Vcb,
984     IN BOOLEAN IgnoreCase,
985     IN BOOLEAN NotDeleted,
986     IN PUNICODE_STRING Name,
987     IN PUDF_FILE_INFO DirInfo,
988  IN OUT uint_di* Index      // IN:start index OUT:found file index
989     )
990 {
991 //    PDIR_INDEX_HDR hDirIndex = DirInfo->Dloc->DirIndex;
992     UNICODE_STRING ShortName;
993     WCHAR ShortNameBuffer[13];
994     PDIR_INDEX_ITEM DirNdx;
995     UDF_DIR_SCAN_CONTEXT ScanContext;
996     uint_di j=(-1), k=(-1);
997     HASH_ENTRY hashes;
998     BOOLEAN CanBe8d3;
999 
1000     UDFBuildHashEntry(Vcb, Name, &hashes, HASH_POSIX | HASH_ULFN);
1001 
1002     if((CanBe8d3 = UDFCanNameBeA8dot3(Name))) {
1003         ShortName.MaximumLength = 13 * sizeof(WCHAR);
1004         ShortName.Buffer = (PWCHAR)&ShortNameBuffer;
1005     }
1006 
1007     if(!UDFDirIndexInitScan(DirInfo, &ScanContext, (*Index)))
1008         return STATUS_OBJECT_NAME_NOT_FOUND;
1009 
1010     if(!IgnoreCase && !CanBe8d3) {
1011         // perform case sensetive sequential directory scan
1012 
1013         while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
1014             if( (DirNdx->hashes.hPosix == hashes.hPosix) &&
1015                  DirNdx->FName.Buffer &&
1016                 (!RtlCompareUnicodeString(&(DirNdx->FName), Name, FALSE)) &&
1017                ( (!UDFIsDeleted(DirNdx)) || (!NotDeleted) ) ) {
1018                 (*Index) = ScanContext.i;
1019                 return STATUS_SUCCESS;
1020             }
1021         }
1022         return STATUS_OBJECT_NAME_NOT_FOUND;
1023     }
1024 
1025     if(hashes.hPosix == hashes.hLfn) {
1026 
1027         while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
1028             if(!DirNdx->FName.Buffer ||
1029                (NotDeleted && UDFIsDeleted(DirNdx)) )
1030                 continue;
1031             if( (DirNdx->hashes.hLfn == hashes.hLfn) &&
1032                 (!RtlCompareUnicodeString(&(DirNdx->FName), Name, IgnoreCase)) ) {
1033                 (*Index) = ScanContext.i;
1034                 return STATUS_SUCCESS;
1035             } else
1036             if( CanBe8d3 &&
1037                 !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS) &&
1038                 (DirNdx->hashes.hDos == hashes.hLfn) &&
1039                 (k == (uint_di)(-1))) {
1040                 UDFDOSName(Vcb, &ShortName, &(DirNdx->FName), ScanContext.i < 2) ;
1041                 if(!RtlCompareUnicodeString(&ShortName, Name, IgnoreCase))
1042                     k = ScanContext.i;
1043             }
1044         }
1045 
1046     } else {
1047 
1048         while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
1049             // perform sequential directory scan
1050             if(!DirNdx->FName.Buffer ||
1051                (NotDeleted && UDFIsDeleted(DirNdx)) )
1052                 continue;
1053             if( (DirNdx->hashes.hPosix == hashes.hPosix) &&
1054                 (!RtlCompareUnicodeString(&(DirNdx->FName), Name, FALSE)) ) {
1055                 (*Index) = ScanContext.i;
1056                 return STATUS_SUCCESS;
1057             } else
1058             if( (DirNdx->hashes.hLfn == hashes.hLfn) &&
1059                 (j == (uint_di)(-1)) &&
1060                 (!RtlCompareUnicodeString(&(DirNdx->FName), Name, IgnoreCase)) ) {
1061                 j = ScanContext.i;
1062             } else
1063             if( CanBe8d3 &&
1064                 !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS) &&
1065                 (DirNdx->hashes.hDos == hashes.hLfn) &&
1066                 (k == (uint_di)(-1))) {
1067                 UDFDOSName(Vcb, &ShortName, &(DirNdx->FName), ScanContext.i < 2 );
1068                 if(!RtlCompareUnicodeString(&ShortName, Name, IgnoreCase)) {
1069                     k = ScanContext.i;
1070                 }
1071             }
1072         }
1073     }
1074 
1075     if(j != (uint_di)(-1)) {
1076         (*Index) = j;
1077         return STATUS_SUCCESS;
1078     } else
1079     if(k != (uint_di)(-1)) {
1080         (*Index) = k;
1081         return STATUS_SUCCESS;
1082     }
1083 
1084     return STATUS_OBJECT_NAME_NOT_FOUND;
1085 
1086 } // end UDFFindFile()
1087 
1088 /*
1089     This routine returns pointer to parent DirIndex
1090 */
1091 PDIR_INDEX_HDR
1092 UDFGetDirIndexByFileInfo(
1093     IN PUDF_FILE_INFO FileInfo
1094     )
1095 {
1096     ValidateFileInfo(FileInfo);
1097 
1098     if(!FileInfo) {
1099         BrutePoint();
1100         return NULL;
1101     }
1102     if (FileInfo->ParentFile) {
1103         ValidateFileInfo(FileInfo->ParentFile);
1104 
1105         if(UDFIsAStreamDir(FileInfo))
1106             return NULL;
1107         if(FileInfo->ParentFile->Dloc)
1108             return FileInfo->ParentFile->Dloc->DirIndex;
1109         return NULL;
1110     }
1111     if(FileInfo->Dloc)
1112         return FileInfo->Dloc->DirIndex;
1113     return NULL;
1114 }
1115 
1116 /*
1117     File Data Location support routines (UDFXxxDloc)
1118     This group is responsible for caching FE locations
1119     If requested FE referenced by another FI the file is assumed to be linked
1120     All linked files reference to common Data Location (& attr) structure
1121  */
1122 
1123 /*
1124     Check if given FE is already in use
1125  */
1126 LONG
1127 UDFFindDloc(
1128     IN PVCB Vcb,
1129     IN uint32 Lba
1130     )
1131 {
1132     PUDF_DATALOC_INDEX DlocList;
1133     uint32 l;
1134 
1135     if(!(DlocList = Vcb->DlocList) || !Lba) return (-1);
1136     // scan FE location cache
1137     l = Vcb->DlocCount;
1138     for(uint32 i=0; i<l; i++, DlocList++) {
1139         if(DlocList->Lba == Lba)
1140             return i;
1141     }
1142     return (-1);
1143 } // end UDFFindDloc()
1144 
1145 /*
1146     Check if given FE is already stored in memory
1147  */
1148 LONG
1149 UDFFindDlocInMem(
1150     IN PVCB Vcb,
1151     IN PUDF_DATALOC_INFO Dloc
1152     )
1153 {
1154     PUDF_DATALOC_INDEX DlocList;
1155     uint32 l;
1156 
1157     if(!(DlocList = Vcb->DlocList) || !Dloc) return (-1);
1158     // scan FE location cache
1159     l = Vcb->DlocCount;
1160     for(uint32 i=0; i<l; i++, DlocList++) {
1161         if(DlocList->Dloc == Dloc)
1162             return i;
1163     }
1164     return (-1);
1165 } // end UDFFindDlocInMem()
1166 
1167 /*
1168     Find free cache entry
1169  */
1170 LONG
1171 UDFFindFreeDloc(
1172     IN PVCB Vcb,
1173     IN uint32 Lba
1174     )
1175 {
1176     PUDF_DATALOC_INDEX DlocList;
1177     uint32 l;
1178 
1179     if(!Vcb->DlocList) {
1180         // init FE location cache
1181         if(!(Vcb->DlocList = (PUDF_DATALOC_INDEX)MyAllocatePoolTag__(NonPagedPool, sizeof(UDF_DATALOC_INDEX)*DLOC_LIST_GRANULARITY, MEM_DLOC_NDX_TAG)))
1182             return (-1);
1183         RtlZeroMemory(Vcb->DlocList, DLOC_LIST_GRANULARITY*sizeof(UDF_DATALOC_INDEX));
1184         Vcb->DlocCount = DLOC_LIST_GRANULARITY;
1185     }
1186     // scan for free entry
1187     DlocList = Vcb->DlocList;
1188     l = Vcb->DlocCount;
1189     for(uint32 i=0; i<l; i++, DlocList++) {
1190         if(!DlocList->Dloc)
1191             return i;
1192     }
1193     // alloc some free entries
1194     if(!MyReallocPool__((int8*)(Vcb->DlocList), Vcb->DlocCount*sizeof(UDF_DATALOC_INDEX),
1195                      (int8**)&(Vcb->DlocList), (Vcb->DlocCount+DLOC_LIST_GRANULARITY)*sizeof(UDF_DATALOC_INDEX))) {
1196         return (-1);
1197     }
1198     RtlZeroMemory(&(Vcb->DlocList[Vcb->DlocCount]), DLOC_LIST_GRANULARITY*sizeof(UDF_DATALOC_INDEX));
1199     Vcb->DlocCount += DLOC_LIST_GRANULARITY;
1200     return (Vcb->DlocCount - DLOC_LIST_GRANULARITY);
1201 } // end UDFFindFreeDloc()
1202 
1203 /*
1204  */
1205 OSSTATUS
1206 UDFAcquireDloc(
1207     IN PVCB Vcb,
1208     IN PUDF_DATALOC_INFO Dloc
1209     )
1210 {
1211     UDFAcquireResourceExclusive(&(Vcb->DlocResource2),TRUE);
1212     if(Dloc->FE_Flags & UDF_FE_FLAG_UNDER_INIT) {
1213         UDFReleaseResource(&(Vcb->DlocResource2));
1214         return STATUS_SHARING_PAUSED;
1215     }
1216     Dloc->FE_Flags |= UDF_FE_FLAG_UNDER_INIT;
1217     UDFReleaseResource(&(Vcb->DlocResource2));
1218     return STATUS_SUCCESS;
1219 } // end UDFAcquireDloc()
1220 
1221 /*
1222  */
1223 OSSTATUS
1224 UDFReleaseDloc(
1225     IN PVCB Vcb,
1226     IN PUDF_DATALOC_INFO Dloc
1227     )
1228 {
1229     UDFAcquireResourceExclusive(&(Vcb->DlocResource2),TRUE);
1230     Dloc->FE_Flags &= ~UDF_FE_FLAG_UNDER_INIT;
1231     UDFReleaseResource(&(Vcb->DlocResource2));
1232     return STATUS_SUCCESS;
1233 } // end UDFReleaseDloc()
1234 
1235 /*
1236     Try to store FE location in cache
1237     If it is already in use, caller will be informed about it
1238  */
1239 OSSTATUS
1240 UDFStoreDloc(
1241     IN PVCB Vcb,
1242     IN PUDF_FILE_INFO fi,
1243     IN uint32 Lba
1244     )
1245 {
1246     LONG i;
1247     PUDF_DATALOC_INFO Dloc;
1248 
1249     if(!Lba) return STATUS_INVALID_PARAMETER;
1250     if(Lba == (ULONG)-1) return STATUS_INVALID_PARAMETER;
1251 
1252     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1253 
1254     // check if FE specified is already in use
1255     if((i = UDFFindDloc(Vcb, Lba)) == (-1)) {
1256         // not used
1257         if((i = UDFFindFreeDloc(Vcb, Lba)) == (-1)) {
1258             UDFReleaseResource(&(Vcb->DlocResource));
1259             return STATUS_INSUFFICIENT_RESOURCES;
1260         }
1261     } else {
1262         if(!OS_SUCCESS(UDFAcquireDloc(Vcb, Dloc = Vcb->DlocList[i].Dloc))) {
1263             UDFReleaseResource(&(Vcb->DlocResource));
1264             return STATUS_SHARING_PAUSED;
1265         }
1266         // update caller's structures & exit
1267         fi->Dloc = Dloc;
1268         UDFReleaseDloc(Vcb, Dloc);
1269 #if defined UDF_DBG && !defined _CONSOLE
1270         if(fi->Dloc->CommonFcb) {
1271             ASSERT((uint32)(fi->Dloc->CommonFcb) != 0xDEADDA7A);
1272             ASSERT(fi->Dloc->CommonFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
1273         }
1274 #endif // UDF_DBG
1275         UDFReleaseResource(&(Vcb->DlocResource));
1276         return STATUS_SUCCESS;
1277     }
1278     // allocate common DataLocation (Dloc) descriptor
1279     Dloc = fi->Dloc = (PUDF_DATALOC_INFO)MyAllocatePoolTag__(UDF_DATALOC_INFO_MT, sizeof(UDF_DATALOC_INFO), MEM_DLOC_INF_TAG);
1280     if(!Dloc) {
1281         UDFReleaseResource(&(Vcb->DlocResource));
1282         return STATUS_INSUFFICIENT_RESOURCES;
1283     }
1284     Vcb->DlocList[i].Lba = Lba;
1285     Vcb->DlocList[i].Dloc = Dloc;
1286     RtlZeroMemory(Dloc, sizeof(UDF_DATALOC_INFO));
1287     Dloc->LinkedFileInfo = fi;
1288     UDFAcquireDloc(Vcb, Dloc);
1289     UDFReleaseResource(&(Vcb->DlocResource));
1290     return STATUS_SUCCESS;
1291 } // end UDFStoreDloc()
1292 
1293 /*
1294     Remove unreferenced FE location from cache & free allocated memory
1295     This routine must be invoked when there are no more opened files
1296     associated with given FE
1297  */
1298 OSSTATUS
1299 UDFRemoveDloc(
1300     IN PVCB Vcb,
1301     IN PUDF_DATALOC_INFO Dloc
1302     )
1303 {
1304     LONG i;
1305 
1306     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1307 
1308     if((i = UDFFindDlocInMem(Vcb, Dloc)) == (-1)) {
1309         // FE specified is not in cache. exit
1310         UDFReleaseResource(&(Vcb->DlocResource));
1311         return STATUS_INVALID_PARAMETER;
1312     }
1313     // remove from cache
1314     ASSERT(Vcb->DlocList);
1315     RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX));
1316     UDFReleaseResource(&(Vcb->DlocResource));
1317     MyFreePool__(Dloc);
1318     return STATUS_SUCCESS;
1319 } // end UDFRemoveDloc()
1320 
1321 /*
1322     Remove unlinked FE location from cache & keep allocated memory
1323     This routine must be invoked when there are no more opened files
1324     associated with given FE
1325  */
1326 OSSTATUS
1327 UDFUnlinkDloc(
1328     IN PVCB Vcb,
1329     IN PUDF_DATALOC_INFO Dloc
1330     )
1331 {
1332     LONG i;
1333 
1334     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1335 
1336     if((i = UDFFindDlocInMem(Vcb, Dloc)) == (-1)) {
1337         // FE specified is not in cache. exit
1338         UDFReleaseResource(&(Vcb->DlocResource));
1339         return STATUS_INVALID_PARAMETER;
1340     }
1341     // remove from cache
1342     ASSERT(Vcb->DlocList);
1343     RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX));
1344     UDFReleaseResource(&(Vcb->DlocResource));
1345     return STATUS_SUCCESS;
1346 } // end UDFUnlinkDloc()
1347 
1348 /*
1349     This routine releases memory allocated for Dloc & removes it from
1350     cache (if it is still there)
1351  */
1352 void
1353 UDFFreeDloc(
1354     IN PVCB Vcb,
1355     IN PUDF_DATALOC_INFO Dloc
1356     )
1357 {
1358     LONG i;
1359 
1360     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1361 
1362     if((i = UDFFindDlocInMem(Vcb, Dloc)) != (-1)) {
1363         ASSERT(Vcb->DlocList);
1364         RtlZeroMemory(&(Vcb->DlocList[i]), sizeof(UDF_DATALOC_INDEX));
1365     }
1366     UDFReleaseResource(&(Vcb->DlocResource));
1367     MyFreePool__(Dloc);
1368 } // end UDFFreeDloc()
1369 
1370 /*
1371     This routine updates Dloc LBA after relocation
1372  */
1373 void
1374 UDFRelocateDloc(
1375     IN PVCB Vcb,
1376     IN PUDF_DATALOC_INFO Dloc,
1377     IN uint32 NewLba
1378     )
1379 {
1380     LONG i;
1381 
1382     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1383 
1384     if((i = UDFFindDlocInMem(Vcb, Dloc)) != (-1)) {
1385         ASSERT(Vcb->DlocList);
1386         Vcb->DlocList[i].Lba = NewLba;
1387     }
1388     UDFReleaseResource(&(Vcb->DlocResource));
1389 
1390 } // end UDFRelocateDloc()
1391 
1392 /*
1393     Release FE cache
1394  */
1395 void
1396 UDFReleaseDlocList(
1397     IN PVCB Vcb
1398     )
1399 {
1400     if(!Vcb->DlocList) return;
1401     UDFAcquireResourceExclusive(&(Vcb->DlocResource),TRUE);
1402     for(uint32 i=0; i<Vcb->DlocCount; i++) {
1403         if(Vcb->DlocList[i].Dloc)
1404             MyFreePool__(Vcb->DlocList[i].Dloc);
1405     }
1406     MyFreePool__(Vcb->DlocList);
1407     Vcb->DlocList = NULL;
1408     Vcb->DlocCount = 0;
1409     UDFReleaseResource(&(Vcb->DlocResource));
1410 } // end UDFReleaseDlocList()
1411 
1412 /*
1413     This routine walks through Linked/Parallel FI chain and looks for
1414     FE with same Index & Parent File
1415  */
1416 PUDF_FILE_INFO
1417 UDFLocateParallelFI(
1418     PUDF_FILE_INFO di,  // parent FileInfo
1419     uint_di i,            // Index
1420     PUDF_FILE_INFO fi   // FileInfo to start search from
1421     )
1422 {
1423     PUDF_FILE_INFO    ParFileInfo = fi->NextLinkedFile;
1424 //    PUDF_DATALOC_INFO Dloc = di->Dloc;
1425     while((ParFileInfo != fi) &&
1426           ((ParFileInfo->ParentFile != di) ||
1427            (ParFileInfo->Index != i)) ) {
1428         ParFileInfo = ParFileInfo->NextLinkedFile;
1429     }
1430     return ParFileInfo;
1431 //   BrutePoint();
1432 } // end UDFLocateParallelFI()
1433 
1434 /*
1435     This routine walks through Linked/Parallel FI chain and looks for
1436     FE with same Index & Parent Dloc
1437  */
1438 PUDF_FILE_INFO
1439 UDFLocateAnyParallelFI(
1440     PUDF_FILE_INFO fi   // FileInfo to start search from
1441     )
1442 {
1443     if(!fi->ParentFile) {
1444         if(fi->NextLinkedFile == fi)
1445             return NULL;
1446         return fi->NextLinkedFile;
1447     }
1448     PUDF_FILE_INFO    ParFileInfo = fi->NextLinkedFile;
1449     PUDF_DATALOC_INFO Dloc = fi->ParentFile->Dloc;
1450     uint_di i = fi->Index;
1451     BOOLEAN NotFound = TRUE;
1452     while((ParFileInfo != fi) &&
1453           (NotFound =
1454            ((ParFileInfo->Index != i) ||
1455             (ParFileInfo->ParentFile->Dloc != Dloc))) ) {
1456         ParFileInfo = ParFileInfo->NextLinkedFile;
1457     }
1458 /*    if(NotFound) {
1459         if((ParFileInfo->Index == i) &&
1460            (ParFileInfo->ParentFile->Dloc == Dloc))
1461             return ParFileInfo;
1462         return NULL;
1463     }
1464     return ParFileInfo;*/
1465     return NotFound ? NULL : ParFileInfo;
1466 //   BrutePoint();
1467 } // end UDFLocateAnyParallelFI()
1468 
1469 void
1470 UDFInsertLinkedFile(
1471     PUDF_FILE_INFO fi,   // FileInfo to be added to chain
1472     PUDF_FILE_INFO fi2   // any FileInfo fro the chain
1473     )
1474 {
1475     fi->NextLinkedFile = fi2->NextLinkedFile;
1476     fi->PrevLinkedFile = fi2;
1477     fi->NextLinkedFile->PrevLinkedFile =
1478     fi->PrevLinkedFile->NextLinkedFile = fi;
1479     return;
1480 } // end UDFInsertLinkedFile()
1481 
1482