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
UDFDirIndexAlloc(IN uint_di i)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
UDFDirIndexFree(PDIR_INDEX_HDR hDirNdx)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
UDFDirIndexGrow(IN PDIR_INDEX_HDR * _hDirNdx,IN uint_di d)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
UDFDirIndexTrunc(IN PDIR_INDEX_HDR * _hDirNdx,IN uint_di d)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
UDFDirIndex(IN PDIR_INDEX_HDR hDirNdx,IN uint32 i)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
UDFDirIndexGetFrame(IN PDIR_INDEX_HDR hDirNdx,IN uint32 Frame,OUT uint32 * FrameLen,OUT uint_di * Index,IN uint_di Rel)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
UDFDirIndexInitScan(IN PUDF_FILE_INFO DirInfo,OUT PUDF_DIR_SCAN_CONTEXT Context,IN uint_di Index)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
UDFDirIndexScan(PUDF_DIR_SCAN_CONTEXT Context,PUDF_FILE_INFO * _FileInfo)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
UDFBuildHashEntry(IN PVCB Vcb,IN PUNICODE_STRING Name,OUT PHASH_ENTRY hashes,IN uint8 Mask)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
UDFFindNextFI(IN int8 * buff,IN uint32 prevOffset,IN uint32 Length)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
UDFIndexDirectory(IN PVCB Vcb,IN OUT PUDF_FILE_INFO FileInfo)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
UDFPackDirectory__(IN PVCB Vcb,IN OUT PUDF_FILE_INFO FileInfo)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
UDFReTagDirectory(IN PVCB Vcb,IN OUT PUDF_FILE_INFO FileInfo)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
UDFFindFile(IN PVCB Vcb,IN BOOLEAN IgnoreCase,IN BOOLEAN NotDeleted,IN PUNICODE_STRING Name,IN PUDF_FILE_INFO DirInfo,IN OUT uint_di * Index)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
UDFGetDirIndexByFileInfo(IN PUDF_FILE_INFO FileInfo)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
UDFFindDloc(IN PVCB Vcb,IN uint32 Lba)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
UDFFindDlocInMem(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFFindFreeDloc(IN PVCB Vcb,IN uint32 Lba)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
UDFAcquireDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFReleaseDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFStoreDloc(IN PVCB Vcb,IN PUDF_FILE_INFO fi,IN uint32 Lba)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
UDFRemoveDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFUnlinkDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFFreeDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc)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
UDFRelocateDloc(IN PVCB Vcb,IN PUDF_DATALOC_INFO Dloc,IN uint32 NewLba)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
UDFReleaseDlocList(IN PVCB Vcb)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
UDFLocateParallelFI(PUDF_FILE_INFO di,uint_di i,PUDF_FILE_INFO fi)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
UDFLocateAnyParallelFI(PUDF_FILE_INFO fi)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
UDFInsertLinkedFile(PUDF_FILE_INFO fi,PUDF_FILE_INFO fi2)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