ReactOS  0.4.14-dev-49-gfb4591c
easup.c
Go to the documentation of this file.
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 
52 _Requires_lock_held_(_Global_critical_region_)
53 VOID
54 FatGetEaLength (
55  IN PIRP_CONTEXT IrpContext,
56  IN PVCB Vcb,
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;
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 
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 
206 _Requires_lock_held_(_Global_critical_region_)
207 VOID
208 FatGetNeedEaCount (
209  IN PIRP_CONTEXT IrpContext,
210  IN PVCB Vcb,
211  IN PDIRENT Dirent,
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;
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 
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 
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,
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;
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 
416 
417  ULONG PackedEasLength;
418  ULONG AllocationLength;
419  ULONG BytesPerCluster;
420 
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
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,
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;
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 
656 _Requires_lock_held_(_Global_critical_region_)
657 VOID
658 FatDeleteEa (
659  IN PIRP_CONTEXT IrpContext,
660  IN PVCB Vcb,
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 
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 
783 _Requires_lock_held_(_Global_critical_region_)
784 VOID
785 FatGetEaFile (
786  IN PIRP_CONTEXT IrpContext,
787  IN OUT PVCB Vcb,
789  OUT PBCB *EaBcb,
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;
1045  PEA_FILE_HEADER FileHeader;
1046  USHORT AllocatedClusters;
1047  PUSHORT CurrentIndex;
1048  ULONG Index;
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 
1103 
1104  UnwindEaDirentCreated = TRUE;
1105 
1106  FatConstructDirent( IrpContext,
1107  *EaDirent,
1108  &EaFileName,
1109  FALSE,
1110  FALSE,
1111  NULL,
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,
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
1307  IN PIRP_CONTEXT IrpContext,
1308  IN PVCB Vcb,
1309  IN USHORT EaHandle,
1311  IN BOOLEAN ReturnEntireSet,
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 
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);
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 ),
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 ),
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);
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,
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,
1515  }
1516 
1517  } _SEH2_FINALLY {
1518 
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 
1535 _Requires_lock_held_(_Global_critical_region_)
1536 VOID
1537 FatDeleteEaSet (
1538  IN PIRP_CONTEXT IrpContext,
1539  IN PVCB Vcb,
1540  IN PBCB EaBcb,
1542  IN USHORT EaHandle,
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;
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;
1615  PEA_SET_HEADER EaSet;
1616  USHORT EaSetClusterCount;
1617 
1618  PAGED_CODE();
1619 
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);
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 ),
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 ),
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);
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,
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  {
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 
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 ),
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 ),
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 
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 
2091 _Requires_lock_held_(_Global_critical_region_)
2092 VOID
2093 FatAddEaSet (
2094  IN PIRP_CONTEXT IrpContext,
2095  IN PVCB Vcb,
2097  IN PBCB EaBcb,
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;
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 ),
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,
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 
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 
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  {
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 
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 ),
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 ),
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,
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 
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
2968  IN PIRP_CONTEXT IrpContext,
2969  IN OUT PEA_SET_HEADER *EaSetHeader,
2970  IN OUT PULONG PackedEasLength,
2971  IN OUT PULONG AllocationLength,
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 
3052  NewAllocationSize,
3054 
3055  //
3056  // Move over the existing ea list, and deallocate the old one
3057  //
3058 
3059  RtlCopyMemory( Temp,
3060  *EaSetHeader,
3061  OldAllocationSize = *AllocationLength
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
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
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
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
3430  IN PIRP_CONTEXT IrpContext,
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 
3502 
3503  return FALSE;
3504  }
3505  }
3506 
3507  return TRUE;
3508 }
3509 
3510 
3511 VOID
3513  IN PIRP_CONTEXT IrpContext,
3514  IN PFILE_OBJECT VirtualEaFile,
3515  IN PFCB EaFcb,
3516  IN OUT PEA_RANGE EaRange,
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 
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
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
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 
signed char * PCHAR
Definition: retypes.h:7
VOID FatConstructDirent(IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING FileName, IN BOOLEAN ComponentReallyLowercase, IN BOOLEAN ExtensionReallyLowercase, IN PUNICODE_STRING Lfn OPTIONAL, IN USHORT Attributes, IN BOOLEAN ZeroAndSetTimeFields, IN PLARGE_INTEGER SetCreationTime OPTIONAL)
Definition: dirsup.c:2171
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:384
#define IN
Definition: typedefs.h:38
UCHAR EaNameLength
Definition: fat.h:696
UCHAR Flags
Definition: fat.h:695
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define MAX_EA_OFFSET_INDEX
Definition: fat.h:751
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define Add2Ptr(PTR, INC)
CHAR EaName[1]
Definition: fat.h:698
NTSYSAPI LONG NTAPI RtlCompareString(PSTRING String1, PSTRING String2, BOOLEAN CaseInSensitive)
#define FCB_LOOKUP_ALLOCATIONSIZE_HINT
Definition: fatstruc.h:1240
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
VOID NTAPI CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:222
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
struct _FILE_FULL_EA_INFORMATION * PFILE_FULL_EA_INFORMATION
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN IN BOOLEAN ExclusiveFcb
Definition: fatprocs.h:904
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
Definition: cdstruc.h:908
VOID Fat8dot3ToString(_In_ PIRP_CONTEXT IrpContext, _In_ PDIRENT Dirent, _In_ BOOLEAN RestoreCase, _Out_ POEM_STRING OutputString)
Definition: namesup.c:179
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
#define EA_SECTION_SIZE
Definition: easup.c:49
USHORT Signature
Definition: fat.h:664
VOID NTAPI CcSetDirtyPinnedData(IN PVOID BcbVoid, IN OPTIONAL PLARGE_INTEGER Lsn)
Definition: cachesub.c:121
USHORT EaBaseTable[240]
Definition: fat.h:647
ULONG32 VBO
Definition: fat.h:38
unsigned char * PUCHAR
Definition: retypes.h:3
BOOLEAN FatIsEaNameValid(IN PIRP_CONTEXT IrpContext, IN OEM_STRING Name)
Definition: easup.c:3429
#define SizeOfPackedEa(EA, SIZE)
Definition: fat.h:738
VOID FatMarkEaRangeDirty(IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT EaFileObject, IN OUT PEA_RANGE EaRange)
Definition: easup.c:3709
LONG NTSTATUS
Definition: precomp.h:26
IN PVCB IN ULONG EaSetLength
Definition: fatprocs.h:936
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
USHORT EA_OFF_TABLE[128]
Definition: fat.h:652
#define FAT_DIRENT_ATTR_HIDDEN
Definition: fat.h:369
VOID NTAPI CcUnpinData(IN PVOID Bcb)
Definition: pinsup.c:955
#define STATUS_NO_EAS_ON_FILE
Definition: ntstatus.h:304
#define MAX_EA_HANDLE
Definition: fat.h:747
USHORT Signature
Definition: fat.h:635
VOID FatUnpinEaRange(IN PIRP_CONTEXT IrpContext, IN OUT PEA_RANGE EaRange)
Definition: easup.c:3782
#define MAX_EA_BASE_INDEX
Definition: fat.h:750
#define MAXIMUM_EA_SIZE
Definition: fat.h:676
EA_FILE_HEADER * PEA_FILE_HEADER
Definition: fat.h:650
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
Definition: cdstruc.h:504
#define FAT_DIRENT_ATTR_READ_ONLY
Definition: fat.h:368
IN PVCB IN PUCHAR IN ULONG IN POEM_STRING OUT PUSHORT EaHandle
Definition: fatprocs.h:884
#define TAG_BCB
Definition: nodetype.h:157
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define CopyU4char(Dst, Src)
Definition: fatprocs.h:2141
STRING OEM_STRING
Definition: umtypes.h:203
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2965
VOID FatPinMappedData(IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb)
Definition: cachesup.c:1866
#define PAGED_CODE()
Definition: video.h:57
_Requires_lock_held_(_Global_critical_region_)
Definition: easup.c:52
_SEH2_TRY
Definition: create.c:4250
#define STATUS_EA_TOO_LARGE
Definition: ntstatus.h:302
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
IN OUT PVCB OUT PDIRENT * EaDirent
Definition: fatprocs.h:904
VOID FatReadEaSet(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT EaHandle, IN POEM_STRING FileName, IN BOOLEAN ReturnEntireSet, OUT PEA_RANGE EaSetRange)
Definition: easup.c:1306
#define EA_NEED_EA_FLAG
Definition: fat.h:745
else
Definition: tritemp.h:161
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
BOOLEAN FatLookupMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount OPTIONAL, OUT PULONG Index OPTIONAL)
Definition: fsctrl.c:418
LONGLONG LBO
Definition: fat.h:34
USHORT OwnEaHandle
Definition: fat.h:665
char Char
Definition: bzip2.c:161
struct NameRec_ * Name
Definition: cdprocs.h:464
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:450
struct _EA_FILE_HEADER EA_FILE_HEADER
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:537
#define EA_CBLIST_OFFSET
Definition: fat.h:749
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:13
#define SizeOfFullEa(EA)
Definition: fatprocs.h:1021
UCHAR OwnerFileName[14]
Definition: fat.h:667
Definition: bufpool.h:45
#define FAT_DIRENT_ATTR_SYSTEM
Definition: fat.h:370
#define RtlOffsetToPointer(B, O)
#define EA_SET_SIGNATURE
Definition: fat.h:626
#define FILE_NEED_EA
#define PCHAR
Definition: match.c:90
#define FatGetIndexFromLbo(VCB, LBO)
Definition: fat.h:566
#define MIN_EA_HANDLE
Definition: fat.h:746
#define DebugUnwind(X)
Definition: fatdata.h:315
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1635
#define CopyUchar4(Dst, Src)
Definition: cdprocs.h:1711
IN PVCB IN PDIRENT OUT PULONG EaLength
Definition: fatprocs.h:866
if(!(yy_init))
Definition: macro.lex.yy.c:714
return Iosb
Definition: create.c:4426
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define try_return(S)
Definition: cdprocs.h:2189
#define STATUS_NONEXISTENT_EA_ENTRY
Definition: ntstatus.h:303
uint64_t ULONGLONG
Definition: typedefs.h:65
IN PVCB IN ULONG IN PBCB OUT PDIRENT OUT PUSHORT OUT PEA_RANGE EaSetRange
Definition: fatprocs.h:936
#define Vcb
Definition: cdprocs.h:1425
static const UCHAR Index[8]
Definition: usbohci.c:18
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)
Definition: easup.c:2967
#define FatUpcaseEaName(IRPCONTEXT, NAME, UPCASEDNAME)
Definition: fatprocs.h:859
#define UNUSED_EA_HANDLE
Definition: fat.h:748
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1955
BOOLEAN NTAPI CcPinRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *Bcb, OUT PVOID *Buffer)
Definition: pinsup.c:802
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)
Definition: easup.c:3512
CD_MCB Mcb
Definition: cdstruc.h:1022
unsigned char UCHAR
Definition: xmlstorage.h:181
#define FsRtlIsAnsiCharacterLegalFat(C, WILD)
Definition: fsrtlfuncs.h:1611
#define VOID
Definition: acefi.h:82
EA_SET_HEADER * PEA_SET_HEADER
Definition: fat.h:672
#define TAG_EA_DATA
Definition: nodetype.h:160
PCHAR Data
Definition: fatstruc.h:1716
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define NOTHING
Definition: env_spec_w32.h:461
PACKED_EA * PPACKED_EA
Definition: fat.h:700
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define STATUS_INVALID_EA_NAME
Definition: ntstatus.h:187
IN PVCB IN VBO StartingVbo
Definition: fatprocs.h:402
#define FatIsFat32(VCB)
Definition: fatprocs.h:1437
BOOLEAN FatLocateEaByName(IN PIRP_CONTEXT IrpContext, IN PPACKED_EA FirstPackedEa, IN ULONG PackedEasLength, IN POEM_STRING EaName, OUT PULONG Offset)
Definition: easup.c:3344
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1061
Status
Definition: gdiplustypes.h:24
#define FAT_DIRENT_ATTR_ARCHIVE
Definition: fat.h:373
BOOLEAN NTAPI CcCopyWrite(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN PVOID Buffer)
Definition: copysup.c:129
ULONG32 NeedEaCount
Definition: fat.h:666
IN PFCB IN PFILE_OBJECT FileObject IN ULONG AllocationSize
Definition: fatprocs.h:310
_SEH2_END
Definition: create.c:4424
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN CreateFile
Definition: fatprocs.h:904
unsigned short USHORT
Definition: pedump.c:61
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:151
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:354
_SEH2_FINALLY
Definition: create.c:4395
ULONG FatLocateNextEa(IN PIRP_CONTEXT IrpContext, IN PPACKED_EA FirstPackedEa, IN ULONG PackedEasLength, IN ULONG PreviousOffset)
Definition: easup.c:3257
IN PVCB IN PDIRENT OUT PULONG NeedEaCount
Definition: fatprocs.h:875
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1053
unsigned int * PULONG
Definition: retypes.h:1
#define STATUS_DATA_ERROR
Definition: ntstatus.h:284
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
UCHAR PackedEas[1]
Definition: fat.h:670
UCHAR cbList[4]
Definition: fat.h:669
PFILE_OBJECT FatOpenEaFile(IN PIRP_CONTEXT IrpContext, IN PFCB EaFcb)
Definition: cachesup.c:979
#define OUT
Definition: typedefs.h:39
#define GetcbList(EASET)
Definition: fat.h:678
unsigned int ULONG
Definition: retypes.h:1
_In_ PFCB _In_ PDIRENT_ENUM_CONTEXT _Inout_ PDIRENT Dirent
Definition: cdprocs.h:429
#define EA_FILE_SIGNATURE
Definition: fat.h:625
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define EA_BCB_ARRAY_SIZE
Definition: fatstruc.h:1712
#define TAG_EA_SET_HEADER
Definition: nodetype.h:161
IN OUT PVCB OUT PDIRENT OUT PBCB * EaBcb
Definition: fatprocs.h:904
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define FsRtlIsLeadDbcsCharacter(DBCS_CHAR)
Definition: init.c:417
#define SIZE_OF_EA_SET_HEADER
Definition: fat.h:674
unsigned short * PUSHORT
Definition: retypes.h:2
#define Dbg
Definition: easup.c:22
#define STATUS_UNABLE_TO_DELETE_SECTION
Definition: ntstatus.h:250
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID FatDeletePackedEa(IN PIRP_CONTEXT IrpContext, IN OUT PEA_SET_HEADER EaSetHeader, IN OUT PULONG PackedEasLength, IN ULONG Offset)
Definition: easup.c:3148
LONGLONG QuadPart
Definition: typedefs.h:112
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:716
#define STATUS_CANT_WAIT
Definition: ntstatus.h:438
#define NT_ASSERT
Definition: rtlfuncs.h:3312