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.

15954 lines
518 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Create.c
  5. Abstract:
  6. This module implements the File Create routine for Ntfs called by the
  7. dispatch driver.
  8. Author:
  9. Brian Andrew [BrianAn] 10-Dec-1991
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. #ifdef NTFSDBG
  14. #include "lockorder.h"
  15. #endif
  16. //
  17. // The local debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_CREATE)
  20. //
  21. // Define a tag for general pool allocations from this module
  22. //
  23. #undef MODULE_POOL_TAG
  24. #define MODULE_POOL_TAG ('CFtN')
  25. //
  26. // Check for stack usage prior to the create call.
  27. //
  28. #ifdef _X86_
  29. #define OVERFLOW_CREATE_THRESHHOLD (0x1200)
  30. #else
  31. #define OVERFLOW_CREATE_THRESHHOLD (0x1B00)
  32. #endif // _X86_
  33. #ifdef BRIANDBG
  34. BOOLEAN NtfsCreateAllSparse = FALSE;
  35. BOOLEAN NtfsTraverseAccessCheck = FALSE;
  36. UNICODE_STRING NtfsTestName = {0x0,0x40,L" "};
  37. VOID
  38. NtfsTestOpenName (
  39. IN PFILE_OBJECT FileObject
  40. );
  41. #endif
  42. //
  43. // Local macros
  44. //
  45. //
  46. // VOID
  47. // NtfsPrepareForIrpCompletion (
  48. // IN PIRP_CONTEXT IrpContext,
  49. // IN PIRP Irp,
  50. // IN PNTFS_COMPLETION_CONTEXT Context
  51. // )
  52. //
  53. #define NtfsPrepareForIrpCompletion(IC,I,C) { \
  54. (C)->IrpContext = (IC); \
  55. IoCopyCurrentIrpStackLocationToNext( (I) ); \
  56. IoSetCompletionRoutine( (I), \
  57. NtfsCreateCompletionRoutine, \
  58. (C), \
  59. TRUE, \
  60. TRUE, \
  61. TRUE ); \
  62. IoSetNextIrpStackLocation( (I) ); \
  63. }
  64. //
  65. // BOOLEAN
  66. // NtfsVerifyNameIsDirectory (
  67. // IN PIRP_CONTEXT IrpContext,
  68. // IN PUNICODE_STRING AttrName,
  69. // IN PUNICODE_STRING AttrCodeName
  70. // )
  71. //
  72. #define NtfsVerifyNameIsDirectory( IC, AN, ACN ) \
  73. ( ( ((ACN)->Length == 0) \
  74. || NtfsAreNamesEqual( IC->Vcb->UpcaseTable, ACN, &NtfsIndexAllocation, TRUE )) \
  75. && \
  76. ( ((AN)->Length == 0) \
  77. || NtfsAreNamesEqual( IC->Vcb->UpcaseTable, AN, &NtfsFileNameIndex, TRUE )))
  78. //
  79. // BOOLEAN
  80. // NtfsVerifyNameIsBitmap (
  81. // IN PIRP_CONTEXT IrpContext,
  82. // IN PUNICODE_STRING AttrName,
  83. // IN PUNICODE_STRING AttrCodeName
  84. // )
  85. //
  86. #define NtfsVerifyNameIsBitmap( IC, AN, ACN ) \
  87. ( ( ((ACN)->Length == 0) \
  88. || NtfsAreNamesEqual( IC->Vcb->UpcaseTable, ACN, &NtfsBitmapString, TRUE )) \
  89. && \
  90. ( ((AN)->Length == 0) \
  91. || NtfsAreNamesEqual( IC->Vcb->UpcaseTable, AN, &NtfsFileNameIndex, TRUE )))
  92. //
  93. // BOOLEAN
  94. // NtfsVerifyNameIsAttributeList (
  95. // IN PIRP_CONTEXT IrpContext,
  96. // IN PUNICODE_STRING AttrName,
  97. // IN PUNICODE_STRING AttrCodeName
  98. // )
  99. //
  100. #define NtfsVerifyNameIsAttributeList( IC, AN, ACN ) \
  101. ( ((ACN)->Length != 0) \
  102. && NtfsAreNamesEqual( IC->Vcb->UpcaseTable, ACN, &NtfsAttrListString, TRUE ))
  103. //
  104. // BOOLEAN
  105. // NtfsVerifyNameIsReparsePoint (
  106. // IN PIRP_CONTEXT IrpContext,
  107. // IN PUNICODE_STRING AttrName,
  108. // IN PUNICODE_STRING AttrCodeName
  109. // )
  110. //
  111. #define NtfsVerifyNameIsReparsePoint( IC, AN, ACN ) \
  112. ( ((ACN)->Length != 0) \
  113. && NtfsAreNamesEqual( IC->Vcb->UpcaseTable, ACN, &NtfsReparsePointString, TRUE ))
  114. //
  115. // These are the flags used by the I/O system in deciding whether
  116. // to apply the share access modes.
  117. //
  118. #define NtfsAccessDataFlags ( \
  119. FILE_EXECUTE \
  120. | FILE_READ_DATA \
  121. | FILE_WRITE_DATA \
  122. | FILE_APPEND_DATA \
  123. | DELETE \
  124. )
  125. #define NtfsIsStreamNew( IrpInfo ) \
  126. ( (IrpInfo == FILE_CREATED) || \
  127. (IrpInfo == FILE_SUPERSEDED) || \
  128. (IrpInfo == FILE_OVERWRITTEN) )
  129. //
  130. // Subset of flags used by IO system to determine whether user has used either
  131. // BACKUP or RESTORE privilege to get access to file.
  132. //
  133. #define NTFS_REQUIRES_BACKUP (FILE_READ_DATA | FILE_READ_ATTRIBUTES)
  134. #define NTFS_REQUIRES_RESTORE (FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | DELETE)
  135. //
  136. // Local definitions
  137. //
  138. typedef enum _SHARE_MODIFICATION_TYPE {
  139. CheckShareAccess,
  140. UpdateShareAccess,
  141. SetShareAccess,
  142. RecheckShareAccess
  143. } SHARE_MODIFICATION_TYPE, *PSHARE_MODIFICATION_TYPE;
  144. typedef struct _CREATE_CONTEXT {
  145. ULONG FileHashValue;
  146. ULONG FileHashLength;
  147. ULONG ParentHashValue;
  148. ULONG ParentHashLength;
  149. } CREATE_CONTEXT, *PCREATE_CONTEXT;
  150. UNICODE_STRING NtfsVolumeDasd = CONSTANT_UNICODE_STRING ( L"$Volume" );
  151. LUID NtfsSecurityPrivilege = { SE_SECURITY_PRIVILEGE, 0 };
  152. //
  153. // VOID
  154. // NtfsBackoutFailedOpens (
  155. // IN PIRP_CONTEXT IrpContext,
  156. // IN PFILE_OBJECT FileObject,
  157. // IN PFCB ThisFcb,
  158. // IN PSCB ThisScb OPTIONAL,
  159. // IN PCCB ThisCcb OPTIONAL
  160. // );
  161. //
  162. #define NtfsBackoutFailedOpens(IC,FO,F,S,C) { \
  163. if (((S) != NULL) && ((C) != NULL)) { \
  164. \
  165. NtfsBackoutFailedOpensPriv( IC, FO, F, S, C ); \
  166. } \
  167. } \
  168. //
  169. // Local support routines.
  170. //
  171. NTSTATUS
  172. NtfsOpenFcbById (
  173. IN PIRP_CONTEXT IrpContext,
  174. IN PIRP Irp,
  175. IN PIO_STACK_LOCATION IrpSp,
  176. IN PVCB Vcb,
  177. IN PLCB ParentLcb OPTIONAL,
  178. IN OUT PFCB *CurrentFcb,
  179. IN BOOLEAN UseCurrentFcb,
  180. IN FILE_REFERENCE FileReference,
  181. IN UNICODE_STRING AttrName,
  182. IN UNICODE_STRING AttrCodeName,
  183. IN PVOID NetworkInfo OPTIONAL,
  184. OUT PSCB *ThisScb,
  185. OUT PCCB *ThisCcb
  186. );
  187. NTSTATUS
  188. NtfsOpenExistingPrefixFcb (
  189. IN PIRP_CONTEXT IrpContext,
  190. IN PIRP Irp,
  191. IN PIO_STACK_LOCATION IrpSp,
  192. IN PFCB ThisFcb,
  193. IN PLCB Lcb OPTIONAL,
  194. IN ULONG FullPathNameLength,
  195. IN UNICODE_STRING AttrName,
  196. IN UNICODE_STRING AttrCodeName,
  197. IN ULONG CreateFlags,
  198. IN PVOID NetworkInfo OPTIONAL,
  199. IN PCREATE_CONTEXT CreateContext,
  200. OUT PSCB *ThisScb,
  201. OUT PCCB *ThisCcb
  202. );
  203. NTSTATUS
  204. NtfsOpenTargetDirectory (
  205. IN PIRP_CONTEXT IrpContext,
  206. IN PIRP Irp,
  207. IN PIO_STACK_LOCATION IrpSp,
  208. IN PFCB ThisFcb,
  209. IN PLCB ParentLcb OPTIONAL,
  210. IN OUT PUNICODE_STRING FullPathName,
  211. IN ULONG FinalNameLength,
  212. IN ULONG CreateFlags,
  213. OUT PSCB *ThisScb,
  214. OUT PCCB *ThisCcb
  215. );
  216. NTSTATUS
  217. NtfsOpenFile (
  218. IN PIRP_CONTEXT IrpContext,
  219. IN PIRP Irp,
  220. IN PIO_STACK_LOCATION IrpSp,
  221. IN PSCB ParentScb,
  222. IN PINDEX_ENTRY IndexEntry,
  223. IN UNICODE_STRING FullPathName,
  224. IN UNICODE_STRING FinalName,
  225. IN UNICODE_STRING AttrName,
  226. IN UNICODE_STRING AttrCodeName,
  227. IN PQUICK_INDEX QuickIndex,
  228. IN ULONG CreateFlags,
  229. IN PVOID NetworkInfo OPTIONAL,
  230. IN PCREATE_CONTEXT CreateContext,
  231. OUT PFCB *CurrentFcb,
  232. OUT PLCB *LcbForTeardown,
  233. OUT PSCB *ThisScb,
  234. OUT PCCB *ThisCcb
  235. );
  236. NTSTATUS
  237. NtfsCreateNewFile (
  238. IN PIRP_CONTEXT IrpContext,
  239. IN PIRP Irp,
  240. IN PIO_STACK_LOCATION IrpSp,
  241. IN PSCB ParentScb,
  242. IN PFILE_NAME FileNameAttr,
  243. IN UNICODE_STRING FullPathName,
  244. IN UNICODE_STRING FinalName,
  245. IN UNICODE_STRING AttrName,
  246. IN UNICODE_STRING AttrCodeName,
  247. IN ULONG CreateFlags,
  248. IN PINDEX_CONTEXT *IndexContext,
  249. IN PCREATE_CONTEXT CreateContext,
  250. OUT PFCB *CurrentFcb,
  251. OUT PLCB *LcbForTeardown,
  252. OUT PSCB *ThisScb,
  253. OUT PCCB *ThisCcb
  254. );
  255. PLCB
  256. NtfsOpenSubdirectory (
  257. IN PIRP_CONTEXT IrpContext,
  258. IN PSCB ParentScb,
  259. IN UNICODE_STRING Name,
  260. IN ULONG CreateFlags,
  261. OUT PFCB *CurrentFcb,
  262. OUT PLCB *LcbForTeardown,
  263. IN PINDEX_ENTRY IndexEntry
  264. );
  265. NTSTATUS
  266. NtfsOpenAttributeInExistingFile (
  267. IN PIRP_CONTEXT IrpContext,
  268. IN PIRP Irp,
  269. IN PIO_STACK_LOCATION IrpSp,
  270. IN PLCB ThisLcb OPTIONAL,
  271. IN PFCB ThisFcb,
  272. IN ULONG LastFileNameOffset,
  273. IN UNICODE_STRING AttrName,
  274. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  275. IN ULONG CcbFlags,
  276. IN ULONG CreateFlags,
  277. IN PVOID NetworkInfo OPTIONAL,
  278. OUT PSCB *ThisScb,
  279. OUT PCCB *ThisCcb
  280. );
  281. NTSTATUS
  282. NtfsOpenExistingAttr (
  283. IN PIRP_CONTEXT IrpContext,
  284. IN PIRP Irp,
  285. IN PIO_STACK_LOCATION IrpSp,
  286. IN PLCB ThisLcb OPTIONAL,
  287. IN PFCB ThisFcb,
  288. IN ULONG LastFileNameOffset,
  289. IN UNICODE_STRING AttrName,
  290. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  291. IN ULONG CcbFlags,
  292. IN ULONG CreateFlags,
  293. IN BOOLEAN DirectoryOpen,
  294. IN PVOID NetworkInfo OPTIONAL,
  295. OUT PSCB *ThisScb,
  296. OUT PCCB *ThisCcb
  297. );
  298. NTSTATUS
  299. NtfsOverwriteAttr (
  300. IN PIRP_CONTEXT IrpContext,
  301. IN PIRP Irp,
  302. IN PIO_STACK_LOCATION IrpSp,
  303. IN PLCB ThisLcb OPTIONAL,
  304. IN PFCB ThisFcb,
  305. IN BOOLEAN Supersede,
  306. IN ULONG LastFileNameOffset,
  307. IN UNICODE_STRING AttrName,
  308. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  309. IN ULONG CcbFlags,
  310. IN ULONG CreateFlags,
  311. OUT PSCB *ThisScb,
  312. OUT PCCB *ThisCcb
  313. );
  314. NTSTATUS
  315. NtfsOpenNewAttr (
  316. IN PIRP_CONTEXT IrpContext,
  317. IN PIRP Irp,
  318. IN PIO_STACK_LOCATION IrpSp,
  319. IN PLCB ThisLcb,
  320. IN PFCB ThisFcb,
  321. IN ULONG LastFileNameOffset,
  322. IN UNICODE_STRING AttrName,
  323. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  324. IN LOGICAL CreateFile,
  325. IN ULONG CcbFlags,
  326. IN BOOLEAN LogIt,
  327. IN ULONG CreateFlags,
  328. OUT PSCB *ThisScb,
  329. OUT PCCB *ThisCcb
  330. );
  331. BOOLEAN
  332. NtfsParseNameForCreate (
  333. IN PIRP_CONTEXT IrpContext,
  334. IN UNICODE_STRING String,
  335. IN OUT PUNICODE_STRING FileObjectString,
  336. IN OUT PUNICODE_STRING OriginalString,
  337. IN OUT PUNICODE_STRING NewNameString,
  338. OUT PUNICODE_STRING AttrName,
  339. OUT PUNICODE_STRING AttrCodeName
  340. );
  341. NTSTATUS
  342. NtfsCheckValidAttributeAccess (
  343. IN PIO_STACK_LOCATION IrpSp,
  344. IN PVCB Vcb,
  345. IN PDUPLICATED_INFORMATION Info OPTIONAL,
  346. IN OUT PUNICODE_STRING AttrName,
  347. IN UNICODE_STRING AttrCodeName,
  348. IN ULONG CreateFlags,
  349. OUT PATTRIBUTE_TYPE_CODE AttrTypeCode,
  350. OUT PULONG CcbFlags,
  351. OUT PBOOLEAN IndexedAttribute
  352. );
  353. NTSTATUS
  354. NtfsOpenAttributeCheck (
  355. IN PIRP_CONTEXT IrpContext,
  356. IN PIRP Irp,
  357. IN PIO_STACK_LOCATION IrpSp,
  358. OUT PSCB *ThisScb,
  359. OUT PSHARE_MODIFICATION_TYPE ShareModificationType
  360. );
  361. VOID
  362. NtfsAddEa (
  363. IN PIRP_CONTEXT IrpContext,
  364. IN PVCB Vcb,
  365. IN PFCB ThisFcb,
  366. IN PFILE_FULL_EA_INFORMATION EaBuffer OPTIONAL,
  367. IN ULONG EaLength,
  368. OUT PIO_STATUS_BLOCK Iosb
  369. );
  370. VOID
  371. NtfsCreateAttribute (
  372. IN PIRP_CONTEXT IrpContext,
  373. IN PIO_STACK_LOCATION IrpSp,
  374. IN OUT PFCB ThisFcb,
  375. IN OUT PSCB ThisScb,
  376. IN PLCB ThisLcb,
  377. IN LONGLONG AllocationSize,
  378. IN BOOLEAN LogIt,
  379. IN BOOLEAN ForceNonresident,
  380. IN PUSHORT PreviousFlags OPTIONAL
  381. );
  382. VOID
  383. NtfsRemoveDataAttributes (
  384. IN PIRP_CONTEXT IrpContext,
  385. IN PFCB ThisFcb,
  386. IN PLCB ThisLcb OPTIONAL,
  387. IN PFILE_OBJECT FileObject,
  388. IN ULONG LastFileNameOffset,
  389. IN ULONG CreateFlags
  390. );
  391. VOID
  392. NtfsRemoveReparsePoint (
  393. IN PIRP_CONTEXT IrpContext,
  394. IN PFCB ThisFcb
  395. );
  396. VOID
  397. NtfsReplaceAttribute (
  398. IN PIRP_CONTEXT IrpContext,
  399. IN PIO_STACK_LOCATION IrpSp,
  400. IN PFCB ThisFcb,
  401. IN PSCB ThisScb,
  402. IN PLCB ThisLcb,
  403. IN LONGLONG AllocationSize
  404. );
  405. NTSTATUS
  406. NtfsOpenAttribute (
  407. IN PIRP_CONTEXT IrpContext,
  408. IN PIO_STACK_LOCATION IrpSp,
  409. IN PVCB Vcb,
  410. IN PLCB ThisLcb OPTIONAL,
  411. IN PFCB ThisFcb,
  412. IN ULONG LastFileNameOffset,
  413. IN UNICODE_STRING AttrName,
  414. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  415. IN SHARE_MODIFICATION_TYPE ShareModificationType,
  416. IN TYPE_OF_OPEN TypeOfOpen,
  417. IN LOGICAL CreateFile,
  418. IN ULONG CcbFlags,
  419. IN PVOID NetworkInfo OPTIONAL,
  420. IN OUT PSCB *ThisScb,
  421. OUT PCCB *ThisCcb
  422. );
  423. VOID
  424. NtfsBackoutFailedOpensPriv (
  425. IN PIRP_CONTEXT IrpContext,
  426. IN PFILE_OBJECT FileObject,
  427. IN PFCB ThisFcb,
  428. IN PSCB ThisScb,
  429. IN PCCB ThisCcb
  430. );
  431. VOID
  432. NtfsUpdateScbFromMemory (
  433. IN OUT PSCB Scb,
  434. IN POLD_SCB_SNAPSHOT ScbSizes
  435. );
  436. VOID
  437. NtfsOplockPrePostIrp (
  438. IN PVOID Context,
  439. IN PIRP Irp
  440. );
  441. NTSTATUS
  442. NtfsCreateCompletionRoutine (
  443. IN PDEVICE_OBJECT DeviceObject,
  444. IN PIRP Irp,
  445. IN PVOID Contxt
  446. );
  447. NTSTATUS
  448. NtfsCheckExistingFile (
  449. IN PIRP_CONTEXT IrpContext,
  450. IN PIO_STACK_LOCATION IrpSp,
  451. IN PLCB ThisLcb OPTIONAL,
  452. IN PFCB ThisFcb,
  453. IN ULONG CcbFlags
  454. );
  455. NTSTATUS
  456. NtfsBreakBatchOplock (
  457. IN PIRP_CONTEXT IrpContext,
  458. IN PIRP Irp,
  459. IN PIO_STACK_LOCATION IrpSp,
  460. IN PFCB ThisFcb,
  461. IN UNICODE_STRING AttrName,
  462. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  463. OUT PSCB *ThisScb
  464. );
  465. NTSTATUS
  466. NtfsCompleteLargeAllocation (
  467. IN PIRP_CONTEXT IrpContext,
  468. IN PIRP Irp,
  469. IN PLCB Lcb,
  470. IN PSCB Scb,
  471. IN PCCB Ccb,
  472. IN ULONG CreateFlags
  473. );
  474. NTSTATUS
  475. NtfsEncryptionCreateCallback (
  476. IN PIRP_CONTEXT IrpContext,
  477. IN PIRP Irp,
  478. IN PIO_STACK_LOCATION IrpSp,
  479. IN PSCB ThisScb,
  480. IN PCCB ThisCcb,
  481. IN PFCB CurrentFcb,
  482. IN PFCB ParentFcb,
  483. IN BOOLEAN CreateNewFile
  484. );
  485. VOID
  486. NtfsPostProcessEncryptedCreate (
  487. IN PIRP_CONTEXT IrpContext,
  488. IN PFILE_OBJECT FileObject,
  489. IN ULONG EncryptionFileDirFlags,
  490. IN ULONG FailedInPostCreateOnly
  491. );
  492. NTSTATUS
  493. NtfsGetReparsePointValue (
  494. IN PIRP_CONTEXT IrpContext,
  495. IN PIRP Irp,
  496. PIO_STACK_LOCATION IrpSp,
  497. IN PFCB Fcb,
  498. IN USHORT RemainingNameLength
  499. );
  500. BOOLEAN
  501. NtfsCheckValidFileAccess(
  502. IN PFCB ThisFcb,
  503. IN PIO_STACK_LOCATION IrpSp
  504. );
  505. NTSTATUS
  506. NtfsLookupObjectId (
  507. IN PIRP_CONTEXT IrpContext,
  508. IN PVCB Vcb,
  509. IN PUNICODE_STRING FileName,
  510. OUT PFILE_REFERENCE FileReference
  511. );
  512. #ifdef ALLOC_PRAGMA
  513. #pragma alloc_text(PAGE, NtfsAddEa)
  514. #pragma alloc_text(PAGE, NtfsBackoutFailedOpensPriv)
  515. #pragma alloc_text(PAGE, NtfsBreakBatchOplock)
  516. #pragma alloc_text(PAGE, NtfsCheckExistingFile)
  517. #pragma alloc_text(PAGE, NtfsCheckValidAttributeAccess)
  518. #pragma alloc_text(PAGE, NtfsCheckValidFileAccess)
  519. #pragma alloc_text(PAGE, NtfsCommonCreate)
  520. #pragma alloc_text(PAGE, NtfsCommonVolumeOpen)
  521. #pragma alloc_text(PAGE, NtfsCompleteLargeAllocation)
  522. #pragma alloc_text(PAGE, NtfsCreateAttribute)
  523. #pragma alloc_text(PAGE, NtfsCreateCompletionRoutine)
  524. #pragma alloc_text(PAGE, NtfsCreateNewFile)
  525. #pragma alloc_text(PAGE, NtfsEncryptionCreateCallback)
  526. #pragma alloc_text(PAGE, NtfsFsdCreate)
  527. #pragma alloc_text(PAGE, NtfsGetReparsePointValue)
  528. #pragma alloc_text(PAGE, NtfsInitializeFcbAndStdInfo)
  529. #pragma alloc_text(PAGE, NtfsLookupObjectId)
  530. #pragma alloc_text(PAGE, NtfsNetworkOpenCreate)
  531. #pragma alloc_text(PAGE, NtfsOpenAttribute)
  532. #pragma alloc_text(PAGE, NtfsOpenAttributeCheck)
  533. #pragma alloc_text(PAGE, NtfsOpenAttributeInExistingFile)
  534. #pragma alloc_text(PAGE, NtfsOpenExistingAttr)
  535. #pragma alloc_text(PAGE, NtfsOpenExistingPrefixFcb)
  536. #pragma alloc_text(PAGE, NtfsOpenFcbById)
  537. #pragma alloc_text(PAGE, NtfsOpenFile)
  538. #pragma alloc_text(PAGE, NtfsOpenNewAttr)
  539. #pragma alloc_text(PAGE, NtfsOpenSubdirectory)
  540. #pragma alloc_text(PAGE, NtfsOpenTargetDirectory)
  541. #pragma alloc_text(PAGE, NtfsOplockPrePostIrp)
  542. #pragma alloc_text(PAGE, NtfsOverwriteAttr)
  543. #pragma alloc_text(PAGE, NtfsParseNameForCreate)
  544. #pragma alloc_text(PAGE, NtfsPostProcessEncryptedCreate)
  545. #pragma alloc_text(PAGE, NtfsRemoveDataAttributes)
  546. #pragma alloc_text(PAGE, NtfsRemoveReparsePoint)
  547. #pragma alloc_text(PAGE, NtfsReplaceAttribute)
  548. #pragma alloc_text(PAGE, NtfsTryOpenFcb)
  549. #pragma alloc_text(PAGE, NtfsUpdateScbFromMemory)
  550. #endif
  551. NTSTATUS
  552. NtfsFsdCreate (
  553. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  554. IN PIRP Irp
  555. )
  556. /*++
  557. Routine Description:
  558. This routine implements the FSD part of Create.
  559. Arguments:
  560. VolumeDeviceObject - Supplies the volume device object where the
  561. file exists
  562. Irp - Supplies the Irp being processed
  563. Return Value:
  564. NTSTATUS - The FSD status for the IRP
  565. --*/
  566. {
  567. TOP_LEVEL_CONTEXT TopLevelContext;
  568. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  569. NTSTATUS Status = STATUS_SUCCESS;
  570. PIRP_CONTEXT IrpContext;
  571. LOGICAL CallPostCreate = FALSE;
  572. BOOLEAN Wait;
  573. OPLOCK_CLEANUP OplockCleanup;
  574. NTFS_COMPLETION_CONTEXT CompletionContext;
  575. LOGICAL PrevStackSwapEnable;
  576. LOGICAL ExitFileSystem;
  577. ASSERT_IRP( Irp );
  578. PAGED_CODE();
  579. //
  580. // If we were called with our file system device object instead of a
  581. // volume device object, just complete this request with STATUS_SUCCESS
  582. //
  583. if (VolumeDeviceObject->DeviceObject.Size == (USHORT)sizeof(DEVICE_OBJECT)) {
  584. Irp->IoStatus.Status = STATUS_SUCCESS;
  585. Irp->IoStatus.Information = FILE_OPENED;
  586. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  587. return STATUS_SUCCESS;
  588. }
  589. DebugTrace( +1, Dbg, ("NtfsFsdCreate\n") );
  590. if (NtfsData.EncryptionCallBackTable.PreCreate != NULL) {
  591. ASSERT( NtfsData.EncryptionCallBackTable.PostCreate != NULL );
  592. Status = NtfsData.EncryptionCallBackTable.PreCreate( (PDEVICE_OBJECT) VolumeDeviceObject,
  593. Irp,
  594. IoGetCurrentIrpStackLocation(Irp)->FileObject );
  595. //
  596. // Raise the status if a failure.
  597. //
  598. if (Status != STATUS_SUCCESS) {
  599. NtfsCompleteRequest( NULL, Irp, Status );
  600. return Status;
  601. }
  602. //
  603. // We have to pair up our PreCreates with PostCreates, so remember them.
  604. //
  605. CallPostCreate = TRUE;
  606. } else {
  607. //
  608. // If we simply don't have a precreate routine registered, then the precreate
  609. // routine can't fail. Let's always remember to call post create in this case.
  610. //
  611. CallPostCreate = TRUE;
  612. }
  613. //
  614. // Call the common Create routine
  615. //
  616. IrpContext = NULL;
  617. FsRtlEnterFileSystem();
  618. ExitFileSystem = TRUE;
  619. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  620. RtlZeroMemory( &OplockCleanup, sizeof( OplockCleanup ) );
  621. do {
  622. try {
  623. if (IrpContext == NULL) {
  624. Wait = CanFsdWait( Irp ) || CallPostCreate;
  625. //
  626. // Allocate and initialize the Irp.
  627. //
  628. NtfsInitializeIrpContext( Irp, Wait, &IrpContext );
  629. //
  630. // Initialize the thread top level structure, if needed.
  631. //
  632. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  633. if (Wait) {
  634. KeInitializeEvent( &CompletionContext.Event, NotificationEvent, FALSE );
  635. OplockCleanup.CompletionContext = &CompletionContext;
  636. }
  637. } else if (Status == STATUS_LOG_FILE_FULL) {
  638. NtfsCheckpointForLogFileFull( IrpContext );
  639. }
  640. //
  641. // Lest we complete the IRP without doing the appropriate PostCreate callouts...
  642. // We'll complete the irp _unless_ we have an attached encryption driver with
  643. // a post create callout registered. An unfortunate side effect here is that we
  644. // have (inadvertently) called PreCreate on VolumeOpens as well...
  645. //
  646. if (CallPostCreate) {
  647. SetFlag( IrpContext->State,
  648. IRP_CONTEXT_STATE_EFS_CREATE | IRP_CONTEXT_STATE_PERSISTENT );
  649. }
  650. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DASD_OPEN )) {
  651. Status = NtfsCommonVolumeOpen( IrpContext, Irp );
  652. ASSERT( Status != STATUS_PENDING );
  653. } else {
  654. //
  655. // Make sure there is sufficient stack to perform the create.
  656. // If we don't, carefully post this request.
  657. //
  658. if (IoGetRemainingStackSize( ) >= OVERFLOW_CREATE_THRESHHOLD) {
  659. Status = NtfsCommonCreate( IrpContext, Irp, &OplockCleanup, NULL );
  660. } else {
  661. ASSERT( IrpContext->ExceptionStatus == 0 );
  662. //
  663. // Use the next stack location with NtfsCreateCompletionRoutine
  664. // and post this to a worker thread.
  665. //
  666. if (OplockCleanup.CompletionContext != NULL) {
  667. NtfsPrepareForIrpCompletion( IrpContext, Irp, OplockCleanup.CompletionContext );
  668. }
  669. //
  670. // If lock buffer call raises, this'll fall through to ProcessException below.
  671. // Normally, this'll just return PENDING and we wait for the IRP to complete.
  672. //
  673. Status = NtfsPostRequest( IrpContext, Irp );
  674. }
  675. }
  676. break;
  677. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  678. //
  679. // We had some trouble trying to perform the requested
  680. // operation, so we'll abort the I/O request with
  681. // the error status that we get back from the
  682. // exception code
  683. //
  684. Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
  685. }
  686. } while (Status == STATUS_CANT_WAIT ||
  687. Status == STATUS_LOG_FILE_FULL);
  688. //
  689. // Check if we need to have control of the Irp.
  690. //
  691. if (OplockCleanup.CompletionContext != NULL) {
  692. //
  693. // If pending then wait on the event to take control of the Irp again.
  694. //
  695. if (Status == STATUS_PENDING) {
  696. KPROCESSOR_MODE WaitMode = UserMode;
  697. //
  698. // Don't let the stack get swapped out in case we post.
  699. //
  700. PrevStackSwapEnable = KeSetKernelStackSwapEnable( FALSE );
  701. FsRtlExitFileSystem();
  702. ExitFileSystem = FALSE;
  703. //
  704. // Retry the wait until it completes successfully.
  705. //
  706. while (TRUE) {
  707. //
  708. // Test the wait status to see if someone is trying to rundown the current
  709. // thread.
  710. //
  711. Status = KeWaitForSingleObject( &OplockCleanup.CompletionContext->Event,
  712. Executive,
  713. WaitMode,
  714. FALSE,
  715. NULL );
  716. if (Status == STATUS_SUCCESS) { break; }
  717. if (Status != STATUS_KERNEL_APC) {
  718. //
  719. // In the (unlikely) event that the Irp we want to cancel is
  720. // waiting for the encryption driver to return from the post
  721. // create callout, we'll deadlock in here. By signalling the
  722. // EncryptionPending event, we're certain that any threads
  723. // in that state will run, and check whether their irp has been
  724. // cancelled. It's harmless to signal this event, since any
  725. // requests still actually waiting for the post create callout
  726. // to return will still see the encryption pending bit set
  727. // in their FCB and know to retry.
  728. //
  729. IoCancelIrp( Irp );
  730. KeSetEvent( &NtfsEncryptionPendingEvent, 0, FALSE );
  731. WaitMode = KernelMode;
  732. }
  733. }
  734. FsRtlEnterFileSystem();
  735. ExitFileSystem = TRUE;
  736. //
  737. // Restore the previous value for the stack swap.
  738. //
  739. if (PrevStackSwapEnable) {
  740. KeSetKernelStackSwapEnable( TRUE );
  741. }
  742. Status = Irp->IoStatus.Status;
  743. if (CallPostCreate) {
  744. goto PreCreateComplete;
  745. }
  746. NtfsCompleteRequest( NULL, Irp, Status );
  747. } else if (CallPostCreate) {
  748. NTSTATUS PostCreateStatus;
  749. ULONG FailedInPostCreateOnly;
  750. PreCreateComplete:
  751. if (NtfsData.EncryptionCallBackTable.PostCreate != NULL) {
  752. PIO_STACK_LOCATION IrpSp;
  753. //
  754. // Restore the thread context pointer if associated with this IrpContext.
  755. //
  756. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  757. NtfsRestoreTopLevelIrp();
  758. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  759. }
  760. FsRtlExitFileSystem();
  761. ExitFileSystem = FALSE;
  762. #ifdef NTFSDBG
  763. ASSERT( IrpContext->OwnershipState == None );
  764. #endif
  765. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  766. PostCreateStatus = NtfsData.EncryptionCallBackTable.PostCreate( (PDEVICE_OBJECT) VolumeDeviceObject,
  767. Irp,
  768. IrpSp->FileObject,
  769. Status,
  770. &IrpContext->EfsCreateContext );
  771. ASSERT( Status != STATUS_REPARSE || PostCreateStatus == STATUS_REPARSE );
  772. //
  773. // If we got STATUS_ACCESS_DENIED and the user asked for MAXIMUM_ALLOWED then simply
  774. // remove the references that allowed read or write access.
  775. //
  776. if ((PostCreateStatus == STATUS_ACCESS_DENIED) &&
  777. FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->OriginalDesiredAccess, MAXIMUM_ALLOWED ) &&
  778. (Irp->IoStatus.Information == FILE_OPENED)) {
  779. PSCB Scb = (PSCB) IrpSp->FileObject->FsContext;
  780. BOOLEAN CapturedDeleteAccess = IrpSp->FileObject->DeleteAccess;
  781. //
  782. // Swallow the error status in this case.
  783. //
  784. PostCreateStatus = STATUS_SUCCESS;
  785. //
  786. // Do all the work to reenter the file system. We should never raise out of this block of
  787. // code.
  788. //
  789. FsRtlEnterFileSystem();
  790. ExitFileSystem = TRUE;
  791. NtfsAcquireResourceExclusive( IrpContext,
  792. Scb,
  793. TRUE );
  794. IoRemoveShareAccess( IrpSp->FileObject,
  795. &Scb->ShareAccess );
  796. //
  797. // Clear out the history in the file object.
  798. //
  799. IrpSp->FileObject->ReadAccess = FALSE;
  800. IrpSp->FileObject->WriteAccess = FALSE;
  801. IrpSp->FileObject->DeleteAccess = FALSE;
  802. IrpSp->FileObject->SharedRead = FALSE;
  803. IrpSp->FileObject->SharedWrite = FALSE;
  804. IrpSp->FileObject->SharedDelete = FALSE;
  805. ClearFlag( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  806. (FILE_READ_DATA |
  807. FILE_EXECUTE |
  808. FILE_WRITE_DATA |
  809. FILE_APPEND_DATA) );
  810. //
  811. // If we already granted delete access then reapply.
  812. //
  813. if (CapturedDeleteAccess) {
  814. PostCreateStatus = IoCheckShareAccess( DELETE,
  815. IrpSp->Parameters.Create.ShareAccess,
  816. IrpSp->FileObject,
  817. &Scb->ShareAccess,
  818. TRUE );
  819. }
  820. NtfsReleaseResource( IrpContext,
  821. Scb );
  822. FsRtlExitFileSystem();
  823. ExitFileSystem = FALSE;
  824. }
  825. } else {
  826. PostCreateStatus = STATUS_SUCCESS;
  827. }
  828. //
  829. // We may have posted the create due to an oplock, in which case the IrpContext
  830. // will look like we're in the FSP thread. Let's clear the bit now since we're
  831. // not in the FSP thread now.
  832. //
  833. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP );
  834. //
  835. // Do our final cleanup only if we created a new encrypted directory/file or
  836. // we got an error from the encryption callback above.
  837. //
  838. FailedInPostCreateOnly = NT_SUCCESS( Status ) && !NT_SUCCESS( PostCreateStatus );
  839. if (FailedInPostCreateOnly ||
  840. FlagOn( IrpContext->EncryptionFileDirFlags, FILE_NEW | DIRECTORY_NEW )) {
  841. //
  842. // Reenter the filesystem at this point.
  843. //
  844. if (!ExitFileSystem) {
  845. FsRtlEnterFileSystem();
  846. ExitFileSystem = TRUE;
  847. }
  848. //
  849. // Initialize the thread top level structure, if needed.
  850. //
  851. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  852. //
  853. // There's no fileobject to cleanup if the normal part of this create failed.
  854. //
  855. if (NT_SUCCESS( Status ) &&
  856. (Status != STATUS_REPARSE)) {
  857. NtfsPostProcessEncryptedCreate( IrpContext,
  858. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  859. IrpContext->EncryptionFileDirFlags,
  860. FailedInPostCreateOnly );
  861. }
  862. }
  863. //
  864. // If the encryption driver came up with a new reason to fail this irp, return
  865. // that status.
  866. //
  867. if (FailedInPostCreateOnly) { Status = PostCreateStatus; }
  868. //
  869. // Now we're really done with both the irp context and the irp, so let's
  870. // get rid of them.
  871. //
  872. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT );
  873. NtfsCompleteRequest( IrpContext, Irp, Status );
  874. }
  875. }
  876. if (ExitFileSystem) {
  877. FsRtlExitFileSystem();
  878. }
  879. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  880. //
  881. // We should never return STATUS_CANT_WAIT or STATUS_PENDING
  882. //
  883. ASSERT( (Status != STATUS_CANT_WAIT) && (Status != STATUS_PENDING ) );
  884. //
  885. // And return to our caller
  886. //
  887. DebugTrace( -1, Dbg, ("NtfsFsdCreate -> %08lx\n", Status) );
  888. return Status;
  889. }
  890. BOOLEAN
  891. NtfsNetworkOpenCreate (
  892. IN PIRP Irp,
  893. OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
  894. IN PDEVICE_OBJECT DeviceObject
  895. )
  896. /*++
  897. Routine Description:
  898. This routine implements the fast open create for path-based queries.
  899. Arguments:
  900. Irp - Supplies the Irp being processed
  901. Buffer - Buffer to return the network query information
  902. DeviceObject - Supplies the volume device object where the file exists
  903. Return Value:
  904. BOOLEAN - Indicates whether or not the fast path could be taken.
  905. --*/
  906. {
  907. TOP_LEVEL_CONTEXT TopLevelContext;
  908. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  909. BOOLEAN Result = TRUE;
  910. BOOLEAN DasdOpen = FALSE;
  911. OPLOCK_CLEANUP OplockCleanup;
  912. NTSTATUS Status;
  913. IRP_CONTEXT LocalIrpContext;
  914. PIRP_CONTEXT IrpContext = &LocalIrpContext;
  915. ASSERT_IRP( Irp );
  916. UNREFERENCED_PARAMETER( DeviceObject );
  917. PAGED_CODE();
  918. //
  919. //
  920. // Call the common Create routine
  921. //
  922. FsRtlEnterFileSystem();
  923. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
  924. RtlZeroMemory( &OplockCleanup, sizeof( OplockCleanup ) );
  925. try {
  926. //
  927. // Allocate the Irp and update the top level storage.
  928. //
  929. NtfsInitializeIrpContext( Irp, TRUE, &IrpContext );
  930. NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
  931. Status = NtfsCommonCreate( IrpContext, Irp, &OplockCleanup, Buffer );
  932. } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  933. //
  934. // Catch the case where someone in attempting this on a DASD open.
  935. //
  936. if ((IrpContext != NULL) && (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_DASD_OPEN ))) {
  937. DasdOpen = TRUE;
  938. }
  939. //
  940. // We had some trouble trying to perform the requested
  941. // operation, so we'll abort the I/O request with
  942. // the error status that we get back from the
  943. // exception code. Since there is no Irp the exception package
  944. // will always deallocate the IrpContext so we won't do
  945. // any retry in this path.
  946. //
  947. Status = GetExceptionCode();
  948. //
  949. // Don't pass a retryable error to ProcessException. We want to
  950. // force this request to the Irp path in any case.
  951. //
  952. if ((Status == STATUS_CANT_WAIT) || (Status == STATUS_LOG_FILE_FULL)) {
  953. Status = STATUS_FILE_LOCK_CONFLICT;
  954. IrpContext->ExceptionStatus = STATUS_FILE_LOCK_CONFLICT;
  955. }
  956. Status = NtfsProcessException( IrpContext, NULL, Status );
  957. //
  958. // Always fail the DASD case.
  959. //
  960. if (DasdOpen) {
  961. Status = STATUS_INVALID_PARAMETER;
  962. }
  963. }
  964. //
  965. // STATUS_SUCCESS is the typical case. Test for it first.
  966. //
  967. if (Status != STATUS_SUCCESS) {
  968. //
  969. // Return STATUS_FILE_LOCK_CONFLICT for any retryable error.
  970. //
  971. ASSERT( (Status != STATUS_CANT_WAIT) && (Status != STATUS_LOG_FILE_FULL) );
  972. if ((Status == STATUS_REPARSE) || (Status == STATUS_FILE_LOCK_CONFLICT)) {
  973. Result = FALSE;
  974. Status = STATUS_FILE_LOCK_CONFLICT;
  975. }
  976. }
  977. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  978. FsRtlExitFileSystem();
  979. //
  980. // And return to our caller
  981. //
  982. Irp->IoStatus.Status = Status;
  983. return Result;
  984. }
  985. NTSTATUS
  986. NtfsCommonCreate (
  987. IN PIRP_CONTEXT IrpContext,
  988. IN PIRP Irp,
  989. IN POPLOCK_CLEANUP OplockCleanup,
  990. OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInfo OPTIONAL
  991. )
  992. /*++
  993. Routine Description:
  994. This is the common routine for Create called by both the fsd and fsp
  995. threads. If this open has already been detected to be a volume open then
  996. take we will take the volume open path instead.
  997. Arguments:
  998. Irp - Supplies the Irp to process
  999. CompletionContext - Event used to serialize waiting for the oplock break.
  1000. NetworkInfo - Optional buffer to return the queried data for
  1001. NetworkInformation. Its presence indicates that we should not
  1002. do a full open.
  1003. Return Value:
  1004. NTSTATUS - The return status for the operation
  1005. --*/
  1006. {
  1007. PIO_STACK_LOCATION IrpSp;
  1008. PFILE_OBJECT RelatedFileObject;
  1009. NTSTATUS Status = STATUS_SUCCESS;
  1010. ULONG AcquireFlags = 0;
  1011. UNICODE_STRING AttrName;
  1012. UNICODE_STRING AttrCodeName;
  1013. PVCB Vcb;
  1014. //
  1015. // The following are used to teardown any Lcb/Fcb this
  1016. // routine is responsible for.
  1017. //
  1018. PLCB LcbForTeardown = NULL;
  1019. //
  1020. // The following indicate how far down the tree we have scanned.
  1021. //
  1022. PFCB ParentFcb;
  1023. PLCB CurrentLcb;
  1024. PFCB CurrentFcb = NULL;
  1025. PSCB LastScb = NULL;
  1026. PSCB CurrentScb;
  1027. PLCB NextLcb;
  1028. //
  1029. // The following are the results of open operations.
  1030. //
  1031. PSCB ThisScb = NULL;
  1032. PCCB ThisCcb = NULL;
  1033. //
  1034. // The following are the in-memory structures associated with
  1035. // the relative file object.
  1036. //
  1037. TYPE_OF_OPEN RelatedFileObjectTypeOfOpen;
  1038. PFCB RelatedFcb;
  1039. PSCB RelatedScb;
  1040. PCCB RelatedCcb;
  1041. UCHAR CreateDisposition;
  1042. PFILE_NAME FileNameAttr = NULL;
  1043. USHORT FileNameAttrLength = 0;
  1044. PINDEX_ENTRY IndexEntry;
  1045. PBCB IndexEntryBcb = NULL;
  1046. QUICK_INDEX QuickIndex;
  1047. #if defined(_WIN64)
  1048. INDEX_CONTEXT IndexContextStruct;
  1049. #endif
  1050. PINDEX_CONTEXT IndexContext = NULL;
  1051. //
  1052. // The following unicode strings are used to track the names
  1053. // during the open operation. They may point to the same
  1054. // buffer so careful checks must be done at cleanup.
  1055. //
  1056. // OriginalFileName - This is the value to restore to the file
  1057. // object on error cleanup. This will containg the
  1058. // attribute type codes and attribute names if present.
  1059. //
  1060. // FullFileName - This is the constructed string which contains
  1061. // only the name components. It may point to the same
  1062. // buffer as the original name but the length value is
  1063. // adjusted to cut off the attribute code and name.
  1064. //
  1065. // ExactCaseName - This is the version of the full filename
  1066. // exactly as given by the caller. Used to preserve the
  1067. // case given by the caller in the event we do a case
  1068. // insensitive lookup. If the user is doing a relative open
  1069. // then we don't need to allocate a new buffer. We can use
  1070. // the original name from above.
  1071. //
  1072. // ExactCaseOffset - This is the offset in the FullFileName where
  1073. // the relative component begins. This is where we position ourselves
  1074. // when restoring the correct case for this name.
  1075. //
  1076. // RemainingName - This is the portion of the full name still
  1077. // to parse.
  1078. //
  1079. // FinalName - This is the current component of the full name.
  1080. //
  1081. // CaseInsensitiveIndex - This is the offset in the full file
  1082. // where we performed upcasing. We need to restore the
  1083. // exact case on failures and if we are creating a file.
  1084. //
  1085. PUNICODE_STRING OriginalFileName = &OplockCleanup->OriginalFileName;
  1086. PUNICODE_STRING FullFileName = &OplockCleanup->FullFileName;
  1087. PUNICODE_STRING ExactCaseName = &OplockCleanup->ExactCaseName;
  1088. USHORT ExactCaseOffset = 0;
  1089. UNICODE_STRING RemainingName;
  1090. UNICODE_STRING FinalName;
  1091. ULONG CaseInsensitiveIndex = 0;
  1092. CREATE_CONTEXT CreateContext;
  1093. ULONG CreateFlags = 0;
  1094. ASSERT_IRP_CONTEXT( IrpContext );
  1095. ASSERT_IRP( Irp );
  1096. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  1097. PAGED_CODE();
  1098. //
  1099. // Get the current Irp stack location
  1100. //
  1101. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1102. //
  1103. // Innitialize all the remaining fields in the OPLOCK_CLEANUP structure.
  1104. //
  1105. OplockCleanup->FileObject = IrpSp->FileObject;
  1106. OplockCleanup->RemainingDesiredAccess = IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess;
  1107. OplockCleanup->PreviouslyGrantedAccess = IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess;
  1108. OplockCleanup->DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  1109. OplockCleanup->AttributeNameLength = 0;
  1110. OplockCleanup->AttributeCodeNameLength = 0;
  1111. #ifdef BRIANDBG
  1112. if (NtfsTestName.Length != 0) {
  1113. NtfsTestOpenName( IrpSp->FileObject );
  1114. }
  1115. #endif
  1116. //
  1117. // Initialize the attribute strings.
  1118. //
  1119. AttrName.Length = 0;
  1120. AttrCodeName.Length = 0;
  1121. DebugTrace( +1, Dbg, ("NtfsCommonCreate: Entered\n") );
  1122. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  1123. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  1124. DebugTrace( 0, Dbg, ("->Flags = %08lx\n", Irp->Flags) );
  1125. DebugTrace( 0, Dbg, ("->FileObject = %08lx\n", IrpSp->FileObject) );
  1126. DebugTrace( 0, Dbg, ("->RelatedFileObject = %08lx\n", IrpSp->FileObject->RelatedFileObject) );
  1127. DebugTrace( 0, Dbg, ("->FileName = %Z\n", &IrpSp->FileObject->FileName) );
  1128. DebugTrace( 0, Dbg, ("->AllocationSize = %08lx %08lx\n", Irp->Overlay.AllocationSize.LowPart,
  1129. Irp->Overlay.AllocationSize.HighPart ) );
  1130. DebugTrace( 0, Dbg, ("->EaBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) );
  1131. DebugTrace( 0, Dbg, ("->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength) );
  1132. DebugTrace( 0, Dbg, ("->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess) );
  1133. DebugTrace( 0, Dbg, ("->Options = %08lx\n", IrpSp->Parameters.Create.Options) );
  1134. DebugTrace( 0, Dbg, ("->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes) );
  1135. DebugTrace( 0, Dbg, ("->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess) );
  1136. DebugTrace( 0, Dbg, ("->Directory = %04x\n", FlagOn( IrpSp->Parameters.Create.Options,
  1137. FILE_DIRECTORY_FILE )) );
  1138. DebugTrace( 0, Dbg, ("->NonDirectoryFile = %04x\n", FlagOn( IrpSp->Parameters.Create.Options,
  1139. FILE_NON_DIRECTORY_FILE )) );
  1140. DebugTrace( 0, Dbg, ("->NoIntermediateBuffering = %04x\n", FlagOn( IrpSp->Parameters.Create.Options,
  1141. FILE_NO_INTERMEDIATE_BUFFERING )) );
  1142. DebugTrace( 0, Dbg, ("->CreateDisposition = %04x\n", (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff) );
  1143. DebugTrace( 0, Dbg, ("->IsPagingFile = %04x\n", FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )) );
  1144. DebugTrace( 0, Dbg, ("->OpenTargetDirectory = %04x\n", FlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY )) );
  1145. DebugTrace( 0, Dbg, ("->CaseSensitive = %04x\n", FlagOn( IrpSp->Flags, SL_CASE_SENSITIVE )) );
  1146. DebugTrace( 0, Dbg, ("->NetworkInfo = %08x\n", NetworkInfo) );
  1147. DebugTrace( 0, Dbg, ("->EntryRemainingDesiredAccess = %08lx\n", OplockCleanup->RemainingDesiredAccess) );
  1148. DebugTrace( 0, Dbg, ("->EntryPreviouslyGrantedAccess = %08lx\n", OplockCleanup->PreviouslyGrantedAccess) );
  1149. //
  1150. // For NT5, the fact that the user has requested that the file be created
  1151. // encrypted means it will not be created compressed, regardless of the
  1152. // compression state of the parent directory.
  1153. //
  1154. if (FlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED )) {
  1155. SetFlag( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION );
  1156. }
  1157. //
  1158. // Clear encryption flags in irpcontext
  1159. //
  1160. IrpContext->EncryptionFileDirFlags = 0;
  1161. //
  1162. // Verify that we can wait and acquire the Vcb exclusively.
  1163. //
  1164. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  1165. DebugTrace( 0, Dbg, ("Can't wait in create\n") );
  1166. Status = NtfsPostRequest( IrpContext, Irp );
  1167. DebugTrace( -1, Dbg, ("NtfsCommonCreate: Exit -> %08lx\n", Status) );
  1168. return Status;
  1169. }
  1170. //
  1171. // If we're retrying this create because we're waiting for the key blob
  1172. // from the encryption driver, we want to wait for our notification
  1173. // event so we don't hog the cpu(s) and prevent the encryption driver
  1174. // from having a chance to give us the key blob.
  1175. //
  1176. if FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ENCRYPTION_RETRY ) {
  1177. KeWaitForSingleObject( &NtfsEncryptionPendingEvent,
  1178. Executive,
  1179. KernelMode,
  1180. FALSE,
  1181. NULL );
  1182. //
  1183. // While we were waiting for the encryption driver's post create callout
  1184. // to return, the create has been cancelled, most likely because the user's
  1185. // process is terminating. In that case, let's complete and exit now.
  1186. //
  1187. if (Irp->Cancel) {
  1188. Status = STATUS_CANCELLED;
  1189. DebugTrace( -1, Dbg, ("NtfsCommonCreate: Exit -> %08lx\n", Status) );
  1190. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE ) ||
  1191. (ARGUMENT_PRESENT( NetworkInfo ))) {
  1192. NtfsCompleteRequest( IrpContext,
  1193. NULL,
  1194. Status );
  1195. } else {
  1196. NtfsCompleteRequest( IrpContext,
  1197. Irp,
  1198. Status );
  1199. }
  1200. return Status;
  1201. }
  1202. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_ENCRYPTION_RETRY );
  1203. }
  1204. //
  1205. // Update the IrpContext with the oplock cleanup structure.
  1206. //
  1207. IrpContext->Union.OplockCleanup = OplockCleanup;
  1208. //
  1209. // Locate the volume device object and Vcb that we are trying to access.
  1210. //
  1211. Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb;
  1212. if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )) {
  1213. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX );
  1214. }
  1215. //
  1216. // Use a try-finally to facilitate cleanup.
  1217. //
  1218. try {
  1219. //
  1220. // Let's do some work here if the close lists have exceeded
  1221. // some threshold. Cast 1 to a pointer to indicate who is calling
  1222. // FspClose.
  1223. //
  1224. if ((NtfsData.AsyncCloseCount + NtfsData.DelayedCloseCount) > NtfsThrottleCreates) {
  1225. NtfsFspClose( (PVCB) 1 );
  1226. }
  1227. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX )) {
  1228. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  1229. } else {
  1230. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  1231. }
  1232. SetFlag( CreateFlags, CREATE_FLAG_ACQUIRED_VCB );
  1233. //
  1234. // Set up local pointers to the file name.
  1235. //
  1236. *FullFileName = *OriginalFileName = OplockCleanup->FileObject->FileName;
  1237. //
  1238. // Make sure that Darryl didn't send us a garbage name
  1239. //
  1240. ASSERT( OplockCleanup->FileObject->FileName.Length != 0 ||
  1241. OplockCleanup->FileObject->FileName.Buffer == 0 );
  1242. ExactCaseName->Buffer = NULL;
  1243. //
  1244. // Check a few flags before we proceed.
  1245. //
  1246. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE ) ==
  1247. (FILE_DIRECTORY_FILE | FILE_NON_DIRECTORY_FILE)) {
  1248. Status = STATUS_INVALID_PARAMETER;
  1249. try_return( Status );
  1250. }
  1251. //
  1252. // If the Vcb is locked then we cannot open another file. If we have performed
  1253. // a dismount then make sure we have the Vcb acquired exclusive so we can
  1254. // check if we should dismount this volume.
  1255. //
  1256. if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_PERFORMED_DISMOUNT )) {
  1257. DebugTrace( 0, Dbg, ("Volume is locked\n") );
  1258. if (FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) &&
  1259. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX )) {
  1260. NtfsReleaseVcb( IrpContext, Vcb );
  1261. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX );
  1262. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  1263. }
  1264. //
  1265. // Either deny access or show the volume was dismounted. Only show the dismount
  1266. // if the user is opening through a relative handle.
  1267. //
  1268. Status = STATUS_ACCESS_DENIED;
  1269. if (FlagOn( Vcb->VcbState, VCB_STATE_EXPLICIT_DISMOUNT ) &&
  1270. (OplockCleanup->FileObject->RelatedFileObject != NULL)) {
  1271. Status = STATUS_VOLUME_DISMOUNTED;
  1272. }
  1273. try_return( NOTHING );
  1274. }
  1275. //
  1276. // Initialize local copies of the stack values.
  1277. //
  1278. RelatedFileObject = OplockCleanup->FileObject->RelatedFileObject;
  1279. if (!FlagOn( IrpSp->Flags, SL_CASE_SENSITIVE )) {
  1280. SetFlag( CreateFlags, CREATE_FLAG_IGNORE_CASE );
  1281. }
  1282. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID)) {
  1283. SetFlag( CreateFlags, CREATE_FLAG_OPEN_BY_ID );
  1284. }
  1285. CreateDisposition = (UCHAR) ((IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
  1286. //
  1287. // We don't want any file modifications to go through if the volume is readonly.
  1288. // However, we don't want to fail any _opens_ for writes either, because that
  1289. // could potentially break many apps. So ignore the PreviouslyGrantedAccess,
  1290. // and just look at the CreateDisposition.
  1291. //
  1292. if (NtfsIsVolumeReadOnly( Vcb )) {
  1293. if ((CreateDisposition == FILE_CREATE) ||
  1294. (CreateDisposition == FILE_SUPERSEDE) ||
  1295. (CreateDisposition == FILE_OVERWRITE) ||
  1296. (CreateDisposition == FILE_OVERWRITE_IF)) {
  1297. Status = STATUS_MEDIA_WRITE_PROTECTED;
  1298. try_return( Status );
  1299. }
  1300. }
  1301. //
  1302. // Acquire the paging io resource if we are superseding/overwriting a
  1303. // file or if we are opening for non-cached access.
  1304. //
  1305. if ((CreateDisposition == FILE_SUPERSEDE) ||
  1306. (CreateDisposition == FILE_OVERWRITE) ||
  1307. (CreateDisposition == FILE_OVERWRITE_IF) ||
  1308. FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
  1309. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  1310. }
  1311. //
  1312. // We don't allow an open for an existing paging file. To insure that the
  1313. // delayed close Scb is not for this paging file we will unconditionally
  1314. // dereference it if this is a paging file open.
  1315. //
  1316. if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  1317. (!IsListEmpty( &NtfsData.AsyncCloseList ) ||
  1318. !IsListEmpty( &NtfsData.DelayedCloseList ))) {
  1319. NtfsFspClose( Vcb );
  1320. }
  1321. //
  1322. // Set up the file object's Vpb pointer in case anything happens.
  1323. // This will allow us to get a reasonable pop-up.
  1324. // Also set the flag to acquire the paging io resource if we might
  1325. // be creating a stream relative to a file. We need to make
  1326. // sure to acquire the paging IO when we get the file.
  1327. //
  1328. if (RelatedFileObject != NULL) {
  1329. OplockCleanup->FileObject->Vpb = RelatedFileObject->Vpb;
  1330. if ((OriginalFileName->Length != 0) &&
  1331. (OriginalFileName->Buffer[0] == L':') &&
  1332. ((CreateDisposition == FILE_OPEN_IF) ||
  1333. (CreateDisposition == FILE_CREATE))) {
  1334. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  1335. }
  1336. }
  1337. //
  1338. // Ping the volume to make sure the Vcb is still mounted. If we need
  1339. // to verify the volume then do it now, and if it comes out okay
  1340. // then clear the verify volume flag in the device object and continue
  1341. // on. If it doesn't verify okay then dismount the volume and
  1342. // either tell the I/O system to try and create again (with a new mount)
  1343. // or that the volume is wrong. This later code is returned if we
  1344. // are trying to do a relative open and the vcb is no longer mounted.
  1345. //
  1346. if (!NtfsPingVolume( IrpContext, Vcb, NULL ) ||
  1347. !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  1348. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX )) {
  1349. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX );
  1350. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  1351. }
  1352. if (!NtfsPerformVerifyOperation( IrpContext, Vcb )) {
  1353. NtfsReleaseVcb( IrpContext, Vcb );
  1354. NtfsAcquireCheckpointSynchronization( IrpContext, Vcb );
  1355. NtfsAcquireExclusiveVcb( IrpContext, Vcb, FALSE );
  1356. if (!NtfsPerformVerifyOperation( IrpContext, Vcb )) {
  1357. try {
  1358. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, NULL );
  1359. } finally {
  1360. NtfsReleaseCheckpointSynchronization( IrpContext, Vcb );
  1361. }
  1362. if (RelatedFileObject == NULL) {
  1363. Irp->IoStatus.Information = IO_REMOUNT;
  1364. NtfsRaiseStatus( IrpContext, STATUS_REPARSE, NULL, NULL );
  1365. } else {
  1366. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  1367. }
  1368. }
  1369. }
  1370. //
  1371. // The volume verified correctly so now clear the verify bit
  1372. // and continue with the create
  1373. //
  1374. ClearFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  1375. }
  1376. //
  1377. // Let's handle the open by Id case immediately.
  1378. //
  1379. if (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )) {
  1380. FILE_REFERENCE FileReference;
  1381. if (OriginalFileName->Length == sizeof( FILE_REFERENCE ) ||
  1382. (OriginalFileName->Length == sizeof( FILE_REFERENCE ) + sizeof(WCHAR))) {
  1383. //
  1384. // This is the regular open by file id case.
  1385. // Perform a safe copy of the data to our local variable.
  1386. // accept slash prefixed filerefs
  1387. //
  1388. if (OriginalFileName->Length == sizeof( FILE_REFERENCE )) {
  1389. RtlCopyMemory( &FileReference,
  1390. OplockCleanup->FileObject->FileName.Buffer,
  1391. sizeof( FILE_REFERENCE ));
  1392. } else {
  1393. RtlCopyMemory( &FileReference,
  1394. OplockCleanup->FileObject->FileName.Buffer + 1,
  1395. sizeof( FILE_REFERENCE ));
  1396. }
  1397. //
  1398. // If it's 16 bytes long, it should be an object id. It may
  1399. // also be one WCHAR longer for the Win32 double backslash.
  1400. // This code only works for 5.0 volumes with object id indices.
  1401. //
  1402. } else if (((OriginalFileName->Length == OBJECT_ID_KEY_LENGTH) ||
  1403. (OriginalFileName->Length == OBJECT_ID_KEY_LENGTH + sizeof(WCHAR))) &&
  1404. (Vcb->ObjectIdTableScb != NULL)) {
  1405. //
  1406. // In the open by object id case, we need to do some
  1407. // more work to find the file reference.
  1408. //
  1409. Status = NtfsLookupObjectId( IrpContext, Vcb, OriginalFileName, &FileReference );
  1410. if (!NT_SUCCESS( Status )) {
  1411. try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  1412. }
  1413. } else {
  1414. Status = STATUS_INVALID_PARAMETER;
  1415. try_return( Status );
  1416. }
  1417. //
  1418. // Clear the name in the file object.
  1419. //
  1420. OplockCleanup->FileObject->FileName.Buffer = NULL;
  1421. OplockCleanup->FileObject->FileName.MaximumLength = OplockCleanup->FileObject->FileName.Length = 0;
  1422. Status = NtfsOpenFcbById( IrpContext,
  1423. Irp,
  1424. IrpSp,
  1425. Vcb,
  1426. NULL,
  1427. &CurrentFcb,
  1428. FALSE,
  1429. FileReference,
  1430. NtfsEmptyString,
  1431. NtfsEmptyString,
  1432. NetworkInfo,
  1433. &ThisScb,
  1434. &ThisCcb );
  1435. if (Status != STATUS_PENDING) {
  1436. //
  1437. // Remember if we can let the user see the name for this file opened by id.
  1438. //
  1439. if (!FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags,
  1440. TOKEN_HAS_TRAVERSE_PRIVILEGE )) {
  1441. SetFlag( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK );
  1442. } else {
  1443. ClearFlag( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK );
  1444. }
  1445. //
  1446. // Put the name back into the file object so that the IO system doesn't
  1447. // think this is a dasd handle. Leave the max length at zero so
  1448. // we know this is not a real name.
  1449. //
  1450. OplockCleanup->FileObject->FileName.Buffer = OriginalFileName->Buffer;
  1451. OplockCleanup->FileObject->FileName.Length = OriginalFileName->Length;
  1452. }
  1453. try_return( Status );
  1454. }
  1455. //
  1456. // Test for double beginning backslashes from the Win32 layer. Apparently
  1457. // they can't test for this.
  1458. //
  1459. if ((OplockCleanup->FileObject->FileName.Length > sizeof( WCHAR )) &&
  1460. (OplockCleanup->FileObject->FileName.Buffer[1] == L'\\') &&
  1461. (OplockCleanup->FileObject->FileName.Buffer[0] == L'\\')) {
  1462. OplockCleanup->FileObject->FileName.Length -= sizeof( WCHAR );
  1463. RtlMoveMemory( &OplockCleanup->FileObject->FileName.Buffer[0],
  1464. &OplockCleanup->FileObject->FileName.Buffer[1],
  1465. OplockCleanup->FileObject->FileName.Length );
  1466. *FullFileName = *OriginalFileName = OplockCleanup->FileObject->FileName;
  1467. //
  1468. // If there are still two beginning backslashes, the name is bogus.
  1469. //
  1470. if ((OplockCleanup->FileObject->FileName.Length > sizeof( WCHAR )) &&
  1471. (OplockCleanup->FileObject->FileName.Buffer[1] == L'\\')) {
  1472. Status = STATUS_OBJECT_NAME_INVALID;
  1473. try_return( Status );
  1474. }
  1475. }
  1476. //
  1477. // If there is a related file object, we decode it to verify that this
  1478. // is a valid relative open.
  1479. //
  1480. if (RelatedFileObject != NULL) {
  1481. PVCB DecodeVcb;
  1482. //
  1483. // Check for a valid name. The name can't begin with a backslash
  1484. // and can't end with two backslashes.
  1485. //
  1486. if (OriginalFileName->Length != 0) {
  1487. //
  1488. // Check for a leading backslash.
  1489. //
  1490. if (OriginalFileName->Buffer[0] == L'\\') {
  1491. DebugTrace( 0, Dbg, ("Invalid name for relative open\n") );
  1492. try_return( Status = STATUS_INVALID_PARAMETER );
  1493. }
  1494. //
  1495. // Trim off any trailing backslash.
  1496. //
  1497. if (OriginalFileName->Buffer[ (OriginalFileName->Length / sizeof( WCHAR )) - 1 ] == L'\\') {
  1498. SetFlag( CreateFlags, CREATE_FLAG_TRAILING_BACKSLASH );
  1499. OplockCleanup->FileObject->FileName.Length -= sizeof( WCHAR );
  1500. *OriginalFileName = *FullFileName = OplockCleanup->FileObject->FileName;
  1501. }
  1502. //
  1503. // Now check if there is a trailing backslash. Note that if
  1504. // there was already a trailing backslash then there must
  1505. // be at least one more character or we would have failed
  1506. // with the original test.
  1507. //
  1508. if (OriginalFileName->Buffer[ (OriginalFileName->Length / sizeof( WCHAR )) - 1 ] == L'\\') {
  1509. Status = STATUS_OBJECT_NAME_INVALID;
  1510. try_return( Status );
  1511. }
  1512. }
  1513. RelatedFileObjectTypeOfOpen = NtfsDecodeFileObject( IrpContext,
  1514. RelatedFileObject,
  1515. &DecodeVcb,
  1516. &RelatedFcb,
  1517. &RelatedScb,
  1518. &RelatedCcb,
  1519. TRUE );
  1520. //
  1521. // Make sure the file object is one that we have seen
  1522. //
  1523. if (RelatedFileObjectTypeOfOpen == UnopenedFileObject) {
  1524. DebugTrace( 0, Dbg, ("Can't use unopend file for relative open\n") );
  1525. try_return( Status = STATUS_INVALID_PARAMETER );
  1526. }
  1527. //
  1528. // If the related file object was not opened as a file then we need to
  1529. // get the name and code if our caller passed a name length of zero.
  1530. // We need to fail this otherwise.
  1531. //
  1532. if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  1533. //
  1534. // If the name length is zero then we want the attribute name and
  1535. // type code from the related file object.
  1536. //
  1537. if (OriginalFileName->Length == 0) {
  1538. PATTRIBUTE_DEFINITION_COLUMNS ThisAttribute;
  1539. AttrName = RelatedScb->AttributeName;
  1540. ThisAttribute = NtfsGetAttributeDefinition( Vcb, RelatedScb->AttributeTypeCode );
  1541. RtlInitUnicodeString( &AttrCodeName, ThisAttribute->AttributeName );
  1542. //
  1543. // The relative file has to have been opened as a file. We
  1544. // cannot do relative opens relative to an opened attribute.
  1545. //
  1546. } else {
  1547. DebugTrace( 0, Dbg, ("Invalid File object for relative open\n") );
  1548. try_return( Status = STATUS_INVALID_PARAMETER );
  1549. }
  1550. }
  1551. //
  1552. // USN_V2 Remember the source info flags for this Ccb.
  1553. //
  1554. IrpContext->SourceInfo = RelatedCcb->UsnSourceInfo;
  1555. //
  1556. // If the related Ccb is was opened by file Id, we will
  1557. // remember that for future use.
  1558. //
  1559. if (FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_FILE_ID )) {
  1560. SetFlag( CreateFlags, CREATE_FLAG_OPEN_BY_ID);
  1561. }
  1562. //
  1563. // Remember if the related Ccb was opened through a Dos-Only
  1564. // component.
  1565. //
  1566. if (FlagOn( RelatedCcb->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT )) {
  1567. SetFlag( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT );
  1568. }
  1569. } else {
  1570. RelatedFileObjectTypeOfOpen = UnopenedFileObject;
  1571. if ((OriginalFileName->Length > 2) &&
  1572. (OriginalFileName->Buffer[ (OriginalFileName->Length / sizeof( WCHAR )) - 1 ] == L'\\')) {
  1573. SetFlag( CreateFlags, CREATE_FLAG_TRAILING_BACKSLASH );
  1574. OplockCleanup->FileObject->FileName.Length -= sizeof( WCHAR );
  1575. *OriginalFileName = *FullFileName = OplockCleanup->FileObject->FileName;
  1576. //
  1577. // If there is still a trailing backslash on the name then
  1578. // the name is invalid.
  1579. //
  1580. if ((OriginalFileName->Length > 2) &&
  1581. (OriginalFileName->Buffer[ (OriginalFileName->Length / sizeof( WCHAR )) - 1 ] == L'\\')) {
  1582. Status = STATUS_OBJECT_NAME_INVALID;
  1583. try_return( Status );
  1584. }
  1585. }
  1586. }
  1587. DebugTrace( 0, Dbg, ("Related File Object, TypeOfOpen -> %08lx\n", RelatedFileObjectTypeOfOpen) );
  1588. //
  1589. // We check if this is a user volume open in that there is no name
  1590. // specified and the related file object is valid if present. In that
  1591. // case set the correct flags in the IrpContext and raise so we can take
  1592. // the volume open path.
  1593. //
  1594. if ((OriginalFileName->Length == 0) &&
  1595. ((RelatedFileObjectTypeOfOpen == UnopenedFileObject) ||
  1596. (RelatedFileObjectTypeOfOpen == UserVolumeOpen))) {
  1597. DebugTrace( 0, Dbg, ("Attempting to open entire volume\n") );
  1598. SetFlag( IrpContext->State,
  1599. IRP_CONTEXT_STATE_ACQUIRE_EX | IRP_CONTEXT_STATE_DASD_OPEN );
  1600. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  1601. }
  1602. //
  1603. // If the related file object was a volume open, then this open is
  1604. // illegal.
  1605. //
  1606. if (RelatedFileObjectTypeOfOpen == UserVolumeOpen) {
  1607. try_return( Status = STATUS_INVALID_PARAMETER );
  1608. }
  1609. //
  1610. // Remember if we need to perform any traverse access checks.
  1611. //
  1612. if (!FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags,
  1613. TOKEN_HAS_TRAVERSE_PRIVILEGE )) {
  1614. DebugTrace( 0, Dbg, ("Performing traverse access on this open\n") );
  1615. SetFlag( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK );
  1616. } else {
  1617. ClearFlag( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK );
  1618. #ifdef BRIANDBG
  1619. if (NtfsTraverseAccessCheck) {
  1620. SetFlag( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK );
  1621. }
  1622. #endif
  1623. }
  1624. //
  1625. // We enter the loop that does the processing for the prefix lookup.
  1626. // We optimize the case where we can match a prefix hit. If there is
  1627. // no hit we will check if the name is legal or might possibly require
  1628. // parsing to handle the case where there is a named data stream.
  1629. //
  1630. SetFlag( CreateFlags, CREATE_FLAG_CHECK_FOR_VALID_NAME | CREATE_FLAG_FIRST_PASS );
  1631. while (TRUE) {
  1632. PUNICODE_STRING FileObjectName;
  1633. LONG Index;
  1634. BOOLEAN ComplexName;
  1635. //
  1636. // Lets make sure we have acquired the starting point for our
  1637. // name search. If we have a relative file object then use
  1638. // that. Otherwise we will start from the root.
  1639. //
  1640. if (RelatedFileObject != NULL) {
  1641. CurrentFcb = RelatedFcb;
  1642. } else {
  1643. CurrentFcb = Vcb->RootIndexScb->Fcb;
  1644. }
  1645. //
  1646. // Init NextLcb
  1647. //
  1648. FileObjectName = &OplockCleanup->FileObject->FileName;
  1649. NextLcb = NULL;
  1650. //
  1651. // We would like to get the starting point shared, unless
  1652. // we know for certain we need it exclusively.
  1653. //
  1654. if (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK | CREATE_FLAG_OPEN_BY_ID ) ||
  1655. !FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE) ||
  1656. (FileObjectName->Length == 0) ||
  1657. (FileObjectName->Buffer[0] == L':') ||
  1658. ((RelatedFileObject == NULL) &&
  1659. ((FileObjectName->Length <= sizeof( WCHAR )) ||
  1660. (FileObjectName->Buffer[1] == L':'))) ||
  1661. ((RelatedFileObject != NULL) &&
  1662. (RelatedFileObjectTypeOfOpen != UserDirectoryOpen))) {
  1663. NtfsAcquireFcbWithPaging( IrpContext, CurrentFcb, 0);
  1664. ClearFlag( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB );
  1665. } else {
  1666. NtfsAcquireSharedFcb( IrpContext, CurrentFcb, NULL, FALSE );
  1667. SetFlag( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB );
  1668. }
  1669. if (!FlagOn( CreateFlags, CREATE_FLAG_FIRST_PASS )) {
  1670. if (!NtfsParseNameForCreate( IrpContext,
  1671. RemainingName,
  1672. FileObjectName,
  1673. OriginalFileName,
  1674. FullFileName,
  1675. &AttrName,
  1676. &AttrCodeName )) {
  1677. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  1678. }
  1679. //
  1680. // Upcase the AttributeCodeName if the user is IgnoreCase.
  1681. //
  1682. if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE ) && (AttrCodeName.Length != 0)) {
  1683. NtfsUpcaseName( Vcb->UpcaseTable, Vcb->UpcaseTableSize, &AttrCodeName );
  1684. }
  1685. //
  1686. // If we might be creating a named stream acquire the
  1687. // paging IO as well. This will keep anyone from peeking
  1688. // at the allocation size of any other streams we are converting
  1689. // to non-resident.
  1690. //
  1691. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) &&
  1692. (AttrName.Length != 0) &&
  1693. ((CreateDisposition == FILE_OPEN_IF) ||
  1694. (CreateDisposition == FILE_CREATE))) {
  1695. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  1696. }
  1697. ClearFlag( CreateFlags, CREATE_FLAG_CHECK_FOR_VALID_NAME );
  1698. //
  1699. // Build up the full name if this is not the open by file Id case.
  1700. //
  1701. } else if (!FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )) {
  1702. //
  1703. // If we have a related file object, then we build up the
  1704. // combined name.
  1705. //
  1706. if (RelatedFileObject != NULL) {
  1707. WCHAR *CurrentPosition;
  1708. USHORT AddSeparator;
  1709. ULONG FullNameLengthTemp;
  1710. if ((FileObjectName->Length == 0) ||
  1711. (RelatedCcb->FullFileName.Length == 2) ||
  1712. (FileObjectName->Buffer[0] == L':')) {
  1713. AddSeparator = 0;
  1714. } else {
  1715. AddSeparator = sizeof( WCHAR );
  1716. }
  1717. ExactCaseOffset = RelatedCcb->FullFileName.Length + AddSeparator;
  1718. FullNameLengthTemp = (ULONG) RelatedCcb->FullFileName.Length + AddSeparator + FileObjectName->Length;
  1719. //
  1720. // A crude test to see if the total length exceeds a ushort.
  1721. //
  1722. if ((FullNameLengthTemp & 0xffff0000L) != 0) {
  1723. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  1724. }
  1725. FullFileName->MaximumLength =
  1726. FullFileName->Length = (USHORT) FullNameLengthTemp;
  1727. //
  1728. // We need to allocate a name buffer.
  1729. //
  1730. FullFileName->Buffer = FsRtlAllocatePoolWithTag(PagedPool, FullFileName->Length, MODULE_POOL_TAG);
  1731. CurrentPosition = (WCHAR *) FullFileName->Buffer;
  1732. RtlCopyMemory( CurrentPosition,
  1733. RelatedCcb->FullFileName.Buffer,
  1734. RelatedCcb->FullFileName.Length );
  1735. CurrentPosition = (WCHAR *) Add2Ptr( CurrentPosition, RelatedCcb->FullFileName.Length );
  1736. if (AddSeparator != 0) {
  1737. *CurrentPosition = L'\\';
  1738. CurrentPosition += 1;
  1739. }
  1740. if (FileObjectName->Length != 0) {
  1741. RtlCopyMemory( CurrentPosition,
  1742. FileObjectName->Buffer,
  1743. FileObjectName->Length );
  1744. }
  1745. //
  1746. // If the user specified a case sensitive comparison, then the
  1747. // case insensitive index is the full length of the resulting
  1748. // string. Otherwise it is the length of the string in
  1749. // the related file object. We adjust for the case when the
  1750. // original file name length is zero.
  1751. //
  1752. if (!FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  1753. CaseInsensitiveIndex = FullFileName->Length;
  1754. } else {
  1755. CaseInsensitiveIndex = RelatedCcb->FullFileName.Length +
  1756. AddSeparator;
  1757. }
  1758. //
  1759. // The entire name is in the FileObjectName. We check the buffer for
  1760. // validity.
  1761. //
  1762. } else {
  1763. //
  1764. // We look at the name string for detectable errors. The
  1765. // length must be non-zero and the first character must be
  1766. // '\'
  1767. //
  1768. if (FileObjectName->Length == 0) {
  1769. DebugTrace( 0, Dbg, ("There is no name to open\n") );
  1770. try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  1771. }
  1772. if (FileObjectName->Buffer[0] != L'\\') {
  1773. DebugTrace( 0, Dbg, ("Name does not begin with a backslash\n") );
  1774. try_return( Status = STATUS_INVALID_PARAMETER );
  1775. }
  1776. //
  1777. // If the user specified a case sensitive comparison, then the
  1778. // case insensitive index is the full length of the resulting
  1779. // string. Otherwise it is zero.
  1780. //
  1781. if (!FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  1782. CaseInsensitiveIndex = FullFileName->Length;
  1783. } else {
  1784. CaseInsensitiveIndex = 0;
  1785. }
  1786. }
  1787. } else if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  1788. CaseInsensitiveIndex = 0;
  1789. } else {
  1790. CaseInsensitiveIndex = FullFileName->Length;
  1791. }
  1792. //
  1793. // The remaining name is stored in the FullFileName variable.
  1794. // If we are doing a case-insensitive operation and have to
  1795. // upcase part of the remaining name then allocate a buffer
  1796. // now. No need to allocate a buffer if we already allocated
  1797. // a new buffer for the full file name.
  1798. //
  1799. if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE ) &&
  1800. (CaseInsensitiveIndex < FullFileName->Length)) {
  1801. UNICODE_STRING StringToUpcase;
  1802. //
  1803. // Original file name and full file name better have the same buffer or there
  1804. // should be a related file object. If there is already an allocated
  1805. // buffer for the ExactCaseName then it should already be big enough for us.
  1806. //
  1807. ASSERT( (RelatedFileObject != NULL) ||
  1808. (FullFileName->Buffer == OriginalFileName->Buffer) );
  1809. //
  1810. // If there is a related name then we can use the original buffer
  1811. // unless the full name is using the same buffer.
  1812. //
  1813. if (OriginalFileName->Buffer != FullFileName->Buffer) {
  1814. //
  1815. // We might have already used the original buffer for the case
  1816. // where we are retrying the request.
  1817. //
  1818. ASSERT( (ExactCaseName->Buffer == NULL) ||
  1819. (ExactCaseName->Buffer == OriginalFileName->Buffer) );
  1820. ExactCaseName->Buffer = OriginalFileName->Buffer;
  1821. //
  1822. // MaximumLength includes any stream descriptors.
  1823. // Length is limited to the Length in the FullName.
  1824. //
  1825. ExactCaseName->MaximumLength = OriginalFileName->Length;
  1826. ExactCaseName->Length = FullFileName->Length - ExactCaseOffset;
  1827. ASSERT( FullFileName->Length >= ExactCaseOffset );
  1828. //
  1829. // We need to store the exact case name away.
  1830. //
  1831. } else {
  1832. //
  1833. // Allocate a buffer if we don't already have one.
  1834. //
  1835. ExactCaseName->MaximumLength = OriginalFileName->Length;
  1836. if (ExactCaseName->Buffer == NULL) {
  1837. ExactCaseName->Buffer = FsRtlAllocatePoolWithTag( PagedPool,
  1838. OriginalFileName->MaximumLength,
  1839. MODULE_POOL_TAG );
  1840. }
  1841. RtlCopyMemory( ExactCaseName->Buffer,
  1842. FullFileName->Buffer,
  1843. FullFileName->MaximumLength );
  1844. ExactCaseName->Length = FullFileName->Length - ExactCaseOffset;
  1845. ASSERT( FullFileName->Length >= ExactCaseOffset );
  1846. }
  1847. //
  1848. // Upcase the file name portion of the full name.
  1849. //
  1850. StringToUpcase.Buffer = Add2Ptr( FullFileName->Buffer,
  1851. CaseInsensitiveIndex );
  1852. StringToUpcase.Length =
  1853. StringToUpcase.MaximumLength = FullFileName->Length - (USHORT) CaseInsensitiveIndex;
  1854. NtfsUpcaseName( Vcb->UpcaseTable, Vcb->UpcaseTableSize, &StringToUpcase );
  1855. }
  1856. RemainingName = *FullFileName;
  1857. //
  1858. // Make it plain we don't have any hash values.
  1859. //
  1860. CreateContext.FileHashLength = CreateContext.ParentHashLength = 0;
  1861. //
  1862. // If this is the traverse access case or the open by file id case we start
  1863. // relative to the file object we have or the root directory.
  1864. // This is also true for the case where the file name in the file object is
  1865. // empty.
  1866. //
  1867. if ((FileObjectName->Length == 0) ||
  1868. (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK ) &&
  1869. (FileObjectName->Buffer[0] != L':'))) {
  1870. //
  1871. // We should already have the parent exclusive if we hit this path.
  1872. //
  1873. ASSERT( !FlagOn( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB ) );
  1874. if (RelatedFileObject != NULL) {
  1875. CurrentLcb = RelatedCcb->Lcb;
  1876. CurrentScb = RelatedScb;
  1877. if (FileObjectName->Length == 0) {
  1878. RemainingName.Length = 0;
  1879. } else if (!FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )) {
  1880. USHORT Increment;
  1881. Increment = RelatedCcb->FullFileName.Length
  1882. + (RelatedCcb->FullFileName.Length == 2
  1883. ? 0
  1884. : 2);
  1885. RemainingName.Buffer = (WCHAR *) Add2Ptr( RemainingName.Buffer,
  1886. Increment );
  1887. RemainingName.Length -= Increment;
  1888. }
  1889. } else {
  1890. CurrentLcb = Vcb->RootLcb;
  1891. CurrentScb = Vcb->RootIndexScb;
  1892. RemainingName.Buffer = (WCHAR *) Add2Ptr( RemainingName.Buffer, sizeof( WCHAR ));
  1893. RemainingName.Length -= sizeof( WCHAR );
  1894. }
  1895. //
  1896. // Otherwise we will try a prefix lookup.
  1897. //
  1898. } else {
  1899. if (RelatedFileObject != NULL) {
  1900. if (!FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )) {
  1901. //
  1902. // Skip over the characters in the related file object.
  1903. //
  1904. RemainingName.Buffer = (WCHAR *) Add2Ptr( RemainingName.Buffer,
  1905. RelatedCcb->FullFileName.Length );
  1906. RemainingName.Length -= RelatedCcb->FullFileName.Length;
  1907. //
  1908. // Step over the backslash if present.
  1909. //
  1910. if ((RemainingName.Length != 0) &&
  1911. (RemainingName.Buffer[0] == L'\\')) {
  1912. RemainingName.Buffer += 1;
  1913. RemainingName.Length -= sizeof( WCHAR );
  1914. }
  1915. }
  1916. CurrentLcb = RelatedCcb->Lcb;
  1917. CurrentScb = RelatedScb;
  1918. } else {
  1919. CurrentLcb = Vcb->RootLcb;
  1920. CurrentScb = Vcb->RootIndexScb;
  1921. //
  1922. // Skip over the lead-in '\' character.
  1923. //
  1924. RemainingName.Buffer = (WCHAR *) Add2Ptr( RemainingName.Buffer,
  1925. sizeof( WCHAR ));
  1926. RemainingName.Length -= sizeof( WCHAR );
  1927. }
  1928. LcbForTeardown = NULL;
  1929. //
  1930. // If we don't have the starting Scb exclusively then let's try for
  1931. // a hash hit first.
  1932. //
  1933. if (FlagOn( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB )) {
  1934. NextLcb = NtfsFindPrefixHashEntry( IrpContext,
  1935. &Vcb->HashTable,
  1936. CurrentScb,
  1937. &CreateFlags,
  1938. &CurrentFcb,
  1939. &CreateContext.FileHashValue,
  1940. &CreateContext.FileHashLength,
  1941. &CreateContext.ParentHashValue,
  1942. &CreateContext.ParentHashLength,
  1943. &RemainingName );
  1944. //
  1945. // If we didn't get an Lcb then release the starting Scb
  1946. // and reacquire exclusively.
  1947. //
  1948. if (NextLcb == NULL) {
  1949. NtfsReleaseFcbWithPaging( IrpContext, CurrentFcb );
  1950. NtfsAcquireFcbWithPaging( IrpContext, CurrentFcb, 0 );
  1951. } else {
  1952. //
  1953. // Remember the Lcb we found. If there is still a
  1954. // portion of the name remaining then check if there
  1955. // is an existing $INDEX_ALLOCATION scb on the file.
  1956. // It is possible that we aren't even at a directory
  1957. // in the reparse case.
  1958. //
  1959. CurrentLcb = NextLcb;
  1960. //
  1961. // We have progressed parsing the name. Mark it as one that needs to be inspected
  1962. // for possible reparse behavior.
  1963. //
  1964. SetFlag( CreateFlags, CREATE_FLAG_INSPECT_NAME_FOR_REPARSE );
  1965. if (RemainingName.Length != 0) {
  1966. CurrentScb = NtfsCreateScb( IrpContext,
  1967. CurrentFcb,
  1968. $INDEX_ALLOCATION,
  1969. &NtfsFileNameIndex,
  1970. TRUE,
  1971. NULL );
  1972. }
  1973. }
  1974. //
  1975. // In both cases here we own the Fcb exclusive.
  1976. //
  1977. ClearFlag( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB );
  1978. #ifdef NTFS_HASH_DATA
  1979. } else {
  1980. Vcb->HashTable.SkipHashLookupCount += 1;
  1981. #endif
  1982. }
  1983. if ((RemainingName.Length != 0) &&
  1984. (CurrentScb != NULL)) {
  1985. NextLcb = NtfsFindPrefix( IrpContext,
  1986. CurrentScb,
  1987. &CurrentFcb,
  1988. &LcbForTeardown,
  1989. RemainingName,
  1990. &CreateFlags,
  1991. &RemainingName );
  1992. }
  1993. //
  1994. // If we found another link then update the CurrentLcb value.
  1995. //
  1996. if (NextLcb != NULL) {
  1997. CurrentLcb = NextLcb;
  1998. //
  1999. // We have progressed parsing the name. Mark it as one that needs to be inspected
  2000. // for possible reparse behavior.
  2001. //
  2002. SetFlag( CreateFlags, CREATE_FLAG_INSPECT_NAME_FOR_REPARSE );
  2003. }
  2004. }
  2005. if ((RemainingName.Length == 0) || !FlagOn( CreateFlags, CREATE_FLAG_FIRST_PASS )) {
  2006. break;
  2007. }
  2008. //
  2009. // If we get here, it means that this is the first pass and we didn't
  2010. // have a prefix match. If there is a colon in the
  2011. // remaining name, then we need to analyze the name in more detail.
  2012. //
  2013. ComplexName = FALSE;
  2014. for (Index = (RemainingName.Length / sizeof( WCHAR )) - 1, ComplexName = FALSE;
  2015. Index >= 0;
  2016. Index -= 1) {
  2017. if (RemainingName.Buffer[Index] == L':') {
  2018. ComplexName = TRUE;
  2019. break;
  2020. }
  2021. }
  2022. if (!ComplexName) {
  2023. break;
  2024. }
  2025. ClearFlag( CreateFlags, CREATE_FLAG_FIRST_PASS);
  2026. //
  2027. // Copy the exact name back to the full name. In this case we want to
  2028. // restore the entire name including stream descriptors.
  2029. //
  2030. if (ExactCaseName->Buffer != NULL) {
  2031. ASSERT( ExactCaseName->Length != 0 );
  2032. ASSERT( FullFileName->MaximumLength >= ExactCaseName->Length );
  2033. RtlCopyMemory( Add2Ptr( FullFileName->Buffer, ExactCaseOffset ),
  2034. ExactCaseName->Buffer,
  2035. ExactCaseName->MaximumLength );
  2036. //
  2037. // Save the buffer for now but set the lengths to zero as a
  2038. // flag to indicate that we have already copied the data back.
  2039. //
  2040. ExactCaseName->Length = ExactCaseName->MaximumLength = 0;
  2041. }
  2042. //
  2043. // Let's release the Fcb we have currently acquired.
  2044. //
  2045. NtfsReleaseFcbWithPaging( IrpContext, CurrentFcb );
  2046. LcbForTeardown = NULL;
  2047. }
  2048. //
  2049. // Check if the link or the Fcb is pending delete.
  2050. //
  2051. if (((CurrentLcb != NULL) && LcbLinkIsDeleted( CurrentLcb )) ||
  2052. CurrentFcb->LinkCount == 0) {
  2053. try_return( Status = STATUS_DELETE_PENDING );
  2054. }
  2055. //
  2056. // Put the new name into the file object.
  2057. //
  2058. OplockCleanup->FileObject->FileName = *FullFileName;
  2059. //
  2060. // If the entire path was parsed, then we have access to the Fcb to
  2061. // open. We either open the parent of the prefix match or the prefix
  2062. // match itself, depending on whether the user wanted to open
  2063. // the target directory.
  2064. //
  2065. if (RemainingName.Length == 0) {
  2066. //
  2067. // Check the attribute name length.
  2068. //
  2069. if (AttrName.Length > (NTFS_MAX_ATTR_NAME_LEN * sizeof( WCHAR ))) {
  2070. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2071. }
  2072. //
  2073. // If this is a target directory we check that the open is for the
  2074. // entire file.
  2075. // We assume that the final component can only have an attribute
  2076. // which corresponds to the type of file this is. Meaning
  2077. // $INDEX_ALLOCATION for directory, $DATA (unnamed) for a file.
  2078. // We verify that the matching Lcb is not the root Lcb.
  2079. //
  2080. if (FlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY )) {
  2081. if (CurrentLcb == Vcb->RootLcb) {
  2082. DebugTrace( 0, Dbg, ("Can't open parent of root\n") );
  2083. try_return( Status = STATUS_INVALID_PARAMETER );
  2084. }
  2085. //
  2086. // We don't allow attribute names or attribute codes to
  2087. // be specified.
  2088. //
  2089. if (AttrName.Length != 0
  2090. || AttrCodeName.Length != 0) {
  2091. DebugTrace( 0, Dbg, ("Can't specify complex name for rename\n") );
  2092. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2093. }
  2094. //
  2095. // When SL_OPEN_TARGET_DIRECTORY is set, the directory should not be opened
  2096. // as a reparse point; FILE_OPEN_REPARSE_POINT should not be set.
  2097. //
  2098. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )) {
  2099. //
  2100. // Wrong open flag, invalid parameter.
  2101. //
  2102. DebugTrace( 0, Dbg, ("Can't open intermediate directory as reparse point 1.\n") );
  2103. Status = STATUS_INVALID_PARAMETER;
  2104. try_return( Status );
  2105. }
  2106. //
  2107. // We want to copy the exact case of the name back into the
  2108. // input buffer for this case.
  2109. //
  2110. if (ExactCaseName->Buffer != NULL) {
  2111. ASSERT( ExactCaseName->Length != 0 );
  2112. ASSERT( FullFileName->MaximumLength >= ExactCaseName->Length + ExactCaseOffset );
  2113. RtlCopyMemory( Add2Ptr( FullFileName->Buffer, ExactCaseOffset ),
  2114. ExactCaseName->Buffer,
  2115. ExactCaseName->MaximumLength );
  2116. }
  2117. //
  2118. // Acquire the parent of the last Fcb. This is the actual file we
  2119. // are opening.
  2120. //
  2121. ParentFcb = CurrentLcb->Scb->Fcb;
  2122. NtfsAcquireFcbWithPaging( IrpContext, ParentFcb, 0 );
  2123. //
  2124. // Call our open target directory, remembering the target
  2125. // file existed.
  2126. //
  2127. SetFlag( CreateFlags, CREATE_FLAG_FOUND_ENTRY );
  2128. Status = NtfsOpenTargetDirectory( IrpContext,
  2129. Irp,
  2130. IrpSp,
  2131. ParentFcb,
  2132. NULL,
  2133. &OplockCleanup->FileObject->FileName,
  2134. CurrentLcb->ExactCaseLink.LinkName.Length,
  2135. CreateFlags,
  2136. &ThisScb,
  2137. &ThisCcb );
  2138. try_return( NOTHING );
  2139. }
  2140. //
  2141. // Otherwise we simply attempt to open the Fcb we matched.
  2142. //
  2143. if (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )) {
  2144. Status = NtfsOpenFcbById( IrpContext,
  2145. Irp,
  2146. IrpSp,
  2147. Vcb,
  2148. CurrentLcb,
  2149. &CurrentFcb,
  2150. TRUE,
  2151. CurrentFcb->FileReference,
  2152. AttrName,
  2153. AttrCodeName,
  2154. NetworkInfo,
  2155. &ThisScb,
  2156. &ThisCcb );
  2157. //
  2158. // If the status is pending, the irp or the file object may have gone
  2159. // away already.
  2160. //
  2161. if (Status != STATUS_PENDING) {
  2162. //
  2163. // There should be no need to set TraverseAccessCheck now, it should
  2164. // already be set correctly.
  2165. //
  2166. ASSERT( (!FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK ) &&
  2167. FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE )) ||
  2168. (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK ) &&
  2169. !FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE )) );
  2170. //
  2171. // Set the maximum length in the file object name to
  2172. // zero so we know that this is not a full name.
  2173. //
  2174. OplockCleanup->FileObject->FileName.MaximumLength = 0;
  2175. }
  2176. } else {
  2177. //
  2178. // The current Fcb is acquired.
  2179. //
  2180. Status = NtfsOpenExistingPrefixFcb( IrpContext,
  2181. Irp,
  2182. IrpSp,
  2183. CurrentFcb,
  2184. CurrentLcb,
  2185. FullFileName->Length,
  2186. AttrName,
  2187. AttrCodeName,
  2188. CreateFlags,
  2189. NetworkInfo,
  2190. &CreateContext,
  2191. &ThisScb,
  2192. &ThisCcb );
  2193. }
  2194. try_return( NOTHING );
  2195. }
  2196. //
  2197. // Check if the current Lcb is a Dos-Only Name.
  2198. //
  2199. if ((CurrentLcb != NULL) &&
  2200. (CurrentLcb->FileNameAttr->Flags == FILE_NAME_DOS)) {
  2201. SetFlag( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT );
  2202. }
  2203. //
  2204. // We have a remaining portion of the file name which was unmatched in the
  2205. // prefix table. We walk through these name components until we reach the
  2206. // last element. If necessary, we add Fcb and Scb's into the graph as we
  2207. // walk through the names.
  2208. //
  2209. SetFlag( CreateFlags, CREATE_FLAG_FIRST_PASS);
  2210. while (TRUE) {
  2211. PFILE_NAME IndexFileName;
  2212. //
  2213. // We check to see whether we need to inspect this name for possible reparse behavior
  2214. // and whether the CurrentFcb is a reparse point.
  2215. // Notice that if a directory is a reparse point, there should be no
  2216. // prefix match possible in NtfsFindPrefix beyond the directory name,
  2217. // as longer matches could bypass a reparse point.
  2218. //
  2219. if (FlagOn( CreateFlags, CREATE_FLAG_INSPECT_NAME_FOR_REPARSE ) &&
  2220. FlagOn( CurrentFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  2221. USHORT AttributeNameLength = 0;
  2222. //
  2223. // Traverse access is done before accessing the disk.
  2224. // For a directory we check for traverse access.
  2225. // For a file we check for read access.
  2226. //
  2227. if (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK )) {
  2228. if (IsDirectory( &CurrentFcb->Info )) {
  2229. NtfsTraverseCheck( IrpContext,
  2230. CurrentFcb,
  2231. Irp );
  2232. } else {
  2233. NtfsAccessCheck ( IrpContext,
  2234. CurrentFcb,
  2235. NULL,
  2236. Irp,
  2237. FILE_GENERIC_READ,
  2238. TRUE );
  2239. }
  2240. }
  2241. //
  2242. // Middle-of-name reparse point call.
  2243. // Notice that the FILE_OPEN_REPARSE_POINT flag only alters the behavior of
  2244. // a final element of a named path, not the intermediate components.
  2245. // Notice further that we need this check here prior to the directory check
  2246. // below as it is legal to have an intermediate name that is a file
  2247. // containing a symbolic link.
  2248. //
  2249. //
  2250. // When NetworkInfo is present, we are in the fast-I/O path to retrieve
  2251. // the attributes of a target file. The fast path does not process retries
  2252. // due to reparse points. We return indicating that a reparse point has
  2253. // been encountered without returning the reparse point data.
  2254. //
  2255. if (ARGUMENT_PRESENT( NetworkInfo )) {
  2256. DebugTrace( 0, Dbg, ("Reparse point encountered with NetworkInfo present.\n") );
  2257. Status = STATUS_REPARSE;
  2258. try_return( Status );
  2259. }
  2260. //
  2261. // We account for the byte size of the attribute name delimiter : (colon)
  2262. // in unicode.
  2263. // If the name of the code or type of the attribute has been passed on explicitly,
  2264. // like $DATA or $INDEX_ALLOCATION, we also account for it.
  2265. //
  2266. // Notice that the code below ignores the case when no attribute name has been specified
  2267. // yet the name of its code, or type, has been specified.
  2268. //
  2269. ASSERT( OplockCleanup->AttributeNameLength == AttrName.Length );
  2270. if (OplockCleanup->AttributeNameLength > 0) {
  2271. AttributeNameLength += OplockCleanup->AttributeNameLength + 2;
  2272. }
  2273. if (OplockCleanup->AttributeCodeNameLength > 0) {
  2274. AttributeNameLength += OplockCleanup->AttributeCodeNameLength + 2;
  2275. }
  2276. if (RemainingName.Length > 0) {
  2277. //
  2278. // Account for the backslash delimeter.
  2279. //
  2280. AttributeNameLength += 2;
  2281. }
  2282. DebugTrace( 0, Dbg, ("RemainingName.Length = %d OplockCleanup->AttributeNameLength = %d OplockCleanup->AttributeCodeNameLength = %d AttributeNameLength = %d sum = %d\n",
  2283. RemainingName.Length, OplockCleanup->AttributeNameLength, OplockCleanup->AttributeCodeNameLength, AttributeNameLength, (RemainingName.Length + AttributeNameLength)) );
  2284. Status = NtfsGetReparsePointValue( IrpContext,
  2285. Irp,
  2286. IrpSp,
  2287. CurrentFcb,
  2288. (USHORT)(RemainingName.Length + AttributeNameLength) );
  2289. try_return( Status );
  2290. }
  2291. //
  2292. // We check that the last Fcb we have is in fact a directory.
  2293. //
  2294. if (!IsDirectory( &CurrentFcb->Info )) {
  2295. DebugTrace( 0, Dbg, ("Intermediate node is not a directory\n") );
  2296. try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  2297. }
  2298. //
  2299. // We dissect the name into the next component and the remaining name string.
  2300. // We don't need to check for a valid name if we examined the name already.
  2301. //
  2302. NtfsDissectName( RemainingName,
  2303. &FinalName,
  2304. &RemainingName );
  2305. DebugTrace( 0, Dbg, ("Final name -> %Z\n", &FinalName) );
  2306. DebugTrace( 0, Dbg, ("Remaining Name -> %Z\n", &RemainingName) );
  2307. //
  2308. // If the final name is too long then either the path or the
  2309. // name is invalid.
  2310. //
  2311. if (FinalName.Length > (NTFS_MAX_FILE_NAME_LENGTH * sizeof( WCHAR ))) {
  2312. if (RemainingName.Length == 0) {
  2313. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2314. } else {
  2315. try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  2316. }
  2317. }
  2318. //
  2319. // Catch single dot names (.) before scanning the index. We don't
  2320. // want to allow someone to open the self entry in the root.
  2321. //
  2322. if ((FinalName.Length == 2) &&
  2323. (FinalName.Buffer[0] == L'.')) {
  2324. if (RemainingName.Length != 0) {
  2325. DebugTrace( 0, Dbg, ("Intermediate component in path doesn't exist\n") );
  2326. try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  2327. //
  2328. // If the final component is illegal, then return the appropriate error.
  2329. //
  2330. } else {
  2331. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2332. }
  2333. }
  2334. //
  2335. // Get the index allocation Scb for the current Fcb.
  2336. //
  2337. //
  2338. // We need to look for the next component in the name string in the directory
  2339. // we've reached. We need to get a Scb to perform the index search.
  2340. // To do the search we need to build a filename attribute to perform the
  2341. // search with and then call the index package to perform the search.
  2342. //
  2343. CurrentScb = NtfsCreateScb( IrpContext,
  2344. CurrentFcb,
  2345. $INDEX_ALLOCATION,
  2346. &NtfsFileNameIndex,
  2347. FALSE,
  2348. NULL );
  2349. //
  2350. // If the CurrentScb does not have its normalized name and we have a valid
  2351. // parent, then update the normalized name.
  2352. //
  2353. if ((LastScb != NULL) &&
  2354. (CurrentScb->ScbType.Index.NormalizedName.Length == 0) &&
  2355. (LastScb->ScbType.Index.NormalizedName.Length != 0)) {
  2356. NtfsUpdateNormalizedName( IrpContext, LastScb, CurrentScb, IndexFileName, FALSE );
  2357. }
  2358. //
  2359. // Release the parent Scb if we own it.
  2360. //
  2361. if (!FlagOn( CreateFlags, CREATE_FLAG_FIRST_PASS )) {
  2362. NtfsReleaseFcbWithPaging( IrpContext, ParentFcb );
  2363. }
  2364. LastScb = CurrentScb;
  2365. //
  2366. // If traverse access is required, we do so now before accessing the
  2367. // disk.
  2368. //
  2369. if (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK )) {
  2370. NtfsTraverseCheck( IrpContext,
  2371. CurrentFcb,
  2372. Irp );
  2373. }
  2374. //
  2375. // Look on the disk to see if we can find the last component on the path.
  2376. //
  2377. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  2378. //
  2379. // Check that the name is valid before scanning the disk.
  2380. //
  2381. if (FlagOn( CreateFlags, CREATE_FLAG_CHECK_FOR_VALID_NAME ) &&
  2382. !NtfsIsFileNameValid( &FinalName, FALSE )) {
  2383. DebugTrace( 0, Dbg, ("Component name is invalid\n") );
  2384. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2385. }
  2386. //
  2387. // Initialize or reinitialize the context as necessary.
  2388. //
  2389. if (IndexContext != NULL) {
  2390. NtfsReinitializeIndexContext( IrpContext, IndexContext );
  2391. } else {
  2392. #if defined(_WIN64)
  2393. IndexContext = &IndexContextStruct;
  2394. #else
  2395. IndexContext = NtfsAllocateFromStack( sizeof( INDEX_CONTEXT ));
  2396. #endif
  2397. NtfsInitializeIndexContext( IndexContext );
  2398. }
  2399. if (NtfsLookupEntry( IrpContext,
  2400. CurrentScb,
  2401. BooleanFlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE ),
  2402. &FinalName,
  2403. &FileNameAttr,
  2404. &FileNameAttrLength,
  2405. &QuickIndex,
  2406. &IndexEntry,
  2407. &IndexEntryBcb,
  2408. IndexContext )) {
  2409. SetFlag( CreateFlags, CREATE_FLAG_FOUND_ENTRY );
  2410. } else {
  2411. ClearFlag( CreateFlags, CREATE_FLAG_FOUND_ENTRY );
  2412. }
  2413. //
  2414. // This call to NtfsLookupEntry may decide to push the root index.
  2415. // Create needs to free resources as it walks down the tree to prevent
  2416. // deadlocks. If there is a transaction, commit it now so we will be
  2417. // able to free this resource.
  2418. //
  2419. if (IrpContext->TransactionId != 0) {
  2420. NtfsCheckpointCurrentTransaction( IrpContext );
  2421. //
  2422. // Go through and free any Scb's in the queue of shared
  2423. // Scb's for transactions.
  2424. //
  2425. if (IrpContext->SharedScb != NULL) {
  2426. NtfsReleaseSharedResources( IrpContext );
  2427. ASSERT( IrpContext->SharedScb == NULL );
  2428. }
  2429. //
  2430. // Release the MftScb, if we acquired it in pushing the root index.
  2431. //
  2432. NtfsReleaseExclusiveScbIfOwned( IrpContext, Vcb->MftScb );
  2433. }
  2434. if (FlagOn( CreateFlags, CREATE_FLAG_FOUND_ENTRY )) {
  2435. ASSERT( !FlagOn( CurrentFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ) );
  2436. //
  2437. // Get the file name attribute so we can get the name out of it.
  2438. //
  2439. IndexFileName = (PFILE_NAME) NtfsFoundIndexEntry( IndexEntry );
  2440. if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  2441. RtlCopyMemory( FinalName.Buffer,
  2442. IndexFileName->FileName,
  2443. FinalName.Length );
  2444. }
  2445. }
  2446. //
  2447. // If we didn't find a matching entry in the index, we need to check if the
  2448. // name is illegal or simply isn't present on the disk.
  2449. //
  2450. if (!FlagOn( CreateFlags, CREATE_FLAG_FOUND_ENTRY )) {
  2451. if (RemainingName.Length != 0) {
  2452. DebugTrace( 0, Dbg, ("Intermediate component in path doesn't exist\n") );
  2453. try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  2454. }
  2455. //
  2456. // We also need to fail when we have a reparse point. We do not allow the
  2457. // creation of subdirectories of a directory that is a reparse point.
  2458. //
  2459. if (FlagOn( CurrentFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  2460. DebugTrace( 0, Dbg, ("For reparse points subdirectories are not allowed.\n") );
  2461. try_return( Status = STATUS_DIRECTORY_IS_A_REPARSE_POINT );
  2462. }
  2463. //
  2464. // Now copy the exact case of the name specified by the user back
  2465. // in the file name buffer and file name attribute in order to
  2466. // create the name.
  2467. //
  2468. if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  2469. ASSERT( ExactCaseName->Length != 0 );
  2470. ASSERT( FullFileName->Length >= ExactCaseName->Length + ExactCaseOffset );
  2471. RtlCopyMemory( FinalName.Buffer,
  2472. Add2Ptr( ExactCaseName->Buffer,
  2473. ExactCaseName->Length - FinalName.Length ),
  2474. FinalName.Length );
  2475. RtlCopyMemory( FileNameAttr->FileName,
  2476. Add2Ptr( ExactCaseName->Buffer,
  2477. ExactCaseName->Length - FinalName.Length ),
  2478. FinalName.Length );
  2479. }
  2480. }
  2481. //
  2482. // If we're at the last component in the path, then this is the file
  2483. // to open or create
  2484. //
  2485. if (RemainingName.Length == 0) {
  2486. break;
  2487. }
  2488. //
  2489. // Otherwise we create an Fcb for the subdirectory and the link between
  2490. // it and its parent Scb.
  2491. //
  2492. //
  2493. // Discard any mapping information we have for the parent.
  2494. //
  2495. NtfsRemoveFromFileRecordCache( IrpContext,
  2496. NtfsSegmentNumber( &CurrentScb->Fcb->FileReference ));
  2497. //
  2498. // Remember that the current values will become the parent values.
  2499. //
  2500. ParentFcb = CurrentFcb;
  2501. CurrentLcb = NtfsOpenSubdirectory( IrpContext,
  2502. CurrentScb,
  2503. FinalName,
  2504. CreateFlags,
  2505. &CurrentFcb,
  2506. &LcbForTeardown,
  2507. IndexEntry );
  2508. //
  2509. // Check that this link is a valid existing link.
  2510. //
  2511. if (LcbLinkIsDeleted( CurrentLcb ) ||
  2512. CurrentFcb->LinkCount == 0) {
  2513. try_return( Status = STATUS_DELETE_PENDING );
  2514. }
  2515. //
  2516. // We have progressed parsing the name. Mark it as one that needs to be inspected
  2517. // for possible reparse behavior.
  2518. //
  2519. SetFlag( CreateFlags, CREATE_FLAG_INSPECT_NAME_FOR_REPARSE );
  2520. //
  2521. // Go ahead and insert this link into the splay tree if it is not
  2522. // a system file.
  2523. //
  2524. if (!FlagOn( CurrentLcb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  2525. //
  2526. // See if we can insert the hash for the parent.
  2527. //
  2528. if ((CreateContext.ParentHashLength != 0) &&
  2529. (RemainingName.Length == CreateContext.FileHashLength - CreateContext.ParentHashLength - sizeof( WCHAR )) &&
  2530. !FlagOn( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT ) &&
  2531. (CurrentLcb->FileNameAttr->Flags != FILE_NAME_DOS)) {
  2532. //
  2533. // Remove any exising hash value.
  2534. //
  2535. if (FlagOn( CurrentLcb->LcbState, LCB_STATE_VALID_HASH_VALUE )) {
  2536. NtfsRemoveHashEntriesForLcb( CurrentLcb );
  2537. #ifdef NTFS_HASH_DATA
  2538. Vcb->HashTable.ParentConflict += 1;
  2539. #endif
  2540. }
  2541. NtfsInsertHashEntry( &Vcb->HashTable,
  2542. CurrentLcb,
  2543. CreateContext.ParentHashLength,
  2544. CreateContext.ParentHashValue );
  2545. #ifdef NTFS_HASH_DATA
  2546. Vcb->HashTable.ParentInsert += 1;
  2547. #endif
  2548. }
  2549. NtfsInsertPrefix( CurrentLcb, CreateFlags );
  2550. }
  2551. //
  2552. // Since we have the location of this entry store the information into
  2553. // the Lcb.
  2554. //
  2555. RtlCopyMemory( &CurrentLcb->QuickIndex,
  2556. &QuickIndex,
  2557. sizeof( QUICK_INDEX ));
  2558. //
  2559. // Check if the current Lcb is a Dos-Only Name.
  2560. //
  2561. if (CurrentLcb->FileNameAttr->Flags == FILE_NAME_DOS) {
  2562. SetFlag( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT );
  2563. }
  2564. ClearFlag( CreateFlags, CREATE_FLAG_FIRST_PASS);
  2565. }
  2566. //
  2567. // We now have the parent of the file to open and know whether the file exists on
  2568. // the disk. At this point we either attempt to open the target directory or
  2569. // the file itself.
  2570. //
  2571. if (FlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY )) {
  2572. ASSERT( IndexContext != NULL );
  2573. NtfsCleanupIndexContext( IrpContext, IndexContext );
  2574. IndexContext = NULL;
  2575. //
  2576. // We don't allow attribute names or attribute codes to
  2577. // be specified.
  2578. //
  2579. if (AttrName.Length != 0
  2580. || AttrCodeName.Length != 0) {
  2581. DebugTrace( 0, Dbg, ("Can't specify complex name for rename\n") );
  2582. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2583. }
  2584. //
  2585. // When SL_OPEN_TARGET_DIRECTORY is set, the directory should not be opened
  2586. // as a reparse point; FILE_OPEN_REPARSE_POINT should not be set.
  2587. //
  2588. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )) {
  2589. //
  2590. // Wrong open flag, invalid parameter.
  2591. //
  2592. DebugTrace( 0, Dbg, ("Can't open intermediate directory as reparse point 2.\n") );
  2593. Status = STATUS_INVALID_PARAMETER;
  2594. try_return( Status );
  2595. }
  2596. //
  2597. // We want to copy the exact case of the name back into the
  2598. // input buffer for this case.
  2599. //
  2600. if (ExactCaseName->Buffer != NULL) {
  2601. ASSERT( ExactCaseName->Length != 0 );
  2602. ASSERT( FullFileName->MaximumLength >= ExactCaseName->MaximumLength + ExactCaseOffset );
  2603. RtlCopyMemory( Add2Ptr( FullFileName->Buffer, ExactCaseOffset ),
  2604. ExactCaseName->Buffer,
  2605. ExactCaseName->MaximumLength );
  2606. }
  2607. //
  2608. // Call our open target directory, remembering the target
  2609. // file existed.
  2610. //
  2611. Status = NtfsOpenTargetDirectory( IrpContext,
  2612. Irp,
  2613. IrpSp,
  2614. CurrentFcb,
  2615. CurrentLcb,
  2616. &OplockCleanup->FileObject->FileName,
  2617. FinalName.Length,
  2618. CreateFlags,
  2619. &ThisScb,
  2620. &ThisCcb );
  2621. try_return( Status );
  2622. }
  2623. //
  2624. // If we didn't find an entry, we will try to create the file.
  2625. //
  2626. if (!FlagOn( CreateFlags, CREATE_FLAG_FOUND_ENTRY )) {
  2627. //
  2628. // Update our pointers to reflect that we are at the
  2629. // parent of the file we want.
  2630. //
  2631. ParentFcb = CurrentFcb;
  2632. //
  2633. // No point in going down the create path for a Network Query.
  2634. //
  2635. if (ARGUMENT_PRESENT( NetworkInfo )) {
  2636. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2637. } else {
  2638. Status = NtfsCreateNewFile( IrpContext,
  2639. Irp,
  2640. IrpSp,
  2641. CurrentScb,
  2642. FileNameAttr,
  2643. *FullFileName,
  2644. FinalName,
  2645. AttrName,
  2646. AttrCodeName,
  2647. CreateFlags,
  2648. &IndexContext,
  2649. &CreateContext,
  2650. &CurrentFcb,
  2651. &LcbForTeardown,
  2652. &ThisScb,
  2653. &ThisCcb );
  2654. }
  2655. SetFlag( CreateFlags, CREATE_FLAG_CREATE_FILE_CASE );
  2656. //
  2657. // Otherwise we call our routine to open the file.
  2658. //
  2659. } else {
  2660. ASSERT( IndexContext != NULL );
  2661. NtfsCleanupIndexContext( IrpContext, IndexContext );
  2662. IndexContext = NULL;
  2663. ParentFcb = CurrentFcb;
  2664. Status = NtfsOpenFile( IrpContext,
  2665. Irp,
  2666. IrpSp,
  2667. CurrentScb,
  2668. IndexEntry,
  2669. *FullFileName,
  2670. FinalName,
  2671. AttrName,
  2672. AttrCodeName,
  2673. &QuickIndex,
  2674. CreateFlags,
  2675. NetworkInfo,
  2676. &CreateContext,
  2677. &CurrentFcb,
  2678. &LcbForTeardown,
  2679. &ThisScb,
  2680. &ThisCcb );
  2681. }
  2682. try_exit: NOTHING;
  2683. //
  2684. // If we raise below then we need to back out any failed opens.
  2685. //
  2686. SetFlag( CreateFlags, CREATE_FLAG_BACKOUT_FAILED_OPENS );
  2687. //
  2688. // Abort transaction on err by raising.
  2689. //
  2690. if (Status != STATUS_PENDING) {
  2691. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  2692. }
  2693. } finally {
  2694. DebugUnwind( NtfsCommonCreate );
  2695. //
  2696. // If we only have the current Fcb shared then simply give it up.
  2697. //
  2698. if (FlagOn( CreateFlags, CREATE_FLAG_SHARED_PARENT_FCB ) && (CurrentFcb != NULL)) {
  2699. NtfsReleaseFcb( IrpContext, CurrentFcb );
  2700. CurrentFcb = NULL;
  2701. }
  2702. //
  2703. // Unpin the index entry.
  2704. //
  2705. NtfsUnpinBcb( IrpContext, &IndexEntryBcb );
  2706. //
  2707. // Cleanup the index context if used.
  2708. //
  2709. if (IndexContext != NULL) {
  2710. NtfsCleanupIndexContext( IrpContext, IndexContext );
  2711. }
  2712. //
  2713. // Free the file name attribute if we allocated it.
  2714. //
  2715. if (FileNameAttr != NULL) {
  2716. NtfsFreePool( FileNameAttr );
  2717. }
  2718. //
  2719. // Capture the status code from the IrpContext if we are in the exception path.
  2720. //
  2721. if (AbnormalTermination()) {
  2722. Status = IrpContext->ExceptionStatus;
  2723. }
  2724. //
  2725. // If this is the oplock completion path then don't do any of this completion work,
  2726. // The Irp may already have been posted to another thread.
  2727. //
  2728. if (Status != STATUS_PENDING) {
  2729. //
  2730. // If we successfully opened the file, we need to update the in-memory
  2731. // structures.
  2732. //
  2733. if (NT_SUCCESS( Status ) && (Status != STATUS_REPARSE)) {
  2734. //
  2735. // If the create completed, there's no reason why we shouldn't have
  2736. // a valid ThisScb now.
  2737. //
  2738. ASSERT( ThisScb != NULL );
  2739. //
  2740. // If we modified the original file name, we can delete the original
  2741. // buffer.
  2742. //
  2743. if ((OriginalFileName->Buffer != NULL) &&
  2744. (OriginalFileName->Buffer != FullFileName->Buffer)) {
  2745. NtfsFreePool( OriginalFileName->Buffer );
  2746. }
  2747. //
  2748. // Do our normal processing if this is not a Network Info query.
  2749. //
  2750. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  2751. //
  2752. // Find the Lcb for this open.
  2753. //
  2754. CurrentLcb = ThisCcb->Lcb;
  2755. //
  2756. // Check if we were opening a paging file and if so then make sure that
  2757. // the internal attribute stream is all closed down
  2758. //
  2759. if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )) {
  2760. NtfsDeleteInternalAttributeStream( ThisScb, TRUE, FALSE );
  2761. }
  2762. //
  2763. // If we are not done with a large allocation for a new attribute,
  2764. // then we must make sure that no one can open the file until we
  2765. // try to get it extended. Do this before dropping the Vcb.
  2766. //
  2767. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_LARGE_ALLOCATION )) {
  2768. //
  2769. // For a new file, we can clear the link count and mark the
  2770. // Lcb (if there is one) delete on close.
  2771. //
  2772. if (FlagOn( CreateFlags, CREATE_FLAG_CREATE_FILE_CASE )) {
  2773. CurrentFcb->LinkCount = 0;
  2774. SetFlag( CurrentLcb->LcbState, LCB_STATE_DELETE_ON_CLOSE );
  2775. //
  2776. // If we just created an attribute, then we will mark that attribute
  2777. // delete on close to prevent it from being opened.
  2778. //
  2779. } else {
  2780. SetFlag( ThisScb->ScbState, SCB_STATE_DELETE_ON_CLOSE );
  2781. }
  2782. }
  2783. //
  2784. // Remember the POSIX flag and whether we had to do any traverse
  2785. // access checking.
  2786. //
  2787. if (FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  2788. SetFlag( ThisCcb->Flags, CCB_FLAG_IGNORE_CASE );
  2789. }
  2790. //
  2791. // Remember if this user needs to do traverse checks so we can show him the
  2792. // name from the root.
  2793. //
  2794. if (FlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK )) {
  2795. SetFlag( ThisCcb->Flags, CCB_FLAG_TRAVERSE_CHECK );
  2796. }
  2797. //
  2798. // Remember who this user is so we know whether to allow
  2799. // raw reads and writes of encrypted data.
  2800. //
  2801. {
  2802. PACCESS_STATE AccessState;
  2803. PRIVILEGE_SET PrivilegeSet;
  2804. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  2805. //
  2806. // No flags should be preset
  2807. //
  2808. ASSERT( ThisCcb->AccessFlags == 0 );
  2809. //
  2810. // This will set the READ_DATA_ACCESS, WRITE_DATA_ACCESS,
  2811. // APPEND_DATA_ACCESS, and EXECUTE_ACCESS bits correctly.
  2812. //
  2813. SetFlag( ThisCcb->AccessFlags,
  2814. FlagOn( AccessState->PreviouslyGrantedAccess, FILE_READ_DATA |
  2815. FILE_WRITE_DATA |
  2816. FILE_APPEND_DATA |
  2817. FILE_EXECUTE |
  2818. FILE_WRITE_ATTRIBUTES |
  2819. FILE_READ_ATTRIBUTES ));
  2820. //
  2821. // Here we're setting BACKUP_ACCESS and RESTORE_ACCESS. We want to set
  2822. // the Ccb flag if the user has the privilege AND they opened the file up
  2823. // with an access that is interesting. For example backup or restore will give
  2824. // you synchronize but if you open the file up only for that we don't want
  2825. // to remember the privileges (its too ambiguous and you'll backup or restore
  2826. // depending op whether you're local or remote))
  2827. //
  2828. if (FlagOn( AccessState->PreviouslyGrantedAccess, NTFS_REQUIRES_BACKUP ) &&
  2829. FlagOn( AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE )) {
  2830. SetFlag( ThisCcb->AccessFlags, BACKUP_ACCESS );
  2831. }
  2832. if (FlagOn( AccessState->PreviouslyGrantedAccess, NTFS_REQUIRES_RESTORE ) &&
  2833. FlagOn( AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE )) {
  2834. SetFlag( ThisCcb->AccessFlags, RESTORE_ACCESS );
  2835. }
  2836. PrivilegeSet.PrivilegeCount = 1;
  2837. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  2838. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE );
  2839. PrivilegeSet.Privilege[0].Attributes = 0;
  2840. if (SePrivilegeCheck( &PrivilegeSet,
  2841. &AccessState->SubjectSecurityContext,
  2842. Irp->RequestorMode )) {
  2843. SetFlag( ThisCcb->AccessFlags, MANAGE_VOLUME_ACCESS );
  2844. }
  2845. }
  2846. //
  2847. // We don't do "delete on close" for directories or open
  2848. // by ID files.
  2849. //
  2850. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE ) &&
  2851. (!FlagOn( ThisCcb->Flags, CCB_FLAG_OPEN_BY_FILE_ID ) ||
  2852. !FlagOn( ThisCcb->Flags, CCB_FLAG_OPEN_AS_FILE ))) {
  2853. SetFlag( CreateFlags, CREATE_FLAG_DELETE_ON_CLOSE );
  2854. //
  2855. // We modify the Scb and Lcb here only if we aren't in the
  2856. // large allocation case.
  2857. //
  2858. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_LARGE_ALLOCATION )) {
  2859. SetFlag( ThisCcb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  2860. }
  2861. }
  2862. //
  2863. // If this is a named stream open and we have set any of our notify
  2864. // flags then report the changes.
  2865. //
  2866. if ((Vcb->NotifyCount != 0) &&
  2867. !FlagOn( ThisCcb->Flags, CCB_FLAG_OPEN_BY_FILE_ID ) &&
  2868. (ThisScb->AttributeName.Length != 0) &&
  2869. NtfsIsTypeCodeUserData( ThisScb->AttributeTypeCode ) &&
  2870. FlagOn( ThisScb->ScbState,
  2871. SCB_STATE_NOTIFY_ADD_STREAM |
  2872. SCB_STATE_NOTIFY_RESIZE_STREAM |
  2873. SCB_STATE_NOTIFY_MODIFY_STREAM )) {
  2874. ULONG Filter = 0;
  2875. ULONG Action;
  2876. //
  2877. // Start by checking for an add.
  2878. //
  2879. if (FlagOn( ThisScb->ScbState, SCB_STATE_NOTIFY_ADD_STREAM )) {
  2880. Filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
  2881. Action = FILE_ACTION_ADDED_STREAM;
  2882. } else {
  2883. //
  2884. // Check if the file size changed.
  2885. //
  2886. if (FlagOn( ThisScb->ScbState, SCB_STATE_NOTIFY_RESIZE_STREAM )) {
  2887. Filter = FILE_NOTIFY_CHANGE_STREAM_SIZE;
  2888. }
  2889. //
  2890. // Now check if the stream data was modified.
  2891. //
  2892. if (FlagOn( ThisScb->ScbState, SCB_STATE_NOTIFY_MODIFY_STREAM )) {
  2893. Filter |= FILE_NOTIFY_CHANGE_STREAM_WRITE;
  2894. }
  2895. Action = FILE_ACTION_MODIFIED_STREAM;
  2896. }
  2897. ASSERT( ThisScb && ThisCcb );
  2898. ASSERT( (ThisCcb->NodeTypeCode == NTFS_NTC_CCB_INDEX) || (ThisCcb->NodeTypeCode == NTFS_NTC_CCB_DATA) );
  2899. NtfsUnsafeReportDirNotify( IrpContext,
  2900. Vcb,
  2901. &ThisCcb->FullFileName,
  2902. ThisCcb->LastFileNameOffset,
  2903. &ThisScb->AttributeName,
  2904. ((FlagOn( ThisCcb->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  2905. (ThisCcb->Lcb != NULL) &&
  2906. (ThisCcb->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  2907. &ThisCcb->Lcb->Scb->ScbType.Index.NormalizedName :
  2908. NULL),
  2909. Filter,
  2910. Action,
  2911. NULL );
  2912. }
  2913. ClearFlag( ThisScb->ScbState,
  2914. SCB_STATE_NOTIFY_ADD_STREAM |
  2915. SCB_STATE_NOTIFY_REMOVE_STREAM |
  2916. SCB_STATE_NOTIFY_RESIZE_STREAM |
  2917. SCB_STATE_NOTIFY_MODIFY_STREAM );
  2918. //
  2919. // Otherwise copy the data out of the Scb/Fcb and return to our caller.
  2920. //
  2921. } else {
  2922. NtfsFillNetworkOpenInfo( NetworkInfo, ThisScb );
  2923. //
  2924. // Teardown the Fcb if we should. We're in a success path
  2925. // here so we don't have to worry about aborting anymore and the
  2926. // need to hold any resources
  2927. //
  2928. if (!ThisScb->CleanupCount && !ThisScb->Fcb->DelayedCloseCount) {
  2929. if (!NtfsAddScbToFspClose( IrpContext, ThisScb, TRUE )) {
  2930. if (NtfsIsExclusiveScb( Vcb->MftScb ) ||
  2931. (NtfsPerformQuotaOperation( CurrentFcb ) &&
  2932. NtfsIsSharedScb( Vcb->QuotaTableScb ))) {
  2933. SetFlag( AcquireFlags, ACQUIRE_DONT_WAIT );
  2934. }
  2935. NtfsTeardownStructures( IrpContext,
  2936. CurrentFcb,
  2937. LcbForTeardown,
  2938. (BOOLEAN) (IrpContext->TransactionId != 0),
  2939. AcquireFlags,
  2940. NULL );
  2941. }
  2942. }
  2943. Irp->IoStatus.Information = sizeof( FILE_NETWORK_OPEN_INFORMATION );
  2944. Status = Irp->IoStatus.Status = STATUS_SUCCESS;
  2945. }
  2946. //
  2947. // Start a teardown on the last Fcb found and restore the name strings on
  2948. // a retryable error.
  2949. //
  2950. } else {
  2951. //
  2952. // Perform the necessary cleanup if we raised writing a UsnJournal.
  2953. //
  2954. if (FlagOn( CreateFlags, CREATE_FLAG_BACKOUT_FAILED_OPENS )) {
  2955. NtfsBackoutFailedOpens( IrpContext, IrpSp->FileObject, CurrentFcb, ThisScb, ThisCcb );
  2956. }
  2957. //
  2958. // Start the cleanup process if we have looked at any Fcb's.
  2959. // We tell TeardownStructures not to remove any Scb's in
  2960. // the open attribute table if there is a transaction underway.
  2961. //
  2962. if (CurrentFcb != NULL) {
  2963. if (NtfsIsExclusiveScb( Vcb->MftScb ) ||
  2964. (NtfsPerformQuotaOperation( CurrentFcb ) &&
  2965. NtfsIsSharedScb( Vcb->QuotaTableScb ))) {
  2966. SetFlag( AcquireFlags, ACQUIRE_DONT_WAIT );
  2967. }
  2968. //
  2969. // Someone may have tried to open the $Bitmap stream. We catch that and
  2970. // fail it but the Fcb won't be in the exclusive list to be released.
  2971. //
  2972. if (NtfsEqualMftRef( &CurrentFcb->FileReference, &BitmapFileReference )) {
  2973. NtfsReleaseFcb( IrpContext, CurrentFcb );
  2974. } else {
  2975. //
  2976. // In transactions that don't own any system resources we must
  2977. // make sure that we don't release all of the resources before
  2978. // the transaction commits. Otherwise we won't correctly serialize
  2979. // with clean checkpoints who wants to know the transaction
  2980. // table is empty. Case in point is if we create the parent Scb
  2981. // and file Fcb in this call and tear them down in Teardown below.
  2982. // If there are no other resources held then we have an open
  2983. // transaction but no serialization.
  2984. //
  2985. // In general we can simply acquire a system resource and put it
  2986. // in the exlusive list in the IrpContext. The best choice is
  2987. // the Mft. HOWEVER there is a strange deadlock path if we
  2988. // try to acquire this while owning the security mutext. This
  2989. // can happen in the CreateNewFile path if we are creating a
  2990. // new security descriptor. So we need to add this check
  2991. // before we acquire the Mft, owning the security stream will
  2992. // give us the transaction protection we need.
  2993. //
  2994. // Possible future cleanup is to change how we acquire the security
  2995. // file after the security mutex. Ideally the security mutex would
  2996. // be a true end resource.
  2997. //
  2998. if ((IrpContext->TransactionId != 0) &&
  2999. (CurrentFcb->CleanupCount == 0) &&
  3000. ((CreateDisposition == FILE_OVERWRITE_IF) ||
  3001. (CreateDisposition == FILE_OVERWRITE) ||
  3002. (CreateDisposition == FILE_SUPERSEDE)) &&
  3003. ((Vcb->SecurityDescriptorStream == NULL) ||
  3004. (!NtfsIsSharedScb( Vcb->SecurityDescriptorStream )))) {
  3005. NtfsAcquireExclusiveScb( IrpContext, Vcb->MftScb );
  3006. SetFlag( AcquireFlags, ACQUIRE_DONT_WAIT );
  3007. }
  3008. NtfsTeardownStructures( IrpContext,
  3009. (ThisScb != NULL) ? (PVOID) ThisScb : CurrentFcb,
  3010. LcbForTeardown,
  3011. (BOOLEAN) (IrpContext->TransactionId != 0),
  3012. AcquireFlags,
  3013. NULL );
  3014. }
  3015. }
  3016. if ((Status == STATUS_LOG_FILE_FULL) ||
  3017. (Status == STATUS_CANT_WAIT) ||
  3018. (Status == STATUS_REPARSE)) {
  3019. //
  3020. // Recover the exact case name if present for a retryable condition.
  3021. // and we haven't already recopied it back (ExactCaseName->Length == 0)
  3022. //
  3023. if ((ExactCaseName->Buffer != OriginalFileName->Buffer) &&
  3024. (ExactCaseName->Buffer != NULL) &&
  3025. (ExactCaseName->Length != 0)) {
  3026. ASSERT( OriginalFileName->MaximumLength >= ExactCaseName->MaximumLength );
  3027. RtlCopyMemory( OriginalFileName->Buffer,
  3028. ExactCaseName->Buffer,
  3029. ExactCaseName->MaximumLength );
  3030. }
  3031. //
  3032. // Restitute the access control state to what it was when we entered the request.
  3033. //
  3034. IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess = OplockCleanup->RemainingDesiredAccess;
  3035. IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess = OplockCleanup->PreviouslyGrantedAccess;
  3036. IrpSp->Parameters.Create.SecurityContext->DesiredAccess = OplockCleanup->DesiredAccess;
  3037. }
  3038. //
  3039. // Free any buffer we allocated.
  3040. //
  3041. if ((FullFileName->Buffer != NULL) &&
  3042. (OriginalFileName->Buffer != FullFileName->Buffer)) {
  3043. DebugTrace( 0, Dbg, ("FullFileName->Buffer will be de-allocated %x\n", FullFileName->Buffer) );
  3044. NtfsFreePool( FullFileName->Buffer );
  3045. DebugDoit( FullFileName->Buffer = NULL );
  3046. }
  3047. //
  3048. // Set the file name in the file object back to it's original value.
  3049. //
  3050. OplockCleanup->FileObject->FileName = *OriginalFileName;
  3051. //
  3052. // Always clear the LARGE_ALLOCATION flag so we don't get
  3053. // spoofed by STATUS_REPARSE.
  3054. //
  3055. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_LARGE_ALLOCATION );
  3056. }
  3057. }
  3058. //
  3059. // Always free the exact case name if allocated and it doesn't match the original
  3060. // name buffer.
  3061. //
  3062. if ((ExactCaseName->Buffer != OriginalFileName->Buffer) &&
  3063. (ExactCaseName->Buffer != NULL)) {
  3064. DebugTrace( 0, Dbg, ("ExactCaseName->Buffer will be de-allocated %x\n", ExactCaseName->Buffer) );
  3065. NtfsFreePool( ExactCaseName->Buffer );
  3066. DebugDoit( ExactCaseName->Buffer = NULL );
  3067. }
  3068. //
  3069. // We always give up the Vcb.
  3070. //
  3071. if (FlagOn( CreateFlags, CREATE_FLAG_ACQUIRED_VCB )) {
  3072. NtfsReleaseVcb( IrpContext, Vcb );
  3073. }
  3074. }
  3075. //
  3076. // If we didn't post this Irp then take action to complete the irp.
  3077. //
  3078. if (Status != STATUS_PENDING) {
  3079. //
  3080. // If the current status is success and there is more allocation to
  3081. // allocate then complete the allocation.
  3082. //
  3083. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_LARGE_ALLOCATION ) &&
  3084. NT_SUCCESS( Status )) {
  3085. //
  3086. // If the Create was successful, but we did not get all of the space
  3087. // allocated that we wanted, we have to complete the allocation now.
  3088. // Basically what we do is commit the current transaction and call
  3089. // NtfsAddAllocation to get the rest of the space. Then if the log
  3090. // file fills up (or we are posting for other reasons) we turn the
  3091. // Irp into an Irp which is just trying to extend the file. If we
  3092. // get any other kind of error, then we just delete the file and
  3093. // return with the error from create.
  3094. //
  3095. Status = NtfsCompleteLargeAllocation( IrpContext,
  3096. Irp,
  3097. CurrentLcb,
  3098. ThisScb,
  3099. ThisCcb,
  3100. CreateFlags );
  3101. //
  3102. // **** TEMPCODE ****
  3103. //
  3104. // The large allocation case is tricky. The problem is that we don't
  3105. // want to call the encryption driver to notify them of a create, and
  3106. // then have the large allocation fail, since we don't have a good
  3107. // way to call them back at this point to tell them the create failed.
  3108. // Our normal cleanup callback passes them back their encryption
  3109. // context, but in this case, we may not yet have their encryption
  3110. // context stored in the scb, since they may not have created it yet.
  3111. //
  3112. #if 0
  3113. //
  3114. // If we managed to do the large allocation, call the
  3115. // encryption driver if one is registered.
  3116. //
  3117. if ((NT_SUCCESS( Status ) && (Status != STATUS_REPARSE)) &&
  3118. FlagOn( EncryptionFileDirFlags, FILE_DIR_TYPE_MASK )) {
  3119. ASSERT(!ARGUMENT_PRESENT( NetworkInfo ));
  3120. NtfsEncryptionCreateCallback( IrpContext,
  3121. Irp,
  3122. IrpSp,
  3123. ThisScb,
  3124. ThisCcb,
  3125. CurrentFcb,
  3126. ParentFcb,
  3127. FALSE );
  3128. }
  3129. #endif
  3130. }
  3131. //
  3132. // If our caller told us not to complete the irp, or if this
  3133. // is a network open, we don't really complete the irp.
  3134. // EFS_CREATES have PostCreate callouts to do before the
  3135. // irp gets completed, and before the irp context gets deleted,
  3136. // and the caller will do that for us. We should at least
  3137. // cleanup the irp context if our caller won't.
  3138. //
  3139. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE ) ||
  3140. (ARGUMENT_PRESENT( NetworkInfo ))) {
  3141. NtfsCompleteRequest( IrpContext,
  3142. NULL,
  3143. Status );
  3144. #ifdef NTFSDBG
  3145. ASSERT( None == IrpContext->OwnershipState );
  3146. #endif
  3147. } else {
  3148. NtfsCompleteRequest( IrpContext,
  3149. Irp,
  3150. Status );
  3151. }
  3152. }
  3153. DebugTrace( -1, Dbg, ("NtfsCommonCreate: Exit -> %08lx\n", Status) );
  3154. return Status;
  3155. }
  3156. NTSTATUS
  3157. NtfsCommonVolumeOpen (
  3158. IN PIRP_CONTEXT IrpContext,
  3159. IN PIRP Irp
  3160. )
  3161. /*++
  3162. Routine Description:
  3163. This routine is opening the Volume Dasd file. We have already done all the
  3164. checks needed to verify that the user is opening the $DATA attribute.
  3165. We check the security attached to the file and take some special action
  3166. based on a volume open.
  3167. Arguments:
  3168. Return Value:
  3169. NTSTATUS - The result of this operation.
  3170. --*/
  3171. {
  3172. NTSTATUS Status;
  3173. PIO_STACK_LOCATION IrpSp;
  3174. PFILE_OBJECT FileObject;
  3175. PVCB Vcb;
  3176. PFCB ThisFcb;
  3177. PCCB ThisCcb;
  3178. BOOLEAN VcbAcquired = FALSE;
  3179. BOOLEAN FcbAcquired = FALSE;
  3180. BOOLEAN SharingViolation;
  3181. BOOLEAN LockVolume = FALSE;
  3182. BOOLEAN NotifyLockFailed = FALSE;
  3183. PAGED_CODE();
  3184. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  3185. DebugTrace( +1, Dbg, ("NtfsCommonVolumeOpen: Entered\n") );
  3186. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3187. FileObject = IrpSp->FileObject;
  3188. //
  3189. // Use a try-finally to facilitate cleanup.
  3190. //
  3191. try {
  3192. //
  3193. // Start by checking the create disposition. We can only open this
  3194. // file.
  3195. //
  3196. {
  3197. ULONG CreateDisposition;
  3198. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  3199. if (CreateDisposition != FILE_OPEN
  3200. && CreateDisposition != FILE_OPEN_IF) {
  3201. try_return( Status = STATUS_ACCESS_DENIED );
  3202. }
  3203. }
  3204. //
  3205. // Make sure the directory flag isn't set for the volume open.
  3206. //
  3207. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
  3208. try_return( Status = STATUS_INVALID_PARAMETER );
  3209. }
  3210. //
  3211. // If this volume open is going to generate an implicit volume lock
  3212. // (a la autochk), notify anyone who wants to close their handles so
  3213. // the lock can happen. We need to do this before we acquire any resources.
  3214. //
  3215. if (!FlagOn( IrpSp->Parameters.Create.ShareAccess,
  3216. FILE_SHARE_WRITE | FILE_SHARE_DELETE )) {
  3217. DebugTrace( 0, Dbg, ("Sending lock notification\n") );
  3218. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK );
  3219. NotifyLockFailed = TRUE;
  3220. }
  3221. //
  3222. // Acquire the Vcb and verify the volume isn't locked.
  3223. //
  3224. Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
  3225. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  3226. VcbAcquired = TRUE;
  3227. if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_PERFORMED_DISMOUNT )) {
  3228. try_return( Status = STATUS_ACCESS_DENIED );
  3229. }
  3230. //
  3231. // We do give READ-WRITE access to the volume even when
  3232. // it's actually write protected. This is just so that we won't break
  3233. // any apps. However, we don't let the user actually do any modifications.
  3234. //
  3235. // if ((NtfsIsVolumeReadOnly( Vcb )) &&
  3236. // (FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  3237. // FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE ))) {
  3238. //
  3239. // try_return( Status = STATUS_MEDIA_WRITE_PROTECTED );
  3240. //}
  3241. //
  3242. // Ping the volume to make sure the Vcb is still mounted. If we need
  3243. // to verify the volume then do it now, and if it comes out okay
  3244. // then clear the verify volume flag in the device object and continue
  3245. // on. If it doesn't verify okay then dismount the volume and
  3246. // either tell the I/O system to try and create again (with a new mount)
  3247. // or that the volume is wrong. This later code is returned if we
  3248. // are trying to do a relative open and the vcb is no longer mounted.
  3249. //
  3250. if (!NtfsPingVolume( IrpContext, Vcb, NULL ) ||
  3251. !FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  3252. if (!NtfsPerformVerifyOperation( IrpContext, Vcb )) {
  3253. NtfsReleaseVcb( IrpContext, Vcb );
  3254. NtfsAcquireCheckpointSynchronization( IrpContext, Vcb );
  3255. NtfsAcquireExclusiveVcb( IrpContext, Vcb, FALSE );
  3256. if (!NtfsPerformVerifyOperation( IrpContext, Vcb )) {
  3257. try {
  3258. NtfsPerformDismountOnVcb( IrpContext, Vcb, TRUE, NULL );
  3259. } finally {
  3260. NtfsReleaseCheckpointSynchronization( IrpContext, Vcb );
  3261. }
  3262. NtfsRaiseStatus( IrpContext, STATUS_WRONG_VOLUME, NULL, NULL );
  3263. }
  3264. }
  3265. //
  3266. // The volume verified correctly so now clear the verify bit
  3267. // and continue with the create
  3268. //
  3269. ClearFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
  3270. }
  3271. //
  3272. // Now acquire the Fcb for the VolumeDasd and verify the user has
  3273. // permission to open the volume.
  3274. //
  3275. ThisFcb = Vcb->VolumeDasdScb->Fcb;
  3276. if (ThisFcb->PagingIoResource != NULL) {
  3277. NtfsAcquireExclusivePagingIo( IrpContext, ThisFcb );
  3278. }
  3279. NtfsAcquireResourceExclusive( IrpContext, ThisFcb, TRUE );
  3280. FcbAcquired = TRUE;
  3281. NtfsOpenCheck( IrpContext, ThisFcb, NULL, Irp );
  3282. //
  3283. // If the user does not want to share write or delete then we will try
  3284. // and take out a lock on the volume.
  3285. //
  3286. if (!FlagOn( IrpSp->Parameters.Create.ShareAccess,
  3287. FILE_SHARE_WRITE | FILE_SHARE_DELETE )) {
  3288. //
  3289. // Do a quick test of the volume cleanup count if this opener won't
  3290. // share with anyone. We can safely examine the cleanup count without
  3291. // further synchronization because we are guaranteed to have the
  3292. // Vcb exclusive at this point.
  3293. //
  3294. #ifdef SYSCACHE_DEBUG
  3295. if (!FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ) &&
  3296. (Vcb->CleanupCount != 1)) {
  3297. #else
  3298. if (!FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ) &&
  3299. (Vcb->CleanupCount != 0)) {
  3300. #endif
  3301. try_return( Status = STATUS_SHARING_VIOLATION );
  3302. #ifdef SYSCACHE_DEBUG
  3303. }
  3304. #else
  3305. }
  3306. #endif
  3307. //
  3308. // Go ahead and flush and purge the volume. Then test to see if all
  3309. // of the user file objects were closed.
  3310. //
  3311. Status = NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, FALSE );
  3312. //
  3313. // We don't care about certain errors in the flush path.
  3314. //
  3315. if (!NT_SUCCESS( Status )) {
  3316. //
  3317. // If there are no conflicts but the status indicates disk corruption
  3318. // or a section that couldn't be removed then ignore the error. We
  3319. // allow this open to succeed so that chkdsk can open the volume to
  3320. // repair the damage.
  3321. //
  3322. if ((Status == STATUS_UNABLE_TO_DELETE_SECTION) ||
  3323. (Status == STATUS_DISK_CORRUPT_ERROR) ||
  3324. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  3325. Status = STATUS_SUCCESS;
  3326. }
  3327. }
  3328. //
  3329. // If the flush and purge was successful but there are still file objects
  3330. // that block this open it is possible that the FspClose thread is
  3331. // blocked behind the Vcb. Drop the Fcb and Vcb to allow this thread
  3332. // to get in and then reacquire them. This will give this Dasd open
  3333. // another chance to succeed on the first try.
  3334. //
  3335. SharingViolation = FALSE;
  3336. if (FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ)) {
  3337. if (Vcb->ReadOnlyCloseCount != (Vcb->CloseCount - Vcb->SystemFileCloseCount)) {
  3338. SharingViolation = TRUE;
  3339. }
  3340. } else if (Vcb->CloseCount != Vcb->SystemFileCloseCount) {
  3341. SharingViolation = TRUE;
  3342. }
  3343. if (SharingViolation && NT_SUCCESS( Status )) {
  3344. //
  3345. // We need to commit the current transaction and release any
  3346. // resources. This will release the Fcb for the volume as
  3347. // well. Explicitly release the Vcb.
  3348. //
  3349. NtfsCheckpointCurrentTransaction( IrpContext );
  3350. while (!IsListEmpty(&IrpContext->ExclusiveFcbList)) {
  3351. NtfsReleaseFcbWithPaging( IrpContext,
  3352. (PFCB)CONTAINING_RECORD(IrpContext->ExclusiveFcbList.Flink,
  3353. FCB,
  3354. ExclusiveFcbLinks ));
  3355. }
  3356. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
  3357. IRP_CONTEXT_FLAG_RELEASE_MFT );
  3358. if (ThisFcb->PagingIoResource != NULL) {
  3359. NtfsReleasePagingIo( IrpContext, ThisFcb );
  3360. }
  3361. NtfsReleaseResource( IrpContext, ThisFcb );
  3362. FcbAcquired = FALSE;
  3363. NtfsReleaseVcb( IrpContext, Vcb );
  3364. VcbAcquired = FALSE;
  3365. CcWaitForCurrentLazyWriterActivity();
  3366. //
  3367. // Now explicitly reacquire the Vcb and Fcb. Test that no one
  3368. // else got in to lock the volume in the meantime.
  3369. //
  3370. NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE );
  3371. VcbAcquired = TRUE;
  3372. if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED | VCB_STATE_PERFORMED_DISMOUNT )) {
  3373. try_return( Status = STATUS_ACCESS_DENIED );
  3374. }
  3375. //
  3376. // Now acquire the Fcb for the VolumeDasd.
  3377. //
  3378. if (ThisFcb->PagingIoResource != NULL) {
  3379. NtfsAcquireExclusivePagingIo( IrpContext, ThisFcb );
  3380. }
  3381. NtfsAcquireResourceExclusive( IrpContext, ThisFcb, TRUE );
  3382. FcbAcquired = TRUE;
  3383. //
  3384. // Duplicate the flush/purge and test if there is no sharing
  3385. // violation.
  3386. //
  3387. Status = NtfsFlushVolume( IrpContext, Vcb, TRUE, TRUE, TRUE, FALSE );
  3388. //
  3389. // We don't care about certain errors in the flush path.
  3390. //
  3391. if (!NT_SUCCESS( Status )) {
  3392. //
  3393. // If there are no conflicts but the status indicates disk corruption
  3394. // or a section that couldn't be removed then ignore the error. We
  3395. // allow this open to succeed so that chkdsk can open the volume to
  3396. // repair the damage.
  3397. //
  3398. if ((Status == STATUS_UNABLE_TO_DELETE_SECTION) ||
  3399. (Status == STATUS_DISK_CORRUPT_ERROR) ||
  3400. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  3401. Status = STATUS_SUCCESS;
  3402. }
  3403. }
  3404. SharingViolation = FALSE;
  3405. if (FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ)) {
  3406. if (Vcb->ReadOnlyCloseCount != (Vcb->CloseCount - Vcb->SystemFileCloseCount)) {
  3407. SharingViolation = TRUE;
  3408. }
  3409. } else if (Vcb->CloseCount != Vcb->SystemFileCloseCount) {
  3410. SharingViolation = TRUE;
  3411. }
  3412. }
  3413. //
  3414. // Return an error if there are still conflicting file objects.
  3415. //
  3416. if (SharingViolation) {
  3417. //
  3418. // If there was an error in the flush then return it. Otherwise
  3419. // return SHARING_VIOLATION.
  3420. //
  3421. if (NT_SUCCESS( Status )) {
  3422. try_return( Status = STATUS_SHARING_VIOLATION );
  3423. } else {
  3424. try_return( Status );
  3425. }
  3426. }
  3427. if (!NT_SUCCESS( Status )) {
  3428. //
  3429. // If there are no conflicts but the status indicates disk corruption
  3430. // or a section that couldn't be removed then ignore the error. We
  3431. // allow this open to succeed so that chkdsk can open the volume to
  3432. // repair the damage.
  3433. //
  3434. if ((Status == STATUS_UNABLE_TO_DELETE_SECTION) ||
  3435. (Status == STATUS_DISK_CORRUPT_ERROR) ||
  3436. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  3437. Status = STATUS_SUCCESS;
  3438. //
  3439. // Fail this request on any other failures.
  3440. //
  3441. } else {
  3442. try_return( Status );
  3443. }
  3444. }
  3445. //
  3446. // Remember that we want to lock the volume if the user plans to write.
  3447. // This is to allow autochk to fiddle with the volume.
  3448. //
  3449. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  3450. FILE_WRITE_DATA | FILE_APPEND_DATA )) {
  3451. LockVolume = TRUE;
  3452. }
  3453. //
  3454. // Just flush the volume data if the user requested read or write.
  3455. // No need to purge or lock the volume.
  3456. //
  3457. } else if (FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  3458. FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA )) {
  3459. if (!NT_SUCCESS( Status = NtfsFlushVolume( IrpContext, Vcb, TRUE, FALSE, TRUE, FALSE ))) {
  3460. //
  3461. // Swallow corruption errors because we want this open to succeed.
  3462. //
  3463. if ((Status == STATUS_DISK_CORRUPT_ERROR) ||
  3464. (Status == STATUS_FILE_CORRUPT_ERROR)) {
  3465. Status = STATUS_SUCCESS;
  3466. } else {
  3467. //
  3468. // Report the error that there is an data section blocking the open by returning
  3469. // sharing violation. Otherwise Win32 callers will get INVALID_PARAMETER.
  3470. //
  3471. if (Status == STATUS_UNABLE_TO_DELETE_SECTION) {
  3472. Status = STATUS_SHARING_VIOLATION;
  3473. }
  3474. try_return( Status );
  3475. }
  3476. }
  3477. }
  3478. //
  3479. // Put the Volume Dasd name in the file object.
  3480. //
  3481. {
  3482. PVOID Temp = FileObject->FileName.Buffer;
  3483. FileObject->FileName.Buffer =
  3484. FsRtlAllocatePoolWithTag(PagedPool, 8 * sizeof( WCHAR ), MODULE_POOL_TAG );
  3485. if (Temp != NULL) {
  3486. NtfsFreePool( Temp );
  3487. }
  3488. RtlCopyMemory( FileObject->FileName.Buffer, L"\\$Volume", 8 * sizeof( WCHAR ));
  3489. FileObject->FileName.MaximumLength =
  3490. FileObject->FileName.Length = 8*2;
  3491. }
  3492. //
  3493. // We never allow cached access to the volume file.
  3494. //
  3495. ClearFlag( FileObject->Flags, FO_CACHE_SUPPORTED );
  3496. SetFlag( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
  3497. //
  3498. // Go ahead open the attribute. This should only fail if there is an
  3499. // allocation failure or share access failure.
  3500. //
  3501. if (NT_SUCCESS( Status = NtfsOpenAttribute( IrpContext,
  3502. IrpSp,
  3503. Vcb,
  3504. NULL,
  3505. ThisFcb,
  3506. 2,
  3507. NtfsEmptyString,
  3508. $DATA,
  3509. (ThisFcb->CleanupCount == 0 ?
  3510. SetShareAccess :
  3511. CheckShareAccess),
  3512. UserVolumeOpen,
  3513. FALSE,
  3514. CCB_FLAG_OPEN_AS_FILE,
  3515. NULL,
  3516. &Vcb->VolumeDasdScb,
  3517. &ThisCcb ))) {
  3518. //
  3519. // Perform the final initialization.
  3520. //
  3521. //
  3522. // Check if we can administer the volume and note it in the ccb
  3523. //
  3524. //
  3525. // If the user was granted both read and write access then
  3526. // he can administer the volume. This allows the interactive
  3527. // user to manage removable media if allowed by the access.
  3528. //
  3529. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  3530. FILE_READ_DATA | FILE_WRITE_DATA ) == (FILE_READ_DATA | FILE_WRITE_DATA)) {
  3531. SetFlag( ThisCcb->AccessFlags, MANAGE_VOLUME_ACCESS );
  3532. //
  3533. // We can also grant it through our ACL.
  3534. //
  3535. } else if (NtfsCanAdministerVolume( IrpContext, Irp, ThisFcb, NULL, NULL )) {
  3536. SetFlag( ThisCcb->AccessFlags, MANAGE_VOLUME_ACCESS );
  3537. //
  3538. // We can also grant this through the MANAGE_VOLUME_PRIVILEGE.
  3539. //
  3540. } else {
  3541. PRIVILEGE_SET PrivilegeSet;
  3542. PrivilegeSet.PrivilegeCount = 1;
  3543. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  3544. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE );
  3545. PrivilegeSet.Privilege[0].Attributes = 0;
  3546. if (SePrivilegeCheck( &PrivilegeSet,
  3547. &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
  3548. Irp->RequestorMode )) {
  3549. SetFlag( ThisCcb->AccessFlags, MANAGE_VOLUME_ACCESS );
  3550. //
  3551. // Well nothing else worked. Now we need to look at the security
  3552. // descriptor on the device.
  3553. //
  3554. } else {
  3555. NTSTATUS SeStatus;
  3556. BOOLEAN MemoryAllocated = FALSE;
  3557. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  3558. ULONG RequestedAccess = FILE_READ_DATA | FILE_WRITE_DATA;
  3559. SeStatus = ObGetObjectSecurity( Vcb->Vpb->RealDevice,
  3560. &SecurityDescriptor,
  3561. &MemoryAllocated );
  3562. if (SeStatus == STATUS_SUCCESS) {
  3563. //
  3564. // If there is a security descriptor then check the access.
  3565. //
  3566. if (SecurityDescriptor != NULL) {
  3567. if (NtfsCanAdministerVolume( IrpContext,
  3568. Irp,
  3569. ThisFcb,
  3570. SecurityDescriptor,
  3571. &RequestedAccess )) {
  3572. SetFlag( ThisCcb->AccessFlags, MANAGE_VOLUME_ACCESS );
  3573. }
  3574. //
  3575. // Free up the descriptor.
  3576. //
  3577. ObReleaseObjectSecurity( SecurityDescriptor,
  3578. MemoryAllocated );
  3579. }
  3580. }
  3581. }
  3582. }
  3583. //
  3584. // If we are locking the volume, do so now.
  3585. //
  3586. if (LockVolume) {
  3587. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  3588. Vcb->FileObjectWithVcbLocked = FileObject;
  3589. //
  3590. // Looks like the lock succeeded, so we don't have to do the
  3591. // lock failed notification now.
  3592. //
  3593. NotifyLockFailed = FALSE;
  3594. }
  3595. //
  3596. // Report that we opened the volume.
  3597. //
  3598. Irp->IoStatus.Information = FILE_OPENED;
  3599. }
  3600. try_exit: NOTHING;
  3601. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  3602. //
  3603. // If we have a successful open then remove the name out of
  3604. // the file object. The IO system gets confused when it
  3605. // is there. We will deallocate the buffer with the Ccb
  3606. // when the handle is closed.
  3607. //
  3608. if (Status == STATUS_SUCCESS) {
  3609. FileObject->FileName.Buffer = NULL;
  3610. FileObject->FileName.MaximumLength =
  3611. FileObject->FileName.Length = 0;
  3612. SetFlag( ThisCcb->Flags, CCB_FLAG_ALLOCATED_FILE_NAME );
  3613. }
  3614. } finally {
  3615. DebugUnwind( NtfsCommonVolumeOpen );
  3616. if (FcbAcquired) { NtfsReleaseResource( IrpContext, ThisFcb ); }
  3617. if (VcbAcquired) {
  3618. NtfsReleaseVcb( IrpContext, Vcb );
  3619. }
  3620. //
  3621. // Now that we aren't holding any resources, notify everyone
  3622. // who might want to reopen their handles. We want to do this
  3623. // before we complete the request because the FileObject might
  3624. // not exist beyond the life of the Irp.
  3625. //
  3626. if (NotifyLockFailed) {
  3627. DebugTrace( 0, Dbg, ("Sending lock_failed notification\n") );
  3628. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK_FAILED );
  3629. }
  3630. DebugTrace( -1, Dbg, ("NtfsCommonVolumeOpen: Exit -> %08lx\n", Status) );
  3631. }
  3632. //
  3633. // If we have already done a PreCreate for this IRP (in FsdCreate),
  3634. // we should do the corresponding PostCreate before we complete the IRP. So,
  3635. // in that case, don't complete the IRP here -- just free the IrpContext.
  3636. // The IRP will be completed by the caller.
  3637. //
  3638. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE )) {
  3639. NtfsCompleteRequest( IrpContext, NULL, Status );
  3640. } else {
  3641. NtfsCompleteRequest( IrpContext, Irp, Status );
  3642. }
  3643. return Status;
  3644. }
  3645. //
  3646. // Local support routine
  3647. //
  3648. NTSTATUS
  3649. NtfsOpenFcbById (
  3650. IN PIRP_CONTEXT IrpContext,
  3651. IN PIRP Irp,
  3652. IN PIO_STACK_LOCATION IrpSp,
  3653. IN PVCB Vcb,
  3654. IN PLCB ParentLcb OPTIONAL,
  3655. IN OUT PFCB *CurrentFcb,
  3656. IN BOOLEAN UseCurrentFcb,
  3657. IN FILE_REFERENCE FileReference,
  3658. IN UNICODE_STRING AttrName,
  3659. IN UNICODE_STRING AttrCodeName,
  3660. IN PVOID NetworkInfo OPTIONAL,
  3661. OUT PSCB *ThisScb,
  3662. OUT PCCB *ThisCcb
  3663. )
  3664. /*++
  3665. Routine Description:
  3666. This routine is called to open a file by its file Id. We need to
  3667. verify that this file Id exists and then compare the type of the
  3668. file with the requested type of open.
  3669. Arguments:
  3670. Irp - This is the Irp for this open operation.
  3671. IrpSp - This is the Irp stack pointer for the filesystem.
  3672. Vcb - Vcb for this volume.
  3673. ParentLcb - Lcb used to reach this Fcb. Only specified when opening
  3674. a file by name relative to a directory opened by file Id.
  3675. CurrentFcb - Address of Fcb pointer. It will either be the
  3676. Fcb to open or we will store the Fcb we find here.
  3677. UseCurrentFcb - Indicate in the CurrentFcb above points to the target
  3678. Fcb or if we should find it here.
  3679. FileReference - This is the file Id for the file to open.
  3680. AttrName - This is the name of the attribute to open.
  3681. AttrCodeName - This is the name of the attribute code to open.
  3682. NetworkInfo - If specified then this call is a fast open call to query
  3683. the network information. We don't update any of the in-memory structures
  3684. for this.
  3685. ThisScb - This is the address to store the Scb from this open.
  3686. ThisCcb - This is the address to store the Ccb from this open.
  3687. Return Value:
  3688. NTSTATUS - Indicates the result of this create file operation.
  3689. --*/
  3690. {
  3691. NTSTATUS Status = STATUS_SUCCESS;
  3692. LONGLONG MftOffset;
  3693. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  3694. PBCB Bcb = NULL;
  3695. BOOLEAN IndexedAttribute;
  3696. PFCB ThisFcb;
  3697. BOOLEAN ExistingFcb = FALSE;
  3698. ULONG CcbFlags = 0;
  3699. ATTRIBUTE_TYPE_CODE AttrTypeCode;
  3700. OLD_SCB_SNAPSHOT ScbSizes;
  3701. BOOLEAN HaveScbSizes = FALSE;
  3702. BOOLEAN DecrementCloseCount = FALSE;
  3703. PSCB ParentScb = NULL;
  3704. PLCB Lcb = ParentLcb;
  3705. BOOLEAN AcquiredParentScb = FALSE;
  3706. BOOLEAN AcquiredMft = FALSE;
  3707. BOOLEAN AcquiredFcbTable = FALSE;
  3708. BOOLEAN PreparedForUpdateDuplicate = FALSE;
  3709. UCHAR CreateDisposition = (UCHAR) ((IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
  3710. UNREFERENCED_PARAMETER( NetworkInfo );
  3711. PAGED_CODE();
  3712. DebugTrace( +1, Dbg, ("NtfsOpenFcbById: Entered\n") );
  3713. //
  3714. // The next thing to do is to figure out what type
  3715. // of attribute the caller is trying to open. This involves the
  3716. // directory/non-directory bits, the attribute name and code strings,
  3717. // the type of file, whether he passed in an ea buffer and whether
  3718. // there was a trailing backslash.
  3719. //
  3720. if (NtfsEqualMftRef( &FileReference,
  3721. &VolumeFileReference )) {
  3722. if (AttrName.Length != 0
  3723. || AttrCodeName.Length != 0) {
  3724. Status = STATUS_INVALID_PARAMETER;
  3725. DebugTrace( -1, Dbg, ("NtfsOpenFcbById: Exit -> %08lx\n", Status) );
  3726. return Status;
  3727. }
  3728. SetFlag( IrpContext->State,
  3729. IRP_CONTEXT_STATE_ACQUIRE_EX | IRP_CONTEXT_STATE_DASD_OPEN );
  3730. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  3731. }
  3732. //
  3733. // Use a try-finally to facilitate cleanup.
  3734. //
  3735. try {
  3736. //
  3737. // If we don't already have the Fcb then look up the file record
  3738. // from the disk.
  3739. //
  3740. if (!UseCurrentFcb) {
  3741. //
  3742. // We start by reading the disk and checking that the file record
  3743. // sequence number matches and that the file record is in use.
  3744. // We remember whether this is a directory. We will only go to
  3745. // the file if the file Id will lie within the Mft File.
  3746. //
  3747. MftOffset = NtfsFullSegmentNumber( &FileReference );
  3748. MftOffset = Int64ShllMod32(MftOffset, Vcb->MftShift);
  3749. //
  3750. // Make sure we are serialized with access to the Mft. Otherwise
  3751. // someone else could be deleting the file as we speak.
  3752. //
  3753. NtfsAcquireSharedFcb( IrpContext, Vcb->MftScb->Fcb, NULL, 0 );
  3754. AcquiredMft = TRUE;
  3755. if (MftOffset >= Vcb->MftScb->Header.FileSize.QuadPart) {
  3756. DebugTrace( 0, Dbg, ("File Id doesn't lie within Mft\n") );
  3757. try_return( Status = STATUS_INVALID_PARAMETER );
  3758. }
  3759. NtfsReadMftRecord( IrpContext,
  3760. Vcb,
  3761. &FileReference,
  3762. FALSE,
  3763. &Bcb,
  3764. &FileRecord,
  3765. NULL );
  3766. //
  3767. // This file record better be in use, have a matching sequence number and
  3768. // be the primary file record for this file.
  3769. //
  3770. if ((FileRecord->SequenceNumber != FileReference.SequenceNumber) ||
  3771. !FlagOn( FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE ) ||
  3772. (*((PLONGLONG) &FileRecord->BaseFileRecordSegment) != 0) ||
  3773. (*((PULONG) FileRecord->MultiSectorHeader.Signature) != *((PULONG) FileSignature))) {
  3774. try_return( Status = STATUS_INVALID_PARAMETER );
  3775. }
  3776. //
  3777. // If indexed then use the name for the file name index.
  3778. //
  3779. if (FlagOn( FileRecord->Flags, FILE_FILE_NAME_INDEX_PRESENT )) {
  3780. AttrName = NtfsFileNameIndex;
  3781. AttrCodeName = NtfsIndexAllocation;
  3782. }
  3783. NtfsUnpinBcb( IrpContext, &Bcb );
  3784. } else {
  3785. ThisFcb = *CurrentFcb;
  3786. ExistingFcb = TRUE;
  3787. }
  3788. Status = NtfsCheckValidAttributeAccess( IrpSp,
  3789. Vcb,
  3790. ExistingFcb ? &ThisFcb->Info : NULL,
  3791. &AttrName,
  3792. AttrCodeName,
  3793. 0, // no flags
  3794. &AttrTypeCode,
  3795. &CcbFlags,
  3796. &IndexedAttribute );
  3797. if (!NT_SUCCESS( Status )) {
  3798. try_return( Status );
  3799. }
  3800. //
  3801. // If we don't have an Fcb then create one now.
  3802. //
  3803. if (!UseCurrentFcb) {
  3804. NtfsAcquireFcbTable( IrpContext, Vcb );
  3805. AcquiredFcbTable = TRUE;
  3806. //
  3807. // We know that it is safe to continue the open. We start by creating
  3808. // an Fcb for this file. It is possible that the Fcb exists.
  3809. // We create the Fcb first, if we need to update the Fcb info structure
  3810. // we copy the one from the index entry. We look at the Fcb to discover
  3811. // if it has any links, if it does then we make this the last Fcb we
  3812. // reached. If it doesn't then we have to clean it up from here.
  3813. //
  3814. ThisFcb = NtfsCreateFcb( IrpContext,
  3815. Vcb,
  3816. FileReference,
  3817. BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ),
  3818. TRUE,
  3819. &ExistingFcb );
  3820. ThisFcb->ReferenceCount += 1;
  3821. //
  3822. // Try to do a fast acquire, otherwise we need to release
  3823. // the Fcb table, acquire the Fcb, acquire the Fcb table to
  3824. // dereference Fcb. This should only be the case if the Fcb already
  3825. // existed. In that case all of the flags indicating whether it
  3826. // has been deleted will be valid when we reacquire it. We don't
  3827. // have to worry about Mft synchronization.
  3828. //
  3829. if (!NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, ACQUIRE_DONT_WAIT )) {
  3830. NtfsReleaseFcbTable( IrpContext, Vcb );
  3831. NtfsReleaseFcb( IrpContext, Vcb->MftScb->Fcb );
  3832. AcquiredMft = FALSE;
  3833. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  3834. NtfsAcquireFcbTable( IrpContext, Vcb );
  3835. } else {
  3836. NtfsReleaseFcb( IrpContext, Vcb->MftScb->Fcb );
  3837. AcquiredMft = FALSE;
  3838. }
  3839. ThisFcb->ReferenceCount -= 1;
  3840. NtfsReleaseFcbTable( IrpContext, Vcb );
  3841. AcquiredFcbTable = FALSE;
  3842. //
  3843. // Store this Fcb into our caller's parameter and remember to
  3844. // to show we acquired it.
  3845. //
  3846. *CurrentFcb = ThisFcb;
  3847. }
  3848. //
  3849. // We perform a check to see whether we will allow the system
  3850. // files to be opened.
  3851. //
  3852. // No test to make if this is not a system file or it is the VolumeDasd file.
  3853. // The ACL will protect the volume file.
  3854. //
  3855. if (FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE ) &&
  3856. (NtfsSegmentNumber( &ThisFcb->FileReference ) != VOLUME_DASD_NUMBER) &&
  3857. NtfsProtectSystemFiles) {
  3858. if (!NtfsCheckValidFileAccess( ThisFcb, IrpSp )) {
  3859. Status = STATUS_ACCESS_DENIED;
  3860. DebugTrace( 0, Dbg, ("Invalid access to system files\n") );
  3861. try_return( NOTHING );
  3862. }
  3863. }
  3864. //
  3865. // If the Fcb existed and this is a paging file then either return
  3866. // sharing violation or force the Fcb and Scb's to go away.
  3867. // Do this for the case where the user is opening a paging file
  3868. // but the Fcb is non-paged or the user is opening a non-paging
  3869. // file and the Fcb is for a paging file.
  3870. //
  3871. if (ExistingFcb &&
  3872. ((FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  3873. !FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) ||
  3874. (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  3875. !FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )))) {
  3876. if (ThisFcb->CleanupCount != 0) {
  3877. try_return( Status = STATUS_SHARING_VIOLATION );
  3878. //
  3879. // If we have a persistent paging file then give up and
  3880. // return SHARING_VIOLATION.
  3881. //
  3882. } else if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP )) {
  3883. try_return( Status = STATUS_SHARING_VIOLATION );
  3884. //
  3885. // If there was an existing Fcb for a paging file we need to force
  3886. // all of the Scb's to be torn down. The easiest way to do this
  3887. // is to flush and purge all of the Scb's (saving any attribute list
  3888. // for last) and then raise LOG_FILE_FULL to allow this request to
  3889. // be posted.
  3890. //
  3891. } else {
  3892. //
  3893. // Reference the Fcb so it doesn't go away.
  3894. //
  3895. InterlockedIncrement( &ThisFcb->CloseCount );
  3896. DecrementCloseCount = TRUE;
  3897. //
  3898. // Flush and purge this Fcb.
  3899. //
  3900. NtfsFlushAndPurgeFcb( IrpContext, ThisFcb );
  3901. InterlockedDecrement( &ThisFcb->CloseCount );
  3902. DecrementCloseCount = FALSE;
  3903. //
  3904. // Force this request to be posted and then raise
  3905. // CANT_WAIT.
  3906. //
  3907. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  3908. //
  3909. // If we are posting then we may want to use the next stack location.
  3910. //
  3911. if (IrpContext->Union.OplockCleanup->CompletionContext != NULL) {
  3912. NtfsPrepareForIrpCompletion( IrpContext, IrpContext->OriginatingIrp, IrpContext->Union.OplockCleanup->CompletionContext );
  3913. IrpContext->Union.OplockCleanup->CompletionContext = NULL;
  3914. }
  3915. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  3916. }
  3917. }
  3918. //
  3919. // If the Fcb Info field needs to be initialized, we do so now.
  3920. // We read this information from the disk.
  3921. //
  3922. if (!FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  3923. HaveScbSizes = NtfsUpdateFcbInfoFromDisk( IrpContext,
  3924. TRUE,
  3925. ThisFcb,
  3926. &ScbSizes );
  3927. //
  3928. // Fix the quota for this file if necessary.
  3929. //
  3930. NtfsConditionallyFixupQuota( IrpContext, ThisFcb );
  3931. }
  3932. //
  3933. // Now that we have the dup info off disk recheck the create options
  3934. //
  3935. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE ) &&
  3936. !IsViewIndex( &ThisFcb->Info ) &&
  3937. !IsDirectory( &ThisFcb->Info )) {
  3938. NtfsRaiseStatus( IrpContext, STATUS_NOT_A_DIRECTORY, NULL, NULL );
  3939. }
  3940. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE ) &&
  3941. (IsViewIndex( &ThisFcb->Info ) || IsDirectory( &ThisFcb->Info ))) {
  3942. NtfsRaiseStatus( IrpContext, STATUS_FILE_IS_A_DIRECTORY, NULL, NULL );
  3943. }
  3944. //
  3945. // If the link count is zero on this Fcb, then delete is pending. Otherwise
  3946. // this might be an unused system file.
  3947. //
  3948. if (ThisFcb->LinkCount == 0) {
  3949. if (NtfsSegmentNumber( &ThisFcb->FileReference ) >= FIRST_USER_FILE_NUMBER) {
  3950. try_return( Status = STATUS_DELETE_PENDING );
  3951. } else {
  3952. try_return( Status = STATUS_INVALID_PARAMETER );
  3953. }
  3954. }
  3955. //
  3956. // Make sure we acquire the parent directory now, before we do anything
  3957. // that might cause us to acquire the quota mutex. If the caller only
  3958. // wants to open an existing file, we can skip this.
  3959. //
  3960. if (CreateDisposition != FILE_OPEN) {
  3961. NtfsPrepareForUpdateDuplicate( IrpContext, ThisFcb, &Lcb, &ParentScb, FALSE );
  3962. PreparedForUpdateDuplicate = TRUE;
  3963. }
  3964. //
  3965. // We now call the worker routine to open an attribute on an existing file.
  3966. //
  3967. Status = NtfsOpenAttributeInExistingFile( IrpContext,
  3968. Irp,
  3969. IrpSp,
  3970. ParentLcb,
  3971. ThisFcb,
  3972. 0,
  3973. AttrName,
  3974. AttrTypeCode,
  3975. CcbFlags,
  3976. CREATE_FLAG_OPEN_BY_ID,
  3977. NULL,
  3978. ThisScb,
  3979. ThisCcb );
  3980. //
  3981. // Check to see if we should update the last access time.
  3982. // We skip this for reparse points as *ThisScb and *ThisCcb may be NULL.
  3983. //
  3984. if (NT_SUCCESS( Status ) &&
  3985. (Status != STATUS_PENDING) &&
  3986. (Status != STATUS_REPARSE)) {
  3987. PSCB Scb = *ThisScb;
  3988. //
  3989. // Now look at whether we need to update the Fcb and on disk
  3990. // structures.
  3991. //
  3992. if (NtfsCheckLastAccess( IrpContext, ThisFcb )) {
  3993. SetFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  3994. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_LAST_ACCESS );
  3995. }
  3996. //
  3997. // Perform the last bit of work. If this a user file open, we need
  3998. // to check if we initialize the Scb.
  3999. //
  4000. if (!IndexedAttribute) {
  4001. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  4002. //
  4003. // We may have the sizes from our Fcb update call.
  4004. //
  4005. if (HaveScbSizes &&
  4006. (AttrTypeCode == $DATA) &&
  4007. (AttrName.Length == 0) &&
  4008. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB )) {
  4009. NtfsUpdateScbFromMemory( Scb, &ScbSizes );
  4010. } else {
  4011. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  4012. }
  4013. }
  4014. //
  4015. // Let's check if we need to set the cache bit.
  4016. //
  4017. if (!FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
  4018. SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
  4019. }
  4020. }
  4021. //
  4022. // If everything has gone well so far, we may want to call the
  4023. // encryption callback if one is registered. We do not do
  4024. // this for network opens or reparse points. We have to pass
  4025. // FILE_EXISTING since we have no parent directory and the
  4026. // encryption callback needs a parent directory to handle a
  4027. // new file create.
  4028. //
  4029. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  4030. NtfsEncryptionCreateCallback( IrpContext,
  4031. Irp,
  4032. IrpSp,
  4033. *ThisScb,
  4034. *ThisCcb,
  4035. ThisFcb,
  4036. NULL,
  4037. FALSE );
  4038. }
  4039. //
  4040. // If this operation was a supersede/overwrite or we created a new
  4041. // attribute stream then we want to perform the file record and
  4042. // directory update now. Otherwise we will defer the updates until
  4043. // the user closes his handle.
  4044. //
  4045. if (NtfsIsStreamNew(Irp->IoStatus.Information)) {
  4046. NtfsUpdateScbFromFileObject( IrpContext, IrpSp->FileObject, *ThisScb, TRUE );
  4047. //
  4048. // Do the standard information, file sizes and then duplicate information
  4049. // if needed.
  4050. //
  4051. if (FlagOn( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  4052. NtfsUpdateStandardInformation( IrpContext, ThisFcb );
  4053. }
  4054. if (FlagOn( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE )) {
  4055. NtfsWriteFileSizes( IrpContext,
  4056. *ThisScb,
  4057. &(*ThisScb)->Header.ValidDataLength.QuadPart,
  4058. FALSE,
  4059. TRUE,
  4060. FALSE );
  4061. }
  4062. if (FlagOn( ThisFcb->InfoFlags, FCB_INFO_DUPLICATE_FLAGS )) {
  4063. ASSERT( PreparedForUpdateDuplicate );
  4064. NtfsUpdateDuplicateInfo( IrpContext, ThisFcb, NULL, NULL );
  4065. NtfsUpdateLcbDuplicateInfo( ThisFcb, Lcb );
  4066. ThisFcb->InfoFlags = 0;
  4067. }
  4068. ClearFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  4069. NtfsAcquireFsrtlHeader( *ThisScb );
  4070. ClearFlag( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
  4071. NtfsReleaseFsrtlHeader( *ThisScb );
  4072. }
  4073. }
  4074. try_exit: NOTHING;
  4075. } finally {
  4076. DebugUnwind( NtfsOpenFcbById );
  4077. if (AcquiredFcbTable) {
  4078. NtfsReleaseFcbTable( IrpContext, Vcb );
  4079. }
  4080. if (AcquiredMft) {
  4081. NtfsReleaseFcb( IrpContext, Vcb->MftScb->Fcb );
  4082. }
  4083. //
  4084. // If this operation was not totally successful we need to
  4085. // back out the following changes.
  4086. //
  4087. // Modifications to the Info fields in the Fcb.
  4088. // Any changes to the allocation of the Scb.
  4089. // Any changes in the open counts in the various structures.
  4090. // Changes to the share access values in the Fcb.
  4091. //
  4092. if (!NT_SUCCESS( Status ) || AbnormalTermination()) {
  4093. NtfsBackoutFailedOpens( IrpContext,
  4094. IrpSp->FileObject,
  4095. ThisFcb,
  4096. *ThisScb,
  4097. *ThisCcb );
  4098. }
  4099. if (DecrementCloseCount) {
  4100. InterlockedDecrement( &ThisFcb->CloseCount );
  4101. }
  4102. NtfsUnpinBcb( IrpContext, &Bcb );
  4103. DebugTrace( -1, Dbg, ("NtfsOpenFcbById: Exit -> %08lx\n", Status) );
  4104. }
  4105. return Status;
  4106. }
  4107. //
  4108. // Local support routine
  4109. //
  4110. NTSTATUS
  4111. NtfsOpenExistingPrefixFcb (
  4112. IN PIRP_CONTEXT IrpContext,
  4113. IN PIRP Irp,
  4114. IN PIO_STACK_LOCATION IrpSp,
  4115. IN PFCB ThisFcb,
  4116. IN PLCB Lcb OPTIONAL,
  4117. IN ULONG FullPathNameLength,
  4118. IN UNICODE_STRING AttrName,
  4119. IN UNICODE_STRING AttrCodeName,
  4120. IN ULONG CreateFlags,
  4121. IN PVOID NetworkInfo OPTIONAL,
  4122. IN PCREATE_CONTEXT CreateContext,
  4123. OUT PSCB *ThisScb,
  4124. OUT PCCB *ThisCcb
  4125. )
  4126. /*++
  4127. Routine Description:
  4128. This routine will open an attribute in a file whose Fcb was found
  4129. with a prefix search.
  4130. Arguments:
  4131. Irp - This is the Irp for this open operation.
  4132. IrpSp - This is the Irp stack pointer for the filesystem.
  4133. ThisFcb - This is the Fcb to open.
  4134. Lcb - This is the Lcb used to reach this Fcb. Not specified if this is a volume open.
  4135. FullPathNameLength - This is the length of the full path name.
  4136. AttrName - This is the name of the attribute to open.
  4137. AttrCodeName - This is the name of the attribute code to open.
  4138. CreateFlags - Flags for create operation - we care about the dos only component and trailing back slash
  4139. flag
  4140. NetworkInfo - If specified then this call is a fast open call to query
  4141. the network information. We don't update any of the in-memory structures
  4142. for this.
  4143. CreateContext - Context with create variables.
  4144. ThisScb - This is the address to store the Scb from this open.
  4145. ThisCcb - This is the address to store the Ccb from this open.
  4146. Return Value:
  4147. NTSTATUS - Indicates the result of this attribute based operation.
  4148. --*/
  4149. {
  4150. NTSTATUS Status = STATUS_SUCCESS;
  4151. ATTRIBUTE_TYPE_CODE AttrTypeCode;
  4152. ULONG CcbFlags;
  4153. BOOLEAN IndexedAttribute;
  4154. BOOLEAN DecrementCloseCount = FALSE;
  4155. ULONG LastFileNameOffset;
  4156. OLD_SCB_SNAPSHOT ScbSizes;
  4157. BOOLEAN HaveScbSizes = FALSE;
  4158. ULONG CreateDisposition;
  4159. PSCB ParentScb = NULL;
  4160. PFCB ParentFcb = NULL;
  4161. BOOLEAN AcquiredParentScb = FALSE;
  4162. PAGED_CODE();
  4163. DebugTrace( +1, Dbg, ("NtfsOpenExistingPrefixFcb: Entered\n") );
  4164. if (FlagOn( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT )) {
  4165. CcbFlags = CCB_FLAG_PARENT_HAS_DOS_COMPONENT;
  4166. } else {
  4167. CcbFlags = 0;
  4168. }
  4169. //
  4170. // The first thing to do is to figure out what type
  4171. // of attribute the caller is trying to open. This involves the
  4172. // directory/non-directory bits, the attribute name and code strings,
  4173. // the type of file, whether he passed in an ea buffer and whether
  4174. // there was a trailing backslash.
  4175. //
  4176. if (NtfsEqualMftRef( &ThisFcb->FileReference, &VolumeFileReference )) {
  4177. if ((AttrName.Length != 0) || (AttrCodeName.Length != 0)) {
  4178. Status = STATUS_INVALID_PARAMETER;
  4179. DebugTrace( -1, Dbg, ("NtfsOpenExistingPrefixFcb: Exit -> %08lx\n", Status) );
  4180. return Status;
  4181. }
  4182. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_ACQUIRE_EX | IRP_CONTEXT_STATE_DASD_OPEN );
  4183. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  4184. }
  4185. ParentScb = Lcb->Scb;
  4186. LastFileNameOffset = FullPathNameLength - Lcb->ExactCaseLink.LinkName.Length;
  4187. if (ParentScb != NULL) {
  4188. ParentFcb = ParentScb->Fcb;
  4189. }
  4190. Status = NtfsCheckValidAttributeAccess( IrpSp,
  4191. ThisFcb->Vcb,
  4192. &ThisFcb->Info,
  4193. &AttrName,
  4194. AttrCodeName,
  4195. CreateFlags,
  4196. &AttrTypeCode,
  4197. &CcbFlags,
  4198. &IndexedAttribute );
  4199. if (!NT_SUCCESS( Status )) {
  4200. DebugTrace( -1, Dbg, ("NtfsOpenExistingPrefixFcb: Exit -> %08lx\n", Status) );
  4201. return Status;
  4202. }
  4203. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  4204. //
  4205. // Use a try-finally to facilitate cleanup.
  4206. //
  4207. try {
  4208. //
  4209. // If the Fcb existed and this is a paging file then either return
  4210. // sharing violation or force the Fcb and Scb's to go away.
  4211. // Do this for the case where the user is opening a paging file
  4212. // but the Fcb is non-paged or the user is opening a non-paging
  4213. // file and the Fcb is for a paging file.
  4214. //
  4215. if ((FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  4216. !FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) ||
  4217. (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  4218. !FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ))) {
  4219. if (ThisFcb->CleanupCount != 0) {
  4220. try_return( Status = STATUS_SHARING_VIOLATION );
  4221. //
  4222. // If we have a persistent paging file then give up and
  4223. // return SHARING_VIOLATION.
  4224. //
  4225. } else if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP )) {
  4226. try_return( Status = STATUS_SHARING_VIOLATION );
  4227. //
  4228. // If there was an existing Fcb for a paging file we need to force
  4229. // all of the Scb's to be torn down. The easiest way to do this
  4230. // is to flush and purge all of the Scb's (saving any attribute list
  4231. // for last) and then raise LOG_FILE_FULL to allow this request to
  4232. // be posted.
  4233. //
  4234. } else {
  4235. //
  4236. // Make sure this Fcb won't go away as a result of purging
  4237. // the Fcb.
  4238. //
  4239. InterlockedIncrement( &ThisFcb->CloseCount );
  4240. DecrementCloseCount = TRUE;
  4241. //
  4242. // Flush and purge this Fcb.
  4243. //
  4244. NtfsFlushAndPurgeFcb( IrpContext, ThisFcb );
  4245. //
  4246. // Now decrement the close count we have already biased.
  4247. //
  4248. InterlockedDecrement( &ThisFcb->CloseCount );
  4249. DecrementCloseCount = FALSE;
  4250. //
  4251. // Force this request to be posted and then raise
  4252. // CANT_WAIT.
  4253. //
  4254. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  4255. //
  4256. // If we are posting then we may want to use the next stack location.
  4257. //
  4258. if (IrpContext->Union.OplockCleanup->CompletionContext != NULL) {
  4259. NtfsPrepareForIrpCompletion( IrpContext,
  4260. IrpContext->OriginatingIrp,
  4261. IrpContext->Union.OplockCleanup->CompletionContext );
  4262. }
  4263. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  4264. }
  4265. }
  4266. //
  4267. // This file might have been recently created, and we might have dropped the
  4268. // Fcb to call the PostCreate encryption callout, so the encryption driver
  4269. // hasn't yet called us back to set the encryption bit on the file. If we're
  4270. // asked to open the file in this window, we would introduce corruption by
  4271. // writing plaintext now. Let's just raise cant_wait and try again later.
  4272. //
  4273. if (FlagOn( ThisFcb->FcbState, FCB_STATE_ENCRYPTION_PENDING )) {
  4274. #ifdef KEITHKA
  4275. EncryptionPendingCount += 1;
  4276. #endif
  4277. //
  4278. // Raise CANT_WAIT so we can wait on the encryption event at the top.
  4279. //
  4280. SetFlag( IrpContext->State, IRP_CONTEXT_STATE_ENCRYPTION_RETRY );
  4281. //
  4282. // Clear the pending event so we can wait for it when we retry.
  4283. //
  4284. KeClearEvent( &NtfsEncryptionPendingEvent );
  4285. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  4286. }
  4287. //
  4288. // If this is a directory, it's possible that we hav an existing Fcb
  4289. // in the prefix table which needs to be initialized from the disk.
  4290. // We look in the InfoInitialized flag to know whether to go to
  4291. // disk.
  4292. //
  4293. if (!FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  4294. //
  4295. // If we have a parent Fcb then make sure to acquire it.
  4296. //
  4297. if (ParentScb != NULL) {
  4298. NtfsAcquireExclusiveScb( IrpContext, ParentScb );
  4299. AcquiredParentScb = TRUE;
  4300. }
  4301. HaveScbSizes = NtfsUpdateFcbInfoFromDisk( IrpContext,
  4302. TRUE,
  4303. ThisFcb,
  4304. &ScbSizes );
  4305. NtfsConditionallyFixupQuota( IrpContext, ThisFcb );
  4306. }
  4307. //
  4308. // Check now whether we will need to acquire the parent to
  4309. // perform a update duplicate info. We need to acquire it
  4310. // now to enforce our locking order in case any of the
  4311. // routines below acquire the Mft Scb. Acquire it if we
  4312. // are doing a supersede/overwrite or possibly creating
  4313. // a named data stream.
  4314. //
  4315. if ((CreateDisposition == FILE_SUPERSEDE) ||
  4316. (CreateDisposition == FILE_OVERWRITE) ||
  4317. (CreateDisposition == FILE_OVERWRITE_IF) ||
  4318. ((AttrName.Length != 0) &&
  4319. ((CreateDisposition == FILE_OPEN_IF) ||
  4320. (CreateDisposition == FILE_CREATE)))) {
  4321. NtfsPrepareForUpdateDuplicate( IrpContext,
  4322. ThisFcb,
  4323. &Lcb,
  4324. &ParentScb,
  4325. FALSE );
  4326. }
  4327. //
  4328. // Call to open an attribute on an existing file.
  4329. // Remember we need to restore the Fcb info structure
  4330. // on errors.
  4331. //
  4332. Status = NtfsOpenAttributeInExistingFile( IrpContext,
  4333. Irp,
  4334. IrpSp,
  4335. Lcb,
  4336. ThisFcb,
  4337. LastFileNameOffset,
  4338. AttrName,
  4339. AttrTypeCode,
  4340. CcbFlags,
  4341. CreateFlags,
  4342. NetworkInfo,
  4343. ThisScb,
  4344. ThisCcb );
  4345. //
  4346. // Check to see if we should update the last access time.
  4347. // We skip this for reparse points as *ThisScb and *ThisCcb may be NULL.
  4348. //
  4349. if (NT_SUCCESS( Status ) &&
  4350. (Status != STATUS_PENDING) &&
  4351. (Status != STATUS_REPARSE)) {
  4352. PSCB Scb = *ThisScb;
  4353. //
  4354. // This is a rare case. There must have been an allocation failure
  4355. // to cause this but make sure the normalized name is stored.
  4356. //
  4357. if ((SafeNodeType( Scb ) == NTFS_NTC_SCB_INDEX) &&
  4358. (Scb->ScbType.Index.NormalizedName.Length == 0)) {
  4359. //
  4360. // We may be able to use the parent.
  4361. //
  4362. if ((ParentScb != NULL) &&
  4363. (ParentScb->ScbType.Index.NormalizedName.Length != 0)) {
  4364. NtfsUpdateNormalizedName( IrpContext,
  4365. ParentScb,
  4366. Scb,
  4367. NULL,
  4368. FALSE );
  4369. } else {
  4370. NtfsBuildNormalizedName( IrpContext,
  4371. Scb->Fcb,
  4372. Scb,
  4373. &Scb->ScbType.Index.NormalizedName );
  4374. }
  4375. }
  4376. //
  4377. // Perform the last bit of work. If this a user file open, we need
  4378. // to check if we initialize the Scb.
  4379. //
  4380. if (!IndexedAttribute) {
  4381. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  4382. //
  4383. // We may have the sizes from our Fcb update call.
  4384. //
  4385. if (HaveScbSizes &&
  4386. (AttrTypeCode == $DATA) &&
  4387. (AttrName.Length == 0) &&
  4388. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB )) {
  4389. NtfsUpdateScbFromMemory( Scb, &ScbSizes );
  4390. } else {
  4391. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  4392. }
  4393. }
  4394. //
  4395. // Let's check if we need to set the cache bit.
  4396. //
  4397. if (!FlagOn( IrpSp->Parameters.Create.Options,
  4398. FILE_NO_INTERMEDIATE_BUFFERING )) {
  4399. SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
  4400. }
  4401. }
  4402. //
  4403. // If this is the paging file, we want to be sure the allocation
  4404. // is loaded.
  4405. //
  4406. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )
  4407. && (Scb->Header.AllocationSize.QuadPart != 0)
  4408. && !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  4409. LCN Lcn;
  4410. VCN Vcn;
  4411. VCN AllocatedVcns;
  4412. AllocatedVcns = Int64ShraMod32(Scb->Header.AllocationSize.QuadPart, Scb->Vcb->ClusterShift);
  4413. //
  4414. // First make sure the Mcb is loaded.
  4415. //
  4416. NtfsPreloadAllocation( IrpContext, Scb, 0, AllocatedVcns );
  4417. //
  4418. // Now make sure the allocation is correctly loaded. The last
  4419. // Vcn should correspond to the allocation size for the file.
  4420. //
  4421. if (!NtfsLookupLastNtfsMcbEntry( &Scb->Mcb,
  4422. &Vcn,
  4423. &Lcn ) ||
  4424. (Vcn + 1) != AllocatedVcns) {
  4425. NtfsRaiseStatus( IrpContext,
  4426. STATUS_FILE_CORRUPT_ERROR,
  4427. NULL,
  4428. ThisFcb );
  4429. }
  4430. }
  4431. //
  4432. // If this open is for an executable image we will want to update the
  4433. // last access time.
  4434. //
  4435. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, FILE_EXECUTE ) &&
  4436. (Scb->AttributeTypeCode == $DATA)) {
  4437. SetFlag( IrpSp->FileObject->Flags, FO_FILE_FAST_IO_READ );
  4438. }
  4439. //
  4440. // If everything has gone well so far, we may want to call the
  4441. // encryption callback if one is registered. We do not do
  4442. // this for network opens or reparse points.
  4443. //
  4444. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  4445. NtfsEncryptionCreateCallback( IrpContext,
  4446. Irp,
  4447. IrpSp,
  4448. *ThisScb,
  4449. *ThisCcb,
  4450. ThisFcb,
  4451. ParentFcb,
  4452. FALSE );
  4453. }
  4454. //
  4455. // Check if should insert the hash entry.
  4456. //
  4457. if ((CreateContext->FileHashLength != 0) &&
  4458. !FlagOn( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  4459. (Lcb->FileNameAttr->Flags != FILE_NAME_DOS) ) {
  4460. //
  4461. // Remove any exising hash value.
  4462. //
  4463. if (FlagOn( Lcb->LcbState, LCB_STATE_VALID_HASH_VALUE )) {
  4464. NtfsRemoveHashEntriesForLcb( Lcb );
  4465. #ifdef NTFS_HASH_DATA
  4466. ThisFcb->Vcb->HashTable.OpenExistingConflict += 1;
  4467. #endif
  4468. }
  4469. NtfsInsertHashEntry( &ThisFcb->Vcb->HashTable,
  4470. Lcb,
  4471. CreateContext->FileHashLength,
  4472. CreateContext->FileHashValue );
  4473. #ifdef NTFS_HASH_DATA
  4474. ThisFcb->Vcb->HashTable.OpenExistingInsert += 1;
  4475. #endif
  4476. }
  4477. //
  4478. // Check if should insert the hash entry.
  4479. //
  4480. if ((CreateContext->FileHashLength != 0) &&
  4481. !FlagOn( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  4482. (Lcb->FileNameAttr->Flags != FILE_NAME_DOS) ) {
  4483. //
  4484. // Remove any exising hash value.
  4485. //
  4486. if (FlagOn( Lcb->LcbState, LCB_STATE_VALID_HASH_VALUE )) {
  4487. NtfsRemoveHashEntriesForLcb( Lcb );
  4488. #ifdef NTFS_HASH_DATA
  4489. ThisFcb->Vcb->HashTable.OpenExistingConflict += 1;
  4490. #endif
  4491. }
  4492. NtfsInsertHashEntry( &ThisFcb->Vcb->HashTable,
  4493. Lcb,
  4494. CreateContext->FileHashLength,
  4495. CreateContext->FileHashValue );
  4496. #ifdef NTFS_HASH_DATA
  4497. ThisFcb->Vcb->HashTable.OpenExistingInsert += 1;
  4498. #endif
  4499. }
  4500. //
  4501. // If this operation was a supersede/overwrite or we created a new
  4502. // attribute stream then we want to perform the file record and
  4503. // directory update now. Otherwise we will defer the updates until
  4504. // the user closes his handle.
  4505. //
  4506. if (NtfsIsStreamNew(Irp->IoStatus.Information)) {
  4507. NtfsUpdateScbFromFileObject( IrpContext, IrpSp->FileObject, *ThisScb, TRUE );
  4508. //
  4509. // Do the standard information, file sizes and then duplicate information
  4510. // if needed.
  4511. //
  4512. if (FlagOn( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  4513. NtfsUpdateStandardInformation( IrpContext, ThisFcb );
  4514. }
  4515. if (FlagOn( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE )) {
  4516. NtfsWriteFileSizes( IrpContext,
  4517. *ThisScb,
  4518. &(*ThisScb)->Header.ValidDataLength.QuadPart,
  4519. FALSE,
  4520. TRUE,
  4521. FALSE );
  4522. }
  4523. if (FlagOn( ThisFcb->InfoFlags, FCB_INFO_DUPLICATE_FLAGS )) {
  4524. ULONG FilterMatch;
  4525. NtfsUpdateDuplicateInfo( IrpContext, ThisFcb, Lcb, ParentScb );
  4526. if (ThisFcb->Vcb->NotifyCount != 0) {
  4527. //
  4528. // We map the Fcb info flags into the dir notify flags.
  4529. //
  4530. FilterMatch = NtfsBuildDirNotifyFilter( IrpContext,
  4531. ThisFcb->InfoFlags | Lcb->InfoFlags );
  4532. //
  4533. // If the filter match is non-zero, that means we also need to do a
  4534. // dir notify call.
  4535. //
  4536. if ((FilterMatch != 0) && (*ThisCcb != NULL)) {
  4537. NtfsReportDirNotify( IrpContext,
  4538. ThisFcb->Vcb,
  4539. &(*ThisCcb)->FullFileName,
  4540. (*ThisCcb)->LastFileNameOffset,
  4541. NULL,
  4542. ((FlagOn( (*ThisCcb)->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  4543. (*ThisCcb)->Lcb != NULL &&
  4544. (*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0) ?
  4545. &(*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName :
  4546. NULL),
  4547. FilterMatch,
  4548. FILE_ACTION_MODIFIED,
  4549. ParentFcb );
  4550. }
  4551. }
  4552. NtfsUpdateLcbDuplicateInfo( ThisFcb, Lcb );
  4553. ThisFcb->InfoFlags = 0;
  4554. }
  4555. ClearFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  4556. NtfsAcquireFsrtlHeader( *ThisScb );
  4557. ClearFlag( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
  4558. NtfsReleaseFsrtlHeader( *ThisScb );
  4559. }
  4560. }
  4561. try_exit: NOTHING;
  4562. } finally {
  4563. DebugUnwind( NtfsOpenExistingPrefixFcb );
  4564. if (DecrementCloseCount) {
  4565. InterlockedDecrement( &ThisFcb->CloseCount );
  4566. }
  4567. //
  4568. // If this operation was not totally successful we need to
  4569. // back out the following changes.
  4570. //
  4571. // Modifications to the Info fields in the Fcb.
  4572. // Any changes to the allocation of the Scb.
  4573. // Any changes in the open counts in the various structures.
  4574. // Changes to the share access values in the Fcb.
  4575. //
  4576. if (!NT_SUCCESS( Status ) || AbnormalTermination()) {
  4577. NtfsBackoutFailedOpens( IrpContext,
  4578. IrpSp->FileObject,
  4579. ThisFcb,
  4580. *ThisScb,
  4581. *ThisCcb );
  4582. }
  4583. DebugTrace( -1, Dbg, ("NtfsOpenExistingPrefixFcb: Exit -> %08lx\n", Status) );
  4584. }
  4585. return Status;
  4586. }
  4587. //
  4588. // Local support routine
  4589. //
  4590. NTSTATUS
  4591. NtfsOpenTargetDirectory (
  4592. IN PIRP_CONTEXT IrpContext,
  4593. IN PIRP Irp,
  4594. IN PIO_STACK_LOCATION IrpSp,
  4595. IN PFCB ThisFcb,
  4596. IN PLCB ParentLcb OPTIONAL,
  4597. IN OUT PUNICODE_STRING FullPathName,
  4598. IN ULONG FinalNameLength,
  4599. IN ULONG CreateFlags,
  4600. OUT PSCB *ThisScb,
  4601. OUT PCCB *ThisCcb
  4602. )
  4603. /*++
  4604. Routine Description:
  4605. This routine will perform the work of opening a target directory. When the
  4606. open is complete the Ccb and Lcb for this file object will be identical
  4607. to any other open. We store the full name for the rename in the
  4608. file object but set the 'Length' field to include only the
  4609. name upto the parent directory. We use the 'MaximumLength' field to
  4610. indicate the full name.
  4611. Arguments:
  4612. Irp - This is the Irp for this create operation.
  4613. IrpSp - This is the Irp stack pointer for the filesystem.
  4614. ThisFcb - This is the Fcb for the directory to open.
  4615. ParentLcb - This is the Lcb used to reach the parent directory. If not
  4616. specified, we will have to find it here. There will be no Lcb to
  4617. find if this Fcb was opened by Id.
  4618. FullPathName - This is the normalized string for open operation. It now
  4619. contains the full name as it appears on the disk for this open path.
  4620. It may not reach all the way to the root if the relative file object
  4621. was opened by Id.
  4622. FinalNameLength - This is the length of the final component in the
  4623. full path name.
  4624. CreateFlags - Flags for create operation - we care about the dos only component flag
  4625. ThisScb - This is the address to store the Scb from this open.
  4626. ThisCcb - This is the address to store the Ccb from this open.
  4627. Return Value:
  4628. NTSTATUS - Indicating the outcome of opening this target directory.
  4629. --*/
  4630. {
  4631. NTSTATUS Status = STATUS_SUCCESS;
  4632. ULONG CcbFlags = CCB_FLAG_OPEN_AS_FILE;
  4633. PAGED_CODE();
  4634. DebugTrace( +1, Dbg, ("NtfsOpenTargetDirectory: Entered\n") );
  4635. if (FlagOn( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT )) {
  4636. SetFlag( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT );
  4637. }
  4638. //
  4639. // If the name doesn't begin with a backslash, remember this as
  4640. // an open by file ID.
  4641. //
  4642. if (FullPathName->Buffer[0] != L'\\') {
  4643. SetFlag( CcbFlags, CCB_FLAG_OPEN_BY_FILE_ID );
  4644. }
  4645. //
  4646. // Modify the full path name so that the Maximum length field describes
  4647. // the full name and the Length field describes the name for the
  4648. // parent.
  4649. //
  4650. FullPathName->MaximumLength = FullPathName->Length;
  4651. //
  4652. // If we don't have an Lcb, we will find it now. We look at each Lcb
  4653. // for the parent Fcb and find one which matches the component
  4654. // ahead of the last component of the full name.
  4655. //
  4656. FullPathName->Length -= (USHORT)FinalNameLength;
  4657. //
  4658. // If we are not at the root then subtract the bytes for the '\\'
  4659. // separator.
  4660. //
  4661. if (FullPathName->Length > sizeof( WCHAR )) {
  4662. FullPathName->Length -= sizeof( WCHAR );
  4663. }
  4664. if (!ARGUMENT_PRESENT( ParentLcb ) && (FullPathName->Length != 0)) {
  4665. PLIST_ENTRY Links;
  4666. PLCB NextLcb;
  4667. //
  4668. // If the length is two then the parent Lcb is the root Lcb.
  4669. //
  4670. if (FullPathName->Length == sizeof( WCHAR )
  4671. && FullPathName->Buffer[0] == L'\\') {
  4672. ParentLcb = (PLCB) ThisFcb->Vcb->RootLcb;
  4673. } else {
  4674. for (Links = ThisFcb->LcbQueue.Flink;
  4675. Links != &ThisFcb->LcbQueue;
  4676. Links = Links->Flink) {
  4677. SHORT NameOffset;
  4678. NextLcb = CONTAINING_RECORD( Links,
  4679. LCB,
  4680. FcbLinks );
  4681. NameOffset = (SHORT) FullPathName->Length - (SHORT) NextLcb->ExactCaseLink.LinkName.Length;
  4682. if (NameOffset >= 0) {
  4683. if (RtlEqualMemory( Add2Ptr( FullPathName->Buffer,
  4684. NameOffset ),
  4685. NextLcb->ExactCaseLink.LinkName.Buffer,
  4686. NextLcb->ExactCaseLink.LinkName.Length )) {
  4687. //
  4688. // We found a matching Lcb. Remember this and exit
  4689. // the loop.
  4690. //
  4691. ParentLcb = NextLcb;
  4692. break;
  4693. }
  4694. }
  4695. }
  4696. }
  4697. }
  4698. //
  4699. // Check this open for security access.
  4700. //
  4701. NtfsOpenCheck( IrpContext, ThisFcb, NULL, Irp );
  4702. //
  4703. // Now actually open the attribute.
  4704. //
  4705. Status = NtfsOpenAttribute( IrpContext,
  4706. IrpSp,
  4707. ThisFcb->Vcb,
  4708. ParentLcb,
  4709. ThisFcb,
  4710. (ARGUMENT_PRESENT( ParentLcb )
  4711. ? FullPathName->Length - ParentLcb->ExactCaseLink.LinkName.Length
  4712. : 0),
  4713. NtfsFileNameIndex,
  4714. $INDEX_ALLOCATION,
  4715. (ThisFcb->CleanupCount == 0 ? SetShareAccess : CheckShareAccess),
  4716. UserDirectoryOpen,
  4717. FALSE,
  4718. CcbFlags,
  4719. NULL,
  4720. ThisScb,
  4721. ThisCcb );
  4722. if (NT_SUCCESS( Status )) {
  4723. //
  4724. // If the Scb does not have a normalized name then update it now.
  4725. //
  4726. if ((*ThisScb)->ScbType.Index.NormalizedName.Length == 0) {
  4727. NtfsBuildNormalizedName( IrpContext,
  4728. (*ThisScb)->Fcb,
  4729. *ThisScb,
  4730. &(*ThisScb)->ScbType.Index.NormalizedName );
  4731. }
  4732. //
  4733. // If the file object name is not from the root then use the normalized name
  4734. // to obtain the full name.
  4735. //
  4736. if (FlagOn( CcbFlags, CCB_FLAG_OPEN_BY_FILE_ID )) {
  4737. USHORT BytesNeeded;
  4738. USHORT Index;
  4739. ULONG ComponentCount;
  4740. ULONG NormalizedComponentCount;
  4741. PWCHAR NewBuffer;
  4742. PWCHAR NextChar;
  4743. //
  4744. // Count the number of components in the directory portion of the
  4745. // name in the file object.
  4746. //
  4747. ComponentCount = 0;
  4748. if (FullPathName->Length != 0) {
  4749. ComponentCount = 1;
  4750. Index = (FullPathName->Length / sizeof( WCHAR )) - 1;
  4751. do {
  4752. if (FullPathName->Buffer[Index] == L'\\') {
  4753. ComponentCount += 1;
  4754. }
  4755. Index -= 1;
  4756. } while (Index != 0);
  4757. }
  4758. //
  4759. // Count back this number of components in the normalized name.
  4760. //
  4761. NormalizedComponentCount = 0;
  4762. Index = (*ThisScb)->ScbType.Index.NormalizedName.Length / sizeof( WCHAR );
  4763. //
  4764. // Special case the root to point directory to the leading backslash.
  4765. //
  4766. if (Index == 1) {
  4767. Index = 0;
  4768. }
  4769. while (NormalizedComponentCount < ComponentCount) {
  4770. Index -= 1;
  4771. while ((*ThisScb)->ScbType.Index.NormalizedName.Buffer[Index] != L'\\') {
  4772. Index -= 1;
  4773. }
  4774. NormalizedComponentCount += 1;
  4775. }
  4776. //
  4777. // Compute the size of the buffer needed for the full name. This
  4778. // will be:
  4779. //
  4780. // - Portion of normalized name used plus a separator
  4781. // - MaximumLength currently in FullPathName
  4782. //
  4783. BytesNeeded = (Index + 1) * sizeof( WCHAR );
  4784. if (MAXUSHORT - FullPathName->MaximumLength < BytesNeeded) {
  4785. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  4786. }
  4787. BytesNeeded += FullPathName->MaximumLength;
  4788. NextChar =
  4789. NewBuffer = NtfsAllocatePool( PagedPool, BytesNeeded );
  4790. //
  4791. // Copy over the portion of the name from the normalized name.
  4792. //
  4793. if (Index != 0) {
  4794. RtlCopyMemory( NextChar,
  4795. (*ThisScb)->ScbType.Index.NormalizedName.Buffer,
  4796. Index * sizeof( WCHAR ));
  4797. NextChar += Index;
  4798. }
  4799. *NextChar = L'\\';
  4800. NextChar += 1;
  4801. //
  4802. // Now copy over the remaining part of the name from the file object.
  4803. //
  4804. RtlCopyMemory( NextChar,
  4805. FullPathName->Buffer,
  4806. FullPathName->MaximumLength );
  4807. //
  4808. // Now free the pool from the file object and update with the newly
  4809. // allocated pool. Don't forget to update the Ccb to point to this new
  4810. // buffer.
  4811. //
  4812. NtfsFreePool( FullPathName->Buffer );
  4813. FullPathName->Buffer = NewBuffer;
  4814. FullPathName->MaximumLength =
  4815. FullPathName->Length = BytesNeeded;
  4816. FullPathName->Length -= (USHORT) FinalNameLength;
  4817. if (FullPathName->Length > sizeof( WCHAR )) {
  4818. FullPathName->Length -= sizeof( WCHAR );
  4819. }
  4820. (*ThisCcb)->FullFileName = *FullPathName;
  4821. (*ThisCcb)->LastFileNameOffset = FullPathName->MaximumLength - (USHORT) FinalNameLength;
  4822. }
  4823. Irp->IoStatus.Information = (FlagOn( CreateFlags, CREATE_FLAG_FOUND_ENTRY ) ? FILE_EXISTS : FILE_DOES_NOT_EXIST);
  4824. }
  4825. DebugTrace( -1, Dbg, ("NtfsOpenTargetDirectory: Exit -> %08lx\n", Status) );
  4826. return Status;
  4827. }
  4828. //
  4829. // Local support routine
  4830. //
  4831. NTSTATUS
  4832. NtfsOpenFile (
  4833. IN PIRP_CONTEXT IrpContext,
  4834. IN PIRP Irp,
  4835. IN PIO_STACK_LOCATION IrpSp,
  4836. IN PSCB ParentScb,
  4837. IN PINDEX_ENTRY IndexEntry,
  4838. IN UNICODE_STRING FullPathName,
  4839. IN UNICODE_STRING FinalName,
  4840. IN UNICODE_STRING AttrName,
  4841. IN UNICODE_STRING AttrCodeName,
  4842. IN PQUICK_INDEX QuickIndex,
  4843. IN ULONG CreateFlags,
  4844. IN PVOID NetworkInfo OPTIONAL,
  4845. IN PCREATE_CONTEXT CreateContext,
  4846. OUT PFCB *CurrentFcb,
  4847. OUT PLCB *LcbForTeardown,
  4848. OUT PSCB *ThisScb,
  4849. OUT PCCB *ThisCcb
  4850. )
  4851. /*++
  4852. Routine Description:
  4853. This routine is called when we need to open an attribute on a file
  4854. which currently exists. We have the ParentScb and the file reference
  4855. for the existing file. We will create the Fcb for this file and the
  4856. link between it and its parent directory. We will add this link to the
  4857. prefix table as well as the link for its parent Scb if specified.
  4858. On entry the caller owns the parent Scb.
  4859. Arguments:
  4860. Irp - This is the Irp for this open operation.
  4861. IrpSp - This is the Irp stack pointer for the filesystem.
  4862. ParentScb - This is the Scb for the parent directory.
  4863. IndexEntry - This is the index entry from the disk for this file.
  4864. FullPathName - This is the string containing the full path name of
  4865. this Fcb. Meaningless for an open by Id call.
  4866. FinalName - This is the string for the final component only. If the length
  4867. is zero then this is an open by Id call.
  4868. AttrName - This is the name of the attribute to open.
  4869. AttriCodeName - This is the name of the attribute code to open.
  4870. CreateFlags - Flags for create option - we use open by id / ignore case / trailing backslash and
  4871. dos only component
  4872. NetworkInfo - If specified then this call is a fast open call to query
  4873. the network information. We don't update any of the in-memory structures
  4874. for this.
  4875. CreateContext - Context with create variables.
  4876. CurrentFcb - This is the address to store the Fcb if we successfully find
  4877. one in the Fcb/Scb tree.
  4878. LcbForTeardown - This is the Lcb to use in teardown if we add an Lcb
  4879. into the tree.
  4880. ThisScb - This is the address to store the Scb from this open.
  4881. ThisCcb - This is the address to store the Ccb from this open.
  4882. Return Value:
  4883. NTSTATUS - Indicates the result of this create file operation.
  4884. --*/
  4885. {
  4886. NTSTATUS Status = STATUS_SUCCESS;
  4887. ATTRIBUTE_TYPE_CODE AttrTypeCode;
  4888. ULONG CcbFlags = 0;
  4889. BOOLEAN IndexedAttribute;
  4890. PFILE_NAME IndexFileName;
  4891. BOOLEAN UpdateFcbInfo = FALSE;
  4892. OLD_SCB_SNAPSHOT ScbSizes;
  4893. BOOLEAN HaveScbSizes = FALSE;
  4894. PVCB Vcb = ParentScb->Vcb;
  4895. PFCB LocalFcbForTeardown = NULL;
  4896. PFCB ThisFcb;
  4897. PLCB ThisLcb;
  4898. BOOLEAN DecrementCloseCount = FALSE;
  4899. BOOLEAN ExistingFcb;
  4900. BOOLEAN AcquiredFcbTable = FALSE;
  4901. FILE_REFERENCE PreviousFileReference;
  4902. BOOLEAN DroppedParent = FALSE;
  4903. PAGED_CODE();
  4904. DebugTrace( +1, Dbg, ("NtfsOpenFile: Entered\n") );
  4905. IndexFileName = (PFILE_NAME) NtfsFoundIndexEntry( IndexEntry );
  4906. if (FlagOn( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT )) {
  4907. SetFlag( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT );
  4908. }
  4909. //
  4910. // The first thing to do is to figure out what type
  4911. // of attribute the caller is trying to open. This involves the
  4912. // directory/non-directory bits, the attribute name and code strings,
  4913. // the type of file, whether he passed in an ea buffer and whether
  4914. // there was a trailing backslash.
  4915. //
  4916. if (NtfsEqualMftRef( &IndexEntry->FileReference,
  4917. &VolumeFileReference )) {
  4918. if (AttrName.Length != 0
  4919. || AttrCodeName.Length != 0) {
  4920. Status = STATUS_INVALID_PARAMETER;
  4921. DebugTrace( -1, Dbg, ("NtfsOpenFile: Exit -> %08lx\n", Status) );
  4922. return Status;
  4923. }
  4924. SetFlag( IrpContext->State,
  4925. IRP_CONTEXT_STATE_ACQUIRE_EX | IRP_CONTEXT_STATE_DASD_OPEN );
  4926. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  4927. }
  4928. Status = NtfsCheckValidAttributeAccess( IrpSp,
  4929. Vcb,
  4930. &IndexFileName->Info,
  4931. &AttrName,
  4932. AttrCodeName,
  4933. CreateFlags,
  4934. &AttrTypeCode,
  4935. &CcbFlags,
  4936. &IndexedAttribute );
  4937. if (!NT_SUCCESS( Status )) {
  4938. DebugTrace( -1, Dbg, ("NtfsOpenFile: Exit -> %08lx\n", Status) );
  4939. return Status;
  4940. }
  4941. NtfsAcquireFcbTable( IrpContext, Vcb );
  4942. AcquiredFcbTable = TRUE;
  4943. //
  4944. // Use a try-finally to facilitate cleanup.
  4945. //
  4946. try {
  4947. //
  4948. // We know that it is safe to continue the open. We start by creating
  4949. // an Fcb and Lcb for this file. It is possible that the Fcb and Lcb
  4950. // both exist. If the Lcb exists, then the Fcb must definitely exist.
  4951. // We create the Fcb first, if we need to update the Fcb info structure
  4952. // we copy the one from the index entry. We look at the Fcb to discover
  4953. // if it has any links, if it does then we make this the last Fcb we
  4954. // reached. If it doesn't then we have to clean it up from here.
  4955. //
  4956. ThisFcb = NtfsCreateFcb( IrpContext,
  4957. ParentScb->Vcb,
  4958. IndexEntry->FileReference,
  4959. BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ),
  4960. BooleanFlagOn( IndexFileName->Info.FileAttributes,
  4961. DUP_FILE_NAME_INDEX_PRESENT ),
  4962. &ExistingFcb );
  4963. ThisFcb->ReferenceCount += 1;
  4964. //
  4965. // If we created this Fcb we must make sure to start teardown
  4966. // on it.
  4967. //
  4968. if (!ExistingFcb) {
  4969. LocalFcbForTeardown = ThisFcb;
  4970. } else {
  4971. *LcbForTeardown = NULL;
  4972. *CurrentFcb = ThisFcb;
  4973. }
  4974. //
  4975. // Try to do a fast acquire, otherwise we need to release
  4976. // the Fcb table, acquire the Fcb, acquire the Fcb table to
  4977. // dereference Fcb.
  4978. //
  4979. if (FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE) &&
  4980. (NtfsSegmentNumber( &ParentScb->Fcb->FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER)) {
  4981. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  4982. NtfsReleaseFcbTable( IrpContext, Vcb );
  4983. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  4984. NtfsAcquireFcbTable( IrpContext, Vcb );
  4985. } else if (!NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, ACQUIRE_DONT_WAIT )) {
  4986. //
  4987. // Remember the current file reference in the index entry.
  4988. // We want to be able to detect whether an entry is removed.
  4989. //
  4990. PreviousFileReference = IndexEntry->FileReference;
  4991. DroppedParent = TRUE;
  4992. ParentScb->Fcb->ReferenceCount += 1;
  4993. InterlockedIncrement( &ParentScb->CleanupCount );
  4994. //
  4995. // Set the IrpContext to acquire paging io resources if our target
  4996. // has one. This will lock the MappedPageWriter out of this file.
  4997. //
  4998. if (ThisFcb->PagingIoResource != NULL) {
  4999. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  5000. }
  5001. NtfsReleaseScbWithPaging( IrpContext, ParentScb );
  5002. NtfsReleaseFcbTable( IrpContext, Vcb );
  5003. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  5004. NtfsAcquireExclusiveScb( IrpContext, ParentScb );
  5005. NtfsAcquireFcbTable( IrpContext, Vcb );
  5006. InterlockedDecrement( &ParentScb->CleanupCount );
  5007. ParentScb->Fcb->ReferenceCount -= 1;
  5008. }
  5009. ThisFcb->ReferenceCount -= 1;
  5010. NtfsReleaseFcbTable( IrpContext, Vcb );
  5011. AcquiredFcbTable = FALSE;
  5012. //
  5013. // Check if something happened to this file in the window where
  5014. // we dropped the parent.
  5015. //
  5016. if (DroppedParent) {
  5017. //
  5018. // Check if the file has been deleted.
  5019. //
  5020. if (ExistingFcb && (ThisFcb->LinkCount == 0)) {
  5021. try_return( Status = STATUS_DELETE_PENDING );
  5022. //
  5023. // Check if the link may have been deleted.
  5024. //
  5025. } else if (!NtfsEqualMftRef( &IndexEntry->FileReference,
  5026. &PreviousFileReference )) {
  5027. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  5028. }
  5029. }
  5030. //
  5031. // If the Fcb existed and this is a paging file then either return
  5032. // sharing violation or force the Fcb and Scb's to go away.
  5033. // Do this for the case where the user is opening a paging file
  5034. // but the Fcb is non-paged or the user is opening a non-paging
  5035. // file and the Fcb is for a paging file.
  5036. //
  5037. if (ExistingFcb &&
  5038. ((FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  5039. !FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) ||
  5040. (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  5041. !FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )))) {
  5042. if (ThisFcb->CleanupCount != 0) {
  5043. try_return( Status = STATUS_SHARING_VIOLATION );
  5044. //
  5045. // If we have a persistent paging file then give up and
  5046. // return SHARING_VIOLATION.
  5047. //
  5048. } else if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP )) {
  5049. try_return( Status = STATUS_SHARING_VIOLATION );
  5050. //
  5051. // If there was an existing Fcb for a paging file we need to force
  5052. // all of the Scb's to be torn down. The easiest way to do this
  5053. // is to flush and purge all of the Scb's (saving any attribute list
  5054. // for last) and then raise LOG_FILE_FULL to allow this request to
  5055. // be posted.
  5056. //
  5057. } else {
  5058. //
  5059. // Reference the Fcb so it won't go away on any flushes.
  5060. //
  5061. InterlockedIncrement( &ThisFcb->CloseCount );
  5062. DecrementCloseCount = TRUE;
  5063. //
  5064. // Flush and purge this Fcb.
  5065. //
  5066. NtfsFlushAndPurgeFcb( IrpContext, ThisFcb );
  5067. InterlockedDecrement( &ThisFcb->CloseCount );
  5068. DecrementCloseCount = FALSE;
  5069. //
  5070. // Force this request to be posted and then raise
  5071. // CANT_WAIT. The Fcb should be torn down in the finally
  5072. // clause below.
  5073. //
  5074. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  5075. //
  5076. // If we are posting then we may want to use the next stack location.
  5077. //
  5078. if (IrpContext->Union.OplockCleanup->CompletionContext != NULL) {
  5079. NtfsPrepareForIrpCompletion( IrpContext,
  5080. IrpContext->OriginatingIrp,
  5081. IrpContext->Union.OplockCleanup->CompletionContext );
  5082. }
  5083. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  5084. }
  5085. }
  5086. //
  5087. // We perform a check to see whether we will allow the system
  5088. // files to be opened.
  5089. //
  5090. // No test to make if this is not a system file or it is the VolumeDasd file.
  5091. // The ACL will protect the volume file.
  5092. //
  5093. if (FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE ) &&
  5094. (NtfsSegmentNumber( &ThisFcb->FileReference ) != VOLUME_DASD_NUMBER) &&
  5095. NtfsProtectSystemFiles) {
  5096. if (!NtfsCheckValidFileAccess( ThisFcb, IrpSp )) {
  5097. Status = STATUS_ACCESS_DENIED;
  5098. DebugTrace( 0, Dbg, ("Invalid access to system files\n") );
  5099. try_return( NOTHING );
  5100. }
  5101. }
  5102. //
  5103. // If the Fcb Info field needs to be initialized, we do so now.
  5104. // We read this information from the disk as the duplicate information
  5105. // in the index entry is not guaranteed to be correct.
  5106. //
  5107. if (!FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  5108. HaveScbSizes = NtfsUpdateFcbInfoFromDisk( IrpContext,
  5109. TRUE,
  5110. ThisFcb,
  5111. &ScbSizes );
  5112. //
  5113. // Remember the last access time in the directory entry.
  5114. //
  5115. ThisFcb->Info.LastAccessTime = IndexFileName->Info.LastAccessTime;
  5116. NtfsConditionallyFixupQuota( IrpContext, ThisFcb );
  5117. }
  5118. //
  5119. // We have the actual data from the disk stored in the duplicate
  5120. // information in the Fcb. We compare this with the duplicate
  5121. // information in the DUPLICATE_INFORMATION structure in the
  5122. // filename attribute. If they don't match, we remember that
  5123. // we need to update the duplicate information.
  5124. //
  5125. if (!RtlEqualMemory( &ThisFcb->Info,
  5126. &IndexFileName->Info,
  5127. FIELD_OFFSET( DUPLICATED_INFORMATION, LastAccessTime ))) {
  5128. UpdateFcbInfo = TRUE;
  5129. //
  5130. // We expect this to be very rare but let's find the ones being changed.
  5131. //
  5132. if (ThisFcb->Info.CreationTime != IndexFileName->Info.CreationTime) {
  5133. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_CREATE );
  5134. }
  5135. if (ThisFcb->Info.LastModificationTime != IndexFileName->Info.LastModificationTime) {
  5136. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_LAST_MOD );
  5137. }
  5138. if (ThisFcb->Info.LastChangeTime != IndexFileName->Info.LastChangeTime) {
  5139. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_LAST_CHANGE );
  5140. }
  5141. }
  5142. if (!RtlEqualMemory( &ThisFcb->Info.AllocatedLength,
  5143. &IndexFileName->Info.AllocatedLength,
  5144. FIELD_OFFSET( DUPLICATED_INFORMATION, Reserved ) -
  5145. FIELD_OFFSET( DUPLICATED_INFORMATION, AllocatedLength ))) {
  5146. UpdateFcbInfo = TRUE;
  5147. if (ThisFcb->Info.AllocatedLength != IndexFileName->Info.AllocatedLength) {
  5148. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
  5149. }
  5150. if (ThisFcb->Info.FileSize != IndexFileName->Info.FileSize) {
  5151. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_FILE_SIZE );
  5152. }
  5153. if (ThisFcb->Info.FileAttributes != IndexFileName->Info.FileAttributes) {
  5154. ASSERTMSG( "conflict with flush",
  5155. NtfsIsSharedFcb( ThisFcb ) ||
  5156. (ThisFcb->PagingIoResource != NULL &&
  5157. NtfsIsSharedFcbPagingIo( ThisFcb )) );
  5158. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  5159. }
  5160. if (ThisFcb->Info.PackedEaSize != IndexFileName->Info.PackedEaSize) {
  5161. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_EA_SIZE );
  5162. }
  5163. }
  5164. //
  5165. // Don't update last access unless more than an hour.
  5166. //
  5167. if (NtfsCheckLastAccess( IrpContext, ThisFcb )) {
  5168. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_LAST_ACCESS );
  5169. UpdateFcbInfo = TRUE;
  5170. }
  5171. //
  5172. // Now get the link for this traversal.
  5173. //
  5174. ThisLcb = NtfsCreateLcb( IrpContext,
  5175. ParentScb,
  5176. ThisFcb,
  5177. FinalName,
  5178. IndexFileName->Flags,
  5179. NULL );
  5180. //
  5181. // We now know the Fcb is linked into the tree.
  5182. //
  5183. LocalFcbForTeardown = NULL;
  5184. *LcbForTeardown = ThisLcb;
  5185. *CurrentFcb = ThisFcb;
  5186. //
  5187. // If the link has been deleted, we cut off the open.
  5188. //
  5189. if (LcbLinkIsDeleted( ThisLcb )) {
  5190. try_return( Status = STATUS_DELETE_PENDING );
  5191. }
  5192. //
  5193. // We now call the worker routine to open an attribute on an existing file.
  5194. //
  5195. Status = NtfsOpenAttributeInExistingFile( IrpContext,
  5196. Irp,
  5197. IrpSp,
  5198. ThisLcb,
  5199. ThisFcb,
  5200. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  5201. ? 0
  5202. : FullPathName.Length - FinalName.Length),
  5203. AttrName,
  5204. AttrTypeCode,
  5205. CcbFlags,
  5206. CreateFlags,
  5207. NetworkInfo,
  5208. ThisScb,
  5209. ThisCcb );
  5210. //
  5211. // Check to see if we should insert any prefix table entries
  5212. // and update the last access time.
  5213. // We skip this for reparse points as *ThisScb and *ThisCcb may be NULL.
  5214. //
  5215. if (NT_SUCCESS( Status ) &&
  5216. (Status != STATUS_PENDING) &&
  5217. (Status != STATUS_REPARSE)) {
  5218. PSCB Scb = *ThisScb;
  5219. //
  5220. // Go ahead and insert this link into the splay tree if it is not
  5221. // a system file.
  5222. //
  5223. if (!FlagOn( ThisLcb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  5224. if ((CreateContext->FileHashLength != 0) &&
  5225. !FlagOn( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  5226. (ThisLcb->FileNameAttr->Flags != FILE_NAME_DOS) ) {
  5227. //
  5228. // Remove any exising hash value.
  5229. //
  5230. if (FlagOn( ThisLcb->LcbState, LCB_STATE_VALID_HASH_VALUE )) {
  5231. NtfsRemoveHashEntriesForLcb( ThisLcb );
  5232. #ifdef NTFS_HASH_DATA
  5233. ThisFcb->Vcb->HashTable.OpenFileConflict += 1;
  5234. #endif
  5235. }
  5236. NtfsInsertHashEntry( &Vcb->HashTable,
  5237. ThisLcb,
  5238. CreateContext->FileHashLength,
  5239. CreateContext->FileHashValue );
  5240. #ifdef NTFS_HASH_DATA
  5241. Vcb->HashTable.OpenFileInsert += 1;
  5242. #endif
  5243. }
  5244. NtfsInsertPrefix( ThisLcb, CreateFlags );
  5245. }
  5246. //
  5247. // If this is a directory open and the normalized name is not in
  5248. // the Scb then do so now.
  5249. //
  5250. if ((SafeNodeType( *ThisScb ) == NTFS_NTC_SCB_INDEX) &&
  5251. ((*ThisScb)->ScbType.Index.NormalizedName.Length == 0)) {
  5252. //
  5253. // We may be able to use the parent.
  5254. //
  5255. if (ParentScb->ScbType.Index.NormalizedName.Length != 0) {
  5256. NtfsUpdateNormalizedName( IrpContext,
  5257. ParentScb,
  5258. *ThisScb,
  5259. IndexFileName,
  5260. FALSE );
  5261. } else {
  5262. NtfsBuildNormalizedName( IrpContext,
  5263. (*ThisScb)->Fcb,
  5264. *ThisScb,
  5265. &(*ThisScb)->ScbType.Index.NormalizedName );
  5266. }
  5267. }
  5268. //
  5269. // Perform the last bit of work. If this a user file open, we need
  5270. // to check if we initialize the Scb.
  5271. //
  5272. if (!IndexedAttribute) {
  5273. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  5274. //
  5275. // We may have the sizes from our Fcb update call.
  5276. //
  5277. if (HaveScbSizes &&
  5278. (AttrTypeCode == $DATA) &&
  5279. (AttrName.Length == 0) &&
  5280. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB )) {
  5281. NtfsUpdateScbFromMemory( Scb, &ScbSizes );
  5282. } else {
  5283. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  5284. }
  5285. }
  5286. //
  5287. // Let's check if we need to set the cache bit.
  5288. //
  5289. if (!FlagOn( IrpSp->Parameters.Create.Options,
  5290. FILE_NO_INTERMEDIATE_BUFFERING )) {
  5291. SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
  5292. }
  5293. }
  5294. //
  5295. // If this is the paging file, we want to be sure the allocation
  5296. // is loaded.
  5297. //
  5298. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  5299. (Scb->Header.AllocationSize.QuadPart != 0) &&
  5300. !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  5301. LCN Lcn;
  5302. VCN Vcn;
  5303. VCN AllocatedVcns;
  5304. AllocatedVcns = Int64ShraMod32(Scb->Header.AllocationSize.QuadPart, Scb->Vcb->ClusterShift);
  5305. NtfsPreloadAllocation( IrpContext, Scb, 0, AllocatedVcns );
  5306. //
  5307. // Now make sure the allocation is correctly loaded. The last
  5308. // Vcn should correspond to the allocation size for the file.
  5309. //
  5310. if (!NtfsLookupLastNtfsMcbEntry( &Scb->Mcb,
  5311. &Vcn,
  5312. &Lcn ) ||
  5313. (Vcn + 1) != AllocatedVcns) {
  5314. NtfsRaiseStatus( IrpContext,
  5315. STATUS_FILE_CORRUPT_ERROR,
  5316. NULL,
  5317. ThisFcb );
  5318. }
  5319. }
  5320. //
  5321. // If this open is for an executable image we update the last
  5322. // access time.
  5323. //
  5324. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess, FILE_EXECUTE ) &&
  5325. (Scb->AttributeTypeCode == $DATA)) {
  5326. SetFlag( IrpSp->FileObject->Flags, FO_FILE_FAST_IO_READ );
  5327. }
  5328. //
  5329. // Let's update the quick index information in the Lcb.
  5330. //
  5331. RtlCopyMemory( &ThisLcb->QuickIndex,
  5332. QuickIndex,
  5333. sizeof( QUICK_INDEX ));
  5334. //
  5335. // If everything has gone well so far, we may want to call the
  5336. // encryption callback if one is registered. We do not do
  5337. // this for network opens or reparse points.
  5338. //
  5339. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  5340. NtfsEncryptionCreateCallback( IrpContext,
  5341. Irp,
  5342. IrpSp,
  5343. *ThisScb,
  5344. *ThisCcb,
  5345. ThisFcb,
  5346. ParentScb->Fcb,
  5347. FALSE );
  5348. }
  5349. //
  5350. // If this operation was a supersede/overwrite or we created a new
  5351. // attribute stream then we want to perform the file record and
  5352. // directory update now. Otherwise we will defer the updates until
  5353. // the user closes his handle.
  5354. //
  5355. if (UpdateFcbInfo ||
  5356. NtfsIsStreamNew(Irp->IoStatus.Information)) {
  5357. NtfsUpdateScbFromFileObject( IrpContext, IrpSp->FileObject, *ThisScb, TRUE );
  5358. //
  5359. // Do the standard information, file sizes and then duplicate information
  5360. // if needed.
  5361. //
  5362. if (FlagOn( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO )) {
  5363. NtfsUpdateStandardInformation( IrpContext, ThisFcb );
  5364. }
  5365. if (FlagOn( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE )) {
  5366. NtfsWriteFileSizes( IrpContext,
  5367. *ThisScb,
  5368. &(*ThisScb)->Header.ValidDataLength.QuadPart,
  5369. FALSE,
  5370. TRUE,
  5371. FALSE );
  5372. }
  5373. if (FlagOn( ThisFcb->InfoFlags, FCB_INFO_DUPLICATE_FLAGS )) {
  5374. ULONG FilterMatch;
  5375. NtfsUpdateDuplicateInfo( IrpContext, ThisFcb, *LcbForTeardown, ParentScb );
  5376. if (Vcb->NotifyCount != 0) {
  5377. //
  5378. // We map the Fcb info flags into the dir notify flags.
  5379. //
  5380. FilterMatch = NtfsBuildDirNotifyFilter( IrpContext,
  5381. ThisFcb->InfoFlags | ThisLcb->InfoFlags );
  5382. //
  5383. // If the filter match is non-zero, that means we also need to do a
  5384. // dir notify call.
  5385. //
  5386. if ((FilterMatch != 0) && (*ThisCcb != NULL)) {
  5387. NtfsReportDirNotify( IrpContext,
  5388. ThisFcb->Vcb,
  5389. &(*ThisCcb)->FullFileName,
  5390. (*ThisCcb)->LastFileNameOffset,
  5391. NULL,
  5392. ((FlagOn( (*ThisCcb)->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  5393. ((*ThisCcb)->Lcb != NULL) &&
  5394. ((*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  5395. &(*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName :
  5396. NULL),
  5397. FilterMatch,
  5398. FILE_ACTION_MODIFIED,
  5399. ParentScb->Fcb );
  5400. }
  5401. }
  5402. NtfsUpdateLcbDuplicateInfo( ThisFcb, *LcbForTeardown );
  5403. ThisFcb->InfoFlags = 0;
  5404. }
  5405. ClearFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  5406. NtfsAcquireFsrtlHeader( *ThisScb );
  5407. ClearFlag( (*ThisScb)->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
  5408. NtfsReleaseFsrtlHeader( *ThisScb );
  5409. }
  5410. }
  5411. try_exit: NOTHING;
  5412. } finally {
  5413. DebugUnwind( NtfsOpenFile );
  5414. if (AcquiredFcbTable) {
  5415. NtfsReleaseFcbTable( IrpContext, Vcb );
  5416. }
  5417. //
  5418. // If this operation was not totally successful we need to
  5419. // back out the following changes.
  5420. //
  5421. // Modifications to the Info fields in the Fcb.
  5422. // Any changes to the allocation of the Scb.
  5423. // Any changes in the open counts in the various structures.
  5424. // Changes to the share access values in the Fcb.
  5425. //
  5426. if (!NT_SUCCESS( Status ) || AbnormalTermination()) {
  5427. NtfsBackoutFailedOpens( IrpContext,
  5428. IrpSp->FileObject,
  5429. ThisFcb,
  5430. *ThisScb,
  5431. *ThisCcb );
  5432. }
  5433. if (DecrementCloseCount) {
  5434. InterlockedDecrement( &ThisFcb->CloseCount );
  5435. }
  5436. //
  5437. // If we are to cleanup the Fcb we, look to see if we created it.
  5438. // If we did we can call our teardown routine. Otherwise we
  5439. // leave it alone.
  5440. //
  5441. if ((LocalFcbForTeardown != NULL) &&
  5442. (Status != STATUS_PENDING)) {
  5443. NtfsTeardownStructures( IrpContext,
  5444. ThisFcb,
  5445. NULL,
  5446. (BOOLEAN) (IrpContext->TransactionId != 0),
  5447. 0,
  5448. NULL );
  5449. }
  5450. DebugTrace( -1, Dbg, ("NtfsOpenFile: Exit -> %08lx\n", Status) );
  5451. }
  5452. return Status;
  5453. }
  5454. //
  5455. // Local support routine
  5456. //
  5457. NTSTATUS
  5458. NtfsCreateNewFile (
  5459. IN PIRP_CONTEXT IrpContext,
  5460. IN PIRP Irp,
  5461. IN PIO_STACK_LOCATION IrpSp,
  5462. IN PSCB ParentScb,
  5463. IN PFILE_NAME FileNameAttr,
  5464. IN UNICODE_STRING FullPathName,
  5465. IN UNICODE_STRING FinalName,
  5466. IN UNICODE_STRING AttrName,
  5467. IN UNICODE_STRING AttrCodeName,
  5468. IN ULONG CreateFlags,
  5469. IN PINDEX_CONTEXT *IndexContext,
  5470. IN PCREATE_CONTEXT CreateContext,
  5471. OUT PFCB *CurrentFcb,
  5472. OUT PLCB *LcbForTeardown,
  5473. OUT PSCB *ThisScb,
  5474. OUT PCCB *ThisCcb
  5475. )
  5476. /*++
  5477. Routine Description:
  5478. This routine is called when we need to open an attribute on a file
  5479. which does not exist yet. We have the ParentScb and the name to use
  5480. for this create. We will attempt to create the file and necessary
  5481. attributes. This will cause us to create an Fcb and the link between
  5482. it and its parent Scb. We will add this link to the prefix table as
  5483. well as the link for its parent Scb if specified.
  5484. Arguments:
  5485. Irp - This is the Irp for this open operation.
  5486. IrpSp - This is the Irp stack pointer for the filesystem.
  5487. ParentScb - This is the Scb for the parent directory.
  5488. FileNameAttr - This is the file name attribute we used to perform the
  5489. search. The file name is correct but the other fields need to
  5490. be initialized.
  5491. FullPathName - This is the string containing the full path name of
  5492. this Fcb.
  5493. FinalName - This is the string for the final component only.
  5494. AttrName - This is the name of the attribute to open.
  5495. AttriCodeName - This is the name of the attribute code to open.
  5496. CreateFlags - Flags for create - we care about ignore case, dos only component,
  5497. trailingbackslashes and open by id
  5498. IndexContext - If this contains a non-NULL value then this is the result of a
  5499. lookup which did not find the file. It can be used to insert the name into the index.
  5500. We will clean it up here in the error path to prevent a deadlock if we call
  5501. TeardownStructures within this routine.
  5502. CreateContext - Context with create variables.
  5503. CurrentFcb - This is the address to store the Fcb if we successfully find
  5504. one in the Fcb/Scb tree.
  5505. LcbForTeardown - This is the Lcb to use in teardown if we add an Lcb
  5506. into the tree.
  5507. ThisScb - This is the address to store the Scb from this open.
  5508. ThisCcb - This is the address to store the Ccb from this open.
  5509. Tunnel - This is the property tunnel to search for restoration
  5510. Return Value:
  5511. NTSTATUS - Indicates the result of this create file operation.
  5512. --*/
  5513. {
  5514. NTSTATUS Status = STATUS_SUCCESS;
  5515. PVCB Vcb;
  5516. ULONG CcbFlags = 0;
  5517. ULONG UsnReasons = 0;
  5518. BOOLEAN IndexedAttribute;
  5519. ATTRIBUTE_TYPE_CODE AttrTypeCode;
  5520. BOOLEAN CleanupAttrContext = FALSE;
  5521. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  5522. PBCB FileRecordBcb = NULL;
  5523. LONGLONG FileRecordOffset;
  5524. FILE_REFERENCE ThisFileReference;
  5525. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  5526. PSCB Scb;
  5527. PLCB ThisLcb = NULL;
  5528. PFCB ThisFcb = NULL;
  5529. BOOLEAN AcquiredFcbTable = FALSE;
  5530. BOOLEAN RemovedFcb = FALSE;
  5531. BOOLEAN DecrementCloseCount = FALSE;
  5532. PACCESS_STATE AccessState;
  5533. BOOLEAN ReturnedExistingFcb;
  5534. BOOLEAN LoggedFileRecord = FALSE;
  5535. BOOLEAN HaveTunneledInformation = FALSE;
  5536. NAME_PAIR NamePair;
  5537. NTFS_TUNNELED_DATA TunneledData;
  5538. ULONG TunneledDataSize;
  5539. ULONG OwnerId;
  5540. PQUOTA_CONTROL_BLOCK QuotaControl = NULL;
  5541. PSHARED_SECURITY SharedSecurity = NULL;
  5542. ULONG CreateDisposition;
  5543. VCN Cluster;
  5544. LCN Lcn;
  5545. VCN Vcn;
  5546. UCHAR FileNameFlags;
  5547. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  5548. BOOLEAN Acquired;
  5549. #endif
  5550. PAGED_CODE();
  5551. DebugTrace( +1, Dbg, ("NtfsCreateNewFile: Entered\n") );
  5552. NtfsInitializeNamePair(&NamePair);
  5553. if (FlagOn( CreateFlags, CREATE_FLAG_DOS_ONLY_COMPONENT )) {
  5554. SetFlag( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT );
  5555. }
  5556. //
  5557. // We will do all the checks to see if this open can fail.
  5558. // This includes checking the specified attribute names, checking
  5559. // the security access and checking the create disposition.
  5560. //
  5561. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  5562. if ((CreateDisposition == FILE_OPEN) ||
  5563. (CreateDisposition == FILE_OVERWRITE)) {
  5564. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  5565. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", Status) );
  5566. return Status;
  5567. } else if (FlagOn( IrpSp->Parameters.Create.Options,
  5568. FILE_DIRECTORY_FILE ) &&
  5569. (CreateDisposition == FILE_OVERWRITE_IF)) {
  5570. Status = STATUS_OBJECT_NAME_INVALID;
  5571. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", Status) );
  5572. return Status;
  5573. }
  5574. Vcb = ParentScb->Vcb;
  5575. //
  5576. // Catch the case where the volume is read-only and the user wanted to create a file
  5577. // if it didn't already exist.
  5578. //
  5579. if (NtfsIsVolumeReadOnly( Vcb ) &&
  5580. (CreateDisposition == FILE_OPEN_IF)) {
  5581. Status = STATUS_MEDIA_WRITE_PROTECTED;
  5582. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", Status) );
  5583. return Status;
  5584. }
  5585. //
  5586. // Better have caught all cases now.
  5587. //
  5588. ASSERT( !NtfsIsVolumeReadOnly( Vcb ));
  5589. Status = NtfsCheckValidAttributeAccess( IrpSp,
  5590. Vcb,
  5591. NULL,
  5592. &AttrName,
  5593. AttrCodeName,
  5594. CreateFlags,
  5595. &AttrTypeCode,
  5596. &CcbFlags,
  5597. &IndexedAttribute );
  5598. if (!NT_SUCCESS( Status )) {
  5599. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", Status) );
  5600. return Status;
  5601. }
  5602. //
  5603. // Fail this request if this is an indexed attribute and the TEMPORARY
  5604. // bit is set.
  5605. //
  5606. if (IndexedAttribute &&
  5607. FlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_TEMPORARY )) {
  5608. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", STATUS_INVALID_PARAMETER) );
  5609. return STATUS_INVALID_PARAMETER;
  5610. }
  5611. //
  5612. // We won't allow someone to create a read-only file with DELETE_ON_CLOSE.
  5613. //
  5614. if (FlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_READONLY ) &&
  5615. FlagOn( IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE )) {
  5616. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", STATUS_CANNOT_DELETE) );
  5617. return STATUS_CANNOT_DELETE;
  5618. }
  5619. //
  5620. // We do not allow that anything be created in a directory that is a reparse
  5621. // point. We verify that the parent is not in this category.
  5622. //
  5623. if (IsDirectory( &ParentScb->Fcb->Info ) &&
  5624. (FlagOn( ParentScb->Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ))) {
  5625. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", STATUS_DIRECTORY_IS_A_REPARSE_POINT) );
  5626. return STATUS_DIRECTORY_IS_A_REPARSE_POINT;
  5627. }
  5628. //
  5629. // We do not allow anything to be created in a system directory (unless it is the root directory).
  5630. // we only allow creates for indices and data streams
  5631. //
  5632. if ((FlagOn( ParentScb->Fcb->FcbState, FCB_STATE_SYSTEM_FILE ) &&
  5633. (ParentScb != Vcb->RootIndexScb)) ||
  5634. !((AttrTypeCode == $DATA) || (AttrTypeCode == $INDEX_ALLOCATION))) {
  5635. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", STATUS_ACCESS_DENIED) );
  5636. return STATUS_ACCESS_DENIED;
  5637. }
  5638. //
  5639. // Use a try-finally to facilitate cleanup.
  5640. //
  5641. try {
  5642. //
  5643. // Now perform the security checks. The first is to check if we
  5644. // may create a file in the parent. The second checks if the user
  5645. // desires ACCESS_SYSTEM_SECURITY and has the required privilege.
  5646. //
  5647. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  5648. if (!FlagOn( AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE )) {
  5649. NtfsCreateCheck( IrpContext, ParentScb->Fcb, Irp );
  5650. }
  5651. //
  5652. // Check if the remaining privilege includes ACCESS_SYSTEM_SECURITY.
  5653. // This is only the case if we skipped the NtfsCreateCheck because of restore
  5654. // privileges above. We still need to get this bit in or set sacl security won't work
  5655. // Normally NtfsCreateCheck calls SeAccessCheck which does this implicitly
  5656. //
  5657. if (FlagOn( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY )) {
  5658. if (!SeSinglePrivilegeCheck( NtfsSecurityPrivilege,
  5659. UserMode )) {
  5660. NtfsRaiseStatus( IrpContext, STATUS_PRIVILEGE_NOT_HELD, NULL, NULL );
  5661. }
  5662. //
  5663. // Move this privilege from the Remaining access to Granted access.
  5664. //
  5665. ClearFlag( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY );
  5666. SetFlag( AccessState->PreviouslyGrantedAccess, ACCESS_SYSTEM_SECURITY );
  5667. }
  5668. //
  5669. // We want to allow this user maximum access to this file. We will
  5670. // use his desired access and check if he specified MAXIMUM_ALLOWED.
  5671. //
  5672. SetFlag( AccessState->PreviouslyGrantedAccess,
  5673. AccessState->RemainingDesiredAccess );
  5674. if (FlagOn( AccessState->PreviouslyGrantedAccess, MAXIMUM_ALLOWED )) {
  5675. SetFlag( AccessState->PreviouslyGrantedAccess, FILE_ALL_ACCESS );
  5676. ClearFlag( AccessState->PreviouslyGrantedAccess, MAXIMUM_ALLOWED );
  5677. }
  5678. AccessState->RemainingDesiredAccess = 0;
  5679. //
  5680. // Find/cache the security descriptor being passed in. This call may
  5681. // create new data in the security indexes/stream and commits
  5682. // before any subsequent disk modifications occur.
  5683. //
  5684. SharedSecurity = NtfsCacheSharedSecurityForCreate( IrpContext, ParentScb->Fcb );
  5685. //
  5686. // Make sure the parent has a normalized name. We want to construct it now
  5687. // while we can still walk up the Lcb queue. Otherwise we can deadlock
  5688. // on the Mft and other resources.
  5689. //
  5690. if ((AttrTypeCode == $INDEX_ALLOCATION) &&
  5691. (ParentScb->ScbType.Index.NormalizedName.Length == 0)) {
  5692. NtfsBuildNormalizedName( IrpContext,
  5693. ParentScb->Fcb,
  5694. ParentScb,
  5695. &ParentScb->ScbType.Index.NormalizedName );
  5696. }
  5697. //
  5698. // Decide whether there's anything in the tunnel cache for this create.
  5699. // We don't do tunnelling in POSIX mode, hence the test for IgnoreCase.
  5700. //
  5701. if (!IndexedAttribute && FlagOn( CreateFlags, CREATE_FLAG_IGNORE_CASE )) {
  5702. TunneledDataSize = sizeof(NTFS_TUNNELED_DATA);
  5703. if (FsRtlFindInTunnelCache( &Vcb->Tunnel,
  5704. *(PULONGLONG)&ParentScb->Fcb->FileReference,
  5705. &FinalName,
  5706. &NamePair.Short,
  5707. &NamePair.Long,
  5708. &TunneledDataSize,
  5709. &TunneledData)) {
  5710. ASSERT( TunneledDataSize == sizeof(NTFS_TUNNELED_DATA) );
  5711. HaveTunneledInformation = TRUE;
  5712. //
  5713. // If we have tunneled data and there's an object in the
  5714. // tunnel cache for this file, we need to acquire the object
  5715. // id index now (before acquiring any quota resources) to
  5716. // prevent a deadlock. If there's no object id, then we
  5717. // won't try to set the object id later, and there's no
  5718. // deadlock to worry about.
  5719. //
  5720. if (TunneledData.HasObjectId) {
  5721. NtfsAcquireExclusiveScb( IrpContext, Vcb->ObjectIdTableScb );
  5722. ASSERT( !FlagOn( CreateFlags, CREATE_FLAG_ACQUIRED_OBJECT_ID_INDEX ) );
  5723. SetFlag( CreateFlags, CREATE_FLAG_ACQUIRED_OBJECT_ID_INDEX );
  5724. //
  5725. // The object id package won't post the Usn reason if it
  5726. // sees it's been called in the create path, since the
  5727. // file name is not yet in the file record, so it's unsafe
  5728. // to call the Usn package. When we post the create to the
  5729. // Usn package below, we'll remember to post this one, too.
  5730. //
  5731. UsnReasons |= USN_REASON_OBJECT_ID_CHANGE;
  5732. }
  5733. }
  5734. }
  5735. //
  5736. // If quota tracking is enabled then get a owner id for the file.
  5737. //
  5738. if (FlagOn( Vcb->QuotaFlags, QUOTA_FLAG_TRACKING_ENABLED )) {
  5739. PSID Sid;
  5740. BOOLEAN OwnerDefaulted;
  5741. //
  5742. // The quota index must be acquired before the MFT SCB is acquired.
  5743. //
  5744. ASSERT( !NtfsIsExclusiveScb( Vcb->MftScb ) || NtfsIsExclusiveScb( Vcb->QuotaTableScb ));
  5745. //
  5746. // Extract the security id from the security descriptor.
  5747. //
  5748. Status = RtlGetOwnerSecurityDescriptor( SharedSecurity->SecurityDescriptor,
  5749. &Sid,
  5750. &OwnerDefaulted );
  5751. if (!NT_SUCCESS( Status )) {
  5752. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  5753. }
  5754. //
  5755. // Generate a owner id.
  5756. //
  5757. OwnerId = NtfsGetOwnerId( IrpContext, Sid, TRUE, NULL );
  5758. QuotaControl = NtfsInitializeQuotaControlBlock( Vcb, OwnerId );
  5759. //
  5760. // Acquire the quota control block. This is done here since it
  5761. // must be acquired before the MFT.
  5762. //
  5763. NtfsAcquireQuotaControl( IrpContext, QuotaControl );
  5764. }
  5765. //
  5766. // We will now try to do all of the on-disk operations. This means first
  5767. // allocating and initializing an Mft record. After that we create
  5768. // an Fcb to use to access this record.
  5769. //
  5770. ThisFileReference = NtfsAllocateMftRecord( IrpContext,
  5771. Vcb,
  5772. FALSE );
  5773. //
  5774. // Pin the file record we need.
  5775. //
  5776. NtfsPinMftRecord( IrpContext,
  5777. Vcb,
  5778. &ThisFileReference,
  5779. TRUE,
  5780. &FileRecordBcb,
  5781. &FileRecord,
  5782. &FileRecordOffset );
  5783. //
  5784. // Initialize the file record header.
  5785. //
  5786. NtfsInitializeMftRecord( IrpContext,
  5787. Vcb,
  5788. &ThisFileReference,
  5789. FileRecord,
  5790. FileRecordBcb,
  5791. IndexedAttribute );
  5792. NtfsAcquireFcbTable( IrpContext, Vcb );
  5793. AcquiredFcbTable = TRUE;
  5794. ThisFcb = NtfsCreateFcb( IrpContext,
  5795. Vcb,
  5796. ThisFileReference,
  5797. BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ),
  5798. IndexedAttribute,
  5799. &ReturnedExistingFcb );
  5800. ASSERT( !ReturnedExistingFcb );
  5801. //
  5802. // Set the flag indicating we want to acquire the paging io resource
  5803. // if it doesn't already exist. Use acquire don't wait for lock order
  5804. // package. Since this is a new file and we haven't dropped the fcb table
  5805. // mutex yet, no one else can own it. So this will always succeed.
  5806. //
  5807. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  5808. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  5809. Acquired =
  5810. #endif
  5811. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, ACQUIRE_DONT_WAIT );
  5812. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  5813. ASSERT( Acquired );
  5814. #endif
  5815. NtfsReleaseFcbTable( IrpContext, Vcb );
  5816. AcquiredFcbTable = FALSE;
  5817. //
  5818. // Reference the Fcb so it won't go away.
  5819. //
  5820. InterlockedIncrement( &ThisFcb->CloseCount );
  5821. DecrementCloseCount = TRUE;
  5822. //
  5823. // The first thing to create is the Ea's for the file. This will
  5824. // update the Ea length field in the Fcb.
  5825. // We test here that the opener is opening the entire file and
  5826. // is not Ea blind.
  5827. //
  5828. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  5829. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE ) ||
  5830. !FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  5831. try_return( Status = STATUS_ACCESS_DENIED );
  5832. }
  5833. }
  5834. SetFlag( ThisFcb->FcbState, FCB_STATE_LARGE_STD_INFO );
  5835. //
  5836. // Set up the security Id (if we've found one earlier).
  5837. // We need to be careful so that this works on upgraded and
  5838. // non-upgraded volumes.
  5839. //
  5840. if (ThisFcb->Vcb->SecurityDescriptorStream != NULL) {
  5841. ThisFcb->SecurityId = SharedSecurity->Header.HashKey.SecurityId;
  5842. ThisFcb->SharedSecurity = SharedSecurity;
  5843. DebugTrace(0, (DEBUG_TRACE_SECURSUP | DEBUG_TRACE_ACLINDEX),
  5844. ( "SetFcbSecurity( %08x, %08x )\n", ThisFcb, SharedSecurity ));
  5845. SharedSecurity = NULL;
  5846. } else {
  5847. ASSERT( ThisFcb->SecurityId == SECURITY_ID_INVALID );
  5848. }
  5849. ASSERT( SharedSecurity == NULL );
  5850. //
  5851. // Assign the owner Id and quota control block to the fcb. Once the
  5852. // quota control block is in the FCB this routine is not responsible
  5853. // for the reference to the quota control block.
  5854. //
  5855. if (QuotaControl != NULL) {
  5856. //
  5857. // Assign the onwer Id and quota control block to the fcb. Once the
  5858. // quota control block is in the FCB this routine is not responsible
  5859. // for the reference to the quota control block.
  5860. //
  5861. ThisFcb->OwnerId = OwnerId;
  5862. ThisFcb->QuotaControl = QuotaControl;
  5863. QuotaControl = NULL;
  5864. }
  5865. //
  5866. // Update the FileAttributes with the state of the CONTENT_INDEXED bit from the
  5867. // parent.
  5868. //
  5869. if (!FlagOn( ParentScb->Fcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  5870. NtfsUpdateFcbInfoFromDisk( IrpContext, FALSE, ParentScb->Fcb, NULL );
  5871. }
  5872. ClearFlag( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED );
  5873. SetFlag( IrpSp->Parameters.Create.FileAttributes,
  5874. (ParentScb->Fcb->Info.FileAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) );
  5875. //
  5876. // The changes to make on disk are first to create a standard information
  5877. // attribute. We start by filling the Fcb with the information we
  5878. // know and creating the attribute on disk.
  5879. //
  5880. NtfsInitializeFcbAndStdInfo( IrpContext,
  5881. ThisFcb,
  5882. IndexedAttribute,
  5883. FALSE,
  5884. (BOOLEAN) (!FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION ) &&
  5885. !FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  5886. FlagOn( ParentScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )),
  5887. IrpSp->Parameters.Create.FileAttributes,
  5888. (HaveTunneledInformation ? &TunneledData : NULL) );
  5889. //
  5890. // Next we create the Index for a directory or the unnamed data for
  5891. // a file if they are not explicitly being opened.
  5892. //
  5893. if (!IndexedAttribute) {
  5894. if (!FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  5895. //
  5896. // Update the quota
  5897. //
  5898. LONGLONG Delta = NtfsResidentStreamQuota( ThisFcb->Vcb );
  5899. NtfsConditionallyUpdateQuota( IrpContext,
  5900. ThisFcb,
  5901. &Delta,
  5902. FALSE,
  5903. TRUE );
  5904. //
  5905. // Create the attribute
  5906. //
  5907. NtfsInitializeAttributeContext( &AttrContext );
  5908. CleanupAttrContext = TRUE;
  5909. NtfsCreateAttributeWithValue( IrpContext,
  5910. ThisFcb,
  5911. $DATA,
  5912. NULL,
  5913. NULL,
  5914. 0,
  5915. (USHORT) ((!FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  5916. !FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION )) ?
  5917. (ParentScb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) :
  5918. 0),
  5919. NULL,
  5920. FALSE,
  5921. &AttrContext );
  5922. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  5923. CleanupAttrContext = FALSE;
  5924. ThisFcb->Info.AllocatedLength = 0;
  5925. ThisFcb->Info.FileSize = 0;
  5926. }
  5927. } else {
  5928. NtfsCreateIndex( IrpContext,
  5929. ThisFcb,
  5930. $FILE_NAME,
  5931. COLLATION_FILE_NAME,
  5932. Vcb->DefaultBytesPerIndexAllocationBuffer,
  5933. (UCHAR)Vcb->DefaultBlocksPerIndexAllocationBuffer,
  5934. NULL,
  5935. (USHORT) (!FlagOn( IrpSp->Parameters.Create.Options,
  5936. FILE_NO_COMPRESSION ) ?
  5937. (ParentScb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK) :
  5938. 0),
  5939. TRUE,
  5940. FALSE );
  5941. }
  5942. //
  5943. // Now we create the Lcb, this means that this Fcb is in the graph.
  5944. //
  5945. ThisLcb = NtfsCreateLcb( IrpContext,
  5946. ParentScb,
  5947. ThisFcb,
  5948. FinalName,
  5949. 0,
  5950. NULL );
  5951. ASSERT( ThisLcb != NULL );
  5952. //
  5953. // Finally we create and open the desired attribute for the user.
  5954. //
  5955. if (AttrTypeCode == $INDEX_ALLOCATION) {
  5956. Status = NtfsOpenAttribute( IrpContext,
  5957. IrpSp,
  5958. Vcb,
  5959. ThisLcb,
  5960. ThisFcb,
  5961. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  5962. ? 0
  5963. : FullPathName.Length - FinalName.Length),
  5964. NtfsFileNameIndex,
  5965. $INDEX_ALLOCATION,
  5966. SetShareAccess,
  5967. UserDirectoryOpen,
  5968. TRUE,
  5969. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  5970. ? CcbFlags | CCB_FLAG_OPEN_BY_FILE_ID
  5971. : CcbFlags),
  5972. NULL,
  5973. ThisScb,
  5974. ThisCcb );
  5975. } else {
  5976. Status = NtfsOpenNewAttr( IrpContext,
  5977. Irp,
  5978. IrpSp,
  5979. ThisLcb,
  5980. ThisFcb,
  5981. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  5982. ? 0
  5983. : FullPathName.Length - FinalName.Length),
  5984. AttrName,
  5985. AttrTypeCode,
  5986. TRUE,
  5987. CcbFlags,
  5988. FALSE,
  5989. CreateFlags,
  5990. ThisScb,
  5991. ThisCcb );
  5992. }
  5993. //
  5994. // If we are successful, we add the parent Lcb to the prefix table if
  5995. // desired. We will always add our link to the prefix queue.
  5996. //
  5997. if (NT_SUCCESS( Status )) {
  5998. Scb = *ThisScb;
  5999. //
  6000. // Initialize the Scb if we need to do so.
  6001. //
  6002. if (!IndexedAttribute) {
  6003. if (!FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  6004. NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
  6005. }
  6006. if (!FlagOn( IrpSp->Parameters.Create.Options,
  6007. FILE_NO_INTERMEDIATE_BUFFERING )) {
  6008. SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
  6009. }
  6010. //
  6011. // If this is the unnamed data attribute, we store the sizes
  6012. // in the Fcb.
  6013. //
  6014. if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  6015. ThisFcb->Info.AllocatedLength = Scb->TotalAllocated;
  6016. ThisFcb->Info.FileSize = Scb->Header.FileSize.QuadPart;
  6017. }
  6018. }
  6019. //
  6020. // Next add this entry to parent. It is possible that this is a link,
  6021. // an Ntfs name, a DOS name or Ntfs/Dos name. We use the filename
  6022. // attribute structure from earlier, but need to add more information.
  6023. //
  6024. NtfsAddLink( IrpContext,
  6025. (BOOLEAN) !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE ),
  6026. ParentScb,
  6027. ThisFcb,
  6028. FileNameAttr,
  6029. &LoggedFileRecord,
  6030. &FileNameFlags,
  6031. &ThisLcb->QuickIndex,
  6032. (HaveTunneledInformation? &NamePair : NULL),
  6033. *IndexContext );
  6034. //
  6035. // We created the Lcb without knowing the correct value for the
  6036. // flags. We update it now.
  6037. //
  6038. ThisLcb->FileNameAttr->Flags = FileNameFlags;
  6039. FileNameAttr->Flags = FileNameFlags;
  6040. //
  6041. // We also have to fix up the ExactCaseLink of the Lcb since we may have had
  6042. // a short name create turned into a tunneled long name create, meaning that
  6043. // it should be full uppercase. And the filename in the IRP.
  6044. //
  6045. if (FileNameFlags == FILE_NAME_DOS) {
  6046. RtlUpcaseUnicodeString(&ThisLcb->ExactCaseLink.LinkName, &ThisLcb->ExactCaseLink.LinkName, FALSE);
  6047. RtlUpcaseUnicodeString(&IrpSp->FileObject->FileName, &IrpSp->FileObject->FileName, FALSE);
  6048. }
  6049. //
  6050. // Clear the flags in the Fcb that indicate we need to update on
  6051. // disk structures. Also clear any file object and Ccb flags
  6052. // which also indicate we may need to do an update.
  6053. //
  6054. ThisFcb->InfoFlags = 0;
  6055. ClearFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  6056. ClearFlag( IrpSp->FileObject->Flags,
  6057. FO_FILE_MODIFIED | FO_FILE_FAST_IO_READ | FO_FILE_SIZE_CHANGED );
  6058. ClearFlag( (*ThisCcb)->Flags,
  6059. (CCB_FLAG_UPDATE_LAST_MODIFY |
  6060. CCB_FLAG_UPDATE_LAST_CHANGE |
  6061. CCB_FLAG_SET_ARCHIVE) );
  6062. //
  6063. // This code is still necessary for non-upgraded volumes.
  6064. //
  6065. NtfsAssignSecurity( IrpContext,
  6066. ParentScb->Fcb,
  6067. Irp,
  6068. ThisFcb,
  6069. FileRecord,
  6070. FileRecordBcb,
  6071. FileRecordOffset,
  6072. &LoggedFileRecord );
  6073. //
  6074. // Log the file record.
  6075. //
  6076. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  6077. Vcb->MftScb,
  6078. FileRecordBcb,
  6079. InitializeFileRecordSegment,
  6080. FileRecord,
  6081. FileRecord->FirstFreeByte,
  6082. Noop,
  6083. NULL,
  6084. 0,
  6085. FileRecordOffset,
  6086. 0,
  6087. 0,
  6088. Vcb->BytesPerFileRecordSegment );
  6089. //
  6090. // Now add the eas for the file. We need to add them now because
  6091. // they are logged and we have to make sure we don't modify the
  6092. // attribute record after adding them.
  6093. //
  6094. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  6095. NtfsAddEa( IrpContext,
  6096. Vcb,
  6097. ThisFcb,
  6098. (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer,
  6099. IrpSp->Parameters.Create.EaLength,
  6100. &Irp->IoStatus );
  6101. }
  6102. //
  6103. // Change the last modification time and last change time for the
  6104. // parent.
  6105. //
  6106. NtfsUpdateFcb( ParentScb->Fcb,
  6107. (FCB_INFO_CHANGED_LAST_CHANGE |
  6108. FCB_INFO_CHANGED_LAST_MOD |
  6109. FCB_INFO_UPDATE_LAST_ACCESS) );
  6110. //
  6111. // If this is the paging file, we want to be sure the allocation
  6112. // is loaded.
  6113. //
  6114. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) {
  6115. Cluster = Int64ShraMod32(Scb->Header.AllocationSize.QuadPart, Scb->Vcb->ClusterShift);
  6116. NtfsPreloadAllocation( IrpContext, Scb, 0, Cluster );
  6117. //
  6118. // Now make sure the allocation is correctly loaded. The last
  6119. // Vcn should correspond to the allocation size for the file.
  6120. //
  6121. if (!NtfsLookupLastNtfsMcbEntry( &Scb->Mcb,
  6122. &Vcn,
  6123. &Lcn ) ||
  6124. (Vcn + 1) != Cluster) {
  6125. NtfsRaiseStatus( IrpContext,
  6126. STATUS_FILE_CORRUPT_ERROR,
  6127. NULL,
  6128. ThisFcb );
  6129. }
  6130. }
  6131. //
  6132. // If everything has gone well so far, we may want to call the
  6133. // encryption callback if one is registered.
  6134. //
  6135. // We need to do this now because the encryption driver may fail
  6136. // the create, and we don't want that to happen _after_ we've
  6137. // added the entry to the prefix table.
  6138. //
  6139. NtfsEncryptionCreateCallback( IrpContext,
  6140. Irp,
  6141. IrpSp,
  6142. *ThisScb,
  6143. *ThisCcb,
  6144. ThisFcb,
  6145. ParentScb->Fcb,
  6146. TRUE );
  6147. //
  6148. // Now that there are no other failures, but *before* inserting the prefix
  6149. // entry and returning to code that assumes it cannot fail, we will post the
  6150. // UsnJournal change and actually attempt to write the UsnJournal. Then we
  6151. // actually commit the transaction in order to reduce UsnJournal contention.
  6152. // This call must be made _after_ the call to NtfsInitializeFcbAndStdInfo,
  6153. // since that's where the object id gets set from the tunnel cache, and we
  6154. // wouldn't want to post the usn reason for the object id change if we
  6155. // haven't actually set the object id yet.
  6156. //
  6157. NtfsPostUsnChange( IrpContext, ThisFcb, (UsnReasons | USN_REASON_FILE_CREATE) );
  6158. //
  6159. // If this is a directory open and the normalized name is not in
  6160. // the Scb then do so now. We should always have a normalized name in the
  6161. // parent to build from.
  6162. //
  6163. if ((SafeNodeType( *ThisScb ) == NTFS_NTC_SCB_INDEX) &&
  6164. ((*ThisScb)->ScbType.Index.NormalizedName.Length == 0)) {
  6165. //
  6166. // We may be able to use the parent.
  6167. //
  6168. if (ParentScb->ScbType.Index.NormalizedName.Length != 0) {
  6169. NtfsUpdateNormalizedName( IrpContext,
  6170. ParentScb,
  6171. *ThisScb,
  6172. FileNameAttr,
  6173. FALSE );
  6174. }
  6175. }
  6176. //
  6177. // Now, if anything at all is posted to the Usn Journal, we must write it now
  6178. // so that we do not get a log file full later.
  6179. //
  6180. ASSERT( IrpContext->Usn.NextUsnFcb == NULL );
  6181. if (IrpContext->Usn.CurrentUsnFcb != NULL) {
  6182. //
  6183. // Now write the journal, checkpoint the transaction, and free the UsnJournal to
  6184. // reduce contention.
  6185. //
  6186. NtfsWriteUsnJournalChanges( IrpContext );
  6187. NtfsCheckpointCurrentTransaction( IrpContext );
  6188. }
  6189. //
  6190. // We report to our parent that we created a new file.
  6191. //
  6192. if (!FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID ) && (Vcb->NotifyCount != 0)) {
  6193. NtfsReportDirNotify( IrpContext,
  6194. ThisFcb->Vcb,
  6195. &(*ThisCcb)->FullFileName,
  6196. (*ThisCcb)->LastFileNameOffset,
  6197. NULL,
  6198. ((FlagOn( (*ThisCcb)->Flags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  6199. ((*ThisCcb)->Lcb != NULL) &&
  6200. ((*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName.Buffer != 0)) ?
  6201. &(*ThisCcb)->Lcb->Scb->ScbType.Index.NormalizedName :
  6202. NULL),
  6203. (IndexedAttribute
  6204. ? FILE_NOTIFY_CHANGE_DIR_NAME
  6205. : FILE_NOTIFY_CHANGE_FILE_NAME),
  6206. FILE_ACTION_ADDED,
  6207. ParentScb->Fcb );
  6208. }
  6209. ThisFcb->InfoFlags = 0;
  6210. //
  6211. // Insert the hash entry for this as well.
  6212. //
  6213. if ((CreateContext->FileHashLength != 0) &&
  6214. !FlagOn( CcbFlags, CCB_FLAG_PARENT_HAS_DOS_COMPONENT ) &&
  6215. (ThisLcb->FileNameAttr->Flags != FILE_NAME_DOS) ) {
  6216. //
  6217. // Remove any exising hash value.
  6218. //
  6219. if (FlagOn( ThisLcb->LcbState, LCB_STATE_VALID_HASH_VALUE )) {
  6220. NtfsRemoveHashEntriesForLcb( ThisLcb );
  6221. }
  6222. NtfsInsertHashEntry( &Vcb->HashTable,
  6223. ThisLcb,
  6224. CreateContext->FileHashLength,
  6225. CreateContext->FileHashValue );
  6226. #ifdef NTFS_HASH_DATA
  6227. Vcb->HashTable.CreateNewFileInsert += 1;
  6228. #endif
  6229. }
  6230. //
  6231. // Now we insert the Lcb for this Fcb.
  6232. //
  6233. NtfsInsertPrefix( ThisLcb, CreateFlags );
  6234. Irp->IoStatus.Information = FILE_CREATED;
  6235. //
  6236. // If we'll be calling a post create callout, make sure
  6237. // NtfsEncryptionCreateCallback set this Fcb bit.
  6238. //
  6239. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_EFS_CREATE ) &&
  6240. FlagOn( IrpContext->State, IRP_CONTEXT_STATE_PERSISTENT ) &&
  6241. FlagOn( IrpContext->EncryptionFileDirFlags, FILE_NEW )) {
  6242. ASSERT( FlagOn( ThisFcb->FcbState, FCB_STATE_ENCRYPTION_PENDING ) );
  6243. }
  6244. }
  6245. try_exit: NOTHING;
  6246. } finally {
  6247. DebugUnwind( NtfsCreateNewFile );
  6248. if (AcquiredFcbTable) {
  6249. NtfsReleaseFcbTable( IrpContext, Vcb );
  6250. }
  6251. NtfsUnpinBcb( IrpContext, &FileRecordBcb );
  6252. if (CleanupAttrContext) {
  6253. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  6254. }
  6255. if (DecrementCloseCount) {
  6256. InterlockedDecrement( &ThisFcb->CloseCount );
  6257. }
  6258. if (FlagOn( CreateFlags, CREATE_FLAG_ACQUIRED_OBJECT_ID_INDEX )) {
  6259. NtfsReleaseScb( IrpContext, Vcb->ObjectIdTableScb );
  6260. ClearFlag( CreateFlags, CREATE_FLAG_ACQUIRED_OBJECT_ID_INDEX );
  6261. }
  6262. if (NamePair.Long.Buffer != NamePair.LongBuffer) {
  6263. NtfsFreePool(NamePair.Long.Buffer);
  6264. }
  6265. if (SharedSecurity != NULL) {
  6266. ASSERT( ThisFcb == NULL || ThisFcb->SharedSecurity == NULL );
  6267. NtfsAcquireFcbSecurity( Vcb );
  6268. RemoveReferenceSharedSecurityUnsafe( &SharedSecurity );
  6269. NtfsReleaseFcbSecurity( Vcb );
  6270. }
  6271. //
  6272. // We need to cleanup any changes to the in memory
  6273. // structures if there is an error.
  6274. //
  6275. if (!NT_SUCCESS( Status ) || AbnormalTermination()) {
  6276. ASSERT( !(AbnormalTermination()) || IrpContext->ExceptionStatus != STATUS_SUCCESS );
  6277. if (*IndexContext != NULL) {
  6278. NtfsCleanupIndexContext( IrpContext, *IndexContext );
  6279. *IndexContext = NULL;
  6280. }
  6281. NtfsBackoutFailedOpens( IrpContext,
  6282. IrpSp->FileObject,
  6283. ThisFcb,
  6284. *ThisScb,
  6285. *ThisCcb );
  6286. //
  6287. // Derefence the quota control block if it was not assigned
  6288. // to the FCB.
  6289. //
  6290. if (QuotaControl != NULL) {
  6291. NtfsDereferenceQuotaControlBlock( Vcb, &QuotaControl );
  6292. }
  6293. //
  6294. // Always force the Fcb to reinitialized.
  6295. //
  6296. if (ThisFcb != NULL) {
  6297. PSCB Scb;
  6298. PLIST_ENTRY Links;
  6299. ClearFlag( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED );
  6300. //
  6301. // Mark the Fcb and all Scb's as deleted to force all subsequent
  6302. // operations to fail.
  6303. //
  6304. SetFlag( ThisFcb->FcbState, FCB_STATE_FILE_DELETED );
  6305. //
  6306. // We need to mark all of the Scbs as gone.
  6307. //
  6308. for (Links = ThisFcb->ScbQueue.Flink;
  6309. Links != &ThisFcb->ScbQueue;
  6310. Links = Links->Flink) {
  6311. Scb = CONTAINING_RECORD( Links, SCB, FcbLinks );
  6312. Scb->ValidDataToDisk =
  6313. Scb->Header.AllocationSize.QuadPart =
  6314. Scb->Header.FileSize.QuadPart =
  6315. Scb->Header.ValidDataLength.QuadPart = 0;
  6316. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  6317. }
  6318. //
  6319. // Clear the Scb field so our caller doesn't try to teardown
  6320. // from this point.
  6321. //
  6322. *ThisScb = NULL;
  6323. //
  6324. // If we created an Fcb then we want to check if we need to
  6325. // unwind any structure allocation. We don't want to remove any
  6326. // structures needed for the coming AbortTransaction. This
  6327. // includes the parent Scb as well as the current Fcb if we
  6328. // logged the ACL creation.
  6329. //
  6330. //
  6331. // Make sure the parent Fcb doesn't go away. Then
  6332. // start a teardown from the Fcb we just found.
  6333. //
  6334. InterlockedIncrement( &ParentScb->CleanupCount );
  6335. NtfsTeardownStructures( IrpContext,
  6336. ThisFcb,
  6337. NULL,
  6338. LoggedFileRecord,
  6339. 0,
  6340. &RemovedFcb );
  6341. //
  6342. // If the Fcb was removed then both the Fcb and Lcb are gone.
  6343. //
  6344. if (RemovedFcb) {
  6345. ThisFcb = NULL;
  6346. ThisLcb = NULL;
  6347. }
  6348. InterlockedDecrement( &ParentScb->CleanupCount );
  6349. }
  6350. }
  6351. //
  6352. // If the new Fcb is still present then either return it as the
  6353. // deepest Fcb encountered in this open or release it.
  6354. //
  6355. if (ThisFcb != NULL) {
  6356. //
  6357. // If the Lcb is present then this is part of the tree. Our
  6358. // caller knows to release it.
  6359. //
  6360. if (ThisLcb != NULL) {
  6361. *LcbForTeardown = ThisLcb;
  6362. *CurrentFcb = ThisFcb;
  6363. }
  6364. }
  6365. ASSERT( QuotaControl == NULL );
  6366. DebugTrace( -1, Dbg, ("NtfsCreateNewFile: Exit -> %08lx\n", Status) );
  6367. }
  6368. return Status;
  6369. }
  6370. //
  6371. // Local support routine
  6372. //
  6373. PLCB
  6374. NtfsOpenSubdirectory (
  6375. IN PIRP_CONTEXT IrpContext,
  6376. IN PSCB ParentScb,
  6377. IN UNICODE_STRING Name,
  6378. IN ULONG CreateFlags,
  6379. OUT PFCB *CurrentFcb,
  6380. OUT PLCB *LcbForTeardown,
  6381. IN PINDEX_ENTRY IndexEntry
  6382. )
  6383. /*++
  6384. Routine Description:
  6385. This routine will create an Fcb for an intermediate node on an open path.
  6386. We use the ParentScb and the information in the FileName attribute returned
  6387. from the disk to create the Fcb and create a link between the Scb and Fcb.
  6388. It's possible that the Fcb and Lcb already exist but the 'CreateXcb' calls
  6389. handle that already. This routine does not expect to fail.
  6390. Arguments:
  6391. ParentScb - This is the Scb for the parent directory.
  6392. Name - This is the name for the entry.
  6393. CreateFlags - Indicates if this open is using traverse access checking.
  6394. CurrentFcb - This is the address to store the Fcb if we successfully find
  6395. one in the Fcb/Scb tree.
  6396. LcbForTeardown - This is the Lcb to use in teardown if we add an Lcb
  6397. into the tree.
  6398. IndexEntry - This is the entry found in searching the parent directory.
  6399. Return Value:
  6400. PLCB - Pointer to the Link control block between the Fcb and its parent.
  6401. --*/
  6402. {
  6403. PFCB ThisFcb;
  6404. PLCB ThisLcb;
  6405. PFCB LocalFcbForTeardown = NULL;
  6406. BOOLEAN AcquiredFcbTable = FALSE;
  6407. BOOLEAN ExistingFcb;
  6408. PVCB Vcb = ParentScb->Vcb;
  6409. PAGED_CODE();
  6410. DebugTrace( +1, Dbg, ("NtfsOpenSubdirectory: Entered\n") );
  6411. DebugTrace( 0, Dbg, ("ParentScb -> %08lx\n") );
  6412. DebugTrace( 0, Dbg, ("IndexEntry -> %08lx\n") );
  6413. //
  6414. // Use a try-finally to facilitate cleanup.
  6415. //
  6416. try {
  6417. NtfsAcquireFcbTable( IrpContext, Vcb );
  6418. AcquiredFcbTable = TRUE;
  6419. //
  6420. // The steps here are very simple create the Fcb, remembering if it
  6421. // already existed. We don't update the information in the Fcb as
  6422. // we can't rely on the information in the duplicated information.
  6423. // A subsequent open of this Fcb will need to perform that work.
  6424. //
  6425. ThisFcb = NtfsCreateFcb( IrpContext,
  6426. ParentScb->Vcb,
  6427. IndexEntry->FileReference,
  6428. FALSE,
  6429. TRUE,
  6430. &ExistingFcb );
  6431. ThisFcb->ReferenceCount += 1;
  6432. //
  6433. // If we created this Fcb we must make sure to start teardown
  6434. // on it.
  6435. //
  6436. if (!ExistingFcb) {
  6437. LocalFcbForTeardown = ThisFcb;
  6438. } else {
  6439. *CurrentFcb = ThisFcb;
  6440. *LcbForTeardown = NULL;
  6441. }
  6442. //
  6443. // Try to do a fast acquire, otherwise we need to release
  6444. // the Fcb table, acquire the Fcb, acquire the Fcb table to
  6445. // dereference Fcb. Just do an acquire for system files under the root i.e $Extend - this will match
  6446. // their canonical order
  6447. //
  6448. if (FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE) &&
  6449. (NtfsSegmentNumber( &ParentScb->Fcb->FileReference ) == ROOT_FILE_NAME_INDEX_NUMBER)) {
  6450. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  6451. NtfsReleaseFcbTable( IrpContext, Vcb );
  6452. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  6453. NtfsAcquireFcbTable( IrpContext, Vcb );
  6454. } else if (!NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, ACQUIRE_DONT_WAIT )) {
  6455. ParentScb->Fcb->ReferenceCount += 1;
  6456. InterlockedIncrement( &ParentScb->CleanupCount );
  6457. //
  6458. // Set the IrpContext to acquire paging io resources if our target
  6459. // has one. This will lock the MappedPageWriter out of this file.
  6460. //
  6461. if (ThisFcb->PagingIoResource != NULL) {
  6462. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING );
  6463. }
  6464. //
  6465. // Release the fcb table first because its an end resource and release
  6466. // scb with paging might reacquire a fast mutex if freeing snapshots
  6467. //
  6468. NtfsReleaseFcbTable( IrpContext, Vcb );
  6469. NtfsReleaseScbWithPaging( IrpContext, ParentScb );
  6470. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  6471. NtfsAcquireExclusiveScb( IrpContext, ParentScb );
  6472. NtfsAcquireFcbTable( IrpContext, Vcb );
  6473. InterlockedDecrement( &ParentScb->CleanupCount );
  6474. ParentScb->Fcb->ReferenceCount -= 1;
  6475. }
  6476. ThisFcb->ReferenceCount -= 1;
  6477. NtfsReleaseFcbTable( IrpContext, Vcb );
  6478. AcquiredFcbTable = FALSE;
  6479. //
  6480. // If this is a directory, it's possible that we hav an existing Fcb
  6481. // in the prefix table which needs to be initialized from the disk.
  6482. // We look in the InfoInitialized flag to know whether to go to
  6483. // disk.
  6484. //
  6485. ThisLcb = NtfsCreateLcb( IrpContext,
  6486. ParentScb,
  6487. ThisFcb,
  6488. Name,
  6489. ((PFILE_NAME) NtfsFoundIndexEntry( IndexEntry ))->Flags,
  6490. NULL );
  6491. LocalFcbForTeardown = NULL;
  6492. *LcbForTeardown = ThisLcb;
  6493. *CurrentFcb = ThisFcb;
  6494. if (!FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  6495. NtfsUpdateFcbInfoFromDisk( IrpContext,
  6496. BooleanFlagOn( CreateFlags, CREATE_FLAG_TRAVERSE_CHECK ),
  6497. ThisFcb,
  6498. NULL );
  6499. NtfsConditionallyFixupQuota( IrpContext, ThisFcb );
  6500. }
  6501. } finally {
  6502. DebugUnwind( NtfsOpenSubdirectory );
  6503. if (AcquiredFcbTable) {
  6504. NtfsReleaseFcbTable( IrpContext, Vcb );
  6505. }
  6506. //
  6507. // If we are to cleanup the Fcb we, look to see if we created it.
  6508. // If we did we can call our teardown routine. Otherwise we
  6509. // leave it alone.
  6510. //
  6511. if (LocalFcbForTeardown != NULL) {
  6512. NtfsTeardownStructures( IrpContext,
  6513. ThisFcb,
  6514. NULL,
  6515. FALSE,
  6516. 0,
  6517. NULL );
  6518. }
  6519. DebugTrace( -1, Dbg, ("NtfsOpenSubdirectory: Lcb -> %08lx\n", ThisLcb) );
  6520. }
  6521. return ThisLcb;
  6522. }
  6523. //
  6524. // Local support routine.
  6525. //
  6526. NTSTATUS
  6527. NtfsOpenAttributeInExistingFile (
  6528. IN PIRP_CONTEXT IrpContext,
  6529. IN PIRP Irp,
  6530. IN PIO_STACK_LOCATION IrpSp,
  6531. IN PLCB ThisLcb OPTIONAL,
  6532. IN PFCB ThisFcb,
  6533. IN ULONG LastFileNameOffset,
  6534. IN UNICODE_STRING AttrName,
  6535. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  6536. IN ULONG CcbFlags,
  6537. IN ULONG CreateFlags,
  6538. IN PVOID NetworkInfo OPTIONAL,
  6539. OUT PSCB *ThisScb,
  6540. OUT PCCB *ThisCcb
  6541. )
  6542. /*++
  6543. Routine Description:
  6544. This routine is the worker routine for opening an attribute on an
  6545. existing file. It will handle volume opens, indexed opens, opening
  6546. or overwriting existing attributes as well as creating new attributes.
  6547. Arguments:
  6548. Irp - This is the Irp for this open operation.
  6549. IrpSp - This is the stack location for this open.
  6550. ThisLcb - This is the Lcb we used to reach this Fcb.
  6551. ThisFcb - This is the Fcb for the file being opened.
  6552. LastFileNameOffset - This is the offset in the full path name of the
  6553. final component.
  6554. AttrName - This is the attribute name in case we need to create
  6555. an Scb.
  6556. AttrTypeCode - This is the attribute type code to use to create
  6557. the Scb.
  6558. CcbFlags - This is the flag field for the Ccb.
  6559. CreateFlags - Indicates if this open is an open by Id.
  6560. NetworkInfo - If specified then this call is a fast open call to query
  6561. the network information. We don't update any of the in-memory structures
  6562. for this.
  6563. ThisScb - This is the address to store the Scb from this open.
  6564. ThisCcb - This is the address to store the Ccb from this open.
  6565. Return Value:
  6566. NTSTATUS - The result of opening this indexed attribute.
  6567. --*/
  6568. {
  6569. NTSTATUS Status = STATUS_SUCCESS;
  6570. ULONG CreateDisposition;
  6571. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  6572. BOOLEAN FoundAttribute;
  6573. PAGED_CODE();
  6574. DebugTrace( +1, Dbg, ("NtfsOpenAttributeInExistingFile: Entered\n") );
  6575. //
  6576. // When the Fcb denotes a reparse point, it will be retrieved below by one of
  6577. // NtfsOpenExistingAttr, NtfsOverwriteAttr or this routine prior to calling
  6578. // NtfsOpenNewAttr.
  6579. //
  6580. // We do not retrieve the reparse point here, as we could, because in
  6581. // NtfsOpenExistingAttr and in NtfsOverwriteAttr there are extensive access
  6582. // control checks that need to be preserved. NtfsOpenNewAttr has no access
  6583. // checks.
  6584. //
  6585. //
  6586. // If the caller is ea blind, let's check the need ea count on the
  6587. // file. We skip this check if he is accessing a named data stream.
  6588. //
  6589. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE )
  6590. && FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  6591. PEA_INFORMATION ThisEaInformation;
  6592. ATTRIBUTE_ENUMERATION_CONTEXT EaInfoAttrContext;
  6593. NtfsInitializeAttributeContext( &EaInfoAttrContext );
  6594. //
  6595. // Use a try-finally to facilitate cleanup.
  6596. //
  6597. try {
  6598. //
  6599. // If we find the Ea information attribute we look in there for
  6600. // Need ea count.
  6601. //
  6602. if (NtfsLookupAttributeByCode( IrpContext,
  6603. ThisFcb,
  6604. &ThisFcb->FileReference,
  6605. $EA_INFORMATION,
  6606. &EaInfoAttrContext )) {
  6607. ThisEaInformation = (PEA_INFORMATION) NtfsAttributeValue( NtfsFoundAttribute( &EaInfoAttrContext ));
  6608. if (ThisEaInformation->NeedEaCount != 0) {
  6609. Status = STATUS_ACCESS_DENIED;
  6610. }
  6611. }
  6612. } finally {
  6613. NtfsCleanupAttributeContext( IrpContext, &EaInfoAttrContext );
  6614. }
  6615. if (Status != STATUS_SUCCESS) {
  6616. DebugTrace( -1, Dbg, ("NtfsOpenAttributeInExistingFile: Exit - %x\n", Status) );
  6617. return Status;
  6618. }
  6619. }
  6620. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  6621. //
  6622. // If the result is a directory operation, then we know the attribute
  6623. // must exist.
  6624. //
  6625. if (AttrTypeCode == $INDEX_ALLOCATION) {
  6626. //
  6627. // If this is not a file name index then we need to verify that the specified index
  6628. // exists. We need to look for the $INDEX_ROOT attribute though not the
  6629. // $INDEX_ALLOCATION attribute.
  6630. //
  6631. if ((AttrName.Buffer != NtfsFileNameIndex.Buffer) || FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  6632. NtfsInitializeAttributeContext( &AttrContext );
  6633. //
  6634. // Use a try-finally to facilitate cleanup.
  6635. //
  6636. try {
  6637. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  6638. ThisFcb,
  6639. &ThisFcb->FileReference,
  6640. $INDEX_ROOT,
  6641. &AttrName,
  6642. NULL,
  6643. (BOOLEAN) !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE ),
  6644. &AttrContext );
  6645. } finally {
  6646. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  6647. }
  6648. //
  6649. // If we didn't find the name then we want to fail the request.
  6650. //
  6651. if (!FoundAttribute) {
  6652. if ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OVERWRITE)) {
  6653. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  6654. } else {
  6655. Status = STATUS_ACCESS_DENIED;
  6656. }
  6657. DebugTrace( -1, Dbg, ("NtfsOpenAttributeInExistingFile: Exit - %x\n", Status) );
  6658. return Status;
  6659. }
  6660. }
  6661. //
  6662. // Check the create disposition.
  6663. //
  6664. if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
  6665. Status = (ThisLcb == ThisFcb->Vcb->RootLcb
  6666. ? STATUS_ACCESS_DENIED
  6667. : STATUS_OBJECT_NAME_COLLISION);
  6668. } else {
  6669. Status = NtfsOpenExistingAttr( IrpContext,
  6670. Irp,
  6671. IrpSp,
  6672. ThisLcb,
  6673. ThisFcb,
  6674. LastFileNameOffset,
  6675. AttrName,
  6676. $INDEX_ALLOCATION,
  6677. CcbFlags,
  6678. CreateFlags,
  6679. TRUE,
  6680. NetworkInfo,
  6681. ThisScb,
  6682. ThisCcb );
  6683. //
  6684. // The IsEncrypted test below is meaningless for an uninitialized Fcb.
  6685. //
  6686. ASSERT( FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED ) );
  6687. if ((Status == STATUS_SUCCESS) &&
  6688. ARGUMENT_PRESENT( NetworkInfo ) &&
  6689. IsEncrypted( &ThisFcb->Info )) {
  6690. //
  6691. // We need to initialize the Scb now, otherwise we won't have set the
  6692. // encryption bit in the index Scb's attribute flags, and we will not
  6693. // return the right file attributes to the network opener.
  6694. //
  6695. if ((*ThisScb)->ScbType.Index.BytesPerIndexBuffer == 0) {
  6696. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  6697. NtfsInitializeAttributeContext( &AttrContext );
  6698. //
  6699. // Use a try-finally to facilitate cleanup.
  6700. //
  6701. try {
  6702. if (NtfsLookupAttributeByCode( IrpContext,
  6703. ThisFcb,
  6704. &ThisFcb->FileReference,
  6705. $INDEX_ROOT,
  6706. &AttrContext )) {
  6707. NtfsUpdateIndexScbFromAttribute( IrpContext,
  6708. *ThisScb,
  6709. NtfsFoundAttribute( &AttrContext ),
  6710. FALSE );
  6711. } else {
  6712. Status = STATUS_FILE_CORRUPT_ERROR;
  6713. }
  6714. } finally {
  6715. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  6716. }
  6717. if (Status != STATUS_SUCCESS) {
  6718. DebugTrace( -1, Dbg, ("NtfsOpenAttributeInExistingFile: Exit - %x\n", Status) );
  6719. return Status;
  6720. }
  6721. }
  6722. }
  6723. }
  6724. } else {
  6725. //
  6726. // If it exists, we first check if the caller wanted to open that attribute.
  6727. // If the open is for a system file then look for that attribute explicitly.
  6728. //
  6729. if ((AttrName.Length == 0) &&
  6730. (AttrTypeCode == $DATA) &&
  6731. !FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  6732. FoundAttribute = TRUE;
  6733. //
  6734. // Otherwise we see if the attribute exists.
  6735. //
  6736. } else {
  6737. //
  6738. // Check that we own the paging io resource. If we are creating the stream and
  6739. // need to break up the allocation then we must own the paging IO resource.
  6740. //
  6741. ASSERT( !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) ||
  6742. (IrpContext->CleanupStructure != NULL) ||
  6743. (ThisFcb->PagingIoResource == NULL) ||
  6744. (ThisFcb == ThisFcb->Vcb->RootIndexScb->Fcb) );
  6745. NtfsInitializeAttributeContext( &AttrContext );
  6746. //
  6747. // Use a try-finally to facilitate cleanup.
  6748. //
  6749. try {
  6750. FoundAttribute = NtfsLookupAttributeByName( IrpContext,
  6751. ThisFcb,
  6752. &ThisFcb->FileReference,
  6753. AttrTypeCode,
  6754. &AttrName,
  6755. NULL,
  6756. (BOOLEAN) !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE ),
  6757. &AttrContext );
  6758. if (FoundAttribute && ($DATA == AttrTypeCode)) {
  6759. //
  6760. // If there is an attribute name, we will copy the case of the name
  6761. // to the input attribute name for data streams. For others the storage is common read-only regions.
  6762. //
  6763. PATTRIBUTE_RECORD_HEADER FoundAttribute;
  6764. FoundAttribute = NtfsFoundAttribute( &AttrContext );
  6765. RtlCopyMemory( AttrName.Buffer,
  6766. Add2Ptr( FoundAttribute, FoundAttribute->NameOffset ),
  6767. AttrName.Length );
  6768. }
  6769. } finally {
  6770. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  6771. }
  6772. }
  6773. if (FoundAttribute) {
  6774. //
  6775. // In this case we call our routine to open this attribute.
  6776. //
  6777. if ((CreateDisposition == FILE_OPEN) ||
  6778. (CreateDisposition == FILE_OPEN_IF)) {
  6779. Status = NtfsOpenExistingAttr( IrpContext,
  6780. Irp,
  6781. IrpSp,
  6782. ThisLcb,
  6783. ThisFcb,
  6784. LastFileNameOffset,
  6785. AttrName,
  6786. AttrTypeCode,
  6787. CcbFlags,
  6788. CreateFlags,
  6789. FALSE,
  6790. NetworkInfo,
  6791. ThisScb,
  6792. ThisCcb );
  6793. if ((Status != STATUS_PENDING) &&
  6794. (*ThisScb != NULL)) {
  6795. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB );
  6796. }
  6797. //
  6798. // If he wanted to overwrite this attribute, we call our overwrite routine.
  6799. //
  6800. } else if ((CreateDisposition == FILE_SUPERSEDE) ||
  6801. (CreateDisposition == FILE_OVERWRITE) ||
  6802. (CreateDisposition == FILE_OVERWRITE_IF)) {
  6803. if (!NtfsIsVolumeReadOnly( IrpContext->Vcb )) {
  6804. //
  6805. // Check if mm will allow us to modify this file.
  6806. //
  6807. Status = NtfsOverwriteAttr( IrpContext,
  6808. Irp,
  6809. IrpSp,
  6810. ThisLcb,
  6811. ThisFcb,
  6812. (BOOLEAN) (CreateDisposition == FILE_SUPERSEDE),
  6813. LastFileNameOffset,
  6814. AttrName,
  6815. AttrTypeCode,
  6816. CcbFlags,
  6817. CreateFlags,
  6818. ThisScb,
  6819. ThisCcb );
  6820. //
  6821. // Remember that this Scb was modified.
  6822. //
  6823. if ((Status != STATUS_PENDING) &&
  6824. (*ThisScb != NULL)) {
  6825. SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED );
  6826. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB );
  6827. }
  6828. } else {
  6829. //
  6830. // We can't do any overwrite/supersede on R/O media.
  6831. //
  6832. Status = STATUS_MEDIA_WRITE_PROTECTED;
  6833. }
  6834. //
  6835. // Otherwise he is trying to create the attribute.
  6836. //
  6837. } else {
  6838. Status = STATUS_OBJECT_NAME_COLLISION;
  6839. }
  6840. //
  6841. // The attribute doesn't exist. If the user expected it to exist, we fail.
  6842. // Otherwise we call our routine to create an attribute.
  6843. //
  6844. } else if ((CreateDisposition == FILE_OPEN) ||
  6845. (CreateDisposition == FILE_OVERWRITE)) {
  6846. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  6847. } else {
  6848. //
  6849. // Perform the open check for this existing file.
  6850. //
  6851. Status = NtfsCheckExistingFile( IrpContext,
  6852. IrpSp,
  6853. ThisLcb,
  6854. ThisFcb,
  6855. CcbFlags );
  6856. //
  6857. // End-of-name call to retrieve a reparse point.
  6858. // As NtfsOpenNewAttr has not access checks, we see whether we need to
  6859. // retrieve the reparse point here, prior to calling NtfsOpenNewAttr.
  6860. // The file information in ThisFcb tells whether this is a reparse point.
  6861. //
  6862. // If we have succeded in the previous check and we do not have
  6863. // FILE_OPEN_REPARSE_POINT set, we retrieve the reparse point.
  6864. //
  6865. if (NT_SUCCESS( Status ) &&
  6866. FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ) &&
  6867. !FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )) {
  6868. USHORT AttributeNameLength = 0;
  6869. //
  6870. // We exclude the case when we get the $I30 name and $INDEX_ALLOCATION type
  6871. // as this is the standard manner of opening a directory.
  6872. //
  6873. if (!((AttrName.Length == NtfsFileNameIndex.Length) &&
  6874. (AttrTypeCode == $INDEX_ALLOCATION) &&
  6875. (RtlEqualMemory( AttrName.Buffer, NtfsFileNameIndex.Buffer, AttrName.Length )))) {
  6876. if (AttrName.Length > 0) {
  6877. ASSERT( AttrName.Length == ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeNameLength );
  6878. AttributeNameLength += AttrName.Length + 2;
  6879. }
  6880. if (((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength > 0) {
  6881. AttributeNameLength += ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength + 2;
  6882. }
  6883. }
  6884. DebugTrace( 0, Dbg, ("AttrTypeCode %x AttrName.Length (1) = %d AttributeCodeNameLength %d LastFileNameOffset %d\n",
  6885. AttrTypeCode, AttrName.Length, ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength, LastFileNameOffset) );
  6886. Status = NtfsGetReparsePointValue( IrpContext,
  6887. Irp,
  6888. IrpSp,
  6889. ThisFcb,
  6890. AttributeNameLength );
  6891. }
  6892. //
  6893. // If this didn't fail and we did not encounter a reparse point,
  6894. // then attempt to create the stream.
  6895. //
  6896. if (NT_SUCCESS( Status ) &&
  6897. (Status != STATUS_REPARSE)) {
  6898. //
  6899. // Don't allow this operation on a system file (except the root directory which can have user data streams)
  6900. // or for anything other than user data streams
  6901. //
  6902. if ((FlagOn( ThisFcb->FcbState, FCB_STATE_SYSTEM_FILE ) &&
  6903. (NtfsSegmentNumber( &ThisFcb->FileReference ) != ROOT_FILE_NAME_INDEX_NUMBER)) ||
  6904. (!NtfsIsTypeCodeUserData( AttrTypeCode ))) {
  6905. Status = STATUS_ACCESS_DENIED;
  6906. } else if (!NtfsIsVolumeReadOnly( IrpContext->Vcb )) {
  6907. NtfsPostUsnChange( IrpContext, ThisFcb, USN_REASON_STREAM_CHANGE );
  6908. Status = NtfsOpenNewAttr( IrpContext,
  6909. Irp,
  6910. IrpSp,
  6911. ThisLcb,
  6912. ThisFcb,
  6913. LastFileNameOffset,
  6914. AttrName,
  6915. AttrTypeCode,
  6916. FALSE,
  6917. CcbFlags,
  6918. TRUE,
  6919. CreateFlags,
  6920. ThisScb,
  6921. ThisCcb );
  6922. } else {
  6923. Status = STATUS_MEDIA_WRITE_PROTECTED;
  6924. }
  6925. }
  6926. if (*ThisScb != NULL) {
  6927. if (*ThisCcb != NULL) {
  6928. SetFlag( (*ThisCcb)->Flags,
  6929. CCB_FLAG_UPDATE_LAST_CHANGE | CCB_FLAG_SET_ARCHIVE );
  6930. }
  6931. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CREATE_MOD_SCB );
  6932. }
  6933. }
  6934. }
  6935. DebugTrace( -1, Dbg, ("NtfsOpenAttributeInExistingFile: Exit - %x\n", Status) );
  6936. return Status;
  6937. }
  6938. //
  6939. // Local support routine.
  6940. //
  6941. NTSTATUS
  6942. NtfsOpenExistingAttr (
  6943. IN PIRP_CONTEXT IrpContext,
  6944. IN PIRP Irp,
  6945. IN PIO_STACK_LOCATION IrpSp,
  6946. IN PLCB ThisLcb OPTIONAL,
  6947. IN PFCB ThisFcb,
  6948. IN ULONG LastFileNameOffset,
  6949. IN UNICODE_STRING AttrName,
  6950. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  6951. IN ULONG CcbFlags,
  6952. IN ULONG CreateFlags,
  6953. IN BOOLEAN DirectoryOpen,
  6954. IN PVOID NetworkInfo OPTIONAL,
  6955. OUT PSCB *ThisScb,
  6956. OUT PCCB *ThisCcb
  6957. )
  6958. /*++
  6959. Routine Description:
  6960. This routine is called to open an existing attribute. We check the
  6961. requested file access, the existance of
  6962. an Ea buffer and the security on this file. If these succeed then
  6963. we check the batch oplocks and regular oplocks on the file.
  6964. We also verify whether we need to retrieve a reparse point or not.
  6965. If we have gotten this far, we simply call our routine to open the
  6966. attribute.
  6967. Arguments:
  6968. Irp - This is the Irp for this open operation.
  6969. IrpSp - This is the Irp stack pointer for the filesystem.
  6970. ThisLcb - This is the Lcb used to reach this Fcb.
  6971. ThisFcb - This is the Fcb to open.
  6972. LastFileNameOffset - This is the offset in the full path name of the
  6973. final component.
  6974. AttrName - This is the attribute name in case we need to create
  6975. an Scb.
  6976. AttrTypeCode - This is the attribute type code to use to create
  6977. the Scb.
  6978. CcbFlags - This is the flag field for the Ccb.
  6979. CreateFlags - Indicates if this open is by file Id.
  6980. DirectoryOpen - Indicates whether this open is a directory open or a data stream.
  6981. NetworkInfo - If specified then this call is a fast open call to query
  6982. the network information. We don't update any of the in-memory structures
  6983. for this.
  6984. ThisScb - This is the address to store the address of the Scb.
  6985. ThisCcb - This is the address to store the address of the Ccb.
  6986. Return Value:
  6987. NTSTATUS - The result of opening this indexed attribute.
  6988. --*/
  6989. {
  6990. NTSTATUS Status = STATUS_SUCCESS;
  6991. NTSTATUS OplockStatus;
  6992. SHARE_MODIFICATION_TYPE ShareModificationType;
  6993. TYPE_OF_OPEN TypeOfOpen;
  6994. PAGED_CODE();
  6995. DebugTrace( +1, Dbg, ("NtfsOpenExistingAttr: Entered\n") );
  6996. //
  6997. // For data streams we need to do a check that includes an oplock check.
  6998. // For directories we just need to figure the share modification type.
  6999. //
  7000. // We also figure the type of open and the node type code based on the
  7001. // directory flag.
  7002. //
  7003. if (DirectoryOpen) {
  7004. //
  7005. // Check for valid access on an existing file.
  7006. //
  7007. Status = NtfsCheckExistingFile( IrpContext,
  7008. IrpSp,
  7009. ThisLcb,
  7010. ThisFcb,
  7011. CcbFlags );
  7012. ShareModificationType = (ThisFcb->CleanupCount == 0 ? SetShareAccess : CheckShareAccess);
  7013. TypeOfOpen = UserDirectoryOpen;
  7014. } else {
  7015. //
  7016. // Don't break the batch oplock if opening to query the network info.
  7017. //
  7018. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  7019. Status = NtfsBreakBatchOplock( IrpContext,
  7020. Irp,
  7021. IrpSp,
  7022. ThisFcb,
  7023. AttrName,
  7024. AttrTypeCode,
  7025. ThisScb );
  7026. if (Status != STATUS_PENDING) {
  7027. if (NT_SUCCESS( Status = NtfsCheckExistingFile( IrpContext,
  7028. IrpSp,
  7029. ThisLcb,
  7030. ThisFcb,
  7031. CcbFlags ))) {
  7032. Status = NtfsOpenAttributeCheck( IrpContext,
  7033. Irp,
  7034. IrpSp,
  7035. ThisScb,
  7036. &ShareModificationType );
  7037. TypeOfOpen = UserFileOpen ;
  7038. }
  7039. }
  7040. //
  7041. // We want to perform the ACL check but not break any oplocks for the
  7042. // NetworkInformation query.
  7043. //
  7044. } else {
  7045. Status = NtfsCheckExistingFile( IrpContext,
  7046. IrpSp,
  7047. ThisLcb,
  7048. ThisFcb,
  7049. CcbFlags );
  7050. TypeOfOpen = UserFileOpen;
  7051. ASSERT( NtfsIsTypeCodeUserData( AttrTypeCode ));
  7052. }
  7053. }
  7054. //
  7055. // End-of-name call to retrieve a reparse point.
  7056. // The file information in ThisFcb tells whether this is a reparse point.
  7057. //
  7058. // In three cases we proceed with the normal open for the file:
  7059. //
  7060. // (1) When FILE_OPEN_REPARSE_POINT is set, as the caller wants a handle on the
  7061. // reparse point itself.
  7062. // (2) When we are retrieving the NetworkInfo, as then the caller can identify
  7063. // the reparse points and decide what to do, without having the need of apriori
  7064. // knowledge of where they are in the system.
  7065. // Note: when we retrieve NetworkInfo we can have FILE_OPEN_REPARSE_POINT set.
  7066. // (3) The data manipulation aspect of the DesiredAccess for this request was, exactly,
  7067. // FILE_READ_ATTRIBUTES, in which case we give a handle to the local entity.
  7068. //
  7069. // Otherwise, we retrieve the value of the $REPARSE_POINT attribute.
  7070. //
  7071. // Note: The logic in the if was re-arranged for performance. It used to read:
  7072. //
  7073. // NT_SUCCESS( Status ) &&
  7074. // (Status != STATUS_PENDING) &&
  7075. // !ARGUMENT_PRESENT( NetworkInfo ) &&
  7076. // FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ) &&
  7077. // !FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )
  7078. //
  7079. if ((Status != STATUS_PENDING) &&
  7080. FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ) &&
  7081. NT_SUCCESS( Status ) &&
  7082. !FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )) {
  7083. USHORT AttributeNameLength = 0;
  7084. //
  7085. // We exclude the case when we get the $I30 name and $INDEX_ALLOCATION type
  7086. // as this is the standard manner of opening a directory.
  7087. //
  7088. if (!((AttrName.Length == NtfsFileNameIndex.Length) &&
  7089. (AttrTypeCode == $INDEX_ALLOCATION) &&
  7090. (RtlEqualMemory( AttrName.Buffer, NtfsFileNameIndex.Buffer, AttrName.Length )))) {
  7091. if (AttrName.Length > 0) {
  7092. ASSERT( AttrName.Length == ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeNameLength );
  7093. AttributeNameLength += AttrName.Length + 2;
  7094. }
  7095. if (((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength > 0) {
  7096. AttributeNameLength += ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength + 2;
  7097. }
  7098. }
  7099. DebugTrace( 0, Dbg, ("AttrTypeCode %x AttrName.Length (2) = %d AttributeCodeNameLength %d LastFileNameOffset %d\n",
  7100. AttrTypeCode, AttrName.Length, ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength, LastFileNameOffset) );
  7101. Status = NtfsGetReparsePointValue( IrpContext,
  7102. Irp,
  7103. IrpSp,
  7104. ThisFcb,
  7105. AttributeNameLength );
  7106. }
  7107. //
  7108. // If we didn't post the Irp and we did not retrieve a reparse point
  7109. // and the operations above were successful, we proceed with the open.
  7110. //
  7111. if (NT_SUCCESS( Status ) &&
  7112. (Status != STATUS_PENDING) &&
  7113. (Status != STATUS_REPARSE)) {
  7114. //
  7115. // Now actually open the attribute.
  7116. //
  7117. OplockStatus = Status;
  7118. Status = NtfsOpenAttribute( IrpContext,
  7119. IrpSp,
  7120. ThisFcb->Vcb,
  7121. ThisLcb,
  7122. ThisFcb,
  7123. LastFileNameOffset,
  7124. AttrName,
  7125. AttrTypeCode,
  7126. ShareModificationType,
  7127. TypeOfOpen,
  7128. FALSE,
  7129. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  7130. ? CcbFlags | CCB_FLAG_OPEN_BY_FILE_ID
  7131. : CcbFlags),
  7132. NetworkInfo,
  7133. ThisScb,
  7134. ThisCcb );
  7135. //
  7136. // If there are no errors at this point, we set the caller's Iosb.
  7137. //
  7138. if (NT_SUCCESS( Status )) {
  7139. //
  7140. // We need to remember if the oplock break is in progress.
  7141. //
  7142. Status = OplockStatus;
  7143. Irp->IoStatus.Information = FILE_OPENED;
  7144. }
  7145. }
  7146. DebugTrace( -1, Dbg, ("NtfsOpenExistingAttr: Exit -> %08lx\n", Status) );
  7147. return Status;
  7148. }
  7149. //
  7150. // Local support routine.
  7151. //
  7152. NTSTATUS
  7153. NtfsOverwriteAttr (
  7154. IN PIRP_CONTEXT IrpContext,
  7155. IN PIRP Irp,
  7156. IN PIO_STACK_LOCATION IrpSp,
  7157. IN PLCB ThisLcb OPTIONAL,
  7158. IN PFCB ThisFcb,
  7159. IN BOOLEAN Supersede,
  7160. IN ULONG LastFileNameOffset,
  7161. IN UNICODE_STRING AttrName,
  7162. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  7163. IN ULONG CcbFlags,
  7164. IN ULONG CreateFlags,
  7165. OUT PSCB *ThisScb,
  7166. OUT PCCB *ThisCcb
  7167. )
  7168. /*++
  7169. Routine Description:
  7170. This routine is called to overwrite an existing attribute. We do all of
  7171. the same work as opening an attribute except that we can change the
  7172. allocation of a file. This routine will handle the case where a
  7173. file is being overwritten and the case where just an attribute is
  7174. being overwritten. In the case of the former, we may change the
  7175. file attributes of the file as well as modify the Ea's on the file.
  7176. After doing all the access checks, we also verify whether we need to
  7177. retrieve a reparse point or not.
  7178. Arguments:
  7179. Irp - This is the Irp for this open operation.
  7180. IrpSp - This is the stack location for this open.
  7181. ThisLcb - This is the Lcb we used to reach this Fcb.
  7182. ThisFcb - This is the Fcb for the file being opened.
  7183. Supersede - This indicates whether this is a supersede or overwrite
  7184. operation.
  7185. LastFileNameOffset - This is the offset in the full path name of the
  7186. final component.
  7187. AttrName - This is the attribute name in case we need to create
  7188. an Scb.
  7189. AttrTypeCode - This is the attribute type code to use to create
  7190. the Scb.
  7191. CcbFlags - This is the flag field for the Ccb.
  7192. CreateFlags - Indicates if this open is by file Id.
  7193. ThisScb - This is the address to store the address of the Scb.
  7194. ThisCcb - This is the address to store the address of the Ccb.
  7195. Return Value:
  7196. NTSTATUS - The result of opening this indexed attribute.
  7197. --*/
  7198. {
  7199. NTSTATUS Status = STATUS_SUCCESS;
  7200. NTSTATUS OplockStatus;
  7201. ULONG FileAttributes;
  7202. ULONG PreviousFileAttributes;
  7203. PACCESS_MASK DesiredAccess;
  7204. ACCESS_MASK AddedAccess = 0;
  7205. BOOLEAN MaximumRequested = FALSE;
  7206. SHARE_MODIFICATION_TYPE ShareModificationType;
  7207. PFILE_FULL_EA_INFORMATION FullEa = NULL;
  7208. ULONG FullEaLength = 0;
  7209. ULONG IncomingFileAttributes = 0; // invalid value
  7210. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  7211. BOOLEAN DecrementScbCloseCount = FALSE;
  7212. PAGED_CODE();
  7213. DebugTrace( +1, Dbg, ("NtfsOverwriteAttr: Entered\n") );
  7214. DesiredAccess = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  7215. if (FlagOn( *DesiredAccess, MAXIMUM_ALLOWED )) {
  7216. MaximumRequested = TRUE;
  7217. }
  7218. //
  7219. // Check the oplock state of this file.
  7220. //
  7221. Status = NtfsBreakBatchOplock( IrpContext,
  7222. Irp,
  7223. IrpSp,
  7224. ThisFcb,
  7225. AttrName,
  7226. AttrTypeCode,
  7227. ThisScb );
  7228. if (Status == STATUS_PENDING) {
  7229. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7230. return Status;
  7231. }
  7232. //
  7233. // Remember the value of the file attribute flags and of the reparse point.
  7234. // If we succeed in NtfsRemoveReparsePoint but fail afterwards, we leave the duplicate
  7235. // information in an inconsistent state.
  7236. //
  7237. IncomingFileAttributes = ThisFcb->Info.FileAttributes;
  7238. IncomingReparsePointTag = ThisFcb->Info.ReparsePointTag;
  7239. //
  7240. // We first want to check that the caller's desired access and specified
  7241. // file attributes are compatible with the state of the file. There
  7242. // are the two overwrite cases to consider.
  7243. //
  7244. // OverwriteFile - The hidden and system bits passed in by the
  7245. // caller must match the current values.
  7246. //
  7247. // OverwriteAttribute - We also modify the requested desired access
  7248. // to explicitly add the implicit access needed by overwrite.
  7249. //
  7250. // We also check that for the overwrite attribute case, there isn't
  7251. // an Ea buffer specified.
  7252. //
  7253. if (FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  7254. BOOLEAN Hidden;
  7255. BOOLEAN System;
  7256. //
  7257. // Get the file attributes and clear any unsupported bits.
  7258. //
  7259. FileAttributes = (ULONG) IrpSp->Parameters.Create.FileAttributes;
  7260. //
  7261. // Always set the archive bit in this operation.
  7262. //
  7263. SetFlag( FileAttributes, FILE_ATTRIBUTE_ARCHIVE );
  7264. ClearFlag( FileAttributes,
  7265. ~FILE_ATTRIBUTE_VALID_SET_FLAGS | FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED );
  7266. if (IsEncrypted( &ThisFcb->Info )) {
  7267. SetFlag( FileAttributes, FILE_ATTRIBUTE_ENCRYPTED );
  7268. }
  7269. DebugTrace( 0, Dbg, ("Checking hidden/system for overwrite/supersede\n") );
  7270. Hidden = BooleanIsHidden( &ThisFcb->Info );
  7271. System = BooleanIsSystem( &ThisFcb->Info );
  7272. if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)
  7273. ||
  7274. System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))
  7275. &&
  7276. !FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE )) {
  7277. DebugTrace( 0, Dbg, ("The hidden and/or system bits do not match\n") );
  7278. Status = STATUS_ACCESS_DENIED;
  7279. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7280. return Status;
  7281. }
  7282. //
  7283. // If the user specified an Ea buffer and they are Ea blind, we deny
  7284. // access.
  7285. //
  7286. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE ) &&
  7287. (Irp->AssociatedIrp.SystemBuffer != NULL)) {
  7288. DebugTrace( 0, Dbg, ("This opener cannot create Ea's\n") );
  7289. Status = STATUS_ACCESS_DENIED;
  7290. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7291. return Status;
  7292. }
  7293. //
  7294. // Add in the extra required access bits if we don't have restore privilege
  7295. // which would automatically grant them to us
  7296. //
  7297. if (!FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  7298. !FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE )) {
  7299. SetFlag( AddedAccess,
  7300. (FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) );
  7301. SetFlag( *DesiredAccess, FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES );
  7302. }
  7303. } else if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  7304. DebugTrace( 0, Dbg, ("Can't specifiy an Ea buffer on an attribute overwrite\n") );
  7305. Status = STATUS_INVALID_PARAMETER;
  7306. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7307. return Status;
  7308. }
  7309. //
  7310. // Supersede or overwrite require specific access. We skip this step if we have the restore privilege
  7311. // which already grants these to us
  7312. //
  7313. if (!FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ) &&
  7314. !FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE )) {
  7315. ULONG NewAccess = FILE_WRITE_DATA;
  7316. if (Supersede) {
  7317. NewAccess = DELETE;
  7318. }
  7319. //
  7320. // Check if the user already has this new access.
  7321. //
  7322. if (!FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  7323. NewAccess )) {
  7324. SetFlag( AddedAccess,
  7325. NewAccess & ~(*DesiredAccess) );
  7326. SetFlag( *DesiredAccess, NewAccess );
  7327. }
  7328. }
  7329. //
  7330. // Check whether we can open this existing file.
  7331. //
  7332. Status = NtfsCheckExistingFile( IrpContext,
  7333. IrpSp,
  7334. ThisLcb,
  7335. ThisFcb,
  7336. CcbFlags );
  7337. //
  7338. // If we have a success status then proceed with the oplock check and
  7339. // open the attribute.
  7340. //
  7341. if (NT_SUCCESS( Status )) {
  7342. Status = NtfsOpenAttributeCheck( IrpContext,
  7343. Irp,
  7344. IrpSp,
  7345. ThisScb,
  7346. &ShareModificationType );
  7347. //
  7348. // End-of-name call to retrieve a reparse point.
  7349. // The file information in ThisFcb tells whether this is a reparse point.
  7350. //
  7351. // If we didn't post the Irp and the check operation was successful, and
  7352. // we do not have FILE_OPEN_REPARSE_POINT set, we retrieve the reparse point.
  7353. //
  7354. if (NT_SUCCESS( Status ) &&
  7355. (Status != STATUS_PENDING)) {
  7356. //
  7357. // If we can't truncate the file size then return now. Since
  7358. // NtfsRemoveDataAttributes will be truncating all the data
  7359. // streams for this file, we need to loop through any existing
  7360. // scbs we have to make sure they are all truncatable.
  7361. //
  7362. PSCB Scb = NULL;
  7363. //
  7364. // We need to reset the share access once we open the file. This is because
  7365. // we may have added WRITE or DELETE access into the granted bits and
  7366. // they may be reflected in the file object. We don't want them
  7367. // present after the create.
  7368. //
  7369. if (ShareModificationType == UpdateShareAccess) {
  7370. ShareModificationType = RecheckShareAccess;
  7371. }
  7372. //
  7373. // If we biased the desired access we need to remove the same
  7374. // bits from the granted access. If maximum allowed was
  7375. // requested then we can skip this.
  7376. //
  7377. if (!MaximumRequested) {
  7378. ClearFlag( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  7379. AddedAccess );
  7380. }
  7381. //
  7382. // Also remove the bits from the desired access field so we won't
  7383. // see them if this request gets posted for any reason.
  7384. //
  7385. ClearFlag( *DesiredAccess, AddedAccess );
  7386. if (FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ) &&
  7387. !FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_REPARSE_POINT )) {
  7388. USHORT AttributeNameLength = 0;
  7389. //
  7390. // We exclude the case when we get the $I30 name and $INDEX_ALLOCATION type
  7391. // as this is the standard manner of opening a directory.
  7392. //
  7393. if (!((AttrName.Length == NtfsFileNameIndex.Length) &&
  7394. (AttrTypeCode == $INDEX_ALLOCATION) &&
  7395. (RtlEqualMemory( AttrName.Buffer, NtfsFileNameIndex.Buffer, AttrName.Length )))) {
  7396. if (AttrName.Length > 0) {
  7397. ASSERT( AttrName.Length == ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeNameLength );
  7398. AttributeNameLength += AttrName.Length + 2;
  7399. }
  7400. if (((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength > 0) {
  7401. AttributeNameLength += ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength + 2;
  7402. }
  7403. }
  7404. DebugTrace( 0, Dbg, ("AttrTypeCode %x AttrName.Length (3) = %d AttributeCodeNameLength %d LastFileNameOffset %d\n",
  7405. AttrTypeCode, AttrName.Length, ((POPLOCK_CLEANUP)(IrpContext->Union.OplockCleanup))->AttributeCodeNameLength, LastFileNameOffset) );
  7406. Status = NtfsGetReparsePointValue( IrpContext,
  7407. Irp,
  7408. IrpSp,
  7409. ThisFcb,
  7410. AttributeNameLength );
  7411. //
  7412. // Exit if we failed or this is a reparse point.
  7413. //
  7414. if (!NT_SUCCESS( Status ) || (Status == STATUS_REPARSE)) {
  7415. return Status;
  7416. }
  7417. }
  7418. //
  7419. // Reference the Fcb so it doesn't go away.
  7420. //
  7421. InterlockedIncrement( &ThisFcb->CloseCount );
  7422. //
  7423. // Use a try-finally to restore the close count correctly.
  7424. //
  7425. try {
  7426. //
  7427. // Make sure the current Scb doesn't get deallocated in the test below.
  7428. //
  7429. if (*ThisScb != NULL) {
  7430. InterlockedIncrement( &(*ThisScb)->CloseCount );
  7431. DecrementScbCloseCount = TRUE;
  7432. }
  7433. while (TRUE) {
  7434. Scb = NtfsGetNextChildScb( ThisFcb, Scb );
  7435. if (Scb == NULL) { break; }
  7436. InterlockedIncrement( &Scb->CloseCount );
  7437. if (!MmCanFileBeTruncated( &(Scb)->NonpagedScb->SegmentObject,
  7438. &Li0 )) {
  7439. Status = STATUS_USER_MAPPED_FILE;
  7440. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7441. //
  7442. // The Scb close count will get decremented when we test
  7443. // for Scb != NULL below.
  7444. //
  7445. try_return( Status );
  7446. }
  7447. InterlockedDecrement( &Scb->CloseCount );
  7448. }
  7449. //
  7450. // Remember the status from the oplock check.
  7451. //
  7452. OplockStatus = Status;
  7453. //
  7454. // We perform the on-disk changes. For a file overwrite, this includes
  7455. // the Ea changes and modifying the file attributes. For an attribute,
  7456. // this refers to modifying the allocation size. We need to keep the
  7457. // Fcb updated and remember which values we changed.
  7458. //
  7459. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  7460. //
  7461. // Remember the values in the Irp.
  7462. //
  7463. FullEa = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  7464. FullEaLength = IrpSp->Parameters.Create.EaLength;
  7465. }
  7466. //
  7467. // Now do the file attributes and either remove or mark for
  7468. // delete all of the other $DATA attributes on the file.
  7469. //
  7470. if (FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  7471. //
  7472. // When appropriate, delete the reparse point attribute.
  7473. // This needs to be done prior to any modification to the Fcb, as we use
  7474. // the value of the reparse point tag stored in ThisFcb.Info
  7475. //
  7476. if (FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT )) {
  7477. //
  7478. // Verify that the volume is of the appropriate kind.
  7479. // Otherwise access a non-existing index.
  7480. //
  7481. if (!NtfsVolumeVersionCheck( ThisFcb->Vcb, NTFS_REPARSE_POINT_VERSION )) {
  7482. //
  7483. // Return a volume not upgraded error.
  7484. //
  7485. Status = STATUS_VOLUME_NOT_UPGRADED;
  7486. DebugTrace( 0, Dbg, ("Trying to delete a reparse point in a back-level volume.\n") );
  7487. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7488. try_return( Status );
  7489. }
  7490. //
  7491. // Remove the reparse point attribute.
  7492. //
  7493. NtfsRemoveReparsePoint( IrpContext,
  7494. ThisFcb );
  7495. //
  7496. // NtfsRemoveReparsPoint will commit if it removes the reparse point. Update our
  7497. // captured info values if there is no transaction.
  7498. //
  7499. if (IrpContext->TransactionId == 0) {
  7500. IncomingFileAttributes = ThisFcb->Info.FileAttributes;
  7501. IncomingReparsePointTag = ThisFcb->Info.ReparsePointTag;
  7502. }
  7503. }
  7504. //
  7505. // This needs to happen after we delete the reparse point attribute to not
  7506. // alter the value of the reparse point tag stored in ThisFcb.Info
  7507. // Replace the current Ea's on the file. This operation will update
  7508. // the Fcb for the file.
  7509. //
  7510. NtfsAddEa( IrpContext,
  7511. ThisFcb->Vcb,
  7512. ThisFcb,
  7513. FullEa,
  7514. FullEaLength,
  7515. &Irp->IoStatus );
  7516. //
  7517. // Copy the directory bit from the current Info structure.
  7518. //
  7519. if (IsDirectory( &ThisFcb->Info)) {
  7520. SetFlag( FileAttributes, DUP_FILE_NAME_INDEX_PRESENT );
  7521. }
  7522. //
  7523. // Copy the view index bit from the current Info structure.
  7524. //
  7525. if (IsViewIndex( &ThisFcb->Info)) {
  7526. SetFlag( FileAttributes, DUP_VIEW_INDEX_PRESENT );
  7527. }
  7528. //
  7529. // Remember the previous file attribute to capture the
  7530. // state of the CONTENT_INDEX flag.
  7531. //
  7532. PreviousFileAttributes = ThisFcb->Info.FileAttributes;
  7533. //
  7534. // Now either add to the current attributes or replace them.
  7535. //
  7536. if (Supersede) {
  7537. ThisFcb->Info.FileAttributes = FileAttributes;
  7538. } else {
  7539. ThisFcb->Info.FileAttributes |= FileAttributes;
  7540. }
  7541. //
  7542. // Get rid of any named $DATA attributes in the file.
  7543. //
  7544. NtfsRemoveDataAttributes( IrpContext,
  7545. ThisFcb,
  7546. ThisLcb,
  7547. IrpSp->FileObject,
  7548. LastFileNameOffset,
  7549. CreateFlags );
  7550. //
  7551. // Check if the CONTENT_INDEX bit changed.
  7552. //
  7553. ASSERT( *ThisScb != NULL );
  7554. if (FlagOn( PreviousFileAttributes ^ ThisFcb->Info.FileAttributes,
  7555. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED )) {
  7556. NtfsPostUsnChange( IrpContext, *ThisScb, USN_REASON_INDEXABLE_CHANGE );
  7557. }
  7558. }
  7559. // **** CONSIDER SETTING SCB ENCRYPTED FLAG HERE??? ****
  7560. //
  7561. // Now we perform the operation of opening the attribute.
  7562. //
  7563. NtfsReplaceAttribute( IrpContext,
  7564. IrpSp,
  7565. ThisFcb,
  7566. *ThisScb,
  7567. ThisLcb,
  7568. *(PLONGLONG)&Irp->Overlay.AllocationSize );
  7569. NtfsPostUsnChange( IrpContext, *ThisScb, USN_REASON_DATA_TRUNCATION );
  7570. //
  7571. // If we are overwriting a fle and the user doesn't want it marked as
  7572. // compressed, then change the attribute flag.
  7573. // If we are overwriting a file and its previous state was sparse
  7574. // then also clear the sparse flag.
  7575. //
  7576. if (FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  7577. if (!FlagOn( (*ThisScb)->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  7578. ClearFlag( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  7579. }
  7580. if (!FlagOn( (*ThisScb)->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  7581. ClearFlag( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_SPARSE_FILE );
  7582. }
  7583. }
  7584. //
  7585. // Now attempt to open the attribute.
  7586. //
  7587. ASSERT( NtfsIsTypeCodeUserData( AttrTypeCode ));
  7588. Status = NtfsOpenAttribute( IrpContext,
  7589. IrpSp,
  7590. ThisFcb->Vcb,
  7591. ThisLcb,
  7592. ThisFcb,
  7593. LastFileNameOffset,
  7594. AttrName,
  7595. AttrTypeCode,
  7596. ShareModificationType,
  7597. UserFileOpen,
  7598. FALSE,
  7599. (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID )
  7600. ? CcbFlags | CCB_FLAG_OPEN_BY_FILE_ID
  7601. : CcbFlags),
  7602. NULL,
  7603. ThisScb,
  7604. ThisCcb );
  7605. try_exit: NOTHING;
  7606. } finally {
  7607. //
  7608. // Roll back any temporary changes to the close counts.
  7609. //
  7610. if (DecrementScbCloseCount) {
  7611. InterlockedDecrement( &(*ThisScb)->CloseCount );
  7612. }
  7613. if (Scb != NULL) {
  7614. InterlockedDecrement( &Scb->CloseCount );
  7615. }
  7616. InterlockedDecrement( &ThisFcb->CloseCount );
  7617. //
  7618. // Need to roll-back the value of the reparse point flag in case of
  7619. // problems.
  7620. //
  7621. if (AbnormalTermination()) {
  7622. ThisFcb->Info.FileAttributes = IncomingFileAttributes;
  7623. ThisFcb->Info.ReparsePointTag = IncomingReparsePointTag;
  7624. }
  7625. }
  7626. if (NT_SUCCESS( Status )) {
  7627. //
  7628. // Set the flag in the Scb to indicate that the size of the
  7629. // attribute has changed.
  7630. //
  7631. SetFlag( (*ThisScb)->ScbState, SCB_STATE_NOTIFY_RESIZE_STREAM );
  7632. //
  7633. // Since this is an supersede/overwrite, purge the section
  7634. // so that mappers will see zeros.
  7635. //
  7636. CcPurgeCacheSection( IrpSp->FileObject->SectionObjectPointer,
  7637. NULL,
  7638. 0,
  7639. FALSE );
  7640. //
  7641. // Remember the status of the oplock in the success code.
  7642. //
  7643. Status = OplockStatus;
  7644. //
  7645. // Now update the Iosb information.
  7646. //
  7647. if (Supersede) {
  7648. Irp->IoStatus.Information = FILE_SUPERSEDED;
  7649. } else {
  7650. Irp->IoStatus.Information = FILE_OVERWRITTEN;
  7651. }
  7652. }
  7653. }
  7654. }
  7655. DebugTrace( -1, Dbg, ("NtfsOverwriteAttr: Exit -> %08lx\n", Status) );
  7656. return Status;
  7657. }
  7658. //
  7659. // Local support routine.
  7660. //
  7661. NTSTATUS
  7662. NtfsOpenNewAttr (
  7663. IN PIRP_CONTEXT IrpContext,
  7664. IN PIRP Irp,
  7665. IN PIO_STACK_LOCATION IrpSp,
  7666. IN PLCB ThisLcb,
  7667. IN PFCB ThisFcb,
  7668. IN ULONG LastFileNameOffset,
  7669. IN UNICODE_STRING AttrName,
  7670. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  7671. IN LOGICAL CreateFile,
  7672. IN ULONG CcbFlags,
  7673. IN BOOLEAN LogIt,
  7674. IN ULONG CreateFlags,
  7675. OUT PSCB *ThisScb,
  7676. OUT PCCB *ThisCcb
  7677. )
  7678. /*++
  7679. Routine Description:
  7680. This routine is called to create a new attribute on the disk.
  7681. All access and security checks have been done outside of this
  7682. routine, all we do is create the attribute and open it.
  7683. We test if the attribute will fit in the Mft record. If so we
  7684. create it there. Otherwise we call the create attribute through
  7685. allocation.
  7686. We then open the attribute with our common routine. In the
  7687. resident case the Scb will have all file values set to
  7688. the allocation size. We set the valid data size back to zero
  7689. and mark the Scb as truncate on close.
  7690. Arguments:
  7691. Irp - This is the Irp for this open operation.
  7692. IrpSp - This is the stack location for this open.
  7693. ThisLcb - This is the Lcb we used to reach this Fcb.
  7694. ThisFcb - This is the Fcb for the file being opened.
  7695. LastFileNameOffset - This is the offset in the full path name of the
  7696. final component.
  7697. AttrName - This is the attribute name in case we need to create
  7698. an Scb.
  7699. AttrTypeCode - This is the attribute type code to use to create
  7700. the Scb.
  7701. CreateFile - Indicates if we are in the create file path.
  7702. CcbFlags - This is the flag field for the Ccb.
  7703. LogIt - Indicates if we need to log the create operations.
  7704. CreateFlags - Indicates if this open is related to a OpenByFile open.
  7705. ThisScb - This is the address to store the address of the Scb.
  7706. ThisCcb - This is the address to store the address of the Ccb.
  7707. Return Value:
  7708. NTSTATUS - The result of opening this indexed attribute.
  7709. --*/
  7710. {
  7711. NTSTATUS Status = STATUS_SUCCESS;
  7712. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  7713. BOOLEAN ScbExisted;
  7714. PAGED_CODE();
  7715. DebugTrace( +1, Dbg, ("NtfsOpenNewAttr: Entered\n") );
  7716. //
  7717. // Check that the attribute name is legal. The only restriction is the name length.
  7718. //
  7719. if (AttrName.Length > NTFS_MAX_ATTR_NAME_LEN * sizeof( WCHAR )) {
  7720. DebugTrace( -1, Dbg, ("NtfsOpenNewAttr: Exit -> %08lx\n", Status) );
  7721. return STATUS_OBJECT_NAME_INVALID;
  7722. }
  7723. NtfsInitializeAttributeContext( &AttrContext );
  7724. //
  7725. // Use a try-finally to facilitate cleanup.
  7726. //
  7727. try {
  7728. //
  7729. // We create the Scb because we will use it.
  7730. //
  7731. *ThisScb = NtfsCreateScb( IrpContext,
  7732. ThisFcb,
  7733. AttrTypeCode,
  7734. &AttrName,
  7735. FALSE,
  7736. &ScbExisted );
  7737. //
  7738. // An attribute has gone away but the Scb hasn't left yet.
  7739. // Also mark the header as unitialized.
  7740. //
  7741. ClearFlag( (*ThisScb)->ScbState, SCB_STATE_HEADER_INITIALIZED |
  7742. SCB_STATE_ATTRIBUTE_RESIDENT |
  7743. SCB_STATE_FILE_SIZE_LOADED );
  7744. //
  7745. // If we're creating an alternate stream in an encrypted file, and the
  7746. // loaded encryption driver wants the stream to be encrypted and uncompressed,
  7747. // we need to make sure the new stream is indeed created uncompressed.
  7748. //
  7749. if (IsEncrypted( &ThisFcb->Info ) &&
  7750. (FlagOn( NtfsData.EncryptionCallBackTable.ImplementationFlags, ENCRYPTION_ALL_STREAMS | ENCRYPTION_ALLOW_COMPRESSION ) == ENCRYPTION_ALL_STREAMS)) {
  7751. DebugTrace( 0, Dbg, ("Encrypted file, creating alternate stream uncompressed") );
  7752. SetFlag( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION );
  7753. }
  7754. //
  7755. // Create the attribute on disk and update the Scb and Fcb.
  7756. //
  7757. NtfsCreateAttribute( IrpContext,
  7758. IrpSp,
  7759. ThisFcb,
  7760. *ThisScb,
  7761. ThisLcb,
  7762. *(PLONGLONG)&Irp->Overlay.AllocationSize,
  7763. LogIt,
  7764. FALSE,
  7765. NULL );
  7766. //
  7767. // Now actually open the attribute.
  7768. //
  7769. ASSERT( NtfsIsTypeCodeUserData( AttrTypeCode ));
  7770. Status = NtfsOpenAttribute( IrpContext,
  7771. IrpSp,
  7772. ThisFcb->Vcb,
  7773. ThisLcb,
  7774. ThisFcb,
  7775. LastFileNameOffset,
  7776. AttrName,
  7777. AttrTypeCode,
  7778. (ThisFcb->CleanupCount != 0 ? CheckShareAccess : SetShareAccess),
  7779. UserFileOpen,
  7780. CreateFile,
  7781. (CcbFlags | (FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID ) ? CCB_FLAG_OPEN_BY_FILE_ID : 0)),
  7782. NULL,
  7783. ThisScb,
  7784. ThisCcb );
  7785. //
  7786. // If there are no errors at this point, we set the caller's Iosb.
  7787. //
  7788. if (NT_SUCCESS( Status )) {
  7789. //
  7790. // Read the attribute information from the disk.
  7791. //
  7792. NtfsUpdateScbFromAttribute( IrpContext, *ThisScb, NULL );
  7793. //
  7794. // Set the flag to indicate that we created a stream and also remember to
  7795. // to check if we need to truncate on close.
  7796. //
  7797. NtfsAcquireFsrtlHeader( *ThisScb );
  7798. SetFlag( (*ThisScb)->ScbState,
  7799. SCB_STATE_TRUNCATE_ON_CLOSE | SCB_STATE_NOTIFY_ADD_STREAM );
  7800. //
  7801. // If we created a temporary stream then mark the Scb.
  7802. //
  7803. if (FlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_TEMPORARY )) {
  7804. SetFlag( (*ThisScb)->ScbState, SCB_STATE_TEMPORARY );
  7805. SetFlag( IrpSp->FileObject->Flags, FO_TEMPORARY_FILE );
  7806. }
  7807. NtfsReleaseFsrtlHeader( *ThisScb );
  7808. Irp->IoStatus.Information = FILE_CREATED;
  7809. }
  7810. } finally {
  7811. DebugUnwind( NtfsOpenNewAttr );
  7812. //
  7813. // Uninitialize the attribute context.
  7814. //
  7815. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  7816. DebugTrace( -1, Dbg, ("NtfsOpenNewAttr: Exit -> %08lx\n", Status) );
  7817. }
  7818. return Status;
  7819. }
  7820. //
  7821. // Local support routine
  7822. //
  7823. BOOLEAN
  7824. NtfsParseNameForCreate (
  7825. IN PIRP_CONTEXT IrpContext,
  7826. IN UNICODE_STRING String,
  7827. IN OUT PUNICODE_STRING FileObjectString,
  7828. IN OUT PUNICODE_STRING OriginalString,
  7829. IN OUT PUNICODE_STRING NewNameString,
  7830. OUT PUNICODE_STRING AttrName,
  7831. OUT PUNICODE_STRING AttrCodeName
  7832. )
  7833. /*++
  7834. Routine Description:
  7835. This routine parses the input string and remove any intermediate
  7836. named attributes from intermediate nodes. It verifies that all
  7837. intermediate nodes specify the file name index attribute if any
  7838. at all. On output it will store the modified string which contains
  7839. component names only, into the file object name pointer pointer. It is legal
  7840. for the last component to have attribute strings. We pass those
  7841. back via the attribute name strings. We also construct the string to be stored
  7842. back in the file object if we need to post this request.
  7843. Arguments:
  7844. String - This is the string to normalize.
  7845. FileObjectString - We store the normalized string into this pointer, removing the
  7846. attribute and attribute code strings from all component.
  7847. OriginalString - This is the same as the file object string except we append the
  7848. attribute name and attribute code strings. We assume that the buffer for this
  7849. string is the same as the buffer for the FileObjectString.
  7850. NewNameString - This is the string which contains the full name being parsed.
  7851. If the buffer is different than the buffer for the Original string then any
  7852. character shifts will be duplicated here.
  7853. AttrName - We store the attribute name specified in the last component
  7854. in this string.
  7855. AttrCodeName - We store the attribute code name specified in the last
  7856. component in this string.
  7857. Return Value:
  7858. BOOLEAN - TRUE if the path is legal, FALSE otherwise.
  7859. --*/
  7860. {
  7861. PARSE_TERMINATION_REASON TerminationReason;
  7862. UNICODE_STRING ParsedPath;
  7863. NTFS_NAME_DESCRIPTOR NameDescript;
  7864. BOOLEAN RemovedComplexName = FALSE;
  7865. LONG FileObjectIndex;
  7866. LONG NewNameIndex;
  7867. BOOLEAN SameBuffers = (OriginalString->Buffer == NewNameString->Buffer);
  7868. PCUNICODE_STRING TestAttrName;
  7869. PCUNICODE_STRING TestAttrCodeName;
  7870. POPLOCK_CLEANUP OplockCleanup = IrpContext->Union.OplockCleanup;
  7871. PAGED_CODE();
  7872. DebugTrace( +1, Dbg, ("NtfsParseNameForCreate: Entered\n") );
  7873. //
  7874. // We loop through the input string calling ParsePath to swallow the
  7875. // biggest chunk we can. The main case we want to deal with is
  7876. // when we encounter a non-simple name. If this is not the
  7877. // final component, the attribute name and code type better
  7878. // indicate that this is a directory. The only other special
  7879. // case we consider is the case where the string is an
  7880. // attribute only. This is legal only for the first component
  7881. // of the file, and then only if there is no leading backslash.
  7882. //
  7883. //
  7884. // Initialize some return values.
  7885. //
  7886. AttrName->Length = 0;
  7887. AttrCodeName->Length = 0;
  7888. //
  7889. // Set up the indexes into our starting file object string.
  7890. //
  7891. FileObjectIndex = (LONG) FileObjectString->Length - (LONG) String.Length;
  7892. NewNameIndex = (LONG) NewNameString->Length - (LONG) String.Length;
  7893. //
  7894. // We don't allow trailing colons.
  7895. //
  7896. if (String.Buffer[(String.Length / sizeof( WCHAR )) - 1] == L':') {
  7897. return FALSE;
  7898. }
  7899. if (String.Length != 0) {
  7900. while (TRUE) {
  7901. //
  7902. // Parse the next chunk in the input string.
  7903. //
  7904. TerminationReason = NtfsParsePath( String,
  7905. FALSE,
  7906. &ParsedPath,
  7907. &NameDescript,
  7908. &String );
  7909. //
  7910. // Analyze the termination reason to discover if we can abort the
  7911. // parse process.
  7912. //
  7913. switch (TerminationReason) {
  7914. case NonSimpleName :
  7915. //
  7916. // We will do the work below.
  7917. //
  7918. break;
  7919. case IllegalCharacterInName :
  7920. case VersionNumberPresent :
  7921. case MalFormedName :
  7922. //
  7923. // We simply return an error.
  7924. //
  7925. DebugTrace( -1, Dbg, ("NtfsParseNameForCreate: Illegal character\n") );
  7926. return FALSE;
  7927. case AttributeOnly :
  7928. //
  7929. // This is legal only if it is the only component of a relative open. We
  7930. // test this by checking that we are at the end of string and the file
  7931. // object name has a lead in ':' character or this is the root directory
  7932. // and the lead in characters are '\:'.
  7933. //
  7934. if ((String.Length != 0) ||
  7935. RemovedComplexName ||
  7936. (FileObjectString->Buffer[0] == L'\\' ?
  7937. FileObjectString->Buffer[1] != L':' :
  7938. FileObjectString->Buffer[0] != L':')) {
  7939. DebugTrace( -1, Dbg, ("NtfsParseNameForCreate: Illegal character\n") );
  7940. return FALSE;
  7941. }
  7942. //
  7943. // We can drop down to the EndOfPath case as it will copy over
  7944. // the parsed path portion.
  7945. //
  7946. case EndOfPathReached :
  7947. NOTHING;
  7948. }
  7949. //
  7950. // We add the filename part of the non-simple name to the parsed
  7951. // path. Check if we can include the separator.
  7952. //
  7953. if ((TerminationReason != EndOfPathReached)
  7954. && (FlagOn( NameDescript.FieldsPresent, FILE_NAME_PRESENT_FLAG ))) {
  7955. if (ParsedPath.Length > sizeof( WCHAR )
  7956. || (ParsedPath.Length == sizeof( WCHAR )
  7957. && ParsedPath.Buffer[0] != L'\\')) {
  7958. ParsedPath.Length += sizeof( WCHAR );
  7959. }
  7960. ParsedPath.Length += NameDescript.FileName.Length;
  7961. }
  7962. FileObjectIndex += ParsedPath.Length;
  7963. NewNameIndex += ParsedPath.Length;
  7964. //
  7965. // If the remaining string is empty, then we remember any attributes and
  7966. // exit now.
  7967. //
  7968. if (String.Length == 0) {
  7969. //
  7970. // If the name specified either an attribute or attribute
  7971. // name, we remember them.
  7972. //
  7973. if (FlagOn( NameDescript.FieldsPresent, ATTRIBUTE_NAME_PRESENT_FLAG )) {
  7974. *AttrName = NameDescript.AttributeName;
  7975. }
  7976. if (FlagOn( NameDescript.FieldsPresent, ATTRIBUTE_TYPE_PRESENT_FLAG )) {
  7977. *AttrCodeName = NameDescript.AttributeType;
  7978. }
  7979. break;
  7980. }
  7981. //
  7982. // This can only be the non-simple case. If there is more to the
  7983. // name, then the attributes better describe a directory. We also shift the
  7984. // remaining bytes of the string down.
  7985. //
  7986. ASSERT( FlagOn( NameDescript.FieldsPresent, ATTRIBUTE_NAME_PRESENT_FLAG | ATTRIBUTE_TYPE_PRESENT_FLAG ));
  7987. TestAttrName = FlagOn( NameDescript.FieldsPresent,
  7988. ATTRIBUTE_NAME_PRESENT_FLAG )
  7989. ? &NameDescript.AttributeName
  7990. : &NtfsEmptyString;
  7991. TestAttrCodeName = FlagOn( NameDescript.FieldsPresent,
  7992. ATTRIBUTE_TYPE_PRESENT_FLAG )
  7993. ? &NameDescript.AttributeType
  7994. : &NtfsEmptyString;
  7995. //
  7996. // Valid Complex names are [$I30]:$INDEX_ALLOCATION
  7997. // [$I30]:$BITMAP
  7998. // :$ATTRIBUTE_LIST
  7999. // :$REPARSE_POINT
  8000. //
  8001. if (!NtfsVerifyNameIsDirectory( IrpContext,
  8002. TestAttrName,
  8003. TestAttrCodeName ) &&
  8004. !NtfsVerifyNameIsBitmap( IrpContext,
  8005. TestAttrName,
  8006. TestAttrCodeName ) &&
  8007. !NtfsVerifyNameIsAttributeList( IrpContext,
  8008. TestAttrName,
  8009. TestAttrCodeName ) &&
  8010. !NtfsVerifyNameIsReparsePoint( IrpContext,
  8011. TestAttrName,
  8012. TestAttrCodeName )) {
  8013. DebugTrace( -1, Dbg, ("NtfsParseNameForCreate: Invalid intermediate component\n") );
  8014. return FALSE;
  8015. }
  8016. RemovedComplexName = TRUE;
  8017. //
  8018. // We need to insert a separator and then move the rest of the string
  8019. // down.
  8020. //
  8021. FileObjectString->Buffer[FileObjectIndex / sizeof( WCHAR )] = L'\\';
  8022. if (!SameBuffers) {
  8023. NewNameString->Buffer[NewNameIndex / sizeof( WCHAR )] = L'\\';
  8024. }
  8025. FileObjectIndex += sizeof( WCHAR );
  8026. NewNameIndex += sizeof( WCHAR );
  8027. RtlMoveMemory( &FileObjectString->Buffer[FileObjectIndex / sizeof( WCHAR )],
  8028. String.Buffer,
  8029. String.Length );
  8030. if (!SameBuffers) {
  8031. RtlMoveMemory( &NewNameString->Buffer[NewNameIndex / sizeof( WCHAR )],
  8032. String.Buffer,
  8033. String.Length );
  8034. }
  8035. String.Buffer = &NewNameString->Buffer[NewNameIndex / sizeof( WCHAR )];
  8036. }
  8037. }
  8038. //
  8039. // At this point the original string is the same as the file object string.
  8040. //
  8041. FileObjectString->Length = (USHORT) FileObjectIndex;
  8042. NewNameString->Length = (USHORT) NewNameIndex;
  8043. OriginalString->Length = FileObjectString->Length;
  8044. //
  8045. // We want to store the attribute index values in the original name
  8046. // string. We just need to extend the original name length.
  8047. //
  8048. if (AttrName->Length != 0
  8049. || AttrCodeName->Length != 0) {
  8050. OriginalString->Length += (2 + AttrName->Length);
  8051. if (AttrCodeName->Length != 0) {
  8052. OriginalString->Length += (2 + AttrCodeName->Length);
  8053. }
  8054. }
  8055. //
  8056. // Store in the OPLOCK_CLEANUP structure the lengths of the names of the attribute and
  8057. // of the code.
  8058. //
  8059. OplockCleanup->AttributeNameLength = AttrName->Length;
  8060. OplockCleanup->AttributeCodeNameLength = AttrCodeName->Length;
  8061. DebugTrace( 0, Dbg, ("AttrName->Length %d AttrCodeName->Length %d\n", OplockCleanup->AttributeNameLength, OplockCleanup->AttributeCodeNameLength) );
  8062. DebugTrace( -1, Dbg, ("NtfsParseNameForCreate: Exit\n") );
  8063. return TRUE;
  8064. }
  8065. //
  8066. // Local support routine.
  8067. //
  8068. BOOLEAN
  8069. NtfsCheckValidFileAccess(
  8070. IN PFCB ThisFcb,
  8071. IN PIO_STACK_LOCATION IrpSp
  8072. )
  8073. /*++
  8074. Routine Description:
  8075. Common routine used to rule out access to files in open path. This only disallows
  8076. always invalid open reqests / acl checks, oplocks sharing are done elsewhere
  8077. Fail immediately if this is a special system file or the user wants an illegal access.
  8078. We allow READ_ATTRIBUTES and some ACL access to a subset of system files. Deny all
  8079. access to the following files.
  8080. USN Journal
  8081. Volume Log File
  8082. Volume Bitmap
  8083. Boot File
  8084. Bad Cluster File
  8085. As of now undefined system files
  8086. Check for supersede/overwrite first.
  8087. Arguments:
  8088. Fcb - Address of the Fcb pointer where the $REPARSE_POINT attribute is located.
  8089. IrpSp - This is the Irp stack pointer for the filesystem.
  8090. Return Value:
  8091. TRUE if access is allowed
  8092. --*/
  8093. {
  8094. ULONG CreateDisposition = (UCHAR) ((IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
  8095. ULONG InvalidAccess;
  8096. BOOLEAN Result = TRUE;
  8097. PAGED_CODE()
  8098. //
  8099. // Verify we don't have the system flag set on the root.
  8100. //
  8101. ASSERT( NtfsSegmentNumber( &ThisFcb->FileReference ) != ROOT_FILE_NAME_INDEX_NUMBER );
  8102. if ((CreateDisposition == FILE_SUPERSEDE) ||
  8103. (CreateDisposition == FILE_OVERWRITE) ||
  8104. (CreateDisposition == FILE_OVERWRITE_IF) ||
  8105. //
  8106. // Check for special system files.
  8107. //
  8108. (NtfsSegmentNumber( &ThisFcb->FileReference ) == LOG_FILE_NUMBER) ||
  8109. (NtfsSegmentNumber( &ThisFcb->FileReference ) == BIT_MAP_FILE_NUMBER) ||
  8110. (NtfsSegmentNumber( &ThisFcb->FileReference ) == BOOT_FILE_NUMBER) ||
  8111. (NtfsSegmentNumber( &ThisFcb->FileReference ) == BAD_CLUSTER_FILE_NUMBER) ||
  8112. FlagOn( ThisFcb->FcbState, FCB_STATE_USN_JOURNAL ) ||
  8113. //
  8114. // Check for currently undefined system files.
  8115. //
  8116. ((NtfsSegmentNumber( &ThisFcb->FileReference ) < FIRST_USER_FILE_NUMBER) &&
  8117. (NtfsSegmentNumber( &ThisFcb->FileReference ) > LAST_SYSTEM_FILE_NUMBER))) {
  8118. Result = FALSE;
  8119. } else {
  8120. //
  8121. // If we are beyond the reserved range then use the ACL to protect the file.
  8122. //
  8123. if (NtfsSegmentNumber( &ThisFcb->FileReference ) >= FIRST_USER_FILE_NUMBER) {
  8124. InvalidAccess = 0;
  8125. //
  8126. // If we are looking at the $Extend directory then permit the ACL operations.
  8127. //
  8128. } else if (NtfsSegmentNumber( &ThisFcb->FileReference ) == EXTEND_NUMBER) {
  8129. InvalidAccess = ~(FILE_READ_ATTRIBUTES | SYNCHRONIZE | READ_CONTROL | WRITE_DAC | WRITE_OWNER);
  8130. //
  8131. // Otherwise restrict access severely.
  8132. //
  8133. } else {
  8134. InvalidAccess = ~(FILE_READ_ATTRIBUTES | SYNCHRONIZE);
  8135. }
  8136. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, InvalidAccess )) {
  8137. Result = FALSE;
  8138. }
  8139. }
  8140. return Result;
  8141. }
  8142. NTSTATUS
  8143. NtfsCheckValidAttributeAccess (
  8144. IN PIO_STACK_LOCATION IrpSp,
  8145. IN PVCB Vcb,
  8146. IN PDUPLICATED_INFORMATION Info OPTIONAL,
  8147. IN OUT PUNICODE_STRING AttrName,
  8148. IN UNICODE_STRING AttrCodeName,
  8149. IN ULONG CreateFlags,
  8150. OUT PATTRIBUTE_TYPE_CODE AttrTypeCode,
  8151. OUT PULONG CcbFlags,
  8152. OUT PBOOLEAN IndexedAttribute
  8153. )
  8154. /*++
  8155. Routine Description:
  8156. This routine looks at the file, the specified attribute name and
  8157. code to determine if an attribute of this file may be opened
  8158. by this user. If there is a conflict between the file type
  8159. and the attribute name and code, or the specified type of attribute
  8160. (directory/nondirectory) we will return FALSE.
  8161. We also check that the attribute code string is defined for the
  8162. volume at this time.
  8163. The final check of this routine is just whether a user is allowed
  8164. to open the particular attribute or if Ntfs will guard them.
  8165. Arguments:
  8166. IrpSp - This is the stack location for this open.
  8167. Vcb - This is the Vcb for this volume.
  8168. Info - If specified, this is the duplicated information for this file.
  8169. AttrName - This is the attribute name specified.
  8170. AttrCodeName - This is the attribute code name to use to open the attribute.
  8171. AttrTypeCode - Used to store the attribute type code determined here.
  8172. CreateFlags - Create flags - we care about the trailing backslash
  8173. CcbFlags - We set the Ccb flags here to store in the Ccb later.
  8174. IndexedAttribute - Set to indicate the type of open.
  8175. Return Value:
  8176. NTSTATUS - STATUS_SUCCESS if access is allowed, the status code indicating
  8177. the reason for denial otherwise.
  8178. --*/
  8179. {
  8180. BOOLEAN Indexed;
  8181. ATTRIBUTE_TYPE_CODE AttrType;
  8182. ULONG CreateDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
  8183. PAGED_CODE();
  8184. DebugTrace( +1, Dbg, ("NtfsCheckValidAttributeAccess: Entered\n") );
  8185. //
  8186. // If the user specified a attribute code string, we find the
  8187. // corresponding attribute. If there is no matching attribute
  8188. // type code then we report that this access is invalid.
  8189. //
  8190. if (AttrCodeName.Length != 0) {
  8191. AttrType = NtfsGetAttributeTypeCode( Vcb, &AttrCodeName );
  8192. if (AttrType == $UNUSED) {
  8193. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: Bad attribute name for index\n") );
  8194. return STATUS_INVALID_PARAMETER;
  8195. //
  8196. // If the type code is Index allocation, and this isn't a view index,
  8197. // then the name better be the filename index. If so then we clear the
  8198. // name length value to make our other tests work.
  8199. //
  8200. } else if (AttrType == $INDEX_ALLOCATION) {
  8201. if (AttrName->Length != 0) {
  8202. if (NtfsAreNamesEqual( Vcb->UpcaseTable, AttrName, &NtfsFileNameIndex, TRUE )) {
  8203. AttrName->Length = 0;
  8204. } else {
  8205. //
  8206. // This isn't a filename index, so it better be a view index.
  8207. //
  8208. if (!ARGUMENT_PRESENT(Info) || !IsViewIndex( Info )) {
  8209. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: Bad name for index allocation\n") );
  8210. return STATUS_INVALID_PARAMETER;
  8211. }
  8212. }
  8213. }
  8214. } else if (AttrType != $DATA) {
  8215. //
  8216. // never allow supersede on any other name attributes
  8217. //
  8218. if ((CreateDisposition == FILE_SUPERSEDE) ||
  8219. (CreateDisposition == FILE_OVERWRITE) ||
  8220. (CreateDisposition == FILE_OVERWRITE_IF)) {
  8221. return STATUS_ACCESS_DENIED;
  8222. }
  8223. }
  8224. DebugTrace( 0, Dbg, ("Attribute type code -> %04x\n", AttrType) );
  8225. } else {
  8226. AttrType = $UNUSED;
  8227. }
  8228. //
  8229. // Pull some values out of the Irp and IrpSp.
  8230. //
  8231. Indexed = BooleanFlagOn( IrpSp->Parameters.Create.Options,
  8232. FILE_DIRECTORY_FILE );
  8233. //
  8234. // We need to determine whether the user expects to open an
  8235. // indexed or non-indexed attribute. If either of the
  8236. // directory/non-directory flags in the Irp stack are set,
  8237. // we will use those.
  8238. //
  8239. // Otherwise we need to examine some of the other input parameters.
  8240. // We have the following information:
  8241. //
  8242. // 1 - We may have a duplicated information structure for the file.
  8243. // (Not present on a create).
  8244. // 2 - The user specified the name with a trailing backslash.
  8245. // 3 - The user passed in an attribute name.
  8246. // 4 - The user passed in an attribute type.
  8247. //
  8248. // We first look at the attribute type code and name. If they are
  8249. // both unspecified we determine the type of access by following
  8250. // the following steps.
  8251. //
  8252. // 1 - If there is a duplicated information structure we
  8253. // set the code to $INDEX_ALLOCATION and remember
  8254. // this is indexed. Otherwise this is a $DATA
  8255. // attribute.
  8256. //
  8257. // 2 - If there is a trailing backslash we assume this is
  8258. // an indexed attribute.
  8259. //
  8260. // If have an attribute code type or name, then if the code type is
  8261. // $INDEX_ALLOCATION without a name this is an indexed attribute.
  8262. // Otherwise we assume a non-indexed attribute.
  8263. //
  8264. if (!FlagOn( IrpSp->Parameters.Create.Options,
  8265. FILE_NON_DIRECTORY_FILE | FILE_DIRECTORY_FILE) &&
  8266. (AttrName->Length == 0)) {
  8267. if (AttrType == $UNUSED) {
  8268. if (ARGUMENT_PRESENT( Info )) {
  8269. Indexed = BooleanIsDirectory( Info );
  8270. } else {
  8271. Indexed = FALSE;
  8272. }
  8273. } else if (AttrType == $INDEX_ALLOCATION) {
  8274. Indexed = TRUE;
  8275. }
  8276. } else if (AttrType == $INDEX_ALLOCATION) {
  8277. Indexed = TRUE;
  8278. }
  8279. //
  8280. // If the type code was unspecified, we can assume it from the attribute
  8281. // name and the type of the file. If the file is a directory and
  8282. // there is no attribute name, we assume this is an indexed open.
  8283. // Otherwise it is a non-indexed open.
  8284. //
  8285. if (AttrType == $UNUSED) {
  8286. if (Indexed && AttrName->Length == 0) {
  8287. AttrType = $INDEX_ALLOCATION;
  8288. } else {
  8289. AttrType = $DATA;
  8290. }
  8291. }
  8292. //
  8293. // If the user specified directory all we need to do is check the
  8294. // following condition.
  8295. //
  8296. // 1 - If the file was specified, it must be a directory.
  8297. // 2 - The attribute type code must be $INDEX_ALLOCATION with either:
  8298. // no attribute name
  8299. // or
  8300. // duplicate info present & view index bit set in dupe info
  8301. // 3 - The user isn't trying to open the volume.
  8302. //
  8303. if (Indexed) {
  8304. if ((AttrType != $INDEX_ALLOCATION) ||
  8305. ((AttrName->Length != 0) &&
  8306. ((!ARGUMENT_PRESENT( Info )) || !IsViewIndex( Info )))) {
  8307. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: Conflict in directory\n") );
  8308. return STATUS_NOT_A_DIRECTORY;
  8309. //
  8310. // If there is a current file and it is not a directory and
  8311. // the caller wanted to perform a create. We return
  8312. // STATUS_OBJECT_NAME_COLLISION, otherwise we return STATUS_NOT_A_DIRECTORY.
  8313. //
  8314. } else if (ARGUMENT_PRESENT( Info ) &&
  8315. !IsDirectory( Info ) &&
  8316. !IsViewIndex( Info)) {
  8317. if (((IrpSp->Parameters.Create.Options >> 24) & 0x000000ff) == FILE_CREATE) {
  8318. return STATUS_OBJECT_NAME_COLLISION;
  8319. } else {
  8320. return STATUS_NOT_A_DIRECTORY;
  8321. }
  8322. }
  8323. SetFlag( *CcbFlags, CCB_FLAG_OPEN_AS_FILE );
  8324. //
  8325. // If the user specified a non-directory that means he is opening a non-indexed
  8326. // attribute. We check for the following condition.
  8327. //
  8328. // 1 - Only the unnamed data attribute may be opened for a volume.
  8329. // 2 - We can't be opening an unnamed $INDEX_ALLOCATION attribute.
  8330. //
  8331. } else {
  8332. //
  8333. // Now determine if we are opening the entire file.
  8334. //
  8335. if (AttrType == $DATA) {
  8336. if (AttrName->Length == 0) {
  8337. SetFlag( *CcbFlags, CCB_FLAG_OPEN_AS_FILE );
  8338. }
  8339. } else {
  8340. //
  8341. // For all other attributes only support read attributes access
  8342. //
  8343. if (IrpSp->Parameters.Create.SecurityContext->AccessState->OriginalDesiredAccess & ~(FILE_READ_ATTRIBUTES | SYNCHRONIZE)) {
  8344. return STATUS_ACCESS_DENIED;
  8345. }
  8346. }
  8347. if (ARGUMENT_PRESENT( Info ) &&
  8348. IsDirectory( Info ) &&
  8349. FlagOn( *CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  8350. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: Can't open directory as file\n") );
  8351. return STATUS_FILE_IS_A_DIRECTORY;
  8352. }
  8353. }
  8354. //
  8355. // If we make it this far, lets check that we will allow access to
  8356. // the attribute specified. Typically we only allow the user to
  8357. // access non system files. Also only the Data attributes and
  8358. // attributes created by the user may be opened. We will protect
  8359. // these with boolean flags to allow the developers to enable
  8360. // reading any attributes.
  8361. //
  8362. if (NtfsProtectSystemAttributes) {
  8363. if (!NtfsIsTypeCodeUserData( AttrType ) &&
  8364. ((AttrType != $INDEX_ALLOCATION) || !Indexed) &&
  8365. (AttrType != $BITMAP) &&
  8366. (AttrType != $ATTRIBUTE_LIST) &&
  8367. (AttrType != $REPARSE_POINT) &&
  8368. (AttrType < $FIRST_USER_DEFINED_ATTRIBUTE)) {
  8369. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: System attribute code\n") );
  8370. return STATUS_ACCESS_DENIED;
  8371. }
  8372. }
  8373. //
  8374. // Now check if the trailing backslash is compatible with the
  8375. // file being opened.
  8376. //
  8377. if (FlagOn( CreateFlags, CREATE_FLAG_TRAILING_BACKSLASH )) {
  8378. if (!Indexed ||
  8379. FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
  8380. return STATUS_OBJECT_NAME_INVALID;
  8381. } else {
  8382. Indexed = TRUE;
  8383. AttrType = $INDEX_ALLOCATION;
  8384. }
  8385. }
  8386. //
  8387. // If we are opening the default index allocation stream, set its attribute
  8388. // name appropriately.
  8389. //
  8390. if ((AttrType == $INDEX_ALLOCATION || AttrType == $BITMAP) &&
  8391. AttrName->Length == 0) {
  8392. *AttrName = NtfsFileNameIndex;
  8393. }
  8394. *IndexedAttribute = Indexed;
  8395. *AttrTypeCode = AttrType;
  8396. DebugTrace( -1, Dbg, ("NtfsCheckValidAttributeAccess: Exit\n") );
  8397. return STATUS_SUCCESS;
  8398. }
  8399. //
  8400. // Local support routine.
  8401. //
  8402. NTSTATUS
  8403. NtfsOpenAttributeCheck (
  8404. IN PIRP_CONTEXT IrpContext,
  8405. IN PIRP Irp,
  8406. IN PIO_STACK_LOCATION IrpSp,
  8407. OUT PSCB *ThisScb,
  8408. OUT PSHARE_MODIFICATION_TYPE ShareModificationType
  8409. )
  8410. /*++
  8411. Routine Description:
  8412. This routine is a general routine which checks if an existing
  8413. non-indexed attribute may be opened. It considers only the oplock
  8414. state of the file and the current share access. In the course of
  8415. performing these checks, the Scb for the attribute may be
  8416. created and the share modification for the actual OpenAttribute
  8417. call is determined.
  8418. Arguments:
  8419. Irp - This is the Irp for this open operation.
  8420. IrpSp - This is the stack location for this open.
  8421. ThisScb - Address to store the Scb if found or created.
  8422. ShareModificationType - Address to store the share modification type
  8423. for a subsequent OpenAttribute call.
  8424. Return Value:
  8425. NTSTATUS - The result of opening this indexed attribute.
  8426. --*/
  8427. {
  8428. NTSTATUS Status = STATUS_SUCCESS;
  8429. BOOLEAN DeleteOnClose;
  8430. PAGED_CODE();
  8431. DebugTrace( +1, Dbg, ("NtfsOpenAttributeCheck: Entered\n") );
  8432. //
  8433. // We should already have the Scb for this file.
  8434. //
  8435. ASSERT_SCB( *ThisScb );
  8436. //
  8437. // If there are other opens on this file, we need to check the share
  8438. // access before we check the oplocks. We remember that
  8439. // we did the share access check by simply updating the share
  8440. // access we open the attribute.
  8441. //
  8442. if ((*ThisScb)->CleanupCount != 0) {
  8443. //
  8444. // We check the share access for this file without updating it.
  8445. //
  8446. Status = IoCheckShareAccess( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  8447. IrpSp->Parameters.Create.ShareAccess,
  8448. IrpSp->FileObject,
  8449. &(*ThisScb)->ShareAccess,
  8450. FALSE );
  8451. if (!NT_SUCCESS( Status )) {
  8452. DebugTrace( -1, Dbg, ("NtfsOpenAttributeCheck: Exit -> %08lx\n", Status) );
  8453. return Status;
  8454. }
  8455. DebugTrace( 0, Dbg, ("Check oplock state of existing Scb\n") );
  8456. if (SafeNodeType( *ThisScb ) == NTFS_NTC_SCB_DATA) {
  8457. //
  8458. // If the handle count is greater than 1 then fail this
  8459. // open now if the caller wants a filter oplock.
  8460. //
  8461. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER ) &&
  8462. ((*ThisScb)->CleanupCount > 1)) {
  8463. NtfsRaiseStatus( IrpContext, STATUS_OPLOCK_NOT_GRANTED, NULL, NULL );
  8464. }
  8465. Status = FsRtlCheckOplock( &(*ThisScb)->ScbType.Data.Oplock,
  8466. Irp,
  8467. IrpContext,
  8468. NtfsOplockComplete,
  8469. NtfsOplockPrePostIrp );
  8470. //
  8471. // Update the FastIoField.
  8472. //
  8473. NtfsAcquireFsrtlHeader( *ThisScb );
  8474. (*ThisScb)->Header.IsFastIoPossible = NtfsIsFastIoPossible( *ThisScb );
  8475. NtfsReleaseFsrtlHeader( *ThisScb );
  8476. //
  8477. // If the return value isn't success or oplock break in progress
  8478. // the irp has been posted. We return right now.
  8479. //
  8480. if (Status == STATUS_PENDING) {
  8481. DebugTrace( 0, Dbg, ("Irp posted through oplock routine\n") );
  8482. DebugTrace( -1, Dbg, ("NtfsOpenAttributeCheck: Exit -> %08lx\n", Status) );
  8483. return Status;
  8484. }
  8485. }
  8486. *ShareModificationType = UpdateShareAccess;
  8487. //
  8488. // If the unclean count in the Fcb is 0, we will simply set the
  8489. // share access.
  8490. //
  8491. } else {
  8492. *ShareModificationType = SetShareAccess;
  8493. }
  8494. DeleteOnClose = BooleanFlagOn( IrpSp->Parameters.Create.Options,
  8495. FILE_DELETE_ON_CLOSE );
  8496. //
  8497. // Can't do DELETE_ON_CLOSE on read only volumes.
  8498. //
  8499. if (DeleteOnClose && NtfsIsVolumeReadOnly( (*ThisScb)->Vcb )) {
  8500. DebugTrace( -1, Dbg, ("NtfsOpenAttributeCheck: Exit -> %08lx\n", STATUS_CANNOT_DELETE) );
  8501. return STATUS_CANNOT_DELETE;
  8502. }
  8503. //
  8504. // If the user wants write access access to the file make sure there
  8505. // is process mapping this file as an image. Any attempt to delete
  8506. // the file will be stopped in fileinfo.c
  8507. //
  8508. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  8509. FILE_WRITE_DATA )
  8510. || DeleteOnClose) {
  8511. //
  8512. // Use a try-finally to decrement the open count. This is a little
  8513. // bit of trickery to keep the scb around while we are doing the
  8514. // flush call.
  8515. //
  8516. InterlockedIncrement( &(*ThisScb)->CloseCount );
  8517. try {
  8518. //
  8519. // If there is an image section then we better have the file
  8520. // exclusively.
  8521. //
  8522. if ((*ThisScb)->NonpagedScb->SegmentObject.ImageSectionObject != NULL) {
  8523. if (!MmFlushImageSection( &(*ThisScb)->NonpagedScb->SegmentObject,
  8524. MmFlushForWrite )) {
  8525. DebugTrace( 0, Dbg, ("Couldn't flush image section\n") );
  8526. Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
  8527. STATUS_SHARING_VIOLATION;
  8528. }
  8529. }
  8530. } finally {
  8531. InterlockedDecrement( &(*ThisScb)->CloseCount );
  8532. }
  8533. }
  8534. DebugTrace( -1, Dbg, ("NtfsOpenAttributeCheck: Exit -> %08lx\n", Status) );
  8535. return Status;
  8536. }
  8537. //
  8538. // Local support routine.
  8539. //
  8540. VOID
  8541. NtfsAddEa (
  8542. IN PIRP_CONTEXT IrpContext,
  8543. IN PVCB Vcb,
  8544. IN PFCB ThisFcb,
  8545. IN PFILE_FULL_EA_INFORMATION EaBuffer OPTIONAL,
  8546. IN ULONG EaLength,
  8547. OUT PIO_STATUS_BLOCK Iosb
  8548. )
  8549. /*++
  8550. Routine Description:
  8551. This routine will add an ea set to the file. It writes the attributes
  8552. to disk and updates the Fcb info structure with the packed ea size.
  8553. Arguments:
  8554. Vcb - This is the volume being opened.
  8555. ThisFcb - This is the Fcb for the file being opened.
  8556. EaBuffer - This is the buffer passed by the user.
  8557. EaLength - This is the stated length of the buffer.
  8558. Iosb - This is the Status Block to use to fill in the offset of an
  8559. offending Ea.
  8560. Return Value:
  8561. None - This routine will raise on error.
  8562. --*/
  8563. {
  8564. NTSTATUS Status = STATUS_SUCCESS;
  8565. EA_LIST_HEADER EaList;
  8566. ULONG Length;
  8567. PAGED_CODE();
  8568. DebugTrace( +1, Dbg, ("NtfsAddEa: Entered\n") );
  8569. //
  8570. // Use a try-finally to facilitate cleanup.
  8571. //
  8572. try {
  8573. //
  8574. // Initialize the EaList header.
  8575. //
  8576. EaList.PackedEaSize = 0;
  8577. EaList.NeedEaCount = 0;
  8578. EaList.UnpackedEaSize = 0;
  8579. EaList.BufferSize = 0;
  8580. EaList.FullEa = NULL;
  8581. if (ARGUMENT_PRESENT( EaBuffer )) {
  8582. //
  8583. // Check the user's buffer for validity.
  8584. //
  8585. Status = IoCheckEaBufferValidity( EaBuffer,
  8586. EaLength,
  8587. &Length );
  8588. if (!NT_SUCCESS( Status )) {
  8589. DebugTrace( -1, Dbg, ("NtfsAddEa: Invalid ea list\n") );
  8590. Iosb->Information = Length;
  8591. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  8592. }
  8593. //
  8594. // **** Maybe this routine should raise.
  8595. //
  8596. Status = NtfsBuildEaList( IrpContext,
  8597. Vcb,
  8598. &EaList,
  8599. EaBuffer,
  8600. &Iosb->Information );
  8601. if (!NT_SUCCESS( Status )) {
  8602. DebugTrace( -1, Dbg, ("NtfsAddEa: Couldn't build Ea list\n") );
  8603. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  8604. }
  8605. }
  8606. //
  8607. // Now replace the existing EAs.
  8608. //
  8609. NtfsReplaceFileEas( IrpContext, ThisFcb, &EaList );
  8610. } finally {
  8611. DebugUnwind( NtfsAddEa );
  8612. //
  8613. // Free the in-memory copy of the Eas.
  8614. //
  8615. if (EaList.FullEa != NULL) {
  8616. NtfsFreePool( EaList.FullEa );
  8617. }
  8618. DebugTrace( -1, Dbg, ("NtfsAddEa: Exit -> %08lx\n", Status) );
  8619. }
  8620. return;
  8621. }
  8622. VOID
  8623. NtfsInitializeFcbAndStdInfo (
  8624. IN PIRP_CONTEXT IrpContext,
  8625. IN PFCB ThisFcb,
  8626. IN BOOLEAN Directory,
  8627. IN BOOLEAN ViewIndex,
  8628. IN BOOLEAN Compressed,
  8629. IN ULONG FileAttributes,
  8630. IN PNTFS_TUNNELED_DATA SetTunneledData OPTIONAL
  8631. )
  8632. /*++
  8633. Routine Description:
  8634. This routine will initialize an Fcb for a newly created file and create
  8635. the standard information attribute on disk. We assume that some information
  8636. may already have been placed in the Fcb so we don't zero it out. We will
  8637. initialize the allocation size to zero, but that may be changed later in
  8638. the create process.
  8639. Arguments:
  8640. ThisFcb - This is the Fcb for the file being opened.
  8641. Directory - Indicates if this is a directory file.
  8642. ViewIndex - Indicates if this is a view index.
  8643. Compressed - Indicates if this is a compressed file.
  8644. FileAttributes - These are the attributes the user wants to attach to
  8645. the file. We will just clear any unsupported bits.
  8646. SetTunneledData - Optionally force the creation time and/or object id
  8647. to a given value
  8648. Return Value:
  8649. None - This routine will raise on error.
  8650. --*/
  8651. {
  8652. STANDARD_INFORMATION StandardInformation;
  8653. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  8654. PAGED_CODE();
  8655. DebugTrace( +1, Dbg, ("NtfsInitializeFcbAndStdInfo: Entered\n") );
  8656. NtfsInitializeAttributeContext( &AttrContext );
  8657. //
  8658. // Use a try-finally to facilitate cleanup.
  8659. //
  8660. try {
  8661. //
  8662. // Mask out the invalid bits of the file atributes. Then set the
  8663. // file name index bit if this is a directory.
  8664. //
  8665. if (!Directory) {
  8666. SetFlag( FileAttributes, FILE_ATTRIBUTE_ARCHIVE );
  8667. }
  8668. ClearFlag( FileAttributes, ~FILE_ATTRIBUTE_VALID_SET_FLAGS | FILE_ATTRIBUTE_NORMAL );
  8669. if (Directory) {
  8670. SetFlag( FileAttributes, DUP_FILE_NAME_INDEX_PRESENT );
  8671. }
  8672. if (ViewIndex) {
  8673. SetFlag( FileAttributes, DUP_VIEW_INDEX_PRESENT );
  8674. }
  8675. if (Compressed) {
  8676. SetFlag( FileAttributes, FILE_ATTRIBUTE_COMPRESSED );
  8677. }
  8678. ThisFcb->Info.FileAttributes = FileAttributes;
  8679. //
  8680. // Fill in the rest of the Fcb Info structure.
  8681. //
  8682. if (SetTunneledData == NULL) {
  8683. NtfsGetCurrentTime( IrpContext, ThisFcb->Info.CreationTime );
  8684. ThisFcb->Info.LastModificationTime = ThisFcb->Info.CreationTime;
  8685. ThisFcb->Info.LastChangeTime = ThisFcb->Info.CreationTime;
  8686. ThisFcb->Info.LastAccessTime = ThisFcb->Info.CreationTime;
  8687. ThisFcb->CurrentLastAccess = ThisFcb->Info.CreationTime;
  8688. } else {
  8689. NtfsSetTunneledData( IrpContext,
  8690. ThisFcb,
  8691. SetTunneledData );
  8692. NtfsGetCurrentTime( IrpContext, ThisFcb->Info.LastModificationTime );
  8693. ThisFcb->Info.LastChangeTime = ThisFcb->Info.LastModificationTime;
  8694. ThisFcb->Info.LastAccessTime = ThisFcb->Info.LastModificationTime;
  8695. ThisFcb->CurrentLastAccess = ThisFcb->Info.LastModificationTime;
  8696. }
  8697. //
  8698. // We assume these sizes are zero.
  8699. //
  8700. ThisFcb->Info.AllocatedLength = 0;
  8701. ThisFcb->Info.FileSize = 0;
  8702. //
  8703. // Copy the standard information fields from the Fcb and create the
  8704. // attribute.
  8705. //
  8706. RtlZeroMemory( &StandardInformation, sizeof( STANDARD_INFORMATION ));
  8707. StandardInformation.CreationTime = ThisFcb->Info.CreationTime;
  8708. StandardInformation.LastModificationTime = ThisFcb->Info.LastModificationTime;
  8709. StandardInformation.LastChangeTime = ThisFcb->Info.LastChangeTime;
  8710. StandardInformation.LastAccessTime = ThisFcb->Info.LastAccessTime;
  8711. StandardInformation.FileAttributes = ThisFcb->Info.FileAttributes;
  8712. StandardInformation.ClassId = 0;
  8713. StandardInformation.OwnerId = ThisFcb->OwnerId;
  8714. StandardInformation.SecurityId = ThisFcb->SecurityId;
  8715. StandardInformation.Usn = ThisFcb->Usn;
  8716. SetFlag(ThisFcb->FcbState, FCB_STATE_LARGE_STD_INFO);
  8717. NtfsCreateAttributeWithValue( IrpContext,
  8718. ThisFcb,
  8719. $STANDARD_INFORMATION,
  8720. NULL,
  8721. &StandardInformation,
  8722. sizeof( STANDARD_INFORMATION ),
  8723. 0,
  8724. NULL,
  8725. FALSE,
  8726. &AttrContext );
  8727. //
  8728. // We know that the open call will generate a single link.
  8729. // (Remember that a separate 8.3 name is not considered a link)
  8730. //
  8731. ThisFcb->LinkCount =
  8732. ThisFcb->TotalLinks = 1;
  8733. //
  8734. // Now set the header initialized flag in the Fcb.
  8735. //
  8736. SetFlag( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED );
  8737. } finally {
  8738. DebugUnwind( NtfsInitializeFcbAndStdInfo );
  8739. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  8740. DebugTrace( -1, Dbg, ("NtfsInitializeFcbAndStdInfo: Exit\n") );
  8741. }
  8742. return;
  8743. }
  8744. //
  8745. // Local support routine.
  8746. //
  8747. VOID
  8748. NtfsCreateAttribute (
  8749. IN PIRP_CONTEXT IrpContext,
  8750. IN PIO_STACK_LOCATION IrpSp,
  8751. IN OUT PFCB ThisFcb,
  8752. IN OUT PSCB ThisScb,
  8753. IN PLCB ThisLcb,
  8754. IN LONGLONG AllocationSize,
  8755. IN BOOLEAN LogIt,
  8756. IN BOOLEAN ForceNonresident,
  8757. IN PUSHORT PreviousFlags OPTIONAL
  8758. )
  8759. /*++
  8760. Routine Description:
  8761. This routine is called to create an attribute of a given size on the
  8762. disk. This path will only create non-resident attributes unless the
  8763. allocation size is zero.
  8764. The Scb will contain the attribute name and type code on entry.
  8765. Arguments:
  8766. IrpSp - Stack location in the Irp for this request.
  8767. ThisFcb - This is the Fcb for the file to create the attribute in.
  8768. ThisScb - This is the Scb for the attribute to create.
  8769. ThisLcb - This is the Lcb for propagating compression parameters
  8770. AllocationSize - This is the size of the attribute to create.
  8771. LogIt - Indicates whether we should log the creation of the attribute.
  8772. Also indicates if this is a create file operation.
  8773. ForceNonresident - Indicates that we want to create this stream non-resident.
  8774. This is the case if this is a supersede of a previously non-resident
  8775. stream. Once a stream is non-resident it can't go back to resident.
  8776. PreviousFlags - If specified then this is a supersede operation and
  8777. this is the previous compression flags for the file.
  8778. Return Value:
  8779. None - This routine will raise on error.
  8780. --*/
  8781. {
  8782. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  8783. PATTRIBUTE_RECORD_HEADER ThisAttribute = NULL;
  8784. USHORT AttributeFlags = 0;
  8785. PAGED_CODE();
  8786. DebugTrace( +1, Dbg, ("NtfsCreateAttribute: Entered\n") );
  8787. NtfsInitializeAttributeContext( &AttrContext );
  8788. //
  8789. // Use a try-finally to facilitate cleanup.
  8790. //
  8791. try {
  8792. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) {
  8793. //
  8794. // Always force this to be non-resident.
  8795. //
  8796. ForceNonresident = TRUE;
  8797. } else if (!FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION )) {
  8798. //
  8799. // If this is the root directory then use the Scb from the Vcb.
  8800. //
  8801. if (ARGUMENT_PRESENT( PreviousFlags)) {
  8802. AttributeFlags = *PreviousFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK;
  8803. } else if (ThisLcb == ThisFcb->Vcb->RootLcb) {
  8804. AttributeFlags = (USHORT)(ThisFcb->Vcb->RootIndexScb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK);
  8805. } else if (ThisLcb != NULL) {
  8806. AttributeFlags = (USHORT)(ThisLcb->Scb->AttributeFlags & ATTRIBUTE_FLAG_COMPRESSION_MASK);
  8807. } else if (IsCompressed( &ThisFcb->Info )) {
  8808. AttributeFlags = COMPRESSION_FORMAT_LZNT1 - 1;
  8809. }
  8810. }
  8811. //
  8812. // If this is a supersede we need to check whether to propagate
  8813. // the sparse bit.
  8814. //
  8815. if ((AllocationSize != 0) && ARGUMENT_PRESENT( PreviousFlags )) {
  8816. SetFlag( AttributeFlags, FlagOn( *PreviousFlags, ATTRIBUTE_FLAG_SPARSE ));
  8817. }
  8818. #ifdef BRIANDBG
  8819. if (!ARGUMENT_PRESENT( PreviousFlags ) &&
  8820. !FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  8821. (ThisScb->AttributeTypeCode == $DATA) &&
  8822. (NtfsCreateAllSparse)) {
  8823. SetFlag( AttributeFlags, ATTRIBUTE_FLAG_SPARSE );
  8824. if (!FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_SPARSE_FILE )) {
  8825. ASSERTMSG( "conflict with flush",
  8826. NtfsIsSharedFcb( ThisFcb ) ||
  8827. (ThisFcb->PagingIoResource != NULL &&
  8828. NtfsIsSharedFcbPagingIo( ThisFcb )) );
  8829. SetFlag( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_SPARSE_FILE );
  8830. SetFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  8831. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  8832. }
  8833. //
  8834. // Set the FastIo state.
  8835. //
  8836. NtfsAcquireFsrtlHeader( ThisScb );
  8837. ThisScb->Header.IsFastIoPossible = NtfsIsFastIoPossible( ThisScb );
  8838. NtfsReleaseFsrtlHeader( ThisScb );
  8839. }
  8840. #endif
  8841. //
  8842. // If we are creating a sparse or compressed stream then set the size to a
  8843. // compression unit boundary.
  8844. //
  8845. if (FlagOn( AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  8846. ULONG CompressionUnit = BytesFromClusters( ThisScb->Vcb, 1 << NTFS_CLUSTERS_PER_COMPRESSION );
  8847. if (ThisScb->Vcb->SparseFileUnit < CompressionUnit) {
  8848. CompressionUnit = ThisScb->Vcb->SparseFileUnit;
  8849. }
  8850. AllocationSize += (CompressionUnit - 1);
  8851. ((PLARGE_INTEGER) &AllocationSize)->LowPart &= ~(CompressionUnit - 1);
  8852. }
  8853. //
  8854. // We lookup that attribute again and it better not be there.
  8855. // We need the file record in order to know whether the attribute
  8856. // is resident or not.
  8857. //
  8858. if (ForceNonresident || (AllocationSize != 0)) {
  8859. DebugTrace( 0, Dbg, ("Create non-resident attribute\n") );
  8860. //
  8861. // If the file is sparse then set the allocation size to zero
  8862. // and add a sparse range after this call.
  8863. //
  8864. if (!NtfsAllocateAttribute( IrpContext,
  8865. ThisScb,
  8866. ThisScb->AttributeTypeCode,
  8867. &ThisScb->AttributeName,
  8868. AttributeFlags,
  8869. FALSE,
  8870. LogIt,
  8871. (FlagOn( AttributeFlags, ATTRIBUTE_FLAG_SPARSE ) ?
  8872. 0 :
  8873. AllocationSize),
  8874. NULL )) {
  8875. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_LARGE_ALLOCATION );
  8876. }
  8877. //
  8878. // Now add the sparse allocation for a sparse file if the size is
  8879. // non-zero.
  8880. //
  8881. if (FlagOn( AttributeFlags, ATTRIBUTE_FLAG_SPARSE ) &&
  8882. (AllocationSize != 0)) {
  8883. //
  8884. // If the sparse flag is set then we better be doing a supersede
  8885. // with logging enabled.
  8886. //
  8887. ASSERT( LogIt );
  8888. NtfsAddSparseAllocation( IrpContext,
  8889. NULL,
  8890. ThisScb,
  8891. 0,
  8892. AllocationSize );
  8893. }
  8894. SetFlag( ThisScb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE );
  8895. } else {
  8896. //
  8897. // Update the quota if this is a user stream.
  8898. //
  8899. if (FlagOn( ThisScb->ScbState, SCB_STATE_SUBJECT_TO_QUOTA )) {
  8900. LONGLONG Delta = NtfsResidentStreamQuota( ThisFcb->Vcb );
  8901. NtfsConditionallyUpdateQuota( IrpContext,
  8902. ThisFcb,
  8903. &Delta,
  8904. LogIt,
  8905. TRUE );
  8906. }
  8907. NtfsCreateAttributeWithValue( IrpContext,
  8908. ThisFcb,
  8909. ThisScb->AttributeTypeCode,
  8910. &ThisScb->AttributeName,
  8911. NULL,
  8912. (ULONG) AllocationSize,
  8913. AttributeFlags,
  8914. NULL,
  8915. LogIt,
  8916. &AttrContext );
  8917. ThisAttribute = NtfsFoundAttribute( &AttrContext );
  8918. }
  8919. //
  8920. // Clear the header initialized bit and read the sizes from the
  8921. // disk.
  8922. //
  8923. ClearFlag( ThisScb->ScbState, SCB_STATE_HEADER_INITIALIZED );
  8924. NtfsUpdateScbFromAttribute( IrpContext,
  8925. ThisScb,
  8926. ThisAttribute );
  8927. } finally {
  8928. DebugUnwind( NtfsCreateAttribute );
  8929. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  8930. DebugTrace( -1, Dbg, ("NtfsCreateAttribute: Exit\n") );
  8931. }
  8932. return;
  8933. UNREFERENCED_PARAMETER( PreviousFlags );
  8934. }
  8935. //
  8936. // Local support routine
  8937. //
  8938. VOID
  8939. NtfsRemoveDataAttributes (
  8940. IN PIRP_CONTEXT IrpContext,
  8941. IN PFCB ThisFcb,
  8942. IN PLCB ThisLcb OPTIONAL,
  8943. IN PFILE_OBJECT FileObject,
  8944. IN ULONG LastFileNameOffset,
  8945. IN ULONG CreateFlags
  8946. )
  8947. /*++
  8948. Routine Description:
  8949. This routine is called to remove (or mark for delete) all of the named
  8950. data attributes on a file. This is done during an overwrite
  8951. or supersede operation.
  8952. Arguments:
  8953. Context - Pointer to the IrpContext to be queued to the Fsp
  8954. ThisFcb - This is the Fcb for the file in question.
  8955. ThisLcb - This is the Lcb used to reach this Fcb (if specified).
  8956. FileObject - This is the file object for the file.
  8957. LastFileNameOffset - This is the offset of the file in the full name.
  8958. CreateFlags - Indicates if this open is being performed by file id.
  8959. Return Value:
  8960. None.
  8961. --*/
  8962. {
  8963. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  8964. PATTRIBUTE_RECORD_HEADER Attribute;
  8965. ATTRIBUTE_TYPE_CODE TypeCode = $DATA;
  8966. UNICODE_STRING AttributeName;
  8967. PSCB ThisScb;
  8968. BOOLEAN MoreToGo;
  8969. ASSERT_EXCLUSIVE_FCB( ThisFcb );
  8970. PAGED_CODE();
  8971. //
  8972. // Use a try-finally to facilitate cleanup.
  8973. //
  8974. try {
  8975. NtfsInitializeAttributeContext( &Context );
  8976. //
  8977. // Enumerate all of the attributes with the matching type code
  8978. //
  8979. MoreToGo = NtfsLookupAttributeByCode( IrpContext,
  8980. ThisFcb,
  8981. &ThisFcb->FileReference,
  8982. TypeCode,
  8983. &Context );
  8984. while (MoreToGo) {
  8985. //
  8986. // Point to the current attribute.
  8987. //
  8988. Attribute = NtfsFoundAttribute( &Context );
  8989. //
  8990. // We only look at named data attributes.
  8991. //
  8992. if (Attribute->NameLength != 0) {
  8993. //
  8994. // Construct the name and find the Scb for the attribute.
  8995. //
  8996. AttributeName.Buffer = (PWSTR) Add2Ptr( Attribute, Attribute->NameOffset );
  8997. AttributeName.MaximumLength = AttributeName.Length = Attribute->NameLength * sizeof( WCHAR );
  8998. ThisScb = NtfsCreateScb( IrpContext,
  8999. ThisFcb,
  9000. TypeCode,
  9001. &AttributeName,
  9002. FALSE,
  9003. NULL );
  9004. //
  9005. // If there is an open handle on this file, we simply mark
  9006. // the Scb as delete pending.
  9007. //
  9008. if (ThisScb->CleanupCount != 0) {
  9009. SetFlag( ThisScb->ScbState, SCB_STATE_DELETE_ON_CLOSE );
  9010. //
  9011. // Otherwise we remove the attribute and mark the Scb as
  9012. // deleted. The Scb will be cleaned up when the Fcb is
  9013. // cleaned up.
  9014. //
  9015. } else {
  9016. NtfsDeleteAttributeRecord( IrpContext,
  9017. ThisFcb,
  9018. (DELETE_LOG_OPERATION |
  9019. DELETE_RELEASE_FILE_RECORD |
  9020. DELETE_RELEASE_ALLOCATION),
  9021. &Context );
  9022. SetFlag( ThisScb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  9023. //
  9024. // If this is a named stream, then report this to the dir notify
  9025. // package.
  9026. //
  9027. if (!FlagOn( CreateFlags, CREATE_FLAG_OPEN_BY_ID ) &&
  9028. (ThisScb->Vcb->NotifyCount != 0) &&
  9029. (ThisScb->AttributeName.Length != 0) &&
  9030. (ThisScb->AttributeTypeCode == TypeCode)) {
  9031. NtfsReportDirNotify( IrpContext,
  9032. ThisFcb->Vcb,
  9033. &FileObject->FileName,
  9034. LastFileNameOffset,
  9035. &ThisScb->AttributeName,
  9036. ((ARGUMENT_PRESENT( ThisLcb ) &&
  9037. (ThisLcb->Scb->ScbType.Index.NormalizedName.Length != 0)) ?
  9038. &ThisLcb->Scb->ScbType.Index.NormalizedName :
  9039. NULL),
  9040. FILE_NOTIFY_CHANGE_STREAM_NAME,
  9041. FILE_ACTION_REMOVED_STREAM,
  9042. NULL );
  9043. }
  9044. //
  9045. // Since we have marked this stream as deleted then we need to checkpoint so
  9046. // that we can uninitialize the Scb. Otherwise some stray operation may
  9047. // attempt to operate on the Scb.
  9048. //
  9049. ThisScb->ValidDataToDisk =
  9050. ThisScb->Header.AllocationSize.QuadPart =
  9051. ThisScb->Header.FileSize.QuadPart =
  9052. ThisScb->Header.ValidDataLength.QuadPart = 0;
  9053. NtfsCheckpointCurrentTransaction( IrpContext );
  9054. ThisScb->AttributeTypeCode = $UNUSED;
  9055. }
  9056. }
  9057. //
  9058. // Get the next attribute.
  9059. //
  9060. MoreToGo = NtfsLookupNextAttributeByCode( IrpContext,
  9061. ThisFcb,
  9062. TypeCode,
  9063. &Context );
  9064. }
  9065. } finally {
  9066. NtfsCleanupAttributeContext( IrpContext, &Context );
  9067. }
  9068. return;
  9069. }
  9070. //
  9071. // Local support routine
  9072. //
  9073. VOID
  9074. NtfsRemoveReparsePoint (
  9075. IN PIRP_CONTEXT IrpContext,
  9076. IN PFCB ThisFcb
  9077. )
  9078. /*++
  9079. Routine Description:
  9080. This routine is called to remove the reparse point that exists in a file.
  9081. Arguments:
  9082. Context - Pointer to the IrpContext to be queued to the Fsp
  9083. ThisFcb - This is the Fcb for the file in question.
  9084. Return Value:
  9085. None.
  9086. --*/
  9087. {
  9088. ATTRIBUTE_ENUMERATION_CONTEXT Context;
  9089. PATTRIBUTE_RECORD_HEADER Attribute;
  9090. PSCB ThisScb = NULL;
  9091. PVCB Vcb = ThisFcb->Vcb;
  9092. MAP_HANDLE MapHandle;
  9093. BOOLEAN ThisScbAcquired = FALSE;
  9094. BOOLEAN CleanupAttributeContext = FALSE;
  9095. BOOLEAN IndexAcquired = FALSE;
  9096. BOOLEAN InitializedMapHandle = FALSE;
  9097. ULONG IncomingFileAttributes = 0; // invalid value
  9098. ULONG IncomingReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO; // invalid value
  9099. ASSERT_EXCLUSIVE_FCB( ThisFcb );
  9100. PAGED_CODE();
  9101. //
  9102. // Remember the values of the file attribute flags and of the reparse tag
  9103. // for abnormal termination recovery.
  9104. //
  9105. IncomingFileAttributes = ThisFcb->Info.FileAttributes;
  9106. IncomingReparsePointTag = ThisFcb->Info.ReparsePointTag;
  9107. //
  9108. // Use a try-finally to facilitate cleanup.
  9109. //
  9110. try {
  9111. NtfsInitializeAttributeContext( &Context );
  9112. CleanupAttributeContext = TRUE;
  9113. //
  9114. // Lookup the reparse point attribute.
  9115. //
  9116. if (NtfsLookupAttributeByCode( IrpContext,
  9117. ThisFcb,
  9118. &ThisFcb->FileReference,
  9119. $REPARSE_POINT,
  9120. &Context )) {
  9121. //
  9122. // Delete the record from the reparse point index.
  9123. //
  9124. {
  9125. NTSTATUS Status = STATUS_SUCCESS;
  9126. INDEX_KEY IndexKey;
  9127. INDEX_ROW IndexRow;
  9128. REPARSE_INDEX_KEY KeyValue;
  9129. //
  9130. // Acquire the mount table index so that the following two operations on it
  9131. // are atomic for this call.
  9132. //
  9133. NtfsAcquireExclusiveScb( IrpContext, Vcb->ReparsePointTableScb );
  9134. IndexAcquired = TRUE;
  9135. //
  9136. // Verify that this file is in the reparse point index and delete it.
  9137. //
  9138. KeyValue.FileReparseTag = ThisFcb->Info.ReparsePointTag;
  9139. KeyValue.FileId = *(PLARGE_INTEGER)&ThisFcb->FileReference;
  9140. IndexKey.Key = (PVOID)&KeyValue;
  9141. IndexKey.KeyLength = sizeof(KeyValue);
  9142. NtOfsInitializeMapHandle( &MapHandle );
  9143. InitializedMapHandle = TRUE;
  9144. //
  9145. // NtOfsFindRecord will return an error status if the key is not found.
  9146. //
  9147. Status = NtOfsFindRecord( IrpContext,
  9148. Vcb->ReparsePointTableScb,
  9149. &IndexKey,
  9150. &IndexRow,
  9151. &MapHandle,
  9152. NULL );
  9153. if (!NT_SUCCESS(Status)) {
  9154. //
  9155. // Should not happen. The reparse point should be in the index.
  9156. //
  9157. DebugTrace( 0, Dbg, ("Record not found in the reparse point index.\n") );
  9158. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, ThisFcb );
  9159. }
  9160. //
  9161. // Remove the entry from the reparse point index.
  9162. //
  9163. NtOfsDeleteRecords( IrpContext,
  9164. Vcb->ReparsePointTableScb,
  9165. 1, // deleting one record from the index
  9166. &IndexKey );
  9167. }
  9168. //
  9169. // Point to the current attribute.
  9170. //
  9171. Attribute = NtfsFoundAttribute( &Context );
  9172. //
  9173. // If the stream is non-resident, then get a hold of an Scb for it.
  9174. //
  9175. if (!NtfsIsAttributeResident( Attribute )) {
  9176. ThisScb = NtfsCreateScb( IrpContext,
  9177. ThisFcb,
  9178. $REPARSE_POINT,
  9179. &NtfsEmptyString,
  9180. FALSE,
  9181. NULL );
  9182. NtfsAcquireExclusiveScb( IrpContext, ThisScb );
  9183. ThisScbAcquired = TRUE;
  9184. }
  9185. //
  9186. // Post the change to the Usn Journal (on errors change is backed out)
  9187. //
  9188. NtfsPostUsnChange( IrpContext, ThisFcb, USN_REASON_REPARSE_POINT_CHANGE );
  9189. NtfsDeleteAttributeRecord( IrpContext,
  9190. ThisFcb,
  9191. DELETE_LOG_OPERATION |
  9192. DELETE_RELEASE_FILE_RECORD |
  9193. DELETE_RELEASE_ALLOCATION,
  9194. &Context );
  9195. //
  9196. // Set the change attribute flag.
  9197. //
  9198. ASSERTMSG( "conflict with flush",
  9199. NtfsIsSharedFcb( ThisFcb ) ||
  9200. (ThisFcb->PagingIoResource != NULL &&
  9201. NtfsIsSharedFcbPagingIo( ThisFcb )) );
  9202. SetFlag( ThisFcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
  9203. //
  9204. // Clear the reparse point bit in the duplicate file attribute.
  9205. //
  9206. ClearFlag( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT );
  9207. //
  9208. // Clear the ReparsePointTag field in the duplicate file attribute.
  9209. //
  9210. ThisFcb->Info.ReparsePointTag = IO_REPARSE_TAG_RESERVED_ZERO;
  9211. //
  9212. // Put the reparse point deletion and the attribute flag into the
  9213. // the same transaction.
  9214. //
  9215. NtfsUpdateStandardInformation( IrpContext, ThisFcb );
  9216. //
  9217. // If we have acquired the Scb then set the sizes back to zero.
  9218. // Flag that the attribute has been deleted.
  9219. // Always commit this change since we update the field in the Fcb.
  9220. //
  9221. if (ThisScbAcquired) {
  9222. ThisScb->Header.FileSize =
  9223. ThisScb->Header.ValidDataLength =
  9224. ThisScb->Header.AllocationSize = Li0;
  9225. }
  9226. //
  9227. // Since we've been called from NtfsOverwriteAttr before
  9228. // NtfsRemoveDataAttributes gets called, we need to make sure
  9229. // that if we're holding the Mft, we drop itwhen we checkpoint.
  9230. // Otherwise we have a potential deadlock when
  9231. // NtfsRemoveDataAttributes tries to acquire the quota index
  9232. // while holding the Mft.
  9233. //
  9234. if ((Vcb->MftScb != NULL) &&
  9235. (Vcb->MftScb->Fcb->ExclusiveFcbLinks.Flink != NULL) &&
  9236. NtfsIsExclusiveScb( Vcb->MftScb )) {
  9237. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_MFT );
  9238. }
  9239. //
  9240. // Checkpoint the Txn to commit the changes.
  9241. //
  9242. NtfsCheckpointCurrentTransaction( IrpContext );
  9243. ClearFlag( ThisFcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
  9244. if (ThisScbAcquired) {
  9245. //
  9246. // Set the Scb flag to indicate that the attribute is gone.
  9247. //
  9248. ThisScb->AttributeTypeCode = $UNUSED;
  9249. SetFlag( ThisScb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  9250. }
  9251. }
  9252. } finally {
  9253. if (ThisScbAcquired) {
  9254. NtfsReleaseScb( IrpContext, ThisScb );
  9255. }
  9256. if (CleanupAttributeContext) {
  9257. NtfsCleanupAttributeContext( IrpContext, &Context );
  9258. }
  9259. //
  9260. // Release the reparse point index Scb and the map handle.
  9261. //
  9262. if (IndexAcquired) {
  9263. NtfsReleaseScb( IrpContext, Vcb->ReparsePointTableScb );
  9264. }
  9265. if (InitializedMapHandle) {
  9266. NtOfsReleaseMap( IrpContext, &MapHandle );
  9267. }
  9268. //
  9269. // Need to roll-back the value of the file attributes and the reparse point
  9270. // flag in case of problems.
  9271. //
  9272. if (AbnormalTermination()) {
  9273. ThisFcb->Info.FileAttributes = IncomingFileAttributes;
  9274. ThisFcb->Info.ReparsePointTag = IncomingReparsePointTag;
  9275. }
  9276. }
  9277. return;
  9278. }
  9279. //
  9280. // Local support routine.
  9281. //
  9282. VOID
  9283. NtfsReplaceAttribute (
  9284. IN PIRP_CONTEXT IrpContext,
  9285. IN PIO_STACK_LOCATION IrpSp,
  9286. IN PFCB ThisFcb,
  9287. IN PSCB ThisScb,
  9288. IN PLCB ThisLcb,
  9289. IN LONGLONG AllocationSize
  9290. )
  9291. /*++
  9292. Routine Description:
  9293. This routine is called to replace an existing attribute with
  9294. an attribute of the given allocation size. This routine will
  9295. handle the case whether the existing attribute is resident
  9296. or non-resident and the resulting attribute is resident or
  9297. non-resident.
  9298. There are two cases to consider. The first is the case where the
  9299. attribute is currently non-resident. In this case we will always
  9300. leave the attribute non-resident regardless of the new allocation
  9301. size. The argument being that the file will probably be used
  9302. as it was before. In this case we will add or delete allocation.
  9303. The second case is where the attribute is currently resident. In
  9304. This case we will remove the old attribute and add a new one.
  9305. Arguments:
  9306. IrpSp - This is the Irp stack location for this request.
  9307. ThisFcb - This is the Fcb for the file being opened.
  9308. ThisScb - This is the Scb for the given attribute.
  9309. ThisLcb - This is the Lcb via which this file is created. It
  9310. is used to propagate compression info.
  9311. AllocationSize - This is the new allocation size.
  9312. Return Value:
  9313. None. This routine will raise.
  9314. --*/
  9315. {
  9316. ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
  9317. PAGED_CODE();
  9318. DebugTrace( +1, Dbg, ("NtfsReplaceAttribute: Entered\n") );
  9319. NtfsInitializeAttributeContext( &AttrContext );
  9320. //
  9321. // Use a try-finally to facilitate cleanup.
  9322. //
  9323. try {
  9324. //
  9325. // Initialize the Scb if needed.
  9326. //
  9327. if (!FlagOn( ThisScb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {
  9328. NtfsUpdateScbFromAttribute( IrpContext, ThisScb, NULL );
  9329. }
  9330. NtfsSnapshotScb( IrpContext, ThisScb );
  9331. //
  9332. // If the attribute is resident, simply remove the old attribute and create
  9333. // a new one.
  9334. //
  9335. if (FlagOn( ThisScb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  9336. USHORT AttributeFlags;
  9337. //
  9338. // Find the attribute on the disk.
  9339. //
  9340. NtfsLookupAttributeForScb( IrpContext,
  9341. ThisScb,
  9342. NULL,
  9343. &AttrContext );
  9344. AttributeFlags = ThisScb->AttributeFlags;
  9345. NtfsDeleteAttributeRecord( IrpContext,
  9346. ThisFcb,
  9347. DELETE_LOG_OPERATION |
  9348. DELETE_RELEASE_FILE_RECORD |
  9349. DELETE_RELEASE_ALLOCATION,
  9350. &AttrContext );
  9351. //
  9352. // Set all the attribute sizes to zero.
  9353. //
  9354. ThisScb->ValidDataToDisk =
  9355. ThisScb->Header.AllocationSize.QuadPart =
  9356. ThisScb->Header.ValidDataLength.QuadPart =
  9357. ThisScb->Header.FileSize.QuadPart = 0;
  9358. ThisScb->TotalAllocated = 0;
  9359. //
  9360. // Create a stream file for the attribute in order to
  9361. // truncate the cache. Set the initialized bit in
  9362. // the Scb so we don't go to disk, but clear it afterwords.
  9363. //
  9364. if ((ThisScb->NonpagedScb->SegmentObject.DataSectionObject != NULL) ||
  9365. #ifdef COMPRESS_ON_WIRE
  9366. (ThisScb->Header.FileObjectC != NULL))
  9367. #else
  9368. FALSE
  9369. #endif
  9370. ) {
  9371. NtfsCreateInternalAttributeStream( IrpContext,
  9372. ThisScb,
  9373. FALSE,
  9374. &NtfsInternalUseFile[REPLACEATTRIBUTE_FILE_NUMBER] );
  9375. NtfsSetBothCacheSizes( ThisScb->FileObject,
  9376. (PCC_FILE_SIZES)&ThisScb->Header.AllocationSize,
  9377. ThisScb );
  9378. }
  9379. //
  9380. // Call our create attribute routine.
  9381. //
  9382. NtfsCreateAttribute( IrpContext,
  9383. IrpSp,
  9384. ThisFcb,
  9385. ThisScb,
  9386. ThisLcb,
  9387. AllocationSize,
  9388. TRUE,
  9389. FALSE,
  9390. &AttributeFlags );
  9391. //
  9392. // Otherwise the attribute will stay non-resident, we simply need to
  9393. // add or remove allocation.
  9394. //
  9395. } else {
  9396. ULONG AllocationUnit;
  9397. //
  9398. // Create an internal attribute stream for the file.
  9399. //
  9400. if ((ThisScb->NonpagedScb->SegmentObject.DataSectionObject != NULL) ||
  9401. #ifdef COMPRESS_ON_WIRE
  9402. (ThisScb->Header.FileObjectC != NULL)
  9403. #else
  9404. FALSE
  9405. #endif
  9406. ) {
  9407. NtfsCreateInternalAttributeStream( IrpContext,
  9408. ThisScb,
  9409. FALSE,
  9410. &NtfsInternalUseFile[REPLACEATTRIBUTE2_FILE_NUMBER] );
  9411. }
  9412. //
  9413. // If the file is sparse or compressed then always round the
  9414. // new size to a compression unit boundary. Otherwise round
  9415. // to a cluster boundary.
  9416. //
  9417. AllocationUnit = ThisScb->Vcb->BytesPerCluster;
  9418. if (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  9419. ASSERT( ThisScb->CompressionUnit != 0 );
  9420. AllocationUnit = ThisScb->CompressionUnit;
  9421. }
  9422. AllocationSize += (LONGLONG) (AllocationUnit - 1);
  9423. ((PLARGE_INTEGER) &AllocationSize)->LowPart &= ~(AllocationUnit - 1);
  9424. //
  9425. // Set the file size and valid data size to zero.
  9426. //
  9427. ThisScb->ValidDataToDisk = 0;
  9428. ThisScb->Header.ValidDataLength = Li0;
  9429. ThisScb->Header.FileSize = Li0;
  9430. DebugTrace( 0, Dbg, ("AllocationSize -> %016I64x\n", AllocationSize) );
  9431. //
  9432. // Write these changes to the file
  9433. //
  9434. //
  9435. // If the attribute is currently compressed or sparse then go ahead and discard
  9436. // all of the allocation.
  9437. //
  9438. if (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  9439. NtfsDeleteAllocation( IrpContext,
  9440. ThisScb->FileObject,
  9441. ThisScb,
  9442. 0,
  9443. MAXLONGLONG,
  9444. TRUE,
  9445. TRUE );
  9446. //
  9447. // Checkpoint the current transaction so we have these clusters
  9448. // available again.
  9449. //
  9450. NtfsCheckpointCurrentTransaction( IrpContext );
  9451. //
  9452. // If the user doesn't want this stream to be compressed then
  9453. // remove the entire stream and recreate it non-compressed. If
  9454. // the stream is currently sparse and the new file size
  9455. // is zero then also create the stream non-sparse.
  9456. //
  9457. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ) ||
  9458. (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION ) &&
  9459. !FlagOn( ThisScb->ScbState, SCB_STATE_COMPRESSION_CHANGE )) ||
  9460. (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ) &&
  9461. (AllocationSize == 0))) {
  9462. //
  9463. // We may need to preserve one or the other of the sparse/compressed
  9464. // flags.
  9465. //
  9466. USHORT PreviousFlags = ThisScb->AttributeFlags;
  9467. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE )) {
  9468. PreviousFlags = 0;
  9469. } else {
  9470. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_COMPRESSION )) {
  9471. ClearFlag( PreviousFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK );
  9472. }
  9473. if ((AllocationSize == 0) &&
  9474. FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  9475. ClearFlag( PreviousFlags, ATTRIBUTE_FLAG_SPARSE );
  9476. }
  9477. }
  9478. NtfsLookupAttributeForScb( IrpContext,
  9479. ThisScb,
  9480. NULL,
  9481. &AttrContext );
  9482. NtfsDeleteAttributeRecord( IrpContext,
  9483. ThisFcb,
  9484. DELETE_LOG_OPERATION |
  9485. DELETE_RELEASE_FILE_RECORD |
  9486. DELETE_RELEASE_ALLOCATION,
  9487. &AttrContext );
  9488. //
  9489. // Call our create attribute routine.
  9490. //
  9491. NtfsCreateAttribute( IrpContext,
  9492. IrpSp,
  9493. ThisFcb,
  9494. ThisScb,
  9495. ThisLcb,
  9496. AllocationSize,
  9497. TRUE,
  9498. TRUE,
  9499. &PreviousFlags );
  9500. //
  9501. // Since the attribute may have changed state we need to
  9502. // checkpoint.
  9503. //
  9504. NtfsCheckpointCurrentTransaction( IrpContext );
  9505. }
  9506. }
  9507. //
  9508. // Now if the file allocation is being increased then we need to only add allocation
  9509. // to the attribute
  9510. //
  9511. if (ThisScb->Header.AllocationSize.QuadPart < AllocationSize) {
  9512. NtfsAddAllocation( IrpContext,
  9513. ThisScb->FileObject,
  9514. ThisScb,
  9515. LlClustersFromBytes( ThisScb->Vcb, ThisScb->Header.AllocationSize.QuadPart ),
  9516. LlClustersFromBytes( ThisScb->Vcb, AllocationSize - ThisScb->Header.AllocationSize.QuadPart ),
  9517. FALSE,
  9518. NULL );
  9519. //
  9520. // Otherwise the allocation is being decreased so we need to delete some allocation
  9521. //
  9522. } else if (ThisScb->Header.AllocationSize.QuadPart > AllocationSize) {
  9523. NtfsDeleteAllocation( IrpContext,
  9524. ThisScb->FileObject,
  9525. ThisScb,
  9526. LlClustersFromBytes( ThisScb->Vcb, AllocationSize ),
  9527. MAXLONGLONG,
  9528. TRUE,
  9529. TRUE );
  9530. }
  9531. //
  9532. // We always unitialize the cache size to zero and write the new
  9533. // file size to disk.
  9534. //
  9535. NtfsWriteFileSizes( IrpContext,
  9536. ThisScb,
  9537. &ThisScb->Header.ValidDataLength.QuadPart,
  9538. FALSE,
  9539. TRUE,
  9540. TRUE );
  9541. NtfsCheckpointCurrentTransaction( IrpContext );
  9542. if (ThisScb->FileObject != NULL) {
  9543. NtfsSetBothCacheSizes( ThisScb->FileObject,
  9544. (PCC_FILE_SIZES)&ThisScb->Header.AllocationSize,
  9545. ThisScb );
  9546. }
  9547. //
  9548. // Make sure the reservation bitmap shows no reserved bits.
  9549. //
  9550. if (ThisScb->ScbType.Data.ReservedBitMap != NULL) {
  9551. NtfsDeleteReservedBitmap( ThisScb );
  9552. ThisScb->ScbType.Data.TotalReserved = 0;
  9553. }
  9554. //
  9555. // Set the FastIo state.
  9556. //
  9557. NtfsAcquireFsrtlHeader( ThisScb );
  9558. ThisScb->Header.IsFastIoPossible = NtfsIsFastIoPossible( ThisScb );
  9559. NtfsReleaseFsrtlHeader( ThisScb );
  9560. }
  9561. } finally {
  9562. DebugUnwind( NtfsReplaceAttribute );
  9563. NtfsCleanupAttributeContext( IrpContext, &AttrContext );
  9564. DebugTrace( -1, Dbg, ("NtfsReplaceAttribute: Exit\n") );
  9565. }
  9566. return;
  9567. }
  9568. //
  9569. // Local support routine
  9570. //
  9571. NTSTATUS
  9572. NtfsOpenAttribute (
  9573. IN PIRP_CONTEXT IrpContext,
  9574. IN PIO_STACK_LOCATION IrpSp,
  9575. IN PVCB Vcb,
  9576. IN PLCB ThisLcb OPTIONAL,
  9577. IN PFCB ThisFcb,
  9578. IN ULONG LastFileNameOffset,
  9579. IN UNICODE_STRING AttrName,
  9580. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  9581. IN SHARE_MODIFICATION_TYPE ShareModificationType,
  9582. IN TYPE_OF_OPEN TypeOfOpen,
  9583. IN LOGICAL CreateFile,
  9584. IN ULONG CcbFlags,
  9585. IN PVOID NetworkInfo OPTIONAL,
  9586. IN OUT PSCB *ThisScb,
  9587. OUT PCCB *ThisCcb
  9588. )
  9589. /*++
  9590. Routine Description:
  9591. This routine does the work of creating the Scb and updating the
  9592. ShareAccess in the Fcb. It also initializes the Scb if neccessary
  9593. and creates Ccb. Its final job is to set the file object type of
  9594. open.
  9595. Arguments:
  9596. IrpSp - This is the stack location for this volume. We use it to get the
  9597. file object, granted access and share access for this open.
  9598. Vcb - Vcb for this volume.
  9599. ThisLcb - This is the Lcb to the Fcb for the file being opened. Not present
  9600. if this is an open by id.
  9601. ThisFcb - This is the Fcb for this file.
  9602. LastFileNameOffset - This is the offset in the full path of the final component.
  9603. AttrName - This is the attribute name to open.
  9604. AttrTypeCode - This is the type code for the attribute being opened.
  9605. ShareModificationType - This indicates how we should modify the
  9606. current share modification on the Fcb.
  9607. TypeOfOpen - This indicates how this attribute is being opened.
  9608. CreateFile - Indicates if we are in the create file path.
  9609. CcbFlags - This is the flag field for the Ccb.
  9610. NetworkInfo - If specified then this open is on behalf of a fast query
  9611. and we don't want to increment the counts or modify the share
  9612. access on the file.
  9613. ThisScb - If this points to a non-NULL value, it is the Scb to use. Otherwise we
  9614. store the Scb we create here.
  9615. ThisCcb - Address to store address of created Ccb.
  9616. Return Value:
  9617. NTSTATUS - Indicating the outcome of opening this attribute.
  9618. --*/
  9619. {
  9620. NTSTATUS Status = STATUS_SUCCESS;
  9621. BOOLEAN RemoveShareAccess = FALSE;
  9622. ACCESS_MASK GrantedAccess;
  9623. PAGED_CODE();
  9624. DebugTrace( +1, Dbg, ("NtfsOpenAttribute: Entered\n") );
  9625. //
  9626. // Use a try-finally to facilitate cleanup.
  9627. //
  9628. try {
  9629. //
  9630. // Remember the granted access.
  9631. //
  9632. GrantedAccess = IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess;
  9633. //
  9634. // Create the Scb for this attribute if it doesn't exist.
  9635. //
  9636. if (*ThisScb == NULL) {
  9637. DebugTrace( 0, Dbg, ("Looking for Scb\n") );
  9638. *ThisScb = NtfsCreateScb( IrpContext,
  9639. ThisFcb,
  9640. AttrTypeCode,
  9641. &AttrName,
  9642. FALSE,
  9643. NULL );
  9644. }
  9645. DebugTrace( 0, Dbg, ("ThisScb -> %08lx\n", *ThisScb) );
  9646. DebugTrace( 0, Dbg, ("ThisLcb -> %08lx\n", ThisLcb) );
  9647. //
  9648. // If this Scb is delete pending, we return an error.
  9649. //
  9650. if (FlagOn( (*ThisScb)->ScbState, SCB_STATE_DELETE_ON_CLOSE )) {
  9651. DebugTrace( 0, Dbg, ("Scb delete is pending\n") );
  9652. Status = STATUS_DELETE_PENDING;
  9653. try_return( NOTHING );
  9654. }
  9655. //
  9656. // Skip all of the operations below if the user is doing a fast
  9657. // path open.
  9658. //
  9659. if (!ARGUMENT_PRESENT( NetworkInfo )) {
  9660. //
  9661. // If this caller wanted a filter oplock and the cleanup count
  9662. // is non-zero then fail the request.
  9663. //
  9664. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) {
  9665. if (SafeNodeType( *ThisScb ) != NTFS_NTC_SCB_DATA) {
  9666. Status = STATUS_INVALID_PARAMETER;
  9667. try_return( NOTHING );
  9668. //
  9669. // This must be the only open on the file and the requested
  9670. // access must be FILE_READ/WRITE_ATTRIBUTES and the
  9671. // share access must share with everyone.
  9672. //
  9673. } else if (((*ThisScb)->CleanupCount != 0) ||
  9674. (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  9675. ~(FILE_READ_ATTRIBUTES))) ||
  9676. ((IrpSp->Parameters.Create.ShareAccess &
  9677. (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) !=
  9678. (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE))) {
  9679. Status = STATUS_OPLOCK_NOT_GRANTED;
  9680. try_return( NOTHING );
  9681. }
  9682. }
  9683. //
  9684. // Update the share access structure.
  9685. //
  9686. //
  9687. // Case on the requested share modification value.
  9688. //
  9689. switch (ShareModificationType) {
  9690. case UpdateShareAccess :
  9691. DebugTrace( 0, Dbg, ("Updating share access\n") );
  9692. IoUpdateShareAccess( IrpSp->FileObject,
  9693. &(*ThisScb)->ShareAccess );
  9694. break;
  9695. case SetShareAccess :
  9696. DebugTrace( 0, Dbg, ("Setting share access\n") );
  9697. //
  9698. // This case is when this is the first open for the file
  9699. // and we simply set the share access.
  9700. //
  9701. IoSetShareAccess( GrantedAccess,
  9702. IrpSp->Parameters.Create.ShareAccess,
  9703. IrpSp->FileObject,
  9704. &(*ThisScb)->ShareAccess );
  9705. break;
  9706. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  9707. case RecheckShareAccess :
  9708. DebugTrace( 0, Dbg, ("Rechecking share access\n") );
  9709. ASSERT( NT_SUCCESS( IoCheckShareAccess( GrantedAccess,
  9710. IrpSp->Parameters.Create.ShareAccess,
  9711. IrpSp->FileObject,
  9712. &(*ThisScb)->ShareAccess,
  9713. FALSE )));
  9714. #endif
  9715. default:
  9716. DebugTrace( 0, Dbg, ("Checking share access\n") );
  9717. //
  9718. // For this case we need to check the share access and
  9719. // fail this request if access is denied.
  9720. //
  9721. if (!NT_SUCCESS( Status = IoCheckShareAccess( GrantedAccess,
  9722. IrpSp->Parameters.Create.ShareAccess,
  9723. IrpSp->FileObject,
  9724. &(*ThisScb)->ShareAccess,
  9725. TRUE ))) {
  9726. try_return( NOTHING );
  9727. }
  9728. }
  9729. RemoveShareAccess = TRUE;
  9730. //
  9731. // If this happens to be the first time we see write access on this
  9732. // Scb, then we need to remember it, and check if we have a disk full
  9733. // condition.
  9734. //
  9735. if (IrpSp->FileObject->WriteAccess &&
  9736. !FlagOn((*ThisScb)->ScbState, SCB_STATE_WRITE_ACCESS_SEEN) &&
  9737. (SafeNodeType( (*ThisScb) ) == NTFS_NTC_SCB_DATA)) {
  9738. if ((*ThisScb)->ScbType.Data.TotalReserved != 0) {
  9739. NtfsAcquireReservedClusters( Vcb );
  9740. //
  9741. // Does this Scb have reserved space that causes us to exceed the free
  9742. // space on the volume?
  9743. //
  9744. if (((LlClustersFromBytes(Vcb, (*ThisScb)->ScbType.Data.TotalReserved) + Vcb->TotalReserved) >
  9745. Vcb->FreeClusters)) {
  9746. NtfsReleaseReservedClusters( Vcb );
  9747. try_return( Status = STATUS_DISK_FULL );
  9748. }
  9749. //
  9750. // Otherwise tally in the reserved space now for this Scb, and
  9751. // remember that we have seen write access.
  9752. //
  9753. Vcb->TotalReserved += LlClustersFromBytes(Vcb, (*ThisScb)->ScbType.Data.TotalReserved);
  9754. NtfsReleaseReservedClusters( Vcb );
  9755. }
  9756. SetFlag( (*ThisScb)->ScbState, SCB_STATE_WRITE_ACCESS_SEEN );
  9757. }
  9758. //
  9759. // Create the Ccb and put the remaining name in it.
  9760. //
  9761. *ThisCcb = NtfsCreateCcb( IrpContext,
  9762. ThisFcb,
  9763. *ThisScb,
  9764. (BOOLEAN)(AttrTypeCode == $INDEX_ALLOCATION),
  9765. ThisFcb->EaModificationCount,
  9766. CcbFlags,
  9767. IrpSp->FileObject,
  9768. LastFileNameOffset );
  9769. if (FlagOn( ThisFcb->Vcb->QuotaFlags, QUOTA_FLAG_TRACKING_ENABLED ) &&
  9770. FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_FOR_FREE_SPACE_QUERY )) {
  9771. //
  9772. // Get the owner id of the calling thread. This must be done at
  9773. // create time since that is the only time the owner is valid.
  9774. //
  9775. (*ThisCcb)->OwnerId = NtfsGetCallersUserId( IrpContext );
  9776. }
  9777. //
  9778. // Link the Ccb into the Lcb.
  9779. //
  9780. if (ARGUMENT_PRESENT( ThisLcb )) {
  9781. NtfsLinkCcbToLcb( IrpContext, *ThisCcb, ThisLcb );
  9782. }
  9783. //
  9784. // Update the Fcb delete counts if necessary.
  9785. //
  9786. if (RemoveShareAccess) {
  9787. //
  9788. // Update the count in the Fcb and store a flag in the Ccb
  9789. // if the user is not sharing the file for deletes. We only
  9790. // set these values if the user is accessing the file
  9791. // for read/write/delete access. The I/O system ignores
  9792. // the sharing mode unless the file is opened with one
  9793. // of these accesses.
  9794. //
  9795. if (FlagOn( GrantedAccess, NtfsAccessDataFlags )
  9796. && !FlagOn( IrpSp->Parameters.Create.ShareAccess,
  9797. FILE_SHARE_DELETE )) {
  9798. ThisFcb->FcbDenyDelete += 1;
  9799. SetFlag( (*ThisCcb)->Flags, CCB_FLAG_DENY_DELETE );
  9800. }
  9801. //
  9802. // Do the same for the file delete count for any user
  9803. // who opened the file as a file and requested delete access.
  9804. //
  9805. if (FlagOn( (*ThisCcb)->Flags, CCB_FLAG_OPEN_AS_FILE )
  9806. && FlagOn( GrantedAccess,
  9807. DELETE )) {
  9808. ThisFcb->FcbDeleteFile += 1;
  9809. SetFlag( (*ThisCcb)->Flags, CCB_FLAG_DELETE_FILE | CCB_FLAG_DELETE_ACCESS );
  9810. }
  9811. }
  9812. //
  9813. // Let our cleanup routine undo the share access change now.
  9814. //
  9815. RemoveShareAccess = FALSE;
  9816. //
  9817. // Increment the cleanup and close counts
  9818. //
  9819. NtfsIncrementCleanupCounts( *ThisScb,
  9820. ThisLcb,
  9821. BooleanFlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ));
  9822. NtfsIncrementCloseCounts( *ThisScb,
  9823. BooleanFlagOn( ThisFcb->FcbState, FCB_STATE_PAGING_FILE ),
  9824. (BOOLEAN) IsFileObjectReadOnly( IrpSp->FileObject ));
  9825. //
  9826. // If this is a user view index open, we want to set TypeOfOpen in
  9827. // time to get it copied into the Ccb.
  9828. //
  9829. if (FlagOn( (*ThisScb)->ScbState, SCB_STATE_VIEW_INDEX )) {
  9830. TypeOfOpen = UserViewIndexOpen;
  9831. }
  9832. if (TypeOfOpen != UserDirectoryOpen) {
  9833. DebugTrace( 0, Dbg, ("Updating Vcb and File object for user open\n") );
  9834. //
  9835. // Set the section object pointer if this is a data Scb
  9836. //
  9837. IrpSp->FileObject->SectionObjectPointer = &(*ThisScb)->NonpagedScb->SegmentObject;
  9838. } else {
  9839. //
  9840. // Set the Scb encrypted bit from the Fcb.
  9841. //
  9842. if (FlagOn( ThisFcb->FcbState, FCB_STATE_DIRECTORY_ENCRYPTED )) {
  9843. SetFlag( (*ThisScb)->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED );
  9844. }
  9845. }
  9846. //
  9847. // Set the file object type.
  9848. //
  9849. NtfsSetFileObject( IrpSp->FileObject,
  9850. TypeOfOpen,
  9851. *ThisScb,
  9852. *ThisCcb );
  9853. //
  9854. // If this is a non-cached open and there are only non-cached opens
  9855. // then go ahead and try to delete the section. We may go through here
  9856. // twice due to a logfile full and on the 2nd time no longer have a section
  9857. // The filesize then is updated in the close path
  9858. // We will never flush and purge system files like the mft in this path
  9859. //
  9860. if (FlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
  9861. !CreateFile &&
  9862. ((*ThisScb)->AttributeTypeCode == $DATA) &&
  9863. ((*ThisScb)->CleanupCount == (*ThisScb)->NonCachedCleanupCount) &&
  9864. ((*ThisScb)->NonpagedScb->SegmentObject.ImageSectionObject == NULL) &&
  9865. ((*ThisScb)->CompressionUnit == 0) &&
  9866. MmCanFileBeTruncated( &(*ThisScb)->NonpagedScb->SegmentObject, NULL ) &&
  9867. FlagOn( (*ThisScb)->ScbState, SCB_STATE_HEADER_INITIALIZED ) &&
  9868. !FlagOn( (*ThisScb)->Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
  9869. //
  9870. // Only do this in the Fsp so we have enough stack space for the flush.
  9871. // Also only call if we really have a datasection
  9872. //
  9873. if (((*ThisScb)->NonpagedScb->SegmentObject.DataSectionObject != NULL) &&
  9874. !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP )) {
  9875. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  9876. //
  9877. // If we are posting then we may want to use the next stack location.
  9878. //
  9879. if (IrpContext->Union.OplockCleanup->CompletionContext != NULL) {
  9880. NtfsPrepareForIrpCompletion( IrpContext,
  9881. IrpContext->OriginatingIrp,
  9882. IrpContext->Union.OplockCleanup->CompletionContext );
  9883. }
  9884. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  9885. }
  9886. //
  9887. // Flush and purge the stream.
  9888. //
  9889. NtfsFlushAndPurgeScb( IrpContext,
  9890. *ThisScb,
  9891. (ARGUMENT_PRESENT( ThisLcb ) ?
  9892. ThisLcb->Scb :
  9893. NULL) );
  9894. }
  9895. //
  9896. // Check if we should request a filter oplock.
  9897. //
  9898. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER )) {
  9899. FsRtlOplockFsctrl( &(*ThisScb)->ScbType.Data.Oplock,
  9900. IrpContext->OriginatingIrp,
  9901. 1 );
  9902. }
  9903. }
  9904. //
  9905. // Mark the Scb if this is a temporary file.
  9906. //
  9907. if (FlagOn( ThisFcb->Info.FileAttributes, FILE_ATTRIBUTE_TEMPORARY )) {
  9908. SetFlag( (*ThisScb)->ScbState, SCB_STATE_TEMPORARY );
  9909. SetFlag( IrpSp->FileObject->Flags, FO_TEMPORARY_FILE );
  9910. }
  9911. try_exit: NOTHING;
  9912. } finally {
  9913. DebugUnwind( NtfsOpenAttribute );
  9914. //
  9915. // Back out local actions on error.
  9916. //
  9917. if (AbnormalTermination()
  9918. && RemoveShareAccess) {
  9919. IoRemoveShareAccess( IrpSp->FileObject, &(*ThisScb)->ShareAccess );
  9920. }
  9921. DebugTrace( -1, Dbg, ("NtfsOpenAttribute: Status -> %08lx\n", Status) );
  9922. }
  9923. return Status;
  9924. }
  9925. //
  9926. // Local support routine.
  9927. //
  9928. VOID
  9929. NtfsBackoutFailedOpensPriv (
  9930. IN PIRP_CONTEXT IrpContext,
  9931. IN PFILE_OBJECT FileObject,
  9932. IN PFCB ThisFcb,
  9933. IN PSCB ThisScb,
  9934. IN PCCB ThisCcb
  9935. )
  9936. /*++
  9937. Routine Description:
  9938. This routine is called during an open that has failed after
  9939. modifying in-memory structures. We will repair the following
  9940. structures.
  9941. Vcb - Decrement the open counts. Check if we locked the volume.
  9942. ThisFcb - Restore he Share Access fields and decrement open counts.
  9943. ThisScb - Decrement the open counts.
  9944. ThisCcb - Remove from the Lcb and delete.
  9945. Arguments:
  9946. FileObject - This is the file object for this open.
  9947. ThisFcb - This is the Fcb for the file being opened.
  9948. ThisScb - This is the Scb for the given attribute.
  9949. ThisCcb - This is the Ccb for this open.
  9950. Return Value:
  9951. None.
  9952. --*/
  9953. {
  9954. PLCB Lcb;
  9955. PVCB Vcb = ThisFcb->Vcb;
  9956. PSCB CurrentParentScb;
  9957. PAGED_CODE();
  9958. DebugTrace( +1, Dbg, ("NtfsBackoutFailedOpens: Entered\n") );
  9959. //
  9960. // If there is an Scb and Ccb, we remove the share access from the
  9961. // Fcb. We also remove all of the open and unclean counts incremented
  9962. // by us.
  9963. //
  9964. //
  9965. // Remove this Ccb from the Lcb.
  9966. //
  9967. Lcb = ThisCcb->Lcb;
  9968. NtfsUnlinkCcbFromLcb( IrpContext, ThisCcb );
  9969. //
  9970. // Check if we need to remove the share access for this open.
  9971. //
  9972. IoRemoveShareAccess( FileObject, &ThisScb->ShareAccess );
  9973. //
  9974. // Modify the delete counts in the Fcb.
  9975. //
  9976. if (FlagOn( ThisCcb->Flags, CCB_FLAG_DELETE_FILE )) {
  9977. ThisFcb->FcbDeleteFile -= 1;
  9978. ClearFlag( ThisCcb->Flags, CCB_FLAG_DELETE_FILE );
  9979. }
  9980. if (FlagOn( ThisCcb->Flags, CCB_FLAG_DENY_DELETE )) {
  9981. ThisFcb->FcbDenyDelete -= 1;
  9982. ClearFlag( ThisCcb->Flags, CCB_FLAG_DENY_DELETE );
  9983. }
  9984. //
  9985. // Decrement the cleanup and close counts
  9986. //
  9987. NtfsDecrementCleanupCounts( ThisScb,
  9988. Lcb,
  9989. BooleanFlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ));
  9990. //
  9991. // Trim any normalized names created in this open if no cleanup counts left
  9992. //
  9993. if (0 == ThisScb->CleanupCount ) {
  9994. switch (ThisCcb->TypeOfOpen) {
  9995. case UserDirectoryOpen :
  9996. //
  9997. // Cleanup the current scb node if it has a name
  9998. //
  9999. if (ThisScb->ScbType.Index.NormalizedName.MaximumLength > LONGNAME_THRESHOLD) {
  10000. NtfsDeleteNormalizedName( ThisScb );
  10001. }
  10002. //
  10003. // Fallthrough to deal with parents - in some case the current node failed to get a name
  10004. // but we populated a tree of long names on the way down
  10005. //
  10006. case UserFileOpen :
  10007. if (Lcb != NULL) {
  10008. CurrentParentScb = Lcb->Scb;
  10009. } else {
  10010. CurrentParentScb = NULL;
  10011. }
  10012. //
  10013. // Try to trim normalized names if the name is suff. long and we don't own the mft
  10014. // which would cause a deadlock
  10015. //
  10016. if ((CurrentParentScb != NULL) &&
  10017. (CurrentParentScb->ScbType.Index.NormalizedName.MaximumLength > LONGNAME_THRESHOLD) &&
  10018. !NtfsIsSharedScb( Vcb->MftScb )) {
  10019. NtfsTrimNormalizedNames( IrpContext, ThisFcb, CurrentParentScb);
  10020. }
  10021. break;
  10022. } // endif switch
  10023. }
  10024. NtfsDecrementCloseCounts( IrpContext,
  10025. ThisScb,
  10026. Lcb,
  10027. (BOOLEAN) BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_PAGING_FILE),
  10028. (BOOLEAN) IsFileObjectReadOnly( FileObject ),
  10029. TRUE );
  10030. //
  10031. // Now clean up the Ccb.
  10032. //
  10033. NtfsDeleteCcb( ThisFcb, &ThisCcb );
  10034. DebugTrace( -1, Dbg, ("NtfsBackoutFailedOpens: Exit\n") );
  10035. return;
  10036. }
  10037. //
  10038. // Local support routine
  10039. //
  10040. VOID
  10041. NtfsUpdateScbFromMemory (
  10042. IN OUT PSCB Scb,
  10043. IN POLD_SCB_SNAPSHOT ScbSizes
  10044. )
  10045. /*++
  10046. Routine Description:
  10047. All of the information from the attribute is stored in the snapshot. We process
  10048. this data identically to NtfsUpdateScbFromAttribute.
  10049. Arguments:
  10050. Scb - This is the Scb to update.
  10051. ScbSizes - This contains the sizes to store in the scb.
  10052. Return Value:
  10053. None.
  10054. --*/
  10055. {
  10056. PAGED_CODE();
  10057. DebugTrace( +1, Dbg, ("NtfsUpdateScbFromMemory: Entered\n") );
  10058. //
  10059. // Check whether this is resident or nonresident
  10060. //
  10061. if (ScbSizes->Resident) {
  10062. Scb->Header.AllocationSize.QuadPart = ScbSizes->FileSize;
  10063. if (!FlagOn(Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED)) {
  10064. Scb->Header.ValidDataLength =
  10065. Scb->Header.FileSize = Scb->Header.AllocationSize;
  10066. }
  10067. #ifdef SYSCACHE_DEBUG
  10068. if (ScbIsBeingLogged( Scb )) {
  10069. FsRtlLogSyscacheEvent( Scb, SCE_VDL_CHANGE, SCE_FLAG_UPDATE_FROM_DISK, Scb->Header.ValidDataLength.QuadPart, 0, 0 );
  10070. }
  10071. #endif
  10072. Scb->Header.AllocationSize.LowPart =
  10073. QuadAlign( Scb->Header.AllocationSize.LowPart );
  10074. Scb->TotalAllocated = Scb->Header.AllocationSize.QuadPart;
  10075. NtfsVerifySizes( &Scb->Header );
  10076. //
  10077. // Set the resident flag in the Scb.
  10078. //
  10079. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT );
  10080. } else {
  10081. VCN FileClusters;
  10082. VCN AllocationClusters;
  10083. if (!FlagOn(Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED)) {
  10084. Scb->Header.ValidDataLength.QuadPart = ScbSizes->ValidDataLength;
  10085. Scb->Header.FileSize.QuadPart = ScbSizes->FileSize;
  10086. if (FlagOn( ScbSizes->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  10087. Scb->ValidDataToDisk = ScbSizes->ValidDataLength;
  10088. }
  10089. }
  10090. Scb->TotalAllocated = ScbSizes->TotalAllocated;
  10091. Scb->Header.AllocationSize.QuadPart = ScbSizes->AllocationSize;
  10092. #ifdef SYSCACHE_DEBUG
  10093. if (ScbIsBeingLogged( Scb )) {
  10094. FsRtlLogSyscacheEvent( Scb, SCE_VDL_CHANGE, SCE_FLAG_UPDATE_FROM_DISK, Scb->Header.ValidDataLength.QuadPart, 1, 0 );
  10095. }
  10096. #endif
  10097. ClearFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT );
  10098. //
  10099. // Get the size of the compression unit.
  10100. //
  10101. ASSERT( (ScbSizes->CompressionUnit == 0) ||
  10102. (ScbSizes->CompressionUnit == NTFS_CLUSTERS_PER_COMPRESSION) ||
  10103. FlagOn( ScbSizes->AttributeFlags, ATTRIBUTE_FLAG_SPARSE ));
  10104. if ((ScbSizes->CompressionUnit != 0) &&
  10105. (ScbSizes->CompressionUnit < 31)) {
  10106. Scb->CompressionUnit = BytesFromClusters( Scb->Vcb,
  10107. 1 << ScbSizes->CompressionUnit );
  10108. Scb->CompressionUnitShift = ScbSizes->CompressionUnit;
  10109. }
  10110. ASSERT( (Scb->CompressionUnit == 0) ||
  10111. (Scb->AttributeTypeCode == $INDEX_ALLOCATION) ||
  10112. NtfsIsTypeCodeCompressible( Scb->AttributeTypeCode ));
  10113. //
  10114. // Compute the clusters for the file and its allocation.
  10115. //
  10116. AllocationClusters = LlClustersFromBytes( Scb->Vcb, Scb->Header.AllocationSize.QuadPart );
  10117. if (Scb->CompressionUnit == 0) {
  10118. FileClusters = LlClustersFromBytes(Scb->Vcb, Scb->Header.FileSize.QuadPart);
  10119. } else {
  10120. FileClusters = Scb->Header.FileSize.QuadPart + Scb->CompressionUnit - 1;
  10121. FileClusters &= ~((ULONG_PTR)Scb->CompressionUnit - 1);
  10122. }
  10123. //
  10124. // If allocated clusters are greater than file clusters, mark
  10125. // the Scb to truncate on close.
  10126. //
  10127. if (AllocationClusters > FileClusters) {
  10128. SetFlag( Scb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE );
  10129. }
  10130. }
  10131. Scb->AttributeFlags = ScbSizes->AttributeFlags;
  10132. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK | ATTRIBUTE_FLAG_SPARSE )) {
  10133. //
  10134. // If sparse CC should flush and purge when the file is mapped to
  10135. // keep reservations accurate
  10136. //
  10137. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {
  10138. SetFlag( Scb->Header.Flags2, FSRTL_FLAG2_PURGE_WHEN_MAPPED );
  10139. }
  10140. if (NtfsIsTypeCodeCompressible( Scb->AttributeTypeCode )) {
  10141. if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
  10142. SetFlag( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED );
  10143. }
  10144. //
  10145. // If the attribute is resident, then we will use our current
  10146. // default.
  10147. //
  10148. if (Scb->CompressionUnit == 0) {
  10149. Scb->CompressionUnit = BytesFromClusters( Scb->Vcb, 1 << NTFS_CLUSTERS_PER_COMPRESSION );
  10150. Scb->CompressionUnitShift = NTFS_CLUSTERS_PER_COMPRESSION;
  10151. //
  10152. // Trim the compression unit for large sparse clusters.
  10153. //
  10154. while (Scb->CompressionUnit > Scb->Vcb->SparseFileUnit) {
  10155. Scb->CompressionUnit >>= 1;
  10156. Scb->CompressionUnitShift -= 1;
  10157. }
  10158. }
  10159. }
  10160. }
  10161. //
  10162. // If the compression unit is non-zero or this is a resident file
  10163. // then set the flag in the common header for the Modified page writer.
  10164. //
  10165. NtfsAcquireFsrtlHeader( Scb );
  10166. Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
  10167. NtfsReleaseFsrtlHeader( Scb );
  10168. SetFlag( Scb->ScbState,
  10169. SCB_STATE_UNNAMED_DATA | SCB_STATE_FILE_SIZE_LOADED | SCB_STATE_HEADER_INITIALIZED );
  10170. DebugTrace( -1, Dbg, ("NtfsUpdateScbFromMemory: Exit\n") );
  10171. return;
  10172. }
  10173. //
  10174. // Local support routine
  10175. //
  10176. VOID
  10177. NtfsOplockPrePostIrp (
  10178. IN PVOID Context,
  10179. IN PIRP Irp
  10180. )
  10181. /*++
  10182. Routine Description:
  10183. This routine performs any neccessary work before STATUS_PENDING is
  10184. returned with the Fsd thread. This routine is called within the
  10185. filesystem and by the oplock package. This routine will update
  10186. the originating Irp in the IrpContext and release all of the Fcbs and
  10187. paging io resources in the IrpContext.
  10188. Arguments:
  10189. Context - Pointer to the IrpContext to be queued to the Fsp
  10190. Irp - I/O Request Packet
  10191. Return Value:
  10192. None.
  10193. --*/
  10194. {
  10195. PIO_STACK_LOCATION IrpSp;
  10196. PIRP_CONTEXT IrpContext;
  10197. POPLOCK_CLEANUP OplockCleanup;
  10198. PAGED_CODE();
  10199. IrpContext = (PIRP_CONTEXT) Context;
  10200. ASSERT_IRP_CONTEXT( IrpContext );
  10201. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_ALLOC_FROM_POOL ));
  10202. IrpContext->OriginatingIrp = Irp;
  10203. OplockCleanup = IrpContext->Union.OplockCleanup;
  10204. //
  10205. // Get the current Irp stack location
  10206. //
  10207. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  10208. //
  10209. // Adjust the filename strings as needed.
  10210. //
  10211. if ((OplockCleanup->ExactCaseName.Buffer != OplockCleanup->OriginalFileName.Buffer) &&
  10212. (OplockCleanup->ExactCaseName.Buffer != NULL)) {
  10213. ASSERT( OplockCleanup->ExactCaseName.Length != 0 );
  10214. ASSERT( OplockCleanup->OriginalFileName.MaximumLength >= OplockCleanup->ExactCaseName.MaximumLength );
  10215. RtlCopyMemory( OplockCleanup->OriginalFileName.Buffer,
  10216. OplockCleanup->ExactCaseName.Buffer,
  10217. OplockCleanup->ExactCaseName.MaximumLength );
  10218. }
  10219. //
  10220. // Restitute the access control state to what it was when we entered the request.
  10221. //
  10222. IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess = OplockCleanup->RemainingDesiredAccess;
  10223. IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess = OplockCleanup->PreviouslyGrantedAccess;
  10224. IrpSp->Parameters.Create.SecurityContext->DesiredAccess = OplockCleanup->DesiredAccess;
  10225. //
  10226. // Free any buffer we allocated.
  10227. //
  10228. if ((OplockCleanup->FullFileName.Buffer != NULL) &&
  10229. (OplockCleanup->OriginalFileName.Buffer != OplockCleanup->FullFileName.Buffer)) {
  10230. NtfsFreePool( OplockCleanup->FullFileName.Buffer );
  10231. OplockCleanup->FullFileName.Buffer = NULL;
  10232. }
  10233. //
  10234. // Set the file name in the file object back to it's original value.
  10235. //
  10236. OplockCleanup->FileObject->FileName = OplockCleanup->OriginalFileName;
  10237. //
  10238. // Cleanup the IrpContext.
  10239. // Restore the thread context pointer if associated with this IrpContext.
  10240. //
  10241. if (FlagOn( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  10242. NtfsRestoreTopLevelIrp();
  10243. ClearFlag( IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  10244. }
  10245. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE );
  10246. NtfsCleanupIrpContext( IrpContext, FALSE );
  10247. //
  10248. // Set the event for synchronous IO and set the IrpCompletion routine.
  10249. //
  10250. if (OplockCleanup->CompletionContext != NULL) {
  10251. NtfsPrepareForIrpCompletion( IrpContext,
  10252. IrpContext->OriginatingIrp,
  10253. IrpContext->Union.OplockCleanup->CompletionContext );
  10254. }
  10255. //
  10256. // Make sure to clear this field since the OplockCleanup structure is on the stack and
  10257. // we don't want anyone else to access this.
  10258. //
  10259. IrpContext->Union.OplockCleanup = NULL;
  10260. //
  10261. // Mark that we've already returned pending to the user
  10262. //
  10263. IoMarkIrpPending( Irp );
  10264. return;
  10265. }
  10266. //
  10267. // Local support routine.
  10268. //
  10269. NTSTATUS
  10270. NtfsCreateCompletionRoutine (
  10271. IN PDEVICE_OBJECT DeviceObject,
  10272. IN PIRP Irp,
  10273. IN PVOID Contxt
  10274. )
  10275. /*++
  10276. Routine Description:
  10277. This is the completion routine for synchronous creates. It is only called if
  10278. STATUS_PENDING was returned. We return MORE_PROCESSING_REQUIRED to take
  10279. control of the Irp again and also clear the top level thread storage. We have to
  10280. do this because we could be calling this routine in an Fsp thread and are
  10281. waiting for the event in an Fsd thread.
  10282. Arguments:
  10283. DeviceObject - Pointer to the file system device object.
  10284. Irp - Pointer to the Irp for this request. (This Irp will no longer
  10285. be accessible after this routine returns.)
  10286. Contxt - This is the event to signal.
  10287. Return Value:
  10288. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can take
  10289. control of the Irp in the original thread.
  10290. --*/
  10291. {
  10292. PAGED_CODE();
  10293. ASSERT_IRP_CONTEXT( ((PNTFS_COMPLETION_CONTEXT) Contxt)->IrpContext );
  10294. //
  10295. // Restore the thread context pointer if associated with this IrpContext.
  10296. // It is important for the create irp because we we might be completing
  10297. // the irp but take control of it again in a separate thread.
  10298. //
  10299. if (FlagOn( ((PNTFS_COMPLETION_CONTEXT) Contxt)->IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )) {
  10300. NtfsRestoreTopLevelIrp();
  10301. ClearFlag( ((PNTFS_COMPLETION_CONTEXT) Contxt)->IrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL );
  10302. }
  10303. KeSetEvent( &((PNTFS_COMPLETION_CONTEXT) Contxt)->Event, 0, FALSE );
  10304. return STATUS_MORE_PROCESSING_REQUIRED;
  10305. UNREFERENCED_PARAMETER( DeviceObject );
  10306. UNREFERENCED_PARAMETER( Irp );
  10307. }
  10308. //
  10309. // Local support routine.
  10310. //
  10311. NTSTATUS
  10312. NtfsCheckExistingFile (
  10313. IN PIRP_CONTEXT IrpContext,
  10314. IN PIO_STACK_LOCATION IrpSp,
  10315. IN PLCB ThisLcb OPTIONAL,
  10316. IN PFCB ThisFcb,
  10317. IN ULONG CcbFlags
  10318. )
  10319. /*++
  10320. Routine Description:
  10321. This routine is called to check the desired access on an existing file
  10322. against the ACL's and the read-only status of the file. If we fail on
  10323. the access check, that routine will raise. Otherwise we will return a
  10324. status to indicate success or the failure cause. This routine will access
  10325. and update the PreviouslyGrantedAccess field in the security context.
  10326. Arguments:
  10327. IrpSp - This is the Irp stack location for this open.
  10328. ThisLcb - This is the Lcb used to reach the Fcb to open.
  10329. ThisFcb - This is the Fcb where the open will occur.
  10330. CcbFlags - This is the flag field for the Ccb.
  10331. Return Value:
  10332. None.
  10333. --*/
  10334. {
  10335. BOOLEAN MaximumAllowed = FALSE;
  10336. PACCESS_STATE AccessState;
  10337. PAGED_CODE();
  10338. //
  10339. // Save a pointer to the access state for convenience.
  10340. //
  10341. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  10342. //
  10343. // Start by checking that there are no bits in the desired access that
  10344. // conflict with the read-only state of the file.
  10345. //
  10346. if (IsReadOnly( &ThisFcb->Info )) {
  10347. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  10348. FILE_WRITE_DATA
  10349. | FILE_APPEND_DATA
  10350. | FILE_ADD_SUBDIRECTORY
  10351. | FILE_DELETE_CHILD )) {
  10352. return STATUS_ACCESS_DENIED;
  10353. }
  10354. }
  10355. //
  10356. // If the volume itself is mounted readonly, we still let open-for-writes
  10357. // go through for legacy reasons. DELETE_ON_CLOSE is an exception.
  10358. //
  10359. if ((IsReadOnly( &ThisFcb->Info )) ||
  10360. (NtfsIsVolumeReadOnly( ThisFcb->Vcb ))) {
  10361. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE )) {
  10362. return STATUS_CANNOT_DELETE;
  10363. }
  10364. }
  10365. //
  10366. // Otherwise we need to check the requested access vs. the allowable
  10367. // access in the ACL on the file. We will want to remember if
  10368. // MAXIMUM_ALLOWED was requested and remove the invalid bits for
  10369. // a read-only file.
  10370. //
  10371. //
  10372. // Remember if maximum allowed was requested.
  10373. //
  10374. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  10375. MAXIMUM_ALLOWED )) {
  10376. MaximumAllowed = TRUE;
  10377. }
  10378. NtfsOpenCheck( IrpContext,
  10379. ThisFcb,
  10380. (((ThisLcb != NULL) && (ThisLcb != ThisFcb->Vcb->RootLcb))
  10381. ? ThisLcb->Scb->Fcb
  10382. : NULL),
  10383. IrpContext->OriginatingIrp );
  10384. //
  10385. // If this is a read-only file and we requested maximum allowed then
  10386. // remove the invalid bits. Ditto for readonly volumes.
  10387. //
  10388. if (MaximumAllowed &&
  10389. (IsReadOnly( &ThisFcb->Info ) ||
  10390. NtfsIsVolumeReadOnly( ThisFcb->Vcb ))) {
  10391. ClearFlag( AccessState->PreviouslyGrantedAccess,
  10392. FILE_WRITE_DATA
  10393. | FILE_APPEND_DATA
  10394. | FILE_ADD_SUBDIRECTORY
  10395. | FILE_DELETE_CHILD );
  10396. }
  10397. //
  10398. // We do a check here to see if we conflict with the delete status on the
  10399. // file. Right now we check if there is already an opener who has delete
  10400. // access on the file and this opener doesn't allow delete access.
  10401. // We can skip this test if the opener is not requesting read, write or
  10402. // delete access.
  10403. //
  10404. if (ThisFcb->FcbDeleteFile != 0
  10405. && FlagOn( AccessState->PreviouslyGrantedAccess, NtfsAccessDataFlags )
  10406. && !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_DELETE )) {
  10407. DebugTrace( -1, Dbg, ("NtfsCheckExistingFile: Exit\n") );
  10408. return STATUS_SHARING_VIOLATION;
  10409. }
  10410. //
  10411. // We do a check here to see if we conflict with the delete status on the
  10412. // file. If we are opening the file and requesting delete, then there can
  10413. // be no current handles which deny delete.
  10414. //
  10415. if (ThisFcb->FcbDenyDelete != 0
  10416. && FlagOn( AccessState->PreviouslyGrantedAccess, DELETE )
  10417. && FlagOn( CcbFlags, CCB_FLAG_OPEN_AS_FILE )) {
  10418. return STATUS_SHARING_VIOLATION;
  10419. }
  10420. return STATUS_SUCCESS;
  10421. }
  10422. //
  10423. // Local support routine.
  10424. //
  10425. NTSTATUS
  10426. NtfsBreakBatchOplock (
  10427. IN PIRP_CONTEXT IrpContext,
  10428. IN PIRP Irp,
  10429. IN PIO_STACK_LOCATION IrpSp,
  10430. IN PFCB ThisFcb,
  10431. IN UNICODE_STRING AttrName,
  10432. IN ATTRIBUTE_TYPE_CODE AttrTypeCode,
  10433. OUT PSCB *ThisScb
  10434. )
  10435. /*++
  10436. Routine Description:
  10437. This routine is called for each open of an existing attribute to
  10438. check for current batch oplocks on the file. We will also check
  10439. whether we will want to flush and purge this stream in the case
  10440. where only non-cached handles remain on the file. We only want
  10441. to do that in an Fsp thread because we will require every bit
  10442. of stack we can get.
  10443. Arguments:
  10444. Irp - This is the Irp for this open operation.
  10445. IrpSp - This is the stack location for this open.
  10446. ThisFcb - This is the Fcb for the file being opened.
  10447. AttrName - This is the attribute name in case we need to create
  10448. an Scb.
  10449. AttrTypeCode - This is the attribute type code to use to create
  10450. the Scb.
  10451. ThisScb - Address to store the Scb if found or created.
  10452. Return Value:
  10453. NTSTATUS - Will be either STATUS_SUCCESS or STATUS_PENDING.
  10454. --*/
  10455. {
  10456. BOOLEAN ScbExisted;
  10457. PSCB NextScb;
  10458. PLIST_ENTRY Links;
  10459. PAGED_CODE();
  10460. DebugTrace( +1, Dbg, ("NtfsBreakBatchOplock: Entered\n") );
  10461. //
  10462. // In general we will just break the batch oplock for the stream we
  10463. // are trying to open. However if we are trying to delete the file
  10464. // and someone has a batch oplock on a different stream which
  10465. // will cause our open to fail then we need to try to break those
  10466. // batch oplocks. Likewise if we are opening a stream and won't share
  10467. // with a file delete then we need to break any batch oplocks on the main
  10468. // stream of the file.
  10469. //
  10470. //
  10471. // Consider the case where we are opening a stream and there is a
  10472. // batch oplock on the main data stream.
  10473. //
  10474. if (AttrName.Length != 0) {
  10475. if (ThisFcb->FcbDeleteFile != 0 &&
  10476. !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_DELETE )) {
  10477. Links = ThisFcb->ScbQueue.Flink;
  10478. while (Links != &ThisFcb->ScbQueue) {
  10479. NextScb = CONTAINING_RECORD( Links, SCB, FcbLinks );
  10480. if (NextScb->AttributeTypeCode == $DATA &&
  10481. NextScb->AttributeName.Length == 0) {
  10482. if (FsRtlCurrentBatchOplock( &NextScb->ScbType.Data.Oplock )) {
  10483. //
  10484. // We remember if a batch oplock break is underway for the
  10485. // case where the sharing check fails.
  10486. //
  10487. Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
  10488. //
  10489. // We wait on the oplock.
  10490. //
  10491. if (FsRtlCheckOplock( &NextScb->ScbType.Data.Oplock,
  10492. Irp,
  10493. (PVOID) IrpContext,
  10494. NtfsOplockComplete,
  10495. NtfsOplockPrePostIrp ) == STATUS_PENDING) {
  10496. return STATUS_PENDING;
  10497. }
  10498. }
  10499. break;
  10500. }
  10501. Links = Links->Flink;
  10502. }
  10503. }
  10504. //
  10505. // Now consider the case where we are opening the main stream and want to
  10506. // delete the file but an opener on a stream is preventing us.
  10507. //
  10508. } else if (ThisFcb->FcbDenyDelete != 0 &&
  10509. FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess,
  10510. MAXIMUM_ALLOWED | DELETE )) {
  10511. //
  10512. // Find all of the other data Scb and check their oplock status.
  10513. //
  10514. Links = ThisFcb->ScbQueue.Flink;
  10515. while (Links != &ThisFcb->ScbQueue) {
  10516. NextScb = CONTAINING_RECORD( Links, SCB, FcbLinks );
  10517. if (NextScb->AttributeTypeCode == $DATA &&
  10518. NextScb->AttributeName.Length != 0) {
  10519. if (FsRtlCurrentBatchOplock( &NextScb->ScbType.Data.Oplock )) {
  10520. //
  10521. // We remember if a batch oplock break is underway for the
  10522. // case where the sharing check fails.
  10523. //
  10524. Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
  10525. //
  10526. // We wait on the oplock.
  10527. //
  10528. if (FsRtlCheckOplock( &NextScb->ScbType.Data.Oplock,
  10529. Irp,
  10530. (PVOID) IrpContext,
  10531. NtfsOplockComplete,
  10532. NtfsOplockPrePostIrp ) == STATUS_PENDING) {
  10533. return STATUS_PENDING;
  10534. }
  10535. Irp->IoStatus.Information = 0;
  10536. }
  10537. }
  10538. Links = Links->Flink;
  10539. }
  10540. }
  10541. //
  10542. // We try to find the Scb for this file.
  10543. //
  10544. *ThisScb = NtfsCreateScb( IrpContext,
  10545. ThisFcb,
  10546. AttrTypeCode,
  10547. &AttrName,
  10548. FALSE,
  10549. &ScbExisted );
  10550. //
  10551. // If there was a previous Scb, we examine the oplocks.
  10552. //
  10553. if (ScbExisted &&
  10554. (SafeNodeType( *ThisScb ) == NTFS_NTC_SCB_DATA)) {
  10555. //
  10556. // If we have to flush and purge then we want to be in the Fsp.
  10557. //
  10558. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_IN_FSP ) &&
  10559. FlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
  10560. ((*ThisScb)->CleanupCount == (*ThisScb)->NonCachedCleanupCount) &&
  10561. ((*ThisScb)->NonpagedScb->SegmentObject.DataSectionObject != NULL)) {
  10562. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  10563. //
  10564. // If we are posting then we may want to use the next stack location.
  10565. //
  10566. if (IrpContext->Union.OplockCleanup->CompletionContext != NULL) {
  10567. NtfsPrepareForIrpCompletion( IrpContext,
  10568. IrpContext->OriginatingIrp,
  10569. IrpContext->Union.OplockCleanup->CompletionContext );
  10570. }
  10571. NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL );
  10572. }
  10573. if (FsRtlCurrentBatchOplock( &(*ThisScb)->ScbType.Data.Oplock )) {
  10574. //
  10575. // If the handle count is greater than 1 then fail this
  10576. // open now.
  10577. //
  10578. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_RESERVE_OPFILTER ) &&
  10579. ((*ThisScb)->CleanupCount > 1)) {
  10580. NtfsRaiseStatus( IrpContext, STATUS_OPLOCK_NOT_GRANTED, NULL, NULL );
  10581. }
  10582. DebugTrace( 0, Dbg, ("Breaking batch oplock\n") );
  10583. //
  10584. // We remember if a batch oplock break is underway for the
  10585. // case where the sharing check fails.
  10586. //
  10587. Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
  10588. if (FsRtlCheckOplock( &(*ThisScb)->ScbType.Data.Oplock,
  10589. Irp,
  10590. (PVOID) IrpContext,
  10591. NtfsOplockComplete,
  10592. NtfsOplockPrePostIrp ) == STATUS_PENDING) {
  10593. return STATUS_PENDING;
  10594. }
  10595. Irp->IoStatus.Information = 0;
  10596. }
  10597. }
  10598. DebugTrace( -1, Dbg, ("NtfsBreakBatchOplock: Exit - %08lx\n", STATUS_SUCCESS) );
  10599. return STATUS_SUCCESS;
  10600. }
  10601. //
  10602. // Local support routine
  10603. //
  10604. NTSTATUS
  10605. NtfsCompleteLargeAllocation (
  10606. IN PIRP_CONTEXT IrpContext,
  10607. IN PIRP Irp,
  10608. IN PLCB Lcb OPTIONAL,
  10609. IN PSCB Scb,
  10610. IN PCCB Ccb,
  10611. IN ULONG CreateFlags
  10612. )
  10613. /*++
  10614. Routine Description:
  10615. This routine is called when we need to add more allocation to a stream
  10616. being opened. This stream could have been reallocated or created with
  10617. this call but we didn't allocate all of the space in the main path.
  10618. Arguments:
  10619. Irp - This is the Irp for this open operation.
  10620. Lcb - This is the Lcb used to reach the stream being opened. Won't be
  10621. specified in the open by ID case.
  10622. Scb - This is the Scb for the stream being opened.
  10623. Ccb - This is the Ccb for the this user handle.
  10624. CreateFlags - Indicates if this handle requires delete on close and
  10625. if we created or reallocated this stream.
  10626. Return Value:
  10627. NTSTATUS - the result of this operation.
  10628. --*/
  10629. {
  10630. NTSTATUS Status;
  10631. FILE_ALLOCATION_INFORMATION AllInfo;
  10632. PAGED_CODE();
  10633. //
  10634. // Commit the current transaction and free all resources.
  10635. //
  10636. NtfsCheckpointCurrentTransaction( IrpContext );
  10637. NtfsReleaseAllResources( IrpContext );
  10638. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  10639. AllInfo.AllocationSize = Irp->Overlay.AllocationSize;
  10640. Status = IoSetInformation( IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10641. FileAllocationInformation,
  10642. sizeof( FILE_ALLOCATION_INFORMATION ),
  10643. &AllInfo );
  10644. ASSERT( (Scb->CompressionUnit == 0) || (Scb->Header.AllocationSize.QuadPart % Scb->CompressionUnit == 0) );
  10645. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_CALL_SELF );
  10646. //
  10647. // Success! We will reacquire the Vcb quickly to undo the
  10648. // actions taken above to block access to the new file/attribute.
  10649. //
  10650. if (NT_SUCCESS( Status )) {
  10651. NtfsAcquireExclusiveVcb( IrpContext, Scb->Vcb, TRUE );
  10652. //
  10653. // Enable access to new file.
  10654. //
  10655. if (FlagOn( CreateFlags, CREATE_FLAG_CREATE_FILE_CASE )) {
  10656. Scb->Fcb->LinkCount = 1;
  10657. if (ARGUMENT_PRESENT( Lcb )) {
  10658. ClearFlag( Lcb->LcbState, LCB_STATE_DELETE_ON_CLOSE );
  10659. if (FlagOn( Lcb->FileNameAttr->Flags, FILE_NAME_DOS | FILE_NAME_NTFS )) {
  10660. ClearFlag( Scb->Fcb->FcbState, FCB_STATE_PRIMARY_LINK_DELETED );
  10661. }
  10662. }
  10663. //
  10664. // Enable access to new attribute.
  10665. //
  10666. } else {
  10667. ClearFlag( Scb->ScbState, SCB_STATE_DELETE_ON_CLOSE );
  10668. }
  10669. //
  10670. // If this is the DeleteOnClose case, we mark the Scb and Lcb
  10671. // appropriately.
  10672. //
  10673. if (FlagOn( CreateFlags, CREATE_FLAG_DELETE_ON_CLOSE )) {
  10674. SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE );
  10675. }
  10676. NtfsReleaseVcb( IrpContext, Scb->Vcb );
  10677. //
  10678. // Else there was some sort of error, and we need to let cleanup
  10679. // and close execute, since when we complete Create with an error
  10680. // cleanup and close would otherwise never occur. Cleanup will
  10681. // delete or truncate a file or attribute as appropriate, based on
  10682. // how we left the Fcb/Lcb or Scb above.
  10683. //
  10684. } else {
  10685. NtfsIoCallSelf( IrpContext,
  10686. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10687. IRP_MJ_CLEANUP );
  10688. NtfsIoCallSelf( IrpContext,
  10689. IoGetCurrentIrpStackLocation( Irp )->FileObject,
  10690. IRP_MJ_CLOSE );
  10691. }
  10692. return Status;
  10693. }
  10694. //
  10695. // Local support routine
  10696. //
  10697. ULONG
  10698. NtfsOpenExistingEncryptedStream (
  10699. IN PIRP_CONTEXT IrpContext,
  10700. IN PSCB ThisScb,
  10701. IN PFCB CurrentFcb
  10702. )
  10703. /*++
  10704. Routine Description:
  10705. This routine determines with which FileDirFlags, if any, we should call
  10706. the encryption driver's create callback.
  10707. Arguments:
  10708. ThisScb - This is the Scb for the file being opened.
  10709. CurrentFcb - This is the Fcb for the file being opened.
  10710. Return Value:
  10711. ULONG - The set of flags, such as FILE_EXISTING or DIRECTORY_EXISTING that
  10712. should be passed to the encryption driver. If 0 is returned, there
  10713. is no need to call the encryption driver for this create.
  10714. --*/
  10715. {
  10716. ULONG EncryptionFileDirFlags = 0;
  10717. //
  10718. // If we don't have an encryption driver then raise ACCESS_DENIED unless
  10719. // this is a directory, in which case there really isn't any encrypted data
  10720. // that we need to worry about. Consider the case where the user has
  10721. // marked a directory as encrypted and then removed the encryption driver.
  10722. // There may be unencrypted files in that directory, and there's no reason
  10723. // to prevent the user from getting to them.
  10724. //
  10725. if (!FlagOn( NtfsData.Flags, NTFS_FLAGS_ENCRYPTION_DRIVER ) &&
  10726. !IsDirectory( &CurrentFcb->Info )) {
  10727. NtfsRaiseStatus( IrpContext, STATUS_ACCESS_DENIED, NULL, NULL );
  10728. }
  10729. //
  10730. // In NT5, we have not tested with encrypted compressed files, so if we
  10731. // encounter one (perhaps NT6 created it and the user has gone back to
  10732. // an NT5 safe build) let's not allow opening it for read/write access.
  10733. // Like the test above, this is only an issue for files, not directories.
  10734. //
  10735. if (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK ) &&
  10736. !IsDirectory( &CurrentFcb->Info )) {
  10737. NtfsRaiseStatus( IrpContext, STATUS_ACCESS_DENIED, NULL, NULL );
  10738. }
  10739. //
  10740. // Set the appropriate flags for the 3 existing stream cases.
  10741. //
  10742. if (IsDirectory( &CurrentFcb->Info )) {
  10743. EncryptionFileDirFlags = DIRECTORY_EXISTING | STREAM_EXISTING;
  10744. } else if (IsEncrypted( &CurrentFcb->Info )) {
  10745. EncryptionFileDirFlags = FILE_EXISTING | STREAM_EXISTING | EXISTING_FILE_ENCRYPTED ;
  10746. } else {
  10747. EncryptionFileDirFlags = FILE_EXISTING | STREAM_EXISTING;
  10748. }
  10749. return EncryptionFileDirFlags;
  10750. }
  10751. //
  10752. // Local support routine
  10753. //
  10754. NTSTATUS
  10755. NtfsEncryptionCreateCallback (
  10756. IN PIRP_CONTEXT IrpContext,
  10757. IN PIRP Irp,
  10758. IN PIO_STACK_LOCATION IrpSp,
  10759. IN PSCB ThisScb,
  10760. IN PCCB ThisCcb,
  10761. IN PFCB CurrentFcb,
  10762. IN PFCB ParentFcb,
  10763. IN BOOLEAN CreateNewFile
  10764. )
  10765. /*++
  10766. Routine Description:
  10767. This routine performs the create callback to the encryption driver if one
  10768. is registered, and it is appropriate to do the callback. We do the
  10769. callback for the open of an existing stream that is marked as encrypted,
  10770. and for the creation of a new file/stream that will be encrypted.
  10771. There are a number of interesting cases, each of which requires its own
  10772. set of flags to be passed to the encryption engine. Some optimization may
  10773. be possible by setting and clearing individual bits for certain semi-general
  10774. cases, but at a massive cost in readability/maintainability.
  10775. Arguments:
  10776. Irp - Supplies the Irp to process.
  10777. ThisScb - This is the Scb for the file being opened.
  10778. ThisCcb - This is the Ccb for the file being opened
  10779. CurrentFcb - This is the Fcb for the file being opened.
  10780. ParentFcb - This is the Fcb for the parent of the file being opened.
  10781. Although not truly optional, it may be NULL for an
  10782. existing file being opened, such as an open by id.
  10783. CreateNewFile - TRUE if we're being called from NtfsCreateNewFile, FALSE otherwise.
  10784. Return Value:
  10785. NTSTATUS - The return status for the operation.
  10786. --*/
  10787. {
  10788. NTSTATUS EncryptionStatus = STATUS_SUCCESS;
  10789. ULONG FileAttributes = (ULONG) IrpSp->Parameters.Create.FileAttributes;
  10790. ULONG EncryptionFileDirFlags = 0;
  10791. PAGED_CODE();
  10792. //
  10793. // If this is an existing stream and the encryption bit is set then either
  10794. // call the driver or fail the request. We have to test CreateNewFile
  10795. // also in case our caller has not set the Information field of the Irp yet.
  10796. //
  10797. if (!NtfsIsStreamNew( Irp->IoStatus.Information ) &&
  10798. !CreateNewFile) {
  10799. if (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) &&
  10800. FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  10801. FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_EXECUTE)) {
  10802. EncryptionFileDirFlags = NtfsOpenExistingEncryptedStream( IrpContext, ThisScb, CurrentFcb );
  10803. } // else EncryptionFileDirFlags = 0;
  10804. //
  10805. // We need the encryption driver for new creates. We may be dealing with a
  10806. // new file create or a supersede/overwrite.
  10807. //
  10808. } else if (FlagOn( NtfsData.Flags, NTFS_FLAGS_ENCRYPTION_DRIVER )) {
  10809. if (CreateNewFile) {
  10810. //
  10811. // This is a new stream in a new file.
  10812. //
  10813. ASSERT( (ParentFcb == NULL) ||
  10814. FlagOn( ParentFcb->FcbState, FCB_STATE_DUP_INITIALIZED ));
  10815. //
  10816. // We want this new file/directory to be created encrypted if
  10817. // its parent directory is encrypted, or our caller has asked
  10818. // to have it created encrypted.
  10819. //
  10820. if (((ParentFcb != NULL) &&
  10821. (IsEncrypted( &ParentFcb->Info ))) ||
  10822. FlagOn( FileAttributes, FILE_ATTRIBUTE_ENCRYPTED )) {
  10823. if (IsDirectory( &CurrentFcb->Info )) {
  10824. EncryptionFileDirFlags = DIRECTORY_NEW | STREAM_NEW;
  10825. } else {
  10826. EncryptionFileDirFlags = FILE_NEW | STREAM_NEW;
  10827. }
  10828. } // else EncryptionFileDirFlags = 0;
  10829. } else {
  10830. //
  10831. // This is a supersede/overwrite or else a new stream being created
  10832. // in an existing file.
  10833. //
  10834. ASSERT( CurrentFcb != NULL );
  10835. ASSERT( NtfsIsStreamNew( Irp->IoStatus.Information ) );
  10836. if ((Irp->IoStatus.Information == FILE_SUPERSEDED) ||
  10837. (Irp->IoStatus.Information == FILE_OVERWRITTEN)) {
  10838. if (FlagOn( FileAttributes, FILE_ATTRIBUTE_ENCRYPTED )) {
  10839. //
  10840. // This is a supersede/overwrite where the caller set the encrypted flag.
  10841. //
  10842. if (IsDirectory( &CurrentFcb->Info )) {
  10843. EncryptionFileDirFlags = DIRECTORY_NEW | STREAM_NEW;
  10844. } else if (FlagOn( ThisScb->ScbState, SCB_STATE_UNNAMED_DATA )) {
  10845. //
  10846. // When superseding/overwriting the unnamed stream, the flags we
  10847. // pass depend on the encrypted state of the old file.
  10848. //
  10849. if (IsEncrypted( &CurrentFcb->Info )) {
  10850. EncryptionFileDirFlags = FILE_EXISTING | STREAM_NEW | EXISTING_FILE_ENCRYPTED;
  10851. } else {
  10852. //
  10853. // If there are open handles to this or any other stream, and the
  10854. // encryption engine will wish it could encrypt all streams, we
  10855. // may as well just fail the create now.
  10856. //
  10857. if ((CurrentFcb->CleanupCount > 1) &&
  10858. FlagOn( NtfsData.EncryptionCallBackTable.ImplementationFlags, ENCRYPTION_ALL_STREAMS )) {
  10859. NtfsRaiseStatus( IrpContext, STATUS_SHARING_VIOLATION, NULL, NULL );
  10860. }
  10861. EncryptionFileDirFlags = FILE_NEW | STREAM_NEW;
  10862. }
  10863. } else if (!FlagOn( NtfsData.EncryptionCallBackTable.ImplementationFlags, ENCRYPTION_ALL_STREAMS )) {
  10864. //
  10865. // We're superseding a named stream; if the encryption engine allows individual
  10866. // streams to be encrypted, notify it.
  10867. //
  10868. EncryptionFileDirFlags = FILE_EXISTING | STREAM_NEW | EXISTING_FILE_ENCRYPTED;
  10869. } // else EncryptionFileDirFlags = 0;
  10870. } else if (!FlagOn( ThisScb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
  10871. IsEncrypted( &CurrentFcb->Info )) {
  10872. //
  10873. // This is a supersede/overwrite of a named stream within an encrypted file.
  10874. //
  10875. if (IsDirectory( &CurrentFcb->Info )) {
  10876. EncryptionFileDirFlags = DIRECTORY_EXISTING | STREAM_NEW;
  10877. } else {
  10878. EncryptionFileDirFlags = FILE_EXISTING | STREAM_NEW | EXISTING_FILE_ENCRYPTED;
  10879. }
  10880. } else {
  10881. //
  10882. // We're superseding/overwriting the unnamed stream, and it's retaining
  10883. // its encryption from before the overwrite.
  10884. //
  10885. if (FlagOn( ThisScb->AttributeFlags, ATTRIBUTE_FLAG_ENCRYPTED ) &&
  10886. FlagOn( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  10887. FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_EXECUTE)) {
  10888. EncryptionFileDirFlags = NtfsOpenExistingEncryptedStream( IrpContext, ThisScb, CurrentFcb );
  10889. }
  10890. }
  10891. } else if (IsEncrypted( &CurrentFcb->Info )) {
  10892. ASSERT( Irp->IoStatus.Information == FILE_CREATED );
  10893. //
  10894. // This is a new stream being created in an existing encrypted file.
  10895. //
  10896. if (IsDirectory( &CurrentFcb->Info )) {
  10897. EncryptionFileDirFlags = DIRECTORY_EXISTING | STREAM_NEW;
  10898. } else {
  10899. EncryptionFileDirFlags = FILE_EXISTING | STREAM_NEW | EXISTING_FILE_ENCRYPTED;
  10900. }
  10901. } // else EncryptionFileDirFlags = 0;
  10902. }
  10903. } // else EncryptionFileDirFlags = 0;
  10904. //
  10905. // Remember the EncryptionFileDirFlags in case we need to use them to
  10906. // cleanup later.
  10907. //
  10908. ASSERT( IrpContext->EncryptionFileDirFlags == 0 ||
  10909. IrpContext->EncryptionFileDirFlags == EncryptionFileDirFlags );
  10910. IrpContext->EncryptionFileDirFlags = EncryptionFileDirFlags;
  10911. //
  10912. // Perform the update if we have encryption flags and there is a callback.
  10913. //
  10914. if (EncryptionFileDirFlags != 0) {
  10915. if (FlagOn( EncryptionFileDirFlags, FILE_NEW | DIRECTORY_NEW )) {
  10916. //
  10917. // While we're still holding the fcb, set the bit that reminds us
  10918. // to block other creates until the encryption engine has had its
  10919. // chance to set the key context for this stream.
  10920. //
  10921. ASSERT_EXCLUSIVE_FCB( CurrentFcb );
  10922. SetFlag( CurrentFcb->FcbState, FCB_STATE_ENCRYPTION_PENDING );
  10923. }
  10924. if (NtfsData.EncryptionCallBackTable.FileCreate != NULL) {
  10925. //
  10926. // Find the parent, if we can't find a parent (most likely in
  10927. // the supersede by id case) just pass the current fcb as the
  10928. // parent.
  10929. //
  10930. if ((ParentFcb == NULL)) {
  10931. if ((ThisCcb->Lcb != NULL) &&
  10932. (ThisCcb->Lcb->Scb != NULL )) {
  10933. ParentFcb = ThisCcb->Lcb->Scb->Fcb;
  10934. } else {
  10935. ParentFcb = CurrentFcb;
  10936. }
  10937. }
  10938. ASSERT( ParentFcb != NULL );
  10939. EncryptionStatus = NtfsData.EncryptionCallBackTable.FileCreate(
  10940. CurrentFcb,
  10941. ParentFcb,
  10942. IrpSp,
  10943. EncryptionFileDirFlags,
  10944. (NtfsIsVolumeReadOnly( CurrentFcb->Vcb )) ? READ_ONLY_VOLUME : 0,
  10945. IrpContext,
  10946. (PDEVICE_OBJECT) CONTAINING_RECORD( CurrentFcb->Vcb,
  10947. VOLUME_DEVICE_OBJECT,
  10948. Vcb ),
  10949. NULL,
  10950. &ThisScb->EncryptionContext,
  10951. &ThisScb->EncryptionContextLength,
  10952. &IrpContext->EfsCreateContext,
  10953. NULL );
  10954. if (EncryptionStatus != STATUS_SUCCESS) {
  10955. NtfsRaiseStatus( IrpContext, EncryptionStatus, NULL, NULL );
  10956. }
  10957. }
  10958. }
  10959. return EncryptionStatus;
  10960. }
  10961. //
  10962. // Local support routine
  10963. //
  10964. VOID
  10965. NtfsPostProcessEncryptedCreate (
  10966. IN PIRP_CONTEXT IrpContext,
  10967. IN PFILE_OBJECT FileObject,
  10968. IN ULONG EncryptionFileDirFlags,
  10969. IN ULONG FailedInPostCreateOnly
  10970. )
  10971. /*++
  10972. Routine Description:
  10973. This routine is called after the encryption driver's post create callout
  10974. returns. If we failed a create in the post create callout that had been
  10975. successful before the post create callout, we have to cleanup the file.
  10976. If we just created the file, we need to clear the encryption_pending bit
  10977. safely.
  10978. Arguments:
  10979. FileObject - Supplies the FileObject being created.
  10980. EncryptionFileDirFlags - Some combination of FILE_NEW, FILE_EXISTING, etc.
  10981. FailedInPostCreateOnly - Pass TRUE if the create operation had succeeded
  10982. until the PostCreate callout.
  10983. Return Value:
  10984. None.
  10985. --*/
  10986. {
  10987. PVCB Vcb;
  10988. PFCB Fcb;
  10989. PSCB Scb;
  10990. PCCB Ccb;
  10991. PLCB Lcb;
  10992. BOOLEAN FcbStillExists = TRUE;
  10993. PAGED_CODE();
  10994. //
  10995. // In some failure cases, we'll have no FileObject, in which case we have
  10996. // no cleanup to do. We can't do much without a FileObject anyway.
  10997. //
  10998. if (FileObject == NULL) {
  10999. return;
  11000. }
  11001. NtfsDecodeFileObject( IrpContext,
  11002. FileObject,
  11003. &Vcb,
  11004. &Fcb,
  11005. &Scb,
  11006. &Ccb,
  11007. FALSE );
  11008. //
  11009. // If we failed only in the post create, backout this create.
  11010. //
  11011. if (FailedInPostCreateOnly) {
  11012. if (FlagOn( EncryptionFileDirFlags, FILE_NEW | DIRECTORY_NEW ) ||
  11013. (FlagOn( EncryptionFileDirFlags, STREAM_NEW ) &&
  11014. FlagOn( EncryptionFileDirFlags, FILE_EXISTING ))) {
  11015. //
  11016. // Delete the stream if we still can. First acquire
  11017. // the Scb so we can safely test some bits in it.
  11018. //
  11019. NtfsAcquireExclusiveScb( IrpContext, Scb );
  11020. //
  11021. // If a dismount happened while we weren't holding the Scb,
  11022. // we should just do the cleanup & close and get out of here.
  11023. //
  11024. if (!FlagOn( Scb->ScbState, SCB_STATE_VOLUME_DISMOUNTED )) {
  11025. //
  11026. // See if we can still delete the stream. N.B. If we're
  11027. // working with the unnamed data stream, deleting the
  11028. // stream will delete the file.
  11029. //
  11030. Lcb = Ccb->Lcb;
  11031. if (!FlagOn( Scb->ScbState, SCB_STATE_MULTIPLE_OPENS ) &&
  11032. (Lcb != NULL)) {
  11033. //
  11034. // Now see if the file is really deleteable according to indexsup
  11035. //
  11036. if (FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  11037. BOOLEAN LastLink;
  11038. BOOLEAN NonEmptyIndex = FALSE;
  11039. //
  11040. // If the link is not deleted, we check if it can be deleted.
  11041. // Since we dropped all our resources for the PostCreate callout,
  11042. // this might be a nonempty index or a file with multiple
  11043. // links already.
  11044. //
  11045. if ((BOOLEAN)!LcbLinkIsDeleted( Lcb )
  11046. && (BOOLEAN)NtfsIsLinkDeleteable( IrpContext, Scb->Fcb, &NonEmptyIndex, &LastLink )) {
  11047. //
  11048. // It is ok to get rid of this guy. All we need to do is
  11049. // mark this Lcb for delete and decrement the link count
  11050. // in the Fcb. If this is a primary link, then we
  11051. // indicate that the primary link has been deleted.
  11052. //
  11053. SetFlag( Lcb->LcbState, LCB_STATE_DELETE_ON_CLOSE );
  11054. ASSERTMSG( "Link count should not be 0\n", Scb->Fcb->LinkCount != 0 );
  11055. Scb->Fcb->LinkCount -= 1;
  11056. if (FlagOn( Lcb->FileNameAttr->Flags, FILE_NAME_DOS | FILE_NAME_NTFS )) {
  11057. SetFlag( Scb->Fcb->FcbState, FCB_STATE_PRIMARY_LINK_DELETED );
  11058. }
  11059. //
  11060. // Indicate in the file object that a delete is pending
  11061. //
  11062. FileObject->DeletePending = TRUE;
  11063. }
  11064. } else {
  11065. //
  11066. // Otherwise we are simply removing the attribute.
  11067. //
  11068. SetFlag( Scb->ScbState, SCB_STATE_DELETE_ON_CLOSE );
  11069. //
  11070. // Indicate in the file object that a delete is pending
  11071. //
  11072. FileObject->DeletePending = TRUE;
  11073. }
  11074. }
  11075. }
  11076. //
  11077. // We can clear the pending bit now that we're done handling the
  11078. // failure.
  11079. //
  11080. if (FlagOn( EncryptionFileDirFlags, FILE_NEW | DIRECTORY_NEW )) {
  11081. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  11082. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  11083. ASSERT( (Scb->EncryptionContext != NULL) || FailedInPostCreateOnly );
  11084. ClearFlag( Fcb->FcbState, FCB_STATE_ENCRYPTION_PENDING );
  11085. KeSetEvent( &NtfsEncryptionPendingEvent, 0, FALSE );
  11086. NtfsReleaseFcb( IrpContext, Fcb );
  11087. }
  11088. //
  11089. // We need to release the Scb now, since the close may
  11090. // result in the Scb getting freed.
  11091. //
  11092. NtfsReleaseScb( IrpContext, Scb );
  11093. NtfsIoCallSelf( IrpContext,
  11094. FileObject,
  11095. IRP_MJ_CLEANUP );
  11096. FcbStillExists = FALSE;
  11097. NtfsIoCallSelf( IrpContext,
  11098. FileObject,
  11099. IRP_MJ_CLOSE );
  11100. } else if ((FlagOn( EncryptionFileDirFlags, FILE_EXISTING ) &&
  11101. FlagOn( EncryptionFileDirFlags, STREAM_EXISTING )) ||
  11102. FlagOn( EncryptionFileDirFlags, DIRECTORY_EXISTING )) {
  11103. #ifdef NTFSDBG
  11104. ASSERT( None == IrpContext->OwnershipState );
  11105. #endif
  11106. //
  11107. // All we have to do in this case is a cleanup and a close.
  11108. //
  11109. NtfsIoCallSelf( IrpContext,
  11110. FileObject,
  11111. IRP_MJ_CLEANUP );
  11112. FcbStillExists = FALSE;
  11113. NtfsIoCallSelf( IrpContext,
  11114. FileObject,
  11115. IRP_MJ_CLOSE );
  11116. }
  11117. }
  11118. //
  11119. // If we've done a cleanup & close, the Fcb may have been freed already,
  11120. // in which case we should just set the pending event and get out of here.
  11121. // If we still have the Fcb, let's make sure we've cleared the pending bit.
  11122. //
  11123. if (FlagOn( EncryptionFileDirFlags, FILE_NEW | DIRECTORY_NEW )) {
  11124. if (FcbStillExists) {
  11125. ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ) );
  11126. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  11127. ClearFlag( Fcb->FcbState, FCB_STATE_ENCRYPTION_PENDING );
  11128. KeSetEvent( &NtfsEncryptionPendingEvent, 0, FALSE );
  11129. NtfsReleaseFcb( IrpContext, Fcb );
  11130. } else {
  11131. KeSetEvent( &NtfsEncryptionPendingEvent, 0, FALSE );
  11132. }
  11133. }
  11134. }
  11135. NTSTATUS
  11136. NtfsTryOpenFcb (
  11137. IN PIRP_CONTEXT IrpContext,
  11138. IN PVCB Vcb,
  11139. OUT PFCB *CurrentFcb,
  11140. IN FILE_REFERENCE FileReference
  11141. )
  11142. /*++
  11143. Routine Description:
  11144. This routine is called to open a file by its file segment number.
  11145. We need to verify that this file Id exists. This code is
  11146. patterned after open by Id.
  11147. Arguments:
  11148. Vcb - Vcb for this volume.
  11149. CurrentFcb - Address of Fcb pointer. Store the Fcb we find here.
  11150. FileReference - This is the file Id for the file to open the
  11151. sequence number is ignored.
  11152. Return Value:
  11153. NTSTATUS - Indicates the result of this create file operation.
  11154. Note:
  11155. If the status is successful then the FCB is returned with its reference
  11156. count incremented and the FCB held exclusive.
  11157. --*/
  11158. {
  11159. NTSTATUS Status = STATUS_SUCCESS;
  11160. LONGLONG MftOffset;
  11161. PFILE_RECORD_SEGMENT_HEADER FileRecord;
  11162. PBCB Bcb = NULL;
  11163. PFCB ThisFcb;
  11164. BOOLEAN AcquiredFcbTable = FALSE;
  11165. BOOLEAN AcquiredMft = TRUE;
  11166. BOOLEAN ThisFcbFree = TRUE;
  11167. PAGED_CODE();
  11168. ASSERT( *CurrentFcb == NULL );
  11169. //
  11170. // Do not bother with system files.
  11171. //
  11172. //
  11173. // If this is a system fcb then return.
  11174. //
  11175. if (NtfsFullSegmentNumber( &FileReference ) < FIRST_USER_FILE_NUMBER &&
  11176. NtfsFullSegmentNumber( &FileReference ) != ROOT_FILE_NAME_INDEX_NUMBER) {
  11177. return STATUS_NOT_FOUND;
  11178. }
  11179. //
  11180. // Calculate the offset in the MFT. Use the full segment number since the user
  11181. // can specify any 48-bit value.
  11182. //
  11183. MftOffset = NtfsFullSegmentNumber( &FileReference );
  11184. MftOffset = Int64ShllMod32(MftOffset, Vcb->MftShift);
  11185. //
  11186. // Acquire the MFT shared so it cannot shrink on us.
  11187. //
  11188. NtfsAcquireSharedScb( IrpContext, Vcb->MftScb );
  11189. try {
  11190. if (MftOffset >= Vcb->MftScb->Header.FileSize.QuadPart) {
  11191. DebugTrace( 0, Dbg, ("File Id doesn't lie within Mft\n") );
  11192. Status = STATUS_END_OF_FILE;
  11193. leave;
  11194. }
  11195. NtfsReadMftRecord( IrpContext,
  11196. Vcb,
  11197. &FileReference,
  11198. FALSE,
  11199. &Bcb,
  11200. &FileRecord,
  11201. NULL );
  11202. //
  11203. // This file record better be in use, better not be one of the other system files,
  11204. // and have a matching sequence number and be the primary file record for this file.
  11205. //
  11206. if (!FlagOn( FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE ) ||
  11207. FlagOn( FileRecord->Flags, FILE_SYSTEM_FILE ) ||
  11208. (*((PLONGLONG) &FileRecord->BaseFileRecordSegment) != 0) ||
  11209. (*((PULONG) FileRecord->MultiSectorHeader.Signature) != *((PULONG) FileSignature))) {
  11210. Status = STATUS_NOT_FOUND;
  11211. leave;
  11212. }
  11213. //
  11214. // Get the current sequence number.
  11215. //
  11216. FileReference.SequenceNumber = FileRecord->SequenceNumber;
  11217. NtfsUnpinBcb( IrpContext, &Bcb );
  11218. NtfsAcquireFcbTable( IrpContext, Vcb );
  11219. AcquiredFcbTable = TRUE;
  11220. //
  11221. // We know that it is safe to continue the open. We start by creating
  11222. // an Fcb for this file. It is possible that the Fcb exists.
  11223. // We create the Fcb first, if we need to update the Fcb info structure
  11224. // we copy the one from the index entry. We look at the Fcb to discover
  11225. // if it has any links, if it does then we make this the last Fcb we
  11226. // reached. If it doesn't then we have to clean it up from here.
  11227. //
  11228. ThisFcb = NtfsCreateFcb( IrpContext,
  11229. Vcb,
  11230. FileReference,
  11231. FALSE,
  11232. TRUE,
  11233. NULL );
  11234. //
  11235. // ReferenceCount the fcb so it does no go away.
  11236. //
  11237. ThisFcb->ReferenceCount += 1;
  11238. //
  11239. // Release the mft and fcb table before acquiring the FCB exclusive.
  11240. //
  11241. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  11242. NtfsReleaseFcbTable( IrpContext, Vcb );
  11243. AcquiredMft = FALSE;
  11244. AcquiredFcbTable = FALSE;
  11245. NtfsAcquireFcbWithPaging( IrpContext, ThisFcb, 0 );
  11246. ThisFcbFree = FALSE;
  11247. //
  11248. // Repin the file record with synchronization to the fcb
  11249. //
  11250. NtfsReadMftRecord( IrpContext,
  11251. Vcb,
  11252. &FileReference,
  11253. FALSE,
  11254. &Bcb,
  11255. &FileRecord,
  11256. NULL );
  11257. //
  11258. // Skip any deleted files.
  11259. //
  11260. if (FlagOn( ThisFcb->FcbState, FCB_STATE_FILE_DELETED ) ||
  11261. !FlagOn( FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE )) {
  11262. NtfsUnpinBcb( IrpContext, &Bcb );
  11263. #ifdef QUOTADBG
  11264. DbgPrint( "NtfsTryOpenFcb: Deleted fcb found. Fcb = %lx\n", ThisFcb );
  11265. #endif
  11266. NtfsAcquireFcbTable( IrpContext, Vcb );
  11267. ASSERT( ThisFcb->ReferenceCount > 0 );
  11268. ThisFcb->ReferenceCount--;
  11269. NtfsReleaseFcbTable( IrpContext, Vcb );
  11270. NtfsTeardownStructures( IrpContext,
  11271. ThisFcb,
  11272. NULL,
  11273. FALSE,
  11274. 0,
  11275. &ThisFcbFree );
  11276. //
  11277. // Release the fcb if it has not been deleted.
  11278. //
  11279. if (!ThisFcbFree) {
  11280. NtfsReleaseFcb( IrpContext, ThisFcb );
  11281. ThisFcbFree = TRUE;
  11282. }
  11283. //
  11284. // Teardown may generate a transaction, clean it up.
  11285. //
  11286. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DONT_DELETE | IRP_CONTEXT_FLAG_RETAIN_FLAGS );
  11287. NtfsCompleteRequest( IrpContext, NULL, Status );
  11288. Status = STATUS_NOT_FOUND;
  11289. leave;
  11290. }
  11291. NtfsUnpinBcb( IrpContext, &Bcb );
  11292. //
  11293. // Store this Fcb into our caller's parameter and remember to
  11294. // to show we acquired it.
  11295. //
  11296. *CurrentFcb = ThisFcb;
  11297. ThisFcbFree = TRUE;
  11298. //
  11299. // If the Fcb Info field needs to be initialized, we do so now.
  11300. // We read this information from the disk.
  11301. //
  11302. if (!FlagOn( ThisFcb->FcbState, FCB_STATE_DUP_INITIALIZED )) {
  11303. NtfsUpdateFcbInfoFromDisk( IrpContext,
  11304. TRUE,
  11305. ThisFcb,
  11306. NULL );
  11307. }
  11308. } finally {
  11309. if (AcquiredFcbTable) {
  11310. NtfsReleaseFcbTable( IrpContext, Vcb );
  11311. }
  11312. NtfsUnpinBcb( IrpContext, &Bcb );
  11313. if (AcquiredMft) {
  11314. NtfsReleaseScb( IrpContext, Vcb->MftScb );
  11315. }
  11316. if (!ThisFcbFree) {
  11317. NtfsReleaseFcb( IrpContext, ThisFcb );
  11318. }
  11319. }
  11320. return Status;
  11321. }
  11322. //
  11323. // Worker routine.
  11324. //
  11325. NTSTATUS
  11326. NtfsGetReparsePointValue (
  11327. IN PIRP_CONTEXT IrpContext,
  11328. IN PIRP Irp,
  11329. PIO_STACK_LOCATION IrpSp,
  11330. IN PFCB Fcb,
  11331. IN USHORT RemainingNameLength
  11332. )
  11333. /*++
  11334. Routine Description:
  11335. This routine retrieves the value of the specified reparse point and returns it to
  11336. the caller.
  11337. The user-controlled data in the reparse point is returned in a new buffer pointed
  11338. from Irp->Tail.Overlay.AuxiliaryBuffer. When the request traverses the stack of
  11339. layered drivers and not one operates on it, it is freed by the I/O subsystem in
  11340. IoCompleteRequest.
  11341. To provide callers with an indication of where in the name the parsing stoped, in
  11342. the Reserved field of the REPARSE_DATA_BUFFER structure we return the length of the
  11343. portion of the name that remains to be parsed by NTFS. We account for the file
  11344. delimiter in our value to make the paste of names easy in IopParseDevice.
  11345. The name offset arithmetic is correct only if:
  11346. (1) All the intermediate names in the path are simple, that is, they do not contain
  11347. any : (colon) in them.
  11348. (2) The RemainingNameLength includes all the parts present in the last name component.
  11349. When this function succeeds, it sets in Irp->IoStatus.Information the Tag of the
  11350. reparse point that we have just copied out. In this case we return STATUS_REPARSE
  11351. and set Irp->IoStatus.Status to STATUS_REPARSE.
  11352. Arguments:
  11353. IrpContext - Supplies the Irp context of the call.
  11354. Irp - Supplies the Irp being processed
  11355. IrpSp - This is the Irp stack pointer for the filesystem.
  11356. Fcb - Address of the Fcb pointer where the $REPARSE_POINT attribute is located.
  11357. RemainingNameLength - Length of the part of the name that still needs to be parsed.
  11358. Return Value:
  11359. NTSTATUS - The return status for the operation
  11360. --*/
  11361. {
  11362. NTSTATUS Status = STATUS_REPARSE;
  11363. PREPARSE_DATA_BUFFER ReparseBuffer = NULL;
  11364. POPLOCK_CLEANUP OplockCleanup = IrpContext->Union.OplockCleanup;
  11365. BOOLEAN CleanupAttributeContext = FALSE;
  11366. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  11367. PATTRIBUTE_RECORD_HEADER AttributeHeader = NULL;
  11368. ULONG AttributeLengthInBytes = 0; // Invalid value
  11369. PVOID AttributeData = NULL;
  11370. PBCB Bcb = NULL;
  11371. PAGED_CODE( );
  11372. DebugTrace( +1, Dbg, ("NtfsGetReparsePointValue, Fcb %08lx\n", Fcb) );
  11373. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  11374. DebugTrace( 0, Dbg, ("OplockCleanup->OriginalFileName %x %Z\n", OplockCleanup->OriginalFileName.Buffer, &OplockCleanup->OriginalFileName) );
  11375. DebugTrace( 0, Dbg, ("OplockCleanup->FullFileName %x %Z\n", OplockCleanup->FullFileName.Buffer, &OplockCleanup->FullFileName) );
  11376. DebugTrace( 0, Dbg, ("OplockCleanup->ExactCaseName %x %Z\n", OplockCleanup->ExactCaseName.Buffer, &OplockCleanup->ExactCaseName) );
  11377. DebugTrace( 0, Dbg, ("IrpSP...->FileName %x %Z\n", IrpSp->FileObject->FileName.Buffer, &IrpSp->FileObject->FileName) );
  11378. #endif
  11379. DebugTrace( 0,
  11380. Dbg,
  11381. ("Length of remaining name [d] %04ld %04lx OriginalFileName.Length [d] %04ld %04lx\n",
  11382. RemainingNameLength,
  11383. RemainingNameLength,
  11384. OplockCleanup->OriginalFileName.Length,
  11385. OplockCleanup->OriginalFileName.Length) );
  11386. ASSERT( FlagOn( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT ));
  11387. ASSERT( Irp->Tail.Overlay.AuxiliaryBuffer == NULL );
  11388. //
  11389. // Now it is time to use a try-finally to facilitate cleanup.
  11390. //
  11391. try {
  11392. //
  11393. // Find the reparse point attribute in the file.
  11394. //
  11395. CleanupAttributeContext = TRUE;
  11396. NtfsInitializeAttributeContext( &AttributeContext );
  11397. if (!NtfsLookupAttributeByCode( IrpContext,
  11398. Fcb,
  11399. &Fcb->FileReference,
  11400. $REPARSE_POINT,
  11401. &AttributeContext )) {
  11402. DebugTrace( 0, Dbg, ("Can't find the $REPARSE_POINT attribute.\n") );
  11403. //
  11404. // Should not happen. Raise an exeption as we are in an
  11405. // inconsistent state. The attribute flag says that
  11406. // $REPARSE_POINT has to be present.
  11407. //
  11408. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  11409. }
  11410. //
  11411. // Find the size of the attribute and map its value to AttributeData.
  11412. //
  11413. AttributeHeader = NtfsFoundAttribute( &AttributeContext );
  11414. if (NtfsIsAttributeResident( AttributeHeader )) {
  11415. AttributeLengthInBytes = AttributeHeader->Form.Resident.ValueLength;
  11416. DebugTrace( 0, Dbg, ("Attribute is resident with length %08lx\n", AttributeLengthInBytes) );
  11417. if (AttributeLengthInBytes > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  11418. //
  11419. // Return STATUS_IO_REPARSE_DATA_INVALID
  11420. //
  11421. Status = STATUS_IO_REPARSE_DATA_INVALID;
  11422. leave;
  11423. }
  11424. //
  11425. // Point to the value of the attribute.
  11426. //
  11427. AttributeData = NtfsAttributeValue( AttributeHeader );
  11428. } else {
  11429. ULONG Length;
  11430. if (AttributeHeader->Form.Nonresident.FileSize > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  11431. //
  11432. // Return STATUS_IO_REPARSE_DATA_INVALID
  11433. //
  11434. Status = STATUS_IO_REPARSE_DATA_INVALID;
  11435. DebugTrace( 0, Dbg, ("Nonresident.FileSize is too long.\n") );
  11436. leave;
  11437. }
  11438. //
  11439. // Note that we coerse different LENGTHS
  11440. //
  11441. AttributeLengthInBytes = (ULONG)AttributeHeader->Form.Nonresident.FileSize;
  11442. DebugTrace( 0, Dbg, ("Attribute is non-resident with length %05lx\n", AttributeLengthInBytes) );
  11443. NtfsMapAttributeValue( IrpContext,
  11444. Fcb,
  11445. &AttributeData,
  11446. &Length,
  11447. &Bcb,
  11448. &AttributeContext );
  11449. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  11450. if (AttributeLengthInBytes != Length) {
  11451. DebugTrace( 0, Dbg, ("AttributeLengthInBytes [d]%05ld and Length [d]%05ld differ.\n", AttributeLengthInBytes, Length) );
  11452. }
  11453. ASSERT( AttributeLengthInBytes == Length );
  11454. #endif
  11455. }
  11456. //
  11457. // Reference the reparse point data.
  11458. // It is appropriate to use this cast, and not concern ourselves with the GUID
  11459. // buffer, because we only read the common fields.
  11460. //
  11461. ReparseBuffer = (PREPARSE_DATA_BUFFER)AttributeData;
  11462. DebugTrace( 0, Dbg, ("ReparseDataLength [d]%08ld %08lx\n",
  11463. ReparseBuffer->ReparseDataLength, ReparseBuffer->ReparseDataLength) );
  11464. //
  11465. // Verify that the length of the reparse point data is within our legal bound.
  11466. //
  11467. // Over time, this length can become illegal due to:
  11468. // (1) A decrease of the maximum legal value of the reparse point data.
  11469. // (2) A corruption of the data stored in the attribute.
  11470. //
  11471. if (ReparseBuffer->ReparseDataLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  11472. //
  11473. // Return STATUS_IO_REPARSE_DATA_INVALID
  11474. //
  11475. Status = STATUS_IO_REPARSE_DATA_INVALID;
  11476. DebugTrace( 0, Dbg, ("ReparseDataLength is (now) too long.\n") );
  11477. leave;
  11478. }
  11479. //
  11480. // We leave all the names in their original state.
  11481. // Return the complete reparse point data buffer off
  11482. // Irp->Tail.Overlay.AuxiliaryBuffer, already including the ReparseDataLength.
  11483. //
  11484. Irp->Tail.Overlay.AuxiliaryBuffer = NtfsAllocatePool( NonPagedPool,
  11485. AttributeLengthInBytes );
  11486. DebugTrace( 0, Dbg, ("Irp->Tail.Overlay.AuxiliaryBuffer %08lx\n", Irp->Tail.Overlay.AuxiliaryBuffer) );
  11487. RtlCopyMemory( (PCHAR)Irp->Tail.Overlay.AuxiliaryBuffer,
  11488. (PCHAR)AttributeData,
  11489. AttributeLengthInBytes );
  11490. //
  11491. // We also return the length of the portion of the name that remains to be parsed using the
  11492. // Reserved field in the REPARSE_DATA_BUFFER structure.
  11493. //
  11494. // The \ (backslash) in a multi-component name is always accounted for by the code before
  11495. // calling this routine.
  11496. // The : (colon) in a complex name is always accounted for by the code before calling this
  11497. // routine.
  11498. //
  11499. ReparseBuffer = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
  11500. ReparseBuffer->Reserved = RemainingNameLength;
  11501. //
  11502. // Better not have a non-zero length if opened by file id.
  11503. //
  11504. ASSERT( (RemainingNameLength == 0) ||
  11505. !FlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID ));
  11506. DebugTrace( 0, Dbg, ("Final value for ReparseBuffer->Reserved = %d\n", ReparseBuffer->Reserved) );
  11507. //
  11508. // When the Reserved field is positive, the offset should always denote the backslash character
  11509. // or the colon character.
  11510. //
  11511. // Assert this here.
  11512. //
  11513. if (ReparseBuffer->Reserved) {
  11514. DebugTrace( 0, Dbg, ("NameOffset = %d\n", (OplockCleanup->OriginalFileName.Length - ReparseBuffer->Reserved)) );
  11515. ASSERT( (*((PCHAR)(OplockCleanup->OriginalFileName.Buffer) + (OplockCleanup->OriginalFileName.Length - ReparseBuffer->Reserved)) == L'\\') ||
  11516. (*((PCHAR)(OplockCleanup->OriginalFileName.Buffer) + (OplockCleanup->OriginalFileName.Length - ReparseBuffer->Reserved)) == L':') );
  11517. ASSERT( (OplockCleanup->OriginalFileName.Buffer[(OplockCleanup->OriginalFileName.Length - ReparseBuffer->Reserved)/sizeof(WCHAR)] == L'\\') ||
  11518. (OplockCleanup->OriginalFileName.Buffer[(OplockCleanup->OriginalFileName.Length - ReparseBuffer->Reserved)/sizeof(WCHAR)] == L':') );
  11519. }
  11520. //
  11521. // Set the Information field to the ReparseTag.
  11522. //
  11523. Irp->IoStatus.Information = ReparseBuffer->ReparseTag;
  11524. } finally {
  11525. DebugUnwind( NtfsGetReparsePointValue );
  11526. if (CleanupAttributeContext) {
  11527. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  11528. }
  11529. //
  11530. // Unpin the Bcb ... in case you needed to pin it above.
  11531. // The unpin routine checks for NULL.
  11532. //
  11533. NtfsUnpinBcb( IrpContext, &Bcb );
  11534. }
  11535. DebugTrace( -1, Dbg, ("NtfsGetReparsePointValue -> IoStatus.Information %08lx Status %08lx\n", Irp->IoStatus.Information, Status) );
  11536. return Status;
  11537. UNREFERENCED_PARAMETER( IrpSp );
  11538. }
  11539. NTSTATUS
  11540. NtfsLookupObjectId (
  11541. IN PIRP_CONTEXT IrpContext,
  11542. IN PVCB Vcb,
  11543. IN PUNICODE_STRING FileName,
  11544. OUT PFILE_REFERENCE FileReference
  11545. )
  11546. /*++
  11547. Routine Description:
  11548. This routine retrieves the value of the specified objectid and returns it to
  11549. the caller.
  11550. Arguments:
  11551. IrpContext - Supplies the Irp context of the call.
  11552. Vcb - the volume to look it up in
  11553. FileName - Contains the objectid embedded in the unicode string
  11554. FileReference - on success contains the file that this objectid refers to
  11555. Return Value:
  11556. NTSTATUS - The return status for the operation
  11557. --*/
  11558. {
  11559. NTSTATUS Status = STATUS_SUCCESS;
  11560. INDEX_KEY IndexKey;
  11561. INDEX_ROW IndexRow;
  11562. UCHAR ObjectId[OBJECT_ID_KEY_LENGTH];
  11563. NTFS_OBJECTID_INFORMATION ObjectIdInfo;
  11564. MAP_HANDLE MapHandle;
  11565. BOOLEAN CleanupMapHandle = FALSE;
  11566. PAGED_CODE();
  11567. //
  11568. // Copy the object id out of the file name, optionally skipping
  11569. // over the Win32 backslash at the start of the buffer.
  11570. //
  11571. if (FileName->Length == OBJECT_ID_KEY_LENGTH) {
  11572. RtlCopyMemory( &ObjectId,
  11573. &FileName->Buffer[0],
  11574. sizeof( ObjectId ) );
  11575. } else {
  11576. RtlCopyMemory( &ObjectId,
  11577. &FileName->Buffer[1],
  11578. sizeof( ObjectId ) );
  11579. }
  11580. //
  11581. // Acquire the object id index for the volume.
  11582. //
  11583. NtfsAcquireSharedScb( IrpContext, Vcb->ObjectIdTableScb );
  11584. //
  11585. // Find the ObjectId.
  11586. //
  11587. try {
  11588. IndexKey.Key = &ObjectId;
  11589. IndexKey.KeyLength = sizeof( ObjectId );
  11590. NtOfsInitializeMapHandle( &MapHandle );
  11591. CleanupMapHandle = TRUE;
  11592. Status = NtOfsFindRecord( IrpContext,
  11593. Vcb->ObjectIdTableScb,
  11594. &IndexKey,
  11595. &IndexRow,
  11596. &MapHandle,
  11597. NULL );
  11598. if (!NT_SUCCESS( Status )) {
  11599. leave;
  11600. }
  11601. ASSERT( IndexRow.DataPart.DataLength == sizeof( NTFS_OBJECTID_INFORMATION ) );
  11602. RtlZeroMemory( &ObjectIdInfo,
  11603. sizeof( NTFS_OBJECTID_INFORMATION ) );
  11604. RtlCopyMemory( &ObjectIdInfo,
  11605. IndexRow.DataPart.Data,
  11606. sizeof( NTFS_OBJECTID_INFORMATION ) );
  11607. RtlCopyMemory( FileReference,
  11608. &ObjectIdInfo.FileSystemReference,
  11609. sizeof( FILE_REFERENCE ) );
  11610. //
  11611. // Now we have a file reference number, we're ready to proceed
  11612. // normally and open the file. There's no point in holding the
  11613. // object id index anymore, we've looked up all we needed in there.
  11614. //
  11615. } finally {
  11616. NtfsReleaseScb( IrpContext, Vcb->ObjectIdTableScb );
  11617. if (CleanupMapHandle) {
  11618. NtOfsReleaseMap( IrpContext, &MapHandle );
  11619. }
  11620. }
  11621. return Status;
  11622. }
  11623. #ifdef BRIANDBG
  11624. VOID
  11625. NtfsTestOpenName (
  11626. IN PFILE_OBJECT FileObject
  11627. )
  11628. {
  11629. ULONG Count = NtfsTestName.Length;
  11630. //
  11631. // This will let us catch particular opens through the debugger.
  11632. //
  11633. if ((Count != 0) &&
  11634. (FileObject->FileName.Length >= Count)) {
  11635. PWCHAR TestChar;
  11636. PWCHAR SourceChar = &FileObject->FileName.Buffer[ FileObject->FileName.Length / sizeof( WCHAR ) ];
  11637. Count = Count / sizeof( WCHAR );
  11638. TestChar = &NtfsTestName.Buffer[ Count ];
  11639. do {
  11640. TestChar -= 1;
  11641. SourceChar -= 1;
  11642. if ((*TestChar | 0x20) != (*SourceChar | 0x20)) {
  11643. break;
  11644. }
  11645. Count -= 1;
  11646. } while (Count != 0);
  11647. ASSERT( Count != 0 );
  11648. }
  11649. }
  11650. #endif