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