ReactOS  0.4.14-dev-50-g13bb5e2
fileinfo.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  FileInfo.c
8 
9 Abstract:
10 
11  This module implements the File Information routines for Fat called by
12  the dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 // The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId (FAT_BUG_CHECK_FILEINFO)
24 
25 //
26 // The local debug trace level
27 //
28 
29 #define Dbg (DEBUG_TRACE_FILEINFO)
30 
31 VOID
33  IN PIRP_CONTEXT IrpContext,
34  IN PFCB Fcb,
38  );
39 
40 _Requires_lock_held_(_Global_critical_region_)
41 VOID
42 FatQueryStandardInfo (
43  IN PIRP_CONTEXT IrpContext,
44  IN PFCB Fcb,
47  );
48 
49 VOID
51  IN PIRP_CONTEXT IrpContext,
52  IN PFCB Fcb,
55  );
56 
57 VOID
59  IN PIRP_CONTEXT IrpContext,
60  IN PFCB Fcb,
63  );
64 
65 VOID
67  IN PIRP_CONTEXT IrpContext,
71  );
72 
73 _Requires_lock_held_(_Global_critical_region_)
74 VOID
75 FatQueryNameInfo (
76  IN PIRP_CONTEXT IrpContext,
77  IN PFCB Fcb,
78  IN PCCB Ccb,
79  IN BOOLEAN Normalized,
82  );
83 
84 VOID
86  IN PIRP_CONTEXT IrpContext,
87  IN PFCB Fcb,
90  );
91 
92 _Requires_lock_held_(_Global_critical_region_)
93 VOID
94 FatQueryNetworkInfo (
95  IN PIRP_CONTEXT IrpContext,
96  IN PFCB Fcb,
100  );
101 
102 _Requires_lock_held_(_Global_critical_region_)
103 NTSTATUS
104 FatSetBasicInfo (
105  IN PIRP_CONTEXT IrpContext,
106  IN PIRP Irp,
107  IN PFCB Fcb,
108  IN PCCB Ccb
109  );
110 
111 _Requires_lock_held_(_Global_critical_region_)
112 NTSTATUS
113 FatSetDispositionInfo (
114  IN PIRP_CONTEXT IrpContext,
115  IN PIRP Irp,
117  IN PFCB Fcb
118  );
119 
120 NTSTATUS
122  IN PIRP_CONTEXT IrpContext,
123  IN PIRP Irp,
124  IN PVCB Vcb,
125  IN PFCB Fcb,
126  IN PCCB Ccb
127  );
128 
129 NTSTATUS
131  IN PIRP_CONTEXT IrpContext,
132  IN PIRP Irp,
134  );
135 
136 _Requires_lock_held_(_Global_critical_region_)
137 NTSTATUS
138 FatSetAllocationInfo (
139  IN PIRP_CONTEXT IrpContext,
140  IN PIRP Irp,
141  IN PFCB Fcb,
143  );
144 
145 _Requires_lock_held_(_Global_critical_region_)
146 NTSTATUS
147 FatSetEndOfFileInfo (
148  IN PIRP_CONTEXT IrpContext,
149  IN PIRP Irp,
151  IN PVCB Vcb,
152  IN PFCB Fcb
153  );
154 
155 _Requires_lock_held_(_Global_critical_region_)
156 NTSTATUS
157 FatSetValidDataLengthInfo (
158  IN PIRP_CONTEXT IrpContext,
159  IN PIRP Irp,
161  IN PFCB Fcb,
162  IN PCCB Ccb
163  );
164 
165 _Requires_lock_held_(_Global_critical_region_)
166 VOID
167 FatRenameEAs (
168  IN PIRP_CONTEXT IrpContext,
169  IN PFCB Fcb,
170  IN USHORT ExtendedAttributes,
171  IN POEM_STRING OldOemName
172  );
173 
174 #ifdef ALLOC_PRAGMA
175 #pragma alloc_text(PAGE, FatCommonQueryInformation)
176 #pragma alloc_text(PAGE, FatCommonSetInformation)
177 #pragma alloc_text(PAGE, FatFsdQueryInformation)
178 #pragma alloc_text(PAGE, FatFsdSetInformation)
179 #pragma alloc_text(PAGE, FatQueryBasicInfo)
180 #pragma alloc_text(PAGE, FatQueryEaInfo)
181 #pragma alloc_text(PAGE, FatQueryInternalInfo)
182 #pragma alloc_text(PAGE, FatQueryNameInfo)
183 #pragma alloc_text(PAGE, FatQueryNetworkInfo)
184 #pragma alloc_text(PAGE, FatQueryShortNameInfo)
185 #pragma alloc_text(PAGE, FatQueryPositionInfo)
186 #pragma alloc_text(PAGE, FatQueryStandardInfo)
187 #pragma alloc_text(PAGE, FatSetAllocationInfo)
188 #pragma alloc_text(PAGE, FatSetBasicInfo)
189 #pragma alloc_text(PAGE, FatSetDispositionInfo)
190 #pragma alloc_text(PAGE, FatSetEndOfFileInfo)
191 #pragma alloc_text(PAGE, FatSetValidDataLengthInfo)
192 #pragma alloc_text(PAGE, FatSetPositionInfo)
193 #pragma alloc_text(PAGE, FatSetRenameInfo)
194 #pragma alloc_text(PAGE, FatDeleteFile)
195 #pragma alloc_text(PAGE, FatRenameEAs)
196 #endif
197 
198 
201 NTSTATUS
202 NTAPI
203 FatFsdQueryInformation (
204  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
206  )
207 
208 /*++
209 
210 Routine Description:
211 
212  This routine implements the Fsd part of the NtQueryInformationFile API
213  call.
214 
215 Arguments:
216 
217  VolumeDeviceObject - Supplies the volume device object where the file
218  being queried exists.
219 
220  Irp - Supplies the Irp being processed.
221 
222 Return Value:
223 
224  NTSTATUS - The FSD status for the Irp.
225 
226 --*/
227 
228 {
230  PIRP_CONTEXT IrpContext = NULL;
231 
233 
234  PAGED_CODE();
235 
236  DebugTrace(+1, Dbg, "FatFsdQueryInformation\n", 0);
237 
238  //
239  // Call the common query routine, with blocking allowed if synchronous
240  //
241 
243 
245 
246  _SEH2_TRY {
247 
248  IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
249 
250  Status = FatCommonQueryInformation( IrpContext, Irp );
251 
253 
254  //
255  // We had some trouble trying to perform the requested
256  // operation, so we'll abort the I/O request with
257  // the error status that we get back from the
258  // execption code
259  //
260 
261  Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
262  } _SEH2_END;
263 
264  if (TopLevel) { IoSetTopLevelIrp( NULL ); }
265 
267 
268  //
269  // And return to our caller
270  //
271 
272  DebugTrace(-1, Dbg, "FatFsdQueryInformation -> %08lx\n", Status);
273 
274  UNREFERENCED_PARAMETER( VolumeDeviceObject );
275 
276  return Status;
277 }
278 
279 
282 NTSTATUS
283 NTAPI
284 FatFsdSetInformation (
285  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
287  )
288 
289 /*++
290 
291 Routine Description:
292 
293  This routine implements the FSD part of the NtSetInformationFile API
294  call.
295 
296 Arguments:
297 
298  VolumeDeviceObject - Supplies the volume device object where the file
299  being set exists.
300 
301  Irp - Supplies the Irp being processed.
302 
303 Return Value:
304 
305  NTSTATUS - The FSD status for the Irp.
306 
307 --*/
308 
309 {
311  PIRP_CONTEXT IrpContext = NULL;
312 
314 
315  PAGED_CODE();
316 
317  DebugTrace(+1, Dbg, "FatFsdSetInformation\n", 0);
318 
319  //
320  // Call the common set routine, with blocking allowed if synchronous
321  //
322 
324 
326 
327  _SEH2_TRY {
328 
329  IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
330 
331  Status = FatCommonSetInformation( IrpContext, Irp );
332 
334 
335  //
336  // We had some trouble trying to perform the requested
337  // operation, so we'll abort the I/O request with
338  // the error status that we get back from the
339  // execption code
340  //
341 
342  Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
343  } _SEH2_END;
344 
345  if (TopLevel) { IoSetTopLevelIrp( NULL ); }
346 
348 
349  //
350  // And return to our caller
351  //
352 
353  DebugTrace(-1, Dbg, "FatFsdSetInformation -> %08lx\n", Status);
354 
355  UNREFERENCED_PARAMETER( VolumeDeviceObject );
356 
357  return Status;
358 }
359 
360 
361 _Requires_lock_held_(_Global_critical_region_)
362 NTSTATUS
363 FatCommonQueryInformation (
364  IN PIRP_CONTEXT IrpContext,
365  IN PIRP Irp
366  )
367 
368 /*++
369 
370 Routine Description:
371 
372  This is the common routine for querying file information called by both
373  the fsd and fsp threads.
374 
375 Arguments:
376 
377  Irp - Supplies the Irp being processed
378 
379 Return Value:
380 
381  NTSTATUS - The return status for the operation
382 
383 --*/
384 
385 {
387 
389 
391 
392  LONG Length;
394  PVOID Buffer;
395 
397  PVCB Vcb;
398  PFCB Fcb;
399  PCCB Ccb;
400 
401  BOOLEAN FcbAcquired = FALSE;
402  BOOLEAN VcbAcquired = FALSE;
403 
404  PFILE_ALL_INFORMATION AllInfo;
405 
406  PAGED_CODE();
407 
408  //
409  // Get the current stack location
410  //
411 
413 
415 
416  DebugTrace(+1, Dbg, "FatCommonQueryInformation...\n", 0);
417  DebugTrace( 0, Dbg, "Irp = %p\n", Irp);
418  DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.QueryFile.Length);
419  DebugTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryFile.FileInformationClass);
420  DebugTrace( 0, Dbg, "->Buffer = %p\n", Irp->AssociatedIrp.SystemBuffer);
421 
422  //
423  // Reference our input parameters to make things easier
424  //
425 
426  Length = (LONG)IrpSp->Parameters.QueryFile.Length;
427  FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
428  Buffer = Irp->AssociatedIrp.SystemBuffer;
429 
430  //
431  // Decode the file object
432  //
433 
435 
437 
438  _SEH2_TRY {
439 
440  //
441  // Case on the type of open we're dealing with
442  //
443 
444  switch (TypeOfOpen) {
445 
446  case UserVolumeOpen:
447 
448  //
449  // We cannot query the user volume open.
450  //
451 
453  break;
454 
455  case UserFileOpen:
456  case UserDirectoryOpen:
457  case DirectoryFile:
458 
459 
460  //
461  // NameInfo requires synchronization with deletion in order to perform
462  // the full filename query. A lighter-weight way to do this would be per
463  // directory as the full name is built up and since the multiple Fcb
464  // lockorder is bottom up, this is conceivable. At this time, though,
465  // this change is safer.
466  //
467 
469 #if (NTDDI_VERSION >= NTDDI_VISTA)
471 #endif
473 
474  if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
475 
476  DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
477 
478  Status = FatFsdPostRequest( IrpContext, Irp );
479  IrpContext = NULL;
480  Irp = NULL;
481 
482  try_return( Status );
483  }
484 
485  VcbAcquired = TRUE;
486  }
487 
488  //
489  // Acquire shared access to the fcb, except for a paging file
490  // in order to avoid deadlocks with Mm.
491  //
492  // The "removable" check was added specifically for ReadyBoost,
493  // which opens its cache file on a removable device as a paging file and
494  // relies on the file system to validate its mapping information after a
495  // power transition.
496  //
497 
500 
501  if (!FatAcquireSharedFcb( IrpContext, Fcb )) {
502 
503  DebugTrace(0, Dbg, "Cannot acquire Fcb\n", 0);
504 
505  Status = FatFsdPostRequest( IrpContext, Irp );
506  IrpContext = NULL;
507  Irp = NULL;
508 
509  try_return( Status );
510  }
511 
512  FcbAcquired = TRUE;
513  }
514 
515  //
516  // Make sure the Fcb is in a usable condition. This
517  // will raise an error condition if the fcb is unusable
518  //
519 
520  FatVerifyFcb( IrpContext, Fcb );
521 
522  //
523  // Based on the information class we'll do different
524  // actions. Each of hte procedures that we're calling fills
525  // up the output buffer, if possible. They will raise the
526  // status STATUS_BUFFER_OVERFLOW for an insufficient buffer.
527  // This is considered a somewhat unusual case and is handled
528  // more cleanly with the exception mechanism rather than
529  // testing a return status value for each call.
530  //
531 
532  switch (FileInformationClass) {
533 
534  case FileAllInformation:
535 
536  //
537  // For the all information class we'll typecast a local
538  // pointer to the output buffer and then call the
539  // individual routines to fill in the buffer.
540  //
541 
542  AllInfo = Buffer;
543  Length -= (sizeof(FILE_ACCESS_INFORMATION)
544  + sizeof(FILE_MODE_INFORMATION)
545  + sizeof(FILE_ALIGNMENT_INFORMATION));
546 
547  FatQueryBasicInfo( IrpContext, Fcb, FileObject, &AllInfo->BasicInformation, &Length );
548  FatQueryStandardInfo( IrpContext, Fcb, &AllInfo->StandardInformation, &Length );
549  FatQueryInternalInfo( IrpContext, Fcb, &AllInfo->InternalInformation, &Length );
550  FatQueryEaInfo( IrpContext, Fcb, &AllInfo->EaInformation, &Length );
551  FatQueryPositionInfo( IrpContext, FileObject, &AllInfo->PositionInformation, &Length );
552  FatQueryNameInfo( IrpContext, Fcb, Ccb, FALSE, &AllInfo->NameInformation, &Length );
553 
554  break;
555 
557 
558  FatQueryBasicInfo( IrpContext, Fcb, FileObject, Buffer, &Length );
559  break;
560 
562 
563  FatQueryStandardInfo( IrpContext, Fcb, Buffer, &Length );
564  break;
565 
567 
568  FatQueryInternalInfo( IrpContext, Fcb, Buffer, &Length );
569  break;
570 
571  case FileEaInformation:
572 
573  FatQueryEaInfo( IrpContext, Fcb, Buffer, &Length );
574  break;
575 
577 
578  FatQueryPositionInfo( IrpContext, FileObject, Buffer, &Length );
579  break;
580 
581  case FileNameInformation:
582 
583  FatQueryNameInfo( IrpContext, Fcb, Ccb, FALSE, Buffer, &Length );
584  break;
585 
586 #if (NTDDI_VERSION >= NTDDI_VISTA)
588 
589  FatQueryNameInfo( IrpContext, Fcb, Ccb, TRUE, Buffer, &Length );
590  break;
591 #endif
592 
594 
595  FatQueryShortNameInfo( IrpContext, Fcb, Buffer, &Length );
596  break;
597 
599 
600  FatQueryNetworkInfo( IrpContext, Fcb, FileObject, Buffer, &Length );
601  break;
602 
603  default:
604 
606  break;
607  }
608 
609  break;
610 
611  default:
612 
615  "FATQueryFile, Illegal TypeOfOpen = %08lx\n",
616  TypeOfOpen));
617 
619  break;
620  }
621 
622  //
623  // If we overflowed the buffer, set the length to 0 and change the
624  // status to STATUS_BUFFER_OVERFLOW.
625  //
626 
627  if ( Length < 0 ) {
628 
630 
631  Length = 0;
632  }
633 
634  //
635  // Set the information field to the number of bytes actually filled in
636  // and then complete the request
637  //
638 
639  Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
640 
641  try_exit: NOTHING;
642  } _SEH2_FINALLY {
643 
644  DebugUnwind( FatCommonQueryInformation );
645 
646  if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
647  if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }
648 
649  if (!_SEH2_AbnormalTermination()) {
650 
651  FatCompleteRequest( IrpContext, Irp, Status );
652  }
653 
654  DebugTrace(-1, Dbg, "FatCommonQueryInformation -> %08lx\n", Status);
655  } _SEH2_END;
656 
657  return Status;
658 }
659 
660 
661 _Requires_lock_held_(_Global_critical_region_)
662 NTSTATUS
663 FatCommonSetInformation (
664  IN PIRP_CONTEXT IrpContext,
665  IN PIRP Irp
666  )
667 
668 /*++
669 
670 Routine Description:
671 
672  This is the common routine for setting file information called by both
673  the fsd and fsp threads.
674 
675 Arguments:
676 
677  Irp - Supplies the Irp being processed
678 
679 Return Value:
680 
681  NTSTATUS - The return status for the operation
682 
683 --*/
684 
685 {
687 
689 
692 
694  PVCB Vcb;
695  PFCB Fcb;
696  PCCB Ccb;
697 
698  BOOLEAN VcbAcquired = FALSE;
699  BOOLEAN FcbAcquired = FALSE;
700 
701  PAGED_CODE();
702 
703  //
704  // Get the current stack location
705  //
706 
708 
709  DebugTrace(+1, Dbg, "FatCommonSetInformation...\n", 0);
710  DebugTrace( 0, Dbg, "Irp = %p\n", Irp);
711  DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.SetFile.Length);
712  DebugTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.SetFile.FileInformationClass);
713  DebugTrace( 0, Dbg, "->FileObject = %p\n", IrpSp->Parameters.SetFile.FileObject);
714  DebugTrace( 0, Dbg, "->ReplaceIfExists = %08lx\n", IrpSp->Parameters.SetFile.ReplaceIfExists);
715  DebugTrace( 0, Dbg, "->Buffer = %p\n", Irp->AssociatedIrp.SystemBuffer);
716 
717  //
718  // Reference our input parameters to make things easier
719  //
720 
721  FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
723 
724  //
725  // Decode the file object
726  //
727 
729 
730  _SEH2_TRY {
731 
732  //
733  // Case on the type of open we're dealing with
734  //
735 
736  switch (TypeOfOpen) {
737 
738  case UserVolumeOpen:
739 
740  //
741  // We cannot query the user volume open.
742  //
743 
745  break;
746 
747  case UserFileOpen:
748 
753 
754  //
755  // We check whether we can proceed
756  // based on the state of the file oplocks.
757  //
758 
760  Irp,
761  IrpContext,
762  NULL,
763  NULL );
764 
765  if (Status != STATUS_SUCCESS) {
766 
767  try_return( Status );
768  }
769 
770  //
771  // Set the flag indicating if Fast I/O is possible
772  //
773 
774  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
775  }
776  break;
777 
778  case UserDirectoryOpen:
779 
780  break;
781 
782  default:
783 
785  }
786 
787  //
788  // We can only do a set on a nonroot dcb, so we do the test
789  // and then fall through to the user file open code.
790  //
791 
792  if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
793 
795 
797  }
798 
800  }
801 
802  //
803  // In the following two cases, we cannot have creates occuring
804  // while we are here, so acquire the volume exclusive.
805  //
806 
809 
810  if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
811 
812  DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
813 
814  Status = FatFsdPostRequest( IrpContext, Irp );
815  Irp = NULL;
816  IrpContext = NULL;
817 
818  try_return( Status );
819  }
820 
821  VcbAcquired = TRUE;
822 
823  //
824  // Make sure we haven't been called recursively by a filter inside an existing
825  // create request.
826  //
827 
828  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS)) {
829 
830 #ifdef _MSC_VER
831 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
832 #endif
833  FatBugCheck( 0, 0, 0);
834  }
835  }
836 
837  //
838  // Acquire exclusive access to the Fcb, We use exclusive
839  // because it is probable that one of the subroutines
840  // that we call will need to monkey with file allocation,
841  // create/delete extra fcbs. So we're willing to pay the
842  // cost of exclusive Fcb access.
843  //
844  // Note that we do not acquire the resource for paging file
845  // operations in order to avoid deadlock with Mm.
846  //
847  // The "removable" check was added specifically for ReadyBoost,
848  // which opens its cache file on a removable device as a paging file and
849  // relies on the file system to validate its mapping information after a
850  // power transition.
851  //
852 
855 
856  if (!FatAcquireExclusiveFcb( IrpContext, Fcb )) {
857 
858  DebugTrace(0, Dbg, "Cannot acquire Fcb\n", 0);
859 
860  Status = FatFsdPostRequest( IrpContext, Irp );
861  Irp = NULL;
862  IrpContext = NULL;
863 
864  try_return( Status );
865  }
866 
867  FcbAcquired = TRUE;
868  }
869 
871 
872  //
873  // Make sure the Fcb is in a usable condition. This
874  // will raise an error condition if the fcb is unusable
875  //
876 
877  FatVerifyFcb( IrpContext, Fcb );
878 
879  //
880  // Now that we've acquired the file, do an oplock check if the operation
881  // so warrants.
882  //
883 
884  if (FatIsFileOplockable( Fcb )&&
887  ((PFILE_DISPOSITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer)->DeleteFile))) {
888 
890  Irp,
891  IrpContext,
893  NULL );
894 
895  //
896  // Set the flag indicating if Fast I/O is possible
897  //
898 
899  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
900 
901  //
902  // If STATUS_PENDING is returned it means the oplock
903  // package has the Irp. Don't complete the request here.
904  //
905 
906  if (Status == STATUS_PENDING) {
907 
908  Irp = NULL;
909  IrpContext = NULL;
910  }
911 
912  if (!NT_SUCCESS( Status ) ||
913  (Status == STATUS_PENDING)) {
914 
915  try_return( Status );
916  }
917  }
918 
919  //
920  // Based on the information class we'll do different
921  // actions. Each of the procedures that we're calling will either
922  // complete the request of send the request off to the fsp
923  // to do the work.
924  //
925 
926  switch (FileInformationClass) {
927 
929 
930  Status = FatSetBasicInfo( IrpContext, Irp, Fcb, Ccb );
931  break;
932 
934 
935  //
936  // If this is on deferred flush media, we have to be able to wait.
937  //
938 
939  if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
940  !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {
941 
942  Status = FatFsdPostRequest( IrpContext, Irp );
943  Irp = NULL;
944  IrpContext = NULL;
945 
946  } else {
947 
948  Status = FatSetDispositionInfo( IrpContext, Irp, FileObject, Fcb );
949  }
950 
951  break;
952 
954 
955  //
956  // We proceed with this operation only if we can wait
957  //
958 
959  if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
960 
961  Status = FatFsdPostRequest( IrpContext, Irp );
962  Irp = NULL;
963  IrpContext = NULL;
964 
965  } else {
966 
967  Status = FatSetRenameInfo( IrpContext, Irp, Vcb, Fcb, Ccb );
968 
969  //
970  // If STATUS_PENDING is returned it means the oplock
971  // package has the Irp. Don't complete the request here.
972  //
973 
974  if (Status == STATUS_PENDING) {
975  Irp = NULL;
976  IrpContext = NULL;
977  }
978  }
979 
980  break;
981 
983 
984  Status = FatSetPositionInfo( IrpContext, Irp, FileObject );
985  break;
986 
987  case FileLinkInformation:
988 
990  break;
991 
993 
994  Status = FatSetAllocationInfo( IrpContext, Irp, Fcb, FileObject );
995  break;
996 
998 
999  Status = FatSetEndOfFileInfo( IrpContext, Irp, FileObject, Vcb, Fcb );
1000  break;
1001 
1003 
1004  Status = FatSetValidDataLengthInfo( IrpContext, Irp, FileObject, Fcb, Ccb );
1005  break;
1006 
1007  default:
1008 
1010  break;
1011  }
1012 
1013  if ( IrpContext != NULL ) {
1014 
1015  FatUnpinRepinnedBcbs( IrpContext );
1016  }
1017 
1018  try_exit: NOTHING;
1019  } _SEH2_FINALLY {
1020 
1021  DebugUnwind( FatCommonSetInformation );
1022 
1023  if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
1024 
1025  if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }
1026 
1027  if (!_SEH2_AbnormalTermination()) {
1028 
1029  FatCompleteRequest( IrpContext, Irp, Status );
1030  }
1031 
1032  DebugTrace(-1, Dbg, "FatCommonSetInformation -> %08lx\n", Status);
1033  } _SEH2_END;
1034 
1035  return Status;
1036 }
1037 
1038 
1039 //
1040 // Internal Support Routine
1041 //
1042 
1043 VOID
1045  IN PIRP_CONTEXT IrpContext,
1046  IN PFCB Fcb,
1049  IN OUT PLONG Length
1050  )
1051 
1052 /*++
1053  Description:
1054 
1055  This routine performs the query basic information function for fat.
1056 
1057 Arguments:
1058 
1059  Fcb - Supplies the Fcb being queried, it has been verified
1060 
1061  FileObject - Supplies the flag bit that indicates the file was modified.
1062 
1063  Buffer - Supplies a pointer to the buffer where the information is to
1064  be returned
1065 
1066  Length - Supplies the length of the buffer in bytes, and receives the
1067  remaining bytes free in the buffer upon return.
1068 
1069 Return Value:
1070 
1071  None
1072 
1073 --*/
1074 
1075 {
1076  PAGED_CODE();
1077 
1079  UNREFERENCED_PARAMETER( IrpContext );
1080 
1081  DebugTrace(+1, Dbg, "FatQueryBasicInfo...\n", 0);
1082 
1083  //
1084  // Zero out the output buffer, and set it to indicate that
1085  // the query is a normal file. Later we might overwrite the
1086  // attribute.
1087  //
1088 
1090 
1091  //
1092  // Extract the data and fill in the non zero fields of the output
1093  // buffer
1094  //
1095 
1096  if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
1097 
1098  //
1099  // We have to munge a lie on the fly. Every time we have to
1100  // use 1/1/80 we need to convert to GMT since the TZ may have
1101  // changed on us.
1102  //
1103 
1105  &Buffer->LastWriteTime );
1106  Buffer->CreationTime = Buffer->LastAccessTime = Buffer->LastWriteTime;
1107 
1108  } else {
1109 
1110  Buffer->LastWriteTime = Fcb->LastWriteTime;
1111  Buffer->CreationTime = Fcb->CreationTime;
1112  Buffer->LastAccessTime = Fcb->LastAccessTime;
1113  }
1114 
1115  Buffer->FileAttributes = Fcb->DirentFatFlags;
1116 
1117 
1118  //
1119  // If the temporary flag is set, then set it in the buffer.
1120  //
1121 
1123 
1124  SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
1125  }
1126 
1127  //
1128  // If no attributes were set, set the normal bit.
1129  //
1130 
1131  if (Buffer->FileAttributes == 0) {
1132 
1133  Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
1134  }
1135 
1136  //
1137  // Update the length and status output variables
1138  //
1139 
1140  *Length -= sizeof( FILE_BASIC_INFORMATION );
1141 
1142  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1143 
1144  DebugTrace(-1, Dbg, "FatQueryBasicInfo -> VOID\n", 0);
1145 
1146  return;
1147 }
1148 
1149 
1150 //
1151 // Internal Support Routine
1152 //
1153 
1154 _Requires_lock_held_(_Global_critical_region_)
1155 VOID
1156 FatQueryStandardInfo (
1157  IN PIRP_CONTEXT IrpContext,
1158  IN PFCB Fcb,
1160  IN OUT PLONG Length
1161  )
1162 
1163 /*++
1164 
1165 Routine Description:
1166 
1167  This routine performs the query standard information function for fat.
1168 
1169 Arguments:
1170 
1171  Fcb - Supplies the Fcb being queried, it has been verified
1172 
1173  Buffer - Supplies a pointer to the buffer where the information is to
1174  be returned
1175 
1176  Length - Supplies the length of the buffer in bytes, and receives the
1177  remaining bytes free in the buffer upon return.
1178 
1179 Return Value:
1180 
1181  None
1182 
1183 --*/
1184 
1185 {
1186  PAGED_CODE();
1187 
1188  DebugTrace(+1, Dbg, "FatQueryStandardInfo...\n", 0);
1189 
1190  //
1191  // Zero out the output buffer, and fill in the number of links
1192  // and the delete pending flag.
1193  //
1194 
1196 
1197  Buffer->NumberOfLinks = 1;
1199 
1200  //
1201  // Case on whether this is a file or a directory, and extract
1202  // the information and fill in the fcb/dcb specific parts
1203  // of the output buffer
1204  //
1205 
1206  if (NodeType(Fcb) == FAT_NTC_FCB) {
1207 
1208  if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1209 
1210  FatLookupFileAllocationSize( IrpContext, Fcb );
1211  }
1212 
1213  Buffer->AllocationSize = Fcb->Header.AllocationSize;
1214  Buffer->EndOfFile = Fcb->Header.FileSize;
1215 
1216  Buffer->Directory = FALSE;
1217 
1218  } else {
1219 
1220  Buffer->Directory = TRUE;
1221  }
1222 
1223  //
1224  // Update the length and status output variables
1225  //
1226 
1227  *Length -= sizeof( FILE_STANDARD_INFORMATION );
1228 
1229  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1230 
1231  DebugTrace(-1, Dbg, "FatQueryStandardInfo -> VOID\n", 0);
1232 
1233  return;
1234 }
1235 
1236 
1237 //
1238 // Internal Support Routine
1239 //
1240 
1241 VOID
1243  IN PIRP_CONTEXT IrpContext,
1244  IN PFCB Fcb,
1246  IN OUT PLONG Length
1247  )
1248 
1249 /*++
1250 
1251 Routine Description:
1252 
1253  This routine performs the query internal information function for fat.
1254 
1255 Arguments:
1256 
1257  Fcb - Supplies the Fcb being queried, it has been verified
1258 
1259  Buffer - Supplies a pointer to the buffer where the information is to
1260  be returned
1261 
1262  Length - Supplies the length of the buffer in bytes, and receives the
1263  remaining bytes free in the buffer upon return.
1264 
1265 Return Value:
1266 
1267  None
1268 
1269 --*/
1270 
1271 {
1272  PAGED_CODE();
1273 
1274  UNREFERENCED_PARAMETER( IrpContext );
1275 
1276  DebugTrace(+1, Dbg, "FatQueryInternalInfo...\n", 0);
1277 
1278  _SEH2_TRY {
1279 
1280  Buffer->IndexNumber.QuadPart = FatGenerateFileIdFromFcb( Fcb );
1281 
1282  //
1283  // Update the length and status output variables
1284  //
1285 
1286  *Length -= sizeof( FILE_INTERNAL_INFORMATION );
1287 
1288  } _SEH2_FINALLY {
1289 
1291 
1292  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1293 
1294  DebugTrace(-1, Dbg, "FatQueryInternalInfo -> VOID\n", 0);
1295  } _SEH2_END;
1296 
1297  return;
1298 }
1299 
1300 
1301 //
1302 // Internal Support Routine
1303 //
1304 
1305 VOID
1307  IN PIRP_CONTEXT IrpContext,
1308  IN PFCB Fcb,
1310  IN OUT PLONG Length
1311  )
1312 
1313 /*++
1314 
1315 Routine Description:
1316 
1317  This routine performs the query Ea information function for fat.
1318 
1319 Arguments:
1320 
1321  Fcb - Supplies the Fcb being queried, it has been verified
1322 
1323  Buffer - Supplies a pointer to the buffer where the information is to
1324  be returned
1325 
1326  Length - Supplies the length of the buffer in bytes, and receives the
1327  remaining bytes free in the buffer upon return.
1328 
1329 Return Value:
1330 
1331  None
1332 
1333 --*/
1334 
1335 {
1336  PBCB Bcb;
1337 
1338  PAGED_CODE();
1339 
1341  UNREFERENCED_PARAMETER( IrpContext );
1342 
1343  DebugTrace(+1, Dbg, "FatQueryEaInfo...\n", 0);
1344 
1345  Bcb = NULL;
1346 
1347  _SEH2_TRY {
1348 
1349  //
1350  // Zero out the output buffer
1351  //
1352 
1354 
1355 #if 0
1356  //
1357  // The Root dcb does not have any EAs so don't look for any. Fat32
1358  // doesn't have any, either.
1359  //
1360 
1361  if ( NodeType( Fcb ) != FAT_NTC_ROOT_DCB &&
1362  !FatIsFat32( Fcb->Vcb )) {
1363 
1364  PDIRENT Dirent;
1365 
1366  //
1367  // Try to get the dirent for this file.
1368  //
1369 
1370  FatGetDirentFromFcbOrDcb( IrpContext,
1371  Fcb,
1372  &Dirent,
1373  &Bcb );
1374 
1375  if (Dirent != NULL) {
1376 
1377  //
1378  // Get a the size needed to store the full eas for the file.
1379  //
1380 
1381  FatGetEaLength( IrpContext,
1382  Fcb->Vcb,
1383  Dirent,
1384  &Buffer->EaSize );
1385  }
1386  }
1387 #endif
1388 
1389  //
1390  // Update the length and status output variables
1391  //
1392 
1393  *Length -= sizeof( FILE_EA_INFORMATION );
1394 
1395  } _SEH2_FINALLY {
1396 
1398 
1399  //
1400  // Unpin the dirent if pinned.
1401  //
1402 
1403  FatUnpinBcb( IrpContext, Bcb );
1404 
1405  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1406 
1407  DebugTrace(-1, Dbg, "FatQueryEaInfo -> VOID\n", 0);
1408  } _SEH2_END;
1409 }
1410 
1411 
1412 //
1413 // Internal Support Routine
1414 //
1415 
1416 VOID
1418  IN PIRP_CONTEXT IrpContext,
1421  IN OUT PLONG Length
1422  )
1423 
1424 /*++
1425 
1426 Routine Description:
1427 
1428  This routine performs the query position information function for fat.
1429 
1430 Arguments:
1431 
1432  FileObject - Supplies the File object being queried
1433 
1434  Buffer - Supplies a pointer to the buffer where the information is to
1435  be returned
1436 
1437  Length - Supplies the length of the buffer in bytes, and receives the
1438  remaining bytes free in the buffer upon return.
1439 
1440 Return Value:
1441 
1442  None
1443 
1444 --*/
1445 
1446 {
1447  PAGED_CODE();
1448 
1449  DebugTrace(+1, Dbg, "FatQueryPositionInfo...\n", 0);
1450 
1451  //
1452  // Get the current position found in the file object.
1453  //
1454 
1455  Buffer->CurrentByteOffset = FileObject->CurrentByteOffset;
1456 
1457  //
1458  // Update the length and status output variables
1459  //
1460 
1461  *Length -= sizeof( FILE_POSITION_INFORMATION );
1462 
1463  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1464 
1465  DebugTrace(-1, Dbg, "FatQueryPositionInfo -> VOID\n", 0);
1466 
1467  UNREFERENCED_PARAMETER( IrpContext );
1468 
1469  return;
1470 }
1471 
1472 
1473 //
1474 // Internal Support Routine
1475 //
1476 
1477 _Requires_lock_held_(_Global_critical_region_)
1478 VOID
1479 FatQueryNameInfo (
1480  IN PIRP_CONTEXT IrpContext,
1481  IN PFCB Fcb,
1482  IN PCCB Ccb,
1483  IN BOOLEAN Normalized,
1485  IN OUT PLONG Length
1486  )
1487 
1488 /*++
1489 
1490 Routine Description:
1491 
1492  This routine performs the query name information function for fat.
1493 
1494 Arguments:
1495 
1496  Fcb - Supplies the Fcb being queried, it has been verified
1497 
1498  Ccb - Supplies the Ccb for the context of the user open
1499 
1500  Normalized - if true the caller wants a normalized name (w/out short names).
1501  This means we're servicing a FileNormalizedNameInformation query.
1502 
1503  Buffer - Supplies a pointer to the buffer where the information is to
1504  be returned
1505 
1506  Length - Supplies the length of the buffer in bytes, and receives the
1507  remaining bytes free in the buffer upon return.
1508 
1509 Return Value:
1510 
1511  None
1512 
1513 --*/
1514 
1515 {
1517  LONG TrimLength;
1518  BOOLEAN Overflow = FALSE;
1519 
1520  PAGED_CODE();
1521 
1522  DebugTrace(+1, Dbg, "FatQueryNameInfo...\n", 0);
1523 
1524  //
1525  // Convert the name to UNICODE
1526  //
1527 
1529 
1530  //
1531  // Use the full filename to build the path up. If we wanted to be
1532  // slick in the future, we'd just build the path directly into the
1533  // return buffer and avoid constructing the full filename, but since
1534  // the full filename winds up being required so often lets not
1535  // over optimize this case yet.
1536  //
1537 
1538  if (Fcb->FullFileName.Buffer == NULL) {
1539 
1540  FatSetFullFileNameInFcb( IrpContext, Fcb );
1541  }
1542 
1543  //
1544  // Here is where it gets a smidge tricky. FinalNameLength is the length
1545  // of the LFN element if it exists, and since the long name is always used
1546  // to build FullFileName, we have two cases:
1547  //
1548  // 1) short name: use FinalNameLength to tear off the path from FullFileName
1549  // and append the UNICODE converted short name.
1550  // 2) long name: just use FullFileName
1551  //
1552  // We bias to the name the user thinks they opened by. This winds
1553  // up fixing some oddball tunneling cases where intermediate filters
1554  // translate operations like delete into renames - this lets them
1555  // do the operation in the context of the name the user was using.
1556  //
1557  // It also matches what NTFS does, and so we have the definition of
1558  // correct behavior.
1559  //
1560 
1561  //
1562  //
1563  // Assume there is no long name and we are just going to use
1564  // FullFileName.
1565  //
1566 
1567  TrimLength = 0;
1568 
1569  //
1570  // If a LongName exists, the caller isn't asking for the normalized name,
1571  // and the original open was by the short name then set TrimLength to point
1572  // to the place where the short name goes.
1573  //
1574  // Note: The Ccb can be NULL. The lazy writer calls to get the name of
1575  // a DirectoryOpen FILE_OBJECT that it wants to display in the lost
1576  // delayed write popup. Handle this case by just using the FileFullName.
1577  //
1578 
1579  if (!Normalized &&
1581 
1582  if ((Ccb != NULL) &&
1584 
1585  TrimLength = Fcb->FinalNameLength;
1586  }
1587  }
1588 
1589  if (*Length < Fcb->FullFileName.Length - TrimLength) {
1590 
1591  BytesToCopy = *Length;
1592  Overflow = TRUE;
1593 
1594  } else {
1595 
1596  BytesToCopy = Fcb->FullFileName.Length - TrimLength;
1597  *Length -= BytesToCopy;
1598  }
1599 
1600  RtlCopyMemory( &Buffer->FileName[0],
1602  BytesToCopy );
1603 
1604  //
1605  // Note that this is just the amount of name we've copied so far. It'll
1606  // either be all of it (long) or the path element including the \ (short).
1607  //
1608 
1609  Buffer->FileNameLength = Fcb->FullFileName.Length - TrimLength;
1610 
1611  //
1612  // If we trimmed off the name element, this is the short name case. Pick
1613  // up the UNICODE conversion and append it.
1614  //
1615 
1616  if (TrimLength != 0) {
1617 
1619  WCHAR ShortNameBuffer[12];
1620  NTSTATUS Status;
1621 
1622  //
1623  // Convert the short name to UNICODE and figure out how much
1624  // of it can fit. Again, we always bump the returned length
1625  // to indicate how much is available even if we can't return it.
1626  //
1627 
1628  ShortName.Length = 0;
1629  ShortName.MaximumLength = sizeof(ShortNameBuffer);
1630  ShortName.Buffer = ShortNameBuffer;
1631 
1632 #ifdef _MSC_VER
1633 #pragma prefast( suppress:28931, "needed for debug build" )
1634 #endif
1636  &Fcb->ShortName.Name.Oem,
1637  FALSE );
1638 
1640 
1641  if (!Overflow) {
1642 
1643  if (*Length < ShortName.Length) {
1644 
1645  BytesToCopy = *Length;
1646  Overflow = TRUE;
1647 
1648  } else {
1649 
1650  BytesToCopy = ShortName.Length;
1651  *Length -= BytesToCopy;
1652  }
1653 
1654  RtlCopyMemory( (PUCHAR)&Buffer->FileName[0] + Buffer->FileNameLength,
1655  ShortName.Buffer,
1656  BytesToCopy );
1657  }
1658 
1659  Buffer->FileNameLength += ShortName.Length;
1660  }
1661 
1662  if (Overflow) {
1663 
1664  *Length = -1;
1665  }
1666 
1667  //
1668  // Return to caller
1669  //
1670 
1671  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1672 
1673  DebugTrace(-1, Dbg, "FatQueryNameInfo -> VOID\n", 0);
1674 
1675  UNREFERENCED_PARAMETER( IrpContext );
1676 
1677  return;
1678 }
1679 
1680 
1681 //
1682 // Internal Support Routine
1683 //
1684 
1685 VOID
1687  IN PIRP_CONTEXT IrpContext,
1688  IN PFCB Fcb,
1690  IN OUT PLONG Length
1691  )
1692 
1693 /*++
1694 
1695 Routine Description:
1696 
1697  This routine queries the short name of the file.
1698 
1699 Arguments:
1700 
1701  Fcb - Supplies the Fcb being queried, it has been verified
1702 
1703  Buffer - Supplies a pointer to the buffer where the information is to
1704  be returned
1705 
1706  Length - Supplies the length of the buffer in bytes, and receives the
1707  remaining bytes free in the buffer upon return.
1708 
1709 Return Value:
1710 
1711  None
1712 
1713 --*/
1714 
1715 {
1716  NTSTATUS Status;
1717 
1719  WCHAR ShortNameBuffer[12];
1721 
1722  PAGED_CODE();
1723 
1724  DebugTrace(+1, Dbg, "FatQueryNameInfo...\n", 0);
1725 
1726  //
1727  // Convert the name to UNICODE
1728  //
1729 
1730  ShortName.Length = 0;
1731  ShortName.MaximumLength = sizeof(ShortNameBuffer);
1732  ShortName.Buffer = ShortNameBuffer;
1733 
1735 
1736 #ifdef _MSC_VER
1737 #pragma prefast( suppress:28931, "needed for debug build" )
1738 #endif
1740  &Fcb->ShortName.Name.Oem,
1741  FALSE );
1742 
1744 
1745  //
1746  // If we overflow, set *Length to -1 as a flag.
1747  //
1748 
1749  if (*Length < ShortName.Length) {
1750 
1751  BytesToCopy = *Length;
1752  *Length = -1;
1753 
1754  } else {
1755 
1756  BytesToCopy = ShortName.Length;
1757  *Length -= ShortName.Length;
1758  }
1759 
1760  RtlCopyMemory( &Buffer->FileName[0],
1761  &ShortName.Buffer[0],
1762  BytesToCopy );
1763 
1764  Buffer->FileNameLength = ShortName.Length;
1765 
1766  //
1767  // Return to caller
1768  //
1769 
1770  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1771 
1772  DebugTrace(-1, Dbg, "FatQueryNameInfo -> VOID\n", 0);
1773 
1774  UNREFERENCED_PARAMETER( IrpContext );
1775 
1776  return;
1777 }
1778 
1779 
1780 //
1781 // Internal Support Routine
1782 //
1783 
1784 _Requires_lock_held_(_Global_critical_region_)
1785 VOID
1786 FatQueryNetworkInfo (
1787  IN PIRP_CONTEXT IrpContext,
1788  IN PFCB Fcb,
1791  IN OUT PLONG Length
1792  )
1793 
1794 /*++
1795  Description:
1796 
1797  This routine performs the query network open information function for fat.
1798 
1799 Arguments:
1800 
1801  Fcb - Supplies the Fcb being queried, it has been verified
1802 
1803  FileObject - Supplies the flag bit that indicates the file was modified.
1804 
1805  Buffer - Supplies a pointer to the buffer where the information is to
1806  be returned
1807 
1808  Length - Supplies the length of the buffer in bytes, and receives the
1809  remaining bytes free in the buffer upon return.
1810 
1811 Return Value:
1812 
1813  None
1814 
1815 --*/
1816 
1817 {
1818  PAGED_CODE();
1819 
1821 
1822  DebugTrace(+1, Dbg, "FatQueryNetworkInfo...\n", 0);
1823 
1824  //
1825  // Zero out the output buffer, and set it to indicate that
1826  // the query is a normal file. Later we might overwrite the
1827  // attribute.
1828  //
1829 
1831 
1832  //
1833  // Extract the data and fill in the non zero fields of the output
1834  // buffer
1835  //
1836 
1837  if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
1838 
1839  //
1840  // We have to munge a lie on the fly. Every time we have to
1841  // use 1/1/80 we need to convert to GMT since the TZ may have
1842  // changed on us.
1843  //
1844 
1846  &Buffer->LastWriteTime );
1847  Buffer->CreationTime = Buffer->LastAccessTime = Buffer->LastWriteTime;
1848 
1849  } else {
1850 
1851  Buffer->LastWriteTime.QuadPart = Fcb->LastWriteTime.QuadPart;
1852  Buffer->CreationTime.QuadPart = Fcb->CreationTime.QuadPart;
1853  Buffer->LastAccessTime.QuadPart = Fcb->LastAccessTime.QuadPart;
1854  }
1855 
1856  Buffer->FileAttributes = Fcb->DirentFatFlags;
1857 
1858 
1859  //
1860  // If the temporary flag is set, then set it in the buffer.
1861  //
1862 
1864 
1865  SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
1866  }
1867 
1868  //
1869  // If no attributes were set, set the normal bit.
1870  //
1871 
1872  if (Buffer->FileAttributes == 0) {
1873 
1874  Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
1875  }
1876  //
1877  // Case on whether this is a file or a directory, and extract
1878  // the information and fill in the fcb/dcb specific parts
1879  // of the output buffer
1880  //
1881 
1882  if (NodeType(Fcb) == FAT_NTC_FCB) {
1883 
1884  if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
1885 
1886  FatLookupFileAllocationSize( IrpContext, Fcb );
1887  }
1888 
1889  Buffer->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
1890  Buffer->EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
1891  }
1892 
1893  //
1894  // Update the length and status output variables
1895  //
1896 
1897  *Length -= sizeof( FILE_NETWORK_OPEN_INFORMATION );
1898 
1899  DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
1900 
1901  DebugTrace(-1, Dbg, "FatQueryNetworkInfo -> VOID\n", 0);
1902 
1903  return;
1904 }
1905 
1906 
1907 //
1908 // Internal Support routine
1909 //
1910 
1911 _Requires_lock_held_(_Global_critical_region_)
1912 NTSTATUS
1913 FatSetBasicInfo (
1914  IN PIRP_CONTEXT IrpContext,
1915  IN PIRP Irp,
1916  IN PFCB Fcb,
1917  IN PCCB Ccb
1918  )
1919 
1920 /*++
1921 
1922 Routine Description:
1923 
1924  This routine performs the set basic information for fat. It either
1925  completes the request or enqueues it off to the fsp.
1926 
1927 Arguments:
1928 
1929  Irp - Supplies the irp being processed
1930 
1931  Fcb - Supplies the Fcb or Dcb being processed, already known not to
1932  be the root dcb
1933 
1934  Ccb - Supplies the flag bit that control updating the last modify
1935  time on cleanup.
1936 
1937 Return Value:
1938 
1939  NTSTATUS - The result of this operation if it completes without
1940  an exception.
1941 
1942 --*/
1943 
1944 {
1945  NTSTATUS Status;
1946 
1948 
1949  PDIRENT Dirent;
1950  PBCB DirentBcb;
1951 
1952 #ifndef __REACTOS__
1953  FAT_TIME_STAMP CreationTime = {0};
1954 #else
1955  FAT_TIME_STAMP CreationTime = {{0}};
1956 #endif
1957  UCHAR CreationMSec = 0;
1958 #ifndef __REACTOS__
1959  FAT_TIME_STAMP LastWriteTime = {0};
1960  FAT_TIME_STAMP LastAccessTime = {0};
1961  FAT_DATE LastAccessDate = {0};
1962 #else
1963  FAT_TIME_STAMP LastWriteTime = {{0}};
1964  FAT_TIME_STAMP LastAccessTime = {{0}};
1965  FAT_DATE LastAccessDate = {0, 0, 0};
1966 #endif
1967  UCHAR Attributes;
1968 
1969  BOOLEAN ModifyCreation = FALSE;
1970  BOOLEAN ModifyLastWrite = FALSE;
1971  BOOLEAN ModifyLastAccess = FALSE;
1972 
1973 #if (NTDDI_VERSION >= NTDDI_WIN8)
1974  BOOLEAN ModifiedAttributes = FALSE;
1975 #endif
1976 
1977 #ifndef __REACTOS__
1978  LARGE_INTEGER LargeCreationTime = {0};
1979  LARGE_INTEGER LargeLastWriteTime = {0};
1980  LARGE_INTEGER LargeLastAccessTime = {0};
1981 #else
1982  LARGE_INTEGER LargeCreationTime = {{0}};
1983  LARGE_INTEGER LargeLastWriteTime = {{0}};
1984  LARGE_INTEGER LargeLastAccessTime = {{0}};
1985 #endif
1986 
1987  ULONG NotifyFilter = 0;
1988 
1989  PAGED_CODE();
1990 
1991  DebugTrace(+1, Dbg, "FatSetBasicInfo...\n", 0);
1992 
1993  Buffer = Irp->AssociatedIrp.SystemBuffer;
1994 
1995  //
1996  // If the user is specifying -1 for a field, that means
1997  // we should leave that field unchanged, even if we might
1998  // have otherwise set it ourselves. We'll set the Ccb flag
1999  // saying that the user set the field so that we
2000  // don't do our default updating.
2001  //
2002  // We set the field to 0 then so we know not to actually
2003  // set the field to the user-specified (and in this case,
2004  // illegal) value.
2005  //
2006 
2007  if (Buffer->LastWriteTime.QuadPart == -1) {
2008 
2010  Buffer->LastWriteTime.QuadPart = 0;
2011  }
2012 
2013  if (Buffer->LastAccessTime.QuadPart == -1) {
2014 
2016  Buffer->LastAccessTime.QuadPart = 0;
2017  }
2018 
2019  if (Buffer->CreationTime.QuadPart == -1) {
2020 
2022  Buffer->CreationTime.QuadPart = 0;
2023  }
2024 
2025  DirentBcb = NULL;
2026 
2028 
2029  _SEH2_TRY {
2030 
2031  LARGE_INTEGER FatLocalDecThirtyOne1979;
2032  LARGE_INTEGER FatLocalJanOne1980;
2033 
2035  &FatLocalDecThirtyOne1979 );
2036 
2038  &FatLocalJanOne1980 );
2039 
2040  //
2041  // Get a pointer to the dirent
2042  //
2043 
2045 
2046  FatGetDirentFromFcbOrDcb( IrpContext,
2047  Fcb,
2048  FALSE,
2049  &Dirent,
2050  &DirentBcb );
2051  //
2052  // Check if the user specified a non-zero creation time
2053  //
2054 
2055  if (FatData.ChicagoMode && (Buffer->CreationTime.QuadPart != 0)) {
2056 
2057  LargeCreationTime = Buffer->CreationTime;
2058 
2059  //
2060  // Convert the Nt time to a Fat time
2061  //
2062 
2063  if ( !FatNtTimeToFatTime( IrpContext,
2064  &LargeCreationTime,
2065  FALSE,
2066  &CreationTime,
2067  &CreationMSec )) {
2068 
2069  //
2070  // Special case the value 12/31/79 and treat this as 1/1/80.
2071  // This '79 value can happen because of time zone issues.
2072  //
2073 
2074  if ((LargeCreationTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2075  (LargeCreationTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2076 
2077  CreationTime = FatTimeJanOne1980;
2078  LargeCreationTime = FatLocalJanOne1980;
2079 
2080  } else {
2081 
2082  DebugTrace(0, Dbg, "Invalid CreationTime\n", 0);
2084  }
2085 
2086  //
2087  // Don't worry about CreationMSec
2088  //
2089 
2090  CreationMSec = 0;
2091  }
2092 
2093  ModifyCreation = TRUE;
2094  }
2095 
2096  //
2097  // Check if the user specified a non-zero last access time
2098  //
2099 
2100  if (FatData.ChicagoMode && (Buffer->LastAccessTime.QuadPart != 0)) {
2101 
2102  LargeLastAccessTime = Buffer->LastAccessTime;
2103 
2104  //
2105  // Convert the Nt time to a Fat time
2106  //
2107 
2108  if ( !FatNtTimeToFatTime( IrpContext,
2109  &LargeLastAccessTime,
2110  TRUE,
2111  &LastAccessTime,
2112  NULL )) {
2113 
2114  //
2115  // Special case the value 12/31/79 and treat this as 1/1/80.
2116  // This '79 value can happen because of time zone issues.
2117  //
2118 
2119  if ((LargeLastAccessTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2120  (LargeLastAccessTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2121 
2122  LastAccessTime = FatTimeJanOne1980;
2123  LargeLastAccessTime = FatLocalJanOne1980;
2124 
2125  } else {
2126 
2127  DebugTrace(0, Dbg, "Invalid LastAccessTime\n", 0);
2129  }
2130  }
2131 
2132  LastAccessDate = LastAccessTime.Date;
2133  ModifyLastAccess = TRUE;
2134  }
2135 
2136  //
2137  // Check if the user specified a non-zero last write time
2138  //
2139 
2140  if (Buffer->LastWriteTime.QuadPart != 0) {
2141 
2142  //
2143  // First do a quick check here if the this time is the same
2144  // time as LastAccessTime.
2145  //
2146 
2147  if (ModifyLastAccess &&
2148  (Buffer->LastWriteTime.QuadPart == Buffer->LastAccessTime.QuadPart)) {
2149 
2150  ModifyLastWrite = TRUE;
2151  LastWriteTime = LastAccessTime;
2152  LargeLastWriteTime = LargeLastAccessTime;
2153 
2154  } else {
2155 
2156  LargeLastWriteTime = Buffer->LastWriteTime;
2157 
2158  //
2159  // Convert the Nt time to a Fat time
2160  //
2161 
2162  if ( !FatNtTimeToFatTime( IrpContext,
2163  &LargeLastWriteTime,
2164  TRUE,
2165  &LastWriteTime,
2166  NULL )) {
2167 
2168 
2169  //
2170  // Special case the value 12/31/79 and treat this as 1/1/80.
2171  // This '79 value can happen because of time zone issues.
2172  //
2173 
2174  if ((LargeLastWriteTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2175  (LargeLastWriteTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2176 
2177  LastWriteTime = FatTimeJanOne1980;
2178  LargeLastWriteTime = FatLocalJanOne1980;
2179 
2180  } else {
2181 
2182  DebugTrace(0, Dbg, "Invalid LastWriteTime\n", 0);
2184  }
2185  }
2186 
2187  ModifyLastWrite = TRUE;
2188  }
2189  }
2190 
2191 
2192  //
2193  // Check if the user specified a non zero file attributes byte
2194  //
2195 
2196  if (Buffer->FileAttributes != 0) {
2197 
2198  //
2199  // Only permit the attributes that FAT understands. The rest are silently
2200  // dropped on the floor.
2201  //
2202 
2203  Attributes = (UCHAR)(Buffer->FileAttributes & (FILE_ATTRIBUTE_READONLY |
2208 
2209  //
2210  // Make sure that for a file the directory bit is not set
2211  // and that for a directory the bit is set.
2212  //
2213 
2214  if (NodeType(Fcb) == FAT_NTC_FCB) {
2215 
2216  if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
2217 
2218  DebugTrace(0, Dbg, "Attempt to set dir attribute on file\n", 0);
2220  }
2221 
2222  } else {
2223 
2225  }
2226 
2227  //
2228  // Mark the FcbState temporary flag correctly.
2229  //
2230 
2231  if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY)) {
2232 
2233  //
2234  // Don't allow the temporary bit to be set on directories.
2235  //
2236 
2237  if (NodeType(Fcb) == FAT_NTC_DCB) {
2238 
2239  DebugTrace(0, Dbg, "No temporary directories\n", 0);
2241  }
2242 
2244 
2247 
2248  } else {
2249 
2251 
2254  }
2255 
2256  //
2257  // Now, only proceed if the requested file attributes are different
2258  // than the existing attributes.
2259  //
2260 
2261  if (Dirent->Attributes != Attributes) {
2262 
2263  //
2264  // Set the new attributes byte, and mark the bcb dirty
2265  //
2266 
2268 
2269  Dirent->Attributes = Attributes;
2270 
2272 
2273 #if (NTDDI_VERSION >= NTDDI_WIN8)
2274  ModifiedAttributes = TRUE;
2275 #endif
2276  }
2277  }
2278 
2279  if ( ModifyCreation ) {
2280 
2281  //
2282  // Set the new last write time in the dirent, and mark
2283  // the bcb dirty
2284  //
2285 
2286  Fcb->CreationTime = LargeCreationTime;
2287  Dirent->CreationTime = CreationTime;
2288  Dirent->CreationMSec = CreationMSec;
2289 
2290 
2292  //
2293  // Now we have to round the time in the Fcb up to the
2294  // nearest tem msec.
2295  //
2296 
2297  Fcb->CreationTime.QuadPart =
2298 
2299  ((Fcb->CreationTime.QuadPart + AlmostTenMSec) /
2300  TenMSec) * TenMSec;
2301 
2302  //
2303  // Now because the user just set the creation time we
2304  // better not set the creation time on close
2305  //
2306 
2308  }
2309 
2310  if ( ModifyLastAccess ) {
2311 
2312  //
2313  // Set the new last write time in the dirent, and mark
2314  // the bcb dirty
2315  //
2316 
2317  Fcb->LastAccessTime = LargeLastAccessTime;
2318  Dirent->LastAccessDate = LastAccessDate;
2319 
2321 
2322  //
2323  // Now we have to truncate the time in the Fcb down to the
2324  // current day. This has to be in LocalTime though, so first
2325  // convert to local, trunacate, then set back to GMT.
2326  //
2327 
2329  &Fcb->LastAccessTime );
2330 
2332 
2335 
2337  &Fcb->LastAccessTime );
2338 
2339  //
2340  // Now because the user just set the last access time we
2341  // better not set the last access time on close
2342  //
2343 
2345  }
2346 
2347  if ( ModifyLastWrite ) {
2348 
2349  //
2350  // Set the new last write time in the dirent, and mark
2351  // the bcb dirty
2352  //
2353 
2354  Fcb->LastWriteTime = LargeLastWriteTime;
2355  Dirent->LastWriteTime = LastWriteTime;
2356 
2358 
2359  //
2360  // Now we have to round the time in the Fcb up to the
2361  // nearest two seconds.
2362  //
2363 
2365 
2368 
2369  //
2370  // Now because the user just set the last write time we
2371  // better not set the last write time on close
2372  //
2373 
2375  }
2376 
2377  //
2378  // If we modified any of the values, we report this to the notify
2379  // package.
2380  //
2381  // We also take this opportunity to set the current file size and
2382  // first cluster in the Dirent in order to support a server hack.
2383  //
2384 
2385  if (NotifyFilter != 0) {
2386 
2387  if (NodeType(Fcb) == FAT_NTC_FCB) {
2388 
2389  Dirent->FileSize = Fcb->Header.FileSize.LowPart;
2390 
2391 
2393 
2394  if (FatIsFat32(Fcb->Vcb)) {
2395 
2396  Dirent->FirstClusterOfFileHi =
2397  (USHORT)(Fcb->FirstClusterOfFile >> 16);
2398  }
2399  }
2400 
2401  FatNotifyReportChange( IrpContext,
2402  Fcb->Vcb,
2403  Fcb,
2404  NotifyFilter,
2406 
2407  FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
2408  }
2409 
2410 #if (NTDDI_VERSION >= NTDDI_WIN8)
2411  //
2412  // If last-access, last-write, or any attribute bits changed, break
2413  // parent directory oplock.
2414  //
2415 
2416  if ((Fcb->ParentDcb != NULL) &&
2417  (ModifyLastAccess ||
2418  ModifyLastWrite ||
2419  ModifiedAttributes)) {
2420 
2421  FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb),
2422  IrpContext->OriginatingIrp,
2423  OPLOCK_FLAG_PARENT_OBJECT,
2424  NULL,
2425  NULL,
2426  NULL );
2427  }
2428 #endif
2429 
2430  try_exit: NOTHING;
2431  } _SEH2_FINALLY {
2432 
2433  DebugUnwind( FatSetBasicInfo );
2434 
2435  FatUnpinBcb( IrpContext, DirentBcb );
2436 
2437  DebugTrace(-1, Dbg, "FatSetBasicInfo -> %08lx\n", Status);
2438  } _SEH2_END;
2439 
2440  return Status;
2441 }
2442 
2443 //
2444 // Internal Support Routine
2445 //
2446 
2447 _Requires_lock_held_(_Global_critical_region_)
2448 NTSTATUS
2449 FatSetDispositionInfo (
2450  IN PIRP_CONTEXT IrpContext,
2451  IN PIRP Irp,
2453  IN PFCB Fcb
2454  )
2455 
2456 /*++
2457 
2458 Routine Description:
2459 
2460  This routine performs the set disposition information for fat. It either
2461  completes the request or enqueues it off to the fsp.
2462 
2463 Arguments:
2464 
2465  Irp - Supplies the irp being processed
2466 
2467  FileObject - Supplies the file object being processed
2468 
2469  Fcb - Supplies the Fcb or Dcb being processed, already known not to
2470  be the root dcb
2471 
2472 Return Value:
2473 
2474  NTSTATUS - The result of this operation if it completes without
2475  an exception.
2476 
2477 --*/
2478 
2479 {
2481  PBCB Bcb;
2482  PDIRENT Dirent;
2483 
2484  PAGED_CODE();
2485 
2486  DebugTrace(+1, Dbg, "FatSetDispositionInfo...\n", 0);
2487 
2488  Buffer = Irp->AssociatedIrp.SystemBuffer;
2489 
2490  //
2491  // Check if the user wants to delete the file or not delete
2492  // the file
2493  //
2494 
2495  if (Buffer->DeleteFile) {
2496 
2497  //
2498  // Check if the file is marked read only
2499  //
2500 
2502 
2503  DebugTrace(-1, Dbg, "Cannot delete readonly file\n", 0);
2504 
2505  return STATUS_CANNOT_DELETE;
2506  }
2507 
2508  //
2509  // Make sure there is no process mapping this file as an image.
2510  //
2511 
2513  MmFlushForDelete )) {
2514 
2515  DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);
2516 
2517  return STATUS_CANNOT_DELETE;
2518  }
2519 
2520  //
2521  // Check if this is a dcb and if so then only allow
2522  // the request if the directory is empty.
2523  //
2524 
2525  if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
2526 
2527  DebugTrace(-1, Dbg, "Cannot delete root Directory\n", 0);
2528 
2529  return STATUS_CANNOT_DELETE;
2530  }
2531 
2532  if (NodeType(Fcb) == FAT_NTC_DCB) {
2533 
2534  DebugTrace(-1, Dbg, "User wants to delete a directory\n", 0);
2535 
2536  //
2537  // Check if the directory is empty
2538  //
2539 
2540  if ( !FatIsDirectoryEmpty(IrpContext, Fcb) ) {
2541 
2542  DebugTrace(-1, Dbg, "Directory is not empty\n", 0);
2543 
2545  }
2546  }
2547 
2548  //
2549  // If this is a floppy, touch the volume so to verify that it
2550  // is not write protected.
2551  //
2552 
2553  if ( FlagOn(Fcb->Vcb->Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2554 
2555  PVCB Vcb;
2556  PBCB LocalBcb = NULL;
2557  UCHAR *LocalBuffer;
2558  UCHAR TmpChar;
2559  ULONG BytesToMap;
2560 
2562 
2563  Vcb = Fcb->Vcb;
2564 
2565  BytesToMap = Vcb->AllocationSupport.FatIndexBitSize == 12 ?
2566  FatReservedBytes(&Vcb->Bpb) +
2567  FatBytesPerFat(&Vcb->Bpb):PAGE_SIZE;
2568 
2569  FatReadVolumeFile( IrpContext,
2570  Vcb,
2571  0,
2572  BytesToMap,
2573  &LocalBcb,
2574  (PVOID *)&LocalBuffer );
2575 
2576  _SEH2_TRY {
2577 
2578  if (!CcPinMappedData( Vcb->VirtualVolumeFile,
2579  &FatLargeZero,
2580  BytesToMap,
2581  BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
2582  &LocalBcb )) {
2583 
2584  //
2585  // Could not pin the data without waiting (cache miss).
2586  //
2587 
2588  FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
2589  }
2590 
2591  //
2592  // Make Mm, myself, and Cc think the byte is dirty, and then
2593  // force a writethrough.
2594  //
2595 
2596  LocalBuffer += FatReservedBytes(&Vcb->Bpb);
2597 
2598  TmpChar = LocalBuffer[0];
2599  LocalBuffer[0] = TmpChar;
2600 
2601  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb,
2602  FatReservedBytes( &Vcb->Bpb ),
2603  FatReservedBytes( &Vcb->Bpb ),
2604  Vcb->Bpb.BytesPerSector );
2605 
2606  } _SEH2_FINALLY {
2607 
2608  if (_SEH2_AbnormalTermination() && (LocalBcb != NULL)) {
2609 
2610  FatUnpinBcb( IrpContext, LocalBcb );
2611  }
2612  } _SEH2_END;
2613 
2614  CcRepinBcb( LocalBcb );
2615  CcSetDirtyPinnedData( LocalBcb, NULL );
2616  CcUnpinData( LocalBcb );
2617  DbgDoit( NT_ASSERT( IrpContext->PinCount ));
2618  DbgDoit( IrpContext->PinCount -= 1 );
2619  CcUnpinRepinnedBcb( LocalBcb, TRUE, &Iosb );
2620 
2621  //
2622  // If this was not successful, raise the status.
2623  //
2624 
2625  if ( !NT_SUCCESS(Iosb.Status) ) {
2626 
2627  FatNormalizeAndRaiseStatus( IrpContext, Iosb.Status );
2628  }
2629 
2630  } else {
2631 
2632  //
2633  // Just set a Bcb dirty here. The above code was only there to
2634  // detect a write protected floppy, while the below code works
2635  // for any write protected media and only takes a hit when the
2636  // volume in clean.
2637  //
2638 
2639  FatGetDirentFromFcbOrDcb( IrpContext,
2640  Fcb,
2641  FALSE,
2642  &Dirent,
2643  &Bcb );
2644 
2645  //
2646  // This has to work for the usual reasons (we verified the Fcb within
2647  // volume synch).
2648  //
2649 
2650  _SEH2_TRY {
2651 
2652  FatSetDirtyBcb( IrpContext, Bcb, Fcb->Vcb, TRUE );
2653 
2654  } _SEH2_FINALLY {
2655 
2656  FatUnpinBcb( IrpContext, Bcb );
2657  } _SEH2_END;
2658  }
2659 
2660  //
2661  // At this point either we have a file or an empty directory
2662  // so we know the delete can proceed.
2663  //
2664 
2666  FileObject->DeletePending = TRUE;
2667 
2668  //
2669  // If this is a directory then report this delete pending to
2670  // the dir notify package.
2671  //
2672 
2673  if (NodeType(Fcb) == FAT_NTC_DCB) {
2674 
2676  &Fcb->Vcb->DirNotifyList,
2677  FileObject->FsContext,
2678  NULL,
2679  FALSE,
2680  FALSE,
2681  0,
2682  NULL,
2683  NULL,
2684  NULL );
2685  }
2686  } else {
2687 
2688  //
2689  // The user doesn't want to delete the file so clear
2690  // the delete on close bit
2691  //
2692 
2693  DebugTrace(0, Dbg, "User want to not delete file\n", 0);
2694 
2696  FileObject->DeletePending = FALSE;
2697  }
2698 
2699  DebugTrace(-1, Dbg, "FatSetDispositionInfo -> STATUS_SUCCESS\n", 0);
2700 
2701  return STATUS_SUCCESS;
2702 }
2703 
2704 
2705 //
2706 // Internal Support Routine
2707 //
2708 
2709 NTSTATUS
2711  IN PIRP_CONTEXT IrpContext,
2712  IN PIRP Irp,
2713  IN PVCB Vcb,
2714  IN PFCB Fcb,
2715  IN PCCB Ccb
2716  )
2717 
2718 /*++
2719 
2720 Routine Description:
2721 
2722  This routine performs the set name information for fat. It either
2723  completes the request or enqueues it off to the fsp.
2724 
2725 Arguments:
2726 
2727  Irp - Supplies the irp being processed
2728 
2729  Vcb - Supplies the Vcb being processed
2730 
2731  Fcb - Supplies the Fcb or Dcb being processed, already known not to
2732  be the root dcb
2733 
2734  Ccb - Supplies the Ccb corresponding to the handle opening the source
2735  file
2736 
2737 Return Value:
2738 
2739  NTSTATUS - The result of this operation if it completes without
2740  an exception.
2741 
2742 --*/
2743 
2744 {
2747  BOOLEAN CaseOnlyRename;
2748  BOOLEAN ContinueWithRename;
2750  BOOLEAN DeleteSourceDirent;
2751  BOOLEAN DeleteTarget;
2752  BOOLEAN NewDirentFromPool;
2753  BOOLEAN RenamedAcrossDirectories;
2754  BOOLEAN ReplaceIfExists;
2755 
2756  CCB LocalCcb;
2757  PCCB SourceCcb;
2758 
2759  DIRENT Dirent;
2760 
2762 
2763  OEM_STRING OldOemName;
2764  OEM_STRING NewOemName;
2765  UCHAR OemNameBuffer[24*2];
2766 
2767  PBCB DotDotBcb;
2768  PBCB NewDirentBcb;
2769  PBCB OldDirentBcb;
2770  PBCB SecondPageBcb;
2771  PBCB TargetDirentBcb;
2772 
2773  PDCB TargetDcb = NULL;
2774  PDCB OldParentDcb;
2775 
2776  PDIRENT DotDotDirent = NULL;
2777  PDIRENT FirstPageDirent = NULL;
2778  PDIRENT NewDirent = NULL;
2779  PDIRENT OldDirent = NULL;
2780  PDIRENT SecondPageDirent = NULL;
2781  PDIRENT ShortDirent = NULL;
2782  PDIRENT TargetDirent = NULL;
2783 
2784  PFCB TempFcb;
2785 
2786  PFILE_OBJECT TargetFileObject;
2788 
2790 
2791  PLIST_ENTRY Links;
2792 
2793  ULONG BytesInFirstPage = 0;
2794  ULONG DirentsInFirstPage = 0;
2795  ULONG DirentsRequired = 0;
2796  ULONG NewOffset = 0;
2797  ULONG NotifyAction = 0;
2798  ULONG SecondPageOffset = 0;
2799  ULONG ShortDirentOffset = 0;
2800  ULONG TargetDirentOffset = 0;
2801  ULONG TargetLfnOffset = 0;
2802 
2803  // NewName comes from the IRP buffer or the TargetFileObject, so we can't
2804  // go around modifying it. Instead we modify NewNameCopy.
2806 
2807  // NB: these five UNICODE_STRINGS are allocated
2808  // from one chopped up pool allocation called UnicodeBuffer.
2809  UNICODE_STRING NewNameCopy;
2810  UNICODE_STRING NewUpcasedName;
2811  UNICODE_STRING OldName;
2812  UNICODE_STRING OldUpcasedName;
2813  UNICODE_STRING TargetLfn;
2814  PWCHAR UnicodeBuffer;
2815 
2816  UNICODE_STRING TargetOrigLfn = {0};
2817 
2818  UNICODE_STRING UniTunneledShortName;
2819  WCHAR UniTunneledShortNameBuffer[12];
2820  UNICODE_STRING UniTunneledLongName;
2821  WCHAR UniTunneledLongNameBuffer[26];
2822 
2823  LARGE_INTEGER TunneledCreationTime;
2824  ULONG TunneledDataSize;
2825  BOOLEAN HaveTunneledInformation = FALSE;
2826  BOOLEAN UsingTunneledLfn = FALSE;
2827 
2828  BOOLEAN InvalidateFcbOnRaise = FALSE;
2829 
2830  PFILE_OBJECT DirectoryFileObject = NULL;
2831  ULONG Flags = 0;
2832 
2833  PAGED_CODE();
2834 
2835  DebugTrace(+1, Dbg, "FatSetRenameInfo...\n", 0);
2836 
2837  //
2838  // P H A S E 0: Initialize some variables.
2839  //
2840 
2841  CaseOnlyRename = FALSE;
2842  ContinueWithRename = FALSE;
2843  DeleteSourceDirent = FALSE;
2844  DeleteTarget = FALSE;
2845  NewDirentFromPool = FALSE;
2846  RenamedAcrossDirectories = FALSE;
2847 
2848  DotDotBcb = NULL;
2849  NewDirentBcb = NULL;
2850  OldDirentBcb = NULL;
2851  SecondPageBcb = NULL;
2852  TargetDirentBcb = NULL;
2853 
2854  NewOemName.Length = 0;
2855  NewOemName.MaximumLength = 24;
2856  NewOemName.Buffer = (PCHAR)&OemNameBuffer[0];
2857 
2858  OldOemName.Length = 0;
2859  OldOemName.MaximumLength = 24;
2860  OldOemName.Buffer = (PCHAR)&OemNameBuffer[24];
2861 
2862  UnicodeBuffer = FsRtlAllocatePoolWithTag( PagedPool,
2863  5 * MAX_LFN_CHARACTERS * sizeof(WCHAR),
2865 
2866  NewUpcasedName.Length = 0;
2867  NewUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2868  NewUpcasedName.Buffer = &UnicodeBuffer[0];
2869 
2870  OldName.Length = 0;
2871  OldName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2872  OldName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS];
2873 
2874  OldUpcasedName.Length = 0;
2875  OldUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2876  OldUpcasedName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 2];
2877 
2878  TargetLfn.Length = 0;
2879  TargetLfn.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2880  TargetLfn.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 3];
2881 
2882  NewNameCopy.Length = 0;
2883  NewNameCopy.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2884  NewNameCopy.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 4];
2885 
2886  UniTunneledShortName.Length = 0;
2887  UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer);
2888  UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0];
2889 
2890  UniTunneledLongName.Length = 0;
2891  UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer);
2892  UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0];
2893 
2894  //
2895  // Remember the name in case we have to modify the name
2896  // value in the ea.
2897  //
2898 
2899  RtlCopyMemory( OldOemName.Buffer,
2900  Fcb->ShortName.Name.Oem.Buffer,
2901  OldOemName.Length );
2902 
2903  //
2904  // Get the current stack location
2905  //
2906 
2908 
2909  //
2910  // Extract information from the Irp to make our life easier
2911  //
2912 
2914  SourceCcb = FileObject->FsContext2;
2915  TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
2916  ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
2917 
2918  RtlZeroMemory( &LocalCcb, sizeof(CCB) );
2919 
2920  //
2921  // P H A S E 1:
2922  //
2923  // Test if rename is legal. Only small side-effects are not undone.
2924  //
2925 
2926  _SEH2_TRY {
2927 
2928  //
2929  // Can't rename the root directory
2930  //
2931 
2932  if ( NodeType(Fcb) == FAT_NTC_ROOT_DCB ) {
2933 
2935  }
2936 
2937  //
2938  // Check that we were not given a dcb with open handles beneath
2939  // it. If there are only UncleanCount == 0 Fcbs beneath us, then
2940  // remove them from the prefix table, and they will just close
2941  // and go away naturally.
2942  //
2943 
2944  if (NodeType(Fcb) == FAT_NTC_DCB) {
2945 
2946  PFCB BatchOplockFcb;
2947  ULONG BatchOplockCount;
2948 
2949  //
2950  // Loop until there are no batch oplocks in the subtree below
2951  // this directory.
2952  //
2953 
2954  while (TRUE) {
2955 
2956  BatchOplockFcb = NULL;
2957  BatchOplockCount = 0;
2958 
2959  //
2960  // First look for any UncleanCount != 0 Fcbs, and fail if we
2961  // find any.
2962  //
2963 
2964  for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
2965  TempFcb != Fcb;
2966  TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
2967 
2968  if ( TempFcb->UncleanCount != 0 ) {
2969 
2970  //
2971  // If there is a batch oplock on this file then
2972  // increment our count and remember the Fcb if
2973  // this is the first.
2974  //
2975 
2976  if (FatIsFileOplockable( TempFcb ) &&
2978 #if (NTDDI_VERSION >= NTDDI_WIN7)
2979  ||
2980  FsRtlCurrentOplockH( FatGetFcbOplock(TempFcb) )
2981 #endif
2982  )) {
2983 
2984  BatchOplockCount += 1;
2985  if ( BatchOplockFcb == NULL ) {
2986 
2987  BatchOplockFcb = TempFcb;
2988  }
2989 
2990  } else {
2991 
2993  }
2994  }
2995  }
2996 
2997  //
2998  // If this is not the first pass for rename and the number
2999  // of batch oplocks has not decreased then give up.
3000  //
3001 
3002  if ( BatchOplockFcb != NULL ) {
3003 
3004  if ( (Irp->IoStatus.Information != 0) &&
3005  (BatchOplockCount >= Irp->IoStatus.Information) ) {
3006 
3008  }
3009 
3010  //
3011  // Try to break this batch oplock.
3012  //
3013 
3014  Irp->IoStatus.Information = BatchOplockCount;
3015  Status = FsRtlCheckOplock( FatGetFcbOplock(BatchOplockFcb),
3016  Irp,
3017  IrpContext,
3019  NULL );
3020 
3021  //
3022  // If the oplock was already broken then look for more
3023  // batch oplocks.
3024  //
3025 
3026  if (Status == STATUS_SUCCESS) {
3027 
3028  continue;
3029  }
3030 
3031  //
3032  // Otherwise the oplock package will post or complete the
3033  // request.
3034  //
3035 
3037  }
3038 
3039  break;
3040  }
3041 
3042  //
3043  // Now try to get as many of these file object, and thus Fcbs
3044  // to go away as possible, flushing first, of course.
3045  //
3046 
3047  FatPurgeReferencedFileObjects( IrpContext, Fcb, Flush );
3048 
3049  //
3050  // OK, so there are no UncleanCount != 0, Fcbs. Infact, there
3051  // shouldn't really be any Fcbs left at all, except obstinate
3052  // ones from user mapped sections .... Remove the full file name
3053  // and exact case lfn.
3054  //
3055 
3056  for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
3057  TempFcb != Fcb;
3058  TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
3059 
3060  FatAcquireExclusiveFcb( IrpContext, TempFcb );
3061 
3062  if (TempFcb->FullFileName.Buffer != NULL) {
3063 
3064  ExFreePool( TempFcb->FullFileName.Buffer );
3065  TempFcb->FullFileName.Buffer = NULL;
3066  }
3067 
3068  FatReleaseFcb( IrpContext, TempFcb );
3069  }
3070  }
3071 
3072  //
3073  // Check if this is a simple rename or a fully-qualified rename
3074  // In both cases we need to figure out what the TargetDcb, and
3075  // NewName are.
3076  //
3077 
3078  if (TargetFileObject == NULL) {
3079 
3080  //
3081  // In the case of a simple rename the target dcb is the
3082  // same as the source file's parent dcb, and the new file name
3083  // is taken from the system buffer
3084  //
3085 
3087 
3088  Buffer = Irp->AssociatedIrp.SystemBuffer;
3089 
3090  TargetDcb = Fcb->ParentDcb;
3091 
3092  NewName.Length = (USHORT) Buffer->FileNameLength;
3093  NewName.Buffer = (PWSTR) &Buffer->FileName;
3094 
3095  //
3096  // Make sure the name is of legal length.
3097  //
3098 
3099  if (NewName.Length > 255*sizeof(WCHAR)) {
3100 
3102  }
3103 
3104  RtlCopyUnicodeString(&NewNameCopy,&NewName);
3105 
3106  } else {
3107 
3108  //
3109  // For a fully-qualified rename the target dcb is taken from
3110  // the target file object, which must be on the same vcb as
3111  // the source.
3112  //
3113 
3114  PVCB TargetVcb;
3115  PCCB TargetCcb;
3116 
3117  if ((FatDecodeFileObject( TargetFileObject,
3118  &TargetVcb,
3119  &TargetDcb,
3120  &TargetCcb ) != UserDirectoryOpen) ||
3121  (TargetVcb != Vcb)) {
3122 
3124  }
3125 
3126  //
3127  // This name is by definition legal.
3128  //
3129 
3130  NewName = *((PUNICODE_STRING)&TargetFileObject->FileName);
3131 
3132  RtlCopyUnicodeString(&NewNameCopy,&NewName);
3133 
3134  }
3135 
3136  //
3137  // We will need an upcased version of the unicode name and the
3138  // old name as well.
3139  //
3140 
3141  Status = RtlUpcaseUnicodeString( &NewUpcasedName, &NewName, FALSE );
3142 
3143  if (!NT_SUCCESS(Status)) {
3144 
3145  try_return( Status );
3146  }
3147 
3148  FatGetUnicodeNameFromFcb( IrpContext, Fcb, &OldName );
3149 
3150  Status = RtlUpcaseUnicodeString( &OldUpcasedName, &OldName, FALSE );
3151 
3152  if (!NT_SUCCESS(Status)) {
3153  try_return(Status);
3154  }
3155 
3156  //
3157  // Check if the current name and new name are equal, and the
3158  // DCBs are equal. If they are then our work is already done.
3159  //
3160 
3161  if (TargetDcb == Fcb->ParentDcb) {
3162 
3163  //
3164  // OK, now if we found something then check if it was an exact
3165  // match or just a case match. If it was an exact match, then
3166  // we can bail here.
3167  //
3168 
3170  &OldName,
3171  FALSE,
3172  NULL )) {
3173 
3175  }
3176 
3177  //
3178  // Check now for a case only rename.
3179  //
3180 
3181 
3182  if (FsRtlAreNamesEqual( &NewUpcasedName,
3183  &OldUpcasedName,
3184  FALSE,
3185  NULL )) {
3186 
3187  CaseOnlyRename = TRUE;
3188  }
3189 
3190  } else {
3191 
3192  RenamedAcrossDirectories = TRUE;
3193  }
3194 
3195  //
3196  // Upcase the name and convert it to the Oem code page.
3197  //
3198  // If the new UNICODE name is already more than 12 characters,
3199  // then we know the Oem name will not be valid
3200  //
3201 
3202  if (NewName.Length <= 12*sizeof(WCHAR)) {
3203 
3204  FatUnicodeToUpcaseOem( IrpContext, &NewOemName, &NewName );
3205 
3206  //
3207  // If the name is not valid 8.3, zero the length.
3208  //
3209 
3210  if (FatSpaceInName( IrpContext, &NewName ) ||
3211  !FatIsNameShortOemValid( IrpContext, NewOemName, FALSE, FALSE, FALSE)) {
3212 
3213  NewOemName.Length = 0;
3214  }
3215 
3216  } else {
3217 
3218  NewOemName.Length = 0;
3219  }
3220 
3221  //
3222  // Look in the tunnel cache for names and timestamps to restore
3223  //
3224 
3225  TunneledDataSize = sizeof(LARGE_INTEGER);
3226  HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel,
3228  &NewName,
3229  &UniTunneledShortName,
3230  &UniTunneledLongName,
3231  &TunneledDataSize,
3232  &TunneledCreationTime );
3233  NT_ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER));
3234 
3235 
3236  //
3237  // Now we need to determine how many dirents this new name will
3238  // require.
3239  //
3240 
3241  if ((NewOemName.Length == 0) ||
3242  (FatEvaluateNameCase( IrpContext,
3243  &NewNameCopy,
3246  &CreateLfn ),
3247  CreateLfn)) {
3248 
3249  DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&NewNameCopy) + 1;
3250 
3251  } else {
3252 
3253  //
3254  // The user-given name is a short name, but we might still have
3255  // a tunneled long name we want to use. See if we can.
3256  //
3257 
3258  if (UniTunneledLongName.Length &&
3259  !FatLfnDirentExists(IrpContext, TargetDcb, &UniTunneledLongName, &TargetLfn)) {
3260 
3261  UsingTunneledLfn = CreateLfn = TRUE;
3262  DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&UniTunneledLongName) + 1;
3263 
3264  } else {
3265 
3266  //
3267  // This really is a simple dirent. Note that the two AllLower BOOLEANs
3268  // are correctly set now.
3269  //
3270 
3271  DirentsRequired = 1;
3272 
3273 
3274  }
3275  }
3276 
3277  //
3278  // Do some extra checks here if we are not in Chicago mode.
3279  //
3280 
3281  if (!FatData.ChicagoMode) {
3282 
3283  //
3284  // If the name was not 8.3 valid, fail the rename.
3285  //
3286 
3287  if (NewOemName.Length == 0) {
3288 
3290  }
3291 
3292  //
3293  // Don't use the magic bits.
3294  //
3295 
3298  CreateLfn = FALSE;
3299  UsingTunneledLfn = FALSE;
3300  }
3301 
3302  if (!CaseOnlyRename) {
3303 
3304  //
3305  // Check if the new name already exists, wait is known to be
3306  // true.
3307  //
3308 
3309  if (NewOemName.Length != 0) {
3310 
3311  FatStringTo8dot3( IrpContext,
3312  NewOemName,
3313  &LocalCcb.OemQueryTemplate.Constant );
3314 
3315  } else {
3316 
3318  }
3319 
3320  LocalCcb.UnicodeQueryTemplate = NewUpcasedName;
3321  LocalCcb.ContainsWildCards = FALSE;
3322 
3323  Flags = 0;
3324 
3325 
3326  FatLocateDirent( IrpContext,
3327  TargetDcb,
3328  &LocalCcb,
3329  0,
3330  &Flags,
3331  &TargetDirent,
3332  &TargetDirentBcb,
3333  (PVBO)&TargetDirentOffset,
3334  NULL,
3335  &TargetLfn,
3336  &TargetOrigLfn );
3337 
3338  if (TargetDirent != NULL) {
3339 
3340 
3341  //
3342  // The name already exists, check if the user wants
3343  // to overwrite the name, and has access to do the overwrite
3344  // We cannot overwrite a directory.
3345  //
3346 
3347  if ((!ReplaceIfExists) ||
3348  (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY)) ||
3349  (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY))) {
3350 
3352  }
3353 
3354  //
3355  // Check that the file has no open user handles, if it does
3356  // then we will deny access. We do the check by searching
3357  // down the list of fcbs opened under our parent Dcb, and making
3358  // sure none of the maching Fcbs have a non-zero unclean count or
3359  // outstanding image sections.
3360  //
3361 
3362  for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
3363  Links != &TargetDcb->Specific.Dcb.ParentDcbQueue; ) {
3364 
3365  TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3366 
3367  //
3368  // Advance now. The image section flush may cause the final
3369  // close, which will recursively happen underneath of us here.
3370  // It would be unfortunate if we looked through free memory.
3371  //
3372 
3373  Links = Links->Flink;
3374 
3375  if ((TempFcb->DirentOffsetWithinDirectory == TargetDirentOffset) &&
3376  ((TempFcb->UncleanCount != 0) ||
3378  MmFlushForDelete))) {
3379 
3380  //
3381  // If there are batch oplocks on this file then break the
3382  // oplocks before failing the rename.
3383  //
3384 
3386 
3387  if (FatIsFileOplockable( TempFcb ) &&
3389 #if (NTDDI_VERSION >= NTDDI_WIN7)
3390  ||
3391  FsRtlCurrentOplockH( FatGetFcbOplock(TempFcb) )
3392 #endif
3393  )) {
3394 
3395  //
3396  // Do all of our cleanup now since the IrpContext
3397  // could go away when this request is posted.
3398  //
3399 
3400  FatUnpinBcb( IrpContext, TargetDirentBcb );
3401 
3403  Irp,
3404  IrpContext,
3406  NULL );
3407 
3408  if (Status != STATUS_PENDING) {
3409 
3411  }
3412  }
3413 
3414  try_return( NOTHING );
3415  }
3416  }
3417 
3418  //
3419  // OK, this target is toast. Remember the Lfn offset.
3420  //
3421 
3422  TargetLfnOffset = TargetDirentOffset -
3423  FAT_LFN_DIRENTS_NEEDED(&TargetOrigLfn) *
3424  sizeof(DIRENT);
3425 
3426  DeleteTarget = TRUE;
3427  }
3428  }
3429 
3430 
3431  //
3432  // If we will need more dirents than we have, allocate them now.
3433  //
3434 
3435  if ((TargetDcb != Fcb->ParentDcb) ||
3436  (DirentsRequired !=
3438  Fcb->LfnOffsetWithinDirectory) / sizeof(DIRENT) + 1)) {
3439 
3440  //
3441  // Get some new allocation
3442  //
3443 
3444  NewOffset = FatCreateNewDirent( IrpContext,
3445  TargetDcb,
3446  DirentsRequired,
3447  FALSE );
3448 
3449  DeleteSourceDirent = TRUE;
3450 
3451  } else {
3452 
3453  NewOffset = Fcb->LfnOffsetWithinDirectory;
3454  }
3455 
3456  ContinueWithRename = TRUE;
3457 
3458  try_exit: NOTHING;
3459 
3460  } _SEH2_FINALLY {
3461 
3462  if (!ContinueWithRename) {
3463 
3464  //
3465  // Undo everything from above.
3466  //
3467 
3468  ExFreePool( UnicodeBuffer );
3469  FatUnpinBcb( IrpContext, TargetDirentBcb );
3470 
3471  }
3472  } _SEH2_END;
3473 
3474  //
3475  // Now, if we are already done, return here.
3476  //
3477 
3478  if (!ContinueWithRename) {
3479 
3480  return Status;
3481  }
3482 
3483  //
3484  // P H A S E 2: Actually perform the rename.
3485  //
3486 
3487  _SEH2_TRY {
3488 
3489  //
3490  // Report the fact that we are going to remove this entry.
3491  // If we renamed within the same directory and the new name for the
3492  // file did not previously exist, we report this as a rename old
3493  // name. Otherwise this is a removed file.
3494  //
3495 
3496  if (!RenamedAcrossDirectories && !DeleteTarget) {
3497 
3498  NotifyAction = FILE_ACTION_RENAMED_OLD_NAME;
3499 
3500  } else {
3501 
3502  NotifyAction = FILE_ACTION_REMOVED;
3503  }
3504 
3505  FatNotifyReportChange( IrpContext,
3506  Vcb,
3507  Fcb,
3508  ((NodeType( Fcb ) == FAT_NTC_FCB)
3511  NotifyAction );
3512 
3513  _SEH2_TRY {
3514 
3515  //
3516  // Capture a copy of the source dirent.
3517  //
3518 
3519  FatGetDirentFromFcbOrDcb( IrpContext, Fcb, FALSE, &OldDirent, &OldDirentBcb );
3520 
3521  Dirent = *OldDirent;
3522 
3523  //
3524  // Tunnel the source Fcb - the names are disappearing regardless of
3525  // whether the dirent allocation physically changed
3526  //
3527 
3528  FatTunnelFcbOrDcb( Fcb, SourceCcb );
3529 
3530  //
3531  // From here until very nearly the end of the operation, if we raise there
3532  // is no reasonable way to suppose we'd be able to undo the damage. Not
3533  // being a transactional filesystem, FAT is at the mercy of a lot of things
3534  // (as the astute reader has no doubt realized by now).
3535  //
3536 
3537  InvalidateFcbOnRaise = TRUE;
3538 
3539  //
3540  // Delete our current dirent(s) if we got a new one.
3541  //
3542 
3543  if (DeleteSourceDirent) {
3544 
3545  FatDeleteDirent( IrpContext, Fcb, NULL, FALSE );
3546  }
3547 
3548  //
3549  // Delete a target conflict if we were meant to.
3550  //
3551 
3552  if (DeleteTarget) {
3553 
3554  FatDeleteFile( IrpContext,
3555  TargetDcb,
3556  TargetLfnOffset,
3557  TargetDirentOffset,
3558  TargetDirent,
3559  &TargetLfn );
3560  }
3561 
3562  //
3563  // We need to evaluate any short names required. If there were any
3564  // conflicts in existing short names, they would have been deleted above.
3565  //
3566  // It isn't neccesary to worry about the UsingTunneledLfn case. Since we
3567  // actually already know whether CreateLfn will be set either NewName is
3568  // an Lfn and !UsingTunneledLfn is implied or NewName is a short name and
3569  // we can handle that externally.
3570  //
3571 
3572  FatSelectNames( IrpContext,
3573  TargetDcb,
3574  &NewOemName,
3575  &NewNameCopy,
3576  &NewOemName,
3577  (HaveTunneledInformation ? &UniTunneledShortName : NULL),
3580  &CreateLfn );
3581 
3582  if (!CreateLfn && UsingTunneledLfn) {
3583 
3584  CreateLfn = TRUE;
3585  RtlCopyUnicodeString( &NewNameCopy, &UniTunneledLongName );
3586 
3587  //
3588  // Short names are always upcase if an LFN exists
3589  //
3590 
3593  }
3594 
3595  //
3596  // OK, now setup the new dirent(s) for the new name.
3597  //
3598 
3599  FatPrepareWriteDirectoryFile( IrpContext,
3600  TargetDcb,
3601  NewOffset,
3602  sizeof(DIRENT),
3603  &NewDirentBcb,
3604 #ifndef __REACTOS__
3605  &NewDirent,
3606 #else
3607  (PVOID *)&NewDirent,
3608 #endif
3609  FALSE,
3610  TRUE,
3611  &Status );
3612 
3613  NT_ASSERT( NT_SUCCESS( Status ) );
3614 
3615  //
3616  // Deal with the special case of an LFN + Dirent structure crossing
3617  // a page boundry.
3618  //
3619 
3620  if ((NewOffset / PAGE_SIZE) !=
3621  ((NewOffset + (DirentsRequired - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
3622 
3623  SecondPageOffset = (NewOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
3624 
3625  BytesInFirstPage = SecondPageOffset - NewOffset;
3626 
3627  DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
3628 
3629  FatPrepareWriteDirectoryFile( IrpContext,
3630  TargetDcb,
3631  SecondPageOffset,
3632  sizeof(DIRENT),
3633  &SecondPageBcb,
3634 #ifndef __REACTOS__
3635  &SecondPageDirent,
3636 #else
3637  (PVOID *)&SecondPageDirent,
3638 #endif
3639  FALSE,
3640  TRUE,
3641  &Status );
3642 
3643  NT_ASSERT( NT_SUCCESS( Status ) );
3644 
3645  FirstPageDirent = NewDirent;
3646 
3647  NewDirent = FsRtlAllocatePoolWithTag( PagedPool,
3648  DirentsRequired * sizeof(DIRENT),
3649  TAG_DIRENT );
3650 
3651  NewDirentFromPool = TRUE;
3652  }
3653 
3654  //
3655  // Bump up Dirent and DirentOffset
3656  //
3657 
3658  ShortDirent = NewDirent + DirentsRequired - 1;
3659  ShortDirentOffset = NewOffset + (DirentsRequired - 1) * sizeof(DIRENT);
3660 
3661  //
3662  // Fill in the fields of the dirent.
3663  //
3664 
3665  *ShortDirent = Dirent;
3666 
3667  FatConstructDirent( IrpContext,
3668  ShortDirent,
3669  &NewOemName,
3672  CreateLfn ? &NewNameCopy : NULL,
3673  Dirent.Attributes,
3674  FALSE,
3675  (HaveTunneledInformation ? &TunneledCreationTime : NULL) );
3676 
3677  if (HaveTunneledInformation) {
3678 
3679  //
3680  // Need to go in and fix the timestamps in the FCB. Note that we can't use
3681  // the TunneledCreationTime since the conversions may have failed.
3682  //
3683 
3684  Fcb->CreationTime = FatFatTimeToNtTime(IrpContext, ShortDirent->CreationTime, ShortDirent->CreationMSec);
3685  Fcb->LastWriteTime = FatFatTimeToNtTime(IrpContext, ShortDirent->LastWriteTime, 0);
3686  Fcb->LastAccessTime = FatFatDateToNtTime(IrpContext, ShortDirent->LastAccessDate);
3687  }
3688 
3689 
3690  //
3691  // If the dirent crossed pages, split the contents of the
3692  // temporary pool between the two pages.
3693  //
3694 
3695  if (NewDirentFromPool) {
3696 
3697  RtlCopyMemory( FirstPageDirent, NewDirent, BytesInFirstPage );
3698 
3699  RtlCopyMemory( SecondPageDirent,
3700  NewDirent + DirentsInFirstPage,
3701  DirentsRequired*sizeof(DIRENT) - BytesInFirstPage );
3702 
3703  ShortDirent = SecondPageDirent +
3704  (DirentsRequired - DirentsInFirstPage) - 1;
3705  }
3706 
3707  Dirent = *ShortDirent;
3708 
3709  } _SEH2_FINALLY {
3710 
3711  //
3712  // Remove the entry from the splay table, and then remove the
3713  // full file name and exact case lfn. It is important that we
3714  // always remove the name from the prefix table regardless of
3715  // other errors.
3716  //
3717 
3718  FatRemoveNames( IrpContext, Fcb );
3719 
3720  if (Fcb->FullFileName.Buffer != NULL) {
3721 
3724  }
3725 
3726  if (Fcb->ExactCaseLongName.Buffer) {
3727 
3730  }
3731 
3732  FatUnpinBcb( IrpContext, OldDirentBcb );
3733  FatUnpinBcb( IrpContext, TargetDirentBcb );
3734  FatUnpinBcb( IrpContext, NewDirentBcb );
3735  FatUnpinBcb( IrpContext, SecondPageBcb );
3736  } _SEH2_END;
3737 
3738  //
3739  // Now we need to update the location of the file's directory
3740  // offset and move the fcb from its current parent dcb to
3741  // the target dcb.
3742  //
3743 
3744  Fcb->LfnOffsetWithinDirectory = NewOffset;
3745  Fcb->DirentOffsetWithinDirectory = ShortDirentOffset;
3746 
3748 
3749  //
3750  // There is a deep reason we put files on the tail, others on the head,
3751  // which is to allow us to easily enumerate all child directories before
3752  // child files. This is important to let us maintain whole-volume lockorder
3753  // via BottomUp enumeration.
3754  //
3755 
3756  if (NodeType(Fcb) == FAT_NTC_FCB) {
3757 
3758  InsertTailList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
3759  &Fcb->ParentDcbLinks );
3760 
3761  } else {
3762 
3763  InsertHeadList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
3764  &Fcb->ParentDcbLinks );
3765  }
3766 
3767  OldParentDcb = Fcb->ParentDcb;
3768  Fcb->ParentDcb = TargetDcb;
3769 
3770 #if (NTDDI_VERSION >= NTDDI_WIN8)
3771  //
3772  // Break parent directory oplock on the old parent. Directory oplock
3773  // breaks are always advisory, so we will never block/get STATUS_PENDING
3774  // here.
3775  //
3776 
3777  FsRtlCheckOplockEx( FatGetFcbOplock(OldParentDcb),
3778  IrpContext->OriginatingIrp,
3779  OPLOCK_FLAG_PARENT_OBJECT,
3780  NULL,
3781  NULL,
3782  NULL );
3783 #endif
3784 
3785  //
3786  // If we renamed across directories, some cleanup is now in order.
3787  //
3788 
3789  if (RenamedAcrossDirectories) {
3790 
3791 #if (NTDDI_VERSION >= NTDDI_WIN8)
3792  //
3793  // Break parent directory oplock on the new parent. Directory oplock
3794  // breaks are always advisory, so we will never block/get STATUS_PENDING
3795  // here.
3796  //
3797 
3798  FsRtlCheckOplockEx( FatGetFcbOplock(TargetDcb),
3799  IrpContext->OriginatingIrp,
3800  OPLOCK_FLAG_PARENT_OBJECT,
3801  NULL,
3802  NULL,
3803  NULL );
3804 #endif
3805 
3806  //
3807  // See if we need to uninitialize the cachemap for the source directory.
3808  // Do this now in case we get unlucky and raise trying to finalize the
3809  // operation.
3810  //
3811 
3812  if (IsListEmpty(&OldParentDcb->Specific.Dcb.ParentDcbQueue) &&
3813  (OldParentDcb->OpenCount == 0) &&
3814  (OldParentDcb->Specific.Dcb.DirectoryFile != NULL)) {
3815 
3816  NT_ASSERT( NodeType(OldParentDcb) == FAT_NTC_DCB );
3817 
3818  DirectoryFileObject = OldParentDcb->Specific.Dcb.DirectoryFile;
3819 
3820  OldParentDcb->Specific.Dcb.DirectoryFile = NULL;
3821  }
3822 
3823  //
3824  // If we move a directory across directories, we have to change
3825  // the cluster number in its .. entry
3826  //
3827 
3828  if (NodeType(Fcb) == FAT_NTC_DCB) {
3829 
3830  FatPrepareWriteDirectoryFile( IrpContext,
3831  Fcb,
3832  sizeof(DIRENT),
3833  sizeof(DIRENT),
3834  &DotDotBcb,
3835 #ifndef __REACTOS__
3836  &DotDotDirent,
3837 #else
3838  (PVOID *)&DotDotDirent,
3839 #endif
3840  FALSE,
3841  TRUE,
3842  &Status );
3843 
3844  NT_ASSERT( NT_SUCCESS( Status ) );
3845 
3846  DotDotDirent->FirstClusterOfFile = (USHORT)
3849 
3850  if (FatIsFat32( Vcb )) {
3851 
3852  DotDotDirent->FirstClusterOfFileHi = (USHORT)
3854  0 : (TargetDcb->FirstClusterOfFile >> 16));
3855  }
3856  }
3857  }
3858 
3859  //
3860  // Now we need to setup the splay table and the name within
3861  // the fcb. Free the old short name at this point.
3862  //
3863 
3864  ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
3865  Fcb->ShortName.Name.Oem.Buffer = NULL;
3866 
3867 
3868  FatConstructNamesInFcb( IrpContext,
3869  Fcb,
3870  &Dirent,
3871  CreateLfn ? &NewName : NULL );
3872 
3873  FatSetFullNameInFcb( IrpContext, Fcb, &NewName );
3874 
3875  //
3876  // The rest of the actions taken are not related to correctness of
3877  // the in-memory structures, so we shouldn't toast the Fcb if we
3878  // raise from here to the end.
3879  //
3880 
3881  InvalidateFcbOnRaise = FALSE;
3882 
3883  //
3884  // If a file, set the file as modified so that the archive bit
3885  // is set. We prevent this from adjusting the write time by
3886  // indicating the user flag in the ccb.
3887  //
3888 
3889  if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) {
3890 
3891  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
3893  }
3894 
3895  //
3896  // We have three cases to report.
3897  //
3898  // 1. If we overwrote an existing file, we report this as
3899  // a modified file.
3900  //
3901  // 2. If we renamed to a new directory, then we added a file.
3902  //
3903  // 3. If we renamed in the same directory, then we report the
3904  // the renamednewname.
3905  //
3906 
3907  if (DeleteTarget) {
3908 
3909  FatNotifyReportChange( IrpContext,
3910  Vcb,
3911  Fcb,
3919 
3920  } else if (RenamedAcrossDirectories) {
3921 
3922  FatNotifyReportChange( IrpContext,
3923  Vcb,
3924  Fcb,
3925  ((NodeType( Fcb ) == FAT_NTC_FCB)
3929 
3930  } else {
3931 
3932  FatNotifyReportChange( IrpContext,
3933  Vcb,
3934  Fcb,
3935  ((NodeType( Fcb ) == FAT_NTC_FCB)
3939  }
3940 
3941  //
3942  // We need to update the file name in the dirent. This value
3943  // is never used elsewhere, so we don't concern ourselves
3944  // with any error we may encounter. We let chkdsk fix the
3945  // disk at some later time.
3946  //
3947 
3948  if (!FatIsFat32(Vcb) &&
3949  Dirent.ExtendedAttributes != 0) {
3950 
3951  FatRenameEAs( IrpContext,
3952  Fcb,
3953  Dirent.ExtendedAttributes,
3954  &OldOemName );
3955  }
3956 
3957  FatUnpinBcb( IrpContext, DotDotBcb );
3958 
3959  FatUnpinRepinnedBcbs( IrpContext );
3960 
3961  //
3962  // Set our final status
3963  //
3964 
3966 
3967  } _SEH2_FINALLY {
3968 
3970 
3971  ExFreePool( UnicodeBuffer );
3972 
3973  if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) {
3974 
3975  //
3976  // Free pool if the buffer was grown on tunneling lookup
3977  //
3978 
3979  ExFreePool(UniTunneledLongName.Buffer);
3980  }
3981 
3982  if (NewDirentFromPool) {
3983 
3984  ExFreePool( NewDirent );
3985  }
3986 
3987  FatUnpinBcb( IrpContext, TargetDirentBcb );
3988  FatUnpinBcb( IrpContext, DotDotBcb );
3989 
3990  //
3991  // Uninitialize the cachemap for the source directory if we need to.
3992  //
3993 
3994  if (DirectoryFileObject) {
3995 
3996  DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0);
3997 
3998  CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
3999 
4000  ObDereferenceObject( DirectoryFileObject );
4001  }
4002 
4003  //
4004  // If this was an abnormal termination, then we are in trouble.
4005  // Should the operation have been in a sensitive state there is
4006  // nothing we can do but invalidate the Fcb.
4007  //
4008 
4009  if (_SEH2_AbnormalTermination() && InvalidateFcbOnRaise) {
4010 
4011  Fcb->FcbCondition = FcbBad;
4012  }
4013 
4014  DebugTrace(-1, Dbg, "FatSetRenameInfo -> %08lx\n", Status);
4015  } _SEH2_END;
4016 
4017  return Status;
4018 }
4019 
4020 
4021 //
4022 // Internal Support Routine
4023 //
4024 
4025 NTSTATUS
4027  IN PIRP_CONTEXT IrpContext,
4028  IN PIRP Irp,
4030  )
4031 
4032 /*++
4033 
4034 Routine Description:
4035 
4036  This routine performs the set position information for fat. It either
4037  completes the request or enqueues it off to the fsp.
4038 
4039 Arguments:
4040 
4041  Irp - Supplies the irp being processed
4042 
4043  FileObject - Supplies the file object being processed
4044 
4045 Return Value:
4046 
4047  NTSTATUS - The result of this operation if it completes without
4048  an exception.
4049 
4050 --*/
4051 
4052 {
4054 
4055  PAGED_CODE();
4056 
4057  DebugTrace(+1, Dbg, "FatSetPositionInfo...\n", 0);
4058 
4059  Buffer = Irp->AssociatedIrp.SystemBuffer;
4060 
4061  //
4062  // Check if the file does not use intermediate buffering. If it
4063  // does not use intermediate buffering then the new position we're
4064  // supplied must be aligned properly for the device
4065  //
4066 
4068 
4070 
4072 
4073  if ((Buffer->CurrentByteOffset.LowPart & DeviceObject->AlignmentRequirement) != 0) {
4074 
4075  DebugTrace(0, Dbg, "Cannot set position due to aligment conflict\n", 0);
4076  DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_INVALID_PARAMETER);
4077 
4078  return STATUS_INVALID_PARAMETER;
4079  }
4080  }
4081 
4082  //
4083  // The input parameter is fine so set the current byte offset and
4084  // complete the request
4085  //
4086 
4087  DebugTrace(0, Dbg, "Set the new position to %08lx\n", Buffer->CurrentByteOffset);
4088 
4089  FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
4090 
4091  DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_SUCCESS);
4092 
4093  UNREFERENCED_PARAMETER( IrpContext );
4094 
4095  return STATUS_SUCCESS;
4096 }
4097 
4098 
4099 //
4100 // Internal Support Routine
4101 //
4102 
4103 _Requires_lock_held_(_Global_critical_region_)
4104 NTSTATUS
4105 FatSetAllocationInfo (
4106  IN PIRP_CONTEXT IrpContext,
4107  IN PIRP Irp,
4108  IN PFCB Fcb,
4110  )
4111 
4112 /*++
4113 
4114 Routine Description:
4115 
4116  This routine performs the set Allocation information for fat. It either
4117  completes the request or enqueues it off to the fsp.
4118 
4119 Arguments:
4120 
4121  Irp - Supplies the irp being processed
4122 
4123  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4124  be the root dcb
4125 
4126  FileObject - Supplies the FileObject being processed, already known not to
4127  be the root dcb
4128 
4129 Return Value:
4130 
4131  NTSTATUS - The result of this operation if it completes without
4132  an exception.
4133 
4134 --*/
4135 
4136 {
4139  ULONG NewAllocationSize = 0;
4140  ULONG HeaderSize = 0;
4141 
4142  BOOLEAN FileSizeTruncated = FALSE;
4143  BOOLEAN CacheMapInitialized = FALSE;
4144  BOOLEAN ResourceAcquired = FALSE;
4145  ULONG OriginalFileSize = 0;
4146  ULONG OriginalValidDataLength = 0;
4147  ULONG OriginalValidDataToDisk = 0;
4148 
4149  PAGED_CODE();
4150 
4151  Buffer = Irp->AssociatedIrp.SystemBuffer;
4152 
4153  NewAllocationSize = Buffer->AllocationSize.LowPart;
4154 
4155  DebugTrace(+1, Dbg, "FatSetAllocationInfo.. to %08lx\n", NewAllocationSize);
4156 
4157  //
4158  // Allocation is only allowed on a file and not a directory
4159  //
4160 
4161  if (NodeType(Fcb) == FAT_NTC_DCB) {
4162 
4163  DebugTrace(-1, Dbg, "Cannot change allocation of a directory\n", 0);
4164 
4166  }
4167 
4168  //
4169  // Check that the new file allocation is legal
4170  //
4171 
4172 
4173  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->AllocationSize, 0)) {
4174 
4175  DebugTrace(-1, Dbg, "Illegal allocation size\n", 0);
4176 
4177  return STATUS_DISK_FULL;
4178  }
4179 
4180 
4181  //
4182  // If we haven't yet looked up the correct AllocationSize, do so.
4183  //
4184 
4185  if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
4186 
4187  FatLookupFileAllocationSize( IrpContext, Fcb );
4188  }
4189 
4190  //
4191  // This is kinda gross, but if the file is not cached, but there is
4192  // a data section, we have to cache the file to avoid a bunch of
4193  // extra work.
4194  //
4195 
4196  if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
4197  (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
4198  !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
4199 
4201 
4202  //
4203  // Now initialize the cache map.
4204  //
4205 
4207  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4208  FALSE,
4210  Fcb );
4211 
4212  CacheMapInitialized = TRUE;
4213  }
4214 
4215  //
4216  // Now mark the fact that the file needs to be truncated on close
4217  //
4218 
4220 
4221  //
4222  // Now mark that the time on the dirent needs to be updated on close.
4223  //
4224 
4225  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
4226 
4227  _SEH2_TRY {
4228 
4229  //
4230  // Increase or decrease the allocation size.
4231  //
4232 
4233  if (NewAllocationSize+HeaderSize > Fcb->Header.AllocationSize.LowPart) {
4234 
4235  FatAddFileAllocation( IrpContext, Fcb, FileObject, NewAllocationSize+HeaderSize);
4236 
4237  } else {
4238 
4239  //
4240  // Check here if we will be decreasing file size and synchonize with
4241  // paging IO.
4242  //
4243 
4244  if ( Fcb->Header.FileSize.LowPart > NewAllocationSize+HeaderSize ) {
4245 
4246  //
4247  // The way Sections for DataScan are created and used, an AV's
4248  // memory-mapping can come into being after we check it's safe
4249  // to truncate a file while continuing to hold the file here.
4250  // This leads to data corruption because Purge eventually fails
4251  // (during call to Cc to set file sizes) and stale data continues
4252  // to live in the cache/memory.
4253  //
4254 
4255  if (Fcb->PurgeFailureModeEnableCount != 0) {
4256 
4258  }
4259 
4260  //
4261  // Before we actually truncate, check to see if the purge
4262  // is going to fail.
4263  //
4264 
4265  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4266  &Buffer->AllocationSize )) {
4267 
4269  }
4270 
4271  FileSizeTruncated = TRUE;
4272 
4273  OriginalFileSize = Fcb->Header.FileSize.LowPart;
4274  OriginalValidDataLength = Fcb->Header.ValidDataLength.LowPart;
4275  OriginalValidDataToDisk = Fcb->ValidDataToDisk;
4276 
4277  (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4278  ResourceAcquired = TRUE;
4279 
4280  Fcb->Header.FileSize.LowPart = NewAllocationSize;
4281 
4282  //
4283  // If we reduced the file size to less than the ValidDataLength,
4284  // adjust the VDL. Likewise ValidDataToDisk.
4285  //
4286 
4287  if (Fcb->Header.ValidDataLength.LowPart > Fcb->Header.FileSize.LowPart) {
4288 
4289  Fcb->Header.ValidDataLength.LowPart = Fcb->Header.FileSize.LowPart;
4290  }
4291  if (Fcb->ValidDataToDisk > Fcb->Header.FileSize.LowPart) {
4292 
4293  Fcb->ValidDataToDisk = Fcb->Header.FileSize.LowPart;
4294  }
4295 
4296  }
4297 
4298  //
4299  // Now that File Size is down, actually do the truncate.
4300  //
4301 
4302  FatTruncateFileAllocation( IrpContext, Fcb, NewAllocationSize+HeaderSize );
4303 
4304  //
4305  // Now check if we needed to decrease the file size accordingly.
4306  //
4307 
4308  if ( FileSizeTruncated ) {
4309 
4310  //
4311  // Tell the cache manager we reduced the file size.
4312  // The call is unconditional, because MM always wants to know.
4313  //
4314 
4315 #if DBG
4316  _SEH2_TRY {
4317 #endif
4318 
4319  CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4320 
4321 #if DBG
4322  } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) {
4323 
4324  NOTHING;
4325  } _SEH2_END;
4326 #endif
4327 
4328  NT_ASSERT( FileObject->DeleteAccess || FileObject->WriteAccess );
4329 
4330  //
4331  // There is no going back from this. If we run into problems updating
4332  // the dirent we will have to live with the consequences. Not sending
4333  // the notifies is likewise pretty benign compared to failing the entire
4334  // operation and trying to back out everything, which could fail for the
4335  // same reasons.
4336  //
4337  // If you want a transacted filesystem, use NTFS ...
4338  //
4339 
4340  FileSizeTruncated = FALSE;
4341 
4342  FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
4343 
4344  //
4345  // Report that we just reduced the file size.
4346  //
4347 
4348  FatNotifyReportChange( IrpContext,
4349  Fcb->Vcb,
4350  Fcb,
4353  }
4354  }
4355 
4356  try_exit: NOTHING;
4357 
4358  } _SEH2_FINALLY {
4359 
4360  if ( _SEH2_AbnormalTermination() && FileSizeTruncated ) {
4361 
4362  Fcb->Header.FileSize.LowPart = OriginalFileSize;
4363  Fcb->Header.ValidDataLength.LowPart = OriginalValidDataLength;
4364  Fcb->ValidDataToDisk = OriginalValidDataToDisk;
4365 
4366  //
4367  // Make sure Cc knows the right filesize.
4368  //
4369 
4370  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4371 
4372  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4373  }
4374 
4375  NT_ASSERT( Fcb->Header.FileSize.LowPart <= Fcb->Header.AllocationSize.LowPart );
4376  }
4377 
4378  if (CacheMapInitialized) {
4379 
4381  }
4382 
4383  if (ResourceAcquired) {
4384 
4385  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4386 
4387  }
4388 
4389  } _SEH2_END;
4390 
4391  DebugTrace(-1, Dbg, "FatSetAllocationInfo -> %08lx\n", STATUS_SUCCESS);
4392 
4393  return Status;
4394 }
4395 
4396 
4397 //
4398 // Internal Support Routine
4399 //
4400 
4401 _Requires_lock_held_(_Global_critical_region_)
4402 NTSTATUS
4403 FatSetEndOfFileInfo (
4404  IN PIRP_CONTEXT IrpContext,
4405  IN PIRP Irp,
4407  IN PVCB Vcb,
4408  IN PFCB Fcb
4409  )
4410 
4411 /*++
4412 
4413 Routine Description:
4414 
4415  This routine performs the set End of File information for fat. It either
4416  completes the request or enqueues it off to the fsp.
4417 
4418 Arguments:
4419 
4420  Irp - Supplies the irp being processed
4421 
4422  FileObject - Supplies the file object being processed
4423 
4424  Vcb - Supplies the Vcb being processed
4425 
4426  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4427  be the root dcb
4428 
4429 Return Value:
4430 
4431  NTSTATUS - The result of this operation if it completes without
4432  an exception.
4433 
4434 --*/
4435 
4436 {
4438 
4440 
4441  ULONG NewFileSize = 0;
4442  ULONG InitialFileSize = 0;
4443  ULONG InitialValidDataLength = 0;
4444  ULONG InitialValidDataToDisk = 0;
4445 
4446  BOOLEAN CacheMapInitialized = FALSE;
4447  BOOLEAN UnwindFileSizes = FALSE;
4448  BOOLEAN ResourceAcquired = FALSE;
4449 
4450 
4451  PAGED_CODE();
4452 
4453  DebugTrace(+1, Dbg, "FatSetEndOfFileInfo...\n", 0);
4454 
4455  Buffer = Irp->AssociatedIrp.SystemBuffer;
4456 
4457  _SEH2_TRY {
4458 
4459  //
4460  // File Size changes are only allowed on a file and not a directory
4461  //
4462 
4463  if (NodeType(Fcb) != FAT_NTC_FCB) {
4464 
4465  DebugTrace(0, Dbg, "Cannot change size of a directory\n", 0);
4466 
4468  }
4469 
4470 
4471  //
4472  // Check that the new file size is legal
4473  //
4474 
4475 
4476  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->EndOfFile, 0)) {
4477 
4478  DebugTrace(0, Dbg, "Illegal allocation size\n", 0);
4479 
4481  }
4482 
4483  NewFileSize = Buffer->EndOfFile.LowPart;
4484 
4485 
4486  //
4487  // If we haven't yet looked up the correct AllocationSize, do so.
4488  //
4489 
4490  if ((Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) &&
4491  (Fcb->FcbCondition == FcbGood)) {
4492 
4493  FatLookupFileAllocationSize( IrpContext, Fcb );
4494  }
4495 
4496  //
4497  // This is kinda gross, but if the file is not cached, but there is
4498  // a data section, we have to cache the file to avoid a bunch of
4499  // extra work.
4500  //
4501 
4502  if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
4503  (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
4504  !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
4505 
4506  if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
4507 
4508  //
4509  // This IRP has raced (and lost) with a close (=>cleanup)
4510  // on the same fileobject. We don't want to reinitialise the
4511  // cachemap here now because we'll leak it (unless we do so &
4512  // then tear it down again here, which is too much of a change at
4513  // this stage). So we'll just say the file is closed - which
4514  // is arguably the right thing to do anyway, since a caller
4515  // racing operations in this way is broken. The only stumbling
4516  // block is possibly filters - do they operate on cleaned
4517  // up fileobjects?
4518  //
4519 
4520  FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED);
4521  }
4522 
4523  //
4524  // Now initialize the cache map.
4525  //
4526 
4528  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4529  FALSE,
4531  Fcb );
4532 
4533  CacheMapInitialized = TRUE;
4534  }
4535 
4536  //
4537  // Do a special case here for the lazy write of file sizes.
4538  //
4539 
4540  if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.AdvanceOnly) {
4541 
4542  //
4543  // Only attempt this if the file hasn't been "deleted on close" and
4544  // this is a good FCB.
4545  //
4546 
4547  if (!IsFileDeleted( IrpContext, Fcb ) && (Fcb->FcbCondition == FcbGood)) {
4548 
4549  PDIRENT Dirent = NULL;
4550  PBCB DirentBcb;
4551 
4552 
4553  //
4554  // Never have the dirent filesize larger than the fcb filesize
4555  //
4556 
4557  if (NewFileSize >= Fcb->Header.FileSize.LowPart) {
4558 
4559  NewFileSize = Fcb->Header.FileSize.LowPart;
4560  }
4561 
4562  //
4563  // Make sure we don't set anything higher than the alloc size.
4564  //
4565 
4566 
4567  NT_ASSERT( NewFileSize <= Fcb->Header.AllocationSize.LowPart );
4568 
4569 
4570  //
4571  // Only advance the file size, never reduce it with this call
4572  //
4573 
4574  FatGetDirentFromFcbOrDcb( IrpContext,
4575  Fcb,
4576  FALSE,
4577  &Dirent,
4578  &DirentBcb );
4579  _SEH2_TRY {
4580 
4581 
4582  if ( NewFileSize > Dirent->FileSize ) {
4583  Dirent->FileSize = NewFileSize;
4584 
4585  FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
4586 
4587  //
4588  // Report that we just changed the file size.
4589  //
4590 
4591  FatNotifyReportChange( IrpContext,
4592  Vcb,
4593  Fcb,
4596 
4597  }
4598 
4599  } _SEH2_FINALLY {
4600 
4601  FatUnpinBcb( IrpContext, DirentBcb );
4602  } _SEH2_END;
4603 
4604  } else {
4605 
4606  DebugTrace(0, Dbg, "Cannot set size on deleted file.\n", 0);
4607  }
4608 
4610  }
4611 
4612  //
4613  // Check if the new file size is greater than the current
4614  // allocation size. If it is then we need to increase the
4615  // allocation size.
4616  //
4617 
4618 
4619  if ( (NewFileSize) > Fcb->Header.AllocationSize.LowPart ) {
4620 
4621  //
4622  // Change the file allocation
4623  //
4624 
4625  FatAddFileAllocation( IrpContext, Fcb, FileObject, NewFileSize );
4626  }
4627 
4628 
4629  //
4630  // At this point we have enough allocation for the file.
4631  // So check if we are really changing the file size
4632  //
4633 
4634  if (Fcb->Header.FileSize.LowPart != NewFileSize) {
4635 
4636  if ( NewFileSize < Fcb->Header.FileSize.LowPart ) {
4637 
4638  //
4639  // The way Sections for DataScan are created and used, an AV's
4640  // memory-mapping can come into being after we check it's safe
4641  // to truncate a file while continuing to hold the file here.
4642  // This leads to data corruption because Purge eventually fails
4643  // (during call to Cc to set file sizes) and stale data continues
4644  // to live in the cache/memory.
4645  //
4646 
4647  if (Fcb->PurgeFailureModeEnableCount != 0) {
4648 
4650  }
4651 
4652  //
4653  // Before we actually truncate, check to see if the purge
4654  // is going to fail.
4655  //
4656 
4657  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4658  &Buffer->EndOfFile )) {
4659 
4661  }
4662 
4663  //
4664  // This call is unconditional, because MM always wants to know.
4665  // Also serialize here with paging io since we are truncating
4666  // the file size.
4667  //
4668 
4669  ResourceAcquired =
4670  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4671  }
4672 
4673  //
4674  // Set the new file size
4675  //
4676 
4677  InitialFileSize = Fcb->Header.FileSize.LowPart;
4678  InitialValidDataLength = Fcb->Header.ValidDataLength.LowPart;
4679  InitialValidDataToDisk = Fcb->ValidDataToDisk;
4680  UnwindFileSizes = TRUE;
4681 
4682  Fcb->Header.FileSize.LowPart = NewFileSize;
4683 
4684  //
4685  // If we reduced the file size to less than the ValidDataLength,
4686  // adjust the VDL. Likewise ValidDataToDisk.
4687  //
4688 
4689  if (Fcb->Header.ValidDataLength.LowPart > NewFileSize) {
4690 
4691  Fcb->Header.ValidDataLength.LowPart = NewFileSize;
4692  }
4693 
4694  if (Fcb->ValidDataToDisk > NewFileSize) {
4695 
4697  }
4698 
4699  DebugTrace(0, Dbg, "New file size is 0x%08lx.\n", NewFileSize);
4700 
4701  //
4702  // We must now update the cache mapping (benign if not cached).
4703  //
4704 
4706  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4707 
4708  FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
4709 
4710  //
4711  // Report that we just changed the file size.
4712  //
4713 
4714  FatNotifyReportChange( IrpContext,
4715  Vcb,
4716  Fcb,
4719 
4720  //
4721  // Mark the fact that the file will need to checked for
4722  // truncation on cleanup.
4723  //
4724 
4726  }
4727 
4728  //
4729  // Set this handle as having modified the file
4730  //
4731 
4732  FileObject->Flags |= FO_FILE_MODIFIED;
4733 
4734  //
4735  // Set our return status to success
4736  //
4737 
4739 
4740  try_exit: NOTHING;
4741 
4742  FatUnpinRepinnedBcbs( IrpContext );
4743 
4744  } _SEH2_FINALLY {
4745 
4746  DebugUnwind( FatSetEndOfFileInfo );
4747 
4748  if (_SEH2_AbnormalTermination() && UnwindFileSizes) {
4749 
4750  Fcb->Header.FileSize.LowPart = InitialFileSize;
4751  Fcb->Header.ValidDataLength.LowPart = InitialValidDataLength;
4752  Fcb->ValidDataToDisk = InitialValidDataToDisk;
4753 
4754  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4755 
4756  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4757  }
4758 
4759  //
4760  // WinSE bug #307418 "Occasional data corruption when
4761  // standby/resume while copying files to removable FAT
4762  // formatted media".
4763  // On system suspend FatUnpinRepinnedBcbs() can fail
4764  // because the underlying drive is already marked with DO_VERIFY
4765  // flag. FatUnpinRepinnedBcbs() will raise in this case and
4766  // the file size changes will be un-rolled in FCB but the change
4767  // to Dirent file still can make it to the disk since its BCB
4768  // will not be purged by FatUnpinRepinnedBcbs(). In this case
4769  // we'll also try to un-roll the change to Dirent to keep
4770  // in-memory and on-disk metadata in sync.
4771  //
4772 
4773  FatSetFileSizeInDirentNoRaise( IrpContext, Fcb, NULL );
4774 
4775  }
4776 
4777  if (CacheMapInitialized) {
4778 
4780  }
4781 
4782  if ( ResourceAcquired ) {
4783 
4784  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4785  }
4786 
4787  DebugTrace(-1, Dbg, "FatSetEndOfFileInfo -> %08lx\n", Status);
4788  } _SEH2_END;
4789 
4790  return Status;
4791 }
4792 
4793 
4794 //
4795 // Internal Support Routine
4796 //
4797 
4798 _Requires_lock_held_(_Global_critical_region_)
4799 NTSTATUS
4800 FatSetValidDataLengthInfo (
4801  IN PIRP_CONTEXT IrpContext,
4802  IN PIRP Irp,
4804  IN PFCB Fcb,
4805  IN PCCB Ccb
4806  )
4807 
4808 /*++
4809 
4810 Routine Description:
4811 
4812  This routine performs the set valid data length information for fat. It either
4813  completes the request or enqueues it off to the fsp.
4814 
4815 Arguments:
4816 
4817  Irp - Supplies the irp being processed
4818 
4819  FileObject - Supplies the file object being processed
4820 
4821  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4822  be the root dcb
4823 
4824  Ccb - Supplies the Ccb corresponding to the handle opening the source
4825  file
4826 
4827 Return Value:
4828 
4829  NTSTATUS - The result of this operation if it completes without
4830  an exception.
4831 
4832 --*/
4833 
4834 {
4836 
4838 
4839  ULONG NewValidDataLength;
4840  BOOLEAN ResourceAcquired = FALSE;
4841 
4842  PAGED_CODE();
4843 
4844  UNREFERENCED_PARAMETER( IrpContext );
4845 
4846  DebugTrace(+1, Dbg, "FatSetValidDataLengthInfo...\n", 0);
4847 
4848  Buffer = Irp->AssociatedIrp.SystemBuffer;
4849 
4850  _SEH2_TRY {
4851 
4852  //
4853  // User must have manage volume privilege to explicitly tweak the VDL
4854  //
4855 
4856  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
4857 
4859  }
4860 
4861  //
4862  // Valid data length changes are only allowed on a file and not a directory
4863  //
4864 
4865  if (NodeType(Fcb) != FAT_NTC_FCB) {
4866 
4867  DebugTrace(0, Dbg, "Cannot change VDL of a directory\n", 0);
4868 
4870  }
4871 
4872  //
4873  // Check that the new file size is legal
4874  //
4875 
4876 
4877  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->ValidDataLength, 0)) {
4878 
4879  DebugTrace(0, Dbg, "Illegal allocation size\n", 0);
4880 
4882  }
4883 
4884 
4885  NewValidDataLength = Buffer->ValidDataLength.LowPart;
4886 
4887  //
4888  // VDL can only move forward
4889  //
4890 
4891  if ((NewValidDataLength < Fcb->Header.ValidDataLength.LowPart) ||
4892  (NewValidDataLength > Fcb->Header.FileSize.LowPart)) {
4893 
4895  }
4896 
4897  //
4898  // We can't change the VDL without being able to purge. This should stay
4899  // constant since we own everything exclusive
4900  //
4901 
4902  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4903  &Buffer->ValidDataLength )) {
4904 
4906  }
4907 
4908  //
4909  // Flush old data out and purge the cache so we can see new data.
4910  //
4911 
4912  if (FileObject->SectionObjectPointer->DataSectionObject != NULL) {
4913 
4914  ResourceAcquired =
4915  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4916 
4917  CcFlushCache( FileObject->SectionObjectPointer,
4918  NULL,
4919  0,
4920  &Irp->IoStatus );
4921 
4922  if (!NT_SUCCESS( Irp->IoStatus.Status )) {
4923 
4924  try_return( Irp->IoStatus.Status );
4925  }
4926 
4927  CcPurgeCacheSection( FileObject->SectionObjectPointer,
4928  NULL,
4929  0,
4930  FALSE );
4931  }
4932 
4933  //
4934  // Set the new ValidDataLength, Likewise ValidDataToDisk.
4935  //
4936 
4937  Fcb->Header.ValidDataLength.LowPart = NewValidDataLength;
4938  Fcb->ValidDataToDisk = NewValidDataLength;
4939 
4940  DebugTrace(0, Dbg, "New VDL is 0x%08lx.\n", NewValidDataLength);
4941 
4942  //
4943  // We must now update the cache mapping.
4944  //
4945 
4946  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4947 
4949  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4950  }
4951 
4952  //
4953  // Set this handle as having modified the file
4954  //
4955 
4956  FileObject->Flags |= FO_FILE_MODIFIED;
4957 
4958  //
4959  // Set our return status to success
4960  //
4961 
4963 
4964  try_exit: NOTHING;
4965 
4966  } _SEH2_FINALLY {
4967 
4968  DebugUnwind( FatSetValidDataLengthInfo );
4969 
4970  if (ResourceAcquired) {
4971 
4972  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4973  }
4974 
4975  DebugTrace(-1, Dbg, "FatSetValidDataLengthInfo -> %08lx\n", Status);
4976  } _SEH2_END;
4977 
4978  return Status;
4979 }
4980 
4981 
4982 
4983 //
4984 // Internal Support Routine
4985 //
4986 
4987 _Requires_lock_held_(_Global_critical_region_)
4988 VOID
4989 FatRenameEAs (
4990  IN PIRP_CONTEXT IrpContext,
4991  IN PFCB Fcb,
4992  IN USHORT ExtendedAttributes,
4993  IN POEM_STRING OldOemName
4994  )
4995 {
4996  BOOLEAN LockedEaFcb = FALSE;
4997 
4998  PBCB EaBcb = NULL;
4999  PDIRENT EaDirent;
5001  PEA_SET_HEADER EaSetHeader;
5002 
5003  PVCB Vcb;
5004 
5005  PAGED_CODE();
5006 
5007  RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
5008 
5009  Vcb = Fcb->Vcb;
5010 
5011  _SEH2_TRY {
5012 
5013  //
5014  // Use a try-except to catch any errors.
5015  //
5016 
5017  _SEH2_TRY {
5018 
5019 
5020  //
5021  // Try to get the Ea file object. Return FALSE on failure.
5022  //
5023 
5024  FatGetEaFile( IrpContext,
5025  Vcb,
5026  &EaDirent,
5027  &EaBcb,
5028  FALSE,
5029  FALSE );
5030 
5031  LockedEaFcb = TRUE;
5032 
5033  //
5034  // If we didn't get the file because it doesn't exist, then the
5035  // disk is corrupted. We do nothing here.
5036  //
5037 
5038  if (Vcb->VirtualEaFile != NULL) {
5039 
5040  //
5041  // Try to pin down the Ea set header for the index in the
5042  // dirent. If the operation doesn't complete, return FALSE
5043  // from this routine.
5044  //
5045 
5046  FatReadEaSet( IrpContext,
5047  Vcb,
5048  ExtendedAttributes,
5049  OldOemName,
5050  FALSE,
5051  &EaSetRange );
5052 
5053  EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
5054 
5055  //
5056  // We now have the Ea set header for this file. We simply
5057  // overwrite the owning file name.
5058  //
5059 
5060  RtlZeroMemory( EaSetHeader->OwnerFileName, 14 );
5061 
5062  RtlCopyMemory( EaSetHeader->OwnerFileName,
5063  Fcb->ShortName.Name.Oem.Buffer,
5064  Fcb->ShortName.Name.Oem.Length );
5065 
5066  FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange );
5067  FatUnpinEaRange( IrpContext, &EaSetRange );
5068 
5069  CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
5070  }
5071 
5073 
5074  //
5075  // We catch all exceptions that Fat catches, but don't do
5076  // anything with them.
5077  //
5078  } _SEH2_END;
5079 
5080  } _SEH2_FINALLY {
5081 
5082  //
5083  // Unpin the EaDirent and the EaSetHeader if pinned.
5084  //
5085 
5086  FatUnpinBcb( IrpContext, EaBcb );
5087  FatUnpinEaRange( IrpContext, &EaSetRange );
5088 
5089  //
5090  // Release the Fcb for the Ea file if locked.
5091  //
5092 
5093  if (LockedEaFcb) {
5094 
5095  FatReleaseFcb( IrpContext, Vcb->EaFcb );
5096  }
5097  } _SEH2_END;
5098 
5099  return;
5100 }
5101 
5102 _Requires_lock_held_(_Global_critical_region_)
5103 VOID
5104 FatDeleteFile (
5105  IN PIRP_CONTEXT IrpContext,
5106  IN PDCB TargetDcb,
5107  IN ULONG LfnOffset,
5109  IN PDIRENT Dirent,
5111  )
5112 {
5113  PFCB Fcb;
5114  PLIST_ENTRY Links;
5115 
5116  PAGED_CODE();
5117 
5118  //
5119  // We can do the replace by removing the other Fcb(s) from
5120  // the prefix table.
5121  //
5122 
5123  for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
5124  Links != &TargetDcb->Specific.Dcb.ParentDcbQueue;
5125  Links = Links->Flink) {
5126 
5127  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
5128 
5131 
5134 
5135  if ( Fcb->UncleanCount != 0 ) {
5136 
5137 #ifdef _MSC_VER
5138 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5139 #endif
5140  FatBugCheck(0,0,0);
5141 
5142  } else {
5143 
5145 
5146  //
5147  // Make this fcb "appear" deleted, synchronizing with
5148  // paging IO.
5149  //
5150 
5151  FatRemoveNames( IrpContext, Fcb );
5152 
5153  Resource = Fcb->Header.PagingIoResource;
5154 
5156 
5158 
5159  Fcb->ValidDataToDisk = 0;
5160  Fcb->Header.FileSize.QuadPart =
5161  Fcb->Header.ValidDataLength.QuadPart = 0;
5162 
5163  Fcb->FirstClusterOfFile = 0;
5164 
5166  }
5167  }
5168  }
5169 
5170  //
5171  // The file is not currently opened so we can delete the file
5172  // that is being overwritten. To do the operation we dummy
5173  // up an fcb, truncate allocation, delete the fcb, and delete
5174  // the dirent.
5175  //
5176 
5177  Fcb = FatCreateFcb( IrpContext,
5178  TargetDcb->Vcb,
5179  TargetDcb,
5180  LfnOffset,
5181  DirentOffset,
5182  Dirent,
5183  Lfn,
5184  NULL,
5185  FALSE,
5186  FALSE );
5187 
5188  Fcb->Header.FileSize.LowPart = 0;
5189 
5190  _SEH2_TRY {
5191 
5192  FatTruncateFileAllocation( IrpContext, Fcb, 0 );
5193 
5194  FatDeleteDirent( IrpContext, Fcb, NULL, TRUE );
5195 
5196  } _SEH2_FINALLY {
5197 
5198  FatDeleteFcb( IrpContext, &Fcb );
5199  } _SEH2_END;
5200 }
5201 
5202 
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING IN PUNICODE_STRING SuggestedShortName IN OUT BOOLEAN IN OUT BOOLEAN * AllLowerExtension
Definition: fatprocs.h:1294
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING ShortName
Definition: fatprocs.h:1294
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
VOID FatConstructDirent(IN PIRP_CONTEXT IrpContext, IN OUT PDIRENT Dirent, IN POEM_STRING FileName, IN BOOLEAN ComponentReallyLowercase, IN BOOLEAN ExtensionReallyLowercase, IN PUNICODE_STRING Lfn OPTIONAL, IN USHORT Attributes, IN BOOLEAN ZeroAndSetTimeFields, IN PLARGE_INTEGER SetCreationTime OPTIONAL)
Definition: dirsup.c:2171
#define DbgDoit(X)
Definition: fatdata.h:336
LONGLONG CreationTime
Definition: cdstruc.h:1036
VOID FatConstructNamesInFcb(IN PIRP_CONTEXT IrpContext, PFCB Fcb, PDIRENT Dirent, PUNICODE_STRING Lfn OPTIONAL)
Definition: strucsup.c:3021
BOOLEAN NTAPI MmCanFileBeTruncated(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize)
Definition: section.c:4724
LARGE_INTEGER LastWriteTime
Definition: fatstruc.h:921
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:384
#define IN
Definition: typedefs.h:38
struct _FILE_INTERNAL_INFORMATION FILE_INTERNAL_INFORMATION
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define TenMSec
Definition: fatdata.h:122
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2983
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define FILE_ATTRIBUTE_TEMPORARY
Definition: nt_native.h:708
FILE_POSITION_INFORMATION PositionInformation
Definition: winternl.h:801
#define FsRtlEnterFileSystem
BOOLEAN FatIsIrpTopLevel(IN PIRP Irp)
Definition: fatdata.c:817
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:402
#define FCB_LOOKUP_ALLOCATIONSIZE_HINT
Definition: fatstruc.h:1240
#define FILE_ACTION_RENAMED_OLD_NAME
PVOID NTAPI FsRtlAllocatePoolWithTag(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes, IN ULONG Tag)
Definition: filter.c:229
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING IN PUNICODE_STRING SuggestedShortName IN OUT BOOLEAN * AllLowerComponent
Definition: fatprocs.h:1294
LARGE_INTEGER FatFatDateToNtTime(_In_ PIRP_CONTEXT IrpContext, _In_ FAT_DATE FatDate)
Definition: timesup.c:171
VOID FatUnicodeToUpcaseOem(IN PIRP_CONTEXT IrpContext, IN POEM_STRING OemString, IN PUNICODE_STRING UnicodeString)
Definition: namesup.c:632
VOID NTAPI CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:222
#define VCB_STATE_FLAG_DEFERRED_FLUSH
Definition: fatstruc.h:567
#define FsRtlExitFileSystem
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
USHORT MaximumLength
Definition: env_spec_w32.h:370
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks
Definition: fatstruc.h:158
#define FatCompleteRequest(IRPCONTEXT, IRP, STATUS)
Definition: fatprocs.h:2621
VOID NTAPI FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
Definition: notify.c:1458
#define STATUS_DIRECTORY_NOT_EMPTY
Definition: udferr_usr.h:167
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING Lfn
Definition: create.c:4157
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
Definition: cdstruc.h:908
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
uint16_t * PWSTR
Definition: typedefs.h:54
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
VOID NTAPI CcSetDirtyPinnedData(IN PVOID BcbVoid, IN OPTIONAL PLARGE_INTEGER Lsn)
Definition: cachesub.c:121
union _FCB::@694 LongName
LARGE_INTEGER FatLargeZero
Definition: fatdata.c:62
#define DPFLTR_INFO_LEVEL
Definition: kdtypes.h:33
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
Definition: cdstruc.h:1073
unsigned char * PUCHAR
Definition: retypes.h:3
Dirent DirentOffset
Definition: dirsup.c:444
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2156
BOOLEAN ContainsWildCards
Definition: fatstruc.h:1374
VOID FatMarkEaRangeDirty(IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT EaFileObject, IN OUT PEA_RANGE EaRange)
Definition: easup.c:3709
VOID NTAPI FatOplockComplete(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:35
LONG NTSTATUS
Definition: precomp.h:26
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
VOID FatReadVolumeFile(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer)
Definition: cachesup.c:102
VOID NTAPI CcUnpinData(IN PVOID Bcb)
Definition: pinsup.c:955
#define FCB_STATE_TEMPORARY
Definition: fatstruc.h:1197
VOID FatUnpinEaRange(IN PIRP_CONTEXT IrpContext, IN OUT PEA_RANGE EaRange)
Definition: easup.c:3782
union _FILE_NAME_NODE::@692 Name
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
UNICODE_STRING UnicodeQueryTemplate
Definition: fatstruc.h:1425
Definition: cdstruc.h:504
#define FAT_DIRENT_ATTR_READ_ONLY
Definition: fat.h:368
#define FILE_NOTIFY_CHANGE_SIZE
NTSTATUS NTAPI RtlOemStringToCountedUnicodeString(IN OUT PUNICODE_STRING UniDest, IN PCOEM_STRING OemSource, IN BOOLEAN AllocateDestinationString)
Definition: unicode.c:1463
struct _FILE_EA_INFORMATION FILE_EA_INFORMATION
PVPB Vpb
Definition: cdstruc.h:517
#define FILE_NOTIFY_CHANGE_LAST_WRITE
VOID FatQueryPositionInfo(IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN OUT PFILE_POSITION_INFORMATION Buffer, IN OUT PLONG Length)
Definition: fileinfo.c:1417
#define FAT_DIRENT_ATTR_DIRECTORY
Definition: fat.h:372
#define FILE_NOTIFY_CHANGE_FILE_NAME
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: fatstruc.h:728
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
static OUT PIO_STATUS_BLOCK OUT PVOID IN ULONG IN FILE_INFORMATION_CLASS FileInformationClass
Definition: pipe.c:75
VOID FatQueryInternalInfo(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_INTERNAL_INFORMATION Buffer, IN OUT PLONG Length)
Definition: fileinfo.c:1242
BOOLEAN ChicagoMode
Definition: fatstruc.h:86
struct _FILE_ACCESS_INFORMATION FILE_ACCESS_INFORMATION
#define TwoSeconds
Definition: fatdata.h:123
uint16_t * PWCHAR
Definition: typedefs.h:54
#define FO_NO_INTERMEDIATE_BUFFERING
Definition: iotypes.h:1735
STRING OEM_STRING
Definition: umtypes.h:203
LIST_ENTRY ParentDcbLinks
Definition: fatstruc.h:827
ULONG VcbState
Definition: cdstruc.h:546
#define InsertTailList(ListHead, Entry)
CLONG PurgeFailureModeEnableCount
Definition: fatstruc.h:895
struct _FILE_POSITION_INFORMATION FILE_POSITION_INFORMATION
#define FatRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2965
#define FILE_NOTIFY_CHANGE_DIR_NAME
struct _FCB * ParentDcb
Definition: fatstruc.h:835
#define CCB_FLAG_MANAGE_VOLUME_ACCESS
Definition: fatstruc.h:1337
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define PAGED_CODE()
Definition: video.h:57
_In_ UINT _In_ UINT BytesToCopy
Definition: ndis.h:3167
struct _FILE_NETWORK_OPEN_INFORMATION FILE_NETWORK_OPEN_INFORMATION
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
#define FatDirectoryKey(FcbOrDcb)
Definition: fatprocs.h:841
_SEH2_TRY
Definition: create.c:4250
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2401
#define KdPrintEx(_x_)
Definition: kdfuncs.h:114
#define CCB_FLAG_OPENED_BY_SHORTNAME
Definition: fatstruc.h:1295
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
IN OUT PVCB OUT PDIRENT * EaDirent
Definition: fatprocs.h:904
#define FatReservedBytes(B)
Definition: fat.h:414
#define CCB_FLAG_USER_SET_CREATION
Definition: fatstruc.h:1267
VOID FatReadEaSet(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN USHORT EaHandle, IN POEM_STRING FileName, IN BOOLEAN ReturnEntireSet, OUT PEA_RANGE EaSetRange)
Definition: easup.c:1306
IN PDCB IN ULONG LfnOffset
Definition: fatprocs.h:779
NTSTATUS FatSetPositionInfo(IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFILE_OBJECT FileObject)
Definition: fileinfo.c:4026
#define FO_FILE_MODIFIED
Definition: iotypes.h:1745
_Function_class_(FAST_IO_QUERY_BASIC_INFO)
Definition: fileinfo.c:465
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:593
#define CCB_FLAG_SKIP_SHORT_NAME_COMPARE
Definition: fatstruc.h:1252
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
LARGE_INTEGER FatFatTimeToNtTime(_In_ PIRP_CONTEXT IrpContext, _In_ FAT_TIME_STAMP FatTime, _In_ UCHAR TenMilliSeconds)
Definition: timesup.c:233
LARGE_INTEGER LastAccessTime
Definition: fatstruc.h:920
ERESOURCE * PERESOURCE
Definition: env_spec_w32.h:595
#define FCB_STATE_NAMES_IN_SPLAY_TREE
Definition: fatstruc.h:1199
VOID FatSetFullNameInFcb(_In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB Fcb, _In_ PUNICODE_STRING FinalName)
Definition: create.c:6758
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:848
Definition: Header.h:8
BOOLEAN NTAPI FsRtlFindInTunnelCache(IN PTUNNEL Cache, IN ULONGLONG DirectoryKey, IN PUNICODE_STRING Name, OUT PUNICODE_STRING ShortName, OUT PUNICODE_STRING LongName, IN OUT PULONG DataLength, OUT PVOID Data)
Definition: tunnel.c:765
#define FCB_STATE_PAGING_FILE
Definition: fatstruc.h:1194
long LONG
Definition: pedump.c:60
LARGE_INTEGER FatJanOne1980
Definition: fatdata.c:73
#define FAT_LFN_DIRENTS_NEEDED(NAME)
Definition: lfn.h:53
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1647
static INLINE BOOLEAN FatIsIoRangeValid(IN PVCB Vcb, IN LARGE_INTEGER Start, IN ULONG Length)
Definition: fatprocs.h:209
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define FatBytesPerFat(B)
Definition: fat.h:410
#define FILE_ACTION_MODIFIED
UCHAR DirentFatFlags
Definition: fatstruc.h:1132
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
union _FCB::@693 Specific
PNON_PAGED_FCB NonPaged
Definition: fatstruc.h:810
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:537
FAT_TIME_STAMP FatTimeJanOne1980
Definition: fatdata.c:83
VOID FatEvaluateNameCase(IN PIRP_CONTEXT IrpContext, IN PUNICODE_STRING Name, IN OUT BOOLEAN *AllLowerComponent, IN OUT BOOLEAN *AllLowerExtension, IN OUT BOOLEAN *CreateLfn)
Definition: namesup.c:891
unsigned char BOOLEAN
#define IsFileDeleted(Mcb)
Definition: ext2fs.h:959
smooth NULL
Definition: ftsmooth.c:416
#define FILE_ACTION_REMOVED
FILE_NAME_NODE Unicode
Definition: fatstruc.h:1165
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:13
ULONG Flags
Definition: cdstruc.h:1086
UCHAR OwnerFileName[14]
Definition: fat.h:667
Definition: bufpool.h:45
#define Dbg
Definition: fileinfo.c:29
#define VCB_STATE_FLAG_REMOVABLE_MEDIA
Definition: fatstruc.h:559
#define STATUS_USER_MAPPED_FILE
Definition: ntstatus.h:697
IN PDCB TargetDcb
Definition: fatprocs.h:779
NodeType
Definition: Node.h:5
#define FCB_STATE_TRUNCATE_ON_CLOSE
Definition: fatstruc.h:1193
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
PIRP_CONTEXT FatCreateIrpContext(IN PIRP Irp, IN BOOLEAN Wait)
Definition: strucsup.c:2300
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define FILE_NOTIFY_CHANGE_CREATION
#define ExSystemTimeToLocalTime(SysTime, LocTime)
Definition: env_spec_w32.h:729
struct _FCB::@693::@695 Dcb
OEM_STRING Oem
Definition: fatstruc.h:692
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define PCHAR
Definition: match.c:90
VOID FatRemoveNames(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb)
Definition: splaysup.c:222
#define NTDDI_VERSION
Definition: k32.h:33
enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS
Definition: directory.c:44
VOID FatQueryBasicInfo(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PFILE_OBJECT FileObject, IN OUT PFILE_BASIC_INFORMATION Buffer, IN OUT PLONG Length)
Definition: fileinfo.c:1044
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
BOOLEAN NTAPI FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1, IN PCUNICODE_STRING Name2, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
Definition: name.c:296
#define FatIsNameShortOemValid(IRPCONTEXT, NAME, CAN_CONTAIN_WILD_CARDS, PATH_NAME_OK, LEADING_BACKSLASH_OK)
Definition: fatprocs.h:1189
#define DebugUnwind(X)
Definition: fatdata.h:315
FAT_DATA FatData
Definition: fatdata.c:56
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1635
VOID FatDeleteFcb(IN PIRP_CONTEXT IrpContext, IN PFCB *Fcb)
Definition: strucsup.c:1951
if(!(yy_init))
Definition: macro.lex.yy.c:714
VOID NTAPI CcUnpinRepinnedBcb(IN PVOID Bcb, IN BOOLEAN WriteThrough, OUT PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:343
#define FCB_STATE_DELETE_ON_CLOSE
Definition: fatstruc.h:1192
__wchar_t WCHAR
Definition: xmlstorage.h:180
return Iosb
Definition: create.c:4426
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
LARGE_INTEGER FatDecThirtyOne1979
Definition: fatdata.c:74
BOOLEAN NTAPI MmFlushImageSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN MMFLUSH_TYPE FlushType)
Definition: section.c:4798
#define try_return(S)
Definition: cdprocs.h:2189
PFCB FatCreateFcb(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PDCB ParentDcb, IN ULONG LfnOffsetWithinDirectory, IN ULONG DirentOffsetWithinDirectory, IN PDIRENT Dirent, IN PUNICODE_STRING Lfn OPTIONAL, IN PUNICODE_STRING OrigLfn OPTIONAL, IN BOOLEAN IsPagingFile, IN BOOLEAN SingleResource)
Definition: strucsup.c:1238
struct _DEVICE_OBJECT * RealDevice
Definition: iotypes.h:172
VBO LfnOffsetWithinDirectory
Definition: fatstruc.h:912
IN PVCB IN ULONG IN PBCB OUT PDIRENT OUT PUSHORT OUT PEA_RANGE EaSetRange
Definition: fatprocs.h:936
#define Vcb
Definition: cdprocs.h:1425
struct _FILE_ALIGNMENT_INFORMATION FILE_ALIGNMENT_INFORMATION
#define CcGetFileSizePointer(FO)
Definition: ccfuncs.h:389
#define MAX_LFN_CHARACTERS
Definition: lfn.h:50
#define NTDDI_WIN7
Definition: sdkddkver.h:112
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FatIsFileOplockable(F)
Definition: fatprocs.h:2839
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:2867
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:244
union _CCB::@697::@699::@701 OemQueryTemplate
#define TAG_FILENAME_BUFFER
Definition: nodetype.h:167
#define STATUS_PURGE_FAILED
Definition: ntstatus.h:950