[FASTFAT_NEW] Import again FastFAT from MS. This time from GitHub for license reasons.
[reactos.git] / drivers / filesystems / fastfat_new / ea.c
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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