Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5654 lines
165 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Create.c
  5. Abstract:
  6. This module implements the File Create routine for Fat called by the
  7. dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 28-Dec-1989
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_CREATE)
  19. //
  20. // The debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_CREATE)
  23. //
  24. // Macros for incrementing performance counters.
  25. //
  26. #define CollectCreateHitStatistics(VCB) { \
  27. PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()]; \
  28. Stats->Fat.CreateHits += 1; \
  29. }
  30. #define CollectCreateStatistics(VCB,STATUS) { \
  31. PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()]; \
  32. if ((STATUS) == STATUS_SUCCESS) { \
  33. Stats->Fat.SuccessfulCreates += 1; \
  34. } else { \
  35. Stats->Fat.FailedCreates += 1; \
  36. } \
  37. }
  38. LUID FatSecurityPrivilege = { SE_SECURITY_PRIVILEGE, 0 };
  39. //
  40. // local procedure prototypes
  41. //
  42. IO_STATUS_BLOCK
  43. FatOpenVolume (
  44. IN PIRP_CONTEXT IrpContext,
  45. IN PFILE_OBJECT FileObject,
  46. IN PVCB Vcb,
  47. IN PACCESS_MASK DesiredAccess,
  48. IN USHORT ShareAccess,
  49. IN ULONG CreateDisposition
  50. );
  51. IO_STATUS_BLOCK
  52. FatOpenRootDcb (
  53. IN PIRP_CONTEXT IrpContext,
  54. IN PFILE_OBJECT FileObject,
  55. IN PVCB Vcb,
  56. IN PACCESS_MASK DesiredAccess,
  57. IN USHORT ShareAccess,
  58. IN ULONG CreateDisposition
  59. );
  60. IO_STATUS_BLOCK
  61. FatOpenExistingDcb (
  62. IN PIRP_CONTEXT IrpContext,
  63. IN PFILE_OBJECT FileObject,
  64. IN PVCB Vcb,
  65. IN PDCB Dcb,
  66. IN PACCESS_MASK DesiredAccess,
  67. IN USHORT ShareAccess,
  68. IN ULONG CreateDisposition,
  69. IN BOOLEAN NoEaKnowledge,
  70. IN BOOLEAN DeleteOnClose
  71. );
  72. IO_STATUS_BLOCK
  73. FatOpenExistingFcb (
  74. IN PIRP_CONTEXT IrpContext,
  75. IN PFILE_OBJECT FileObject,
  76. IN PVCB Vcb,
  77. IN PFCB Fcb,
  78. IN PACCESS_MASK DesiredAccess,
  79. IN USHORT ShareAccess,
  80. IN ULONG AllocationSize,
  81. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  82. IN ULONG EaLength,
  83. IN UCHAR FileAttributes,
  84. IN ULONG CreateDisposition,
  85. IN BOOLEAN DeleteOnClose,
  86. IN BOOLEAN NoEaKnowledge,
  87. IN BOOLEAN FileNameOpenedDos,
  88. OUT PBOOLEAN OplockPostIrp
  89. );
  90. IO_STATUS_BLOCK
  91. FatOpenTargetDirectory (
  92. IN PIRP_CONTEXT IrpContext,
  93. IN PFILE_OBJECT FileObject,
  94. IN PDCB Dcb,
  95. IN PACCESS_MASK DesiredAccess,
  96. IN USHORT ShareAccess,
  97. IN BOOLEAN DoesNameExist
  98. );
  99. IO_STATUS_BLOCK
  100. FatOpenExistingDirectory (
  101. IN PIRP_CONTEXT IrpContext,
  102. IN PFILE_OBJECT FileObject,
  103. IN PVCB Vcb,
  104. IN PDCB ParentDcb,
  105. IN PDIRENT Dirent,
  106. IN ULONG LfnByteOffset,
  107. IN ULONG DirentByteOffset,
  108. IN PUNICODE_STRING Lfn,
  109. IN PACCESS_MASK DesiredAccess,
  110. IN USHORT ShareAccess,
  111. IN ULONG CreateDisposition,
  112. IN BOOLEAN NoEaKnowledge,
  113. IN BOOLEAN DeleteOnClose
  114. );
  115. IO_STATUS_BLOCK
  116. FatOpenExistingFile (
  117. IN PIRP_CONTEXT IrpContext,
  118. IN PFILE_OBJECT FileObject,
  119. IN PVCB Vcb,
  120. IN PDCB ParentDcb,
  121. IN PDIRENT Dirent,
  122. IN ULONG LfnByteOffset,
  123. IN ULONG DirentByteOffset,
  124. IN PUNICODE_STRING Lfn,
  125. IN PACCESS_MASK DesiredAccess,
  126. IN USHORT ShareAccess,
  127. IN ULONG AllocationSize,
  128. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  129. IN ULONG EaLength,
  130. IN UCHAR FileAttributes,
  131. IN ULONG CreateDisposition,
  132. IN BOOLEAN IsPagingFile,
  133. IN BOOLEAN NoEaKnowledge,
  134. IN BOOLEAN DeleteOnClose,
  135. IN BOOLEAN FileNameOpenedDos
  136. );
  137. IO_STATUS_BLOCK
  138. FatCreateNewDirectory (
  139. IN PIRP_CONTEXT IrpContext,
  140. IN PFILE_OBJECT FileObject,
  141. IN PVCB Vcb,
  142. IN PDCB ParentDcb,
  143. IN POEM_STRING OemName,
  144. IN PUNICODE_STRING UnicodeName,
  145. IN PACCESS_MASK DesiredAccess,
  146. IN USHORT ShareAccess,
  147. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  148. IN ULONG EaLength,
  149. IN UCHAR FileAttributes,
  150. IN BOOLEAN NoEaKnowledge,
  151. IN BOOLEAN DeleteOnClose
  152. );
  153. IO_STATUS_BLOCK
  154. FatCreateNewFile (
  155. IN PIRP_CONTEXT IrpContext,
  156. IN PFILE_OBJECT FileObject,
  157. IN PVCB Vcb,
  158. IN PDCB ParentDcb,
  159. IN POEM_STRING OemName,
  160. IN PUNICODE_STRING UnicodeName,
  161. IN PACCESS_MASK DesiredAccess,
  162. IN USHORT ShareAccess,
  163. IN ULONG AllocationSize,
  164. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  165. IN ULONG EaLength,
  166. IN UCHAR FileAttributes,
  167. IN PUNICODE_STRING LfnBuffer,
  168. IN BOOLEAN IsPagingFile,
  169. IN BOOLEAN NoEaKnowledge,
  170. IN BOOLEAN DeleteOnClose,
  171. IN BOOLEAN TemporaryFile
  172. );
  173. IO_STATUS_BLOCK
  174. FatSupersedeOrOverwriteFile (
  175. IN PIRP_CONTEXT IrpContext,
  176. IN PFILE_OBJECT FileObject,
  177. IN PFCB Fcb,
  178. IN ULONG AllocationSize,
  179. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  180. IN ULONG EaLength,
  181. IN UCHAR FileAttributes,
  182. IN ULONG CreateDisposition,
  183. IN BOOLEAN NoEaKnowledge
  184. );
  185. NTSTATUS
  186. FatCheckSystemSecurityAccess(
  187. PIRP_CONTEXT IrpContext
  188. );
  189. #ifdef ALLOC_PRAGMA
  190. #pragma alloc_text(PAGE, FatCheckSystemSecurityAccess)
  191. #pragma alloc_text(PAGE, FatCommonCreate)
  192. #pragma alloc_text(PAGE, FatCreateNewDirectory)
  193. #pragma alloc_text(PAGE, FatCreateNewFile)
  194. #pragma alloc_text(PAGE, FatFsdCreate)
  195. #pragma alloc_text(PAGE, FatOpenExistingDcb)
  196. #pragma alloc_text(PAGE, FatOpenExistingDirectory)
  197. #pragma alloc_text(PAGE, FatOpenExistingFcb)
  198. #pragma alloc_text(PAGE, FatOpenExistingFile)
  199. #pragma alloc_text(PAGE, FatOpenRootDcb)
  200. #pragma alloc_text(PAGE, FatOpenTargetDirectory)
  201. #pragma alloc_text(PAGE, FatOpenVolume)
  202. #pragma alloc_text(PAGE, FatSupersedeOrOverwriteFile)
  203. #pragma alloc_text(PAGE, FatSetFullNameInFcb)
  204. #endif
  205. NTSTATUS
  206. FatFsdCreate (
  207. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  208. IN PIRP Irp
  209. )
  210. /*++
  211. Routine Description:
  212. This routine implements the FSD part of the NtCreateFile and NtOpenFile
  213. API calls.
  214. Arguments:
  215. VolumeDeviceObject - Supplies the volume device object where the
  216. file/directory exists that we are trying to open/create
  217. Irp - Supplies the Irp being processed
  218. Return Value:
  219. NTSTATUS - The Fsd status for the Irp
  220. --*/
  221. {
  222. NTSTATUS Status;
  223. PIRP_CONTEXT IrpContext = NULL;
  224. BOOLEAN TopLevel;
  225. //
  226. // If we were called with our file system device object instead of a
  227. // volume device object, just complete this request with STATUS_SUCCESS
  228. //
  229. if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) {
  230. Irp->IoStatus.Status = STATUS_SUCCESS;
  231. Irp->IoStatus.Information = FILE_OPENED;
  232. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  233. return STATUS_SUCCESS;
  234. }
  235. TimerStart(Dbg);
  236. DebugTrace(+1, Dbg, "FatFsdCreate\n", 0);
  237. //
  238. // Call the common create routine, with block allowed if the operation
  239. // is synchronous.
  240. //
  241. FsRtlEnterFileSystem();
  242. TopLevel = FatIsIrpTopLevel( Irp );
  243. try {
  244. IrpContext = FatCreateIrpContext( Irp, TRUE );
  245. Status = FatCommonCreate( IrpContext, Irp );
  246. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  247. //
  248. // We had some trouble trying to perform the requested
  249. // operation, so we'll abort the I/O request with
  250. // the error status that we get back from the
  251. // execption code
  252. //
  253. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  254. }
  255. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  256. FsRtlExitFileSystem();
  257. //
  258. // And return to our caller
  259. //
  260. DebugTrace(-1, Dbg, "FatFsdCreate -> %08lx\n", Status );
  261. TimerStop(Dbg,"FatFsdCreate");
  262. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  263. return Status;
  264. }
  265. NTSTATUS
  266. FatCommonCreate (
  267. IN PIRP_CONTEXT IrpContext,
  268. IN PIRP Irp
  269. )
  270. /*++
  271. Routine Description:
  272. This is the common routine for creating/opening a file called by
  273. both the fsd and fsp threads.
  274. Arguments:
  275. Irp - Supplies the Irp to process
  276. Return Value:
  277. NTSTATUS - the return status for the operation
  278. --*/
  279. {
  280. NTSTATUS Status;
  281. IO_STATUS_BLOCK Iosb;
  282. PIO_STACK_LOCATION IrpSp;
  283. PFILE_OBJECT FileObject;
  284. PFILE_OBJECT RelatedFileObject;
  285. UNICODE_STRING FileName;
  286. ULONG AllocationSize;
  287. PFILE_FULL_EA_INFORMATION EaBuffer;
  288. PACCESS_MASK DesiredAccess;
  289. ULONG Options;
  290. UCHAR FileAttributes;
  291. USHORT ShareAccess;
  292. ULONG EaLength;
  293. BOOLEAN CreateDirectory;
  294. BOOLEAN SequentialOnly;
  295. BOOLEAN NoIntermediateBuffering;
  296. BOOLEAN OpenDirectory;
  297. BOOLEAN IsPagingFile;
  298. BOOLEAN OpenTargetDirectory;
  299. BOOLEAN DirectoryFile;
  300. BOOLEAN NonDirectoryFile;
  301. BOOLEAN NoEaKnowledge;
  302. BOOLEAN DeleteOnClose;
  303. BOOLEAN TemporaryFile;
  304. BOOLEAN FileNameOpenedDos = FALSE;
  305. ULONG CreateDisposition;
  306. PVCB Vcb;
  307. PFCB Fcb;
  308. PCCB Ccb;
  309. PDCB ParentDcb;
  310. PDCB FinalDcb = NULL;
  311. UNICODE_STRING FinalName;
  312. UNICODE_STRING RemainingPart;
  313. UNICODE_STRING NextRemainingPart;
  314. UNICODE_STRING UpcasedFinalName;
  315. WCHAR UpcasedBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
  316. OEM_STRING OemFinalName;
  317. UCHAR OemBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE*2];
  318. BOOLEAN FreeOemBuffer;
  319. BOOLEAN FreeUpcasedBuffer;
  320. PDIRENT Dirent;
  321. PBCB DirentBcb = NULL;
  322. ULONG LfnByteOffset;
  323. ULONG DirentByteOffset;
  324. BOOLEAN PostIrp = FALSE;
  325. BOOLEAN OplockPostIrp = FALSE;
  326. BOOLEAN TrailingBackslash;
  327. BOOLEAN FirstLoop = TRUE;
  328. CCB LocalCcb;
  329. UNICODE_STRING Lfn;
  330. WCHAR LfnBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
  331. //
  332. // Get the current IRP stack location
  333. //
  334. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  335. DebugTrace(+1, Dbg, "FatCommonCreate\n", 0 );
  336. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  337. DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags );
  338. DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject );
  339. DebugTrace( 0, Dbg, " ->RelatedFileObject = %08lx\n", IrpSp->FileObject->RelatedFileObject );
  340. DebugTrace( 0, Dbg, " ->FileName = %Z\n", &IrpSp->FileObject->FileName );
  341. DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
  342. DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
  343. DebugTrace( 0, Dbg, "->SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer );
  344. DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
  345. DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options );
  346. DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes );
  347. DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess );
  348. DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
  349. //
  350. // This is here because the Win32 layer can't avoid sending me double
  351. // beginning backslashes.
  352. //
  353. if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
  354. (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
  355. (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
  356. IrpSp->FileObject->FileName.Length -= sizeof(WCHAR);
  357. RtlMoveMemory( &IrpSp->FileObject->FileName.Buffer[0],
  358. &IrpSp->FileObject->FileName.Buffer[1],
  359. IrpSp->FileObject->FileName.Length );
  360. //
  361. // If there are still two beginning backslashes, the name is bogus.
  362. //
  363. if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
  364. (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
  365. (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
  366. FatCompleteRequest( IrpContext, Irp, STATUS_OBJECT_NAME_INVALID );
  367. DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_OBJECT_NAME_INVALID\n", 0);
  368. return STATUS_OBJECT_NAME_INVALID;
  369. }
  370. }
  371. //
  372. // Reference our input parameters to make things easier
  373. //
  374. ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
  375. FileObject = IrpSp->FileObject;
  376. FileName = FileObject->FileName;
  377. RelatedFileObject = FileObject->RelatedFileObject;
  378. AllocationSize = Irp->Overlay.AllocationSize.LowPart;
  379. EaBuffer = Irp->AssociatedIrp.SystemBuffer;
  380. DesiredAccess = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  381. Options = IrpSp->Parameters.Create.Options;
  382. FileAttributes = (UCHAR)(IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL);
  383. ShareAccess = IrpSp->Parameters.Create.ShareAccess;
  384. EaLength = IrpSp->Parameters.Create.EaLength;
  385. //
  386. // Set up the file object's Vpb pointer in case anything happens.
  387. // This will allow us to get a reasonable pop-up.
  388. //
  389. if ( RelatedFileObject != NULL ) {
  390. FileObject->Vpb = RelatedFileObject->Vpb;
  391. }
  392. //
  393. // Force setting the archive bit in the attributes byte to follow OS/2,
  394. // & DOS semantics. Also mask out any extraneous bits, note that
  395. // we can't use the ATTRIBUTE_VALID_FLAGS constant because that has
  396. // the control and normal flags set.
  397. //
  398. // Delay setting ARCHIVE in case this is a directory: DavidGoe 2/16/95
  399. //
  400. FileAttributes &= (FILE_ATTRIBUTE_READONLY |
  401. FILE_ATTRIBUTE_HIDDEN |
  402. FILE_ATTRIBUTE_SYSTEM |
  403. FILE_ATTRIBUTE_ARCHIVE );
  404. //
  405. // Locate the volume device object and Vcb that we are trying to access
  406. //
  407. Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
  408. //
  409. // Decipher Option flags and values
  410. //
  411. //
  412. // If this is an open by fileid operation, just fail it explicitly. FAT's
  413. // source of fileids is not reversible for open operations.
  414. //
  415. if (BooleanFlagOn( Options, FILE_OPEN_BY_FILE_ID )) {
  416. FatCompleteRequest( IrpContext, Irp, STATUS_NOT_IMPLEMENTED );
  417. return STATUS_NOT_IMPLEMENTED;
  418. }
  419. DirectoryFile = BooleanFlagOn( Options, FILE_DIRECTORY_FILE );
  420. NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE );
  421. SequentialOnly = BooleanFlagOn( Options, FILE_SEQUENTIAL_ONLY );
  422. NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
  423. NoEaKnowledge = BooleanFlagOn( Options, FILE_NO_EA_KNOWLEDGE );
  424. DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );
  425. TemporaryFile = BooleanFlagOn( IrpSp->Parameters.Create.FileAttributes,
  426. FILE_ATTRIBUTE_TEMPORARY );
  427. CreateDisposition = (Options >> 24) & 0x000000ff;
  428. IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE );
  429. OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
  430. CreateDirectory = (BOOLEAN)(DirectoryFile &&
  431. ((CreateDisposition == FILE_CREATE) ||
  432. (CreateDisposition == FILE_OPEN_IF)));
  433. OpenDirectory = (BOOLEAN)(DirectoryFile &&
  434. ((CreateDisposition == FILE_OPEN) ||
  435. (CreateDisposition == FILE_OPEN_IF)));
  436. //
  437. // Make sure the input large integer is valid and that the dir/nondir
  438. // indicates a storage type we understand.
  439. //
  440. if (Irp->Overlay.AllocationSize.HighPart != 0 ||
  441. (DirectoryFile && NonDirectoryFile)) {
  442. FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  443. DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_INVALID_PARAMETER\n", 0);
  444. return STATUS_INVALID_PARAMETER;
  445. }
  446. //
  447. // Acquire exclusive access to the vcb, and enqueue the Irp if
  448. // we didn't get it.
  449. //
  450. if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
  451. DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
  452. Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
  453. DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status );
  454. return Iosb.Status;
  455. }
  456. //
  457. // Initialize the DirentBcb to null
  458. //
  459. DirentBcb = NULL;
  460. //
  461. // Initialize our temp strings with their stack buffers.
  462. //
  463. OemFinalName.Length = 0;
  464. OemFinalName.MaximumLength = sizeof( OemBuffer);
  465. OemFinalName.Buffer = OemBuffer;
  466. UpcasedFinalName.Length = 0;
  467. UpcasedFinalName.MaximumLength = sizeof( UpcasedBuffer);
  468. UpcasedFinalName.Buffer = UpcasedBuffer;
  469. Lfn.Length = 0;
  470. Lfn.MaximumLength = sizeof( LfnBuffer);
  471. Lfn.Buffer = LfnBuffer;
  472. try {
  473. //
  474. // Make sure the vcb is in a usable condition. This will raise
  475. // and error condition if the volume is unusable
  476. //
  477. FatVerifyVcb( IrpContext, Vcb );
  478. //
  479. // If the Vcb is locked then we cannot open another file
  480. //
  481. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
  482. DebugTrace(0, Dbg, "Volume is locked\n", 0);
  483. Status = STATUS_ACCESS_DENIED;
  484. if (Vcb->VcbCondition != VcbGood) {
  485. Status = STATUS_VOLUME_DISMOUNTED;
  486. }
  487. try_return( Iosb.Status = Status );
  488. }
  489. //
  490. // Don't allow the DELETE_ON_CLOSE option if the volume is
  491. // write-protected.
  492. //
  493. if (DeleteOnClose && FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  494. //
  495. // Set the real device for the pop-up info, and set the verify
  496. // bit in the device object, so that we will force a verify
  497. // in case the user put the correct media back in.
  498. //
  499. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  500. Vcb->Vpb->RealDevice );
  501. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  502. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  503. }
  504. //
  505. // If this is a fat32 volume, EA's are not supported.
  506. //
  507. if (EaBuffer != NULL &&
  508. FatIsFat32(Vcb)) {
  509. try_return( Iosb.Status = STATUS_EAS_NOT_SUPPORTED );
  510. }
  511. //
  512. // Check if we are opening the volume and not a file/directory.
  513. // We are opening the volume if the name is empty and there
  514. // isn't a related file object. If there is a related file object
  515. // then it is the Vcb itself.
  516. //
  517. if (FileName.Length == 0) {
  518. PVCB DecodeVcb;
  519. if (RelatedFileObject == NULL ||
  520. FatDecodeFileObject( RelatedFileObject,
  521. &DecodeVcb,
  522. &Fcb,
  523. &Ccb ) == UserVolumeOpen) {
  524. ASSERT( RelatedFileObject == NULL || Vcb == DecodeVcb );
  525. //
  526. // Check if we were to open a directory
  527. //
  528. if (DirectoryFile) {
  529. DebugTrace(0, Dbg, "Cannot open volume as a directory\n", 0);
  530. try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY );
  531. }
  532. //
  533. // Can't open the TargetDirectory of the DASD volume.
  534. //
  535. if (OpenTargetDirectory) {
  536. try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
  537. }
  538. DebugTrace(0, Dbg, "Opening the volume, Vcb = %08lx\n", Vcb);
  539. CollectCreateHitStatistics(Vcb);
  540. Iosb = FatOpenVolume( IrpContext,
  541. FileObject,
  542. Vcb,
  543. DesiredAccess,
  544. ShareAccess,
  545. CreateDisposition );
  546. Irp->IoStatus.Information = Iosb.Information;
  547. try_return( Iosb.Status );
  548. }
  549. }
  550. //
  551. // If there is a related file object then this is a relative open.
  552. // The related file object is the directory to start our search at.
  553. // Return an error if it is not a directory.
  554. //
  555. if (RelatedFileObject != NULL) {
  556. PVCB RelatedVcb;
  557. PDCB RelatedDcb;
  558. PCCB RelatedCcb;
  559. TYPE_OF_OPEN TypeOfOpen;
  560. TypeOfOpen = FatDecodeFileObject( RelatedFileObject,
  561. &RelatedVcb,
  562. &RelatedDcb,
  563. &RelatedCcb );
  564. if (TypeOfOpen != UserFileOpen &&
  565. TypeOfOpen != UserDirectoryOpen) {
  566. DebugTrace(0, Dbg, "Invalid related file object\n", 0);
  567. try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND );
  568. }
  569. //
  570. // A relative open must be via a relative path.
  571. //
  572. if (FileName.Length != 0 &&
  573. FileName.Buffer[0] == L'\\') {
  574. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  575. }
  576. //
  577. // Set up the file object's Vpb pointer in case anything happens.
  578. //
  579. ASSERT( Vcb == RelatedVcb );
  580. FileObject->Vpb = RelatedFileObject->Vpb;
  581. ParentDcb = RelatedDcb;
  582. } else {
  583. //
  584. // This is not a relative open, so check if we're
  585. // opening the root dcb
  586. //
  587. if ((FileName.Length == sizeof(WCHAR)) &&
  588. (FileName.Buffer[0] == L'\\')) {
  589. //
  590. // Check if we were not supposed to open a directory
  591. //
  592. if (NonDirectoryFile) {
  593. DebugTrace(0, Dbg, "Cannot open root directory as a file\n", 0);
  594. try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY );
  595. }
  596. //
  597. // Can't open the TargetDirectory of the root directory.
  598. //
  599. if (OpenTargetDirectory) {
  600. try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
  601. }
  602. //
  603. // Not allowed to delete root directory.
  604. //
  605. if (DeleteOnClose) {
  606. try_return( Iosb.Status = STATUS_CANNOT_DELETE );
  607. }
  608. DebugTrace(0, Dbg, "Opening root dcb\n", 0);
  609. CollectCreateHitStatistics(Vcb);
  610. Iosb = FatOpenRootDcb( IrpContext,
  611. FileObject,
  612. Vcb,
  613. DesiredAccess,
  614. ShareAccess,
  615. CreateDisposition );
  616. Irp->IoStatus.Information = Iosb.Information;
  617. try_return( Iosb.Status );
  618. }
  619. //
  620. // Nope, we will be opening relative to the root directory.
  621. //
  622. ParentDcb = Vcb->RootDcb;
  623. }
  624. //
  625. // FatCommonCreate(): trailing backslash check
  626. //
  627. if ((FileName.Length != 0) &&
  628. (FileName.Buffer[FileName.Length/sizeof(WCHAR)-1] == L'\\')) {
  629. FileName.Length -= sizeof(WCHAR);
  630. TrailingBackslash = TRUE;
  631. } else {
  632. TrailingBackslash = FALSE;
  633. }
  634. //
  635. // Check for max path. We might want to tighten this down to DOS MAX_PATH
  636. // for maximal interchange with non-NT platforms, but for now defer to the
  637. // possibility of something depending on it.
  638. //
  639. if (ParentDcb->FullFileName.Buffer == NULL) {
  640. FatSetFullFileNameInFcb( IrpContext, ParentDcb );
  641. }
  642. if ((USHORT) (ParentDcb->FullFileName.Length + sizeof(WCHAR) + FileName.Length) <= FileName.Length) {
  643. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  644. }
  645. //
  646. // We loop here until we land on an Fcb that is in a good
  647. // condition. This way we can reopen files that have stale handles
  648. // to files of the same name but are now different.
  649. //
  650. while ( TRUE ) {
  651. Fcb = ParentDcb;
  652. RemainingPart = FileName;
  653. //
  654. // Now walk down the Dcb tree looking for the longest prefix.
  655. // This one exit condition in the while() is to handle a
  656. // special case condition (relative NULL name open), the main
  657. // exit conditions are at the bottom of the loop.
  658. //
  659. while (RemainingPart.Length != 0) {
  660. PFCB NextFcb;
  661. FsRtlDissectName( RemainingPart,
  662. &FinalName,
  663. &NextRemainingPart );
  664. //
  665. // If RemainingPart starts with a backslash the name is
  666. // invalid.
  667. // Check for no more than 255 characters in FinalName
  668. //
  669. if (((NextRemainingPart.Length != 0) && (NextRemainingPart.Buffer[0] == L'\\')) ||
  670. (FinalName.Length > 255*sizeof(WCHAR))) {
  671. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  672. }
  673. //
  674. // Now, try to convert this one component into Oem and search
  675. // the splay tree. If it works then that's great, otherwise
  676. // we have to try with the UNICODE name instead.
  677. //
  678. FatEnsureStringBufferEnough( &OemFinalName,
  679. FinalName.Length);
  680. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE );
  681. if (NT_SUCCESS(Status)) {
  682. NextFcb = FatFindFcb( IrpContext,
  683. &Fcb->Specific.Dcb.RootOemNode,
  684. (PSTRING)&OemFinalName,
  685. &FileNameOpenedDos );
  686. } else {
  687. NextFcb = NULL;
  688. OemFinalName.Length = 0;
  689. if (Status != STATUS_UNMAPPABLE_CHARACTER) {
  690. try_return( Iosb.Status = Status );
  691. }
  692. }
  693. //
  694. // If we didn't find anything searching the Oem space, we
  695. // have to try the Unicode space. To save cycles in the
  696. // common case that this tree is empty, we do a quick check
  697. // here.
  698. //
  699. if ((NextFcb == NULL) && Fcb->Specific.Dcb.RootUnicodeNode) {
  700. //
  701. // First downcase, then upcase the string, because this
  702. // is what happens when putting names into the tree (see
  703. // strucsup.c, FatConstructNamesInFcb()).
  704. //
  705. FatEnsureStringBufferEnough( &UpcasedFinalName,
  706. FinalName.Length);
  707. Status = RtlDowncaseUnicodeString(&UpcasedFinalName, &FinalName, FALSE );
  708. ASSERT( NT_SUCCESS( Status ));
  709. Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &UpcasedFinalName, FALSE );
  710. ASSERT( NT_SUCCESS( Status ));
  711. NextFcb = FatFindFcb( IrpContext,
  712. &Fcb->Specific.Dcb.RootUnicodeNode,
  713. (PSTRING)&UpcasedFinalName,
  714. &FileNameOpenedDos );
  715. }
  716. //
  717. // If we got back an Fcb then we consumed the FinalName
  718. // legitimately, so the remaining name is now RemainingPart.
  719. //
  720. if (NextFcb != NULL) {
  721. Fcb = NextFcb;
  722. RemainingPart = NextRemainingPart;
  723. }
  724. if ((NextFcb == NULL) ||
  725. (NodeType(NextFcb) == FAT_NTC_FCB) ||
  726. (NextRemainingPart.Length == 0)) {
  727. break;
  728. }
  729. }
  730. //
  731. // Remaining name cannot start with a backslash
  732. //
  733. if (RemainingPart.Length && (RemainingPart.Buffer[0] == L'\\')) {
  734. RemainingPart.Length -= sizeof(WCHAR);
  735. RemainingPart.Buffer += 1;
  736. }
  737. //
  738. // Now verify that everybody up to the longest found prefix is valid.
  739. //
  740. try {
  741. FatVerifyFcb( IrpContext, Fcb );
  742. } except( (GetExceptionCode() == STATUS_FILE_INVALID) ?
  743. EXCEPTION_EXECUTE_HANDLER :
  744. EXCEPTION_CONTINUE_SEARCH ) {
  745. FatResetExceptionState( IrpContext );
  746. }
  747. if ( Fcb->FcbCondition == FcbGood ) {
  748. //
  749. // If we are trying to open a paging file and have happened
  750. // upon the DelayedCloseFcb, make it go away, and try again.
  751. //
  752. if (IsPagingFile && FirstLoop &&
  753. (NodeType(Fcb) == FAT_NTC_FCB) &&
  754. (!IsListEmpty( &FatData.AsyncCloseList ) ||
  755. !IsListEmpty( &FatData.DelayedCloseList ))) {
  756. FatFspClose(Vcb);
  757. FirstLoop = FALSE;
  758. continue;
  759. } else {
  760. break;
  761. }
  762. } else {
  763. FatRemoveNames( IrpContext, Fcb );
  764. }
  765. }
  766. ASSERT( Fcb->FcbCondition == FcbGood );
  767. //
  768. // If there is already an Fcb for a paging file open and
  769. // it was not already opened as a paging file, we cannot
  770. // continue as it is too difficult to move a live Fcb to
  771. // non-paged pool.
  772. //
  773. if (IsPagingFile) {
  774. if (NodeType(Fcb) == FAT_NTC_FCB &&
  775. !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  776. try_return( Iosb.Status = STATUS_SHARING_VIOLATION );
  777. }
  778. //
  779. // Check for a system file.
  780. //
  781. } else if (FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  782. try_return( Iosb.Status = STATUS_ACCESS_DENIED );
  783. }
  784. //
  785. // If the longest prefix is pending delete (either the file or
  786. // some higher level directory), we cannot continue.
  787. //
  788. if (FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) {
  789. try_return( Iosb.Status = STATUS_DELETE_PENDING );
  790. }
  791. //
  792. // Now that we've found the longest matching prefix we'll
  793. // check if there isn't any remaining part because that means
  794. // we've located an existing fcb/dcb to open and we can do the open
  795. // without going to the disk
  796. //
  797. if (RemainingPart.Length == 0) {
  798. //
  799. // First check if the user wanted to open the target directory
  800. // and if so then call the subroutine to finish the open.
  801. //
  802. if (OpenTargetDirectory) {
  803. CollectCreateHitStatistics(Vcb);
  804. Iosb = FatOpenTargetDirectory( IrpContext,
  805. FileObject,
  806. Fcb->ParentDcb,
  807. DesiredAccess,
  808. ShareAccess,
  809. TRUE );
  810. Irp->IoStatus.Information = Iosb.Information;
  811. try_return( Iosb.Status );
  812. }
  813. //
  814. // We can open an existing fcb/dcb, now we only need to case
  815. // on which type to open.
  816. //
  817. if (NodeType(Fcb) == FAT_NTC_DCB || NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
  818. //
  819. // This is a directory we're opening up so check if
  820. // we were not to open a directory
  821. //
  822. if (NonDirectoryFile) {
  823. DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
  824. try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY );
  825. }
  826. DebugTrace(0, Dbg, "Open existing dcb, Dcb = %08lx\n", Fcb);
  827. CollectCreateHitStatistics(Vcb);
  828. Iosb = FatOpenExistingDcb( IrpContext,
  829. FileObject,
  830. Vcb,
  831. (PDCB)Fcb,
  832. DesiredAccess,
  833. ShareAccess,
  834. CreateDisposition,
  835. NoEaKnowledge,
  836. DeleteOnClose );
  837. Irp->IoStatus.Information = Iosb.Information;
  838. try_return( Iosb.Status );
  839. }
  840. //
  841. // Check if we're trying to open an existing Fcb and that
  842. // the user didn't want to open a directory. Note that this
  843. // call might actually come back with status_pending because
  844. // the user wanted to supersede or overwrite the file and we
  845. // cannot block. If it is pending then we do not complete the
  846. // request, and we fall through the bottom to the code that
  847. // dispatches the request to the fsp.
  848. //
  849. if (NodeType(Fcb) == FAT_NTC_FCB) {
  850. //
  851. // Check if we were only to open a directory
  852. //
  853. if (OpenDirectory) {
  854. DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
  855. try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY );
  856. }
  857. DebugTrace(0, Dbg, "Open existing fcb, Fcb = %08lx\n", Fcb);
  858. if ( TrailingBackslash ) {
  859. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  860. }
  861. CollectCreateHitStatistics(Vcb);
  862. Iosb = FatOpenExistingFcb( IrpContext,
  863. FileObject,
  864. Vcb,
  865. Fcb,
  866. DesiredAccess,
  867. ShareAccess,
  868. AllocationSize,
  869. EaBuffer,
  870. EaLength,
  871. FileAttributes,
  872. CreateDisposition,
  873. NoEaKnowledge,
  874. DeleteOnClose,
  875. FileNameOpenedDos,
  876. &OplockPostIrp );
  877. if (Iosb.Status != STATUS_PENDING) {
  878. //
  879. // Check if we need to set the cache support flag in
  880. // the file object
  881. //
  882. if (NT_SUCCESS( Iosb.Status) && !NoIntermediateBuffering) {
  883. FileObject->Flags |= FO_CACHE_SUPPORTED;
  884. }
  885. Irp->IoStatus.Information = Iosb.Information;
  886. } else {
  887. DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0);
  888. PostIrp = TRUE;
  889. }
  890. try_return( Iosb.Status );
  891. }
  892. //
  893. // Not and Fcb or a Dcb so we bug check
  894. //
  895. FatBugCheck( NodeType(Fcb), (ULONG_PTR) Fcb, 0 );
  896. }
  897. //
  898. // There is more in the name to parse than we have in existing
  899. // fcbs/dcbs. So now make sure that fcb we got for the largest
  900. // matching prefix is really a dcb otherwise we can't go any
  901. // further
  902. //
  903. if ((NodeType(Fcb) != FAT_NTC_DCB) && (NodeType(Fcb) != FAT_NTC_ROOT_DCB)) {
  904. DebugTrace(0, Dbg, "Cannot open file as subdirectory, Fcb = %08lx\n", Fcb);
  905. try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND );
  906. }
  907. //
  908. // Otherwise we continue on processing the Irp and allowing ourselves
  909. // to block for I/O as necessary. Find/create additional dcb's for
  910. // the one we're trying to open. We loop until either remaining part
  911. // is empty or we get a bad filename. When we exit FinalName is
  912. // the last name in the string we're after, and ParentDcb is the
  913. // parent directory that will contain the opened/created
  914. // file/directory.
  915. //
  916. // Make sure the rest of the name is valid in at least the LFN
  917. // character set (which just happens to be that of HPFS).
  918. //
  919. // If we are not in ChicagoMode, use FAT symantics.
  920. //
  921. ParentDcb = Fcb;
  922. FirstLoop = TRUE;
  923. while (TRUE) {
  924. //
  925. // We do one little optimization here on the first itterration of
  926. // the loop since we know that we have already tried to convert
  927. // FinalOemName from the original UNICODE.
  928. //
  929. if (FirstLoop) {
  930. FirstLoop = FALSE;
  931. RemainingPart = NextRemainingPart;
  932. Status = OemFinalName.Length ? STATUS_SUCCESS : STATUS_UNMAPPABLE_CHARACTER;
  933. } else {
  934. //
  935. // Dissect the remaining part.
  936. //
  937. DebugTrace(0, Dbg, "Dissecting the name %Z\n", &RemainingPart);
  938. FsRtlDissectName( RemainingPart,
  939. &FinalName,
  940. &RemainingPart );
  941. //
  942. // If RemainingPart starts with a backslash the name is
  943. // invalid.
  944. // Check for no more than 255 characters in FinalName
  945. //
  946. if (((RemainingPart.Length != 0) && (RemainingPart.Buffer[0] == L'\\')) ||
  947. (FinalName.Length > 255*sizeof(WCHAR))) {
  948. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  949. }
  950. //
  951. // Now, try to convert this one component into Oem. If it works
  952. // then that's great, otherwise we have to try with the UNICODE
  953. // name instead.
  954. //
  955. FatEnsureStringBufferEnough( &OemFinalName,
  956. FinalName.Length);
  957. Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE );
  958. }
  959. if (NT_SUCCESS(Status)) {
  960. //
  961. // We'll start by trying to locate the dirent for the name. Note
  962. // that we already know that there isn't an Fcb/Dcb for the file
  963. // otherwise we would have found it when we did our prefix lookup.
  964. //
  965. if (FatIsNameShortOemValid( IrpContext, OemFinalName, FALSE, FALSE, FALSE )) {
  966. FatStringTo8dot3( IrpContext,
  967. OemFinalName,
  968. &LocalCcb.OemQueryTemplate.Constant );
  969. LocalCcb.Flags = 0;
  970. } else {
  971. LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE;
  972. }
  973. } else {
  974. LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE;
  975. if (Status != STATUS_UNMAPPABLE_CHARACTER) {
  976. try_return( Iosb.Status = Status );
  977. }
  978. }
  979. //
  980. // Now we know a lot about the final name, so do legal name
  981. // checking here.
  982. //
  983. if (FatData.ChicagoMode) {
  984. if (!FatIsNameLongUnicodeValid( IrpContext, &FinalName, FALSE, FALSE, FALSE )) {
  985. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  986. }
  987. } else {
  988. if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) {
  989. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  990. }
  991. }
  992. DebugTrace(0, Dbg, "FinalName is %Z\n", &FinalName);
  993. DebugTrace(0, Dbg, "RemainingPart is %Z\n", &RemainingPart);
  994. FatEnsureStringBufferEnough( &UpcasedFinalName,
  995. FinalName.Length);
  996. if (!NT_SUCCESS(Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &FinalName, FALSE))) {
  997. try_return( Iosb.Status = Status );
  998. }
  999. LocalCcb.UnicodeQueryTemplate = UpcasedFinalName;
  1000. LocalCcb.ContainsWildCards = FALSE;
  1001. Lfn.Length = 0;
  1002. FatLocateDirent( IrpContext,
  1003. ParentDcb,
  1004. &LocalCcb,
  1005. 0,
  1006. &Dirent,
  1007. &DirentBcb,
  1008. &DirentByteOffset,
  1009. &FileNameOpenedDos,
  1010. &Lfn);
  1011. //
  1012. // Remember we read this Dcb for error recovery.
  1013. //
  1014. FinalDcb = ParentDcb;
  1015. //
  1016. // If the remaining part is now empty then this is the last name
  1017. // in the string and the one we want to open
  1018. //
  1019. if (RemainingPart.Length == 0) { break; }
  1020. //
  1021. // We didn't find a dirent, bail.
  1022. //
  1023. if (Dirent == NULL) {
  1024. Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1025. try_return( Iosb.Status );
  1026. }
  1027. //
  1028. // We now have a dirent, make sure it is a directory
  1029. //
  1030. if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
  1031. Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1032. try_return( Iosb.Status );
  1033. }
  1034. //
  1035. // Compute the LfnByteOffset.
  1036. //
  1037. LfnByteOffset = DirentByteOffset -
  1038. FAT_LFN_DIRENTS_NEEDED(&Lfn) * sizeof(LFN_DIRENT);
  1039. //
  1040. // Create a dcb for the new directory
  1041. //
  1042. ParentDcb = FatCreateDcb( IrpContext,
  1043. Vcb,
  1044. ParentDcb,
  1045. LfnByteOffset,
  1046. DirentByteOffset,
  1047. Dirent,
  1048. &Lfn );
  1049. //
  1050. // Remember we created this Dcb for error recovery.
  1051. //
  1052. FinalDcb = ParentDcb;
  1053. FatSetFullNameInFcb( IrpContext, ParentDcb, &FinalName );
  1054. }
  1055. //
  1056. // First check if the user wanted to open the target directory
  1057. // and if so then call the subroutine to finish the open.
  1058. //
  1059. if (OpenTargetDirectory) {
  1060. Iosb = FatOpenTargetDirectory( IrpContext,
  1061. FileObject,
  1062. ParentDcb,
  1063. DesiredAccess,
  1064. ShareAccess,
  1065. Dirent ? TRUE : FALSE);
  1066. Irp->IoStatus.Information = Iosb.Information;
  1067. try_return( Iosb.Status );
  1068. }
  1069. if (Dirent != NULL) {
  1070. //
  1071. // Compute the LfnByteOffset.
  1072. //
  1073. LfnByteOffset = DirentByteOffset -
  1074. FAT_LFN_DIRENTS_NEEDED(&Lfn) * sizeof(LFN_DIRENT);
  1075. //
  1076. // We were able to locate an existing dirent entry, so now
  1077. // see if it is a directory that we're trying to open.
  1078. //
  1079. if (FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
  1080. //
  1081. // Make sure its okay to open a directory
  1082. //
  1083. if (NonDirectoryFile) {
  1084. DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
  1085. try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY );
  1086. }
  1087. DebugTrace(0, Dbg, "Open existing directory\n", 0);
  1088. Iosb = FatOpenExistingDirectory( IrpContext,
  1089. FileObject,
  1090. Vcb,
  1091. ParentDcb,
  1092. Dirent,
  1093. LfnByteOffset,
  1094. DirentByteOffset,
  1095. &Lfn,
  1096. DesiredAccess,
  1097. ShareAccess,
  1098. CreateDisposition,
  1099. NoEaKnowledge,
  1100. DeleteOnClose );
  1101. Irp->IoStatus.Information = Iosb.Information;
  1102. try_return( Iosb.Status );
  1103. }
  1104. //
  1105. // Otherwise we're trying to open and existing file, and we
  1106. // need to check if the user only wanted to open a directory.
  1107. //
  1108. if (OpenDirectory) {
  1109. DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
  1110. try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY );
  1111. }
  1112. DebugTrace(0, Dbg, "Open existing file\n", 0);
  1113. if ( TrailingBackslash ) {
  1114. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  1115. }
  1116. Iosb = FatOpenExistingFile( IrpContext,
  1117. FileObject,
  1118. Vcb,
  1119. ParentDcb,
  1120. Dirent,
  1121. LfnByteOffset,
  1122. DirentByteOffset,
  1123. &Lfn,
  1124. DesiredAccess,
  1125. ShareAccess,
  1126. AllocationSize,
  1127. EaBuffer,
  1128. EaLength,
  1129. FileAttributes,
  1130. CreateDisposition,
  1131. IsPagingFile,
  1132. NoEaKnowledge,
  1133. DeleteOnClose,
  1134. FileNameOpenedDos );
  1135. //
  1136. // Check if we need to set the cache support flag in
  1137. // the file object
  1138. //
  1139. if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
  1140. FileObject->Flags |= FO_CACHE_SUPPORTED;
  1141. }
  1142. Irp->IoStatus.Information = Iosb.Information;
  1143. try_return( Iosb.Status );
  1144. }
  1145. //
  1146. // We can't locate a dirent so this is a new file.
  1147. //
  1148. //
  1149. // Now check to see if we wanted to only open an existing file.
  1150. // And then case on whether we wanted to create a file or a directory.
  1151. //
  1152. if ((CreateDisposition == FILE_OPEN) ||
  1153. (CreateDisposition == FILE_OVERWRITE)) {
  1154. DebugTrace( 0, Dbg, "Cannot open nonexisting file\n", 0);
  1155. try_return( Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND );
  1156. }
  1157. //
  1158. // Skip a few cycles later if we know now that the Oem name is not
  1159. // valid 8.3.
  1160. //
  1161. if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) {
  1162. OemFinalName.Length = 0;
  1163. }
  1164. //
  1165. // Determine the granted access for this operation now.
  1166. //
  1167. if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
  1168. try_return( Iosb );
  1169. }
  1170. if (CreateDirectory) {
  1171. DebugTrace(0, Dbg, "Create new directory\n", 0);
  1172. //
  1173. // If this media is write protected, don't even try the create.
  1174. //
  1175. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  1176. //
  1177. // Set the real device for the pop-up info, and set the verify
  1178. // bit in the device object, so that we will force a verify
  1179. // in case the user put the correct media back in.
  1180. //
  1181. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1182. Vcb->Vpb->RealDevice );
  1183. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  1184. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  1185. }
  1186. //
  1187. // Don't allow people to create directories with the
  1188. // temporary bit set.
  1189. //
  1190. if (TemporaryFile) {
  1191. try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
  1192. }
  1193. Iosb = FatCreateNewDirectory( IrpContext,
  1194. FileObject,
  1195. Vcb,
  1196. ParentDcb,
  1197. &OemFinalName,
  1198. &FinalName,
  1199. DesiredAccess,
  1200. ShareAccess,
  1201. EaBuffer,
  1202. EaLength,
  1203. FileAttributes,
  1204. NoEaKnowledge,
  1205. DeleteOnClose );
  1206. Irp->IoStatus.Information = Iosb.Information;
  1207. try_return( Iosb.Status );
  1208. }
  1209. DebugTrace(0, Dbg, "Create new file\n", 0);
  1210. if ( TrailingBackslash ) {
  1211. try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
  1212. }
  1213. //
  1214. // If this media is write protected, don't even try the create.
  1215. //
  1216. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  1217. //
  1218. // Set the real device for the pop-up info, and set the verify
  1219. // bit in the device object, so that we will force a verify
  1220. // in case the user put the correct media back in.
  1221. //
  1222. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  1223. Vcb->Vpb->RealDevice );
  1224. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  1225. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  1226. }
  1227. Iosb = FatCreateNewFile( IrpContext,
  1228. FileObject,
  1229. Vcb,
  1230. ParentDcb,
  1231. &OemFinalName,
  1232. &FinalName,
  1233. DesiredAccess,
  1234. ShareAccess,
  1235. AllocationSize,
  1236. EaBuffer,
  1237. EaLength,
  1238. FileAttributes,
  1239. &Lfn,
  1240. IsPagingFile,
  1241. NoEaKnowledge,
  1242. DeleteOnClose,
  1243. TemporaryFile );
  1244. //
  1245. // Check if we need to set the cache support flag in
  1246. // the file object
  1247. //
  1248. if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
  1249. FileObject->Flags |= FO_CACHE_SUPPORTED;
  1250. }
  1251. Irp->IoStatus.Information = Iosb.Information;
  1252. try_exit: NOTHING;
  1253. //
  1254. // This is a Beta Fix. Do this at a better place later.
  1255. //
  1256. if (NT_SUCCESS(Iosb.Status) && !OpenTargetDirectory) {
  1257. PFCB Fcb;
  1258. //
  1259. // If there is an Fcb/Dcb, set the long file name.
  1260. //
  1261. Fcb = FileObject->FsContext;
  1262. if (Fcb &&
  1263. ((NodeType(Fcb) == FAT_NTC_FCB) ||
  1264. (NodeType(Fcb) == FAT_NTC_DCB)) &&
  1265. (Fcb->FullFileName.Buffer == NULL)) {
  1266. FatSetFullNameInFcb( IrpContext, Fcb, &FinalName );
  1267. }
  1268. }
  1269. } finally {
  1270. DebugUnwind( FatCommonCreate );
  1271. //
  1272. // There used to be a test here - the ASSERT replaces it. We will
  1273. // never have begun enumerating directories if we post the IRP for
  1274. // oplock reasons.
  1275. //
  1276. ASSERT( !OplockPostIrp || DirentBcb == NULL );
  1277. FatUnpinBcb( IrpContext, DirentBcb );
  1278. //
  1279. // If we are in an error path, check for any created subdir Dcbs that
  1280. // have to be unwound. Don't whack the root directory.
  1281. //
  1282. // Note this will leave a branch of Dcbs dangling if the directory file
  1283. // had not been built on the leaf (case: opening path which has an
  1284. // element containing an invalid character name).
  1285. //
  1286. if ((AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) &&
  1287. (FinalDcb != NULL) &&
  1288. (NodeType(FinalDcb) == FAT_NTC_DCB) &&
  1289. IsListEmpty(&FinalDcb->Specific.Dcb.ParentDcbQueue) &&
  1290. (FinalDcb->OpenCount == 0) &&
  1291. (FinalDcb->Specific.Dcb.DirectoryFile != NULL)) {
  1292. PFILE_OBJECT DirectoryFileObject;
  1293. ULONG SavedFlags;
  1294. //
  1295. // Before doing the uninitialize, we have to unpin anything
  1296. // that has been repinned, but disable writethrough first. We
  1297. // disable raise from unpin-repin since we're already failing.
  1298. //
  1299. SavedFlags = IrpContext->Flags;
  1300. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE |
  1301. IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH );
  1302. FatUnpinRepinnedBcbs( IrpContext );
  1303. DirectoryFileObject = FinalDcb->Specific.Dcb.DirectoryFile;
  1304. FinalDcb->Specific.Dcb.DirectoryFile = NULL;
  1305. CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
  1306. ObDereferenceObject( DirectoryFileObject );
  1307. IrpContext->Flags = SavedFlags;
  1308. }
  1309. if (AbnormalTermination()) {
  1310. FatReleaseVcb( IrpContext, Vcb );
  1311. }
  1312. //
  1313. // Free up any string buffers we allocated
  1314. //
  1315. FatFreeStringBuffer( &OemFinalName);
  1316. FatFreeStringBuffer( &UpcasedFinalName);
  1317. FatFreeStringBuffer( &Lfn);
  1318. }
  1319. //
  1320. // The following code is only executed if we are exiting the
  1321. // procedure through a normal termination. We complete the request
  1322. // and if for any reason that bombs out then we need to unreference
  1323. // and possibly delete the fcb and ccb.
  1324. //
  1325. try {
  1326. if (PostIrp) {
  1327. //
  1328. // If the Irp hasn't already been posted, do it now.
  1329. //
  1330. if (!OplockPostIrp) {
  1331. Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
  1332. }
  1333. } else {
  1334. FatUnpinRepinnedBcbs( IrpContext );
  1335. }
  1336. } finally {
  1337. DebugUnwind( FatCommonCreate-in-FatCompleteRequest );
  1338. if (AbnormalTermination()) {
  1339. PVCB Vcb;
  1340. PFCB Fcb;
  1341. PCCB Ccb;
  1342. //
  1343. // Unwind all of our counts. Note that if a write failed, then
  1344. // the volume has been marked for verify, and all volume
  1345. // structures will be cleaned up automatically.
  1346. //
  1347. (VOID) FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  1348. Fcb->UncleanCount -= 1;
  1349. Fcb->OpenCount -= 1;
  1350. Vcb->OpenFileCount -= 1;
  1351. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
  1352. //
  1353. // If we leafed out on a new Fcb we should get rid of it at this point.
  1354. //
  1355. // Since the object isn't being opened, we have to do all of the teardown
  1356. // here. Our close path will not occur for this fileobject. Note this
  1357. // will leave a branch of Dcbs dangling since we do it by hand and don't
  1358. // chase to the root.
  1359. //
  1360. if (Fcb->OpenCount == 0 &&
  1361. (NodeType( Fcb ) == FAT_NTC_FCB ||
  1362. IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue))) {
  1363. ASSERT( NodeType( Fcb ) != FAT_NTC_ROOT_DCB );
  1364. if ( (NodeType( Fcb ) == FAT_NTC_DCB) &&
  1365. (Fcb->Specific.Dcb.DirectoryFile != NULL) ) {
  1366. FatSyncUninitializeCacheMap( IrpContext,
  1367. Fcb->Specific.Dcb.DirectoryFile );
  1368. InterlockedDecrement( &Fcb->Specific.Dcb.DirectoryFileOpenCount );
  1369. FatSetFileObject( Fcb->Specific.Dcb.DirectoryFile,
  1370. UnopenedFileObject,
  1371. NULL,
  1372. NULL );
  1373. ObDereferenceObject( Fcb->Specific.Dcb.DirectoryFile );
  1374. Fcb->Specific.Dcb.DirectoryFile = NULL;
  1375. }
  1376. FatDeleteFcb( IrpContext, Fcb );
  1377. }
  1378. FatDeleteCcb( IrpContext, Ccb );
  1379. FatReleaseVcb( IrpContext, Vcb );
  1380. } else {
  1381. FatReleaseVcb( IrpContext, Vcb );
  1382. if ( !PostIrp ) {
  1383. //
  1384. // If this request is successful and the file was opened
  1385. // for FILE_EXECUTE access, then set the FileObject bit.
  1386. //
  1387. ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
  1388. if (FlagOn( *DesiredAccess, FILE_EXECUTE )) {
  1389. SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
  1390. }
  1391. //
  1392. // Lock volume in drive if we opened a paging file, allocating a
  1393. // reserve MDL to guarantee paging file operations can always
  1394. // go forward.
  1395. //
  1396. if (IsPagingFile && NT_SUCCESS(Iosb.Status)) {
  1397. if (!FatReserveMdl) {
  1398. PMDL ReserveMdl = IoAllocateMdl( NULL,
  1399. FAT_RESERVE_MDL_SIZE * PAGE_SIZE,
  1400. TRUE,
  1401. FALSE,
  1402. NULL );
  1403. //
  1404. // Stash the MDL, and if it turned out there was already one there
  1405. // just free what we got.
  1406. //
  1407. InterlockedCompareExchangePointer( &FatReserveMdl, ReserveMdl, NULL );
  1408. if (FatReserveMdl != ReserveMdl) {
  1409. IoFreeMdl( ReserveMdl );
  1410. }
  1411. }
  1412. SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE);
  1413. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
  1414. FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
  1415. }
  1416. }
  1417. //
  1418. // Complete the request.
  1419. //
  1420. FatCompleteRequest( IrpContext, Irp, Iosb.Status );
  1421. }
  1422. }
  1423. DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status);
  1424. }
  1425. CollectCreateStatistics(Vcb, Iosb.Status);
  1426. return Iosb.Status;
  1427. }
  1428. //
  1429. // Internal support routine
  1430. //
  1431. IO_STATUS_BLOCK
  1432. FatOpenVolume (
  1433. IN PIRP_CONTEXT IrpContext,
  1434. IN PFILE_OBJECT FileObject,
  1435. IN PVCB Vcb,
  1436. IN PACCESS_MASK DesiredAccess,
  1437. IN USHORT ShareAccess,
  1438. IN ULONG CreateDisposition
  1439. )
  1440. /*++
  1441. Routine Description:
  1442. This routine opens the specified volume for DASD access
  1443. Arguments:
  1444. FileObject - Supplies the File object
  1445. Vcb - Supplies the Vcb denoting the volume being opened
  1446. DesiredAccess - Supplies the desired access of the caller
  1447. ShareAccess - Supplies the share access of the caller
  1448. CreateDisposition - Supplies the create disposition for this operation
  1449. Return Value:
  1450. IO_STATUS_BLOCK - Returns the completion status for the operation
  1451. --*/
  1452. {
  1453. NTSTATUS Status;
  1454. PIO_STACK_LOCATION IrpSp;
  1455. IO_STATUS_BLOCK Iosb = {0,0};
  1456. BOOLEAN CleanedVolume = FALSE;
  1457. //
  1458. // The following variables are for abnormal termination
  1459. //
  1460. BOOLEAN UnwindShareAccess = FALSE;
  1461. PCCB UnwindCcb = NULL;
  1462. BOOLEAN UnwindCounts = FALSE;
  1463. BOOLEAN UnwindVolumeLock = FALSE;
  1464. DebugTrace(+1, Dbg, "FatOpenVolume...\n", 0);
  1465. try {
  1466. //
  1467. // Check for proper desired access and rights
  1468. //
  1469. if ((CreateDisposition != FILE_OPEN) &&
  1470. (CreateDisposition != FILE_OPEN_IF)) {
  1471. try_return( Iosb.Status = STATUS_ACCESS_DENIED );
  1472. }
  1473. //
  1474. // If the user does not want to share write or delete then we will try
  1475. // and take out a lock on the volume.
  1476. //
  1477. if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) &&
  1478. !FlagOn(ShareAccess, FILE_SHARE_DELETE)) {
  1479. //
  1480. // Do a quick check here for handles on exclusive open.
  1481. //
  1482. if (!FlagOn(ShareAccess, FILE_SHARE_READ) &&
  1483. !FatIsHandleCountZero( IrpContext, Vcb )) {
  1484. try_return( Iosb.Status = STATUS_SHARING_VIOLATION );
  1485. }
  1486. //
  1487. // Force Mm to get rid of its referenced file objects.
  1488. //
  1489. FatFlushFat( IrpContext, Vcb );
  1490. FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
  1491. //
  1492. // If the user also does not want to share read then we check
  1493. // if anyone is already using the volume, and if so then we
  1494. // deny the access. If the user wants to share read then
  1495. // we allow the current opens to stay provided they are only
  1496. // readonly opens and deny further opens.
  1497. //
  1498. if (!FlagOn(ShareAccess, FILE_SHARE_READ)) {
  1499. if (Vcb->OpenFileCount != 0) {
  1500. try_return( Iosb.Status = STATUS_SHARING_VIOLATION );
  1501. }
  1502. } else {
  1503. if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) {
  1504. try_return( Iosb.Status = STATUS_SHARING_VIOLATION );
  1505. }
  1506. }
  1507. //
  1508. // Lock the volume
  1509. //
  1510. Vcb->VcbState |= VCB_STATE_FLAG_LOCKED;
  1511. Vcb->FileObjectWithVcbLocked = FileObject;
  1512. UnwindVolumeLock = TRUE;
  1513. //
  1514. // Clean the volume
  1515. //
  1516. CleanedVolume = TRUE;
  1517. } else if (FlagOn( *DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA )) {
  1518. //
  1519. // Flush the volume and let ourselves push the clean bit out if everything
  1520. // worked.
  1521. //
  1522. if (NT_SUCCESS( FatFlushVolume( IrpContext, Vcb, Flush ))) {
  1523. CleanedVolume = TRUE;
  1524. }
  1525. }
  1526. //
  1527. // Clean the volume if we believe it safe and reasonable.
  1528. //
  1529. if (CleanedVolume &&
  1530. FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) &&
  1531. !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) &&
  1532. !CcIsThereDirtyData(Vcb->Vpb)) {
  1533. //
  1534. // Cancel any pending clean volumes.
  1535. //
  1536. (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
  1537. (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
  1538. FatMarkVolume( IrpContext, Vcb, VolumeClean );
  1539. ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
  1540. //
  1541. // Unlock the volume if it is removable.
  1542. //
  1543. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
  1544. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
  1545. FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
  1546. }
  1547. }
  1548. //
  1549. // If the volume is already opened by someone then we need to check
  1550. // the share access
  1551. //
  1552. if (Vcb->DirectAccessOpenCount > 0) {
  1553. if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess,
  1554. ShareAccess,
  1555. FileObject,
  1556. &Vcb->ShareAccess,
  1557. TRUE ))) {
  1558. try_return( Iosb.Status );
  1559. }
  1560. } else {
  1561. IoSetShareAccess( *DesiredAccess,
  1562. ShareAccess,
  1563. FileObject,
  1564. &Vcb->ShareAccess );
  1565. }
  1566. UnwindShareAccess = TRUE;
  1567. //
  1568. // Set up the context and section object pointers, and update
  1569. // our reference counts
  1570. //
  1571. FatSetFileObject( FileObject,
  1572. UserVolumeOpen,
  1573. Vcb,
  1574. UnwindCcb = FatCreateCcb( IrpContext ));
  1575. FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
  1576. Vcb->DirectAccessOpenCount += 1;
  1577. Vcb->OpenFileCount += 1;
  1578. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  1579. UnwindCounts = TRUE;
  1580. FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
  1581. //
  1582. // At this point the open will succeed, so check if the user is getting explicit access
  1583. // to the device. If not, we will note this so we can deny modifying FSCTL to it.
  1584. //
  1585. IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
  1586. Status = FatExplicitDeviceAccessGranted( IrpContext,
  1587. Vcb->Vpb->RealDevice,
  1588. IrpSp->Parameters.Create.SecurityContext->AccessState,
  1589. (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ?
  1590. UserMode :
  1591. IrpContext->OriginatingIrp->RequestorMode ));
  1592. if (NT_SUCCESS( Status )) {
  1593. SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS );
  1594. }
  1595. //
  1596. // And set our status to success
  1597. //
  1598. Iosb.Status = STATUS_SUCCESS;
  1599. Iosb.Information = FILE_OPENED;
  1600. try_exit: NOTHING;
  1601. } finally {
  1602. DebugUnwind( FatOpenVolume );
  1603. //
  1604. // If this is an abnormal termination then undo our work
  1605. //
  1606. if (AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) {
  1607. if (UnwindCounts) {
  1608. Vcb->DirectAccessOpenCount -= 1;
  1609. Vcb->OpenFileCount -= 1;
  1610. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
  1611. }
  1612. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  1613. if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); }
  1614. if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; }
  1615. }
  1616. DebugTrace(-1, Dbg, "FatOpenVolume -> Iosb.Status = %08lx\n", Iosb.Status);
  1617. }
  1618. return Iosb;
  1619. }
  1620. //
  1621. // Internal support routine
  1622. //
  1623. IO_STATUS_BLOCK
  1624. FatOpenRootDcb (
  1625. IN PIRP_CONTEXT IrpContext,
  1626. IN PFILE_OBJECT FileObject,
  1627. IN PVCB Vcb,
  1628. IN PACCESS_MASK DesiredAccess,
  1629. IN USHORT ShareAccess,
  1630. IN ULONG CreateDisposition
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This routine opens the root dcb for the volume
  1635. Arguments:
  1636. FileObject - Supplies the File object
  1637. Vcb - Supplies the Vcb denoting the volume whose dcb is being opened.
  1638. DesiredAccess - Supplies the desired access of the caller
  1639. ShareAccess - Supplies the share access of the caller
  1640. CreateDisposition - Supplies the create disposition for this operation
  1641. Return Value:
  1642. IO_STATUS_BLOCK - Returns the completion status for the operation
  1643. Arguments:
  1644. --*/
  1645. {
  1646. PDCB RootDcb;
  1647. IO_STATUS_BLOCK Iosb;
  1648. //
  1649. // The following variables are for abnormal termination
  1650. //
  1651. BOOLEAN UnwindShareAccess = FALSE;
  1652. PCCB UnwindCcb = NULL;
  1653. BOOLEAN UnwindCounts = FALSE;
  1654. BOOLEAN RootDcbAcquired = FALSE;
  1655. DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0);
  1656. //
  1657. // Locate the root dcb
  1658. //
  1659. RootDcb = Vcb->RootDcb;
  1660. //
  1661. // Get the Dcb exlcusive. This is important as cleanup does not
  1662. // acquire the Vcb.
  1663. //
  1664. (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb );
  1665. RootDcbAcquired = TRUE;
  1666. try {
  1667. //
  1668. // Check the create disposition and desired access
  1669. //
  1670. if ((CreateDisposition != FILE_OPEN) &&
  1671. (CreateDisposition != FILE_OPEN_IF)) {
  1672. Iosb.Status = STATUS_ACCESS_DENIED;
  1673. try_return( Iosb );
  1674. }
  1675. if (!FatCheckFileAccess( IrpContext,
  1676. RootDcb->DirentFatFlags,
  1677. DesiredAccess)) {
  1678. Iosb.Status = STATUS_ACCESS_DENIED;
  1679. try_return( Iosb );
  1680. }
  1681. //
  1682. // If the Root dcb is already opened by someone then we need
  1683. // to check the share access
  1684. //
  1685. if (RootDcb->OpenCount > 0) {
  1686. if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess,
  1687. ShareAccess,
  1688. FileObject,
  1689. &RootDcb->ShareAccess,
  1690. TRUE ))) {
  1691. try_return( Iosb );
  1692. }
  1693. } else {
  1694. IoSetShareAccess( *DesiredAccess,
  1695. ShareAccess,
  1696. FileObject,
  1697. &RootDcb->ShareAccess );
  1698. }
  1699. UnwindShareAccess = TRUE;
  1700. //
  1701. // Setup the context and section object pointers, and update
  1702. // our reference counts
  1703. //
  1704. FatSetFileObject( FileObject,
  1705. UserDirectoryOpen,
  1706. RootDcb,
  1707. UnwindCcb = FatCreateCcb( IrpContext ));
  1708. RootDcb->UncleanCount += 1;
  1709. RootDcb->OpenCount += 1;
  1710. Vcb->OpenFileCount += 1;
  1711. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  1712. UnwindCounts = TRUE;
  1713. //
  1714. // And set our status to success
  1715. //
  1716. Iosb.Status = STATUS_SUCCESS;
  1717. Iosb.Information = FILE_OPENED;
  1718. try_exit: NOTHING;
  1719. } finally {
  1720. DebugUnwind( FatOpenRootDcb );
  1721. //
  1722. // If this is an abnormal termination then undo our work
  1723. //
  1724. if (AbnormalTermination()) {
  1725. if (UnwindCounts) {
  1726. RootDcb->UncleanCount -= 1;
  1727. RootDcb->OpenCount -= 1;
  1728. Vcb->OpenFileCount -= 1;
  1729. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
  1730. }
  1731. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  1732. if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); }
  1733. }
  1734. if (RootDcbAcquired) {
  1735. FatReleaseFcb( IrpContext, RootDcb );
  1736. }
  1737. DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status);
  1738. }
  1739. return Iosb;
  1740. }
  1741. //
  1742. // Internal support routine
  1743. //
  1744. IO_STATUS_BLOCK
  1745. FatOpenExistingDcb (
  1746. IN PIRP_CONTEXT IrpContext,
  1747. IN PFILE_OBJECT FileObject,
  1748. IN PVCB Vcb,
  1749. IN PDCB Dcb,
  1750. IN PACCESS_MASK DesiredAccess,
  1751. IN USHORT ShareAccess,
  1752. IN ULONG CreateDisposition,
  1753. IN BOOLEAN NoEaKnowledge,
  1754. IN BOOLEAN DeleteOnClose
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. This routine opens the specified existing dcb
  1759. Arguments:
  1760. FileObject - Supplies the File object
  1761. Vcb - Supplies the Vcb denoting the volume containing the dcb
  1762. Dcb - Supplies the already existing dcb
  1763. DesiredAccess - Supplies the desired access of the caller
  1764. ShareAccess - Supplies the share access of the caller
  1765. CreateDisposition - Supplies the create disposition for this operation
  1766. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  1767. open if the file has NeedEa's.
  1768. DeleteOnClose - The caller wants the file gone when the handle is closed
  1769. Return Value:
  1770. IO_STATUS_BLOCK - Returns the completion status for the operation
  1771. --*/
  1772. {
  1773. IO_STATUS_BLOCK Iosb;
  1774. PBCB DirentBcb = NULL;
  1775. PDIRENT Dirent;
  1776. //
  1777. // The following variables are for abnormal termination
  1778. //
  1779. BOOLEAN UnwindShareAccess = FALSE;
  1780. PCCB UnwindCcb = NULL;
  1781. BOOLEAN DcbAcquired = FALSE;
  1782. DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0);
  1783. //
  1784. // Get the Dcb exlcusive. This is important as cleanup does not
  1785. // acquire the Vcb.
  1786. //
  1787. (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
  1788. DcbAcquired = TRUE;
  1789. try {
  1790. //
  1791. // Before spending any noticeable effort, see if we have the odd case
  1792. // of someone trying to delete-on-close the root dcb. This will only
  1793. // happen if we're hit with a null-filename relative open via the root.
  1794. //
  1795. if (NodeType(Dcb) == FAT_NTC_ROOT_DCB && DeleteOnClose) {
  1796. Iosb.Status = STATUS_CANNOT_DELETE;
  1797. try_return( Iosb );
  1798. }
  1799. //
  1800. // If the caller has no Ea knowledge, we immediately check for
  1801. // Need Ea's on the file. We don't need to check for ea's on the
  1802. // root directory, because it never has any. Fat32 doesn't have
  1803. // any, either.
  1804. //
  1805. if (NoEaKnowledge && NodeType(Dcb) != FAT_NTC_ROOT_DCB &&
  1806. !FatIsFat32(Vcb)) {
  1807. ULONG NeedEaCount;
  1808. //
  1809. // Get the dirent for the file and then check that the need
  1810. // ea count is 0.
  1811. //
  1812. FatGetDirentFromFcbOrDcb( IrpContext,
  1813. Dcb,
  1814. &Dirent,
  1815. &DirentBcb );
  1816. ASSERT( Dirent && DirentBcb );
  1817. FatGetNeedEaCount( IrpContext,
  1818. Vcb,
  1819. Dirent,
  1820. &NeedEaCount );
  1821. FatUnpinBcb( IrpContext, DirentBcb );
  1822. if (NeedEaCount != 0) {
  1823. Iosb.Status = STATUS_ACCESS_DENIED;
  1824. try_return( Iosb );
  1825. }
  1826. }
  1827. //
  1828. // Check the create disposition and desired access
  1829. //
  1830. if ((CreateDisposition != FILE_OPEN) &&
  1831. (CreateDisposition != FILE_OPEN_IF)) {
  1832. Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
  1833. try_return( Iosb );
  1834. }
  1835. if (!FatCheckFileAccess( IrpContext,
  1836. Dcb->DirentFatFlags,
  1837. DesiredAccess)) {
  1838. Iosb.Status = STATUS_ACCESS_DENIED;
  1839. try_return( Iosb );
  1840. }
  1841. //
  1842. // If the dcb is already opened by someone then we need
  1843. // to check the share access
  1844. //
  1845. if (Dcb->OpenCount > 0) {
  1846. if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess,
  1847. ShareAccess,
  1848. FileObject,
  1849. &Dcb->ShareAccess,
  1850. TRUE ))) {
  1851. try_return( Iosb );
  1852. }
  1853. } else {
  1854. IoSetShareAccess( *DesiredAccess,
  1855. ShareAccess,
  1856. FileObject,
  1857. &Dcb->ShareAccess );
  1858. }
  1859. UnwindShareAccess = TRUE;
  1860. //
  1861. // Setup the context and section object pointers, and update
  1862. // our reference counts
  1863. //
  1864. FatSetFileObject( FileObject,
  1865. UserDirectoryOpen,
  1866. Dcb,
  1867. UnwindCcb = FatCreateCcb( IrpContext ));
  1868. Dcb->UncleanCount += 1;
  1869. Dcb->OpenCount += 1;
  1870. Vcb->OpenFileCount += 1;
  1871. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  1872. //
  1873. // Mark the delete on close bit if the caller asked for that.
  1874. //
  1875. {
  1876. PCCB Ccb = (PCCB)FileObject->FsContext2;
  1877. if (DeleteOnClose) {
  1878. SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  1879. }
  1880. }
  1881. //
  1882. // In case this was set, clear it now.
  1883. //
  1884. ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE);
  1885. //
  1886. // And set our status to success
  1887. //
  1888. Iosb.Status = STATUS_SUCCESS;
  1889. Iosb.Information = FILE_OPENED;
  1890. try_exit: NOTHING;
  1891. } finally {
  1892. DebugUnwind( FatOpenExistingDcb );
  1893. //
  1894. // Unpin the Dirent Bcb if pinned.
  1895. //
  1896. FatUnpinBcb( IrpContext, DirentBcb );
  1897. //
  1898. // If this is an abnormal termination then undo our work
  1899. //
  1900. if (AbnormalTermination()) {
  1901. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  1902. if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
  1903. }
  1904. if (DcbAcquired) {
  1905. FatReleaseFcb( IrpContext, Dcb );
  1906. }
  1907. DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status);
  1908. }
  1909. return Iosb;
  1910. }
  1911. //
  1912. // Internal support routine
  1913. //
  1914. IO_STATUS_BLOCK
  1915. FatOpenExistingFcb (
  1916. IN PIRP_CONTEXT IrpContext,
  1917. IN PFILE_OBJECT FileObject,
  1918. IN PVCB Vcb,
  1919. IN PFCB Fcb,
  1920. IN PACCESS_MASK DesiredAccess,
  1921. IN USHORT ShareAccess,
  1922. IN ULONG AllocationSize,
  1923. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  1924. IN ULONG EaLength,
  1925. IN UCHAR FileAttributes,
  1926. IN ULONG CreateDisposition,
  1927. IN BOOLEAN NoEaKnowledge,
  1928. IN BOOLEAN DeleteOnClose,
  1929. IN BOOLEAN FileNameOpenedDos,
  1930. OUT PBOOLEAN OplockPostIrp
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. This routine opens the specified existing fcb
  1935. Arguments:
  1936. FileObject - Supplies the File object
  1937. Vcb - Supplies the Vcb denoting the volume containing the Fcb
  1938. Fcb - Supplies the already existing fcb
  1939. DesiredAccess - Supplies the desired access of the caller
  1940. ShareAccess - Supplies the share access of the caller
  1941. AllocationSize - Supplies the initial allocation if the file is being
  1942. superseded or overwritten
  1943. EaBuffer - Supplies the Ea set if the file is being superseded or
  1944. overwritten
  1945. EaLength - Supplies the size, in byte, of the EaBuffer
  1946. FileAttributes - Supplies file attributes to use if the file is being
  1947. superseded or overwritten
  1948. CreateDisposition - Supplies the create disposition for this operation
  1949. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  1950. open if the file has NeedEa's.
  1951. DeleteOnClose - The caller wants the file gone when the handle is closed
  1952. FileNameOpenedDos - The caller hit the short side of the name pair finding
  1953. this file
  1954. OplockPostIrp - Address to store boolean indicating if the Irp needs to
  1955. be posted to the Fsp.
  1956. Return Value:
  1957. IO_STATUS_BLOCK - Returns the completion status for the operation
  1958. --*/
  1959. {
  1960. IO_STATUS_BLOCK Iosb;
  1961. PBCB DirentBcb = NULL;
  1962. PDIRENT Dirent;
  1963. ACCESS_MASK AddedAccess = 0;
  1964. //
  1965. // The following variables are for abnormal termination
  1966. //
  1967. BOOLEAN UnwindShareAccess = FALSE;
  1968. PCCB UnwindCcb = NULL;
  1969. BOOLEAN DecrementFcbOpenCount = FALSE;
  1970. BOOLEAN FcbAcquired = FALSE;
  1971. DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0);
  1972. //
  1973. // Get the Fcb exlcusive. This is important as cleanup does not
  1974. // acquire the Vcb.
  1975. //
  1976. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  1977. FcbAcquired = TRUE;
  1978. try {
  1979. *OplockPostIrp = FALSE;
  1980. //
  1981. // Take special action if there is a current batch oplock or
  1982. // batch oplock break in process on the Fcb.
  1983. //
  1984. if (FsRtlCurrentBatchOplock( &Fcb->Specific.Fcb.Oplock )) {
  1985. //
  1986. // We remember if a batch oplock break is underway for the
  1987. // case where the sharing check fails.
  1988. //
  1989. Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
  1990. Iosb.Status = FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
  1991. IrpContext->OriginatingIrp,
  1992. IrpContext,
  1993. FatOplockComplete,
  1994. FatPrePostIrp );
  1995. if (Iosb.Status != STATUS_SUCCESS
  1996. && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) {
  1997. *OplockPostIrp = TRUE;
  1998. try_return( NOTHING );
  1999. }
  2000. }
  2001. //
  2002. // Check if the user wanted to create the file, also special case
  2003. // the supersede and overwrite options. Those add additional,
  2004. // possibly only implied, desired accesses to the caller, which
  2005. // we must be careful to pull back off if the caller did not actually
  2006. // request them.
  2007. //
  2008. // In other words, check against the implied access, but do not modify
  2009. // share access as a result.
  2010. //
  2011. if (CreateDisposition == FILE_CREATE) {
  2012. Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
  2013. try_return( Iosb );
  2014. } else if (CreateDisposition == FILE_SUPERSEDE) {
  2015. SetFlag( AddedAccess,
  2016. DELETE & ~(*DesiredAccess) );
  2017. *DesiredAccess |= DELETE;
  2018. } else if ((CreateDisposition == FILE_OVERWRITE) ||
  2019. (CreateDisposition == FILE_OVERWRITE_IF)) {
  2020. SetFlag( AddedAccess,
  2021. (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) );
  2022. *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
  2023. }
  2024. //
  2025. // Check the desired access
  2026. //
  2027. if (!FatCheckFileAccess( IrpContext,
  2028. Fcb->DirentFatFlags,
  2029. DesiredAccess )) {
  2030. Iosb.Status = STATUS_ACCESS_DENIED;
  2031. try_return( Iosb );
  2032. }
  2033. //
  2034. // Check for trying to delete a read only file.
  2035. //
  2036. if (DeleteOnClose &&
  2037. FlagOn( Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY )) {
  2038. Iosb.Status = STATUS_CANNOT_DELETE;
  2039. try_return( Iosb );
  2040. }
  2041. //
  2042. // If we are asked to do an overwrite or supersede operation then
  2043. // deny access for files where the file attributes for system and
  2044. // hidden do not match
  2045. //
  2046. if ((CreateDisposition == FILE_SUPERSEDE) ||
  2047. (CreateDisposition == FILE_OVERWRITE) ||
  2048. (CreateDisposition == FILE_OVERWRITE_IF)) {
  2049. BOOLEAN Hidden;
  2050. BOOLEAN System;
  2051. Hidden = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_HIDDEN );
  2052. System = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_SYSTEM );
  2053. if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
  2054. (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) {
  2055. DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
  2056. Iosb.Status = STATUS_ACCESS_DENIED;
  2057. try_return( Iosb );
  2058. }
  2059. //
  2060. // If this media is write protected, don't even try the create.
  2061. //
  2062. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  2063. //
  2064. // Set the real device for the pop-up info, and set the verify
  2065. // bit in the device object, so that we will force a verify
  2066. // in case the user put the correct media back in.
  2067. //
  2068. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  2069. Vcb->Vpb->RealDevice );
  2070. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  2071. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  2072. }
  2073. }
  2074. //
  2075. // Check if the Fcb has the proper share access
  2076. //
  2077. if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess,
  2078. ShareAccess,
  2079. FileObject,
  2080. &Fcb->ShareAccess,
  2081. FALSE ))) {
  2082. try_return( Iosb );
  2083. }
  2084. //
  2085. // Now check that we can continue based on the oplock state of the
  2086. // file.
  2087. //
  2088. // It is important that we modified the DesiredAccess in place so
  2089. // that the Oplock check proceeds against any added access we had
  2090. // to give the caller.
  2091. //
  2092. Iosb.Status = FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
  2093. IrpContext->OriginatingIrp,
  2094. IrpContext,
  2095. FatOplockComplete,
  2096. FatPrePostIrp );
  2097. if (Iosb.Status != STATUS_SUCCESS
  2098. && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) {
  2099. *OplockPostIrp = TRUE;
  2100. try_return( NOTHING );
  2101. }
  2102. //
  2103. // Set the flag indicating if Fast I/O is possible
  2104. //
  2105. Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
  2106. //
  2107. // If the user wants write access access to the file make sure there
  2108. // is not a process mapping this file as an image. Any attempt to
  2109. // delete the file will be stopped in fileinfo.c
  2110. //
  2111. // If the user wants to delete on close, we must check at this
  2112. // point though.
  2113. //
  2114. if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {
  2115. Fcb->OpenCount += 1;
  2116. DecrementFcbOpenCount = TRUE;
  2117. if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
  2118. MmFlushForWrite )) {
  2119. Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
  2120. STATUS_SHARING_VIOLATION;
  2121. try_return( Iosb );
  2122. }
  2123. }
  2124. //
  2125. // If this is a non-cached open on a non-paging file, and there
  2126. // are no open cached handles, but there is a still a data
  2127. // section, attempt a flush and purge operation to avoid cache
  2128. // coherency overhead later. We ignore any I/O errors from
  2129. // the flush.
  2130. //
  2131. // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from
  2132. // going away out from underneath us.
  2133. //
  2134. if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
  2135. (Fcb->UncleanCount == Fcb->NonCachedUncleanCount) &&
  2136. (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) &&
  2137. !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  2138. SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
  2139. CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL );
  2140. //
  2141. // Grab and release PagingIo to serialize ourselves with the lazy writer.
  2142. // This will work to ensure that all IO has completed on the cached
  2143. // data and we will succesfully tear away the cache section.
  2144. //
  2145. ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
  2146. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  2147. CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers,
  2148. NULL,
  2149. 0,
  2150. FALSE );
  2151. ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
  2152. }
  2153. //
  2154. // Check if the user only wanted to open the file
  2155. //
  2156. if ((CreateDisposition == FILE_OPEN) ||
  2157. (CreateDisposition == FILE_OPEN_IF)) {
  2158. DebugTrace(0, Dbg, "Doing open operation\n", 0);
  2159. //
  2160. // If the caller has no Ea knowledge, we immediately check for
  2161. // Need Ea's on the file.
  2162. //
  2163. if (NoEaKnowledge && !FatIsFat32(Vcb)) {
  2164. ULONG NeedEaCount;
  2165. //
  2166. // Get the dirent for the file and then check that the need
  2167. // ea count is 0.
  2168. //
  2169. FatGetDirentFromFcbOrDcb( IrpContext,
  2170. Fcb,
  2171. &Dirent,
  2172. &DirentBcb );
  2173. FatGetNeedEaCount( IrpContext,
  2174. Vcb,
  2175. Dirent,
  2176. &NeedEaCount );
  2177. FatUnpinBcb( IrpContext, DirentBcb );
  2178. if (NeedEaCount != 0) {
  2179. Iosb.Status = STATUS_ACCESS_DENIED;
  2180. try_return( Iosb );
  2181. }
  2182. }
  2183. //
  2184. // Everything checks out okay, so setup the context and
  2185. // section object pointers.
  2186. //
  2187. FatSetFileObject( FileObject,
  2188. UserFileOpen,
  2189. Fcb,
  2190. UnwindCcb = FatCreateCcb( IrpContext ));
  2191. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  2192. //
  2193. // Fill in the information field, the status field is already
  2194. // set.
  2195. //
  2196. Iosb.Information = FILE_OPENED;
  2197. try_return( Iosb );
  2198. }
  2199. //
  2200. // Check if we are to supersede/overwrite the file, we can wait for
  2201. // any I/O at this point
  2202. //
  2203. if ((CreateDisposition == FILE_SUPERSEDE) ||
  2204. (CreateDisposition == FILE_OVERWRITE) ||
  2205. (CreateDisposition == FILE_OVERWRITE_IF)) {
  2206. NTSTATUS OldStatus;
  2207. DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
  2208. //
  2209. // Determine the granted access for this operation now.
  2210. //
  2211. if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
  2212. try_return( Iosb );
  2213. }
  2214. //
  2215. // And overwrite the file. We remember the previous status
  2216. // code because it may contain information about
  2217. // the oplock status.
  2218. //
  2219. OldStatus = Iosb.Status;
  2220. Iosb = FatSupersedeOrOverwriteFile( IrpContext,
  2221. FileObject,
  2222. Fcb,
  2223. AllocationSize,
  2224. EaBuffer,
  2225. EaLength,
  2226. FileAttributes,
  2227. CreateDisposition,
  2228. NoEaKnowledge );
  2229. if (Iosb.Status == STATUS_SUCCESS) {
  2230. Iosb.Status = OldStatus;
  2231. }
  2232. try_return( Iosb );
  2233. }
  2234. //
  2235. // If we ever get here then the I/O system gave us some bad input
  2236. //
  2237. FatBugCheck( CreateDisposition, 0, 0 );
  2238. try_exit: NOTHING;
  2239. //
  2240. // Update the share access and counts if successful
  2241. //
  2242. if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
  2243. //
  2244. // Now, we may have added some access bits above to indicate the access
  2245. // this caller would conflict with (as opposed to what they get) in order
  2246. // to perform the overwrite/supersede. We need to make a call to that will
  2247. // recalculate the bits in the fileobject to reflect the real access they
  2248. // will get.
  2249. //
  2250. if (AddedAccess) {
  2251. NTSTATUS Status;
  2252. ClearFlag( *DesiredAccess, AddedAccess );
  2253. Status = IoCheckShareAccess( *DesiredAccess,
  2254. ShareAccess,
  2255. FileObject,
  2256. &Fcb->ShareAccess,
  2257. TRUE );
  2258. //
  2259. // It must be the case that we are really asking for less access, so
  2260. // any conflict must have been detected before this point.
  2261. //
  2262. ASSERT( Status == STATUS_SUCCESS );
  2263. } else {
  2264. IoUpdateShareAccess( FileObject, &Fcb->ShareAccess );
  2265. }
  2266. UnwindShareAccess = TRUE;
  2267. //
  2268. // In case this was set, clear it now.
  2269. //
  2270. ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE);
  2271. Fcb->UncleanCount += 1;
  2272. Fcb->OpenCount += 1;
  2273. if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) {
  2274. Fcb->NonCachedUncleanCount += 1;
  2275. }
  2276. Vcb->OpenFileCount += 1;
  2277. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  2278. {
  2279. PCCB Ccb;
  2280. Ccb = (PCCB)FileObject->FsContext2;
  2281. //
  2282. // Mark the DeleteOnClose bit if the operation was successful.
  2283. //
  2284. if ( DeleteOnClose ) {
  2285. SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  2286. }
  2287. //
  2288. // Mark the OpenedByShortName bit if the operation was successful.
  2289. //
  2290. if ( FileNameOpenedDos ) {
  2291. SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME );
  2292. }
  2293. }
  2294. }
  2295. } finally {
  2296. DebugUnwind( FatOpenExistingFcb );
  2297. //
  2298. // Unpin the Dirent Bcb if pinned.
  2299. //
  2300. FatUnpinBcb( IrpContext, DirentBcb );
  2301. //
  2302. // If this is an abnormal termination then undo our work
  2303. //
  2304. if (AbnormalTermination()) {
  2305. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  2306. if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); }
  2307. }
  2308. if (DecrementFcbOpenCount) {
  2309. Fcb->OpenCount -= 1;
  2310. if (Fcb->OpenCount == 0) { FatDeleteFcb( IrpContext, Fcb ); }
  2311. }
  2312. if (FcbAcquired) {
  2313. FatReleaseFcb( IrpContext, Fcb );
  2314. }
  2315. DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status);
  2316. }
  2317. return Iosb;
  2318. }
  2319. //
  2320. // Internal support routine
  2321. //
  2322. IO_STATUS_BLOCK
  2323. FatOpenTargetDirectory (
  2324. IN PIRP_CONTEXT IrpContext,
  2325. IN PFILE_OBJECT FileObject,
  2326. IN PDCB Dcb,
  2327. IN PACCESS_MASK DesiredAccess,
  2328. IN USHORT ShareAccess,
  2329. IN BOOLEAN DoesNameExist
  2330. )
  2331. /*++
  2332. Routine Description:
  2333. This routine opens the target directory and replaces the name in the
  2334. file object with the remaining name.
  2335. Arguments:
  2336. FileObject - Supplies the File object
  2337. Dcb - Supplies an already existing dcb that we are going to open
  2338. DesiredAccess - Supplies the desired access of the caller
  2339. ShareAccess - Supplies the share access of the caller
  2340. DoesNameExist - Indicates if the file name already exists in the
  2341. target directory.
  2342. Return Value:
  2343. IO_STATUS_BLOCK - Returns the completion status for the operation
  2344. --*/
  2345. {
  2346. IO_STATUS_BLOCK Iosb;
  2347. //
  2348. // The following variables are for abnormal termination
  2349. //
  2350. BOOLEAN UnwindShareAccess = FALSE;
  2351. PCCB UnwindCcb = NULL;
  2352. BOOLEAN DcbAcquired = FALSE;
  2353. DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0);
  2354. //
  2355. // Get the Dcb exlcusive. This is important as cleanup does not
  2356. // acquire the Vcb.
  2357. //
  2358. (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
  2359. DcbAcquired = TRUE;
  2360. try {
  2361. ULONG i;
  2362. //
  2363. // If the Dcb is already opened by someone then we need
  2364. // to check the share access
  2365. //
  2366. if (Dcb->OpenCount > 0) {
  2367. if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess,
  2368. ShareAccess,
  2369. FileObject,
  2370. &Dcb->ShareAccess,
  2371. TRUE ))) {
  2372. try_return( Iosb );
  2373. }
  2374. } else {
  2375. IoSetShareAccess( *DesiredAccess,
  2376. ShareAccess,
  2377. FileObject,
  2378. &Dcb->ShareAccess );
  2379. }
  2380. UnwindShareAccess = TRUE;
  2381. //
  2382. // Setup the context and section object pointers, and update
  2383. // our reference counts
  2384. //
  2385. FatSetFileObject( FileObject,
  2386. UserDirectoryOpen,
  2387. Dcb,
  2388. UnwindCcb = FatCreateCcb( IrpContext ));
  2389. Dcb->UncleanCount += 1;
  2390. Dcb->OpenCount += 1;
  2391. Dcb->Vcb->OpenFileCount += 1;
  2392. if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; }
  2393. //
  2394. // Update the name in the file object, by definition the remaining
  2395. // part must be shorter than the original file name so we'll just
  2396. // overwrite the file name.
  2397. //
  2398. i = FileObject->FileName.Length/sizeof(WCHAR) - 1;
  2399. //
  2400. // Get rid of a trailing backslash
  2401. //
  2402. if (FileObject->FileName.Buffer[i] == L'\\') {
  2403. ASSERT(i != 0);
  2404. FileObject->FileName.Length -= sizeof(WCHAR);
  2405. i -= 1;
  2406. }
  2407. //
  2408. // Find the first non-backslash character. i will be its index.
  2409. //
  2410. while (TRUE) {
  2411. if (FileObject->FileName.Buffer[i] == L'\\') {
  2412. i += 1;
  2413. break;
  2414. }
  2415. if (i == 0) {
  2416. break;
  2417. }
  2418. i--;
  2419. }
  2420. if (i) {
  2421. FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR));
  2422. RtlCopyMemory( &FileObject->FileName.Buffer[0],
  2423. &FileObject->FileName.Buffer[i],
  2424. FileObject->FileName.Length );
  2425. }
  2426. //
  2427. // And set our status to success
  2428. //
  2429. Iosb.Status = STATUS_SUCCESS;
  2430. Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST);
  2431. try_exit: NOTHING;
  2432. } finally {
  2433. DebugUnwind( FatOpenTargetDirectory );
  2434. //
  2435. // If this is an abnormal termination then undo our work
  2436. //
  2437. if (AbnormalTermination()) {
  2438. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  2439. if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
  2440. }
  2441. if (DcbAcquired) {
  2442. FatReleaseFcb( IrpContext, Dcb );
  2443. }
  2444. DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
  2445. }
  2446. return Iosb;
  2447. }
  2448. //
  2449. // Internal support routine
  2450. //
  2451. IO_STATUS_BLOCK
  2452. FatOpenExistingDirectory (
  2453. IN PIRP_CONTEXT IrpContext,
  2454. IN PFILE_OBJECT FileObject,
  2455. IN PVCB Vcb,
  2456. IN PDCB ParentDcb,
  2457. IN PDIRENT Dirent,
  2458. IN ULONG LfnByteOffset,
  2459. IN ULONG DirentByteOffset,
  2460. IN PUNICODE_STRING Lfn,
  2461. IN PACCESS_MASK DesiredAccess,
  2462. IN USHORT ShareAccess,
  2463. IN ULONG CreateDisposition,
  2464. IN BOOLEAN NoEaKnowledge,
  2465. IN BOOLEAN DeleteOnClose
  2466. )
  2467. /*++
  2468. Routine Description:
  2469. This routine opens the specified directory. The directory has not
  2470. previously been opened.
  2471. Arguments:
  2472. FileObject - Supplies the File object
  2473. Vcb - Supplies the Vcb denoting the volume containing the dcb
  2474. ParentDcb - Supplies the parent directory containing the subdirectory
  2475. to be opened
  2476. DirectoryName - Supplies the file name of the directory being opened.
  2477. Dirent - Supplies the dirent for the directory being opened
  2478. LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
  2479. this field is the same as DirentByteOffset.
  2480. DirentByteOffset - Supplies the Vbo of the dirent within its parent
  2481. directory
  2482. Lfn - May supply a long name for the file.
  2483. DesiredAccess - Supplies the desired access of the caller
  2484. ShareAccess - Supplies the share access of the caller
  2485. CreateDisposition - Supplies the create disposition for this operation
  2486. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  2487. open if the file has NeedEa's.
  2488. DeleteOnClose - The caller wants the file gone when the handle is closed
  2489. Return Value:
  2490. IO_STATUS_BLOCK - Returns the completion status for the operation
  2491. --*/
  2492. {
  2493. IO_STATUS_BLOCK Iosb;
  2494. PDCB Dcb;
  2495. //
  2496. // The following variables are for abnormal termination
  2497. //
  2498. PDCB UnwindDcb = NULL;
  2499. PCCB UnwindCcb = NULL;
  2500. DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0);
  2501. try {
  2502. //
  2503. // If the caller has no Ea knowledge, we immediately check for
  2504. // Need Ea's on the file.
  2505. //
  2506. if (NoEaKnowledge && !FatIsFat32(Vcb)) {
  2507. ULONG NeedEaCount;
  2508. FatGetNeedEaCount( IrpContext,
  2509. Vcb,
  2510. Dirent,
  2511. &NeedEaCount );
  2512. if (NeedEaCount != 0) {
  2513. Iosb.Status = STATUS_ACCESS_DENIED;
  2514. try_return( Iosb );
  2515. }
  2516. }
  2517. //
  2518. // Check the create disposition and desired access
  2519. //
  2520. if ((CreateDisposition != FILE_OPEN) &&
  2521. (CreateDisposition != FILE_OPEN_IF)) {
  2522. Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
  2523. try_return( Iosb );
  2524. }
  2525. if (!FatCheckFileAccess( IrpContext,
  2526. Dirent->Attributes,
  2527. DesiredAccess)) {
  2528. Iosb.Status = STATUS_ACCESS_DENIED;
  2529. try_return( Iosb );
  2530. }
  2531. //
  2532. // Create a new dcb for the directory
  2533. //
  2534. Dcb = UnwindDcb = FatCreateDcb( IrpContext,
  2535. Vcb,
  2536. ParentDcb,
  2537. LfnByteOffset,
  2538. DirentByteOffset,
  2539. Dirent,
  2540. Lfn );
  2541. //
  2542. // Setup our share access
  2543. //
  2544. IoSetShareAccess( *DesiredAccess,
  2545. ShareAccess,
  2546. FileObject,
  2547. &Dcb->ShareAccess );
  2548. //
  2549. // Setup the context and section object pointers, and update
  2550. // our reference counts
  2551. //
  2552. FatSetFileObject( FileObject,
  2553. UserDirectoryOpen,
  2554. Dcb,
  2555. UnwindCcb = FatCreateCcb( IrpContext ));
  2556. Dcb->UncleanCount += 1;
  2557. Dcb->OpenCount += 1;
  2558. Vcb->OpenFileCount += 1;
  2559. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  2560. //
  2561. // And set our status to success
  2562. //
  2563. Iosb.Status = STATUS_SUCCESS;
  2564. Iosb.Information = FILE_OPENED;
  2565. try_exit: NOTHING;
  2566. } finally {
  2567. DebugUnwind( FatOpenExistingDirectory );
  2568. //
  2569. // If this is an abnormal termination then undo our work
  2570. //
  2571. if (AbnormalTermination()) {
  2572. if (UnwindDcb != NULL) { FatDeleteFcb( IrpContext, UnwindDcb ); }
  2573. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  2574. }
  2575. DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
  2576. }
  2577. return Iosb;
  2578. }
  2579. //
  2580. // Internal support routine
  2581. //
  2582. IO_STATUS_BLOCK
  2583. FatOpenExistingFile (
  2584. IN PIRP_CONTEXT IrpContext,
  2585. IN PFILE_OBJECT FileObject,
  2586. IN PVCB Vcb,
  2587. IN PDCB ParentDcb,
  2588. IN PDIRENT Dirent,
  2589. IN ULONG LfnByteOffset,
  2590. IN ULONG DirentByteOffset,
  2591. IN PUNICODE_STRING Lfn,
  2592. IN PACCESS_MASK DesiredAccess,
  2593. IN USHORT ShareAccess,
  2594. IN ULONG AllocationSize,
  2595. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  2596. IN ULONG EaLength,
  2597. IN UCHAR FileAttributes,
  2598. IN ULONG CreateDisposition,
  2599. IN BOOLEAN IsPagingFile,
  2600. IN BOOLEAN NoEaKnowledge,
  2601. IN BOOLEAN DeleteOnClose,
  2602. IN BOOLEAN FileNameOpenedDos
  2603. )
  2604. /*++
  2605. Routine Description:
  2606. This routine opens the specified file. The file has not previously
  2607. been opened.
  2608. Arguments:
  2609. FileObject - Supplies the File object
  2610. Vcb - Supplies the Vcb denoting the volume containing the file
  2611. ParentFcb - Supplies the parent directory containing the file to be
  2612. opened
  2613. Dirent - Supplies the dirent for the file being opened
  2614. LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
  2615. this field is the same as DirentByteOffset.
  2616. DirentByteOffset - Supplies the Vbo of the dirent within its parent
  2617. directory
  2618. Lfn - May supply a long name for the file.
  2619. DesiredAccess - Supplies the desired access of the caller
  2620. ShareAccess - Supplies the share access of the caller
  2621. AllocationSize - Supplies the initial allocation if the file is being
  2622. superseded, overwritten, or created.
  2623. EaBuffer - Supplies the Ea set if the file is being superseded,
  2624. overwritten, or created.
  2625. EaLength - Supplies the size, in byte, of the EaBuffer
  2626. FileAttributes - Supplies file attributes to use if the file is being
  2627. superseded, overwritten, or created
  2628. CreateDisposition - Supplies the create disposition for this operation
  2629. IsPagingFile - Indicates if this is the paging file being opened.
  2630. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  2631. open if the file has NeedEa's.
  2632. DeleteOnClose - The caller wants the file gone when the handle is closed
  2633. FileNameOpenedDos - The caller opened this file by hitting the 8.3 side
  2634. of the Lfn/8.3 pair
  2635. Return Value:
  2636. IO_STATUS_BLOCK - Returns the completion status for the operation
  2637. --*/
  2638. {
  2639. IO_STATUS_BLOCK Iosb;
  2640. PFCB Fcb;
  2641. ACCESS_MASK AddedAccess = 0;
  2642. //
  2643. // The following variables are for abnormal termination
  2644. //
  2645. PFCB UnwindFcb = NULL;
  2646. PCCB UnwindCcb = NULL;
  2647. DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0);
  2648. try {
  2649. //
  2650. // Check if the user wanted to create the file or if access is
  2651. // denied
  2652. //
  2653. if (CreateDisposition == FILE_CREATE) {
  2654. Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
  2655. try_return( Iosb );
  2656. } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
  2657. SetFlag( AddedAccess,
  2658. DELETE & ~(*DesiredAccess) );
  2659. *DesiredAccess |= DELETE;
  2660. } else if (((CreateDisposition == FILE_OVERWRITE) ||
  2661. (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
  2662. SetFlag( AddedAccess,
  2663. (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) );
  2664. *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
  2665. }
  2666. if (!FatCheckFileAccess( IrpContext,
  2667. Dirent->Attributes,
  2668. DesiredAccess)) {
  2669. Iosb.Status = STATUS_ACCESS_DENIED;
  2670. try_return( Iosb );
  2671. }
  2672. //
  2673. // Check for trying to delete a read only file.
  2674. //
  2675. if (DeleteOnClose &&
  2676. FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) {
  2677. Iosb.Status = STATUS_CANNOT_DELETE;
  2678. try_return( Iosb );
  2679. }
  2680. //
  2681. // IF we are asked to do an overwrite or supersede operation then
  2682. // deny access for files where the file attributes for system and
  2683. // hidden do not match
  2684. //
  2685. if ((CreateDisposition == FILE_SUPERSEDE) ||
  2686. (CreateDisposition == FILE_OVERWRITE) ||
  2687. (CreateDisposition == FILE_OVERWRITE_IF)) {
  2688. BOOLEAN Hidden;
  2689. BOOLEAN System;
  2690. Hidden = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_HIDDEN );
  2691. System = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_SYSTEM );
  2692. if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
  2693. (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) {
  2694. DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
  2695. if ( !IsPagingFile ) {
  2696. Iosb.Status = STATUS_ACCESS_DENIED;
  2697. try_return( Iosb );
  2698. }
  2699. }
  2700. //
  2701. // If this media is write protected, don't even try the create.
  2702. //
  2703. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  2704. //
  2705. // Set the real device for the pop-up info, and set the verify
  2706. // bit in the device object, so that we will force a verify
  2707. // in case the user put the correct media back in.
  2708. //
  2709. IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
  2710. Vcb->Vpb->RealDevice );
  2711. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  2712. FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED );
  2713. }
  2714. }
  2715. //
  2716. // Create a new Fcb for the file, and set the file size in
  2717. // the fcb.
  2718. //
  2719. Fcb = UnwindFcb = FatCreateFcb( IrpContext,
  2720. Vcb,
  2721. ParentDcb,
  2722. LfnByteOffset,
  2723. DirentByteOffset,
  2724. Dirent,
  2725. Lfn,
  2726. IsPagingFile,
  2727. FALSE );
  2728. //
  2729. // If this is a paging file, lookup the allocation size so that
  2730. // the Mcb is always valid
  2731. //
  2732. if (IsPagingFile) {
  2733. FatLookupFileAllocationSize( IrpContext, Fcb );
  2734. }
  2735. //
  2736. // Now case on whether we are to simply open, supersede, or
  2737. // overwrite the file.
  2738. //
  2739. switch (CreateDisposition) {
  2740. case FILE_OPEN:
  2741. case FILE_OPEN_IF:
  2742. DebugTrace(0, Dbg, "Doing only an open operation\n", 0);
  2743. //
  2744. // If the caller has no Ea knowledge, we immediately check for
  2745. // Need Ea's on the file.
  2746. //
  2747. if (NoEaKnowledge && !FatIsFat32(Vcb)) {
  2748. ULONG NeedEaCount;
  2749. FatGetNeedEaCount( IrpContext,
  2750. Vcb,
  2751. Dirent,
  2752. &NeedEaCount );
  2753. if (NeedEaCount != 0) {
  2754. FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED );
  2755. }
  2756. }
  2757. //
  2758. // Setup the context and section object pointers.
  2759. //
  2760. FatSetFileObject( FileObject,
  2761. UserFileOpen,
  2762. Fcb,
  2763. UnwindCcb = FatCreateCcb( IrpContext ));
  2764. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  2765. Iosb.Status = STATUS_SUCCESS;
  2766. Iosb.Information = FILE_OPENED;
  2767. break;
  2768. case FILE_SUPERSEDE:
  2769. case FILE_OVERWRITE:
  2770. case FILE_OVERWRITE_IF:
  2771. DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
  2772. //
  2773. // Determine the granted access for this operation now.
  2774. //
  2775. if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
  2776. try_return( Iosb );
  2777. }
  2778. Iosb = FatSupersedeOrOverwriteFile( IrpContext,
  2779. FileObject,
  2780. Fcb,
  2781. AllocationSize,
  2782. EaBuffer,
  2783. EaLength,
  2784. FileAttributes,
  2785. CreateDisposition,
  2786. NoEaKnowledge );
  2787. break;
  2788. default:
  2789. DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0);
  2790. FatBugCheck( CreateDisposition, 0, 0 );
  2791. break;
  2792. }
  2793. try_exit: NOTHING;
  2794. //
  2795. // Setup our share access and counts if things were successful.
  2796. //
  2797. if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
  2798. //
  2799. // Remove any virtual access the caller needed to check against, but will
  2800. // not really receive. Overwrite/supersede is a bit of a special case.
  2801. //
  2802. ClearFlag( *DesiredAccess, AddedAccess );
  2803. IoSetShareAccess( *DesiredAccess,
  2804. ShareAccess,
  2805. FileObject,
  2806. &Fcb->ShareAccess );
  2807. Fcb->UncleanCount += 1;
  2808. Fcb->OpenCount += 1;
  2809. if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) {
  2810. Fcb->NonCachedUncleanCount += 1;
  2811. }
  2812. Vcb->OpenFileCount += 1;
  2813. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  2814. }
  2815. {
  2816. PCCB Ccb;
  2817. Ccb = (PCCB)FileObject->FsContext2;
  2818. if ( NT_SUCCESS(Iosb.Status) ) {
  2819. //
  2820. // Mark the DeleteOnClose bit if the operation was successful.
  2821. //
  2822. if ( DeleteOnClose ) {
  2823. SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  2824. }
  2825. //
  2826. // Mark the OpenedByShortName bit if the operation was successful.
  2827. //
  2828. if ( FileNameOpenedDos ) {
  2829. SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME );
  2830. }
  2831. }
  2832. }
  2833. } finally {
  2834. DebugUnwind( FatOpenExistingFile );
  2835. //
  2836. // If this is an abnormal termination then undo our work
  2837. //
  2838. if (AbnormalTermination()) {
  2839. if (UnwindFcb != NULL) { FatDeleteFcb( IrpContext, UnwindFcb ); }
  2840. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  2841. }
  2842. DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status);
  2843. }
  2844. return Iosb;
  2845. }
  2846. //
  2847. // Internal support routine
  2848. //
  2849. IO_STATUS_BLOCK
  2850. FatCreateNewDirectory (
  2851. IN PIRP_CONTEXT IrpContext,
  2852. IN PFILE_OBJECT FileObject,
  2853. IN PVCB Vcb,
  2854. IN PDCB ParentDcb,
  2855. IN POEM_STRING OemName,
  2856. IN PUNICODE_STRING UnicodeName,
  2857. IN PACCESS_MASK DesiredAccess,
  2858. IN USHORT ShareAccess,
  2859. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  2860. IN ULONG EaLength,
  2861. IN UCHAR FileAttributes,
  2862. IN BOOLEAN NoEaKnowledge,
  2863. IN BOOLEAN DeleteOnClose
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. This routine creates a new directory. The directory has already been
  2868. verified not to exist yet.
  2869. Arguments:
  2870. FileObject - Supplies the file object for the newly created directory
  2871. Vcb - Supplies the Vcb denote the volume to contain the new directory
  2872. ParentDcb - Supplies the parent directory containg the newly created
  2873. directory
  2874. OemName - Supplies the Oem name for the newly created directory. It may
  2875. or maynot be 8.3 complient, but will be upcased.
  2876. UnicodeName - Supplies the Unicode name for the newly created directory.
  2877. It may or maynot be 8.3 complient. This name contains the original
  2878. case information.
  2879. DesiredAccess - Supplies the desired access of the caller
  2880. ShareAccess - Supplies the shared access of the caller
  2881. EaBuffer - Supplies the Ea set for the newly created directory
  2882. EaLength - Supplies the length, in bytes, of EaBuffer
  2883. FileAttributes - Supplies the file attributes for the newly created
  2884. directory.
  2885. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  2886. open if the file has NeedEa's.
  2887. DeleteOnClose - The caller wants the file gone when the handle is closed
  2888. Return Value:
  2889. IO_STATUS_BLOCK - Returns the completion status for the operation
  2890. --*/
  2891. {
  2892. IO_STATUS_BLOCK Iosb;
  2893. PDCB Dcb = NULL;
  2894. PCCB Ccb = NULL;
  2895. PDIRENT Dirent = NULL;
  2896. PBCB DirentBcb = NULL;
  2897. ULONG DirentsNeeded;
  2898. ULONG DirentByteOffset;
  2899. PDIRENT ShortDirent;
  2900. ULONG ShortDirentByteOffset;
  2901. USHORT EaHandle;
  2902. BOOLEAN AllLowerComponent;
  2903. BOOLEAN AllLowerExtension;
  2904. BOOLEAN CreateLfn;
  2905. ULONG BytesInFirstPage;
  2906. ULONG DirentsInFirstPage;
  2907. PDIRENT FirstPageDirent;
  2908. PBCB SecondPageBcb = NULL;
  2909. ULONG SecondPageOffset;
  2910. PDIRENT SecondPageDirent;
  2911. BOOLEAN DirentFromPool = FALSE;
  2912. OEM_STRING ShortName;
  2913. UCHAR ShortNameBuffer[12];
  2914. ULONG LocalAbnormalTermination = FALSE;
  2915. DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0);
  2916. ShortName.Length = 0;
  2917. ShortName.MaximumLength = 12;
  2918. ShortName.Buffer = &ShortNameBuffer[0];
  2919. EaHandle = 0;
  2920. //
  2921. // We fail this operation if the caller doesn't understand Ea's.
  2922. //
  2923. if (NoEaKnowledge
  2924. && EaLength > 0) {
  2925. Iosb.Status = STATUS_ACCESS_DENIED;
  2926. DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
  2927. return Iosb;
  2928. }
  2929. //
  2930. // DeleteOnClose and ReadOnly are not compatible.
  2931. //
  2932. if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
  2933. Iosb.Status = STATUS_CANNOT_DELETE;
  2934. return Iosb;
  2935. }
  2936. // Now get the names that we will be using.
  2937. //
  2938. FatSelectNames( IrpContext,
  2939. ParentDcb,
  2940. OemName,
  2941. UnicodeName,
  2942. &ShortName,
  2943. NULL,
  2944. &AllLowerComponent,
  2945. &AllLowerExtension,
  2946. &CreateLfn );
  2947. //
  2948. // If we are not in Chicago mode, ignore the magic bits.
  2949. //
  2950. if (!FatData.ChicagoMode) {
  2951. AllLowerComponent = FALSE;
  2952. AllLowerExtension = FALSE;
  2953. CreateLfn = FALSE;
  2954. }
  2955. //
  2956. // Create/allocate a new dirent
  2957. //
  2958. DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(UnicodeName) + 1 : 1;
  2959. DirentByteOffset = FatCreateNewDirent( IrpContext,
  2960. ParentDcb,
  2961. DirentsNeeded );
  2962. try {
  2963. FatPrepareWriteDirectoryFile( IrpContext,
  2964. ParentDcb,
  2965. DirentByteOffset,
  2966. sizeof(DIRENT),
  2967. &DirentBcb,
  2968. &Dirent,
  2969. FALSE,
  2970. TRUE,
  2971. &Iosb.Status );
  2972. ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent );
  2973. //
  2974. // Deal with the special case of an LFN + Dirent structure crossing
  2975. // a page boundry.
  2976. //
  2977. if ((DirentByteOffset / PAGE_SIZE) !=
  2978. ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
  2979. SecondPageBcb;
  2980. SecondPageOffset;
  2981. SecondPageDirent;
  2982. SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
  2983. BytesInFirstPage = SecondPageOffset - DirentByteOffset;
  2984. DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
  2985. FatPrepareWriteDirectoryFile( IrpContext,
  2986. ParentDcb,
  2987. SecondPageOffset,
  2988. sizeof(DIRENT),
  2989. &SecondPageBcb,
  2990. &SecondPageDirent,
  2991. FALSE,
  2992. TRUE,
  2993. &Iosb.Status );
  2994. ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent );
  2995. FirstPageDirent = Dirent;
  2996. Dirent = FsRtlAllocatePoolWithTag( PagedPool,
  2997. DirentsNeeded * sizeof(DIRENT),
  2998. TAG_DIRENT );
  2999. DirentFromPool = TRUE;
  3000. }
  3001. //
  3002. // Bump up Dirent and DirentByteOffset
  3003. //
  3004. ShortDirent = Dirent + DirentsNeeded - 1;
  3005. ShortDirentByteOffset = DirentByteOffset +
  3006. (DirentsNeeded - 1) * sizeof(DIRENT);
  3007. ASSERT( NT_SUCCESS( Iosb.Status ));
  3008. //
  3009. // Fill in the fields of the dirent.
  3010. //
  3011. FatConstructDirent( IrpContext,
  3012. ShortDirent,
  3013. &ShortName,
  3014. AllLowerComponent,
  3015. AllLowerExtension,
  3016. CreateLfn ? UnicodeName : NULL,
  3017. (UCHAR)(FileAttributes | FAT_DIRENT_ATTR_DIRECTORY),
  3018. TRUE,
  3019. NULL );
  3020. //
  3021. // If the dirent crossed pages, we have to do some real gross stuff.
  3022. //
  3023. if (DirentFromPool) {
  3024. RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage );
  3025. RtlCopyMemory( SecondPageDirent,
  3026. Dirent + DirentsInFirstPage,
  3027. DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage );
  3028. ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1;
  3029. }
  3030. //
  3031. // Create a new dcb for the directory.
  3032. //
  3033. Dcb = FatCreateDcb( IrpContext,
  3034. Vcb,
  3035. ParentDcb,
  3036. DirentByteOffset,
  3037. ShortDirentByteOffset,
  3038. ShortDirent,
  3039. CreateLfn ? UnicodeName : NULL );
  3040. //
  3041. // Tentatively add the new Ea's,
  3042. //
  3043. if (EaLength > 0) {
  3044. //
  3045. // This returns false if we are trying to create a file
  3046. // with Need Ea's and don't understand EA's.
  3047. //
  3048. FatCreateEa( IrpContext,
  3049. Dcb->Vcb,
  3050. (PUCHAR) EaBuffer,
  3051. EaLength,
  3052. &Dcb->ShortName.Name.Oem,
  3053. &EaHandle );
  3054. }
  3055. if (!FatIsFat32(Dcb->Vcb)) {
  3056. ShortDirent->ExtendedAttributes = EaHandle;
  3057. }
  3058. //
  3059. // After this point we cannot just simply mark the dirent deleted,
  3060. // we have to deal with the directory file object.
  3061. //
  3062. //
  3063. // Make the dirent into a directory. Note that even if this call
  3064. // raises because of disk space, the diectory file object has been
  3065. // created.
  3066. //
  3067. FatInitializeDirectoryDirent( IrpContext, Dcb, ShortDirent );
  3068. //
  3069. // Setup the context and section object pointers, and update
  3070. // our reference counts. Note that this call cannot fail.
  3071. //
  3072. FatSetFileObject( FileObject,
  3073. UserDirectoryOpen,
  3074. Dcb,
  3075. Ccb = FatCreateCcb( IrpContext ) );
  3076. //
  3077. // Initialize the LongFileName if it has not already been set, so that
  3078. // FatNotify below won't have to. If there are filesystem filters
  3079. // attached to FAT, the LongFileName could have gotten set if the
  3080. // filter queried for name information on this file object while
  3081. // watching the IO needed in FatInitializeDirectoryDirent.
  3082. //
  3083. if (Dcb->FullFileName.Buffer == NULL) {
  3084. FatSetFullNameInFcb( IrpContext, Dcb, UnicodeName );
  3085. }
  3086. //
  3087. // We call the notify package to report that the
  3088. // we added a file.
  3089. //
  3090. FatNotifyReportChange( IrpContext,
  3091. Vcb,
  3092. Dcb,
  3093. FILE_NOTIFY_CHANGE_DIR_NAME,
  3094. FILE_ACTION_ADDED );
  3095. //
  3096. // Setup our share access
  3097. //
  3098. IoSetShareAccess( *DesiredAccess,
  3099. ShareAccess,
  3100. FileObject,
  3101. &Dcb->ShareAccess );
  3102. //
  3103. // From this point on, nothing can raise.
  3104. //
  3105. Dcb->UncleanCount += 1;
  3106. Dcb->OpenCount += 1;
  3107. Vcb->OpenFileCount += 1;
  3108. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  3109. if (DeleteOnClose) {
  3110. SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  3111. }
  3112. //
  3113. // And set our return status
  3114. //
  3115. Iosb.Status = STATUS_SUCCESS;
  3116. Iosb.Information = FILE_CREATED;
  3117. } finally {
  3118. DebugUnwind( FatCreateNewDirectory );
  3119. LocalAbnormalTermination = AbnormalTermination();
  3120. //
  3121. // If this is an abnormal termination then undo our work
  3122. //
  3123. if (LocalAbnormalTermination) {
  3124. //
  3125. // We always have to delete the Ccb if we created one.
  3126. //
  3127. if ( Ccb != NULL ) {
  3128. FatDeleteCcb( IrpContext, Ccb );
  3129. }
  3130. if ( Dcb == NULL) {
  3131. ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
  3132. RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap,
  3133. DirentByteOffset / sizeof(DIRENT),
  3134. DirentsNeeded ) );
  3135. RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap,
  3136. DirentByteOffset / sizeof(DIRENT),
  3137. DirentsNeeded );
  3138. //
  3139. // Mark the dirents deleted. The codes is complex because of
  3140. // dealing with an LFN than crosses a page boundry.
  3141. //
  3142. if (Dirent != NULL) {
  3143. ULONG i;
  3144. //
  3145. // We failed before creating a directory file object.
  3146. // We can just mark the dirent deleted and exit.
  3147. //
  3148. for (i = 0; i < DirentsNeeded; i++) {
  3149. if (DirentFromPool == FALSE) {
  3150. //
  3151. // Simple case.
  3152. //
  3153. Dirent[i].FileName[0] = FAT_DIRENT_DELETED;
  3154. } else {
  3155. //
  3156. // If the second CcPreparePinWrite failed, we have
  3157. // to stop early.
  3158. //
  3159. if ((SecondPageBcb == NULL) &&
  3160. (i == DirentsInFirstPage)) {
  3161. break;
  3162. }
  3163. //
  3164. // Now conditionally update either page.
  3165. //
  3166. if (i < DirentsInFirstPage) {
  3167. FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED;
  3168. } else {
  3169. SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED;
  3170. }
  3171. }
  3172. }
  3173. }
  3174. }
  3175. }
  3176. //
  3177. // Just drop the Bcbs we have in the parent right now so if this
  3178. // was abnormal termination and we take the path to rip apart
  3179. // the partially created child, when we sync-uninit we won't cause
  3180. // a lazy writer processing the parent to block on us. This would
  3181. // consume one of the lazy writers, one of which must be running free
  3182. // in order for us to come back from the sync-uninit.
  3183. //
  3184. // Neat, huh?
  3185. //
  3186. // Granted, the delete dirent below will be marginally less efficient
  3187. // since the Bcb may be reclaimed by the time it executes. Life is
  3188. // tough.
  3189. //
  3190. FatUnpinBcb( IrpContext, DirentBcb );
  3191. FatUnpinBcb( IrpContext, SecondPageBcb );
  3192. if (DirentFromPool) {
  3193. ExFreePool( Dirent );
  3194. }
  3195. if (LocalAbnormalTermination) {
  3196. if (Dcb != NULL) {
  3197. //
  3198. // We have created the Dcb. If an error occurred while
  3199. // creating the Ea's, there will be no directory file
  3200. // object.
  3201. //
  3202. PFILE_OBJECT DirectoryFileObject;
  3203. DirectoryFileObject = Dcb->Specific.Dcb.DirectoryFile;
  3204. //
  3205. // Knock down all of the repinned data so we can begin to destroy
  3206. // this failed child. We don't care about any raising here - we're
  3207. // already got a fire going.
  3208. //
  3209. // Note that if we failed to do this, the repinned initial pieces
  3210. // of the child would cause the sync-uninit to block forever.
  3211. //
  3212. // A previous spin on this fix had us not make the ./.. creation
  3213. // "reversible" (bad term) and thus avoid having the Bcb still
  3214. // outstanding. This wound up causing very bad things to happen
  3215. // on DMF floppies when we tried to do a similar yank-down in the
  3216. // create path - we want the purge it does to make sure we never
  3217. // try to write the bytes out ... it is just a lot cleaner to
  3218. // unpinrepin. I'll leave the reversible logic in place if it ever
  3219. // proves useful.
  3220. //
  3221. //
  3222. // There is a possibility that this may be a generally good idea
  3223. // for "live" finally clauses - set in ExceptionFilter, clear in
  3224. // ProcessException. Think about this.
  3225. //
  3226. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE );
  3227. FatUnpinRepinnedBcbs( IrpContext );
  3228. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE );
  3229. if (DirectoryFileObject != NULL) {
  3230. FatSyncUninitializeCacheMap( IrpContext,
  3231. DirectoryFileObject );
  3232. }
  3233. try {
  3234. //
  3235. // Now zap the allocation backing it. Do it after removing the cachemap so that
  3236. // pending writes don't get perplexed looking at free FAT entries.
  3237. //
  3238. FatTruncateFileAllocation( IrpContext, Dcb, 0);
  3239. } finally {
  3240. try {
  3241. //
  3242. // Remove the directory entry we made in the parent Dcb.
  3243. //
  3244. FatDeleteDirent( IrpContext, Dcb, NULL, TRUE );
  3245. } finally {
  3246. //
  3247. // Finaly, dereference the directory file object. This will
  3248. // cause a close Irp to be processed, blowing away the Fcb.
  3249. //
  3250. if (DirectoryFileObject != NULL) {
  3251. //
  3252. // The following was a fix for the PDK only, but after five
  3253. // years it is the real one. By making this an unopened stream
  3254. // file we won't try to clean up our parent.
  3255. //
  3256. InterlockedDecrement( &Dcb->Specific.Dcb.DirectoryFileOpenCount );
  3257. Dcb->Specific.Dcb.DirectoryFile = NULL;
  3258. FatSetFileObject( DirectoryFileObject,
  3259. UnopenedFileObject,
  3260. NULL,
  3261. NULL );
  3262. ObDereferenceObject( DirectoryFileObject );
  3263. }
  3264. //
  3265. // This was also a PDK fix. If the stream file exists, this would
  3266. // be done during the dereference file object operation. Otherwise
  3267. // we have to remove the Dcb and check if we should remove the parent.
  3268. // For now we will just leave the parent lying around.
  3269. //
  3270. FatDeleteFcb( IrpContext, Dcb );
  3271. }
  3272. }
  3273. }
  3274. }
  3275. DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
  3276. }
  3277. UNREFERENCED_PARAMETER( EaBuffer );
  3278. UNREFERENCED_PARAMETER( EaLength );
  3279. return Iosb;
  3280. }
  3281. //
  3282. // Internal support routine
  3283. //
  3284. IO_STATUS_BLOCK
  3285. FatCreateNewFile (
  3286. IN PIRP_CONTEXT IrpContext,
  3287. IN PFILE_OBJECT FileObject,
  3288. IN PVCB Vcb,
  3289. IN PDCB ParentDcb,
  3290. IN POEM_STRING OemName,
  3291. IN PUNICODE_STRING UnicodeName,
  3292. IN PACCESS_MASK DesiredAccess,
  3293. IN USHORT ShareAccess,
  3294. IN ULONG AllocationSize,
  3295. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  3296. IN ULONG EaLength,
  3297. IN UCHAR FileAttributes,
  3298. IN PUNICODE_STRING LfnBuffer,
  3299. IN BOOLEAN IsPagingFile,
  3300. IN BOOLEAN NoEaKnowledge,
  3301. IN BOOLEAN DeleteOnClose,
  3302. IN BOOLEAN TemporaryFile
  3303. )
  3304. /*++
  3305. Routine Description:
  3306. This routine creates a new file. The file has already been verified
  3307. not to exist yet.
  3308. Arguments:
  3309. FileObject - Supplies the file object for the newly created file
  3310. Vcb - Supplies the Vcb denote the volume to contain the new file
  3311. ParentDcb - Supplies the parent directory containg the newly created
  3312. File
  3313. OemName - Supplies the Oem name for the newly created file. It may
  3314. or maynot be 8.3 complient, but will be upcased.
  3315. UnicodeName - Supplies the Unicode name for the newly created file.
  3316. It may or maynot be 8.3 complient. This name contains the original
  3317. case information.
  3318. DesiredAccess - Supplies the desired access of the caller
  3319. ShareAccess - Supplies the shared access of the caller
  3320. AllocationSize - Supplies the initial allocation size for the file
  3321. EaBuffer - Supplies the Ea set for the newly created file
  3322. EaLength - Supplies the length, in bytes, of EaBuffer
  3323. FileAttributes - Supplies the file attributes for the newly created
  3324. file
  3325. LfnBuffer - A MAX_LFN sized buffer for directory searching
  3326. IsPagingFile - Indicates if this is the paging file being created
  3327. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  3328. open if the file has NeedEa's.
  3329. DeleteOnClose - The caller wants the file gone when the handle is closed
  3330. TemporaryFile - Signals the lazywriter to not write dirty data unless
  3331. absolutely has to.
  3332. Return Value:
  3333. IO_STATUS_BLOCK - Returns the completion status for the operation
  3334. --*/
  3335. {
  3336. IO_STATUS_BLOCK Iosb;
  3337. PFCB Fcb;
  3338. PDIRENT Dirent = NULL;
  3339. PBCB DirentBcb = NULL;
  3340. ULONG DirentsNeeded;
  3341. ULONG DirentByteOffset;
  3342. PDIRENT ShortDirent;
  3343. ULONG ShortDirentByteOffset;
  3344. USHORT EaHandle;
  3345. BOOLEAN AllLowerComponent;
  3346. BOOLEAN AllLowerExtension;
  3347. BOOLEAN CreateLfn;
  3348. ULONG BytesInFirstPage;
  3349. ULONG DirentsInFirstPage;
  3350. PDIRENT FirstPageDirent;
  3351. PBCB SecondPageBcb = NULL;
  3352. ULONG SecondPageOffset;
  3353. PDIRENT SecondPageDirent;
  3354. BOOLEAN DirentFromPool = FALSE;
  3355. OEM_STRING ShortName;
  3356. UCHAR ShortNameBuffer[12];
  3357. UNICODE_STRING UniTunneledShortName;
  3358. WCHAR UniTunneledShortNameBuffer[12];
  3359. UNICODE_STRING UniTunneledLongName;
  3360. WCHAR UniTunneledLongNameBuffer[26];
  3361. LARGE_INTEGER TunneledCreationTime;
  3362. ULONG TunneledDataSize;
  3363. BOOLEAN HaveTunneledInformation;
  3364. BOOLEAN UsingTunneledLfn = FALSE;
  3365. PUNICODE_STRING RealUnicodeName;
  3366. //
  3367. // The following variables are for abnormal termination
  3368. //
  3369. PDIRENT UnwindDirent = NULL;
  3370. PFCB UnwindFcb = NULL;
  3371. BOOLEAN UnwindAllocation = FALSE;
  3372. PCCB UnwindCcb = NULL;
  3373. ULONG LocalAbnormalTermination = FALSE;
  3374. DebugTrace(+1, Dbg, "FatCreateNewFile...\n", 0);
  3375. ShortName.Length = 0;
  3376. ShortName.MaximumLength = sizeof(ShortNameBuffer);
  3377. ShortName.Buffer = &ShortNameBuffer[0];
  3378. UniTunneledShortName.Length = 0;
  3379. UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer);
  3380. UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0];
  3381. UniTunneledLongName.Length = 0;
  3382. UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer);
  3383. UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0];
  3384. EaHandle = 0;
  3385. //
  3386. // We fail this operation if the caller doesn't understand Ea's.
  3387. //
  3388. if (NoEaKnowledge
  3389. && EaLength > 0) {
  3390. Iosb.Status = STATUS_ACCESS_DENIED;
  3391. DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status);
  3392. return Iosb;
  3393. }
  3394. //
  3395. // DeleteOnClose and ReadOnly are not compatible.
  3396. //
  3397. if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
  3398. Iosb.Status = STATUS_CANNOT_DELETE;
  3399. return Iosb;
  3400. }
  3401. //
  3402. // Look in the tunnel cache for names and timestamps to restore
  3403. //
  3404. TunneledDataSize = sizeof(LARGE_INTEGER);
  3405. HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel,
  3406. FatDirectoryKey(ParentDcb),
  3407. UnicodeName,
  3408. &UniTunneledShortName,
  3409. &UniTunneledLongName,
  3410. &TunneledDataSize,
  3411. &TunneledCreationTime );
  3412. ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER));
  3413. //
  3414. // Now get the names that we will be using.
  3415. //
  3416. FatSelectNames( IrpContext,
  3417. ParentDcb,
  3418. OemName,
  3419. UnicodeName,
  3420. &ShortName,
  3421. (HaveTunneledInformation? &UniTunneledShortName : NULL),
  3422. &AllLowerComponent,
  3423. &AllLowerExtension,
  3424. &CreateLfn );
  3425. //
  3426. // If we are not in Chicago mode, ignore the magic bits.
  3427. //
  3428. RealUnicodeName = UnicodeName;
  3429. if (!FatData.ChicagoMode) {
  3430. AllLowerComponent = FALSE;
  3431. AllLowerExtension = FALSE;
  3432. CreateLfn = FALSE;
  3433. } else {
  3434. //
  3435. // If the Unicode name was legal for a short name and we got
  3436. // a tunneling hit which had a long name associated which is
  3437. // avaliable for use, use it.
  3438. //
  3439. if (!CreateLfn &&
  3440. UniTunneledLongName.Length &&
  3441. !FatLfnDirentExists(IrpContext, ParentDcb, &UniTunneledLongName, LfnBuffer)) {
  3442. UsingTunneledLfn = TRUE;
  3443. CreateLfn = TRUE;
  3444. RealUnicodeName = &UniTunneledLongName;
  3445. //
  3446. // Short names are always upcase if an LFN exists
  3447. //
  3448. AllLowerComponent = FALSE;
  3449. AllLowerExtension = FALSE;
  3450. }
  3451. }
  3452. //
  3453. // Create/allocate a new dirent
  3454. //
  3455. DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(RealUnicodeName) + 1 : 1;
  3456. DirentByteOffset = FatCreateNewDirent( IrpContext,
  3457. ParentDcb,
  3458. DirentsNeeded );
  3459. try {
  3460. FatPrepareWriteDirectoryFile( IrpContext,
  3461. ParentDcb,
  3462. DirentByteOffset,
  3463. sizeof(DIRENT),
  3464. &DirentBcb,
  3465. &Dirent,
  3466. FALSE,
  3467. TRUE,
  3468. &Iosb.Status );
  3469. ASSERT( NT_SUCCESS( Iosb.Status ) );
  3470. UnwindDirent = Dirent;
  3471. //
  3472. // Deal with the special case of an LFN + Dirent structure crossing
  3473. // a page boundry.
  3474. //
  3475. if ((DirentByteOffset / PAGE_SIZE) !=
  3476. ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
  3477. SecondPageBcb;
  3478. SecondPageOffset;
  3479. SecondPageDirent;
  3480. SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
  3481. BytesInFirstPage = SecondPageOffset - DirentByteOffset;
  3482. DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
  3483. FatPrepareWriteDirectoryFile( IrpContext,
  3484. ParentDcb,
  3485. SecondPageOffset,
  3486. sizeof(DIRENT),
  3487. &SecondPageBcb,
  3488. &SecondPageDirent,
  3489. FALSE,
  3490. TRUE,
  3491. &Iosb.Status );
  3492. ASSERT( NT_SUCCESS( Iosb.Status ) );
  3493. FirstPageDirent = Dirent;
  3494. Dirent = FsRtlAllocatePoolWithTag( PagedPool,
  3495. DirentsNeeded * sizeof(DIRENT),
  3496. TAG_DIRENT );
  3497. DirentFromPool = TRUE;
  3498. }
  3499. //
  3500. // Bump up Dirent and DirentByteOffset
  3501. //
  3502. ShortDirent = Dirent + DirentsNeeded - 1;
  3503. ShortDirentByteOffset = DirentByteOffset +
  3504. (DirentsNeeded - 1) * sizeof(DIRENT);
  3505. ASSERT( NT_SUCCESS( Iosb.Status ));
  3506. //
  3507. // Fill in the fields of the dirent.
  3508. //
  3509. FatConstructDirent( IrpContext,
  3510. ShortDirent,
  3511. &ShortName,
  3512. AllLowerComponent,
  3513. AllLowerExtension,
  3514. CreateLfn ? RealUnicodeName : NULL,
  3515. (UCHAR)(FileAttributes | FILE_ATTRIBUTE_ARCHIVE),
  3516. TRUE,
  3517. (HaveTunneledInformation ? &TunneledCreationTime : NULL) );
  3518. //
  3519. // If the dirent crossed pages, we have to do some real gross stuff.
  3520. //
  3521. if (DirentFromPool) {
  3522. RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage );
  3523. RtlCopyMemory( SecondPageDirent,
  3524. Dirent + DirentsInFirstPage,
  3525. DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage );
  3526. ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1;
  3527. }
  3528. //
  3529. // Create a new Fcb for the file. Once the Fcb is created we
  3530. // will not need to unwind dirent because delete dirent will
  3531. // now do the work.
  3532. //
  3533. Fcb = UnwindFcb = FatCreateFcb( IrpContext,
  3534. Vcb,
  3535. ParentDcb,
  3536. DirentByteOffset,
  3537. ShortDirentByteOffset,
  3538. ShortDirent,
  3539. CreateLfn ? RealUnicodeName : NULL,
  3540. IsPagingFile,
  3541. FALSE );
  3542. UnwindDirent = NULL;
  3543. //
  3544. // If this is a temporary file, note it in the FcbState
  3545. //
  3546. if (TemporaryFile) {
  3547. SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
  3548. }
  3549. //
  3550. // Add some initial file allocation
  3551. //
  3552. FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize );
  3553. UnwindAllocation = TRUE;
  3554. Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
  3555. //
  3556. // Tentatively add the new Ea's
  3557. //
  3558. if ( EaLength > 0 ) {
  3559. FatCreateEa( IrpContext,
  3560. Fcb->Vcb,
  3561. (PUCHAR) EaBuffer,
  3562. EaLength,
  3563. &Fcb->ShortName.Name.Oem,
  3564. &EaHandle );
  3565. }
  3566. if (!FatIsFat32(Fcb->Vcb)) {
  3567. ShortDirent->ExtendedAttributes = EaHandle;
  3568. }
  3569. //
  3570. // Initialize the LongFileName right now so that FatNotify
  3571. // below won't have to.
  3572. //
  3573. FatSetFullNameInFcb( IrpContext, Fcb, RealUnicodeName );
  3574. //
  3575. // Setup the context and section object pointers, and update
  3576. // our reference counts
  3577. //
  3578. FatSetFileObject( FileObject,
  3579. UserFileOpen,
  3580. Fcb,
  3581. UnwindCcb = FatCreateCcb( IrpContext ));
  3582. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  3583. //
  3584. // We call the notify package to report that the
  3585. // we added a file.
  3586. //
  3587. FatNotifyReportChange( IrpContext,
  3588. Vcb,
  3589. Fcb,
  3590. FILE_NOTIFY_CHANGE_FILE_NAME,
  3591. FILE_ACTION_ADDED );
  3592. //
  3593. // Setup our share access
  3594. //
  3595. IoSetShareAccess( *DesiredAccess,
  3596. ShareAccess,
  3597. FileObject,
  3598. &Fcb->ShareAccess );
  3599. Fcb->UncleanCount += 1;
  3600. Fcb->OpenCount += 1;
  3601. if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) {
  3602. Fcb->NonCachedUncleanCount += 1;
  3603. }
  3604. Vcb->OpenFileCount += 1;
  3605. if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
  3606. //
  3607. // And set our return status
  3608. //
  3609. Iosb.Status = STATUS_SUCCESS;
  3610. Iosb.Information = FILE_CREATED;
  3611. if ( NT_SUCCESS(Iosb.Status) ) {
  3612. //
  3613. // Mark the DeleteOnClose bit if the operation was successful.
  3614. //
  3615. if ( DeleteOnClose ) {
  3616. SetFlag( UnwindCcb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  3617. }
  3618. //
  3619. // Mark the OpenedByShortName bit if the operation was successful.
  3620. // If we created an Lfn, we have some sort of generated short name
  3621. // and thus don't consider ourselves to have opened it - though we
  3622. // may have had a case mix Lfn "Foo.bar" and generated "FOO.BAR"
  3623. //
  3624. // Unless, of course, we wanted to create a short name and hit an
  3625. // associated Lfn in the tunnel cache
  3626. //
  3627. if ( !CreateLfn && !UsingTunneledLfn ) {
  3628. SetFlag( UnwindCcb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME );
  3629. }
  3630. }
  3631. } finally {
  3632. DebugUnwind( FatCreateNewFile );
  3633. if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) {
  3634. //
  3635. // Tunneling package grew the buffer from pool
  3636. //
  3637. ExFreePool( UniTunneledLongName.Buffer );
  3638. }
  3639. //
  3640. // If this is an abnormal termination then undo our work.
  3641. //
  3642. // The extra exception handling here is so nasty. We've got
  3643. // two places here where an exception can be thrown again.
  3644. //
  3645. LocalAbnormalTermination = AbnormalTermination();
  3646. if (LocalAbnormalTermination) {
  3647. if (UnwindFcb == NULL) {
  3648. ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) ||
  3649. RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap,
  3650. DirentByteOffset / sizeof(DIRENT),
  3651. DirentsNeeded ) );
  3652. RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap,
  3653. DirentByteOffset / sizeof(DIRENT),
  3654. DirentsNeeded );
  3655. }
  3656. //
  3657. // Mark the dirents deleted. The code is complex because of
  3658. // dealing with an LFN than crosses a page boundry.
  3659. //
  3660. if (UnwindDirent != NULL) {
  3661. ULONG i;
  3662. for (i = 0; i < DirentsNeeded; i++) {
  3663. if (DirentFromPool == FALSE) {
  3664. //
  3665. // Simple case.
  3666. //
  3667. Dirent[i].FileName[0] = FAT_DIRENT_DELETED;
  3668. } else {
  3669. //
  3670. // If the second CcPreparePinWrite failed, we have
  3671. // to stop early.
  3672. //
  3673. if ((SecondPageBcb == NULL) &&
  3674. (i == DirentsInFirstPage)) {
  3675. break;
  3676. }
  3677. //
  3678. // Now conditionally update either page.
  3679. //
  3680. if (i < DirentsInFirstPage) {
  3681. FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED;
  3682. } else {
  3683. SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED;
  3684. }
  3685. }
  3686. }
  3687. }
  3688. }
  3689. //
  3690. // We must handle exceptions in the following fragments and plow on with the
  3691. // unwind of this create operation. This is basically inverted from the
  3692. // previous state of the code. Since AbnormalTermination() changes when we
  3693. // enter a new enclosure, we cached the original state ...
  3694. //
  3695. try {
  3696. if (LocalAbnormalTermination) {
  3697. if (UnwindAllocation) {
  3698. FatTruncateFileAllocation( IrpContext, Fcb, 0 );
  3699. }
  3700. }
  3701. } finally {
  3702. try {
  3703. if (LocalAbnormalTermination) {
  3704. if (UnwindFcb != NULL) {
  3705. FatDeleteDirent( IrpContext, UnwindFcb, NULL, TRUE );
  3706. }
  3707. }
  3708. } finally {
  3709. if (LocalAbnormalTermination) {
  3710. if (UnwindFcb != NULL) { FatDeleteFcb( IrpContext, UnwindFcb ); }
  3711. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  3712. }
  3713. //
  3714. // This is the normal cleanup code.
  3715. //
  3716. FatUnpinBcb( IrpContext, DirentBcb );
  3717. FatUnpinBcb( IrpContext, SecondPageBcb );
  3718. if (DirentFromPool) {
  3719. ExFreePool( Dirent );
  3720. }
  3721. }
  3722. }
  3723. DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status);
  3724. }
  3725. return Iosb;
  3726. }
  3727. //
  3728. // Internal support routine
  3729. //
  3730. IO_STATUS_BLOCK
  3731. FatSupersedeOrOverwriteFile (
  3732. IN PIRP_CONTEXT IrpContext,
  3733. IN PFILE_OBJECT FileObject,
  3734. IN PFCB Fcb,
  3735. IN ULONG AllocationSize,
  3736. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  3737. IN ULONG EaLength,
  3738. IN UCHAR FileAttributes,
  3739. IN ULONG CreateDisposition,
  3740. IN BOOLEAN NoEaKnowledge
  3741. )
  3742. /*++
  3743. Routine Description:
  3744. This routine performs a file supersede or overwrite operation.
  3745. Arguments:
  3746. FileObject - Supplies a pointer to the file object
  3747. Fcb - Supplies a pointer to the Fcb
  3748. AllocationSize - Supplies an initial allocation size
  3749. EaBuffer - Supplies the Ea set for the superseded/overwritten file
  3750. EaLength - Supplies the length, in bytes, of EaBuffer
  3751. FileAttributes - Supplies the supersede/overwrite file attributes
  3752. CreateDisposition - Supplies the create disposition for the file
  3753. It must be either supersede, overwrite, or overwrite if.
  3754. NoEaKnowledge - This opener doesn't understand Ea's and we fail this
  3755. open if the file has NeedEa's.
  3756. Return Value:
  3757. IO_STATUS_BLOCK - Returns the completion status for the operation
  3758. --*/
  3759. {
  3760. IO_STATUS_BLOCK Iosb;
  3761. PDIRENT Dirent;
  3762. PBCB DirentBcb;
  3763. USHORT EaHandle = 0;
  3764. BOOLEAN EaChange = FALSE;
  3765. BOOLEAN ReleasePaging = FALSE;
  3766. PCCB Ccb;
  3767. ULONG NotifyFilter;
  3768. //
  3769. // The following variables are for abnormal termination
  3770. //
  3771. PCCB UnwindCcb = NULL;
  3772. USHORT UnwindEa = 0;
  3773. DebugTrace(+1, Dbg, "FatSupersedeOrOverwriteFile...\n", 0);
  3774. DirentBcb = NULL;
  3775. //
  3776. // We fail this operation if the caller doesn't understand Ea's.
  3777. //
  3778. if (NoEaKnowledge
  3779. && EaLength > 0) {
  3780. Iosb.Status = STATUS_ACCESS_DENIED;
  3781. DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status);
  3782. return Iosb;
  3783. }
  3784. try {
  3785. //
  3786. // Before we actually truncate, check to see if the purge
  3787. // is going to fail.
  3788. //
  3789. if (!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers,
  3790. &FatLargeZero )) {
  3791. try_return( Iosb.Status = STATUS_USER_MAPPED_FILE );
  3792. }
  3793. //
  3794. // Setup the context and section object pointers, and update
  3795. // our reference counts
  3796. //
  3797. FatSetFileObject( FileObject,
  3798. UserFileOpen,
  3799. Fcb,
  3800. Ccb = UnwindCcb = FatCreateCcb( IrpContext ));
  3801. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  3802. //
  3803. // Since this is an supersede/overwrite, purge the section so
  3804. // that mappers will see zeros. We set the CREATE_IN_PROGRESS flag
  3805. // to prevent the Fcb from going away out from underneath us.
  3806. //
  3807. SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
  3808. CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE );
  3809. //
  3810. // Tentatively add the new Ea's
  3811. //
  3812. if (EaLength > 0) {
  3813. FatCreateEa( IrpContext,
  3814. Fcb->Vcb,
  3815. (PUCHAR) EaBuffer,
  3816. EaLength,
  3817. &Fcb->ShortName.Name.Oem,
  3818. &EaHandle );
  3819. UnwindEa = EaHandle;
  3820. EaChange = TRUE;
  3821. }
  3822. //
  3823. // Now set the new allocation size, we do that by first
  3824. // zeroing out the current file size. Then we truncate and
  3825. // allocate up to the new allocation size
  3826. //
  3827. (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
  3828. TRUE );
  3829. ReleasePaging = TRUE;
  3830. Fcb->Header.FileSize.LowPart = 0;
  3831. Fcb->Header.ValidDataLength.LowPart = 0;
  3832. Fcb->ValidDataToDisk = 0;
  3833. //
  3834. // Tell the cache manager the size went to zero
  3835. // This call is unconditional, because MM always wants to know.
  3836. //
  3837. CcSetFileSizes( FileObject,
  3838. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  3839. FatTruncateFileAllocation( IrpContext, Fcb, AllocationSize );
  3840. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  3841. ReleasePaging = FALSE;
  3842. FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize );
  3843. Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
  3844. //
  3845. // Modify the attributes and time of the file, by first reading
  3846. // in the dirent for the file and then updating its attributes
  3847. // and time fields. Note that for supersede we replace the file
  3848. // attributes as opposed to adding to them.
  3849. //
  3850. FatGetDirentFromFcbOrDcb( IrpContext,
  3851. Fcb,
  3852. &Dirent,
  3853. &DirentBcb );
  3854. //
  3855. // We must get the dirent since this Fcb is in good condition, verified as
  3856. // we crawled down the prefix tree. Prefix (no relation) isn't noticing
  3857. // this guarantee, so I'll help.
  3858. //
  3859. ASSERT( Dirent && DirentBcb );
  3860. //
  3861. // Update the appropriate dirent fields, and the fcb fields
  3862. //
  3863. Dirent->FileSize = 0;
  3864. FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
  3865. if (CreateDisposition == FILE_SUPERSEDE) {
  3866. Dirent->Attributes = FileAttributes;
  3867. } else {
  3868. Dirent->Attributes |= FileAttributes;
  3869. }
  3870. Fcb->DirentFatFlags = Dirent->Attributes;
  3871. KeQuerySystemTime( &Fcb->LastWriteTime );
  3872. (VOID)FatNtTimeToFatTime( IrpContext,
  3873. &Fcb->LastWriteTime,
  3874. TRUE,
  3875. &Dirent->LastWriteTime,
  3876. NULL );
  3877. if (FatData.ChicagoMode) {
  3878. Dirent->LastAccessDate = Dirent->LastWriteTime.Date;
  3879. }
  3880. NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE
  3881. | FILE_NOTIFY_CHANGE_ATTRIBUTES
  3882. | FILE_NOTIFY_CHANGE_SIZE;
  3883. //
  3884. // And now delete the previous Ea set if there was one.
  3885. //
  3886. if (!FatIsFat32(Fcb->Vcb) && Dirent->ExtendedAttributes != 0) {
  3887. //
  3888. // **** SDK fix, we won't fail this if there is
  3889. // an error in the Ea's, we'll just leave
  3890. // the orphaned Ea's in the file.
  3891. //
  3892. EaChange = TRUE;
  3893. try {
  3894. FatDeleteEa( IrpContext,
  3895. Fcb->Vcb,
  3896. Dirent->ExtendedAttributes,
  3897. &Fcb->ShortName.Name.Oem );
  3898. } except( EXCEPTION_EXECUTE_HANDLER ) {
  3899. FatResetExceptionState( IrpContext );
  3900. }
  3901. }
  3902. //
  3903. // Update the extended attributes handle in the dirent.
  3904. //
  3905. if (EaChange) {
  3906. ASSERT(!FatIsFat32(Fcb->Vcb));
  3907. Dirent->ExtendedAttributes = EaHandle;
  3908. NotifyFilter |= FILE_NOTIFY_CHANGE_EA;
  3909. }
  3910. //
  3911. // Now update the dirent to the new ea handle and set the bcb dirty
  3912. // Once we do this we can no longer back out the Ea
  3913. //
  3914. FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
  3915. UnwindEa = 0;
  3916. //
  3917. // Indicate that the Eas for this file have changed.
  3918. //
  3919. Ccb->EaModificationCount += Fcb->EaModificationCount;
  3920. //
  3921. // Check to see if we need to notify outstanding Irps for full
  3922. // changes only (i.e., we haven't added, deleted, or renamed the file).
  3923. //
  3924. FatNotifyReportChange( IrpContext,
  3925. Fcb->Vcb,
  3926. Fcb,
  3927. NotifyFilter,
  3928. FILE_ACTION_MODIFIED );
  3929. //
  3930. // And set our status to success
  3931. //
  3932. Iosb.Status = STATUS_SUCCESS;
  3933. if (CreateDisposition == FILE_SUPERSEDE) {
  3934. Iosb.Information = FILE_SUPERSEDED;
  3935. } else {
  3936. Iosb.Information = FILE_OVERWRITTEN;
  3937. }
  3938. try_exit: NOTHING;
  3939. } finally {
  3940. DebugUnwind( FatSupersedeOfOverwriteFile );
  3941. if (ReleasePaging) { ExReleaseResourceLite( Fcb->Header.PagingIoResource ); }
  3942. //
  3943. // If this is an abnormal termination then undo our work.
  3944. //
  3945. if (AbnormalTermination()) {
  3946. if (UnwindEa != 0) { FatDeleteEa( IrpContext, Fcb->Vcb, UnwindEa, &Fcb->ShortName.Name.Oem ); }
  3947. if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, UnwindCcb ); }
  3948. }
  3949. FatUnpinBcb( IrpContext, DirentBcb );
  3950. ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS);
  3951. DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status);
  3952. }
  3953. return Iosb;
  3954. }
  3955. VOID
  3956. FatSetFullNameInFcb(
  3957. IN PIRP_CONTEXT IrpContext,
  3958. IN PFCB Fcb,
  3959. IN PUNICODE_STRING FinalName
  3960. )
  3961. /*++
  3962. Routine Description:
  3963. This routine attempts a quick form of the full FatSetFullFileNameInFcb
  3964. operation.
  3965. NOTE: this routine is probably not worth the code duplication involved,
  3966. and is not equipped to handle the cases where the parent doesn't have
  3967. the full name set up.
  3968. Arguments:
  3969. Fcb - Supplies a pointer to the Fcb
  3970. FinalName - Supplies the last component of the path to this Fcb's dirent
  3971. Return Value:
  3972. None. May silently fail.
  3973. --*/
  3974. {
  3975. ASSERT( Fcb->FullFileName.Buffer == NULL );
  3976. //
  3977. // Prefer the ExactCaseLongName of the file for this operation, if set. In
  3978. // this way we avoid building the fullname with a short filename. Several
  3979. // operations assume this - the FinalNameLength in particular is the Lfn
  3980. // (if existant) length, and we use this to crack the fullname in paths
  3981. // such as the FsRtlNotify caller.
  3982. //
  3983. // If the caller specified a particular name and it is short, it is the
  3984. // case that the long name was set up.
  3985. //
  3986. if (Fcb->ExactCaseLongName.Buffer) {
  3987. ASSERT( Fcb->ExactCaseLongName.Length != 0 );
  3988. FinalName = &Fcb->ExactCaseLongName;
  3989. }
  3990. //
  3991. // Special case the root.
  3992. //
  3993. if (NodeType(Fcb->ParentDcb) == FAT_NTC_ROOT_DCB) {
  3994. Fcb->FullFileName.Length =
  3995. Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + FinalName->Length;
  3996. Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  3997. Fcb->FullFileName.Length,
  3998. TAG_FILENAME_BUFFER );
  3999. Fcb->FullFileName.Buffer[0] = L'\\';
  4000. RtlCopyMemory( &Fcb->FullFileName.Buffer[1],
  4001. &FinalName->Buffer[0],
  4002. FinalName->Length );
  4003. } else {
  4004. PUNICODE_STRING Prefix;
  4005. Prefix = &Fcb->ParentDcb->FullFileName;
  4006. //
  4007. // It is possible our parent's full filename is not set. Simply fail
  4008. // this attempt.
  4009. //
  4010. if (Prefix->Buffer == NULL) {
  4011. return;
  4012. }
  4013. Fcb->FullFileName.Length =
  4014. Fcb->FullFileName.MaximumLength = Prefix->Length + sizeof(WCHAR) + FinalName->Length;
  4015. Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  4016. Fcb->FullFileName.Length,
  4017. TAG_FILENAME_BUFFER );
  4018. RtlCopyMemory( &Fcb->FullFileName.Buffer[0],
  4019. &Prefix->Buffer[0],
  4020. Prefix->Length );
  4021. Fcb->FullFileName.Buffer[Prefix->Length / sizeof(WCHAR)] = L'\\';
  4022. RtlCopyMemory( &Fcb->FullFileName.Buffer[(Prefix->Length / sizeof(WCHAR)) + 1],
  4023. &FinalName->Buffer[0],
  4024. FinalName->Length );
  4025. }
  4026. }
  4027. NTSTATUS
  4028. FatCheckSystemSecurityAccess(
  4029. PIRP_CONTEXT IrpContext
  4030. )
  4031. {
  4032. PACCESS_STATE AccessState;
  4033. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
  4034. //
  4035. // We check if the caller wants ACCESS_SYSTEM_SECURITY access on this
  4036. // object and fail the request if he does.
  4037. //
  4038. ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
  4039. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  4040. //
  4041. // Check if the remaining privilege includes ACCESS_SYSTEM_SECURITY.
  4042. //
  4043. if (FlagOn( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY )) {
  4044. if (!SeSinglePrivilegeCheck( FatSecurityPrivilege,
  4045. UserMode )) {
  4046. return STATUS_ACCESS_DENIED;
  4047. }
  4048. //
  4049. // Move this privilege from the Remaining access to Granted access.
  4050. //
  4051. ClearFlag( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY );
  4052. SetFlag( AccessState->PreviouslyGrantedAccess, ACCESS_SYSTEM_SECURITY );
  4053. }
  4054. return STATUS_SUCCESS;
  4055. }