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.

4617 lines
123 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. FileInfo.c
  5. Abstract:
  6. This module implements the File Information routines for Fat called by
  7. the dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 22-Oct-1990
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_FILEINFO)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_FILEINFO)
  23. VOID
  24. FatQueryBasicInfo (
  25. IN PIRP_CONTEXT IrpContext,
  26. IN PFCB Fcb,
  27. IN PFILE_OBJECT FileObject,
  28. IN OUT PFILE_BASIC_INFORMATION Buffer,
  29. IN OUT PLONG Length
  30. );
  31. VOID
  32. FatQueryStandardInfo (
  33. IN PIRP_CONTEXT IrpContext,
  34. IN PFCB Fcb,
  35. IN OUT PFILE_STANDARD_INFORMATION Buffer,
  36. IN OUT PLONG Length
  37. );
  38. VOID
  39. FatQueryInternalInfo (
  40. IN PIRP_CONTEXT IrpContext,
  41. IN PFCB Fcb,
  42. IN OUT PFILE_INTERNAL_INFORMATION Buffer,
  43. IN OUT PLONG Length
  44. );
  45. VOID
  46. FatQueryEaInfo (
  47. IN PIRP_CONTEXT IrpContext,
  48. IN PFCB Fcb,
  49. IN OUT PFILE_EA_INFORMATION Buffer,
  50. IN OUT PLONG Length
  51. );
  52. VOID
  53. FatQueryPositionInfo (
  54. IN PIRP_CONTEXT IrpContext,
  55. IN PFILE_OBJECT FileObject,
  56. IN OUT PFILE_POSITION_INFORMATION Buffer,
  57. IN OUT PLONG Length
  58. );
  59. VOID
  60. FatQueryNameInfo (
  61. IN PIRP_CONTEXT IrpContext,
  62. IN PFCB Fcb,
  63. IN PCCB Ccb,
  64. IN OUT PFILE_NAME_INFORMATION Buffer,
  65. IN OUT PLONG Length
  66. );
  67. VOID
  68. FatQueryShortNameInfo (
  69. IN PIRP_CONTEXT IrpContext,
  70. IN PFCB Fcb,
  71. IN OUT PFILE_NAME_INFORMATION Buffer,
  72. IN OUT PLONG Length
  73. );
  74. VOID
  75. FatQueryNetworkInfo (
  76. IN PIRP_CONTEXT IrpContext,
  77. IN PFCB Fcb,
  78. IN PFILE_OBJECT FileObject,
  79. IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
  80. IN OUT PLONG Length
  81. );
  82. NTSTATUS
  83. FatSetBasicInfo (
  84. IN PIRP_CONTEXT IrpContext,
  85. IN PIRP Irp,
  86. IN PFCB Fcb,
  87. IN PCCB Ccb
  88. );
  89. NTSTATUS
  90. FatSetDispositionInfo (
  91. IN PIRP_CONTEXT IrpContext,
  92. IN PIRP Irp,
  93. IN PFILE_OBJECT FileObject,
  94. IN PFCB Fcb
  95. );
  96. NTSTATUS
  97. FatSetRenameInfo (
  98. IN PIRP_CONTEXT IrpContext,
  99. IN PIRP Irp,
  100. IN PVCB Vcb,
  101. IN PFCB Fcb,
  102. IN PCCB Ccb
  103. );
  104. NTSTATUS
  105. FatSetPositionInfo (
  106. IN PIRP_CONTEXT IrpContext,
  107. IN PIRP Irp,
  108. IN PFILE_OBJECT FileObject
  109. );
  110. NTSTATUS
  111. FatSetAllocationInfo (
  112. IN PIRP_CONTEXT IrpContext,
  113. IN PIRP Irp,
  114. IN PFCB Fcb,
  115. IN PFILE_OBJECT FileObject
  116. );
  117. NTSTATUS
  118. FatSetEndOfFileInfo (
  119. IN PIRP_CONTEXT IrpContext,
  120. IN PIRP Irp,
  121. IN PFILE_OBJECT FileObject,
  122. IN PVCB Vcb,
  123. IN PFCB Fcb
  124. );
  125. VOID
  126. FatDeleteFile (
  127. IN PIRP_CONTEXT IrpContext,
  128. IN PDCB TargetDcb,
  129. IN ULONG LfnOffset,
  130. IN ULONG DirentOffset,
  131. IN PDIRENT Dirent,
  132. IN PUNICODE_STRING Lfn
  133. );
  134. VOID
  135. FatRenameEAs (
  136. IN PIRP_CONTEXT IrpContext,
  137. IN PFCB Fcb,
  138. IN USHORT ExtendedAttributes,
  139. IN POEM_STRING OldOemName
  140. );
  141. #ifdef ALLOC_PRAGMA
  142. #pragma alloc_text(PAGE, FatCommonQueryInformation)
  143. #pragma alloc_text(PAGE, FatCommonSetInformation)
  144. #pragma alloc_text(PAGE, FatFsdQueryInformation)
  145. #pragma alloc_text(PAGE, FatFsdSetInformation)
  146. #pragma alloc_text(PAGE, FatQueryBasicInfo)
  147. #pragma alloc_text(PAGE, FatQueryEaInfo)
  148. #pragma alloc_text(PAGE, FatQueryInternalInfo)
  149. #pragma alloc_text(PAGE, FatQueryNameInfo)
  150. #pragma alloc_text(PAGE, FatQueryNetworkInfo)
  151. #pragma alloc_text(PAGE, FatQueryShortNameInfo)
  152. #pragma alloc_text(PAGE, FatQueryPositionInfo)
  153. #pragma alloc_text(PAGE, FatQueryStandardInfo)
  154. #pragma alloc_text(PAGE, FatSetAllocationInfo)
  155. #pragma alloc_text(PAGE, FatSetBasicInfo)
  156. #pragma alloc_text(PAGE, FatSetDispositionInfo)
  157. #pragma alloc_text(PAGE, FatSetEndOfFileInfo)
  158. #pragma alloc_text(PAGE, FatSetPositionInfo)
  159. #pragma alloc_text(PAGE, FatSetRenameInfo)
  160. #pragma alloc_text(PAGE, FatDeleteFile)
  161. #pragma alloc_text(PAGE, FatRenameEAs)
  162. #endif
  163. NTSTATUS
  164. FatFsdQueryInformation (
  165. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  166. IN PIRP Irp
  167. )
  168. /*++
  169. Routine Description:
  170. This routine implements the Fsd part of the NtQueryInformationFile API
  171. call.
  172. Arguments:
  173. VolumeDeviceObject - Supplies the volume device object where the file
  174. being queried exists.
  175. Irp - Supplies the Irp being processed.
  176. Return Value:
  177. NTSTATUS - The FSD status for the Irp.
  178. --*/
  179. {
  180. NTSTATUS Status;
  181. PIRP_CONTEXT IrpContext = NULL;
  182. BOOLEAN TopLevel;
  183. DebugTrace(+1, Dbg, "FatFsdQueryInformation\n", 0);
  184. //
  185. // Call the common query routine, with blocking allowed if synchronous
  186. //
  187. FsRtlEnterFileSystem();
  188. TopLevel = FatIsIrpTopLevel( Irp );
  189. try {
  190. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  191. Status = FatCommonQueryInformation( IrpContext, Irp );
  192. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  193. //
  194. // We had some trouble trying to perform the requested
  195. // operation, so we'll abort the I/O request with
  196. // the error status that we get back from the
  197. // execption code
  198. //
  199. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  200. }
  201. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  202. FsRtlExitFileSystem();
  203. //
  204. // And return to our caller
  205. //
  206. DebugTrace(-1, Dbg, "FatFsdQueryInformation -> %08lx\n", Status);
  207. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  208. return Status;
  209. }
  210. NTSTATUS
  211. FatFsdSetInformation (
  212. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  213. IN PIRP Irp
  214. )
  215. /*++
  216. Routine Description:
  217. This routine implements the FSD part of the NtSetInformationFile API
  218. call.
  219. Arguments:
  220. VolumeDeviceObject - Supplies the volume device object where the file
  221. being set exists.
  222. Irp - Supplies the Irp being processed.
  223. Return Value:
  224. NTSTATUS - The FSD status for the Irp.
  225. --*/
  226. {
  227. NTSTATUS Status;
  228. PIRP_CONTEXT IrpContext = NULL;
  229. BOOLEAN TopLevel;
  230. DebugTrace(+1, Dbg, "FatFsdSetInformation\n", 0);
  231. //
  232. // Call the common set routine, with blocking allowed if synchronous
  233. //
  234. FsRtlEnterFileSystem();
  235. TopLevel = FatIsIrpTopLevel( Irp );
  236. try {
  237. IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
  238. Status = FatCommonSetInformation( IrpContext, Irp );
  239. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  240. //
  241. // We had some trouble trying to perform the requested
  242. // operation, so we'll abort the I/O request with
  243. // the error status that we get back from the
  244. // execption code
  245. //
  246. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  247. }
  248. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  249. FsRtlExitFileSystem();
  250. //
  251. // And return to our caller
  252. //
  253. DebugTrace(-1, Dbg, "FatFsdSetInformation -> %08lx\n", Status);
  254. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  255. return Status;
  256. }
  257. NTSTATUS
  258. FatCommonQueryInformation (
  259. IN PIRP_CONTEXT IrpContext,
  260. IN PIRP Irp
  261. )
  262. /*++
  263. Routine Description:
  264. This is the common routine for querying file information called by both
  265. the fsd and fsp threads.
  266. Arguments:
  267. Irp - Supplies the Irp being processed
  268. Return Value:
  269. NTSTATUS - The return status for the operation
  270. --*/
  271. {
  272. NTSTATUS Status;
  273. PIO_STACK_LOCATION IrpSp;
  274. PFILE_OBJECT FileObject;
  275. LONG Length;
  276. FILE_INFORMATION_CLASS FileInformationClass;
  277. PVOID Buffer;
  278. TYPE_OF_OPEN TypeOfOpen;
  279. PVCB Vcb;
  280. PFCB Fcb;
  281. PCCB Ccb;
  282. BOOLEAN FcbAcquired;
  283. PFILE_ALL_INFORMATION AllInfo;
  284. //
  285. // Get the current stack location
  286. //
  287. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  288. FileObject = IrpSp->FileObject;
  289. DebugTrace(+1, Dbg, "FatCommonQueryInformation...\n", 0);
  290. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  291. DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.QueryFile.Length);
  292. DebugTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryFile.FileInformationClass);
  293. DebugTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
  294. //
  295. // Reference our input parameters to make things easier
  296. //
  297. Length = (LONG)IrpSp->Parameters.QueryFile.Length;
  298. FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
  299. Buffer = Irp->AssociatedIrp.SystemBuffer;
  300. //
  301. // Decode the file object
  302. //
  303. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  304. FcbAcquired = FALSE;
  305. Status = STATUS_SUCCESS;
  306. try {
  307. //
  308. // Case on the type of open we're dealing with
  309. //
  310. switch (TypeOfOpen) {
  311. case UserVolumeOpen:
  312. //
  313. // We cannot query the user volume open.
  314. //
  315. Status = STATUS_INVALID_PARAMETER;
  316. break;
  317. case UserFileOpen:
  318. case UserDirectoryOpen:
  319. case DirectoryFile:
  320. //
  321. // Acquire shared access to the fcb, except for a paging file
  322. // in order to avoid deadlocks with Mm.
  323. //
  324. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  325. if (!FatAcquireSharedFcb( IrpContext, Fcb )) {
  326. DebugTrace(0, Dbg, "Cannot acquire Fcb\n", 0);
  327. Status = FatFsdPostRequest( IrpContext, Irp );
  328. IrpContext = NULL;
  329. Irp = NULL;
  330. try_return( Status );
  331. }
  332. FcbAcquired = TRUE;
  333. }
  334. //
  335. // Make sure the Fcb is in a usable condition. This
  336. // will raise an error condition if the fcb is unusable
  337. //
  338. FatVerifyFcb( IrpContext, Fcb );
  339. //
  340. // Based on the information class we'll do different
  341. // actions. Each of hte procedures that we're calling fills
  342. // up the output buffer, if possible. They will raise the
  343. // status STATUS_BUFFER_OVERFLOW for an insufficient buffer.
  344. // This is considered a somewhat unusual case and is handled
  345. // more cleanly with the exception mechanism rather than
  346. // testing a return status value for each call.
  347. //
  348. switch (FileInformationClass) {
  349. case FileAllInformation:
  350. //
  351. // For the all information class we'll typecast a local
  352. // pointer to the output buffer and then call the
  353. // individual routines to fill in the buffer.
  354. //
  355. AllInfo = Buffer;
  356. Length -= (sizeof(FILE_ACCESS_INFORMATION)
  357. + sizeof(FILE_MODE_INFORMATION)
  358. + sizeof(FILE_ALIGNMENT_INFORMATION));
  359. FatQueryBasicInfo( IrpContext, Fcb, FileObject, &AllInfo->BasicInformation, &Length );
  360. FatQueryStandardInfo( IrpContext, Fcb, &AllInfo->StandardInformation, &Length );
  361. FatQueryInternalInfo( IrpContext, Fcb, &AllInfo->InternalInformation, &Length );
  362. FatQueryEaInfo( IrpContext, Fcb, &AllInfo->EaInformation, &Length );
  363. FatQueryPositionInfo( IrpContext, FileObject, &AllInfo->PositionInformation, &Length );
  364. FatQueryNameInfo( IrpContext, Fcb, Ccb, &AllInfo->NameInformation, &Length );
  365. break;
  366. case FileBasicInformation:
  367. FatQueryBasicInfo( IrpContext, Fcb, FileObject, Buffer, &Length );
  368. break;
  369. case FileStandardInformation:
  370. FatQueryStandardInfo( IrpContext, Fcb, Buffer, &Length );
  371. break;
  372. case FileInternalInformation:
  373. FatQueryInternalInfo( IrpContext, Fcb, Buffer, &Length );
  374. break;
  375. case FileEaInformation:
  376. FatQueryEaInfo( IrpContext, Fcb, Buffer, &Length );
  377. break;
  378. case FilePositionInformation:
  379. FatQueryPositionInfo( IrpContext, FileObject, Buffer, &Length );
  380. break;
  381. case FileNameInformation:
  382. FatQueryNameInfo( IrpContext, Fcb, Ccb, Buffer, &Length );
  383. break;
  384. case FileAlternateNameInformation:
  385. FatQueryShortNameInfo( IrpContext, Fcb, Buffer, &Length );
  386. break;
  387. case FileNetworkOpenInformation:
  388. FatQueryNetworkInfo( IrpContext, Fcb, FileObject, Buffer, &Length );
  389. break;
  390. default:
  391. Status = STATUS_INVALID_PARAMETER;
  392. break;
  393. }
  394. break;
  395. default:
  396. KdPrintEx((DPFLTR_FASTFAT_ID,
  397. DPFLTR_INFO_LEVEL,
  398. "FATQueryFile, Illegal TypeOfOpen = %08lx\n",
  399. TypeOfOpen));
  400. Status = STATUS_INVALID_PARAMETER;
  401. break;
  402. }
  403. //
  404. // If we overflowed the buffer, set the length to 0 and change the
  405. // status to STATUS_BUFFER_OVERFLOW.
  406. //
  407. if ( Length < 0 ) {
  408. Status = STATUS_BUFFER_OVERFLOW;
  409. Length = 0;
  410. }
  411. //
  412. // Set the information field to the number of bytes actually filled in
  413. // and then complete the request
  414. //
  415. Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
  416. try_exit: NOTHING;
  417. } finally {
  418. DebugUnwind( FatCommonQueryInformation );
  419. if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
  420. if (!AbnormalTermination()) {
  421. FatCompleteRequest( IrpContext, Irp, Status );
  422. }
  423. DebugTrace(-1, Dbg, "FatCommonQueryInformation -> %08lx\n", Status);
  424. }
  425. return Status;
  426. }
  427. NTSTATUS
  428. FatCommonSetInformation (
  429. IN PIRP_CONTEXT IrpContext,
  430. IN PIRP Irp
  431. )
  432. /*++
  433. Routine Description:
  434. This is the common routine for setting file information called by both
  435. the fsd and fsp threads.
  436. Arguments:
  437. Irp - Supplies the Irp being processed
  438. Return Value:
  439. NTSTATUS - The return status for the operation
  440. --*/
  441. {
  442. NTSTATUS Status;
  443. PIO_STACK_LOCATION IrpSp;
  444. PFILE_OBJECT FileObject;
  445. FILE_INFORMATION_CLASS FileInformationClass;
  446. TYPE_OF_OPEN TypeOfOpen;
  447. PVCB Vcb;
  448. PFCB Fcb;
  449. PCCB Ccb;
  450. BOOLEAN VcbAcquired = FALSE;
  451. BOOLEAN FcbAcquired = FALSE;
  452. //
  453. // Get the current stack location
  454. //
  455. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  456. DebugTrace(+1, Dbg, "FatCommonSetInformation...\n", 0);
  457. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  458. DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.SetFile.Length);
  459. DebugTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.SetFile.FileInformationClass);
  460. DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->Parameters.SetFile.FileObject);
  461. DebugTrace( 0, Dbg, "->ReplaceIfExists = %08lx\n", IrpSp->Parameters.SetFile.ReplaceIfExists);
  462. DebugTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
  463. //
  464. // Reference our input parameters to make things easier
  465. //
  466. FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
  467. FileObject = IrpSp->FileObject;
  468. //
  469. // Decode the file object
  470. //
  471. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  472. try {
  473. //
  474. // Case on the type of open we're dealing with
  475. //
  476. switch (TypeOfOpen) {
  477. case UserVolumeOpen:
  478. //
  479. // We cannot query the user volume open.
  480. //
  481. try_return( Status = STATUS_INVALID_PARAMETER );
  482. break;
  483. case UserFileOpen:
  484. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ) &&
  485. ((FileInformationClass == FileEndOfFileInformation) ||
  486. (FileInformationClass == FileAllocationInformation))) {
  487. //
  488. // We check whether we can proceed
  489. // based on the state of the file oplocks.
  490. //
  491. Status = FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
  492. Irp,
  493. IrpContext,
  494. NULL,
  495. NULL );
  496. if (Status != STATUS_SUCCESS) {
  497. try_return( Status );
  498. }
  499. //
  500. // Set the flag indicating if Fast I/O is possible
  501. //
  502. Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
  503. }
  504. break;
  505. case UserDirectoryOpen:
  506. break;
  507. default:
  508. try_return( Status = STATUS_INVALID_PARAMETER );
  509. }
  510. //
  511. // We can only do a set on a nonroot dcb, so we do the test
  512. // and then fall through to the user file open code.
  513. //
  514. if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
  515. if (FileInformationClass == FileDispositionInformation) {
  516. try_return( Status = STATUS_CANNOT_DELETE );
  517. }
  518. try_return( Status = STATUS_INVALID_PARAMETER );
  519. }
  520. //
  521. // In the following two cases, we cannot have creates occuring
  522. // while we are here, so acquire the volume exclusive.
  523. //
  524. if ((FileInformationClass == FileDispositionInformation) ||
  525. (FileInformationClass == FileRenameInformation)) {
  526. if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
  527. DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
  528. Status = FatFsdPostRequest( IrpContext, Irp );
  529. Irp = NULL;
  530. IrpContext = NULL;
  531. try_return( Status );
  532. }
  533. VcbAcquired = TRUE;
  534. }
  535. //
  536. // We need to look here to check whether the oplock state
  537. // will allow us to continue. We may have to loop to prevent
  538. // an oplock being granted between the time we check the oplock
  539. // and obtain the Fcb.
  540. //
  541. //
  542. // Acquire exclusive access to the Fcb, We use exclusive
  543. // because it is probable that one of the subroutines
  544. // that we call will need to monkey with file allocation,
  545. // create/delete extra fcbs. So we're willing to pay the
  546. // cost of exclusive Fcb access.
  547. //
  548. // Note that we do not acquire the resource for paging file
  549. // operations in order to avoid deadlock with Mm.
  550. //
  551. if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
  552. if (!FatAcquireExclusiveFcb( IrpContext, Fcb )) {
  553. DebugTrace(0, Dbg, "Cannot acquire Fcb\n", 0);
  554. Status = FatFsdPostRequest( IrpContext, Irp );
  555. Irp = NULL;
  556. IrpContext = NULL;
  557. try_return( Status );
  558. }
  559. FcbAcquired = TRUE;
  560. }
  561. Status = STATUS_SUCCESS;
  562. //
  563. // Make sure the Fcb is in a usable condition. This
  564. // will raise an error condition if the fcb is unusable
  565. //
  566. FatVerifyFcb( IrpContext, Fcb );
  567. //
  568. // Based on the information class we'll do different
  569. // actions. Each of the procedures that we're calling will either
  570. // complete the request of send the request off to the fsp
  571. // to do the work.
  572. //
  573. switch (FileInformationClass) {
  574. case FileBasicInformation:
  575. Status = FatSetBasicInfo( IrpContext, Irp, Fcb, Ccb );
  576. break;
  577. case FileDispositionInformation:
  578. //
  579. // If this is on deferred flush media, we have to be able to wait.
  580. //
  581. if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
  582. !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {
  583. Status = FatFsdPostRequest( IrpContext, Irp );
  584. Irp = NULL;
  585. IrpContext = NULL;
  586. } else {
  587. Status = FatSetDispositionInfo( IrpContext, Irp, FileObject, Fcb );
  588. }
  589. break;
  590. case FileRenameInformation:
  591. //
  592. // We proceed with this operation only if we can wait
  593. //
  594. if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
  595. Status = FatFsdPostRequest( IrpContext, Irp );
  596. Irp = NULL;
  597. IrpContext = NULL;
  598. } else {
  599. Status = FatSetRenameInfo( IrpContext, Irp, Vcb, Fcb, Ccb );
  600. //
  601. // If STATUS_PENDING is returned it means the oplock
  602. // package has the Irp. Don't complete the request here.
  603. //
  604. if (Status == STATUS_PENDING) {
  605. Irp = NULL;
  606. IrpContext = NULL;
  607. }
  608. }
  609. break;
  610. case FilePositionInformation:
  611. Status = FatSetPositionInfo( IrpContext, Irp, FileObject );
  612. break;
  613. case FileLinkInformation:
  614. Status = STATUS_INVALID_DEVICE_REQUEST;
  615. break;
  616. case FileAllocationInformation:
  617. Status = FatSetAllocationInfo( IrpContext, Irp, Fcb, FileObject );
  618. break;
  619. case FileEndOfFileInformation:
  620. Status = FatSetEndOfFileInfo( IrpContext, Irp, FileObject, Vcb, Fcb );
  621. break;
  622. default:
  623. Status = STATUS_INVALID_PARAMETER;
  624. break;
  625. }
  626. if ( IrpContext != NULL ) {
  627. FatUnpinRepinnedBcbs( IrpContext );
  628. }
  629. try_exit: NOTHING;
  630. } finally {
  631. DebugUnwind( FatCommonSetInformation );
  632. if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }
  633. if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }
  634. if (!AbnormalTermination()) {
  635. FatCompleteRequest( IrpContext, Irp, Status );
  636. }
  637. DebugTrace(-1, Dbg, "FatCommonSetInformation -> %08lx\n", Status);
  638. }
  639. return Status;
  640. }
  641. //
  642. // Internal Support Routine
  643. //
  644. VOID
  645. FatQueryBasicInfo (
  646. IN PIRP_CONTEXT IrpContext,
  647. IN PFCB Fcb,
  648. IN PFILE_OBJECT FileObject,
  649. IN OUT PFILE_BASIC_INFORMATION Buffer,
  650. IN OUT PLONG Length
  651. )
  652. /*++
  653. Description:
  654. This routine performs the query basic information function for fat.
  655. Arguments:
  656. Fcb - Supplies the Fcb being queried, it has been verified
  657. FileObject - Supplies the flag bit that indicates the file was modified.
  658. Buffer - Supplies a pointer to the buffer where the information is to
  659. be returned
  660. Length - Supplies the length of the buffer in bytes, and receives the
  661. remaining bytes free in the buffer upon return.
  662. Return Value:
  663. None
  664. --*/
  665. {
  666. DebugTrace(+1, Dbg, "FatQueryBasicInfo...\n", 0);
  667. //
  668. // Zero out the output buffer, and set it to indicate that
  669. // the query is a normal file. Later we might overwrite the
  670. // attribute.
  671. //
  672. RtlZeroMemory( Buffer, sizeof(FILE_BASIC_INFORMATION) );
  673. //
  674. // Extract the data and fill in the non zero fields of the output
  675. // buffer
  676. //
  677. if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
  678. //
  679. // We have to munge a lie on the fly. Every time we have to
  680. // use 1/1/80 we need to convert to GMT since the TZ may have
  681. // changed on us.
  682. //
  683. ExLocalTimeToSystemTime( &FatJanOne1980,
  684. &Buffer->LastWriteTime );
  685. Buffer->CreationTime = Buffer->LastAccessTime = Buffer->LastWriteTime;
  686. } else {
  687. Buffer->LastWriteTime = Fcb->LastWriteTime;
  688. Buffer->CreationTime = Fcb->CreationTime;
  689. Buffer->LastAccessTime = Fcb->LastAccessTime;
  690. }
  691. Buffer->FileAttributes = Fcb->DirentFatFlags;
  692. //
  693. // If the temporary flag is set, then set it in the buffer.
  694. //
  695. if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
  696. SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
  697. }
  698. //
  699. // If no attributes were set, set the normal bit.
  700. //
  701. if (Buffer->FileAttributes == 0) {
  702. Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
  703. }
  704. //
  705. // Update the length and status output variables
  706. //
  707. *Length -= sizeof( FILE_BASIC_INFORMATION );
  708. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  709. DebugTrace(-1, Dbg, "FatQueryBasicInfo -> VOID\n", 0);
  710. return;
  711. }
  712. //
  713. // Internal Support Routine
  714. //
  715. VOID
  716. FatQueryStandardInfo (
  717. IN PIRP_CONTEXT IrpContext,
  718. IN PFCB Fcb,
  719. IN OUT PFILE_STANDARD_INFORMATION Buffer,
  720. IN OUT PLONG Length
  721. )
  722. /*++
  723. Routine Description:
  724. This routine performs the query standard information function for fat.
  725. Arguments:
  726. Fcb - Supplies the Fcb being queried, it has been verified
  727. Buffer - Supplies a pointer to the buffer where the information is to
  728. be returned
  729. Length - Supplies the length of the buffer in bytes, and receives the
  730. remaining bytes free in the buffer upon return.
  731. Return Value:
  732. None
  733. --*/
  734. {
  735. DebugTrace(+1, Dbg, "FatQueryStandardInfo...\n", 0);
  736. //
  737. // Zero out the output buffer, and fill in the number of links
  738. // and the delete pending flag.
  739. //
  740. RtlZeroMemory( Buffer, sizeof(FILE_STANDARD_INFORMATION) );
  741. Buffer->NumberOfLinks = 1;
  742. Buffer->DeletePending = BooleanFlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  743. //
  744. // Case on whether this is a file or a directory, and extract
  745. // the information and fill in the fcb/dcb specific parts
  746. // of the output buffer
  747. //
  748. if (NodeType(Fcb) == FAT_NTC_FCB) {
  749. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  750. FatLookupFileAllocationSize( IrpContext, Fcb );
  751. }
  752. Buffer->AllocationSize = Fcb->Header.AllocationSize;
  753. Buffer->EndOfFile = Fcb->Header.FileSize;
  754. Buffer->Directory = FALSE;
  755. } else {
  756. Buffer->Directory = TRUE;
  757. }
  758. //
  759. // Update the length and status output variables
  760. //
  761. *Length -= sizeof( FILE_STANDARD_INFORMATION );
  762. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  763. DebugTrace(-1, Dbg, "FatQueryStandardInfo -> VOID\n", 0);
  764. return;
  765. }
  766. //
  767. // Internal Support Routine
  768. //
  769. VOID
  770. FatQueryInternalInfo (
  771. IN PIRP_CONTEXT IrpContext,
  772. IN PFCB Fcb,
  773. IN OUT PFILE_INTERNAL_INFORMATION Buffer,
  774. IN OUT PLONG Length
  775. )
  776. /*++
  777. Routine Description:
  778. This routine performs the query internal information function for fat.
  779. Arguments:
  780. Fcb - Supplies the Fcb being queried, it has been verified
  781. Buffer - Supplies a pointer to the buffer where the information is to
  782. be returned
  783. Length - Supplies the length of the buffer in bytes, and receives the
  784. remaining bytes free in the buffer upon return.
  785. Return Value:
  786. None
  787. --*/
  788. {
  789. DebugTrace(+1, Dbg, "FatQueryInternalInfo...\n", 0);
  790. try {
  791. Buffer->IndexNumber.QuadPart = FatGenerateFileIdFromFcb( Fcb );
  792. //
  793. // Update the length and status output variables
  794. //
  795. *Length -= sizeof( FILE_INTERNAL_INFORMATION );
  796. } finally {
  797. DebugUnwind( FatQueryInternalInfo );
  798. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  799. DebugTrace(-1, Dbg, "FatQueryInternalInfo -> VOID\n", 0);
  800. }
  801. return;
  802. }
  803. //
  804. // Internal Support Routine
  805. //
  806. VOID
  807. FatQueryEaInfo (
  808. IN PIRP_CONTEXT IrpContext,
  809. IN PFCB Fcb,
  810. IN OUT PFILE_EA_INFORMATION Buffer,
  811. IN OUT PLONG Length
  812. )
  813. /*++
  814. Routine Description:
  815. This routine performs the query Ea information function for fat.
  816. Arguments:
  817. Fcb - Supplies the Fcb being queried, it has been verified
  818. Buffer - Supplies a pointer to the buffer where the information is to
  819. be returned
  820. Length - Supplies the length of the buffer in bytes, and receives the
  821. remaining bytes free in the buffer upon return.
  822. Return Value:
  823. None
  824. --*/
  825. {
  826. PBCB Bcb;
  827. DebugTrace(+1, Dbg, "FatQueryEaInfo...\n", 0);
  828. Bcb = NULL;
  829. try {
  830. //
  831. // Zero out the output buffer
  832. //
  833. RtlZeroMemory( Buffer, sizeof(FILE_EA_INFORMATION) );
  834. //
  835. // The Root dcb does not have any EAs so don't look for any. Fat32
  836. // doesn't have any, either.
  837. //
  838. if ( NodeType( Fcb ) != FAT_NTC_ROOT_DCB &&
  839. !FatIsFat32( Fcb->Vcb )) {
  840. PDIRENT Dirent;
  841. //
  842. // Try to get the dirent for this file.
  843. //
  844. FatGetDirentFromFcbOrDcb( IrpContext,
  845. Fcb,
  846. &Dirent,
  847. &Bcb );
  848. if (Dirent != NULL) {
  849. //
  850. // Get a the size needed to store the full eas for the file.
  851. //
  852. FatGetEaLength( IrpContext,
  853. Fcb->Vcb,
  854. Dirent,
  855. &Buffer->EaSize );
  856. }
  857. }
  858. //
  859. // Update the length and status output variables
  860. //
  861. *Length -= sizeof( FILE_EA_INFORMATION );
  862. } finally {
  863. DebugUnwind( FatQueryEaInfo );
  864. //
  865. // Unpin the dirent if pinned.
  866. //
  867. FatUnpinBcb( IrpContext, Bcb );
  868. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  869. DebugTrace(-1, Dbg, "FatQueryEaInfo -> VOID\n", 0);
  870. }
  871. return;
  872. }
  873. //
  874. // Internal Support Routine
  875. //
  876. VOID
  877. FatQueryPositionInfo (
  878. IN PIRP_CONTEXT IrpContext,
  879. IN PFILE_OBJECT FileObject,
  880. IN OUT PFILE_POSITION_INFORMATION Buffer,
  881. IN OUT PLONG Length
  882. )
  883. /*++
  884. Routine Description:
  885. This routine performs the query position information function for fat.
  886. Arguments:
  887. FileObject - Supplies the File object being queried
  888. Buffer - Supplies a pointer to the buffer where the information is to
  889. be returned
  890. Length - Supplies the length of the buffer in bytes, and receives the
  891. remaining bytes free in the buffer upon return.
  892. Return Value:
  893. None
  894. --*/
  895. {
  896. DebugTrace(+1, Dbg, "FatQueryPositionInfo...\n", 0);
  897. //
  898. // Get the current position found in the file object.
  899. //
  900. Buffer->CurrentByteOffset = FileObject->CurrentByteOffset;
  901. //
  902. // Update the length and status output variables
  903. //
  904. *Length -= sizeof( FILE_POSITION_INFORMATION );
  905. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  906. DebugTrace(-1, Dbg, "FatQueryPositionInfo -> VOID\n", 0);
  907. UNREFERENCED_PARAMETER( IrpContext );
  908. return;
  909. }
  910. //
  911. // Internal Support Routine
  912. //
  913. VOID
  914. FatQueryNameInfo (
  915. IN PIRP_CONTEXT IrpContext,
  916. IN PFCB Fcb,
  917. IN PCCB Ccb,
  918. IN OUT PFILE_NAME_INFORMATION Buffer,
  919. IN OUT PLONG Length
  920. )
  921. /*++
  922. Routine Description:
  923. This routine performs the query name information function for fat.
  924. Arguments:
  925. Fcb - Supplies the Fcb being queried, it has been verified
  926. Ccb - Supplies the Ccb for the context of the user open
  927. Buffer - Supplies a pointer to the buffer where the information is to
  928. be returned
  929. Length - Supplies the length of the buffer in bytes, and receives the
  930. remaining bytes free in the buffer upon return.
  931. Return Value:
  932. None
  933. --*/
  934. {
  935. ULONG BytesToCopy;
  936. LONG TrimLength;
  937. BOOLEAN Overflow = FALSE;
  938. DebugTrace(+1, Dbg, "FatQueryNameInfo...\n", 0);
  939. //
  940. // Convert the name to UNICODE
  941. //
  942. *Length -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
  943. //
  944. // Use the full filename to build the path up. If we wanted to be
  945. // slick in the future, we'd just build the path directly into the
  946. // return buffer and avoid constructing the full filename, but since
  947. // the full filename winds up being required so often lets not
  948. // over optimize this case yet.
  949. //
  950. if (Fcb->FullFileName.Buffer == NULL) {
  951. FatSetFullFileNameInFcb( IrpContext, Fcb );
  952. }
  953. //
  954. // Here is where it gets a smidge tricky. FinalNameLength is the length
  955. // of the LFN element if it exists, and since the long name is always used
  956. // to build FullFileName, we have two cases:
  957. //
  958. // 1) short name: use FinalNameLength to tear off the path from FullFileName
  959. // and append the UNICODE converted short name.
  960. // 2) long name: just use FullFileName
  961. //
  962. // We bias to the name the user thinks they opened by. This winds
  963. // up fixing some oddball tunneling cases where intermediate filters
  964. // translate operations like delete into renames - this lets them
  965. // do the operation in the context of the name the user was using.
  966. //
  967. // It also matches what NTFS does, and so we have the definition of
  968. // correct behavior.
  969. //
  970. //
  971. //
  972. // Assume there is no long name and we are just going to use
  973. // FullFileName.
  974. //
  975. TrimLength = 0;
  976. //
  977. // If a LongName exists and the original open was by the short name
  978. // then set TrimLength to point to the place where the short name goes.
  979. //
  980. //
  981. // Note: The Ccb can be NULL. The lazy writer calls to get the name of
  982. // a DirectoryOpen FILE_OBJECT that it wants to display in the lost
  983. // delayed write popup. Handle this case by just using the FileFullName.
  984. //
  985. if (Fcb->LongName.Unicode.Name.Unicode.Buffer != NULL) {
  986. if ((Ccb != NULL) && FlagOn(Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME)) {
  987. TrimLength = Fcb->FinalNameLength;
  988. }
  989. }
  990. if (*Length < Fcb->FullFileName.Length - TrimLength) {
  991. BytesToCopy = *Length;
  992. Overflow = TRUE;
  993. } else {
  994. BytesToCopy = Fcb->FullFileName.Length - TrimLength;
  995. *Length -= BytesToCopy;
  996. }
  997. RtlCopyMemory( &Buffer->FileName[0],
  998. Fcb->FullFileName.Buffer,
  999. BytesToCopy );
  1000. //
  1001. // Note that this is just the amount of name we've copied so far. It'll
  1002. // either be all of it (long) or the path element including the \ (short).
  1003. //
  1004. Buffer->FileNameLength = Fcb->FullFileName.Length - TrimLength;
  1005. //
  1006. // If we trimmed off the name element, this is the short name case. Pick
  1007. // up the UNICODE conversion and append it.
  1008. //
  1009. if (TrimLength != 0) {
  1010. UNICODE_STRING ShortName;
  1011. WCHAR ShortNameBuffer[12];
  1012. NTSTATUS Status;
  1013. //
  1014. // Convert the short name to UNICODE and figure out how much
  1015. // of it can fit. Again, we always bump the returned length
  1016. // to indicate how much is available even if we can't return it.
  1017. //
  1018. ShortName.Length = 0;
  1019. ShortName.MaximumLength = sizeof(ShortNameBuffer);
  1020. ShortName.Buffer = ShortNameBuffer;
  1021. Status = RtlOemStringToCountedUnicodeString( &ShortName,
  1022. &Fcb->ShortName.Name.Oem,
  1023. FALSE );
  1024. ASSERT( Status == STATUS_SUCCESS );
  1025. if (!Overflow) {
  1026. if (*Length < ShortName.Length) {
  1027. BytesToCopy = *Length;
  1028. Overflow = TRUE;
  1029. } else {
  1030. BytesToCopy = ShortName.Length;
  1031. *Length -= BytesToCopy;
  1032. }
  1033. RtlCopyMemory( (PUCHAR)&Buffer->FileName[0] + Buffer->FileNameLength,
  1034. ShortName.Buffer,
  1035. BytesToCopy );
  1036. }
  1037. Buffer->FileNameLength += ShortName.Length;
  1038. }
  1039. if (Overflow) {
  1040. *Length = -1;
  1041. }
  1042. //
  1043. // Return to caller
  1044. //
  1045. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  1046. DebugTrace(-1, Dbg, "FatQueryNameInfo -> VOID\n", 0);
  1047. UNREFERENCED_PARAMETER( IrpContext );
  1048. return;
  1049. }
  1050. //
  1051. // Internal Support Routine
  1052. //
  1053. VOID
  1054. FatQueryShortNameInfo (
  1055. IN PIRP_CONTEXT IrpContext,
  1056. IN PFCB Fcb,
  1057. IN OUT PFILE_NAME_INFORMATION Buffer,
  1058. IN OUT PLONG Length
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. This routine queries the short name of the file.
  1063. Arguments:
  1064. Fcb - Supplies the Fcb being queried, it has been verified
  1065. Buffer - Supplies a pointer to the buffer where the information is to
  1066. be returned
  1067. Length - Supplies the length of the buffer in bytes, and receives the
  1068. remaining bytes free in the buffer upon return.
  1069. Return Value:
  1070. None
  1071. --*/
  1072. {
  1073. NTSTATUS Status;
  1074. ULONG BytesToCopy;
  1075. WCHAR ShortNameBuffer[12];
  1076. UNICODE_STRING ShortName;
  1077. DebugTrace(+1, Dbg, "FatQueryNameInfo...\n", 0);
  1078. //
  1079. // Convert the name to UNICODE
  1080. //
  1081. ShortName.Length = 0;
  1082. ShortName.MaximumLength = sizeof(ShortNameBuffer);
  1083. ShortName.Buffer = ShortNameBuffer;
  1084. *Length -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
  1085. Status = RtlOemStringToCountedUnicodeString( &ShortName,
  1086. &Fcb->ShortName.Name.Oem,
  1087. FALSE );
  1088. ASSERT( Status == STATUS_SUCCESS );
  1089. //
  1090. // If we overflow, set *Length to -1 as a flag.
  1091. //
  1092. if (*Length < ShortName.Length) {
  1093. BytesToCopy = *Length;
  1094. *Length = -1;
  1095. } else {
  1096. BytesToCopy = ShortName.Length;
  1097. *Length -= ShortName.Length;
  1098. }
  1099. RtlCopyMemory( &Buffer->FileName[0],
  1100. &ShortName.Buffer[0],
  1101. BytesToCopy );
  1102. Buffer->FileNameLength = ShortName.Length;
  1103. //
  1104. // Return to caller
  1105. //
  1106. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  1107. DebugTrace(-1, Dbg, "FatQueryNameInfo -> VOID\n", 0);
  1108. UNREFERENCED_PARAMETER( IrpContext );
  1109. return;
  1110. }
  1111. //
  1112. // Internal Support Routine
  1113. //
  1114. VOID
  1115. FatQueryNetworkInfo (
  1116. IN PIRP_CONTEXT IrpContext,
  1117. IN PFCB Fcb,
  1118. IN PFILE_OBJECT FileObject,
  1119. IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer,
  1120. IN OUT PLONG Length
  1121. )
  1122. /*++
  1123. Description:
  1124. This routine performs the query network open information function for fat.
  1125. Arguments:
  1126. Fcb - Supplies the Fcb being queried, it has been verified
  1127. FileObject - Supplies the flag bit that indicates the file was modified.
  1128. Buffer - Supplies a pointer to the buffer where the information is to
  1129. be returned
  1130. Length - Supplies the length of the buffer in bytes, and receives the
  1131. remaining bytes free in the buffer upon return.
  1132. Return Value:
  1133. None
  1134. --*/
  1135. {
  1136. DebugTrace(+1, Dbg, "FatQueryNetworkInfo...\n", 0);
  1137. //
  1138. // Zero out the output buffer, and set it to indicate that
  1139. // the query is a normal file. Later we might overwrite the
  1140. // attribute.
  1141. //
  1142. RtlZeroMemory( Buffer, sizeof(FILE_NETWORK_OPEN_INFORMATION) );
  1143. //
  1144. // Extract the data and fill in the non zero fields of the output
  1145. // buffer
  1146. //
  1147. if (Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB) {
  1148. //
  1149. // We have to munge a lie on the fly. Every time we have to
  1150. // use 1/1/80 we need to convert to GMT since the TZ may have
  1151. // changed on us.
  1152. //
  1153. ExLocalTimeToSystemTime( &FatJanOne1980,
  1154. &Buffer->LastWriteTime );
  1155. Buffer->CreationTime = Buffer->LastAccessTime = Buffer->LastWriteTime;
  1156. } else {
  1157. Buffer->LastWriteTime.QuadPart = Fcb->LastWriteTime.QuadPart;
  1158. Buffer->CreationTime.QuadPart = Fcb->CreationTime.QuadPart;
  1159. Buffer->LastAccessTime.QuadPart = Fcb->LastAccessTime.QuadPart;
  1160. }
  1161. Buffer->FileAttributes = Fcb->DirentFatFlags;
  1162. //
  1163. // If the temporary flag is set, then set it in the buffer.
  1164. //
  1165. if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) {
  1166. SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY );
  1167. }
  1168. //
  1169. // If no attributes were set, set the normal bit.
  1170. //
  1171. if (Buffer->FileAttributes == 0) {
  1172. Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1173. }
  1174. //
  1175. // Case on whether this is a file or a directory, and extract
  1176. // the information and fill in the fcb/dcb specific parts
  1177. // of the output buffer
  1178. //
  1179. if (NodeType(Fcb) == FAT_NTC_FCB) {
  1180. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  1181. FatLookupFileAllocationSize( IrpContext, Fcb );
  1182. }
  1183. Buffer->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart;
  1184. Buffer->EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
  1185. }
  1186. //
  1187. // Update the length and status output variables
  1188. //
  1189. *Length -= sizeof( FILE_NETWORK_OPEN_INFORMATION );
  1190. DebugTrace( 0, Dbg, "*Length = %08lx\n", *Length);
  1191. DebugTrace(-1, Dbg, "FatQueryNetworkInfo -> VOID\n", 0);
  1192. return;
  1193. }
  1194. //
  1195. // Internal Support routine
  1196. //
  1197. NTSTATUS
  1198. FatSetBasicInfo (
  1199. IN PIRP_CONTEXT IrpContext,
  1200. IN PIRP Irp,
  1201. IN PFCB Fcb,
  1202. IN PCCB Ccb
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. This routine performs the set basic information for fat. It either
  1207. completes the request or enqueues it off to the fsp.
  1208. Arguments:
  1209. Irp - Supplies the irp being processed
  1210. Fcb - Supplies the Fcb or Dcb being processed, already known not to
  1211. be the root dcb
  1212. Ccb - Supplies the flag bit that control updating the last modify
  1213. time on cleanup.
  1214. Return Value:
  1215. NTSTATUS - The result of this operation if it completes without
  1216. an exception.
  1217. --*/
  1218. {
  1219. NTSTATUS Status;
  1220. PFILE_BASIC_INFORMATION Buffer;
  1221. PDIRENT Dirent;
  1222. PBCB DirentBcb;
  1223. FAT_TIME_STAMP CreationTime;
  1224. UCHAR CreationMSec;
  1225. FAT_TIME_STAMP LastWriteTime;
  1226. FAT_TIME_STAMP LastAccessTime;
  1227. FAT_DATE LastAccessDate;
  1228. UCHAR Attributes;
  1229. BOOLEAN ModifyCreation = FALSE;
  1230. BOOLEAN ModifyLastWrite = FALSE;
  1231. BOOLEAN ModifyLastAccess = FALSE;
  1232. LARGE_INTEGER LargeCreationTime;
  1233. LARGE_INTEGER LargeLastWriteTime;
  1234. LARGE_INTEGER LargeLastAccessTime;
  1235. ULONG NotifyFilter = 0;
  1236. DebugTrace(+1, Dbg, "FatSetBasicInfo...\n", 0);
  1237. Buffer = Irp->AssociatedIrp.SystemBuffer;
  1238. //
  1239. // If the user is specifying -1 for a field, that means
  1240. // we should leave that field unchanged, even if we might
  1241. // have otherwise set it ourselves. We'll set the Ccb flag
  1242. // saying that the user set the field so that we
  1243. // don't do our default updating.
  1244. //
  1245. // We set the field to 0 then so we know not to actually
  1246. // set the field to the user-specified (and in this case,
  1247. // illegal) value.
  1248. //
  1249. if (Buffer->LastWriteTime.QuadPart == -1) {
  1250. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_WRITE );
  1251. Buffer->LastWriteTime.QuadPart = 0;
  1252. }
  1253. if (Buffer->LastAccessTime.QuadPart == -1) {
  1254. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_ACCESS );
  1255. Buffer->LastAccessTime.QuadPart = 0;
  1256. }
  1257. if (Buffer->CreationTime.QuadPart == -1) {
  1258. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_CREATION );
  1259. Buffer->CreationTime.QuadPart = 0;
  1260. }
  1261. DirentBcb = NULL;
  1262. Status = STATUS_SUCCESS;
  1263. try {
  1264. LARGE_INTEGER FatLocalDecThirtyOne1979;
  1265. LARGE_INTEGER FatLocalJanOne1980;
  1266. ExLocalTimeToSystemTime( &FatDecThirtyOne1979,
  1267. &FatLocalDecThirtyOne1979 );
  1268. ExLocalTimeToSystemTime( &FatJanOne1980,
  1269. &FatLocalJanOne1980 );
  1270. //
  1271. // Get a pointer to the dirent
  1272. //
  1273. ASSERT( Fcb->FcbCondition == FcbGood );
  1274. FatGetDirentFromFcbOrDcb( IrpContext,
  1275. Fcb,
  1276. &Dirent,
  1277. &DirentBcb );
  1278. ASSERT( Dirent && DirentBcb );
  1279. //
  1280. // Check if the user specified a non-zero creation time
  1281. //
  1282. if (FatData.ChicagoMode && (Buffer->CreationTime.QuadPart != 0)) {
  1283. LargeCreationTime = Buffer->CreationTime;
  1284. //
  1285. // Convert the Nt time to a Fat time
  1286. //
  1287. if ( !FatNtTimeToFatTime( IrpContext,
  1288. &LargeCreationTime,
  1289. FALSE,
  1290. &CreationTime,
  1291. &CreationMSec )) {
  1292. //
  1293. // Special case the value 12/31/79 and treat this as 1/1/80.
  1294. // This '79 value can happen because of time zone issues.
  1295. //
  1296. if ((LargeCreationTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
  1297. (LargeCreationTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
  1298. CreationTime = FatTimeJanOne1980;
  1299. LargeCreationTime = FatLocalJanOne1980;
  1300. } else {
  1301. DebugTrace(0, Dbg, "Invalid CreationTime\n", 0);
  1302. try_return( Status = STATUS_INVALID_PARAMETER );
  1303. }
  1304. //
  1305. // Don't worry about CreationMSec
  1306. //
  1307. CreationMSec = 0;
  1308. }
  1309. ModifyCreation = TRUE;
  1310. }
  1311. //
  1312. // Check if the user specified a non-zero last access time
  1313. //
  1314. if (FatData.ChicagoMode && (Buffer->LastAccessTime.QuadPart != 0)) {
  1315. LargeLastAccessTime = Buffer->LastAccessTime;
  1316. //
  1317. // Convert the Nt time to a Fat time
  1318. //
  1319. if ( !FatNtTimeToFatTime( IrpContext,
  1320. &LargeLastAccessTime,
  1321. TRUE,
  1322. &LastAccessTime,
  1323. NULL )) {
  1324. //
  1325. // Special case the value 12/31/79 and treat this as 1/1/80.
  1326. // This '79 value can happen because of time zone issues.
  1327. //
  1328. if ((LargeLastAccessTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
  1329. (LargeLastAccessTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
  1330. LastAccessTime = FatTimeJanOne1980;
  1331. LargeLastAccessTime = FatLocalJanOne1980;
  1332. } else {
  1333. DebugTrace(0, Dbg, "Invalid LastAccessTime\n", 0);
  1334. try_return( Status = STATUS_INVALID_PARAMETER );
  1335. }
  1336. }
  1337. LastAccessDate = LastAccessTime.Date;
  1338. ModifyLastAccess = TRUE;
  1339. }
  1340. //
  1341. // Check if the user specified a non-zero last write time
  1342. //
  1343. if (Buffer->LastWriteTime.QuadPart != 0) {
  1344. //
  1345. // First do a quick check here if the this time is the same
  1346. // time as LastAccessTime.
  1347. //
  1348. if (ModifyLastAccess &&
  1349. (Buffer->LastWriteTime.QuadPart == Buffer->LastAccessTime.QuadPart)) {
  1350. ModifyLastWrite = TRUE;
  1351. LastWriteTime = LastAccessTime;
  1352. LargeLastWriteTime = LargeLastAccessTime;
  1353. } else {
  1354. LargeLastWriteTime = Buffer->LastWriteTime;
  1355. //
  1356. // Convert the Nt time to a Fat time
  1357. //
  1358. if ( !FatNtTimeToFatTime( IrpContext,
  1359. &LargeLastWriteTime,
  1360. TRUE,
  1361. &LastWriteTime,
  1362. NULL )) {
  1363. //
  1364. // Special case the value 12/31/79 and treat this as 1/1/80.
  1365. // This '79 value can happen because of time zone issues.
  1366. //
  1367. if ((LargeLastWriteTime.QuadPart >= FatLocalDecThirtyOne1979.QuadPart) &&
  1368. (LargeLastWriteTime.QuadPart < FatLocalJanOne1980.QuadPart)) {
  1369. LastWriteTime = FatTimeJanOne1980;
  1370. LargeLastWriteTime = FatLocalJanOne1980;
  1371. } else {
  1372. DebugTrace(0, Dbg, "Invalid LastWriteTime\n", 0);
  1373. try_return( Status = STATUS_INVALID_PARAMETER );
  1374. }
  1375. }
  1376. ModifyLastWrite = TRUE;
  1377. }
  1378. }
  1379. //
  1380. // Check if the user specified a non zero file attributes byte
  1381. //
  1382. if (Buffer->FileAttributes != 0) {
  1383. //
  1384. // Only permit the attributes that FAT understands. The rest are silently
  1385. // dropped on the floor.
  1386. //
  1387. Attributes = (UCHAR)(Buffer->FileAttributes & (FILE_ATTRIBUTE_READONLY |
  1388. FILE_ATTRIBUTE_HIDDEN |
  1389. FILE_ATTRIBUTE_SYSTEM |
  1390. FILE_ATTRIBUTE_DIRECTORY |
  1391. FILE_ATTRIBUTE_ARCHIVE));
  1392. //
  1393. // Make sure that for a file the directory bit is not set
  1394. // and that for a directory the bit is set.
  1395. //
  1396. if (NodeType(Fcb) == FAT_NTC_FCB) {
  1397. if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
  1398. DebugTrace(0, Dbg, "Attempt to set dir attribute on file\n", 0);
  1399. try_return( Status = STATUS_INVALID_PARAMETER );
  1400. }
  1401. } else {
  1402. Attributes |= FAT_DIRENT_ATTR_DIRECTORY;
  1403. }
  1404. //
  1405. // Mark the FcbState temporary flag correctly.
  1406. //
  1407. if (FlagOn(Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY)) {
  1408. //
  1409. // Don't allow the temporary bit to be set on directories.
  1410. //
  1411. if (NodeType(Fcb) == FAT_NTC_DCB) {
  1412. DebugTrace(0, Dbg, "No temporary directories\n", 0);
  1413. try_return( Status = STATUS_INVALID_PARAMETER );
  1414. }
  1415. SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
  1416. SetFlag( IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags,
  1417. FO_TEMPORARY_FILE );
  1418. } else {
  1419. ClearFlag( Fcb->FcbState, FCB_STATE_TEMPORARY );
  1420. ClearFlag( IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags,
  1421. FO_TEMPORARY_FILE );
  1422. }
  1423. //
  1424. // Set the new attributes byte, and mark the bcb dirty
  1425. //
  1426. Fcb->DirentFatFlags = Attributes;
  1427. Dirent->Attributes = Attributes;
  1428. NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
  1429. }
  1430. if ( ModifyCreation ) {
  1431. //
  1432. // Set the new last write time in the dirent, and mark
  1433. // the bcb dirty
  1434. //
  1435. Fcb->CreationTime = LargeCreationTime;
  1436. Dirent->CreationTime = CreationTime;
  1437. Dirent->CreationMSec = CreationMSec;
  1438. NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
  1439. //
  1440. // Now we have to round the time in the Fcb up to the
  1441. // nearest tem msec.
  1442. //
  1443. Fcb->CreationTime.QuadPart =
  1444. ((Fcb->CreationTime.QuadPart + AlmostTenMSec) /
  1445. TenMSec) * TenMSec;
  1446. //
  1447. // Now because the user just set the creation time we
  1448. // better not set the creation time on close
  1449. //
  1450. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_CREATION );
  1451. }
  1452. if ( ModifyLastAccess ) {
  1453. //
  1454. // Set the new last write time in the dirent, and mark
  1455. // the bcb dirty
  1456. //
  1457. Fcb->LastAccessTime = LargeLastAccessTime;
  1458. Dirent->LastAccessDate = LastAccessDate;
  1459. NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
  1460. //
  1461. // Now we have to truncate the time in the Fcb down to the
  1462. // current day. This has to be in LocalTime though, so first
  1463. // convert to local, trunacate, then set back to GMT.
  1464. //
  1465. ExSystemTimeToLocalTime( &Fcb->LastAccessTime,
  1466. &Fcb->LastAccessTime );
  1467. Fcb->LastAccessTime.QuadPart =
  1468. (Fcb->LastAccessTime.QuadPart /
  1469. FatOneDay.QuadPart) * FatOneDay.QuadPart;
  1470. ExLocalTimeToSystemTime( &Fcb->LastAccessTime,
  1471. &Fcb->LastAccessTime );
  1472. //
  1473. // Now because the user just set the last access time we
  1474. // better not set the last access time on close
  1475. //
  1476. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_ACCESS );
  1477. }
  1478. if ( ModifyLastWrite ) {
  1479. //
  1480. // Set the new last write time in the dirent, and mark
  1481. // the bcb dirty
  1482. //
  1483. Fcb->LastWriteTime = LargeLastWriteTime;
  1484. Dirent->LastWriteTime = LastWriteTime;
  1485. NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
  1486. //
  1487. // Now we have to round the time in the Fcb up to the
  1488. // nearest two seconds.
  1489. //
  1490. Fcb->LastWriteTime.QuadPart =
  1491. ((Fcb->LastWriteTime.QuadPart + AlmostTwoSeconds) /
  1492. TwoSeconds) * TwoSeconds;
  1493. //
  1494. // Now because the user just set the last write time we
  1495. // better not set the last write time on close
  1496. //
  1497. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_WRITE );
  1498. }
  1499. //
  1500. // If we modified any of the values, we report this to the notify
  1501. // package.
  1502. //
  1503. // We also take this opportunity to set the current file size and
  1504. // first cluster in the Dirent in order to support a server hack.
  1505. //
  1506. if (NotifyFilter != 0) {
  1507. if (NodeType(Fcb) == FAT_NTC_FCB) {
  1508. Dirent->FileSize = Fcb->Header.FileSize.LowPart;
  1509. Dirent->FirstClusterOfFile = (USHORT)Fcb->FirstClusterOfFile;
  1510. if (FatIsFat32(Fcb->Vcb)) {
  1511. Dirent->FirstClusterOfFileHi =
  1512. (USHORT)(Fcb->FirstClusterOfFile >> 16);
  1513. }
  1514. }
  1515. FatNotifyReportChange( IrpContext,
  1516. Fcb->Vcb,
  1517. Fcb,
  1518. NotifyFilter,
  1519. FILE_ACTION_MODIFIED );
  1520. FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
  1521. }
  1522. try_exit: NOTHING;
  1523. } finally {
  1524. DebugUnwind( FatSetBasicInfo );
  1525. FatUnpinBcb( IrpContext, DirentBcb );
  1526. DebugTrace(-1, Dbg, "FatSetBasicInfo -> %08lx\n", Status);
  1527. }
  1528. return Status;
  1529. }
  1530. //
  1531. // Internal Support Routine
  1532. //
  1533. NTSTATUS
  1534. FatSetDispositionInfo (
  1535. IN PIRP_CONTEXT IrpContext,
  1536. IN PIRP Irp,
  1537. IN PFILE_OBJECT FileObject,
  1538. IN PFCB Fcb
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. This routine performs the set disposition information for fat. It either
  1543. completes the request or enqueues it off to the fsp.
  1544. Arguments:
  1545. Irp - Supplies the irp being processed
  1546. FileObject - Supplies the file object being processed
  1547. Fcb - Supplies the Fcb or Dcb being processed, already known not to
  1548. be the root dcb
  1549. Return Value:
  1550. NTSTATUS - The result of this operation if it completes without
  1551. an exception.
  1552. --*/
  1553. {
  1554. PFILE_DISPOSITION_INFORMATION Buffer;
  1555. PBCB Bcb;
  1556. PDIRENT Dirent;
  1557. DebugTrace(+1, Dbg, "FatSetDispositionInfo...\n", 0);
  1558. Buffer = Irp->AssociatedIrp.SystemBuffer;
  1559. //
  1560. // Check if the user wants to delete the file or not delete
  1561. // the file
  1562. //
  1563. if (Buffer->DeleteFile) {
  1564. //
  1565. // Check if the file is marked read only
  1566. //
  1567. if (FlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY)) {
  1568. DebugTrace(-1, Dbg, "Cannot delete readonly file\n", 0);
  1569. return STATUS_CANNOT_DELETE;
  1570. }
  1571. //
  1572. // Make sure there is no process mapping this file as an image.
  1573. //
  1574. if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
  1575. MmFlushForDelete )) {
  1576. DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);
  1577. return STATUS_CANNOT_DELETE;
  1578. }
  1579. //
  1580. // Check if this is a dcb and if so then only allow
  1581. // the request if the directory is empty.
  1582. //
  1583. if (NodeType(Fcb) == FAT_NTC_ROOT_DCB) {
  1584. DebugTrace(-1, Dbg, "Cannot delete root Directory\n", 0);
  1585. return STATUS_CANNOT_DELETE;
  1586. }
  1587. if (NodeType(Fcb) == FAT_NTC_DCB) {
  1588. DebugTrace(-1, Dbg, "User wants to delete a directory\n", 0);
  1589. //
  1590. // Check if the directory is empty
  1591. //
  1592. if ( !FatIsDirectoryEmpty(IrpContext, Fcb) ) {
  1593. DebugTrace(-1, Dbg, "Directory is not empty\n", 0);
  1594. return STATUS_DIRECTORY_NOT_EMPTY;
  1595. }
  1596. }
  1597. //
  1598. // If this is a floppy, touch the volume so to verify that it
  1599. // is not write protected.
  1600. //
  1601. if ( FlagOn(Fcb->Vcb->Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
  1602. PVCB Vcb;
  1603. PBCB Bcb = NULL;
  1604. UCHAR *Buffer;
  1605. UCHAR TmpChar;
  1606. ULONG BytesToMap;
  1607. IO_STATUS_BLOCK Iosb;
  1608. Vcb = Fcb->Vcb;
  1609. BytesToMap = Vcb->AllocationSupport.FatIndexBitSize == 12 ?
  1610. FatReservedBytes(&Vcb->Bpb) +
  1611. FatBytesPerFat(&Vcb->Bpb):PAGE_SIZE;
  1612. FatReadVolumeFile( IrpContext,
  1613. Vcb,
  1614. 0,
  1615. BytesToMap,
  1616. &Bcb,
  1617. (PVOID *)&Buffer );
  1618. try {
  1619. if (!CcPinMappedData( Vcb->VirtualVolumeFile,
  1620. &FatLargeZero,
  1621. BytesToMap,
  1622. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  1623. &Bcb )) {
  1624. //
  1625. // Could not pin the data without waiting (cache miss).
  1626. //
  1627. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  1628. }
  1629. //
  1630. // Make Mm, myself, and Cc think the byte is dirty, and then
  1631. // force a writethrough.
  1632. //
  1633. Buffer += FatReservedBytes(&Vcb->Bpb);
  1634. TmpChar = Buffer[0];
  1635. Buffer[0] = TmpChar;
  1636. FatAddMcbEntry( Vcb, &Vcb->DirtyFatMcb,
  1637. FatReservedBytes( &Vcb->Bpb ),
  1638. FatReservedBytes( &Vcb->Bpb ),
  1639. Vcb->Bpb.BytesPerSector );
  1640. } finally {
  1641. if (AbnormalTermination() && (Bcb != NULL)) {
  1642. FatUnpinBcb( IrpContext, Bcb );
  1643. }
  1644. }
  1645. CcRepinBcb( Bcb );
  1646. CcSetDirtyPinnedData( Bcb, NULL );
  1647. CcUnpinData( Bcb );
  1648. DbgDoit( ASSERT( IrpContext->PinCount ));
  1649. DbgDoit( IrpContext->PinCount -= 1 );
  1650. CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
  1651. //
  1652. // If this was not successful, raise the status.
  1653. //
  1654. if ( !NT_SUCCESS(Iosb.Status) ) {
  1655. FatNormalizeAndRaiseStatus( IrpContext, Iosb.Status );
  1656. }
  1657. } else {
  1658. //
  1659. // Just set a Bcb dirty here. The above code was only there to
  1660. // detect a write protected floppy, while the below code works
  1661. // for any write protected media and only takes a hit when the
  1662. // volume in clean.
  1663. //
  1664. FatGetDirentFromFcbOrDcb( IrpContext,
  1665. Fcb,
  1666. &Dirent,
  1667. &Bcb );
  1668. //
  1669. // This has to work for the usual reasons (we verified the Fcb within
  1670. // volume synch).
  1671. //
  1672. ASSERT( Bcb != NULL );
  1673. try {
  1674. FatSetDirtyBcb( IrpContext, Bcb, Fcb->Vcb, TRUE );
  1675. } finally {
  1676. FatUnpinBcb( IrpContext, Bcb );
  1677. }
  1678. }
  1679. //
  1680. // At this point either we have a file or an empty directory
  1681. // so we know the delete can proceed.
  1682. //
  1683. SetFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  1684. FileObject->DeletePending = TRUE;
  1685. //
  1686. // If this is a directory then report this delete pending to
  1687. // the dir notify package.
  1688. //
  1689. if (NodeType(Fcb) == FAT_NTC_DCB) {
  1690. FsRtlNotifyFullChangeDirectory( Fcb->Vcb->NotifySync,
  1691. &Fcb->Vcb->DirNotifyList,
  1692. FileObject->FsContext,
  1693. NULL,
  1694. FALSE,
  1695. FALSE,
  1696. 0,
  1697. NULL,
  1698. NULL,
  1699. NULL );
  1700. }
  1701. } else {
  1702. //
  1703. // The user doesn't want to delete the file so clear
  1704. // the delete on close bit
  1705. //
  1706. DebugTrace(0, Dbg, "User want to not delete file\n", 0);
  1707. ClearFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  1708. FileObject->DeletePending = FALSE;
  1709. }
  1710. DebugTrace(-1, Dbg, "FatSetDispositionInfo -> STATUS_SUCCESS\n", 0);
  1711. return STATUS_SUCCESS;
  1712. }
  1713. //
  1714. // Internal Support Routine
  1715. //
  1716. NTSTATUS
  1717. FatSetRenameInfo (
  1718. IN PIRP_CONTEXT IrpContext,
  1719. IN PIRP Irp,
  1720. IN PVCB Vcb,
  1721. IN PFCB Fcb,
  1722. IN PCCB Ccb
  1723. )
  1724. /*++
  1725. Routine Description:
  1726. This routine performs the set name information for fat. It either
  1727. completes the request or enqueues it off to the fsp.
  1728. Arguments:
  1729. Irp - Supplies the irp being processed
  1730. Vcb - Supplies the Vcb being processed
  1731. Fcb - Supplies the Fcb or Dcb being processed, already known not to
  1732. be the root dcb
  1733. Ccb - Supplies the Ccb corresponding to the handle opening the source
  1734. file
  1735. Return Value:
  1736. NTSTATUS - The result of this operation if it completes without
  1737. an exception.
  1738. --*/
  1739. {
  1740. BOOLEAN AllLowerComponent;
  1741. BOOLEAN AllLowerExtension;
  1742. BOOLEAN CaseOnlyRename;
  1743. BOOLEAN ContinueWithRename;
  1744. BOOLEAN CreateLfn;
  1745. BOOLEAN DeleteSourceDirent;
  1746. BOOLEAN DeleteTarget;
  1747. BOOLEAN NewDirentFromPool;
  1748. BOOLEAN RenamedAcrossDirectories;
  1749. BOOLEAN ReplaceIfExists;
  1750. CCB LocalCcb;
  1751. PCCB SourceCcb;
  1752. DIRENT SourceDirent;
  1753. NTSTATUS Status;
  1754. OEM_STRING OldOemName;
  1755. OEM_STRING NewOemName;
  1756. UCHAR OemNameBuffer[24*2];
  1757. PBCB DotDotBcb;
  1758. PBCB NewDirentBcb;
  1759. PBCB OldDirentBcb;
  1760. PBCB SecondPageBcb;
  1761. PBCB TargetDirentBcb;
  1762. PDCB TargetDcb;
  1763. PDCB OldParentDcb;
  1764. PDIRENT DotDotDirent;
  1765. PDIRENT FirstPageDirent;
  1766. PDIRENT NewDirent;
  1767. PDIRENT OldDirent;
  1768. PDIRENT SecondPageDirent;
  1769. PDIRENT ShortDirent;
  1770. PDIRENT TargetDirent;
  1771. PFCB TempFcb;
  1772. PFILE_OBJECT TargetFileObject;
  1773. PFILE_OBJECT FileObject;
  1774. PIO_STACK_LOCATION IrpSp;
  1775. PLIST_ENTRY Links;
  1776. ULONG BytesInFirstPage;
  1777. ULONG DirentsInFirstPage;
  1778. ULONG DirentsRequired;
  1779. ULONG NewOffset;
  1780. ULONG NotifyAction;
  1781. ULONG SecondPageOffset;
  1782. ULONG ShortDirentOffset;
  1783. ULONG TargetDirentOffset;
  1784. ULONG TargetLfnOffset;
  1785. UNICODE_STRING NewName;
  1786. UNICODE_STRING NewUpcasedName;
  1787. UNICODE_STRING OldName;
  1788. UNICODE_STRING OldUpcasedName;
  1789. UNICODE_STRING TargetLfn;
  1790. PWCHAR UnicodeBuffer;
  1791. UNICODE_STRING UniTunneledShortName;
  1792. WCHAR UniTunneledShortNameBuffer[12];
  1793. UNICODE_STRING UniTunneledLongName;
  1794. WCHAR UniTunneledLongNameBuffer[26];
  1795. LARGE_INTEGER TunneledCreationTime;
  1796. ULONG TunneledDataSize;
  1797. BOOLEAN HaveTunneledInformation;
  1798. BOOLEAN UsingTunneledLfn = FALSE;
  1799. BOOLEAN InvalidateFcbOnRaise = FALSE;
  1800. DebugTrace(+1, Dbg, "FatSetRenameInfo...\n", 0);
  1801. //
  1802. // P H A S E 0: Initialize some variables.
  1803. //
  1804. CaseOnlyRename = FALSE;
  1805. ContinueWithRename = FALSE;
  1806. DeleteSourceDirent = FALSE;
  1807. DeleteTarget = FALSE;
  1808. NewDirentFromPool = FALSE;
  1809. RenamedAcrossDirectories = FALSE;
  1810. DotDotBcb = NULL;
  1811. NewDirentBcb = NULL;
  1812. OldDirentBcb = NULL;
  1813. SecondPageBcb = NULL;
  1814. TargetDirentBcb = NULL;
  1815. NewOemName.Length = 0;
  1816. NewOemName.MaximumLength = 24;
  1817. NewOemName.Buffer = &OemNameBuffer[0];
  1818. OldOemName.Length = 0;
  1819. OldOemName.MaximumLength = 24;
  1820. OldOemName.Buffer = &OemNameBuffer[24];
  1821. UnicodeBuffer = FsRtlAllocatePoolWithTag( PagedPool,
  1822. 4 * MAX_LFN_CHARACTERS * sizeof(WCHAR),
  1823. TAG_FILENAME_BUFFER );
  1824. NewUpcasedName.Length = 0;
  1825. NewUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
  1826. NewUpcasedName.Buffer = &UnicodeBuffer[0];
  1827. OldName.Length = 0;
  1828. OldName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
  1829. OldName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS];
  1830. OldUpcasedName.Length = 0;
  1831. OldUpcasedName.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
  1832. OldUpcasedName.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 2];
  1833. TargetLfn.Length = 0;
  1834. TargetLfn.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
  1835. TargetLfn.Buffer = &UnicodeBuffer[MAX_LFN_CHARACTERS * 3];
  1836. UniTunneledShortName.Length = 0;
  1837. UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer);
  1838. UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0];
  1839. UniTunneledLongName.Length = 0;
  1840. UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer);
  1841. UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0];
  1842. //
  1843. // Remember the name in case we have to modify the name
  1844. // value in the ea.
  1845. //
  1846. RtlCopyMemory( OldOemName.Buffer,
  1847. Fcb->ShortName.Name.Oem.Buffer,
  1848. OldOemName.Length );
  1849. //
  1850. // Get the current stack location
  1851. //
  1852. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1853. //
  1854. // Extract information from the Irp to make our life easier
  1855. //
  1856. FileObject = IrpSp->FileObject;
  1857. SourceCcb = FileObject->FsContext2;
  1858. TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
  1859. ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
  1860. RtlZeroMemory( &LocalCcb, sizeof(CCB) );
  1861. //
  1862. // P H A S E 1:
  1863. //
  1864. // Test if rename is legal. Only small side-effects are not undone.
  1865. //
  1866. try {
  1867. //
  1868. // Can't rename the root directory
  1869. //
  1870. if ( NodeType(Fcb) == FAT_NTC_ROOT_DCB ) {
  1871. try_return( Status = STATUS_INVALID_PARAMETER );
  1872. }
  1873. //
  1874. // Check that we were not given a dcb with open handles beneath
  1875. // it. If there are only UncleanCount == 0 Fcbs beneath us, then
  1876. // remove them from the prefix table, and they will just close
  1877. // and go away naturally.
  1878. //
  1879. if (NodeType(Fcb) == FAT_NTC_DCB) {
  1880. PFCB BatchOplockFcb;
  1881. ULONG BatchOplockCount;
  1882. //
  1883. // Loop until there are no batch oplocks in the subtree below
  1884. // this directory.
  1885. //
  1886. while (TRUE) {
  1887. BatchOplockFcb = NULL;
  1888. BatchOplockCount = 0;
  1889. //
  1890. // First look for any UncleanCount != 0 Fcbs, and fail if we
  1891. // find any.
  1892. //
  1893. for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
  1894. TempFcb != Fcb;
  1895. TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
  1896. if ( TempFcb->UncleanCount != 0 ) {
  1897. //
  1898. // If there is a batch oplock on this file then
  1899. // increment our count and remember the Fcb if
  1900. // this is the first.
  1901. //
  1902. if ( (NodeType(TempFcb) == FAT_NTC_FCB) &&
  1903. FsRtlCurrentBatchOplock( &TempFcb->Specific.Fcb.Oplock ) ) {
  1904. BatchOplockCount += 1;
  1905. if ( BatchOplockFcb == NULL ) {
  1906. BatchOplockFcb = TempFcb;
  1907. }
  1908. } else {
  1909. try_return( Status = STATUS_ACCESS_DENIED );
  1910. }
  1911. }
  1912. }
  1913. //
  1914. // If this is not the first pass for rename and the number
  1915. // of batch oplocks has not decreased then give up.
  1916. //
  1917. if ( BatchOplockFcb != NULL ) {
  1918. if ( (Irp->IoStatus.Information != 0) &&
  1919. (BatchOplockCount >= Irp->IoStatus.Information) ) {
  1920. try_return( Status = STATUS_ACCESS_DENIED );
  1921. }
  1922. //
  1923. // Try to break this batch oplock.
  1924. //
  1925. Irp->IoStatus.Information = BatchOplockCount;
  1926. Status = FsRtlCheckOplock( &BatchOplockFcb->Specific.Fcb.Oplock,
  1927. Irp,
  1928. IrpContext,
  1929. FatOplockComplete,
  1930. NULL );
  1931. //
  1932. // If the oplock was already broken then look for more
  1933. // batch oplocks.
  1934. //
  1935. if (Status == STATUS_SUCCESS) {
  1936. continue;
  1937. }
  1938. //
  1939. // Otherwise the oplock package will post or complete the
  1940. // request.
  1941. //
  1942. try_return( Status = STATUS_PENDING );
  1943. }
  1944. break;
  1945. }
  1946. //
  1947. // Now try to get as many of these file object, and thus Fcbs
  1948. // to go away as possible, flushing first, of course.
  1949. //
  1950. FatPurgeReferencedFileObjects( IrpContext, Fcb, TRUE );
  1951. //
  1952. // OK, so there are no UncleanCount != 0, Fcbs. Infact, there
  1953. // shouldn't really be any Fcbs left at all, except obstinate
  1954. // ones from user mapped sections ....oh well, he shouldn't have
  1955. // closed his handle if he wanted the file to stick around. So
  1956. // remove any Fcbs beneath us from the splay table and mark them
  1957. // DELETE_ON_CLOSE so that any future operations will fail.
  1958. //
  1959. for ( TempFcb = FatGetNextFcbBottomUp(IrpContext, NULL, Fcb);
  1960. TempFcb != Fcb;
  1961. TempFcb = FatGetNextFcbBottomUp(IrpContext, TempFcb, Fcb) ) {
  1962. FatRemoveNames( IrpContext, TempFcb );
  1963. SetFlag( TempFcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  1964. }
  1965. }
  1966. //
  1967. // Check if this is a simple rename or a fully-qualified rename
  1968. // In both cases we need to figure out what the TargetDcb, and
  1969. // NewName are.
  1970. //
  1971. if (TargetFileObject == NULL) {
  1972. //
  1973. // In the case of a simple rename the target dcb is the
  1974. // same as the source file's parent dcb, and the new file name
  1975. // is taken from the system buffer
  1976. //
  1977. PFILE_RENAME_INFORMATION Buffer;
  1978. Buffer = Irp->AssociatedIrp.SystemBuffer;
  1979. TargetDcb = Fcb->ParentDcb;
  1980. NewName.Length = (USHORT) Buffer->FileNameLength;
  1981. NewName.Buffer = (PWSTR) &Buffer->FileName;
  1982. //
  1983. // Make sure the name is of legal length.
  1984. //
  1985. if (NewName.Length >= 255*sizeof(WCHAR)) {
  1986. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  1987. }
  1988. } else {
  1989. //
  1990. // For a fully-qualified rename the target dcb is taken from
  1991. // the target file object, which must be on the same vcb as
  1992. // the source.
  1993. //
  1994. PVCB TargetVcb;
  1995. PCCB TargetCcb;
  1996. if ((FatDecodeFileObject( TargetFileObject,
  1997. &TargetVcb,
  1998. &TargetDcb,
  1999. &TargetCcb ) != UserDirectoryOpen) ||
  2000. (TargetVcb != Vcb)) {
  2001. try_return( Status = STATUS_INVALID_PARAMETER );
  2002. }
  2003. //
  2004. // This name is by definition legal.
  2005. //
  2006. NewName = *((PUNICODE_STRING)&TargetFileObject->FileName);
  2007. }
  2008. //
  2009. // We will need an upcased version of the unicode name and the
  2010. // old name as well.
  2011. //
  2012. Status = RtlUpcaseUnicodeString( &NewUpcasedName, &NewName, FALSE );
  2013. if (!NT_SUCCESS(Status)) {
  2014. try_return( Status );
  2015. }
  2016. FatGetUnicodeNameFromFcb( IrpContext, Fcb, &OldName );
  2017. Status = RtlUpcaseUnicodeString( &OldUpcasedName, &OldName, FALSE );
  2018. if (!NT_SUCCESS(Status)) {
  2019. try_return(Status);
  2020. }
  2021. //
  2022. // Check if the current name and new name are equal, and the
  2023. // DCBs are equal. If they are then our work is already done.
  2024. //
  2025. if (TargetDcb == Fcb->ParentDcb) {
  2026. //
  2027. // OK, now if we found something then check if it was an exact
  2028. // match or just a case match. If it was an exact match, then
  2029. // we can bail here.
  2030. //
  2031. if (FsRtlAreNamesEqual( &NewName,
  2032. &OldName,
  2033. FALSE,
  2034. NULL )) {
  2035. try_return( Status = STATUS_SUCCESS );
  2036. }
  2037. //
  2038. // Check now for a case only rename.
  2039. //
  2040. if (FsRtlAreNamesEqual( &NewUpcasedName,
  2041. &OldUpcasedName,
  2042. FALSE,
  2043. NULL )) {
  2044. CaseOnlyRename = TRUE;
  2045. }
  2046. } else {
  2047. RenamedAcrossDirectories = TRUE;
  2048. }
  2049. //
  2050. // Upcase the name and convert it to the Oem code page.
  2051. //
  2052. // If the new UNICODE name is already more than 12 characters,
  2053. // then we know the Oem name will not be valid
  2054. //
  2055. if (NewName.Length <= 12*sizeof(WCHAR)) {
  2056. FatUnicodeToUpcaseOem( IrpContext, &NewOemName, &NewName );
  2057. //
  2058. // If the name is not valid 8.3, zero the length.
  2059. //
  2060. if (FatSpaceInName( IrpContext, &NewName ) ||
  2061. !FatIsNameShortOemValid( IrpContext, NewOemName, FALSE, FALSE, FALSE)) {
  2062. NewOemName.Length = 0;
  2063. }
  2064. } else {
  2065. NewOemName.Length = 0;
  2066. }
  2067. //
  2068. // Look in the tunnel cache for names and timestamps to restore
  2069. //
  2070. TunneledDataSize = sizeof(LARGE_INTEGER);
  2071. HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel,
  2072. FatDirectoryKey(TargetDcb),
  2073. &NewName,
  2074. &UniTunneledShortName,
  2075. &UniTunneledLongName,
  2076. &TunneledDataSize,
  2077. &TunneledCreationTime );
  2078. ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER));
  2079. //
  2080. // Now we need to determine how many dirents this new name will
  2081. // require.
  2082. //
  2083. if ((NewOemName.Length == 0) ||
  2084. (FatEvaluateNameCase( IrpContext,
  2085. &NewName,
  2086. &AllLowerComponent,
  2087. &AllLowerExtension,
  2088. &CreateLfn ),
  2089. CreateLfn)) {
  2090. DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&NewName) + 1;
  2091. } else {
  2092. //
  2093. // The user-given name is a short name, but we might still have
  2094. // a tunneled long name we want to use. See if we can.
  2095. //
  2096. if (UniTunneledLongName.Length &&
  2097. !FatLfnDirentExists(IrpContext, TargetDcb, &UniTunneledLongName, &TargetLfn)) {
  2098. UsingTunneledLfn = CreateLfn = TRUE;
  2099. DirentsRequired = FAT_LFN_DIRENTS_NEEDED(&UniTunneledLongName) + 1;
  2100. } else {
  2101. //
  2102. // This really is a simple dirent. Note that the two AllLower BOOLEANs
  2103. // are correctly set now.
  2104. //
  2105. DirentsRequired = 1;
  2106. }
  2107. }
  2108. //
  2109. // Do some extra checks here if we are not in Chicago mode.
  2110. //
  2111. if (!FatData.ChicagoMode) {
  2112. //
  2113. // If the name was not 8.3 valid, fail the rename.
  2114. //
  2115. if (NewOemName.Length == 0) {
  2116. try_return( Status = STATUS_OBJECT_NAME_INVALID );
  2117. }
  2118. //
  2119. // Don't use the magic bits.
  2120. //
  2121. AllLowerComponent = FALSE;
  2122. AllLowerExtension = FALSE;
  2123. CreateLfn = FALSE;
  2124. UsingTunneledLfn = FALSE;
  2125. }
  2126. if (!CaseOnlyRename) {
  2127. //
  2128. // Check if the new name already exists, wait is known to be
  2129. // true.
  2130. //
  2131. if (NewOemName.Length != 0) {
  2132. FatStringTo8dot3( IrpContext,
  2133. NewOemName,
  2134. &LocalCcb.OemQueryTemplate.Constant );
  2135. } else {
  2136. SetFlag( LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE );
  2137. }
  2138. LocalCcb.UnicodeQueryTemplate = NewUpcasedName;
  2139. LocalCcb.ContainsWildCards = FALSE;
  2140. FatLocateDirent( IrpContext,
  2141. TargetDcb,
  2142. &LocalCcb,
  2143. 0,
  2144. &TargetDirent,
  2145. &TargetDirentBcb,
  2146. &TargetDirentOffset,
  2147. NULL,
  2148. &TargetLfn);
  2149. if (TargetDirent != NULL) {
  2150. //
  2151. // The name already exists, check if the user wants
  2152. // to overwrite the name, and has access to do the overwrite
  2153. // We cannot overwrite a directory.
  2154. //
  2155. if ((!ReplaceIfExists) ||
  2156. (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY)) ||
  2157. (FlagOn(TargetDirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY))) {
  2158. try_return( Status = STATUS_OBJECT_NAME_COLLISION );
  2159. }
  2160. //
  2161. // Check that the file has no open user handles, if it does
  2162. // then we will deny access. We do the check by searching
  2163. // down the list of fcbs opened under our parent Dcb, and making
  2164. // sure none of the maching Fcbs have a non-zero unclean count or
  2165. // outstanding image sections.
  2166. //
  2167. for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
  2168. Links != &TargetDcb->Specific.Dcb.ParentDcbQueue; ) {
  2169. TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
  2170. //
  2171. // Advance now. The image section flush may cause the final
  2172. // close, which will recursively happen underneath of us here.
  2173. // It would be unfortunate if we looked through free memory.
  2174. //
  2175. Links = Links->Flink;
  2176. if ((TempFcb->DirentOffsetWithinDirectory == TargetDirentOffset) &&
  2177. ((TempFcb->UncleanCount != 0) ||
  2178. !MmFlushImageSection( &TempFcb->NonPaged->SectionObjectPointers,
  2179. MmFlushForDelete))) {
  2180. //
  2181. // If there are batch oplocks on this file then break the
  2182. // oplocks before failing the rename.
  2183. //
  2184. Status = STATUS_ACCESS_DENIED;
  2185. if ((NodeType(TempFcb) == FAT_NTC_FCB) &&
  2186. FsRtlCurrentBatchOplock( &TempFcb->Specific.Fcb.Oplock )) {
  2187. //
  2188. // Do all of our cleanup now since the IrpContext
  2189. // could go away when this request is posted.
  2190. //
  2191. FatUnpinBcb( IrpContext, TargetDirentBcb );
  2192. Status = FsRtlCheckOplock( &TempFcb->Specific.Fcb.Oplock,
  2193. Irp,
  2194. IrpContext,
  2195. FatOplockComplete,
  2196. NULL );
  2197. if (Status != STATUS_PENDING) {
  2198. Status = STATUS_ACCESS_DENIED;
  2199. }
  2200. }
  2201. try_return( NOTHING );
  2202. }
  2203. }
  2204. //
  2205. // OK, this target is toast. Remember the Lfn offset.
  2206. //
  2207. TargetLfnOffset = TargetDirentOffset -
  2208. FAT_LFN_DIRENTS_NEEDED(&TargetLfn) *
  2209. sizeof(DIRENT);
  2210. DeleteTarget = TRUE;
  2211. }
  2212. }
  2213. //
  2214. // If we will need more dirents than we have, allocate them now.
  2215. //
  2216. if ((TargetDcb != Fcb->ParentDcb) ||
  2217. (DirentsRequired !=
  2218. (Fcb->DirentOffsetWithinDirectory -
  2219. Fcb->LfnOffsetWithinDirectory) / sizeof(DIRENT) + 1)) {
  2220. //
  2221. // Get some new allocation
  2222. //
  2223. NewOffset = FatCreateNewDirent( IrpContext,
  2224. TargetDcb,
  2225. DirentsRequired );
  2226. DeleteSourceDirent = TRUE;
  2227. } else {
  2228. NewOffset = Fcb->LfnOffsetWithinDirectory;
  2229. }
  2230. ContinueWithRename = TRUE;
  2231. try_exit: NOTHING;
  2232. } finally {
  2233. if (!ContinueWithRename) {
  2234. //
  2235. // Undo everything from above.
  2236. //
  2237. ExFreePool( UnicodeBuffer );
  2238. FatUnpinBcb( IrpContext, TargetDirentBcb );
  2239. }
  2240. }
  2241. //
  2242. // Now, if we are already done, return here.
  2243. //
  2244. if (!ContinueWithRename) {
  2245. return Status;
  2246. }
  2247. //
  2248. // P H A S E 2: Actually perform the rename.
  2249. //
  2250. try {
  2251. //
  2252. // Report the fact that we are going to remove this entry.
  2253. // If we renamed within the same directory and the new name for the
  2254. // file did not previously exist, we report this as a rename old
  2255. // name. Otherwise this is a removed file.
  2256. //
  2257. if (!RenamedAcrossDirectories && !DeleteTarget) {
  2258. NotifyAction = FILE_ACTION_RENAMED_OLD_NAME;
  2259. } else {
  2260. NotifyAction = FILE_ACTION_REMOVED;
  2261. }
  2262. FatNotifyReportChange( IrpContext,
  2263. Vcb,
  2264. Fcb,
  2265. ((NodeType( Fcb ) == FAT_NTC_FCB)
  2266. ? FILE_NOTIFY_CHANGE_FILE_NAME
  2267. : FILE_NOTIFY_CHANGE_DIR_NAME ),
  2268. NotifyAction );
  2269. //
  2270. // Capture a copy of the source dirent.
  2271. //
  2272. FatGetDirentFromFcbOrDcb( IrpContext, Fcb, &OldDirent, &OldDirentBcb );
  2273. SourceDirent = *OldDirent;
  2274. try {
  2275. //
  2276. // Tunnel the source Fcb - the names are disappearing regardless of
  2277. // whether the dirent allocation physically changed
  2278. //
  2279. FatTunnelFcbOrDcb( Fcb, SourceCcb );
  2280. //
  2281. // From here until very nearly the end of the operation, if we raise there
  2282. // is no reasonable way to suppose we'd be able to undo the damage. Not
  2283. // being a transactional filesystem, FAT is at the mercy of a lot of things
  2284. // (as the astute reader has no doubt realized by now).
  2285. //
  2286. InvalidateFcbOnRaise = TRUE;
  2287. //
  2288. // Delete our current dirent(s) if we got a new one.
  2289. //
  2290. if (DeleteSourceDirent) {
  2291. FatDeleteDirent( IrpContext, Fcb, NULL, FALSE );
  2292. }
  2293. //
  2294. // Delete a target conflict if we were meant to.
  2295. //
  2296. if (DeleteTarget) {
  2297. FatDeleteFile( IrpContext,
  2298. TargetDcb,
  2299. TargetLfnOffset,
  2300. TargetDirentOffset,
  2301. TargetDirent,
  2302. &TargetLfn );
  2303. }
  2304. //
  2305. // We need to evaluate any short names required. If there were any
  2306. // conflicts in existing short names, they would have been deleted above.
  2307. //
  2308. // It isn't neccesary to worry about the UsingTunneledLfn case. Since we
  2309. // actually already know whether CreateLfn will be set either NewName is
  2310. // an Lfn and !UsingTunneledLfn is implied or NewName is a short name and
  2311. // we can handle that externally.
  2312. //
  2313. FatSelectNames( IrpContext,
  2314. TargetDcb,
  2315. &NewOemName,
  2316. &NewName,
  2317. &NewOemName,
  2318. (HaveTunneledInformation ? &UniTunneledShortName : NULL),
  2319. &AllLowerComponent,
  2320. &AllLowerExtension,
  2321. &CreateLfn );
  2322. if (!CreateLfn && UsingTunneledLfn) {
  2323. CreateLfn = TRUE;
  2324. NewName = UniTunneledLongName;
  2325. //
  2326. // Short names are always upcase if an LFN exists
  2327. //
  2328. AllLowerComponent = FALSE;
  2329. AllLowerExtension = FALSE;
  2330. }
  2331. //
  2332. // OK, now setup the new dirent(s) for the new name.
  2333. //
  2334. FatPrepareWriteDirectoryFile( IrpContext,
  2335. TargetDcb,
  2336. NewOffset,
  2337. sizeof(DIRENT),
  2338. &NewDirentBcb,
  2339. &NewDirent,
  2340. FALSE,
  2341. TRUE,
  2342. &Status );
  2343. ASSERT( NT_SUCCESS( Status ) );
  2344. //
  2345. // Deal with the special case of an LFN + Dirent structure crossing
  2346. // a page boundry.
  2347. //
  2348. if ((NewOffset / PAGE_SIZE) !=
  2349. ((NewOffset + (DirentsRequired - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
  2350. SecondPageOffset = (NewOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
  2351. BytesInFirstPage = SecondPageOffset - NewOffset;
  2352. DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
  2353. FatPrepareWriteDirectoryFile( IrpContext,
  2354. TargetDcb,
  2355. SecondPageOffset,
  2356. sizeof(DIRENT),
  2357. &SecondPageBcb,
  2358. &SecondPageDirent,
  2359. FALSE,
  2360. TRUE,
  2361. &Status );
  2362. ASSERT( NT_SUCCESS( Status ) );
  2363. FirstPageDirent = NewDirent;
  2364. NewDirent = FsRtlAllocatePoolWithTag( PagedPool,
  2365. DirentsRequired * sizeof(DIRENT),
  2366. TAG_DIRENT );
  2367. NewDirentFromPool = TRUE;
  2368. }
  2369. //
  2370. // Bump up Dirent and DirentOffset
  2371. //
  2372. ShortDirent = NewDirent + DirentsRequired - 1;
  2373. ShortDirentOffset = NewOffset + (DirentsRequired - 1) * sizeof(DIRENT);
  2374. //
  2375. // Fill in the fields of the dirent.
  2376. //
  2377. *ShortDirent = SourceDirent;
  2378. FatConstructDirent( IrpContext,
  2379. ShortDirent,
  2380. &NewOemName,
  2381. AllLowerComponent,
  2382. AllLowerExtension,
  2383. CreateLfn ? &NewName : NULL,
  2384. SourceDirent.Attributes,
  2385. FALSE,
  2386. (HaveTunneledInformation ? &TunneledCreationTime : NULL) );
  2387. if (HaveTunneledInformation) {
  2388. //
  2389. // Need to go in and fix the timestamps in the FCB. Note that we can't use
  2390. // the TunneledCreationTime since the conversions may have failed.
  2391. //
  2392. Fcb->CreationTime = FatFatTimeToNtTime(IrpContext, ShortDirent->CreationTime, ShortDirent->CreationMSec);
  2393. Fcb->LastWriteTime = FatFatTimeToNtTime(IrpContext, ShortDirent->LastWriteTime, 0);
  2394. Fcb->LastAccessTime = FatFatDateToNtTime(IrpContext, ShortDirent->LastAccessDate);
  2395. }
  2396. //
  2397. // If the dirent crossed pages, split the contents of the
  2398. // temporary pool between the two pages.
  2399. //
  2400. if (NewDirentFromPool) {
  2401. RtlCopyMemory( FirstPageDirent, NewDirent, BytesInFirstPage );
  2402. RtlCopyMemory( SecondPageDirent,
  2403. NewDirent + DirentsInFirstPage,
  2404. DirentsRequired*sizeof(DIRENT) - BytesInFirstPage );
  2405. ShortDirent = SecondPageDirent +
  2406. (DirentsRequired - DirentsInFirstPage) - 1;
  2407. }
  2408. } finally {
  2409. //
  2410. // Remove the entry from the splay table, and then remove the
  2411. // full file name and exact case lfn. It is important that we
  2412. // always remove the name from the prefix table regardless of
  2413. // other errors.
  2414. //
  2415. FatRemoveNames( IrpContext, Fcb );
  2416. if (Fcb->FullFileName.Buffer != NULL) {
  2417. ExFreePool( Fcb->FullFileName.Buffer );
  2418. Fcb->FullFileName.Buffer = NULL;
  2419. }
  2420. if (Fcb->ExactCaseLongName.Buffer) {
  2421. ExFreePool( Fcb->ExactCaseLongName.Buffer );
  2422. Fcb->ExactCaseLongName.Buffer = NULL;
  2423. }
  2424. }
  2425. //
  2426. // Now we need to update the location of the file's directory
  2427. // offset and move the fcb from its current parent dcb to
  2428. // the target dcb.
  2429. //
  2430. Fcb->LfnOffsetWithinDirectory = NewOffset;
  2431. Fcb->DirentOffsetWithinDirectory = ShortDirentOffset;
  2432. RemoveEntryList( &Fcb->ParentDcbLinks );
  2433. //
  2434. // There is a deep reason we put files on the tail, others on the head,
  2435. // which is to allow us to easily enumerate all child directories before
  2436. // child files. This is important to let us maintain whole-volume lockorder
  2437. // via BottomUp enumeration.
  2438. //
  2439. if (NodeType(Fcb) == FAT_NTC_FCB) {
  2440. InsertTailList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
  2441. &Fcb->ParentDcbLinks );
  2442. } else {
  2443. InsertHeadList( &TargetDcb->Specific.Dcb.ParentDcbQueue,
  2444. &Fcb->ParentDcbLinks );
  2445. }
  2446. OldParentDcb = Fcb->ParentDcb;
  2447. Fcb->ParentDcb = TargetDcb;
  2448. //
  2449. // If we renamed across directories, some cleanup is now in order.
  2450. //
  2451. if (RenamedAcrossDirectories) {
  2452. //
  2453. // See if we need to uninitialize the cachemap for the source directory.
  2454. // Do this now in case we get unlucky and raise trying to finalize the
  2455. // operation.
  2456. //
  2457. if (IsListEmpty(&OldParentDcb->Specific.Dcb.ParentDcbQueue) &&
  2458. (OldParentDcb->OpenCount == 0) &&
  2459. (OldParentDcb->Specific.Dcb.DirectoryFile != NULL)) {
  2460. PFILE_OBJECT DirectoryFileObject;
  2461. ASSERT( NodeType(OldParentDcb) == FAT_NTC_DCB );
  2462. DirectoryFileObject = OldParentDcb->Specific.Dcb.DirectoryFile;
  2463. DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0);
  2464. CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
  2465. OldParentDcb->Specific.Dcb.DirectoryFile = NULL;
  2466. ObDereferenceObject( DirectoryFileObject );
  2467. }
  2468. //
  2469. // If we move a directory across directories, we have to change
  2470. // the cluster number in its .. entry
  2471. //
  2472. if (NodeType(Fcb) == FAT_NTC_DCB) {
  2473. FatPrepareWriteDirectoryFile( IrpContext,
  2474. Fcb,
  2475. sizeof(DIRENT),
  2476. sizeof(DIRENT),
  2477. &DotDotBcb,
  2478. &DotDotDirent,
  2479. FALSE,
  2480. TRUE,
  2481. &Status );
  2482. ASSERT( NT_SUCCESS( Status ) );
  2483. DotDotDirent->FirstClusterOfFile = (USHORT)
  2484. ( NodeType(TargetDcb) == FAT_NTC_ROOT_DCB ?
  2485. 0 : TargetDcb->FirstClusterOfFile);
  2486. if (FatIsFat32( Vcb )) {
  2487. DotDotDirent->FirstClusterOfFileHi = (USHORT)
  2488. ( NodeType( TargetDcb ) == FAT_NTC_ROOT_DCB ?
  2489. 0 : (TargetDcb->FirstClusterOfFile >> 16));
  2490. }
  2491. }
  2492. }
  2493. //
  2494. // Now we need to setup the splay table and the name within
  2495. // the fcb. Free the old short name at this point.
  2496. //
  2497. ExFreePool( Fcb->ShortName.Name.Oem.Buffer );
  2498. Fcb->ShortName.Name.Oem.Buffer = NULL;
  2499. FatConstructNamesInFcb( IrpContext,
  2500. Fcb,
  2501. ShortDirent,
  2502. CreateLfn ? &NewName : NULL );
  2503. FatSetFullNameInFcb( IrpContext, Fcb, &NewName );
  2504. //
  2505. // The rest of the actions taken are not related to correctness of
  2506. // the in-memory structures, so we shouldn't toast the Fcb if we
  2507. // raise from here to the end.
  2508. //
  2509. InvalidateFcbOnRaise = FALSE;
  2510. //
  2511. // If a file, set the file as modified so that the archive bit
  2512. // is set. We prevent this from adjusting the write time by
  2513. // indicating the user flag in the ccb.
  2514. //
  2515. if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) {
  2516. SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
  2517. SetFlag( Ccb->Flags, CCB_FLAG_USER_SET_LAST_WRITE );
  2518. }
  2519. //
  2520. // We have three cases to report.
  2521. //
  2522. // 1. If we overwrote an existing file, we report this as
  2523. // a modified file.
  2524. //
  2525. // 2. If we renamed to a new directory, then we added a file.
  2526. //
  2527. // 3. If we renamed in the same directory, then we report the
  2528. // the renamednewname.
  2529. //
  2530. if (DeleteTarget) {
  2531. FatNotifyReportChange( IrpContext,
  2532. Vcb,
  2533. Fcb,
  2534. FILE_NOTIFY_CHANGE_ATTRIBUTES
  2535. | FILE_NOTIFY_CHANGE_SIZE
  2536. | FILE_NOTIFY_CHANGE_LAST_WRITE
  2537. | FILE_NOTIFY_CHANGE_LAST_ACCESS
  2538. | FILE_NOTIFY_CHANGE_CREATION
  2539. | FILE_NOTIFY_CHANGE_EA,
  2540. FILE_ACTION_MODIFIED );
  2541. } else if (RenamedAcrossDirectories) {
  2542. FatNotifyReportChange( IrpContext,
  2543. Vcb,
  2544. Fcb,
  2545. ((NodeType( Fcb ) == FAT_NTC_FCB)
  2546. ? FILE_NOTIFY_CHANGE_FILE_NAME
  2547. : FILE_NOTIFY_CHANGE_DIR_NAME ),
  2548. FILE_ACTION_ADDED );
  2549. } else {
  2550. FatNotifyReportChange( IrpContext,
  2551. Vcb,
  2552. Fcb,
  2553. ((NodeType( Fcb ) == FAT_NTC_FCB)
  2554. ? FILE_NOTIFY_CHANGE_FILE_NAME
  2555. : FILE_NOTIFY_CHANGE_DIR_NAME ),
  2556. FILE_ACTION_RENAMED_NEW_NAME );
  2557. }
  2558. //
  2559. // We need to update the file name in the dirent. This value
  2560. // is never used elsewhere, so we don't concern ourselves
  2561. // with any error we may encounter. We let chkdsk fix the
  2562. // disk at some later time.
  2563. //
  2564. if (!FatIsFat32(Vcb) &&
  2565. ShortDirent->ExtendedAttributes != 0) {
  2566. FatRenameEAs( IrpContext,
  2567. Fcb,
  2568. ShortDirent->ExtendedAttributes,
  2569. &OldOemName );
  2570. }
  2571. //
  2572. // Set our final status
  2573. //
  2574. Status = STATUS_SUCCESS;
  2575. } finally {
  2576. DebugUnwind( FatSetRenameInfo );
  2577. ExFreePool( UnicodeBuffer );
  2578. if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) {
  2579. //
  2580. // Free pool if the buffer was grown on tunneling lookup
  2581. //
  2582. ExFreePool(UniTunneledLongName.Buffer);
  2583. }
  2584. FatUnpinBcb( IrpContext, OldDirentBcb );
  2585. FatUnpinBcb( IrpContext, TargetDirentBcb );
  2586. FatUnpinBcb( IrpContext, NewDirentBcb );
  2587. FatUnpinBcb( IrpContext, SecondPageBcb );
  2588. FatUnpinBcb( IrpContext, DotDotBcb );
  2589. //
  2590. // If this was an abnormal termination, then we are in trouble.
  2591. // Should the operation have been in a sensitive state there is
  2592. // nothing we can do but invalidate the Fcb.
  2593. //
  2594. if (AbnormalTermination() && InvalidateFcbOnRaise) {
  2595. Fcb->FcbCondition = FcbBad;
  2596. }
  2597. DebugTrace(-1, Dbg, "FatSetRenameInfo -> %08lx\n", Status);
  2598. }
  2599. return Status;
  2600. }
  2601. //
  2602. // Internal Support Routine
  2603. //
  2604. NTSTATUS
  2605. FatSetPositionInfo (
  2606. IN PIRP_CONTEXT IrpContext,
  2607. IN PIRP Irp,
  2608. IN PFILE_OBJECT FileObject
  2609. )
  2610. /*++
  2611. Routine Description:
  2612. This routine performs the set position information for fat. It either
  2613. completes the request or enqueues it off to the fsp.
  2614. Arguments:
  2615. Irp - Supplies the irp being processed
  2616. FileObject - Supplies the file object being processed
  2617. Return Value:
  2618. NTSTATUS - The result of this operation if it completes without
  2619. an exception.
  2620. --*/
  2621. {
  2622. PFILE_POSITION_INFORMATION Buffer;
  2623. DebugTrace(+1, Dbg, "FatSetPositionInfo...\n", 0);
  2624. Buffer = Irp->AssociatedIrp.SystemBuffer;
  2625. //
  2626. // Check if the file does not use intermediate buffering. If it
  2627. // does not use intermediate buffering then the new position we're
  2628. // supplied must be aligned properly for the device
  2629. //
  2630. if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
  2631. PDEVICE_OBJECT DeviceObject;
  2632. DeviceObject = IoGetCurrentIrpStackLocation( Irp )->DeviceObject;
  2633. if ((Buffer->CurrentByteOffset.LowPart & DeviceObject->AlignmentRequirement) != 0) {
  2634. DebugTrace(0, Dbg, "Cannot set position due to aligment conflict\n", 0);
  2635. DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_INVALID_PARAMETER);
  2636. return STATUS_INVALID_PARAMETER;
  2637. }
  2638. }
  2639. //
  2640. // The input parameter is fine so set the current byte offset and
  2641. // complete the request
  2642. //
  2643. DebugTrace(0, Dbg, "Set the new position to %08lx\n", Buffer->CurrentByteOffset);
  2644. FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
  2645. DebugTrace(-1, Dbg, "FatSetPositionInfo -> %08lx\n", STATUS_SUCCESS);
  2646. UNREFERENCED_PARAMETER( IrpContext );
  2647. return STATUS_SUCCESS;
  2648. }
  2649. //
  2650. // Internal Support Routine
  2651. //
  2652. NTSTATUS
  2653. FatSetAllocationInfo (
  2654. IN PIRP_CONTEXT IrpContext,
  2655. IN PIRP Irp,
  2656. IN PFCB Fcb,
  2657. IN PFILE_OBJECT FileObject
  2658. )
  2659. /*++
  2660. Routine Description:
  2661. This routine performs the set Allocation information for fat. It either
  2662. completes the request or enqueues it off to the fsp.
  2663. Arguments:
  2664. Irp - Supplies the irp being processed
  2665. Fcb - Supplies the Fcb or Dcb being processed, already known not to
  2666. be the root dcb
  2667. FileObject - Supplies the FileObject being processed, already known not to
  2668. be the root dcb
  2669. Return Value:
  2670. NTSTATUS - The result of this operation if it completes without
  2671. an exception.
  2672. --*/
  2673. {
  2674. NTSTATUS Status = STATUS_SUCCESS;
  2675. PFILE_ALLOCATION_INFORMATION Buffer;
  2676. ULONG NewAllocationSize;
  2677. BOOLEAN FileSizeTruncated = FALSE;
  2678. BOOLEAN CacheMapInitialized = FALSE;
  2679. BOOLEAN ResourceAcquired = FALSE;
  2680. ULONG OriginalFileSize;
  2681. ULONG OriginalValidDataLength;
  2682. ULONG OriginalValidDataToDisk;
  2683. Buffer = Irp->AssociatedIrp.SystemBuffer;
  2684. NewAllocationSize = Buffer->AllocationSize.LowPart;
  2685. DebugTrace(+1, Dbg, "FatSetAllocationInfo.. to %08lx\n", NewAllocationSize);
  2686. //
  2687. // Allocation is only allowed on a file and not a directory
  2688. //
  2689. if (NodeType(Fcb) == FAT_NTC_DCB) {
  2690. DebugTrace(-1, Dbg, "Cannot change allocation of a directory\n", 0);
  2691. return STATUS_INVALID_DEVICE_REQUEST;
  2692. }
  2693. //
  2694. // Check that the new file allocation is legal
  2695. //
  2696. if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->AllocationSize, 0 )) {
  2697. DebugTrace(-1, Dbg, "Illegal allocation size\n", 0);
  2698. return STATUS_DISK_FULL;
  2699. }
  2700. //
  2701. // If we haven't yet looked up the correct AllocationSize, do so.
  2702. //
  2703. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  2704. FatLookupFileAllocationSize( IrpContext, Fcb );
  2705. }
  2706. //
  2707. // This is kinda gross, but if the file is not cached, but there is
  2708. // a data section, we have to cache the file to avoid a bunch of
  2709. // extra work.
  2710. //
  2711. if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
  2712. (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
  2713. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  2714. ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) );
  2715. //
  2716. // Now initialize the cache map.
  2717. //
  2718. CcInitializeCacheMap( FileObject,
  2719. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
  2720. FALSE,
  2721. &FatData.CacheManagerCallbacks,
  2722. Fcb );
  2723. CacheMapInitialized = TRUE;
  2724. }
  2725. //
  2726. // Now mark the fact that the file needs to be truncated on close
  2727. //
  2728. Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
  2729. //
  2730. // Now mark that the time on the dirent needs to be updated on close.
  2731. //
  2732. SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
  2733. try {
  2734. //
  2735. // Increase or decrease the allocation size.
  2736. //
  2737. if (NewAllocationSize > Fcb->Header.AllocationSize.LowPart) {
  2738. FatAddFileAllocation( IrpContext, Fcb, FileObject, NewAllocationSize);
  2739. } else {
  2740. //
  2741. // Check here if we will be decreasing file size and synchonize with
  2742. // paging IO.
  2743. //
  2744. if ( Fcb->Header.FileSize.LowPart > NewAllocationSize ) {
  2745. //
  2746. // Before we actually truncate, check to see if the purge
  2747. // is going to fail.
  2748. //
  2749. if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
  2750. &Buffer->AllocationSize )) {
  2751. try_return( Status = STATUS_USER_MAPPED_FILE );
  2752. }
  2753. FileSizeTruncated = TRUE;
  2754. OriginalFileSize = Fcb->Header.FileSize.LowPart;
  2755. OriginalValidDataLength = Fcb->Header.ValidDataLength.LowPart;
  2756. OriginalValidDataToDisk = Fcb->ValidDataToDisk;
  2757. (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
  2758. ResourceAcquired = TRUE;
  2759. Fcb->Header.FileSize.LowPart = NewAllocationSize;
  2760. //
  2761. // If we reduced the file size to less than the ValidDataLength,
  2762. // adjust the VDL. Likewise ValidDataToDisk.
  2763. //
  2764. if (Fcb->Header.ValidDataLength.LowPart > Fcb->Header.FileSize.LowPart) {
  2765. Fcb->Header.ValidDataLength.LowPart = Fcb->Header.FileSize.LowPart;
  2766. }
  2767. if (Fcb->ValidDataToDisk > Fcb->Header.FileSize.LowPart) {
  2768. Fcb->ValidDataToDisk = Fcb->Header.FileSize.LowPart;
  2769. }
  2770. }
  2771. //
  2772. // Now that File Size is down, actually do the truncate.
  2773. //
  2774. FatTruncateFileAllocation( IrpContext, Fcb, NewAllocationSize);
  2775. //
  2776. // Now check if we needed to decrease the file size accordingly.
  2777. //
  2778. if ( FileSizeTruncated ) {
  2779. //
  2780. // Tell the cache manager we reduced the file size.
  2781. // The call is unconditional, because MM always wants to know.
  2782. //
  2783. #if DBG
  2784. try {
  2785. #endif
  2786. CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  2787. #if DBG
  2788. } except(FatBugCheckExceptionFilter( GetExceptionInformation() )) {
  2789. NOTHING;
  2790. }
  2791. #endif
  2792. ASSERT( FileObject->DeleteAccess || FileObject->WriteAccess );
  2793. //
  2794. // There is no going back from this. If we run into problems updating
  2795. // the dirent we will have to live with the consequences. Not sending
  2796. // the notifies is likewise pretty benign compared to failing the entire
  2797. // operation and trying to back out everything, which could fail for the
  2798. // same reasons.
  2799. //
  2800. // If you want a transacted filesystem, use NTFS ...
  2801. //
  2802. FileSizeTruncated = FALSE;
  2803. FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
  2804. //
  2805. // Report that we just reduced the file size.
  2806. //
  2807. FatNotifyReportChange( IrpContext,
  2808. Fcb->Vcb,
  2809. Fcb,
  2810. FILE_NOTIFY_CHANGE_SIZE,
  2811. FILE_ACTION_MODIFIED );
  2812. }
  2813. }
  2814. try_exit: NOTHING;
  2815. } finally {
  2816. if ( AbnormalTermination() && FileSizeTruncated ) {
  2817. Fcb->Header.FileSize.LowPart = OriginalFileSize;
  2818. Fcb->Header.ValidDataLength.LowPart = OriginalValidDataLength;
  2819. Fcb->ValidDataToDisk = OriginalValidDataToDisk;
  2820. //
  2821. // Make sure Cc knows the right filesize.
  2822. //
  2823. if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
  2824. *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
  2825. }
  2826. ASSERT( Fcb->Header.FileSize.LowPart <= Fcb->Header.AllocationSize.LowPart );
  2827. }
  2828. if (CacheMapInitialized) {
  2829. CcUninitializeCacheMap( FileObject, NULL, NULL );
  2830. }
  2831. if (ResourceAcquired) {
  2832. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  2833. }
  2834. }
  2835. DebugTrace(-1, Dbg, "FatSetAllocationInfo -> %08lx\n", STATUS_SUCCESS);
  2836. return Status;
  2837. }
  2838. //
  2839. // Internal Support Routine
  2840. //
  2841. NTSTATUS
  2842. FatSetEndOfFileInfo (
  2843. IN PIRP_CONTEXT IrpContext,
  2844. IN PIRP Irp,
  2845. IN PFILE_OBJECT FileObject,
  2846. IN PVCB Vcb,
  2847. IN PFCB Fcb
  2848. )
  2849. /*++
  2850. Routine Description:
  2851. This routine performs the set End of File information for fat. It either
  2852. completes the request or enqueues it off to the fsp.
  2853. Arguments:
  2854. Irp - Supplies the irp being processed
  2855. FileObject - Supplies the file object being processed
  2856. Vcb - Supplies the Vcb being processed
  2857. Fcb - Supplies the Fcb or Dcb being processed, already known not to
  2858. be the root dcb
  2859. Return Value:
  2860. NTSTATUS - The result of this operation if it completes without
  2861. an exception.
  2862. --*/
  2863. {
  2864. NTSTATUS Status;
  2865. PFILE_END_OF_FILE_INFORMATION Buffer;
  2866. ULONG NewFileSize;
  2867. ULONG InitialFileSize;
  2868. ULONG InitialValidDataLength;
  2869. ULONG InitialValidDataToDisk;
  2870. BOOLEAN CacheMapInitialized = FALSE;
  2871. BOOLEAN UnwindFileSizes = FALSE;
  2872. BOOLEAN ResourceAcquired = FALSE;
  2873. DebugTrace(+1, Dbg, "FatSetEndOfFileInfo...\n", 0);
  2874. Buffer = Irp->AssociatedIrp.SystemBuffer;
  2875. try {
  2876. //
  2877. // File Size changes are only allowed on a file and not a directory
  2878. //
  2879. if (NodeType(Fcb) != FAT_NTC_FCB) {
  2880. DebugTrace(0, Dbg, "Cannot change size of a directory\n", 0);
  2881. try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
  2882. }
  2883. //
  2884. // Check that the new file size is legal
  2885. //
  2886. if (!FatIsIoRangeValid( Fcb->Vcb, Buffer->EndOfFile, 0 )) {
  2887. DebugTrace(0, Dbg, "Illegal allocation size\n", 0);
  2888. try_return( Status = STATUS_DISK_FULL );
  2889. }
  2890. NewFileSize = Buffer->EndOfFile.LowPart;
  2891. //
  2892. // If we haven't yet looked up the correct AllocationSize, do so.
  2893. //
  2894. if (Fcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
  2895. FatLookupFileAllocationSize( IrpContext, Fcb );
  2896. }
  2897. //
  2898. // This is kinda gross, but if the file is not cached, but there is
  2899. // a data section, we have to cache the file to avoid a bunch of
  2900. // extra work.
  2901. //
  2902. if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
  2903. (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
  2904. !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  2905. if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  2906. //
  2907. // This IRP has raced (and lost) with a close (=>cleanup)
  2908. // on the same fileobject. We don't want to reinitialise the
  2909. // cachemap here now because we'll leak it (unless we do so &
  2910. // then tear it down again here, which is too much of a change at
  2911. // this stage). So we'll just say the file is closed - which
  2912. // is arguably the right thing to do anyway, since a caller
  2913. // racing operations in this way is broken. The only stumbling
  2914. // block is possibly filters - do they operate on cleaned
  2915. // up fileobjects?
  2916. //
  2917. FatRaiseStatus( IrpContext, STATUS_FILE_CLOSED);
  2918. }
  2919. //
  2920. // Now initialize the cache map.
  2921. //
  2922. CcInitializeCacheMap( FileObject,
  2923. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
  2924. FALSE,
  2925. &FatData.CacheManagerCallbacks,
  2926. Fcb );
  2927. CacheMapInitialized = TRUE;
  2928. }
  2929. //
  2930. // Do a special case here for the lazy write of file sizes.
  2931. //
  2932. if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.AdvanceOnly) {
  2933. //
  2934. // Only attempt this if the file hasn't been "deleted on close" and
  2935. // this is a good FCB.
  2936. //
  2937. if (!IsFileDeleted( IrpContext, Fcb ) && (Fcb->FcbCondition == FcbGood)) {
  2938. PDIRENT Dirent;
  2939. PBCB DirentBcb;
  2940. //
  2941. // Never have the dirent filesize larger than the fcb filesize
  2942. //
  2943. if (NewFileSize >= Fcb->Header.FileSize.LowPart) {
  2944. NewFileSize = Fcb->Header.FileSize.LowPart;
  2945. }
  2946. //
  2947. // Make sure we don't set anything higher than the alloc size.
  2948. //
  2949. ASSERT( NewFileSize <= Fcb->Header.AllocationSize.LowPart );
  2950. //
  2951. // Only advance the file size, never reduce it with this call
  2952. //
  2953. FatGetDirentFromFcbOrDcb( IrpContext,
  2954. Fcb,
  2955. &Dirent,
  2956. &DirentBcb );
  2957. ASSERT( Dirent && DirentBcb );
  2958. try {
  2959. if ( NewFileSize > Dirent->FileSize ) {
  2960. Dirent->FileSize = NewFileSize;
  2961. FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE );
  2962. //
  2963. // Report that we just changed the file size.
  2964. //
  2965. FatNotifyReportChange( IrpContext,
  2966. Vcb,
  2967. Fcb,
  2968. FILE_NOTIFY_CHANGE_SIZE,
  2969. FILE_ACTION_MODIFIED );
  2970. }
  2971. } finally {
  2972. FatUnpinBcb( IrpContext, DirentBcb );
  2973. }
  2974. } else {
  2975. DebugTrace(0, Dbg, "Cannot set size on deleted file.\n", 0);
  2976. }
  2977. try_return( Status = STATUS_SUCCESS );
  2978. }
  2979. //
  2980. // Check if the new file size is greater than the current
  2981. // allocation size. If it is then we need to increase the
  2982. // allocation size.
  2983. //
  2984. if ( NewFileSize > Fcb->Header.AllocationSize.LowPart ) {
  2985. //
  2986. // Change the file allocation
  2987. //
  2988. FatAddFileAllocation( IrpContext, Fcb, FileObject, NewFileSize );
  2989. }
  2990. //
  2991. // At this point we have enough allocation for the file.
  2992. // So check if we are really changing the file size
  2993. //
  2994. if (Fcb->Header.FileSize.LowPart != NewFileSize) {
  2995. if ( NewFileSize < Fcb->Header.FileSize.LowPart ) {
  2996. //
  2997. // Before we actually truncate, check to see if the purge
  2998. // is going to fail.
  2999. //
  3000. if (!MmCanFileBeTruncated( FileObject->SectionObjectPointer,
  3001. &Buffer->EndOfFile )) {
  3002. try_return( Status = STATUS_USER_MAPPED_FILE );
  3003. }
  3004. //
  3005. // This call is unconditional, because MM always wants to know.
  3006. // Also serialize here with paging io since we are truncating
  3007. // the file size.
  3008. //
  3009. ResourceAcquired =
  3010. ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE );
  3011. }
  3012. //
  3013. // Set the new file size
  3014. //
  3015. InitialFileSize = Fcb->Header.FileSize.LowPart;
  3016. InitialValidDataLength = Fcb->Header.ValidDataLength.LowPart;
  3017. InitialValidDataToDisk = Fcb->ValidDataToDisk;
  3018. UnwindFileSizes = TRUE;
  3019. Fcb->Header.FileSize.LowPart = NewFileSize;
  3020. //
  3021. // If we reduced the file size to less than the ValidDataLength,
  3022. // adjust the VDL. Likewise ValidDataToDisk.
  3023. //
  3024. if (Fcb->Header.ValidDataLength.LowPart > NewFileSize) {
  3025. Fcb->Header.ValidDataLength.LowPart = NewFileSize;
  3026. }
  3027. if (Fcb->ValidDataToDisk > NewFileSize) {
  3028. Fcb->ValidDataToDisk = NewFileSize;
  3029. }
  3030. DebugTrace(0, Dbg, "New file size is 0x%08lx.\n", NewFileSize);
  3031. //
  3032. // We must now update the cache mapping (benign if not cached).
  3033. //
  3034. CcSetFileSizes( FileObject,
  3035. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  3036. FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
  3037. //
  3038. // Report that we just changed the file size.
  3039. //
  3040. FatNotifyReportChange( IrpContext,
  3041. Vcb,
  3042. Fcb,
  3043. FILE_NOTIFY_CHANGE_SIZE,
  3044. FILE_ACTION_MODIFIED );
  3045. //
  3046. // Mark the fact that the file will need to checked for
  3047. // truncation on cleanup.
  3048. //
  3049. SetFlag( Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE );
  3050. }
  3051. //
  3052. // Set this handle as having modified the file
  3053. //
  3054. FileObject->Flags |= FO_FILE_MODIFIED;
  3055. //
  3056. // Set our return status to success
  3057. //
  3058. Status = STATUS_SUCCESS;
  3059. try_exit: NOTHING;
  3060. FatUnpinRepinnedBcbs( IrpContext );
  3061. } finally {
  3062. DebugUnwind( FatSetEndOfFileInfo );
  3063. if (AbnormalTermination() && UnwindFileSizes) {
  3064. Fcb->Header.FileSize.LowPart = InitialFileSize;
  3065. Fcb->Header.ValidDataLength.LowPart = InitialValidDataLength;
  3066. Fcb->ValidDataToDisk = InitialValidDataToDisk;
  3067. if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) {
  3068. *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
  3069. }
  3070. }
  3071. if (CacheMapInitialized) {
  3072. CcUninitializeCacheMap( FileObject, NULL, NULL );
  3073. }
  3074. if ( ResourceAcquired ) {
  3075. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  3076. }
  3077. DebugTrace(-1, Dbg, "FatSetEndOfFileInfo -> %08lx\n", Status);
  3078. }
  3079. return Status;
  3080. }
  3081. //
  3082. // Internal Support Routine
  3083. //
  3084. VOID
  3085. FatDeleteFile (
  3086. IN PIRP_CONTEXT IrpContext,
  3087. IN PDCB TargetDcb,
  3088. IN ULONG LfnOffset,
  3089. IN ULONG DirentOffset,
  3090. IN PDIRENT Dirent,
  3091. IN PUNICODE_STRING Lfn
  3092. )
  3093. {
  3094. PFCB Fcb;
  3095. PLIST_ENTRY Links;
  3096. //
  3097. // We can do the replace by removing the other Fcb(s) from
  3098. // the prefix table.
  3099. //
  3100. for (Links = TargetDcb->Specific.Dcb.ParentDcbQueue.Flink;
  3101. Links != &TargetDcb->Specific.Dcb.ParentDcbQueue;
  3102. Links = Links->Flink) {
  3103. Fcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
  3104. if (FlagOn(Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE) &&
  3105. (Fcb->DirentOffsetWithinDirectory == DirentOffset)) {
  3106. ASSERT( NodeType(Fcb) == FAT_NTC_FCB );
  3107. ASSERT( Fcb->LfnOffsetWithinDirectory == LfnOffset );
  3108. if ( Fcb->UncleanCount != 0 ) {
  3109. FatBugCheck(0,0,0);
  3110. } else {
  3111. PERESOURCE Resource;
  3112. //
  3113. // Make this fcb "appear" deleted, synchronizing with
  3114. // paging IO.
  3115. //
  3116. FatRemoveNames( IrpContext, Fcb );
  3117. Resource = Fcb->Header.PagingIoResource;
  3118. (VOID)ExAcquireResourceExclusiveLite( Resource, TRUE );
  3119. SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
  3120. Fcb->ValidDataToDisk = 0;
  3121. Fcb->Header.FileSize.QuadPart =
  3122. Fcb->Header.ValidDataLength.QuadPart = 0;
  3123. Fcb->FirstClusterOfFile = 0;
  3124. ExReleaseResourceLite( Resource );
  3125. }
  3126. }
  3127. }
  3128. //
  3129. // The file is not currently opened so we can delete the file
  3130. // that is being overwritten. To do the operation we dummy
  3131. // up an fcb, truncate allocation, delete the fcb, and delete
  3132. // the dirent.
  3133. //
  3134. Fcb = FatCreateFcb( IrpContext,
  3135. TargetDcb->Vcb,
  3136. TargetDcb,
  3137. LfnOffset,
  3138. DirentOffset,
  3139. Dirent,
  3140. Lfn,
  3141. FALSE,
  3142. FALSE );
  3143. Fcb->Header.FileSize.LowPart = 0;
  3144. try {
  3145. FatTruncateFileAllocation( IrpContext, Fcb, 0 );
  3146. FatDeleteDirent( IrpContext, Fcb, NULL, TRUE );
  3147. } finally {
  3148. FatDeleteFcb( IrpContext, Fcb );
  3149. }
  3150. }
  3151. //
  3152. // Internal Support Routine
  3153. //
  3154. VOID
  3155. FatRenameEAs (
  3156. IN PIRP_CONTEXT IrpContext,
  3157. IN PFCB Fcb,
  3158. IN USHORT ExtendedAttributes,
  3159. IN POEM_STRING OldOemName
  3160. )
  3161. {
  3162. BOOLEAN LockedEaFcb = FALSE;
  3163. PBCB EaBcb = NULL;
  3164. PDIRENT EaDirent;
  3165. EA_RANGE EaSetRange;
  3166. PEA_SET_HEADER EaSetHeader;
  3167. PVCB Vcb;
  3168. RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
  3169. Vcb = Fcb->Vcb;
  3170. try {
  3171. //
  3172. // Use a try-except to catch any errors.
  3173. //
  3174. try {
  3175. //
  3176. // Try to get the Ea file object. Return FALSE on failure.
  3177. //
  3178. FatGetEaFile( IrpContext,
  3179. Vcb,
  3180. &EaDirent,
  3181. &EaBcb,
  3182. FALSE,
  3183. FALSE );
  3184. LockedEaFcb = TRUE;
  3185. //
  3186. // If we didn't get the file because it doesn't exist, then the
  3187. // disk is corrupted. We do nothing here.
  3188. //
  3189. if (Vcb->VirtualEaFile != NULL) {
  3190. //
  3191. // Try to pin down the Ea set header for the index in the
  3192. // dirent. If the operation doesn't complete, return FALSE
  3193. // from this routine.
  3194. //
  3195. FatReadEaSet( IrpContext,
  3196. Vcb,
  3197. ExtendedAttributes,
  3198. OldOemName,
  3199. FALSE,
  3200. &EaSetRange );
  3201. EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
  3202. //
  3203. // We now have the Ea set header for this file. We simply
  3204. // overwrite the owning file name.
  3205. //
  3206. RtlZeroMemory( EaSetHeader->OwnerFileName, 14 );
  3207. RtlCopyMemory( EaSetHeader->OwnerFileName,
  3208. Fcb->ShortName.Name.Oem.Buffer,
  3209. Fcb->ShortName.Name.Oem.Length );
  3210. FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange );
  3211. FatUnpinEaRange( IrpContext, &EaSetRange );
  3212. CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
  3213. }
  3214. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  3215. //
  3216. // We catch all exceptions that Fat catches, but don't do
  3217. // anything with them.
  3218. //
  3219. }
  3220. } finally {
  3221. //
  3222. // Unpin the EaDirent and the EaSetHeader if pinned.
  3223. //
  3224. FatUnpinBcb( IrpContext, EaBcb );
  3225. FatUnpinEaRange( IrpContext, &EaSetRange );
  3226. //
  3227. // Release the Fcb for the Ea file if locked.
  3228. //
  3229. if (LockedEaFcb) {
  3230. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  3231. }
  3232. }
  3233. return;
  3234. }