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