ReactOS 0.4.15-dev-7842-g558ab78
dirsup.c
Go to the documentation of this file.
1/*++
2
3Copyright (c) 1989-2000 Microsoft Corporation
4
5Module Name:
6
7 DirSup.c
8
9Abstract:
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) \
133if ((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
153UCHAR
156 );
157
158_Requires_lock_held_(_Global_critical_region_)
159VOID
160FatRescanDirectory (
161 PIRP_CONTEXT IrpContext,
162 PDCB Dcb
163 );
164
165_Requires_lock_held_(_Global_critical_region_)
166ULONG
167FatDefragDirectory (
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_)
199ULONG
200FatCreateNewDirent (
201 IN PIRP_CONTEXT IrpContext,
205 )
206
207/*++
208
209Routine 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
217Arguments:
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
224Return 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;
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
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
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
476 (ByteOffset - sizeof(DIRENT))/ sizeof(DIRENT),
477 DirentsNeeded ) );
478
479 RtlClearBits( &ParentDirectory->Specific.Dcb.FreeDirentBitmap,
480 (ByteOffset - sizeof(DIRENT))/ sizeof(DIRENT),
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),
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_)
551VOID
552FatInitializeDirectoryDirent (
553 IN PIRP_CONTEXT IrpContext,
554 IN PDCB Dcb,
556 )
557
558/*++
559
560Routine 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
569Arguments:
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
577Return Value:
578
579 None.
580
581--*/
582
583{
584 PBCB Bcb;
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
651VOID
655 )
656/*++
657
658Routine 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
663Arguments:
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
670Return 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_)
785VOID
786FatDeleteDirent (
787 IN PIRP_CONTEXT IrpContext,
791 )
792
793/*++
794
795Routine Description:
796
797 This routine Deletes on the disk the indicated dirent. It does
798 this by marking the dirent as deleted.
799
800Arguments:
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
814Return Value:
815
816 None.
817
818--*/
819
820{
821 PBCB Bcb = NULL;
823 NTSTATUS DontCare;
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) ||
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 -
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
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_)
1001BOOLEAN
1002FatLfnDirentExists (
1003 IN PIRP_CONTEXT IrpContext,
1004 IN PDCB Dcb,
1007 )
1008/*++
1009
1010Routine Description:
1011
1012 This routine looks for a given Lfn in a directory
1013
1014Arguments:
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
1023Retrn Value:
1024
1025 BOOLEAN TRUE if it exists, FALSE if not
1026
1027--*/
1028{
1029 CCB Ccb;
1031 PBCB DirentBcb = NULL;
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_)
1076VOID
1077FatLocateDirent (
1078 IN PIRP_CONTEXT IrpContext,
1080 IN PCCB Ccb,
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
1093Routine Description:
1094
1095 This routine locates on the disk an undeleted dirent matching a given name.
1096
1097Arguments:
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
1125Return Value:
1126
1127 None.
1128
1129--*/
1130
1131{
1133
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
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
1316
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
1694GetNextDirent:
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_)
1720VOID
1721FatLocateSimpleOemDirent (
1722 IN PIRP_CONTEXT IrpContext,
1726 OUT PBCB *Bcb,
1728 )
1729
1730/*++
1731
1732Routine 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
1738Arguments:
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
1758Return 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_)
1799VOID
1800FatLocateVolumeLabel (
1801 IN PIRP_CONTEXT IrpContext,
1802 IN PVCB Vcb,
1804 OUT PBCB *Bcb,
1806 )
1807
1808/*++
1809
1810Routine 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
1816Arguments:
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
1829Return 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_)
1941VOID
1942FatGetDirentFromFcbOrDcb (
1943 IN PIRP_CONTEXT IrpContext,
1947 OUT PBCB *Bcb
1948 )
1949
1950/*++
1951
1952Routine Description:
1953
1954 This routine reads locates on the disk the dirent denoted by the
1955 specified Fcb/Dcb.
1956
1957Arguments:
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
1966Return 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_)
2045BOOLEAN
2046FatIsDirectoryEmpty (
2047 IN PIRP_CONTEXT IrpContext,
2048 IN PDCB Dcb
2049 )
2050
2051/*++
2052
2053Routine 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
2059Arguments:
2060
2061 Dcb - Supplies the DCB for the directory being queried.
2062
2063Return 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;
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
2170VOID
2172 IN PIRP_CONTEXT IrpContext,
2175 IN BOOLEAN ComponentReallyLowercase,
2176 IN BOOLEAN ExtensionReallyLowercase,
2179 IN BOOLEAN ZeroAndSetTimeFields,
2180 IN PLARGE_INTEGER SetCreationTime OPTIONAL
2181 )
2182
2183/*++
2184
2185Routine Description:
2186
2187 This routine modifies the fields of a dirent.
2188
2189Arguments:
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
2212Return 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
2243
2244 if (FatData.ChicagoMode) {
2245
2246 if (!SetCreationTime || !FatNtTimeToFatTime( IrpContext,
2247 SetCreationTime,
2248 FALSE,
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,
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
2439VOID
2441 IN PIRP_CONTEXT IrpContext,
2444 )
2445
2446/*++
2447
2448Routine Description:
2449
2450 This routine modifies the fields of a dirent to be used for a label.
2451
2452Arguments:
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
2459Return 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_)
2499VOID
2500FatSetFileSizeInDirent (
2501 IN PIRP_CONTEXT IrpContext,
2502 IN PFCB Fcb,
2503 IN PULONG AlternativeFileSize OPTIONAL
2504 )
2505
2506/*++
2507
2508Routine Description:
2509
2510 This routine saves the file size in an fcb into its dirent.
2511
2512Arguments:
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
2519Return Value:
2520
2521 None.
2522
2523--*/
2524
2525{
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_)
2553VOID
2554FatSetFileSizeInDirentNoRaise (
2555 IN PIRP_CONTEXT IrpContext,
2556 IN PFCB Fcb,
2557 IN PULONG AlternativeFileSize OPTIONAL
2558 )
2559
2560/*++
2561
2562Routine 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
2568Arguments:
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
2575Return 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_)
2594VOID
2595FatUpdateDirentFromFcb (
2596 IN PIRP_CONTEXT IrpContext,
2599 IN PCCB Ccb
2600 )
2601
2602
2603/*++
2604
2605Routine 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
2611Arguments:
2612
2613 FileObject - Fileobject representing the handle involved
2614
2615 FcbOrDcb - File/Dir involved
2616
2617 Ccb - User context involved
2618
2619Return Value:
2620
2621 None.
2622
2623--*/
2624
2625{
2626 BOOLEAN SetArchiveBit;
2627
2629 BOOLEAN UpdateLastWriteTime;
2630 BOOLEAN UpdateLastAccessTime;
2631 BOOLEAN UpdateDirent = FALSE;
2632
2634 PBCB DirentBcb = NULL;
2635 ULONG NotifyFilter = 0;
2636 FAT_TIME_STAMP CurrentFatTime = {0};
2637
2638 LARGE_INTEGER CurrentTime;
2639 LARGE_INTEGER CurrentDay = {0};
2640 LARGE_INTEGER LastAccessDay;
2641
2642 PAGED_CODE();
2643
2644 //
2645 // Nothing to do if the fcb is bad, volume is readonly or we got the
2646 // root dir.
2647 //
2648
2649 if (FcbOrDcb->FcbCondition != FcbGood ||
2652
2653 return;
2654 }
2655
2656 //
2657 // Check if we should be changing the time or file size and set
2658 // the archive bit on the file.
2659 //
2660
2661 KeQuerySystemTime( &CurrentTime );
2662
2663 //
2664 // Note that we HAVE to use BooleanFlagOn() here because
2665 // FO_FILE_SIZE_CHANGED > 0x80 (i.e., not in the first byte).
2666 //
2667
2668 SetArchiveBit = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
2669
2670 UpdateLastWriteTime = FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
2672
2675
2676 //
2677 // Do one further check here of access time. Only update it if
2678 // the current version is at least one day old. We know that
2679 // the current FcbOrDcb->LastAccessTime corresponds to 12 midnight local
2680 // time, so just see if the current time is on the same day.
2681 //
2682
2683 if (FatData.ChicagoMode &&
2684 (UpdateLastWriteTime ||
2687
2688 ExSystemTimeToLocalTime( &FcbOrDcb->LastAccessTime, &LastAccessDay );
2689 ExSystemTimeToLocalTime( &CurrentTime, &CurrentDay );
2690
2691 LastAccessDay.QuadPart /= FatOneDay.QuadPart;
2692 CurrentDay.QuadPart /= FatOneDay.QuadPart;
2693
2694 if (LastAccessDay.LowPart != CurrentDay.LowPart) {
2695
2696 UpdateLastAccessTime = TRUE;
2697
2698 } else {
2699
2700 UpdateLastAccessTime = FALSE;
2701 }
2702
2703 } else {
2704
2705 UpdateLastAccessTime = FALSE;
2706 }
2707
2708 if (SetArchiveBit ||
2710 UpdateLastWriteTime ||
2711 UpdateLastAccessTime
2712 ) {
2713
2714 DebugTrace(0, Dbg, "Update Time and/or file size on File/Dir\n", 0);
2715
2716 _SEH2_TRY {
2717
2718 _SEH2_TRY {
2719
2720#if (NTDDI_VERSION >= NTDDI_WIN8)
2721 //
2722 // Break parent directory oplock. Directory oplock breaks are
2723 // always advisory, so we will never block/get STATUS_PENDING here.
2724 //
2725
2726 if (FcbOrDcb->ParentDcb != NULL) {
2727
2728 FsRtlCheckOplockEx( FatGetFcbOplock(FcbOrDcb->ParentDcb),
2729 IrpContext->OriginatingIrp,
2730 OPLOCK_FLAG_PARENT_OBJECT,
2731 NULL,
2732 NULL,
2733 NULL );
2734 }
2735#endif
2736
2737 //
2738 // Get the dirent
2739 //
2740
2741 FatGetDirentFromFcbOrDcb( IrpContext,
2742 FcbOrDcb,
2743 FALSE,
2744 &Dirent,
2745 &DirentBcb );
2746
2747 if (UpdateLastWriteTime || UpdateLastAccessTime) {
2748
2749 (VOID)FatNtTimeToFatTime( IrpContext,
2750 &CurrentTime,
2751 TRUE,
2752 &CurrentFatTime,
2753 NULL );
2754 }
2755
2756 if (SetArchiveBit) {
2757
2758 Dirent->Attributes |= FILE_ATTRIBUTE_ARCHIVE;
2760
2762 UpdateDirent = TRUE;
2763 }
2764
2765 if (UpdateLastWriteTime) {
2766
2767 //
2768 // Update its time of last write
2769 //
2770
2771 FcbOrDcb->LastWriteTime = CurrentTime;
2772 Dirent->LastWriteTime = CurrentFatTime;
2773
2774 //
2775 // We call the notify package to report that the
2776 // last modification time has changed.
2777 //
2778
2780 UpdateDirent = TRUE;
2781 }
2782
2783 if (UpdateLastAccessTime) {
2784
2785 //
2786 // Now we have to truncate the local time down
2787 // to the current day, then convert back to UTC.
2788 //
2789
2791 CurrentDay.QuadPart * FatOneDay.QuadPart;
2792
2795
2796 Dirent->LastAccessDate = CurrentFatTime.Date;
2797
2798 //
2799 // We call the notify package to report that the
2800 // last access time has changed.
2801 //
2802
2804 UpdateDirent = TRUE;
2805 }
2806
2807 if (UpdateFileSize) {
2808
2809 //
2810 // Perhaps we were called to make certain that the
2811 // filesize on disc was updated - don't bother updating
2812 // and firing the filter if nothing changed.
2813 //
2814
2816
2817 if (Dirent->FileSize != FcbOrDcb->Header.FileSize.LowPart) {
2818
2819 //
2820 // Update the dirent file size
2821 //
2822
2823 Dirent->FileSize = FcbOrDcb->Header.FileSize.LowPart;
2824
2825 //
2826 // We call the notify package to report that the
2827 // size has changed.
2828 //
2829
2831 UpdateDirent = TRUE;
2832 }
2833
2834
2835 }
2836
2837
2838 FatNotifyReportChange( IrpContext,
2839 FcbOrDcb->Vcb,
2840 FcbOrDcb,
2843
2844 if (UpdateDirent) {
2845
2846 //
2847 // If all we did was update last access time,
2848 // don't mark the volume dirty.
2849 //
2850
2851 FatSetDirtyBcb( IrpContext,
2852 DirentBcb,
2854 NULL : FcbOrDcb->Vcb,
2855 TRUE );
2856 }
2857
2860
2861 FatResetExceptionState( IrpContext );
2862 } _SEH2_END;
2863
2864 } _SEH2_FINALLY {
2865
2866 FatUnpinBcb( IrpContext, DirentBcb );
2867 } _SEH2_END;
2868 }
2869
2870}
2871
2872
2873//
2874// Internal support routine
2875//
2876
2877UCHAR
2880 )
2881
2882/*++
2883
2884Routine Description:
2885
2886 This routine computes the Chicago long file name checksum.
2887
2888Arguments:
2889
2890 Dirent - Specifies the dirent that we are to compute a checksum for.
2891
2892Return Value:
2893
2894 The checksum.
2895
2896--*/
2897
2898{
2899 ULONG i;
2900 UCHAR Checksum;
2901
2902 PAGED_CODE();
2903
2904 Checksum = Dirent->FileName[0];
2905
2906 for (i=1; i < 11; i++) {
2907
2908 Checksum = ((Checksum & 1) ? 0x80 : 0) +
2909 (Checksum >> 1) +
2910 Dirent->FileName[i];
2911 }
2912
2913 return Checksum;
2914}
2915
2916
2917
2918#if 0 // It turns out Win95 is still creating short names without a ~
2919
2920//
2921// Internal support routine
2922//
2923
2924BOOLEAN
2925FatIsLfnPairValid (
2926 PWCHAR Lfn,
2927 ULONG LfnSize,
2929 )
2930
2931/*++
2932
2933Routine Description:
2934
2935 This routine does a few more checks to make sure that a LFN/short
2936 name pairing is legitimate. Basically this is the test:
2937
2938 Pairing is valid if:
2939
2940 DIRENT has a ~ character ||
2941 (LFN is 8.3 compliant &&
2942 (LFN has extended character(s) ? TRUE :
2943 LFN upcases to DIRENT))
2944
2945 When checking for the presence of a tilda character in the short
2946 name, note that we purposely do a single byte search instead of
2947 converting the name to UNICODE and looking there for the tilda.
2948 This protects us from accidently missing the tilda if the
2949 preceding byte is a lead byte in the current Oem code page,
2950 but wasn't in the Oem code page that created the file.
2951
2952 Also note that if the LFN is longer than 12 characters, then the
2953 second clause of the OR must be false.
2954
2955Arguments:
2956
2957 Lfn - Points to a buffer of UNICODE chars.
2958
2959 LfnSize - This is the size of the LFN in characters.
2960
2961 Dirent - Specifies the dirent we are to consider.
2962
2963Return Value:
2964
2965 TRUE if the Lfn/DIRENT form a legitimate pair, FALSE otherwise.
2966
2967--*/
2968
2969{
2970 ULONG i;
2971 BOOLEAN ExtendedChars;
2972 ULONG DirentBuffer[3];
2973 PUCHAR DirentName;
2974 ULONG DirentIndex;
2975 BOOLEAN DotEncountered;
2976
2977 //
2978 // First, look for a tilda
2979 //
2980
2981 for (i=0; i<11; i++) {
2982 if (Dirent->FileName[i] == '~') {
2983 return TRUE;
2984 }
2985 }
2986
2987 //
2988 // No tilda. If the LFN is longer than 12 characters, then it can
2989 // neither upcase to the DIRENT nor be 8.3 complient.
2990 //
2991
2992 if (LfnSize > 12) {
2993 return FALSE;
2994 }
2995
2996 //
2997 // Now see if the name is 8.3, and build an upcased DIRENT as well.
2998 //
2999
3000 DirentBuffer[0] = 0x20202020;
3001 DirentBuffer[1] = 0x20202020;
3002 DirentBuffer[2] = 0x20202020;
3003
3004 DirentName = (PUCHAR)DirentBuffer;
3005
3006 ExtendedChars = FALSE;
3007 DirentIndex = 0;
3008 DotEncountered = FALSE;
3009
3010 for (i=0; i < LfnSize; i++) {
3011
3012 //
3013 // Do dot transition work
3014 //
3015
3016 if (Lfn[i] == L'.') {
3017 if (DotEncountered ||
3018 (i > 8) ||
3019 ((LfnSize - i) > 4) ||
3020 (i && Lfn[i-1] == L' ')) {
3021 return FALSE;
3022 }
3023 DotEncountered = TRUE;
3024 DirentIndex = 8;
3025 continue;
3026 }
3027
3028 //
3029 // The character must be legal in order to be 8.3
3030 //
3031
3032 if ((Lfn[i] < 0x80) &&
3034 return FALSE;
3035 }
3036
3037 //
3038 // If the name contains no extended chars, continue building DIRENT
3039 //
3040
3041 if (!ExtendedChars) {
3042 if (Lfn[i] > 0x7f) {
3043 ExtendedChars = TRUE;
3044 } else {
3045 DirentName[DirentIndex++] = (UCHAR) (
3046 Lfn[i] < 'a' ? Lfn[i] : Lfn[i] <= 'z' ? Lfn[i] - ('a' - 'A') : Lfn[i]);
3047 }
3048 }
3049 }
3050
3051 //
3052 // If the LFN ended in a space, or there was no dot and the name
3053 // has more than 8 characters, then it is not 8.3 compliant.
3054 //
3055
3056 if ((Lfn[LfnSize - 1] == L' ') ||
3057 (!DotEncountered && (LfnSize > 8))) {
3058 return FALSE;
3059 }
3060
3061 //
3062 // OK, now if we got this far then the LFN is 8dot3. If there are
3063 // no extended characters, then we can also check to make sure that
3064 // the LFN is only a case varient of the DIRENT.
3065 //
3066
3067 if (!ExtendedChars &&
3068 !RtlEqualMemory(Dirent->FileName, DirentName, 11)) {
3069
3070 return FALSE;
3071 }
3072
3073 //
3074 // We have now verified this pairing the very best we can without
3075 // knowledge of the code page that the file was created under.
3076 //
3077
3078 return TRUE;
3079}
3080#endif //0
3081
3082//
3083// Internal support routine
3084//
3085
3086_Requires_lock_held_(_Global_critical_region_)
3087VOID
3088FatRescanDirectory (
3089 PIRP_CONTEXT IrpContext,
3090 PDCB Dcb
3091 )
3092
3093/*++
3094
3095Routine Description:
3096
3097 This routine rescans the given directory, finding the first unused
3098 dirent, first deleted dirent, and setting the free dirent bitmap
3099 appropriately.
3100
3101Arguments:
3102
3103 Dcb - Supplies the directory to rescan.
3104
3105Return Value:
3106
3107 None.
3108
3109--*/
3110
3111{
3112 PBCB Bcb = NULL;
3115
3116 ULONG UnusedVbo;
3117 ULONG DeletedHint;
3118 ULONG DirentIndex;
3119 ULONG DirentsThisRun;
3120 ULONG StartIndexOfThisRun;
3121
3122 enum RunType {
3123 InitialRun,
3124 FreeDirents,
3125 AllocatedDirents,
3126 } CurrentRun;
3127
3128 PAGED_CODE();
3129
3130 DebugTrace( 0, Dbg, "We must scan the whole directory.\n", 0);
3131
3132 UnusedVbo = 0;
3133 DeletedHint = 0xffffffff;
3134
3135 //
3136 // To start with, we have to find out if the first dirent is free.
3137 //
3138
3139 CurrentRun = InitialRun;
3140 DirentIndex =
3141 StartIndexOfThisRun = 0;
3142
3143 _SEH2_TRY {
3144
3145 while ( TRUE ) {
3146
3147 BOOLEAN DirentDeleted;
3148
3149 //
3150 // Read a dirent
3151 //
3152
3153 FatReadDirent( IrpContext,
3154 Dcb,
3155 UnusedVbo,
3156 &Bcb,
3157 &Dirent,
3158 &Status );
3159
3160 //
3161 // If EOF, or we found a NEVER_USED entry, we exit the loop
3162 //
3163
3164 if ( (Status == STATUS_END_OF_FILE ) ||
3165 (Dirent->FileName[0] == FAT_DIRENT_NEVER_USED)) {
3166
3167 break;
3168 }
3169
3170 //
3171 // If the dirent is DELETED, and it is the first one we found, set
3172 // it in the deleted hint.
3173 //
3174
3175 if (Dirent->FileName[0] == FAT_DIRENT_DELETED) {
3176
3177 DirentDeleted = TRUE;
3178
3179 if (DeletedHint == 0xffffffff) {
3180
3181 DeletedHint = UnusedVbo;
3182 }
3183
3184 } else {
3185
3186 DirentDeleted = FALSE;
3187 }
3188
3189 //
3190 // Check for the first time through the loop, and determine
3191 // the current run type.
3192 //
3193
3194 if (CurrentRun == InitialRun) {
3195
3196 CurrentRun = DirentDeleted ?
3197 FreeDirents : AllocatedDirents;
3198
3199 } else {
3200
3201 //
3202 // Are we switching from a free run to an allocated run?
3203 //
3204
3205 if ((CurrentRun == FreeDirents) && !DirentDeleted) {
3206
3207 DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3208
3209 RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3210 StartIndexOfThisRun,
3211 DirentsThisRun );
3212
3213 CurrentRun = AllocatedDirents;
3214 StartIndexOfThisRun = DirentIndex;
3215 }
3216
3217 //
3218 // Are we switching from an allocated run to a free run?
3219 //
3220
3221 if ((CurrentRun == AllocatedDirents) && DirentDeleted) {
3222
3223 DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3224
3225 RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3226 StartIndexOfThisRun,
3227 DirentsThisRun );
3228
3229 CurrentRun = FreeDirents;
3230 StartIndexOfThisRun = DirentIndex;
3231 }
3232 }
3233
3234 //
3235 // Move on to the next dirent.
3236 //
3237
3238 UnusedVbo += sizeof(DIRENT);
3239 Dirent += 1;
3240 DirentIndex += 1;
3241 }
3242
3243 //
3244 // Now we have to record the final run we encoutered
3245 //
3246
3247 DirentsThisRun = DirentIndex - StartIndexOfThisRun;
3248
3249 if ((CurrentRun == FreeDirents) || (CurrentRun == InitialRun)) {
3250
3251 RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3252 StartIndexOfThisRun,
3253 DirentsThisRun );
3254
3255 } else {
3256
3257 RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3258 StartIndexOfThisRun,
3259 DirentsThisRun );
3260 }
3261
3262 //
3263 // Now if there we bailed prematurely out of the loop because
3264 // we hit an unused entry, set all the rest as free.
3265 //
3266
3267 if (UnusedVbo < Dcb->Header.AllocationSize.LowPart) {
3268
3269 StartIndexOfThisRun = UnusedVbo / sizeof(DIRENT);
3270
3271 DirentsThisRun = (Dcb->Header.AllocationSize.LowPart -
3272 UnusedVbo) / sizeof(DIRENT);
3273
3274 RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3275 StartIndexOfThisRun,
3276 DirentsThisRun);
3277 }
3278
3279 } _SEH2_FINALLY {
3280
3281 FatUnpinBcb( IrpContext, Bcb );
3282 } _SEH2_END;
3283
3284 //
3285 // If there weren't any DELETED entries, set the index to our current
3286 // position.
3287 //
3288
3289 if (DeletedHint == 0xffffffff) { DeletedHint = UnusedVbo; }
3290
3291 Dcb->Specific.Dcb.UnusedDirentVbo = UnusedVbo;
3292 Dcb->Specific.Dcb.DeletedDirentHint = DeletedHint;
3293
3294 return;
3295}
3296
3297
3298//
3299// Internal support routine
3300//
3301
3302_Requires_lock_held_(_Global_critical_region_)
3303ULONG
3304FatDefragDirectory (
3305 IN PIRP_CONTEXT IrpContext,
3306 IN PDCB Dcb,
3308 )
3309
3310/*++
3311
3312Routine Description:
3313
3314 This routine determines if the requested number of dirents can be found
3315 in the directory, looking for deleted dirents and orphaned LFNs. If the
3316 request can be satisifed, orphaned LFNs are marked as deleted, and deleted
3317 dirents are all grouped together at the end of the directory.
3318
3319 Note that this routine is currently used only on the root directory, but
3320 it is completely general and could be used on any directory.
3321
3322Arguments:
3323
3324 Dcb - Supplies the directory to defrag.
3325
3326Return Value:
3327
3328 The Index of the first dirent available for use, or -1 if the
3329 request cannot be satisfied.
3330
3331--*/
3332
3333{
3334 ULONG SavedIrpContextFlag;
3335 PLIST_ENTRY Links;
3336 ULONG ReturnValue = 0;
3337 PFCB Fcb;
3338
3339 PBCB Bcb = NULL;
3341 UNICODE_STRING Lfn = {0,0,NULL};
3342
3343 LARGE_MCB Mcb;
3344 BOOLEAN McbInitialized = FALSE;
3345 BOOLEAN InvalidateFcbs = FALSE;
3346
3348 PUCHAR UnusedDirents;
3349 PUCHAR UnusedDirentBuffer = NULL;
3350 PUCHAR UsedDirents;
3351 PUCHAR UsedDirentBuffer = NULL;
3352
3353 PBCB *Bcbs = NULL;
3354 ULONG Page;
3355 ULONG PagesPinned = 0;
3356
3357 ULONG DcbSize;
3359
3360 PAGED_CODE();
3361
3362 //
3363 // We assume we own the Vcb.
3364 //
3365
3366 NT_ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
3367
3368 //
3369 // We will only attempt this on directories less than 0x40000 bytes
3370 // long (by default on DOS the root directory is only 0x2000 long).
3371 // This is to avoid a cache manager complication.
3372 //
3373
3374 DcbSize = Dcb->Header.AllocationSize.LowPart;
3375
3376 if (DcbSize > 0x40000) {
3377
3378 return (ULONG)-1;
3379 }
3380
3381 //
3382 // Force wait to TRUE
3383 //
3384
3385 SavedIrpContextFlag = IrpContext->Flags;
3386
3387 SetFlag( IrpContext->Flags,
3389
3390 //
3391 // Now acquire all open Fcbs in the Dcb exclusive.
3392 //
3393
3394 for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3395 Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3396 Links = Links->Flink) {
3397
3398 Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3399
3401 }
3402
3403 _SEH2_TRY {
3404
3405 CCB Ccb;
3406 ULONG QueryOffset = 0;
3407 ULONG FoundOffset = 0;
3408 ULONGLONG BytesUsed = 0;
3409
3410 NTSTATUS DontCare;
3411 ULONG Run;
3412 ULONG TotalRuns;
3414 PUCHAR Char;
3415
3416 //
3417 // We are going to build a new bitmap that will show all orphaned
3418 // LFNs as well as deleted dirents as available.
3419 //
3420 // Initialize our local CCB that will match all files and even
3421 // a label if it is here.
3422 //
3423
3424 RtlZeroMemory( &Ccb, sizeof(CCB) );
3426
3427 //
3428 // Init the Long File Name string.
3429 //
3430
3431 Lfn.MaximumLength = 260 * sizeof(WCHAR);
3433 260*sizeof(WCHAR),
3435
3436 //
3437 // Initalize the Mcb. We use this structure to keep track of runs
3438 // of free and allocated dirents. Runs are identity allocations, and
3439 // holes are free dirents.
3440 //
3441
3443
3444 McbInitialized = TRUE;
3445
3446 do {
3447
3448 FatLocateDirent( IrpContext,
3449 Dcb,
3450 &Ccb,
3451 QueryOffset,
3452 NULL,
3453 &Dirent,
3454 &Bcb,
3455 (PVBO)&FoundOffset,
3456 NULL,
3457 &Lfn,
3458 NULL );
3459
3460 if (Dirent != NULL) {
3461
3463
3464 //
3465 // Compute the LfnByteOffset.
3466 //
3467
3468 LfnByteOffset = FoundOffset -
3470
3471 BytesUsed = FoundOffset - LfnByteOffset + sizeof(DIRENT);
3472
3473 //
3474 // Set a run to represent all the dirents used for this
3475 // file in the Dcb dir.
3476 //
3477
3478#ifdef _MSC_VER
3479#pragma prefast( suppress:28931, "needed for debug build" )
3480#endif
3484 BytesUsed );
3485
3486 NT_ASSERT( Result );
3487
3488 //
3489 // Move on to the next dirent.
3490 //
3491
3492 TotalBytesAllocated += (ULONG) BytesUsed;
3493 QueryOffset = FoundOffset + sizeof(DIRENT);
3494 }
3495
3496 } while ((Dirent != NULL) && (QueryOffset < DcbSize));
3497
3498 if (Bcb != NULL) {
3499
3500 FatUnpinBcb( IrpContext, Bcb );
3501 }
3502
3503 //
3504 // If we need more dirents than are available, bail.
3505 //
3506
3507 if (DirentsNeeded > (DcbSize - TotalBytesAllocated)/sizeof(DIRENT)) {
3508
3510 }
3511
3512 //
3513 // Now we are going to copy all the used and un-used parts of the
3514 // directory to separate pool.
3515 //
3516 // Allocate these buffers and pin the entire directory.
3517 //
3518
3519 UnusedDirents =
3520 UnusedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3521 DcbSize - TotalBytesAllocated,
3522 TAG_DIRENT );
3523
3524 UsedDirents =
3525 UsedDirentBuffer = FsRtlAllocatePoolWithTag( PagedPool,
3527 TAG_DIRENT );
3528
3529 PagesPinned = (DcbSize + (PAGE_SIZE - 1 )) / PAGE_SIZE;
3530
3532 PagesPinned * sizeof(PBCB),
3533 TAG_BCB );
3534
3535 RtlZeroMemory( Bcbs, PagesPinned * sizeof(PBCB) );
3536
3537 for (Page = 0; Page < PagesPinned; Page += 1) {
3538
3539 ULONG PinSize;
3540
3541 //
3542 // Don't try to pin beyond the Dcb size.
3543 //
3544
3545 if ((Page + 1) * PAGE_SIZE > DcbSize) {
3546
3547 PinSize = DcbSize - (Page * PAGE_SIZE);
3548
3549 } else {
3550
3551 PinSize = PAGE_SIZE;
3552 }
3553
3554 FatPrepareWriteDirectoryFile( IrpContext,
3555 Dcb,
3556 Page * PAGE_SIZE,
3557 PinSize,
3558 &Bcbs[Page],
3559#ifndef __REACTOS__
3560 &Dirent,
3561#else
3562 (PVOID *)&Dirent,
3563#endif
3564 FALSE,
3565 TRUE,
3566 &DontCare );
3567
3568 if (Page == 0) {
3570 }
3571 }
3572
3573 TotalRuns = FsRtlNumberOfRunsInLargeMcb( &Mcb );
3574
3575 for (Run = 0; Run < TotalRuns; Run++) {
3576
3577 LBO Vbo;
3578 LBO Lbo;
3579
3580#ifdef _MSC_VER
3581#pragma prefast( suppress:28931, "needed for debug build" )
3582#endif
3584 Run,
3585 &Vbo,
3586 &Lbo,
3587 (PLONGLONG)&BytesUsed );
3588
3590
3591 //
3592 // Copy each run to their specific pool.
3593 //
3594
3595 if (Lbo != -1) {
3596
3597 RtlCopyMemory( UsedDirents,
3598 Directory + Vbo,
3599 (ULONG) BytesUsed );
3600
3601 UsedDirents += BytesUsed;
3602
3603 } else {
3604
3605 RtlCopyMemory( UnusedDirents,
3606 Directory + Vbo,
3607 (ULONG) BytesUsed );
3608
3609 UnusedDirents += BytesUsed;
3610 }
3611 }
3612
3613 //
3614 // Marking all the un-used dirents as "deleted". This will reclaim
3615 // storage used by orphaned LFNs.
3616 //
3617
3618 for (Char = UnusedDirentBuffer; Char < UnusedDirents; Char += sizeof(DIRENT)) {
3619
3620 *Char = FAT_DIRENT_DELETED;
3621 }
3622
3623 //
3624 // Now, for the permanent step. Copy the two pool buffer back to the
3625 // real Dcb directory, and flush the Dcb directory
3626 //
3627
3628 NT_ASSERT( TotalBytesAllocated == (ULONG)(UsedDirents - UsedDirentBuffer) );
3629
3630 RtlCopyMemory( Directory, UsedDirentBuffer, TotalBytesAllocated );
3631
3633 UnusedDirentBuffer,
3634 UnusedDirents - UnusedDirentBuffer );
3635
3636 //
3637 // We need to unpin here so that the UnpinRepinned won't deadlock.
3638 //
3639
3640 if (Bcbs) {
3641 for (Page = 0; Page < PagesPinned; Page += 1) {
3642 FatUnpinBcb( IrpContext, Bcbs[Page] );
3643 }
3644 ExFreePool(Bcbs);
3645 Bcbs = NULL;
3646 }
3647
3648 //
3649 // Now make the free dirent bitmap reflect the new state of the Dcb
3650 // directory.
3651 //
3652
3653 RtlSetBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3654 0,
3655 TotalBytesAllocated / sizeof(DIRENT) );
3656
3657 RtlClearBits( &Dcb->Specific.Dcb.FreeDirentBitmap,
3658 TotalBytesAllocated / sizeof(DIRENT),
3659 (DcbSize - TotalBytesAllocated) / sizeof(DIRENT) );
3660
3662
3663 //
3664 // Flush the directory to disk. If we raise, we will need to invalidate
3665 // all of the children. Sorry, guys, but I can't figure out where you are
3666 // now - if this failed I probably can't read the media either. And we
3667 // probably purged the cache to boot.
3668 //
3669
3670 _SEH2_TRY {
3671
3672 FatUnpinRepinnedBcbs( IrpContext );
3673
3676
3677 InvalidateFcbs = TRUE;
3678 } _SEH2_END;
3679
3680 //
3681 // OK, now nothing can go wrong. We have two more things to do.
3682 // First, we have to fix up all the dirent offsets in any open Fcbs.
3683 // If we cannot now find the Fcb, the file is marked invalid. Also,
3684 // we skip deleted files.
3685 //
3686
3687 for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3688 Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3689 Links = Links->Flink) {
3690
3691 PBCB TmpBcb = NULL;
3692 ULONG TmpOffset = 0;
3693 PDIRENT TmpDirent = NULL;
3694 ULONG PreviousLfnSpread;
3695
3696 Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3697
3698 if (IsFileDeleted( IrpContext, Fcb )) {
3699
3700 continue;
3701 }
3702
3703 //
3704 // If we aren't already giving up, safely try to pick up the dirent
3705 // to update the Fcb. If this raises, we have to give up and blow
3706 // evenyone else away too.
3707 //
3708
3709 if (!InvalidateFcbs) {
3710
3711 _SEH2_TRY {
3712
3713 FatLocateSimpleOemDirent( IrpContext,
3714 Dcb,
3716 &TmpDirent,
3717 &TmpBcb,
3718 (PVBO)&TmpOffset );
3719
3722
3723 InvalidateFcbs = TRUE;
3724 } _SEH2_END;
3725 }
3726
3727 if (TmpBcb == NULL || InvalidateFcbs) {
3728
3729 FatUnpinBcb( IrpContext, TmpBcb );
3730 FatMarkFcbCondition( IrpContext, Fcb, FcbBad, TRUE );
3731
3732 } else {
3733
3734 FatUnpinBcb( IrpContext, TmpBcb );
3735
3736 PreviousLfnSpread = Fcb->DirentOffsetWithinDirectory -
3738
3739 Fcb->DirentOffsetWithinDirectory = TmpOffset;
3740 Fcb->LfnOffsetWithinDirectory = TmpOffset - PreviousLfnSpread;
3741 }
3742 }
3743
3744 try_exit: NOTHING;
3745 } _SEH2_FINALLY {
3746
3747 //
3748 // Free all our resources and stuff.
3749 //
3750
3751 if (McbInitialized) {
3753 }
3754
3755 if (Lfn.Buffer) {
3757 }
3758
3759 if (UnusedDirentBuffer) {
3760 ExFreePool( UnusedDirentBuffer );
3761 }
3762
3763 if (UsedDirentBuffer) {
3764 ExFreePool( UsedDirentBuffer );
3765 }
3766
3767 if (Bcbs) {
3768 for (Page = 0; Page < PagesPinned; Page += 1) {
3769 FatUnpinBcb( IrpContext, Bcbs[Page] );
3770 }
3771 ExFreePool(Bcbs);
3772 }
3773
3774 FatUnpinBcb( IrpContext, Bcb );
3775
3776 for (Links = Dcb->Specific.Dcb.ParentDcbQueue.Flink;
3777 Links != &Dcb->Specific.Dcb.ParentDcbQueue;
3778 Links = Links->Flink) {
3779
3780 Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3781
3782 ExReleaseResourceLite( Fcb->Header.Resource );
3783 }
3784
3785 IrpContext->Flags = SavedIrpContextFlag;
3786 } _SEH2_END;
3787
3788 //
3789 // Now return the offset of the first free dirent to the caller.
3790 //
3791
3792 return ReturnValue;
3793}
3794
3795
3796
NodeType
Definition: Node.h:6
unsigned char BOOLEAN
#define VOID
Definition: acefi.h:82
UINT32 void void ** ReturnValue
Definition: acevents.h:216
struct NameRec_ * Name
Definition: cdprocs.h:460
LONG NTSTATUS
Definition: precomp.h:26
VOID DeleteContext(PWSTR pszName)
Definition: context.c:224
PWCHAR Label
Definition: format.c:70
_In_ PFCB Fcb
Definition: dirsup.c:398
PAGED_CODE()
_In_ PFCB _In_ PDIRENT_ENUM_CONTEXT _Inout_ PDIRENT Dirent
Definition: dirsup.c:425
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:592
#define try_return(S)
Definition: cdprocs.h:2179
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1215
@ FcbGood
Definition: cdstruc.h:779
@ FcbBad
Definition: cdstruc.h:780
@ FcbNeedsToBeVerified
Definition: cdstruc.h:781
Definition: bufpool.h:45
Definition: Header.h:9
#define _Requires_lock_held_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define NodeType(P)
Definition: nodetype.h:51
_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:4144
_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:4145
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG LfnByteOffset
Definition: create.c:4143
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB * Dcb
Definition: create.c:4140
LONGLONG LBO
Definition: fat.h:34
#define FAT_DIRENT_NT_BYTE_8_LOWER_CASE
Definition: fat.h:361
#define FAT_DIRENT_ATTR_ARCHIVE
Definition: fat.h:373
VBO * PVBO
Definition: fat.h:39
#define FAT_DIRENT_ATTR_VOLUME_ID
Definition: fat.h:371
ULONG32 VBO
Definition: fat.h:38
#define FAT_DIRENT_NT_BYTE_3_LOWER_CASE
Definition: fat.h:362
#define FAT_DIRENT_DELETED
Definition: fat.h:337
FAT8DOT3 * PFAT8DOT3
Definition: fat.h:296
#define FAT_DIRENT_NEVER_USED
Definition: fat.h:334
#define FAT_DIRENT_ATTR_LFN
Definition: fat.h:375
#define MAX_LFN_DIRENTS
Definition: lfn.h:51
#define FAT_LAST_LONG_ENTRY
Definition: lfn.h:35
LFN_DIRENT * PLFN_DIRENT
Definition: lfn.h:44
PACKED_LFN_DIRENT LFN_DIRENT
Definition: lfn.h:43
#define FAT_LFN_DIRENTS_NEEDED(NAME)
Definition: lfn.h:53
#define FAT_NTC_ROOT_DCB
Definition: nodetype.h:31
#define FAT_NTC_FCB
Definition: nodetype.h:29
#define FAT_NTC_DCB
Definition: nodetype.h:30
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define TAG_DIRENT
Definition: nodetype.h:158
#define TAG_BCB
Definition: nodetype.h:157
#define TAG_FILENAME_BUFFER
Definition: nodetype.h:167
LONG TotalBytesAllocated
Definition: memory.c:15
#define ExLocalTimeToSystemTime(LocTime, SysTime)
Definition: env_spec_w32.h:738
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define ExSystemTimeToLocalTime(SysTime, LocTime)
Definition: env_spec_w32.h:729
#define PagedPool
Definition: env_spec_w32.h:308
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
#define IRP_CONTEXT_FLAG_WRITE_THROUGH
Definition: ext2fs.h:1088
#define IsFileDeleted(Mcb)
Definition: ext2fs.h:968
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
VOID FatPinMappedData(IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb)
Definition: cachesup.c:1866
VOID FatTunnelFcbOrDcb(IN PFCB FcbOrDcb, IN PCCB Ccb OPTIONAL)
Definition: dirsup.c:652
#define FatConstructDot(IRPCONTEXT, DCB, PARENT, DIRENT)
Definition: dirsup.c:49
#define FatConstructDotDot(IRPCONTEXT, DCB, PARENT, DIRENT)
Definition: dirsup.c:80
#define FatReadDirent(IRPCONTEXT, DCB, VBO, BCB, DIRENT, STATUS)
Definition: dirsup.c:132
VOID FatConstructLabelDirent(IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING Label)
Definition: dirsup.c:2440
UCHAR FatComputeLfnChecksum(PDIRENT Dirent)
Definition: dirsup.c:2878
#define Dbg
Definition: dirsup.c:28
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
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
FAT_DATA FatData
Definition: fatdata.c:56
LARGE_INTEGER FatOneDay
Definition: fatdata.c:72
#define TimerStart(LEVEL)
Definition: fatdata.h:318
#define TimerStop(LEVEL, s)
Definition: fatdata.h:319
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
#define DIRENT
Definition: fatfs.h:187
#define FatVcbAcquiredExclusive(IRPCONTEXT, VCB)
Definition: fatprocs.h:1495
IN PDCB IN ULONG IN BOOLEAN RescanDir
Definition: fatprocs.h:701
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:414
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:546
VOID FatStringTo8dot3(_In_ PIRP_CONTEXT IrpContext, _In_ OEM_STRING InputString, _Out_writes_bytes_(11) PFAT8DOT3 Output8dot3)
Definition: namesup.c:79
IN PFCB IN BOOLEAN ReturnOnFailure
Definition: fatprocs.h:772
FAT_TIME_STAMP FatGetCurrentFatTime(_In_ PIRP_CONTEXT IrpContext)
Definition: timesup.c:317
IN PFCB IN VBO OUT PLBO Lbo
Definition: fatprocs.h:308
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2168
IN PDCB IN PCCB IN VBO OffsetToStartSearchFrom
Definition: fatprocs.h:727
#define FatResetExceptionState(IRPCONTEXT)
Definition: fatprocs.h:2983
IN PDCB ParentDirectory
Definition: fatprocs.h:698
IN PDCB IN PUNICODE_STRING IN PUNICODE_STRING LfnTmp
Definition: fatprocs.h:755
IN PFCB IN PDELETE_CONTEXT DeleteContext IN BOOLEAN DeleteEa
Definition: fatprocs.h:718
VOID FatEnsureStringBufferEnough(_Inout_ PVOID String, _In_ USHORT DesiredBufferSize)
Definition: strucsup.c:3739
IN PFCB FcbOrDcb
Definition: fatprocs.h:306
IN PDCB IN ULONG DirentsNeeded
Definition: fatprocs.h:699
IN PFCB IN VBO Vbo
Definition: fatprocs.h:307
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2995
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2977
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:731
BOOLEAN FatIsNameInExpression(IN PIRP_CONTEXT IrpContext, IN OEM_STRING Expression, IN OEM_STRING Name)
Definition: namesup.c:35
VOID Fat8dot3ToString(_In_ PIRP_CONTEXT IrpContext, _In_ PDIRENT Dirent, _In_ BOOLEAN RestoreCase, _Out_ POEM_STRING OutputString)
Definition: namesup.c:179
VOID FatFreeStringBuffer(_Inout_ PVOID String)
Definition: strucsup.c:3784
#define FatDirectoryKey(FcbOrDcb)
Definition: fatprocs.h:850
IN PDCB IN PDIRENT ParentDirent
Definition: fatprocs.h:709
IN PVCB IN ULONG IN OUT PULONG IN BOOLEAN OUT PLARGE_MCB Mcb
Definition: fatprocs.h:348
#define FatIsFat32(VCB)
Definition: fatprocs.h:1446
VOID FatMarkFcbCondition(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FCB_CONDITION FcbCondition, IN BOOLEAN Recursive)
#define FCB_STATE_8_LOWER_CASE
Definition: fatstruc.h:1210
#define CCB_FLAG_QUERY_TEMPLATE_MIXED
Definition: fatstruc.h:1303
#define CCB_FLAG_USER_SET_LAST_WRITE
Definition: fatstruc.h:1266
#define VCB_STATE_FLAG_REMOVABLE_MEDIA
Definition: fatstruc.h:560
#define CCB_FLAG_OPENED_BY_SHORTNAME
Definition: fatstruc.h:1296
#define CCB_FLAG_SKIP_SHORT_NAME_COMPARE
Definition: fatstruc.h:1253
#define VCB_STATE_FLAG_WRITE_PROTECTED
Definition: fatstruc.h:570
#define CCB_FLAG_MATCH_VOLUME_ID
Definition: fatstruc.h:1317
#define CCB_FLAG_MATCH_ALL
Definition: fatstruc.h:1252
#define CCB_FLAG_USER_SET_LAST_ACCESS
Definition: fatstruc.h:1267
#define FCB_STATE_3_LOWER_CASE
Definition: fatstruc.h:1211
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define FsRtlIsAnsiCharacterLegalFat(C, WILD)
Definition: fsrtlfuncs.h:1611
Status
Definition: gdiplustypes.h:25
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 EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
NTSYSAPI BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP, ULONG, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlDowncaseUnicodeString(UNICODE_STRING *, const UNICODE_STRING *, BOOLEAN)
NTSYSAPI ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP, ULONG, ULONG)
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI void WINAPI RtlSetBits(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
#define NOTHING
Definition: input_list.c:10
#define RtlEqualMemory(a, b, c)
Definition: kdvm.h:18
BOOLEAN NTAPI FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb, IN LONGLONG Vbn, IN LONGLONG Lbn, IN LONGLONG SectorCount)
Definition: largemcb.c:288
VOID NTAPI FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:1096
VOID NTAPI FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb, IN POOL_TYPE PoolType)
Definition: largemcb.c:451
ULONG NTAPI FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
Definition: largemcb.c:765
BOOLEAN NTAPI FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb, IN ULONG RunIndex, OUT PLONGLONG Vbn, OUT PLONGLONG Lbn, OUT PLONGLONG SectorCount)
Definition: largemcb.c:392
#define PCHAR
Definition: match.c:90
static PLARGE_INTEGER Time
Definition: time.c:105
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
__GNU_EXTENSION typedef __int64 * PLONGLONG
Definition: ntbasedef.h:382
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define ARGUMENT_PRESENT(ArgumentPointer)
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
BOOLEAN NTAPI ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
Definition: resource.c:1624
ULONG NTAPI ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
Definition: resource.c:1663
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
BOOLEAN NTAPI FsRtlIsNtstatusExpected(IN NTSTATUS NtStatus)
Definition: filter.c:61
BOOLEAN NTAPI FsRtlIsNameInExpression(IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCHAR UpcaseTable OPTIONAL)
Definition: name.c:514
BOOLEAN NTAPI FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1, IN PCUNICODE_STRING Name2, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
Definition: name.c:296
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1306
#define STATUS_CANNOT_MAKE
Definition: ntstatus.h:854
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
#define Vcb
Definition: cdprocs.h:1415
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:158
NTSTATUS NTAPI RtlOemStringToCountedUnicodeString(IN OUT PUNICODE_STRING UniDest, IN PCOEM_STRING OemSource, IN BOOLEAN AllocateDestinationString)
Definition: unicode.c:1473
#define STATUS_END_OF_FILE
Definition: shellext.h:67
#define STATUS_SUCCESS
Definition: shellext.h:65
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base for all directory entries
Definition: entries.h:138
Definition: cdstruc.h:1067
union _CCB::@723::@725::@727 OemQueryTemplate
FAT8DOT3 Constant
Definition: fatstruc.h:1426
ULONG Flags
Definition: cdstruc.h:1080
BOOLEAN ContainsWildCards
Definition: fatstruc.h:1379
BOOLEAN ChicagoMode
Definition: fatstruc.h:87
FAT_DATE Date
Definition: fat.h:286
Definition: cdstruc.h:902
struct _FCB * ParentDcb
Definition: fatstruc.h:836
VBO LfnOffsetWithinDirectory
Definition: fatstruc.h:913
LONGLONG CreationTime
Definition: cdstruc.h:1030
union _FCB::@719 Specific
ULONG Flags
Definition: ntfs.h:536
PVCB Vcb
Definition: cdstruc.h:933
UNICODE_STRING ExactCaseLongName
Definition: fatstruc.h:1139
FCB_CONDITION FcbCondition
Definition: fatstruc.h:850
LARGE_INTEGER LastWriteTime
Definition: fatstruc.h:922
ULONG FirstClusterOfFile
Definition: fatstruc.h:818
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:925
ULONG FcbState
Definition: cdstruc.h:971
LARGE_INTEGER LastAccessTime
Definition: fatstruc.h:921
struct _FCB::@719::@721 Dcb
FILE_NAME_NODE ShortName
Definition: fatstruc.h:1115
UCHAR DirentFatFlags
Definition: fatstruc.h:1133
VBO DirentOffsetWithinDirectory
Definition: fatstruc.h:906
union _FILE_NAME_NODE::@718 Name
OEM_STRING Oem
Definition: fatstruc.h:693
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
UCHAR Attributes
Definition: lfn.h:26
WCHAR Name2[6]
Definition: lfn.h:29
UCHAR Name1[10]
Definition: lfn.h:25
WCHAR Name3[2]
Definition: lfn.h:31
UCHAR Ordinal
Definition: lfn.h:24
USHORT MustBeZero
Definition: lfn.h:30
UCHAR Checksum
Definition: lfn.h:28
UCHAR Type
Definition: lfn.h:27
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: cdstruc.h:498
ERESOURCE Resource
Definition: fatstruc.h:404
TUNNEL Tunnel
Definition: fatstruc.h:512
ULONG VcbState
Definition: cdstruc.h:540
Definition: bidi.c:434
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:342
VOID NTAPI FsRtlDeleteKeyFromTunnelCache(IN PTUNNEL Cache, IN ULONGLONG DirectoryKey)
Definition: tunnel.c:589
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char * PBOOLEAN
Definition: typedefs.h:53
uint16_t * PUSHORT
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
#define STATUS_FILE_CORRUPT_ERROR
Definition: udferr_usr.h:168
STRING OEM_STRING
Definition: umtypes.h:203
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
struct tagRun Run
static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize, BOOLEAN IsFatX)
Definition: finfo.c:1182
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_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:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define FILE_NOTIFY_CHANGE_SIZE
#define FILE_ACTION_MODIFIED
#define FO_FILE_FAST_IO_READ
Definition: iotypes.h:1795
#define FILE_NOTIFY_CHANGE_LAST_ACCESS
#define FILE_NOTIFY_CHANGE_ATTRIBUTES
#define FO_FILE_MODIFIED
Definition: iotypes.h:1788
* PFILE_OBJECT
Definition: iotypes.h:1998
#define FO_FILE_SIZE_CHANGED
Definition: iotypes.h:1789
#define FILE_NOTIFY_CHANGE_LAST_WRITE
#define NT_ASSERT
Definition: rtlfuncs.h:3310
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180
_In_opt_ HANDLE _In_opt_ PIO_APC_ROUTINE _In_opt_ PVOID _Out_ PIO_STATUS_BLOCK _In_ ULONG NotifyFilter
Definition: zwfuncs.h:504