xref: /reactos/drivers/filesystems/fastfat/easup.c (revision 23b7c7b8)
1 /*++
2 
3 Copyright (c) 1990-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     EaSup.c
8 
9 Abstract:
10 
11     This module implements the cluster operations on the EA file for Fat.
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 //
19 //  Local debug trace level
20 //
21 
22 #define Dbg                              (DEBUG_TRACE_EA)
23 
24 #ifdef ALLOC_PRAGMA
25 #pragma alloc_text(PAGE, FatAddEaSet)
26 #pragma alloc_text(PAGE, FatAppendPackedEa)
27 #pragma alloc_text(PAGE, FatCreateEa)
28 #pragma alloc_text(PAGE, FatDeleteEa)
29 #pragma alloc_text(PAGE, FatDeleteEaSet)
30 #pragma alloc_text(PAGE, FatDeletePackedEa)
31 #pragma alloc_text(PAGE, FatGetEaFile)
32 #pragma alloc_text(PAGE, FatGetEaLength)
33 #pragma alloc_text(PAGE, FatGetNeedEaCount)
34 #pragma alloc_text(PAGE, FatIsEaNameValid)
35 #pragma alloc_text(PAGE, FatLocateEaByName)
36 #pragma alloc_text(PAGE, FatLocateNextEa)
37 #pragma alloc_text(PAGE, FatReadEaSet)
38 #pragma alloc_text(PAGE, FatPinEaRange)
39 #pragma alloc_text(PAGE, FatMarkEaRangeDirty)
40 #pragma alloc_text(PAGE, FatUnpinEaRange)
41 #endif
42 
43 
44 //
45 //  Any access to the Ea file must recognize when a section boundary is being
46 //  crossed.
47 //
48 
49 #define EA_SECTION_SIZE             (0x00040000)
50 
51 
_Requires_lock_held_(_Global_critical_region_)52 _Requires_lock_held_(_Global_critical_region_)
53 VOID
54 FatGetEaLength (
55     IN PIRP_CONTEXT IrpContext,
56     IN PVCB Vcb,
57     IN PDIRENT Dirent,
58     OUT PULONG EaLength
59     )
60 
61 /*++
62 
63 Routine Description:
64 
65     This routine looks up the Ea length for the Eas of the file.  This
66     length is the  length of the packed eas, including the 4 bytes which
67     contain the Ea length.
68 
69     This routine pins down the Ea set for the desired file and copies
70     this field from the Ea set header.
71 
72 Arguments:
73 
74     Vcb - Vcb for the volume containing the Eas.
75 
76     Dirent - Supplies a pointer to the dirent for the file in question.
77 
78     EaLength - Supplies the address to store the length of the Eas.
79 
80 Return Value:
81 
82     None
83 
84 --*/
85 
86 {
87     PBCB EaBcb = NULL;
88     BOOLEAN LockedEaFcb = FALSE;
89     EA_RANGE EaSetRange;
90 
91     PAGED_CODE();
92 
93     DebugTrace(+1, Dbg, "FatGetEaLength ...\n", 0);
94 
95     //
96     //  If this is Fat32 volume, or if the handle is 0 then the Ea length is 0.
97     //
98 
99     if (FatIsFat32( Vcb ) ||
100         Dirent->ExtendedAttributes == 0) {
101 
102         *EaLength = 0;
103         DebugTrace(-1, Dbg, "FatGetEaLength -> %08lx\n", TRUE);
104         return;
105     }
106 
107     RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
108 
109     //
110     //  Use a try to facilitate cleanup.
111     //
112 
113     _SEH2_TRY {
114 
115         PDIRENT EaDirent;
116         OEM_STRING ThisFilename;
117         UCHAR Buffer[12];
118         PEA_SET_HEADER EaSetHeader;
119 
120         //
121         //  Initial the local values.
122         //
123 
124         EaBcb = NULL;
125         LockedEaFcb = FALSE;
126 
127         //
128         //  Try to get the Ea file object.  Return FALSE on failure.
129         //
130 
131         FatGetEaFile( IrpContext,
132                       Vcb,
133                       &EaDirent,
134                       &EaBcb,
135                       FALSE,
136                       FALSE );
137 
138         LockedEaFcb = TRUE;
139 
140         //
141         //  If we didn't get the file because it doesn't exist, then the
142         //  disk is corrupted.
143         //
144 
145         if (Vcb->VirtualEaFile == NULL) {
146 
147             DebugTrace(0, Dbg, "FatGetEaLength:  Ea file doesn't exist\n", 0);
148             FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
149         }
150 
151         //
152         //  Try to pin down the Ea set header for the index in the
153         //  dirent.  If the operation doesn't complete, return FALSE
154         //  from this routine.
155         //
156 
157         ThisFilename.Buffer = (PCHAR)Buffer;
158         Fat8dot3ToString( IrpContext, Dirent, FALSE, &ThisFilename );
159 
160         FatReadEaSet( IrpContext,
161                       Vcb,
162                       Dirent->ExtendedAttributes,
163                       &ThisFilename,
164                       FALSE,
165                       &EaSetRange );
166 
167         EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
168 
169         //
170         //  We now have the Ea set header for this file.  We simply copy
171         //  the Ea length field.
172         //
173 
174         CopyUchar4( EaLength, EaSetHeader->cbList );
175         DebugTrace(0, Dbg, "FatGetEaLength:  Length of Ea is -> %08lx\n",
176                    *EaLength);
177 
178     } _SEH2_FINALLY {
179 
180         DebugUnwind( FatGetEaLength );
181 
182         //
183         //  Unpin the EaDirent and the EaSetHeader if pinned.
184         //
185 
186         FatUnpinBcb( IrpContext, EaBcb );
187 
188         FatUnpinEaRange( IrpContext, &EaSetRange );
189 
190         //
191         //  Release the Fcb for the Ea file if locked.
192         //
193 
194         if (LockedEaFcb) {
195 
196             FatReleaseFcb( IrpContext, Vcb->EaFcb );
197         }
198 
199         DebugTrace(-1, Dbg, "FatGetEaLength:  Ea length -> %08lx\n", *EaLength);
200     } _SEH2_END;
201 
202     return;
203 }
204 
205 
_Requires_lock_held_(_Global_critical_region_)206 _Requires_lock_held_(_Global_critical_region_)
207 VOID
208 FatGetNeedEaCount (
209     IN PIRP_CONTEXT IrpContext,
210     IN PVCB Vcb,
211     IN PDIRENT Dirent,
212     OUT PULONG NeedEaCount
213     )
214 
215 /*++
216 
217 Routine Description:
218 
219     This routine looks up the Need Ea count for the file.  The value is the
220     in the ea header for the file.
221 
222 Arguments:
223 
224     Vcb - Vcb for the volume containing the Eas.
225 
226     Dirent - Supplies a pointer to the dirent for the file in question.
227 
228     NeedEaCount - Supplies the address to store the Need Ea count.
229 
230 Return Value:
231 
232     None
233 
234 --*/
235 
236 {
237     PBCB EaBcb = NULL;
238     BOOLEAN LockedEaFcb = FALSE;
239     EA_RANGE EaSetRange;
240 
241     PAGED_CODE();
242 
243     DebugTrace(+1, Dbg, "FatGetNeedEaCount ...\n", 0);
244 
245     //
246     //  If the handle is 0 then the Need Ea count is 0.
247     //
248 
249     if (Dirent->ExtendedAttributes == 0) {
250 
251         *NeedEaCount = 0;
252         DebugTrace(-1, Dbg, "FatGetNeedEaCount -> %08lx\n", TRUE);
253         return;
254     }
255 
256     RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
257 
258     //
259     //  Use a try to facilitate cleanup.
260     //
261 
262     _SEH2_TRY {
263 
264         PDIRENT EaDirent;
265         OEM_STRING ThisFilename;
266         UCHAR Buffer[12];
267         PEA_SET_HEADER EaSetHeader;
268 
269         //
270         //  Initial the local values.
271         //
272 
273         EaBcb = NULL;
274         LockedEaFcb = FALSE;
275 
276         //
277         //  Try to get the Ea file object.  Return FALSE on failure.
278         //
279 
280         FatGetEaFile( IrpContext,
281                       Vcb,
282                       &EaDirent,
283                       &EaBcb,
284                       FALSE,
285                       FALSE );
286 
287         LockedEaFcb = TRUE;
288 
289         //
290         //  If we didn't get the file because it doesn't exist, then the
291         //  disk is corrupted.
292         //
293 
294         if (Vcb->VirtualEaFile == NULL) {
295 
296             DebugTrace(0, Dbg, "FatGetNeedEaCount:  Ea file doesn't exist\n", 0);
297             FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
298         }
299 
300         //
301         //  Try to pin down the Ea set header for the index in the
302         //  dirent.  If the operation doesn't complete, return FALSE
303         //  from this routine.
304         //
305 
306         ThisFilename.Buffer = (PCHAR)Buffer;
307         Fat8dot3ToString( IrpContext, Dirent, FALSE, &ThisFilename );
308 
309         FatReadEaSet( IrpContext,
310                       Vcb,
311                       Dirent->ExtendedAttributes,
312                       &ThisFilename,
313                       FALSE,
314                       &EaSetRange );
315 
316         EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
317 
318         //
319         //  We now have the Ea set header for this file.  We simply copy
320         //  the Need Ea field.
321         //
322 
323         *NeedEaCount = EaSetHeader->NeedEaCount;
324 
325     } _SEH2_FINALLY {
326 
327         DebugUnwind( FatGetNeedEaCount );
328 
329         //
330         //  Unpin the EaDirent and the EaSetHeader if pinned.
331         //
332 
333         FatUnpinBcb( IrpContext, EaBcb );
334 
335         FatUnpinEaRange( IrpContext, &EaSetRange );
336 
337         //
338         //  Release the Fcb for the Ea file if locked.
339         //
340 
341         if (LockedEaFcb) {
342 
343             FatReleaseFcb( IrpContext, Vcb->EaFcb );
344         }
345 
346         DebugTrace(-1, Dbg, "FatGetNeedEaCount:  NeedEaCount -> %08lx\n", *NeedEaCount);
347     } _SEH2_END;
348 
349     return;
350 }
351 
352 
_Requires_lock_held_(_Global_critical_region_)353 _Requires_lock_held_(_Global_critical_region_)
354 VOID
355 FatCreateEa (
356     IN PIRP_CONTEXT IrpContext,
357     IN PVCB Vcb,
358     IN PUCHAR Buffer,
359     IN ULONG Length,
360     IN POEM_STRING FileName,
361     OUT PUSHORT EaHandle
362     )
363 
364 /*++
365 
366 Routine Description:
367 
368     This routine adds an entire ea set to the Ea file.  The owning file
369     is specified in 'FileName'.  This is used to replace the Ea set attached
370     to an existing file during a supersede operation.
371 
372     NOTE: This routine may block, it should not be called unless the
373     thread is waitable.
374 
375 Arguments:
376 
377     Vcb - Supplies the Vcb for the volume.
378 
379     Buffer - Buffer with the Ea list to add.
380 
381     Length - Length of the buffer.
382 
383     FileName - The Ea's will be attached to this file.
384 
385     EaHandle - The new ea handle will be assigned to this address.
386 
387 Return Value:
388 
389     None
390 
391 --*/
392 
393 {
394     PBCB EaBcb;
395     BOOLEAN LockedEaFcb;
396 
397     PEA_SET_HEADER EaSetHeader = NULL;
398     EA_RANGE EaSetRange;
399 
400     PAGED_CODE();
401 
402     DebugTrace(+1, Dbg, "FatCreateEa...\n", 0);
403 
404     EaBcb = NULL;
405     LockedEaFcb = FALSE;
406 
407     RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
408 
409     //
410     //  Use 'try' to facilitate cleanup.
411     //
412 
413     _SEH2_TRY {
414 
415         PDIRENT EaDirent;
416 
417         ULONG PackedEasLength;
418         ULONG AllocationLength;
419         ULONG BytesPerCluster;
420 
421         PFILE_FULL_EA_INFORMATION FullEa;
422 
423         //
424         //  We will allocate a buffer and copy the Ea list from the user's
425         //  buffer to a FAT packed Ea list.  Initial allocation is one
426         //  cluster, our starting offset into the packed Ea list is 0.
427         //
428 
429         PackedEasLength = 0;
430 
431         BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
432 
433         AllocationLength = (PackedEasLength
434                             + SIZE_OF_EA_SET_HEADER
435                             + BytesPerCluster - 1)
436                            & ~(BytesPerCluster - 1);
437 
438         //
439         //  Allocate the memory and store the file name into it.
440         //
441 
442         EaSetHeader = FsRtlAllocatePoolWithTag( PagedPool,
443                                                 AllocationLength,
444                                                 TAG_EA_SET_HEADER );
445 
446         RtlZeroMemory( EaSetHeader, AllocationLength );
447 
448         RtlCopyMemory( EaSetHeader->OwnerFileName,
449                        FileName->Buffer,
450                        FileName->Length );
451 
452         AllocationLength -= SIZE_OF_EA_SET_HEADER;
453 
454         //
455         //  Loop through the user's Ea list.  Catch any error for invalid
456         //  name or non-existent Ea value.
457         //
458 
459         for ( FullEa = (PFILE_FULL_EA_INFORMATION) Buffer;
460               FullEa < (PFILE_FULL_EA_INFORMATION) &Buffer[Length];
461               FullEa = (PFILE_FULL_EA_INFORMATION) (FullEa->NextEntryOffset == 0 ?
462                                    &Buffer[Length] :
463                                    (PUCHAR) FullEa + FullEa->NextEntryOffset)) {
464 
465             OEM_STRING EaName;
466             ULONG EaOffset;
467 
468             EaName.Length = FullEa->EaNameLength;
469             EaName.Buffer = &FullEa->EaName[0];
470 
471             //
472             //  Make sure the ea name is valid
473             //
474 
475             if (!FatIsEaNameValid( IrpContext, EaName )) {
476 
477                 DebugTrace(0, Dbg,
478                            "FatCreateEa:  Invalid Ea Name -> %Z\n",
479                            EaName);
480 
481                 IrpContext->OriginatingIrp->IoStatus.Information = (PUCHAR)FullEa - Buffer;
482                 IrpContext->OriginatingIrp->IoStatus.Status = STATUS_INVALID_EA_NAME;
483                 FatRaiseStatus( IrpContext, STATUS_INVALID_EA_NAME );
484             }
485 
486             //
487             //  Check that no invalid ea flags are set.
488             //
489 
490             //
491             //  TEMPCODE  We are returning STATUS_INVALID_EA_NAME
492             //  until a more appropriate error code exists.
493             //
494 
495             if (FullEa->Flags != 0
496                 && FullEa->Flags != FILE_NEED_EA) {
497 
498                 IrpContext->OriginatingIrp->IoStatus.Information = (PUCHAR)FullEa - Buffer;
499                 IrpContext->OriginatingIrp->IoStatus.Status = STATUS_INVALID_EA_NAME;
500                 FatRaiseStatus( IrpContext, STATUS_INVALID_EA_NAME );
501             }
502 
503             //
504             //  If this is a duplicate name then delete the current ea
505             //  value.
506             //
507 
508             if (FatLocateEaByName( IrpContext,
509                                    (PPACKED_EA) EaSetHeader->PackedEas,
510                                    PackedEasLength,
511                                    &EaName,
512                                    &EaOffset )) {
513 
514                 DebugTrace(0, Dbg, "FatCreateEa:  Duplicate name found\n", 0);
515 
516                 FatDeletePackedEa( IrpContext,
517                                    EaSetHeader,
518                                    &PackedEasLength,
519                                    EaOffset );
520             }
521 
522             //
523             //  We ignore this value if the eavalue length is zero.
524             //
525 
526             if (FullEa->EaValueLength == 0) {
527 
528                 DebugTrace(0, Dbg,
529                            "FatCreateEa:  Empty ea\n",
530                            0);
531 
532                 continue;
533             }
534 
535             FatAppendPackedEa( IrpContext,
536                                &EaSetHeader,
537                                &PackedEasLength,
538                                &AllocationLength,
539                                FullEa,
540                                BytesPerCluster );
541         }
542 
543         //
544         //  If the resulting length isn't zero, then allocate a FAT cluster
545         //  to store the data.
546         //
547 
548         if (PackedEasLength != 0) {
549 
550             PEA_SET_HEADER NewEaSetHeader;
551 
552             //
553             //  If the packed eas length (plus 4 bytes) is greater
554             //  than the maximum allowed ea size, we return an error.
555             //
556 
557             if (PackedEasLength + 4 > MAXIMUM_EA_SIZE) {
558 
559                 DebugTrace( 0, Dbg, "Ea length is greater than maximum\n", 0 );
560 
561                 FatRaiseStatus( IrpContext, STATUS_EA_TOO_LARGE );
562             }
563 
564             //
565             //  Get the Ea file.
566             //
567 
568             FatGetEaFile( IrpContext,
569                           Vcb,
570                           &EaDirent,
571                           &EaBcb,
572                           TRUE,
573                           TRUE );
574 
575             LockedEaFcb = TRUE;
576 
577             FatAddEaSet( IrpContext,
578                          Vcb,
579                          PackedEasLength + SIZE_OF_EA_SET_HEADER,
580                          EaBcb,
581                          EaDirent,
582                          EaHandle,
583                          &EaSetRange );
584 
585             NewEaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
586 
587             //
588             //  Store the length of the new Ea's into the NewEaSetHeader.
589             //  This is the PackedEasLength + 4.
590             //
591 
592             PackedEasLength += 4;
593 
594             CopyU4char( EaSetHeader->cbList, &PackedEasLength );
595 
596             //
597             //  Copy all but the first four bytes of EaSetHeader into
598             //  the new ea.  The signature and index fields have
599             //  already been filled in.
600             //
601 
602             RtlCopyMemory( &NewEaSetHeader->NeedEaCount,
603                            &EaSetHeader->NeedEaCount,
604                            PackedEasLength + SIZE_OF_EA_SET_HEADER - 8 );
605 
606             FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange );
607             FatUnpinEaRange( IrpContext, &EaSetRange );
608 
609             CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
610 
611         //
612         //  There was no data added to the Ea file.  Return a handle
613         //  of 0.
614         //
615 
616         } else {
617 
618             *EaHandle = 0;
619         }
620 
621     } _SEH2_FINALLY {
622 
623         DebugUnwind( FatCreateEa );
624 
625         //
626         //  Deallocate the EaSetHeader if present.
627         //
628 
629         if (EaSetHeader) {
630 
631             ExFreePool( EaSetHeader );
632         }
633 
634         //
635         //  Release the EaFcb if held.
636         //
637 
638         if (LockedEaFcb) {
639 
640             FatReleaseFcb( IrpContext, Vcb->EaFcb );
641         }
642 
643         //
644         //  Unpin the dirents for the EaFcb and EaSetFcb if necessary.
645         //
646 
647         FatUnpinBcb( IrpContext, EaBcb );
648         FatUnpinEaRange( IrpContext, &EaSetRange );
649 
650         DebugTrace(-1, Dbg, "FatCreateEa -> Exit\n", 0);
651     } _SEH2_END;
652 
653     return;
654 }
655 
_Requires_lock_held_(_Global_critical_region_)656 _Requires_lock_held_(_Global_critical_region_)
657 VOID
658 FatDeleteEa (
659     IN PIRP_CONTEXT IrpContext,
660     IN PVCB Vcb,
661     IN USHORT EaHandle,
662     IN POEM_STRING FileName
663     )
664 
665 /*++
666 
667 Routine Description:
668 
669     This routine is called to remove an entire ea set.  Most of the work
670     is done in the call to 'FatDeleteEaSet'.  This routine opens the
671     Ea file and then calls the support routine.
672 
673     NOTE: This routine may block, it should not be called unless the
674     thread is waitable.
675 
676 Arguments:
677 
678     Vcb - Vcb for the volume
679 
680     EaHandle - The handle for the Ea's to remove.  This handle will be
681                verified during this operation.
682 
683     FileName - The name of the file whose Ea's are being removed.  This
684                name is compared against the Ea owner's name in the Ea set.
685 
686 Return Value:
687 
688     None.
689 
690 --*/
691 
692 {
693     PBCB EaBcb;
694     BOOLEAN LockedEaFcb;
695 
696     PAGED_CODE();
697 
698     DebugTrace(+1, Dbg, "FatDeleteEa...\n", 0);
699 
700     //
701     //  Initialize local values.
702     //
703 
704     EaBcb = NULL;
705     LockedEaFcb = FALSE;
706 
707     //
708     //  Use a try statement to facilitate cleanup.
709     //
710 
711     _SEH2_TRY {
712 
713         PDIRENT EaDirent;
714 
715         //
716         //  Get the Ea stream file.  If the file doesn't exist on the disk
717         //  then the disk has been corrupted.
718         //
719 
720         FatGetEaFile( IrpContext,
721                       Vcb,
722                       &EaDirent,
723                       &EaBcb,
724                       FALSE,
725                       TRUE );
726 
727         LockedEaFcb = TRUE;
728 
729         //
730         //  If we didn't get the Ea file, then the disk is corrupt.
731         //
732 
733         if ( EaBcb == NULL ) {
734 
735 
736             DebugTrace(0, Dbg,
737                        "FatDeleteEa:  No Ea file exists\n",
738                        0);
739 
740             FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
741         }
742 
743         //
744         //  We now have everything we need to delete the ea set.  Call the
745         //  support routine to do this.
746         //
747 
748         FatDeleteEaSet( IrpContext,
749                         Vcb,
750                         EaBcb,
751                         EaDirent,
752                         EaHandle,
753                         FileName );
754 
755         CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
756 
757     } _SEH2_FINALLY {
758 
759         DebugUnwind( FatDeleteEa );
760 
761         //
762         //  Release the EaFcb if held.
763         //
764 
765         if (LockedEaFcb) {
766 
767             FatReleaseFcb( IrpContext, Vcb->EaFcb );
768         }
769 
770         //
771         //  Unpin the dirent for the Ea file if pinned.
772         //
773 
774         FatUnpinBcb( IrpContext, EaBcb );
775 
776         DebugTrace(-1, Dbg, "FatDeleteEa -> Exit\n", 0);
777     } _SEH2_END;
778 
779     return;
780 }
781 
782 
_Requires_lock_held_(_Global_critical_region_)783 _Requires_lock_held_(_Global_critical_region_)
784 VOID
785 FatGetEaFile (
786     IN PIRP_CONTEXT IrpContext,
787     IN OUT PVCB Vcb,
788     OUT PDIRENT *EaDirent,
789     OUT PBCB *EaBcb,
790     IN BOOLEAN CreateFile,
791     IN BOOLEAN ExclusiveFcb
792     )
793 
794 /*++
795 
796 Routine Description:
797 
798     This routine is used to completely initialize the Vcb and
799     the Ea file for the Vcb.
800 
801     If the Vcb doesn't have the Ea file object, then we first try to
802     lookup the Ea data file in the root directory and if that fails
803     we try to create the file.  The 'CreateFile' flag is used to check
804     whether it is necessary to create the Ea file.
805 
806     This routine will lock down the Fcb for exclusive or shared access before
807     performing any operations.  If the operation does not complete due
808     to blocking, exclusive or shared access will be given up before returning.
809 
810     If we are creating the Ea file and marking sections of it dirty,
811     we can't use the repin feature through the cache map.  In that case
812     we use a local IrpContext and then unpin all of the Bcb's before
813     continuing.
814 
815     Note: If this routine will be creating the Ea file, we are guaranteed
816     to be waitable.
817 
818 Arguments:
819 
820     Vcb - Vcb for the volume
821 
822     EaDirent - Location to store the address of the pinned dirent for the
823                Ea file.
824 
825     EaBcb - Location to store the address of the Bcb for the pinned dirent.
826 
827     CreateFile - Boolean indicating whether we should create the Ea file
828                  on the disk.
829 
830     ExclusiveFcb - Indicates whether shared or exclusive access is desired
831                    for the EaFcb.
832 
833 Return Value:
834 
835     None.
836 
837 --*/
838 
839 {
840     PFILE_OBJECT EaStreamFile = NULL;
841     EA_RANGE EaFileRange;
842 
843     BOOLEAN UnwindLockedEaFcb = FALSE;
844     BOOLEAN UnwindLockedRootDcb = FALSE;
845     BOOLEAN UnwindAllocatedDiskSpace = FALSE;
846     BOOLEAN UnwindEaDirentCreated = FALSE;
847     BOOLEAN UnwindUpdatedSizes = FALSE;
848 
849     PAGED_CODE();
850 
851     DebugTrace(+1, Dbg, "FatGetEaFile ...\n", 0);
852 
853     RtlZeroMemory( &EaFileRange, sizeof( EA_RANGE ));
854 
855     //
856     //  Use a try to facilitate cleanup
857     //
858 
859     _SEH2_TRY {
860 
861         OEM_STRING EaFileName;
862         LARGE_INTEGER SectionSize;
863 
864         //
865         //  Check if the Vcb already has the file object.  If it doesn't, then
866         //  we need to search the root directory for the Ea data file.
867         //
868 
869         if (Vcb->VirtualEaFile == NULL) {
870 
871             //
872             //  Always lock the Ea file exclusively if we have to create the file.
873             //
874 
875             if ( !FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb )) {
876 
877                 DebugTrace(0, Dbg, "FatGetEaFile:  Can't grab exclusive\n", 0);
878                 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
879             }
880 
881             UnwindLockedEaFcb = TRUE;
882 
883         //
884         //  Otherwise we acquire the Fcb as the caller requested.
885         //
886 
887         } else {
888 
889             if ((ExclusiveFcb && !FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb ))
890                 || (!ExclusiveFcb && !FatAcquireSharedFcb( IrpContext, Vcb->EaFcb))) {
891 
892                 DebugTrace(0, Dbg, "FatGetEaFile:  Can't grab EaFcb\n", 0);
893 
894                 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
895             }
896 
897             UnwindLockedEaFcb = TRUE;
898 
899             //
900             //  If the file now does not exist we need to release the Fcb and
901             //  reacquire exclusive if we acquired shared.
902             //
903 
904             if ((Vcb->VirtualEaFile == NULL) && !ExclusiveFcb) {
905 
906                 FatReleaseFcb( IrpContext, Vcb->EaFcb );
907                 UnwindLockedEaFcb = FALSE;
908 
909                 if (!FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb )) {
910 
911                     DebugTrace(0, Dbg, "FatGetEaFile:  Can't grab EaFcb\n", 0);
912 
913                     FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
914                 }
915 
916                 UnwindLockedEaFcb = TRUE;
917             }
918         }
919 
920         //
921         //  If the file object is now there we only need to get the
922         //  dirent for the Ea file.
923         //
924 
925         if (Vcb->VirtualEaFile != NULL) {
926 
927             FatVerifyFcb( IrpContext, Vcb->EaFcb );
928 
929             FatGetDirentFromFcbOrDcb( IrpContext,
930                                       Vcb->EaFcb,
931                                       FALSE,
932                                       EaDirent,
933                                       EaBcb );
934 
935             try_return( NOTHING );
936 
937         } else {
938 
939             VBO ByteOffset = 0;
940 
941             //
942             //  Always mark the ea fcb as good.
943             //
944 
945             Vcb->EaFcb->FcbCondition = FcbGood;
946 
947             //
948             //  We try to lookup the dirent for the Ea Fcb.
949             //
950 
951             EaFileName.Buffer = "EA DATA. SF";
952             EaFileName.Length = 11;
953             EaFileName.MaximumLength = 12;
954 
955             //
956             //  Now pick up the root directory to be synchronized with
957             //  deletion/creation of entries.  If we may create the file,
958             //  get it exclusive right now.
959             //
960             //  Again, note how we are relying on bottom-up lockorder. We
961             //  already got the EaFcb.
962             //
963 
964             if (CreateFile) {
965                 ExAcquireResourceExclusiveLite( Vcb->RootDcb->Header.Resource, TRUE );
966             } else {
967                 ExAcquireResourceSharedLite( Vcb->RootDcb->Header.Resource, TRUE );
968             }
969             UnwindLockedRootDcb = TRUE;
970 
971             FatLocateSimpleOemDirent( IrpContext,
972                                       Vcb->EaFcb->ParentDcb,
973                                       &EaFileName,
974                                       EaDirent,
975                                       EaBcb,
976                                       &ByteOffset );
977 
978             //
979             //  If the file exists, we need to create the virtual file
980             //  object for it.
981             //
982 
983             if (*EaDirent != NULL) {
984 
985                 //
986                 //  Since we may be modifying the dirent, pin the data now.
987                 //
988 
989                 FatPinMappedData( IrpContext,
990                                   Vcb->EaFcb->ParentDcb,
991                                   ByteOffset,
992                                   sizeof(DIRENT),
993                                   EaBcb );
994 
995                 //
996                 //  Update the Fcb with information on the file size
997                 //  and disk location.  Also increment the open/unclean
998                 //  counts in the EaFcb and the open count in the
999                 //  Vcb.
1000                 //
1001 
1002                 Vcb->EaFcb->FirstClusterOfFile = (*EaDirent)->FirstClusterOfFile;
1003                 Vcb->EaFcb->DirentOffsetWithinDirectory = ByteOffset;
1004 
1005                 //
1006                 //  Find the allocation size.  The purpose here is
1007                 //  really to completely fill in the Mcb for the
1008                 //  file.
1009                 //
1010 
1011                 Vcb->EaFcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
1012 
1013                 FatLookupFileAllocationSize( IrpContext, Vcb->EaFcb );
1014 
1015                 //
1016                 //  Start by computing the section size for the cache
1017                 //  manager.
1018                 //
1019 
1020                 SectionSize.QuadPart = (*EaDirent)->FileSize;
1021                 Vcb->EaFcb->Header.AllocationSize = SectionSize;
1022                 Vcb->EaFcb->Header.FileSize = SectionSize;
1023 
1024                 //
1025                 //  Create and initialize the file object for the
1026                 //  Ea virtual file.
1027                 //
1028 
1029                 EaStreamFile = FatOpenEaFile( IrpContext, Vcb->EaFcb );
1030 
1031                 Vcb->VirtualEaFile = EaStreamFile;
1032 
1033             //
1034             //  Else there was no dirent.  If we were instructed to
1035             //  create the file object, we will try to create the dirent,
1036             //  allocate disk space, initialize the Ea file header and
1037             //  return this information to the user.
1038             //
1039 
1040             } else if (CreateFile) {
1041 
1042                 ULONG BytesPerCluster;
1043                 ULONG OffsetTableSize;
1044                 ULONG AllocationSize;
1045                 PEA_FILE_HEADER FileHeader;
1046                 USHORT AllocatedClusters;
1047                 PUSHORT CurrentIndex;
1048                 ULONG Index;
1049                 NTSTATUS Status = STATUS_SUCCESS;
1050 
1051                 DebugTrace(0, Dbg, "FatGetEaFile:  Creating local IrpContext\n", 0);
1052 
1053                 BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
1054 
1055                 AllocationSize = (((ULONG) sizeof( EA_FILE_HEADER ) << 1) + BytesPerCluster - 1)
1056                                  & ~(BytesPerCluster - 1);
1057 
1058                 AllocatedClusters = (USHORT) (AllocationSize
1059                                     >> Vcb->AllocationSupport.LogOfBytesPerCluster);
1060 
1061                 OffsetTableSize = AllocationSize - sizeof( EA_FILE_HEADER );
1062 
1063                 //
1064                 //  Allocate disk space, the space allocated is 1024 bytes
1065                 //  rounded up to the nearest cluster size.
1066                 //
1067 
1068                 FatAllocateDiskSpace( IrpContext,
1069                                       Vcb,
1070                                       0,
1071                                       &AllocationSize,
1072                                       FALSE,
1073                                       &Vcb->EaFcb->Mcb );
1074 
1075                 UnwindAllocatedDiskSpace = TRUE;
1076 
1077                 //
1078                 //  Allocate and initialize a dirent in the root directory
1079                 //  to describe this new file.
1080                 //
1081 
1082                 Vcb->EaFcb->DirentOffsetWithinDirectory =
1083                     FatCreateNewDirent( IrpContext,
1084                                         Vcb->EaFcb->ParentDcb,
1085                                         1,
1086                                         FALSE );
1087 
1088                 FatPrepareWriteDirectoryFile( IrpContext,
1089                                               Vcb->EaFcb->ParentDcb,
1090                                               Vcb->EaFcb->DirentOffsetWithinDirectory,
1091                                               sizeof(DIRENT),
1092                                               EaBcb,
1093 #ifndef __REACTOS__
1094                                               EaDirent,
1095 #else
1096                                               (PVOID *)EaDirent,
1097 #endif
1098                                               FALSE,
1099                                               TRUE,
1100                                               &Status );
1101 
1102                 NT_ASSERT( NT_SUCCESS( Status ));
1103 
1104                 UnwindEaDirentCreated = TRUE;
1105 
1106                 FatConstructDirent( IrpContext,
1107                                     *EaDirent,
1108                                     &EaFileName,
1109                                     FALSE,
1110                                     FALSE,
1111                                     NULL,
1112                                     FAT_DIRENT_ATTR_READ_ONLY
1113                                     | FAT_DIRENT_ATTR_HIDDEN
1114                                     | FAT_DIRENT_ATTR_SYSTEM
1115                                     | FAT_DIRENT_ATTR_ARCHIVE,
1116                                     TRUE,
1117                                     NULL );
1118 
1119                 (*EaDirent)->FileSize = AllocationSize;
1120 
1121                 //
1122                 //  Initialize the Fcb for this file and initialize the
1123                 //  cache map as well.
1124                 //
1125 
1126                 //
1127                 //  Start by computing the section size for the cache
1128                 //  manager.
1129                 //
1130 
1131                 SectionSize.QuadPart = (*EaDirent)->FileSize;
1132                 Vcb->EaFcb->Header.AllocationSize = SectionSize;
1133                 Vcb->EaFcb->Header.FileSize = SectionSize;
1134                 UnwindUpdatedSizes = TRUE;
1135 
1136                 //
1137                 //  Create and initialize the file object for the
1138                 //  Ea virtual file.
1139                 //
1140 
1141                 EaStreamFile = FatOpenEaFile( IrpContext, Vcb->EaFcb );
1142 
1143                 //
1144                 //  Update the Fcb with information on the file size
1145                 //  and disk location.  Also increment the open/unclean
1146                 //  counts in the EaFcb and the open count in the
1147                 //  Vcb.
1148                 //
1149 
1150                 {
1151                     LBO FirstLboOfFile;
1152 
1153                     FatLookupMcbEntry( Vcb, &Vcb->EaFcb->Mcb,
1154                                        0,
1155                                        &FirstLboOfFile,
1156                                        NULL,
1157                                        NULL );
1158 
1159                     //
1160                     //  The discerning reader will note that this doesn't take
1161                     //  FAT32 into account, which is of course intentional.
1162                     //
1163 
1164                     (*EaDirent)->FirstClusterOfFile =
1165                         (USHORT) FatGetIndexFromLbo( Vcb, FirstLboOfFile );
1166                 }
1167 
1168                 Vcb->EaFcb->FirstClusterOfFile = (*EaDirent)->FirstClusterOfFile;
1169 
1170                 //
1171                 //  Initialize the Ea file header and mark the Bcb as dirty.
1172                 //
1173 
1174                 FatPinEaRange( IrpContext,
1175                                EaStreamFile,
1176                                Vcb->EaFcb,
1177                                &EaFileRange,
1178                                0,
1179                                AllocationSize,
1180                                STATUS_DATA_ERROR );
1181 
1182                 FileHeader = (PEA_FILE_HEADER) EaFileRange.Data;
1183 
1184                 RtlZeroMemory( FileHeader, AllocationSize );
1185                 FileHeader->Signature = EA_FILE_SIGNATURE;
1186 
1187                 for (Index = MAX_EA_BASE_INDEX, CurrentIndex = FileHeader->EaBaseTable;
1188                      Index;
1189                      Index--, CurrentIndex++) {
1190 
1191                     *CurrentIndex = AllocatedClusters;
1192                 }
1193 
1194                 //
1195                 //  Initialize the offset table with the offset set to
1196                 //  after the just allocated clusters.
1197                 //
1198 
1199                 for (Index = OffsetTableSize >> 1,
1200                         CurrentIndex = (PUSHORT) ((PUCHAR) FileHeader + sizeof( EA_FILE_HEADER ));
1201                      Index;
1202                      Index--, CurrentIndex++) {
1203 
1204                     *CurrentIndex = UNUSED_EA_HANDLE;
1205                 }
1206 
1207                 //
1208                 //  Unpin the file header and offset table.
1209                 //
1210 
1211                 FatMarkEaRangeDirty( IrpContext, EaStreamFile, &EaFileRange );
1212                 FatUnpinEaRange( IrpContext, &EaFileRange );
1213 
1214                 CcFlushCache( EaStreamFile->SectionObjectPointer, NULL, 0, NULL );
1215 
1216                 //
1217                 //  Return the Ea file object to the user.
1218                 //
1219 
1220                 Vcb->VirtualEaFile = EaStreamFile;
1221             }
1222         }
1223     try_exit:  NOTHING;
1224     } _SEH2_FINALLY {
1225 
1226         DebugUnwind( FatGetEaFile );
1227 
1228         //
1229         //  If this is abnormal termination and disk space has been
1230         //  allocated.  We deallocate it now.
1231         //
1232 
1233         if (_SEH2_AbnormalTermination()) {
1234 
1235             //
1236             //  Deallocate the Ea file
1237             //
1238 
1239             if (UnwindAllocatedDiskSpace) {
1240 
1241                 FatDeallocateDiskSpace( IrpContext,
1242                                         Vcb,
1243                                         &Vcb->EaFcb->Mcb,
1244                                         FALSE );
1245             }
1246 
1247             //
1248             //  Delete the dirent for the Ea file, if created.
1249             //
1250 
1251             if (UnwindEaDirentCreated) {
1252 
1253                 if (UnwindUpdatedSizes) {
1254 
1255                     Vcb->EaFcb->Header.AllocationSize.QuadPart = 0;
1256                     Vcb->EaFcb->Header.FileSize.QuadPart = 0;
1257                 }
1258 
1259                 FatUnpinBcb( IrpContext, *EaBcb );
1260                 FatDeleteDirent( IrpContext, Vcb->EaFcb, NULL, TRUE );
1261             }
1262 
1263             //
1264             //  Release the EA Fcb if held
1265             //
1266 
1267             if (UnwindLockedEaFcb) {
1268 
1269                 FatReleaseFcb( IrpContext, Vcb->EaFcb );
1270             }
1271 
1272             //
1273             //  Dereference the Ea stream file if created.
1274             //
1275 
1276             if (EaStreamFile != NULL) {
1277 
1278                 ObDereferenceObject( EaStreamFile );
1279             }
1280         }
1281 
1282         //
1283         //  Always release the root Dcb (our caller releases the EA Fcb if we
1284         //  do not raise).
1285         //
1286 
1287         if (UnwindLockedRootDcb) {
1288 
1289             FatReleaseFcb( IrpContext, Vcb->RootDcb );
1290         }
1291 
1292         //
1293         //  If the Ea file header is locked down.  We unpin it now.
1294         //
1295 
1296         FatUnpinEaRange( IrpContext, &EaFileRange );
1297 
1298         DebugTrace(-1, Dbg, "FatGetEaFile:  Exit\n", 0);
1299     } _SEH2_END;
1300 
1301     return;
1302 }
1303 
1304 
1305 VOID
FatReadEaSet(IN PIRP_CONTEXT IrpContext,IN PVCB Vcb,IN USHORT EaHandle,IN POEM_STRING FileName,IN BOOLEAN ReturnEntireSet,OUT PEA_RANGE EaSetRange)1306 FatReadEaSet (
1307     IN PIRP_CONTEXT IrpContext,
1308     IN PVCB Vcb,
1309     IN USHORT EaHandle,
1310     IN POEM_STRING FileName,
1311     IN BOOLEAN ReturnEntireSet,
1312     OUT PEA_RANGE EaSetRange
1313     )
1314 
1315 /*++
1316 
1317 Routine Description:
1318 
1319     This routine pins the Ea set for the given ea handle within the
1320     Ea stream file.  The EaHandle, after first comparing against valid
1321     index values, is used to compute the cluster offset for this
1322     this Ea set.  The Ea set is then verified as belonging to this
1323     index and lying within the Ea data file.
1324 
1325     The caller of this function will have verified that the Ea file
1326     exists and that the Vcb field points to an initialized cache file.
1327     The caller will already have gained exclusive access to the
1328     EaFcb.
1329 
1330 Arguments:
1331 
1332     Vcb - Supplies the Vcb for the volume.
1333 
1334     EaHandle - Supplies the handle for the Ea's to read.
1335 
1336     FileName - Name of the file whose Ea's are being read.
1337 
1338     ReturnEntireSet - Indicates if the caller needs the entire set
1339         as opposed to just the header.
1340 
1341     EaSetRange - Pointer to the EaRange structure which will describe the Ea
1342         on return.
1343 
1344 Return Value:
1345 
1346     None
1347 
1348 --*/
1349 
1350 {
1351     ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
1352 
1353     ULONG EaOffsetVbo;
1354     EA_RANGE EaOffsetRange;
1355     USHORT EaOffsetCluster;
1356 
1357     EA_RANGE EaHeaderRange;
1358     PEA_FILE_HEADER EaHeader;
1359 
1360     ULONG EaSetVbo;
1361     PEA_SET_HEADER EaSet;
1362 
1363     ULONG CbList;
1364 
1365     PAGED_CODE();
1366 
1367     UNREFERENCED_PARAMETER( FileName );
1368 
1369     DebugTrace(+1, Dbg, "FatReadEaSet\n", 0);
1370     DebugTrace( 0, Dbg, "  Vcb      = %p\n", Vcb);
1371 
1372     //
1373     //  Verify that the Ea index has a legal value.  Raise status
1374     //  STATUS_NONEXISTENT_EA_ENTRY if illegal.
1375     //
1376 
1377     if (EaHandle < MIN_EA_HANDLE
1378         || EaHandle > MAX_EA_HANDLE) {
1379 
1380         DebugTrace(-1, Dbg, "FatReadEaSet: Illegal handle value\n", 0);
1381         FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
1382     }
1383 
1384     //
1385     //  Verify that the virtual Ea file is large enough for us to read
1386     //  the EaOffet table for this index.
1387     //
1388 
1389     EaOffsetVbo = sizeof( EA_FILE_HEADER ) + (((ULONGLONG)EaHandle >> 7) << 8);
1390 
1391     //
1392     //  Zero the Ea range structures.
1393     //
1394 
1395     RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
1396     RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
1397 
1398     //
1399     //  Use a try statement to clean up on exit.
1400     //
1401 
1402     _SEH2_TRY {
1403 
1404         //
1405         //  Pin down the EA file header.
1406         //
1407 
1408         FatPinEaRange( IrpContext,
1409                        Vcb->VirtualEaFile,
1410                        Vcb->EaFcb,
1411                        &EaHeaderRange,
1412                        0,
1413                        sizeof( EA_FILE_HEADER ),
1414                        STATUS_NONEXISTENT_EA_ENTRY );
1415 
1416         EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
1417 
1418         //
1419         //  Pin down the Ea offset table for the particular index.
1420         //
1421 
1422         FatPinEaRange( IrpContext,
1423                        Vcb->VirtualEaFile,
1424                        Vcb->EaFcb,
1425                        &EaOffsetRange,
1426                        EaOffsetVbo,
1427                        sizeof( EA_OFF_TABLE ),
1428                        STATUS_NONEXISTENT_EA_ENTRY );
1429 
1430         //
1431         //  Check if the specifific handle is currently being used.
1432         //
1433 
1434         EaOffsetCluster = *((PUSHORT) EaOffsetRange.Data
1435                             + (EaHandle & (MAX_EA_OFFSET_INDEX - 1)));
1436 
1437         if (EaOffsetCluster == UNUSED_EA_HANDLE) {
1438 
1439             DebugTrace(0, Dbg, "FatReadEaSet: Ea handle is unused\n", 0);
1440             FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
1441         }
1442 
1443         //
1444         //  Compute the file offset for the Ea data.
1445         //
1446 
1447         EaSetVbo = (EaHeader->EaBaseTable[EaHandle >> 7] + EaOffsetCluster)
1448                    << Vcb->AllocationSupport.LogOfBytesPerCluster;
1449 
1450         //
1451         //  Unpin the file header and offset table.
1452         //
1453 
1454         FatUnpinEaRange( IrpContext, &EaHeaderRange );
1455         FatUnpinEaRange( IrpContext, &EaOffsetRange );
1456 
1457         //
1458         //  Pin the ea set.
1459         //
1460 
1461         FatPinEaRange( IrpContext,
1462                        Vcb->VirtualEaFile,
1463                        Vcb->EaFcb,
1464                        EaSetRange,
1465                        EaSetVbo,
1466                        BytesPerCluster,
1467                        STATUS_DATA_ERROR );
1468 
1469         //
1470         //  Verify that the Ea set is valid and belongs to this index.
1471         //  Raise STATUS_DATA_ERROR if there is a data conflict.
1472         //
1473 
1474         EaSet = (PEA_SET_HEADER) EaSetRange->Data;
1475 
1476         if (EaSet->Signature != EA_SET_SIGNATURE
1477             || EaSet->OwnEaHandle != EaHandle ) {
1478 
1479             DebugTrace(0, Dbg, "FatReadEaSet: Ea set header is corrupt\n", 0);
1480             FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
1481         }
1482 
1483         //
1484         //  At this point we have pinned a single cluster of Ea data.  If
1485         //  this represents the entire Ea data for the Ea index, we are
1486         //  done.  Otherwise we need to check on the entire size of
1487         //  of the Ea set header and whether it is contained in the allocated
1488         //  size of the Ea virtual file.  At that point we can unpin
1489         //  the partial Ea set header and repin the entire header.
1490         //
1491 
1492         CbList = GetcbList( EaSet );
1493 
1494         if (ReturnEntireSet
1495             && CbList > BytesPerCluster ) {
1496 
1497             //
1498             //  Round up to the cluster size.
1499             //
1500 
1501             CbList = (CbList + EA_CBLIST_OFFSET + BytesPerCluster - 1)
1502                      & ~(BytesPerCluster - 1);
1503 
1504             FatUnpinEaRange( IrpContext, EaSetRange );
1505 
1506             RtlZeroMemory( EaSetRange, sizeof( EA_RANGE ));
1507 
1508             FatPinEaRange( IrpContext,
1509                            Vcb->VirtualEaFile,
1510                            Vcb->EaFcb,
1511                            EaSetRange,
1512                            EaSetVbo,
1513                            CbList,
1514                            STATUS_DATA_ERROR );
1515         }
1516 
1517     } _SEH2_FINALLY {
1518 
1519         DebugUnwind( FatReadEaSet );
1520 
1521         //
1522         //  Unpin the Ea base and offset tables if locked down.
1523         //
1524 
1525         FatUnpinEaRange( IrpContext, &EaHeaderRange );
1526         FatUnpinEaRange( IrpContext, &EaOffsetRange );
1527 
1528         DebugTrace(-1, Dbg, "FatReadEaSet:  Exit\n", 0);
1529     } _SEH2_END;
1530 
1531     return;
1532 }
1533 
1534 
_Requires_lock_held_(_Global_critical_region_)1535 _Requires_lock_held_(_Global_critical_region_)
1536 VOID
1537 FatDeleteEaSet (
1538     IN PIRP_CONTEXT IrpContext,
1539     IN PVCB Vcb,
1540     IN PBCB EaBcb,
1541     OUT PDIRENT EaDirent,
1542     IN USHORT EaHandle,
1543     IN POEM_STRING FileName
1544     )
1545 
1546 /*++
1547 
1548 Routine Description:
1549 
1550     This routines clips the Ea set for a particular index out of the
1551     Ea file for a volume.  The index is verified as belonging to a valid
1552     handle.  The clusters are removed and the Ea stream file along with
1553     the Ea base and offset files are updated.
1554 
1555     The caller of this function will have verified that the Ea file
1556     exists and that the Vcb field points to an initialized cache file.
1557     The caller will already have gained exclusive access to the
1558     EaFcb.
1559 
1560 Arguments:
1561 
1562     Vcb - Supplies the Vcb for the volume.
1563 
1564     VirtualEeFile - Pointer to the file object for the virtual Ea file.
1565 
1566     EaFcb - Supplies the pointer to the Fcb for the Ea file.
1567 
1568     EaBcb - Supplies a pointer to the Bcb for the Ea dirent.
1569 
1570     EaDirent - Supplies a pointer to the dirent for the Ea file.
1571 
1572     EaHandle - Supplies the handle for the Ea's to read.
1573 
1574     FileName - Name of the file whose Ea's are being read.
1575 
1576 Return Value:
1577 
1578     None.
1579 
1580 --*/
1581 
1582 {
1583     ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
1584     ULONG CbList;
1585     LARGE_INTEGER FileOffset;
1586 
1587     LARGE_MCB DataMcb;
1588     BOOLEAN UnwindInitializeDataMcb = FALSE;
1589     BOOLEAN UnwindSplitData = FALSE;
1590 
1591     LARGE_MCB TailMcb;
1592     BOOLEAN UnwindInitializeTailMcb = FALSE;
1593     BOOLEAN UnwindSplitTail = FALSE;
1594     BOOLEAN UnwindMergeTail = FALSE;
1595 
1596     BOOLEAN UnwindModifiedEaHeader = FALSE;
1597     BOOLEAN UnwindCacheValues = FALSE;
1598     ULONG UnwindPrevFileSize = 0;
1599 
1600     ULONG EaOffsetVbo;
1601     USHORT EaOffsetIndex;
1602     EA_RANGE EaOffsetRange;
1603     USHORT EaOffsetCluster;
1604 
1605     PFILE_OBJECT VirtualEaFile = Vcb->VirtualEaFile;
1606     PFCB EaFcb = Vcb->EaFcb;
1607 
1608     EA_RANGE EaHeaderRange;
1609     PEA_FILE_HEADER EaHeader;
1610     USHORT EaHeaderBaseIndex;
1611 
1612     ULONG EaSetVbo = 0;
1613     ULONG EaSetLength;
1614     EA_RANGE EaSetRange;
1615     PEA_SET_HEADER EaSet;
1616     USHORT EaSetClusterCount;
1617 
1618     PAGED_CODE();
1619 
1620     UNREFERENCED_PARAMETER( FileName );
1621 
1622     //
1623     //  Verify that the Ea index has a legal value.  Raise status
1624     //  STATUS_INVALID_HANDLE if illegal.
1625     //
1626 
1627     if (EaHandle < MIN_EA_HANDLE
1628         || EaHandle > MAX_EA_HANDLE) {
1629 
1630         DebugTrace(-1, Dbg, "FatDeleteEaSet: Illegal handle value\n", 0);
1631         FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
1632     }
1633 
1634     //
1635     //  Verify that the virtual Ea file is large enough for us to read
1636     //  the EaOffet table for this index.
1637     //
1638 
1639     EaOffsetVbo = sizeof( EA_FILE_HEADER ) + (((ULONGLONG)EaHandle >> 7) << 8);
1640 
1641     //
1642     //  Zero the Ea range structures.
1643     //
1644 
1645     RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
1646     RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
1647     RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
1648 
1649     //
1650     //  Use a try to facilitate cleanup.
1651     //
1652 
1653     _SEH2_TRY {
1654 
1655         //
1656         //  Pin down the EA file header.
1657         //
1658 
1659         FatPinEaRange( IrpContext,
1660                        VirtualEaFile,
1661                        EaFcb,
1662                        &EaHeaderRange,
1663                        0,
1664                        sizeof( EA_FILE_HEADER ),
1665                        STATUS_NONEXISTENT_EA_ENTRY );
1666 
1667         EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
1668 
1669         //
1670         //  Pin down the Ea offset table for the particular index.
1671         //
1672 
1673         FatPinEaRange( IrpContext,
1674                        VirtualEaFile,
1675                        EaFcb,
1676                        &EaOffsetRange,
1677                        EaOffsetVbo,
1678                        sizeof( EA_OFF_TABLE ),
1679                        STATUS_NONEXISTENT_EA_ENTRY );
1680 
1681         //
1682         //  Check if the specifific handle is currently being used.
1683         //
1684 
1685         EaOffsetIndex = EaHandle & (MAX_EA_OFFSET_INDEX - 1);
1686         EaOffsetCluster = *((PUSHORT) EaOffsetRange.Data + EaOffsetIndex);
1687 
1688         if (EaOffsetCluster == UNUSED_EA_HANDLE) {
1689 
1690             DebugTrace(0, Dbg, "FatReadEaSet: Ea handle is unused\n", 0);
1691             FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
1692         }
1693 
1694         //
1695         //  Compute the file offset for the Ea data.
1696         //
1697 
1698         EaHeaderBaseIndex = EaHandle >> 7;
1699         EaSetVbo = (EaHeader->EaBaseTable[EaHeaderBaseIndex] + EaOffsetCluster)
1700                    << Vcb->AllocationSupport.LogOfBytesPerCluster;
1701 
1702         //
1703         //  Unpin the file header and offset table.
1704         //
1705 
1706         FatUnpinEaRange( IrpContext, &EaHeaderRange );
1707         FatUnpinEaRange( IrpContext, &EaOffsetRange );
1708 
1709         //
1710         //  Try to pin the requested Ea set.
1711         //
1712 
1713         FatPinEaRange( IrpContext,
1714                        VirtualEaFile,
1715                        EaFcb,
1716                        &EaSetRange,
1717                        EaSetVbo,
1718                        BytesPerCluster,
1719                        STATUS_DATA_ERROR );
1720 
1721         EaSet = (PEA_SET_HEADER) EaSetRange.Data;
1722 
1723         if (EaSet->Signature != EA_SET_SIGNATURE
1724             || EaSet->OwnEaHandle != EaHandle ) {
1725 
1726             DebugTrace(0, Dbg, "FatReadEaSet: Ea set header is corrupt\n", 0);
1727             FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
1728         }
1729 
1730         //
1731         //  At this point we have pinned a single cluster of Ea data.  If
1732         //  this represents the entire Ea data for the Ea index, we know
1733         //  the number of clusters to remove.  Otherwise we need to check
1734         //  on the entire size of the Ea set header and whether it is
1735         //  contained in the allocated size of the Ea virtual file.  At
1736         //  that point we unpin the partial Ea set header and remember the
1737         //  starting cluster offset and number of clusters in both cluster
1738         //  and Vbo formats.
1739         //
1740         //  At that point the following variables have the described
1741         //  values.
1742         //
1743         //      EaSetVbo - Vbo to start splice at.
1744         //      EaSetLength - Number of bytes to splice.
1745         //      EaSetClusterCount - Number of clusters to splice.
1746         //
1747 
1748         CbList = GetcbList( EaSet );
1749 
1750         EaSetClusterCount = (USHORT) ((CbList + EA_CBLIST_OFFSET + BytesPerCluster - 1)
1751                                       >> Vcb->AllocationSupport.LogOfBytesPerCluster);
1752 
1753         EaSetLength = EaSetClusterCount << Vcb->AllocationSupport.LogOfBytesPerCluster;
1754 
1755         if (EaSetLength > BytesPerCluster) {
1756 
1757             if (EaFcb->Header.FileSize.LowPart - EaSetVbo < EaSetLength) {
1758 
1759                 DebugTrace(0, Dbg, "FatDeleteEaSet: Full Ea set not contained in file\n", 0);
1760 
1761                 FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
1762             }
1763         }
1764 
1765         FatUnpinEaRange( IrpContext, &EaSetRange );
1766 
1767         //
1768         //  Update the cache manager for this file.  This is done by
1769         //  truncating to the point where the data was spliced and
1770         //  reinitializing with the modified size of the file.
1771         //
1772         //  NOTE: Even if the all the EA's are removed the Ea file will
1773         //  always exist and the header area will never shrink.
1774         //
1775 
1776         FileOffset.LowPart = EaSetVbo;
1777         FileOffset.HighPart = 0;
1778 
1779         //
1780         //  Round the cache map down to a system page boundary.
1781         //
1782 
1783         FileOffset.LowPart &= ~(PAGE_SIZE - 1);
1784 
1785         //
1786         //  Make sure all the data gets out to the disk.
1787         //
1788 
1789         {
1790             IO_STATUS_BLOCK Iosb;
1791             ULONG PurgeCount = 5;
1792 
1793             while (--PurgeCount) {
1794 
1795                 Iosb.Status = STATUS_SUCCESS;
1796 
1797                 CcFlushCache( VirtualEaFile->SectionObjectPointer,
1798                               NULL,
1799                               0,
1800                               &Iosb );
1801 
1802                 NT_ASSERT( Iosb.Status == STATUS_SUCCESS );
1803 
1804                 //
1805                 //  We do not have to worry about a lazy writer firing in parallel
1806                 //  with our CcFlushCache since we have the EaFcb exclusive.  Thus
1807                 //  we know all data is out.
1808                 //
1809 
1810                 //
1811                 //  We throw the unwanted pages out of the cache and then
1812                 //  truncate the Ea File for the new size.
1813                 //
1814 
1815                 if (CcPurgeCacheSection( VirtualEaFile->SectionObjectPointer,
1816                                          &FileOffset,
1817                                          0,
1818                                          FALSE )) {
1819 
1820                     break;
1821                 }
1822             }
1823 
1824             if (!PurgeCount) {
1825 
1826                 FatRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION );
1827             }
1828         }
1829 
1830         FileOffset.LowPart = EaFcb->Header.FileSize.LowPart - EaSetLength;
1831 
1832         //
1833         //  Perform the splice operation on the FAT chain.  This is done
1834         //  by splitting the target clusters out and merging the remaining
1835         //  clusters around them.  We can ignore the return value from
1836         //  the merge and splice functions because we are guaranteed
1837         //  to be able to block.
1838         //
1839 
1840         {
1841             FsRtlInitializeLargeMcb( &DataMcb, PagedPool );
1842 
1843             UnwindInitializeDataMcb = TRUE;
1844 
1845             FatSplitAllocation( IrpContext,
1846                                 Vcb,
1847                                 &EaFcb->Mcb,
1848                                 EaSetVbo,
1849                                 &DataMcb );
1850 
1851             UnwindSplitData = TRUE;
1852 
1853             if (EaSetLength + EaSetVbo != EaFcb->Header.FileSize.LowPart) {
1854 
1855                 FsRtlInitializeLargeMcb( &TailMcb, PagedPool );
1856 
1857                 UnwindInitializeTailMcb = TRUE;
1858 
1859                 FatSplitAllocation( IrpContext,
1860                                     Vcb,
1861                                     &DataMcb,
1862                                     EaSetLength,
1863                                     &TailMcb );
1864 
1865                 UnwindSplitTail = TRUE;
1866 
1867                 FatMergeAllocation( IrpContext,
1868                                     Vcb,
1869                                     &EaFcb->Mcb,
1870                                     &TailMcb );
1871 
1872                 UnwindMergeTail = TRUE;
1873             }
1874         }
1875 
1876         //
1877         //  Update the Fcb for the Ea file
1878         //
1879 
1880         UnwindPrevFileSize = EaFcb->Header.FileSize.LowPart;
1881 
1882         (VOID)ExAcquireResourceExclusiveLite( EaFcb->Header.PagingIoResource,
1883                                           TRUE );
1884 
1885         EaFcb->Header.FileSize.LowPart = EaFcb->Header.FileSize.LowPart - EaSetLength;
1886         EaFcb->Header.AllocationSize = EaFcb->Header.FileSize;
1887 
1888 
1889         CcSetFileSizes( VirtualEaFile,
1890                         (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
1891 
1892         ExReleaseResourceLite( EaFcb->Header.PagingIoResource );
1893 
1894         UnwindCacheValues = TRUE;
1895 
1896         EaDirent->FileSize = EaFcb->Header.FileSize.LowPart;
1897 
1898         FatSetDirtyBcb( IrpContext, EaBcb, Vcb, TRUE );
1899 
1900         //
1901         //  Update the Ea base and offset tables.  For the Ea base table,
1902         //  all subsequent index values must be decremented by the number
1903         //  of clusters removed.
1904         //
1905         //  For the entries in the relevant Ea offset table, all entries
1906         //  after this index must also be decreased by the number of
1907         //  clusters removed.
1908         //
1909 
1910         //
1911         //  Pin down the EA file header.
1912         //
1913 
1914         RtlZeroMemory( &EaHeaderRange,
1915                        sizeof( EA_RANGE ));
1916 
1917         FatPinEaRange( IrpContext,
1918                        VirtualEaFile,
1919                        EaFcb,
1920                        &EaHeaderRange,
1921                        0,
1922                        sizeof( EA_FILE_HEADER ),
1923                        STATUS_NONEXISTENT_EA_ENTRY );
1924 
1925         EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
1926 
1927         //
1928         //  Pin down the Ea offset table for the particular index.
1929         //
1930 
1931         RtlZeroMemory( &EaOffsetRange,
1932                        sizeof( EA_RANGE ));
1933 
1934         FatPinEaRange( IrpContext,
1935                        VirtualEaFile,
1936                        EaFcb,
1937                        &EaOffsetRange,
1938                        EaOffsetVbo,
1939                        sizeof( EA_OFF_TABLE ),
1940                        STATUS_NONEXISTENT_EA_ENTRY );
1941 
1942         {
1943             ULONG Count;
1944             PUSHORT NextEaIndex;
1945 
1946             Count = MAX_EA_BASE_INDEX - EaHeaderBaseIndex - 1;
1947 
1948             NextEaIndex = &EaHeader->EaBaseTable[EaHeaderBaseIndex + 1];
1949 
1950             while (Count--) {
1951 
1952                 *(NextEaIndex++) -= EaSetClusterCount;
1953             }
1954 
1955             FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaHeaderRange );
1956 
1957             Count = MAX_EA_OFFSET_INDEX - EaOffsetIndex - 1;
1958             NextEaIndex = (PUSHORT) EaOffsetRange.Data + EaOffsetIndex;
1959 
1960             *(NextEaIndex++) = UNUSED_EA_HANDLE;
1961 
1962             while (Count--) {
1963 
1964                 if (*NextEaIndex != UNUSED_EA_HANDLE) {
1965 
1966                     *NextEaIndex -= EaSetClusterCount;
1967                 }
1968 
1969                 NextEaIndex++;
1970             }
1971 
1972             FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaOffsetRange );
1973         }
1974 
1975         UnwindModifiedEaHeader = TRUE;
1976 
1977         //
1978         //  Deallocate the ea set removed
1979         //
1980 
1981         FatDeallocateDiskSpace( IrpContext,
1982                                 Vcb,
1983                                 &DataMcb,
1984                                 FALSE );
1985 
1986     } _SEH2_FINALLY {
1987 
1988         DebugUnwind( FatDeleteEaSet );
1989 
1990         //
1991         //  Restore file if abnormal termination.
1992         //
1993         //  If we have modified the ea file header we ignore this
1994         //  error.  Otherwise we walk through the state variables.
1995         //
1996 
1997         if (_SEH2_AbnormalTermination()
1998             && !UnwindModifiedEaHeader) {
1999 
2000             //
2001             //  If we modified the Ea dirent or Fcb, recover the previous
2002             //  values.
2003             //
2004 
2005             if (UnwindPrevFileSize) {
2006 
2007                 EaFcb->Header.FileSize.LowPart = UnwindPrevFileSize;
2008                 EaFcb->Header.AllocationSize.LowPart = UnwindPrevFileSize;
2009                 EaDirent->FileSize = UnwindPrevFileSize;
2010 
2011                 if (UnwindCacheValues) {
2012 
2013                     CcSetFileSizes( VirtualEaFile,
2014                                     (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
2015                 }
2016             }
2017 
2018             //
2019             //  If we merged the tail with the
2020             //  ea file header.  We split it out
2021             //  again.
2022             //
2023 
2024             if (UnwindMergeTail) {
2025 
2026                 FatSplitAllocation( IrpContext,
2027                                     Vcb,
2028                                     &EaFcb->Mcb,
2029                                     EaSetVbo,
2030                                     &TailMcb );
2031             }
2032 
2033             //
2034             //  If we split the tail off we merge the tail back
2035             //  with the ea data to remove.
2036             //
2037 
2038             if (UnwindSplitTail) {
2039 
2040                 FatMergeAllocation( IrpContext,
2041                                     Vcb,
2042                                     &DataMcb,
2043                                     &TailMcb );
2044             }
2045 
2046             //
2047             //  If the ea set has been split out, we merge that
2048             //  cluster string back in the file.  Otherwise we
2049             //  simply uninitialize the local Mcb.
2050             //
2051 
2052             if (UnwindSplitData) {
2053 
2054                 FatMergeAllocation( IrpContext,
2055                                     Vcb,
2056                                     &EaFcb->Mcb,
2057                                     &DataMcb );
2058             }
2059         }
2060 
2061         //
2062         //  Unpin any Bcb's still active.
2063         //
2064 
2065         FatUnpinEaRange( IrpContext, &EaHeaderRange );
2066         FatUnpinEaRange( IrpContext, &EaOffsetRange );
2067         FatUnpinEaRange( IrpContext, &EaSetRange );
2068 
2069         //
2070         //  Uninitialize any initialized Mcbs
2071         //
2072 
2073         if (UnwindInitializeDataMcb) {
2074 
2075             FsRtlUninitializeLargeMcb( &DataMcb );
2076         }
2077 
2078         if (UnwindInitializeTailMcb) {
2079 
2080             FsRtlUninitializeLargeMcb( &TailMcb );
2081         }
2082 
2083         DebugTrace(-1, Dbg, "FatDeleteEaSet -> Exit\n", 0);
2084     } _SEH2_END;
2085 
2086     return;
2087 }
2088 
2089 
2090 
_Requires_lock_held_(_Global_critical_region_)2091 _Requires_lock_held_(_Global_critical_region_)
2092 VOID
2093 FatAddEaSet (
2094     IN PIRP_CONTEXT IrpContext,
2095     IN PVCB Vcb,
2096     IN ULONG EaSetLength,
2097     IN PBCB EaBcb,
2098     OUT PDIRENT EaDirent,
2099     OUT PUSHORT EaHandle,
2100     OUT PEA_RANGE EaSetRange
2101     )
2102 
2103 /*++
2104 
2105 Routine Description:
2106 
2107     This routine will add the necessary clusters to support a new
2108     Ea set of the given size.  This is done by splicing a chain of
2109     clusters into the existing Ea file.  An Ea index is assigned to
2110     this new chain and the Ea base and offset tables are updated to
2111     include this new handle.  This routine also pins the added
2112     clusters and returns their address and a Bcb.
2113 
2114     The caller of this function will have verified that the Ea file
2115     exists and that the Vcb field points to an initialized cache file.
2116     The caller will already have gained exclusive access to the
2117     EaFcb.
2118 
2119 Arguments:
2120 
2121     Vcb - Supplies the Vcb to fill in.
2122 
2123     EaSetLength - The number of bytes needed to contain the Ea set.  This
2124         routine will round this up the next cluster size.
2125 
2126     EaBcb - Supplies a pointer to the Bcb for the Ea dirent.
2127 
2128     EaDirent - Supplies a pointer to the dirent for the Ea file.
2129 
2130     EaHandle - Supplies the address to store the ea index generated here.
2131 
2132     EaSetRange - This is the structure that describes new range in the Ea file.
2133 
2134 Return Value:
2135 
2136     None.
2137 
2138 --*/
2139 
2140 {
2141     ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
2142 
2143     EA_RANGE EaHeaderRange;
2144     USHORT EaHeaderIndex;
2145     PEA_FILE_HEADER EaHeader;
2146 
2147     EA_RANGE EaOffsetRange;
2148     ULONG EaNewOffsetVbo = 0;
2149     USHORT EaOffsetIndex;
2150     ULONG EaOffsetTableSize;
2151     PUSHORT EaOffsetTable;
2152 
2153     ULONG EaSetClusterOffset;
2154     ULONG EaSetVbo = 0;
2155     USHORT EaSetClusterCount;
2156     PEA_SET_HEADER EaSet;
2157 
2158     PFILE_OBJECT VirtualEaFile = Vcb->VirtualEaFile;
2159     PFCB EaFcb = Vcb->EaFcb;
2160 
2161     LARGE_MCB EaSetMcb;
2162     BOOLEAN UnwindInitializedEaSetMcb = FALSE;
2163     BOOLEAN UnwindAllocatedNewAllocation = FALSE;
2164     BOOLEAN UnwindMergedNewEaSet = FALSE;
2165 
2166     LARGE_MCB EaOffsetMcb;
2167     BOOLEAN UnwindInitializedOffsetMcb = FALSE;
2168     BOOLEAN UnwindSplitNewAllocation = FALSE;
2169     BOOLEAN UnwindMergedNewOffset = FALSE;
2170 
2171     LARGE_MCB EaTailMcb;
2172     BOOLEAN UnwindInitializedTailMcb = FALSE;
2173     BOOLEAN UnwindSplitTail = FALSE;
2174     BOOLEAN UnwindMergedTail = FALSE;
2175 
2176     LARGE_MCB EaInitialEaMcb;
2177     BOOLEAN UnwindInitializedInitialEaMcb = FALSE;
2178     BOOLEAN UnwindSplitInitialEa = FALSE;
2179     BOOLEAN UnwindMergedInitialEa = FALSE;
2180 
2181     USHORT NewEaIndex;
2182     PUSHORT NextEaOffset;
2183 
2184     ULONG NewAllocation;
2185     LARGE_INTEGER FileOffset;
2186     ULONG Count;
2187 
2188     ULONG UnwindPrevFileSize = 0;
2189     BOOLEAN UnwindCacheValues = FALSE;
2190 
2191     BOOLEAN TailExists = FALSE;
2192     BOOLEAN AddedOffsetTableCluster = FALSE;
2193     BOOLEAN UnwindPurgeCacheMap = FALSE;
2194 
2195     PAGED_CODE();
2196 
2197     DebugTrace(+1, Dbg, "FatAddEaSet\n", 0);
2198     DebugTrace( 0, Dbg, "  Vcb         = %p\n", Vcb);
2199     DebugTrace( 0, Dbg, "  EaSetLength = %ul\n", EaSetLength );
2200 
2201     //
2202     //  Zero the Ea range structures.
2203     //
2204 
2205     RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
2206     RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
2207 
2208     //
2209     //  Use a try statement to facilitate cleanup.
2210     //
2211 
2212     _SEH2_TRY {
2213 
2214         //
2215         //  Pin down the file header.
2216         //
2217 
2218         FatPinEaRange( IrpContext,
2219                        VirtualEaFile,
2220                        EaFcb,
2221                        &EaHeaderRange,
2222                        0,
2223                        sizeof( EA_FILE_HEADER ),
2224                        STATUS_DATA_ERROR );
2225 
2226         EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
2227 
2228         //
2229         //  Compute the size of the offset table.
2230         //
2231 
2232         EaNewOffsetVbo = EaHeader->EaBaseTable[0] << Vcb->AllocationSupport.LogOfBytesPerCluster;
2233         EaOffsetTableSize = EaNewOffsetVbo - sizeof( EA_FILE_HEADER );
2234 
2235         //
2236         //  Pin down the entire offset table.
2237         //
2238 
2239         FatPinEaRange( IrpContext,
2240                        VirtualEaFile,
2241                        EaFcb,
2242                        &EaOffsetRange,
2243                        sizeof( EA_FILE_HEADER ),
2244                        EaOffsetTableSize,
2245                        STATUS_DATA_ERROR );
2246 
2247         //
2248         //  We now look for a valid handle out of the existing offset table.
2249         //  We start at the last entry and walk backwards.  We stop at the
2250         //  first unused handle which is preceded by a used handle (or handle
2251         //  1).
2252         //
2253         //  As we walk backwards, we need to remember the file offset of the
2254         //  cluster which will follow the clusters we add.  We initially
2255         //  remember the end of the file.  If the end of the offset table
2256         //  consists of a string of used handles, we remember the offset of
2257         //  the handle prior to the transition from used to unused handles.
2258         //
2259 
2260         EaSetClusterOffset = EaFcb->Header.FileSize.LowPart
2261                              >> Vcb->AllocationSupport.LogOfBytesPerCluster;
2262 
2263         NewEaIndex = (USHORT) ((EaOffsetTableSize >> 1) - 1);
2264 
2265         NextEaOffset = (PUSHORT) EaOffsetRange.Data + NewEaIndex;
2266 
2267         //
2268         //  Walk through the used handles at the end of the offset table.
2269         //
2270 
2271         if (*NextEaOffset != UNUSED_EA_HANDLE) {
2272 
2273             while (NewEaIndex != 0) {
2274 
2275                 if (*(NextEaOffset - 1) == UNUSED_EA_HANDLE) {
2276 
2277                     //
2278                     //  If the handle is 1, we take no action.  Otherwise
2279                     //  we save the cluster offset of the current handle
2280                     //  knowing we will use a previous handle and insert
2281                     //  a chain of clusters.
2282                     //
2283 
2284                     if (NewEaIndex != 1) {
2285 
2286                         EaSetClusterOffset = *NextEaOffset
2287                                              + EaHeader->EaBaseTable[NewEaIndex >> 7];
2288 
2289                         TailExists = TRUE;
2290                     }
2291 
2292                     NewEaIndex--;
2293                     NextEaOffset--;
2294 
2295                     break;
2296                 }
2297 
2298                 NewEaIndex--;
2299                 NextEaOffset--;
2300             }
2301         }
2302 
2303         //
2304         //  Walk through looking for the first unused handle in a string
2305         //  of unused handles.
2306         //
2307 
2308         while (NewEaIndex) {
2309 
2310             if (*(NextEaOffset - 1) != UNUSED_EA_HANDLE) {
2311 
2312                 break;
2313             }
2314 
2315             NextEaOffset--;
2316             NewEaIndex--;
2317         }
2318 
2319         //
2320         //  If the handle is zero, we do a special test to see if handle 1
2321         //  is available.  Otherwise we will use the first handle of a new
2322         //  cluster.  A non-zero handle now indicates that a handle was found
2323         //  in an existing offset table cluster.
2324         //
2325 
2326         if (NewEaIndex == 0) {
2327 
2328             if (*(NextEaOffset + 1) == UNUSED_EA_HANDLE) {
2329 
2330                 NewEaIndex = 1;
2331 
2332             } else {
2333 
2334                 NewEaIndex = (USHORT) EaOffsetTableSize >> 1;
2335                 AddedOffsetTableCluster = TRUE;
2336             }
2337         }
2338 
2339         //
2340         //  If the Ea index is outside the legal range then raise an
2341         //  exception.
2342         //
2343 
2344         if (NewEaIndex > MAX_EA_HANDLE) {
2345 
2346             DebugTrace(-1, Dbg,
2347                        "FatAddEaSet: Illegal handle value for new handle\n", 0);
2348 
2349             FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2350         }
2351 
2352         //
2353         //  Compute the base and offset indexes.
2354         //
2355 
2356         EaHeaderIndex = NewEaIndex >> 7;
2357         EaOffsetIndex = NewEaIndex & (MAX_EA_OFFSET_INDEX - 1);
2358 
2359         //
2360         //  Compute the byte offset of the new ea data in the file.
2361         //
2362 
2363         EaSetVbo = EaSetClusterOffset << Vcb->AllocationSupport.LogOfBytesPerCluster;
2364 
2365         //
2366         //  Allocate all the required disk space together to insure this
2367         //  operation is atomic.  We don't want to allocate one block
2368         //  of disk space and then fail on a second allocation.
2369         //
2370 
2371         EaSetLength = (EaSetLength + BytesPerCluster - 1)
2372                       & ~(BytesPerCluster - 1);
2373 
2374         NewAllocation = EaSetLength
2375                         + (AddedOffsetTableCluster ? BytesPerCluster : 0);
2376 
2377         //
2378         //  Verify that adding these clusters will not grow the Ea file
2379         //  beyond its legal value.  The maximum number of clusters is
2380         //  2^16 since the Ea sets are referenced by a 16 bit cluster
2381         //  offset value.
2382         //
2383 
2384         if ((ULONG) ((0x0000FFFF << Vcb->AllocationSupport.LogOfBytesPerCluster)
2385                      - EaFcb->Header.FileSize.LowPart)
2386             < NewAllocation) {
2387 
2388             DebugTrace(-1, Dbg,
2389                        "FatAddEaSet: New Ea file size is too large\n", 0);
2390 
2391             FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2392         }
2393 
2394         FsRtlInitializeLargeMcb( &EaSetMcb, PagedPool );
2395 
2396         UnwindInitializedEaSetMcb = TRUE;
2397 
2398         FatAllocateDiskSpace( IrpContext,
2399                               Vcb,
2400                               0,
2401                               &NewAllocation,
2402                               FALSE,
2403                               &EaSetMcb );
2404 
2405         UnwindAllocatedNewAllocation = TRUE;
2406 
2407         EaSetClusterCount = (USHORT) (EaSetLength >> Vcb->AllocationSupport.LogOfBytesPerCluster);
2408 
2409         if (AddedOffsetTableCluster) {
2410 
2411             FsRtlInitializeLargeMcb( &EaOffsetMcb, PagedPool );
2412 
2413             UnwindInitializedOffsetMcb = TRUE;
2414 
2415             FatSplitAllocation( IrpContext,
2416                                 Vcb,
2417                                 &EaSetMcb,
2418                                 EaSetLength,
2419                                 &EaOffsetMcb );
2420 
2421             UnwindSplitNewAllocation = TRUE;
2422         }
2423 
2424         FatUnpinEaRange( IrpContext, &EaHeaderRange );
2425         FatUnpinEaRange( IrpContext, &EaOffsetRange );
2426 
2427         if (AddedOffsetTableCluster) {
2428 
2429             FileOffset.LowPart = EaNewOffsetVbo;
2430 
2431         } else {
2432 
2433             FileOffset.LowPart = EaSetVbo;
2434         }
2435 
2436         FileOffset.HighPart = 0;
2437 
2438         //
2439         //  Round the cache map down to a system page boundary.
2440         //
2441 
2442         FileOffset.LowPart &= ~(PAGE_SIZE - 1);
2443 
2444         {
2445             IO_STATUS_BLOCK Iosb;
2446             ULONG PurgeCount = 5;
2447 
2448             while (--PurgeCount) {
2449 
2450                 Iosb.Status = STATUS_SUCCESS;
2451 
2452                 CcFlushCache( VirtualEaFile->SectionObjectPointer,
2453                               NULL,
2454                               0,
2455                               &Iosb );
2456 
2457                 NT_ASSERT( Iosb.Status == STATUS_SUCCESS );
2458 
2459                 //
2460                 //  We do not have to worry about a lazy writer firing in parallel
2461                 //  with our CcFlushCache since we have the EaFcb exclusive.  Thus
2462                 //  we know all data is out.
2463                 //
2464 
2465                 //
2466                 //  We throw the unwanted pages out of the cache and then
2467                 //  truncate the Ea File for the new size.
2468                 //
2469                 //
2470 
2471                 if (CcPurgeCacheSection( VirtualEaFile->SectionObjectPointer,
2472                                          &FileOffset,
2473                                          0,
2474                                          FALSE )) {
2475 
2476                     break;
2477                 }
2478             }
2479 
2480             if (!PurgeCount) {
2481 
2482                 FatRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION );
2483             }
2484         }
2485 
2486         UnwindPurgeCacheMap = TRUE;
2487 
2488         FileOffset.LowPart = EaFcb->Header.FileSize.LowPart + NewAllocation;
2489 
2490         //
2491         //  If there is a tail to the file, then we initialize an Mcb
2492         //  for the file section and split the tail from the file.
2493         //
2494 
2495         if (TailExists) {
2496 
2497             FsRtlInitializeLargeMcb( &EaTailMcb, PagedPool );
2498 
2499             UnwindInitializedTailMcb = TRUE;
2500 
2501             FatSplitAllocation( IrpContext,
2502                                 Vcb,
2503                                 &EaFcb->Mcb,
2504                                 EaSetVbo,
2505                                 &EaTailMcb );
2506 
2507             UnwindSplitTail = TRUE;
2508         }
2509 
2510         //
2511         //  If there is an initial section of ea data, we initialize an
2512         //  Mcb for that section.
2513         //
2514 
2515         if (AddedOffsetTableCluster
2516             && EaSetVbo != EaNewOffsetVbo) {
2517 
2518             FsRtlInitializeLargeMcb( &EaInitialEaMcb, PagedPool );
2519 
2520             UnwindInitializedInitialEaMcb = TRUE;
2521 
2522             FatSplitAllocation( IrpContext,
2523                                 Vcb,
2524                                 &EaFcb->Mcb,
2525                                 EaNewOffsetVbo,
2526                                 &EaInitialEaMcb );
2527 
2528             UnwindSplitInitialEa = TRUE;
2529         }
2530 
2531         //
2532         //  We have now split the new file allocation into the new
2533         //  ea set and possibly a new offset table.
2534         //
2535         //  We have also split the existing file data into a file
2536         //  header, an initial section of ea data and the tail of the
2537         //  file.  These last 2 may not exist.
2538         //
2539         //  Each section is described by an Mcb.
2540         //
2541 
2542         //
2543         //  Merge the new offset information if it exists.
2544         //
2545 
2546         if (AddedOffsetTableCluster) {
2547 
2548             FatMergeAllocation( IrpContext,
2549                                 Vcb,
2550                                 &EaFcb->Mcb,
2551                                 &EaOffsetMcb );
2552 
2553             FsRtlUninitializeLargeMcb( &EaOffsetMcb );
2554             FsRtlInitializeLargeMcb( &EaOffsetMcb, PagedPool );
2555 
2556             UnwindMergedNewOffset = TRUE;
2557         }
2558 
2559         //
2560         //  Merge the existing initial ea data if it exists.
2561         //
2562 
2563         if (UnwindInitializedInitialEaMcb) {
2564 
2565             FatMergeAllocation( IrpContext,
2566                                 Vcb,
2567                                 &EaFcb->Mcb,
2568                                 &EaInitialEaMcb );
2569 
2570             FsRtlUninitializeLargeMcb( &EaInitialEaMcb );
2571             FsRtlInitializeLargeMcb( &EaInitialEaMcb, PagedPool );
2572 
2573             UnwindMergedInitialEa = TRUE;
2574         }
2575 
2576         //
2577         //  We modify the offset of the new ea set by one cluster if
2578         //  we added one to the offset table.
2579         //
2580 
2581         if (AddedOffsetTableCluster) {
2582 
2583             EaSetClusterOffset += 1;
2584             EaSetVbo += BytesPerCluster;
2585         }
2586 
2587         //
2588         //  Merge the new ea set.
2589         //
2590 
2591         FatMergeAllocation( IrpContext,
2592                             Vcb,
2593                             &EaFcb->Mcb,
2594                             &EaSetMcb );
2595 
2596         FsRtlUninitializeLargeMcb( &EaSetMcb );
2597         FsRtlInitializeLargeMcb( &EaSetMcb, PagedPool );
2598 
2599         UnwindMergedNewEaSet = TRUE;
2600 
2601         //
2602         //  Merge the tail if it exists.
2603         //
2604 
2605         if (UnwindInitializedTailMcb) {
2606 
2607             FatMergeAllocation( IrpContext,
2608                                 Vcb,
2609                                 &EaFcb->Mcb,
2610                                 &EaTailMcb );
2611 
2612             FsRtlUninitializeLargeMcb( &EaTailMcb );
2613             FsRtlInitializeLargeMcb( &EaTailMcb, PagedPool );
2614 
2615             UnwindMergedTail = TRUE;
2616         }
2617 
2618         //
2619         //  If we added a new cluster for the offset table, we need to
2620         //  lock the entire cluster down and initialize all the handles to
2621         //  the unused state except the first one.
2622         //
2623 
2624         //
2625         //  Update the Fcb information.
2626         //
2627 
2628         UnwindPrevFileSize = EaFcb->Header.FileSize.LowPart;
2629 
2630         EaFcb->Header.FileSize.LowPart += NewAllocation;
2631         EaFcb->Header.AllocationSize = EaFcb->Header.FileSize;
2632         EaDirent->FileSize = EaFcb->Header.FileSize.LowPart;
2633 
2634         FatSetDirtyBcb( IrpContext, EaBcb, Vcb, TRUE );
2635 
2636         //
2637         //  Let Mm and Cc know the new file sizes.
2638         //
2639 
2640         CcSetFileSizes( VirtualEaFile,
2641                         (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
2642 
2643         UnwindCacheValues = TRUE;
2644 
2645         //
2646         //  Pin down the file header.
2647         //
2648 
2649         RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
2650 
2651         FatPinEaRange( IrpContext,
2652                        VirtualEaFile,
2653                        EaFcb,
2654                        &EaHeaderRange,
2655                        0,
2656                        sizeof( EA_FILE_HEADER ),
2657                        STATUS_DATA_ERROR );
2658 
2659         EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
2660 
2661         //
2662         //  Pin down the entire offset table.
2663         //
2664 
2665 
2666         RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
2667 
2668         FatPinEaRange( IrpContext,
2669                        VirtualEaFile,
2670                        EaFcb,
2671                        &EaOffsetRange,
2672                        sizeof( EA_FILE_HEADER ) + (((ULONGLONG)NewEaIndex >> 7) << 8),
2673                        sizeof( EA_OFF_TABLE ),
2674                        STATUS_DATA_ERROR );
2675 
2676         EaOffsetTable = (PUSHORT) EaOffsetRange.Data;
2677 
2678         //
2679         //  Pin the Ea set header for the added clusters and initialize
2680         //  the fields of interest.  These are the signature field, the
2681         //  owning handle field, the need Ea field and the cbList field.
2682         //  Also mark the data as dirty.
2683         //
2684 
2685         //
2686         //  Pin the ea set.
2687         //
2688 
2689         FatPinEaRange( IrpContext,
2690                        VirtualEaFile,
2691                        EaFcb,
2692                        EaSetRange,
2693                        EaSetVbo,
2694                        EaSetLength,
2695                        STATUS_DATA_ERROR );
2696 
2697         EaSet = (PEA_SET_HEADER) EaSetRange->Data;
2698 
2699         EaSet->Signature = EA_SET_SIGNATURE;
2700         EaSet->OwnEaHandle = NewEaIndex;
2701 
2702         FatMarkEaRangeDirty( IrpContext, VirtualEaFile, EaSetRange );
2703 
2704         //
2705         //  Update the Ea base and offset tables.  For the Ea base table,
2706         //  all subsequent index values must be incremented by the number
2707         //  of clusters added.
2708         //
2709         //  For the entries in the relevant Ea offset table, all entries
2710         //  after this index must also be increased by the number of
2711         //  clusters added.
2712         //
2713         //  If we added another cluster to the offset table, then we increment
2714         //  all the base table values by 1.
2715         //
2716 
2717         Count = MAX_EA_BASE_INDEX - EaHeaderIndex - 1;
2718 
2719         NextEaOffset = &EaHeader->EaBaseTable[EaHeaderIndex + 1];
2720 
2721         while (Count--) {
2722 
2723             *(NextEaOffset++) += EaSetClusterCount;
2724         }
2725 
2726         if (AddedOffsetTableCluster) {
2727 
2728             Count = MAX_EA_BASE_INDEX;
2729 
2730             NextEaOffset = &EaHeader->EaBaseTable[0];
2731 
2732             while (Count--) {
2733 
2734                 *(NextEaOffset++) += 1;
2735             }
2736         }
2737 
2738         FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaHeaderRange );
2739 
2740         //
2741         //  If we added an offset table cluster, we need to initialize
2742         //  the handles to unused.
2743         //
2744 
2745         if (AddedOffsetTableCluster) {
2746 
2747             Count = (BytesPerCluster >> 1) - 1;
2748             NextEaOffset = EaOffsetTable;
2749 
2750             *NextEaOffset++ = 0;
2751 
2752             while (Count--) {
2753 
2754                 *NextEaOffset++ = UNUSED_EA_HANDLE;
2755             }
2756         }
2757 
2758         //
2759         //  We need to compute the offset of the added Ea set clusters
2760         //  from their base.
2761         //
2762 
2763         NextEaOffset = EaOffsetTable + EaOffsetIndex;
2764 
2765         *NextEaOffset++ = (USHORT) (EaSetClusterOffset
2766                                     - EaHeader->EaBaseTable[EaHeaderIndex]);
2767 
2768         Count = MAX_EA_OFFSET_INDEX - EaOffsetIndex - 1;
2769 
2770         while (Count--) {
2771 
2772             if (*NextEaOffset != UNUSED_EA_HANDLE) {
2773 
2774                 *NextEaOffset += EaSetClusterCount;
2775             }
2776 
2777             NextEaOffset++;
2778         }
2779 
2780         FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaOffsetRange );
2781 
2782         //
2783         //  Update the callers parameters.
2784         //
2785 
2786         *EaHandle = NewEaIndex;
2787 
2788         DebugTrace(0, Dbg, "FatAddEaSet: Return values\n", 0);
2789 
2790         DebugTrace(0, Dbg, "FatAddEaSet: New Handle -> %x\n",
2791                    *EaHandle);
2792 
2793     } _SEH2_FINALLY {
2794 
2795         DebugUnwind( FatAddEaSet );
2796 
2797         //
2798         //  Handle cleanup for abnormal termination only if we allocated
2799         //  disk space for the new ea set.
2800         //
2801 
2802         if (_SEH2_AbnormalTermination() && UnwindAllocatedNewAllocation) {
2803 
2804             //
2805             //  If we modified the Ea dirent or Fcb, recover the previous
2806             //  values.  Even though we are decreasing FileSize here, we
2807             //  don't need to synchronize to synchronize with paging Io
2808             //  because there was no dirty data generated in the new allocation.
2809             //
2810 
2811             if (UnwindPrevFileSize) {
2812 
2813                 EaFcb->Header.FileSize.LowPart = UnwindPrevFileSize;
2814                 EaFcb->Header.AllocationSize.LowPart = UnwindPrevFileSize;
2815                 EaDirent->FileSize = UnwindPrevFileSize;
2816 
2817                 if (UnwindCacheValues) {
2818 
2819                     CcSetFileSizes( VirtualEaFile,
2820                                     (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
2821                 }
2822             }
2823 
2824             //
2825             //  If we merged the tail then split it off.
2826             //
2827 
2828             if (UnwindMergedTail) {
2829 
2830                 VBO NewTailPosition;
2831 
2832                 NewTailPosition = EaSetVbo + EaSetLength;
2833 
2834                 FatSplitAllocation( IrpContext,
2835                                     Vcb,
2836                                     &EaFcb->Mcb,
2837                                     NewTailPosition,
2838                                     &EaTailMcb );
2839             }
2840 
2841             //
2842             //  If we merged the new ea data then split it out.
2843             //
2844 
2845             if (UnwindMergedNewEaSet) {
2846 
2847                 FatSplitAllocation( IrpContext,
2848                                     Vcb,
2849                                     &EaFcb->Mcb,
2850                                     EaSetVbo,
2851                                     &EaSetMcb );
2852             }
2853 
2854             //
2855             //  If we merged the initial ea data then split it out.
2856             //
2857 
2858             if (UnwindMergedInitialEa) {
2859 
2860                 FatSplitAllocation( IrpContext,
2861                                     Vcb,
2862                                     &EaFcb->Mcb,
2863                                     EaNewOffsetVbo + BytesPerCluster,
2864                                     &EaInitialEaMcb );
2865             }
2866 
2867             //
2868             //  If we added a new offset cluster, then split it out.
2869             //
2870 
2871             if (UnwindMergedNewOffset) {
2872 
2873                 FatSplitAllocation( IrpContext,
2874                                     Vcb,
2875                                     &EaFcb->Mcb,
2876                                     EaNewOffsetVbo,
2877                                     &EaOffsetMcb );
2878             }
2879 
2880             //
2881             //  If there is an initial ea section prior to the new section, merge
2882             //  it with the rest of the file.
2883             //
2884 
2885             if (UnwindSplitInitialEa) {
2886 
2887                 FatMergeAllocation( IrpContext, Vcb, &EaFcb->Mcb, &EaInitialEaMcb );
2888             }
2889 
2890             //
2891             //  If there is a file tail split off, merge it with the
2892             //  rest of the file.
2893             //
2894 
2895             if (UnwindSplitTail) {
2896 
2897                 FatMergeAllocation( IrpContext, Vcb, &EaFcb->Mcb, &EaTailMcb );
2898             }
2899 
2900             //
2901             //  If we modified the cache initialization for the ea file,
2902             //  then throw away the ea file object.
2903             //
2904 
2905             if (UnwindPurgeCacheMap) {
2906 
2907                 Vcb->VirtualEaFile = NULL;
2908                 ObDereferenceObject( VirtualEaFile );
2909             }
2910 
2911             //
2912             //  If we split the allocation, then deallocate the block for
2913             //  the new offset information.
2914             //
2915 
2916             if (UnwindSplitNewAllocation) {
2917 
2918                 FatDeallocateDiskSpace( IrpContext, Vcb, &EaOffsetMcb, FALSE );
2919             }
2920 
2921             //
2922             //  Deallocate the disk space.
2923             //
2924 
2925             FatDeallocateDiskSpace( IrpContext, Vcb, &EaSetMcb, FALSE );
2926         }
2927 
2928         //
2929         //  Unpin the Ea ranges.
2930         //
2931 
2932         FatUnpinEaRange( IrpContext, &EaHeaderRange );
2933         FatUnpinEaRange( IrpContext, &EaOffsetRange );
2934 
2935         //
2936         //  Uninitialize any local Mcbs
2937         //
2938 
2939         if (UnwindInitializedEaSetMcb) {
2940 
2941             FsRtlUninitializeLargeMcb( &EaSetMcb );
2942         }
2943 
2944         if (UnwindInitializedOffsetMcb) {
2945 
2946             FsRtlUninitializeLargeMcb( &EaOffsetMcb );
2947         }
2948 
2949         if (UnwindInitializedTailMcb) {
2950 
2951             FsRtlUninitializeLargeMcb( &EaTailMcb );
2952         }
2953 
2954         if (UnwindInitializedInitialEaMcb) {
2955 
2956             FsRtlUninitializeLargeMcb( &EaInitialEaMcb );
2957         }
2958 
2959         DebugTrace(-1, Dbg, "FatAddEaSet ->  Exit\n", 0);
2960     } _SEH2_END;
2961 
2962     return;
2963 }
2964 
2965 
2966 VOID
FatAppendPackedEa(IN PIRP_CONTEXT IrpContext,IN OUT PEA_SET_HEADER * EaSetHeader,IN OUT PULONG PackedEasLength,IN OUT PULONG AllocationLength,IN PFILE_FULL_EA_INFORMATION FullEa,IN ULONG BytesPerCluster)2967 FatAppendPackedEa (
2968     IN PIRP_CONTEXT IrpContext,
2969     IN OUT PEA_SET_HEADER *EaSetHeader,
2970     IN OUT PULONG PackedEasLength,
2971     IN OUT PULONG AllocationLength,
2972     IN PFILE_FULL_EA_INFORMATION FullEa,
2973     IN ULONG BytesPerCluster
2974     )
2975 
2976 /*++
2977 
2978 Routine Description:
2979 
2980     This routine appends a new packed ea onto an existing packed ea list,
2981     it also will allocate/dealloate pool as necessary to hold the ea list.
2982 
2983 Arguments:
2984 
2985     EaSetHeader - Supplies the address to store the pointer to pool memory
2986                   which contains the Ea list for a file.
2987 
2988     PackedEasLength - Supplies the length of the actual Ea data.  The
2989                       new Ea data will be appended at this point.
2990 
2991     AllocationLength - Supplies the allocated length available for Ea
2992                        data.
2993 
2994     FullEa - Supplies a pointer to the new full ea that is to be appended
2995              (in packed form) to the packed ea list.
2996 
2997     BytesPerCluster - Number of bytes per cluster on this volume.
2998 
2999     NOTE: The EaSetHeader refers to the entire block of Ea data for a
3000           file.  This includes the Ea's and their values as well as the
3001           header information.  The PackedEasLength and AllocationLength
3002           parameters refer to the name/value pairs only.
3003 
3004 Return Value:
3005 
3006     None.
3007 
3008 --*/
3009 
3010 {
3011     ULONG PackedEaSize;
3012     PPACKED_EA ThisPackedEa;
3013     OEM_STRING EaName;
3014 
3015     PAGED_CODE();
3016 
3017     DebugTrace(+1, Dbg, "FatAppendPackedEa...\n", 0);
3018 
3019     //
3020     //  As a quick check see if the computed packed ea size plus the
3021     //  current packed ea list size will overflow the buffer.  Full Ea and
3022     //  packed Ea only differ by 4 in their size
3023     //
3024 
3025     PackedEaSize = SizeOfFullEa( FullEa ) - 4;
3026 
3027     if ( PackedEaSize + *PackedEasLength > *AllocationLength ) {
3028 
3029         //
3030         //  We will overflow our current work buffer so allocate a larger
3031         //  one and copy over the current buffer
3032         //
3033 
3034         PVOID Temp;
3035         ULONG NewAllocationSize;
3036         ULONG OldAllocationSize;
3037 
3038         DebugTrace(0, Dbg, "Allocate a new ea list buffer\n", 0);
3039 
3040         //
3041         //  Compute a new size and allocate space.  Always increase the
3042         //  allocation in cluster increments.
3043         //
3044 
3045         NewAllocationSize = (SIZE_OF_EA_SET_HEADER
3046                              + PackedEaSize
3047                              + *PackedEasLength
3048                              + BytesPerCluster - 1)
3049                             & ~(BytesPerCluster - 1);
3050 
3051         Temp = FsRtlAllocatePoolWithTag( PagedPool,
3052                                          NewAllocationSize,
3053                                          TAG_EA_SET_HEADER );
3054 
3055         //
3056         //  Move over the existing ea list, and deallocate the old one
3057         //
3058 
3059         RtlCopyMemory( Temp,
3060                        *EaSetHeader,
3061                        OldAllocationSize = *AllocationLength
3062                                            + SIZE_OF_EA_SET_HEADER );
3063 
3064         ExFreePool( *EaSetHeader );
3065 
3066         //
3067         //  Set up so we will use the new packed ea list
3068         //
3069 
3070         *EaSetHeader = Temp;
3071 
3072         //
3073         //  Zero out the added memory.
3074         //
3075 
3076         RtlZeroMemory( &(*EaSetHeader)->PackedEas[*AllocationLength],
3077                        NewAllocationSize - OldAllocationSize );
3078 
3079         *AllocationLength = NewAllocationSize - SIZE_OF_EA_SET_HEADER;
3080     }
3081 
3082     //
3083     //  Determine if we need to increment our need ea changes count
3084     //
3085 
3086     if ( FlagOn(FullEa->Flags, FILE_NEED_EA )) {
3087 
3088         //
3089         //  The NeedEaCount field is long aligned so we will write
3090         //  directly to it.
3091         //
3092 
3093         (*EaSetHeader)->NeedEaCount++;
3094     }
3095 
3096     //
3097     //  Now copy over the ea, full ea's and packed ea are identical except
3098     //  that full ea also have a next ea offset that we skip over
3099     //
3100     //  Before:
3101     //             UsedSize                     Allocated
3102     //                |                             |
3103     //                V                             V
3104     //      +xxxxxxxx+-----------------------------+
3105     //
3106     //  After:
3107     //                              UsedSize    Allocated
3108     //                                 |            |
3109     //                                 V            V
3110     //      +xxxxxxxx+yyyyyyyyyyyyyyyy+------------+
3111     //
3112 
3113     ThisPackedEa = (PPACKED_EA) (RtlOffsetToPointer( (*EaSetHeader)->PackedEas,
3114                                                      *PackedEasLength ));
3115 
3116     RtlCopyMemory( ThisPackedEa,
3117                    (PUCHAR) FullEa + 4,
3118                    PackedEaSize );
3119 
3120     //
3121     //  Now convert the name to uppercase.
3122     //
3123 
3124     EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
3125     EaName.Buffer = ThisPackedEa->EaName;
3126 
3127     FatUpcaseEaName( IrpContext, &EaName, &EaName );
3128 
3129     //
3130     //  Increment the used size in the packed ea list structure
3131     //
3132 
3133     *PackedEasLength += PackedEaSize;
3134 
3135     //
3136     //  And return to our caller
3137     //
3138 
3139     DebugTrace(-1, Dbg, "FatAppendPackedEa -> VOID\n", 0);
3140 
3141     UNREFERENCED_PARAMETER( IrpContext );
3142 
3143     return;
3144 }
3145 
3146 
3147 VOID
FatDeletePackedEa(IN PIRP_CONTEXT IrpContext,IN OUT PEA_SET_HEADER EaSetHeader,IN OUT PULONG PackedEasLength,IN ULONG Offset)3148 FatDeletePackedEa (
3149     IN PIRP_CONTEXT IrpContext,
3150     IN OUT PEA_SET_HEADER EaSetHeader,
3151     IN OUT PULONG PackedEasLength,
3152     IN ULONG Offset
3153     )
3154 
3155 /*++
3156 
3157 Routine Description:
3158 
3159     This routine deletes an individual packed ea from the supplied
3160     packed ea list.
3161 
3162 Arguments:
3163 
3164     EaSetHeader - Supplies the address to store the pointer to pool memory
3165                   which contains the Ea list for a file.
3166 
3167     PackedEasLength - Supplies the length of the actual Ea data.  The
3168                       new Ea data will be appended at this point.
3169 
3170     Offset - Supplies the offset to the individual ea in the list to delete
3171 
3172     NOTE: The EaSetHeader refers to the entire block of Ea data for a
3173           file.  This includes the Ea's and their values as well as the
3174           header information.  The PackedEasLength parameter refer to the
3175           name/value pairs only.
3176 
3177 Return Value:
3178 
3179     None.
3180 
3181 --*/
3182 
3183 {
3184     PPACKED_EA PackedEa;
3185     ULONG PackedEaSize;
3186 
3187     PAGED_CODE();
3188 
3189     DebugTrace(+1, Dbg, "FatDeletePackedEa, Offset = %08lx\n", Offset);
3190 
3191     //
3192     //  Get a reference to the packed ea and figure out its size
3193     //
3194 
3195     PackedEa = (PPACKED_EA) (&EaSetHeader->PackedEas[Offset]);
3196 
3197     SizeOfPackedEa( PackedEa, &PackedEaSize );
3198 
3199     //
3200     //  Determine if we need to decrement our need ea changes count
3201     //
3202 
3203     if (FlagOn(PackedEa->Flags, EA_NEED_EA_FLAG)) {
3204 
3205         EaSetHeader->NeedEaCount--;
3206     }
3207 
3208     //
3209     //  Shrink the ea list over the deleted ea.  The amount to copy is the
3210     //  total size of the ea list minus the offset to the end of the ea
3211     //  we're deleting.
3212     //
3213     //  Before:
3214     //              Offset    Offset+PackedEaSize      UsedSize    Allocated
3215     //                |                |                  |            |
3216     //                V                V                  V            V
3217     //      +xxxxxxxx+yyyyyyyyyyyyyyyy+zzzzzzzzzzzzzzzzzz+------------+
3218     //
3219     //  After
3220     //              Offset            UsedSize                     Allocated
3221     //                |                  |                             |
3222     //                V                  V                             V
3223     //      +xxxxxxxx+zzzzzzzzzzzzzzzzzz+-----------------------------+
3224     //
3225 
3226     RtlCopyMemory( PackedEa,
3227                    (PUCHAR) PackedEa + PackedEaSize,
3228                    *PackedEasLength - (Offset + PackedEaSize) );
3229 
3230     //
3231     //  And zero out the remaing part of the ea list, to make things
3232     //  nice and more robust
3233     //
3234 
3235     RtlZeroMemory( &EaSetHeader->PackedEas[*PackedEasLength - PackedEaSize],
3236                    PackedEaSize );
3237 
3238     //
3239     //  Decrement the used size by the amount we just removed
3240     //
3241 
3242     *PackedEasLength -= PackedEaSize;
3243 
3244     //
3245     //  And return to our caller
3246     //
3247 
3248     DebugTrace(-1, Dbg, "FatDeletePackedEa -> VOID\n", 0);
3249 
3250     UNREFERENCED_PARAMETER( IrpContext );
3251 
3252     return;
3253 }
3254 
3255 
3256 ULONG
FatLocateNextEa(IN PIRP_CONTEXT IrpContext,IN PPACKED_EA FirstPackedEa,IN ULONG PackedEasLength,IN ULONG PreviousOffset)3257 FatLocateNextEa (
3258     IN PIRP_CONTEXT IrpContext,
3259     IN PPACKED_EA FirstPackedEa,
3260     IN ULONG PackedEasLength,
3261     IN ULONG PreviousOffset
3262     )
3263 
3264 /*++
3265 
3266 Routine Description:
3267 
3268     This routine locates the offset for the next individual packed ea
3269     inside of a packed ea list, given the offset to a previous Ea.
3270     Instead of returing boolean to indicate if we've found the next one
3271     we let the return offset be so large that it overuns the used size
3272     of the packed ea list, and that way it's an easy construct to use
3273     in a for loop.
3274 
3275 Arguments:
3276 
3277     FirstPackedEa - Supplies a pointer to the packed ea list structure
3278 
3279     PackedEasLength - Supplies the length of the packed ea list
3280 
3281     PreviousOffset - Supplies the offset to a individual packed ea in the
3282         list
3283 
3284 Return Value:
3285 
3286     ULONG - The offset to the next ea in the list or 0xffffffff of one
3287         does not exist.
3288 
3289 --*/
3290 
3291 {
3292     PPACKED_EA PackedEa;
3293     ULONG PackedEaSize;
3294     ULONG Offset;
3295 
3296     PAGED_CODE();
3297 
3298     DebugTrace(+1, Dbg, "FatLocateNextEa, PreviousOffset = %08lx\n",
3299                PreviousOffset);
3300 
3301     //
3302     //  Make sure the previous offset is within the used size range
3303     //
3304 
3305     if ( PreviousOffset >= PackedEasLength ) {
3306 
3307         DebugTrace(-1, Dbg, "FatLocateNextEa -> 0xffffffff\n", 0);
3308         return 0xffffffff;
3309     }
3310 
3311     //
3312     //  Get a reference to the previous packed ea, and compute its size
3313     //
3314 
3315     PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + PreviousOffset );
3316     SizeOfPackedEa( PackedEa, &PackedEaSize );
3317 
3318     //
3319     //  Compute to the next ea
3320     //
3321 
3322     Offset = PreviousOffset + PackedEaSize;
3323 
3324     //
3325     //  Now, if the new offset is beyond the ea size then we know
3326     //  that there isn't one so, we return an offset of 0xffffffff.
3327     //  otherwise we'll leave the new offset alone.
3328     //
3329 
3330     if ( Offset >= PackedEasLength ) {
3331 
3332         Offset = 0xffffffff;
3333     }
3334 
3335     DebugTrace(-1, Dbg, "FatLocateNextEa -> %08lx\n", Offset);
3336 
3337     UNREFERENCED_PARAMETER( IrpContext );
3338 
3339     return Offset;
3340 }
3341 
3342 
3343 BOOLEAN
FatLocateEaByName(IN PIRP_CONTEXT IrpContext,IN PPACKED_EA FirstPackedEa,IN ULONG PackedEasLength,IN POEM_STRING EaName,OUT PULONG Offset)3344 FatLocateEaByName (
3345     IN PIRP_CONTEXT IrpContext,
3346     IN PPACKED_EA FirstPackedEa,
3347     IN ULONG PackedEasLength,
3348     IN POEM_STRING EaName,
3349     OUT PULONG Offset
3350     )
3351 
3352 /*++
3353 
3354 Routine Description:
3355 
3356     This routine locates the offset for the next individual packed ea
3357     inside of a packed ea list, given the name of the ea to locate
3358 
3359 Arguments:
3360 
3361     FirstPackedEa - Supplies a pointer to the packed ea list structure
3362 
3363     PackedEasLength - Supplies the length of the packed ea list
3364 
3365     EaName - Supplies the name of the ea search for
3366 
3367     Offset - Receives the offset to the located individual ea in the list
3368         if one exists.
3369 
3370 Return Value:
3371 
3372     BOOLEAN - TRUE if the named packed ea exists in the list and FALSE
3373         otherwise.
3374 
3375 --*/
3376 
3377 {
3378     PPACKED_EA PackedEa;
3379     OEM_STRING Name;
3380 
3381     PAGED_CODE();
3382 
3383     DebugTrace(+1, Dbg, "FatLocateEaByName, EaName = %Z\n", EaName);
3384 
3385     //
3386     //  For each packed ea in the list check its name against the
3387     //  ea name we're searching for
3388     //
3389 
3390     for ( *Offset = 0;
3391           *Offset < PackedEasLength;
3392           *Offset = FatLocateNextEa( IrpContext,
3393                                      FirstPackedEa,
3394                                      PackedEasLength,
3395                                      *Offset )) {
3396 
3397         //
3398         //  Reference the packed ea and get a string to its name
3399         //
3400 
3401         PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + *Offset);
3402 
3403         Name.Buffer = &PackedEa->EaName[0];
3404         Name.Length = PackedEa->EaNameLength;
3405         Name.MaximumLength = PackedEa->EaNameLength;
3406 
3407         //
3408         //  Compare the two strings, if they are equal then we've
3409         //  found the caller's ea
3410         //
3411 
3412         if ( RtlCompareString( EaName, &Name, TRUE ) == 0 ) {
3413 
3414             DebugTrace(-1, Dbg, "FatLocateEaByName -> TRUE, *Offset = %08lx\n", *Offset);
3415             return TRUE;
3416         }
3417     }
3418 
3419     //
3420     //  We've exhausted the ea list without finding a match so return false
3421     //
3422 
3423     DebugTrace(-1, Dbg, "FatLocateEaByName -> FALSE\n", 0);
3424     return FALSE;
3425 }
3426 
3427 
3428 BOOLEAN
FatIsEaNameValid(IN PIRP_CONTEXT IrpContext,IN OEM_STRING Name)3429 FatIsEaNameValid (
3430     IN PIRP_CONTEXT IrpContext,
3431     IN OEM_STRING Name
3432     )
3433 
3434 /*++
3435 
3436 Routine Description:
3437 
3438     This routine simple returns whether the specified file names conforms
3439     to the file system specific rules for legal Ea names.
3440 
3441     For Ea names, the following rules apply:
3442 
3443     A. An Ea name may not contain any of the following characters:
3444 
3445        0x0000 - 0x001F  \ / : * ? " < > | , + = [ ] ;
3446 
3447 Arguments:
3448 
3449     Name - Supllies the name to check.
3450 
3451 Return Value:
3452 
3453     BOOLEAN - TRUE if the name is legal, FALSE otherwise.
3454 
3455 --*/
3456 
3457 {
3458     ULONG Index;
3459 
3460     UCHAR Char;
3461 
3462     PAGED_CODE();
3463 
3464     UNREFERENCED_PARAMETER( IrpContext );
3465 
3466     //
3467     //  Empty names are not valid.
3468     //
3469 
3470     if ( Name.Length == 0 ) { return FALSE; }
3471 
3472     //
3473     //  At this point we should only have a single name, which can't have
3474     //  more than 254 characters
3475     //
3476 
3477     if ( Name.Length > 254 ) { return FALSE; }
3478 
3479     for ( Index = 0; Index < (ULONG)Name.Length; Index += 1 ) {
3480 
3481         Char = Name.Buffer[ Index ];
3482 
3483         //
3484         //  Skip over and Dbcs chacters
3485         //
3486 
3487         if ( FsRtlIsLeadDbcsCharacter( Char ) ) {
3488 
3489             NT_ASSERT( Index != (ULONG)(Name.Length - 1) );
3490 
3491             Index += 1;
3492 
3493             continue;
3494         }
3495 
3496         //
3497         //  Make sure this character is legal, and if a wild card, that
3498         //  wild cards are permissible.
3499         //
3500 
3501         if ( !FsRtlIsAnsiCharacterLegalFat(Char, FALSE) ) {
3502 
3503             return FALSE;
3504         }
3505     }
3506 
3507     return TRUE;
3508 }
3509 
3510 
3511 VOID
FatPinEaRange(IN PIRP_CONTEXT IrpContext,IN PFILE_OBJECT VirtualEaFile,IN PFCB EaFcb,IN OUT PEA_RANGE EaRange,IN ULONG StartingVbo,IN ULONG Length,IN NTSTATUS ErrorStatus)3512 FatPinEaRange (
3513     IN PIRP_CONTEXT IrpContext,
3514     IN PFILE_OBJECT VirtualEaFile,
3515     IN PFCB EaFcb,
3516     IN OUT PEA_RANGE EaRange,
3517     IN ULONG StartingVbo,
3518     IN ULONG Length,
3519     IN NTSTATUS ErrorStatus
3520     )
3521 
3522 /*++
3523 
3524 Routine Description:
3525 
3526     This routine is called to pin a range within the Ea file.  It will follow all the
3527     rules required by the cache manager so that we don't have overlapping pin operations.
3528     If the range being pinned spans a section then the desired data will be copied into
3529     an auxilary buffer.  FatMarkEaRangeDirty will know whether to copy the data back
3530     into the cache or whether to simply mark the pinned data dirty.
3531 
3532 Arguments:
3533 
3534     VirtualEaFile - This is the stream file for the Ea file.
3535 
3536     EaFcb - This is the Fcb for the Ea file.
3537 
3538     EaRange - This is the Ea range structure for this request.
3539 
3540     StartingVbo - This is the starting offset in the Ea file to read from.
3541 
3542     Length - This is the length of the read.
3543 
3544     ErrorStatus - This is the error status to use if we are reading outside
3545         of the file.
3546 
3547 Return Value:
3548 
3549     None.
3550 
3551 --*/
3552 
3553 {
3554     LARGE_INTEGER LargeVbo;
3555     ULONG ByteCount;
3556     PBCB *NextBcb;
3557     PVOID Buffer;
3558     PCHAR DestinationBuffer = NULL;
3559     BOOLEAN FirstPage = TRUE;
3560 
3561     PAGED_CODE();
3562 
3563     //
3564     //  Verify that the entire read is contained within the Ea file.
3565     //
3566 
3567     if (Length == 0
3568         || StartingVbo >= EaFcb->Header.AllocationSize.LowPart
3569         || (EaFcb->Header.AllocationSize.LowPart - StartingVbo) < Length) {
3570 
3571         FatRaiseStatus( IrpContext, ErrorStatus );
3572     }
3573 
3574     //
3575     //  If the read will span a section, the system addresses may not be contiguous.
3576     //  Allocate a separate buffer in this case.
3577     //
3578 
3579     if (((StartingVbo & (EA_SECTION_SIZE - 1)) + Length) > EA_SECTION_SIZE) {
3580 
3581         EaRange->Data = FsRtlAllocatePoolWithTag( PagedPool,
3582                                                   Length,
3583                                                   TAG_EA_DATA );
3584         EaRange->AuxilaryBuffer = TRUE;
3585 
3586         DestinationBuffer = EaRange->Data;
3587 
3588     } else {
3589 
3590         //
3591         //  PREfix correctly notes that if we don't decide here to have an aux buffer
3592         //  and the flag is up in the EaRange, we'll party on random memory since
3593         //  DestinationBuffer won't be set; however, this will never happen due to
3594         //  initialization of ea ranges and the cleanup in UnpinEaRange.
3595         //
3596 
3597         NT_ASSERT( EaRange->AuxilaryBuffer == FALSE );
3598     }
3599 
3600 
3601     //
3602     //  If the read will require more pages than our structure will hold then
3603     //  allocate an auxilary buffer.  We have to figure the number of pages
3604     //  being requested so we have to include the page offset of the first page of
3605     //  the request.
3606     //
3607 
3608     EaRange->BcbChainLength = (USHORT) (((StartingVbo & (PAGE_SIZE - 1)) + Length + PAGE_SIZE - 1) / PAGE_SIZE);
3609 
3610     if (EaRange->BcbChainLength > EA_BCB_ARRAY_SIZE) {
3611 
3612         EaRange->BcbChain = FsRtlAllocatePoolWithTag( PagedPool,
3613                                                       sizeof( PBCB ) * EaRange->BcbChainLength,
3614                                                       TAG_BCB );
3615 
3616         RtlZeroMemory( EaRange->BcbChain, sizeof( PBCB ) * EaRange->BcbChainLength );
3617 
3618     } else {
3619 
3620         EaRange->BcbChain = (PBCB *) &EaRange->BcbArray;
3621     }
3622 
3623     //
3624     //  Store the byte range data in the Ea Range structure.
3625     //
3626 
3627     EaRange->StartingVbo = StartingVbo;
3628     EaRange->Length = Length;
3629 
3630     //
3631     //  Compute the initial pin length.
3632     //
3633 
3634     ByteCount = PAGE_SIZE - (StartingVbo & (PAGE_SIZE - 1));
3635 
3636     //
3637     //  For each page in the range; pin the page and update the Bcb count, copy to
3638     //  the auxiliary buffer.
3639     //
3640 
3641     NextBcb = EaRange->BcbChain;
3642 
3643     while (Length != 0) {
3644 
3645         //
3646         //  Pin the page and remember the data start.
3647         //
3648 
3649         LargeVbo.QuadPart = StartingVbo;
3650 
3651         if (ByteCount > Length) {
3652 
3653             ByteCount = Length;
3654         }
3655 
3656         if (!CcPinRead( VirtualEaFile,
3657                         &LargeVbo,
3658                         ByteCount,
3659                         BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
3660                         NextBcb,
3661                         &Buffer )) {
3662 
3663             //
3664             // Could not read the data without waiting (cache miss).
3665             //
3666 
3667             FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
3668         }
3669 
3670         //
3671         //  Increment the Bcb pointer and copy to the auxilary buffer if necessary.
3672         //
3673 
3674         NextBcb += 1;
3675 
3676         if (EaRange->AuxilaryBuffer == TRUE) {
3677 
3678             RtlCopyMemory( DestinationBuffer,
3679                            Buffer,
3680                            ByteCount );
3681 
3682             DestinationBuffer = (PCHAR) Add2Ptr( DestinationBuffer, ByteCount );
3683         }
3684 
3685         StartingVbo += ByteCount;
3686         Length -= ByteCount;
3687 
3688         //
3689         //  If this is the first page then update the Ea Range structure.
3690         //
3691 
3692         if (FirstPage) {
3693 
3694             FirstPage = FALSE;
3695             ByteCount = PAGE_SIZE;
3696 
3697             if (EaRange->AuxilaryBuffer == FALSE) {
3698 
3699                 EaRange->Data = Buffer;
3700             }
3701         }
3702     }
3703 
3704     return;
3705 }
3706 
3707 
3708 VOID
FatMarkEaRangeDirty(IN PIRP_CONTEXT IrpContext,IN PFILE_OBJECT EaFileObject,IN OUT PEA_RANGE EaRange)3709 FatMarkEaRangeDirty (
3710     IN PIRP_CONTEXT IrpContext,
3711     IN PFILE_OBJECT EaFileObject,
3712     IN OUT PEA_RANGE EaRange
3713     )
3714 
3715 /*++
3716 
3717 Routine Description:
3718 
3719     This routine is called to mark a range of the Ea file as dirty.  If the modified
3720     data is sitting in an auxilary buffer then we will copy it back into the cache.
3721     In any case we will go through the list of Bcb's and mark them dirty.
3722 
3723 Arguments:
3724 
3725     EaFileObject - This is the file object for the Ea file.
3726 
3727     EaRange - This is the Ea range structure for this request.
3728 
3729 Return Value:
3730 
3731     None.
3732 
3733 --*/
3734 
3735 {
3736     PBCB *NextBcb;
3737     ULONG BcbCount;
3738 
3739     PAGED_CODE();
3740 
3741     UNREFERENCED_PARAMETER( IrpContext );
3742 
3743     //
3744     //  If there is an auxilary buffer we need to copy the data back into the cache.
3745     //
3746 
3747     if (EaRange->AuxilaryBuffer == TRUE) {
3748 
3749         LARGE_INTEGER LargeVbo;
3750 
3751         LargeVbo.QuadPart = EaRange->StartingVbo;
3752 
3753         CcCopyWrite( EaFileObject,
3754                      &LargeVbo,
3755                      EaRange->Length,
3756                      TRUE,
3757                      EaRange->Data );
3758     }
3759 
3760     //
3761     //  Now walk through the Bcb chain and mark everything dirty.
3762     //
3763 
3764     BcbCount = EaRange->BcbChainLength;
3765     NextBcb = EaRange->BcbChain;
3766 
3767     while (BcbCount--) {
3768 
3769         if (*NextBcb != NULL) {
3770 
3771             CcSetDirtyPinnedData( *NextBcb, NULL );
3772         }
3773 
3774         NextBcb += 1;
3775     }
3776 
3777     return;
3778 }
3779 
3780 
3781 VOID
FatUnpinEaRange(IN PIRP_CONTEXT IrpContext,IN OUT PEA_RANGE EaRange)3782 FatUnpinEaRange (
3783     IN PIRP_CONTEXT IrpContext,
3784     IN OUT PEA_RANGE EaRange
3785     )
3786 
3787 /*++
3788 
3789 Routine Description:
3790 
3791     This routine is called to unpin a range in the Ea file.  Any structures allocated
3792     will be deallocated here.
3793 
3794 Arguments:
3795 
3796     EaRange - This is the Ea range structure for this request.
3797 
3798 Return Value:
3799 
3800     None.
3801 
3802 --*/
3803 
3804 {
3805     PBCB *NextBcb;
3806     ULONG BcbCount;
3807 
3808     PAGED_CODE();
3809 
3810     UNREFERENCED_PARAMETER( IrpContext );
3811 
3812     //
3813     //  If we allocated a auxilary buffer, deallocate it here.
3814     //
3815 
3816     if (EaRange->AuxilaryBuffer == TRUE) {
3817 
3818         ExFreePool( EaRange->Data );
3819         EaRange->AuxilaryBuffer = FALSE;
3820     }
3821 
3822     //
3823     //  Walk through the Bcb chain and unpin the data.
3824     //
3825 
3826     if (EaRange->BcbChain != NULL) {
3827 
3828         BcbCount = EaRange->BcbChainLength;
3829         NextBcb = EaRange->BcbChain;
3830 
3831         while (BcbCount--) {
3832 
3833             if (*NextBcb != NULL) {
3834 
3835                 CcUnpinData( *NextBcb );
3836                 *NextBcb = NULL;
3837             }
3838 
3839             NextBcb += 1;
3840         }
3841 
3842         //
3843         //  If we allocated a Bcb chain, deallocate it here.
3844         //
3845 
3846         if (EaRange->BcbChain != &EaRange->BcbArray[0]) {
3847 
3848             ExFreePool( EaRange->BcbChain );
3849         }
3850 
3851         EaRange->BcbChain = NULL;
3852     }
3853 
3854     return;
3855 }
3856 
3857