ReactOS  0.4.15-dev-1033-gd7d716a
dirsup.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  DirSup.c
8 
9 Abstract:
10 
11  This module implements the dirent 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_DIRSUP)
23 
24 //
25 // Local debug trace level
26 //
27 
28 #define Dbg (DEBUG_TRACE_DIRSUP)
29 
30 //
31 // The following three macro all assume the input dirent has been zeroed.
32 //
33 
34 //
35 // VOID
36 // FatConstructDot (
37 // IN PIRP_CONTEXT IrpContext,
38 // IN PDCB Directory,
39 // IN PDIRENT ParentDirent,
40 // IN OUT PDIRENT Dirent
41 // );
42 //
43 // The following macro is called to initalize the "." dirent.
44 //
45 // Always setting FirstClusterOfFileHi is OK because it will be zero
46 // unless we're working on a FAT 32 disk.
47 //
48 
49 #define FatConstructDot(IRPCONTEXT,DCB,PARENT,DIRENT) { \
50  \
51  RtlCopyMemory( (PUCHAR)(DIRENT), ". ", 11 ); \
52  (DIRENT)->Attributes = FAT_DIRENT_ATTR_DIRECTORY; \
53  (DIRENT)->LastWriteTime = (PARENT)->LastWriteTime; \
54  if (FatData.ChicagoMode) { \
55  (DIRENT)->CreationTime = (PARENT)->CreationTime; \
56  (DIRENT)->CreationMSec = (PARENT)->CreationMSec; \
57  (DIRENT)->LastAccessDate = (PARENT)->LastAccessDate; \
58  } \
59  (DIRENT)->FirstClusterOfFile = \
60  (USHORT)(DCB)->FirstClusterOfFile; \
61  (DIRENT)->FirstClusterOfFileHi = \
62  (USHORT)((DCB)->FirstClusterOfFile/0x10000); \
63 }
64 
65 //
66 // VOID
67 // FatConstructDotDot (
68 // IN PIRP_CONTEXT IrpContext,
69 // IN PDCB Directory,
70 // IN PDIRENT ParentDirent,
71 // IN OUT PDIRENT Dirent
72 // );
73 //
74 // The following macro is called to initalize the ".." dirent.
75 //
76 // Always setting FirstClusterOfFileHi is OK because it will be zero
77 // unless we're working on a FAT 32 disk.
78 //
79 
80 #define FatConstructDotDot(IRPCONTEXT,DCB,PARENT,DIRENT) { \
81  \
82  RtlCopyMemory( (PUCHAR)(DIRENT), ".. ", 11 ); \
83  (DIRENT)->Attributes = FAT_DIRENT_ATTR_DIRECTORY; \
84  (DIRENT)->LastWriteTime = (PARENT)->LastWriteTime; \
85  if (FatData.ChicagoMode) { \
86  (DIRENT)->CreationTime = (PARENT)->CreationTime; \
87  (DIRENT)->CreationMSec = (PARENT)->CreationMSec; \
88  (DIRENT)->LastAccessDate = (PARENT)->LastAccessDate; \
89  } \
90  if (NodeType((DCB)->ParentDcb) == FAT_NTC_ROOT_DCB) { \
91  (DIRENT)->FirstClusterOfFile = 0; \
92  (DIRENT)->FirstClusterOfFileHi = 0; \
93  } else { \
94  (DIRENT)->FirstClusterOfFile = (USHORT) \
95  ((DCB)->ParentDcb->FirstClusterOfFile); \
96  (DIRENT)->FirstClusterOfFileHi = (USHORT) \
97  ((DCB)->ParentDcb->FirstClusterOfFile/0x10000); \
98  } \
99 }
100 
101 //
102 // VOID
103 // FatConstructEndDirent (
104 // IN PIRP_CONTEXT IrpContext,
105 // IN OUT PDIRENT Dirent
106 // );
107 //
108 // The following macro created the end dirent. Note that since the
109 // dirent was zeroed, the first byte of the name already contains 0x0,
110 // so there is nothing to do.
111 //
112 
113 #define FatConstructEndDirent(IRPCONTEXT,DIRENT) NOTHING
114 
115 //
116 // VOID
117 // FatReadDirent (
118 // IN PIRP_CONTEXT IrpContext,
119 // IN PDCB Dcb,
120 // IN VBO Vbo,
121 // OUT PBCB *Bcb,
122 // OUT PVOID *Dirent,
123 // OUT PNTSTATUS Status
124 // );
125 //
126 
127 //
128 // This macro reads in a page of dirents when we step onto a new page,
129 // or this is the first iteration of a loop and Bcb is NULL.
130 //
131 
132 #define FatReadDirent(IRPCONTEXT,DCB,VBO,BCB,DIRENT,STATUS) \
133 if ((VBO) >= (DCB)->Header.AllocationSize.LowPart) { \
134  *(STATUS) = STATUS_END_OF_FILE; \
135  FatUnpinBcb( (IRPCONTEXT), *(BCB) ); \
136 } else if ( ((VBO) % PAGE_SIZE == 0) || (*(BCB) == NULL) ) { \
137  FatUnpinBcb( (IRPCONTEXT), *(BCB) ); \
138  FatReadDirectoryFile( (IRPCONTEXT), \
139  (DCB), \
140  (VBO) & ~(PAGE_SIZE - 1), \
141  PAGE_SIZE, \
142  FALSE, \
143  (BCB), \
144  (PVOID *)(DIRENT), \
145  (STATUS) ); \
146  *(DIRENT) = (PVOID)((PUCHAR)*(DIRENT) + ((VBO) % PAGE_SIZE)); \
147 }
148 
149 //
150 // Internal support routines
151 //
152 
153 UCHAR
156  );
157 
158 _Requires_lock_held_(_Global_critical_region_)
159 VOID
160 FatRescanDirectory (
161  PIRP_CONTEXT IrpContext,
162  PDCB Dcb
163  );
164 
165 _Requires_lock_held_(_Global_critical_region_)
166 ULONG
167 FatDefragDirectory (
168  IN PIRP_CONTEXT IrpContext,
169  IN PDCB Dcb,
171  );
172 
173 
174 #ifdef ALLOC_PRAGMA
175 #pragma alloc_text(PAGE, FatComputeLfnChecksum)
176 #pragma alloc_text(PAGE, FatConstructDirent)
177 #pragma alloc_text(PAGE, FatConstructLabelDirent)
178 #pragma alloc_text(PAGE, FatCreateNewDirent)
179 #pragma alloc_text(PAGE, FatDefragDirectory)
180 #pragma alloc_text(PAGE, FatDeleteDirent)
181 #pragma alloc_text(PAGE, FatGetDirentFromFcbOrDcb)
182 #pragma alloc_text(PAGE, FatInitializeDirectoryDirent)
183 #pragma alloc_text(PAGE, FatIsDirectoryEmpty)
184 #pragma alloc_text(PAGE, FatLfnDirentExists)
185 #pragma alloc_text(PAGE, FatLocateDirent)
186 #pragma alloc_text(PAGE, FatLocateSimpleOemDirent)
187 #pragma alloc_text(PAGE, FatLocateVolumeLabel)
188 #pragma alloc_text(PAGE, FatRescanDirectory)
189 #pragma alloc_text(PAGE, FatSetFileSizeInDirent)
190 #pragma alloc_text(PAGE, FatSetFileSizeInDirentNoRaise)
191 #pragma alloc_text(PAGE, FatTunnelFcbOrDcb)
192 #pragma alloc_text(PAGE, FatUpdateDirentFromFcb)
193 
194 
195 #endif
196 
197 
198 _Requires_lock_held_(_Global_critical_region_)
199 ULONG
200 FatCreateNewDirent (
201  IN PIRP_CONTEXT IrpContext,
205  )
206 
207 /*++
208 
209 Routine Description:
210 
211  This routine allocates on the disk a new dirent inside of the
212  parent directory. If a new dirent cannot be allocated (i.e.,
213  because the disk is full or the root directory is full) then
214  it raises the appropriate status. The dirent itself is
215  neither initialized nor pinned by this procedure.
216 
217 Arguments:
218 
219  ParentDirectory - Supplies the DCB for the directory in which
220  to create the new dirent
221 
222  DirentsNeeded - This is the number of continginous dirents required
223 
224 Return Value:
225 
226  ByteOffset - Returns the VBO within the Parent directory where
227  the dirent has been allocated
228 
229 --*/
230 
231 {
232  VBO UnusedVbo;
233  VBO DeletedHint;
235 
236  PBCB Bcb = NULL;
237  PDIRENT Dirent = NULL;
239 
240  PAGED_CODE();
241 
242  DebugTrace(+1, Dbg, "FatCreateNewDirent\n", 0);
243 
244  DebugTrace( 0, Dbg, " ParentDirectory = %p\n", ParentDirectory);
245 
246  //
247  // If UnusedDirentVbo is within our current file allocation then we
248  // don't have to search through the directory at all; we know just
249  // where to put it.
250  //
251  // If UnusedDirentVbo is beyond the current file allocation then
252  // there are no more unused dirents in the current allocation, though
253  // upon adding another cluster of allocation UnusedDirentVbo
254  // will point to an unused dirent. Haveing found no unused dirents
255  // we use the DeletedDirentHint to try and find a deleted dirent in
256  // the current allocation. In this also runs off the end of the file,
257  // we finally have to break down and allocate another sector. Note
258  // that simply writing beyond the current allocation will automatically
259  // do just this.
260  //
261  // We also must deal with the special case where UnusedDirentVbo and
262  // DeletedDirentHint have yet to be initialized. In this case we must
263  // first walk through the directory looking for the first deleted entry
264  // first unused dirent. After this point we continue as before.
265  // This initial state is denoted by the special value of 0xffffffff.
266  //
267 
268  UnusedVbo = ParentDirectory->Specific.Dcb.UnusedDirentVbo;
269  DeletedHint = ParentDirectory->Specific.Dcb.DeletedDirentHint;
270 
271  //
272  // Check for our first call to this routine with this Dcb. If so
273  // we have to correctly set the two hints in the Dcb.
274  //
275 
276  if (UnusedVbo == 0xffffffff || RescanDir) {
277 
278  FatRescanDirectory( IrpContext, ParentDirectory );
279 
280  UnusedVbo = ParentDirectory->Specific.Dcb.UnusedDirentVbo;
281  DeletedHint = ParentDirectory->Specific.Dcb.DeletedDirentHint;
282  }
283 
284  //
285  // Now we know that UnusedDirentVbo and DeletedDirentHint are correctly
286  // set so we check if there is already an unused dirent in the the
287  // current allocation. This is the easy case.
288  //
289 
290  DebugTrace( 0, Dbg, " UnusedVbo = %08lx\n", UnusedVbo);
291  DebugTrace( 0, Dbg, " DeletedHint = %08lx\n", DeletedHint);
292 
293  if (!RescanDir && ( UnusedVbo + (DirentsNeeded * sizeof(DIRENT)) <=
294  ParentDirectory->Header.AllocationSize.LowPart )) {
295 
296  //
297  // Get this unused dirent for the caller. We have a
298  // sporting chance that we won't have to wait.
299  //
300 
301  DebugTrace( 0, Dbg, "There is a never used entry.\n", 0);
302 
303  ByteOffset = UnusedVbo;
304 
305  UnusedVbo += DirentsNeeded * sizeof(DIRENT);
306 
307  } else {
308 
309  //
310  // Life is tough. We have to march from the DeletedDirentHint
311  // looking for a deleted dirent. If we get to EOF without finding
312  // one, we will have to allocate a new cluster.
313  //
314 
315  ByteOffset =
316  RtlFindClearBits( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
318  DeletedHint / sizeof(DIRENT) );
319 
320  //
321  // Do a quick check for a root directory allocation that failed
322  // simply because of fragmentation. Also, only attempt to defrag
323  // if the length is less that 0x40000. This is to avoid
324  // complications arising from crossing a MM view boundary (256kb).
325  // By default on DOS the root directory is only 0x2000 long.
326  //
327  // Don't try to defrag fat32 root dirs.
328  //
329 
330  if (!FatIsFat32(ParentDirectory->Vcb) &&
331  (ByteOffset == -1) &&
333  (ParentDirectory->Header.AllocationSize.LowPart <= 0x40000)) {
334 
335  ByteOffset = FatDefragDirectory( IrpContext, ParentDirectory, DirentsNeeded );
336  }
337 
338  if (ByteOffset != -1) {
339 
340  //
341  // If we consuemed deleted dirents at Deleted Hint, update.
342  // We also may have consumed some un-used dirents as well,
343  // so be sure to check for that as well.
344  //
345 
346  ByteOffset *= sizeof(DIRENT);
347 
348  if (ByteOffset == DeletedHint) {
349 
350  DeletedHint += DirentsNeeded * sizeof(DIRENT);
351  }
352 
353  if (ByteOffset + DirentsNeeded * sizeof(DIRENT) > UnusedVbo) {
354 
355  UnusedVbo = ByteOffset + DirentsNeeded * sizeof(DIRENT);
356  }
357 
358  } else {
359 
360  //
361  // We are going to have to allocate another cluster. Do
362  // so, update both the UnusedVbo and the DeletedHint and bail.
363  //
364 
365  DebugTrace( 0, Dbg, "We have to allocate another cluster.\n", 0);
366 
367  //
368  // A reason why we might fail, unrelated to physical reasons,
369  // is that we constrain to 64k directory entries to match the
370  // restriction on Win95. There are fundamental reasons to do
371  // this since searching a FAT directory is a linear operation
372  // and to allow FAT32 to toss us over the cliff is not permissable.
373  //
374 
375  if (ParentDirectory->Header.AllocationSize.LowPart >= (64 * 1024 * sizeof(DIRENT)) ||
376 
377  //
378  // Make sure we are not trying to expand the root directory on non
379  // FAT32. FAT16 and FAT12 have fixed size allocations.
380  //
381 
384 
385  DebugTrace(0, Dbg, "Full root directory or too big on FAT32. Raise Status.\n", 0);
386 
387  FatRaiseStatus( IrpContext, STATUS_CANNOT_MAKE );
388  }
389 
390  //
391  // Take the last dirent(s) in this cluster. We will allocate
392  // more clusters below.
393  //
394 
395  ByteOffset = UnusedVbo;
396  UnusedVbo += DirentsNeeded * sizeof(DIRENT);
397 
398  //
399  // Touch the directory file to cause space for the new dirents
400  // to be allocated.
401  //
402 
403  Bcb = NULL;
404 
405  _SEH2_TRY {
406 
407  PVOID Buffer;
408 
409  FatPrepareWriteDirectoryFile( IrpContext,
411  UnusedVbo,
412  1,
413  &Bcb,
414  &Buffer,
415  FALSE,
416  TRUE,
417  &Status );
418 
419  } _SEH2_FINALLY {
420 
421  FatUnpinBcb( IrpContext, Bcb );
422  } _SEH2_END;
423  }
424  }
425 
426  //
427  // If we are only requesting a single dirent, and we did not get the
428  // first dirent in a directory, then check that the preceding dirent
429  // is not an orphaned LFN. If it is, then mark it deleted. Thus
430  // reducing the possibility of an accidental pairing.
431  //
432  // Only do this when we are in Chicago Mode.
433  //
434 
435  Bcb = NULL;
436 
437  if (FatData.ChicagoMode &&
438  (DirentsNeeded == 1) &&
440  0 : 2 * sizeof(DIRENT)))) {
441  _SEH2_TRY {
442 
443  FatReadDirent( IrpContext,
445  ByteOffset - sizeof(DIRENT),
446  &Bcb,
447  &Dirent,
448  &Status );
449 
450  if ((Status != STATUS_SUCCESS) ||
451  (Dirent->FileName[0] == FAT_DIRENT_NEVER_USED)) {
452 
453  FatPopUpFileCorrupt( IrpContext, ParentDirectory );
454 
456  }
457 
458  if ((Dirent->Attributes == FAT_DIRENT_ATTR_LFN) &&
459  (Dirent->FileName[0] != FAT_DIRENT_DELETED)) {
460 
461  //
462  // Pin it, mark it, and set it dirty.
463  //
464 
465  FatPinMappedData( IrpContext,
467  ByteOffset - sizeof(DIRENT),
468  sizeof(DIRENT),
469  &Bcb );
470 
471  Dirent->FileName[0] = FAT_DIRENT_DELETED;
472 
473  FatSetDirtyBcb( IrpContext, Bcb, ParentDirectory->Vcb, TRUE );
474 
475  NT_ASSERT( RtlAreBitsSet( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
476  (ByteOffset - sizeof(DIRENT))/ sizeof(DIRENT),
477  DirentsNeeded ) );
478 
479  RtlClearBits( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
480  (ByteOffset - sizeof(DIRENT))/ sizeof(DIRENT),
481  DirentsNeeded );
482 
483  }
484 
485  } _SEH2_FINALLY {
486 
487  FatUnpinBcb( IrpContext, Bcb );
488  } _SEH2_END;
489  }
490 
491  //
492  // Assert that the dirents are in fact unused
493  //
494 
495  _SEH2_TRY {
496 
497  ULONG i;
498 
499  Bcb = NULL;
500 
501  for (i = 0; i < DirentsNeeded; i++) {
502 
503  FatReadDirent( IrpContext,
505  ByteOffset + i*sizeof(DIRENT),
506  &Bcb,
507  &Dirent,
508  &Status );
509 
510  if ((Status != STATUS_SUCCESS) ||
511  ((Dirent->FileName[0] != FAT_DIRENT_NEVER_USED) &&
512  (Dirent->FileName[0] != FAT_DIRENT_DELETED))) {
513 
514  FatPopUpFileCorrupt( IrpContext, ParentDirectory );
516  }
517  }
518 
519  } _SEH2_FINALLY {
520 
521  FatUnpinBcb( IrpContext, Bcb );
522  } _SEH2_END;
523 
524  //
525  // Set the Bits in the bitmap and move the Unused Dirent Vbo.
526  //
527 
529  ByteOffset / sizeof(DIRENT),
530  DirentsNeeded ) );
531 
532  RtlSetBits( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
533  ByteOffset / sizeof(DIRENT),
534  DirentsNeeded );
535 
536  //
537  // Save the newly computed values in the Parent Directory Fcb
538  //
539 
540  ParentDirectory->Specific.Dcb.UnusedDirentVbo = UnusedVbo;
541  ParentDirectory->Specific.Dcb.DeletedDirentHint = DeletedHint;
542 
543  DebugTrace(-1, Dbg, "FatCreateNewDirent -> (VOID)\n", 0);
544 
545  return ByteOffset;
546 }
547 
548 
549 
550 _Requires_lock_held_(_Global_critical_region_)
551 VOID
552 FatInitializeDirectoryDirent (
553  IN PIRP_CONTEXT IrpContext,
554  IN PDCB Dcb,
556  )
557 
558 /*++
559 
560 Routine Description:
561 
562  This routine converts a dirent into a directory on the disk. It does this
563  setting the directory flag in the dirent, and by allocating the necessary
564  space for the "." and ".." dirents and initializing them.
565 
566  If a new dirent cannot be allocated (i.e., because the disk is full) then
567  it raises the appropriate status.
568 
569 Arguments:
570 
571  Dcb - Supplies the Dcb denoting the file that is to be made into a
572  directory. This must be input a completely empty file with
573  an allocation size of zero.
574 
575  ParentDirent - Provides the parent Dirent for a time-stamp model.
576 
577 Return Value:
578 
579  None.
580 
581 --*/
582 
583 {
584  PBCB Bcb;
585  PVOID Buffer;
586  NTSTATUS DontCare = STATUS_SUCCESS;
587 
588  PAGED_CODE();
589 
590  DebugTrace(+1, Dbg, "FatInitializeDirectoryDirent\n", 0);
591 
592  DebugTrace( 0, Dbg, " Dcb = %p\n", Dcb);
593 
594  //
595  // Assert that we are not attempting this on the root directory.
596  //
597 
599 
600  //
601  // Assert that this is only attempted on newly created directories.
602  //
603 
604  NT_ASSERT( Dcb->Header.AllocationSize.LowPart == 0 );
605 
606  //
607  // Prepare the directory file for writing. Note that we can use a single
608  // Bcb for these two entries because we know they are the first two in
609  // the directory, and thus together do not span a page boundry. Also
610  // note that we prepare write 2 entries: one for "." and one for "..".
611  // The end of directory marker is automatically set since the whole
612  // directory is initially zero (DIRENT_NEVER_USED).
613  //
614 
615  FatPrepareWriteDirectoryFile( IrpContext,
616  Dcb,
617  0,
618  2 * sizeof(DIRENT),
619  &Bcb,
620  &Buffer,
621  FALSE,
622  TRUE,
623  &DontCare );
624 
625  NT_ASSERT( NT_SUCCESS( DontCare ));
626 
627  //
628  // Add the . and .. entries
629  //
630 
631  _SEH2_TRY {
632 
633  FatConstructDot( IrpContext, Dcb, ParentDirent, (PDIRENT)Buffer + 0);
634 
635  FatConstructDotDot( IrpContext, Dcb, ParentDirent, (PDIRENT)Buffer + 1);
636 
637  //
638  // Unpin the buffer and return to the caller.
639  //
640 
641  } _SEH2_FINALLY {
642 
643  FatUnpinBcb( IrpContext, Bcb );
644  } _SEH2_END;
645 
646  DebugTrace(-1, Dbg, "FatInitializeDirectoryDirent -> (VOID)\n", 0);
647  return;
648 }
649 
650 
651 VOID
653  IN PFCB FcbOrDcb,
655  )
656 /*++
657 
658 Routine Description:
659 
660  This routine handles tunneling of an Fcb or Dcb associated with
661  an object whose name is disappearing from a directory.
662 
663 Arguments:
664 
665  FcbOrDcb - Supplies the Fcb/Dcb whose name will be going away
666 
667  Ccb - Supplies the Ccb for the Fcb (not reqired for a Dcb) so
668  that we know which name the Fcb was opened by
669 
670 Return Value:
671 
672  None.
673 
674 --*/
675 {
676  UNICODE_STRING ShortNameWithCase = {0};
677  UNICODE_STRING DownCaseSeg;
678  WCHAR ShortNameBuffer[8+1+3];
680  USHORT i;
681 
682  PAGED_CODE();
683 
684  DebugTrace(+1, Dbg, "FatTunnelFcbOrDcb\n", 0);
685 
686  if (NodeType(FcbOrDcb) == FAT_NTC_DCB) {
687 
688  //
689  // Directory deletion. Flush all entries from this directory in
690  // the cache for this volume
691  //
692 
695 
696  } else {
697 
698  //
699  // Was a file, so throw it into the tunnel cache
700  //
701 
702  //
703  // Get the short name into UNICODE
704  //
705 
706  ShortNameWithCase.Length = 0;
707  ShortNameWithCase.MaximumLength = sizeof(ShortNameBuffer);
708  ShortNameWithCase.Buffer = ShortNameBuffer;
709 
710 #ifdef _MSC_VER
711 #pragma prefast( suppress:28931, "needed for debug build" )
712 #endif
713  Status = RtlOemStringToCountedUnicodeString( &ShortNameWithCase,
715  FALSE);
716 
717  NT_ASSERT(ShortNameWithCase.Length != 0);
718 
720 
722 
723  //
724  // Have to repair the case of the short name
725  //
726 
727  for (i = 0; i < (ShortNameWithCase.Length/sizeof(WCHAR)) &&
728  ShortNameWithCase.Buffer[i] != L'.'; i++);
729 
730  //
731  // Now pointing at the '.', or otherwise the end of name component
732  //
733 
735 
736  DownCaseSeg.Buffer = ShortNameWithCase.Buffer;
737  DownCaseSeg.MaximumLength = DownCaseSeg.Length = i*sizeof(WCHAR);
738 
739  RtlDowncaseUnicodeString(&DownCaseSeg, &DownCaseSeg, FALSE);
740  }
741 
742  i++;
743 
744  //
745  // Now pointing at first wchar of the extension.
746  //
747 
749 
750  //
751  // It is not neccesarily the case that we can rely on the flag
752  // indicating that we really have an extension.
753  //
754 
755  if ((i*sizeof(WCHAR)) < ShortNameWithCase.Length) {
756  DownCaseSeg.Buffer = &ShortNameWithCase.Buffer[i];
757  DownCaseSeg.MaximumLength = DownCaseSeg.Length = ShortNameWithCase.Length - i*sizeof(WCHAR);
758 
759  RtlDowncaseUnicodeString(&DownCaseSeg, &DownCaseSeg, FALSE);
760  }
761  }
762  }
763 
764  //
765  // ... and add it in
766  //
767 
770  &ShortNameWithCase,
773  sizeof(LARGE_INTEGER),
775  }
776 
777  DebugTrace(-1, Dbg, "FatTunnelFcbOrDcb -> (VOID)\n", 0);
778 
779  return;
780 }
781 
782 
783 
784 _Requires_lock_held_(_Global_critical_region_)
785 VOID
786 FatDeleteDirent (
787  IN PIRP_CONTEXT IrpContext,
788  IN PFCB FcbOrDcb,
789  IN PDELETE_CONTEXT DeleteContext OPTIONAL,
791  )
792 
793 /*++
794 
795 Routine Description:
796 
797  This routine Deletes on the disk the indicated dirent. It does
798  this by marking the dirent as deleted.
799 
800 Arguments:
801 
802  FcbOrDcb - Supplies the FCB/DCB for the file/directory being
803  deleted. For a file the file size and allocation must be zero.
804  (Zero allocation is implied by a zero cluster index).
805  For a directory the allocation must be zero.
806 
807  DeleteContext - This variable, if speicified, may be used to preserve
808  the file size and first cluster of file information in the dirent
809  fot the benefit of unerase utilities.
810 
811  DeleteEa - Tells us whether to delete the EA and whether to check
812  for no allocation/ Mainly TRUE. FALSE passed in from rename.
813 
814 Return Value:
815 
816  None.
817 
818 --*/
819 
820 {
821  PBCB Bcb = NULL;
822  PDIRENT Dirent = NULL;
823  NTSTATUS DontCare;
824  ULONG Offset;
825  ULONG DirentsToDelete;
826 
827  PAGED_CODE();
828 
829  DebugTrace(+1, Dbg, "FatDeleteDirent\n", 0);
830 
831  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
832 
833  //
834  // We must be holding the vcb exclusive here to deal with the locate dirent
835  // cases where it cannot be holding the parent simply. This is actually
836  // a true statement from olden daze, lets just wire in our assertion.
837  //
838  // Among other reasons, it'd be unfortunate if this raced with the
839  // rename path.
840  //
841 
843 
844  //
845  // Assert that we are not attempting this on the root directory.
846  //
847 
849 
850  //
851  // Make sure all requests have zero allocation/file size
852  //
853 
854  if (DeleteEa &&
855  ((FcbOrDcb->Header.AllocationSize.LowPart != 0) ||
856  ((NodeType(FcbOrDcb) == FAT_NTC_FCB) &&
857  (FcbOrDcb->Header.FileSize.LowPart != 0)))) {
858 
859  DebugTrace( 0, Dbg, "Called with non zero allocation/file size.\n", 0);
860 
861 #ifdef _MSC_VER
862 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
863 #endif
864  FatBugCheck( 0, 0, 0 );
865  }
866 
867  //
868  // Now, mark the dirents deleted, unpin the Bcb, and return to the caller.
869  // Assert that there isn't any allocation associated with this dirent.
870  //
871  // Note that this loop will end with Dirent pointing to the short name.
872  //
873 
874  _SEH2_TRY {
875 
876  //
877  // We must acquire our parent exclusive to synchronize with enumerators
878  // who do not hold the vcb (ex: dirctrl).
879  //
880  // This relies on our bottom up lockorder.
881  //
882 
884 
886  Offset <= FcbOrDcb->DirentOffsetWithinDirectory;
887  Offset += sizeof(DIRENT), Dirent += 1 ) {
888 
889  //
890  // If we stepped onto a new page, or this is the first iteration,
891  // unpin the old page, and pin the new one.
892  //
893 
895  ((Offset & (PAGE_SIZE - 1)) == 0)) {
896 
897  FatUnpinBcb( IrpContext, Bcb );
898 
899  FatPrepareWriteDirectoryFile( IrpContext,
901  Offset,
902  sizeof(DIRENT),
903  &Bcb,
904  (PVOID *)&Dirent,
905  FALSE,
906  TRUE,
907  &DontCare );
908  }
909 
911  Dirent->FileName[0] = FAT_DIRENT_DELETED;
912  }
913 
914  //
915  // Back Dirent off by one to point back to the short dirent.
916  //
917 
918  Dirent -= 1;
919 
920  //
921  // If there are extended attributes for this dirent, we will attempt
922  // to remove them. We ignore any errors in removing Eas.
923  //
924 
925  if (!FatIsFat32(FcbOrDcb->Vcb) &&
926  DeleteEa && (Dirent->ExtendedAttributes != 0)) {
927 
928  _SEH2_TRY {
929 
930  FatDeleteEa( IrpContext,
931  FcbOrDcb->Vcb,
932  Dirent->ExtendedAttributes,
934 
936 
937  //
938  // We catch all exceptions that Fat catches, but don't do
939  // anything with them.
940  //
941  } _SEH2_END;
942  }
943 
944  //
945  // Now clear the bits in the free dirent mask.
946  //
947 
948  DirentsToDelete = (FcbOrDcb->DirentOffsetWithinDirectory -
949  FcbOrDcb->LfnOffsetWithinDirectory) / sizeof(DIRENT) + 1;
950 
951 
952  NT_ASSERT( (FcbOrDcb->ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
953  RtlAreBitsSet( &FcbOrDcb->ParentDcb->Specific.Dcb.FreeDirentBitmap,
955  DirentsToDelete ) );
956 
957  RtlClearBits( &FcbOrDcb->ParentDcb->Specific.Dcb.FreeDirentBitmap,
959  DirentsToDelete );
960 
961  //
962  // Now, if the caller specified a DeleteContext, use it.
963  //
964 
965  if ( ARGUMENT_PRESENT( DeleteContext ) ) {
966 
967  Dirent->FileSize = DeleteContext->FileSize;
968 
969 
970  Dirent->FirstClusterOfFile = (USHORT)DeleteContext->FirstClusterOfFile;
971  }
972 
973  //
974  // If this newly deleted dirent is before the DeletedDirentHint, change
975  // the DeletedDirentHint to point here.
976  //
977 
979  FcbOrDcb->ParentDcb->Specific.Dcb.DeletedDirentHint) {
980 
981  FcbOrDcb->ParentDcb->Specific.Dcb.DeletedDirentHint =
983  }
984 
985  } _SEH2_FINALLY {
986 
987  FatUnpinBcb( IrpContext, Bcb );
988 
989  //
990  // Release our parent.
991  //
992 
993  ExReleaseResourceLite( FcbOrDcb->ParentDcb->Header.Resource );
994  } _SEH2_END;
995 
996  DebugTrace(-1, Dbg, "FatDeleteDirent -> (VOID)\n", 0);
997  return;
998 }
999 
1000 _Requires_lock_held_(_Global_critical_region_)
1001 BOOLEAN
1002 FatLfnDirentExists (
1003  IN PIRP_CONTEXT IrpContext,
1004  IN PDCB Dcb,
1007  )
1008 /*++
1009 
1010 Routine Description:
1011 
1012  This routine looks for a given Lfn in a directory
1013 
1014 Arguments:
1015 
1016  Dcb - The directory to search
1017 
1018  Lfn - The Lfn to look for
1019 
1020  Lfn - Temporary buffer to use to search for Lfn with (if < MAX_LFN then this
1021  function may cause it to be allocated from pool if not large enough.
1022 
1023 Retrn Value:
1024 
1025  BOOLEAN TRUE if it exists, FALSE if not
1026 
1027 --*/
1028 {
1029  CCB Ccb;
1030  PDIRENT Dirent;
1031  PBCB DirentBcb = NULL;
1033  BOOLEAN Result = FALSE;
1034  ULONG Flags = 0;
1035 
1036  PAGED_CODE();
1037 
1038  //
1039  // Pay performance penalty by forcing the compares to be case insensitive as
1040  // opposed to grabbing more pool for a monocased copy of the Lfn. This is slight.
1041  //
1042 
1043  Ccb.UnicodeQueryTemplate = *Lfn;
1044  Ccb.ContainsWildCards = FALSE;
1046 
1047  _SEH2_TRY {
1048 
1049  FatLocateDirent( IrpContext,
1050  Dcb,
1051  &Ccb,
1052  0,
1053  &Flags,
1054  &Dirent,
1055  &DirentBcb,
1057  NULL,
1058  LfnTmp,
1059  NULL );
1060 
1061  } _SEH2_FINALLY {
1062 
1063  if (DirentBcb) {
1064 
1065  Result = TRUE;
1066  }
1067 
1068  FatUnpinBcb(IrpContext, DirentBcb);
1069  } _SEH2_END;
1070 
1071  return Result;
1072 }
1073 
1074 
1075 _Requires_lock_held_(_Global_critical_region_)
1076 VOID
1077 FatLocateDirent (
1078  IN PIRP_CONTEXT IrpContext,
1080  IN PCCB Ccb,
1082  IN OUT PULONG Flags,
1083  OUT PDIRENT *Dirent,
1084  OUT PBCB *Bcb,
1086  OUT PBOOLEAN FileNameDos OPTIONAL,
1087  IN OUT PUNICODE_STRING LongFileName OPTIONAL,
1088  IN OUT PUNICODE_STRING OrigLongFileName OPTIONAL
1089  )
1090 
1091 /*++
1092 
1093 Routine Description:
1094 
1095  This routine locates on the disk an undeleted dirent matching a given name.
1096 
1097 Arguments:
1098 
1099  ParentDirectory - Supplies the DCB for the directory to search
1100 
1101  Ccb - Contains a context control block with all matching information.
1102 
1103  OffsetToStartSearchFrom - Supplies the VBO within the parent directory
1104  from which to start looking for another real dirent.
1105 
1106  Dirent - Receives a pointer to the located dirent if one was found
1107  or NULL otherwise.
1108 
1109  Bcb - Receives the Bcb for the located dirent if one was found or
1110  NULL otherwise.
1111 
1112  ByteOffset - Receives the VBO within the Parent directory for
1113  the located dirent if one was found, or 0 otherwise.
1114 
1115  FileNameDos - Receives TRUE if the element of the dirent we hit on
1116  was the short (non LFN) side
1117 
1118  LongFileName - If specified, this parameter returns the long file name
1119  associated with the returned dirent. Note that it is the caller's
1120  responsibility to provide the buffer (and set MaximumLength
1121  accordingly) for this unicode string. The Length field is reset
1122  to 0 by this routine on invocation. If the supplied buffer is not
1123  large enough, a new one will be allocated from pool.
1124 
1125 Return Value:
1126 
1127  None.
1128 
1129 --*/
1130 
1131 {
1133 
1134  OEM_STRING Name;
1135  UCHAR NameBuffer[12];
1136 
1137  BOOLEAN UpcasedLfnValid = FALSE;
1138  UNICODE_STRING UpcasedLfn = {0};
1139  WCHAR LocalLfnBuffer[32];
1140 
1141 
1142  BOOLEAN LfnInProgress = FALSE;
1143  UCHAR LfnChecksum = 0;
1144  ULONG LfnSize = 0;
1145  ULONG LfnIndex = 0;
1146  UCHAR Ordinal = 0;
1147  VBO LfnByteOffset = 0;
1148 
1149  TimerStart(Dbg);
1150 
1151  PAGED_CODE();
1152 
1153  DebugTrace(+1, Dbg, "FatLocateDirent\n", 0);
1154 
1155  DebugTrace( 0, Dbg, " ParentDirectory = %p\n", ParentDirectory);
1156  DebugTrace( 0, Dbg, " OffsetToStartSearchFrom = %08lx\n", OffsetToStartSearchFrom);
1157  DebugTrace( 0, Dbg, " Dirent = %p\n", Dirent);
1158  DebugTrace( 0, Dbg, " Bcb = %p\n", Bcb);
1159  DebugTrace( 0, Dbg, " ByteOffset = %08lx\n", *ByteOffset);
1160 
1161  //
1162  // We must have acquired the parent or the vcb to synchronize with deletion. This
1163  // is important since we can't survive racing a thread marking a series of lfn
1164  // dirents deleted - we'd get a bogus ordinal, and otherwise get really messed up.
1165  //
1166  // This routine cannot do the acquire since it would be out-of-order with respect
1167  // to the Bcb resources on iterative calls. Our order has Bcbs as the inferior resource.
1168  //
1169  // Deletion always grabs the parent (safely - this used to not be possible until the
1170  // multiple fcb lockorder was fixed to be bottom up!). Deletion always occurs with
1171  // the vcb held exclusive as well, and this will cover the cases where we can't easily
1172  // hold the parent here, see above.
1173  //
1174 
1179 
1180  //
1181  // The algorithm here is pretty simple. We just walk through the
1182  // parent directory until we:
1183  //
1184  // A) Find a matching entry.
1185  // B) Can't Wait
1186  // C) Hit the End of Directory
1187  // D) Hit Eof
1188  //
1189  // In the first case we found it, in the latter three cases we did not.
1190  //
1191 
1192  UNREFERENCED_PARAMETER( Flags ); // future use
1193 
1194 
1195  Name.MaximumLength = 12;
1196  Name.Buffer = (PCHAR)NameBuffer;
1197 
1198  UpcasedLfn.Length = 0;
1199  UpcasedLfn.MaximumLength = sizeof( LocalLfnBuffer);
1200  UpcasedLfn.Buffer = LocalLfnBuffer;
1201 
1202 
1203  //
1204  // If we were given a non-NULL Bcb, compute the new Dirent address
1205  // from the prior one, or unpin the Bcb if the new Dirent is not pinned.
1206  //
1207 
1208  if (*Bcb != NULL) {
1209 
1211 
1212  *Dirent += (OffsetToStartSearchFrom - *ByteOffset) / sizeof(DIRENT);
1213 
1214  } else {
1215 
1216  FatUnpinBcb( IrpContext, *Bcb );
1217  }
1218  }
1219 
1220  //
1221  // Init the Lfn if we were given one.
1222  //
1223 
1224  if (ARGUMENT_PRESENT(LongFileName)) {
1225 
1226  LongFileName->Length = 0;
1227  }
1228 
1229  if (ARGUMENT_PRESENT(OrigLongFileName)) {
1230 
1231  OrigLongFileName->Length = 0;
1232  }
1233 
1234  //
1235  // Init the FileNameDos flag
1236  //
1237 
1238  if (FileNameDos) {
1239 
1240  *FileNameDos = FALSE;
1241  }
1242 
1243  //
1244  // Round up OffsetToStartSearchFrom to the nearest Dirent, and store
1245  // in ByteOffset. Note that this wipes out the prior value.
1246  //
1247 
1248  *ByteOffset = (OffsetToStartSearchFrom + (sizeof(DIRENT) - 1))
1249  & ~(sizeof(DIRENT) - 1);
1250 
1251  _SEH2_TRY {
1252 
1253  while ( TRUE ) {
1254 
1255  BOOLEAN FoundValidLfn;
1256 
1257  UpcasedLfnValid = FALSE;
1258 
1259 
1260  //
1261  // Try to read in the dirent
1262  //
1263 
1264  FatReadDirent( IrpContext,
1266  *ByteOffset,
1267  Bcb,
1268  Dirent,
1269  &Status );
1270 
1271  //
1272  // If End Directory dirent or EOF, set all out parameters to
1273  // indicate entry not found and, like, bail.
1274  //
1275  // Note that the order of evaluation here is important since we
1276  // cannot check the first character of the dirent until after we
1277  // know we are not beyond EOF
1278  //
1279 
1280  if ((Status == STATUS_END_OF_FILE) ||
1281  ((*Dirent)->FileName[0] == FAT_DIRENT_NEVER_USED)) {
1282 
1283  DebugTrace( 0, Dbg, "End of directory: entry not found.\n", 0);
1284 
1285  //
1286  // If there is a Bcb, unpin it and set it to null
1287  //
1288 
1289  FatUnpinBcb( IrpContext, *Bcb );
1290 
1291  *Dirent = NULL;
1292  *ByteOffset = 0;
1293  break;
1294  }
1295 
1296  //
1297  // If the entry is marked deleted, skip. If there was an Lfn in
1298  // progress we throw it out at this point.
1299  //
1300 
1301  if ((*Dirent)->FileName[0] == FAT_DIRENT_DELETED) {
1302 
1303  LfnInProgress = FALSE;
1304  goto GetNextDirent;
1305  }
1306 
1307  //
1308  // If we have wandered onto an LFN entry, try to interpret it.
1309  //
1310 
1311  if (FatData.ChicagoMode &&
1312  ARGUMENT_PRESENT(LongFileName) &&
1313  ((*Dirent)->Attributes == FAT_DIRENT_ATTR_LFN)) {
1314 
1315  PLFN_DIRENT Lfn;
1316 
1317  Lfn = (PLFN_DIRENT)*Dirent;
1318 
1319  if (LfnInProgress) {
1320 
1321  //
1322  // Check for a proper continuation of the Lfn in progress.
1323  //
1324 
1325  if ((Lfn->Ordinal & FAT_LAST_LONG_ENTRY) ||
1326  (Lfn->Ordinal == 0) ||
1327  (Lfn->Ordinal != Ordinal - 1) ||
1328  (Lfn->Checksum != LfnChecksum) ||
1329  (Lfn->MustBeZero != 0)) {
1330 
1331  //
1332  // The Lfn is not proper, stop constructing it.
1333  //
1334 
1335  LfnInProgress = FALSE;
1336 
1337  } else {
1338 
1339  NT_ASSERT( ((LfnIndex % 13) == 0) && LfnIndex );
1340 
1341  LfnIndex -= 13;
1342 
1343  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+0],
1344  &Lfn->Name1[0],
1345  5*sizeof(WCHAR) );
1346 
1347  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+5],
1348  &Lfn->Name2[0],
1349  6 * sizeof(WCHAR) );
1350 
1351  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+11],
1352  &Lfn->Name3[0],
1353  2 * sizeof(WCHAR) );
1354 
1355  Ordinal = Lfn->Ordinal;
1357  }
1358  }
1359 
1360  //
1361  // Now check (maybe again) if we should analyze this entry
1362  // for a possible last entry.
1363  //
1364 
1365  if ((!LfnInProgress) &&
1366  (Lfn->Ordinal & FAT_LAST_LONG_ENTRY) &&
1367  ((Lfn->Ordinal & ~FAT_LAST_LONG_ENTRY) <= MAX_LFN_DIRENTS) &&
1368  (Lfn->MustBeZero == 0)) {
1369 
1370  BOOLEAN CheckTail = FALSE;
1371 
1372  Ordinal = Lfn->Ordinal & ~FAT_LAST_LONG_ENTRY;
1373 
1374  //
1375  // We're usually permissive (following the lead of Win9x) when we find
1376  // malformation of the LFN dirent pile. I'm not sure this is a good idea,
1377  // so I'm going to trigger corruption on this particularly ugly one. Perhaps
1378  // we should come back and redo the original code here with this in mind in the
1379  // future.
1380  //
1381 
1382  if (Ordinal == 0) {
1383 
1384  //
1385  // First LFN in the pile was zero marked as the last. This is never
1386  // possible since oridinals are 1-based.
1387  //
1388 
1389  FatPopUpFileCorrupt( IrpContext, ParentDirectory );
1391  }
1392 
1393  LfnIndex = (Ordinal - 1) * 13;
1394 
1395  FatEnsureStringBufferEnough( LongFileName,
1396  (USHORT)((LfnIndex + 13) << 1));
1397 
1398  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+0],
1399  &Lfn->Name1[0],
1400  5*sizeof(WCHAR));
1401 
1402  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+5],
1403  &Lfn->Name2[0],
1404  6 * sizeof(WCHAR) );
1405 
1406  RtlCopyMemory( &LongFileName->Buffer[LfnIndex+11],
1407  &Lfn->Name3[0],
1408  2 * sizeof(WCHAR) );
1409 
1410  //
1411  // Now compute the Lfn size and make sure that the tail
1412  // bytes are correct.
1413  //
1414 
1415  while (LfnIndex != (ULONG)Ordinal * 13) {
1416 
1417  if (!CheckTail) {
1418 
1419  if (LongFileName->Buffer[LfnIndex] == 0x0000) {
1420 
1421  LfnSize = LfnIndex;
1422  CheckTail = TRUE;
1423  }
1424 
1425  } else {
1426 
1427  if (LongFileName->Buffer[LfnIndex] != 0xffff) {
1428 
1429  break;
1430  }
1431  }
1432 
1433  LfnIndex += 1;
1434  }
1435 
1436  //
1437  // If we exited this loop prematurely, the LFN is not valid.
1438  //
1439 
1440  if (LfnIndex == (ULONG)Ordinal * 13) {
1441 
1442  //
1443  // If we didn't find the NULL terminator, then the size
1444  // is LfnIndex.
1445  //
1446 
1447  if (!CheckTail) {
1448 
1449  LfnSize = LfnIndex;
1450  }
1451 
1452  LfnIndex -= 13;
1453  LfnInProgress = TRUE;
1454  LfnChecksum = Lfn->Checksum;
1456  }
1457  }
1458 
1459  //
1460  // Move on to the next dirent.
1461  //
1462 
1463  goto GetNextDirent;
1464  }
1465 
1466  //
1467  // If this is the volume label, skip. Note that we never arrive here
1468  // while building the LFN. If we did, we weren't asked to find LFNs
1469  // and that is another good reason to skip this LFN fragment.
1470  //
1471 
1472  if (FlagOn((*Dirent)->Attributes, FAT_DIRENT_ATTR_VOLUME_ID)) {
1473 
1474  //
1475  // If we actually were asked to hand back volume labels,
1476  // do it.
1477  //
1478 
1480 
1481  break;
1482  }
1483 
1484  goto GetNextDirent;
1485  }
1486 
1487  //
1488  // We may have just stepped off a valid Lfn run. Check to see if
1489  // it is indeed valid for the following dirent.
1490  //
1491 
1492  if (LfnInProgress &&
1493  (*ByteOffset == LfnByteOffset + sizeof(DIRENT)) &&
1494  (LfnIndex == 0) &&
1495  (FatComputeLfnChecksum(*Dirent) == LfnChecksum)) {
1496 
1497  NT_ASSERT( Ordinal == 1);
1498 
1499  FoundValidLfn = TRUE;
1500  LongFileName->Length = (USHORT)(LfnSize * sizeof(WCHAR));
1501 
1502 
1503  if (ARGUMENT_PRESENT(OrigLongFileName)) {
1504  *OrigLongFileName = *LongFileName;
1505  }
1506 
1507  } else {
1508 
1509  FoundValidLfn = FALSE;
1510  }
1511 
1512 
1513 
1514  //
1515  // If we are supposed to match all entries, then match this entry.
1516  //
1517 
1519 
1520  break;
1521  }
1522 
1523  //
1524  // Check against the short name given if one was.
1525  //
1526 
1528 
1529  if (Ccb->ContainsWildCards) {
1530 
1531  //
1532  // If we get one, note that all out parameters are already set.
1533  //
1534 
1535  (VOID)Fat8dot3ToString( IrpContext, (*Dirent), FALSE, &Name );
1536 
1537  //
1538  // For fat we special case the ".." dirent because we want it to
1539  // match ????????.??? and to do that we change ".." to "." before
1540  // calling the Fsrtl routine. But only do this if the expression
1541  // is greater than one character long.
1542  //
1543 
1544  if ((Name.Length == 2) &&
1545  (Name.Buffer[0] == '.') &&
1546  (Name.Buffer[1] == '.') &&
1547  (Ccb->OemQueryTemplate.Wild.Length > 1)) {
1548 
1549  Name.Length = 1;
1550  }
1551 
1552  if (FatIsNameInExpression( IrpContext,
1553  Ccb->OemQueryTemplate.Wild,
1554  Name)) {
1555 
1556  DebugTrace( 0, Dbg, "Entry found: Name = \"%Z\"\n", &Name);
1557  DebugTrace( 0, Dbg, " VBO = %08lx\n", *ByteOffset);
1558 
1559  if (FileNameDos) {
1560 
1561  *FileNameDos = TRUE;
1562  }
1563 
1565 
1566  break;
1567  }
1568 
1569  } else {
1570 
1571  //
1572  // Do the quickest 8.3 equivalency check possible
1573  //
1574 
1575  if (!FlagOn((*Dirent)->Attributes, FAT_DIRENT_ATTR_VOLUME_ID) &&
1576  (*(PULONG)&(Ccb->OemQueryTemplate.Constant[0]) == *(PULONG)&((*Dirent)->FileName[0])) &&
1577  (*(PULONG)&(Ccb->OemQueryTemplate.Constant[4]) == *(PULONG)&((*Dirent)->FileName[4])) &&
1578  (*(PUSHORT)&(Ccb->OemQueryTemplate.Constant[8]) == *(PUSHORT)&((*Dirent)->FileName[8])) &&
1579  (*(PUCHAR)&(Ccb->OemQueryTemplate.Constant[10]) == *(PUCHAR)&((*Dirent)->FileName[10]))) {
1580 
1581  DebugTrace( 0, Dbg, "Entry found.\n", 0);
1582 
1583  if (FileNameDos) {
1584 
1585  *FileNameDos = TRUE;
1586  }
1587 
1589 
1590  break;
1591  }
1592  }
1593  }
1594 
1595  //
1596  // No matches were found with the short name. If an LFN exists,
1597  // use it for the search.
1598  //
1599 
1600  if (FoundValidLfn) {
1601 
1602 
1603  //
1604  // First do a quick check here for different sized constant
1605  // name and expression before upcasing.
1606  //
1607 
1608  if (!Ccb->ContainsWildCards &&
1609  (Ccb->UnicodeQueryTemplate.Length != (USHORT)(LfnSize * sizeof(WCHAR)))) {
1610 
1611  //
1612  // Move on to the next dirent.
1613  //
1614 
1615  FoundValidLfn = FALSE;
1616  LongFileName->Length = 0;
1617  if (OrigLongFileName) {
1618  OrigLongFileName->Length = 0;
1619  }
1620 
1621  goto GetNextDirent;
1622  }
1623 
1624 
1625 
1626  if (!UpcasedLfnValid) {
1627 
1628  //
1629  // We need to upcase the name we found on disk.
1630  // We need a buffer. Try to avoid doing an allocation.
1631  //
1632 
1633  FatEnsureStringBufferEnough( &UpcasedLfn,
1634  LongFileName->Length);
1635 
1636  Status = RtlUpcaseUnicodeString( &UpcasedLfn,
1637  LongFileName,
1638  FALSE );
1639 
1640  if (!NT_SUCCESS(Status)) {
1641 
1642  FatNormalizeAndRaiseStatus( IrpContext, Status );
1643  }
1644 
1645 
1646  UpcasedLfnValid = TRUE;
1647 
1648  }
1649 
1650  //
1651  // Do the compare
1652  //
1653 
1654  if (Ccb->ContainsWildCards) {
1655 
1656  if (FsRtlIsNameInExpression( &Ccb->UnicodeQueryTemplate,
1657  &UpcasedLfn,
1658  TRUE,
1659  NULL )) {
1660 
1661  break;
1662  }
1663 
1664  } else {
1665 
1666  if (FsRtlAreNamesEqual( &Ccb->UnicodeQueryTemplate,
1667  &UpcasedLfn,
1669  NULL )) {
1670 
1671  break;
1672  }
1673 
1674 
1675  }
1676 
1677  }
1678 
1679  //
1680  // This long name was not a match. Zero out the Length field.
1681  //
1682 
1683  if (FoundValidLfn) {
1684 
1685  FoundValidLfn = FALSE;
1686  LongFileName->Length = 0;
1687 
1688 
1689  if (OrigLongFileName) {
1690  OrigLongFileName->Length = 0;
1691  }
1692  }
1693 
1694 GetNextDirent:
1695 
1696  //
1697  // Move on to the next dirent.
1698  //
1699 
1700  *ByteOffset += sizeof(DIRENT);
1701  *Dirent += 1;
1702  }
1703 
1704  } _SEH2_FINALLY {
1705 
1706  FatFreeStringBuffer( &UpcasedLfn );
1707 
1708 
1709  } _SEH2_END;
1710 
1711  DebugTrace(-1, Dbg, "FatLocateDirent -> (VOID)\n", 0);
1712 
1713  TimerStop(Dbg,"FatLocateDirent");
1714 
1715  return;
1716 }
1717 
1718 
1719 _Requires_lock_held_(_Global_critical_region_)
1720 VOID
1721 FatLocateSimpleOemDirent (
1722  IN PIRP_CONTEXT IrpContext,
1725  OUT PDIRENT *Dirent,
1726  OUT PBCB *Bcb,
1728  )
1729 
1730 /*++
1731 
1732 Routine Description:
1733 
1734  This routine locates on the disk an undelted simple Oem dirent. By simple
1735  I mean that FileName cannot contain any extended characters, and we do
1736  not search LFNs or return them.
1737 
1738 Arguments:
1739 
1740  ParentDirectory - Supplies the DCB for the directory in which
1741  to search
1742 
1743  FileName - Supplies the filename to search for. The name may contain
1744  wild cards
1745 
1746  OffsetToStartSearchFrom - Supplies the VBO within the parent directory
1747  from which to start looking for another real dirent.
1748 
1749  Dirent - Receives a pointer to the located dirent if one was found
1750  or NULL otherwise.
1751 
1752  Bcb - Receives the Bcb for the located dirent if one was found or
1753  NULL otherwise.
1754 
1755  ByteOffset - Receives the VBO within the Parent directory for
1756  the located dirent if one was found, or 0 otherwise.
1757 
1758 Return Value:
1759 
1760  None.
1761 
1762 --*/
1763 
1764 {
1765  CCB LocalCcb;
1766 
1767  PAGED_CODE();
1768 
1769  //
1770  // Note, this routine is called rarely, so performance is not critical.
1771  // Just fill in a Ccb structure on my stack with the values that are
1772  // required.
1773  //
1774 
1775  FatStringTo8dot3( IrpContext,
1776  *FileName,
1777  &LocalCcb.OemQueryTemplate.Constant );
1778  LocalCcb.ContainsWildCards = FALSE;
1779  LocalCcb.Flags = 0;
1780 
1781  FatLocateDirent( IrpContext,
1783  &LocalCcb,
1784  0,
1785  NULL,
1786  Dirent,
1787  Bcb,
1788  ByteOffset,
1789  NULL,
1790  NULL,
1791  NULL );
1792 
1793  return;
1794 }
1795 
1796 
1797 
1798 _Requires_lock_held_(_Global_critical_region_)
1799 VOID
1800 FatLocateVolumeLabel (
1801  IN PIRP_CONTEXT IrpContext,
1802  IN PVCB Vcb,
1803  OUT PDIRENT *Dirent,
1804  OUT PBCB *Bcb,
1806  )
1807 
1808 /*++
1809 
1810 Routine Description:
1811 
1812  This routine locates on the disk a dirent representing the volume
1813  label. It does this by searching the root directory for a special
1814  volume label dirent.
1815 
1816 Arguments:
1817 
1818  Vcb - Supplies the VCB for the volume to search
1819 
1820  Dirent - Receives a pointer to the located dirent if one was found
1821  or NULL otherwise.
1822 
1823  Bcb - Receives the Bcb for the located dirent if one was found or
1824  NULL otherwise.
1825 
1826  ByteOffset - Receives the VBO within the Parent directory for
1827  the located dirent if one was found, or 0 otherwise.
1828 
1829 Return Value:
1830 
1831  None.
1832 
1833 --*/
1834 
1835 {
1837 
1838  PAGED_CODE();
1839 
1840  DebugTrace(+1, Dbg, "FatLocateVolumeLabel\n", 0);
1841 
1842  DebugTrace( 0, Dbg, " Vcb = %p\n", Vcb);
1843  DebugTrace( 0, Dbg, " Dirent = %p\n", Dirent);
1844  DebugTrace( 0, Dbg, " Bcb = %p\n", Bcb);
1845  DebugTrace( 0, Dbg, " ByteOffset = %08lx\n", *ByteOffset);
1846 
1847  //
1848  // The algorithm here is really simple. We just walk through the
1849  // root directory until we:
1850  //
1851  // A) Find the non-deleted volume label
1852  // B) Can't Wait
1853  // C) Hit the End of Directory
1854  // D) Hit Eof
1855  //
1856  // In the first case we found it, in the latter three cases we did not.
1857  //
1858 
1859  *Bcb = NULL;
1860  *ByteOffset = 0;
1861 
1862  while ( TRUE ) {
1863 
1864  //
1865  // Try to read in the dirent
1866  //
1867 
1868  FatReadDirent( IrpContext,
1869  Vcb->RootDcb,
1870  *ByteOffset,
1871  Bcb,
1872  Dirent,
1873  &Status );
1874 
1875  //
1876  // If End Directory dirent or EOF, set all out parameters to
1877  // indicate volume label not found and, like, bail.
1878  //
1879  // Note that the order of evaluation here is important since we cannot
1880  // check the first character of the dirent until after we know we
1881  // are not beyond EOF
1882  //
1883 
1884  if ((Status == STATUS_END_OF_FILE) ||
1885  ((*Dirent)->FileName[0] == FAT_DIRENT_NEVER_USED)) {
1886 
1887  DebugTrace( 0, Dbg, "Volume label not found.\n", 0);
1888 
1889  //
1890  // If there is a Bcb, unpin it and set it to null
1891  //
1892 
1893  FatUnpinBcb( IrpContext, *Bcb );
1894 
1895  *Dirent = NULL;
1896  *ByteOffset = 0;
1897  break;
1898  }
1899 
1900  //
1901  // If the entry is the non-deleted volume label break from the loop.
1902  //
1903  // Note that all out parameters are already correctly set.
1904  //
1905 
1906  if ((((*Dirent)->Attributes & ~FAT_DIRENT_ATTR_ARCHIVE) == FAT_DIRENT_ATTR_VOLUME_ID) &&
1907  ((*Dirent)->FileName[0] != FAT_DIRENT_DELETED)) {
1908 
1909  DebugTrace( 0, Dbg, "Volume label found at VBO = %08lx\n", *ByteOffset);
1910 
1911  //
1912  // We may set this dirty, so pin it.
1913  //
1914 
1915  FatPinMappedData( IrpContext,
1916  Vcb->RootDcb,
1917  *ByteOffset,
1918  sizeof(DIRENT),
1919  Bcb );
1920 
1921  break;
1922  }
1923 
1924  //
1925  // Move on to the next dirent.
1926  //
1927 
1928  *ByteOffset += sizeof(DIRENT);
1929  *Dirent += 1;
1930  }
1931 
1932 
1933  DebugTrace(-1, Dbg, "FatLocateVolumeLabel -> (VOID)\n", 0);
1934 
1935  return;
1936 }
1937 
1938 
1939 
1940 _Requires_lock_held_(_Global_critical_region_)
1941 VOID
1942 FatGetDirentFromFcbOrDcb (
1943  IN PIRP_CONTEXT IrpContext,
1944  IN PFCB FcbOrDcb,
1946  OUT PDIRENT *Dirent,
1947  OUT PBCB *Bcb
1948  )
1949 
1950 /*++
1951 
1952 Routine Description:
1953 
1954  This routine reads locates on the disk the dirent denoted by the
1955  specified Fcb/Dcb.
1956 
1957 Arguments:
1958 
1959  FcbOrDcb - Supplies the FCB/DCB for the file/directory whose dirent
1960  we are trying to read in. This must not be the root dcb.
1961 
1962  Dirent - Receives a pointer to the dirent
1963 
1964  Bcb - Receives the Bcb for the dirent
1965 
1966 Return Value:
1967 
1968  None.
1969 
1970 --*/
1971 
1972 {
1973  NTSTATUS DontCare = STATUS_SUCCESS;
1974 
1975  PAGED_CODE();
1976 
1977  DebugTrace(+1, Dbg, "FatGetDirentFromFcbOrDcb\n", 0);
1978 
1979  DebugTrace( 0, Dbg, " FcbOrDcb = %p\n", FcbOrDcb);
1980  DebugTrace( 0, Dbg, " Dirent = %p\n", Dirent);
1981  DebugTrace( 0, Dbg, " Bcb = %p\n", Bcb);
1982 
1983  //
1984  // Assert that we are not attempting this on the root directory.
1985  //
1986 
1988 
1989  //
1990  // We know the offset of the dirent within the directory file,
1991  // so we just read it (with pinning).
1992  //
1993 
1994  FatReadDirectoryFile( IrpContext,
1997  sizeof(DIRENT),
1998  TRUE,
1999  Bcb,
2000  (PVOID *)Dirent,
2001  &DontCare );
2002 
2003  //
2004  // Previous call can fail. We used to assert success, but we use this
2005  // as part of volume verification (DetermineAndMarkFcbCondition) after
2006  // media has been removed. Clearly the directory could shrink and we
2007  // would try to read beyond filesize.
2008  //
2009  // The caller will note this via NULL pointers for Bcb/Buffer. Note that
2010  // both asserts below are OK since this should never happen fixed media.
2011  //
2012  // This was a Prefix catch.
2013  //
2014 
2016  NT_SUCCESS( DontCare ));
2017 
2018  //
2019  // Note also that the only way this could fail is if the Fcb was being
2020  // verified. This can't happen if the Fcb is in good condition.
2021  //
2022  // Also a Prefix catch.
2023  //
2024 
2026 
2027  //
2028  // This should never happen except in very specific cases (during volume
2029  // verify) but we'll handle and raise here to save all callers checking the
2030  // pointers.
2031  //
2032 
2033  if ((NULL == *Dirent) && !ReturnOnFailure) {
2034 
2035  NT_ASSERT( FALSE);
2037  }
2038 
2039  DebugTrace(-1, Dbg, "FatGetDirentFromFcbOrDcb -> (VOID)\n", 0);
2040 }
2041 
2042 
2043 
2044 _Requires_lock_held_(_Global_critical_region_)
2045 BOOLEAN
2046 FatIsDirectoryEmpty (
2047  IN PIRP_CONTEXT IrpContext,
2048  IN PDCB Dcb
2049  )
2050 
2051 /*++
2052 
2053 Routine Description:
2054 
2055  This routine indicates to the caller if the specified directory
2056  is empty. (i.e., it is not the root dcb and it only contains
2057  the "." and ".." entries, or deleted files).
2058 
2059 Arguments:
2060 
2061  Dcb - Supplies the DCB for the directory being queried.
2062 
2063 Return Value:
2064 
2065  BOOLEAN - Returns TRUE if the directory is empty and
2066  FALSE if the directory and is not empty.
2067 
2068 --*/
2069 
2070 {
2071  PBCB Bcb;
2072  ULONG ByteOffset;
2073  PDIRENT Dirent = NULL;
2074 
2075  BOOLEAN IsDirectoryEmpty = FALSE;
2076 
2078 
2079  PAGED_CODE();
2080 
2081  DebugTrace(+1, Dbg, "FatIsDirectoryEmpty\n", 0);
2082 
2083  DebugTrace( 0, Dbg, " Dcb = %p\n", Dcb);
2084  DebugTrace( 0, Dbg, " IsDirectoryEmpty = %08lx\n", IsDirectoryEmpty);
2085 
2086  //
2087  // Check to see if the first entry is an and of directory marker.
2088  // For the root directory we check at Vbo = 0, for normal directories
2089  // we check after the "." and ".." entries.
2090  //
2091 
2092  ByteOffset = (NodeType(Dcb) == FAT_NTC_ROOT_DCB) ? 0 : 2*sizeof(DIRENT);
2093 
2094  //
2095  // We just march through the directory looking for anything other
2096  // than deleted files, LFNs, an EOF, or end of directory marker.
2097  //
2098 
2099  Bcb = NULL;
2100 
2101  _SEH2_TRY {
2102 
2103  while ( TRUE ) {
2104 
2105  //
2106  // Try to read in the dirent
2107  //
2108 
2109  FatReadDirent( IrpContext,
2110  Dcb,
2111  ByteOffset,
2112  &Bcb,
2113  &Dirent,
2114  &Status );
2115 
2116  //
2117  // If End Directory dirent or EOF, set IsDirectoryEmpty to TRUE and,
2118  // like, bail.
2119  //
2120  // Note that the order of evaluation here is important since we cannot
2121  // check the first character of the dirent until after we know we
2122  // are not beyond EOF
2123  //
2124 
2125  if ((Status == STATUS_END_OF_FILE) ||
2126  (Dirent->FileName[0] == FAT_DIRENT_NEVER_USED)) {
2127 
2128  DebugTrace( 0, Dbg, "Empty. Last exempt entry at VBO = %08lx\n", ByteOffset);
2129 
2130  IsDirectoryEmpty = TRUE;
2131  break;
2132  }
2133 
2134  //
2135  // If this dirent is NOT deleted or an LFN set IsDirectoryEmpty to
2136  // FALSE and, like, bail.
2137  //
2138 
2139  if ((Dirent->FileName[0] != FAT_DIRENT_DELETED) &&
2140  (Dirent->Attributes != FAT_DIRENT_ATTR_LFN)) {
2141 
2142 
2143  break;
2144 
2145 
2146  }
2147 
2148  //
2149  // Move on to the next dirent.
2150  //
2151 
2152  ByteOffset += sizeof(DIRENT);
2153  Dirent += 1;
2154  }
2155 
2156  } _SEH2_FINALLY {
2157 
2158  FatUnpinBcb( IrpContext, Bcb );
2159  } _SEH2_END;
2160 
2161  DebugTrace(-1, Dbg, "FatIsDirectoryEmpty -> %ld\n", IsDirectoryEmpty);
2162 
2163  return IsDirectoryEmpty;
2164 }
2165 
2166 
2167 
2168 
2169 
2170 VOID
2172  IN PIRP_CONTEXT IrpContext,
2173  IN OUT PDIRENT Dirent,
2175  IN BOOLEAN ComponentReallyLowercase,
2176  IN BOOLEAN ExtensionReallyLowercase,
2179  IN BOOLEAN ZeroAndSetTimeFields,
2180  IN PLARGE_INTEGER SetCreationTime OPTIONAL
2181  )
2182 
2183 /*++
2184 
2185 Routine Description:
2186 
2187  This routine modifies the fields of a dirent.
2188 
2189 Arguments:
2190 
2191  Dirent - Supplies the dirent being modified.
2192 
2193  FileName - Supplies the name to store in the Dirent. This
2194  name must not contain wildcards.
2195 
2196  ComponentReallyLowercase - This boolean indicates that the User Specified
2197  compoent name was really all a-z and < 0x80 characters. We set the
2198  magic bit in this case.
2199 
2200  ExtensionReallyLowercase - Same as above, but for the extension.
2201 
2202  Lfn - May supply a long file name.
2203 
2204  Attributes - Supplies the attributes to store in the dirent
2205 
2206  ZeroAndSetTimeFields - Tells whether or not to initially zero the dirent
2207  and update the time fields.
2208 
2209  SetCreationTime - If specified, contains a timestamp to use as the creation
2210  time of this dirent
2211 
2212 Return Value:
2213 
2214  None.
2215 
2216 --*/
2217 
2218 {
2219  PAGED_CODE();
2220 
2221  DebugTrace(+1, Dbg, "FatConstructDirent\n", 0);
2222 
2223  DebugTrace( 0, Dbg, " Dirent = %p\n", Dirent);
2224  DebugTrace( 0, Dbg, " FileName = %Z\n", FileName);
2225  DebugTrace( 0, Dbg, " Attributes = %08lx\n", Attributes);
2226 
2227  if (ZeroAndSetTimeFields) {
2228 
2229  RtlZeroMemory( Dirent, sizeof(DIRENT) );
2230  }
2231 
2232  //
2233  // We just merrily go and fill up the dirent with the fields given.
2234  //
2235 
2236  FatStringTo8dot3( IrpContext, *FileName, (PFAT8DOT3)&Dirent->FileName[0] );
2237 
2238  if (ZeroAndSetTimeFields || SetCreationTime) {
2239 
2240  LARGE_INTEGER Time, SaveTime;
2241 
2242  KeQuerySystemTime( &Time );
2243 
2244  if (FatData.ChicagoMode) {
2245 
2246  if (!SetCreationTime || !FatNtTimeToFatTime( IrpContext,
2247  SetCreationTime,
2248  FALSE,
2249  &Dirent->CreationTime,
2250  &Dirent->CreationMSec )) {
2251 
2252  //
2253  // No tunneled time or the tunneled time was bogus. Since we aren't
2254  // responsible for initializing the to-be-created Fcb with creation
2255  // time, we can't do the usual thing and let NtTimeToFatTime perform
2256  // rounding on the timestamp - this would mess up converting to the
2257  // LastWriteTime below.
2258  //
2259 
2260  SaveTime = Time;
2261 
2262  if (!FatNtTimeToFatTime( IrpContext,
2263  &SaveTime,
2264  FALSE,
2265  &Dirent->CreationTime,
2266  &Dirent->CreationMSec )) {
2267 
2268  //
2269  // Failed again. Wow.
2270  //
2271 
2273  Dirent->CreationMSec = 0;
2274  }
2275  }
2276  }
2277 
2278  if (ZeroAndSetTimeFields) {
2279 
2280  //
2281  // We only touch the other timestamps if we are initializing the dirent
2282  //
2283 
2284  if (!FatNtTimeToFatTime( IrpContext,
2285  &Time,
2286  TRUE,
2288  NULL )) {
2289 
2290  DebugTrace( 0, Dbg, "Current time invalid.\n", 0);
2291 
2293  }
2294 
2295  if (FatData.ChicagoMode) {
2296 
2297  Dirent->LastAccessDate = Dirent->LastWriteTime.Date;
2298  }
2299  }
2300  }
2301 
2302  //
2303  // Copy the attributes
2304  //
2305 
2306  Dirent->Attributes = (UCHAR)Attributes;
2307 
2308  //
2309  // Set the magic bit here, to tell dirctrl.c that this name is really
2310  // lowercase.
2311  //
2312 
2313  Dirent->NtByte = 0;
2314 
2315  if (ComponentReallyLowercase) {
2316 
2318  }
2319 
2320  if (ExtensionReallyLowercase) {
2321 
2323  }
2324 
2325  //
2326  // See if we have to create an Lfn entry
2327  //
2328 
2329  if (ARGUMENT_PRESENT(Lfn)) {
2330 
2331  UCHAR DirentChecksum;
2332  UCHAR DirentsInLfn;
2333  UCHAR LfnOrdinal;
2334  PWCHAR LfnBuffer;
2335  PLFN_DIRENT LfnDirent;
2336 
2338 
2339  DirentChecksum = FatComputeLfnChecksum( Dirent );
2340 
2341  LfnOrdinal =
2342  DirentsInLfn = (UCHAR)FAT_LFN_DIRENTS_NEEDED(Lfn);
2343 
2344  LfnBuffer = &Lfn->Buffer[(DirentsInLfn - 1) * 13];
2345 
2346  NT_ASSERT( DirentsInLfn <= MAX_LFN_DIRENTS );
2347 
2348  for (LfnDirent = (PLFN_DIRENT)Dirent - DirentsInLfn;
2349  LfnDirent < (PLFN_DIRENT)Dirent;
2350  LfnDirent += 1, LfnOrdinal -= 1, LfnBuffer -= 13) {
2351 
2352  WCHAR FinalLfnBuffer[13];
2353  PWCHAR Buffer;
2354 
2355  //
2356  // We need to special case the "final" dirent.
2357  //
2358 
2359  if (LfnOrdinal == DirentsInLfn) {
2360 
2361  ULONG i;
2362  ULONG RemainderChars;
2363 
2364  RemainderChars = (Lfn->Length / sizeof(WCHAR)) % 13;
2365 
2366  LfnDirent->Ordinal = LfnOrdinal | FAT_LAST_LONG_ENTRY;
2367 
2368  if (RemainderChars != 0) {
2369 
2370  RtlCopyMemory( FinalLfnBuffer,
2371  LfnBuffer,
2372  RemainderChars * sizeof(WCHAR) );
2373 
2374  for (i = RemainderChars; i < 13; i++) {
2375 
2376  //
2377  // Figure out which character to use.
2378  //
2379 
2380  if (i == RemainderChars) {
2381 
2382  FinalLfnBuffer[i] = 0x0000;
2383 
2384  } else {
2385 
2386  FinalLfnBuffer[i] = 0xffff;
2387  }
2388  }
2389 
2390  Buffer = FinalLfnBuffer;
2391 
2392  } else {
2393 
2394  Buffer = LfnBuffer;
2395  }
2396 
2397  } else {
2398 
2399  LfnDirent->Ordinal = LfnOrdinal;
2400 
2401  Buffer = LfnBuffer;
2402  }
2403 
2404  //
2405  // Now fill in the name.
2406  //
2407 
2408  RtlCopyMemory( &LfnDirent->Name1[0],
2409  &Buffer[0],
2410  5 * sizeof(WCHAR) );
2411 
2412  RtlCopyMemory( &LfnDirent->Name2[0],
2413  &Buffer[5],
2414  6 * sizeof(WCHAR) );
2415 
2416  RtlCopyMemory( &LfnDirent->Name3[0],
2417  &Buffer[11],
2418  2 * sizeof(WCHAR) );
2419 
2420  //
2421  // And the other fields
2422  //
2423 
2424  LfnDirent->Attributes = FAT_DIRENT_ATTR_LFN;
2425 
2426  LfnDirent->Type = 0;
2427 
2428  LfnDirent->Checksum = DirentChecksum;
2429 
2430  LfnDirent->MustBeZero = 0;
2431  }
2432  }
2433 
2434  DebugTrace(-1, Dbg, "FatConstructDirent -> (VOID)\n", 0);
2435  return;
2436 }
2437 
2438 
2439 VOID
2441  IN PIRP_CONTEXT IrpContext,
2442  IN OUT PDIRENT Dirent,
2444  )
2445 
2446 /*++
2447 
2448 Routine Description:
2449 
2450  This routine modifies the fields of a dirent to be used for a label.
2451 
2452 Arguments:
2453 
2454  Dirent - Supplies the dirent being modified.
2455 
2456  Label - Supplies the name to store in the Dirent. This
2457  name must not contain wildcards.
2458 
2459 Return Value:
2460 
2461  None.
2462 
2463 --*/
2464 
2465 {
2466  PAGED_CODE();
2467 
2468  DebugTrace(+1, Dbg, "FatConstructLabelDirent\n", 0);
2469 
2470  DebugTrace( 0, Dbg, " Dirent = %p\n", Dirent);
2471  DebugTrace( 0, Dbg, " Label = %Z\n", Label);
2472 
2473  RtlZeroMemory( Dirent, sizeof(DIRENT) );
2474 
2475  //
2476  // We just merrily go and fill up the dirent with the fields given.
2477  //
2478 
2479  RtlCopyMemory( Dirent->FileName, Label->Buffer, Label->Length );
2480 
2481  //
2482  // Pad the label with spaces, not nulls.
2483  //
2484 
2485  RtlFillMemory( &Dirent->FileName[Label->Length], 11 - Label->Length, ' ');
2486 
2487  Dirent->LastWriteTime = FatGetCurrentFatTime( IrpContext );
2488 
2489  Dirent->Attributes = FAT_DIRENT_ATTR_VOLUME_ID;
2490  Dirent->ExtendedAttributes = 0;
2491  Dirent->FileSize = 0;
2492 
2493  DebugTrace(-1, Dbg, "FatConstructLabelDirent -> (VOID)\n", 0);
2494  return;
2495 }
2496 
2497 
2498 _Requires_lock_held_(_Global_critical_region_)
2499 VOID
2500 FatSetFileSizeInDirent (
2501  IN PIRP_CONTEXT IrpContext,
2502  IN PFCB Fcb,
2503  IN PULONG AlternativeFileSize OPTIONAL
2504  )
2505 
2506 /*++
2507 
2508 Routine Description:
2509 
2510  This routine saves the file size in an fcb into its dirent.
2511 
2512 Arguments:
2513 
2514  Fcb - Supplies the Fcb being referenced
2515 
2516  AlternativeFileSize - If non-null we use the ULONG it points to as
2517  the new file size. Otherwise we use the one in the Fcb.
2518 
2519 Return Value:
2520 
2521  None.
2522 
2523 --*/
2524 
2525 {
2526  PDIRENT Dirent;
2527  PBCB DirentBcb;
2528 
2529  PAGED_CODE();
2530 
2532 
2533  FatGetDirentFromFcbOrDcb( IrpContext,
2534  Fcb,
2535  FALSE,
2536  &Dirent,
2537  &DirentBcb );
2538  _SEH2_TRY {
2539 
2540  Dirent->FileSize = ARGUMENT_PRESENT( AlternativeFileSize ) ?
2541  *AlternativeFileSize : Fcb->Header.FileSize.LowPart;
2542 
2543 
2544  FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
2545 
2546  } _SEH2_FINALLY {
2547 
2548  FatUnpinBcb( IrpContext, DirentBcb );
2549  } _SEH2_END;
2550 }
2551 
2552 _Requires_lock_held_(_Global_critical_region_)
2553 VOID
2554 FatSetFileSizeInDirentNoRaise (
2555  IN PIRP_CONTEXT IrpContext,
2556  IN PFCB Fcb,
2557  IN PULONG AlternativeFileSize OPTIONAL
2558  )
2559 
2560 /*++
2561 
2562 Routine Description:
2563 
2564  This routine saves the file size in an fcb into its dirent.
2565  All exceptions thrown from FatSetFileSizeInDirent are
2566  silently swallowed.
2567 
2568 Arguments:
2569 
2570  Fcb - Supplies the Fcb being referenced
2571 
2572  AlternativeFileSize - If non-null we use the ULONG it points to as
2573  the new file size. Otherwise we use the one in the Fcb.
2574 
2575 Return Value:
2576 
2577  None.
2578 
2579 --*/
2580 
2581 {
2582  _SEH2_TRY {
2583 
2584  FatSetFileSizeInDirent( IrpContext, Fcb, AlternativeFileSize );
2585 
2587 
2588  NOTHING;
2589  } _SEH2_END;
2590 }
2591 
2592 
2593 _Requires_lock_held_(_Global_critical_region_)
2594 VOID
2595 FatUpdateDirentFromFcb (
2596  IN PIRP_CONTEXT IrpContext,
2598  IN PFCB FcbOrDcb,
2599  IN PCCB Ccb
2600  )
2601 
2602 
2603 /*++
2604 
2605 Routine Description:
2606 
2607  This routine modifies an objects directory entry based on the hints
2608  that have been built up over previous operations on a handle. Notify
2609  change filters are built and fired as a result of these updates.
2610 
2611 Arguments:
2612 
2613  FileObject - Fileobject representing the handle involved
2614 
2615  FcbOrDcb - File/Dir involved
2616 
2617  Ccb - User context involved
2618 
2619 Return Value:
2620 
2621  None.
2622 
2623 --*/
2624 
2625 {
2626  BOOLEAN SetArchiveBit;
2627 
2629  BOOLEAN UpdateLastWriteTime;
2630  BOOLEAN UpdateLastAccessTime;
2631  BOOLEAN UpdateDirent = FALSE;
2632 
2633  PDIRENT Dirent;
2634  PBCB DirentBcb = NULL;
2635  ULONG NotifyFilter = 0;
2636  FAT_TIME_STAMP CurrentFatTime = {0};
2637 
2638  LARGE_INTEGER CurrentTime;
2639  LARGE_INTEGER CurrentDay = {0};
2640  LARGE_INTEGER LastAccessDay;
2641 
2642  PAGED_CODE();
2643 
2644  //
2645  // Nothing to do if the fcb is bad, volume is readonly or we got the
2646  // root dir.
2647  //
2648 
2649  if (FcbOrDcb->FcbCondition != FcbGood ||
2652 
2653  return;
2654  }
2655 
2656  //
2657  // Check if we should be changing the time or file size and set
2658  // the archive bit on the file.
2659  //
2660 
2661  KeQuerySystemTime( &CurrentTime );
2662 
2663  //
2664  // Note that we HAVE to use BooleanFlagOn() here because
2665  // FO_FILE_SIZE_CHANGED > 0x80 (i.e., not in the first byte).
2666  //
2667 
2668  SetArchiveBit = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
2669 
2670  UpdateLastWriteTime = FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
2672 
2675 
2676  //
2677  // Do one further check here of access time. Only update it if
2678  // the current version is at least one day old. We know that
2679  // the current FcbOrDcb->LastAccessTime corresponds to 12 midnight local
2680  // time, so just see if the current time is on the same day.
2681  //
2682 
2683  if (FatData.ChicagoMode &&
2684  (UpdateLastWriteTime ||
2687 
2688  ExSystemTimeToLocalTime( &FcbOrDcb->LastAccessTime, &LastAccessDay );
2689  ExSystemTimeToLocalTime( &CurrentTime, &CurrentDay );
2690 
2691  LastAccessDay.QuadPart /= FatOneDay.QuadPart;
2692  CurrentDay.QuadPart /= FatOneDay.QuadPart;
2693 
2694  if (LastAccessDay.LowPart != CurrentDay.LowPart) {
2695 
2696  UpdateLastAccessTime = TRUE;
2697 
2698  } else {
2699 
2700  UpdateLastAccessTime = FALSE;
2701  }
2702 
2703  } else {
2704 
2705  UpdateLastAccessTime = FALSE;
2706  }
2707 
2708  if (SetArchiveBit ||
2709  UpdateFileSize ||
2710  UpdateLastWriteTime ||
2711  UpdateLastAccessTime
2712  ) {
2713 
2714  DebugTrace(0, Dbg, "Update Time and/or file size on File/Dir\n", 0);
2715 
2716  _SEH2_TRY {
2717 
2718  _SEH2_TRY {
2719 
2720 #if (NTDDI_VERSION >= NTDDI_WIN8)
2721  //
2722  // Break parent directory oplock. Directory oplock breaks are
2723  // always advisory, so we will never block/get STATUS_PENDING here.
2724  //
2725 
2726  if (FcbOrDcb->ParentDcb != NULL) {
2727 
2728  FsRtlCheckOplockEx( FatGetFcbOplock(FcbOrDcb->ParentDcb),
2729  IrpContext->OriginatingIrp,
2730  OPLOCK_FLAG_PARENT_OBJECT,
2731  NULL,
2732  NULL,
2733  NULL );
2734  }
2735 #endif
2736 
2737  //
2738  // Get the dirent
2739  //
2740 
2741  FatGetDirentFromFcbOrDcb( IrpContext,
2742  FcbOrDcb,
2743  FALSE,
2744  &Dirent,
2745  &DirentBcb );
2746 
2747  if (UpdateLastWriteTime || UpdateLastAccessTime) {
2748 
2749  (VOID)FatNtTimeToFatTime( IrpContext,
2750  &CurrentTime,
2751  TRUE,
2752  &CurrentFatTime,
2753  NULL );
2754  }
2755 
2756  if (SetArchiveBit) {
2757 
2758  Dirent->Attributes |= FILE_ATTRIBUTE_ARCHIVE;
2760 
2762  UpdateDirent = TRUE;
2763  }
2764 
2765  if (UpdateLastWriteTime) {
2766 
2767  //
2768  // Update its time of last write
2769  //
2770 
2771  FcbOrDcb->LastWriteTime = CurrentTime;
2772  Dirent->LastWriteTime = CurrentFatTime;
2773 
2774  //
2775  // We call the notify package to report that the
2776  // last modification time has changed.
2777  //
2778 
2780  UpdateDirent = TRUE;
2781  }
2782 
2783  if (UpdateLastAccessTime) {
2784 
2785  //
2786  // Now we have to truncate the local time down
2787  // to the current day, then convert back to UTC.
2788  //
2789 
2791  CurrentDay.QuadPart * FatOneDay.QuadPart;
2792 
2795 
2796  Dirent->LastAccessDate = CurrentFatTime.Date;
2797 
2798  //
2799  // We call the notify package to report that the
2800  // last access time has changed.
2801  //
2802 
2804  UpdateDirent = TRUE;
2805  }
2806 
2807  if (UpdateFileSize) {
2808 
2809  //
2810  // Perhaps we were called to make certain that the
2811  // filesize on disc was updated - don't bother updating
2812  // and firing the filter if nothing changed.
2813  //
2814 
2816 
2817  if (Dirent->FileSize != FcbOrDcb->Header.FileSize.LowPart) {
2818 
2819  //
2820  // Update the dirent file size
2821  //
2822 
2823  Dirent->FileSize = FcbOrDcb->Header.FileSize.LowPart;
2824 
2825  //
2826  // We call the notify package to report that the
2827  // size has changed.
2828  //
2829 
2831  UpdateDirent = TRUE;
2832  }
2833 
2834 
2835  }
2836 
2837 
2838  FatNotifyReportChange( IrpContext,
2839  FcbOrDcb->Vcb,
2840  FcbOrDcb,
2841  NotifyFilter,
2843 
2844  if (UpdateDirent) {
2845 
2846  //
2847  // If all we did was update last access time,
2848  // don't mark the volume dirty.
2849  //
2850 
2851  FatSetDirtyBcb( IrpContext,
2852  DirentBcb,
2854  NULL : FcbOrDcb->Vcb,
2855  TRUE );
2856  }
2857 
2860 
2861  FatResetExceptionState( IrpContext );
2862  } _SEH2_END;
2863 
2864  } _SEH2_FINALLY {
2865 
2866  FatUnpinBcb( IrpContext, DirentBcb );
2867  } _SEH2_END;
2868  }
2869 
2870 }
2871 
2872 
2873 //
2874 // Internal support routine
2875 //
2876 
2877 UCHAR
2879  PDIRENT Dirent
2880  )
2881 
2882 /*++
2883 
2884 Routine Description:
2885 
2886  This routine computes the Chicago long file name checksum.
2887 
2888 Arguments:
2889 
2890  Dirent - Specifies the dirent that we are to compute a checksum for.
2891 
2892 Return Value:
2893 
2894  The checksum.
2895 
2896 --*/
2897 
2898 {
2899  ULONG i;
2900  UCHAR Checksum;
2901 
2902  PAGED_CODE();
2903 
2904  Checksum = Dirent->FileName[0];
2905 
2906  for (i=1; i < 11; i++) {
2907 
2908  Checksum = ((Checksum & 1) ? 0x80 : 0) +
2909  (Checksum >> 1) +
2910  Dirent->FileName[i];
2911  }
2912 
2913  return Checksum;
2914 }
2915 
2916 
2917 
2918 #if 0 // It turns out Win95 is still creating short names without a ~
2919 
2920 //
2921 // Internal support routine
2922 //
2923 
2924 BOOLEAN
2925 FatIsLfnPairValid (
2926  PWCHAR Lfn,
2927  ULONG LfnSize,
2928  PDIRENT Dirent
2929  )
2930 
2931 /*++
2932 
2933 Routine Description:
2934 
2935  This routine does a few more checks to make sure that a LFN/short
2936  name pairing is legitimate. Basically this is the test:
2937 
2938  Pairing is valid if:
2939 
2940  DIRENT has a ~ character ||
2941  (LFN is 8.3 compliant &&
2942  (LFN has extended character(s) ? TRUE :
2943  LFN upcases to DIRENT))
2944 
2945  When checking for the presence of a tilda character in the short
2946  name, note that we purposely do a single byte search instead of
2947  converting the name to UNICODE and looking there for the tilda.
2948  This protects us from accidently missing the tilda if the
2949  preceding byte is a lead byte in the current Oem code page,
2950  but wasn't in the Oem code page that created the file.
2951 
2952  Also note that if the LFN is longer than 12 characters, then the
2953  second clause of the OR must be false.
2954 
2955 Arguments:
2956 
2957  Lfn - Points to a buffer of UNICODE chars.
2958 
2959  LfnSize - This is the size of the LFN in characters.
2960 
2961  Dirent - Specifies the dirent we are to consider.
2962 
2963 Return Value:
2964 
2965  TRUE if the Lfn/DIRENT form a legitimate pair, FALSE otherwise.
2966 
2967 --*/
2968 
2969 {
2970  ULONG i;
2971  BOOLEAN ExtendedChars;
2972  ULONG DirentBuffer[3];
2973  PUCHAR DirentName;
2974  ULONG DirentIndex;
2975  BOOLEAN DotEncountered;
2976 
2977  //
2978  // First, look for a tilda
2979  //
2980 
2981  for (i=0; i<11; i++) {
2982  if (Dirent->FileName[i] == '~') {
2983  return TRUE;
2984  }
2985  }
2986 
2987  //
2988  // No tilda. If the LFN is longer than 12 characters, then it can
2989  // neither upcase to the DIRENT nor be 8.3 complient.
2990  //
2991 
2992  if (LfnSize > 12) {
2993  return FALSE;
2994  }
2995 
2996  //
2997  // Now see if the name is 8.3, and build an upcased DIRENT as well.
2998  //
2999 
3000  DirentBuffer[0] = 0x20202020;
3001  DirentBuffer[1] = 0x20202020;
3002  DirentBuffer[2] = 0x20202020;
3003 
3004  DirentName = (PUCHAR)DirentBuffer;
3005 
3006  ExtendedChars = FALSE;
3007  DirentIndex = 0;
3008  DotEncountered = FALSE;
3009 
3010  for (i=0; i < LfnSize; i++) {
3011 
3012  //
3013  // Do dot transition work
3014  //
3015 
3016  if (Lfn[i] == L'.') {
3017  if (DotEncountered ||
3018  (i > 8) ||
3019  ((LfnSize - i) > 4) ||
3020  (i && Lfn[i-1] == L' ')) {
3021  return FALSE;
3022  }
3023  DotEncountered = TRUE;
3024  DirentIndex = 8;
3025  continue;
3026  }
3027 
3028  //
3029  // The character must be legal in order to be 8.3
3030  //
3031 
3032  if ((Lfn[i] < 0x80) &&
3034  return FALSE;
3035  }
3036 
3037  //
3038  // If the name contains no extended chars, continue building DIRENT
3039  //
3040 
3041  if (!ExtendedChars) {
3042  if (Lfn[i] > 0x7f) {
3043  ExtendedChars = TRUE;
3044  } else {
3045  DirentName[DirentIndex++] = (UCHAR) (
3046  Lfn[i] < 'a' ? Lfn[i] : Lfn[i] <= 'z' ? Lfn[i] - ('a' - 'A') : Lfn[i]);
3047  }
3048  }
3049  }
3050 
3051  //
3052  // If the LFN ended in a space, or there was no dot and the name
3053  // has more than 8 characters, then it is not 8.3 compliant.
3054  //
3055 
3056  if ((Lfn[LfnSize - 1] == L' ') ||
3057  (!DotEncountered && (LfnSize > 8))) {
3058  return FALSE;
3059  }
3060 
3061  //
3062  // OK, now if we got this far then the LFN is 8dot3. If there are
3063  // no extended characters, then we can also check to make sure that
3064  // the LFN is only a case varient of the DIRENT.
3065  //
3066 
3067  if (!ExtendedChars &&
3068  !RtlEqualMemory(Dirent->FileName, DirentName, 11)) {
3069 
3070  return FALSE;
3071  }
3072 
3073  //
3074  // We have now verified this pairing the very best we can without
3075  // knowledge of the code page that the file was created under.
3076  //
3077 
3078  return TRUE;
3079 }
3080 #endif //0
3081 
3082 //
3083 // Internal support routine
3084 //
3085 
3086 _Requires_lock_held_(_Global_critical_region_)
3087 VOID
3088 FatRescanDirectory (
3089  PIRP_CONTEXT IrpContext,
3090  PDCB Dcb
3091  )
3092 
3093 /*++
3094 
3095 Routine Description:
3096 
3097  This routine rescans the given directory, finding the first unused
3098  dirent, first deleted dirent, and setting the free dirent bitmap
3099  appropriately.
3100 
3101 Arguments:
3102 
3103  Dcb - Supplies the directory to rescan.
3104 
3105 Return Value:
3106 
3107  None.
3108 
3109 --*/
3110 
3111 {
3112  PBCB Bcb = NULL;
3113  PDIRENT Dirent = NULL;
3115 
3116  ULONG UnusedVbo;
3117  ULONG DeletedHint;
3118  ULONG DirentIndex;
3119  ULONG DirentsThisRun;
3120  ULONG StartIndexOfThisRun;
3121 
3122  enum RunType {
3123  InitialRun,
3124  FreeDirents,
3125  AllocatedDirents,
3126  } CurrentRun;
3127 
3128  PAGED_CODE();
3129 
3130  DebugTrace( 0, Dbg, "We must scan the whole directory.\n", 0);
3131 
3132  UnusedVbo = 0;
3133  DeletedHint = 0xffffffff;
3134 
3135  //
3136  // To start with, we have to find out if the first dirent is free.
3137  //
3138 
3139  CurrentRun = InitialRun;
3140  DirentIndex =
3141  StartIndexOfThisRun = 0;
3142 
3143  _SEH2_TRY {
3144 
3145  while ( TRUE ) {
3146 
3147  BOOLEAN DirentDeleted;
3148 
3149  //
3150  // Read a dirent
3151  //
3152 
3153  FatReadDirent( IrpContext,
3154  Dcb,
3155  UnusedVbo,
3156  &Bcb,
3157  &Dirent,
3158  &Status );
3159 
3160  //
3161  // If EOF, or we found a NEVER_USED entry, we exit the loop
3162  //
3163 
3164  if ( (Status == STATUS_END_OF_FILE ) ||
3165  (Dirent->FileName[0] == FAT_DIRENT_NEVER_USED)) {
3166 
3167  break;
3168  }
3169 
3170  //
3171  // If the dirent is DELETED, and it is the first one we found, set
3172  // it in the deleted hint.
3173  //
3174 
3175  if (Dirent->FileName[0] == FAT_DIRENT_DELETED) {
3176 
3177  DirentDeleted = TRUE;
3178 
3179  if (DeletedHint == 0xffffffff) {
3180 
3181  DeletedHint = UnusedVbo;
3182  }
3183 
3184  } else {
3185 
3186  DirentDeleted = FALSE;
3187  }
3188 
3189  //
3190  // Check for the first time through the loop, and determine
3191  // the current run type.
3192  //
3193 
3194  if (CurrentRun == InitialRun) {
3195 
3196  CurrentRun = DirentDeleted ?
3197  FreeDirents : AllocatedDirents;
3198 
3199  } else {
3200 
3201  //
3202  // Are we switching from a free run to an allocated run?
3203  //
3204 
3205  if ((CurrentRun == FreeDirents) && !DirentDeleted) {
3206 
3207  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3208 
3209  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3210  StartIndexOfThisRun,
3211  DirentsThisRun );
3212 
3213  CurrentRun = AllocatedDirents;
3214  StartIndexOfThisRun = DirentIndex;
3215  }
3216 
3217  //
3218  // Are we switching from an allocated run to a free run?
3219  //
3220 
3221  if ((CurrentRun == AllocatedDirents) && DirentDeleted) {
3222 
3223  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3224 
3225  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3226  StartIndexOfThisRun,
3227  DirentsThisRun );
3228 
3229  CurrentRun = FreeDirents;
3230  StartIndexOfThisRun = DirentIndex;
3231  }
3232  }
3233 
3234  //
3235  // Move on to the next dirent.
3236  //
3237 
3238  UnusedVbo += sizeof(DIRENT);
3239  Dirent += 1;
3240  DirentIndex += 1;
3241  }
3242 
3243  //
3244  // Now we have to record the final run we encoutered
3245  //
3246 
3247  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3248 
3249  if ((CurrentRun == FreeDirents) || (CurrentRun == InitialRun)) {
3250 
3251  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3252  StartIndexOfThisRun,
3253  DirentsThisRun );
3254 
3255  } else {
3256 
3257  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3258  StartIndexOfThisRun,
3259  DirentsThisRun );
3260  }
3261 
3262  //
3263  // Now if there we bailed prematurely out of the loop because
3264  // we hit an unused entry, set all the rest as free.
3265  //
3266 
3267  if (UnusedVbo < Dcb->Header.AllocationSize.LowPart) {
3268 
3269  StartIndexOfThisRun = UnusedVbo / sizeof(DIRENT);
3270 
3271  DirentsThisRun = (Dcb->Header.AllocationSize.LowPart -
3272  UnusedVbo) / sizeof(DIRENT);
3273 
3274  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3275  StartIndexOfThisRun,
3276  DirentsThisRun);
3277  }
3278 
3279  } _SEH2_FINALLY {
3280 
3281  FatUnpinBcb( IrpContext, Bcb );
3282  } _SEH2_END;
3283 
3284  //
3285  // If there weren't any DELETED entries, set the index to our current
3286  // position.
3287  //
3288 
3289  if (DeletedHint == 0xffffffff) { DeletedHint = UnusedVbo; }
3290 
3291  Dcb->Specific.Dcb.UnusedDirentVbo = UnusedVbo;
3292  Dcb->Specific.Dcb.DeletedDirentHint = DeletedHint;
3293 
3294  return;
3295 }
3296 
3297 
3298 //
3299 // Internal support routine
3300 //
3301 
3302 _Requires_lock_held_(_Global_critical_region_)
3303 ULONG
3304 FatDefragDirectory (
3305  IN PIRP_CONTEXT IrpContext,
3306  IN PDCB Dcb,
3308  )
3309 
3310 /*++
3311 
3312 Routine Description:
3313 
3314  This routine determines if the requested number of dirents can be found
3315  in the directory, looking for deleted dirents and orphaned LFNs. If the
3316  request can be satisifed, orphaned LFNs are marked as deleted, and deleted
3317  dirents are all grouped together at the end of the directory.
3318 
3319  Note that this routine is currently used only on the root directory, but
3320  it is completely general and could be used on any directory.
3321 
3322 Arguments:
3323 
3324  Dcb - Supplies the directory to defrag.
3325 
3326 Return Value:
3327 
3328  The Index of the first dirent available for use, or -1 if the
3329  request cannot be satisfied.
3330 
3331 --*/
3332 
3333 {
3334  ULONG SavedIrpContextFlag;
3335  PLIST_ENTRY Links;
3336  ULONG ReturnValue = 0;
3337  PFCB Fcb;
3338 
3339  PBCB Bcb = NULL;
3340  PDIRENT Dirent = NULL;
3341  UNICODE_STRING Lfn = {0,0,NULL};
3342 
3343  LARGE_MCB Mcb;
3344  BOOLEAN McbInitialized = FALSE;
3345  BOOLEAN InvalidateFcbs = FALSE;
3346 
3347  PUCHAR Directory = NULL;
3348  PUCHAR UnusedDirents;
3349  PUCHAR UnusedDirentBuffer = NULL;
3350  PUCHAR UsedDirents;
3351  PUCHAR UsedDirentBuffer = NULL;
3352 
3353  PBCB *Bcbs = NULL;
3354  ULONG Page;
3355  ULONG PagesPinned = 0;
3356 
3357  ULONG DcbSize;
3359 
3360  PAGED_CODE();
3361 
3362  //
3363  // We assume we own the Vcb.
3364  //
3365 
3366  NT_ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
3367 
3368  //
3369  // We will only attempt this on directories less than 0x40000 bytes
3370  // long (by default on DOS the root directory is only 0x2000 long).
3371  // This is to avoid a cache manager complication.
3372  //
3373 
3374  DcbSize = Dcb->Header.AllocationSize.LowPart;
3375 
3376  if (DcbSize > 0x40000) {
3377 
3378  return (ULONG)-1;
3379  }
3380 
3381  //
3382  // Force wait to TRUE
3383  //
3384 
3385  SavedIrpContextFlag = IrpContext->Flags;
3386 
3387  SetFlag( IrpContext->Flags,
3389 
3390  //
3391  // Now acquire all open Fcbs in the Dcb exclusive.
3392  //
3393 
3394  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3395  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3396  Links = Links->Flink) {
3397 
3398  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3399 
3401  }
3402 
3403  _SEH2_TRY {
3404 
3405  CCB Ccb;
3406  ULONG QueryOffset = 0;
3407  ULONG FoundOffset = 0;
3408  ULONGLONG BytesUsed = 0;
3409 
3410  NTSTATUS DontCare;
3411  ULONG Run;
3412  ULONG TotalRuns;
3413  BOOLEAN Result;
3414  PUCHAR Char;
3415 
3416  //
3417  // We are going to build a new bitmap that will show all orphaned
3418  // LFNs as well as deleted dirents as available.
3419  //
3420  // Initialize our local CCB that will match all files and even
3421  // a label if it is here.
3422  //
3423 
3424  RtlZeroMemory( &Ccb, sizeof(CCB) );
3426 
3427  //
3428  // Init the Long File Name string.
3429  //
3430 
3431  Lfn.MaximumLength = 260 * sizeof(WCHAR);
3433  260*sizeof(WCHAR),
3435 
3436  //
3437  // Initalize the Mcb. We use this structure to keep track of runs
3438  // of free and allocated dirents. Runs are identity allocations, and
3439  // holes are free dirents.
3440  //
3441 
3443 
3444  McbInitialized = TRUE;
3445 
3446  do {
3447 
3448  FatLocateDirent( IrpContext,
3449  Dcb,
3450  &Ccb,
3451  QueryOffset,
3452  NULL,
3453  &Dirent,
3454  &Bcb,
3455  (PVBO)&FoundOffset,
3456  NULL,
3457  &Lfn,
3458  NULL );
3459 
3460  if (Dirent != NULL) {
3461 
3463 
3464  //
3465  // Compute the LfnByteOffset.
3466  //
3467 
3468  LfnByteOffset = FoundOffset -
3470 
3471  BytesUsed = FoundOffset - LfnByteOffset + sizeof(DIRENT);
3472 
3473  //
3474  // Set a run to represent all the dirents used for this
3475  // file in the Dcb dir.
3476  //
3477 
3478 #ifdef _MSC_VER
3479 #pragma prefast( suppress:28931, "needed for debug build" )
3480 #endif
3482  LfnByteOffset,
3483  LfnByteOffset,
3484  BytesUsed );
3485 
3486  NT_ASSERT( Result );
3487 
3488  //
3489  // Move on to the next dirent.
3490  //
3491 
3492  TotalBytesAllocated += (ULONG) BytesUsed;
3493  QueryOffset = FoundOffset + sizeof(DIRENT);
3494  }
3495 
3496  } while ((Dirent != NULL) && (QueryOffset < DcbSize));
3497 
3498  if (Bcb != NULL) {
3499 
3500  FatUnpinBcb( IrpContext, Bcb );
3501  }
3502 
3503  //
3504  // If we need more dirents than are available, bail.
3505  //
3506 
3507  if (DirentsNeeded > (DcbSize - TotalBytesAllocated)/sizeof(DIRENT)) {
3508 
3509  try_return(ReturnValue = (ULONG)-1);
3510  }
3511 
3512  //
3513  // Now we are going to copy all the used and un-used parts of the
3514  // directory to separate pool.
3515  //
3516  // Allocate these buffers and pin the entire directory.
3517  //
3518 
3519  UnusedDirents =
3520  UnusedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3521  DcbSize - TotalBytesAllocated,
3522  TAG_DIRENT );
3523 
3524  UsedDirents =
3525  UsedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3527  TAG_DIRENT );
3528 
3529  PagesPinned = (DcbSize + (PAGE_SIZE - 1 )) / PAGE_SIZE;
3530 
3532  PagesPinned * sizeof(PBCB),
3533  TAG_BCB );
3534 
3535  RtlZeroMemory( Bcbs, PagesPinned * sizeof(PBCB) );
3536 
3537  for (Page = 0; Page < PagesPinned; Page += 1) {
3538 
3539  ULONG PinSize;
3540 
3541  //
3542  // Don't try to pin beyond the Dcb size.
3543  //
3544 
3545  if ((Page + 1) * PAGE_SIZE > DcbSize) {
3546 
3547  PinSize = DcbSize - (Page * PAGE_SIZE);
3548 
3549  } else {
3550 
3551  PinSize = PAGE_SIZE;
3552  }
3553 
3554  FatPrepareWriteDirectoryFile( IrpContext,
3555  Dcb,
3556  Page * PAGE_SIZE,
3557  PinSize,
3558  &Bcbs[Page],
3559 #ifndef __REACTOS__
3560  &Dirent,
3561 #else
3562  (PVOID *)&Dirent,
3563 #endif
3564  FALSE,
3565  TRUE,
3566  &DontCare );
3567 
3568  if (Page == 0) {
3569  Directory = (PUCHAR)Dirent;
3570  }
3571  }
3572 
3573  TotalRuns = FsRtlNumberOfRunsInLargeMcb( &Mcb );
3574 
3575  for (Run = 0; Run < TotalRuns; Run++) {
3576 
3577  LBO Vbo;
3578  LBO Lbo;
3579 
3580 #ifdef _MSC_VER
3581 #pragma prefast( suppress:28931, "needed for debug build" )
3582 #endif
3584  Run,
3585  &Vbo,
3586  &Lbo,
3587  (PLONGLONG)&BytesUsed );
3588 
3589  NT_ASSERT(Result);
3590 
3591  //
3592  // Copy each run to their specific pool.
3593  //
3594 
3595  if (Lbo != -1) {
3596 
3597  RtlCopyMemory( UsedDirents,
3598  Directory + Vbo,
3599  (ULONG) BytesUsed );
3600 
3601  UsedDirents += BytesUsed;
3602 
3603  } else {
3604 
3605  RtlCopyMemory( UnusedDirents,
3606  Directory + Vbo,
3607  (ULONG) BytesUsed );
3608 
3609  UnusedDirents += BytesUsed;
3610  }
3611  }
3612 
3613  //
3614  // Marking all the un-used dirents as "deleted". This will reclaim
3615  // storage used by orphaned LFNs.
3616  //
3617 
3618  for (Char = UnusedDirentBuffer; Char < UnusedDirents; Char += sizeof(DIRENT)) {
3619 
3620  *Char = FAT_DIRENT_DELETED;
3621  }
3622 
3623  //
3624  // Now, for the permanent step. Copy the two pool buffer back to the
3625  // real Dcb directory, and flush the Dcb directory
3626  //
3627 
3628  NT_ASSERT( TotalBytesAllocated == (ULONG)(UsedDirents - UsedDirentBuffer) );
3629 
3630  RtlCopyMemory( Directory, UsedDirentBuffer, TotalBytesAllocated );
3631 
3633  UnusedDirentBuffer,
3634  UnusedDirents - UnusedDirentBuffer );
3635 
3636  //
3637  // We need to unpin here so that the UnpinRepinned won't deadlock.
3638  //
3639 
3640  if (Bcbs) {
3641  for (Page = 0; Page < PagesPinned; Page += 1) {
3642  FatUnpinBcb( IrpContext, Bcbs[Page] );
3643  }
3644  ExFreePool(Bcbs);
3645  Bcbs = NULL;
3646  }
3647 
3648  //
3649  // Now make the free dirent bitmap reflect the new state of the Dcb
3650  // directory.
3651  //
3652 
3653  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3654  0,
3655  TotalBytesAllocated / sizeof(DIRENT) );
3656 
3657  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3658  TotalBytesAllocated / sizeof(DIRENT),
3659  (DcbSize - TotalBytesAllocated) / sizeof(DIRENT) );
3660 
3662 
3663  //
3664  // Flush the directory to disk. If we raise, we will need to invalidate
3665  // all of the children. Sorry, guys, but I can't figure out where you are
3666  // now - if this failed I probably can't read the media either. And we
3667  // probably purged the cache to boot.
3668  //
3669 
3670  _SEH2_TRY {
3671 
3672  FatUnpinRepinnedBcbs( IrpContext );
3673 
3676 
3677  InvalidateFcbs = TRUE;
3678  } _SEH2_END;
3679 
3680  //
3681  // OK, now nothing can go wrong. We have two more things to do.
3682  // First, we have to fix up all the dirent offsets in any open Fcbs.
3683  // If we cannot now find the Fcb, the file is marked invalid. Also,
3684  // we skip deleted files.
3685  //
3686 
3687  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3688  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3689  Links = Links->Flink) {
3690 
3691  PBCB TmpBcb = NULL;
3692  ULONG TmpOffset = 0;
3693  PDIRENT TmpDirent = NULL;
3694  ULONG PreviousLfnSpread;
3695 
3696  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3697 
3698  if (IsFileDeleted( IrpContext, Fcb )) {
3699 
3700  continue;
3701  }
3702 
3703  //
3704  // If we aren't already giving up, safely try to pick up the dirent
3705  // to update the Fcb. If this raises, we have to give up and blow
3706  // evenyone else away too.
3707  //
3708 
3709  if (!InvalidateFcbs) {
3710 
3711  _SEH2_TRY {
3712 
3713  FatLocateSimpleOemDirent( IrpContext,
3714  Dcb,
3715  &Fcb->ShortName.Name.Oem,
3716  &TmpDirent,
3717  &TmpBcb,
3718  (PVBO)&TmpOffset );
3719 
3722 
3723  InvalidateFcbs = TRUE;
3724  } _SEH2_END;
3725  }
3726 
3727  if (TmpBcb == NULL || InvalidateFcbs) {
3728 
3729  FatUnpinBcb( IrpContext, TmpBcb );
3730  FatMarkFcbCondition( IrpContext, Fcb, FcbBad, TRUE );
3731 
3732  } else {
3733 
3734  FatUnpinBcb( IrpContext, TmpBcb );
3735 
3736  PreviousLfnSpread = Fcb->DirentOffsetWithinDirectory -
3738 
3739  Fcb->DirentOffsetWithinDirectory = TmpOffset;
3740  Fcb->LfnOffsetWithinDirectory = TmpOffset - PreviousLfnSpread;
3741  }
3742  }
3743 
3744  try_exit: NOTHING;
3745  } _SEH2_FINALLY {
3746 
3747  //
3748  // Free all our resources and stuff.
3749  //
3750 
3751  if (McbInitialized) {
3753  }
3754 
3755  if (Lfn.Buffer) {
3756  ExFreePool( Lfn.Buffer );
3757  }
3758 
3759  if (UnusedDirentBuffer) {
3760  ExFreePool( UnusedDirentBuffer );
3761  }
3762 
3763  if (UsedDirentBuffer) {
3764  ExFreePool( UsedDirentBuffer );
3765  }
3766 
3767  if (Bcbs) {
3768  for (Page = 0; Page < PagesPinned; Page += 1) {
3769  FatUnpinBcb( IrpContext, Bcbs[Page] );
3770  }
3771  ExFreePool(Bcbs);
3772  }
3773 
3774  FatUnpinBcb( IrpContext, Bcb );
3775 
3776  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3777  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3778  Links = Links->Flink) {
3779 
3780  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3781 
3782  ExReleaseResourceLite( Fcb->Header.Resource );
3783  }
3784 
3785  IrpContext->Flags = SavedIrpContextFlag;
3786  } _SEH2_END;
3787 
3788  //
3789  // Now return the offset of the first free dirent to the caller.
3790  //
3791 
3792  return ReturnValue;
3793 }
3794 
3795 
3796 
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
VOID FatConstructDirent(IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING FileName, IN BOOLEAN ComponentReallyLowercase, IN BOOLEAN ExtensionReallyLowercase, IN PUNICODE_STRING Lfn OPTIONAL, IN USHORT Attributes, IN BOOLEAN ZeroAndSetTimeFields, IN PLARGE_INTEGER SetCreationTime OPTIONAL)
Definition: dirsup.c:2171
#define Dbg
Definition: dirsup.c:28
struct _FCB::@715::@717 Dcb
LONGLONG CreationTime
Definition: cdstruc.h:1036
LARGE_INTEGER LastWriteTime
Definition: fatstruc.h:921
Definition: bidi.c:433
_Requires_lock_held_(_Global_critical_region_)
Definition: dirsup.c:158
#define IN
Definition: typedefs.h:39
BOOLEAN NTAPI FsRtlIsNtstatusExpected(IN NTSTATUS NtStatus)
Definition: filter.c:61
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2992
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
FAT_TIME_STAMP FatGetCurrentFatTime(_In_ PIRP_CONTEXT IrpContext)
Definition: timesup.c:317
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:411
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
#define STATUS_CANNOT_MAKE
Definition: ntstatus.h:854
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
USHORT MaximumLength
Definition: env_spec_w32.h:370
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING Lfn
Definition: create.c:4137
ERESOURCE Resource
Definition: fatstruc.h:403
#define TRUE
Definition: types.h:120
Definition: cdstruc.h:908
VOID Fat8dot3ToString(_In_ PIRP_CONTEXT IrpContext, _In_ PDIRENT Dirent, _In_ BOOLEAN RestoreCase, _Out_ POEM_STRING OutputString)
Definition: namesup.c:179
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
#define IRP_CONTEXT_FLAG_WRITE_THROUGH
Definition: ext2fs.h:1079
#define FAT_DIRENT_NEVER_USED
Definition: fat.h:334
union _FILE_NAME_NODE::@714 Name
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
Definition: cdstruc.h:1073
ULONG32 VBO
Definition: fat.h:38
unsigned char * PUCHAR
Definition: retypes.h:3
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2165
BOOLEAN ContainsWildCards
Definition: fatstruc.h:1374
#define FatConstructDotDot(IRPCONTEXT, DCB, PARENT, DIRENT)
Definition: dirsup.c:80
LONG NTSTATUS
Definition: precomp.h:26
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
IN PFCB IN VBO OUT PLBO Lbo
Definition: fatprocs.h:306
#define TimerStart(LEVEL)
Definition: fatdata.h:318
VOID NTAPI FsRtlDeleteKeyFromTunnelCache(IN PTUNNEL Cache, IN ULONGLONG DirectoryKey)
Definition: tunnel.c:588
#define FCB_STATE_3_LOWER_CASE
Definition: fatstruc.h:1210
Definition: cdstruc.h:504
#define VCB_STATE_FLAG_WRITE_PROTECTED
Definition: fatstruc.h:569
#define FILE_NOTIFY_CHANGE_SIZE
NTSTATUS NTAPI RtlOemStringToCountedUnicodeString(IN OUT PUNICODE_STRING UniDest, IN PCOEM_STRING OemSource, IN BOOLEAN AllocateDestinationString)
Definition: unicode.c:1463
#define FILE_NOTIFY_CHANGE_LAST_WRITE
#define TAG_BCB
Definition: nodetype.h:157
IN PDCB IN ULONG IN BOOLEAN RescanDir
Definition: fatprocs.h:698
BOOLEAN ChicagoMode
Definition: fatstruc.h:86
_In_ PFCB _In_ PCD_NAME Name
Definition: dirsup.c:1110
uint16_t * PWCHAR
Definition: typedefs.h:56
STRING OEM_STRING
Definition: umtypes.h:203
ULONG VcbState
Definition: cdstruc.h:546
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2974
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:769
struct _FCB * ParentDcb
Definition: fatstruc.h:835
BOOLEAN NTAPI FsRtlIsNameInExpression(IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL)
Definition: name.c:514
VOID FatPinMappedData(IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb)
Definition: cachesup.c:1866
IN PFCB IN BOOLEAN ReturnOnFailure
Definition: fatprocs.h:771
#define FatDirectoryKey(FcbOrDcb)
Definition: fatprocs.h:850
_SEH2_TRY
Definition: create.c:4226
#define CCB_FLAG_OPENED_BY_SHORTNAME
Definition: fatstruc.h:1295
#define STATUS_END_OF_FILE
Definition: shellext.h:67
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
#define FO_FILE_SIZE_CHANGED
Definition: iotypes.h:1753
BOOLEAN NTAPI FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb, IN ULONG RunIndex, OUT PLONGLONG Vbn, OUT PLONGLONG Lbn, OUT PLONGLONG SectorCount)
Definition: largemcb.c:391
#define FAT_DIRENT_NT_BYTE_8_LOWER_CASE
Definition: fat.h:361
__GNU_EXTENSION typedef __int64 * PLONGLONG
Definition: ntbasedef.h:383
#define FO_FILE_MODIFIED
Definition: iotypes.h:1752
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define CCB_FLAG_SKIP_SHORT_NAME_COMPARE
Definition: fatstruc.h:1252
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
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
NTSYSAPI NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING *, const UNICODE_STRING *, BOOLEAN)
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
LARGE_INTEGER LastAccessTime
Definition: fatstruc.h:920
#define FAT_LAST_LONG_ENTRY
Definition: lfn.h:35
UINT32 void void ** ReturnValue
Definition: acevents.h:214
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
VOID NTAPI FsRtlAddToTunnelCache(IN PTUNNEL Cache, IN ULONGLONG DirectoryKey, IN PUNICODE_STRING ShortName, IN PUNICODE_STRING LongName, IN BOOLEAN KeyByShortName, IN ULONG DataLength, IN PVOID Data)
Definition: tunnel.c:341
#define FALSE
Definition: types.h:117
Definition: Header.h:8
#define FO_FILE_FAST_IO_READ
Definition: iotypes.h:1759
#define FAT_LFN_DIRENTS_NEEDED(NAME)
Definition: lfn.h:53
LONGLONG LBO
Definition: fat.h:34
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define FILE_ACTION_MODIFIED
UCHAR DirentFatFlags
Definition: fatstruc.h:1132
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:450
VOID FatEnsureStringBufferEnough(_Inout_ PVOID String, _In_ USHORT DesiredBufferSize)
Definition: strucsup.c:3727
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:546
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG DirentByteOffset
Definition: create.c:4137
unsigned char BOOLEAN
#define IsFileDeleted(Mcb)
Definition: ext2fs.h:959
smooth NULL
Definition: ftsmooth.c:416
PAGED_CODE()
BOOLEAN NTAPI ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
Definition: resource.c:1619
_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 CCB_FLAG_QUERY_TEMPLATE_MIXED
Definition: fatstruc.h:1302
struct tagRun Run
ULONG Flags
Definition: cdstruc.h:1086
Definition: bufpool.h:45
NTSYSAPI ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP, ULONG, ULONG)
IN PFCB IN PDELETE_CONTEXT DeleteContext IN BOOLEAN DeleteEa
Definition: fatprocs.h:715
#define VCB_STATE_FLAG_REMOVABLE_MEDIA
Definition: fatstruc.h:559
union _FCB::@715 Specific
NodeType
Definition: Node.h:5
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:588
union _CCB::@719::@721::@723 OemQueryTemplate
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ExSystemTimeToLocalTime(SysTime, LocTime)
Definition: env_spec_w32.h:729
OEM_STRING Oem
Definition: fatstruc.h:692
#define PCHAR
Definition: match.c:90
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
BOOLEAN NTAPI FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1, IN PCUNICODE_STRING Name2, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
Definition: name.c:296
#define CCB_FLAG_MATCH_ALL
Definition: fatstruc.h:1251
FAT_DATA FatData
Definition: fatdata.c:56
NTSYSAPI ULONG NTAPI RtlEqualMemory(CONST VOID *Source1, CONST VOID *Source2, ULONG Length)
#define FatResetExceptionState(IRPCONTEXT)
Definition: fatprocs.h:2980
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define try_return(S)
Definition: cdprocs.h:2179
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:593
#define FatReadDirent(IRPCONTEXT, DCB, VBO, BCB, DIRENT, STATUS)
Definition: dirsup.c:132
uint64_t ULONGLONG
Definition: typedefs.h:67
#define ARGUMENT_PRESENT(ArgumentPointer)
VBO LfnOffsetWithinDirectory
Definition: fatstruc.h:912
#define Vcb
Definition: cdprocs.h:1415
static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize, BOOLEAN IsFatX)
Definition: finfo.c:1180
FAT8DOT3 * PFAT8DOT3
Definition: fat.h:296
#define TAG_FILENAME_BUFFER
Definition: nodetype.h:167
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
LONG TotalBytesAllocated
Definition: memory.c:15
LARGE_INTEGER FatOneDay
Definition: fatdata.c:72
* PFILE_OBJECT
Definition: iotypes.h:1962
FAT_DATE Date
Definition: fat.h:286
BOOLEAN NTAPI FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb, IN LONGLONG Vbn, IN LONGLONG Lbn, IN LONGLONG SectorCount)
Definition: largemcb.c:282
ULONG Flags
Definition: ntfs.h:532
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
VOID FatMarkFcbCondition(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FCB_CONDITION FcbCondition, IN BOOLEAN Recursive)
unsigned char UCHAR
Definition: xmlstorage.h:181
IN PDCB IN PUNICODE_STRING IN PUNICODE_STRING LfnTmp
Definition: fatprocs.h:752
char * PBOOLEAN
Definition: retypes.h:11
Status
Definition: gdiplustypes.h:24
_In_ PFCB Fcb
Definition: dirsup.c:398
VBO * PVBO
Definition: fat.h:39
static const WCHAR L[]
Definition: oid.c:1250
LFN_DIRENT * PLFN_DIRENT
Definition: lfn.h:44
#define FsRtlIsAnsiCharacterLegalFat(C, WILD)
Definition: fsrtlfuncs.h:1611
IN PDCB IN PDIRENT ParentDirent
Definition: fatprocs.h:707
#define VOID
Definition: acefi.h:82
ULONG LowPart
Definition: typedefs.h:106
#define CCB_FLAG_USER_SET_LAST_WRITE
Definition: fatstruc.h:1265
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:588
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define FCB_STATE_8_LOWER_CASE
Definition: fatstruc.h:1209
#define NOTHING
Definition: env_spec_w32.h:461
Definition: typedefs.h:119
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define FatIsFat32(VCB)
Definition: fatprocs.h:1446
#define FAT_DIRENT_ATTR_ARCHIVE
Definition: fat.h:373
#define CCB_FLAG_MATCH_VOLUME_ID
Definition: fatstruc.h:1316
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
BOOLEAN FatIsNameInExpression(IN PIRP_CONTEXT IrpContext, IN OEM_STRING Expression, IN OEM_STRING Name)
Definition: namesup.c:35
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
_Must_inspect_result_ _In_ USHORT _In_ PHIDP_PREPARSED_DATA _Out_writes_to_ LengthAttributes PHIDP_EXTENDED_ATTRIBUTES Attributes
Definition: hidpi.h:348
#define FAT_DIRENT_NT_BYTE_3_LOWER_CASE
Definition: fat.h:362
_SEH2_END
Definition: create.c:4400
VBO DirentOffsetWithinDirectory
Definition: fatstruc.h:905
unsigned short USHORT
Definition: pedump.c:61
#define FAT_DIRENT_ATTR_LFN
Definition: fat.h:375
#define ExLocalTimeToSystemTime(LocTime, SysTime)
Definition: env_spec_w32.h:738
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
#define FAT_NTC_ROOT_DCB
Definition: nodetype.h:31
#define FILE_NOTIFY_CHANGE_ATTRIBUTES
IN PVCB IN ULONG IN OUT PULONG IN BOOLEAN OUT PLARGE_MCB Mcb
Definition: fatprocs.h:343
#define FAT_DIRENT_DELETED
Definition: fat.h:337
NTSYSAPI void WINAPI RtlSetBits(PRTL_BITMAP, ULONG, ULONG)
_SEH2_FINALLY
Definition: create.c:4371
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1053
unsigned int * PULONG
Definition: retypes.h:1
_In_ PFCB _In_ PDIRENT_ENUM_CONTEXT _Inout_ PDIRENT Dirent
Definition: dirsup.c:425
IN PDCB ParentDirectory
Definition: fatprocs.h:698
VOID FatFreeStringBuffer(_Inout_ PVOID String)
Definition: strucsup.c:3772
#define FAT_NTC_DCB
Definition: nodetype.h:30
VOID FatTunnelFcbOrDcb(IN PFCB FcbOrDcb, IN PCCB Ccb OPTIONAL)
Definition: dirsup.c:652
ULONG FirstClusterOfFile
Definition: fatstruc.h:817
TUNNEL Tunnel
Definition: fatstruc.h:511
VOID FatStringTo8dot3(_In_ PIRP_CONTEXT IrpContext, _In_ OEM_STRING InputString, _Out_writes_bytes_(11) PFAT8DOT3 Output8dot3)
Definition: namesup.c:79
#define FatVcbAcquiredExclusive(IRPCONTEXT, VCB)
Definition: fatprocs.h:1495
UCHAR FatComputeLfnChecksum(PDIRENT Dirent)
Definition: dirsup.c:2878
#define FAT_DIRENT_ATTR_VOLUME_ID
Definition: fat.h:371
#define OUT
Definition: typedefs.h:40
#define DIRENT
Definition: fatfs.h:187
unsigned int ULONG
Definition: retypes.h:1
ULONG NTAPI ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
Definition: resource.c:1658
base for all directory entries
Definition: entries.h:138
PWCHAR Label
Definition: format.c:70
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
PACKED_LFN_DIRENT LFN_DIRENT
Definition: lfn.h:43
PVCB Vcb
Definition: cdstruc.h:939
NTSYSAPI BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP, ULONG, ULONG)
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define MAX_LFN_DIRENTS
Definition: lfn.h:51
VOID FatConstructLabelDirent(IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING Label)
Definition: dirsup.c:2440
#define CCB_FLAG_USER_SET_LAST_ACCESS
Definition: fatstruc.h:1266
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
#define TimerStop(LEVEL, s)
Definition: fatdata.h:319
UNREFERENCED_PARAMETER(Fcb)
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:3014
#define FILE_NOTIFY_CHANGE_LAST_ACCESS
#define FatConstructDot(IRPCONTEXT, DCB, PARENT, DIRENT)
Definition: dirsup.c:49
FILE_NAME_NODE ShortName
Definition: fatstruc.h:1114
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB * Dcb
Definition: create.c:4137
ULONG FcbState
Definition: cdstruc.h:977
IN PFCB IN VBO Vbo
Definition: fatprocs.h:306
unsigned short * PUSHORT
Definition: retypes.h:2
static PLARGE_INTEGER Time
Definition: time.c:105
#define FAT_NTC_FCB
Definition: nodetype.h:29
UNICODE_STRING ExactCaseLongName
Definition: fatstruc.h:1138
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
_In_opt_ HANDLE _In_opt_ PIO_APC_ROUTINE _In_opt_ PVOID _Out_ PIO_STATUS_BLOCK _In_ ULONG NotifyFilter
Definition: zwfuncs.h:500
#define TAG_DIRENT
Definition: vfat.h:549
IN PDCB IN ULONG DirentsNeeded
Definition: fatprocs.h:698
LONGLONG QuadPart
Definition: typedefs.h:114
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:725
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG LfnByteOffset
Definition: create.c:4137
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
#define NT_ASSERT
Definition: rtlfuncs.h:3312
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
IN PDCB IN PCCB IN VBO OffsetToStartSearchFrom
Definition: fatprocs.h:725
FCB_CONDITION FcbCondition
Definition: fatstruc.h:849