3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the EA routines for Fat called by
20 // The local debug trace level
23 #define Dbg (DEBUG_TRACE_EA)
26 // Local procedure prototypes
30 FatQueryEaUserEaList (
31 IN PIRP_CONTEXT IrpContext
,
33 IN PPACKED_EA FirstPackedEa
,
34 IN ULONG PackedEasLength
,
35 OUT PUCHAR UserBuffer
,
36 IN ULONG UserBufferLength
,
38 IN ULONG UserEaListLength
,
39 IN BOOLEAN ReturnSingleEntry
43 FatQueryEaIndexSpecified (
44 IN PIRP_CONTEXT IrpContext
,
46 IN PPACKED_EA FirstPackedEa
,
47 IN ULONG PackedEasLength
,
48 OUT PUCHAR UserBuffer
,
49 IN ULONG UserBufferLength
,
51 IN BOOLEAN ReturnSingleEntry
55 FatQueryEaSimpleScan (
56 IN PIRP_CONTEXT IrpContext
,
58 IN PPACKED_EA FirstPackedEa
,
59 IN ULONG PackedEasLength
,
60 OUT PUCHAR UserBuffer
,
61 IN ULONG UserBufferLength
,
62 IN BOOLEAN ReturnSingleEntry
,
67 FatIsDuplicateEaName (
68 IN PIRP_CONTEXT IrpContext
,
69 IN PFILE_GET_EA_INFORMATION GetEa
,
74 #pragma alloc_text(PAGE, FatCommonQueryEa)
75 #pragma alloc_text(PAGE, FatCommonSetEa)
76 #pragma alloc_text(PAGE, FatFsdQueryEa)
77 #pragma alloc_text(PAGE, FatFsdSetEa)
79 #pragma alloc_text(PAGE, FatIsDuplicateEaName)
80 #pragma alloc_text(PAGE, FatQueryEaIndexSpecified)
81 #pragma alloc_text(PAGE, FatQueryEaSimpleScan)
82 #pragma alloc_text(PAGE, FatQueryEaUserEaList)
87 _Function_class_(IRP_MJ_QUERY_EA
)
88 _Function_class_(DRIVER_DISPATCH
)
92 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
100 This routine implements the Fsd part of the NtQueryEa API
105 VolumeDeviceObject - Supplies the volume device object where the file
106 being queried exists.
108 Irp - Supplies the Irp being processed.
112 NTSTATUS - The FSD status for the Irp.
118 PIRP_CONTEXT IrpContext
= NULL
;
124 DebugTrace(+1, Dbg
, "FatFsdQueryEa\n", 0);
127 // Call the common query routine, with blocking allowed if synchronous
130 FsRtlEnterFileSystem();
132 TopLevel
= FatIsIrpTopLevel( Irp
);
136 IrpContext
= FatCreateIrpContext( Irp
, CanFsdWait( Irp
) );
138 Status
= FatCommonQueryEa( IrpContext
, Irp
);
140 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
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
149 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
152 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
154 FsRtlExitFileSystem();
157 // And return to our caller
160 DebugTrace(-1, Dbg
, "FatFsdQueryEa -> %08lx\n", Status
);
162 UNREFERENCED_PARAMETER( VolumeDeviceObject
);
168 _Function_class_(IRP_MJ_SET_EA
)
169 _Function_class_(DRIVER_DISPATCH
)
173 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject
,
181 This routine implements the FSD part of the NtSetEa API
186 VolumeDeviceObject - Supplies the volume device object where the file
189 Irp - Supplies the Irp being processed.
193 NTSTATUS - The FSD status for the Irp.
199 PIRP_CONTEXT IrpContext
= NULL
;
205 DebugTrace(+1, Dbg
, "FatFsdSetEa\n", 0);
208 // Call the common set routine, with blocking allowed if synchronous
211 FsRtlEnterFileSystem();
213 TopLevel
= FatIsIrpTopLevel( Irp
);
217 IrpContext
= FatCreateIrpContext( Irp
, CanFsdWait( Irp
) );
219 Status
= FatCommonSetEa( IrpContext
, Irp
);
221 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
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
230 Status
= FatProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
233 if (TopLevel
) { IoSetTopLevelIrp( NULL
); }
235 FsRtlExitFileSystem();
238 // And return to our caller
241 DebugTrace(-1, Dbg
, "FatFsdSetEa -> %08lx\n", Status
);
243 UNREFERENCED_PARAMETER( VolumeDeviceObject
);
251 IN PIRP_CONTEXT IrpContext
,
259 This is the common routine for querying File ea called by both
260 the fsd and fsp threads.
264 Irp - Supplies the Irp being processed
268 NTSTATUS - The return status for the operation
274 PIO_STACK_LOCATION IrpSp
;
279 ULONG UserBufferLength
;
282 ULONG UserEaListLength
;
285 BOOLEAN ReturnSingleEntry
;
286 BOOLEAN IndexSpecified
;
299 PEA_SET_HEADER EaSetHeader
;
302 USHORT ExtendedAttributes
;
307 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
308 return STATUS_INVALID_DEVICE_REQUEST
;
312 // Get the current Irp stack location
315 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
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
));
329 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
330 Irp
->IoStatus
.Information
= 0;
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
339 TYPE_OF_OPEN OpenType
;
341 if (((OpenType
= FatDecodeFileObject( IrpSp
->FileObject
,
344 &Ccb
)) != UserFileOpen
345 && OpenType
!= UserDirectoryOpen
) ||
347 (NodeType( Fcb
)) == FAT_NTC_ROOT_DCB
) {
349 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
352 "FatCommonQueryEa -> %08lx\n",
353 STATUS_INVALID_PARAMETER
);
355 return STATUS_INVALID_PARAMETER
;
360 // Fat32 does not support ea's.
363 if (FatIsFat32(Vcb
)) {
365 FatCompleteRequest( IrpContext
, Irp
, STATUS_EAS_NOT_SUPPORTED
);
367 "FatCommonQueryEa -> %08lx\n",
368 STATUS_EAS_NOT_SUPPORTED
);
369 return STATUS_EAS_NOT_SUPPORTED
;
373 // Acquire shared access to the Fcb and enqueue the Irp if we didn't
377 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
379 DebugTrace(0, Dbg
, "FatCommonQueryEa: Thread can't wait\n", 0);
381 Status
= FatFsdPostRequest( IrpContext
, Irp
);
383 DebugTrace(-1, Dbg
, "FatCommonQueryEa -> %08lx\n", Status
);
388 FatAcquireSharedFcb( IrpContext
, Fcb
);
391 // Reference our input parameters to make things easier
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
);
403 // Initialize our local values.
410 Status
= STATUS_SUCCESS
;
412 RtlZeroMemory( &EaSetRange
, sizeof( EA_RANGE
));
416 PPACKED_EA FirstPackedEa
;
417 ULONG PackedEasLength
;
419 Buffer
= FatMapUserBuffer( IrpContext
, Irp
);
422 // We verify that the Fcb is still valid.
425 FatVerifyFcb( IrpContext
, Fcb
);
428 // We need to get the dirent for the Fcb to recover the Ea handle.
431 FatGetDirentFromFcbOrDcb( IrpContext
, Fcb
, &Dirent
, &Bcb
);
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.
441 if (UserEaList
== NULL
442 && Ccb
->OffsetOfNextEaToReturn
!= 0
445 && Fcb
->EaModificationCount
!= Ccb
->EaModificationCount
) {
448 "FatCommonQueryEa: Ea file in unknown state\n", 0);
450 Status
= STATUS_EA_CORRUPT_ERROR
;
452 try_return( Status
);
456 // Show that the Ea's for this file are consistant for this
460 Ccb
->EaModificationCount
= Fcb
->EaModificationCount
;
463 // If the handle value is 0, then the file has no Eas. We dummy up
464 // an ea list to use below.
467 ExtendedAttributes
= Dirent
->ExtendedAttributes
;
469 FatUnpinBcb( IrpContext
, Bcb
);
471 if (ExtendedAttributes
== 0) {
474 "FatCommonQueryEa: Zero handle, no Ea's for this file\n", 0);
476 FirstPackedEa
= (PPACKED_EA
) NULL
;
483 // We need to get the Ea file for this volume. If the
484 // operation doesn't complete due to blocking, then queue the
488 FatGetEaFile( IrpContext
,
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.
503 if (Vcb
->VirtualEaFile
== NULL
) {
506 "FatCommonQueryEa: No Ea file found when expected\n", 0);
508 Status
= STATUS_NO_EAS_ON_FILE
;
510 try_return( Status
);
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.
518 FatReadEaSet( IrpContext
,
521 &Fcb
->ShortName
.Name
.Oem
,
525 EaSetHeader
= (PEA_SET_HEADER
) EaSetRange
.Data
;
528 // Find the start and length of the Eas.
531 FirstPackedEa
= (PPACKED_EA
) EaSetHeader
->PackedEas
;
533 PackedEasLength
= GetcbList( EaSetHeader
) - 4;
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 ...
545 // Let's clear the output buffer.
548 RtlZeroMemory( Buffer
, UserBufferLength
);
551 // We now satisfy the user's request depending on whether he
552 // specified an Ea name list, an Ea index or restarting the
557 // The user has supplied a list of Ea names.
560 if (UserEaList
!= NULL
) {
562 Irp
->IoStatus
= FatQueryEaUserEaList( IrpContext
,
573 // The user supplied an index into the Ea list.
576 } else if (IndexSpecified
) {
578 Irp
->IoStatus
= FatQueryEaIndexSpecified( IrpContext
,
588 // Else perform a simple scan, taking into account the restart
589 // flag and the position of the next Ea stored in the Ccb.
594 Irp
->IoStatus
= FatQueryEaSimpleScan( IrpContext
,
603 : Ccb
->OffsetOfNextEaToReturn
);
606 } except (!FsRtlIsNtstatusExpected(GetExceptionCode()) ?
607 EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
610 // We must have had a problem filling in the user's buffer, so fail.
613 Irp
->IoStatus
.Status
= GetExceptionCode();
614 Irp
->IoStatus
.Information
= 0;
617 Status
= Irp
->IoStatus
.Status
;
622 DebugUnwind( FatCommonQueryEa
);
625 // Release the Fcb for the file object, and the Ea Fcb if
626 // successfully locked.
629 FatReleaseFcb( IrpContext
, Fcb
);
633 FatReleaseFcb( IrpContext
, Vcb
->EaFcb
);
637 // Unpin the dirents for the Fcb, EaFcb and EaSetFcb if necessary.
640 FatUnpinBcb( IrpContext
, Bcb
);
641 FatUnpinBcb( IrpContext
, EaBcb
);
643 FatUnpinEaRange( IrpContext
, &EaSetRange
);
645 if (!AbnormalTermination()) {
647 FatCompleteRequest( IrpContext
, Irp
, Status
);
650 DebugTrace(-1, Dbg
, "FatCommonQueryEa -> %08lx\n", Status
);
660 IN PIRP_CONTEXT IrpContext
,
668 This routine implements the common Set Ea File Api called by the
669 the Fsd and Fsp threads
673 Irp - Supplies the Irp to process
677 NTSTATUS - The appropriate status for the Irp
683 PIO_STACK_LOCATION IrpSp
;
687 USHORT ExtendedAttributes
;
690 ULONG UserBufferLength
;
699 PDIRENT EaDirent
= NULL
;
702 PEA_SET_HEADER EaSetHeader
= NULL
;
704 PEA_SET_HEADER PrevEaSetHeader
;
705 PEA_SET_HEADER NewEaSetHeader
;
708 BOOLEAN AcquiredVcb
= FALSE
;
709 BOOLEAN AcquiredFcb
= FALSE
;
710 BOOLEAN AcquiredParentDcb
= FALSE
;
711 BOOLEAN AcquiredRootDcb
= FALSE
;
712 BOOLEAN AcquiredEaFcb
= FALSE
;
717 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
718 return STATUS_INVALID_DEVICE_REQUEST
;
723 // The following booleans are used in the unwind process.
727 // Get the current Irp stack location
730 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
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
);
738 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
739 Irp
->IoStatus
.Information
= 0;
742 // Check that the file object is associated with either a user file
743 // or directory open.
747 TYPE_OF_OPEN OpenType
;
749 if (((OpenType
= FatDecodeFileObject( IrpSp
->FileObject
,
752 &Ccb
)) != UserFileOpen
753 && OpenType
!= UserDirectoryOpen
) ||
755 (NodeType( Fcb
)) == FAT_NTC_ROOT_DCB
) {
757 FatCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
760 "FatCommonSetEa -> %08lx\n",
761 STATUS_INVALID_PARAMETER
);
763 return STATUS_INVALID_PARAMETER
;
768 // Fat32 does not support ea's.
771 if (FatIsFat32(Vcb
)) {
773 FatCompleteRequest( IrpContext
, Irp
, STATUS_EAS_NOT_SUPPORTED
);
775 "FatCommonSetEa -> %08lx\n",
776 STATUS_EAS_NOT_SUPPORTED
);
777 return STATUS_EAS_NOT_SUPPORTED
;
781 // Reference our input parameters to make things easier
784 UserBufferLength
= IrpSp
->Parameters
.SetEa
.Length
;
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
793 Buffer
= FatBufferUserBuffer( IrpContext
, Irp
, UserBufferLength
);
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.
802 Status
= IoCheckEaBufferValidity( (PFILE_FULL_EA_INFORMATION
) Buffer
,
804 (PULONG
)&Irp
->IoStatus
.Information
);
806 if (!NT_SUCCESS( Status
)) {
808 FatCompleteRequest( IrpContext
, Irp
, Status
);
810 "FatCommonSetEa -> %08lx\n",
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).
822 // We are primarily synchronizing with directory enumeration here.
824 // If we cannot wait need to send things off to the fsp.
827 if (!FlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
829 DebugTrace(0, Dbg
, "FatCommonSetEa: Set Ea must be waitable\n", 0);
831 Status
= FatFsdPostRequest( IrpContext
, Irp
);
833 DebugTrace(-1, Dbg
, "FatCommonSetEa -> %08lx\n", Status
);
839 // Set this handle as having modified the file
842 IrpSp
->FileObject
->Flags
|= FO_FILE_MODIFIED
;
844 RtlZeroMemory( &EaSetRange
, sizeof( EA_RANGE
));
848 ULONG PackedEasLength
;
850 ULONG AllocationLength
;
851 ULONG BytesPerCluster
;
854 PFILE_FULL_EA_INFORMATION FullEa
;
857 // Now go pick up everything
860 FatAcquireSharedVcb( IrpContext
, Fcb
->Vcb
);
862 FatAcquireExclusiveFcb( IrpContext
, Fcb
);
865 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
867 if (Fcb
->ParentDcb
) {
869 FatAcquireExclusiveFcb( IrpContext
, Fcb
->ParentDcb
);
870 AcquiredParentDcb
= TRUE
;
873 FatAcquireExclusiveFcb( IrpContext
, Fcb
->Vcb
->RootDcb
);
874 AcquiredRootDcb
= TRUE
;
878 // We verify that the Fcb is still valid.
881 FatVerifyFcb( IrpContext
, Fcb
);
884 // We need to get the dirent for the Fcb to recover the Ea handle.
887 FatGetDirentFromFcbOrDcb( IrpContext
, Fcb
, &Dirent
, &Bcb
);
889 DebugTrace(0, Dbg
, "FatCommonSetEa: Dirent Address -> %p\n",
891 DebugTrace(0, Dbg
, "FatCommonSetEa: Dirent Bcb -> %p\n",
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.
901 ExtendedAttributes
= Dirent
->ExtendedAttributes
;
903 FatUnpinBcb( IrpContext
, Bcb
);
905 if (ExtendedAttributes
== 0) {
910 "FatCommonSetEa: File has no current Eas\n", 0 );
916 DebugTrace(0, Dbg
, "FatCommonSetEa: File has previous Eas\n", 0 );
918 FatGetEaFile( IrpContext
,
925 AcquiredEaFcb
= TRUE
;
928 // If we didn't get the file then there is an error on
932 if (Vcb
->VirtualEaFile
== NULL
) {
934 Status
= STATUS_NO_EAS_ON_FILE
;
935 try_return( Status
);
939 DebugTrace(0, Dbg
, "FatCommonSetEa: EaBcb -> %p\n", EaBcb
);
941 DebugTrace(0, Dbg
, "FatCommonSetEa: EaDirent -> %p\n", EaDirent
);
944 // If the file has existing ea's, we need to read them to
945 // determine the size of the buffer allocation.
951 // We need to try to get the Ea set for the desired file.
954 FatReadEaSet( IrpContext
,
957 &Fcb
->ShortName
.Name
.Oem
,
961 PrevEaSetHeader
= (PEA_SET_HEADER
) EaSetRange
.Data
;
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.
969 PackedEasLength
= GetcbList( PrevEaSetHeader
) - 4;
972 // Else we will create a dummy EaSetHeader.
980 BytesPerCluster
= 1 << Vcb
->AllocationSupport
.LogOfBytesPerCluster
;
982 AllocationLength
= (PackedEasLength
983 + SIZE_OF_EA_SET_HEADER
984 + BytesPerCluster
- 1)
985 & ~(BytesPerCluster
- 1);
987 EaSetHeader
= FsRtlAllocatePoolWithTag( PagedPool
,
992 // Copy the existing Eas over to pool memory.
997 RtlCopyMemory( EaSetHeader
, PrevEaSetHeader
, AllocationLength
);
999 FatUnpinEaRange( IrpContext
, &EaSetRange
);
1003 RtlZeroMemory( EaSetHeader
, AllocationLength
);
1005 RtlCopyMemory( EaSetHeader
->OwnerFileName
,
1006 Fcb
->ShortName
.Name
.Oem
.Buffer
,
1007 Fcb
->ShortName
.Name
.Oem
.Length
);
1011 AllocationLength
-= SIZE_OF_EA_SET_HEADER
;
1013 DebugTrace(0, Dbg
, "FatCommonSetEa: Initial Ea set -> %p\n",
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
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
)) {
1032 EaName
.MaximumLength
= EaName
.Length
= FullEa
->EaNameLength
;
1033 EaName
.Buffer
= &FullEa
->EaName
[0];
1035 DebugTrace(0, Dbg
, "FatCommonSetEa: Next Ea name -> %Z\n",
1039 // Make sure the ea name is valid
1042 if (!FatIsEaNameValid( IrpContext
,EaName
)) {
1044 Irp
->IoStatus
.Information
= (PUCHAR
)FullEa
- Buffer
;
1045 Status
= STATUS_INVALID_EA_NAME
;
1046 try_return( Status
);
1050 // Check that no invalid ea flags are set.
1054 // TEMPCODE We are returning STATUS_INVALID_EA_NAME
1055 // until a more appropriate error code exists.
1058 if (FullEa
->Flags
!= 0
1059 && FullEa
->Flags
!= FILE_NEED_EA
) {
1061 Irp
->IoStatus
.Information
= (PUCHAR
)FullEa
- (PUCHAR
)Buffer
;
1062 try_return( Status
= STATUS_INVALID_EA_NAME
);
1066 // See if we can locate the ea name in the ea set
1069 if (FatLocateEaByName( IrpContext
,
1070 (PPACKED_EA
) EaSetHeader
->PackedEas
,
1075 DebugTrace(0, Dbg
, "FatCommonSetEa: Found Ea name\n", 0);
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
1083 FatDeletePackedEa( IrpContext
,
1089 if (FullEa
->EaValueLength
!= 0) {
1091 FatAppendPackedEa( IrpContext
,
1101 // If there are any ea's not removed, we
1102 // call 'AddEaSet' to insert them into the Fat chain.
1105 if (PackedEasLength
!= 0) {
1107 LARGE_INTEGER EaOffset
;
1109 EaOffset
.HighPart
= 0;
1112 // If the packed eas length (plus 4 bytes) is greater
1113 // than the maximum allowed ea size, we return an error.
1116 if (PackedEasLength
+ 4 > MAXIMUM_EA_SIZE
) {
1118 DebugTrace( 0, Dbg
, "Ea length is greater than maximum\n", 0 );
1120 try_return( Status
= STATUS_EA_TOO_LARGE
);
1124 // We need to now read the ea file if we haven't already.
1127 if (EaDirent
== NULL
) {
1129 FatGetEaFile( IrpContext
,
1136 AcquiredEaFcb
= TRUE
;
1139 FatGetDirentFromFcbOrDcb( IrpContext
, Fcb
, &Dirent
, &Bcb
);
1141 RtlZeroMemory( &EaSetRange
, sizeof( EA_RANGE
));
1143 FatAddEaSet( IrpContext
,
1145 PackedEasLength
+ SIZE_OF_EA_SET_HEADER
,
1151 NewEaSetHeader
= (PEA_SET_HEADER
) EaSetRange
.Data
;
1153 DebugTrace(0, Dbg
, "FatCommonSetEa: Adding an ea set\n", 0);
1156 // Store the length of the new Ea's into the EaSetHeader.
1157 // This is the PackedEasLength + 4.
1160 PackedEasLength
+= 4;
1162 CopyU4char( EaSetHeader
->cbList
, &PackedEasLength
);
1165 // Copy all but the first four bytes of EaSetHeader into
1166 // NewEaSetHeader. The signature and index fields have
1167 // already been filled in.
1170 RtlCopyMemory( &NewEaSetHeader
->NeedEaCount
,
1171 &EaSetHeader
->NeedEaCount
,
1172 PackedEasLength
+ SIZE_OF_EA_SET_HEADER
- 8 );
1174 FatMarkEaRangeDirty( IrpContext
, Vcb
->VirtualEaFile
, &EaSetRange
);
1175 FatUnpinEaRange( IrpContext
, &EaSetRange
);
1177 CcFlushCache( Vcb
->VirtualEaFile
->SectionObjectPointer
, NULL
, 0, NULL
);
1181 FatGetDirentFromFcbOrDcb( IrpContext
, Fcb
, &Dirent
, &Bcb
);
1187 // Now we do a wholesale replacement of the ea for the file
1192 FatDeleteEaSet( IrpContext
,
1197 &Fcb
->ShortName
.Name
.Oem
);
1199 CcFlushCache( Vcb
->VirtualEaFile
->SectionObjectPointer
, NULL
, 0, NULL
);
1202 if (PackedEasLength
!= 0 ) {
1204 Fcb
->EaModificationCount
++;
1208 // Mark the dirent with the new ea's
1211 Dirent
->ExtendedAttributes
= EaHandle
;
1213 FatSetDirtyBcb( IrpContext
, Bcb
, Vcb
, TRUE
);
1216 // We call the notify package to report that the ea's were
1220 FatNotifyReportChange( IrpContext
,
1223 FILE_NOTIFY_CHANGE_EA
,
1224 FILE_ACTION_MODIFIED
);
1226 Irp
->IoStatus
.Information
= 0;
1227 Status
= STATUS_SUCCESS
;
1232 // Unpin the dirents for the Fcb and EaFcb if necessary.
1235 FatUnpinBcb( IrpContext
, Bcb
);
1236 FatUnpinBcb( IrpContext
, EaBcb
);
1238 FatUnpinRepinnedBcbs( IrpContext
);
1242 DebugUnwind( FatCommonSetEa
);
1245 // If this is an abnormal termination, we need to clean up
1246 // any locked resources.
1249 if (AbnormalTermination()) {
1252 // Unpin the dirents for the Fcb, EaFcb and EaSetFcb if necessary.
1255 FatUnpinBcb( IrpContext
, Bcb
);
1256 FatUnpinBcb( IrpContext
, EaBcb
);
1258 FatUnpinEaRange( IrpContext
, &EaSetRange
);
1262 // Release the Fcbs/Vcb acquired.
1265 if (AcquiredEaFcb
) {
1266 FatReleaseFcb( IrpContext
, Vcb
->EaFcb
);
1270 FatReleaseFcb( IrpContext
, Fcb
);
1273 if (AcquiredParentDcb
) {
1274 FatReleaseFcb( IrpContext
, Fcb
->ParentDcb
);
1277 if (AcquiredRootDcb
) {
1278 FatReleaseFcb( IrpContext
, Fcb
->Vcb
->RootDcb
);
1282 FatReleaseVcb( IrpContext
, Fcb
->Vcb
);
1286 // Deallocate our Ea buffer.
1289 if (EaSetHeader
!= NULL
) {
1291 ExFreePool( EaSetHeader
);
1295 // Complete the irp.
1298 if (!AbnormalTermination()) {
1300 FatCompleteRequest( IrpContext
, Irp
, Status
);
1303 DebugTrace(-1, Dbg
, "FatCommonSetEa -> %08lx\n", Status
);
1307 // And return to our caller
1318 // Local Support Routine
1322 FatQueryEaUserEaList (
1323 IN PIRP_CONTEXT IrpContext
,
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
1336 Routine Description:
1338 This routine is the work routine for querying EAs given an ea index
1342 Ccb - Supplies the Ccb for the query
1344 FirstPackedEa - Supplies the first ea for the file being queried
1346 PackedEasLength - Supplies the length of the ea data
1348 UserBuffer - Supplies the buffer to receive the full eas
1350 UserBufferLength - Supplies the length, in bytes, of the user buffer
1352 UserEaList - Supplies the user specified ea name list
1354 UserEaListLength - Supplies the length, in bytes, of the user ea list
1356 ReturnSingleEntry - Indicates if we are to return a single entry or not
1360 IO_STATUS_BLOCK - Receives the completion status for the operation
1365 IO_STATUS_BLOCK Iosb
;
1368 ULONG RemainingUserBufferLength
;
1370 PPACKED_EA PackedEa
;
1373 PFILE_FULL_EA_INFORMATION LastFullEa
= NULL
;
1374 ULONG LastFullEaSize
;
1375 PFILE_FULL_EA_INFORMATION NextFullEa
;
1377 PFILE_GET_EA_INFORMATION GetEa
;
1381 DebugTrace(+1, Dbg
, "FatQueryEaUserEaList...\n", 0);
1384 NextFullEa
= (PFILE_FULL_EA_INFORMATION
) UserBuffer
;
1385 RemainingUserBufferLength
= UserBufferLength
;
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
))) {
1398 OEM_STRING OutputEaName
;
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
);
1406 // Make a string reference to the GetEa and see if we can
1407 // locate the ea by name
1410 Str
.MaximumLength
= Str
.Length
= GetEa
->EaNameLength
;
1411 Str
.Buffer
= &GetEa
->EaName
[0];
1414 // Check for a valid name.
1417 if (!FatIsEaNameValid( IrpContext
, Str
)) {
1420 "FatQueryEaUserEaList: Invalid Ea Name -> %Z\n",
1423 Iosb
.Information
= (PUCHAR
)GetEa
- UserEaList
;
1424 Iosb
.Status
= STATUS_INVALID_EA_NAME
;
1429 // If this is a duplicate name, we skip to the next.
1432 if (FatIsDuplicateEaName( IrpContext
, GetEa
, UserEaList
)) {
1434 DebugTrace(0, Dbg
, "FatQueryEaUserEaList: Duplicate name\n", 0);
1438 if (!FatLocateEaByName( IrpContext
,
1444 Offset
= 0xffffffff;
1446 DebugTrace(0, Dbg
, "Need to dummy up an ea\n", 0);
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 +
1456 if ((ULONG
)(4+1+1+2+GetEa
->EaNameLength
+1)
1457 > RemainingUserBufferLength
) {
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.
1468 NextFullEa
->NextEntryOffset
= 0;
1469 NextFullEa
->Flags
= 0;
1470 NextFullEa
->EaNameLength
= GetEa
->EaNameLength
;
1471 NextFullEa
->EaValueLength
= 0;
1472 RtlCopyMemory( &NextFullEa
->EaName
[0],
1474 GetEa
->EaNameLength
);
1477 // Upcase the name in the buffer.
1480 OutputEaName
.MaximumLength
= OutputEaName
.Length
= Str
.Length
;
1481 OutputEaName
.Buffer
= NextFullEa
->EaName
;
1483 FatUpcaseEaName( IrpContext
, &OutputEaName
, &OutputEaName
);
1485 NextFullEa
->EaName
[GetEa
->EaNameLength
] = 0;
1489 DebugTrace(0, Dbg
, "Located the ea, Offset = %08lx\n", Offset
);
1492 // We were able to locate the packed ea
1493 // Reference the packed ea
1496 PackedEa
= (PPACKED_EA
) ((PUCHAR
) FirstPackedEa
+ Offset
);
1497 SizeOfPackedEa( PackedEa
, &PackedEaSize
);
1499 DebugTrace(0, Dbg
, "PackedEaSize = %08lx\n", PackedEaSize
);
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.
1507 if (PackedEaSize
+ 4 > RemainingUserBufferLength
) {
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.
1518 RtlCopyMemory( &NextFullEa
->Flags
,
1522 NextFullEa
->NextEntryOffset
= 0;
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.
1531 if (LastFullEa
!= NULL
) {
1533 LastFullEa
->NextEntryOffset
= (ULONG
)((PUCHAR
) NextFullEa
1534 - (PUCHAR
) LastFullEa
);
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
1543 LastFullEa
= NextFullEa
;
1544 LastFullEaSize
= LongAlign( SizeOfFullEa( LastFullEa
));
1545 RemainingUserBufferLength
-= LastFullEaSize
;
1546 NextFullEa
= (PFILE_FULL_EA_INFORMATION
) ((PUCHAR
) NextFullEa
1550 // Remember the offset of the next ea in case we're asked to
1551 // resume the iteration
1554 Ccb
->OffsetOfNextEaToReturn
= FatLocateNextEa( IrpContext
,
1560 // If we were to return a single entry then break out of our loop
1564 if (ReturnSingleEntry
) {
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
1579 Iosb
.Information
= 0;
1580 Iosb
.Status
= STATUS_BUFFER_OVERFLOW
;
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.
1592 Iosb
.Information
= ((PUCHAR
) LastFullEa
- UserBuffer
)
1593 + SizeOfFullEa(LastFullEa
);
1595 Iosb
.Status
= STATUS_SUCCESS
;
1598 DebugTrace(-1, Dbg
, "FatQueryEaUserEaList -> Iosb.Status = %08lx\n",
1606 // Local Support Routine
1610 FatQueryEaIndexSpecified (
1611 IN PIRP_CONTEXT IrpContext
,
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
1623 Routine Description:
1625 This routine is the work routine for querying EAs given an ea index
1629 Ccb - Supplies the Ccb for the query
1631 FirstPackedEa - Supplies the first ea for the file being queried
1633 PackedEasLength - Supplies the length of the ea data
1635 UserBuffer - Supplies the buffer to receive the full eas
1637 UserBufferLength - Supplies the length, in bytes, of the user buffer
1639 UserEaIndex - Supplies the index of the first ea to return.
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
1647 IO_STATUS_BLOCK - Receives the completion status for the operation
1652 IO_STATUS_BLOCK Iosb
;
1657 DebugTrace(+1, Dbg
, "FatQueryEaIndexSpecified...\n", 0);
1660 // Zero out the information field of the iosb
1663 Iosb
.Information
= 0;
1666 // If the index value is zero or there are no Eas on the file, then
1667 // the specified index can't be returned.
1670 if (UserEaIndex
== 0
1671 || PackedEasLength
== 0) {
1673 DebugTrace( -1, Dbg
, "FatQueryEaIndexSpecified: Non-existant entry\n", 0 );
1675 Iosb
.Status
= STATUS_NONEXISTENT_EA_ENTRY
;
1681 // Iterate the eas until we find the index we're after.
1684 for (i
= 1, Offset
= 0;
1685 (i
< UserEaIndex
) && (Offset
< PackedEasLength
);
1686 i
+= 1, Offset
= FatLocateNextEa( IrpContext
,
1688 PackedEasLength
, Offset
)) {
1694 // Make sure the offset we're given to the ea is a real offset otherwise
1695 // the ea doesn't exist
1698 if (Offset
>= PackedEasLength
) {
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.
1705 if (i
== UserEaIndex
) {
1707 Iosb
.Status
= STATUS_NO_MORE_EAS
;
1710 // Otherwise we report that this is a bad ea index.
1715 Iosb
.Status
= STATUS_NONEXISTENT_EA_ENTRY
;
1718 DebugTrace(-1, Dbg
, "FatQueryEaIndexSpecified -> %08lx\n", Iosb
.Status
);
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.
1727 Iosb
= FatQueryEaSimpleScan( IrpContext
,
1736 DebugTrace(-1, Dbg
, "FatQueryEaIndexSpecified -> %08lx\n", Iosb
.Status
);
1744 // Local Support Routine
1748 FatQueryEaSimpleScan (
1749 IN PIRP_CONTEXT IrpContext
,
1751 IN PPACKED_EA FirstPackedEa
,
1752 IN ULONG PackedEasLength
,
1753 OUT PUCHAR UserBuffer
,
1754 IN ULONG UserBufferLength
,
1755 IN BOOLEAN ReturnSingleEntry
,
1761 Routine Description:
1763 This routine is the work routine for querying EAs from the beginning of
1768 Ccb - Supplies the Ccb for the query
1770 FirstPackedEa - Supplies the first ea for the file being queried
1772 PackedEasLength - Supplies the length of the ea data
1774 UserBuffer - Supplies the buffer to receive the full eas
1776 UserBufferLength - Supplies the length, in bytes, of the user buffer
1778 ReturnSingleEntry - Indicates if we are to return a single entry or not
1780 StartOffset - Indicates the offset within the Ea data to return the
1781 first block of data.
1785 IO_STATUS_BLOCK - Receives the completion status for the operation
1790 IO_STATUS_BLOCK Iosb
;
1792 ULONG RemainingUserBufferLength
;
1794 PPACKED_EA PackedEa
;
1797 PFILE_FULL_EA_INFORMATION LastFullEa
;
1798 ULONG LastFullEaSize
;
1799 PFILE_FULL_EA_INFORMATION NextFullEa
;
1800 BOOLEAN BufferOverflow
= FALSE
;
1803 DebugTrace(+1, Dbg
, "FatQueryEaSimpleScan...\n", 0);
1806 // Zero out the information field in the Iosb
1809 Iosb
.Information
= 0;
1812 NextFullEa
= (PFILE_FULL_EA_INFORMATION
) UserBuffer
;
1813 RemainingUserBufferLength
= UserBufferLength
;
1815 while (StartOffset
< PackedEasLength
) {
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
);
1823 // Reference the packed ea of interest.
1826 PackedEa
= (PPACKED_EA
) ((PUCHAR
) FirstPackedEa
+ StartOffset
);
1828 SizeOfPackedEa( PackedEa
, &PackedEaSize
);
1830 DebugTrace(0, Dbg
, "PackedEaSize = %08lx\n", PackedEaSize
);
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.
1838 if (PackedEaSize
+ 4 > RemainingUserBufferLength
) {
1840 BufferOverflow
= TRUE
;
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.
1851 RtlCopyMemory( &NextFullEa
->Flags
, &PackedEa
->Flags
, PackedEaSize
);
1852 NextFullEa
->NextEntryOffset
= 0;
1854 if (LastFullEa
!= NULL
) {
1856 LastFullEa
->NextEntryOffset
= (ULONG
)((PUCHAR
) NextFullEa
1857 - (PUCHAR
) LastFullEa
);
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
1866 LastFullEa
= NextFullEa
;
1867 LastFullEaSize
= LongAlign( SizeOfFullEa( LastFullEa
));
1868 RemainingUserBufferLength
-= LastFullEaSize
;
1869 NextFullEa
= (PFILE_FULL_EA_INFORMATION
) ((PUCHAR
) NextFullEa
1873 // Remember the offset of the next ea in case we're asked to
1874 // resume the teration
1877 StartOffset
= FatLocateNextEa( IrpContext
,
1882 Ccb
->OffsetOfNextEaToReturn
= StartOffset
;
1885 // If we were to return a single entry then break out of our loop
1889 if (ReturnSingleEntry
) {
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
1901 if (LastFullEa
== NULL
) {
1903 Iosb
.Information
= 0;
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
1912 if (PackedEasLength
== 0) {
1914 Iosb
.Status
= STATUS_NO_EAS_ON_FILE
;
1916 } else if (StartOffset
>= PackedEasLength
) {
1918 Iosb
.Status
= STATUS_NO_MORE_EAS
;
1922 Iosb
.Status
= STATUS_BUFFER_TOO_SMALL
;
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.
1935 Iosb
.Information
= ((PUCHAR
) LastFullEa
- UserBuffer
)
1936 + SizeOfFullEa( LastFullEa
);
1939 // If there are more to return, report the buffer was too small.
1940 // Otherwise return STATUS_SUCCESS.
1943 if (BufferOverflow
) {
1945 Iosb
.Status
= STATUS_BUFFER_OVERFLOW
;
1949 Iosb
.Status
= STATUS_SUCCESS
;
1953 DebugTrace(-1, Dbg
, "FatQueryEaSimpleScan -> Iosb.Status = %08lx\n",
1962 // Local Support Routine
1966 FatIsDuplicateEaName (
1967 IN PIRP_CONTEXT IrpContext
,
1968 IN PFILE_GET_EA_INFORMATION GetEa
,
1969 IN PUCHAR UserBuffer
1974 Routine Description:
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.
1983 GetEa - Supplies the Ea name structure for the ea name to match.
1985 UserBuffer - Supplies a pointer to the user buffer with the list
1986 of ea names to search for.
1990 BOOLEAN - TRUE if a previous match is found, FALSE otherwise.
1995 PFILE_GET_EA_INFORMATION ThisGetEa
;
1997 BOOLEAN DuplicateFound
;
1998 OEM_STRING EaString
;
2000 DebugTrace(+1, Dbg
, "FatIsDuplicateEaName...\n", 0);
2002 EaString
.MaximumLength
= EaString
.Length
= GetEa
->EaNameLength
;
2003 EaString
.Buffer
= &GetEa
->EaName
[0];
2005 FatUpcaseEaName( IrpContext
, &EaString
, &EaString
);
2007 DuplicateFound
= FALSE
;
2009 for (ThisGetEa
= (PFILE_GET_EA_INFORMATION
) &UserBuffer
[0];
2011 && ThisGetEa
->NextEntryOffset
!= 0;
2012 ThisGetEa
= (PFILE_GET_EA_INFORMATION
) ((PUCHAR
) ThisGetEa
2013 + ThisGetEa
->NextEntryOffset
)) {
2017 DebugTrace(0, Dbg
, "Top of loop, ThisGetEa = %p\n", ThisGetEa
);
2020 // Make a string reference to the GetEa and see if we can
2021 // locate the ea by name
2024 Str
.MaximumLength
= Str
.Length
= ThisGetEa
->EaNameLength
;
2025 Str
.Buffer
= &ThisGetEa
->EaName
[0];
2027 DebugTrace(0, Dbg
, "FatIsDuplicateEaName: Next Name -> %Z\n", &Str
);
2029 if ( FatAreNamesEqual(IrpContext
, Str
, EaString
) ) {
2031 DebugTrace(0, Dbg
, "FatIsDuplicateEaName: Duplicate found\n", 0);
2032 DuplicateFound
= TRUE
;
2037 DebugTrace(-1, Dbg
, "FatIsDuplicateEaName: Exit -> %04x\n", DuplicateFound
);
2039 return DuplicateFound
;