ReactOS  0.4.15-dev-1070-ge1a01de
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  FAT_TIME_STAMP CreationTime = {0};
1953  UCHAR CreationMSec = 0;
1954  FAT_TIME_STAMP LastWriteTime = {0};
1955  FAT_TIME_STAMP LastAccessTime = {0};
1956  FAT_DATE LastAccessDate = {0};
1957  UCHAR Attributes;
1958 
1959  BOOLEAN ModifyCreation = FALSE;
1960  BOOLEAN ModifyLastWrite = FALSE;
1961  BOOLEAN ModifyLastAccess = FALSE;
1962 
1963 #if (NTDDI_VERSION >= NTDDI_WIN8)
1964  BOOLEAN ModifiedAttributes = FALSE;
1965 #endif
1966 
1967  LARGE_INTEGER LargeCreationTime = {0};
1968  LARGE_INTEGER LargeLastWriteTime = {0};
1969  LARGE_INTEGER LargeLastAccessTime = {0};
1970 
1971  ULONG NotifyFilter = 0;
1972 
1973  PAGED_CODE();
1974 
1975  DebugTrace(+1, Dbg, "FatSetBasicInfo...\n", 0);
1976 
1977  Buffer = Irp->AssociatedIrp.SystemBuffer;
1978 
1979  //
1980  // If the user is specifying -1 for a field, that means
1981  // we should leave that field unchanged, even if we might
1982  // have otherwise set it ourselves. We'll set the Ccb flag
1983  // saying that the user set the field so that we
1984  // don't do our default updating.
1985  //
1986  // We set the field to 0 then so we know not to actually
1987  // set the field to the user-specified (and in this case,
1988  // illegal) value.
1989  //
1990 
1991  if (Buffer->LastWriteTime.QuadPart == -1) {
1992 
1994  Buffer->LastWriteTime.QuadPart = 0;
1995  }
1996 
1997  if (Buffer->LastAccessTime.QuadPart == -1) {
1998 
2000  Buffer->LastAccessTime.QuadPart = 0;
2001  }
2002 
2003  if (Buffer->CreationTime.QuadPart == -1) {
2004 
2006  Buffer->CreationTime.QuadPart = 0;
2007  }
2008 
2009  DirentBcb = NULL;
2010 
2012 
2013  _SEH2_TRY {
2014 
2015  LARGE_INTEGER FatLocalDecThirtyOne1979;
2016  LARGE_INTEGER FatLocalJanOne1980;
2017 
2019  &FatLocalDecThirtyOne1979 );
2020 
2022  &FatLocalJanOne1980 );
2023 
2024  //
2025  // Get a pointer to the dirent
2026  //
2027 
2029 
2030  FatGetDirentFromFcbOrDcb( IrpContext,
2031  Fcb,
2032  FALSE,
2033  &Dirent,
2034  &DirentBcb );
2035  //
2036  // Check if the user specified a non-zero creation time
2037  //
2038 
2039  if (FatData.ChicagoMode && (Buffer->CreationTime.QuadPart != 0)) {
2040 
2041  LargeCreationTime = Buffer->CreationTime;
2042 
2043  //
2044  // Convert the Nt time to a Fat time
2045  //
2046 
2047  if ( !FatNtTimeToFatTime( IrpContext,
2048  &LargeCreationTime,
2049  FALSE,
2050  &CreationTime,
2051  &CreationMSec )) {
2052 
2053  //
2054  // Special case the value 12/31/79 and treat this as 1/1/80.
2055  // This '79 value can happen because of time zone issues.
2056  //
2057 
2058  if ((LargeCreationTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2059  (LargeCreationTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2060 
2061  CreationTime = FatTimeJanOne1980;
2062  LargeCreationTime = FatLocalJanOne1980;
2063 
2064  } else {
2065 
2066  DebugTrace(0, Dbg, "Invalid CreationTime\n", 0);
2068  }
2069 
2070  //
2071  // Don't worry about CreationMSec
2072  //
2073 
2074  CreationMSec = 0;
2075  }
2076 
2077  ModifyCreation = TRUE;
2078  }
2079 
2080  //
2081  // Check if the user specified a non-zero last access time
2082  //
2083 
2084  if (FatData.ChicagoMode && (Buffer->LastAccessTime.QuadPart != 0)) {
2085 
2086  LargeLastAccessTime = Buffer->LastAccessTime;
2087 
2088  //
2089  // Convert the Nt time to a Fat time
2090  //
2091 
2092  if ( !FatNtTimeToFatTime( IrpContext,
2093  &LargeLastAccessTime,
2094  TRUE,
2095  &LastAccessTime,
2096  NULL )) {
2097 
2098  //
2099  // Special case the value 12/31/79 and treat this as 1/1/80.
2100  // This '79 value can happen because of time zone issues.
2101  //
2102 
2103  if ((LargeLastAccessTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2104  (LargeLastAccessTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2105 
2106  LastAccessTime = FatTimeJanOne1980;
2107  LargeLastAccessTime = FatLocalJanOne1980;
2108 
2109  } else {
2110 
2111  DebugTrace(0, Dbg, "Invalid LastAccessTime\n", 0);
2113  }
2114  }
2115 
2116  LastAccessDate = LastAccessTime.Date;
2117  ModifyLastAccess = TRUE;
2118  }
2119 
2120  //
2121  // Check if the user specified a non-zero last write time
2122  //
2123 
2124  if (Buffer->LastWriteTime.QuadPart != 0) {
2125 
2126  //
2127  // First do a quick check here if the this time is the same
2128  // time as LastAccessTime.
2129  //
2130 
2131  if (ModifyLastAccess &&
2132  (Buffer->LastWriteTime.QuadPart == Buffer->LastAccessTime.QuadPart)) {
2133 
2134  ModifyLastWrite = TRUE;
2135  LastWriteTime = LastAccessTime;
2136  LargeLastWriteTime = LargeLastAccessTime;
2137 
2138  } else {
2139 
2140  LargeLastWriteTime = Buffer->LastWriteTime;
2141 
2142  //
2143  // Convert the Nt time to a Fat time
2144  //
2145 
2146  if ( !FatNtTimeToFatTime( IrpContext,
2147  &LargeLastWriteTime,
2148  TRUE,
2149  &LastWriteTime,
2150  NULL )) {
2151 
2152 
2153  //
2154  // Special case the value 12/31/79 and treat this as 1/1/80.
2155  // This '79 value can happen because of time zone issues.
2156  //
2157 
2158  if ((LargeLastWriteTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
2159  (LargeLastWriteTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
2160 
2161  LastWriteTime = FatTimeJanOne1980;
2162  LargeLastWriteTime = FatLocalJanOne1980;
2163 
2164  } else {
2165 
2166  DebugTrace(0, Dbg, "Invalid LastWriteTime\n", 0);
2168  }
2169  }
2170 
2171  ModifyLastWrite = TRUE;
2172  }
2173  }
2174 
2175 
2176  //
2177  // Check if the user specified a non zero file attributes byte
2178  //
2179 
2180  if (Buffer->FileAttributes != 0) {
2181 
2182  //
2183  // Only permit the attributes that FAT understands. The rest are silently
2184  // dropped on the floor.
2185  //
2186 
2187  Attributes = (UCHAR)(Buffer->FileAttributes & (FILE_ATTRIBUTE_READONLY |
2192 
2193  //
2194  // Make sure that for a file the directory bit is not set
2195  // and that for a directory the bit is set.
2196  //
2197 
2198  if (NodeType(Fcb) == FAT_NTC_FCB) {
2199 
2200  if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
2201 
2202  DebugTrace(0, Dbg, "Attempt to set dir attribute on file\n", 0);
2204  }
2205 
2206  } else {
2207 
2209  }
2210 
2211  //
2212  // Mark the FcbState temporary flag correctly.
2213  //
2214 
2215  if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY)) {
2216 
2217  //
2218  // Don't allow the temporary bit to be set on directories.
2219  //
2220 
2221  if (NodeType(Fcb) == FAT_NTC_DCB) {
2222 
2223  DebugTrace(0, Dbg, "No temporary directories\n", 0);
2225  }
2226 
2228 
2231 
2232  } else {
2233 
2235 
2238  }
2239 
2240  //
2241  // Now, only proceed if the requested file attributes are different
2242  // than the existing attributes.
2243  //
2244 
2245  if (Dirent->Attributes != Attributes) {
2246 
2247  //
2248  // Set the new attributes byte, and mark the bcb dirty
2249  //
2250 
2252 
2253  Dirent->Attributes = Attributes;
2254 
2256 
2257 #if (NTDDI_VERSION >= NTDDI_WIN8)
2258  ModifiedAttributes = TRUE;
2259 #endif
2260  }
2261  }
2262 
2263  if ( ModifyCreation ) {
2264 
2265  //
2266  // Set the new last write time in the dirent, and mark
2267  // the bcb dirty
2268  //
2269 
2270  Fcb->CreationTime = LargeCreationTime;
2271  Dirent->CreationTime = CreationTime;
2272  Dirent->CreationMSec = CreationMSec;
2273 
2274 
2276  //
2277  // Now we have to round the time in the Fcb up to the
2278  // nearest tem msec.
2279  //
2280 
2281  Fcb->CreationTime.QuadPart =
2282 
2283  ((Fcb->CreationTime.QuadPart + AlmostTenMSec) /
2284  TenMSec) * TenMSec;
2285 
2286  //
2287  // Now because the user just set the creation time we
2288  // better not set the creation time on close
2289  //
2290 
2292  }
2293 
2294  if ( ModifyLastAccess ) {
2295 
2296  //
2297  // Set the new last write time in the dirent, and mark
2298  // the bcb dirty
2299  //
2300 
2301  Fcb->LastAccessTime = LargeLastAccessTime;
2302  Dirent->LastAccessDate = LastAccessDate;
2303 
2305 
2306  //
2307  // Now we have to truncate the time in the Fcb down to the
2308  // current day. This has to be in LocalTime though, so first
2309  // convert to local, trunacate, then set back to GMT.
2310  //
2311 
2313  &Fcb->LastAccessTime );
2314 
2316 
2319 
2321  &Fcb->LastAccessTime );
2322 
2323  //
2324  // Now because the user just set the last access time we
2325  // better not set the last access time on close
2326  //
2327 
2329  }
2330 
2331  if ( ModifyLastWrite ) {
2332 
2333  //
2334  // Set the new last write time in the dirent, and mark
2335  // the bcb dirty
2336  //
2337 
2338  Fcb->LastWriteTime = LargeLastWriteTime;
2339  Dirent->LastWriteTime = LastWriteTime;
2340 
2342 
2343  //
2344  // Now we have to round the time in the Fcb up to the
2345  // nearest two seconds.
2346  //
2347 
2349 
2352 
2353  //
2354  // Now because the user just set the last write time we
2355  // better not set the last write time on close
2356  //
2357 
2359  }
2360 
2361  //
2362  // If we modified any of the values, we report this to the notify
2363  // package.
2364  //
2365  // We also take this opportunity to set the current file size and
2366  // first cluster in the Dirent in order to support a server hack.
2367  //
2368 
2369  if (NotifyFilter != 0) {
2370 
2371  if (NodeType(Fcb) == FAT_NTC_FCB) {
2372 
2373  Dirent->FileSize = Fcb->Header.FileSize.LowPart;
2374 
2375 
2377 
2378  if (FatIsFat32(Fcb->Vcb)) {
2379 
2380  Dirent->FirstClusterOfFileHi =
2381  (USHORT)(Fcb->FirstClusterOfFile >> 16);
2382  }
2383  }
2384 
2385  FatNotifyReportChange( IrpContext,
2386  Fcb->Vcb,
2387  Fcb,
2388  NotifyFilter,
2390 
2391  FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
2392  }
2393 
2394 #if (NTDDI_VERSION >= NTDDI_WIN8)
2395  //
2396  // If last-access, last-write, or any attribute bits changed, break
2397  // parent directory oplock.
2398  //
2399 
2400  if ((Fcb->ParentDcb != NULL) &&
2401  (ModifyLastAccess ||
2402  ModifyLastWrite ||
2403  ModifiedAttributes)) {
2404 
2405  FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb),
2406  IrpContext->OriginatingIrp,
2407  OPLOCK_FLAG_PARENT_OBJECT,
2408  NULL,
2409  NULL,
2410  NULL );
2411  }
2412 #endif
2413 
2414  try_exit: NOTHING;
2415  } _SEH2_FINALLY {
2416 
2417  DebugUnwind( FatSetBasicInfo );
2418 
2419  FatUnpinBcb( IrpContext, DirentBcb );
2420 
2421  DebugTrace(-1, Dbg, "FatSetBasicInfo -> %08lx\n", Status);
2422  } _SEH2_END;
2423 
2424  return Status;
2425 }
2426 
2427 //
2428 // Internal Support Routine
2429 //
2430 
2431 _Requires_lock_held_(_Global_critical_region_)
2432 NTSTATUS
2433 FatSetDispositionInfo (
2434  IN PIRP_CONTEXT IrpContext,
2435  IN PIRP Irp,
2437  IN PFCB Fcb
2438  )
2439 
2440 /*++
2441 
2442 Routine Description:
2443 
2444  This routine performs the set disposition information for fat. It either
2445  completes the request or enqueues it off to the fsp.
2446 
2447 Arguments:
2448 
2449  Irp - Supplies the irp being processed
2450 
2451  FileObject - Supplies the file object being processed
2452 
2453  Fcb - Supplies the Fcb or Dcb being processed, already known not to
2454  be the root dcb
2455 
2456 Return Value:
2457 
2458  NTSTATUS - The result of this operation if it completes without
2459  an exception.
2460 
2461 --*/
2462 
2463 {
2465  PBCB Bcb;
2466  PDIRENT Dirent;
2467 
2468  PAGED_CODE();
2469 
2470  DebugTrace(+1, Dbg, "FatSetDispositionInfo...\n", 0);
2471 
2472  Buffer = Irp->AssociatedIrp.SystemBuffer;
2473 
2474  //
2475  // Check if the user wants to delete the file or not delete
2476  // the file
2477  //
2478 
2479  if (Buffer->DeleteFile) {
2480 
2481  //
2482  // Check if the file is marked read only
2483  //
2484 
2486 
2487  DebugTrace(-1, Dbg, "Cannot delete readonly file\n", 0);
2488 
2489  return STATUS_CANNOT_DELETE;
2490  }
2491 
2492  //
2493  // Make sure there is no process mapping this file as an image.
2494  //
2495 
2497  MmFlushForDelete )) {
2498 
2499  DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);
2500 
2501  return STATUS_CANNOT_DELETE;
2502  }
2503 
2504  //
2505  // Check if this is a dcb and if so then only allow
2506  // the request if the directory is empty.
2507  //
2508 
2509  if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
2510 
2511  DebugTrace(-1, Dbg, "Cannot delete root Directory\n", 0);
2512 
2513  return STATUS_CANNOT_DELETE;
2514  }
2515 
2516  if (NodeType(Fcb) == FAT_NTC_DCB) {
2517 
2518  DebugTrace(-1, Dbg, "User wants to delete a directory\n", 0);
2519 
2520  //
2521  // Check if the directory is empty
2522  //
2523 
2524  if ( !FatIsDirectoryEmpty(IrpContext, Fcb) ) {
2525 
2526  DebugTrace(-1, Dbg, "Directory is not empty\n", 0);
2527 
2529  }
2530  }
2531 
2532  //
2533  // If this is a floppy, touch the volume so to verify that it
2534  // is not write protected.
2535  //
2536 
2537  if ( FlagOn(Fcb->Vcb->Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2538 
2539  PVCB Vcb;
2540  PBCB LocalBcb = NULL;
2541  UCHAR *LocalBuffer;
2542  UCHAR TmpChar;
2543  ULONG BytesToMap;
2544 
2546 
2547  Vcb = Fcb->Vcb;
2548 
2549  BytesToMap = Vcb->AllocationSupport.FatIndexBitSize == 12 ?
2550  FatReservedBytes(&Vcb->Bpb) +
2551  FatBytesPerFat(&Vcb->Bpb):PAGE_SIZE;
2552 
2553  FatReadVolumeFile( IrpContext,
2554  Vcb,
2555  0,
2556  BytesToMap,
2557  &LocalBcb,
2558  (PVOID *)&LocalBuffer );
2559 
2560  _SEH2_TRY {
2561 
2562  if (!CcPinMappedData( Vcb->VirtualVolumeFile,
2563  &FatLargeZero,
2564  BytesToMap,
2565  BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
2566  &LocalBcb )) {
2567 
2568  //
2569  // Could not pin the data without waiting (cache miss).
2570  //
2571 
2572  FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
2573  }
2574 
2575  //
2576  // Make Mm, myself, and Cc think the byte is dirty, and then
2577  // force a writethrough.
2578  //
2579 
2580  LocalBuffer += FatReservedBytes(&Vcb->Bpb);
2581 
2582  TmpChar = LocalBuffer[0];
2583  LocalBuffer[0] = TmpChar;
2584 
2585  FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb,
2586  FatReservedBytes( &Vcb->Bpb ),
2587  FatReservedBytes( &Vcb->Bpb ),
2588  Vcb->Bpb.BytesPerSector );
2589 
2590  } _SEH2_FINALLY {
2591 
2592  if (_SEH2_AbnormalTermination() && (LocalBcb != NULL)) {
2593 
2594  FatUnpinBcb( IrpContext, LocalBcb );
2595  }
2596  } _SEH2_END;
2597 
2598  CcRepinBcb( LocalBcb );
2599  CcSetDirtyPinnedData( LocalBcb, NULL );
2600  CcUnpinData( LocalBcb );
2601  DbgDoit( NT_ASSERT( IrpContext->PinCount ));
2602  DbgDoit( IrpContext->PinCount -= 1 );
2603  CcUnpinRepinnedBcb( LocalBcb, TRUE, &Iosb );
2604 
2605  //
2606  // If this was not successful, raise the status.
2607  //
2608 
2609  if ( !NT_SUCCESS(Iosb.Status) ) {
2610 
2611  FatNormalizeAndRaiseStatus( IrpContext, Iosb.Status );
2612  }
2613 
2614  } else {
2615 
2616  //
2617  // Just set a Bcb dirty here. The above code was only there to
2618  // detect a write protected floppy, while the below code works
2619  // for any write protected media and only takes a hit when the
2620  // volume in clean.
2621  //
2622 
2623  FatGetDirentFromFcbOrDcb( IrpContext,
2624  Fcb,
2625  FALSE,
2626  &Dirent,
2627  &Bcb );
2628 
2629  //
2630  // This has to work for the usual reasons (we verified the Fcb within
2631  // volume synch).
2632  //
2633 
2634  _SEH2_TRY {
2635 
2636  FatSetDirtyBcb( IrpContext, Bcb, Fcb->Vcb, TRUE );
2637 
2638  } _SEH2_FINALLY {
2639 
2640  FatUnpinBcb( IrpContext, Bcb );
2641  } _SEH2_END;
2642  }
2643 
2644  //
2645  // At this point either we have a file or an empty directory
2646  // so we know the delete can proceed.
2647  //
2648 
2650  FileObject->DeletePending = TRUE;
2651 
2652  //
2653  // If this is a directory then report this delete pending to
2654  // the dir notify package.
2655  //
2656 
2657  if (NodeType(Fcb) == FAT_NTC_DCB) {
2658 
2660  &Fcb->Vcb->DirNotifyList,
2661  FileObject->FsContext,
2662  NULL,
2663  FALSE,
2664  FALSE,
2665  0,
2666  NULL,
2667  NULL,
2668  NULL );
2669  }
2670  } else {
2671 
2672  //
2673  // The user doesn't want to delete the file so clear
2674  // the delete on close bit
2675  //
2676 
2677  DebugTrace(0, Dbg, "User want to not delete file\n", 0);
2678 
2680  FileObject->DeletePending = FALSE;
2681  }
2682 
2683  DebugTrace(-1, Dbg, "FatSetDispositionInfo -> STATUS_SUCCESS\n", 0);
2684 
2685  return STATUS_SUCCESS;
2686 }
2687 
2688 
2689 //
2690 // Internal Support Routine
2691 //
2692 
2693 NTSTATUS
2695  IN PIRP_CONTEXT IrpContext,
2696  IN PIRP Irp,
2697  IN PVCB Vcb,
2698  IN PFCB Fcb,
2699  IN PCCB Ccb
2700  )
2701 
2702 /*++
2703 
2704 Routine Description:
2705 
2706  This routine performs the set name information for fat. It either
2707  completes the request or enqueues it off to the fsp.
2708 
2709 Arguments:
2710 
2711  Irp - Supplies the irp being processed
2712 
2713  Vcb - Supplies the Vcb being processed
2714 
2715  Fcb - Supplies the Fcb or Dcb being processed, already known not to
2716  be the root dcb
2717 
2718  Ccb - Supplies the Ccb corresponding to the handle opening the source
2719  file
2720 
2721 Return Value:
2722 
2723  NTSTATUS - The result of this operation if it completes without
2724  an exception.
2725 
2726 --*/
2727 
2728 {
2731  BOOLEAN CaseOnlyRename;
2732  BOOLEAN ContinueWithRename;
2734  BOOLEAN DeleteSourceDirent;
2735  BOOLEAN DeleteTarget;
2736  BOOLEAN NewDirentFromPool;
2737  BOOLEAN RenamedAcrossDirectories;
2738  BOOLEAN ReplaceIfExists;
2739 
2740  CCB LocalCcb;
2741  PCCB SourceCcb;
2742 
2743  DIRENT Dirent;
2744 
2746 
2747  OEM_STRING OldOemName;
2748  OEM_STRING NewOemName;
2749  UCHAR OemNameBuffer[24*2];
2750 
2751  PBCB DotDotBcb;
2752  PBCB NewDirentBcb;
2753  PBCB OldDirentBcb;
2754  PBCB SecondPageBcb;
2755  PBCB TargetDirentBcb;
2756 
2757  PDCB TargetDcb = NULL;
2758  PDCB OldParentDcb;
2759 
2760  PDIRENT DotDotDirent = NULL;
2761  PDIRENT FirstPageDirent = NULL;
2762  PDIRENT NewDirent = NULL;
2763  PDIRENT OldDirent = NULL;
2764  PDIRENT SecondPageDirent = NULL;
2765  PDIRENT ShortDirent = NULL;
2766  PDIRENT TargetDirent = NULL;
2767 
2768  PFCB TempFcb;
2769 
2770  PFILE_OBJECT TargetFileObject;
2772 
2774 
2775  PLIST_ENTRY Links;
2776 
2777  ULONG BytesInFirstPage = 0;
2778  ULONG DirentsInFirstPage = 0;
2779  ULONG DirentsRequired = 0;
2780  ULONG NewOffset = 0;
2781  ULONG NotifyAction = 0;
2782  ULONG SecondPageOffset = 0;
2783  ULONG ShortDirentOffset = 0;
2784  ULONG TargetDirentOffset = 0;
2785  ULONG TargetLfnOffset = 0;
2786 
2787  // NewName comes from the IRP buffer or the TargetFileObject, so we can't
2788  // go around modifying it. Instead we modify NewNameCopy.
2790 
2791  // NB: these five UNICODE_STRINGS are allocated
2792  // from one chopped up pool allocation called UnicodeBuffer.
2793  UNICODE_STRING NewNameCopy;
2794  UNICODE_STRING NewUpcasedName;
2795  UNICODE_STRING OldName;
2796  UNICODE_STRING OldUpcasedName;
2797  UNICODE_STRING TargetLfn;
2798  PWCHAR UnicodeBuffer;
2799 
2800  UNICODE_STRING TargetOrigLfn = {0};
2801 
2802  UNICODE_STRING UniTunneledShortName;
2803  WCHAR UniTunneledShortNameBuffer[12];
2804  UNICODE_STRING UniTunneledLongName;
2805  WCHAR UniTunneledLongNameBuffer[26];
2806 
2807  LARGE_INTEGER TunneledCreationTime;
2808  ULONG TunneledDataSize;
2809  BOOLEAN HaveTunneledInformation = FALSE;
2810  BOOLEAN UsingTunneledLfn = FALSE;
2811 
2812  BOOLEAN InvalidateFcbOnRaise = FALSE;
2813 
2814  PFILE_OBJECT DirectoryFileObject = NULL;
2815  ULONG Flags = 0;
2816 
2817  PAGED_CODE();
2818 
2819  DebugTrace(+1, Dbg, "FatSetRenameInfo...\n", 0);
2820 
2821  //
2822  // P H A S E 0: Initialize some variables.
2823  //
2824 
2825  CaseOnlyRename = FALSE;
2826  ContinueWithRename = FALSE;
2827  DeleteSourceDirent = FALSE;
2828  DeleteTarget = FALSE;
2829  NewDirentFromPool = FALSE;
2830  RenamedAcrossDirectories = FALSE;
2831 
2832  DotDotBcb = NULL;
2833  NewDirentBcb = NULL;
2834  OldDirentBcb = NULL;
2835  SecondPageBcb = NULL;
2836  TargetDirentBcb = NULL;
2837 
2838  NewOemName.Length = 0;
2839  NewOemName.MaximumLength = 24;
2840  NewOemName.Buffer = (PCHAR)&OemNameBuffer[0];
2841 
2842  OldOemName.Length = 0;
2843  OldOemName.MaximumLength = 24;
2844  OldOemName.Buffer = (PCHAR)&OemNameBuffer[24];
2845 
2846  UnicodeBuffer = FsRtlAllocatePoolWithTag( PagedPool,
2847  5 * MAX_LFN_CHARACTERS * sizeof(WCHAR),
2849 
2850  NewUpcasedName.Length = 0;
2851  NewUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2852  NewUpcasedName.Buffer = &UnicodeBuffer[0];
2853 
2854  OldName.Length = 0;
2855  OldName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2856  OldName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS];
2857 
2858  OldUpcasedName.Length = 0;
2859  OldUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2860  OldUpcasedName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 2];
2861 
2862  TargetLfn.Length = 0;
2863  TargetLfn.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2864  TargetLfn.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 3];
2865 
2866  NewNameCopy.Length = 0;
2867  NewNameCopy.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
2868  NewNameCopy.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 4];
2869 
2870  UniTunneledShortName.Length = 0;
2871  UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer);
2872  UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0];
2873 
2874  UniTunneledLongName.Length = 0;
2875  UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer);
2876  UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0];
2877 
2878  //
2879  // Remember the name in case we have to modify the name
2880  // value in the ea.
2881  //
2882 
2883  RtlCopyMemory( OldOemName.Buffer,
2884  Fcb->ShortName.Name.Oem.Buffer,
2885  OldOemName.Length );
2886 
2887  //
2888  // Get the current stack location
2889  //
2890 
2892 
2893  //
2894  // Extract information from the Irp to make our life easier
2895  //
2896 
2898  SourceCcb = FileObject->FsContext2;
2899  TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
2900  ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
2901 
2902  RtlZeroMemory( &LocalCcb, sizeof(CCB) );
2903 
2904  //
2905  // P H A S E 1:
2906  //
2907  // Test if rename is legal. Only small side-effects are not undone.
2908  //
2909 
2910  _SEH2_TRY {
2911 
2912  //
2913  // Can't rename the root directory
2914  //
2915 
2916  if ( NodeType(Fcb) == FAT_NTC_ROOT_DCB ) {
2917 
2919  }
2920 
2921  //
2922  // Check that we were not given a dcb with open handles beneath
2923  // it. If there are only UncleanCount == 0 Fcbs beneath us, then
2924  // remove them from the prefix table, and they will just close
2925  // and go away naturally.
2926  //
2927 
2928  if (NodeType(Fcb) == FAT_NTC_DCB) {
2929 
2930  PFCB BatchOplockFcb;
2931  ULONG BatchOplockCount;
2932 
2933  //
2934  // Loop until there are no batch oplocks in the subtree below
2935  // this directory.
2936  //
2937 
2938  while (TRUE) {
2939 
2940  BatchOplockFcb = NULL;
2941  BatchOplockCount = 0;
2942 
2943  //
2944  // First look for any UncleanCount != 0 Fcbs, and fail if we
2945  // find any.
2946  //
2947 
2948  for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
2949  TempFcb != Fcb;
2950  TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
2951 
2952  if ( TempFcb->UncleanCount != 0 ) {
2953 
2954  //
2955  // If there is a batch oplock on this file then
2956  // increment our count and remember the Fcb if
2957  // this is the first.
2958  //
2959 
2960  if (FatIsFileOplockable( TempFcb ) &&
2962 #if (NTDDI_VERSION >= NTDDI_WIN7)
2963  ||
2964  FsRtlCurrentOplockH( FatGetFcbOplock(TempFcb) )
2965 #endif
2966  )) {
2967 
2968  BatchOplockCount += 1;
2969  if ( BatchOplockFcb == NULL ) {
2970 
2971  BatchOplockFcb = TempFcb;
2972  }
2973 
2974  } else {
2975 
2977  }
2978  }
2979  }
2980 
2981  //
2982  // If this is not the first pass for rename and the number
2983  // of batch oplocks has not decreased then give up.
2984  //
2985 
2986  if ( BatchOplockFcb != NULL ) {
2987 
2988  if ( (Irp->IoStatus.Information != 0) &&
2989  (BatchOplockCount >= Irp->IoStatus.Information) ) {
2990 
2992  }
2993 
2994  //
2995  // Try to break this batch oplock.
2996  //
2997 
2998  Irp->IoStatus.Information = BatchOplockCount;
2999  Status = FsRtlCheckOplock( FatGetFcbOplock(BatchOplockFcb),
3000  Irp,
3001  IrpContext,
3003  NULL );
3004 
3005  //
3006  // If the oplock was already broken then look for more
3007  // batch oplocks.
3008  //
3009 
3010  if (Status == STATUS_SUCCESS) {
3011 
3012  continue;
3013  }
3014 
3015  //
3016  // Otherwise the oplock package will post or complete the
3017  // request.
3018  //
3019 
3021  }
3022 
3023  break;
3024  }
3025 
3026  //
3027  // Now try to get as many of these file object, and thus Fcbs
3028  // to go away as possible, flushing first, of course.
3029  //
3030 
3031  FatPurgeReferencedFileObjects( IrpContext, Fcb, Flush );
3032 
3033  //
3034  // OK, so there are no UncleanCount != 0, Fcbs. Infact, there
3035  // shouldn't really be any Fcbs left at all, except obstinate
3036  // ones from user mapped sections .... Remove the full file name
3037  // and exact case lfn.
3038  //
3039 
3040  for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
3041  TempFcb != Fcb;
3042  TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
3043 
3044  FatAcquireExclusiveFcb( IrpContext, TempFcb );
3045 
3046  if (TempFcb->FullFileName.Buffer != NULL) {
3047 
3048  ExFreePool( TempFcb->FullFileName.Buffer );
3049  TempFcb->FullFileName.Buffer = NULL;
3050  }
3051 
3052  FatReleaseFcb( IrpContext, TempFcb );
3053  }
3054  }
3055 
3056  //
3057  // Check if this is a simple rename or a fully-qualified rename
3058  // In both cases we need to figure out what the TargetDcb, and
3059  // NewName are.
3060  //
3061 
3062  if (TargetFileObject == NULL) {
3063 
3064  //
3065  // In the case of a simple rename the target dcb is the
3066  // same as the source file's parent dcb, and the new file name
3067  // is taken from the system buffer
3068  //
3069 
3071 
3072  Buffer = Irp->AssociatedIrp.SystemBuffer;
3073 
3074  TargetDcb = Fcb->ParentDcb;
3075 
3076  NewName.Length = (USHORT) Buffer->FileNameLength;
3077  NewName.Buffer = (PWSTR) &Buffer->FileName;
3078 
3079  //
3080  // Make sure the name is of legal length.
3081  //
3082 
3083  if (NewName.Length > 255*sizeof(WCHAR)) {
3084 
3086  }
3087 
3088  RtlCopyUnicodeString(&NewNameCopy,&NewName);
3089 
3090  } else {
3091 
3092  //
3093  // For a fully-qualified rename the target dcb is taken from
3094  // the target file object, which must be on the same vcb as
3095  // the source.
3096  //
3097 
3098  PVCB TargetVcb;
3099  PCCB TargetCcb;
3100 
3101  if ((FatDecodeFileObject( TargetFileObject,
3102  &TargetVcb,
3103  &TargetDcb,
3104  &TargetCcb ) != UserDirectoryOpen) ||
3105  (TargetVcb != Vcb)) {
3106 
3108  }
3109 
3110  //
3111  // This name is by definition legal.
3112  //
3113 
3114  NewName = *((PUNICODE_STRING)&TargetFileObject->FileName);
3115 
3116  RtlCopyUnicodeString(&NewNameCopy,&NewName);
3117 
3118  }
3119 
3120  //
3121  // We will need an upcased version of the unicode name and the
3122  // old name as well.
3123  //
3124 
3125  Status = RtlUpcaseUnicodeString( &NewUpcasedName, &NewName, FALSE );
3126 
3127  if (!NT_SUCCESS(Status)) {
3128 
3129  try_return( Status );
3130  }
3131 
3132  FatGetUnicodeNameFromFcb( IrpContext, Fcb, &OldName );
3133 
3134  Status = RtlUpcaseUnicodeString( &OldUpcasedName, &OldName, FALSE );
3135 
3136  if (!NT_SUCCESS(Status)) {
3137  try_return(Status);
3138  }
3139 
3140  //
3141  // Check if the current name and new name are equal, and the
3142  // DCBs are equal. If they are then our work is already done.
3143  //
3144 
3145  if (TargetDcb == Fcb->ParentDcb) {
3146 
3147  //
3148  // OK, now if we found something then check if it was an exact
3149  // match or just a case match. If it was an exact match, then
3150  // we can bail here.
3151  //
3152 
3154  &OldName,
3155  FALSE,
3156  NULL )) {
3157 
3159  }
3160 
3161  //
3162  // Check now for a case only rename.
3163  //
3164 
3165 
3166  if (FsRtlAreNamesEqual( &NewUpcasedName,
3167  &OldUpcasedName,
3168  FALSE,
3169  NULL )) {
3170 
3171  CaseOnlyRename = TRUE;
3172  }
3173 
3174  } else {
3175 
3176  RenamedAcrossDirectories = TRUE;
3177  }
3178 
3179  //
3180  // Upcase the name and convert it to the Oem code page.
3181  //
3182  // If the new UNICODE name is already more than 12 characters,
3183  // then we know the Oem name will not be valid
3184  //
3185 
3186  if (NewName.Length <= 12*sizeof(WCHAR)) {
3187 
3188  FatUnicodeToUpcaseOem( IrpContext, &NewOemName, &NewName );
3189 
3190  //
3191  // If the name is not valid 8.3, zero the length.
3192  //
3193 
3194  if (FatSpaceInName( IrpContext, &NewName ) ||
3195  !FatIsNameShortOemValid( IrpContext, NewOemName, FALSE, FALSE, FALSE)) {
3196 
3197  NewOemName.Length = 0;
3198  }
3199 
3200  } else {
3201 
3202  NewOemName.Length = 0;
3203  }
3204 
3205  //
3206  // Look in the tunnel cache for names and timestamps to restore
3207  //
3208 
3209  TunneledDataSize = sizeof(LARGE_INTEGER);
3210  HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel,
3212  &NewName,
3213  &UniTunneledShortName,
3214  &UniTunneledLongName,
3215  &TunneledDataSize,
3216  &TunneledCreationTime );
3217  NT_ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER));
3218 
3219 
3220  //
3221  // Now we need to determine how many dirents this new name will
3222  // require.
3223  //
3224 
3225  if ((NewOemName.Length == 0) ||
3226  (FatEvaluateNameCase( IrpContext,
3227  &NewNameCopy,
3230  &CreateLfn ),
3231  CreateLfn)) {
3232 
3233  DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&NewNameCopy) + 1;
3234 
3235  } else {
3236 
3237  //
3238  // The user-given name is a short name, but we might still have
3239  // a tunneled long name we want to use. See if we can.
3240  //
3241 
3242  if (UniTunneledLongName.Length &&
3243  !FatLfnDirentExists(IrpContext, TargetDcb, &UniTunneledLongName, &TargetLfn)) {
3244 
3245  UsingTunneledLfn = CreateLfn = TRUE;
3246  DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&UniTunneledLongName) + 1;
3247 
3248  } else {
3249 
3250  //
3251  // This really is a simple dirent. Note that the two AllLower BOOLEANs
3252  // are correctly set now.
3253  //
3254 
3255  DirentsRequired = 1;
3256 
3257 
3258  }
3259  }
3260 
3261  //
3262  // Do some extra checks here if we are not in Chicago mode.
3263  //
3264 
3265  if (!FatData.ChicagoMode) {
3266 
3267  //
3268  // If the name was not 8.3 valid, fail the rename.
3269  //
3270 
3271  if (NewOemName.Length == 0) {
3272 
3274  }
3275 
3276  //
3277  // Don't use the magic bits.
3278  //
3279 
3282  CreateLfn = FALSE;
3283  UsingTunneledLfn = FALSE;
3284  }
3285 
3286  if (!CaseOnlyRename) {
3287 
3288  //
3289  // Check if the new name already exists, wait is known to be
3290  // true.
3291  //
3292 
3293  if (NewOemName.Length != 0) {
3294 
3295  FatStringTo8dot3( IrpContext,
3296  NewOemName,
3297  &LocalCcb.OemQueryTemplate.Constant );
3298 
3299  } else {
3300 
3302  }
3303 
3304  LocalCcb.UnicodeQueryTemplate = NewUpcasedName;
3305  LocalCcb.ContainsWildCards = FALSE;
3306 
3307  Flags = 0;
3308 
3309 
3310  FatLocateDirent( IrpContext,
3311  TargetDcb,
3312  &LocalCcb,
3313  0,
3314  &Flags,
3315  &TargetDirent,
3316  &TargetDirentBcb,
3317  (PVBO)&TargetDirentOffset,
3318  NULL,
3319  &TargetLfn,
3320  &TargetOrigLfn );
3321 
3322  if (TargetDirent != NULL) {
3323 
3324 
3325  //
3326  // The name already exists, check if the user wants
3327  // to overwrite the name, and has access to do the overwrite
3328  // We cannot overwrite a directory.
3329  //
3330 
3331  if ((!ReplaceIfExists) ||
3332  (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY)) ||
3333  (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY))) {
3334 
3336  }
3337 
3338  //
3339  // Check that the file has no open user handles, if it does
3340  // then we will deny access. We do the check by searching
3341  // down the list of fcbs opened under our parent Dcb, and making
3342  // sure none of the maching Fcbs have a non-zero unclean count or
3343  // outstanding image sections.
3344  //
3345 
3346  for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
3347  Links != &TargetDcb->Specific.Dcb.ParentDcbQueue; ) {
3348 
3349  TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
3350 
3351  //
3352  // Advance now. The image section flush may cause the final
3353  // close, which will recursively happen underneath of us here.
3354  // It would be unfortunate if we looked through free memory.
3355  //
3356 
3357  Links = Links->Flink;
3358 
3359  if ((TempFcb->DirentOffsetWithinDirectory == TargetDirentOffset) &&
3360  ((TempFcb->UncleanCount != 0) ||
3362  MmFlushForDelete))) {
3363 
3364  //
3365  // If there are batch oplocks on this file then break the
3366  // oplocks before failing the rename.
3367  //
3368 
3370 
3371  if (FatIsFileOplockable( TempFcb ) &&
3373 #if (NTDDI_VERSION >= NTDDI_WIN7)
3374  ||
3375  FsRtlCurrentOplockH( FatGetFcbOplock(TempFcb) )
3376 #endif
3377  )) {
3378 
3379  //
3380  // Do all of our cleanup now since the IrpContext
3381  // could go away when this request is posted.
3382  //
3383 
3384  FatUnpinBcb( IrpContext, TargetDirentBcb );
3385 
3387  Irp,
3388  IrpContext,
3390  NULL );
3391 
3392  if (Status != STATUS_PENDING) {
3393 
3395  }
3396  }
3397 
3398  try_return( NOTHING );
3399  }
3400  }
3401 
3402  //
3403  // OK, this target is toast. Remember the Lfn offset.
3404  //
3405 
3406  TargetLfnOffset = TargetDirentOffset -
3407  FAT_LFN_DIRENTS_NEEDED(&TargetOrigLfn) *
3408  sizeof(DIRENT);
3409 
3410  DeleteTarget = TRUE;
3411  }
3412  }
3413 
3414 
3415  //
3416  // If we will need more dirents than we have, allocate them now.
3417  //
3418 
3419  if ((TargetDcb != Fcb->ParentDcb) ||
3420  (DirentsRequired !=
3422  Fcb->LfnOffsetWithinDirectory) / sizeof(DIRENT) + 1)) {
3423 
3424  //
3425  // Get some new allocation
3426  //
3427 
3428  NewOffset = FatCreateNewDirent( IrpContext,
3429  TargetDcb,
3430  DirentsRequired,
3431  FALSE );
3432 
3433  DeleteSourceDirent = TRUE;
3434 
3435  } else {
3436 
3437  NewOffset = Fcb->LfnOffsetWithinDirectory;
3438  }
3439 
3440  ContinueWithRename = TRUE;
3441 
3442  try_exit: NOTHING;
3443 
3444  } _SEH2_FINALLY {
3445 
3446  if (!ContinueWithRename) {
3447 
3448  //
3449  // Undo everything from above.
3450  //
3451 
3452  ExFreePool( UnicodeBuffer );
3453  FatUnpinBcb( IrpContext, TargetDirentBcb );
3454 
3455  }
3456  } _SEH2_END;
3457 
3458  //
3459  // Now, if we are already done, return here.
3460  //
3461 
3462  if (!ContinueWithRename) {
3463 
3464  return Status;
3465  }
3466 
3467  //
3468  // P H A S E 2: Actually perform the rename.
3469  //
3470 
3471  _SEH2_TRY {
3472 
3473  //
3474  // Report the fact that we are going to remove this entry.
3475  // If we renamed within the same directory and the new name for the
3476  // file did not previously exist, we report this as a rename old
3477  // name. Otherwise this is a removed file.
3478  //
3479 
3480  if (!RenamedAcrossDirectories && !DeleteTarget) {
3481 
3482  NotifyAction = FILE_ACTION_RENAMED_OLD_NAME;
3483 
3484  } else {
3485 
3486  NotifyAction = FILE_ACTION_REMOVED;
3487  }
3488 
3489  FatNotifyReportChange( IrpContext,
3490  Vcb,
3491  Fcb,
3492  ((NodeType( Fcb ) == FAT_NTC_FCB)
3495  NotifyAction );
3496 
3497  _SEH2_TRY {
3498 
3499  //
3500  // Capture a copy of the source dirent.
3501  //
3502 
3503  FatGetDirentFromFcbOrDcb( IrpContext, Fcb, FALSE, &OldDirent, &OldDirentBcb );
3504 
3505  Dirent = *OldDirent;
3506 
3507  //
3508  // Tunnel the source Fcb - the names are disappearing regardless of
3509  // whether the dirent allocation physically changed
3510  //
3511 
3512  FatTunnelFcbOrDcb( Fcb, SourceCcb );
3513 
3514  //
3515  // From here until very nearly the end of the operation, if we raise there
3516  // is no reasonable way to suppose we'd be able to undo the damage. Not
3517  // being a transactional filesystem, FAT is at the mercy of a lot of things
3518  // (as the astute reader has no doubt realized by now).
3519  //
3520 
3521  InvalidateFcbOnRaise = TRUE;
3522 
3523  //
3524  // Delete our current dirent(s) if we got a new one.
3525  //
3526 
3527  if (DeleteSourceDirent) {
3528 
3529  FatDeleteDirent( IrpContext, Fcb, NULL, FALSE );
3530  }
3531 
3532  //
3533  // Delete a target conflict if we were meant to.
3534  //
3535 
3536  if (DeleteTarget) {
3537 
3538  FatDeleteFile( IrpContext,
3539  TargetDcb,
3540  TargetLfnOffset,
3541  TargetDirentOffset,
3542  TargetDirent,
3543  &TargetLfn );
3544  }
3545 
3546  //
3547  // We need to evaluate any short names required. If there were any
3548  // conflicts in existing short names, they would have been deleted above.
3549  //
3550  // It isn't neccesary to worry about the UsingTunneledLfn case. Since we
3551  // actually already know whether CreateLfn will be set either NewName is
3552  // an Lfn and !UsingTunneledLfn is implied or NewName is a short name and
3553  // we can handle that externally.
3554  //
3555 
3556  FatSelectNames( IrpContext,
3557  TargetDcb,
3558  &NewOemName,
3559  &NewNameCopy,
3560  &NewOemName,
3561  (HaveTunneledInformation ? &UniTunneledShortName : NULL),
3564  &CreateLfn );
3565 
3566  if (!CreateLfn && UsingTunneledLfn) {
3567 
3568  CreateLfn = TRUE;
3569  RtlCopyUnicodeString( &NewNameCopy, &UniTunneledLongName );
3570 
3571  //
3572  // Short names are always upcase if an LFN exists
3573  //
3574 
3577  }
3578 
3579  //
3580  // OK, now setup the new dirent(s) for the new name.
3581  //
3582 
3583  FatPrepareWriteDirectoryFile( IrpContext,
3584  TargetDcb,
3585  NewOffset,
3586  sizeof(DIRENT),
3587  &NewDirentBcb,
3588 #ifndef __REACTOS__
3589  &NewDirent,
3590 #else
3591  (PVOID *)&NewDirent,
3592 #endif
3593  FALSE,
3594  TRUE,
3595  &Status );
3596 
3597  NT_ASSERT( NT_SUCCESS( Status ) );
3598 
3599  //
3600  // Deal with the special case of an LFN + Dirent structure crossing
3601  // a page boundry.
3602  //
3603 
3604  if ((NewOffset / PAGE_SIZE) !=
3605  ((NewOffset + (DirentsRequired - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
3606 
3607  SecondPageOffset = (NewOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
3608 
3609  BytesInFirstPage = SecondPageOffset - NewOffset;
3610 
3611  DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
3612 
3613  FatPrepareWriteDirectoryFile( IrpContext,
3614  TargetDcb,
3615  SecondPageOffset,
3616  sizeof(DIRENT),
3617  &SecondPageBcb,
3618 #ifndef __REACTOS__
3619  &SecondPageDirent,
3620 #else
3621  (PVOID *)&SecondPageDirent,
3622 #endif
3623  FALSE,
3624  TRUE,
3625  &Status );
3626 
3627  NT_ASSERT( NT_SUCCESS( Status ) );
3628 
3629  FirstPageDirent = NewDirent;
3630 
3631  NewDirent = FsRtlAllocatePoolWithTag( PagedPool,
3632  DirentsRequired * sizeof(DIRENT),
3633  TAG_DIRENT );
3634 
3635  NewDirentFromPool = TRUE;
3636  }
3637 
3638  //
3639  // Bump up Dirent and DirentOffset
3640  //
3641 
3642  ShortDirent = NewDirent + DirentsRequired - 1;
3643  ShortDirentOffset = NewOffset + (DirentsRequired - 1) * sizeof(DIRENT);
3644 
3645  //
3646  // Fill in the fields of the dirent.
3647  //
3648 
3649  *ShortDirent = Dirent;
3650 
3651  FatConstructDirent( IrpContext,
3652  ShortDirent,
3653  &NewOemName,
3656  CreateLfn ? &NewNameCopy : NULL,
3657  Dirent.Attributes,
3658  FALSE,
3659  (HaveTunneledInformation ? &TunneledCreationTime : NULL) );
3660 
3661  if (HaveTunneledInformation) {
3662 
3663  //
3664  // Need to go in and fix the timestamps in the FCB. Note that we can't use
3665  // the TunneledCreationTime since the conversions may have failed.
3666  //
3667 
3668  Fcb->CreationTime = FatFatTimeToNtTime(IrpContext, ShortDirent->CreationTime, ShortDirent->CreationMSec);
3669  Fcb->LastWriteTime = FatFatTimeToNtTime(IrpContext, ShortDirent->LastWriteTime, 0);
3670  Fcb->LastAccessTime = FatFatDateToNtTime(IrpContext, ShortDirent->LastAccessDate);
3671  }
3672 
3673 
3674  //
3675  // If the dirent crossed pages, split the contents of the
3676  // temporary pool between the two pages.
3677  //
3678 
3679  if (NewDirentFromPool) {
3680 
3681  RtlCopyMemory( FirstPageDirent, NewDirent, BytesInFirstPage );
3682 
3683  RtlCopyMemory( SecondPageDirent,
3684  NewDirent + DirentsInFirstPage,
3685  DirentsRequired*sizeof(DIRENT) - BytesInFirstPage );
3686 
3687  ShortDirent = SecondPageDirent +
3688  (DirentsRequired - DirentsInFirstPage) - 1;
3689  }
3690 
3691  Dirent = *ShortDirent;
3692 
3693  } _SEH2_FINALLY {
3694 
3695  //
3696  // Remove the entry from the splay table, and then remove the
3697  // full file name and exact case lfn. It is important that we
3698  // always remove the name from the prefix table regardless of
3699  // other errors.
3700  //
3701 
3702  FatRemoveNames( IrpContext, Fcb );
3703 
3704  if (Fcb->FullFileName.Buffer != NULL) {
3705 
3708  }
3709 
3710  if (Fcb->ExactCaseLongName.Buffer) {
3711 
3714  }
3715 
3716  FatUnpinBcb( IrpContext, OldDirentBcb );
3717  FatUnpinBcb( IrpContext, TargetDirentBcb );
3718  FatUnpinBcb( IrpContext, NewDirentBcb );
3719  FatUnpinBcb( IrpContext, SecondPageBcb );
3720  } _SEH2_END;
3721 
3722  //
3723  // Now we need to update the location of the file's directory
3724  // offset and move the fcb from its current parent dcb to
3725  // the target dcb.
3726  //
3727 
3728  Fcb->LfnOffsetWithinDirectory = NewOffset;
3729  Fcb->DirentOffsetWithinDirectory = ShortDirentOffset;
3730 
3732 
3733  //
3734  // There is a deep reason we put files on the tail, others on the head,
3735  // which is to allow us to easily enumerate all child directories before
3736  // child files. This is important to let us maintain whole-volume lockorder
3737  // via BottomUp enumeration.
3738  //
3739 
3740  if (NodeType(Fcb) == FAT_NTC_FCB) {
3741 
3742  InsertTailList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
3743  &Fcb->ParentDcbLinks );
3744 
3745  } else {
3746 
3747  InsertHeadList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
3748  &Fcb->ParentDcbLinks );
3749  }
3750 
3751  OldParentDcb = Fcb->ParentDcb;
3752  Fcb->ParentDcb = TargetDcb;
3753 
3754 #if (NTDDI_VERSION >= NTDDI_WIN8)
3755  //
3756  // Break parent directory oplock on the old parent. Directory oplock
3757  // breaks are always advisory, so we will never block/get STATUS_PENDING
3758  // here.
3759  //
3760 
3761  FsRtlCheckOplockEx( FatGetFcbOplock(OldParentDcb),
3762  IrpContext->OriginatingIrp,
3763  OPLOCK_FLAG_PARENT_OBJECT,
3764  NULL,
3765  NULL,
3766  NULL );
3767 #endif
3768 
3769  //
3770  // If we renamed across directories, some cleanup is now in order.
3771  //
3772 
3773  if (RenamedAcrossDirectories) {
3774 
3775 #if (NTDDI_VERSION >= NTDDI_WIN8)
3776  //
3777  // Break parent directory oplock on the new parent. Directory oplock
3778  // breaks are always advisory, so we will never block/get STATUS_PENDING
3779  // here.
3780  //
3781 
3782  FsRtlCheckOplockEx( FatGetFcbOplock(TargetDcb),
3783  IrpContext->OriginatingIrp,
3784  OPLOCK_FLAG_PARENT_OBJECT,
3785  NULL,
3786  NULL,
3787  NULL );
3788 #endif
3789 
3790  //
3791  // See if we need to uninitialize the cachemap for the source directory.
3792  // Do this now in case we get unlucky and raise trying to finalize the
3793  // operation.
3794  //
3795 
3796  if (IsListEmpty(&OldParentDcb->Specific.Dcb.ParentDcbQueue) &&
3797  (OldParentDcb->OpenCount == 0) &&
3798  (OldParentDcb->Specific.Dcb.DirectoryFile != NULL)) {
3799 
3800  NT_ASSERT( NodeType(OldParentDcb) == FAT_NTC_DCB );
3801 
3802  DirectoryFileObject = OldParentDcb->Specific.Dcb.DirectoryFile;
3803 
3804  OldParentDcb->Specific.Dcb.DirectoryFile = NULL;
3805  }
3806 
3807  //
3808  // If we move a directory across directories, we have to change
3809  // the cluster number in its .. entry
3810  //
3811 
3812  if (NodeType(Fcb) == FAT_NTC_DCB) {
3813 
3814  FatPrepareWriteDirectoryFile( IrpContext,
3815  Fcb,
3816  sizeof(DIRENT),
3817  sizeof(DIRENT),
3818  &DotDotBcb,
3819 #ifndef __REACTOS__
3820  &DotDotDirent,
3821 #else
3822  (PVOID *)&DotDotDirent,
3823 #endif
3824  FALSE,
3825  TRUE,
3826  &Status );
3827 
3828  NT_ASSERT( NT_SUCCESS( Status ) );
3829 
3830  DotDotDirent->FirstClusterOfFile = (USHORT)
3833 
3834  if (FatIsFat32( Vcb )) {
3835 
3836  DotDotDirent->FirstClusterOfFileHi = (USHORT)
3838  0 : (TargetDcb->FirstClusterOfFile >> 16));
3839  }
3840  }
3841  }
3842 
3843  //
3844  // Now we need to setup the splay table and the name within
3845  // the fcb. Free the old short name at this point.
3846  //
3847 
3848  ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
3849  Fcb->ShortName.Name.Oem.Buffer = NULL;
3850 
3851 
3852  FatConstructNamesInFcb( IrpContext,
3853  Fcb,
3854  &Dirent,
3855  CreateLfn ? &NewName : NULL );
3856 
3857  FatSetFullNameInFcb( IrpContext, Fcb, &NewName );
3858 
3859  //
3860  // The rest of the actions taken are not related to correctness of
3861  // the in-memory structures, so we shouldn't toast the Fcb if we
3862  // raise from here to the end.
3863  //
3864 
3865  InvalidateFcbOnRaise = FALSE;
3866 
3867  //
3868  // If a file, set the file as modified so that the archive bit
3869  // is set. We prevent this from adjusting the write time by
3870  // indicating the user flag in the ccb.
3871  //
3872 
3873  if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) {
3874 
3875  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
3877  }
3878 
3879  //
3880  // We have three cases to report.
3881  //
3882  // 1. If we overwrote an existing file, we report this as
3883  // a modified file.
3884  //
3885  // 2. If we renamed to a new directory, then we added a file.
3886  //
3887  // 3. If we renamed in the same directory, then we report the
3888  // the renamednewname.
3889  //
3890 
3891  if (DeleteTarget) {
3892 
3893  FatNotifyReportChange( IrpContext,
3894  Vcb,
3895  Fcb,
3903 
3904  } else if (RenamedAcrossDirectories) {
3905 
3906  FatNotifyReportChange( IrpContext,
3907  Vcb,
3908  Fcb,
3909  ((NodeType( Fcb ) == FAT_NTC_FCB)
3913 
3914  } else {
3915 
3916  FatNotifyReportChange( IrpContext,
3917  Vcb,
3918  Fcb,
3919  ((NodeType( Fcb ) == FAT_NTC_FCB)
3923  }
3924 
3925  //
3926  // We need to update the file name in the dirent. This value
3927  // is never used elsewhere, so we don't concern ourselves
3928  // with any error we may encounter. We let chkdsk fix the
3929  // disk at some later time.
3930  //
3931 
3932  if (!FatIsFat32(Vcb) &&
3933  Dirent.ExtendedAttributes != 0) {
3934 
3935  FatRenameEAs( IrpContext,
3936  Fcb,
3937  Dirent.ExtendedAttributes,
3938  &OldOemName );
3939  }
3940 
3941  FatUnpinBcb( IrpContext, DotDotBcb );
3942 
3943  FatUnpinRepinnedBcbs( IrpContext );
3944 
3945  //
3946  // Set our final status
3947  //
3948 
3950 
3951  } _SEH2_FINALLY {
3952 
3954 
3955  ExFreePool( UnicodeBuffer );
3956 
3957  if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) {
3958 
3959  //
3960  // Free pool if the buffer was grown on tunneling lookup
3961  //
3962 
3963  ExFreePool(UniTunneledLongName.Buffer);
3964  }
3965 
3966  if (NewDirentFromPool) {
3967 
3968  ExFreePool( NewDirent );
3969  }
3970 
3971  FatUnpinBcb( IrpContext, TargetDirentBcb );
3972  FatUnpinBcb( IrpContext, DotDotBcb );
3973 
3974  //
3975  // Uninitialize the cachemap for the source directory if we need to.
3976  //
3977 
3978  if (DirectoryFileObject) {
3979 
3980  DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0);
3981 
3982  CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
3983 
3984  ObDereferenceObject( DirectoryFileObject );
3985  }
3986 
3987  //
3988  // If this was an abnormal termination, then we are in trouble.
3989  // Should the operation have been in a sensitive state there is
3990  // nothing we can do but invalidate the Fcb.
3991  //
3992 
3993  if (_SEH2_AbnormalTermination() && InvalidateFcbOnRaise) {
3994 
3995  Fcb->FcbCondition = FcbBad;
3996  }
3997 
3998  DebugTrace(-1, Dbg, "FatSetRenameInfo -> %08lx\n", Status);
3999  } _SEH2_END;
4000 
4001  return Status;
4002 }
4003 
4004 
4005 //
4006 // Internal Support Routine
4007 //
4008 
4009 NTSTATUS
4011  IN PIRP_CONTEXT IrpContext,
4012  IN PIRP Irp,
4014  )
4015 
4016 /*++
4017 
4018 Routine Description:
4019 
4020  This routine performs the set position information for fat. It either
4021  completes the request or enqueues it off to the fsp.
4022 
4023 Arguments:
4024 
4025  Irp - Supplies the irp being processed
4026 
4027  FileObject - Supplies the file object being processed
4028 
4029 Return Value:
4030 
4031  NTSTATUS - The result of this operation if it completes without
4032  an exception.
4033 
4034 --*/
4035 
4036 {
4038 
4039  PAGED_CODE();
4040 
4041  DebugTrace(+1, Dbg, "FatSetPositionInfo...\n", 0);
4042 
4043  Buffer = Irp->AssociatedIrp.SystemBuffer;
4044 
4045  //
4046  // Check if the file does not use intermediate buffering. If it
4047  // does not use intermediate buffering then the new position we're
4048  // supplied must be aligned properly for the device
4049  //
4050 
4052 
4054 
4056 
4057  if ((Buffer->CurrentByteOffset.LowPart & DeviceObject->AlignmentRequirement) != 0) {
4058 
4059  DebugTrace(0, Dbg, "Cannot set position due to aligment conflict\n", 0);
4060  DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_INVALID_PARAMETER);
4061 
4062  return STATUS_INVALID_PARAMETER;
4063  }
4064  }
4065 
4066  //
4067  // The input parameter is fine so set the current byte offset and
4068  // complete the request
4069  //
4070 
4071  DebugTrace(0, Dbg, "Set the new position to %08lx\n", Buffer->CurrentByteOffset);
4072 
4073  FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
4074 
4075  DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_SUCCESS);
4076 
4077  UNREFERENCED_PARAMETER( IrpContext );
4078 
4079  return STATUS_SUCCESS;
4080 }
4081 
4082 
4083 //
4084 // Internal Support Routine
4085 //
4086 
4087 _Requires_lock_held_(_Global_critical_region_)
4088 NTSTATUS
4089 FatSetAllocationInfo (
4090  IN PIRP_CONTEXT IrpContext,
4091  IN PIRP Irp,
4092  IN PFCB Fcb,
4094  )
4095 
4096 /*++
4097 
4098 Routine Description:
4099 
4100  This routine performs the set Allocation information for fat. It either
4101  completes the request or enqueues it off to the fsp.
4102 
4103 Arguments:
4104 
4105  Irp - Supplies the irp being processed
4106 
4107  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4108  be the root dcb
4109 
4110  FileObject - Supplies the FileObject being processed, already known not to
4111  be the root dcb
4112 
4113 Return Value:
4114 
4115  NTSTATUS - The result of this operation if it completes without
4116  an exception.
4117 
4118 --*/
4119 
4120 {
4123  ULONG NewAllocationSize = 0;
4124  ULONG HeaderSize = 0;
4125 
4126  BOOLEAN FileSizeTruncated = FALSE;
4127  BOOLEAN CacheMapInitialized = FALSE;
4128  BOOLEAN ResourceAcquired = FALSE;
4129  ULONG OriginalFileSize = 0;
4130  ULONG OriginalValidDataLength = 0;
4131  ULONG OriginalValidDataToDisk = 0;
4132 
4133  PAGED_CODE();
4134 
4135  Buffer = Irp->AssociatedIrp.SystemBuffer;
4136 
4137  NewAllocationSize = Buffer->AllocationSize.LowPart;
4138 
4139  DebugTrace(+1, Dbg, "FatSetAllocationInfo.. to %08lx\n", NewAllocationSize);
4140 
4141  //
4142  // Allocation is only allowed on a file and not a directory
4143  //
4144 
4145  if (NodeType(Fcb) == FAT_NTC_DCB) {
4146 
4147  DebugTrace(-1, Dbg, "Cannot change allocation of a directory\n", 0);
4148 
4150  }
4151 
4152  //
4153  // Check that the new file allocation is legal
4154  //
4155 
4156 
4157  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->AllocationSize, 0)) {
4158 
4159  DebugTrace(-1, Dbg, "Illegal allocation size\n", 0);
4160 
4161  return STATUS_DISK_FULL;
4162  }
4163 
4164 
4165  //
4166  // If we haven't yet looked up the correct AllocationSize, do so.
4167  //
4168 
4169  if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
4170 
4171  FatLookupFileAllocationSize( IrpContext, Fcb );
4172  }
4173 
4174  //
4175  // This is kinda gross, but if the file is not cached, but there is
4176  // a data section, we have to cache the file to avoid a bunch of
4177  // extra work.
4178  //
4179 
4180  if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
4181  (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
4182  !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
4183 
4185 
4186  //
4187  // Now initialize the cache map.
4188  //
4189 
4191  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4192  FALSE,
4194  Fcb );
4195 
4196  CacheMapInitialized = TRUE;
4197  }
4198 
4199  //
4200  // Now mark the fact that the file needs to be truncated on close
4201  //
4202 
4204 
4205  //
4206  // Now mark that the time on the dirent needs to be updated on close.
4207  //
4208 
4209  SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
4210 
4211  _SEH2_TRY {
4212 
4213  //
4214  // Increase or decrease the allocation size.
4215  //
4216 
4217  if (NewAllocationSize+HeaderSize > Fcb->Header.AllocationSize.LowPart) {
4218 
4219  FatAddFileAllocation( IrpContext, Fcb, FileObject, NewAllocationSize+HeaderSize);
4220 
4221  } else {
4222 
4223  //
4224  // Check here if we will be decreasing file size and synchonize with
4225  // paging IO.
4226  //
4227 
4228  if ( Fcb->Header.FileSize.LowPart > NewAllocationSize+HeaderSize ) {
4229 
4230  //
4231  // The way Sections for DataScan are created and used, an AV's
4232  // memory-mapping can come into being after we check it's safe
4233  // to truncate a file while continuing to hold the file here.
4234  // This leads to data corruption because Purge eventually fails
4235  // (during call to Cc to set file sizes) and stale data continues
4236  // to live in the cache/memory.
4237  //
4238 
4239  if (Fcb->PurgeFailureModeEnableCount != 0) {
4240 
4242  }
4243 
4244  //
4245  // Before we actually truncate, check to see if the purge
4246  // is going to fail.
4247  //
4248 
4249  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4250  &Buffer->AllocationSize )) {
4251 
4253  }
4254 
4255  FileSizeTruncated = TRUE;
4256 
4257  OriginalFileSize = Fcb->Header.FileSize.LowPart;
4258  OriginalValidDataLength = Fcb->Header.ValidDataLength.LowPart;
4259  OriginalValidDataToDisk = Fcb->ValidDataToDisk;
4260 
4261  (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4262  ResourceAcquired = TRUE;
4263 
4264  Fcb->Header.FileSize.LowPart = NewAllocationSize;
4265 
4266  //
4267  // If we reduced the file size to less than the ValidDataLength,
4268  // adjust the VDL. Likewise ValidDataToDisk.
4269  //
4270 
4271  if (Fcb->Header.ValidDataLength.LowPart > Fcb->Header.FileSize.LowPart) {
4272 
4273  Fcb->Header.ValidDataLength.LowPart = Fcb->Header.FileSize.LowPart;
4274  }
4275  if (Fcb->ValidDataToDisk > Fcb->Header.FileSize.LowPart) {
4276 
4277  Fcb->ValidDataToDisk = Fcb->Header.FileSize.LowPart;
4278  }
4279 
4280  }
4281 
4282  //
4283  // Now that File Size is down, actually do the truncate.
4284  //
4285 
4286  FatTruncateFileAllocation( IrpContext, Fcb, NewAllocationSize+HeaderSize );
4287 
4288  //
4289  // Now check if we needed to decrease the file size accordingly.
4290  //
4291 
4292  if ( FileSizeTruncated ) {
4293 
4294  //
4295  // Tell the cache manager we reduced the file size.
4296  // The call is unconditional, because MM always wants to know.
4297  //
4298 
4299 #if DBG
4300  _SEH2_TRY {
4301 #endif
4302 
4303  CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4304 
4305 #if DBG
4306  } _SEH2_EXCEPT(FatBugCheckExceptionFilter( _SEH2_GetExceptionInformation() )) {
4307 
4308  NOTHING;
4309  } _SEH2_END;
4310 #endif
4311 
4312  NT_ASSERT( FileObject->DeleteAccess || FileObject->WriteAccess );
4313 
4314  //
4315  // There is no going back from this. If we run into problems updating
4316  // the dirent we will have to live with the consequences. Not sending
4317  // the notifies is likewise pretty benign compared to failing the entire
4318  // operation and trying to back out everything, which could fail for the
4319  // same reasons.
4320  //
4321  // If you want a transacted filesystem, use NTFS ...
4322  //
4323 
4324  FileSizeTruncated = FALSE;
4325 
4326  FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
4327 
4328  //
4329  // Report that we just reduced the file size.
4330  //
4331 
4332  FatNotifyReportChange( IrpContext,
4333  Fcb->Vcb,
4334  Fcb,
4337  }
4338  }
4339 
4340  try_exit: NOTHING;
4341 
4342  } _SEH2_FINALLY {
4343 
4344  if ( _SEH2_AbnormalTermination() && FileSizeTruncated ) {
4345 
4346  Fcb->Header.FileSize.LowPart = OriginalFileSize;
4347  Fcb->Header.ValidDataLength.LowPart = OriginalValidDataLength;
4348  Fcb->ValidDataToDisk = OriginalValidDataToDisk;
4349 
4350  //
4351  // Make sure Cc knows the right filesize.
4352  //
4353 
4354  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4355 
4356  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4357  }
4358 
4359  NT_ASSERT( Fcb->Header.FileSize.LowPart <= Fcb->Header.AllocationSize.LowPart );
4360  }
4361 
4362  if (CacheMapInitialized) {
4363 
4365  }
4366 
4367  if (ResourceAcquired) {
4368 
4369  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4370 
4371  }
4372 
4373  } _SEH2_END;
4374 
4375  DebugTrace(-1, Dbg, "FatSetAllocationInfo -> %08lx\n", STATUS_SUCCESS);
4376 
4377  return Status;
4378 }
4379 
4380 
4381 //
4382 // Internal Support Routine
4383 //
4384 
4385 _Requires_lock_held_(_Global_critical_region_)
4386 NTSTATUS
4387 FatSetEndOfFileInfo (
4388  IN PIRP_CONTEXT IrpContext,
4389  IN PIRP Irp,
4391  IN PVCB Vcb,
4392  IN PFCB Fcb
4393  )
4394 
4395 /*++
4396 
4397 Routine Description:
4398 
4399  This routine performs the set End of File information for fat. It either
4400  completes the request or enqueues it off to the fsp.
4401 
4402 Arguments:
4403 
4404  Irp - Supplies the irp being processed
4405 
4406  FileObject - Supplies the file object being processed
4407 
4408  Vcb - Supplies the Vcb being processed
4409 
4410  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4411  be the root dcb
4412 
4413 Return Value:
4414 
4415  NTSTATUS - The result of this operation if it completes without
4416  an exception.
4417 
4418 --*/
4419 
4420 {
4422 
4424 
4425  ULONG NewFileSize = 0;
4426  ULONG InitialFileSize = 0;
4427  ULONG InitialValidDataLength = 0;
4428  ULONG InitialValidDataToDisk = 0;
4429 
4430  BOOLEAN CacheMapInitialized = FALSE;
4431  BOOLEAN UnwindFileSizes = FALSE;
4432  BOOLEAN ResourceAcquired = FALSE;
4433 
4434 
4435  PAGED_CODE();
4436 
4437  DebugTrace(+1, Dbg, "FatSetEndOfFileInfo...\n", 0);
4438 
4439  Buffer = Irp->AssociatedIrp.SystemBuffer;
4440 
4441  _SEH2_TRY {
4442 
4443  //
4444  // File Size changes are only allowed on a file and not a directory
4445  //
4446 
4447  if (NodeType(Fcb) != FAT_NTC_FCB) {
4448 
4449  DebugTrace(0, Dbg, "Cannot change size of a directory\n", 0);
4450 
4452  }
4453 
4454 
4455  //
4456  // Check that the new file size is legal
4457  //
4458 
4459 
4460  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->EndOfFile, 0)) {
4461 
4462  DebugTrace(0, Dbg, "Illegal allocation size\n", 0);
4463 
4465  }
4466 
4467  NewFileSize = Buffer->EndOfFile.LowPart;
4468 
4469 
4470  //
4471  // If we haven't yet looked up the correct AllocationSize, do so.
4472  //
4473 
4474  if ((Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) &&
4475  (Fcb->FcbCondition == FcbGood)) {
4476 
4477  FatLookupFileAllocationSize( IrpContext, Fcb );
4478  }
4479 
4480  //
4481  // This is kinda gross, but if the file is not cached, but there is
4482  // a data section, we have to cache the file to avoid a bunch of
4483  // extra work.
4484  //
4485 
4486  if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
4487  (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
4488  !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
4489 
4490  if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
4491 
4492  //
4493  // This IRP has raced (and lost) with a close (=>cleanup)
4494  // on the same fileobject. We don't want to reinitialise the
4495  // cachemap here now because we'll leak it (unless we do so &
4496  // then tear it down again here, which is too much of a change at
4497  // this stage). So we'll just say the file is closed - which
4498  // is arguably the right thing to do anyway, since a caller
4499  // racing operations in this way is broken. The only stumbling
4500  // block is possibly filters - do they operate on cleaned
4501  // up fileobjects?
4502  //
4503 
4504  FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED);
4505  }
4506 
4507  //
4508  // Now initialize the cache map.
4509  //
4510 
4512  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
4513  FALSE,
4515  Fcb );
4516 
4517  CacheMapInitialized = TRUE;
4518  }
4519 
4520  //
4521  // Do a special case here for the lazy write of file sizes.
4522  //
4523 
4524  if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.AdvanceOnly) {
4525 
4526  //
4527  // Only attempt this if the file hasn't been "deleted on close" and
4528  // this is a good FCB.
4529  //
4530 
4531  if (!IsFileDeleted( IrpContext, Fcb ) && (Fcb->FcbCondition == FcbGood)) {
4532 
4533  PDIRENT Dirent = NULL;
4534  PBCB DirentBcb;
4535 
4536 
4537  //
4538  // Never have the dirent filesize larger than the fcb filesize
4539  //
4540 
4541  if (NewFileSize >= Fcb->Header.FileSize.LowPart) {
4542 
4543  NewFileSize = Fcb->Header.FileSize.LowPart;
4544  }
4545 
4546  //
4547  // Make sure we don't set anything higher than the alloc size.
4548  //
4549 
4550 
4551  NT_ASSERT( NewFileSize <= Fcb->Header.AllocationSize.LowPart );
4552 
4553 
4554  //
4555  // Only advance the file size, never reduce it with this call
4556  //
4557 
4558  FatGetDirentFromFcbOrDcb( IrpContext,
4559  Fcb,
4560  FALSE,
4561  &Dirent,
4562  &DirentBcb );
4563  _SEH2_TRY {
4564 
4565 
4566  if ( NewFileSize > Dirent->FileSize ) {
4567  Dirent->FileSize = NewFileSize;
4568 
4569  FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
4570 
4571  //
4572  // Report that we just changed the file size.
4573  //
4574 
4575  FatNotifyReportChange( IrpContext,
4576  Vcb,
4577  Fcb,
4580 
4581  }
4582 
4583  } _SEH2_FINALLY {
4584 
4585  FatUnpinBcb( IrpContext, DirentBcb );
4586  } _SEH2_END;
4587 
4588  } else {
4589 
4590  DebugTrace(0, Dbg, "Cannot set size on deleted file.\n", 0);
4591  }
4592 
4594  }
4595 
4596  //
4597  // Check if the new file size is greater than the current
4598  // allocation size. If it is then we need to increase the
4599  // allocation size.
4600  //
4601 
4602 
4603  if ( (NewFileSize) > Fcb->Header.AllocationSize.LowPart ) {
4604 
4605  //
4606  // Change the file allocation
4607  //
4608 
4609  FatAddFileAllocation( IrpContext, Fcb, FileObject, NewFileSize );
4610  }
4611 
4612 
4613  //
4614  // At this point we have enough allocation for the file.
4615  // So check if we are really changing the file size
4616  //
4617 
4618  if (Fcb->Header.FileSize.LowPart != NewFileSize) {
4619 
4620  if ( NewFileSize < Fcb->Header.FileSize.LowPart ) {
4621 
4622  //
4623  // The way Sections for DataScan are created and used, an AV's
4624  // memory-mapping can come into being after we check it's safe
4625  // to truncate a file while continuing to hold the file here.
4626  // This leads to data corruption because Purge eventually fails
4627  // (during call to Cc to set file sizes) and stale data continues
4628  // to live in the cache/memory.
4629  //
4630 
4631  if (Fcb->PurgeFailureModeEnableCount != 0) {
4632 
4634  }
4635 
4636  //
4637  // Before we actually truncate, check to see if the purge
4638  // is going to fail.
4639  //
4640 
4641  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4642  &Buffer->EndOfFile )) {
4643 
4645  }
4646 
4647  //
4648  // This call is unconditional, because MM always wants to know.
4649  // Also serialize here with paging io since we are truncating
4650  // the file size.
4651  //
4652 
4653  ResourceAcquired =
4654  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4655  }
4656 
4657  //
4658  // Set the new file size
4659  //
4660 
4661  InitialFileSize = Fcb->Header.FileSize.LowPart;
4662  InitialValidDataLength = Fcb->Header.ValidDataLength.LowPart;
4663  InitialValidDataToDisk = Fcb->ValidDataToDisk;
4664  UnwindFileSizes = TRUE;
4665 
4666  Fcb->Header.FileSize.LowPart = NewFileSize;
4667 
4668  //
4669  // If we reduced the file size to less than the ValidDataLength,
4670  // adjust the VDL. Likewise ValidDataToDisk.
4671  //
4672 
4673  if (Fcb->Header.ValidDataLength.LowPart > NewFileSize) {
4674 
4675  Fcb->Header.ValidDataLength.LowPart = NewFileSize;
4676  }
4677 
4678  if (Fcb->ValidDataToDisk > NewFileSize) {
4679 
4681  }
4682 
4683  DebugTrace(0, Dbg, "New file size is 0x%08lx.\n", NewFileSize);
4684 
4685  //
4686  // We must now update the cache mapping (benign if not cached).
4687  //
4688 
4690  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4691 
4692  FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
4693 
4694  //
4695  // Report that we just changed the file size.
4696  //
4697 
4698  FatNotifyReportChange( IrpContext,
4699  Vcb,
4700  Fcb,
4703 
4704  //
4705  // Mark the fact that the file will need to checked for
4706  // truncation on cleanup.
4707  //
4708 
4710  }
4711 
4712  //
4713  // Set this handle as having modified the file
4714  //
4715 
4716  FileObject->Flags |= FO_FILE_MODIFIED;
4717 
4718  //
4719  // Set our return status to success
4720  //
4721 
4723 
4724  try_exit: NOTHING;
4725 
4726  FatUnpinRepinnedBcbs( IrpContext );
4727 
4728  } _SEH2_FINALLY {
4729 
4730  DebugUnwind( FatSetEndOfFileInfo );
4731 
4732  if (_SEH2_AbnormalTermination() && UnwindFileSizes) {
4733 
4734  Fcb->Header.FileSize.LowPart = InitialFileSize;
4735  Fcb->Header.ValidDataLength.LowPart = InitialValidDataLength;
4736  Fcb->ValidDataToDisk = InitialValidDataToDisk;
4737 
4738  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4739 
4740  *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
4741  }
4742 
4743  //
4744  // WinSE bug #307418 "Occasional data corruption when
4745  // standby/resume while copying files to removable FAT
4746  // formatted media".
4747  // On system suspend FatUnpinRepinnedBcbs() can fail
4748  // because the underlying drive is already marked with DO_VERIFY
4749  // flag. FatUnpinRepinnedBcbs() will raise in this case and
4750  // the file size changes will be un-rolled in FCB but the change
4751  // to Dirent file still can make it to the disk since its BCB
4752  // will not be purged by FatUnpinRepinnedBcbs(). In this case
4753  // we'll also try to un-roll the change to Dirent to keep
4754  // in-memory and on-disk metadata in sync.
4755  //
4756 
4757  FatSetFileSizeInDirentNoRaise( IrpContext, Fcb, NULL );
4758 
4759  }
4760 
4761  if (CacheMapInitialized) {
4762 
4764  }
4765 
4766  if ( ResourceAcquired ) {
4767 
4768  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4769  }
4770 
4771  DebugTrace(-1, Dbg, "FatSetEndOfFileInfo -> %08lx\n", Status);
4772  } _SEH2_END;
4773 
4774  return Status;
4775 }
4776 
4777 
4778 //
4779 // Internal Support Routine
4780 //
4781 
4782 _Requires_lock_held_(_Global_critical_region_)
4783 NTSTATUS
4784 FatSetValidDataLengthInfo (
4785  IN PIRP_CONTEXT IrpContext,
4786  IN PIRP Irp,
4788  IN PFCB Fcb,
4789  IN PCCB Ccb
4790  )
4791 
4792 /*++
4793 
4794 Routine Description:
4795 
4796  This routine performs the set valid data length information for fat. It either
4797  completes the request or enqueues it off to the fsp.
4798 
4799 Arguments:
4800 
4801  Irp - Supplies the irp being processed
4802 
4803  FileObject - Supplies the file object being processed
4804 
4805  Fcb - Supplies the Fcb or Dcb being processed, already known not to
4806  be the root dcb
4807 
4808  Ccb - Supplies the Ccb corresponding to the handle opening the source
4809  file
4810 
4811 Return Value:
4812 
4813  NTSTATUS - The result of this operation if it completes without
4814  an exception.
4815 
4816 --*/
4817 
4818 {
4820 
4822 
4823  ULONG NewValidDataLength;
4824  BOOLEAN ResourceAcquired = FALSE;
4825 
4826  PAGED_CODE();
4827 
4828  UNREFERENCED_PARAMETER( IrpContext );
4829 
4830  DebugTrace(+1, Dbg, "FatSetValidDataLengthInfo...\n", 0);
4831 
4832  Buffer = Irp->AssociatedIrp.SystemBuffer;
4833 
4834  _SEH2_TRY {
4835 
4836  //
4837  // User must have manage volume privilege to explicitly tweak the VDL
4838  //
4839 
4840  if ((Ccb == NULL) || !FlagOn( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS )) {
4841 
4843  }
4844 
4845  //
4846  // Valid data length changes are only allowed on a file and not a directory
4847  //
4848 
4849  if (NodeType(Fcb) != FAT_NTC_FCB) {
4850 
4851  DebugTrace(0, Dbg, "Cannot change VDL of a directory\n", 0);
4852 
4854  }
4855 
4856  //
4857  // Check that the new file size is legal
4858  //
4859 
4860 
4861  if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->ValidDataLength, 0)) {
4862 
4863  DebugTrace(0, Dbg, "Illegal allocation size\n", 0);
4864 
4866  }
4867 
4868 
4869  NewValidDataLength = Buffer->ValidDataLength.LowPart;
4870 
4871  //
4872  // VDL can only move forward
4873  //
4874 
4875  if ((NewValidDataLength < Fcb->Header.ValidDataLength.LowPart) ||
4876  (NewValidDataLength > Fcb->Header.FileSize.LowPart)) {
4877 
4879  }
4880 
4881  //
4882  // We can't change the VDL without being able to purge. This should stay
4883  // constant since we own everything exclusive
4884  //
4885 
4886  if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
4887  &Buffer->ValidDataLength )) {
4888 
4890  }
4891 
4892  //
4893  // Flush old data out and purge the cache so we can see new data.
4894  //
4895 
4896  if (FileObject->SectionObjectPointer->DataSectionObject != NULL) {
4897 
4898  ResourceAcquired =
4899  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
4900 
4901  CcFlushCache( FileObject->SectionObjectPointer,
4902  NULL,
4903  0,
4904  &Irp->IoStatus );
4905 
4906  if (!NT_SUCCESS( Irp->IoStatus.Status )) {
4907 
4908  try_return( Irp->IoStatus.Status );
4909  }
4910 
4911  CcPurgeCacheSection( FileObject->SectionObjectPointer,
4912  NULL,
4913  0,
4914  FALSE );
4915  }
4916 
4917  //
4918  // Set the new ValidDataLength, Likewise ValidDataToDisk.
4919  //
4920 
4921  Fcb->Header.ValidDataLength.LowPart = NewValidDataLength;
4922  Fcb->ValidDataToDisk = NewValidDataLength;
4923 
4924  DebugTrace(0, Dbg, "New VDL is 0x%08lx.\n", NewValidDataLength);
4925 
4926  //
4927  // We must now update the cache mapping.
4928  //
4929 
4930  if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
4931 
4933  (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
4934  }
4935 
4936  //
4937  // Set this handle as having modified the file
4938  //
4939 
4940  FileObject->Flags |= FO_FILE_MODIFIED;
4941 
4942  //
4943  // Set our return status to success
4944  //
4945 
4947 
4948  try_exit: NOTHING;
4949 
4950  } _SEH2_FINALLY {
4951 
4952  DebugUnwind( FatSetValidDataLengthInfo );
4953 
4954  if (ResourceAcquired) {
4955 
4956  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
4957  }
4958 
4959  DebugTrace(-1, Dbg, "FatSetValidDataLengthInfo -> %08lx\n", Status);
4960  } _SEH2_END;
4961 
4962  return Status;
4963 }
4964 
4965 
4966 
4967 //
4968 // Internal Support Routine
4969 //
4970 
4971 _Requires_lock_held_(_Global_critical_region_)
4972 VOID
4973 FatRenameEAs (
4974  IN PIRP_CONTEXT IrpContext,
4975  IN PFCB Fcb,
4976  IN USHORT ExtendedAttributes,
4977  IN POEM_STRING OldOemName
4978  )
4979 {
4980  BOOLEAN LockedEaFcb = FALSE;
4981 
4982  PBCB EaBcb = NULL;
4983  PDIRENT EaDirent;
4985  PEA_SET_HEADER EaSetHeader;
4986 
4987  PVCB Vcb;
4988 
4989  PAGED_CODE();
4990 
4991  RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
4992 
4993  Vcb = Fcb->Vcb;
4994 
4995  _SEH2_TRY {
4996 
4997  //
4998  // Use a try-except to catch any errors.
4999  //
5000 
5001  _SEH2_TRY {
5002 
5003 
5004  //
5005  // Try to get the Ea file object. Return FALSE on failure.
5006  //
5007 
5008  FatGetEaFile( IrpContext,
5009  Vcb,
5010  &EaDirent,
5011  &EaBcb,
5012  FALSE,
5013  FALSE );
5014 
5015  LockedEaFcb = TRUE;
5016 
5017  //
5018  // If we didn't get the file because it doesn't exist, then the
5019  // disk is corrupted. We do nothing here.
5020  //
5021 
5022  if (Vcb->VirtualEaFile != NULL) {
5023 
5024  //
5025  // Try to pin down the Ea set header for the index in the
5026  // dirent. If the operation doesn't complete, return FALSE
5027  // from this routine.
5028  //
5029 
5030  FatReadEaSet( IrpContext,
5031  Vcb,
5032  ExtendedAttributes,
5033  OldOemName,
5034  FALSE,
5035  &EaSetRange );
5036 
5037  EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
5038 
5039  //
5040  // We now have the Ea set header for this file. We simply
5041  // overwrite the owning file name.
5042  //
5043 
5044  RtlZeroMemory( EaSetHeader->OwnerFileName, 14 );
5045 
5046  RtlCopyMemory( EaSetHeader->OwnerFileName,
5047  Fcb->ShortName.Name.Oem.Buffer,
5048  Fcb->ShortName.Name.Oem.Length );
5049 
5050  FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange );
5051  FatUnpinEaRange( IrpContext, &EaSetRange );
5052 
5053  CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
5054  }
5055 
5057 
5058  //
5059  // We catch all exceptions that Fat catches, but don't do
5060  // anything with them.
5061  //
5062  } _SEH2_END;
5063 
5064  } _SEH2_FINALLY {
5065 
5066  //
5067  // Unpin the EaDirent and the EaSetHeader if pinned.
5068  //
5069 
5070  FatUnpinBcb( IrpContext, EaBcb );
5071  FatUnpinEaRange( IrpContext, &EaSetRange );
5072 
5073  //
5074  // Release the Fcb for the Ea file if locked.
5075  //
5076 
5077  if (LockedEaFcb) {
5078 
5079  FatReleaseFcb( IrpContext, Vcb->EaFcb );
5080  }
5081  } _SEH2_END;
5082 
5083  return;
5084 }
5085 
5086 _Requires_lock_held_(_Global_critical_region_)
5087 VOID
5088 FatDeleteFile (
5089  IN PIRP_CONTEXT IrpContext,
5090  IN PDCB TargetDcb,
5091  IN ULONG LfnOffset,
5093  IN PDIRENT Dirent,
5095  )
5096 {
5097  PFCB Fcb;
5098  PLIST_ENTRY Links;
5099 
5100  PAGED_CODE();
5101 
5102  //
5103  // We can do the replace by removing the other Fcb(s) from
5104  // the prefix table.
5105  //
5106 
5107  for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
5108  Links != &TargetDcb->Specific.Dcb.ParentDcbQueue;
5109  Links = Links->Flink) {
5110 
5111  Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
5112 
5115 
5118 
5119  if ( Fcb->UncleanCount != 0 ) {
5120 
5121 #ifdef _MSC_VER
5122 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
5123 #endif
5124  FatBugCheck(0,0,0);
5125 
5126  } else {
5127 
5129 
5130  //
5131  // Make this fcb "appear" deleted, synchronizing with
5132  // paging IO.
5133  //
5134 
5135  FatRemoveNames( IrpContext, Fcb );
5136 
5137  Resource = Fcb->Header.PagingIoResource;
5138 
5140 
5142 
5143  Fcb->ValidDataToDisk = 0;
5144  Fcb->Header.FileSize.QuadPart =
5145  Fcb->Header.ValidDataLength.QuadPart = 0;
5146 
5147  Fcb->FirstClusterOfFile = 0;
5148 
5150  }
5151  }
5152  }
5153 
5154  //
5155  // The file is not currently opened so we can delete the file
5156  // that is being overwritten. To do the operation we dummy
5157  // up an fcb, truncate allocation, delete the fcb, and delete
5158  // the dirent.
5159  //
5160 
5161  Fcb = FatCreateFcb( IrpContext,
5162  TargetDcb->Vcb,
5163  TargetDcb,
5164  LfnOffset,
5165  DirentOffset,
5166  Dirent,
5167  Lfn,
5168  NULL,
5169  FALSE,
5170  FALSE );
5171 
5172  Fcb->Header.FileSize.LowPart = 0;
5173 
5174  _SEH2_TRY {
5175 
5176  FatTruncateFileAllocation( IrpContext, Fcb, 0 );
5177 
5178  FatDeleteDirent( IrpContext, Fcb, NULL, TRUE );
5179 
5180  } _SEH2_FINALLY {
5181 
5182  FatDeleteFcb( IrpContext, &Fcb );
5183  } _SEH2_END;
5184 }
5185 
5186 
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:1303
IN PDCB IN POEM_STRING IN PUNICODE_STRING IN OUT POEM_STRING ShortName
Definition: fatprocs.h:1303
#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:3010
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:386
#define IN
Definition: typedefs.h:39
struct _FILE_INTERNAL_INFORMATION FILE_INTERNAL_INFORMATION
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:2992
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:411
#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:1303
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:2630
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:4137
_In_ PIRP Irp
Definition: csq.h:116
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
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:56
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::@713 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:2165
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
#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
PVPB Vpb
Definition: cdstruc.h:517
#define FILE_NOTIFY_CHANGE_LAST_WRITE
struct _FCB::@712::@714 Dcb
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:56
#define FO_NO_INTERMEDIATE_BUFFERING
Definition: iotypes.h:1758
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:2974
#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
_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:850
_SEH2_TRY
Definition: create.c:4226
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2410
#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:913
#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:788
NTSTATUS FatSetPositionInfo(IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFILE_OBJECT FileObject)
Definition: fileinfo.c:4010
#define FO_FILE_MODIFIED
Definition: iotypes.h:1768
_Function_class_(FAST_IO_QUERY_BASIC_INFO)
Definition: fileinfo.c:465
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:588
#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:6718
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:843
#define FALSE
Definition: types.h:117
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
union _FILE_NAME_NODE::@711 Name
#define FAT_LFN_DIRENTS_NEEDED(NAME)
Definition: lfn.h:53
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
static INLINE BOOLEAN FatIsIoRangeValid(IN PVCB Vcb, IN LARGE_INTEGER Start, IN ULONG Length)
Definition: fatprocs.h:218
#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
PNON_PAGED_FCB NonPaged
Definition: fatstruc.h:810
#define FatUnpinBcb(IRPCONTEXT, BCB)
Definition: fatprocs.h:546
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:711
IN PDCB TargetDcb
Definition: fatprocs.h:788
NodeType
Definition: Node.h:5
#define FCB_STATE_TRUNCATE_ON_CLOSE
Definition: fatstruc.h:1193
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:588
PIRP_CONTEXT FatCreateIrpContext(IN PIRP Irp, IN BOOLEAN Wait)
Definition: strucsup.c:2289
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
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
union _CCB::@716::@718::@720 OemQueryTemplate
#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:121
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:1198
#define DebugUnwind(X)
Definition: fatdata.h:315
FAT_DATA FatData
Definition: fatdata.c:56
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1644
VOID FatDeleteFcb(IN PIRP_CONTEXT IrpContext, IN PFCB *Fcb)
Definition: strucsup.c:1940
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:4402
#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:2179
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:1240
struct _DEVICE_OBJECT * RealDevice
Definition: iotypes.h:174
VBO LfnOffsetWithinDirectory
Definition: fatstruc.h:912
IN PVCB IN ULONG IN PBCB OUT PDIRENT OUT PUSHORT OUT PEA_RANGE EaSetRange
Definition: fatprocs.h:945
#define Vcb
Definition: cdprocs.h:1415
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:2848
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:3202
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define _Inout_
Definition: no_sal2.h:244
#define TAG_FILENAME_BUFFER
Definition: nodetype.h:167
#define STATUS_PURGE_FAILED
Definition: ntstatus.h:964
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define AlmostTenMSec
Definition: fatdata.h:124
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
LARGE_INTEGER FatOneDay
Definition: fatdata.c:72
#define VCB_STATE_FLAG_CREATE_IN_PROGRESS
Definition: fatstruc.h:565
struct _FILE_EA_INFORMATION FILE_EA_INFORMATION
BOOLEAN NTAPI FsRtlCurrentBatchOplock(IN POPLOCK Oplock)
Definition: oplock.c:1366
* PFILE_OBJECT
Definition: iotypes.h:1978
UNICODE_STRING FullFileName
Definition:</