ReactOS  0.4.13-dev-257-gfabbd7c
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 #ifndef __REACTOS__
2637  FAT_TIME_STAMP CurrentFatTime = {0};
2638 #else
2639  FAT_TIME_STAMP CurrentFatTime = {{0}};
2640 #endif
2641 
2642  LARGE_INTEGER CurrentTime;
2643 #ifndef __REACTOS__
2644  LARGE_INTEGER CurrentDay = {0};
2645 #else
2646  LARGE_INTEGER CurrentDay = {.LowPart = 0, .HighPart = 0};
2647 #endif
2648  LARGE_INTEGER LastAccessDay;
2649 
2650  PAGED_CODE();
2651 
2652  //
2653  // Nothing to do if the fcb is bad, volume is readonly or we got the
2654  // root dir.
2655  //
2656 
2657  if (FcbOrDcb->FcbCondition != FcbGood ||
2660 
2661  return;
2662  }
2663 
2664  //
2665  // Check if we should be changing the time or file size and set
2666  // the archive bit on the file.
2667  //
2668 
2669  KeQuerySystemTime( &CurrentTime );
2670 
2671  //
2672  // Note that we HAVE to use BooleanFlagOn() here because
2673  // FO_FILE_SIZE_CHANGED > 0x80 (i.e., not in the first byte).
2674  //
2675 
2676  SetArchiveBit = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
2677 
2678  UpdateLastWriteTime = FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
2680 
2683 
2684  //
2685  // Do one further check here of access time. Only update it if
2686  // the current version is at least one day old. We know that
2687  // the current FcbOrDcb->LastAccessTime corresponds to 12 midnight local
2688  // time, so just see if the current time is on the same day.
2689  //
2690 
2691  if (FatData.ChicagoMode &&
2692  (UpdateLastWriteTime ||
2695 
2696  ExSystemTimeToLocalTime( &FcbOrDcb->LastAccessTime, &LastAccessDay );
2697  ExSystemTimeToLocalTime( &CurrentTime, &CurrentDay );
2698 
2699  LastAccessDay.QuadPart /= FatOneDay.QuadPart;
2700  CurrentDay.QuadPart /= FatOneDay.QuadPart;
2701 
2702  if (LastAccessDay.LowPart != CurrentDay.LowPart) {
2703 
2704  UpdateLastAccessTime = TRUE;
2705 
2706  } else {
2707 
2708  UpdateLastAccessTime = FALSE;
2709  }
2710 
2711  } else {
2712 
2713  UpdateLastAccessTime = FALSE;
2714  }
2715 
2716  if (SetArchiveBit ||
2717  UpdateFileSize ||
2718  UpdateLastWriteTime ||
2719  UpdateLastAccessTime
2720  ) {
2721 
2722  DebugTrace(0, Dbg, "Update Time and/or file size on File/Dir\n", 0);
2723 
2724  _SEH2_TRY {
2725 
2726  _SEH2_TRY {
2727 
2728 #if (NTDDI_VERSION >= NTDDI_WIN8)
2729  //
2730  // Break parent directory oplock. Directory oplock breaks are
2731  // always advisory, so we will never block/get STATUS_PENDING here.
2732  //
2733 
2734  if (FcbOrDcb->ParentDcb != NULL) {
2735 
2736  FsRtlCheckOplockEx( FatGetFcbOplock(FcbOrDcb->ParentDcb),
2737  IrpContext->OriginatingIrp,
2738  OPLOCK_FLAG_PARENT_OBJECT,
2739  NULL,
2740  NULL,
2741  NULL );
2742  }
2743 #endif
2744 
2745  //
2746  // Get the dirent
2747  //
2748 
2749  FatGetDirentFromFcbOrDcb( IrpContext,
2750  FcbOrDcb,
2751  FALSE,
2752  &Dirent,
2753  &DirentBcb );
2754 
2755  if (UpdateLastWriteTime || UpdateLastAccessTime) {
2756 
2757  (VOID)FatNtTimeToFatTime( IrpContext,
2758  &CurrentTime,
2759  TRUE,
2760  &CurrentFatTime,
2761  NULL );
2762  }
2763 
2764  if (SetArchiveBit) {
2765 
2766  Dirent->Attributes |= FILE_ATTRIBUTE_ARCHIVE;
2768 
2770  UpdateDirent = TRUE;
2771  }
2772 
2773  if (UpdateLastWriteTime) {
2774 
2775  //
2776  // Update its time of last write
2777  //
2778 
2779  FcbOrDcb->LastWriteTime = CurrentTime;
2780  Dirent->LastWriteTime = CurrentFatTime;
2781 
2782  //
2783  // We call the notify package to report that the
2784  // last modification time has changed.
2785  //
2786 
2788  UpdateDirent = TRUE;
2789  }
2790 
2791  if (UpdateLastAccessTime) {
2792 
2793  //
2794  // Now we have to truncate the local time down
2795  // to the current day, then convert back to UTC.
2796  //
2797 
2799  CurrentDay.QuadPart * FatOneDay.QuadPart;
2800 
2803 
2804  Dirent->LastAccessDate = CurrentFatTime.Date;
2805 
2806  //
2807  // We call the notify package to report that the
2808  // last access time has changed.
2809  //
2810 
2812  UpdateDirent = TRUE;
2813  }
2814 
2815  if (UpdateFileSize) {
2816 
2817  //
2818  // Perhaps we were called to make certain that the
2819  // filesize on disc was updated - don't bother updating
2820  // and firing the filter if nothing changed.
2821  //
2822 
2824 
2825  if (Dirent->FileSize != FcbOrDcb->Header.FileSize.LowPart) {
2826 
2827  //
2828  // Update the dirent file size
2829  //
2830 
2831  Dirent->FileSize = FcbOrDcb->Header.FileSize.LowPart;
2832 
2833  //
2834  // We call the notify package to report that the
2835  // size has changed.
2836  //
2837 
2839  UpdateDirent = TRUE;
2840  }
2841 
2842 
2843  }
2844 
2845 
2846  FatNotifyReportChange( IrpContext,
2847  FcbOrDcb->Vcb,
2848  FcbOrDcb,
2849  NotifyFilter,
2851 
2852  if (UpdateDirent) {
2853 
2854  //
2855  // If all we did was update last access time,
2856  // don't mark the volume dirty.
2857  //
2858 
2859  FatSetDirtyBcb( IrpContext,
2860  DirentBcb,
2862  NULL : FcbOrDcb->Vcb,
2863  TRUE );
2864  }
2865 
2868 
2869  FatResetExceptionState( IrpContext );
2870  } _SEH2_END;
2871 
2872  } _SEH2_FINALLY {
2873 
2874  FatUnpinBcb( IrpContext, DirentBcb );
2875  } _SEH2_END;
2876  }
2877 
2878 }
2879 
2880 
2881 //
2882 // Internal support routine
2883 //
2884 
2885 UCHAR
2887  PDIRENT Dirent
2888  )
2889 
2890 /*++
2891 
2892 Routine Description:
2893 
2894  This routine computes the Chicago long file name checksum.
2895 
2896 Arguments:
2897 
2898  Dirent - Specifies the dirent that we are to compute a checksum for.
2899 
2900 Return Value:
2901 
2902  The checksum.
2903 
2904 --*/
2905 
2906 {
2907  ULONG i;
2908  UCHAR Checksum;
2909 
2910  PAGED_CODE();
2911 
2912  Checksum = Dirent->FileName[0];
2913 
2914  for (i=1; i < 11; i++) {
2915 
2916  Checksum = ((Checksum & 1) ? 0x80 : 0) +
2917  (Checksum >> 1) +
2918  Dirent->FileName[i];
2919  }
2920 
2921  return Checksum;
2922 }
2923 
2924 
2925 
2926 #if 0 // It turns out Win95 is still creating short names without a ~
2927 
2928 //
2929 // Internal support routine
2930 //
2931 
2932 BOOLEAN
2933 FatIsLfnPairValid (
2934  PWCHAR Lfn,
2935  ULONG LfnSize,
2936  PDIRENT Dirent
2937  )
2938 
2939 /*++
2940 
2941 Routine Description:
2942 
2943  This routine does a few more checks to make sure that a LFN/short
2944  name pairing is legitimate. Basically this is the test:
2945 
2946  Pairing is valid if:
2947 
2948  DIRENT has a ~ character ||
2949  (LFN is 8.3 compliant &&
2950  (LFN has extended character(s) ? TRUE :
2951  LFN upcases to DIRENT))
2952 
2953  When checking for the presence of a tilda character in the short
2954  name, note that we purposely do a single byte search instead of
2955  converting the name to UNICODE and looking there for the tilda.
2956  This protects us from accidently missing the tilda if the
2957  preceding byte is a lead byte in the current Oem code page,
2958  but wasn't in the Oem code page that created the file.
2959 
2960  Also note that if the LFN is longer than 12 characters, then the
2961  second clause of the OR must be false.
2962 
2963 Arguments:
2964 
2965  Lfn - Points to a buffer of UNICODE chars.
2966 
2967  LfnSize - This is the size of the LFN in characters.
2968 
2969  Dirent - Specifies the dirent we are to consider.
2970 
2971 Return Value:
2972 
2973  TRUE if the Lfn/DIRENT form a legitimate pair, FALSE otherwise.
2974 
2975 --*/
2976 
2977 {
2978  ULONG i;
2979  BOOLEAN ExtendedChars;
2980  ULONG DirentBuffer[3];
2981  PUCHAR DirentName;
2982  ULONG DirentIndex;
2983  BOOLEAN DotEncountered;
2984 
2985  //
2986  // First, look for a tilda
2987  //
2988 
2989  for (i=0; i<11; i++) {
2990  if (Dirent->FileName[i] == '~') {
2991  return TRUE;
2992  }
2993  }
2994 
2995  //
2996  // No tilda. If the LFN is longer than 12 characters, then it can
2997  // neither upcase to the DIRENT nor be 8.3 complient.
2998  //
2999 
3000  if (LfnSize > 12) {
3001  return FALSE;
3002  }
3003 
3004  //
3005  // Now see if the name is 8.3, and build an upcased DIRENT as well.
3006  //
3007 
3008  DirentBuffer[0] = 0x20202020;
3009  DirentBuffer[1] = 0x20202020;
3010  DirentBuffer[2] = 0x20202020;
3011 
3012  DirentName = (PUCHAR)DirentBuffer;
3013 
3014  ExtendedChars = FALSE;
3015  DirentIndex = 0;
3016  DotEncountered = FALSE;
3017 
3018  for (i=0; i < LfnSize; i++) {
3019 
3020  //
3021  // Do dot transition work
3022  //
3023 
3024  if (Lfn[i] == L'.') {
3025  if (DotEncountered ||
3026  (i > 8) ||
3027  ((LfnSize - i) > 4) ||
3028  (i && Lfn[i-1] == L' ')) {
3029  return FALSE;
3030  }
3031  DotEncountered = TRUE;
3032  DirentIndex = 8;
3033  continue;
3034  }
3035 
3036  //
3037  // The character must be legal in order to be 8.3
3038  //
3039 
3040  if ((Lfn[i] < 0x80) &&
3042  return FALSE;
3043  }
3044 
3045  //
3046  // If the name contains no extended chars, continue building DIRENT
3047  //
3048 
3049  if (!ExtendedChars) {
3050  if (Lfn[i] > 0x7f) {
3051  ExtendedChars = TRUE;
3052  } else {
3053  DirentName[DirentIndex++] = (UCHAR) (
3054  Lfn[i] < 'a' ? Lfn[i] : Lfn[i] <= 'z' ? Lfn[i] - ('a' - 'A') : Lfn[i]);
3055  }
3056  }
3057  }
3058 
3059  //
3060  // If the LFN ended in a space, or there was no dot and the name
3061  // has more than 8 characters, then it is not 8.3 compliant.
3062  //
3063 
3064  if ((Lfn[LfnSize - 1] == L' ') ||
3065  (!DotEncountered && (LfnSize > 8))) {
3066  return FALSE;
3067  }
3068 
3069  //
3070  // OK, now if we got this far then the LFN is 8dot3. If there are
3071  // no extended characters, then we can also check to make sure that
3072  // the LFN is only a case varient of the DIRENT.
3073  //
3074 
3075  if (!ExtendedChars &&
3076  !RtlEqualMemory(Dirent->FileName, DirentName, 11)) {
3077 
3078  return FALSE;
3079  }
3080 
3081  //
3082  // We have now verified this pairing the very best we can without
3083  // knowledge of the code page that the file was created under.
3084  //
3085 
3086  return TRUE;
3087 }
3088 #endif //0
3089 
3090 //
3091 // Internal support routine
3092 //
3093 
3094 _Requires_lock_held_(_Global_critical_region_)
3095 VOID
3096 FatRescanDirectory (
3097  PIRP_CONTEXT IrpContext,
3098  PDCB Dcb
3099  )
3100 
3101 /*++
3102 
3103 Routine Description:
3104 
3105  This routine rescans the given directory, finding the first unused
3106  dirent, first deleted dirent, and setting the free dirent bitmap
3107  appropriately.
3108 
3109 Arguments:
3110 
3111  Dcb - Supplies the directory to rescan.
3112 
3113 Return Value:
3114 
3115  None.
3116 
3117 --*/
3118 
3119 {
3120  PBCB Bcb = NULL;
3121  PDIRENT Dirent = NULL;
3123 
3124  ULONG UnusedVbo;
3125  ULONG DeletedHint;
3126  ULONG DirentIndex;
3127  ULONG DirentsThisRun;
3128  ULONG StartIndexOfThisRun;
3129 
3130  enum RunType {
3131  InitialRun,
3132  FreeDirents,
3133  AllocatedDirents,
3134  } CurrentRun;
3135 
3136  PAGED_CODE();
3137 
3138  DebugTrace( 0, Dbg, "We must scan the whole directory.\n", 0);
3139 
3140  UnusedVbo = 0;
3141  DeletedHint = 0xffffffff;
3142 
3143  //
3144  // To start with, we have to find out if the first dirent is free.
3145  //
3146 
3147  CurrentRun = InitialRun;
3148  DirentIndex =
3149  StartIndexOfThisRun = 0;
3150 
3151  _SEH2_TRY {
3152 
3153  while ( TRUE ) {
3154 
3155  BOOLEAN DirentDeleted;
3156 
3157  //
3158  // Read a dirent
3159  //
3160 
3161  FatReadDirent( IrpContext,
3162  Dcb,
3163  UnusedVbo,
3164  &Bcb,
3165  &Dirent,
3166  &Status );
3167 
3168  //
3169  // If EOF, or we found a NEVER_USED entry, we exit the loop
3170  //
3171 
3172  if ( (Status == STATUS_END_OF_FILE ) ||
3173  (Dirent->FileName[0] == FAT_DIRENT_NEVER_USED)) {
3174 
3175  break;
3176  }
3177 
3178  //
3179  // If the dirent is DELETED, and it is the first one we found, set
3180  // it in the deleted hint.
3181  //
3182 
3183  if (Dirent->FileName[0] == FAT_DIRENT_DELETED) {
3184 
3185  DirentDeleted = TRUE;
3186 
3187  if (DeletedHint == 0xffffffff) {
3188 
3189  DeletedHint = UnusedVbo;
3190  }
3191 
3192  } else {
3193 
3194  DirentDeleted = FALSE;
3195  }
3196 
3197  //
3198  // Check for the first time through the loop, and determine
3199  // the current run type.
3200  //
3201 
3202  if (CurrentRun == InitialRun) {
3203 
3204  CurrentRun = DirentDeleted ?
3205  FreeDirents : AllocatedDirents;
3206 
3207  } else {
3208 
3209  //
3210  // Are we switching from a free run to an allocated run?
3211  //
3212 
3213  if ((CurrentRun == FreeDirents) && !DirentDeleted) {
3214 
3215  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3216 
3217  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3218  StartIndexOfThisRun,
3219  DirentsThisRun );
3220 
3221  CurrentRun = AllocatedDirents;
3222  StartIndexOfThisRun = DirentIndex;
3223  }
3224 
3225  //
3226  // Are we switching from an allocated run to a free run?
3227  //
3228 
3229  if ((CurrentRun == AllocatedDirents) && DirentDeleted) {
3230 
3231  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3232 
3233  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3234  StartIndexOfThisRun,
3235  DirentsThisRun );
3236 
3237  CurrentRun = FreeDirents;
3238  StartIndexOfThisRun = DirentIndex;
3239  }
3240  }
3241 
3242  //
3243  // Move on to the next dirent.
3244  //
3245 
3246  UnusedVbo += sizeof(DIRENT);
3247  Dirent += 1;
3248  DirentIndex += 1;
3249  }
3250 
3251  //
3252  // Now we have to record the final run we encoutered
3253  //
3254 
3255  DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3256 
3257  if ((CurrentRun == FreeDirents) || (CurrentRun == InitialRun)) {
3258 
3259  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3260  StartIndexOfThisRun,
3261  DirentsThisRun );
3262 
3263  } else {
3264 
3265  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3266  StartIndexOfThisRun,
3267  DirentsThisRun );
3268  }
3269 
3270  //
3271  // Now if there we bailed prematurely out of the loop because
3272  // we hit an unused entry, set all the rest as free.
3273  //
3274 
3275  if (UnusedVbo < Dcb->Header.AllocationSize.LowPart) {
3276 
3277  StartIndexOfThisRun = UnusedVbo / sizeof(DIRENT);
3278 
3279  DirentsThisRun = (Dcb->Header.AllocationSize.LowPart -
3280  UnusedVbo) / sizeof(DIRENT);
3281 
3282  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3283  StartIndexOfThisRun,
3284  DirentsThisRun);
3285  }
3286 
3287  } _SEH2_FINALLY {
3288 
3289  FatUnpinBcb( IrpContext, Bcb );
3290  } _SEH2_END;
3291 
3292  //
3293  // If there weren't any DELETED entries, set the index to our current
3294  // position.
3295  //
3296 
3297  if (DeletedHint == 0xffffffff) { DeletedHint = UnusedVbo; }
3298 
3299  Dcb->Specific.Dcb.UnusedDirentVbo = UnusedVbo;
3300  Dcb->Specific.Dcb.DeletedDirentHint = DeletedHint;
3301 
3302  return;
3303 }
3304 
3305 
3306 //
3307 // Internal support routine
3308 //
3309 
3310 _Requires_lock_held_(_Global_critical_region_)
3311 ULONG
3312 FatDefragDirectory (
3313  IN PIRP_CONTEXT IrpContext,
3314  IN PDCB Dcb,
3316  )
3317 
3318 /*++
3319 
3320 Routine Description:
3321 
3322  This routine determines if the requested number of dirents can be found
3323  in the directory, looking for deleted dirents and orphaned LFNs. If the
3324  request can be satisifed, orphaned LFNs are marked as deleted, and deleted
3325  dirents are all grouped together at the end of the directory.
3326 
3327  Note that this routine is currently used only on the root directory, but
3328  it is completely general and could be used on any directory.
3329 
3330 Arguments:
3331 
3332  Dcb - Supplies the directory to defrag.
3333 
3334 Return Value:
3335 
3336  The Index of the first dirent available for use, or -1 if the
3337  request cannot be satisfied.
3338 
3339 --*/
3340 
3341 {
3342  ULONG SavedIrpContextFlag;
3343  PLIST_ENTRY Links;
3344  ULONG ReturnValue = 0;
3345  PFCB Fcb;
3346 
3347  PBCB Bcb = NULL;
3348  PDIRENT Dirent = NULL;
3349  UNICODE_STRING Lfn = {0,0,NULL};
3350 
3351  LARGE_MCB Mcb;
3352  BOOLEAN McbInitialized = FALSE;
3353  BOOLEAN InvalidateFcbs = FALSE;
3354 
3355  PUCHAR Directory = NULL;
3356  PUCHAR UnusedDirents;
3357  PUCHAR UnusedDirentBuffer = NULL;
3358  PUCHAR UsedDirents;
3359  PUCHAR UsedDirentBuffer = NULL;
3360 
3361  PBCB *Bcbs = NULL;
3362  ULONG Page;
3363  ULONG PagesPinned = 0;
3364 
3365  ULONG DcbSize;
3367 
3368  PAGED_CODE();
3369 
3370  //
3371  // We assume we own the Vcb.
3372  //
3373 
3374  NT_ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
3375 
3376  //
3377  // We will only attempt this on directories less than 0x40000 bytes
3378  // long (by default on DOS the root directory is only 0x2000 long).
3379  // This is to avoid a cache manager complication.
3380  //
3381 
3382  DcbSize = Dcb->Header.AllocationSize.LowPart;
3383 
3384  if (DcbSize > 0x40000) {
3385 
3386  return (ULONG)-1;
3387  }
3388 
3389  //
3390  // Force wait to TRUE
3391  //
3392 
3393  SavedIrpContextFlag = IrpContext->Flags;
3394 
3395  SetFlag( IrpContext->Flags,
3397 
3398  //
3399  // Now acquire all open Fcbs in the Dcb exclusive.
3400  //
3401 
3402  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3403  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3404  Links = Links->Flink) {
3405 
3406  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3407 
3409  }
3410 
3411  _SEH2_TRY {
3412 
3413  CCB Ccb;
3414  ULONG QueryOffset = 0;
3415  ULONG FoundOffset = 0;
3416  ULONGLONG BytesUsed = 0;
3417 
3418  NTSTATUS DontCare;
3419  ULONG Run;
3420  ULONG TotalRuns;
3421  BOOLEAN Result;
3422  PUCHAR Char;
3423 
3424  //
3425  // We are going to build a new bitmap that will show all orphaned
3426  // LFNs as well as deleted dirents as available.
3427  //
3428  // Initialize our local CCB that will match all files and even
3429  // a label if it is here.
3430  //
3431 
3432  RtlZeroMemory( &Ccb, sizeof(CCB) );
3434 
3435  //
3436  // Init the Long File Name string.
3437  //
3438 
3439  Lfn.MaximumLength = 260 * sizeof(WCHAR);
3441  260*sizeof(WCHAR),
3443 
3444  //
3445  // Initalize the Mcb. We use this structure to keep track of runs
3446  // of free and allocated dirents. Runs are identity allocations, and
3447  // holes are free dirents.
3448  //
3449 
3451 
3452  McbInitialized = TRUE;
3453 
3454  do {
3455 
3456  FatLocateDirent( IrpContext,
3457  Dcb,
3458  &Ccb,
3459  QueryOffset,
3460  NULL,
3461  &Dirent,
3462  &Bcb,
3463  (PVBO)&FoundOffset,
3464  NULL,
3465  &Lfn,
3466  NULL );
3467 
3468  if (Dirent != NULL) {
3469 
3471 
3472  //
3473  // Compute the LfnByteOffset.
3474  //
3475 
3476  LfnByteOffset = FoundOffset -
3478 
3479  BytesUsed = FoundOffset - LfnByteOffset + sizeof(DIRENT);
3480 
3481  //
3482  // Set a run to represent all the dirents used for this
3483  // file in the Dcb dir.
3484  //
3485 
3486 #ifdef _MSC_VER
3487 #pragma prefast( suppress:28931, "needed for debug build" )
3488 #endif
3490  LfnByteOffset,
3491  LfnByteOffset,
3492  BytesUsed );
3493 
3494  NT_ASSERT( Result );
3495 
3496  //
3497  // Move on to the next dirent.
3498  //
3499 
3500  TotalBytesAllocated += (ULONG) BytesUsed;
3501  QueryOffset = FoundOffset + sizeof(DIRENT);
3502  }
3503 
3504  } while ((Dirent != NULL) && (QueryOffset < DcbSize));
3505 
3506  if (Bcb != NULL) {
3507 
3508  FatUnpinBcb( IrpContext, Bcb );
3509  }
3510 
3511  //
3512  // If we need more dirents than are available, bail.
3513  //
3514 
3515  if (DirentsNeeded > (DcbSize - TotalBytesAllocated)/sizeof(DIRENT)) {
3516 
3517  try_return(ReturnValue = (ULONG)-1);
3518  }
3519 
3520  //
3521  // Now we are going to copy all the used and un-used parts of the
3522  // directory to separate pool.
3523  //
3524  // Allocate these buffers and pin the entire directory.
3525  //
3526 
3527  UnusedDirents =
3528  UnusedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3529  DcbSize - TotalBytesAllocated,
3530  TAG_DIRENT );
3531 
3532  UsedDirents =
3533  UsedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3535  TAG_DIRENT );
3536 
3537  PagesPinned = (DcbSize + (PAGE_SIZE - 1 )) / PAGE_SIZE;
3538 
3540  PagesPinned * sizeof(PBCB),
3541  TAG_BCB );
3542 
3543  RtlZeroMemory( Bcbs, PagesPinned * sizeof(PBCB) );
3544 
3545  for (Page = 0; Page < PagesPinned; Page += 1) {
3546 
3547  ULONG PinSize;
3548 
3549  //
3550  // Don't try to pin beyond the Dcb size.
3551  //
3552 
3553  if ((Page + 1) * PAGE_SIZE > DcbSize) {
3554 
3555  PinSize = DcbSize - (Page * PAGE_SIZE);
3556 
3557  } else {
3558 
3559  PinSize = PAGE_SIZE;
3560  }
3561 
3562  FatPrepareWriteDirectoryFile( IrpContext,
3563  Dcb,
3564  Page * PAGE_SIZE,
3565  PinSize,
3566  &Bcbs[Page],
3567 #ifndef __REACTOS__
3568  &Dirent,
3569 #else
3570  (PVOID *)&Dirent,
3571 #endif
3572  FALSE,
3573  TRUE,
3574  &DontCare );
3575 
3576  if (Page == 0) {
3577  Directory = (PUCHAR)Dirent;
3578  }
3579  }
3580 
3581  TotalRuns = FsRtlNumberOfRunsInLargeMcb( &Mcb );
3582 
3583  for (Run = 0; Run < TotalRuns; Run++) {
3584 
3585  LBO Vbo;
3586  LBO Lbo;
3587 
3588 #ifdef _MSC_VER
3589 #pragma prefast( suppress:28931, "needed for debug build" )
3590 #endif
3592  Run,
3593  &Vbo,
3594  &Lbo,
3595  (PLONGLONG)&BytesUsed );
3596 
3597  NT_ASSERT(Result);
3598 
3599  //
3600  // Copy each run to their specific pool.
3601  //
3602 
3603  if (Lbo != -1) {
3604 
3605  RtlCopyMemory( UsedDirents,
3606  Directory + Vbo,
3607  (ULONG) BytesUsed );
3608 
3609  UsedDirents += BytesUsed;
3610 
3611  } else {
3612 
3613  RtlCopyMemory( UnusedDirents,
3614  Directory + Vbo,
3615  (ULONG) BytesUsed );
3616 
3617  UnusedDirents += BytesUsed;
3618  }
3619  }
3620 
3621  //
3622  // Marking all the un-used dirents as "deleted". This will reclaim
3623  // storage used by orphaned LFNs.
3624  //
3625 
3626  for (Char = UnusedDirentBuffer; Char < UnusedDirents; Char += sizeof(DIRENT)) {
3627 
3629  }
3630 
3631  //
3632  // Now, for the permanent step. Copy the two pool buffer back to the
3633  // real Dcb directory, and flush the Dcb directory
3634  //
3635 
3636  NT_ASSERT( TotalBytesAllocated == (ULONG)(UsedDirents - UsedDirentBuffer) );
3637 
3638  RtlCopyMemory( Directory, UsedDirentBuffer, TotalBytesAllocated );
3639 
3641  UnusedDirentBuffer,
3642  UnusedDirents - UnusedDirentBuffer );
3643 
3644  //
3645  // We need to unpin here so that the UnpinRepinned won't deadlock.
3646  //
3647 
3648  if (Bcbs) {
3649  for (Page = 0; Page < PagesPinned; Page += 1) {
3650  FatUnpinBcb( IrpContext, Bcbs[Page] );
3651  }
3652  ExFreePool(Bcbs);
3653  Bcbs = NULL;
3654  }
3655 
3656  //
3657  // Now make the free dirent bitmap reflect the new state of the Dcb
3658  // directory.
3659  //
3660 
3661  RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3662  0,
3663  TotalBytesAllocated / sizeof(DIRENT) );
3664 
3665  RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3666  TotalBytesAllocated / sizeof(DIRENT),
3667  (DcbSize - TotalBytesAllocated) / sizeof(DIRENT) );
3668 
3670 
3671  //
3672  // Flush the directory to disk. If we raise, we will need to invalidate
3673  // all of the children. Sorry, guys, but I can't figure out where you are
3674  // now - if this failed I probably can't read the media either. And we
3675  // probably purged the cache to boot.
3676  //
3677 
3678  _SEH2_TRY {
3679 
3680  FatUnpinRepinnedBcbs( IrpContext );
3681 
3684 
3685  InvalidateFcbs = TRUE;
3686  } _SEH2_END;
3687 
3688  //
3689  // OK, now nothing can go wrong. We have two more things to do.
3690  // First, we have to fix up all the dirent offsets in any open Fcbs.
3691  // If we cannot now find the Fcb, the file is marked invalid. Also,
3692  // we skip deleted files.
3693  //
3694 
3695  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3696  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3697  Links = Links->Flink) {
3698 
3699  PBCB TmpBcb = NULL;
3700  ULONG TmpOffset = 0;
3701  PDIRENT TmpDirent = NULL;
3702  ULONG PreviousLfnSpread;
3703 
3704  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3705 
3706  if (IsFileDeleted( IrpContext, Fcb )) {
3707 
3708  continue;
3709  }
3710 
3711  //
3712  // If we aren't already giving up, safely try to pick up the dirent
3713  // to update the Fcb. If this raises, we have to give up and blow
3714  // evenyone else away too.
3715  //
3716 
3717  if (!InvalidateFcbs) {
3718 
3719  _SEH2_TRY {
3720 
3721  FatLocateSimpleOemDirent( IrpContext,
3722  Dcb,
3723  &Fcb->ShortName.Name.Oem,
3724  &TmpDirent,
3725  &TmpBcb,
3726  (PVBO)&TmpOffset );
3727 
3730 
3731  InvalidateFcbs = TRUE;
3732  } _SEH2_END;
3733  }
3734 
3735  if (TmpBcb == NULL || InvalidateFcbs) {
3736 
3737  FatUnpinBcb( IrpContext, TmpBcb );
3738  FatMarkFcbCondition( IrpContext, Fcb, FcbBad, TRUE );
3739 
3740  } else {
3741 
3742  FatUnpinBcb( IrpContext, TmpBcb );
3743 
3744  PreviousLfnSpread = Fcb->DirentOffsetWithinDirectory -
3746 
3747  Fcb->DirentOffsetWithinDirectory = TmpOffset;
3748  Fcb->LfnOffsetWithinDirectory = TmpOffset - PreviousLfnSpread;
3749  }
3750  }
3751 
3752  try_exit: NOTHING;
3753  } _SEH2_FINALLY {
3754 
3755  //
3756  // Free all our resources and stuff.
3757  //
3758 
3759  if (McbInitialized) {
3761  }
3762 
3763  if (Lfn.Buffer) {
3764  ExFreePool( Lfn.Buffer );
3765  }
3766 
3767  if (UnusedDirentBuffer) {
3768  ExFreePool( UnusedDirentBuffer );
3769  }
3770 
3771  if (UsedDirentBuffer) {
3772  ExFreePool( UsedDirentBuffer );
3773  }
3774 
3775  if (Bcbs) {
3776  for (Page = 0; Page < PagesPinned; Page += 1) {
3777  FatUnpinBcb( IrpContext, Bcbs[Page] );
3778  }
3779  ExFreePool(Bcbs);
3780  }
3781 
3782  FatUnpinBcb( IrpContext, Bcb );
3783 
3784  for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3785  Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3786  Links = Links->Flink) {
3787 
3788  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3789 
3790  ExReleaseResourceLite( Fcb->Header.Resource );
3791  }
3792 
3793  IrpContext->Flags = SavedIrpContextFlag;
3794  } _SEH2_END;
3795 
3796  //
3797  // Now return the offset of the first free dirent to the caller.
3798  //
3799 
3800  return ReturnValue;
3801 }
3802 
3803 
3804 
#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
LONGLONG CreationTime
Definition: cdstruc.h:1036
LARGE_INTEGER LastWriteTime
Definition: fatstruc.h:918
Definition: bidi.c:477
_Requires_lock_held_(_Global_critical_region_)
Definition: dirsup.c:158
#define IN
Definition: typedefs.h:38
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
BOOLEAN NTAPI FsRtlIsNtstatusExpected(IN NTSTATUS NtStatus)
Definition: filter.c:61
#define TRUE
Definition: types.h:120
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:2983
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
union _FCB::@684 Specific
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:402
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
#define STATUS_CANNOT_MAKE
Definition: ntstatus.h:840
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:4157
ERESOURCE Resource
Definition: fatstruc.h:400
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
NTSYSAPI BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP, ULONG, ULONG)
#define IRP_CONTEXT_FLAG_WRITE_THROUGH
Definition: ext2fs.h:1079
#define FAT_DIRENT_NEVER_USED
Definition: fat.h:334
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:2156
BOOLEAN ContainsWildCards
Definition: fatstruc.h:1371
#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:297
#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:1207
Definition: cdstruc.h:504
#define VCB_STATE_FLAG_WRITE_PROTECTED
Definition: fatstruc.h:566
#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:689
BOOLEAN ChicagoMode
Definition: fatstruc.h:83
_In_ PFCB _In_ PCD_NAME Name
Definition: dirsup.c:1110
uint16_t * PWCHAR
Definition: typedefs.h:54
STRING OEM_STRING
Definition: umtypes.h:203
ULONG VcbState
Definition: cdstruc.h:546
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2965
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:769
struct _FCB * ParentDcb
Definition: fatstruc.h:832
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:762
#define FatDirectoryKey(FcbOrDcb)
Definition: fatprocs.h:841
_SEH2_TRY
Definition: create.c:4250
#define CCB_FLAG_OPENED_BY_SHORTNAME
Definition: fatstruc.h:1292
#define STATUS_END_OF_FILE
Definition: shellext.h:62
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
#define FO_FILE_SIZE_CHANGED
Definition: iotypes.h:1745
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:389
#define FO_FILE_MODIFIED
Definition: iotypes.h:1744
IN PFCB FcbOrDcb
Definition: fatprocs.h:297
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define CCB_FLAG_SKIP_SHORT_NAME_COMPARE
Definition: fatstruc.h:1249
_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
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
LARGE_INTEGER LastAccessTime
Definition: fatstruc.h:917
#define FAT_LAST_LONG_ENTRY
Definition: lfn.h:35
UINT32 void void ** ReturnValue
Definition: acevents.h:213
_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
Definition: Header.h:8
#define FO_FILE_FAST_IO_READ
Definition: iotypes.h:1751
#define FAT_LFN_DIRENTS_NEEDED(NAME)
Definition: lfn.h:53
LONGLONG LBO
Definition: fat.h:34
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1647
char Char
Definition: bzip2.c:161
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define FILE_ACTION_MODIFIED
UCHAR DirentFatFlags
Definition: fatstruc.h:1129
#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:3738
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:537
_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:4157
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:1299
struct tagRun Run
ULONG Flags
Definition: cdstruc.h:1086
Definition: bufpool.h:45
IN PFCB IN PDELETE_CONTEXT DeleteContext IN BOOLEAN DeleteEa
Definition: fatprocs.h:706
#define VCB_STATE_FLAG_REMOVABLE_MEDIA
Definition: fatstruc.h:556
NodeType
Definition: Node.h:5
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
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:689
#define PCHAR
Definition: match.c:90
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
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:1248
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:2971
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define try_return(S)
Definition: cdprocs.h:2189
#define FatReadDirent(IRPCONTEXT, DCB, VBO, BCB, DIRENT, STATUS)
Definition: dirsup.c:132
uint64_t ULONGLONG
Definition: typedefs.h:65
#define ARGUMENT_PRESENT(ArgumentPointer)
VBO LfnOffsetWithinDirectory
Definition: fatstruc.h:909
#define Vcb
Definition: cdprocs.h:1425
static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize, BOOLEAN IsFatX)
Definition: finfo.c:1178
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:1954
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:520
#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:743
char * PBOOLEAN
Definition: retypes.h:11
_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:698
#define VOID
Definition: acefi.h:82
ULONG LowPart
Definition: typedefs.h:104
#define CCB_FLAG_USER_SET_LAST_WRITE
Definition: fatstruc.h:1262
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:593
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define FCB_STATE_8_LOWER_CASE
Definition: fatstruc.h:1206
#define NOTHING
Definition: env_spec_w32.h:461
Definition: typedefs.h:117
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define FatIsFat32(VCB)
Definition: fatprocs.h:1437
Status
Definition: gdiplustypes.h:24
#define FAT_DIRENT_ATTR_ARCHIVE
Definition: fat.h:373
#define CCB_FLAG_MATCH_VOLUME_ID
Definition: fatstruc.h:1313
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:4424
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
VBO DirentOffsetWithinDirectory
Definition: fatstruc.h:902
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:334
#define FAT_DIRENT_DELETED
Definition: fat.h:337
_SEH2_FINALLY
Definition: create.c:4395
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
struct _FCB::@684::@686 Dcb
union _FILE_NAME_NODE::@683 Name
IN PDCB ParentDirectory
Definition: fatprocs.h:689
VOID FatFreeStringBuffer(_Inout_ PVOID String)
Definition: strucsup.c:3783
#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:814
TUNNEL Tunnel
Definition: fatstruc.h:508
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:1486
UCHAR FatComputeLfnChecksum(PDIRENT Dirent)
Definition: dirsup.c:2886
#define FAT_DIRENT_ATTR_VOLUME_ID
Definition: fat.h:371
#define OUT
Definition: typedefs.h:39
#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:261
PACKED_LFN_DIRENT LFN_DIRENT
Definition: lfn.h:43
PVCB Vcb
Definition: cdstruc.h:939
NTSYSAPI void WINAPI RtlSetBits(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING *, const UNICODE_STRING *, BOOLEAN)
#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:1263
#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:2745
#define FILE_NOTIFY_CHANGE_LAST_ACCESS
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:593
#define FatConstructDot(IRPCONTEXT, DCB, PARENT, DIRENT)
Definition: dirsup.c:49
FILE_NAME_NODE ShortName
Definition: fatstruc.h:1111
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB * Dcb
Definition: create.c:4157
NTSYSAPI ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP, ULONG, ULONG)
union _CCB::@688::@690::@692 OemQueryTemplate
ULONG FcbState
Definition: cdstruc.h:977
IN PFCB IN VBO Vbo
Definition: fatprocs.h:297
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:1135
#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:689
LONGLONG QuadPart
Definition: typedefs.h:112
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:716
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG LfnByteOffset
Definition: create.c:4157
#define NT_ASSERT
Definition: rtlfuncs.h:3312
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
IN PDCB IN PCCB IN VBO OffsetToStartSearchFrom
Definition: fatprocs.h:716
FCB_CONDITION FcbCondition
Definition: fatstruc.h:846