ReactOS  0.4.15-dev-2704-gd5265b0
allocsup.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1990-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  AllocSup.c
8 
9 Abstract:
10 
11  This module implements the Allocation support routines for Fat.
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 //
19 // The Bug check file id for this module
20 //
21 
22 #define BugCheckFileId (FAT_BUG_CHECK_ALLOCSUP)
23 
24 //
25 // Local debug trace level
26 //
27 
28 #define Dbg (DEBUG_TRACE_ALLOCSUP)
29 
30 #define FatMin(a, b) ((a) < (b) ? (a) : (b))
31 
32 //
33 // Define prefetch page count for the FAT
34 //
35 
36 #define FAT_PREFETCH_PAGE_COUNT 0x100
37 
38 //
39 // Local support routine prototypes
40 //
41 
42 VOID
44  IN PIRP_CONTEXT IrpContext,
45  IN PVCB Vcb,
49  );
50 
51 VOID
53  IN PIRP_CONTEXT IrpContext,
54  IN PVCB Vcb,
55  IN ULONG StartingFatIndex,
56  IN ULONG ClusterCount,
57  IN BOOLEAN ChainTogether
58  );
59 
60 UCHAR
61 FatLogOf(
62  IN ULONG Value
63  );
64 
65 //
66 // Note that the KdPrint below will ONLY fire when the assert does. Leave it
67 // alone.
68 //
69 
70 #if DBG
71 #define ASSERT_CURRENT_WINDOW_GOOD(VCB) { \
72  ULONG FreeClusterBitMapClear; \
73  NT_ASSERT( (VCB)->FreeClusterBitMap.Buffer != NULL ); \
74  FreeClusterBitMapClear = RtlNumberOfClearBits(&(VCB)->FreeClusterBitMap); \
75  if ((VCB)->CurrentWindow->ClustersFree != FreeClusterBitMapClear) { \
76  KdPrint(("FAT: ClustersFree %x h != FreeClusterBitMapClear %x h\n", \
77  (VCB)->CurrentWindow->ClustersFree, \
78  FreeClusterBitMapClear)); \
79  } \
80  NT_ASSERT( (VCB)->CurrentWindow->ClustersFree == FreeClusterBitMapClear ); \
81 }
82 #else
83 #define ASSERT_CURRENT_WINDOW_GOOD(VCB)
84 #endif
85 
86 //
87 // The following macros provide a convenient way of hiding the details
88 // of bitmap allocation schemes.
89 //
90 
91 
92 //
93 // VOID
94 // FatLockFreeClusterBitMap (
95 // IN PVCB Vcb
96 // );
97 //
98 
99 #define FatLockFreeClusterBitMap(VCB) { \
100  NT_ASSERT(KeAreApcsDisabled()); \
101  ExAcquireFastMutexUnsafe( &(VCB)->FreeClusterBitMapMutex ); \
102  ASSERT_CURRENT_WINDOW_GOOD(VCB) \
103 }
104 
105 //
106 // VOID
107 // FatUnlockFreeClusterBitMap (
108 // IN PVCB Vcb
109 // );
110 //
111 
112 #define FatUnlockFreeClusterBitMap(VCB) { \
113  ASSERT_CURRENT_WINDOW_GOOD(VCB) \
114  NT_ASSERT(KeAreApcsDisabled()); \
115  ExReleaseFastMutexUnsafe( &(VCB)->FreeClusterBitMapMutex ); \
116 }
117 
118 //
119 // BOOLEAN
120 // FatIsClusterFree (
121 // IN PIRP_CONTEXT IrpContext,
122 // IN PVCB Vcb,
123 // IN ULONG FatIndex
124 // );
125 //
126 
127 #define FatIsClusterFree(IRPCONTEXT,VCB,FAT_INDEX) \
128  (RtlCheckBit(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2) == 0)
129 
130 //
131 // VOID
132 // FatFreeClusters (
133 // IN PIRP_CONTEXT IrpContext,
134 // IN PVCB Vcb,
135 // IN ULONG FatIndex,
136 // IN ULONG ClusterCount
137 // );
138 //
139 
140 #define FatFreeClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) { \
141  if ((CLUSTER_COUNT) == 1) { \
142  FatSetFatEntry((IRPCONTEXT),(VCB),(FAT_INDEX),FAT_CLUSTER_AVAILABLE); \
143  } else { \
144  FatSetFatRun((IRPCONTEXT),(VCB),(FAT_INDEX),(CLUSTER_COUNT),FALSE); \
145  } \
146 }
147 
148 //
149 // VOID
150 // FatAllocateClusters (
151 // IN PIRP_CONTEXT IrpContext,
152 // IN PVCB Vcb,
153 // IN ULONG FatIndex,
154 // IN ULONG ClusterCount
155 // );
156 //
157 
158 #define FatAllocateClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) { \
159  if ((CLUSTER_COUNT) == 1) { \
160  FatSetFatEntry((IRPCONTEXT),(VCB),(FAT_INDEX),FAT_CLUSTER_LAST); \
161  } else { \
162  FatSetFatRun((IRPCONTEXT),(VCB),(FAT_INDEX),(CLUSTER_COUNT),TRUE); \
163  } \
164 }
165 
166 //
167 // VOID
168 // FatUnreserveClusters (
169 // IN PIRP_CONTEXT IrpContext,
170 // IN PVCB Vcb,
171 // IN ULONG FatIndex,
172 // IN ULONG ClusterCount
173 // );
174 //
175 
176 #define FatUnreserveClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) { \
177  NT_ASSERT( (FAT_INDEX) + (CLUSTER_COUNT) - 2 <= (VCB)->FreeClusterBitMap.SizeOfBitMap );\
178  NT_ASSERT( (FAT_INDEX) >= 2); \
179  RtlClearBits(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2,(CLUSTER_COUNT)); \
180  if ((FAT_INDEX) < (VCB)->ClusterHint) { \
181  (VCB)->ClusterHint = (FAT_INDEX); \
182  } \
183 }
184 
185 //
186 // VOID
187 // FatReserveClusters (
188 // IN PIRP_CONTEXT IrpContext,
189 // IN PVCB Vcb,
190 // IN ULONG FatIndex,
191 // IN ULONG ClusterCount
192 // );
193 //
194 // Handle wrapping the hint back to the front.
195 //
196 
197 #define FatReserveClusters(IRPCONTEXT,VCB,FAT_INDEX,CLUSTER_COUNT) { \
198  ULONG _AfterRun = (FAT_INDEX) + (CLUSTER_COUNT); \
199  NT_ASSERT( (FAT_INDEX) + (CLUSTER_COUNT) - 2 <= (VCB)->FreeClusterBitMap.SizeOfBitMap );\
200  NT_ASSERT( (FAT_INDEX) >= 2); \
201  RtlSetBits(&(VCB)->FreeClusterBitMap,(FAT_INDEX)-2,(CLUSTER_COUNT)); \
202  \
203  if (_AfterRun - 2 >= (VCB)->FreeClusterBitMap.SizeOfBitMap) { \
204  _AfterRun = 2; \
205  } \
206  if (RtlCheckBit(&(VCB)->FreeClusterBitMap, _AfterRun - 2)) { \
207  (VCB)->ClusterHint = RtlFindClearBits( &(VCB)->FreeClusterBitMap, 1, _AfterRun - 2) + 2; \
208  if (1 == (VCB)->ClusterHint) { \
209  (VCB)->ClusterHint = 2; \
210  } \
211  } \
212  else { \
213  (VCB)->ClusterHint = _AfterRun; \
214  } \
215 }
216 
217 //
218 // ULONG
219 // FatFindFreeClusterRun (
220 // IN PIRP_CONTEXT IrpContext,
221 // IN PVCB Vcb,
222 // IN ULONG ClusterCount,
223 // IN ULONG AlternateClusterHint
224 // );
225 //
226 // Do a special check if only one cluster is desired.
227 //
228 
229 #define FatFindFreeClusterRun(IRPCONTEXT,VCB,CLUSTER_COUNT,CLUSTER_HINT) ( \
230  (CLUSTER_COUNT == 1) && \
231  FatIsClusterFree((IRPCONTEXT), (VCB), (CLUSTER_HINT)) ? \
232  (CLUSTER_HINT) : \
233  RtlFindClearBits( &(VCB)->FreeClusterBitMap, \
234  (CLUSTER_COUNT), \
235  (CLUSTER_HINT) - 2) + 2 \
236 )
237 
238 //
239 // FAT32: Define the maximum size of the FreeClusterBitMap to be the
240 // maximum size of a FAT16 FAT. If there are more clusters on the
241 // volume than can be represented by this many bytes of bitmap, the
242 // FAT will be split into "buckets", each of which does fit.
243 //
244 // Note this count is in clusters/bits of bitmap.
245 //
246 
247 #define MAX_CLUSTER_BITMAP_SIZE (1 << 16)
248 
249 //
250 // Calculate the window a given cluster number is in.
251 //
252 
253 #define FatWindowOfCluster(C) (((C) - 2) / MAX_CLUSTER_BITMAP_SIZE)
254 
255 #ifdef ALLOC_PRAGMA
256 #pragma alloc_text(PAGE, FatAddFileAllocation)
257 #pragma alloc_text(PAGE, FatAllocateDiskSpace)
258 #pragma alloc_text(PAGE, FatDeallocateDiskSpace)
259 #pragma alloc_text(PAGE, FatExamineFatEntries)
260 #pragma alloc_text(PAGE, FatInterpretClusterType)
261 #pragma alloc_text(PAGE, FatLogOf)
262 #pragma alloc_text(PAGE, FatLookupFatEntry)
263 #pragma alloc_text(PAGE, FatLookupFileAllocation)
264 #pragma alloc_text(PAGE, FatLookupFileAllocationSize)
265 #pragma alloc_text(PAGE, FatMergeAllocation)
266 #pragma alloc_text(PAGE, FatSetFatEntry)
267 #pragma alloc_text(PAGE, FatSetFatRun)
268 #pragma alloc_text(PAGE, FatSetupAllocationSupport)
269 #pragma alloc_text(PAGE, FatSplitAllocation)
270 #pragma alloc_text(PAGE, FatTearDownAllocationSupport)
271 #pragma alloc_text(PAGE, FatTruncateFileAllocation)
272 #endif
273 
274 #ifdef __REACTOS__
275 static
276 #endif
277 INLINE
278 ULONG
280  IN PVCB Vcb
281  )
282 /*++
283 
284 Routine Description:
285 
286  Choose a window to allocate clusters from. Order of preference is:
287 
288  1. First window with >50% free clusters
289  2. First empty window
290  3. Window with greatest number of free clusters.
291 
292 Arguments:
293 
294  Vcb - Supplies the Vcb for the volume
295 
296 Return Value:
297 
298  'Best window' number (index into Vcb->Windows[])
299 
300 --*/
301 {
302  ULONG i, Fave = 0;
303  ULONG MaxFree = 0;
304  ULONG FirstEmpty = (ULONG)-1;
305  ULONG ClustersPerWindow = MAX_CLUSTER_BITMAP_SIZE;
306 
307  NT_ASSERT( 1 != Vcb->NumberOfWindows);
308 
309  for (i = 0; i < Vcb->NumberOfWindows; i++) {
310 
311  if (Vcb->Windows[i].ClustersFree == ClustersPerWindow) {
312 
313  if (-1 == FirstEmpty) {
314 
315  //
316  // Keep note of the first empty window on the disc
317  //
318 
319  FirstEmpty = i;
320  }
321  }
322  else if (Vcb->Windows[i].ClustersFree > MaxFree) {
323 
324  //
325  // This window has the most free clusters, so far
326  //
327 
328  MaxFree = Vcb->Windows[i].ClustersFree;
329  Fave = i;
330 
331  //
332  // If this window has >50% free clusters, then we will take it,
333  // so don't bother considering more windows.
334  //
335 
336  if (MaxFree >= (ClustersPerWindow >> 1)) {
337 
338  break;
339  }
340  }
341  }
342 
343  //
344  // If there were no windows with 50% or more freespace, then select the
345  // first empty window on the disc, if any - otherwise we'll just go with
346  // the one with the most free clusters.
347  //
348 
349  if ((MaxFree < (ClustersPerWindow >> 1)) && (-1 != FirstEmpty)) {
350 
351  Fave = FirstEmpty;
352  }
353 
354  return Fave;
355 }
356 
357 
358 VOID
360  IN PIRP_CONTEXT IrpContext,
361  IN PVCB Vcb
362  )
363 
364 /*++
365 
366 Routine Description:
367 
368  This routine fills in the Allocation Support structure in the Vcb.
369  Most entries are computed using fat.h macros supplied with data from
370  the Bios Parameter Block. The free cluster count, however, requires
371  going to the Fat and actually counting free sectors. At the same time
372  the free cluster bit map is initalized.
373 
374 Arguments:
375 
376  Vcb - Supplies the Vcb to fill in.
377 
378 --*/
379 
380 {
381  ULONG BitIndex;
382  ULONG ClustersDescribableByFat;
383 
384  PAGED_CODE();
385 
386  DebugTrace(+1, Dbg, "FatSetupAllocationSupport\n", 0);
387  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
388 
389  //
390  // Compute a number of fields for Vcb.AllocationSupport
391  //
392 
393  Vcb->AllocationSupport.RootDirectoryLbo = FatRootDirectoryLbo( &Vcb->Bpb );
394  Vcb->AllocationSupport.RootDirectorySize = FatRootDirectorySize( &Vcb->Bpb );
395 
396  Vcb->AllocationSupport.FileAreaLbo = FatFileAreaLbo( &Vcb->Bpb );
397 
398  Vcb->AllocationSupport.NumberOfClusters = FatNumberOfClusters( &Vcb->Bpb );
399 
400  Vcb->AllocationSupport.FatIndexBitSize = FatIndexBitSize( &Vcb->Bpb );
401 
402  Vcb->AllocationSupport.LogOfBytesPerSector = FatLogOf(Vcb->Bpb.BytesPerSector);
403  Vcb->AllocationSupport.LogOfBytesPerCluster = FatLogOf(FatBytesPerCluster( &Vcb->Bpb ));
404  Vcb->AllocationSupport.NumberOfFreeClusters = 0;
405 
406 
407  //
408  // Deal with a bug in DOS 5 format, if the Fat is not big enough to
409  // describe all the clusters on the disk, reduce this number. We expect
410  // that fat32 volumes will not have this problem.
411  //
412  // Turns out this was not a good assumption. We have to do this always now.
413  //
414 
415  ClustersDescribableByFat = ( ((FatIsFat32(Vcb)? Vcb->Bpb.LargeSectorsPerFat :
416  Vcb->Bpb.SectorsPerFat) *
417  Vcb->Bpb.BytesPerSector * 8)
418  / FatIndexBitSize(&Vcb->Bpb) ) - 2;
419 
420  if (Vcb->AllocationSupport.NumberOfClusters > ClustersDescribableByFat) {
421 
422  Vcb->AllocationSupport.NumberOfClusters = ClustersDescribableByFat;
423  }
424 
425  //
426  // Extend the virtual volume file to include the Fat
427  //
428 
429  {
431 
434  FatBytesPerFat( &Vcb->Bpb ));
436 
437  if ( Vcb->VirtualVolumeFile->PrivateCacheMap == NULL ) {
438 
439  FatInitializeCacheMap( Vcb->VirtualVolumeFile,
440  &FileSizes,
441  TRUE,
443  Vcb );
444 
445  } else {
446 
447  CcSetFileSizes( Vcb->VirtualVolumeFile, &FileSizes );
448  }
449  }
450 
451  _SEH2_TRY {
452 
453  if (FatIsFat32(Vcb) &&
454  Vcb->AllocationSupport.NumberOfClusters > MAX_CLUSTER_BITMAP_SIZE) {
455 
456  Vcb->NumberOfWindows = (Vcb->AllocationSupport.NumberOfClusters +
459 
460  } else {
461 
462  Vcb->NumberOfWindows = 1;
463  }
464 
466  Vcb->NumberOfWindows * sizeof(FAT_WINDOW),
467  TAG_FAT_WINDOW );
468 
469  RtlInitializeBitMap( &Vcb->FreeClusterBitMap,
470  NULL,
471  0 );
472 
473  //
474  // Chose a FAT window to begin operation in.
475  //
476 
477  if (Vcb->NumberOfWindows > 1) {
478 
479  //
480  // Read the fat and count up free clusters. We bias by the two reserved
481  // entries in the FAT.
482  //
483 
484  FatExamineFatEntries( IrpContext, Vcb,
485  2,
486  Vcb->AllocationSupport.NumberOfClusters + 2 - 1,
487  TRUE,
488  NULL,
489  NULL);
490 
491 
492  //
493  // Pick a window to begin allocating from
494  //
495 
496  Vcb->CurrentWindow = &Vcb->Windows[ FatSelectBestWindow( Vcb)];
497 
498  } else {
499 
500  Vcb->CurrentWindow = &Vcb->Windows[0];
501 
502  //
503  // Carefully bias ourselves by the two reserved entries in the FAT.
504  //
505 
506  Vcb->CurrentWindow->FirstCluster = 2;
507  Vcb->CurrentWindow->LastCluster = Vcb->AllocationSupport.NumberOfClusters + 2 - 1;
508  }
509 
510  //
511  // Now transition to the FAT window we have chosen.
512  //
513 
514  FatExamineFatEntries( IrpContext, Vcb,
515  0,
516  0,
517  FALSE,
518  Vcb->CurrentWindow,
519  NULL);
520 
521  //
522  // Now set the ClusterHint to the first free bit in our favorite
523  // window (except the ClusterHint is off by two).
524  //
525 
526  Vcb->ClusterHint =
527  (BitIndex = RtlFindClearBits( &Vcb->FreeClusterBitMap, 1, 0 )) != -1 ?
528  BitIndex + 2 : 2;
529 
530  } _SEH2_FINALLY {
531 
533 
534  //
535  // If we hit an exception, back out.
536  //
537 
539 
540  FatTearDownAllocationSupport( IrpContext, Vcb );
541  }
542  } _SEH2_END;
543 
544  return;
545 }
546 
547 
548 VOID
550  IN PIRP_CONTEXT IrpContext,
551  IN PVCB Vcb
552  )
553 
554 /*++
555 
556 Routine Description:
557 
558  This routine prepares the volume for closing. Specifically, we must
559  release the free fat bit map buffer, and uninitialize the dirty fat
560  Mcb.
561 
562 Arguments:
563 
564  Vcb - Supplies the Vcb to fill in.
565 
566 Return Value:
567 
568  VOID
569 
570 --*/
571 
572 {
573  DebugTrace(+1, Dbg, "FatTearDownAllocationSupport\n", 0);
574  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
575 
576  PAGED_CODE();
577 
578  //
579  // If there are FAT buckets, free them.
580  //
581 
582  if ( Vcb->Windows != NULL ) {
583 
584  ExFreePool( Vcb->Windows );
585  Vcb->Windows = NULL;
586  }
587 
588  //
589  // Free the memory associated with the free cluster bitmap.
590  //
591 
592  if ( Vcb->FreeClusterBitMap.Buffer != NULL ) {
593 
594  ExFreePool( Vcb->FreeClusterBitMap.Buffer );
595 
596  //
597  // NULL this field as an flag.
598  //
599 
600  Vcb->FreeClusterBitMap.Buffer = NULL;
601  }
602 
603  //
604  // And remove all the runs in the dirty fat Mcb
605  //
606 
607  FatRemoveMcbEntry( Vcb, &Vcb->DirtyFatMcb, 0, 0xFFFFFFFF );
608 
609  DebugTrace(-1, Dbg, "FatTearDownAllocationSupport -> (VOID)\n", 0);
610 
611  UNREFERENCED_PARAMETER( IrpContext );
612 
613  return;
614 }
615 
616 
617 _Requires_lock_held_(_Global_critical_region_)
618 VOID
619 FatLookupFileAllocation (
620  IN PIRP_CONTEXT IrpContext,
621  IN PFCB FcbOrDcb,
622  IN VBO Vbo,
623  OUT PLBO Lbo,
628  )
629 
630 /*++
631 
632 Routine Description:
633 
634  This routine looks up the existing mapping of VBO to LBO for a
635  file/directory. The information it queries is either stored in the
636  mcb field of the fcb/dcb or it is stored on in the fat table and
637  needs to be retrieved and decoded, and updated in the mcb.
638 
639 Arguments:
640 
641  FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being queried
642 
643  Vbo - Supplies the VBO whose LBO we want returned
644 
645  Lbo - Receives the LBO corresponding to the input Vbo if one exists
646 
647  ByteCount - Receives the number of bytes within the run the run
648  that correpond between the input vbo and output lbo.
649 
650  Allocated - Receives TRUE if the Vbo does have a corresponding Lbo
651  and FALSE otherwise.
652 
653  EndOnMax - Receives TRUE if the run ends in the maximal FAT cluster,
654  which results in a fractional bytecount.
655 
656  Index - Receives the Index of the run
657 
658 --*/
659 
660 {
661  VBO CurrentVbo;
662  LBO CurrentLbo;
663  LBO PriorLbo;
664 
665  VBO FirstVboOfCurrentRun = 0;
666  LBO FirstLboOfCurrentRun;
667 
668  BOOLEAN LastCluster;
669  ULONG Runs;
670 
671  PVCB Vcb;
673  ULONG BytesPerCluster;
674  ULARGE_INTEGER BytesOnVolume;
675 
677 
678  PAGED_CODE();
679 
680  Vcb = FcbOrDcb->Vcb;
681 
682 
683  DebugTrace(+1, Dbg, "FatLookupFileAllocation\n", 0);
684  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
685  DebugTrace( 0, Dbg, " Vbo = %8lx\n", Vbo);
686  DebugTrace( 0, Dbg, " pLbo = %8lx\n", Lbo);
687  DebugTrace( 0, Dbg, " pByteCount = %8lx\n", ByteCount);
688  DebugTrace( 0, Dbg, " pAllocated = %8lx\n", Allocated);
689 
690  Context.Bcb = NULL;
691 
692  *EndOnMax = FALSE;
693 
694  //
695  // Check the trivial case that the mapping is already in our
696  // Mcb.
697  //
698 
700 
701  *Allocated = TRUE;
702 
703  NT_ASSERT( *ByteCount != 0 );
704 
705  //
706  // Detect the overflow case, trim and claim the condition.
707  //
708 
709  if (Vbo + *ByteCount == 0) {
710 
711  *EndOnMax = TRUE;
712  }
713 
714  DebugTrace( 0, Dbg, "Found run in Mcb.\n", 0);
715  DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
716  return;
717  }
718 
719  //
720  // Initialize the Vcb, the cluster size, LastCluster, and
721  // FirstLboOfCurrentRun (to be used as an indication of the first
722  // iteration through the following while loop).
723  //
724 
725  BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
726 
727  BytesOnVolume.QuadPart = UInt32x32To64( Vcb->AllocationSupport.NumberOfClusters, BytesPerCluster );
728 
729  LastCluster = FALSE;
730  FirstLboOfCurrentRun = 0;
731 
732  //
733  // Discard the case that the request extends beyond the end of
734  // allocation. Note that if the allocation size if not known
735  // AllocationSize is set to 0xffffffff.
736  //
737 
738  if ( Vbo >= FcbOrDcb->Header.AllocationSize.LowPart ) {
739 
740  *Allocated = FALSE;
741 
742  DebugTrace( 0, Dbg, "Vbo beyond end of file.\n", 0);
743  DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
744  return;
745  }
746 
747  //
748  // The Vbo is beyond the last Mcb entry. So we adjust Current Vbo/Lbo
749  // and FatEntry to describe the beginning of the last entry in the Mcb.
750  // This is used as initialization for the following loop.
751  //
752  // If the Mcb was empty, we start at the beginning of the file with
753  // CurrentVbo set to 0 to indicate a new run.
754  //
755 
756  if (FatLookupLastMcbEntry( Vcb, &FcbOrDcb->Mcb, &CurrentVbo, &CurrentLbo, &Runs )) {
757 
758  DebugTrace( 0, Dbg, "Current Mcb size = %8lx.\n", CurrentVbo + 1);
759 
760  CurrentVbo -= (BytesPerCluster - 1);
761  CurrentLbo -= (BytesPerCluster - 1);
762 
763  //
764  // Convert an index to a count.
765  //
766 
767  Runs += 1;
768 
769  } else {
770 
771  DebugTrace( 0, Dbg, "Mcb empty.\n", 0);
772 
773  //
774  // Check for an FcbOrDcb that has no allocation
775  //
776 
777  if (FcbOrDcb->FirstClusterOfFile == 0) {
778 
779  *Allocated = FALSE;
780 
781  DebugTrace( 0, Dbg, "File has no allocation.\n", 0);
782  DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
783  return;
784 
785  } else {
786 
787  CurrentVbo = 0;
789  FirstVboOfCurrentRun = CurrentVbo;
790  FirstLboOfCurrentRun = CurrentLbo;
791 
792  Runs = 0;
793 
794  DebugTrace( 0, Dbg, "First Lbo of file = %8lx\n", CurrentLbo);
795  }
796  }
797 
798  //
799  // Now we know that we are looking up a valid Vbo, but it is
800  // not in the Mcb, which is a monotonically increasing list of
801  // Vbo's. Thus we have to go to the Fat, and update
802  // the Mcb as we go. We use a try-finally to unpin the page
803  // of fat hanging around. Also we mark *Allocated = FALSE, so that
804  // the caller wont try to use the data if we hit an exception.
805  //
806 
807  *Allocated = FALSE;
808 
809  _SEH2_TRY {
810 
811  FatEntry = (FAT_ENTRY)FatGetIndexFromLbo( Vcb, CurrentLbo );
812 
813  //
814  // ASSERT that CurrentVbo and CurrentLbo are now cluster alligned.
815  // The assumption here, is that only whole clusters of Vbos and Lbos
816  // are mapped in the Mcb.
817  //
818 
819  NT_ASSERT( ((CurrentLbo - Vcb->AllocationSupport.FileAreaLbo)
820  % BytesPerCluster == 0) &&
821  (CurrentVbo % BytesPerCluster == 0) );
822 
823  //
824  // Starting from the first Vbo after the last Mcb entry, scan through
825  // the Fat looking for our Vbo. We continue through the Fat until we
826  // hit a noncontiguity beyond the desired Vbo, or the last cluster.
827  //
828 
829  while ( !LastCluster ) {
830 
831  //
832  // Get the next fat entry, and update our Current variables.
833  //
834 
835  FatLookupFatEntry( IrpContext, Vcb, FatEntry, (PULONG)&FatEntry, &Context );
836 
837  PriorLbo = CurrentLbo;
838  CurrentLbo = FatGetLboFromIndex( Vcb, FatEntry );
839  CurrentVbo += BytesPerCluster;
840 
841  switch ( FatInterpretClusterType( Vcb, FatEntry )) {
842 
843  //
844  // Check for a break in the Fat allocation chain.
845  //
846 
847  case FatClusterAvailable:
848  case FatClusterReserved:
849  case FatClusterBad:
850 
851  DebugTrace( 0, Dbg, "Break in allocation chain, entry = %d\n", FatEntry);
852  DebugTrace(-1, Dbg, "FatLookupFileAllocation -> Fat Corrupt. Raise Status.\n", 0);
853 
854  FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
856  break;
857 
858  //
859  // If this is the last cluster, we must update the Mcb and
860  // exit the loop.
861  //
862 
863  case FatClusterLast:
864 
865  //
866  // Assert we know where the current run started. If the
867  // Mcb was empty when we were called, thenFirstLboOfCurrentRun
868  // was set to the start of the file. If the Mcb contained an
869  // entry, then FirstLboOfCurrentRun was set on the first
870  // iteration through the loop. Thus if FirstLboOfCurrentRun
871  // is 0, then there was an Mcb entry and we are on our first
872  // iteration, meaing that the last cluster in the Mcb was
873  // really the last allocated cluster, but we checked Vbo
874  // against AllocationSize, and found it OK, thus AllocationSize
875  // must be too large.
876  //
877  // Note that, when we finally arrive here, CurrentVbo is actually
878  // the first Vbo beyond the file allocation and CurrentLbo is
879  // meaningless.
880  //
881 
882  DebugTrace( 0, Dbg, "Read last cluster of file.\n", 0);
883 
884  //
885  // Detect the case of the maximal file. Note that this really isn't
886  // a proper Vbo - those are zero-based, and this is a one-based number.
887  // The maximal file, of 2^32 - 1 bytes, has a maximum byte offset of
888  // 2^32 - 2.
889  //
890  // Just so we don't get confused here.
891  //
892 
893  if (CurrentVbo == 0) {
894 
895  *EndOnMax = TRUE;
896  CurrentVbo -= 1;
897  }
898 
899  LastCluster = TRUE;
900 
901  if (FirstLboOfCurrentRun != 0 ) {
902 
903  DebugTrace( 0, Dbg, "Adding a run to the Mcb.\n", 0);
904  DebugTrace( 0, Dbg, " Vbo = %08lx.\n", FirstVboOfCurrentRun);
905  DebugTrace( 0, Dbg, " Lbo = %08lx.\n", FirstLboOfCurrentRun);
906  DebugTrace( 0, Dbg, " Length = %08lx.\n", CurrentVbo - FirstVboOfCurrentRun);
907 
909  &FcbOrDcb->Mcb,
910  FirstVboOfCurrentRun,
911  FirstLboOfCurrentRun,
912  CurrentVbo - FirstVboOfCurrentRun );
913 
914  Runs += 1;
915  }
916 
917  //
918  // Being at the end of allocation, make sure we have found
919  // the Vbo. If we haven't, seeing as we checked VBO
920  // against AllocationSize, the real disk allocation is less
921  // than that of AllocationSize. This comes about when the
922  // real allocation is not yet known, and AllocaitonSize
923  // contains MAXULONG.
924  //
925  // KLUDGE! - If we were called by FatLookupFileAllocationSize
926  // Vbo is set to MAXULONG - 1, and AllocationSize to the lookup
927  // hint. Thus we merrily go along looking for a match that isn't
928  // there, but in the meantime building an Mcb. If this is
929  // the case, fill in AllocationSize and return.
930  //
931 
932  if ( Vbo == MAXULONG - 1 ) {
933 
934  *Allocated = FALSE;
935 
936  FcbOrDcb->Header.AllocationSize.QuadPart = CurrentVbo;
937 
938  DebugTrace( 0, Dbg, "New file allocation size = %08lx.\n", CurrentVbo);
939  try_return ( NOTHING );
940  }
941 
942  //
943  // We will lie ever so slightly if we really terminated on the
944  // maximal byte of a file. It is really allocated.
945  //
946 
947  if (Vbo >= CurrentVbo && !*EndOnMax) {
948 
949  *Allocated = FALSE;
950  try_return ( NOTHING );
951  }
952 
953  break;
954 
955  //
956  // This is a continuation in the chain. If the run has a
957  // discontiguity at this point, update the Mcb, and if we are beyond
958  // the desired Vbo, this is the end of the run, so set LastCluster
959  // and exit the loop.
960  //
961 
962  case FatClusterNext:
963 
964  //
965  // This is the loop check. The Vbo must not be bigger than the size of
966  // the volume, and the Vbo must not have a) wrapped and b) not been at the
967  // very last cluster in the chain, for the case of the maximal file.
968  //
969 
970  if ( CurrentVbo == 0 ||
971  (BytesOnVolume.HighPart == 0 && CurrentVbo > BytesOnVolume.LowPart)) {
972 
973  FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
975  }
976 
977  if ( PriorLbo + BytesPerCluster != CurrentLbo ) {
978 
979  //
980  // Note that on the first time through the loop
981  // (FirstLboOfCurrentRun == 0), we don't add the
982  // run to the Mcb since it curresponds to the last
983  // run already stored in the Mcb.
984  //
985 
986  if ( FirstLboOfCurrentRun != 0 ) {
987 
988  DebugTrace( 0, Dbg, "Adding a run to the Mcb.\n", 0);
989  DebugTrace( 0, Dbg, " Vbo = %08lx.\n", FirstVboOfCurrentRun);
990  DebugTrace( 0, Dbg, " Lbo = %08lx.\n", FirstLboOfCurrentRun);
991  DebugTrace( 0, Dbg, " Length = %08lx.\n", CurrentVbo - FirstVboOfCurrentRun);
992 
994  &FcbOrDcb->Mcb,
995  FirstVboOfCurrentRun,
996  FirstLboOfCurrentRun,
997  CurrentVbo - FirstVboOfCurrentRun );
998 
999  Runs += 1;
1000  }
1001 
1002  //
1003  // Since we are at a run boundry, with CurrentLbo and
1004  // CurrentVbo being the first cluster of the next run,
1005  // we see if the run we just added encompases the desired
1006  // Vbo, and if so exit. Otherwise we set up two new
1007  // First*boOfCurrentRun, and continue.
1008  //
1009 
1010  if (CurrentVbo > Vbo) {
1011 
1012  LastCluster = TRUE;
1013 
1014  } else {
1015 
1016  FirstVboOfCurrentRun = CurrentVbo;
1017  FirstLboOfCurrentRun = CurrentLbo;
1018  }
1019  }
1020  break;
1021 
1022  default:
1023 
1024  DebugTrace(0, Dbg, "Illegal Cluster Type.\n", FatEntry);
1025 
1026 #ifdef _MSC_VER
1027 #pragma prefast( suppress: 28159, "we bugcheck here because our internal data structures are seriously corrupted if this happens" )
1028 #endif
1029  FatBugCheck( 0, 0, 0 );
1030 
1031  break;
1032 
1033  } // switch()
1034  } // while()
1035 
1036  //
1037  // Load up the return parameters.
1038  //
1039  // On exit from the loop, Vbo still contains the desired Vbo, and
1040  // CurrentVbo is the first byte after the run that contained the
1041  // desired Vbo.
1042  //
1043 
1044  *Allocated = TRUE;
1045 
1046  *Lbo = FirstLboOfCurrentRun + (Vbo - FirstVboOfCurrentRun);
1047 
1048  *ByteCount = CurrentVbo - Vbo;
1049 
1050  if (ARGUMENT_PRESENT(Index)) {
1051 
1052  //
1053  // Note that Runs only needs to be accurate with respect to where we
1054  // ended. Since partial-lookup cases will occur without exclusive
1055  // synchronization, the Mcb itself may be much bigger by now.
1056  //
1057 
1058  *Index = Runs - 1;
1059  }
1060 
1061  try_exit: NOTHING;
1062 
1063  } _SEH2_FINALLY {
1064 
1065  DebugUnwind( FatLookupFileAllocation );
1066 
1067  //
1068  // We are done reading the Fat, so unpin the last page of fat
1069  // that is hanging around
1070  //
1071 
1072  FatUnpinBcb( IrpContext, Context.Bcb );
1073 
1074  DebugTrace(-1, Dbg, "FatLookupFileAllocation -> (VOID)\n", 0);
1075  } _SEH2_END;
1076 
1077  return;
1078 }
1079 
1080 
1081 _Requires_lock_held_(_Global_critical_region_)
1082 VOID
1083 FatAddFileAllocation (
1084  IN PIRP_CONTEXT IrpContext,
1085  IN PFCB FcbOrDcb,
1087  IN ULONG DesiredAllocationSize
1088  )
1089 
1090 /*++
1091 
1092 Routine Description:
1093 
1094  This routine adds additional allocation to the specified file/directory.
1095  Additional allocation is added by appending clusters to the file/directory.
1096 
1097  If the file already has a sufficient allocation then this procedure
1098  is effectively a noop.
1099 
1100 Arguments:
1101 
1102  FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified.
1103  This parameter must not specify the root dcb.
1104 
1105  FileObject - If supplied inform the cache manager of the change.
1106 
1107  DesiredAllocationSize - Supplies the minimum size, in bytes, that we want
1108  allocated to the file/directory.
1109 
1110 --*/
1111 
1112 {
1113  PVCB Vcb;
1114  LARGE_MCB NewMcb = {0};
1115  PLARGE_MCB McbToCleanup = NULL;
1116  PDIRENT Dirent = NULL;
1117  ULONG NewAllocation = 0;
1118  PBCB Bcb = NULL;
1119  BOOLEAN UnwindWeAllocatedDiskSpace = FALSE;
1120  BOOLEAN UnwindAllocationSizeSet = FALSE;
1121  BOOLEAN UnwindCacheManagerInformed = FALSE;
1122  BOOLEAN UnwindWeInitializedMcb = FALSE;
1123 
1124  PAGED_CODE();
1125 
1126  DebugTrace(+1, Dbg, "FatAddFileAllocation\n", 0);
1127  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
1128  DebugTrace( 0, Dbg, " DesiredAllocationSize = %8lx\n", DesiredAllocationSize);
1129 
1130  Vcb = FcbOrDcb->Vcb;
1131 
1132  //
1133  // If we haven't yet set the correct AllocationSize, do so.
1134  //
1135 
1136  if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1137 
1138  FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
1139  }
1140 
1141  //
1142  // Check for the benign case that the desired allocation is already
1143  // within the allocation size.
1144  //
1145 
1146  if (DesiredAllocationSize <= FcbOrDcb->Header.AllocationSize.LowPart) {
1147 
1148  DebugTrace(0, Dbg, "Desired size within current allocation.\n", 0);
1149 
1150  DebugTrace(-1, Dbg, "FatAddFileAllocation -> (VOID)\n", 0);
1151  return;
1152  }
1153 
1154  DebugTrace( 0, Dbg, "InitialAllocation = %08lx.\n", FcbOrDcb->Header.AllocationSize.LowPart);
1155 
1156  //
1157  // Get a chunk of disk space that will fullfill our needs. If there
1158  // was no initial allocation, start from the hint in the Vcb, otherwise
1159  // try to allocate from the cluster after the initial allocation.
1160  //
1161  // If there was no initial allocation to the file, we can just use the
1162  // Mcb in the FcbOrDcb, otherwise we have to use a new one, and merge
1163  // it to the one in the FcbOrDcb.
1164  //
1165 
1166  _SEH2_TRY {
1167 
1168  if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
1169 
1170  LBO FirstLboOfFile;
1171 
1173 
1174  FatGetDirentFromFcbOrDcb( IrpContext,
1175  FcbOrDcb,
1176  FALSE,
1177  &Dirent,
1178  &Bcb );
1179  //
1180  // Set this dirty right now since this call can fail.
1181  //
1182 
1183  FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE );
1184 
1185  FatAllocateDiskSpace( IrpContext,
1186  Vcb,
1187  0,
1188  &DesiredAllocationSize,
1189  FALSE,
1190  &FcbOrDcb->Mcb );
1191 
1192  UnwindWeAllocatedDiskSpace = TRUE;
1193  McbToCleanup = &FcbOrDcb->Mcb;
1194 
1195  //
1196  // We have to update the dirent and FcbOrDcb copies of
1197  // FirstClusterOfFile since before it was 0
1198  //
1199 
1201  &FcbOrDcb->Mcb,
1202  0,
1203  &FirstLboOfFile,
1204  (PULONG)NULL,
1205  NULL );
1206 
1207  DebugTrace( 0, Dbg, "First Lbo of file will be %08lx.\n", FirstLboOfFile );
1208 
1209  FcbOrDcb->FirstClusterOfFile = FatGetIndexFromLbo( Vcb, FirstLboOfFile );
1210 
1212 
1213  if ( FatIsFat32(Vcb) ) {
1214 
1215  Dirent->FirstClusterOfFileHi = (USHORT)(FcbOrDcb->FirstClusterOfFile >> 16);
1216  }
1217 
1218  //
1219  // Note the size of the allocation we need to tell the cache manager about.
1220  //
1221 
1222  NewAllocation = DesiredAllocationSize;
1223 
1224  } else {
1225 
1226  LBO LastAllocatedLbo;
1227  VBO DontCare;
1228 
1229  //
1230  // Get the first cluster following the current allocation. It is possible
1231  // the Mcb is empty (or short, etc.) so we need to be slightly careful
1232  // about making sure we don't lie with the hint.
1233  //
1234 
1235  (void)FatLookupLastMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, &DontCare, &LastAllocatedLbo, NULL );
1236 
1237  //
1238  // Try to get some disk space starting from there.
1239  //
1240 
1241  NewAllocation = DesiredAllocationSize - FcbOrDcb->Header.AllocationSize.LowPart;
1242 
1243  FsRtlInitializeLargeMcb( &NewMcb, PagedPool );
1244  UnwindWeInitializedMcb = TRUE;
1245  McbToCleanup = &NewMcb;
1246 
1247  FatAllocateDiskSpace( IrpContext,
1248  Vcb,
1249  (LastAllocatedLbo != ~0 ?
1250  FatGetIndexFromLbo(Vcb,LastAllocatedLbo + 1) :
1251  0),
1252  &NewAllocation,
1253  FALSE,
1254  &NewMcb );
1255 
1256  UnwindWeAllocatedDiskSpace = TRUE;
1257  }
1258 
1259  //
1260  // Now that we increased the allocation of the file, mark it in the
1261  // FcbOrDcb. Carefully prepare to handle an inability to grow the cache
1262  // structures.
1263  //
1264 
1265  FcbOrDcb->Header.AllocationSize.LowPart += NewAllocation;
1266 
1267  //
1268  // Handle the maximal file case, where we may have just wrapped. Note
1269  // that this must be the precise boundary case wrap, i.e. by one byte,
1270  // so that the new allocation is actually one byte "less" as far as we're
1271  // concerned. This is important for the extension case.
1272  //
1273 
1274  if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
1275 
1276  NewAllocation -= 1;
1277  FcbOrDcb->Header.AllocationSize.LowPart = 0xffffffff;
1278  }
1279 
1280  UnwindAllocationSizeSet = TRUE;
1281 
1282  //
1283  // Inform the cache manager to increase the section size
1284  //
1285 
1287 
1289  (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
1290  UnwindCacheManagerInformed = TRUE;
1291  }
1292 
1293  //
1294  // In the extension case, we have held off actually gluing the new
1295  // allocation onto the file. This simplifies exception cleanup since
1296  // if it was already added and the section grow failed, we'd have to
1297  // do extra work to unglue it. This way, we can assume that if we
1298  // raise the only thing we need to do is deallocate the disk space.
1299  //
1300  // Merge the allocation now.
1301  //
1302 
1303  if (FcbOrDcb->Header.AllocationSize.LowPart != NewAllocation) {
1304 
1305  //
1306  // Tack the new Mcb onto the end of the FcbOrDcb one.
1307  //
1308 
1309  FatMergeAllocation( IrpContext,
1310  Vcb,
1311  &FcbOrDcb->Mcb,
1312  &NewMcb );
1313  }
1314 
1315  } _SEH2_FINALLY {
1316 
1317  DebugUnwind( FatAddFileAllocation );
1318 
1319  //
1320  // Give FlushFileBuffer/Cleanup a clue here, regardless of success/fail..
1321  //
1322 
1324 
1325  //
1326  // If we were dogged trying to complete this operation, we need to go
1327  // back various things out.
1328  //
1329 
1330  if (_SEH2_AbnormalTermination()) {
1331 
1332  //
1333  // Pull off the allocation size we tried to add to this object if
1334  // we failed to grow cache structures or Mcb structures.
1335  //
1336 
1337  if (UnwindAllocationSizeSet) {
1338 
1339  FcbOrDcb->Header.AllocationSize.LowPart -= NewAllocation;
1340  }
1341 
1342  if (UnwindCacheManagerInformed) {
1343 
1345  (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
1346  }
1347 
1348  //
1349  // In the case of initial allocation, we used the Fcb's Mcb and have
1350  // to clean that up as well as the FAT chain references.
1351  //
1352 
1353  if (FcbOrDcb->Header.AllocationSize.LowPart == 0) {
1354 
1355  if (Dirent != NULL) {
1356 
1359 
1360  if ( FatIsFat32(Vcb) ) {
1361 
1362  Dirent->FirstClusterOfFileHi = 0;
1363  }
1364  }
1365  }
1366 
1367  //
1368  // ... and drop the dirent Bcb if we got it. Do it now
1369  // so we can afford to take the exception if we have to.
1370  //
1371 
1372  FatUnpinBcb( IrpContext, Bcb );
1373 
1374  _SEH2_TRY {
1375 
1376  //
1377  // Note this can re-raise.
1378  //
1379 
1380  if ( UnwindWeAllocatedDiskSpace ) {
1381 
1382  FatDeallocateDiskSpace( IrpContext, Vcb, McbToCleanup, FALSE );
1383  }
1384 
1385  } _SEH2_FINALLY {
1386 
1387  //
1388  // We always want to clean up the non-initial allocation temporary Mcb,
1389  // otherwise we have the Fcb's Mcb and we just truncate it away.
1390  //
1391 
1392  if (UnwindWeInitializedMcb == TRUE) {
1393 
1394  //
1395  // Note that we already know a raise is in progress. No danger
1396  // of encountering the normal case code below and doing this again.
1397  //
1398 
1399  FsRtlUninitializeLargeMcb( McbToCleanup );
1400 
1401  } else {
1402 
1403  if (McbToCleanup) {
1404 
1405  FsRtlTruncateLargeMcb( McbToCleanup, 0 );
1406  }
1407  }
1408  } _SEH2_END;
1409  }
1410 
1411  DebugTrace(-1, Dbg, "FatAddFileAllocation -> (VOID)\n", 0);
1412  } _SEH2_END;
1413 
1414  //
1415  // Non-exceptional cleanup we always want to do. In handling the re-raise possibilities
1416  // during exceptions we had to make sure these two steps always happened there beforehand.
1417  // So now we handle the usual case.
1418  //
1419 
1420  FatUnpinBcb( IrpContext, Bcb );
1421 
1422  if (UnwindWeInitializedMcb == TRUE) {
1423 
1424  FsRtlUninitializeLargeMcb( &NewMcb );
1425  }
1426 }
1427 
1428 _Requires_lock_held_(_Global_critical_region_)
1429 VOID
1430 FatTruncateFileAllocation (
1431  IN PIRP_CONTEXT IrpContext,
1432  IN PFCB FcbOrDcb,
1433  IN ULONG DesiredAllocationSize
1434  )
1435 
1436 /*++
1437 
1438 Routine Description:
1439 
1440  This routine truncates the allocation to the specified file/directory.
1441 
1442  If the file is already smaller than the indicated size then this procedure
1443  is effectively a noop.
1444 
1445 
1446 Arguments:
1447 
1448  FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
1449  This parameter must not specify the root dcb.
1450 
1451  DesiredAllocationSize - Supplies the maximum size, in bytes, that we want
1452  allocated to the file/directory. It is rounded
1453  up to the nearest cluster.
1454 
1455 Return Value:
1456 
1457  VOID - TRUE if the operation completed and FALSE if it had to
1458  block but could not.
1459 
1460 --*/
1461 
1462 {
1463  PVCB Vcb;
1464  PBCB Bcb = NULL;
1465  LARGE_MCB RemainingMcb = {0};
1466  ULONG BytesPerCluster;
1467  PDIRENT Dirent = NULL;
1468  BOOLEAN UpdatedDirent = FALSE;
1469 
1470  ULONG UnwindInitialAllocationSize;
1471  ULONG UnwindInitialFirstClusterOfFile;
1472  BOOLEAN UnwindWeAllocatedMcb = FALSE;
1473 
1474  PAGED_CODE();
1475 
1476  Vcb = FcbOrDcb->Vcb;
1477 
1478  DebugTrace(+1, Dbg, "FatTruncateFileAllocation\n", 0);
1479  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
1480  DebugTrace( 0, Dbg, " DesiredAllocationSize = %8lx\n", DesiredAllocationSize);
1481 
1482  //
1483  // If the Fcb isn't in good condition, we have no business whacking around on
1484  // the disk after "its" clusters.
1485  //
1486  // Inspired by a Prefix complaint.
1487  //
1488 
1490 
1491  //
1492  // If we haven't yet set the correct AllocationSize, do so.
1493  //
1494 
1495  if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1496 
1497  FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
1498  }
1499 
1500  //
1501  // Round up the Desired Allocation Size to the next cluster size
1502  //
1503 
1504  BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
1505 
1506  //
1507  // Note if the desired allocation is zero, to distinguish this from
1508  // the wrap case below.
1509  //
1510 
1511  if (DesiredAllocationSize != 0) {
1512 
1513  DesiredAllocationSize = (DesiredAllocationSize + (BytesPerCluster - 1)) &
1514  ~(BytesPerCluster - 1);
1515  //
1516  // Check for the benign case that the file is already smaller than
1517  // the desired truncation. Note that if it wraps, then a) it was
1518  // specifying an offset in the maximally allocatable cluster and
1519  // b) we're not asking to extend the file, either. So stop.
1520  //
1521 
1522  if (DesiredAllocationSize == 0 ||
1523  DesiredAllocationSize >= FcbOrDcb->Header.AllocationSize.LowPart) {
1524 
1525  DebugTrace(0, Dbg, "Desired size within current allocation.\n", 0);
1526 
1527  DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
1528  return;
1529  }
1530 
1531  }
1532 
1533  //
1534  // This is a no-op if the allocation size is already what we want.
1535  //
1536 
1537  if (DesiredAllocationSize == FcbOrDcb->Header.AllocationSize.LowPart) {
1538 
1539  DebugTrace(0, Dbg, "Desired size equals current allocation.\n", 0);
1540  DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
1541  return;
1542  }
1543 
1544  UnwindInitialAllocationSize = FcbOrDcb->Header.AllocationSize.LowPart;
1545  UnwindInitialFirstClusterOfFile = FcbOrDcb->FirstClusterOfFile;
1546 
1547  //
1548  // Update the FcbOrDcb allocation size. If it is now zero, we have the
1549  // additional task of modifying the FcbOrDcb and Dirent copies of
1550  // FirstClusterInFile.
1551  //
1552  // Note that we must pin the dirent before actually deallocating the
1553  // disk space since, in unwind, it would not be possible to reallocate
1554  // deallocated disk space as someone else may have reallocated it and
1555  // may cause an exception when you try to get some more disk space.
1556  // Thus FatDeallocateDiskSpace must be the final dangerous operation.
1557  //
1558 
1559  _SEH2_TRY {
1560 
1561  FcbOrDcb->Header.AllocationSize.QuadPart = DesiredAllocationSize;
1562 
1563  //
1564  // Special case 0
1565  //
1566 
1567  if (DesiredAllocationSize == 0) {
1568 
1569  //
1570  // We have to update the dirent and FcbOrDcb copies of
1571  // FirstClusterOfFile since before it was 0
1572  //
1573 
1575 
1576  FatGetDirentFromFcbOrDcb( IrpContext, FcbOrDcb, FALSE, &Dirent, &Bcb );
1577 
1579 
1580  if (FatIsFat32(Vcb)) {
1581 
1582  Dirent->FirstClusterOfFileHi = 0;
1583  }
1584 
1586 
1587  FatSetDirtyBcb( IrpContext, Bcb, Vcb, TRUE );
1588  UpdatedDirent = TRUE;
1589 
1590  FatDeallocateDiskSpace( IrpContext, Vcb, &FcbOrDcb->Mcb, ((FcbOrDcb->FcbState & FCB_STATE_ZERO_ON_DEALLOCATION) != 0));
1591 
1592  FatRemoveMcbEntry( FcbOrDcb->Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
1593 
1594  } else {
1595 
1596  //
1597  // Split the existing allocation into two parts, one we will keep, and
1598  // one we will deallocate.
1599  //
1600 
1602  UnwindWeAllocatedMcb = TRUE;
1603 
1604  FatSplitAllocation( IrpContext,
1605  Vcb,
1606  &FcbOrDcb->Mcb,
1607  DesiredAllocationSize,
1608  &RemainingMcb );
1609 
1610  FatDeallocateDiskSpace( IrpContext, Vcb, &RemainingMcb, ((FcbOrDcb->FcbState & FCB_STATE_ZERO_ON_DEALLOCATION) != 0) );
1611 
1613  }
1614 
1615  } _SEH2_FINALLY {
1616 
1617  DebugUnwind( FatTruncateFileAllocation );
1618 
1619  //
1620  // Is this really the right backout strategy? It would be nice if we could
1621  // pretend the truncate worked if we knew that the file had gotten into
1622  // a consistent state. Leaving dangled clusters is probably quite preferable.
1623  //
1624 
1625  if ( _SEH2_AbnormalTermination() ) {
1626 
1627  FcbOrDcb->Header.AllocationSize.LowPart = UnwindInitialAllocationSize;
1628 
1629  if ( (DesiredAllocationSize == 0) && (Dirent != NULL)) {
1630 
1631  if (UpdatedDirent) {
1632 
1633  //
1634  // If the dirent has been updated ok and marked dirty, then we
1635  // failed in deallocatediscspace, and don't know what state
1636  // the on disc fat chain is in. So we throw away the mcb,
1637  // and potentially loose a few clusters until the next
1638  // chkdsk. The operation has succeeded, but the exception
1639  // will still propogate. 5.1
1640  //
1641 
1642  FatRemoveMcbEntry( Vcb, &FcbOrDcb->Mcb, 0, 0xFFFFFFFF );
1643  FcbOrDcb->Header.AllocationSize.QuadPart = 0;
1644  }
1645  else if (FcbOrDcb->FirstClusterOfFile == 0) {
1646 
1647  Dirent->FirstClusterOfFile = (USHORT)UnwindInitialFirstClusterOfFile;
1648 
1649  if ( FatIsFat32(Vcb) ) {
1650 
1651  Dirent->FirstClusterOfFileHi =
1652  (USHORT)(UnwindInitialFirstClusterOfFile >> 16);
1653  }
1654 
1655  FcbOrDcb->FirstClusterOfFile = UnwindInitialFirstClusterOfFile;
1656  }
1657  }
1658 
1659  if ( UnwindWeAllocatedMcb ) {
1660 
1662  }
1663 
1664  //
1665  // Note that in the non zero truncation case, we will also
1666  // leak clusters. However, apart from this, the in memory and on disc
1667  // structures will agree.
1668  }
1669 
1670  FatUnpinBcb( IrpContext, Bcb );
1671 
1672  //
1673  // Give FlushFileBuffer/Cleanup a clue here, regardless of success/fail.
1674  //
1675 
1677 
1678  DebugTrace(-1, Dbg, "FatTruncateFileAllocation -> (VOID)\n", 0);
1679  } _SEH2_END;
1680 }
1681 
1682 
1683 _Requires_lock_held_(_Global_critical_region_)
1684 VOID
1685 FatLookupFileAllocationSize (
1686  IN PIRP_CONTEXT IrpContext,
1687  IN PFCB FcbOrDcb
1688  )
1689 
1690 /*++
1691 
1692 Routine Description:
1693 
1694  This routine retrieves the current file allocatio size for the
1695  specified file/directory.
1696 
1697 Arguments:
1698 
1699  FcbOrDcb - Supplies the Fcb/Dcb of the file/directory being modified
1700 
1701 --*/
1702 
1703 {
1704  LBO Lbo;
1705  ULONG ByteCount;
1706  BOOLEAN DontCare;
1707 
1708  PAGED_CODE();
1709 
1710  DebugTrace(+1, Dbg, "FatLookupAllocationSize\n", 0);
1711  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
1712 
1713  //
1714  // We call FatLookupFileAllocation with Vbo of 0xffffffff - 1.
1715  //
1716 
1717  FatLookupFileAllocation( IrpContext,
1718  FcbOrDcb,
1719  MAXULONG - 1,
1720  &Lbo,
1721  &ByteCount,
1722  &DontCare,
1723  &DontCare,
1724  NULL );
1725 
1726  //
1727  // FileSize was set at Fcb creation time from the contents of the directory entry,
1728  // and we are only now looking up the real length of the allocation chain. If it
1729  // cannot be contained, this is trash. Probably more where that came from.
1730  //
1731 
1732  if (FcbOrDcb->Header.FileSize.LowPart > FcbOrDcb->Header.AllocationSize.LowPart) {
1733 
1734  FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
1736  }
1737 
1738  DebugTrace(-1, Dbg, "FatLookupFileAllocationSize -> (VOID)\n", 0);
1739  return;
1740 }
1741 
1742 
1743 _Requires_lock_held_(_Global_critical_region_)
1744 VOID
1745 FatAllocateDiskSpace (
1746  IN PIRP_CONTEXT IrpContext,
1747  IN PVCB Vcb,
1752  )
1753 
1754 /*++
1755 
1756 Routine Description:
1757 
1758  This procedure allocates additional disk space and builds an mcb
1759  representing the newly allocated space. If the space cannot be
1760  allocated then this procedure raises an appropriate status.
1761 
1762  Searching starts from the hint index in the Vcb unless an alternative
1763  non-zero hint is given in AlternateClusterHint. If we are using the
1764  hint field in the Vcb, it is set to the cluster following our allocation
1765  when we are done.
1766 
1767  Disk space can only be allocated in cluster units so this procedure
1768  will round up any byte count to the next cluster boundary.
1769 
1770  Pictorially what is done is the following (where ! denotes the end of
1771  the fat chain (i.e., FAT_CLUSTER_LAST)):
1772 
1773 
1774  Mcb (empty)
1775 
1776  becomes
1777 
1778  Mcb |--a--|--b--|--c--!
1779 
1780  ^
1781  ByteCount ----------+
1782 
1783 Arguments:
1784 
1785  Vcb - Supplies the VCB being modified
1786 
1787  AbsoluteClusterHint - Supplies an alternate hint index to start the
1788  search from. If this is zero we use, and update,
1789  the Vcb hint field.
1790 
1791  ByteCount - Supplies the number of bytes that we are requesting, and
1792  receives the number of bytes that we got.
1793 
1794  ExactMatchRequired - Caller should set this to TRUE if only the precise run requested
1795  is acceptable.
1796 
1797  Mcb - Receives the MCB describing the newly allocated disk space. The
1798  caller passes in an initialized Mcb that is filled in by this procedure.
1799 
1800  Return Value:
1801 
1802  TRUE - Allocated ok
1803  FALSE - Failed to allocate exactly as requested (=> ExactMatchRequired was TRUE)
1804 
1805 --*/
1806 
1807 {
1808  UCHAR LogOfBytesPerCluster;
1809  ULONG BytesPerCluster;
1810  ULONG StartingCluster;
1811  ULONG ClusterCount;
1812  ULONG WindowRelativeHint;
1813 #if DBG
1814  ULONG PreviousClear = 0;
1815 #endif
1816 
1818  BOOLEAN Wait = FALSE;
1819  BOOLEAN Result = TRUE;
1820 
1821  PAGED_CODE();
1822 
1823  DebugTrace(+1, Dbg, "FatAllocateDiskSpace\n", 0);
1824  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
1825  DebugTrace( 0, Dbg, " *ByteCount = %8lx\n", *ByteCount);
1826  DebugTrace( 0, Dbg, " Mcb = %p\n", Mcb);
1827  DebugTrace( 0, Dbg, " Hint = %8lx\n", AbsoluteClusterHint);
1828 
1829  NT_ASSERT((AbsoluteClusterHint <= Vcb->AllocationSupport.NumberOfClusters + 2) && (1 != AbsoluteClusterHint));
1830 
1831  //
1832  // Make sure byte count is not zero
1833  //
1834 
1835  if (*ByteCount == 0) {
1836 
1837  DebugTrace(0, Dbg, "Nothing to allocate.\n", 0);
1838 
1839  DebugTrace(-1, Dbg, "FatAllocateDiskSpace -> (VOID)\n", 0);
1840  return;
1841  }
1842 
1843  //
1844  // Compute the cluster count based on the byte count, rounding up
1845  // to the next cluster if there is any remainder. Note that the
1846  // pathalogical case BytesCount == 0 has been eliminated above.
1847  //
1848 
1849  LogOfBytesPerCluster = Vcb->AllocationSupport.LogOfBytesPerCluster;
1850  BytesPerCluster = 1 << LogOfBytesPerCluster;
1851 
1852  *ByteCount = (*ByteCount + (BytesPerCluster - 1))
1853  & ~(BytesPerCluster - 1);
1854 
1855  //
1856  // If ByteCount is NOW zero, then we were asked for the maximal
1857  // filesize (or at least for bytes in the last allocatable sector).
1858  //
1859 
1860  if (*ByteCount == 0) {
1861 
1862  *ByteCount = 0xffffffff;
1863  ClusterCount = 1 << (32 - LogOfBytesPerCluster);
1864 
1865  } else {
1866 
1867  ClusterCount = (*ByteCount >> LogOfBytesPerCluster);
1868  }
1869 
1870  //
1871  // Analysis tools don't figure out that ClusterCount is not zero because
1872  // of the ByteCount == 0 checks, so give them a hint.
1873  //
1874  _Analysis_assume_(ClusterCount > 0);
1875 
1876  //
1877  // Make sure there are enough free clusters to start with, and
1878  // take them now so that nobody else takes them from us.
1879  //
1880 
1881  ExAcquireResourceSharedLite(&Vcb->ChangeBitMapResource, TRUE);
1883 
1884  if (ClusterCount <= Vcb->AllocationSupport.NumberOfFreeClusters) {
1885 
1886  Vcb->AllocationSupport.NumberOfFreeClusters -= ClusterCount;
1887 
1888  } else {
1889 
1891  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
1892 
1893  DebugTrace(0, Dbg, "Disk Full. Raise Status.\n", 0);
1894  FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
1895  }
1896 
1897  //
1898  // Did the caller supply a hint?
1899  //
1900 
1901  if ((0 != AbsoluteClusterHint) && (AbsoluteClusterHint < (Vcb->AllocationSupport.NumberOfClusters + 2))) {
1902 
1903  if (Vcb->NumberOfWindows > 1) {
1904 
1905  //
1906  // If we're being called upon to allocate clusters outside the
1907  // current window (which happens only via MoveFile), it's a problem.
1908  // We address this by changing the current window to be the one which
1909  // contains the alternate cluster hint. Note that if the user's
1910  // request would cross a window boundary, he doesn't really get what
1911  // he wanted.
1912  //
1913 
1914  if (AbsoluteClusterHint < Vcb->CurrentWindow->FirstCluster ||
1915  AbsoluteClusterHint > Vcb->CurrentWindow->LastCluster) {
1916 
1918 
1919  NT_ASSERT( BucketNum < Vcb->NumberOfWindows);
1920 
1921  //
1922  // Drop our shared lock on the ChangeBitMapResource, and pick it up again
1923  // exclusive in preparation for making the window swap.
1924  //
1925 
1927  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
1928  ExAcquireResourceExclusiveLite(&Vcb->ChangeBitMapResource, TRUE);
1930 
1931  Window = &Vcb->Windows[BucketNum];
1932 
1933  //
1934  // Again, test the current window against the one we want - some other
1935  // thread could have sneaked in behind our backs and kindly set it to the one
1936  // we need, when we dropped and reacquired the ChangeBitMapResource above.
1937  //
1938 
1939  if (Window != Vcb->CurrentWindow) {
1940 
1941  _SEH2_TRY {
1942 
1943  Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1944  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1945 
1946  //
1947  // Change to the new window (update Vcb->CurrentWindow) and scan it
1948  // to build up a freespace bitmap etc.
1949  //
1950 
1951  FatExamineFatEntries( IrpContext, Vcb,
1952  0,
1953  0,
1954  FALSE,
1955  Window,
1956  NULL);
1957 
1958  } _SEH2_FINALLY {
1959 
1960  if (!Wait) {
1961 
1962  ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
1963  }
1964 
1965  if (_SEH2_AbnormalTermination()) {
1966 
1967  //
1968  // We will have raised as a result of failing to pick up the
1969  // chunk of the FAT for this window move. Release our resources
1970  // and return the cluster count to the volume.
1971  //
1972 
1973  Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
1974 
1976  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
1977  }
1978  } _SEH2_END;
1979  }
1980  }
1981 
1982  //
1983  // Make the hint cluster number relative to the base of the current window...
1984  //
1985  // Currentwindow->Firstcluster is baised by +2 already, so we will lose the
1986  // bias already in AbsoluteClusterHint. Put it back....
1987  //
1988 
1989  WindowRelativeHint = AbsoluteClusterHint - Vcb->CurrentWindow->FirstCluster + 2;
1990  }
1991  else {
1992 
1993  //
1994  // Only one 'window', ie fat16/12. No modification necessary.
1995  //
1996 
1997  WindowRelativeHint = AbsoluteClusterHint;
1998  }
1999  }
2000  else {
2001 
2002  //
2003  // Either no hint supplied, or it was out of range, so grab one from the Vcb
2004  //
2005  // NOTE: Clusterhint in the Vcb is not guaranteed to be set (may be -1)
2006  //
2007 
2008  WindowRelativeHint = Vcb->ClusterHint;
2009  AbsoluteClusterHint = 0;
2010 
2011  //
2012  // Vcb hint may not have been initialized yet. Force to valid cluster.
2013  //
2014 
2015  if (-1 == WindowRelativeHint) {
2016 
2017  WindowRelativeHint = 2;
2018  }
2019  }
2020 
2021  NT_ASSERT((WindowRelativeHint >= 2) && (WindowRelativeHint < Vcb->FreeClusterBitMap.SizeOfBitMap + 2));
2022 
2023  //
2024  // Keep track of the window we're allocating from, so we can clean
2025  // up correctly if the current window changes after we unlock the
2026  // bitmap.
2027  //
2028 
2029  Window = Vcb->CurrentWindow;
2030 
2031  //
2032  // Try to find a run of free clusters large enough for us.
2033  //
2034 
2035  StartingCluster = FatFindFreeClusterRun( IrpContext,
2036  Vcb,
2037  ClusterCount,
2038  WindowRelativeHint );
2039  //
2040  // If the above call was successful, we can just update the fat
2041  // and Mcb and exit. Otherwise we have to look for smaller free
2042  // runs.
2043  //
2044  // This test is a bit funky. Note that the error return from
2045  // RtlFindClearBits is -1, and adding two to that is 1.
2046  //
2047 
2048  if ((StartingCluster != 1) &&
2049  ((0 == AbsoluteClusterHint) || (StartingCluster == WindowRelativeHint))
2050  ) {
2051 
2052 #if DBG
2053  PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
2054 #endif // DBG
2055 
2056  //
2057  // Take the clusters we found, and unlock the bit map.
2058  //
2059 
2060  FatReserveClusters(IrpContext, Vcb, StartingCluster, ClusterCount);
2061 
2062  Window->ClustersFree -= ClusterCount;
2063 
2064  StartingCluster += Window->FirstCluster;
2065  StartingCluster -= 2;
2066 
2067  NT_ASSERT( PreviousClear - ClusterCount == Window->ClustersFree );
2068 
2070 
2071  //
2072  // Note that this call will never fail since there is always
2073  // room for one entry in an empty Mcb.
2074  //
2075 
2077  0,
2078  FatGetLboFromIndex( Vcb, StartingCluster ),
2079  *ByteCount);
2080  _SEH2_TRY {
2081 
2082  //
2083  // Update the fat.
2084  //
2085 
2086  FatAllocateClusters(IrpContext, Vcb,
2087  StartingCluster,
2088  ClusterCount);
2089 
2090  } _SEH2_FINALLY {
2091 
2092  DebugUnwind( FatAllocateDiskSpace );
2093 
2094  //
2095  // If the allocate clusters failed, remove the run from the Mcb,
2096  // unreserve the clusters, and reset the free cluster count.
2097  //
2098 
2099  if (_SEH2_AbnormalTermination()) {
2100 
2102 
2104 
2105  // Only clear bits if the bitmap window is the same.
2106 
2107  if (Window == Vcb->CurrentWindow) {
2108 
2109  // Both values (startingcluster and window->firstcluster) are
2110  // already biased by 2, so will cancel, so we need to add in the 2 again.
2111 
2112  FatUnreserveClusters( IrpContext, Vcb,
2113  StartingCluster - Window->FirstCluster + 2,
2114  ClusterCount );
2115  }
2116 
2117  Window->ClustersFree += ClusterCount;
2118  Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
2119 
2121  }
2122 
2123  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
2124  } _SEH2_END;
2125 
2126  } else {
2127 
2128  //
2129  // Note that Index is a zero-based window-relative number. When appropriate
2130  // it'll get converted into a true cluster number and put in Cluster, which
2131  // will be a volume relative true cluster number.
2132  //
2133 
2134  ULONG Index = 0;
2135  ULONG Cluster = 0;
2136  ULONG CurrentVbo = 0;
2137  ULONG PriorLastCluster = 0;
2138  ULONG BytesFound = 0;
2139 
2140  ULONG ClustersFound = 0;
2141  ULONG ClustersRemaining = 0;
2142 
2143  BOOLEAN LockedBitMap = FALSE;
2144  BOOLEAN SelectNextContigWindow = FALSE;
2145 
2146  //
2147  // Drop our shared lock on the ChangeBitMapResource, and pick it up again
2148  // exclusive in preparation for making a window swap.
2149  //
2150 
2152  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
2153  ExAcquireResourceExclusiveLite(&Vcb->ChangeBitMapResource, TRUE);
2155  LockedBitMap = TRUE;
2156 
2157  _SEH2_TRY {
2158 
2159  if ( ExactMatchRequired && (1 == Vcb->NumberOfWindows)) {
2160 
2161  //
2162  // Give up right now, there are no more windows to search! RtlFindClearBits
2163  // searchs the whole bitmap, so we would have found any contiguous run
2164  // large enough.
2165  //
2166 
2167  try_leave( Result = FALSE);
2168  }
2169 
2170  //
2171  // While the request is still incomplete, look for the largest
2172  // run of free clusters, mark them taken, allocate the run in
2173  // the Mcb and Fat, and if this isn't the first time through
2174  // the loop link it to prior run on the fat. The Mcb will
2175  // coalesce automatically.
2176  //
2177 
2178  ClustersRemaining = ClusterCount;
2179  CurrentVbo = 0;
2180  PriorLastCluster = 0;
2181 
2182  while (ClustersRemaining != 0) {
2183 
2184  //
2185  // If we just entered the loop, the bit map is already locked
2186  //
2187 
2188  if ( !LockedBitMap ) {
2189 
2191  LockedBitMap = TRUE;
2192  }
2193 
2194  //
2195  // Find the largest run of free clusters. If the run is
2196  // bigger than we need, only use what we need. Note that
2197  // this will then be the last while() iteration.
2198  //
2199 
2200  // 12/3/95: need to bias bitmap by 2 bits for the defrag
2201  // hooks and the below macro became impossible to do without in-line
2202  // procedures.
2203  //
2204  // ClustersFound = FatLongestFreeClusterRun( IrpContext, Vcb, &Index );
2205 
2206  ClustersFound = 0;
2207 
2208  if (!SelectNextContigWindow) {
2209 
2210  if ( 0 != WindowRelativeHint) {
2211 
2212  ULONG Desired = Vcb->FreeClusterBitMap.SizeOfBitMap - (WindowRelativeHint - 2);
2213 
2214  //
2215  // We will try to allocate contiguously. Try from the current hint the to
2216  // end of current window. Don't try for more than we actually need.
2217  //
2218 
2219  if (Desired > ClustersRemaining) {
2220 
2221  Desired = ClustersRemaining;
2222  }
2223 
2224  if (RtlAreBitsClear( &Vcb->FreeClusterBitMap,
2225  WindowRelativeHint - 2,
2226  Desired))
2227  {
2228  //
2229  // Clusters from hint->...windowend are free. Take them.
2230  //
2231 
2232  Index = WindowRelativeHint - 2;
2233  ClustersFound = Desired;
2234 
2235  if (FatIsFat32(Vcb)) {
2236 
2237  //
2238  // We're now up against the end of the current window, so indicate that we
2239  // want the next window in the sequence next time around. (If we're not up
2240  // against the end of the window, then we got what we needed and won't be
2241  // coming around again anyway).
2242  //
2243 
2244  SelectNextContigWindow = TRUE;
2245  WindowRelativeHint = 2;
2246  }
2247  else {
2248 
2249  //
2250  // FAT 12/16 - we've run up against the end of the volume. Clear the
2251  // hint, since we now have no idea where to look.
2252  //
2253 
2254  WindowRelativeHint = 0;
2255  }
2256 #if DBG
2257  PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
2258 #endif // DBG
2259  }
2260  else {
2261 
2262  if (ExactMatchRequired) {
2263 
2264  //
2265  // If our caller required an exact match, then we're hosed. Bail out now.
2266  //
2267 
2268  try_leave( Result = FALSE);
2269  }
2270 
2271  //
2272  // Hint failed, drop back to pot luck
2273  //
2274 
2275  WindowRelativeHint = 0;
2276  }
2277  }
2278 
2279  if ((0 == WindowRelativeHint) && (0 == ClustersFound)) {
2280 
2281  if (ClustersRemaining <= Vcb->CurrentWindow->ClustersFree) {
2282 
2283  //
2284  // The remaining allocation could be satisfied entirely from this
2285  // window. We will ask only for what we need, to try and avoid
2286  // unnecessarily fragmenting large runs of space by always using
2287  // (part of) the largest run we can find. This call will return the
2288  // first run large enough.
2289  //
2290 
2291  Index = RtlFindClearBits( &Vcb->FreeClusterBitMap, ClustersRemaining, 0);
2292 
2293  if (-1 != Index) {
2294 
2295  ClustersFound = ClustersRemaining;
2296  }
2297  }
2298 
2299  if (0 == ClustersFound) {
2300 
2301  //
2302  // Still nothing, so just take the largest free run we can find.
2303  //
2304 
2305  ClustersFound = RtlFindLongestRunClear( &Vcb->FreeClusterBitMap, &Index );
2306 
2307  }
2308 #if DBG
2309  PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
2310 #endif // DBG
2311  if (ClustersFound >= ClustersRemaining) {
2312 
2313  ClustersFound = ClustersRemaining;
2314  }
2315  else {
2316 
2317  //
2318  // If we just ran up to the end of a window, set up a hint that
2319  // we'd like the next consecutive window after this one. (FAT32 only)
2320  //
2321 
2322  if ( ((Index + ClustersFound) == Vcb->FreeClusterBitMap.SizeOfBitMap) &&
2323  FatIsFat32( Vcb)
2324  ) {
2325 
2326  SelectNextContigWindow = TRUE;
2327  WindowRelativeHint = 2;
2328  }
2329  }
2330  }
2331  }
2332 
2333  if (ClustersFound == 0) {
2334 
2335  ULONG FaveWindow = 0;
2336  BOOLEAN SelectedWindow;
2337 
2338  //
2339  // If we found no free clusters on a single-window FAT,
2340  // there was a bad problem with the free cluster count.
2341  //
2342 
2343  if (1 == Vcb->NumberOfWindows) {
2344 
2345 #ifdef _MSC_VER
2346 #pragma prefast( suppress: 28159, "we bugcheck here because our internal data structures are seriously corrupted if this happens" )
2347 #endif
2348  FatBugCheck( 0, 5, 0 );
2349  }
2350 
2351  //
2352  // Switch to a new bucket. Possibly the next one if we're
2353  // currently on a roll (allocating contiguously)
2354  //
2355 
2356  SelectedWindow = FALSE;
2357 
2358  if ( SelectNextContigWindow) {
2359 
2360  ULONG NextWindow;
2361 
2362  NextWindow = (((ULONG)((PUCHAR)Vcb->CurrentWindow - (PUCHAR)Vcb->Windows)) / sizeof( FAT_WINDOW)) + 1;
2363 
2364  if ((NextWindow < Vcb->NumberOfWindows) &&
2365  ( Vcb->Windows[ NextWindow].ClustersFree > 0)
2366  ) {
2367 
2368  FaveWindow = NextWindow;
2369  SelectedWindow = TRUE;
2370  }
2371  else {
2372 
2373  if (ExactMatchRequired) {
2374 
2375  //
2376  // Some dope tried to allocate a run past the end of the volume...
2377  //
2378 
2379  try_leave( Result = FALSE);
2380  }
2381 
2382  //
2383  // Give up on the contiguous allocation attempts
2384  //
2385 
2386  WindowRelativeHint = 0;
2387  }
2388 
2389  SelectNextContigWindow = FALSE;
2390  }
2391 
2392  if (!SelectedWindow) {
2393 
2394  //
2395  // Select a new window to begin allocating from
2396  //
2397 
2398  FaveWindow = FatSelectBestWindow( Vcb);
2399  }
2400 
2401  //
2402  // By now we'd better have found a window with some free clusters
2403  //
2404 
2405  if (0 == Vcb->Windows[ FaveWindow].ClustersFree) {
2406 
2407 #ifdef _MSC_VER
2408 #pragma prefast( suppress: 28159, "we bugcheck here because our internal data structures are seriously corrupted if this happens" )
2409 #endif
2410  FatBugCheck( 0, 5, 1 );
2411  }
2412 
2413  Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2414  SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2415 
2416  FatExamineFatEntries( IrpContext, Vcb,
2417  0,
2418  0,
2419  FALSE,
2420  &Vcb->Windows[FaveWindow],
2421  NULL);
2422 
2423  if (!Wait) {
2424 
2425  ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2426  }
2427 
2428  //
2429  // Now we'll just go around the loop again, having switched windows,
2430  // and allocate....
2431  //
2432 #if DBG
2433  PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
2434 #endif //DBG
2435  } // if (clustersfound == 0)
2436  else {
2437 
2438  //
2439  // Take the clusters we found, convert our index to a cluster number
2440  // and unlock the bit map.
2441  //
2442 
2443  Window = Vcb->CurrentWindow;
2444 
2445  FatReserveClusters( IrpContext, Vcb, (Index + 2), ClustersFound );
2446 
2447  Cluster = Index + Window->FirstCluster;
2448 
2449  Window->ClustersFree -= ClustersFound;
2450  NT_ASSERT( PreviousClear - ClustersFound == Window->ClustersFree );
2451 
2453  LockedBitMap = FALSE;
2454 
2455  //
2456  // Add the newly alloced run to the Mcb.
2457  //
2458 
2459  BytesFound = ClustersFound << LogOfBytesPerCluster;
2460 
2462  CurrentVbo,
2463  FatGetLboFromIndex( Vcb, Cluster ),
2464  BytesFound );
2465 
2466  //
2467  // Connect the last allocated run with this one, and allocate
2468  // this run on the Fat.
2469  //
2470 
2471  if (PriorLastCluster != 0) {
2472 
2473  FatSetFatEntry( IrpContext,
2474  Vcb,
2475  PriorLastCluster,
2476  (FAT_ENTRY)Cluster );
2477  }
2478 
2479  //
2480  // Update the fat
2481  //
2482 
2483  FatAllocateClusters( IrpContext, Vcb, Cluster, ClustersFound );
2484 
2485  //
2486  // Prepare for the next iteration.
2487  //
2488 
2489  CurrentVbo += BytesFound;
2490  ClustersRemaining -= ClustersFound;
2491  PriorLastCluster = Cluster + ClustersFound - 1;
2492  }
2493  } // while (clustersremaining)
2494 
2495  } _SEH2_FINALLY {
2496 
2497  DebugUnwind( FatAllocateDiskSpace );
2498 
2499  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
2500 
2501  //
2502  // Is there any unwinding to do?
2503  //
2504 
2505  if ( _SEH2_AbnormalTermination() || (FALSE == Result)) {
2506 
2507  //
2508  // Flag to the caller that they're getting nothing
2509  //
2510 
2511  *ByteCount = 0;
2512 
2513  //
2514  // There are three places we could have taken this exception:
2515  // when switching the window (FatExamineFatEntries), adding
2516  // a found run to the Mcb (FatAddMcbEntry), or when writing
2517  // the changes to the FAT (FatSetFatEntry). In the first case
2518  // we don't have anything to unwind before deallocation, and
2519  // can detect this by seeing if we have the ClusterBitmap
2520  // mutex out.
2521 
2522  if (!LockedBitMap) {
2523 
2525 
2526  //
2527  // In these cases, we have the possiblity that the FAT
2528  // window is still in place and we need to clear the bits.
2529  // If the Mcb entry isn't there (we raised trying to add
2530  // it), the effect of trying to remove it is a noop.
2531  //
2532 
2533  if (Window == Vcb->CurrentWindow) {
2534 
2535  //
2536  // Cluster reservation works on cluster 2 based window-relative
2537  // numbers, so we must convert. The subtraction will lose the
2538  // cluster 2 base, so bias the result.
2539  //
2540 
2541  FatUnreserveClusters( IrpContext, Vcb,
2542  (Cluster - Window->FirstCluster) + 2,
2543  ClustersFound );
2544  }
2545 
2546  //
2547  // Note that FatDeallocateDiskSpace will take care of adjusting
2548  // to account for the entries in the Mcb. All we have to account
2549  // for is the last run that didn't make it.
2550  //
2551 
2552  Window->ClustersFree += ClustersFound;
2553  Vcb->AllocationSupport.NumberOfFreeClusters += ClustersFound;
2554 
2556 
2557  FatRemoveMcbEntry( Vcb, Mcb, CurrentVbo, BytesFound );
2558 
2559  } else {
2560 
2561  //
2562  // Just drop the mutex now - we didn't manage to do anything
2563  // that needs to be backed out.
2564  //
2565 
2567  }
2568 
2569  _SEH2_TRY {
2570 
2571  //
2572  // Now we have tidied up, we are ready to just send the Mcb
2573  // off to deallocate disk space
2574  //
2575 
2576  FatDeallocateDiskSpace( IrpContext, Vcb, Mcb, FALSE );
2577 
2578  } _SEH2_FINALLY {
2579 
2580  //
2581  // Now finally (really), remove all the entries from the mcb
2582  //
2583 
2584  FatRemoveMcbEntry( Vcb, Mcb, 0, 0xFFFFFFFF );
2585  } _SEH2_END;
2586  }
2587 
2588  DebugTrace(-1, Dbg, "FatAllocateDiskSpace -> (VOID)\n", 0);
2589 
2590  } _SEH2_END; // finally
2591  }
2592 
2593  return;
2594 }
2595 
2596 
2597 
2598 //
2599 // Limit our zeroing writes to 1 MB.
2600 //
2601 
2602 #define MAX_ZERO_MDL_SIZE (1*1024*1024)
2603 
2604 _Requires_lock_held_(_Global_critical_region_)
2605 VOID
2606 FatDeallocateDiskSpace (
2607  IN PIRP_CONTEXT IrpContext,
2608  IN PVCB Vcb,
2609  IN PLARGE_MCB Mcb,
2611  )
2612 
2613 /*++
2614 
2615 Routine Description:
2616 
2617  This procedure deallocates the disk space denoted by an input
2618  mcb. Note that the input MCB does not need to necessarily describe
2619  a chain that ends with a FAT_CLUSTER_LAST entry.
2620 
2621  Pictorially what is done is the following
2622 
2623  Fat |--a--|--b--|--c--|
2624  Mcb |--a--|--b--|--c--|
2625 
2626  becomes
2627 
2628  Fat |--0--|--0--|--0--|
2629  Mcb |--a--|--b--|--c--|
2630 
2631 Arguments:
2632 
2633  Vcb - Supplies the VCB being modified
2634 
2635  Mcb - Supplies the MCB describing the disk space to deallocate. Note
2636  that Mcb is unchanged by this procedure.
2637 
2638 
2639 Return Value:
2640 
2641  None.
2642 
2643 --*/
2644 
2645 {
2646  LBO Lbo;
2647  VBO Vbo;
2648 
2649  ULONG RunsInMcb;
2650  ULONG ByteCount;
2651  ULONG ClusterCount = 0;
2652  ULONG ClusterIndex = 0;
2653  ULONG McbIndex = 0;
2654 
2655  UCHAR LogOfBytesPerCluster;
2656 
2658 
2659  NTSTATUS ZeroingStatus = STATUS_SUCCESS;
2660 
2661  PAGED_CODE();
2662 
2663  DebugTrace(+1, Dbg, "FatDeallocateDiskSpace\n", 0);
2664  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
2665  DebugTrace( 0, Dbg, " Mcb = %p\n", Mcb);
2666 
2667  LogOfBytesPerCluster = Vcb->AllocationSupport.LogOfBytesPerCluster;
2668 
2669  RunsInMcb = FsRtlNumberOfRunsInLargeMcb( Mcb );
2670 
2671  if ( RunsInMcb == 0 ) {
2672 
2673  DebugTrace(-1, Dbg, "FatDeallocateDiskSpace -> (VOID)\n", 0);
2674  return;
2675  }
2676 
2677  //
2678  // If we are supposed to zero out the allocation before freeing it, do so.
2679  //
2680 
2681  if (ZeroOnDeallocate) {
2682 
2683  _SEH2_TRY {
2684 
2685  PIRP IoIrp;
2686  KEVENT IoEvent;
2688  PVOID Buffer = NULL;
2689  PMDL Mdl;
2690  ULONG ByteCountToZero;
2691  ULONG MdlSizeMapped;
2692 
2693  //
2694  // Issue the writes down for each run in the Mcb
2695  //
2696 
2697  KeInitializeEvent( &IoEvent,
2699  FALSE );
2700 
2701  for ( McbIndex = 0; McbIndex < RunsInMcb; McbIndex++ ) {
2702 
2703  FatGetNextMcbEntry( Vcb, Mcb, McbIndex, &Vbo, &Lbo, &ByteCount );
2704 
2705  //
2706  // Assert that Fat files have no holes.
2707  //
2708 
2709  NT_ASSERT( Lbo != 0 );
2710 
2711  //
2712  // Setup our MDL for the this run.
2713  //
2714 
2715  if (ByteCount > MAX_ZERO_MDL_SIZE) {
2716  Mdl = FatBuildZeroMdl( IrpContext, MAX_ZERO_MDL_SIZE);
2717  } else {
2718  Mdl = FatBuildZeroMdl( IrpContext, ByteCount);
2719  }
2720 
2721  if (!Mdl) {
2722  ZeroingStatus = STATUS_INSUFFICIENT_RESOURCES;
2723  goto try_exit;
2724  }
2725 
2726  _SEH2_TRY {
2727 
2728  //
2729  // Map the MDL.
2730  //
2731 
2732  Buffer = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority|MdlMappingNoExecute);
2733  if (!Buffer) {
2734  NT_ASSERT( FALSE );
2735  ZeroingStatus = STATUS_INSUFFICIENT_RESOURCES;
2736  goto try_exit2;
2737  }
2738 
2739  //
2740  // We might not have not been able to get an MDL big enough to map the whole
2741  // run. In this case, break up the write.
2742  //
2743 
2744  MdlSizeMapped = min( ByteCount, Mdl->ByteCount );
2745  ByteCountToZero = ByteCount;
2746 
2747  //
2748  // Loop until there are no bytes left to write
2749  //
2750 
2751  while (ByteCountToZero != 0) {
2752 
2753  //
2754  // Write zeros to each run.
2755  //
2756 
2757  KeClearEvent( &IoEvent );
2758 
2760  Vcb->TargetDeviceObject,
2761  Buffer,
2762  MdlSizeMapped,
2763  (PLARGE_INTEGER)&Lbo,
2764  &IoEvent,
2765  &Iosb );
2766 
2767  if (IoIrp == NULL) {
2768  NT_ASSERT( FALSE );
2769  ZeroingStatus = STATUS_INSUFFICIENT_RESOURCES;
2770  goto try_exit2;
2771  }
2772 
2773  //
2774  // Set a flag indicating that we want to write through any
2775  // cache on the controller. This eliminates the need for
2776  // an explicit flush-device after the write.
2777  //
2778 
2780 
2781  ZeroingStatus = IoCallDriver( Vcb->TargetDeviceObject, IoIrp );
2782 
2783  if (ZeroingStatus == STATUS_PENDING) {
2784 
2785  (VOID)KeWaitForSingleObject( &IoEvent,
2786  Executive,
2787  KernelMode,
2788  FALSE,
2789  (PLARGE_INTEGER)NULL );
2790 
2791  ZeroingStatus = Iosb.Status;
2792  }
2793 
2794  if (!NT_SUCCESS( ZeroingStatus )) {
2795  NT_ASSERT( FALSE );
2796  goto try_exit2;
2797  }
2798 
2799  //
2800  // Increment the starting offset where we will zero.
2801  //
2802 
2803  Lbo += MdlSizeMapped;
2804 
2805  //
2806  // Decrement ByteCount
2807  //
2808 
2809  ByteCountToZero -= MdlSizeMapped;
2810 
2811  if (ByteCountToZero < MdlSizeMapped) {
2812  MdlSizeMapped = ByteCountToZero;
2813  }
2814 
2815  }
2816 
2817  try_exit2:
2818 
2819  NOTHING;
2820 
2821  } _SEH2_FINALLY {
2822 
2823  if (!FlagOn( Mdl->MdlFlags, MDL_SOURCE_IS_NONPAGED_POOL) &&
2824  FlagOn( Mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA )) {
2825 
2826  MmUnmapLockedPages( Mdl->MappedSystemVa, Mdl );
2827  }
2828  IoFreeMdl( Mdl );
2829  } _SEH2_END;
2830 
2831  }
2832 
2833  try_exit:
2834 
2835  NOTHING;
2836 
2838 
2839  //
2840  // If we failed to zero for some reason, still go ahead and deallocate
2841  // the clusters. Otherwise we'll leak space from the volume.
2842  //
2843 
2844  ZeroingStatus = _SEH2_GetExceptionCode();
2845 
2846  } _SEH2_END;
2847 
2848  }
2849 
2850  NT_ASSERT( NT_SUCCESS(ZeroingStatus) );
2851 
2852  _SEH2_TRY {
2853 
2854  //
2855  // Run though the Mcb, freeing all the runs in the fat.
2856  //
2857  // We do this in two steps (first update the fat, then the bitmap
2858  // (which can't fail)) to prevent other people from taking clusters
2859  // that we need to re-allocate in the event of unwind.
2860  //
2861 
2862  ExAcquireResourceSharedLite(&Vcb->ChangeBitMapResource, TRUE);
2863 
2864  RunsInMcb = FsRtlNumberOfRunsInLargeMcb( Mcb );
2865 
2866  for ( McbIndex = 0; McbIndex < RunsInMcb; McbIndex++ ) {
2867 
2868  FatGetNextMcbEntry( Vcb, Mcb, McbIndex, &Vbo, &Lbo, &ByteCount );
2869 
2870  //
2871  // Assert that Fat files have no holes.
2872  //
2873 
2874  NT_ASSERT( Lbo != 0 );
2875 
2876  //
2877  // Write FAT_CLUSTER_AVAILABLE to each cluster in the run.
2878  //
2879 
2880  if (ByteCount == 0xFFFFFFFF) {
2881 
2882  //
2883  // Special case the computation of ClusterCout
2884  // when file is of max size (4GiB - 1).
2885  //
2886 
2887  ClusterCount = (1 << (32 - LogOfBytesPerCluster));
2888 
2889  } else {
2890 
2891  ClusterCount = ByteCount >> LogOfBytesPerCluster;
2892  }
2893 
2894  ClusterIndex = FatGetIndexFromLbo( Vcb, Lbo );
2895 
2896  FatFreeClusters( IrpContext, Vcb, ClusterIndex, ClusterCount );
2897  }
2898 
2899  //
2900  // From now on, nothing can go wrong .... (as in raise)
2901  //
2902 
2904 
2905  for ( McbIndex = 0; McbIndex < RunsInMcb; McbIndex++ ) {
2906 
2907  ULONG ClusterEnd;
2908  ULONG MyStart, MyLength, count;
2909 #if DBG
2910 #ifndef __REACTOS__
2911  ULONG PreviousClear = 0;
2912 #endif
2913  ULONG i = 0;
2914 #endif
2915 
2916  FatGetNextMcbEntry( Vcb, Mcb, McbIndex, &Vbo, &Lbo, &ByteCount );
2917 
2918  //
2919  // Mark the bits clear in the FreeClusterBitMap.
2920  //
2921 
2922  if (ByteCount == 0xFFFFFFFF) {
2923 
2924  //
2925  // Special case the computation of ClusterCout
2926  // when file is of max size (2^32 - 1).
2927  //
2928 
2929  ClusterCount = (1 << (32 - LogOfBytesPerCluster));
2930 
2931  } else {
2932 
2933  ClusterCount = ByteCount >> LogOfBytesPerCluster;
2934  }
2935 
2936  ClusterIndex = FatGetIndexFromLbo( Vcb, Lbo );
2937 
2938  Window = Vcb->CurrentWindow;
2939 
2940  //
2941  // If we've divided the bitmap, elide bitmap manipulation for
2942  // runs that are outside the current bucket.
2943  //
2944 
2945  ClusterEnd = ClusterIndex + ClusterCount - 1;
2946 
2947  if (!(ClusterIndex > Window->LastCluster ||
2948  ClusterEnd < Window->FirstCluster)) {
2949 
2950  //
2951  // The run being freed overlaps the current bucket, so we'll
2952  // have to clear some bits.
2953  //
2954 
2955  if (ClusterIndex < Window->FirstCluster &&
2956  ClusterEnd > Window->LastCluster) {
2957 
2958  MyStart = Window->FirstCluster;
2959  MyLength = Window->LastCluster - Window->FirstCluster + 1;
2960 
2961  } else if (ClusterIndex < Window->FirstCluster) {
2962 
2963  MyStart = Window->FirstCluster;
2964  MyLength = ClusterEnd - Window->FirstCluster + 1;
2965 
2966  } else {
2967 
2968  //
2969  // The range being freed starts in the bucket, and may possibly
2970  // extend beyond the bucket.
2971  //
2972 
2973  MyStart = ClusterIndex;
2974 
2975  if (ClusterEnd <= Window->LastCluster) {
2976 
2977  MyLength = ClusterCount;
2978 
2979  } else {
2980 
2981  MyLength = Window->LastCluster - ClusterIndex + 1;
2982  }
2983  }
2984 
2985  if (MyLength == 0) {
2986 
2987  continue;
2988  }
2989 
2990 #if DBG
2991 #ifndef __REACTOS__
2992 #ifdef _MSC_VER
2993 #pragma prefast( suppress:28931, "this is DBG build only" )
2994 #endif
2995  PreviousClear = RtlNumberOfClearBits( &Vcb->FreeClusterBitMap );
2996 #endif
2997 
2998 
2999  //
3000  // Verify that the Bits are all really set.
3001  //
3002 
3003  NT_ASSERT( MyStart + MyLength - Window->FirstCluster <= Vcb->FreeClusterBitMap.SizeOfBitMap );
3004 
3005  for (i = 0; i < MyLength; i++) {
3006 
3007  NT_ASSERT( RtlCheckBit(&Vcb->FreeClusterBitMap,
3008  MyStart - Window->FirstCluster + i) == 1 );
3009  }
3010 #endif // DBG
3011 
3012  FatUnreserveClusters( IrpContext, Vcb,
3013  MyStart - Window->FirstCluster + 2,
3014  MyLength );
3015  }
3016 
3017  //
3018  // Adjust the ClustersFree count for each bitmap window, even the ones
3019  // that are not the current window.
3020  //
3021 
3022  if (FatIsFat32(Vcb)) {
3023 
3024  Window = &Vcb->Windows[FatWindowOfCluster( ClusterIndex )];
3025 
3026  } else {
3027 
3028  Window = &Vcb->Windows[0];
3029  }
3030 
3031  MyStart = ClusterIndex;
3032 
3033  for (MyLength = ClusterCount; MyLength > 0; MyLength -= count) {
3034 
3035  count = FatMin(Window->LastCluster - MyStart + 1, MyLength);
3036  Window->ClustersFree += count;
3037 
3038  //
3039  // If this was not the last window this allocation spanned,
3040  // advance to the next.
3041  //
3042 
3043  if (MyLength != count) {
3044 
3045  Window++;
3046  MyStart = Window->FirstCluster;
3047  }
3048  }
3049 
3050  //
3051  // Deallocation is now complete. Adjust the free cluster count.
3052  //
3053 
3054  Vcb->AllocationSupport.NumberOfFreeClusters += ClusterCount;
3055  }
3056 
3057 #if DBG
3058  if (Vcb->CurrentWindow->ClustersFree !=
3059  RtlNumberOfClearBits(&Vcb->FreeClusterBitMap)) {
3060 
3061  DbgPrint("%x vs %x\n", Vcb->CurrentWindow->ClustersFree,
3062  RtlNumberOfClearBits(&Vcb->FreeClusterBitMap));
3063 
3064  DbgPrint("%x for %x\n", ClusterIndex, ClusterCount);
3065  }
3066 #endif
3067 
3069 
3070 
3071  } _SEH2_FINALLY {
3072 
3073  DebugUnwind( FatDeallocateDiskSpace );
3074 
3075  //
3076  // Is there any unwinding to do?
3077  //
3078 
3079  ExReleaseResourceLite(&Vcb->ChangeBitMapResource);
3080 
3081  if ( _SEH2_AbnormalTermination() ) {
3082 
3083  LBO LocalLbo;
3084  VBO LocalVbo;
3085 
3086  ULONG Index;
3087  ULONG Clusters;
3088  ULONG FatIndex;
3089  ULONG PriorLastIndex;
3090 
3091  //
3092  // For each entry we already deallocated, reallocate it,
3093  // chaining together as nessecary. Note that we continue
3094  // up to and including the last "for" iteration even though
3095  // the SetFatRun could not have been successful. This
3096  // allows us a convienent way to re-link the final successful
3097  // SetFatRun.
3098  //
3099  // It is possible that the reason we got here will prevent us
3100  // from succeeding in this operation.
3101  //
3102 
3103  PriorLastIndex = 0;
3104 
3105  for (Index = 0; Index <= McbIndex; Index++) {
3106 
3107  FatGetNextMcbEntry(Vcb, Mcb, Index, &LocalVbo, &LocalLbo, &ByteCount);
3108 
3109  if (ByteCount == 0xFFFFFFFF) {
3110 
3111  //
3112  // Special case the computation of ClusterCout
3113  // when file is of max size (2^32 - 1).
3114  //
3115 
3116  Clusters = (1 << (32 - LogOfBytesPerCluster));
3117 
3118  } else {
3119 
3120  Clusters = ByteCount >> LogOfBytesPerCluster;
3121  }
3122 
3123  FatIndex = FatGetIndexFromLbo( Vcb, LocalLbo );
3124 
3125  //
3126  // We must always restore the prior iteration's last
3127  // entry, pointing it to the first cluster of this run.
3128  //
3129 
3130  if (PriorLastIndex != 0) {
3131 
3132  FatSetFatEntry( IrpContext,
3133  Vcb,
3134  PriorLastIndex,
3135  (FAT_ENTRY)FatIndex );
3136  }
3137 
3138  //
3139  // If this is not the last entry (the one that failed)
3140  // then reallocate the disk space on the fat.
3141  //
3142 
3143  if ( Index < McbIndex ) {
3144 
3145  FatAllocateClusters(IrpContext, Vcb, FatIndex, Clusters);
3146 
3147  PriorLastIndex = FatIndex + Clusters - 1;
3148  }
3149  }
3150  }
3151 
3152  DebugTrace(-1, Dbg, "FatDeallocateDiskSpace -> (VOID)\n", 0);
3153  } _SEH2_END;
3154 
3155  return;
3156 }
3157 
3158 
3159 _Requires_lock_held_(_Global_critical_region_)
3160 VOID
3161 FatSplitAllocation (
3162  IN PIRP_CONTEXT IrpContext,
3163  IN PVCB Vcb,
3164  IN OUT PLARGE_MCB Mcb,
3165  IN VBO SplitAtVbo,
3167  )
3168 
3169 /*++
3170 
3171 Routine Description:
3172 
3173  This procedure takes a single mcb and splits its allocation into
3174  two separate allocation units. The separation must only be done
3175  on cluster boundaries, otherwise we bugcheck.
3176 
3177  On the disk this actually works by inserting a FAT_CLUSTER_LAST into
3178  the last index of the first part being split out.
3179 
3180  Pictorially what is done is the following (where ! denotes the end of
3181  the fat chain (i.e., FAT_CLUSTER_LAST)):
3182 
3183 
3184  Mcb |--a--|--b--|--c--|--d--|--e--|--f--|
3185 
3186  ^
3187  SplitAtVbo ---------------------+
3188 
3189  RemainingMcb (empty)
3190 
3191  becomes
3192 
3193  Mcb |--a--|--b--|--c--!
3194 
3195 
3196  RemainingMcb |--d--|--e--|--f--|
3197 
3198 Arguments:
3199 
3200  Vcb - Supplies the VCB being modified
3201 
3202  Mcb - Supplies the MCB describing the allocation being split into
3203  two parts. Upon return this Mcb now contains the first chain.
3204 
3205  SplitAtVbo - Supplies the VBO of the first byte for the second chain
3206  that we creating.
3207 
3208  RemainingMcb - Receives the MCB describing the second chain of allocated
3209  disk space. The caller passes in an initialized Mcb that
3210  is filled in by this procedure STARTING AT VBO 0.
3211 
3212 Return Value:
3213 
3214  VOID - TRUE if the operation completed and FALSE if it had to
3215  block but could not.
3216 
3217 --*/
3218 
3219 {
3220  VBO SourceVbo;
3221  VBO TargetVbo;
3222  VBO DontCare;
3223 
3224  LBO Lbo;
3225 
3226  ULONG ByteCount;
3227 
3228 #if DBG
3229  ULONG BytesPerCluster;
3230 #endif
3231 
3232  PAGED_CODE();
3233 
3234  DebugTrace(+1, Dbg, "FatSplitAllocation\n", 0);
3235  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
3236  DebugTrace( 0, Dbg, " Mcb = %p\n", Mcb);
3237  DebugTrace( 0, Dbg, " SplitAtVbo = %8lx\n", SplitAtVbo);
3238  DebugTrace( 0, Dbg, " RemainingMcb = %p\n", RemainingMcb);
3239 
3240 #if DBG
3241  BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
3242 #endif
3243 
3244  //
3245  // Assert that the split point is cluster alligned
3246  //
3247 
3248  NT_ASSERT( (SplitAtVbo & (BytesPerCluster - 1)) == 0 );
3249 
3250  //
3251  // We should never be handed an empty source MCB and asked to split
3252  // at a non zero point.
3253  //
3254 
3255  NT_ASSERT( !((0 != SplitAtVbo) && (0 == FsRtlNumberOfRunsInLargeMcb( Mcb))));
3256 
3257  //
3258  // Assert we were given an empty target Mcb.
3259  //
3260 
3261  //
3262  // This assert is commented out to avoid hitting in the Ea error
3263  // path. In that case we will be using the same Mcb's to split the
3264  // allocation that we used to merge them. The target Mcb will contain
3265  // the runs that the split will attempt to insert.
3266  //
3267  //
3268  // NT_ASSERT( FsRtlNumberOfRunsInMcb( RemainingMcb ) == 0 );
3269  //
3270 
3271  _SEH2_TRY {
3272 
3273  //
3274  // Move the runs after SplitAtVbo from the souce to the target
3275  //
3276 
3277  SourceVbo = SplitAtVbo;
3278  TargetVbo = 0;
3279 
3280  while (FatLookupMcbEntry(Vcb, Mcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
3281 
3282  FatAddMcbEntry( Vcb, RemainingMcb, TargetVbo, Lbo, ByteCount );
3283 
3284  FatRemoveMcbEntry( Vcb, Mcb, SourceVbo, ByteCount );
3285 
3286  TargetVbo += ByteCount;
3287  SourceVbo += ByteCount;
3288 
3289  //
3290  // If SourceVbo overflows, we were actually snipping off the end
3291  // of the maximal file ... and are now done.
3292  //
3293 
3294  if (SourceVbo == 0) {
3295 
3296  break;
3297  }
3298  }
3299 
3300  //
3301  // Mark the last pre-split cluster as a FAT_LAST_CLUSTER
3302  //
3303 
3304  if ( SplitAtVbo != 0 ) {
3305 
3306  FatLookupLastMcbEntry( Vcb, Mcb, &DontCare, &Lbo, NULL );
3307 
3308  FatSetFatEntry( IrpContext,
3309  Vcb,
3311  FAT_CLUSTER_LAST );
3312  }
3313 
3314  } _SEH2_FINALLY {
3315 
3316  DebugUnwind( FatSplitAllocation );
3317 
3318  //
3319  // If we got an exception, we must glue back together the Mcbs
3320  //
3321 
3322  if ( _SEH2_AbnormalTermination() ) {
3323 
3324  TargetVbo = SplitAtVbo;
3325  SourceVbo = 0;
3326 
3327  while (FatLookupMcbEntry(Vcb, RemainingMcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
3328 
3329  FatAddMcbEntry( Vcb, Mcb, TargetVbo, Lbo, ByteCount );
3330 
3331  FatRemoveMcbEntry( Vcb, RemainingMcb, SourceVbo, ByteCount );
3332 
3333  TargetVbo += ByteCount;
3334  SourceVbo += ByteCount;
3335  }
3336  }
3337 
3338  DebugTrace(-1, Dbg, "FatSplitAllocation -> (VOID)\n", 0);
3339  } _SEH2_END;
3340 
3341  return;
3342 }
3343 
3344 
3345 _Requires_lock_held_(_Global_critical_region_)
3346 VOID
3347 FatMergeAllocation (
3348  IN PIRP_CONTEXT IrpContext,
3349  IN PVCB Vcb,
3350  IN OUT PLARGE_MCB Mcb,
3352  )
3353 
3354 /*++
3355 
3356 Routine Description:
3357 
3358  This routine takes two separate allocations described by two MCBs and
3359  joins them together into one allocation.
3360 
3361  Pictorially what is done is the following (where ! denotes the end of
3362  the fat chain (i.e., FAT_CLUSTER_LAST)):
3363 
3364 
3365  Mcb |--a--|--b--|--c--!
3366 
3367  SecondMcb |--d--|--e--|--f--|
3368 
3369  becomes
3370 
3371  Mcb |--a--|--b--|--c--|--d--|--e--|--f--|
3372 
3373  SecondMcb |--d--|--e--|--f--|
3374 
3375 
3376 Arguments:
3377 
3378  Vcb - Supplies the VCB being modified
3379 
3380  Mcb - Supplies the MCB of the first allocation that is being modified.
3381  Upon return this Mcb will also describe the newly enlarged
3382  allocation
3383 
3384  SecondMcb - Supplies the ZERO VBO BASED MCB of the second allocation
3385  that is being appended to the first allocation. This
3386  procedure leaves SecondMcb unchanged.
3387 
3388 Return Value:
3389 
3390  VOID - TRUE if the operation completed and FALSE if it had to
3391  block but could not.
3392 
3393 --*/
3394 
3395 {
3396  VBO SpliceVbo = 0;
3397  LBO SpliceLbo;
3398 
3399  VBO SourceVbo;
3400  VBO TargetVbo = 0;
3401 
3402  LBO Lbo;
3403 
3404  ULONG ByteCount;
3405 
3406  PAGED_CODE();
3407 
3408  DebugTrace(+1, Dbg, "FatMergeAllocation\n", 0);
3409  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
3410  DebugTrace( 0, Dbg, " Mcb = %p\n", Mcb);
3411  DebugTrace( 0, Dbg, " SecondMcb = %p\n", SecondMcb);
3412 
3413  _SEH2_TRY {
3414 
3415  //
3416  // Append the runs from SecondMcb to Mcb
3417  //
3418 
3419  (void)FatLookupLastMcbEntry( Vcb, Mcb, &SpliceVbo, &SpliceLbo, NULL );
3420 
3421  SourceVbo = 0;
3422  TargetVbo = SpliceVbo + 1;
3423 
3424  while (FatLookupMcbEntry(Vcb, SecondMcb, SourceVbo, &Lbo, &ByteCount, NULL)) {
3425 
3426  FatAddMcbEntry( Vcb, Mcb, TargetVbo, Lbo, ByteCount );
3427 
3428  SourceVbo += ByteCount;
3429  TargetVbo += ByteCount;
3430  }
3431 
3432  //
3433  // Link the last pre-merge cluster to the first cluster of SecondMcb
3434  //
3435 
3437 
3438  FatSetFatEntry( IrpContext,
3439  Vcb,
3440  FatGetIndexFromLbo( Vcb, SpliceLbo ),
3442 
3443  } _SEH2_FINALLY {
3444 
3445  DebugUnwind( FatMergeAllocation );
3446 
3447  //
3448  // If we got an exception, we must remove the runs added to Mcb
3449  //
3450 
3451  if ( _SEH2_AbnormalTermination() ) {
3452 
3453  ULONG CutLength;
3454 
3455  if ((CutLength = TargetVbo - (SpliceVbo + 1)) != 0) {
3456 
3457  FatRemoveMcbEntry( Vcb, Mcb, SpliceVbo + 1, CutLength);
3458  }
3459  }
3460 
3461  DebugTrace(-1, Dbg, "FatMergeAllocation -> (VOID)\n", 0);
3462  } _SEH2_END;
3463 
3464  return;
3465 }
3466 
3467 
3468 //
3469 // Internal support routine
3470 //
3471 
3474  IN PVCB Vcb,
3476  )
3477 
3478 /*++
3479 
3480 Routine Description:
3481 
3482  This procedure tells the caller how to interpret the input fat table
3483  entry. It will indicate if the fat cluster is available, resereved,
3484  bad, the last one, or the another fat index. This procedure can deal
3485  with both 12 and 16 bit fat.
3486 
3487 Arguments:
3488 
3489  Vcb - Supplies the Vcb to examine, yields 12/16 bit info
3490 
3491  Entry - Supplies the fat entry to examine
3492 
3493 Return Value:
3494 
3495  CLUSTER_TYPE - Is the type of the input Fat entry
3496 
3497 --*/
3498 
3499 {
3500  DebugTrace(+1, Dbg, "InterpretClusterType\n", 0);
3501  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
3502  DebugTrace( 0, Dbg, " Entry = %8lx\n", Entry);
3503 
3504  PAGED_CODE();
3505 
3506  switch(Vcb->AllocationSupport.FatIndexBitSize ) {
3507  case 32:
3509  break;
3510 
3511  case 12:
3512  NT_ASSERT( Entry <= 0xfff );
3513  if (Entry >= 0x0ff0) {
3514  Entry |= 0x0FFFF000;
3515  }
3516  break;
3517 
3518  default:
3519  case 16:
3520  NT_ASSERT( Entry <= 0xffff );
3521  if (Entry >= 0x0fff0) {
3522  Entry |= 0x0FFF0000;
3523  }
3524  break;
3525  }
3526 
3527  if (Entry == FAT_CLUSTER_AVAILABLE) {
3528 
3529  DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterAvailable\n", 0);
3530 
3531  return FatClusterAvailable;
3532 
3533  } else if (Entry < FAT_CLUSTER_RESERVED) {
3534 
3535  DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterNext\n", 0);
3536 
3537  return FatClusterNext;
3538 
3539  } else if (Entry < FAT_CLUSTER_BAD) {
3540 
3541  DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterReserved\n", 0);
3542 
3543  return FatClusterReserved;
3544 
3545  } else if (Entry == FAT_CLUSTER_BAD) {
3546 
3547  DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterBad\n", 0);
3548 
3549  return FatClusterBad;
3550 
3551  } else {
3552 
3553  DebugTrace(-1, Dbg, "FatInterpretClusterType -> FatClusterLast\n", 0);
3554 
3555  return FatClusterLast;
3556  }
3557 }
3558 
3559 
3560 //
3561 // Internal support routine
3562 //
3563 
3564 VOID
3566  IN PIRP_CONTEXT IrpContext,
3567  IN PVCB Vcb,
3568  IN ULONG FatIndex,
3571  )
3572 
3573 /*++
3574 
3575 Routine Description:
3576 
3577  This routine takes an index into the fat and gives back the value
3578  in the Fat at this index. At any given time, for a 16 bit fat, this
3579  routine allows only one page per volume of the fat to be pinned in
3580  memory. For a 12 bit bit fat, the entire fat (max 6k) is pinned. This
3581  extra layer of caching makes the vast majority of requests very
3582  fast. The context for this caching stored in a structure in the Vcb.
3583 
3584 Arguments:
3585 
3586  Vcb - Supplies the Vcb to examine, yields 12/16 bit info,
3587  fat access context, etc.
3588 
3589  FatIndex - Supplies the fat index to examine.
3590 
3591  FatEntry - Receives the fat entry pointed to by FatIndex. Note that
3592  it must point to non-paged pool.
3593 
3594  Context - This structure keeps track of a page of pinned fat between calls.
3595 
3596 --*/
3597 
3598 {
3599  PAGED_CODE();
3600 
3601  DebugTrace(+1, Dbg, "FatLookupFatEntry\n", 0);
3602  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
3603  DebugTrace( 0, Dbg, " FatIndex = %4x\n", FatIndex);
3604  DebugTrace( 0, Dbg, " FatEntry = %8lx\n", FatEntry);
3605 
3606  //
3607  // Make sure they gave us a valid fat index.
3608  //
3609 
3610  FatVerifyIndexIsValid(IrpContext, Vcb, FatIndex);
3611 
3612  //
3613  // Case on 12 or 16 bit fats.
3614  //
3615  // In the 12 bit case (mostly floppies) we always have the whole fat
3616  // (max 6k bytes) pinned during allocation operations. This is possibly
3617  // a wee bit slower, but saves headaches over fat entries with 8 bits
3618  // on one page, and 4 bits on the next.
3619  //
3620  // The 16 bit case always keeps the last used page pinned until all
3621  // operations are done and it is unpinned.
3622  //
3623 
3624  //
3625  // DEAL WITH 12 BIT CASE
3626  //
3627 
3628  if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
3629 
3630  //
3631  // Check to see if the fat is already pinned, otherwise pin it.
3632  //
3633 
3634  if (Context->Bcb == NULL) {
3635 
3636  FatReadVolumeFile( IrpContext,
3637  Vcb,
3638  FatReservedBytes( &Vcb->Bpb ),
3639  FatBytesPerFat( &Vcb->Bpb ),
3640  &Context->Bcb,
3641  &Context->PinnedPage );
3642  }
3643 
3644  //
3645  // Load the return value.
3646  //
3647 
3648 
3649  FatLookup12BitEntry( Context->PinnedPage, FatIndex, FatEntry );
3650 
3651  } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
3652 
3653  //
3654  // DEAL WITH 32 BIT CASE
3655  //
3656 
3657  ULONG PageEntryOffset;
3658  ULONG OffsetIntoVolumeFile;
3659 
3660  //
3661  // Initialize two local variables that help us.
3662  //
3663  OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(FAT_ENTRY);
3664  PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(FAT_ENTRY);
3665 
3666  //
3667  // Check to see if we need to read in a new page of fat
3668  //
3669 
3670  if ((Context->Bcb == NULL) ||
3671  (OffsetIntoVolumeFile / PAGE_SIZE != Context->VboOfPinnedPage / PAGE_SIZE)) {
3672 
3673  //
3674  // The entry wasn't in the pinned page, so must we unpin the current
3675  // page (if any) and read in a new page.
3676  //
3677 
3678  FatUnpinBcb( IrpContext, Context->Bcb );
3679 
3680  FatReadVolumeFile( IrpContext,
3681  Vcb,
3682  OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
3683  PAGE_SIZE,
3684  &Context->Bcb,
3685  &Context->PinnedPage );
3686 
3687  Context->VboOfPinnedPage = OffsetIntoVolumeFile & ~(PAGE_SIZE - 1);
3688  }
3689 
3690  //
3691  // Grab the fat entry from the pinned page, and return
3692  //
3693 
3694  *FatEntry = ((PULONG)(Context->PinnedPage))[PageEntryOffset] & FAT32_ENTRY_MASK;
3695 
3696  } else {
3697 
3698  //
3699  // DEAL WITH 16 BIT CASE
3700  //
3701 
3702  ULONG PageEntryOffset;
3703  ULONG OffsetIntoVolumeFile;
3704 
3705  //
3706  // Initialize two local variables that help us.
3707  //
3708 
3709  OffsetIntoVolumeFile = FatReservedBytes(&Vcb->Bpb) + FatIndex * sizeof(USHORT);
3710  PageEntryOffset = (OffsetIntoVolumeFile % PAGE_SIZE) / sizeof(USHORT);
3711 
3712  //
3713  // Check to see if we need to read in a new page of fat
3714  //
3715 
3716  if ((Context->Bcb == NULL) ||
3717  (OffsetIntoVolumeFile / PAGE_SIZE != Context->VboOfPinnedPage / PAGE_SIZE)) {
3718 
3719  //
3720  // The entry wasn't in the pinned page, so must we unpin the current
3721  // page (if any) and read in a new page.
3722  //
3723 
3724  FatUnpinBcb( IrpContext, Context->Bcb );
3725 
3726  FatReadVolumeFile( IrpContext,
3727  Vcb,
3728  OffsetIntoVolumeFile & ~(PAGE_SIZE - 1),
3729  PAGE_SIZE,
3730  &Context->Bcb,
3731  &Context->PinnedPage );
3732 
3733  Context->VboOfPinnedPage = OffsetIntoVolumeFile & ~(PAGE_SIZE - 1);
3734  }
3735 
3736  //
3737  // Grab the fat entry from the pinned page, and return
3738  //
3739 
3740  *FatEntry = ((PUSHORT)(Context->PinnedPage))[PageEntryOffset];
3741  }
3742 
3743  DebugTrace(-1, Dbg, "FatLookupFatEntry -> (VOID)\n", 0);
3744  return;
3745 }
3746 
3747 
3748 _Requires_lock_held_(_Global_critical_region_)
3749 VOID
3750 FatSetFatEntry (
3751  IN PIRP_CONTEXT IrpContext,
3752  IN PVCB Vcb,
3753  IN ULONG FatIndex,
3755  )
3756 
3757 /*++
3758 
3759 Routine Description:
3760 
3761  This routine takes an index into the fat and puts a value in the Fat
3762  at this index. The routine special cases 12, 16 and 32 bit fats. In
3763  all cases we go to the cache manager for a piece of the fat.
3764 
3765  We have a special form of this call for setting the DOS-style dirty bit.
3766  Unlike the dirty bit in the boot sector, we do not go to special effort
3767  to make sure that this hits the disk synchronously - if the system goes
3768  down in the window between the dirty bit being set in the boot sector
3769  and the FAT index zero dirty bit being lazy written, then life is tough.
3770 
3771  The only possible scenario is that Win9x may see what it thinks is a clean
3772  volume that really isn't (hopefully Memphis will pay attention to our dirty
3773  bit as well). The dirty bit will get out quickly, and if heavy activity is
3774  occurring, then the dirty bit should actually be there virtually all of the
3775  time since the act of cleaning the volume is the "rare" occurance.
3776 
3777  There are synchronization concerns that would crop up if we tried to make
3778  this synchronous. This thread may already own the Bcb shared for the first
3779  sector of the FAT (so we can't get it exclusive for a writethrough). This
3780  would require some more serious replumbing to work around than I want to
3781  consider at this time.
3782 
3783  We can and do, however, synchronously set the bit clean.
3784 
3785  At this point the reader should understand why the NT dirty bit is where it is.
3786 
3787 Arguments:
3788 
3789  Vcb - Supplies the Vcb to examine, yields 12/16/32 bit info, etc.
3790 
3791  FatIndex - Supplies the destination fat index.
3792 
3793  FatEntry - Supplies the source fat entry.
3794 
3795 --*/
3796 
3797 {
3798  LBO Lbo;
3799  PBCB Bcb = NULL;
3800  ULONG SectorSize;
3801  ULONG OffsetIntoVolumeFile;
3802  ULONG WasWait = TRUE;
3803  BOOLEAN RegularOperation = TRUE;
3804  BOOLEAN CleaningOperation = FALSE;
3806 
3807  PAGED_CODE();
3808 
3809  DebugTrace(+1, Dbg, "FatSetFatEntry\n", 0);
3810  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
3811  DebugTrace( 0, Dbg, " FatIndex = %4x\n", FatIndex);
3812  DebugTrace( 0, Dbg, " FatEntry = %4x\n", FatEntry);
3813 
3814  //
3815  // Make sure they gave us a valid fat index if this isn't the special
3816  // clean-bit modifying call.
3817  //
3818 
3819  if (FatIndex == FAT_DIRTY_BIT_INDEX) {
3820 
3821  //
3822  // We are setting the clean bit state. Of course, we could
3823  // have corruption that would cause us to try to fiddle the
3824  // reserved index - we guard against this by having the
3825  // special entry values use the reserved high 4 bits that
3826  // we know that we'll never try to set.
3827  //
3828 
3829  //
3830  // We don't want to repin the FAT pages involved here. Just
3831  // let the lazy writer hit them when it can.
3832  //
3833 
3834  RegularOperation = FALSE;
3835 
3836  switch (FatEntry) {
3837  case FAT_CLEAN_VOLUME:
3839  CleaningOperation = TRUE;
3840  break;
3841 
3842  case FAT_DIRTY_VOLUME:
3843  switch (Vcb->AllocationSupport.FatIndexBitSize) {
3844  case 12:
3846  break;
3847 
3848  case 32:
3850  break;
3851 
3852  default:
3854  break;
3855  }
3856  break;
3857 
3858  default:
3860  break;
3861  }
3862 
3863  //
3864  // Disable dirtying semantics for the duration of this operation. Force this
3865  // operation to wait for the duration.
3866  //
3867 
3868  WasWait = FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
3870 
3871  } else {
3872 
3874  FatVerifyIndexIsValid(IrpContext, Vcb, FatIndex);
3875  }
3876 
3877  //
3878  // Set Sector Size
3879  //
3880 
3881  SectorSize = 1 << Vcb->AllocationSupport.LogOfBytesPerSector;
3882 
3883  //
3884  // Case on 12 or 16 bit fats.
3885  //
3886  // In the 12 bit case (mostly floppies) we always have the whole fat
3887  // (max 6k bytes) pinned during allocation operations. This is possibly
3888  // a wee bit slower, but saves headaches over fat entries with 8 bits
3889  // on one page, and 4 bits on the next.
3890  //
3891  // In the 16 bit case we only read the page that we need to set the fat
3892  // entry.
3893  //
3894 
3895  //
3896  // DEAL WITH 12 BIT CASE
3897  //
3898 
3899  _SEH2_TRY {
3900 
3901  if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
3902 
3903  PVOID PinnedFat;
3904 
3905  //
3906  // Make sure we have a valid entry
3907  //
3908 
3909  FatEntry &= 0xfff;
3910 
3911  //
3912  // We read in the entire fat. Note that using prepare write marks
3913  // the bcb pre-dirty, so we don't have to do it explicitly.
3914  //
3915 
3916  OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) + FatIndex * 3 / 2;
3917 
3918  FatPrepareWriteVolumeFile( IrpContext,
3919  Vcb,
3920  FatReservedBytes( &Vcb->Bpb ),
3921  FatBytesPerFat( &Vcb->Bpb ),
3922  &Bcb,
3923  &PinnedFat,
3924  RegularOperation,
3925  FALSE );
3926 
3927  //
3928  // Mark the sector(s) dirty in the DirtyFatMcb. This call is
3929  // complicated somewhat for the 12 bit case since a single
3930  // entry write can span two sectors (and pages).
3931  //
3932  // Get the Lbo for the sector where the entry starts, and add it to
3933  // the dirty fat Mcb.
3934  //
3935 
3936  Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
3937 
3938  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
3939 
3940  //
3941  // If the entry started on the last byte of the sector, it continues
3942  // to the next sector, so mark the next sector dirty as well.
3943  //
3944  // Note that this entry will simply coalese with the last entry,
3945  // so this operation cannot fail. Also if we get this far, we have
3946  // made it, so no unwinding will be needed.
3947  //
3948 
3949  if ( (OffsetIntoVolumeFile & (SectorSize - 1)) == (SectorSize - 1) ) {
3950 
3951  Lbo += SectorSize;
3952 
3953  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
3954  }
3955 
3956  //
3957  // Store the entry into the fat; we need a little synchonization
3958  // here and can't use a spinlock since the bytes might not be
3959  // resident.
3960  //
3961 
3963  ReleaseMutex = TRUE;
3964 
3965  FatSet12BitEntry( PinnedFat, FatIndex, FatEntry );
3966 
3968  ReleaseMutex = FALSE;
3969 
3970  } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
3971 
3972  //
3973  // DEAL WITH 32 BIT CASE
3974  //
3975 
3976  PULONG PinnedFatEntry32;
3977 
3978  //
3979  // Read in a new page of fat
3980  //
3981 
3982  OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) +
3983  FatIndex * sizeof( FAT_ENTRY );
3984 
3985  FatPrepareWriteVolumeFile( IrpContext,
3986  Vcb,
3987  OffsetIntoVolumeFile,
3988  sizeof(FAT_ENTRY),
3989  &Bcb,
3990  (PVOID *)&PinnedFatEntry32,
3991  RegularOperation,
3992  FALSE );
3993  //
3994  // Mark the sector dirty in the DirtyFatMcb
3995  //
3996 
3997  Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
3998 
3999  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
4000 
4001  //
4002  // Store the FatEntry to the pinned page.
4003  //
4004  // Preserve the reserved bits in FAT32 entries in the file heap.
4005  //
4006 
4007 #ifdef ALPHA
4009  ReleaseMutex = TRUE;
4010 #endif // ALPHA
4011 
4012  if (FatIndex != FAT_DIRTY_BIT_INDEX) {
4013 
4014  *PinnedFatEntry32 = ((*PinnedFatEntry32 & ~FAT32_ENTRY_MASK) | FatEntry);
4015 
4016  } else {
4017 
4018  *PinnedFatEntry32 = FatEntry;
4019  }
4020 
4021 #ifdef ALPHA
4023  ReleaseMutex = FALSE;
4024 #endif // ALPHA
4025 
4026  } else {
4027 
4028  //
4029  // DEAL WITH 16 BIT CASE
4030  //
4031 
4032  PUSHORT PinnedFatEntry;
4033 
4034  //
4035  // Read in a new page of fat
4036  //
4037 
4038  OffsetIntoVolumeFile = FatReservedBytes( &Vcb->Bpb ) +
4039  FatIndex * sizeof(USHORT);
4040 
4041  FatPrepareWriteVolumeFile( IrpContext,
4042  Vcb,
4043  OffsetIntoVolumeFile,
4044  sizeof(USHORT),
4045  &Bcb,
4046  (PVOID *)&PinnedFatEntry,
4047  RegularOperation,
4048  FALSE );
4049  //
4050  // Mark the sector dirty in the DirtyFatMcb
4051  //
4052 
4053  Lbo = OffsetIntoVolumeFile & ~(SectorSize - 1);
4054 
4055  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize);
4056 
4057  //
4058  // Store the FatEntry to the pinned page.
4059  //
4060  // We need extra synchronization here for broken architectures
4061  // like the ALPHA that don't support atomic 16 bit writes.
4062  //
4063 
4064 #ifdef ALPHA
4066  ReleaseMutex = TRUE;
4067 #endif // ALPHA
4068 
4069  *PinnedFatEntry = (USHORT)FatEntry;
4070 
4071 #ifdef ALPHA
4073  ReleaseMutex = FALSE;
4074 #endif // ALPHA
4075  }
4076 
4077  } _SEH2_FINALLY {
4078 
4079  DebugUnwind( FatSetFatEntry );
4080 
4081  //
4082  // Re-enable volume dirtying in case this was a dirty bit operation.
4083  //
4084 
4085  ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_DIRTY );
4086 
4087  //
4088  // Make this operation asynchronous again if needed.
4089  //
4090 
4091  if (!WasWait) {
4092 
4093  ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
4094  }
4095 
4096  //
4097  // If we still somehow have the Mutex, release it.
4098  //
4099 
4100  if (ReleaseMutex) {
4101 
4103 
4105  }
4106 
4107  //
4108  // Unpin the Bcb. For cleaning operations or if the corruption was detected while mounting we make this write-through.
4109  //
4110 
4111  if ((CleaningOperation ||
4113  Bcb) {
4114 
4115  IO_STATUS_BLOCK IgnoreStatus;
4116 
4117  CcRepinBcb( Bcb );
4118  CcUnpinData( Bcb );
4119  DbgDoit( IrpContext->PinCount -= 1 );
4120  CcUnpinRepinnedBcb( Bcb, TRUE, &IgnoreStatus );
4121 
4122  } else {
4123 
4124  FatUnpinBcb(IrpContext, Bcb);
4125  }
4126 
4127  DebugTrace(-1, Dbg, "FatSetFatEntry -> (VOID)\n", 0);
4128  } _SEH2_END;
4129 
4130  return;
4131 }
4132 
4133 
4134 //
4135 // Internal support routine
4136 //
4137 
4138 VOID
4140  IN PIRP_CONTEXT IrpContext,
4141  IN PVCB Vcb,
4142  IN ULONG StartingFatIndex,
4143  IN ULONG ClusterCount,
4144  IN BOOLEAN ChainTogether
4145  )
4146 
4147 /*++
4148 
4149 Routine Description:
4150 
4151  This routine sets a continuous run of clusters in the fat. If ChainTogether
4152  is TRUE, then the clusters are linked together as in normal Fat fasion,
4153  with the last cluster receiving FAT_CLUSTER_LAST. If ChainTogether is
4154  FALSE, all the entries are set to FAT_CLUSTER_AVAILABLE, effectively
4155  freeing all the clusters in the run.
4156 
4157 Arguments:
4158 
4159  Vcb - Supplies the Vcb to examine, yields 12/16 bit info, etc.
4160 
4161  StartingFatIndex - Supplies the destination fat index.
4162 
4163  ClusterCount - Supplies the number of contiguous clusters to work on.
4164 
4165  ChainTogether - Tells us whether to fill the entries with links, or
4166  FAT_CLUSTER_AVAILABLE
4167 
4168 
4169 Return Value:
4170 
4171  VOID
4172 
4173 --*/
4174 
4175 {
4176 #define MAXCOUNTCLUS 0x10000
4177 #define COUNTSAVEDBCBS ((MAXCOUNTCLUS * sizeof(FAT_ENTRY) / PAGE_SIZE) + 2)
4178  PBCB SavedBcbs[COUNTSAVEDBCBS][2];
4179 
4180  ULONG SectorSize;
4181  ULONG Cluster;
4182 
4183  LBO StartSectorLbo;
4184  LBO FinalSectorLbo;
4185  LBO Lbo;
4186 
4187  PVOID PinnedFat;
4188 
4190 
4191  ULONG SavedStartingFatIndex = StartingFatIndex;
4192 
4193  PAGED_CODE();
4194 
4195  DebugTrace(+1, Dbg, "FatSetFatRun\n", 0);
4196  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
4197  DebugTrace( 0, Dbg, " StartingFatIndex = %8x\n", StartingFatIndex);
4198  DebugTrace( 0, Dbg, " ClusterCount = %8lx\n", ClusterCount);
4199  DebugTrace( 0, Dbg, " ChainTogether = %s\n", ChainTogether ? "TRUE":"FALSE");
4200 
4201  //
4202  // Make sure they gave us a valid fat run.
4203  //
4204 
4205  FatVerifyIndexIsValid(IrpContext, Vcb, StartingFatIndex);
4206  FatVerifyIndexIsValid(IrpContext, Vcb, StartingFatIndex + ClusterCount - 1);
4207 
4208  //
4209  // Check special case
4210  //
4211 
4212  if (ClusterCount == 0) {
4213 
4214  DebugTrace(-1, Dbg, "FatSetFatRun -> (VOID)\n", 0);
4215  return;
4216  }
4217 
4218  //
4219  // Set Sector Size
4220  //
4221 
4222  SectorSize = 1 << Vcb->AllocationSupport.LogOfBytesPerSector;
4223 
4224  //
4225  // Case on 12 or 16 bit fats.
4226  //
4227  // In the 12 bit case (mostly floppies) we always have the whole fat
4228  // (max 6k bytes) pinned during allocation operations. This is possibly
4229  // a wee bit slower, but saves headaches over fat entries with 8 bits
4230  // on one page, and 4 bits on the next.
4231  //
4232  // In the 16 bit case we only read one page at a time, as needed.
4233  //
4234 
4235  //
4236  // DEAL WITH 12 BIT CASE
4237  //
4238 
4239  _SEH2_TRY {
4240 
4241  if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
4242 
4243  //
4244  // We read in the entire fat. Note that using prepare write marks
4245  // the bcb pre-dirty, so we don't have to do it explicitly.
4246  //
4247 
4248  RtlZeroMemory( &SavedBcbs[0][0], 2 * sizeof(PBCB) * 2);
4249 
4250  FatPrepareWriteVolumeFile( IrpContext,
4251  Vcb,
4252  FatReservedBytes( &Vcb->Bpb ),
4253  FatBytesPerFat( &Vcb->Bpb ),
4254  &SavedBcbs[0][0],
4255  &PinnedFat,
4256  TRUE,
4257  FALSE );
4258 
4259  //
4260  // Mark the affected sectors dirty. Note that FinalSectorLbo is
4261  // the Lbo of the END of the entry (Thus * 3 + 2). This makes sure
4262  // we catch the case of a dirty fat entry straddling a sector boundry.
4263  //
4264  // Note that if the first AddMcbEntry succeeds, all following ones
4265  // will simply coalese, and thus also succeed.
4266  //
4267 
4268  StartSectorLbo = (FatReservedBytes( &Vcb->Bpb ) + StartingFatIndex * 3 / 2)
4269  & ~(SectorSize - 1);
4270 
4271  FinalSectorLbo = (FatReservedBytes( &Vcb->Bpb ) + ((StartingFatIndex +
4272  ClusterCount) * 3 + 2) / 2) & ~(SectorSize - 1);
4273 
4274  for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
4275 
4276  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
4277  }
4278 
4279  //
4280  // Store the entries into the fat; we need a little
4281  // synchonization here and can't use a spinlock since the bytes
4282  // might not be resident.
4283  //
4284 
4286  ReleaseMutex = TRUE;
4287 
4288  for (Cluster = StartingFatIndex;
4289  Cluster < StartingFatIndex + ClusterCount - 1;
4290  Cluster++) {
4291 
4292  FatSet12BitEntry( PinnedFat,
4293  Cluster,
4294  ChainTogether ? Cluster + 1 : FAT_CLUSTER_AVAILABLE );
4295  }
4296 
4297  //
4298  // Save the last entry
4299  //
4300 
4301  FatSet12BitEntry( PinnedFat,
4302  Cluster,
4303  ChainTogether ?
4305 
4307  ReleaseMutex = FALSE;
4308 
4309  } else if (Vcb->AllocationSupport.FatIndexBitSize == 32) {
4310 
4311  //
4312  // DEAL WITH 32 BIT CASE
4313  //
4314 
4315  for (;;) {
4316 
4317  VBO StartOffsetInVolume;
4318  VBO FinalOffsetInVolume;
4319 
4320  ULONG Page;
4321  ULONG FinalCluster;
4322  PULONG FatEntry = NULL;
4323  ULONG ClusterCountThisRun;
4324 
4325  StartOffsetInVolume = FatReservedBytes(&Vcb->Bpb) +
4326  StartingFatIndex * sizeof(FAT_ENTRY);
4327 
4328  if (ClusterCount > MAXCOUNTCLUS) {
4329  ClusterCountThisRun = MAXCOUNTCLUS;
4330  } else {
4331  ClusterCountThisRun = ClusterCount;
4332  }
4333 
4334  FinalOffsetInVolume = StartOffsetInVolume +
4335  (ClusterCountThisRun - 1) * sizeof(FAT_ENTRY);
4336 
4337  {
4338  ULONG NumberOfPages;
4339  ULONG Offset;
4340 
4341  NumberOfPages = (FinalOffsetInVolume / PAGE_SIZE) -
4342  (StartOffsetInVolume / PAGE_SIZE) + 1;
4343 
4344  RtlZeroMemory( &SavedBcbs[0][0], (NumberOfPages + 1) * sizeof(PBCB) * 2 );
4345 
4346  for ( Page = 0, Offset = StartOffsetInVolume & ~(PAGE_SIZE - 1);
4347  Page < NumberOfPages;
4348  Page++, Offset += PAGE_SIZE ) {
4349 
4350  FatPrepareWriteVolumeFile( IrpContext,
4351  Vcb,
4352  Offset,
4353  PAGE_SIZE,
4354  &SavedBcbs[Page][0],
4355  (PVOID *)&SavedBcbs[Page][1],
4356  TRUE,
4357  FALSE );
4358 
4359  if (Page == 0) {
4360 
4361  FatEntry = (PULONG)((PUCHAR)SavedBcbs[0][1] +
4362  (StartOffsetInVolume % PAGE_SIZE));
4363  }
4364  }
4365  }
4366 
4367  //
4368  // Mark the run dirty
4369  //
4370 
4371  StartSectorLbo = StartOffsetInVolume & ~(SectorSize - 1);
4372  FinalSectorLbo = FinalOffsetInVolume & ~(SectorSize - 1);
4373 
4374  for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
4375 
4376  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO)Lbo, Lbo, SectorSize );
4377  }
4378 
4379  //
4380  // Store the entries
4381  //
4382  // We need extra synchronization here for broken architectures
4383  // like the ALPHA that don't support atomic 16 bit writes.
4384  //
4385 
4386 #ifdef ALPHA
4388  ReleaseMutex = TRUE;
4389 #endif // ALPHA
4390 
4391  FinalCluster = StartingFatIndex + ClusterCountThisRun - 1;
4392  Page = 0;
4393 
4394  for (Cluster = StartingFatIndex;
4395  Cluster <= FinalCluster;
4396  Cluster++, FatEntry++) {
4397 
4398  //
4399  // If we just crossed a page boundry (as opposed to starting
4400  // on one), update our idea of FatEntry.
4401 
4402  if ( (((ULONG_PTR)FatEntry & (PAGE_SIZE-1)) == 0) &&
4403  (Cluster != StartingFatIndex) ) {
4404 
4405  Page += 1;
4406  FatEntry = (PULONG)SavedBcbs[Page][1];
4407  }
4408 
4409  *FatEntry = ChainTogether ? (FAT_ENTRY)(Cluster + 1) :
4411  }
4412 
4413  //
4414  // Fix up the last entry if we were chaining together
4415  //
4416 
4417  if ((ClusterCount <= MAXCOUNTCLUS) &&
4418  ChainTogether ) {
4419 
4420  *(FatEntry-1) = FAT_CLUSTER_LAST;
4421  }
4422 
4423 #ifdef ALPHA
4425  ReleaseMutex = FALSE;
4426 #endif // ALPHA
4427 
4428  {
4429  ULONG i;
4430 
4431  //
4432  // Unpin the Bcbs
4433  //
4434 
4435  for (i = 0; (i < COUNTSAVEDBCBS) && (SavedBcbs[i][0] != NULL); i++) {
4436 
4437  FatUnpinBcb( IrpContext, SavedBcbs[i][0] );
4438  SavedBcbs[i][0] = NULL;
4439  }
4440  }
4441 
4442  if (ClusterCount <= MAXCOUNTCLUS) {
4443 
4444  break;
4445 
4446  } else {
4447 
4448  StartingFatIndex += MAXCOUNTCLUS;
4449  ClusterCount -= MAXCOUNTCLUS;
4450  }
4451  }
4452 
4453  } else {
4454 
4455  //
4456  // DEAL WITH 16 BIT CASE
4457  //
4458 
4459  VBO StartOffsetInVolume;
4460  VBO FinalOffsetInVolume;
4461 
4462  ULONG Page;
4463  ULONG FinalCluster;
4464  PUSHORT FatEntry = NULL;
4465 
4466  StartOffsetInVolume = FatReservedBytes(&Vcb->Bpb) +
4467  StartingFatIndex * sizeof(USHORT);
4468 
4469  FinalOffsetInVolume = StartOffsetInVolume +
4470  (ClusterCount - 1) * sizeof(USHORT);
4471 
4472  //
4473  // Read in one page of fat at a time. We cannot read in the
4474  // all of the fat we need because of cache manager limitations.
4475  //
4476  // SavedBcb was initialized to be able to hold the largest
4477  // possible number of pages in a fat plus and extra one to
4478  // accomadate the boot sector, plus one more to make sure there
4479  // is enough room for the RtlZeroMemory below that needs the mark
4480  // the first Bcb after all the ones we will use as an end marker.
4481  //
4482 
4483  {
4484  ULONG NumberOfPages;
4485  ULONG Offset;
4486 
4487  NumberOfPages = (FinalOffsetInVolume / PAGE_SIZE) -
4488  (StartOffsetInVolume / PAGE_SIZE) + 1;
4489 
4490  RtlZeroMemory( &SavedBcbs[0][0], (NumberOfPages + 1) * sizeof(PBCB) * 2 );
4491 
4492  for ( Page = 0, Offset = StartOffsetInVolume & ~(PAGE_SIZE - 1);
4493  Page < NumberOfPages;
4494  Page++, Offset += PAGE_SIZE ) {
4495 
4496  FatPrepareWriteVolumeFile( IrpContext,
4497  Vcb,
4498  Offset,
4499  PAGE_SIZE,
4500  &SavedBcbs[Page][0],
4501  (PVOID *)&SavedBcbs[Page][1],
4502  TRUE,
4503  FALSE );
4504 
4505  if (Page == 0) {
4506 
4507  FatEntry = (PUSHORT)((PUCHAR)SavedBcbs[0][1] +
4508  (StartOffsetInVolume % PAGE_SIZE));
4509  }
4510  }
4511  }
4512 
4513  //
4514  // Mark the run dirty
4515  //
4516 
4517  StartSectorLbo = StartOffsetInVolume & ~(SectorSize - 1);
4518  FinalSectorLbo = FinalOffsetInVolume & ~(SectorSize - 1);
4519 
4520  for (Lbo = StartSectorLbo; Lbo <= FinalSectorLbo; Lbo += SectorSize) {
4521 
4522  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb, (VBO) Lbo, Lbo, SectorSize );
4523  }
4524 
4525  //
4526  // Store the entries
4527  //
4528  // We need extra synchronization here for broken architectures
4529  // like the ALPHA that don't support atomic 16 bit writes.
4530  //
4531 
4532 #ifdef ALPHA
4534  ReleaseMutex = TRUE;
4535 #endif // ALPHA
4536 
4537  FinalCluster = StartingFatIndex + ClusterCount - 1;
4538  Page = 0;
4539 
4540  for (Cluster = StartingFatIndex;
4541  Cluster <= FinalCluster;
4542  Cluster++, FatEntry++) {
4543 
4544  //
4545  // If we just crossed a page boundry (as opposed to starting
4546  // on one), update our idea of FatEntry.
4547 
4548  if ( (((ULONG_PTR)FatEntry & (PAGE_SIZE-1)) == 0) &&
4549  (Cluster != StartingFatIndex) ) {
4550 
4551  Page += 1;
4552  FatEntry = (PUSHORT)SavedBcbs[Page][1];
4553  }
4554 
4555  *FatEntry = (USHORT) (ChainTogether ? (FAT_ENTRY)(Cluster + 1) :
4557  }
4558 
4559  //
4560  // Fix up the last entry if we were chaining together
4561  //
4562 
4563  if ( ChainTogether ) {
4564 
4565 #ifdef _MSC_VER
4566 #pragma warning( suppress: 4310 )
4567 #endif
4569 
4570  }
4571 #ifdef ALPHA
4573  ReleaseMutex = FALSE;
4574 #endif // ALPHA
4575  }
4576 
4577  } _SEH2_FINALLY {
4578 
4579  ULONG i;
4580 
4582 
4583  //
4584  // If we still somehow have the Mutex, release it.
4585  //
4586 
4587  if (ReleaseMutex) {
4588 
4590 
4592  }
4593 
4594  //
4595  // Unpin the Bcbs
4596  //
4597 
4598  for (i = 0; (i < COUNTSAVEDBCBS) && (SavedBcbs[i][0] != NULL); i++) {
4599 
4600  FatUnpinBcb( IrpContext, SavedBcbs[i][0] );
4601  }
4602 
4603  //
4604  // At this point nothing in this finally clause should have raised.
4605  // So, now comes the unsafe (sigh) stuff.
4606  //
4607 
4608  if ( _SEH2_AbnormalTermination() &&
4609  (Vcb->AllocationSupport.FatIndexBitSize == 32) ) {
4610 
4611  //
4612  // Fat32 unwind
4613  //
4614  // This case is more complex because the FAT12 and FAT16 cases
4615  // pin all the needed FAT pages (128K max), after which it
4616  // can't fail, before changing any FAT entries. In the Fat32
4617  // case, it may not be practical to pin all the needed FAT
4618  // pages, because that could span many megabytes. So Fat32
4619  // attacks in chunks, and if a failure occurs once the first
4620  // chunk has been updated, we have to back out the updates.
4621  //
4622  // The unwind consists of walking back over each FAT entry we
4623  // have changed, setting it back to the previous value. Note
4624  // that the previous value with either be FAT_CLUSTER_AVAILABLE
4625  // (if ChainTogether==TRUE) or a simple link to the successor
4626  // (if ChainTogether==FALSE).
4627  //
4628  // We concede that any one of these calls could fail too; our
4629  // objective is to make this case no more likely than the case
4630  // for a file consisting of multiple disjoint runs.
4631  //
4632 
4633  while ( StartingFatIndex > SavedStartingFatIndex ) {
4634 
4635  StartingFatIndex--;
4636 
4637  FatSetFatEntry( IrpContext, Vcb, StartingFatIndex,
4638  ChainTogether ?
4639  StartingFatIndex + 1 : FAT_CLUSTER_AVAILABLE );
4640  }
4641  }
4642 
4643  DebugTrace(-1, Dbg, "FatSetFatRun -> (VOID)\n", 0);
4644  } _SEH2_END;
4645 
4646  return;
4647 }
4648 
4649 
4650 //
4651 // Internal support routine
4652 //
4653 
4654 UCHAR
4656  IN ULONG Value
4657  )
4658 
4659 /*++
4660 
4661 Routine Description:
4662 
4663  This routine just computes the base 2 log of an integer. It is only used
4664  on objects that are know to be powers of two.
4665 
4666 Arguments:
4667 
4668  Value - The value to take the base 2 log of.
4669 
4670 Return Value:
4671 
4672  UCHAR - The base 2 log of Value.
4673 
4674 --*/
4675 
4676 {
4677  UCHAR Log = 0;
4678 
4679 #if FASTFATDBG
4680  ULONG OrigValue = Value;
4681 #endif
4682 
4683  PAGED_CODE();
4684 
4685  //
4686  // Knock bits off until we we get a one at position 0
4687  //
4688 
4689  while ( (Value & 0xfffffffe) != 0 ) {
4690 
4691  Log++;
4692  Value >>= 1;
4693  }
4694 
4695  //
4696  // If there was more than one bit set, the file system messed up,
4697  // Bug Check.
4698  //
4699 
4700  if (Value != 0x1) {
4701 
4702  DebugTrace(+1, Dbg, "LogOf\n", 0);
4703  DebugTrace( 0, Dbg, " Value = %8lx\n", OrigValue);
4704 
4705  DebugTrace( 0, Dbg, "Received non power of 2.\n", 0);
4706 
4707  DebugTrace(-1, Dbg, "LogOf -> %8lx\n", Log);
4708 
4709 #ifdef _MSC_VER
4710 #pragma prefast( suppress: 28159, "we bugcheck here because our internal data structures are seriously corrupted if this happens" )
4711 #endif
4712  FatBugCheck( Value, Log, 0 );
4713  }
4714 
4715  return Log;
4716 }
4717 
4718 
4719 VOID
4721  IN PIRP_CONTEXT IrpContext,
4722  IN PVCB Vcb,
4723  IN ULONG StartIndex OPTIONAL,
4724  IN ULONG EndIndex OPTIONAL,
4725  IN BOOLEAN SetupWindows,
4726  IN PFAT_WINDOW SwitchToWindow OPTIONAL,
4727  IN PULONG BitMapBuffer OPTIONAL
4728  )
4729 /*++
4730 
4731 Routine Description:
4732 
4733  This routine handles scanning a segment of the FAT into in-memory structures.
4734 
4735  There are three fundamental cases, with variations depending on the FAT type:
4736 
4737  1) During volume setup, FatSetupAllocations
4738 
4739  1a) for FAT12/16, read the FAT into our free clusterbitmap
4740  1b) for FAT32, perform the initial scan for window free cluster counts
4741 
4742  2) Switching FAT32 windows on the fly during system operation
4743 
4744  3) Reading arbitrary segments of the FAT for the purposes of the GetVolumeBitmap
4745  call (only for FAT32)
4746 
4747  There really is too much going on in here. At some point this should be
4748  substantially rewritten.
4749 
4750 Arguments:
4751 
4752  Vcb - Supplies the volume involved
4753 
4754  StartIndex - Supplies the starting cluster, ignored if SwitchToWindow supplied
4755 
4756  EndIndex - Supplies the ending cluster, ignored if SwitchToWindow supplied
4757 
4758  SetupWindows - Indicates if we are doing the initial FAT32 scan
4759 
4760  SwitchToWindow - Supplies the FAT window we are examining and will switch to
4761 
4762  BitMapBuffer - Supplies a specific bitmap to fill in, if not supplied we fill
4763  in the volume free cluster bitmap if !SetupWindows
4764 
4765 Return Value:
4766 
4767  None. Lots of side effects.
4768 
4769 --*/
4770 {
4772  ULONG Page = 0;
4773  ULONG Offset = 0;
4774  ULONG FatIndex;
4776  FAT_ENTRY FirstFatEntry = FAT_CLUSTER_AVAILABLE;
4777  PUSHORT FatBuffer;
4778  PVOID pv;
4779  PBCB Bcb = NULL;
4780  ULONG EntriesPerWindow;
4781 
4782  ULONG ClustersThisRun;
4783  ULONG StartIndexOfThisRun;
4784 
4785  PULONG FreeClusterCount = NULL;
4786 
4787  PFAT_WINDOW CurrentWindow = NULL;
4788 
4789  PVOID NewBitMapBuffer = NULL;
4790  PRTL_BITMAP BitMap = NULL;
4791  RTL_BITMAP PrivateBitMap;
4792 
4793  ULONG ClusterSize = 0;
4794  ULONG PrefetchPages = 0;
4795  ULONG FatPages = 0;
4796 
4797  VBO BadClusterVbo = 0;
4798  LBO Lbo = 0;
4799 
4800  enum RunType {
4801  FreeClusters,
4802  AllocatedClusters,
4803  UnknownClusters
4804  } CurrentRun;
4805 
4806  PAGED_CODE();
4807 
4808  //
4809  // Now assert correct usage.
4810  //
4811 
4812  FatIndexBitSize = Vcb->AllocationSupport.FatIndexBitSize;
4813 
4814  NT_ASSERT( !(SetupWindows && (SwitchToWindow || BitMapBuffer)));
4815  NT_ASSERT( !(SetupWindows && FatIndexBitSize != 32));
4816 
4817  if (Vcb->NumberOfWindows > 1) {
4818 
4819  //
4820  // FAT32: Calculate the number of FAT entries covered by a window. This is
4821  // equal to the number of bits in the freespace bitmap, the size of which
4822  // is hardcoded.
4823  //
4824 
4825  EntriesPerWindow = MAX_CLUSTER_BITMAP_SIZE;
4826 
4827  } else {
4828 
4829  EntriesPerWindow = Vcb->AllocationSupport.NumberOfClusters;
4830  }
4831 
4832  //
4833  // We will also fill in the cumulative count of free clusters for
4834  // the entire volume. If this is not appropriate, NULL it out
4835  // shortly.
4836  //
4837 
4838  FreeClusterCount = &Vcb->AllocationSupport.NumberOfFreeClusters;
4839 
4840  if (SetupWindows) {
4841 
4842  NT_ASSERT(BitMapBuffer == NULL);
4843 
4844  //
4845  // In this case we're just supposed to scan the fat and set up
4846  // the information regarding where the buckets fall and how many
4847  // free clusters are in each.
4848  //
4849  // It is fine to monkey with the real windows, we must be able
4850  // to do this to activate the volume.
4851  //
4852 
4853  BitMap = NULL;
4854 
4855  CurrentWindow = &Vcb->Windows[0];
4856  CurrentWindow->FirstCluster = StartIndex;
4857  CurrentWindow->ClustersFree = 0;
4858 
4859  //
4860  // We always wish to calculate total free clusters when
4861  // setting up the FAT windows.
4862  //
4863 
4864  } else if (BitMapBuffer == NULL) {
4865 
4866  //
4867  // We will be filling in the free cluster bitmap for the volume.
4868  // Careful, we can raise out of here and be hopelessly hosed if
4869  // we built this up in the main bitmap/window itself.
4870  //
4871  // For simplicity's sake, we'll do the swap for everyone. FAT32
4872  // provokes the need since we can't tolerate partial results
4873  // when switching windows.
4874  //
4875 
4876  NT_ASSERT( SwitchToWindow );
4877 
4878  CurrentWindow = SwitchToWindow;
4879  StartIndex = CurrentWindow->FirstCluster;
4880  EndIndex = CurrentWindow->LastCluster;
4881 
4882  BitMap = &PrivateBitMap;
4883  NewBitMapBuffer = FsRtlAllocatePoolWithTag( PagedPool,
4884  (EntriesPerWindow + 7) / 8,
4885  TAG_FAT_BITMAP );
4886 
4887  RtlInitializeBitMap( &PrivateBitMap,
4888  NewBitMapBuffer,
4889  EndIndex - StartIndex + 1);
4890 
4891  if ((FatIndexBitSize == 32) &&
4892  (Vcb->NumberOfWindows > 1)) {
4893 
4894  //
4895  // We do not wish count total clusters here.
4896  //
4897 
4898  FreeClusterCount = NULL;
4899 
4900  }
4901 
4902  } else {
4903 
4904  BitMap = &PrivateBitMap;
4905  RtlInitializeBitMap(&PrivateBitMap,
4906  BitMapBuffer,
4907  EndIndex - StartIndex + 1);
4908 
4909  //
4910  // We do not count total clusters here.
4911  //
4912 
4913  FreeClusterCount = NULL;
4914  }
4915 
4916  //
4917  // Now, our start index better be in the file heap.
4918  //
4919 
4920  NT_ASSERT( StartIndex >= 2 );
4921 
4922  _SEH2_TRY {
4923 
4924  //
4925  // Pick up the initial chunk of the FAT and first entry.
4926  //
4927 
4928  if (FatIndexBitSize == 12) {
4929 
4930  //
4931  // We read in the entire fat in the 12 bit case.
4932  //
4933 
4934  FatReadVolumeFile( IrpContext,
4935  Vcb,
4936  FatReservedBytes( &Vcb->Bpb ),
4937  FatBytesPerFat( &Vcb->Bpb ),
4938  &Bcb,
4939  (PVOID *)&FatBuffer );
4940 
4941  FatLookup12BitEntry(FatBuffer, 0, &FirstFatEntry);
4942 
4943  } else {
4944 
4945  //
4946  // Read in one page of fat at a time. We cannot read in the
4947  // all of the fat we need because of cache manager limitations.
4948  //
4949 
4950  ULONG BytesPerEntry = FatIndexBitSize >> 3;
4951 
4952  FatPages = (FatReservedBytes(&Vcb->Bpb) + FatBytesPerFat(&Vcb->Bpb) + (PAGE_SIZE - 1)) / PAGE_SIZE;
4953  Page = (FatReservedBytes(&Vcb->Bpb) + StartIndex * BytesPerEntry) / PAGE_SIZE;
4954 
4955  Offset = Page * PAGE_SIZE;
4956 
4957  //
4958  // Prefetch the FAT entries in memory for optimal performance.
4959  //
4960 
4961  PrefetchPages = FatPages - Page;
4962 
4963  if (PrefetchPages > FAT_PREFETCH_PAGE_COUNT) {
4964 
4965  PrefetchPages = ALIGN_UP_BY(Page, FAT_PREFETCH_PAGE_COUNT) - Page;
4966  }
4967 
4968 #if (NTDDI_VERSION >= NTDDI_WIN8)
4969  FatPrefetchPages( IrpContext,
4970  Vcb->VirtualVolumeFile,
4971  Page,
4972  PrefetchPages );
4973 #endif
4974 
4975  FatReadVolumeFile( IrpContext,
4976  Vcb,
4977  Offset,
4978  PAGE_SIZE,
4979  &Bcb,
4980  &pv);
4981 
4982  if (FatIndexBitSize == 32) {
4983 
4984  FatBuffer = (PUSHORT)((PUCHAR)pv +
4985  (FatReservedBytes(&Vcb->Bpb) + StartIndex * BytesPerEntry) %
4986  PAGE_SIZE);
4987 
4988  FirstFatEntry = *((PULONG)FatBuffer);
4989  FirstFatEntry = FirstFatEntry & FAT32_ENTRY_MASK;
4990 
4991  } else {
4992 
4993  FatBuffer = (PUSHORT)((PUCHAR)pv +
4994  FatReservedBytes(&Vcb->Bpb) % PAGE_SIZE) + 2;
4995 
4996  FirstFatEntry = *FatBuffer;
4997  }
4998 
4999  }
5000 
5001  ClusterSize = 1 << (Vcb->AllocationSupport.LogOfBytesPerCluster);
5002 
5003  CurrentRun = (FirstFatEntry == FAT_CLUSTER_AVAILABLE) ?
5004  FreeClusters : AllocatedClusters;
5005 
5006  StartIndexOfThisRun = StartIndex;
5007 
5008  for (FatIndex = StartIndex; FatIndex <= EndIndex; FatIndex++) {
5009 
5010  if (FatIndexBitSize == 12) {
5011 
5012  FatLookup12BitEntry(FatBuffer, FatIndex, &FatEntry);
5013 
5014  } else {
5015 
5016  //
5017  // If we are setting up the FAT32 windows and have stepped into a new
5018  // bucket, finalize this one and move forward.
5019  //
5020 
5021  if (SetupWindows &&
5022  FatIndex > StartIndex &&
5023  (FatIndex - 2) % EntriesPerWindow == 0) {
5024 
5025  CurrentWindow->LastCluster = FatIndex - 1;
5026 
5027  if (CurrentRun == FreeClusters) {
5028 
5029  //
5030  // We must be counting clusters in order to modify the
5031  // contents of the window.
5032  //
5033 
5034  NT_ASSERT( FreeClusterCount );
5035 
5036  ClustersThisRun = FatIndex - StartIndexOfThisRun;
5037  CurrentWindow->ClustersFree += ClustersThisRun;
5038 
5039  if (FreeClusterCount) {
5040  *FreeClusterCount += ClustersThisRun;
5041  }
5042 
5043  } else {
5044 
5045  NT_ASSERT(CurrentRun == AllocatedClusters);
5046 
5047  }
5048 
5049  StartIndexOfThisRun = FatIndex;
5050  CurrentRun = UnknownClusters;
5051 
5052  CurrentWindow++;
5053  CurrentWindow->ClustersFree = 0;
5054  CurrentWindow->FirstCluster = FatIndex;
5055  }
5056 
5057  //
5058  // If we just stepped onto a new page, grab a new pointer.
5059  //
5060 
5061  if (((ULONG_PTR)FatBuffer & (PAGE_SIZE - 1)) == 0) {
5062 
5063  FatUnpinBcb( IrpContext, Bcb );
5064 
5065  Page++;
5066  Offset += PAGE_SIZE;
5067 
5068 #if (NTDDI_VERSION >= NTDDI_WIN8)
5069  //
5070  // If we have exhausted all the prefetch pages, prefetch the next chunk.
5071  //
5072 
5073  if (--PrefetchPages == 0) {
5074 
5075  PrefetchPages = FatPages - Page;
5076 
5077  if (PrefetchPages > FAT_PREFETCH_PAGE_COUNT) {
5078 
5079  PrefetchPages = FAT_PREFETCH_PAGE_COUNT;
5080  }
5081 
5082  FatPrefetchPages( IrpContext,
5083  Vcb->VirtualVolumeFile,
5084  Page,
5085  PrefetchPages );
5086  }
5087 #endif
5088 
5089  FatReadVolumeFile( IrpContext,
5090  Vcb,
5091  Offset,
5092  PAGE_SIZE,
5093  &Bcb,
5094  &pv );
5095 
5096  FatBuffer = (PUSHORT)pv;
5097  }
5098 
5099  if (FatIndexBitSize == 32) {
5100 
5101 #ifndef __REACTOS__
5102 #ifdef _MSC_VER
5103 #pragma warning( suppress: 4213 )
5104 #endif
5105  FatEntry = *((PULONG)FatBuffer)++;
5107 #else
5108  FatEntry = *((PULONG)FatBuffer);
5109  FatBuffer += 2; /* PUSHORT FatBuffer */
5111 #endif
5112 
5113  } else {
5114 
5115  FatEntry = *FatBuffer;
5116  FatBuffer += 1;
5117  }
5118  }
5119 
5120  if (CurrentRun == UnknownClusters) {
5121 
5122  CurrentRun = (FatEntry == FAT_CLUSTER_AVAILABLE) ?
5123  FreeClusters : AllocatedClusters;
5124  }
5125 
5126  //
5127  // Are we switching from a free run to an allocated run?
5128  //
5129 
5130  if (CurrentRun == FreeClusters &&
5132 
5133  ClustersThisRun = FatIndex - StartIndexOfThisRun;
5134 
5135  if (FreeClusterCount) {
5136 
5137  *FreeClusterCount += ClustersThisRun;
5138  CurrentWindow->ClustersFree += ClustersThisRun;
5139  }
5140 
5141  if (BitMap) {
5142 
5143  RtlClearBits( BitMap,
5144  StartIndexOfThisRun - StartIndex,
5145  ClustersThisRun );
5146  }
5147 
5148  CurrentRun = AllocatedClusters;
5149  StartIndexOfThisRun = FatIndex;
5150  }
5151 
5152  //
5153  // Are we switching from an allocated run to a free run?
5154  //
5155 
5156  if (CurrentRun == AllocatedClusters &&
5158 
5159  ClustersThisRun = FatIndex - StartIndexOfThisRun;
5160 
5161  if (BitMap) {
5162 
5163  RtlSetBits( BitMap,
5164  StartIndexOfThisRun - StartIndex,
5165  ClustersThisRun );
5166  }
5167 
5168  CurrentRun = FreeClusters;
5169  StartIndexOfThisRun = FatIndex;
5170  }
5171 
5172  //
5173  // If the entry is marked bad, add it to the bad block MCB
5174  //
5175 
5176  if ((SetupWindows || (Vcb->NumberOfWindows == 1)) &&
5178 
5179  //
5180  // This cluster is marked bad.
5181  // Add it to the BadBlockMcb.
5182  //
5183 
5185  FatAddMcbEntry( Vcb, &Vcb->BadBlockMcb, BadClusterVbo, Lbo, ClusterSize );
5186  BadClusterVbo += ClusterSize;
5187  }
5188  }
5189 
5190  //
5191  // If we finished the scan, then we know about all the possible bad clusters.
5192  //
5193 
5195 
5196  //
5197  // Now we have to record the final run we encountered
5198  //
5199 
5200  ClustersThisRun = FatIndex - StartIndexOfThisRun;
5201 
5202  if (CurrentRun == FreeClusters) {
5203 
5204  if (FreeClusterCount) {
5205 
5206  *FreeClusterCount += ClustersThisRun;
5207  CurrentWindow->ClustersFree += ClustersThisRun;
5208  }
5209 
5210  if (BitMap) {
5211 
5212  RtlClearBits( BitMap,
5213  StartIndexOfThisRun - StartIndex,
5214  ClustersThisRun );
5215  }
5216 
5217  } else {
5218 
5219  if (BitMap) {
5220 
5221  RtlSetBits( BitMap,
5222  StartIndexOfThisRun - StartIndex,
5223  ClustersThisRun );
5224  }
5225  }
5226 
5227  //
5228  // And finish the last window if we are in setup.
5229  //
5230 
5231  if (SetupWindows) {
5232 
5233  CurrentWindow->LastCluster = FatIndex - 1;
5234  }
5235 
5236  //
5237  // Now switch the active window if required. We've succesfully gotten everything
5238  // nailed down.
5239  //
5240  // If we were tracking the free cluster count, this means we should update the
5241  // window. This is the case of FAT12/16 initialization.
5242  //
5243 
5244  if (SwitchToWindow) {
5245 
5246  if (Vcb->FreeClusterBitMap.Buffer) {
5247 
5248  ExFreePool( Vcb->FreeClusterBitMap.Buffer );
5249  }
5250 
5251  RtlInitializeBitMap( &Vcb->FreeClusterBitMap,
5252  NewBitMapBuffer,
5253  EndIndex - StartIndex + 1 );
5254 
5255  NewBitMapBuffer = NULL;
5256 
5257  Vcb->CurrentWindow = SwitchToWindow;
5258  Vcb->ClusterHint = (ULONG)-1;
5259 
5260  if (FreeClusterCount) {
5261 
5262  NT_ASSERT( !SetupWindows );
5263 
5264  Vcb->CurrentWindow->ClustersFree = *FreeClusterCount;
5265  }
5266  }
5267 
5268  //
5269  // Make sure plausible things occured ...
5270  //
5271 
5272  if (!SetupWindows && BitMapBuffer == NULL) {
5273 
5275  }
5276 
5277  NT_ASSERT(Vcb->AllocationSupport.NumberOfFreeClusters <= Vcb->AllocationSupport.NumberOfClusters);
5278 
5279  } _SEH2_FINALLY {
5280 
5281  //
5282  // Unpin the last bcb and drop the temporary bitmap buffer if it exists.
5283  //
5284 
5285  FatUnpinBcb( IrpContext, Bcb);
5286 
5287  if (NewBitMapBuffer) {
5288 
5289  ExFreePool( NewBitMapBuffer );
5290  }
5291  } _SEH2_END;
5292 }
5293 
#define FAT_CLUSTER_LAST
Definition: fat.h:258
#define DbgDoit(X)
Definition: fatdata.h:336
IN PVCB IN ULONG AbsoluteClusterHint
Definition: fatprocs.h:343
#define FatFileAreaLbo(B)
Definition: fat.h:458
#define IN
Definition: typedefs.h:39
CLUSTER_TYPE FatInterpretClusterType(IN PVCB Vcb, IN FAT_ENTRY Entry)
Definition: allocsup.c:3473
#define FatLockFreeClusterBitMap(VCB)
Definition: allocsup.c:99
#define MAX_CLUSTER_BITMAP_SIZE
Definition: allocsup.c:247
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1215
#define FatGetLboFromIndex(VCB, FAT_INDEX)
Definition: fat.h:559
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
ULONG ClustersFree
Definition: fatstruc.h:174
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:411
#define ASSERT_CURRENT_WINDOW_GOOD(VCB)
Definition: allocsup.c:83
#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
#define FCB_STATE_ZERO_ON_DEALLOCATION
Definition: fatstruc.h:1223
#define DbgPrint
Definition: loader.c:25
#define FatMin(a, b)
Definition: allocsup.c:30
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:925
PIRP NTAPI IoBuildSynchronousFsdRequest(IN ULONG MajorFunction, IN PDEVICE_OBJECT DeviceObject, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER StartingOffset, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:1069
#define FatIndexBitSize(B)
Definition: fat.h:515
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
Definition: cdstruc.h:902
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
NTSTATUS FatPrefetchPages(IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN ULONG StartingPage, IN ULONG PageCount)
Definition: cachesup.c:1929
PMDL FatBuildZeroMdl(__in PIRP_CONTEXT IrpContext, __in ULONG Length)
Definition: deviosup.c:3734
NTSTATUS FreeClusters(PNTFS_VCB Vcb, PNTFS_ATTR_CONTEXT AttrContext, ULONG AttrOffset, PFILE_RECORD_HEADER FileRecord, ULONG ClustersToFree)
Definition: attrib.c:1057
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:167
GLuint GLuint GLsizei count
Definition: gl.h:1545
ULONG32 VBO
Definition: fat.h:38
unsigned char * PUCHAR
Definition: retypes.h:3
IN PVCB IN OUT PLARGE_MCB IN PLARGE_MCB SecondMcb
Definition: fatprocs.h:373
#define FCB_STATE_FLUSH_FAT
Definition: fatstruc.h:1196
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
LONG NTSTATUS
Definition: precomp.h:26
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
IN PFCB IN VBO OUT PLBO Lbo
Definition: fatprocs.h:306
#define TAG_FAT_WINDOW
Definition: nodetype.h:166
VOID FatReadVolumeFile(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer)
Definition: cachesup.c:102
VOID NTAPI CcUnpinData(IN PVOID Bcb)
Definition: pinsup.c:955
#define FAT_DIRTY_VOLUME
Definition: fat.h:235
$ULONG LowPart
Definition: ntbasedef.h:569
ULONG FirstCluster
Definition: fatstruc.h:172
Definition: cdstruc.h:498
LBO * PLBO
Definition: fat.h:36
#define RtlCheckBit(BMH, BP)
Definition: rtlfuncs.h:3154
#define FAT_CLUSTER_BAD
Definition: fat.h:257
VOID FatExamineFatEntries(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG StartIndex OPTIONAL, IN ULONG EndIndex OPTIONAL, IN BOOLEAN SetupWindows, IN PFAT_WINDOW SwitchToWindow OPTIONAL, IN PULONG BitMapBuffer OPTIONAL)
Definition: allocsup.c:4720
static CC_FILE_SIZES FileSizes
BOOLEAN FatLookupLastMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, OUT PVBO Vbo, OUT PLBO Lbo, OUT PULONG Index OPTIONAL)
Definition: fsctrl.c:494
if(dx==0 &&dy==0)
Definition: linetemp.h:174
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2977
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:765
#define MAXCOUNTCLUS
#define MDL_MAPPED_TO_SYSTEM_VA
Definition: mmtypes.h:18
VOID FatSetupAllocationSupport(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: allocsup.c:359
VOID NTAPI FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb, IN LONGLONG Vbn)
Definition: largemcb.c:1059
#define FatVerifyIndexIsValid(IC, V, I)
Definition: fat.h:532
LARGE_INTEGER FileSize
Definition: cctypes.h:16
_SEH2_TRY
Definition: create.c:4226
uint32_t ULONG_PTR
Definition: typedefs.h:65
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
#define FatReservedBytes(B)
Definition: fat.h:414
INLINE ULONG FatSelectBestWindow(IN PVCB Vcb)
Definition: allocsup.c:279
#define FatUnreserveClusters(IRPCONTEXT, VCB, FAT_INDEX, CLUSTER_COUNT)
Definition: allocsup.c:176
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
Definition: window.c:28
IN PFCB IN VBO OUT PLBO OUT PULONG OUT PBOOLEAN OUT PBOOLEAN EndOnMax
Definition: fatprocs.h:306
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define VCB_STATE_FLAG_BAD_BLOCKS_POPULATED
Definition: fatstruc.h:575
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
#define FALSE
Definition: types.h:117
Definition: Header.h:8
LONGLONG LBO
Definition: fat.h:34
VOID NTAPI MmUnmapLockedPages(IN PVOID BaseAddress, IN PMDL Mdl)
Definition: mdlsup.c:828
#define CcIsFileCached(FO)
VOID FatRemoveMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN ULONG SectorCount)
Definition: fsctrl.c:599
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define FatBytesPerFat(B)
Definition: fat.h:410
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:164
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:451
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:546
UCHAR FatLogOf(IN ULONG Value)
Definition: allocsup.c:4655
unsigned char BOOLEAN
IN PFCB IN VBO OUT PLBO OUT PULONG OUT PBOOLEAN Allocated
Definition: fatprocs.h:306
#define FatWindowOfCluster(C)
Definition: allocsup.c:253
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:166
#define FatRootDirectorySize(B)
Definition: fat.h:427
#define FAT_CLEAN_VOLUME
Definition: fat.h:234
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
#define MDL_SOURCE_IS_NONPAGED_POOL
Definition: mmtypes.h:20
#define FatLookup12BitEntry(FAT, INDEX, ENTRY)
Definition: fat.h:584
#define FatReserveClusters(IRPCONTEXT, VCB, FAT_INDEX, CLUSTER_COUNT)
Definition: allocsup.c:197
Definition: bufpool.h:45
NTSYSAPI ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP, ULONG, ULONG)
VOID FatSetFatRun(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG StartingFatIndex, IN ULONG ClusterCount, IN BOOLEAN ChainTogether)
Definition: allocsup.c:4139
PFN_NUMBER Page
Definition: section.c:4757
VOID FatTearDownAllocationSupport(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: allocsup.c:549
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:547
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406
#define try_leave(S)
Definition: cdprocs.h:2180
#define FatGetIndexFromLbo(VCB, LBO)
Definition: fat.h:566
#define FAT_CLUSTER_AVAILABLE
Definition: fat.h:255
#define DebugUnwind(X)
Definition: fatdata.h:315
#define FatAllocateClusters(IRPCONTEXT, VCB, FAT_INDEX, CLUSTER_COUNT)
Definition: allocsup.c:158
FAT_DATA FatData
Definition: fatdata.c:56
$ULONG HighPart
Definition: ntbasedef.h:570
#define Dbg
Definition: allocsup.c:28
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define INLINE
Definition: rosdhcp.h:56
VOID NTAPI CcUnpinRepinnedBcb(IN PVOID Bcb, IN BOOLEAN WriteThrough, OUT PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:343
return Iosb
Definition: create.c:4402
enum _CLUSTER_TYPE CLUSTER_TYPE
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define try_return(S)
Definition: cdprocs.h:2179
_In_ WDFCOLLECTION _In_ ULONG Index
#define COUNTSAVEDBCBS
#define ARGUMENT_PRESENT(ArgumentPointer)
#define FAT16_DIRTY_ENTRY
Definition: fat.h:248
_Requires_lock_held_(_Global_critical_region_)
Definition: allocsup.c:87
#define Vcb
Definition: cdprocs.h:1415
DWORD ClusterSize
Definition: format.c:67
IN PVCB IN OUT PLARGE_MCB IN VBO OUT PLARGE_MCB RemainingMcb
Definition: fatprocs.h:363
BOOLEAN FatGetNextMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN ULONG RunIndex, OUT PVBO Vbo, OUT PLBO Lbo, OUT PULONG ByteCount)
Definition: fsctrl.c:541
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
* PFILE_OBJECT
Definition: iotypes.h:1998
ULONG LastCluster
Definition: fatstruc.h:173
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
int Window
Definition: x11stubs.h:26
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseMutex(IN HANDLE hMutex)
Definition: synch.c:618
CD_MCB Mcb
Definition: cdstruc.h:1016
unsigned char UCHAR
Definition: xmlstorage.h:181
#define FAT32_DIRTY_ENTRY
Definition: fat.h:249
char * PBOOLEAN
Definition: retypes.h:11
IN PVCB IN ULONG IN OUT PULONG IN BOOLEAN ExactMatchRequired
Definition: fatprocs.h:343
Definition: fsck.fat.h:192
#define VOID
Definition: acefi.h:82
#define FatUnlockFreeClusterBitMap(VCB)
Definition: allocsup.c:112
LARGE_INTEGER ValidDataLength
Definition: cctypes.h:17
IN PVCB IN ULONG FatIndex
Definition: fatprocs.h:382
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define NOTHING
Definition: env_spec_w32.h:461
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define TAG_FAT_BITMAP
Definition: nodetype.h:163
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define FatIsFat32(VCB)
Definition: fatprocs.h:1446
IN PVCB IN PLARGE_MCB IN BOOLEAN ZeroOnDeallocate
Definition: fatprocs.h:354
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
#define VCB_STATE_FLAG_MOUNT_IN_PROGRESS
Definition: fatstruc.h:577
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _In_ LARGE_INTEGER ByteCount
Definition: iotypes.h:1098
ULONG Runs
Definition: symtest.c:7
BOOLEAN FatAddMcbEntry(IN PVCB Vcb, IN PLARGE_MCB Mcb, IN VBO Vbo, IN LBO Lbo, IN ULONG SectorCount)
Definition: fsctrl.c:364
#define MAXULONG
Definition: typedefs.h:251
IN PVCB IN OUT PLARGE_MCB IN VBO SplitAtVbo
Definition: fatprocs.h:363
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
#define MAX_ZERO_MDL_SIZE
Definition: allocsup.c:2602
#define FatNumberOfClusters(B)
Definition: fat.h:482
VOID FatInitializeCacheMap(_In_ PFILE_OBJECT FileObject, _In_ PCC_FILE_SIZES FileSizes, _In_ BOOLEAN PinAccess, _In_ PCACHE_MANAGER_CALLBACKS Callbacks, _In_ PVOID LazyWriteContext)
Definition: cachesup.c:62
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
_SEH2_END
Definition: create.c:4400
#define FAT_DIRTY_BIT_INDEX
Definition: fat.h:237
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
LARGE_INTEGER AllocationSize
Definition: cctypes.h:15
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned short USHORT
Definition: pedump.c:61
LARGE_INTEGER FatMaxLarge
Definition: fatdata.c:63
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
#define FAT12_DIRTY_ENTRY
Definition: fat.h:247
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:356
NTSYSAPI ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP, PULONG)
IN PVCB IN ULONG IN OUT PULONG IN BOOLEAN OUT PLARGE_MCB Mcb
Definition: fatprocs.h:343
NTSYSAPI void WINAPI RtlSetBits(PRTL_BITMAP, ULONG, ULONG)
_SEH2_FINALLY
Definition: create.c:4371
#define _Analysis_assume_
Definition: no_sal2.h:388
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1096
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
#define NULL
Definition: types.h:112
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
BOOLEAN NTAPI ExAcquireResourceSharedLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:885
#define FatSet12BitEntry(FAT, INDEX, ENTRY)
Definition: fat.h:603
#define SL_WRITE_THROUGH
Definition: iotypes.h:1824
ULONG FirstClusterOfFile
Definition: fatstruc.h:817
ULONG32 FAT_ENTRY
Definition: fat.h:225
#define FAT_CLUSTER_RESERVED
Definition: fat.h:256
struct tagContext Context
Definition: acpixf.h:1034
#define OUT
Definition: typedefs.h:40
#define STATUS_DISK_FULL
Definition: udferr_usr.h:155
#define IRP_CONTEXT_FLAG_DISABLE_DIRTY
Definition: fatstruc.h:1557
#define FAT_CLEAN_ENTRY
Definition: fat.h:245
#define FatFindFreeClusterRun(IRPCONTEXT, VCB, CLUSTER_COUNT, CLUSTER_HINT)
Definition: allocsup.c:229
unsigned int ULONG
Definition: retypes.h:1
_In_ PFCB _In_ PDIRENT_ENUM_CONTEXT _Inout_ PDIRENT Dirent
Definition: cdprocs.h:424
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ALIGN_UP_BY(size, align)
PVCB Vcb
Definition: cdstruc.h:933
#define FatRootDirectoryLbo(B)
Definition: fat.h:445
VOID NTAPI CcRepinBcb(IN PVOID Bcb)
Definition: cachesub.c:331
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
NTSYSAPI BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP, ULONG, ULONG)
#define FAT32_ENTRY_MASK
Definition: fat.h:227
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
_In_ ULONG SectorSize
Definition: halfuncs.h:291
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
IN PVCB IN ULONG IN FAT_ENTRY FatEntry
Definition: fatprocs.h:382
NTSYSAPI ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP)
#define UInt32x32To64(a, b)
Definition: intsafe.h:250
ULONG FcbState
Definition: cdstruc.h:971
unsigned short * PUSHORT
Definition: retypes.h:2
IN PFCB IN VBO Vbo
Definition: fatprocs.h:306
base of all file and directory entries
Definition: entries.h:82
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
LONGLONG QuadPart
Definition: typedefs.h:114
VOID FatLookupFatEntry(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN ULONG FatIndex, IN OUT PULONG FatEntry, IN OUT PFAT_ENUMERATION_CONTEXT Context)
Definition: allocsup.c:3565
#define FAT_PREFETCH_PAGE_COUNT
Definition: allocsup.c:36
#define FatBytesPerCluster(B)
Definition: fat.h:408
#define PAGED_CODE()
#define FatFreeClusters(IRPCONTEXT, VCB, FAT_INDEX, CLUSTER_COUNT)
Definition: allocsup.c:140
#define NT_ASSERT
Definition: rtlfuncs.h:3312
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
FCB_CONDITION FcbCondition
Definition: fatstruc.h:849
CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks
Definition: fatstruc.h:159