1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 Ea.c 8 9 Abstract: 10 11 This module implements the EA routines for Fat called by 12 the dispatch driver. 13 14 15 --*/ 16 17 #include "fatprocs.h" 18 19 // 20 // The local debug trace level 21 // 22 23 #define Dbg (DEBUG_TRACE_EA) 24 25 // 26 // Local procedure prototypes 27 // 28 29 IO_STATUS_BLOCK 30 FatQueryEaUserEaList ( 31 IN PIRP_CONTEXT IrpContext, 32 OUT PCCB Ccb, 33 IN PPACKED_EA FirstPackedEa, 34 IN ULONG PackedEasLength, 35 OUT PUCHAR UserBuffer, 36 IN ULONG UserBufferLength, 37 IN PUCHAR UserEaList, 38 IN ULONG UserEaListLength, 39 IN BOOLEAN ReturnSingleEntry 40 ); 41 42 IO_STATUS_BLOCK 43 FatQueryEaIndexSpecified ( 44 IN PIRP_CONTEXT IrpContext, 45 OUT PCCB Ccb, 46 IN PPACKED_EA FirstPackedEa, 47 IN ULONG PackedEasLength, 48 OUT PUCHAR UserBuffer, 49 IN ULONG UserBufferLength, 50 IN ULONG UserEaIndex, 51 IN BOOLEAN ReturnSingleEntry 52 ); 53 54 IO_STATUS_BLOCK 55 FatQueryEaSimpleScan ( 56 IN PIRP_CONTEXT IrpContext, 57 OUT PCCB Ccb, 58 IN PPACKED_EA FirstPackedEa, 59 IN ULONG PackedEasLength, 60 OUT PUCHAR UserBuffer, 61 IN ULONG UserBufferLength, 62 IN BOOLEAN ReturnSingleEntry, 63 ULONG StartOffset 64 ); 65 66 BOOLEAN 67 FatIsDuplicateEaName ( 68 IN PIRP_CONTEXT IrpContext, 69 IN PFILE_GET_EA_INFORMATION GetEa, 70 IN PUCHAR UserBuffer 71 ); 72 73 #ifdef ALLOC_PRAGMA 74 #pragma alloc_text(PAGE, FatCommonQueryEa) 75 #pragma alloc_text(PAGE, FatCommonSetEa) 76 #pragma alloc_text(PAGE, FatFsdQueryEa) 77 #pragma alloc_text(PAGE, FatFsdSetEa) 78 #if 0 79 #pragma alloc_text(PAGE, FatIsDuplicateEaName) 80 #pragma alloc_text(PAGE, FatQueryEaIndexSpecified) 81 #pragma alloc_text(PAGE, FatQueryEaSimpleScan) 82 #pragma alloc_text(PAGE, FatQueryEaUserEaList) 83 #endif 84 #endif 85 86 87 _Function_class_(IRP_MJ_QUERY_EA) 88 _Function_class_(DRIVER_DISPATCH) 89 NTSTATUS 90 NTAPI 91 FatFsdQueryEa ( 92 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 93 _Inout_ PIRP Irp 94 ) 95 96 /*++ 97 98 Routine Description: 99 100 This routine implements the Fsd part of the NtQueryEa API 101 call. 102 103 Arguments: 104 105 VolumeDeviceObject - Supplies the volume device object where the file 106 being queried exists. 107 108 Irp - Supplies the Irp being processed. 109 110 Return Value: 111 112 NTSTATUS - The FSD status for the Irp. 113 114 --*/ 115 116 { 117 NTSTATUS Status; 118 PIRP_CONTEXT IrpContext = NULL; 119 120 BOOLEAN TopLevel; 121 122 PAGED_CODE(); 123 124 DebugTrace(+1, Dbg, "FatFsdQueryEa\n", 0); 125 126 // 127 // Call the common query routine, with blocking allowed if synchronous 128 // 129 130 FsRtlEnterFileSystem(); 131 132 TopLevel = FatIsIrpTopLevel( Irp ); 133 134 _SEH2_TRY { 135 136 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) ); 137 138 Status = FatCommonQueryEa( IrpContext, Irp ); 139 140 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 141 142 // 143 // We had some trouble trying to perform the requested 144 // operation, so we'll abort the I/O request with 145 // the error status that we get back from the 146 // execption code 147 // 148 149 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 150 } _SEH2_END; 151 152 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 153 154 FsRtlExitFileSystem(); 155 156 // 157 // And return to our caller 158 // 159 160 DebugTrace(-1, Dbg, "FatFsdQueryEa -> %08lx\n", Status); 161 162 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 163 164 return Status; 165 } 166 167 168 _Function_class_(IRP_MJ_SET_EA) 169 _Function_class_(DRIVER_DISPATCH) 170 NTSTATUS 171 NTAPI 172 FatFsdSetEa ( 173 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 174 _Inout_ PIRP Irp 175 ) 176 177 /*++ 178 179 Routine Description: 180 181 This routine implements the FSD part of the NtSetEa API 182 call. 183 184 Arguments: 185 186 VolumeDeviceObject - Supplies the volume device object where the file 187 being set exists. 188 189 Irp - Supplies the Irp being processed. 190 191 Return Value: 192 193 NTSTATUS - The FSD status for the Irp. 194 195 --*/ 196 197 { 198 NTSTATUS Status; 199 PIRP_CONTEXT IrpContext = NULL; 200 201 BOOLEAN TopLevel; 202 203 PAGED_CODE(); 204 205 DebugTrace(+1, Dbg, "FatFsdSetEa\n", 0); 206 207 // 208 // Call the common set routine, with blocking allowed if synchronous 209 // 210 211 FsRtlEnterFileSystem(); 212 213 TopLevel = FatIsIrpTopLevel( Irp ); 214 215 _SEH2_TRY { 216 217 IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) ); 218 219 Status = FatCommonSetEa( IrpContext, Irp ); 220 221 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 222 223 // 224 // We had some trouble trying to perform the requested 225 // operation, so we'll abort the I/O request with 226 // the error status that we get back from the 227 // execption code 228 // 229 230 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 231 } _SEH2_END; 232 233 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 234 235 FsRtlExitFileSystem(); 236 237 // 238 // And return to our caller 239 // 240 241 DebugTrace(-1, Dbg, "FatFsdSetEa -> %08lx\n", Status); 242 243 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 244 245 return Status; 246 } 247 248 249 NTSTATUS 250 FatCommonQueryEa ( 251 IN PIRP_CONTEXT IrpContext, 252 IN PIRP Irp 253 ) 254 255 /*++ 256 257 Routine Description: 258 259 This is the common routine for querying File ea called by both 260 the fsd and fsp threads. 261 262 Arguments: 263 264 Irp - Supplies the Irp being processed 265 266 Return Value: 267 268 NTSTATUS - The return status for the operation 269 270 --*/ 271 272 { 273 #if 0 274 PIO_STACK_LOCATION IrpSp; 275 276 NTSTATUS Status; 277 278 PUCHAR Buffer; 279 ULONG UserBufferLength; 280 281 PUCHAR UserEaList; 282 ULONG UserEaListLength; 283 ULONG UserEaIndex; 284 BOOLEAN RestartScan; 285 BOOLEAN ReturnSingleEntry; 286 BOOLEAN IndexSpecified; 287 288 PVCB Vcb; 289 PCCB Ccb; 290 291 PFCB Fcb; 292 PDIRENT Dirent; 293 PBCB Bcb; 294 295 PDIRENT EaDirent; 296 PBCB EaBcb; 297 BOOLEAN LockedEaFcb; 298 299 PEA_SET_HEADER EaSetHeader; 300 EA_RANGE EaSetRange; 301 302 USHORT ExtendedAttributes; 303 #endif 304 305 PAGED_CODE(); 306 307 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST); 308 return STATUS_INVALID_DEVICE_REQUEST; 309 310 #if 0 311 // 312 // Get the current Irp stack location 313 // 314 315 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 316 317 DebugTrace(+1, Dbg, "FatCommonQueryEa...\n", 0); 318 DebugTrace( 0, Dbg, " Wait = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); 319 DebugTrace( 0, Dbg, " Irp = %p\n", Irp ); 320 DebugTrace( 0, Dbg, " ->SystemBuffer = %p\n", Irp->AssociatedIrp.SystemBuffer ); 321 DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.QueryEa.Length ); 322 DebugTrace( 0, Dbg, " ->EaList = %08lx\n", IrpSp->Parameters.QueryEa.EaList ); 323 DebugTrace( 0, Dbg, " ->EaListLength = %08lx\n", IrpSp->Parameters.QueryEa.EaListLength ); 324 DebugTrace( 0, Dbg, " ->EaIndex = %08lx\n", IrpSp->Parameters.QueryEa.EaIndex ); 325 DebugTrace( 0, Dbg, " ->RestartScan = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN)); 326 DebugTrace( 0, Dbg, " ->ReturnSingleEntry = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY)); 327 DebugTrace( 0, Dbg, " ->IndexSpecified = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED)); 328 329 Irp->IoStatus.Status = STATUS_SUCCESS; 330 Irp->IoStatus.Information = 0; 331 332 // 333 // Check that the file object is associated with either a user file 334 // or directory open. We don't allow Ea operations on the root 335 // directory. 336 // 337 338 { 339 TYPE_OF_OPEN OpenType; 340 341 if (((OpenType = FatDecodeFileObject( IrpSp->FileObject, 342 &Vcb, 343 &Fcb, 344 &Ccb )) != UserFileOpen 345 && OpenType != UserDirectoryOpen) || 346 347 (NodeType( Fcb )) == FAT_NTC_ROOT_DCB) { 348 349 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 350 351 DebugTrace(-1, Dbg, 352 "FatCommonQueryEa -> %08lx\n", 353 STATUS_INVALID_PARAMETER); 354 355 return STATUS_INVALID_PARAMETER; 356 } 357 } 358 359 // 360 // Fat32 does not support ea's. 361 // 362 363 if (FatIsFat32(Vcb)) { 364 365 FatCompleteRequest( IrpContext, Irp, STATUS_EAS_NOT_SUPPORTED ); 366 DebugTrace(-1, Dbg, 367 "FatCommonQueryEa -> %08lx\n", 368 STATUS_EAS_NOT_SUPPORTED); 369 return STATUS_EAS_NOT_SUPPORTED; 370 } 371 372 // 373 // Acquire shared access to the Fcb and enqueue the Irp if we didn't 374 // get access. 375 // 376 377 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { 378 379 DebugTrace(0, Dbg, "FatCommonQueryEa: Thread can't wait\n", 0); 380 381 Status = FatFsdPostRequest( IrpContext, Irp ); 382 383 DebugTrace(-1, Dbg, "FatCommonQueryEa -> %08lx\n", Status ); 384 385 return Status; 386 } 387 388 FatAcquireSharedFcb( IrpContext, Fcb ); 389 390 // 391 // Reference our input parameters to make things easier 392 // 393 394 UserBufferLength = IrpSp->Parameters.QueryEa.Length; 395 UserEaList = IrpSp->Parameters.QueryEa.EaList; 396 UserEaListLength = IrpSp->Parameters.QueryEa.EaListLength; 397 UserEaIndex = IrpSp->Parameters.QueryEa.EaIndex; 398 RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN); 399 ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); 400 IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); 401 402 // 403 // Initialize our local values. 404 // 405 406 LockedEaFcb = FALSE; 407 Bcb = NULL; 408 EaBcb = NULL; 409 410 Status = STATUS_SUCCESS; 411 412 RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE )); 413 414 try { 415 416 PPACKED_EA FirstPackedEa; 417 ULONG PackedEasLength; 418 419 Buffer = FatMapUserBuffer( IrpContext, Irp ); 420 421 // 422 // We verify that the Fcb is still valid. 423 // 424 425 FatVerifyFcb( IrpContext, Fcb ); 426 427 // 428 // We need to get the dirent for the Fcb to recover the Ea handle. 429 // 430 431 FatGetDirentFromFcbOrDcb( IrpContext, Fcb, &Dirent, &Bcb ); 432 433 // 434 // Verify that the Ea file is in a consistant state. If the 435 // Ea modification count in the Fcb doesn't match that in 436 // the CCB, then the Ea file has been changed from under 437 // us. If we are not starting the search from the beginning 438 // of the Ea set, we return an error. 439 // 440 441 if (UserEaList == NULL 442 && Ccb->OffsetOfNextEaToReturn != 0 443 && !IndexSpecified 444 && !RestartScan 445 && Fcb->EaModificationCount != Ccb->EaModificationCount) { 446 447 DebugTrace(0, Dbg, 448 "FatCommonQueryEa: Ea file in unknown state\n", 0); 449 450 Status = STATUS_EA_CORRUPT_ERROR; 451 452 try_return( Status ); 453 } 454 455 // 456 // Show that the Ea's for this file are consistant for this 457 // file handle. 458 // 459 460 Ccb->EaModificationCount = Fcb->EaModificationCount; 461 462 // 463 // If the handle value is 0, then the file has no Eas. We dummy up 464 // an ea list to use below. 465 // 466 467 ExtendedAttributes = Dirent->ExtendedAttributes; 468 469 FatUnpinBcb( IrpContext, Bcb ); 470 471 if (ExtendedAttributes == 0) { 472 473 DebugTrace(0, Dbg, 474 "FatCommonQueryEa: Zero handle, no Ea's for this file\n", 0); 475 476 FirstPackedEa = (PPACKED_EA) NULL; 477 478 PackedEasLength = 0; 479 480 } else { 481 482 // 483 // We need to get the Ea file for this volume. If the 484 // operation doesn't complete due to blocking, then queue the 485 // Irp to the Fsp. 486 // 487 488 FatGetEaFile( IrpContext, 489 Vcb, 490 &EaDirent, 491 &EaBcb, 492 FALSE, 493 FALSE ); 494 495 LockedEaFcb = TRUE; 496 497 // 498 // If the above operation completed and the Ea file did not exist, 499 // the disk has been corrupted. There is an existing Ea handle 500 // without any Ea data. 501 // 502 503 if (Vcb->VirtualEaFile == NULL) { 504 505 DebugTrace(0, Dbg, 506 "FatCommonQueryEa: No Ea file found when expected\n", 0); 507 508 Status = STATUS_NO_EAS_ON_FILE; 509 510 try_return( Status ); 511 } 512 513 // 514 // We need to try to get the Ea set for the desired file. If 515 // blocking is necessary then we'll post the request to the Fsp. 516 // 517 518 FatReadEaSet( IrpContext, 519 Vcb, 520 ExtendedAttributes, 521 &Fcb->ShortName.Name.Oem, 522 TRUE, 523 &EaSetRange ); 524 525 EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data; 526 527 // 528 // Find the start and length of the Eas. 529 // 530 531 FirstPackedEa = (PPACKED_EA) EaSetHeader->PackedEas; 532 533 PackedEasLength = GetcbList( EaSetHeader ) - 4; 534 } 535 536 // 537 // Protect our access to the user buffer since IO dosn't do this 538 // for us in this path unless we had specified that our driver 539 // requires buffering for these large requests. We don't, so ... 540 // 541 542 try { 543 544 // 545 // Let's clear the output buffer. 546 // 547 548 RtlZeroMemory( Buffer, UserBufferLength ); 549 550 // 551 // We now satisfy the user's request depending on whether he 552 // specified an Ea name list, an Ea index or restarting the 553 // search. 554 // 555 556 // 557 // The user has supplied a list of Ea names. 558 // 559 560 if (UserEaList != NULL) { 561 562 Irp->IoStatus = FatQueryEaUserEaList( IrpContext, 563 Ccb, 564 FirstPackedEa, 565 PackedEasLength, 566 Buffer, 567 UserBufferLength, 568 UserEaList, 569 UserEaListLength, 570 ReturnSingleEntry ); 571 572 // 573 // The user supplied an index into the Ea list. 574 // 575 576 } else if (IndexSpecified) { 577 578 Irp->IoStatus = FatQueryEaIndexSpecified( IrpContext, 579 Ccb, 580 FirstPackedEa, 581 PackedEasLength, 582 Buffer, 583 UserBufferLength, 584 UserEaIndex, 585 ReturnSingleEntry ); 586 587 // 588 // Else perform a simple scan, taking into account the restart 589 // flag and the position of the next Ea stored in the Ccb. 590 // 591 592 } else { 593 594 Irp->IoStatus = FatQueryEaSimpleScan( IrpContext, 595 Ccb, 596 FirstPackedEa, 597 PackedEasLength, 598 Buffer, 599 UserBufferLength, 600 ReturnSingleEntry, 601 RestartScan 602 ? 0 603 : Ccb->OffsetOfNextEaToReturn ); 604 } 605 606 } except (!FsRtlIsNtstatusExpected(GetExceptionCode()) ? 607 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 608 609 // 610 // We must have had a problem filling in the user's buffer, so fail. 611 // 612 613 Irp->IoStatus.Status = GetExceptionCode(); 614 Irp->IoStatus.Information = 0; 615 } 616 617 Status = Irp->IoStatus.Status; 618 619 try_exit: NOTHING; 620 } finally { 621 622 DebugUnwind( FatCommonQueryEa ); 623 624 // 625 // Release the Fcb for the file object, and the Ea Fcb if 626 // successfully locked. 627 // 628 629 FatReleaseFcb( IrpContext, Fcb ); 630 631 if (LockedEaFcb) { 632 633 FatReleaseFcb( IrpContext, Vcb->EaFcb ); 634 } 635 636 // 637 // Unpin the dirents for the Fcb, EaFcb and EaSetFcb if necessary. 638 // 639 640 FatUnpinBcb( IrpContext, Bcb ); 641 FatUnpinBcb( IrpContext, EaBcb ); 642 643 FatUnpinEaRange( IrpContext, &EaSetRange ); 644 645 if (!AbnormalTermination()) { 646 647 FatCompleteRequest( IrpContext, Irp, Status ); 648 } 649 650 DebugTrace(-1, Dbg, "FatCommonQueryEa -> %08lx\n", Status); 651 } 652 653 return Status; 654 #endif 655 } 656 657 658 NTSTATUS 659 FatCommonSetEa ( 660 IN PIRP_CONTEXT IrpContext, 661 IN PIRP Irp 662 ) 663 664 /*++ 665 666 Routine Description: 667 668 This routine implements the common Set Ea File Api called by the 669 the Fsd and Fsp threads 670 671 Arguments: 672 673 Irp - Supplies the Irp to process 674 675 Return Value: 676 677 NTSTATUS - The appropriate status for the Irp 678 679 --*/ 680 681 { 682 #if 0 683 PIO_STACK_LOCATION IrpSp; 684 685 NTSTATUS Status; 686 687 USHORT ExtendedAttributes; 688 689 PUCHAR Buffer; 690 ULONG UserBufferLength; 691 692 PVCB Vcb; 693 PCCB Ccb; 694 695 PFCB Fcb; 696 PDIRENT Dirent; 697 PBCB Bcb = NULL; 698 699 PDIRENT EaDirent = NULL; 700 PBCB EaBcb = NULL; 701 702 PEA_SET_HEADER EaSetHeader = NULL; 703 704 PEA_SET_HEADER PrevEaSetHeader; 705 PEA_SET_HEADER NewEaSetHeader; 706 EA_RANGE EaSetRange; 707 708 BOOLEAN AcquiredVcb = FALSE; 709 BOOLEAN AcquiredFcb = FALSE; 710 BOOLEAN AcquiredParentDcb = FALSE; 711 BOOLEAN AcquiredRootDcb = FALSE; 712 BOOLEAN AcquiredEaFcb = FALSE; 713 #endif 714 715 PAGED_CODE(); 716 717 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST); 718 return STATUS_INVALID_DEVICE_REQUEST; 719 720 #if 0 721 722 // 723 // The following booleans are used in the unwind process. 724 // 725 726 // 727 // Get the current Irp stack location 728 // 729 730 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 731 732 DebugTrace(+1, Dbg, "FatCommonSetEa...\n", 0); 733 DebugTrace( 0, Dbg, " Wait = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); 734 DebugTrace( 0, Dbg, " Irp = %p\n", Irp ); 735 DebugTrace( 0, Dbg, " ->SystemBuffer = %p\n", Irp->AssociatedIrp.SystemBuffer ); 736 DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.SetEa.Length ); 737 738 Irp->IoStatus.Status = STATUS_SUCCESS; 739 Irp->IoStatus.Information = 0; 740 741 // 742 // Check that the file object is associated with either a user file 743 // or directory open. 744 // 745 746 { 747 TYPE_OF_OPEN OpenType; 748 749 if (((OpenType = FatDecodeFileObject( IrpSp->FileObject, 750 &Vcb, 751 &Fcb, 752 &Ccb )) != UserFileOpen 753 && OpenType != UserDirectoryOpen) || 754 755 (NodeType( Fcb )) == FAT_NTC_ROOT_DCB) { 756 757 FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); 758 759 DebugTrace(-1, Dbg, 760 "FatCommonSetEa -> %08lx\n", 761 STATUS_INVALID_PARAMETER); 762 763 return STATUS_INVALID_PARAMETER; 764 } 765 } 766 767 // 768 // Fat32 does not support ea's. 769 // 770 771 if (FatIsFat32(Vcb)) { 772 773 FatCompleteRequest( IrpContext, Irp, STATUS_EAS_NOT_SUPPORTED ); 774 DebugTrace(-1, Dbg, 775 "FatCommonSetEa -> %08lx\n", 776 STATUS_EAS_NOT_SUPPORTED); 777 return STATUS_EAS_NOT_SUPPORTED; 778 } 779 780 // 781 // Reference our input parameters to make things easier 782 // 783 784 UserBufferLength = IrpSp->Parameters.SetEa.Length; 785 786 // 787 // Since we ask for no outside help (direct or buffered IO), it 788 // is our responsibility to insulate ourselves from the 789 // deviousness of the user above. Now, buffer and validate the 790 // contents. 791 // 792 793 Buffer = FatBufferUserBuffer( IrpContext, Irp, UserBufferLength ); 794 795 // 796 // Check the validity of the buffer with the new eas. We really 797 // need to do this always since we don't know, if it was already 798 // buffered, that we buffered and checked it or some overlying 799 // filter buffered without checking. 800 // 801 802 Status = IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION) Buffer, 803 UserBufferLength, 804 (PULONG)&Irp->IoStatus.Information ); 805 806 if (!NT_SUCCESS( Status )) { 807 808 FatCompleteRequest( IrpContext, Irp, Status ); 809 DebugTrace(-1, Dbg, 810 "FatCommonSetEa -> %08lx\n", 811 Status); 812 return Status; 813 } 814 815 // 816 // Acquire exclusive access to the Fcb. If this is a write-through operation 817 // we will need to pick up the other possible streams that can be modified in 818 // this operation so that the locking order is preserved - the root directory 819 // (dirent addition if EA database doesn't already exist) and the parent 820 // directory (addition of the EA handle to the object's dirent). 821 // 822 // We are primarily synchronizing with directory enumeration here. 823 // 824 // If we cannot wait need to send things off to the fsp. 825 // 826 827 if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { 828 829 DebugTrace(0, Dbg, "FatCommonSetEa: Set Ea must be waitable\n", 0); 830 831 Status = FatFsdPostRequest( IrpContext, Irp ); 832 833 DebugTrace(-1, Dbg, "FatCommonSetEa -> %08lx\n", Status ); 834 835 return Status; 836 } 837 838 // 839 // Set this handle as having modified the file 840 // 841 842 IrpSp->FileObject->Flags |= FO_FILE_MODIFIED; 843 844 RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE )); 845 846 try { 847 848 ULONG PackedEasLength; 849 BOOLEAN PreviousEas; 850 ULONG AllocationLength; 851 ULONG BytesPerCluster; 852 USHORT EaHandle; 853 854 PFILE_FULL_EA_INFORMATION FullEa; 855 856 // 857 // Now go pick up everything 858 // 859 860 FatAcquireSharedVcb( IrpContext, Fcb->Vcb ); 861 AcquiredVcb = TRUE; 862 FatAcquireExclusiveFcb( IrpContext, Fcb ); 863 AcquiredFcb = TRUE; 864 865 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { 866 867 if (Fcb->ParentDcb) { 868 869 FatAcquireExclusiveFcb( IrpContext, Fcb->ParentDcb ); 870 AcquiredParentDcb = TRUE; 871 } 872 873 FatAcquireExclusiveFcb( IrpContext, Fcb->Vcb->RootDcb ); 874 AcquiredRootDcb = TRUE; 875 } 876 877 // 878 // We verify that the Fcb is still valid. 879 // 880 881 FatVerifyFcb( IrpContext, Fcb ); 882 883 // 884 // We need to get the dirent for the Fcb to recover the Ea handle. 885 // 886 887 FatGetDirentFromFcbOrDcb( IrpContext, Fcb, &Dirent, &Bcb ); 888 889 DebugTrace(0, Dbg, "FatCommonSetEa: Dirent Address -> %p\n", 890 Dirent ); 891 DebugTrace(0, Dbg, "FatCommonSetEa: Dirent Bcb -> %p\n", 892 Bcb); 893 894 // 895 // If the handle value is 0, then the file has no Eas. In that 896 // case we allocate memory to hold the Eas to be added. If there 897 // are existing Eas for the file, then we must read from the 898 // file and copy the Eas. 899 // 900 901 ExtendedAttributes = Dirent->ExtendedAttributes; 902 903 FatUnpinBcb( IrpContext, Bcb ); 904 905 if (ExtendedAttributes == 0) { 906 907 PreviousEas = FALSE; 908 909 DebugTrace(0, Dbg, 910 "FatCommonSetEa: File has no current Eas\n", 0 ); 911 912 } else { 913 914 PreviousEas = TRUE; 915 916 DebugTrace(0, Dbg, "FatCommonSetEa: File has previous Eas\n", 0 ); 917 918 FatGetEaFile( IrpContext, 919 Vcb, 920 &EaDirent, 921 &EaBcb, 922 FALSE, 923 TRUE ); 924 925 AcquiredEaFcb = TRUE; 926 927 // 928 // If we didn't get the file then there is an error on 929 // the disk. 930 // 931 932 if (Vcb->VirtualEaFile == NULL) { 933 934 Status = STATUS_NO_EAS_ON_FILE; 935 try_return( Status ); 936 } 937 } 938 939 DebugTrace(0, Dbg, "FatCommonSetEa: EaBcb -> %p\n", EaBcb); 940 941 DebugTrace(0, Dbg, "FatCommonSetEa: EaDirent -> %p\n", EaDirent); 942 943 // 944 // If the file has existing ea's, we need to read them to 945 // determine the size of the buffer allocation. 946 // 947 948 if (PreviousEas) { 949 950 // 951 // We need to try to get the Ea set for the desired file. 952 // 953 954 FatReadEaSet( IrpContext, 955 Vcb, 956 ExtendedAttributes, 957 &Fcb->ShortName.Name.Oem, 958 TRUE, 959 &EaSetRange ); 960 961 PrevEaSetHeader = (PEA_SET_HEADER) EaSetRange.Data; 962 963 // 964 // We now must allocate pool memory for our copy of the 965 // EaSetHeader and then copy the Ea data into it. At that 966 // time we can unpin the EaSet. 967 // 968 969 PackedEasLength = GetcbList( PrevEaSetHeader ) - 4; 970 971 // 972 // Else we will create a dummy EaSetHeader. 973 // 974 975 } else { 976 977 PackedEasLength = 0; 978 } 979 980 BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster; 981 982 AllocationLength = (PackedEasLength 983 + SIZE_OF_EA_SET_HEADER 984 + BytesPerCluster - 1) 985 & ~(BytesPerCluster - 1); 986 987 EaSetHeader = FsRtlAllocatePoolWithTag( PagedPool, 988 AllocationLength, 989 TAG_EA_SET_HEADER ); 990 991 // 992 // Copy the existing Eas over to pool memory. 993 // 994 995 if (PreviousEas) { 996 997 RtlCopyMemory( EaSetHeader, PrevEaSetHeader, AllocationLength ); 998 999 FatUnpinEaRange( IrpContext, &EaSetRange ); 1000 1001 } else { 1002 1003 RtlZeroMemory( EaSetHeader, AllocationLength ); 1004 1005 RtlCopyMemory( EaSetHeader->OwnerFileName, 1006 Fcb->ShortName.Name.Oem.Buffer, 1007 Fcb->ShortName.Name.Oem.Length ); 1008 } 1009 1010 1011 AllocationLength -= SIZE_OF_EA_SET_HEADER; 1012 1013 DebugTrace(0, Dbg, "FatCommonSetEa: Initial Ea set -> %p\n", 1014 EaSetHeader); 1015 1016 // 1017 // At this point we have either read in the current eas for the file 1018 // or we have initialized a new empty buffer for the eas. Now for 1019 // each full ea in the input user buffer we do the specified operation 1020 // on the ea 1021 // 1022 1023 for (FullEa = (PFILE_FULL_EA_INFORMATION) Buffer; 1024 FullEa < (PFILE_FULL_EA_INFORMATION) &Buffer[UserBufferLength]; 1025 FullEa = (PFILE_FULL_EA_INFORMATION) (FullEa->NextEntryOffset == 0 ? 1026 &Buffer[UserBufferLength] : 1027 (PUCHAR) FullEa + FullEa->NextEntryOffset)) { 1028 1029 OEM_STRING EaName; 1030 ULONG Offset; 1031 1032 EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; 1033 EaName.Buffer = &FullEa->EaName[0]; 1034 1035 DebugTrace(0, Dbg, "FatCommonSetEa: Next Ea name -> %Z\n", 1036 &EaName); 1037 1038 // 1039 // Make sure the ea name is valid 1040 // 1041 1042 if (!FatIsEaNameValid( IrpContext,EaName )) { 1043 1044 Irp->IoStatus.Information = (PUCHAR)FullEa - Buffer; 1045 Status = STATUS_INVALID_EA_NAME; 1046 try_return( Status ); 1047 } 1048 1049 // 1050 // Check that no invalid ea flags are set. 1051 // 1052 1053 // 1054 // TEMPCODE We are returning STATUS_INVALID_EA_NAME 1055 // until a more appropriate error code exists. 1056 // 1057 1058 if (FullEa->Flags != 0 1059 && FullEa->Flags != FILE_NEED_EA) { 1060 1061 Irp->IoStatus.Information = (PUCHAR)FullEa - (PUCHAR)Buffer; 1062 try_return( Status = STATUS_INVALID_EA_NAME ); 1063 } 1064 1065 // 1066 // See if we can locate the ea name in the ea set 1067 // 1068 1069 if (FatLocateEaByName( IrpContext, 1070 (PPACKED_EA) EaSetHeader->PackedEas, 1071 PackedEasLength, 1072 &EaName, 1073 &Offset )) { 1074 1075 DebugTrace(0, Dbg, "FatCommonSetEa: Found Ea name\n", 0); 1076 1077 // 1078 // We found the ea name so now delete the current entry, 1079 // and if the new ea value length is not zero then we 1080 // replace if with the new ea 1081 // 1082 1083 FatDeletePackedEa( IrpContext, 1084 EaSetHeader, 1085 &PackedEasLength, 1086 Offset ); 1087 } 1088 1089 if (FullEa->EaValueLength != 0) { 1090 1091 FatAppendPackedEa( IrpContext, 1092 &EaSetHeader, 1093 &PackedEasLength, 1094 &AllocationLength, 1095 FullEa, 1096 BytesPerCluster ); 1097 } 1098 } 1099 1100 // 1101 // If there are any ea's not removed, we 1102 // call 'AddEaSet' to insert them into the Fat chain. 1103 // 1104 1105 if (PackedEasLength != 0) { 1106 1107 LARGE_INTEGER EaOffset; 1108 1109 EaOffset.HighPart = 0; 1110 1111 // 1112 // If the packed eas length (plus 4 bytes) is greater 1113 // than the maximum allowed ea size, we return an error. 1114 // 1115 1116 if (PackedEasLength + 4 > MAXIMUM_EA_SIZE) { 1117 1118 DebugTrace( 0, Dbg, "Ea length is greater than maximum\n", 0 ); 1119 1120 try_return( Status = STATUS_EA_TOO_LARGE ); 1121 } 1122 1123 // 1124 // We need to now read the ea file if we haven't already. 1125 // 1126 1127 if (EaDirent == NULL) { 1128 1129 FatGetEaFile( IrpContext, 1130 Vcb, 1131 &EaDirent, 1132 &EaBcb, 1133 TRUE, 1134 TRUE ); 1135 1136 AcquiredEaFcb = TRUE; 1137 } 1138 1139 FatGetDirentFromFcbOrDcb( IrpContext, Fcb, &Dirent, &Bcb ); 1140 1141 RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE )); 1142 1143 FatAddEaSet( IrpContext, 1144 Vcb, 1145 PackedEasLength + SIZE_OF_EA_SET_HEADER, 1146 EaBcb, 1147 EaDirent, 1148 &EaHandle, 1149 &EaSetRange ); 1150 1151 NewEaSetHeader = (PEA_SET_HEADER) EaSetRange.Data; 1152 1153 DebugTrace(0, Dbg, "FatCommonSetEa: Adding an ea set\n", 0); 1154 1155 // 1156 // Store the length of the new Ea's into the EaSetHeader. 1157 // This is the PackedEasLength + 4. 1158 // 1159 1160 PackedEasLength += 4; 1161 1162 CopyU4char( EaSetHeader->cbList, &PackedEasLength ); 1163 1164 // 1165 // Copy all but the first four bytes of EaSetHeader into 1166 // NewEaSetHeader. The signature and index fields have 1167 // already been filled in. 1168 // 1169 1170 RtlCopyMemory( &NewEaSetHeader->NeedEaCount, 1171 &EaSetHeader->NeedEaCount, 1172 PackedEasLength + SIZE_OF_EA_SET_HEADER - 8 ); 1173 1174 FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange ); 1175 FatUnpinEaRange( IrpContext, &EaSetRange ); 1176 1177 CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL ); 1178 1179 } else { 1180 1181 FatGetDirentFromFcbOrDcb( IrpContext, Fcb, &Dirent, &Bcb ); 1182 1183 EaHandle = 0; 1184 } 1185 1186 // 1187 // Now we do a wholesale replacement of the ea for the file 1188 // 1189 1190 if (PreviousEas) { 1191 1192 FatDeleteEaSet( IrpContext, 1193 Vcb, 1194 EaBcb, 1195 EaDirent, 1196 ExtendedAttributes, 1197 &Fcb->ShortName.Name.Oem ); 1198 1199 CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL ); 1200 } 1201 1202 if (PackedEasLength != 0 ) { 1203 1204 Fcb->EaModificationCount++; 1205 } 1206 1207 // 1208 // Mark the dirent with the new ea's 1209 // 1210 1211 Dirent->ExtendedAttributes = EaHandle; 1212 1213 FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE ); 1214 1215 // 1216 // We call the notify package to report that the ea's were 1217 // modified. 1218 // 1219 1220 FatNotifyReportChange( IrpContext, 1221 Vcb, 1222 Fcb, 1223 FILE_NOTIFY_CHANGE_EA, 1224 FILE_ACTION_MODIFIED ); 1225 1226 Irp->IoStatus.Information = 0; 1227 Status = STATUS_SUCCESS; 1228 1229 try_exit: NOTHING; 1230 1231 // 1232 // Unpin the dirents for the Fcb and EaFcb if necessary. 1233 // 1234 1235 FatUnpinBcb( IrpContext, Bcb ); 1236 FatUnpinBcb( IrpContext, EaBcb ); 1237 1238 FatUnpinRepinnedBcbs( IrpContext ); 1239 1240 } finally { 1241 1242 DebugUnwind( FatCommonSetEa ); 1243 1244 // 1245 // If this is an abnormal termination, we need to clean up 1246 // any locked resources. 1247 // 1248 1249 if (AbnormalTermination()) { 1250 1251 // 1252 // Unpin the dirents for the Fcb, EaFcb and EaSetFcb if necessary. 1253 // 1254 1255 FatUnpinBcb( IrpContext, Bcb ); 1256 FatUnpinBcb( IrpContext, EaBcb ); 1257 1258 FatUnpinEaRange( IrpContext, &EaSetRange ); 1259 } 1260 1261 // 1262 // Release the Fcbs/Vcb acquired. 1263 // 1264 1265 if (AcquiredEaFcb) { 1266 FatReleaseFcb( IrpContext, Vcb->EaFcb ); 1267 } 1268 1269 if (AcquiredFcb) { 1270 FatReleaseFcb( IrpContext, Fcb ); 1271 } 1272 1273 if (AcquiredParentDcb) { 1274 FatReleaseFcb( IrpContext, Fcb->ParentDcb ); 1275 } 1276 1277 if (AcquiredRootDcb) { 1278 FatReleaseFcb( IrpContext, Fcb->Vcb->RootDcb ); 1279 } 1280 1281 if (AcquiredVcb) { 1282 FatReleaseVcb( IrpContext, Fcb->Vcb ); 1283 } 1284 1285 // 1286 // Deallocate our Ea buffer. 1287 // 1288 1289 if (EaSetHeader != NULL) { 1290 1291 ExFreePool( EaSetHeader ); 1292 } 1293 1294 // 1295 // Complete the irp. 1296 // 1297 1298 if (!AbnormalTermination()) { 1299 1300 FatCompleteRequest( IrpContext, Irp, Status ); 1301 } 1302 1303 DebugTrace(-1, Dbg, "FatCommonSetEa -> %08lx\n", Status); 1304 } 1305 1306 // 1307 // And return to our caller 1308 // 1309 1310 return Status; 1311 #endif 1312 } 1313 1314 1315 #if 0 1316 1317 // 1318 // Local Support Routine 1319 // 1320 1321 IO_STATUS_BLOCK 1322 FatQueryEaUserEaList ( 1323 IN PIRP_CONTEXT IrpContext, 1324 OUT PCCB Ccb, 1325 IN PPACKED_EA FirstPackedEa, 1326 IN ULONG PackedEasLength, 1327 OUT PUCHAR UserBuffer, 1328 IN ULONG UserBufferLength, 1329 IN PUCHAR UserEaList, 1330 IN ULONG UserEaListLength, 1331 IN BOOLEAN ReturnSingleEntry 1332 ) 1333 1334 /*++ 1335 1336 Routine Description: 1337 1338 This routine is the work routine for querying EAs given an ea index 1339 1340 Arguments: 1341 1342 Ccb - Supplies the Ccb for the query 1343 1344 FirstPackedEa - Supplies the first ea for the file being queried 1345 1346 PackedEasLength - Supplies the length of the ea data 1347 1348 UserBuffer - Supplies the buffer to receive the full eas 1349 1350 UserBufferLength - Supplies the length, in bytes, of the user buffer 1351 1352 UserEaList - Supplies the user specified ea name list 1353 1354 UserEaListLength - Supplies the length, in bytes, of the user ea list 1355 1356 ReturnSingleEntry - Indicates if we are to return a single entry or not 1357 1358 Return Value: 1359 1360 IO_STATUS_BLOCK - Receives the completion status for the operation 1361 1362 --*/ 1363 1364 { 1365 IO_STATUS_BLOCK Iosb; 1366 1367 ULONG Offset; 1368 ULONG RemainingUserBufferLength; 1369 1370 PPACKED_EA PackedEa; 1371 ULONG PackedEaSize; 1372 1373 PFILE_FULL_EA_INFORMATION LastFullEa = NULL; 1374 ULONG LastFullEaSize; 1375 PFILE_FULL_EA_INFORMATION NextFullEa; 1376 1377 PFILE_GET_EA_INFORMATION GetEa; 1378 1379 BOOLEAN Overflow; 1380 1381 DebugTrace(+1, Dbg, "FatQueryEaUserEaList...\n", 0); 1382 1383 LastFullEa = NULL; 1384 NextFullEa = (PFILE_FULL_EA_INFORMATION) UserBuffer; 1385 RemainingUserBufferLength = UserBufferLength; 1386 1387 Overflow = FALSE; 1388 1389 for (GetEa = (PFILE_GET_EA_INFORMATION) &UserEaList[0]; 1390 GetEa < (PFILE_GET_EA_INFORMATION) ((PUCHAR) UserEaList 1391 + UserEaListLength); 1392 GetEa = (GetEa->NextEntryOffset == 0 1393 ? (PFILE_GET_EA_INFORMATION) MAXUINT_PTR 1394 : (PFILE_GET_EA_INFORMATION) ((PUCHAR) GetEa 1395 + GetEa->NextEntryOffset))) { 1396 1397 OEM_STRING Str; 1398 OEM_STRING OutputEaName; 1399 1400 DebugTrace(0, Dbg, "Top of loop, GetEa = %p\n", GetEa); 1401 DebugTrace(0, Dbg, "LastFullEa = %p\n", LastFullEa); 1402 DebugTrace(0, Dbg, "NextFullEa = %p\n", NextFullEa); 1403 DebugTrace(0, Dbg, "RemainingUserBufferLength = %08lx\n", RemainingUserBufferLength); 1404 1405 // 1406 // Make a string reference to the GetEa and see if we can 1407 // locate the ea by name 1408 // 1409 1410 Str.MaximumLength = Str.Length = GetEa->EaNameLength; 1411 Str.Buffer = &GetEa->EaName[0]; 1412 1413 // 1414 // Check for a valid name. 1415 // 1416 1417 if (!FatIsEaNameValid( IrpContext, Str )) { 1418 1419 DebugTrace(-1, Dbg, 1420 "FatQueryEaUserEaList: Invalid Ea Name -> %Z\n", 1421 &Str); 1422 1423 Iosb.Information = (PUCHAR)GetEa - UserEaList; 1424 Iosb.Status = STATUS_INVALID_EA_NAME; 1425 return Iosb; 1426 } 1427 1428 // 1429 // If this is a duplicate name, we skip to the next. 1430 // 1431 1432 if (FatIsDuplicateEaName( IrpContext, GetEa, UserEaList )) { 1433 1434 DebugTrace(0, Dbg, "FatQueryEaUserEaList: Duplicate name\n", 0); 1435 continue; 1436 } 1437 1438 if (!FatLocateEaByName( IrpContext, 1439 FirstPackedEa, 1440 PackedEasLength, 1441 &Str, 1442 &Offset )) { 1443 1444 Offset = 0xffffffff; 1445 1446 DebugTrace(0, Dbg, "Need to dummy up an ea\n", 0); 1447 1448 // 1449 // We were not able to locate the name therefore we must 1450 // dummy up a entry for the query. The needed Ea size is 1451 // the size of the name + 4 (next entry offset) + 1 (flags) 1452 // + 1 (name length) + 2 (value length) + the name length + 1453 // 1 (null byte). 1454 // 1455 1456 if ((ULONG)(4+1+1+2+GetEa->EaNameLength+1) 1457 > RemainingUserBufferLength) { 1458 1459 Overflow = TRUE; 1460 break; 1461 } 1462 1463 // 1464 // Everything is going to work fine, so copy over the name, 1465 // set the name length and zero out the rest of the ea. 1466 // 1467 1468 NextFullEa->NextEntryOffset = 0; 1469 NextFullEa->Flags = 0; 1470 NextFullEa->EaNameLength = GetEa->EaNameLength; 1471 NextFullEa->EaValueLength = 0; 1472 RtlCopyMemory( &NextFullEa->EaName[0], 1473 &GetEa->EaName[0], 1474 GetEa->EaNameLength ); 1475 1476 // 1477 // Upcase the name in the buffer. 1478 // 1479 1480 OutputEaName.MaximumLength = OutputEaName.Length = Str.Length; 1481 OutputEaName.Buffer = NextFullEa->EaName; 1482 1483 FatUpcaseEaName( IrpContext, &OutputEaName, &OutputEaName ); 1484 1485 NextFullEa->EaName[GetEa->EaNameLength] = 0; 1486 1487 } else { 1488 1489 DebugTrace(0, Dbg, "Located the ea, Offset = %08lx\n", Offset); 1490 1491 // 1492 // We were able to locate the packed ea 1493 // Reference the packed ea 1494 // 1495 1496 PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + Offset); 1497 SizeOfPackedEa( PackedEa, &PackedEaSize ); 1498 1499 DebugTrace(0, Dbg, "PackedEaSize = %08lx\n", PackedEaSize); 1500 1501 // 1502 // We know that the packed ea is 4 bytes smaller than its 1503 // equivalent full ea so we need to check the remaining 1504 // user buffer length against the computed full ea size. 1505 // 1506 1507 if (PackedEaSize + 4 > RemainingUserBufferLength) { 1508 1509 Overflow = TRUE; 1510 break; 1511 } 1512 1513 // 1514 // Everything is going to work fine, so copy over the packed 1515 // ea to the full ea and zero out the next entry offset field. 1516 // 1517 1518 RtlCopyMemory( &NextFullEa->Flags, 1519 &PackedEa->Flags, 1520 PackedEaSize ); 1521 1522 NextFullEa->NextEntryOffset = 0; 1523 } 1524 1525 // 1526 // At this point we've copied a new full ea into the next full ea 1527 // location. So now go back and set the set full eas entry offset 1528 // field to be the difference between out two pointers. 1529 // 1530 1531 if (LastFullEa != NULL) { 1532 1533 LastFullEa->NextEntryOffset = (ULONG)((PUCHAR) NextFullEa 1534 - (PUCHAR) LastFullEa); 1535 } 1536 1537 // 1538 // Set the last full ea to the next full ea, compute 1539 // where the next full should be, and decrement the remaining user 1540 // buffer length appropriately 1541 // 1542 1543 LastFullEa = NextFullEa; 1544 LastFullEaSize = LongAlign( SizeOfFullEa( LastFullEa )); 1545 RemainingUserBufferLength -= LastFullEaSize; 1546 NextFullEa = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) NextFullEa 1547 + LastFullEaSize); 1548 1549 // 1550 // Remember the offset of the next ea in case we're asked to 1551 // resume the iteration 1552 // 1553 1554 Ccb->OffsetOfNextEaToReturn = FatLocateNextEa( IrpContext, 1555 FirstPackedEa, 1556 PackedEasLength, 1557 Offset ); 1558 1559 // 1560 // If we were to return a single entry then break out of our loop 1561 // now 1562 // 1563 1564 if (ReturnSingleEntry) { 1565 1566 break; 1567 } 1568 } 1569 1570 // 1571 // Now we've iterated all that can and we've exited the preceding loop 1572 // with either all, some or no information stored in the return buffer. 1573 // We can decide if we got everything to fit by checking the local 1574 // Overflow variable 1575 // 1576 1577 if (Overflow) { 1578 1579 Iosb.Information = 0; 1580 Iosb.Status = STATUS_BUFFER_OVERFLOW; 1581 1582 } else { 1583 1584 // 1585 // Otherwise we've been successful in returing at least one 1586 // ea so we'll compute the number of bytes used to store the 1587 // full ea information. The number of bytes used is the difference 1588 // between the LastFullEa and the start of the buffer, and the 1589 // non-aligned size of the last full ea. 1590 // 1591 1592 Iosb.Information = ((PUCHAR) LastFullEa - UserBuffer) 1593 + SizeOfFullEa(LastFullEa); 1594 1595 Iosb.Status = STATUS_SUCCESS; 1596 } 1597 1598 DebugTrace(-1, Dbg, "FatQueryEaUserEaList -> Iosb.Status = %08lx\n", 1599 Iosb.Status); 1600 1601 return Iosb; 1602 } 1603 1604 1605 // 1606 // Local Support Routine 1607 // 1608 1609 IO_STATUS_BLOCK 1610 FatQueryEaIndexSpecified ( 1611 IN PIRP_CONTEXT IrpContext, 1612 OUT PCCB Ccb, 1613 IN PPACKED_EA FirstPackedEa, 1614 IN ULONG PackedEasLength, 1615 OUT PUCHAR UserBuffer, 1616 IN ULONG UserBufferLength, 1617 IN ULONG UserEaIndex, 1618 IN BOOLEAN ReturnSingleEntry 1619 ) 1620 1621 /*++ 1622 1623 Routine Description: 1624 1625 This routine is the work routine for querying EAs given an ea index 1626 1627 Arguments: 1628 1629 Ccb - Supplies the Ccb for the query 1630 1631 FirstPackedEa - Supplies the first ea for the file being queried 1632 1633 PackedEasLength - Supplies the length of the ea data 1634 1635 UserBuffer - Supplies the buffer to receive the full eas 1636 1637 UserBufferLength - Supplies the length, in bytes, of the user buffer 1638 1639 UserEaIndex - Supplies the index of the first ea to return. 1640 1641 RestartScan - Indicates if the first item to return is at the 1642 beginning of the packed ea list or if we should resume our 1643 previous iteration 1644 1645 Return Value: 1646 1647 IO_STATUS_BLOCK - Receives the completion status for the operation 1648 1649 --*/ 1650 1651 { 1652 IO_STATUS_BLOCK Iosb; 1653 1654 ULONG i; 1655 ULONG Offset; 1656 1657 DebugTrace(+1, Dbg, "FatQueryEaIndexSpecified...\n", 0); 1658 1659 // 1660 // Zero out the information field of the iosb 1661 // 1662 1663 Iosb.Information = 0; 1664 1665 // 1666 // If the index value is zero or there are no Eas on the file, then 1667 // the specified index can't be returned. 1668 // 1669 1670 if (UserEaIndex == 0 1671 || PackedEasLength == 0) { 1672 1673 DebugTrace( -1, Dbg, "FatQueryEaIndexSpecified: Non-existant entry\n", 0 ); 1674 1675 Iosb.Status = STATUS_NONEXISTENT_EA_ENTRY; 1676 1677 return Iosb; 1678 } 1679 1680 // 1681 // Iterate the eas until we find the index we're after. 1682 // 1683 1684 for (i = 1, Offset = 0; 1685 (i < UserEaIndex) && (Offset < PackedEasLength); 1686 i += 1, Offset = FatLocateNextEa( IrpContext, 1687 FirstPackedEa, 1688 PackedEasLength, Offset )) { 1689 1690 NOTHING; 1691 } 1692 1693 // 1694 // Make sure the offset we're given to the ea is a real offset otherwise 1695 // the ea doesn't exist 1696 // 1697 1698 if (Offset >= PackedEasLength) { 1699 1700 // 1701 // If we just passed the last Ea, we will return STATUS_NO_MORE_EAS. 1702 // This is for the caller who may be enumerating the Eas. 1703 // 1704 1705 if (i == UserEaIndex) { 1706 1707 Iosb.Status = STATUS_NO_MORE_EAS; 1708 1709 // 1710 // Otherwise we report that this is a bad ea index. 1711 // 1712 1713 } else { 1714 1715 Iosb.Status = STATUS_NONEXISTENT_EA_ENTRY; 1716 } 1717 1718 DebugTrace(-1, Dbg, "FatQueryEaIndexSpecified -> %08lx\n", Iosb.Status); 1719 return Iosb; 1720 } 1721 1722 // 1723 // We now have the offset of the first Ea to return to the user. 1724 // We simply call our EaSimpleScan routine to do the actual work. 1725 // 1726 1727 Iosb = FatQueryEaSimpleScan( IrpContext, 1728 Ccb, 1729 FirstPackedEa, 1730 PackedEasLength, 1731 UserBuffer, 1732 UserBufferLength, 1733 ReturnSingleEntry, 1734 Offset ); 1735 1736 DebugTrace(-1, Dbg, "FatQueryEaIndexSpecified -> %08lx\n", Iosb.Status); 1737 1738 return Iosb; 1739 1740 } 1741 1742 1743 // 1744 // Local Support Routine 1745 // 1746 1747 IO_STATUS_BLOCK 1748 FatQueryEaSimpleScan ( 1749 IN PIRP_CONTEXT IrpContext, 1750 OUT PCCB Ccb, 1751 IN PPACKED_EA FirstPackedEa, 1752 IN ULONG PackedEasLength, 1753 OUT PUCHAR UserBuffer, 1754 IN ULONG UserBufferLength, 1755 IN BOOLEAN ReturnSingleEntry, 1756 ULONG StartOffset 1757 ) 1758 1759 /*++ 1760 1761 Routine Description: 1762 1763 This routine is the work routine for querying EAs from the beginning of 1764 the ea list. 1765 1766 Arguments: 1767 1768 Ccb - Supplies the Ccb for the query 1769 1770 FirstPackedEa - Supplies the first ea for the file being queried 1771 1772 PackedEasLength - Supplies the length of the ea data 1773 1774 UserBuffer - Supplies the buffer to receive the full eas 1775 1776 UserBufferLength - Supplies the length, in bytes, of the user buffer 1777 1778 ReturnSingleEntry - Indicates if we are to return a single entry or not 1779 1780 StartOffset - Indicates the offset within the Ea data to return the 1781 first block of data. 1782 1783 Return Value: 1784 1785 IO_STATUS_BLOCK - Receives the completion status for the operation 1786 1787 --*/ 1788 1789 { 1790 IO_STATUS_BLOCK Iosb; 1791 1792 ULONG RemainingUserBufferLength; 1793 1794 PPACKED_EA PackedEa; 1795 ULONG PackedEaSize; 1796 1797 PFILE_FULL_EA_INFORMATION LastFullEa; 1798 ULONG LastFullEaSize; 1799 PFILE_FULL_EA_INFORMATION NextFullEa; 1800 BOOLEAN BufferOverflow = FALSE; 1801 1802 1803 DebugTrace(+1, Dbg, "FatQueryEaSimpleScan...\n", 0); 1804 1805 // 1806 // Zero out the information field in the Iosb 1807 // 1808 1809 Iosb.Information = 0; 1810 1811 LastFullEa = NULL; 1812 NextFullEa = (PFILE_FULL_EA_INFORMATION) UserBuffer; 1813 RemainingUserBufferLength = UserBufferLength; 1814 1815 while (StartOffset < PackedEasLength) { 1816 1817 DebugTrace(0, Dbg, "Top of loop, Offset = %08lx\n", StartOffset); 1818 DebugTrace(0, Dbg, "LastFullEa = %p\n", LastFullEa); 1819 DebugTrace(0, Dbg, "NextFullEa = %p\n", NextFullEa); 1820 DebugTrace(0, Dbg, "RemainingUserBufferLength = %08lx\n", RemainingUserBufferLength); 1821 1822 // 1823 // Reference the packed ea of interest. 1824 // 1825 1826 PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + StartOffset); 1827 1828 SizeOfPackedEa( PackedEa, &PackedEaSize ); 1829 1830 DebugTrace(0, Dbg, "PackedEaSize = %08lx\n", PackedEaSize); 1831 1832 // 1833 // We know that the packed ea is 4 bytes smaller than its 1834 // equivalent full ea so we need to check the remaining 1835 // user buffer length against the computed full ea size. 1836 // 1837 1838 if (PackedEaSize + 4 > RemainingUserBufferLength) { 1839 1840 BufferOverflow = TRUE; 1841 break; 1842 } 1843 1844 // 1845 // Everything is going to work fine, so copy over the packed 1846 // ea to the full ea and zero out the next entry offset field. 1847 // Then go back and set the last full eas entry offset field 1848 // to be the difference between the two pointers. 1849 // 1850 1851 RtlCopyMemory( &NextFullEa->Flags, &PackedEa->Flags, PackedEaSize ); 1852 NextFullEa->NextEntryOffset = 0; 1853 1854 if (LastFullEa != NULL) { 1855 1856 LastFullEa->NextEntryOffset = (ULONG)((PUCHAR) NextFullEa 1857 - (PUCHAR) LastFullEa); 1858 } 1859 1860 // 1861 // Set the last full ea to the next full ea, compute 1862 // where the next full should be, and decrement the remaining user 1863 // buffer length appropriately 1864 // 1865 1866 LastFullEa = NextFullEa; 1867 LastFullEaSize = LongAlign( SizeOfFullEa( LastFullEa )); 1868 RemainingUserBufferLength -= LastFullEaSize; 1869 NextFullEa = (PFILE_FULL_EA_INFORMATION) ((PUCHAR) NextFullEa 1870 + LastFullEaSize); 1871 1872 // 1873 // Remember the offset of the next ea in case we're asked to 1874 // resume the teration 1875 // 1876 1877 StartOffset = FatLocateNextEa( IrpContext, 1878 FirstPackedEa, 1879 PackedEasLength, 1880 StartOffset ); 1881 1882 Ccb->OffsetOfNextEaToReturn = StartOffset; 1883 1884 // 1885 // If we were to return a single entry then break out of our loop 1886 // now 1887 // 1888 1889 if (ReturnSingleEntry) { 1890 1891 break; 1892 } 1893 } 1894 1895 // 1896 // Now we've iterated all that can and we've exited the preceding loop 1897 // with either some or no information stored in the return buffer. 1898 // We can decide which it is by checking if the last full ea is null 1899 // 1900 1901 if (LastFullEa == NULL) { 1902 1903 Iosb.Information = 0; 1904 1905 // 1906 // We were not able to return a single ea entry, now we need to find 1907 // out if it is because we didn't have an entry to return or the 1908 // buffer is too small. If the Offset variable is less than 1909 // PackedEaList->UsedSize then the user buffer is too small 1910 // 1911 1912 if (PackedEasLength == 0) { 1913 1914 Iosb.Status = STATUS_NO_EAS_ON_FILE; 1915 1916 } else if (StartOffset >= PackedEasLength) { 1917 1918 Iosb.Status = STATUS_NO_MORE_EAS; 1919 1920 } else { 1921 1922 Iosb.Status = STATUS_BUFFER_TOO_SMALL; 1923 } 1924 1925 } else { 1926 1927 // 1928 // Otherwise we've been successful in returing at least one 1929 // ea so we'll compute the number of bytes used to store the 1930 // full ea information. The number of bytes used is the difference 1931 // between the LastFullEa and the start of the buffer, and the 1932 // non-aligned size of the last full ea. 1933 // 1934 1935 Iosb.Information = ((PUCHAR) LastFullEa - UserBuffer) 1936 + SizeOfFullEa( LastFullEa ); 1937 1938 // 1939 // If there are more to return, report the buffer was too small. 1940 // Otherwise return STATUS_SUCCESS. 1941 // 1942 1943 if (BufferOverflow) { 1944 1945 Iosb.Status = STATUS_BUFFER_OVERFLOW; 1946 1947 } else { 1948 1949 Iosb.Status = STATUS_SUCCESS; 1950 } 1951 } 1952 1953 DebugTrace(-1, Dbg, "FatQueryEaSimpleScan -> Iosb.Status = %08lx\n", 1954 Iosb.Status); 1955 1956 return Iosb; 1957 1958 } 1959 1960 1961 // 1962 // Local Support Routine 1963 // 1964 1965 BOOLEAN 1966 FatIsDuplicateEaName ( 1967 IN PIRP_CONTEXT IrpContext, 1968 IN PFILE_GET_EA_INFORMATION GetEa, 1969 IN PUCHAR UserBuffer 1970 ) 1971 1972 /*++ 1973 1974 Routine Description: 1975 1976 This routine walks through a list of ea names to find a duplicate name. 1977 'GetEa' is an actual position in the list. We are only interested in 1978 previous matching ea names, as the ea information for that ea name 1979 would have been returned with the previous instance. 1980 1981 Arguments: 1982 1983 GetEa - Supplies the Ea name structure for the ea name to match. 1984 1985 UserBuffer - Supplies a pointer to the user buffer with the list 1986 of ea names to search for. 1987 1988 Return Value: 1989 1990 BOOLEAN - TRUE if a previous match is found, FALSE otherwise. 1991 1992 --*/ 1993 1994 { 1995 PFILE_GET_EA_INFORMATION ThisGetEa; 1996 1997 BOOLEAN DuplicateFound; 1998 OEM_STRING EaString; 1999 2000 DebugTrace(+1, Dbg, "FatIsDuplicateEaName...\n", 0); 2001 2002 EaString.MaximumLength = EaString.Length = GetEa->EaNameLength; 2003 EaString.Buffer = &GetEa->EaName[0]; 2004 2005 FatUpcaseEaName( IrpContext, &EaString, &EaString ); 2006 2007 DuplicateFound = FALSE; 2008 2009 for (ThisGetEa = (PFILE_GET_EA_INFORMATION) &UserBuffer[0]; 2010 ThisGetEa < GetEa 2011 && ThisGetEa->NextEntryOffset != 0; 2012 ThisGetEa = (PFILE_GET_EA_INFORMATION) ((PUCHAR) ThisGetEa 2013 + ThisGetEa->NextEntryOffset)) { 2014 2015 OEM_STRING Str; 2016 2017 DebugTrace(0, Dbg, "Top of loop, ThisGetEa = %p\n", ThisGetEa); 2018 2019 // 2020 // Make a string reference to the GetEa and see if we can 2021 // locate the ea by name 2022 // 2023 2024 Str.MaximumLength = Str.Length = ThisGetEa->EaNameLength; 2025 Str.Buffer = &ThisGetEa->EaName[0]; 2026 2027 DebugTrace(0, Dbg, "FatIsDuplicateEaName: Next Name -> %Z\n", &Str); 2028 2029 if ( FatAreNamesEqual(IrpContext, Str, EaString) ) { 2030 2031 DebugTrace(0, Dbg, "FatIsDuplicateEaName: Duplicate found\n", 0); 2032 DuplicateFound = TRUE; 2033 break; 2034 } 2035 } 2036 2037 DebugTrace(-1, Dbg, "FatIsDuplicateEaName: Exit -> %04x\n", DuplicateFound); 2038 2039 return DuplicateFound; 2040 } 2041 #endif 2042 2043 2044