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.

3805 lines
101 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. EaSup.c
  5. Abstract:
  6. This module implements the cluster operations on the EA file for Fat.
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Brian Andrew [BrianAn] 07-Nov-1990
  10. // @@END_DDKSPLIT
  11. --*/
  12. #include "FatProcs.h"
  13. //
  14. // Local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_EA)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, FatAddEaSet)
  19. #pragma alloc_text(PAGE, FatAppendPackedEa)
  20. #pragma alloc_text(PAGE, FatCreateEa)
  21. #pragma alloc_text(PAGE, FatDeleteEa)
  22. #pragma alloc_text(PAGE, FatDeleteEaSet)
  23. #pragma alloc_text(PAGE, FatDeletePackedEa)
  24. #pragma alloc_text(PAGE, FatGetEaFile)
  25. #pragma alloc_text(PAGE, FatGetEaLength)
  26. #pragma alloc_text(PAGE, FatGetNeedEaCount)
  27. #pragma alloc_text(PAGE, FatIsEaNameValid)
  28. #pragma alloc_text(PAGE, FatLocateEaByName)
  29. #pragma alloc_text(PAGE, FatLocateNextEa)
  30. #pragma alloc_text(PAGE, FatReadEaSet)
  31. #pragma alloc_text(PAGE, FatPinEaRange)
  32. #pragma alloc_text(PAGE, FatMarkEaRangeDirty)
  33. #pragma alloc_text(PAGE, FatUnpinEaRange)
  34. #endif
  35. #define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))
  36. //
  37. // Any access to the Ea file must recognize when a section boundary is being
  38. // crossed.
  39. //
  40. #define EA_SECTION_SIZE (0x00040000)
  41. VOID
  42. FatGetEaLength (
  43. IN PIRP_CONTEXT IrpContext,
  44. IN PVCB Vcb,
  45. IN PDIRENT Dirent,
  46. OUT PULONG EaLength
  47. )
  48. /*++
  49. Routine Description:
  50. This routine looks up the Ea length for the Eas of the file. This
  51. length is the length of the packed eas, including the 4 bytes which
  52. contain the Ea length.
  53. This routine pins down the Ea set for the desired file and copies
  54. this field from the Ea set header.
  55. Arguments:
  56. Vcb - Vcb for the volume containing the Eas.
  57. Dirent - Supplies a pointer to the dirent for the file in question.
  58. EaLength - Supplies the address to store the length of the Eas.
  59. Return Value:
  60. None
  61. --*/
  62. {
  63. PBCB EaBcb;
  64. BOOLEAN LockedEaFcb;
  65. EA_RANGE EaSetRange;
  66. DebugTrace(+1, Dbg, "FatGetEaLength ...\n", 0);
  67. //
  68. // If this is Fat32 volume, or if the handle is 0 then the Ea length is 0.
  69. //
  70. if (FatIsFat32( Vcb ) ||
  71. Dirent->ExtendedAttributes == 0) {
  72. *EaLength = 0;
  73. DebugTrace(-1, Dbg, "FatGetEaLength -> %08lx\n", TRUE);
  74. return;
  75. }
  76. RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
  77. //
  78. // Use a try to facilitate cleanup.
  79. //
  80. try {
  81. PDIRENT EaDirent;
  82. OEM_STRING ThisFilename;
  83. UCHAR Buffer[12];
  84. PEA_SET_HEADER EaSetHeader;
  85. //
  86. // Initial the local values.
  87. //
  88. EaBcb = NULL;
  89. LockedEaFcb = FALSE;
  90. //
  91. // Try to get the Ea file object. Return FALSE on failure.
  92. //
  93. FatGetEaFile( IrpContext,
  94. Vcb,
  95. &EaDirent,
  96. &EaBcb,
  97. FALSE,
  98. FALSE );
  99. LockedEaFcb = TRUE;
  100. //
  101. // If we didn't get the file because it doesn't exist, then the
  102. // disk is corrupted.
  103. //
  104. if (Vcb->VirtualEaFile == NULL) {
  105. DebugTrace(0, Dbg, "FatGetEaLength: Ea file doesn't exist\n", 0);
  106. FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
  107. }
  108. //
  109. // Try to pin down the Ea set header for the index in the
  110. // dirent. If the operation doesn't complete, return FALSE
  111. // from this routine.
  112. //
  113. ThisFilename.Buffer = Buffer;
  114. Fat8dot3ToString( IrpContext, Dirent, FALSE, &ThisFilename );
  115. FatReadEaSet( IrpContext,
  116. Vcb,
  117. Dirent->ExtendedAttributes,
  118. &ThisFilename,
  119. FALSE,
  120. &EaSetRange );
  121. EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
  122. //
  123. // We now have the Ea set header for this file. We simply copy
  124. // the Ea length field.
  125. //
  126. CopyUchar4( EaLength, EaSetHeader->cbList );
  127. DebugTrace(0, Dbg, "FatGetEaLength: Length of Ea is -> %08lx\n",
  128. *EaLength);
  129. } finally {
  130. DebugUnwind( FatGetEaLength );
  131. //
  132. // Unpin the EaDirent and the EaSetHeader if pinned.
  133. //
  134. FatUnpinBcb( IrpContext, EaBcb );
  135. FatUnpinEaRange( IrpContext, &EaSetRange );
  136. //
  137. // Release the Fcb for the Ea file if locked.
  138. //
  139. if (LockedEaFcb) {
  140. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  141. }
  142. DebugTrace(-1, Dbg, "FatGetEaLength: Ea length -> %08lx\n", *EaLength);
  143. }
  144. return;
  145. }
  146. VOID
  147. FatGetNeedEaCount (
  148. IN PIRP_CONTEXT IrpContext,
  149. IN PVCB Vcb,
  150. IN PDIRENT Dirent,
  151. OUT PULONG NeedEaCount
  152. )
  153. /*++
  154. Routine Description:
  155. This routine looks up the Need Ea count for the file. The value is the
  156. in the ea header for the file.
  157. Arguments:
  158. Vcb - Vcb for the volume containing the Eas.
  159. Dirent - Supplies a pointer to the dirent for the file in question.
  160. NeedEaCount - Supplies the address to store the Need Ea count.
  161. Return Value:
  162. None
  163. --*/
  164. {
  165. PBCB EaBcb;
  166. BOOLEAN LockedEaFcb;
  167. EA_RANGE EaSetRange;
  168. DebugTrace(+1, Dbg, "FatGetNeedEaCount ...\n", 0);
  169. //
  170. // If the handle is 0 then the Need Ea count is 0.
  171. //
  172. if (Dirent->ExtendedAttributes == 0) {
  173. *NeedEaCount = 0;
  174. DebugTrace(-1, Dbg, "FatGetNeedEaCount -> %08lx\n", TRUE);
  175. return;
  176. }
  177. RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
  178. //
  179. // Use a try to facilitate cleanup.
  180. //
  181. try {
  182. PDIRENT EaDirent;
  183. OEM_STRING ThisFilename;
  184. UCHAR Buffer[12];
  185. PEA_SET_HEADER EaSetHeader;
  186. //
  187. // Initial the local values.
  188. //
  189. EaBcb = NULL;
  190. LockedEaFcb = FALSE;
  191. //
  192. // Try to get the Ea file object. Return FALSE on failure.
  193. //
  194. FatGetEaFile( IrpContext,
  195. Vcb,
  196. &EaDirent,
  197. &EaBcb,
  198. FALSE,
  199. FALSE );
  200. LockedEaFcb = TRUE;
  201. //
  202. // If we didn't get the file because it doesn't exist, then the
  203. // disk is corrupted.
  204. //
  205. if (Vcb->VirtualEaFile == NULL) {
  206. DebugTrace(0, Dbg, "FatGetNeedEaCount: Ea file doesn't exist\n", 0);
  207. FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
  208. }
  209. //
  210. // Try to pin down the Ea set header for the index in the
  211. // dirent. If the operation doesn't complete, return FALSE
  212. // from this routine.
  213. //
  214. ThisFilename.Buffer = Buffer;
  215. Fat8dot3ToString( IrpContext, Dirent, FALSE, &ThisFilename );
  216. FatReadEaSet( IrpContext,
  217. Vcb,
  218. Dirent->ExtendedAttributes,
  219. &ThisFilename,
  220. FALSE,
  221. &EaSetRange );
  222. EaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
  223. //
  224. // We now have the Ea set header for this file. We simply copy
  225. // the Need Ea field.
  226. //
  227. *NeedEaCount = EaSetHeader->NeedEaCount;
  228. } finally {
  229. DebugUnwind( FatGetNeedEaCount );
  230. //
  231. // Unpin the EaDirent and the EaSetHeader if pinned.
  232. //
  233. FatUnpinBcb( IrpContext, EaBcb );
  234. FatUnpinEaRange( IrpContext, &EaSetRange );
  235. //
  236. // Release the Fcb for the Ea file if locked.
  237. //
  238. if (LockedEaFcb) {
  239. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  240. }
  241. DebugTrace(-1, Dbg, "FatGetNeedEaCount: NeedEaCount -> %08lx\n", *NeedEaCount);
  242. }
  243. return;
  244. }
  245. VOID
  246. FatCreateEa (
  247. IN PIRP_CONTEXT IrpContext,
  248. IN PVCB Vcb,
  249. IN PUCHAR Buffer,
  250. IN ULONG Length,
  251. IN POEM_STRING FileName,
  252. OUT PUSHORT EaHandle
  253. )
  254. /*++
  255. Routine Description:
  256. This routine adds an entire ea set to the Ea file. The owning file
  257. is specified in 'FileName'. This is used to replace the Ea set attached
  258. to an existing file during a supersede operation.
  259. NOTE: This routine may block, it should not be called unless the
  260. thread is waitable.
  261. Arguments:
  262. Vcb - Supplies the Vcb for the volume.
  263. Buffer - Buffer with the Ea list to add.
  264. Length - Length of the buffer.
  265. FileName - The Ea's will be attached to this file.
  266. EaHandle - The new ea handle will be assigned to this address.
  267. Return Value:
  268. None
  269. --*/
  270. {
  271. PBCB EaBcb;
  272. BOOLEAN LockedEaFcb;
  273. PEA_SET_HEADER EaSetHeader;
  274. EA_RANGE EaSetRange;
  275. DebugTrace(+1, Dbg, "FatCreateEa...\n", 0);
  276. EaBcb = NULL;
  277. LockedEaFcb = FALSE;
  278. RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
  279. //
  280. // Use 'try' to facilitate cleanup.
  281. //
  282. try {
  283. PDIRENT EaDirent;
  284. ULONG PackedEasLength;
  285. ULONG AllocationLength;
  286. ULONG BytesPerCluster;
  287. PFILE_FULL_EA_INFORMATION FullEa;
  288. //
  289. // We will allocate a buffer and copy the Ea list from the user's
  290. // buffer to a FAT packed Ea list. Initial allocation is one
  291. // cluster, our starting offset into the packed Ea list is 0.
  292. //
  293. PackedEasLength = 0;
  294. BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
  295. AllocationLength = (PackedEasLength
  296. + SIZE_OF_EA_SET_HEADER
  297. + BytesPerCluster - 1)
  298. & ~(BytesPerCluster - 1);
  299. //
  300. // Allocate the memory and store the file name into it.
  301. //
  302. EaSetHeader = FsRtlAllocatePoolWithTag( PagedPool,
  303. AllocationLength,
  304. TAG_EA_SET_HEADER );
  305. RtlZeroMemory( EaSetHeader, AllocationLength );
  306. RtlCopyMemory( EaSetHeader->OwnerFileName,
  307. FileName->Buffer,
  308. FileName->Length );
  309. AllocationLength -= SIZE_OF_EA_SET_HEADER;
  310. //
  311. // Loop through the user's Ea list. Catch any error for invalid
  312. // name or non-existent Ea value.
  313. //
  314. for ( FullEa = (PFILE_FULL_EA_INFORMATION) Buffer;
  315. FullEa < (PFILE_FULL_EA_INFORMATION) &Buffer[Length];
  316. FullEa = (PFILE_FULL_EA_INFORMATION) (FullEa->NextEntryOffset == 0 ?
  317. &Buffer[Length] :
  318. (PUCHAR) FullEa + FullEa->NextEntryOffset)) {
  319. OEM_STRING EaName;
  320. ULONG EaOffset;
  321. EaName.Length = FullEa->EaNameLength;
  322. EaName.Buffer = &FullEa->EaName[0];
  323. //
  324. // Make sure the ea name is valid
  325. //
  326. if (!FatIsEaNameValid( IrpContext, EaName )) {
  327. DebugTrace(0, Dbg,
  328. "FatCreateEa: Invalid Ea Name -> %Z\n",
  329. EaName);
  330. IrpContext->OriginatingIrp->IoStatus.Information = (PUCHAR)FullEa - Buffer;
  331. IrpContext->OriginatingIrp->IoStatus.Status = STATUS_INVALID_EA_NAME;
  332. FatRaiseStatus( IrpContext, STATUS_INVALID_EA_NAME );
  333. }
  334. //
  335. // Check that no invalid ea flags are set.
  336. //
  337. //
  338. // TEMPCODE We are returning STATUS_INVALID_EA_NAME
  339. // until a more appropriate error code exists.
  340. //
  341. if (FullEa->Flags != 0
  342. && FullEa->Flags != FILE_NEED_EA) {
  343. IrpContext->OriginatingIrp->IoStatus.Information = (PUCHAR)FullEa - Buffer;
  344. IrpContext->OriginatingIrp->IoStatus.Status = STATUS_INVALID_EA_NAME;
  345. FatRaiseStatus( IrpContext, STATUS_INVALID_EA_NAME );
  346. }
  347. //
  348. // If this is a duplicate name then delete the current ea
  349. // value.
  350. //
  351. if (FatLocateEaByName( IrpContext,
  352. (PPACKED_EA) EaSetHeader->PackedEas,
  353. PackedEasLength,
  354. &EaName,
  355. &EaOffset )) {
  356. DebugTrace(0, Dbg, "FatCreateEa: Duplicate name found\n", 0);
  357. FatDeletePackedEa( IrpContext,
  358. EaSetHeader,
  359. &PackedEasLength,
  360. EaOffset );
  361. }
  362. //
  363. // We ignore this value if the eavalue length is zero.
  364. //
  365. if (FullEa->EaValueLength == 0) {
  366. DebugTrace(0, Dbg,
  367. "FatCreateEa: Empty ea\n",
  368. 0);
  369. continue;
  370. }
  371. FatAppendPackedEa( IrpContext,
  372. &EaSetHeader,
  373. &PackedEasLength,
  374. &AllocationLength,
  375. FullEa,
  376. BytesPerCluster );
  377. }
  378. //
  379. // If the resulting length isn't zero, then allocate a FAT cluster
  380. // to store the data.
  381. //
  382. if (PackedEasLength != 0) {
  383. PEA_SET_HEADER NewEaSetHeader;
  384. //
  385. // If the packed eas length (plus 4 bytes) is greater
  386. // than the maximum allowed ea size, we return an error.
  387. //
  388. if (PackedEasLength + 4 > MAXIMUM_EA_SIZE) {
  389. DebugTrace( 0, Dbg, "Ea length is greater than maximum\n", 0 );
  390. FatRaiseStatus( IrpContext, STATUS_EA_TOO_LARGE );
  391. }
  392. //
  393. // Get the Ea file.
  394. //
  395. FatGetEaFile( IrpContext,
  396. Vcb,
  397. &EaDirent,
  398. &EaBcb,
  399. TRUE,
  400. TRUE );
  401. LockedEaFcb = TRUE;
  402. FatAddEaSet( IrpContext,
  403. Vcb,
  404. PackedEasLength + SIZE_OF_EA_SET_HEADER,
  405. EaBcb,
  406. EaDirent,
  407. EaHandle,
  408. &EaSetRange );
  409. NewEaSetHeader = (PEA_SET_HEADER) EaSetRange.Data;
  410. //
  411. // Store the length of the new Ea's into the NewEaSetHeader.
  412. // This is the PackedEasLength + 4.
  413. //
  414. PackedEasLength += 4;
  415. CopyU4char( EaSetHeader->cbList, &PackedEasLength );
  416. //
  417. // Copy all but the first four bytes of EaSetHeader into
  418. // the new ea. The signature and index fields have
  419. // already been filled in.
  420. //
  421. RtlCopyMemory( &NewEaSetHeader->NeedEaCount,
  422. &EaSetHeader->NeedEaCount,
  423. PackedEasLength + SIZE_OF_EA_SET_HEADER - 8 );
  424. FatMarkEaRangeDirty( IrpContext, Vcb->VirtualEaFile, &EaSetRange );
  425. FatUnpinEaRange( IrpContext, &EaSetRange );
  426. CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
  427. //
  428. // There was no data added to the Ea file. Return a handle
  429. // of 0.
  430. //
  431. } else {
  432. *EaHandle = 0;
  433. }
  434. } finally {
  435. DebugUnwind( FatCreateEa );
  436. //
  437. // Deallocate the EaSetHeader if present.
  438. //
  439. if (EaSetHeader) {
  440. ExFreePool( EaSetHeader );
  441. }
  442. //
  443. // Release the EaFcb if held.
  444. //
  445. if (LockedEaFcb) {
  446. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  447. }
  448. //
  449. // Unpin the dirents for the EaFcb and EaSetFcb if necessary.
  450. //
  451. FatUnpinBcb( IrpContext, EaBcb );
  452. FatUnpinEaRange( IrpContext, &EaSetRange );
  453. DebugTrace(-1, Dbg, "FatCreateEa -> Exit\n", 0);
  454. }
  455. return;
  456. }
  457. VOID
  458. FatDeleteEa (
  459. IN PIRP_CONTEXT IrpContext,
  460. IN PVCB Vcb,
  461. IN USHORT EaHandle,
  462. IN POEM_STRING FileName
  463. )
  464. /*++
  465. Routine Description:
  466. This routine is called to remove an entire ea set. Most of the work
  467. is done in the call to 'FatDeleteEaSet'. This routine opens the
  468. Ea file and then calls the support routine.
  469. NOTE: This routine may block, it should not be called unless the
  470. thread is waitable.
  471. Arguments:
  472. Vcb - Vcb for the volume
  473. EaHandle - The handle for the Ea's to remove. This handle will be
  474. verified during this operation.
  475. FileName - The name of the file whose Ea's are being removed. This
  476. name is compared against the Ea owner's name in the Ea set.
  477. Return Value:
  478. None.
  479. --*/
  480. {
  481. PBCB EaBcb;
  482. BOOLEAN LockedEaFcb;
  483. DebugTrace(+1, Dbg, "FatDeleteEa...\n", 0);
  484. //
  485. // Initialize local values.
  486. //
  487. EaBcb = NULL;
  488. LockedEaFcb = FALSE;
  489. //
  490. // Use a try statement to facilitate cleanup.
  491. //
  492. try {
  493. PDIRENT EaDirent;
  494. //
  495. // Get the Ea stream file. If the file doesn't exist on the disk
  496. // then the disk has been corrupted.
  497. //
  498. FatGetEaFile( IrpContext,
  499. Vcb,
  500. &EaDirent,
  501. &EaBcb,
  502. FALSE,
  503. TRUE );
  504. LockedEaFcb = TRUE;
  505. //
  506. // If we didn't get the Ea file, then the disk is corrupt.
  507. //
  508. if ( EaBcb == NULL ) {
  509. DebugTrace(0, Dbg,
  510. "FatDeleteEa: No Ea file exists\n",
  511. 0);
  512. FatRaiseStatus( IrpContext, STATUS_NO_EAS_ON_FILE );
  513. }
  514. //
  515. // We now have everything we need to delete the ea set. Call the
  516. // support routine to do this.
  517. //
  518. FatDeleteEaSet( IrpContext,
  519. Vcb,
  520. EaBcb,
  521. EaDirent,
  522. EaHandle,
  523. FileName );
  524. CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
  525. } finally {
  526. DebugUnwind( FatDeleteEa );
  527. //
  528. // Release the EaFcb if held.
  529. //
  530. if (LockedEaFcb) {
  531. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  532. }
  533. //
  534. // Unpin the dirent for the Ea file if pinned.
  535. //
  536. FatUnpinBcb( IrpContext, EaBcb );
  537. DebugTrace(-1, Dbg, "FatDeleteEa -> Exit\n", 0);
  538. }
  539. return;
  540. }
  541. VOID
  542. FatGetEaFile (
  543. IN PIRP_CONTEXT IrpContext,
  544. IN OUT PVCB Vcb,
  545. OUT PDIRENT *EaDirent,
  546. OUT PBCB *EaBcb,
  547. IN BOOLEAN CreateFile,
  548. IN BOOLEAN ExclusiveFcb
  549. )
  550. /*++
  551. Routine Description:
  552. This routine is used to completely initialize the Vcb and
  553. the Ea file for the Vcb.
  554. If the Vcb doesn't have the Ea file object, then we first try to
  555. lookup the Ea data file in the root directory and if that fails
  556. we try to create the file. The 'CreateFile' flag is used to check
  557. whether it is necessary to create the Ea file.
  558. This routine will lock down the Fcb for exclusive or shared access before
  559. performing any operations. If the operation does not complete due
  560. to blocking, exclusive or shared access will be given up before returning.
  561. If we are creating the Ea file and marking sections of it dirty,
  562. we can't use the repin feature through the cache map. In that case
  563. we use a local IrpContext and then unpin all of the Bcb's before
  564. continuing.
  565. Note: If this routine will be creating the Ea file, we are guaranteed
  566. to be waitable.
  567. Arguments:
  568. Vcb - Vcb for the volume
  569. EaDirent - Location to store the address of the pinned dirent for the
  570. Ea file.
  571. EaBcb - Location to store the address of the Bcb for the pinned dirent.
  572. CreateFile - Boolean indicating whether we should create the Ea file
  573. on the disk.
  574. ExclusiveFcb - Indicates whether shared or exclusive access is desired
  575. for the EaFcb.
  576. Return Value:
  577. None.
  578. --*/
  579. {
  580. PFILE_OBJECT EaStreamFile = NULL;
  581. EA_RANGE EaFileRange;
  582. BOOLEAN UnwindLockedEaFcb = FALSE;
  583. BOOLEAN UnwindLockedRootDcb = FALSE;
  584. BOOLEAN UnwindAllocatedDiskSpace = FALSE;
  585. BOOLEAN UnwindEaDirentCreated = FALSE;
  586. BOOLEAN UnwindUpdatedSizes = FALSE;
  587. DebugTrace(+1, Dbg, "FatGetEaFile ...\n", 0);
  588. RtlZeroMemory( &EaFileRange, sizeof( EA_RANGE ));
  589. //
  590. // Use a try to facilitate cleanup
  591. //
  592. try {
  593. OEM_STRING EaFileName;
  594. LARGE_INTEGER SectionSize;
  595. //
  596. // Check if the Vcb already has the file object. If it doesn't, then
  597. // we need to search the root directory for the Ea data file.
  598. //
  599. if (Vcb->VirtualEaFile == NULL) {
  600. //
  601. // Always lock the Ea file exclusively if we have to create the file.
  602. //
  603. if ( !FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb )) {
  604. DebugTrace(0, Dbg, "FatGetEaFile: Can't grab exclusive\n", 0);
  605. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  606. }
  607. UnwindLockedEaFcb = TRUE;
  608. //
  609. // Otherwise we acquire the Fcb as the caller requested.
  610. //
  611. } else {
  612. if ((ExclusiveFcb && !FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb ))
  613. || (!ExclusiveFcb && !FatAcquireSharedFcb( IrpContext, Vcb->EaFcb))) {
  614. DebugTrace(0, Dbg, "FatGetEaFile: Can't grab EaFcb\n", 0);
  615. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  616. }
  617. UnwindLockedEaFcb = TRUE;
  618. //
  619. // If the file now does not exist we need to release the Fcb and
  620. // reacquire exclusive if we acquired shared.
  621. //
  622. if ((Vcb->VirtualEaFile == NULL) && !ExclusiveFcb) {
  623. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  624. UnwindLockedEaFcb = FALSE;
  625. if (!FatAcquireExclusiveFcb( IrpContext, Vcb->EaFcb )) {
  626. DebugTrace(0, Dbg, "FatGetEaFile: Can't grab EaFcb\n", 0);
  627. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  628. }
  629. UnwindLockedEaFcb = TRUE;
  630. }
  631. }
  632. //
  633. // If the file object is now there we only need to get the
  634. // dirent for the Ea file.
  635. //
  636. if (Vcb->VirtualEaFile != NULL) {
  637. FatVerifyFcb( IrpContext, Vcb->EaFcb );
  638. FatGetDirentFromFcbOrDcb( IrpContext,
  639. Vcb->EaFcb,
  640. EaDirent,
  641. EaBcb );
  642. try_return( NOTHING );
  643. } else {
  644. VBO ByteOffset;
  645. //
  646. // Always mark the ea fcb as good.
  647. //
  648. Vcb->EaFcb->FcbCondition = FcbGood;
  649. //
  650. // We try to lookup the dirent for the Ea Fcb.
  651. //
  652. EaFileName.Buffer = "EA DATA. SF";
  653. EaFileName.Length = 11;
  654. EaFileName.MaximumLength = 12;
  655. //
  656. // Now pick up the root directory to be synchronized with
  657. // deletion/creation of entries. If we may create the file,
  658. // get it exclusive right now.
  659. //
  660. // Again, note how we are relying on bottom-up lockorder. We
  661. // already got the EaFcb.
  662. //
  663. if (CreateFile) {
  664. ExAcquireResourceExclusiveLite( Vcb->RootDcb->Header.Resource, TRUE );
  665. } else {
  666. ExAcquireResourceSharedLite( Vcb->RootDcb->Header.Resource, TRUE );
  667. }
  668. UnwindLockedRootDcb = TRUE;
  669. FatLocateSimpleOemDirent( IrpContext,
  670. Vcb->EaFcb->ParentDcb,
  671. &EaFileName,
  672. EaDirent,
  673. EaBcb,
  674. &ByteOffset );
  675. //
  676. // If the file exists, we need to create the virtual file
  677. // object for it.
  678. //
  679. if (*EaDirent != NULL) {
  680. //
  681. // Since we may be modifying the dirent, pin the data now.
  682. //
  683. FatPinMappedData( IrpContext,
  684. Vcb->EaFcb->ParentDcb,
  685. ByteOffset,
  686. sizeof(DIRENT),
  687. EaBcb );
  688. //
  689. // Update the Fcb with information on the file size
  690. // and disk location. Also increment the open/unclean
  691. // counts in the EaFcb and the open count in the
  692. // Vcb.
  693. //
  694. Vcb->EaFcb->FirstClusterOfFile = (*EaDirent)->FirstClusterOfFile;
  695. Vcb->EaFcb->DirentOffsetWithinDirectory = ByteOffset;
  696. //
  697. // Find the allocation size. The purpose here is
  698. // really to completely fill in the Mcb for the
  699. // file.
  700. //
  701. Vcb->EaFcb->Header.AllocationSize.QuadPart = FCB_LOOKUP_ALLOCATIONSIZE_HINT;
  702. FatLookupFileAllocationSize( IrpContext, Vcb->EaFcb );
  703. //
  704. // Start by computing the section size for the cache
  705. // manager.
  706. //
  707. SectionSize.QuadPart = (*EaDirent)->FileSize;
  708. Vcb->EaFcb->Header.AllocationSize = SectionSize;
  709. Vcb->EaFcb->Header.FileSize = SectionSize;
  710. //
  711. // Create and initialize the file object for the
  712. // Ea virtual file.
  713. //
  714. EaStreamFile = FatOpenEaFile( IrpContext, Vcb->EaFcb );
  715. Vcb->VirtualEaFile = EaStreamFile;
  716. //
  717. // Else there was no dirent. If we were instructed to
  718. // create the file object, we will try to create the dirent,
  719. // allocate disk space, initialize the Ea file header and
  720. // return this information to the user.
  721. //
  722. } else if (CreateFile) {
  723. ULONG BytesPerCluster;
  724. ULONG OffsetTableSize;
  725. ULONG AllocationSize;
  726. PEA_FILE_HEADER FileHeader;
  727. USHORT AllocatedClusters;
  728. PUSHORT CurrentIndex;
  729. ULONG Index;
  730. NTSTATUS Status;
  731. DebugTrace(0, Dbg, "FatGetEaFile: Creating local IrpContext\n", 0);
  732. BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
  733. AllocationSize = (((ULONG) sizeof( EA_FILE_HEADER ) << 1) + BytesPerCluster - 1)
  734. & ~(BytesPerCluster - 1);
  735. AllocatedClusters = (USHORT) (AllocationSize
  736. >> Vcb->AllocationSupport.LogOfBytesPerCluster);
  737. OffsetTableSize = AllocationSize - sizeof( EA_FILE_HEADER );
  738. //
  739. // Allocate disk space, the space allocated is 1024 bytes
  740. // rounded up to the nearest cluster size.
  741. //
  742. FatAllocateDiskSpace( IrpContext,
  743. Vcb,
  744. 0,
  745. &AllocationSize,
  746. FALSE,
  747. &Vcb->EaFcb->Mcb );
  748. UnwindAllocatedDiskSpace = TRUE;
  749. //
  750. // Allocate and initialize a dirent in the root directory
  751. // to describe this new file.
  752. //
  753. Vcb->EaFcb->DirentOffsetWithinDirectory =
  754. FatCreateNewDirent( IrpContext,
  755. Vcb->EaFcb->ParentDcb,
  756. 1 );
  757. FatPrepareWriteDirectoryFile( IrpContext,
  758. Vcb->EaFcb->ParentDcb,
  759. Vcb->EaFcb->DirentOffsetWithinDirectory,
  760. sizeof(DIRENT),
  761. EaBcb,
  762. EaDirent,
  763. FALSE,
  764. TRUE,
  765. &Status );
  766. ASSERT( NT_SUCCESS( Status ));
  767. UnwindEaDirentCreated = TRUE;
  768. FatConstructDirent( IrpContext,
  769. *EaDirent,
  770. &EaFileName,
  771. FALSE,
  772. FALSE,
  773. NULL,
  774. FAT_DIRENT_ATTR_READ_ONLY
  775. | FAT_DIRENT_ATTR_HIDDEN
  776. | FAT_DIRENT_ATTR_SYSTEM
  777. | FAT_DIRENT_ATTR_ARCHIVE,
  778. TRUE,
  779. NULL );
  780. (*EaDirent)->FileSize = AllocationSize;
  781. //
  782. // Initialize the Fcb for this file and initialize the
  783. // cache map as well.
  784. //
  785. //
  786. // Start by computing the section size for the cache
  787. // manager.
  788. //
  789. SectionSize.QuadPart = (*EaDirent)->FileSize;
  790. Vcb->EaFcb->Header.AllocationSize = SectionSize;
  791. Vcb->EaFcb->Header.FileSize = SectionSize;
  792. UnwindUpdatedSizes = TRUE;
  793. //
  794. // Create and initialize the file object for the
  795. // Ea virtual file.
  796. //
  797. EaStreamFile = FatOpenEaFile( IrpContext, Vcb->EaFcb );
  798. //
  799. // Update the Fcb with information on the file size
  800. // and disk location. Also increment the open/unclean
  801. // counts in the EaFcb and the open count in the
  802. // Vcb.
  803. //
  804. {
  805. LBO FirstLboOfFile;
  806. FatLookupMcbEntry( Vcb, &Vcb->EaFcb->Mcb,
  807. 0,
  808. &FirstLboOfFile,
  809. NULL,
  810. NULL );
  811. //
  812. // The discerning reader will note that this doesn't take
  813. // FAT32 into account, which is of course intentional.
  814. //
  815. (*EaDirent)->FirstClusterOfFile =
  816. (USHORT) FatGetIndexFromLbo( Vcb, FirstLboOfFile );
  817. }
  818. Vcb->EaFcb->FirstClusterOfFile = (*EaDirent)->FirstClusterOfFile;
  819. //
  820. // Initialize the Ea file header and mark the Bcb as dirty.
  821. //
  822. FatPinEaRange( IrpContext,
  823. EaStreamFile,
  824. Vcb->EaFcb,
  825. &EaFileRange,
  826. 0,
  827. AllocationSize,
  828. STATUS_DATA_ERROR );
  829. FileHeader = (PEA_FILE_HEADER) EaFileRange.Data;
  830. RtlZeroMemory( FileHeader, AllocationSize );
  831. FileHeader->Signature = EA_FILE_SIGNATURE;
  832. for (Index = MAX_EA_BASE_INDEX, CurrentIndex = FileHeader->EaBaseTable;
  833. Index;
  834. Index--, CurrentIndex++) {
  835. *CurrentIndex = AllocatedClusters;
  836. }
  837. //
  838. // Initialize the offset table with the offset set to
  839. // after the just allocated clusters.
  840. //
  841. for (Index = OffsetTableSize >> 1,
  842. CurrentIndex = (PUSHORT) ((PUCHAR) FileHeader + sizeof( EA_FILE_HEADER ));
  843. Index;
  844. Index--, CurrentIndex++) {
  845. *CurrentIndex = UNUSED_EA_HANDLE;
  846. }
  847. //
  848. // Unpin the file header and offset table.
  849. //
  850. FatMarkEaRangeDirty( IrpContext, EaStreamFile, &EaFileRange );
  851. FatUnpinEaRange( IrpContext, &EaFileRange );
  852. CcFlushCache( EaStreamFile->SectionObjectPointer, NULL, 0, NULL );
  853. //
  854. // Return the Ea file object to the user.
  855. //
  856. Vcb->VirtualEaFile = EaStreamFile;
  857. }
  858. }
  859. try_exit: NOTHING;
  860. } finally {
  861. DebugUnwind( FatGetEaFile );
  862. //
  863. // If this is abnormal termination and disk space has been
  864. // allocated. We deallocate it now.
  865. //
  866. if (AbnormalTermination()) {
  867. //
  868. // Deallocate the Ea file
  869. //
  870. if (UnwindAllocatedDiskSpace) {
  871. FatDeallocateDiskSpace( IrpContext,
  872. Vcb,
  873. &Vcb->EaFcb->Mcb );
  874. }
  875. //
  876. // Delete the dirent for the Ea file, if created.
  877. //
  878. if (UnwindEaDirentCreated) {
  879. if (UnwindUpdatedSizes) {
  880. Vcb->EaFcb->Header.AllocationSize.QuadPart = 0;
  881. Vcb->EaFcb->Header.FileSize.QuadPart = 0;
  882. }
  883. FatUnpinBcb( IrpContext, *EaBcb );
  884. FatDeleteDirent( IrpContext, Vcb->EaFcb, NULL, TRUE );
  885. }
  886. //
  887. // Release the EA Fcb if held
  888. //
  889. if (UnwindLockedEaFcb) {
  890. FatReleaseFcb( IrpContext, Vcb->EaFcb );
  891. }
  892. //
  893. // Dereference the Ea stream file if created.
  894. //
  895. if (EaStreamFile != NULL) {
  896. ObDereferenceObject( EaStreamFile );
  897. }
  898. }
  899. //
  900. // Always release the root Dcb (our caller releases the EA Fcb if we
  901. // do not raise).
  902. //
  903. if (UnwindLockedRootDcb) {
  904. FatReleaseFcb( IrpContext, Vcb->RootDcb );
  905. }
  906. //
  907. // If the Ea file header is locked down. We unpin it now.
  908. //
  909. FatUnpinEaRange( IrpContext, &EaFileRange );
  910. DebugTrace(-1, Dbg, "FatGetEaFile: Exit\n", 0);
  911. }
  912. return;
  913. }
  914. VOID
  915. FatReadEaSet (
  916. IN PIRP_CONTEXT IrpContext,
  917. IN PVCB Vcb,
  918. IN USHORT EaHandle,
  919. IN POEM_STRING FileName,
  920. IN BOOLEAN ReturnEntireSet,
  921. OUT PEA_RANGE EaSetRange
  922. )
  923. /*++
  924. Routine Description:
  925. This routine pins the Ea set for the given ea handle within the
  926. Ea stream file. The EaHandle, after first comparing against valid
  927. index values, is used to compute the cluster offset for this
  928. this Ea set. The Ea set is then verified as belonging to this
  929. index and lying within the Ea data file.
  930. The caller of this function will have verified that the Ea file
  931. exists and that the Vcb field points to an initialized cache file.
  932. The caller will already have gained exclusive access to the
  933. EaFcb.
  934. Arguments:
  935. Vcb - Supplies the Vcb for the volume.
  936. EaHandle - Supplies the handle for the Ea's to read.
  937. FileName - Name of the file whose Ea's are being read.
  938. ReturnEntireSet - Indicates if the caller needs the entire set
  939. as opposed to just the header.
  940. EaSetRange - Pointer to the EaRange structure which will describe the Ea
  941. on return.
  942. Return Value:
  943. None
  944. --*/
  945. {
  946. ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
  947. ULONG EaOffsetVbo;
  948. EA_RANGE EaOffsetRange;
  949. USHORT EaOffsetCluster;
  950. EA_RANGE EaHeaderRange;
  951. PEA_FILE_HEADER EaHeader;
  952. ULONG EaSetVbo;
  953. PEA_SET_HEADER EaSet;
  954. ULONG CbList;
  955. DebugTrace(+1, Dbg, "FatReadEaSet\n", 0);
  956. DebugTrace( 0, Dbg, " Vcb = %8lx\n", Vcb);
  957. //
  958. // Verify that the Ea index has a legal value. Raise status
  959. // STATUS_NONEXISTENT_EA_ENTRY if illegal.
  960. //
  961. if (EaHandle < MIN_EA_HANDLE
  962. || EaHandle > MAX_EA_HANDLE) {
  963. DebugTrace(-1, Dbg, "FatReadEaSet: Illegal handle value\n", 0);
  964. FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
  965. }
  966. //
  967. // Verify that the virtual Ea file is large enough for us to read
  968. // the EaOffet table for this index.
  969. //
  970. EaOffsetVbo = sizeof( EA_FILE_HEADER ) + ((EaHandle >> 7) << 8);
  971. //
  972. // Zero the Ea range structures.
  973. //
  974. RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
  975. RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
  976. //
  977. // Use a try statement to clean up on exit.
  978. //
  979. try {
  980. //
  981. // Pin down the EA file header.
  982. //
  983. FatPinEaRange( IrpContext,
  984. Vcb->VirtualEaFile,
  985. Vcb->EaFcb,
  986. &EaHeaderRange,
  987. 0,
  988. sizeof( EA_FILE_HEADER ),
  989. STATUS_NONEXISTENT_EA_ENTRY );
  990. EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
  991. //
  992. // Pin down the Ea offset table for the particular index.
  993. //
  994. FatPinEaRange( IrpContext,
  995. Vcb->VirtualEaFile,
  996. Vcb->EaFcb,
  997. &EaOffsetRange,
  998. EaOffsetVbo,
  999. sizeof( EA_OFF_TABLE ),
  1000. STATUS_NONEXISTENT_EA_ENTRY );
  1001. //
  1002. // Check if the specifific handle is currently being used.
  1003. //
  1004. EaOffsetCluster = *((PUSHORT) EaOffsetRange.Data
  1005. + (EaHandle & (MAX_EA_OFFSET_INDEX - 1)));
  1006. if (EaOffsetCluster == UNUSED_EA_HANDLE) {
  1007. DebugTrace(0, Dbg, "FatReadEaSet: Ea handle is unused\n", 0);
  1008. FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
  1009. }
  1010. //
  1011. // Compute the file offset for the Ea data.
  1012. //
  1013. EaSetVbo = (EaHeader->EaBaseTable[EaHandle >> 7] + EaOffsetCluster)
  1014. << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1015. //
  1016. // Unpin the file header and offset table.
  1017. //
  1018. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  1019. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  1020. //
  1021. // Pin the ea set.
  1022. //
  1023. FatPinEaRange( IrpContext,
  1024. Vcb->VirtualEaFile,
  1025. Vcb->EaFcb,
  1026. EaSetRange,
  1027. EaSetVbo,
  1028. BytesPerCluster,
  1029. STATUS_DATA_ERROR );
  1030. //
  1031. // Verify that the Ea set is valid and belongs to this index.
  1032. // Raise STATUS_DATA_ERROR if there is a data conflict.
  1033. //
  1034. EaSet = (PEA_SET_HEADER) EaSetRange->Data;
  1035. if (EaSet->Signature != EA_SET_SIGNATURE
  1036. || EaSet->OwnEaHandle != EaHandle ) {
  1037. DebugTrace(0, Dbg, "FatReadEaSet: Ea set header is corrupt\n", 0);
  1038. FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
  1039. }
  1040. //
  1041. // At this point we have pinned a single cluster of Ea data. If
  1042. // this represents the entire Ea data for the Ea index, we are
  1043. // done. Otherwise we need to check on the entire size of
  1044. // of the Ea set header and whether it is contained in the allocated
  1045. // size of the Ea virtual file. At that point we can unpin
  1046. // the partial Ea set header and repin the entire header.
  1047. //
  1048. CbList = GetcbList( EaSet );
  1049. if (ReturnEntireSet
  1050. && CbList > BytesPerCluster ) {
  1051. //
  1052. // Round up to the cluster size.
  1053. //
  1054. CbList = (CbList + EA_CBLIST_OFFSET + BytesPerCluster - 1)
  1055. & ~(BytesPerCluster - 1);
  1056. FatUnpinEaRange( IrpContext, EaSetRange );
  1057. RtlZeroMemory( EaSetRange, sizeof( EA_RANGE ));
  1058. FatPinEaRange( IrpContext,
  1059. Vcb->VirtualEaFile,
  1060. Vcb->EaFcb,
  1061. EaSetRange,
  1062. EaSetVbo,
  1063. CbList,
  1064. STATUS_DATA_ERROR );
  1065. }
  1066. } finally {
  1067. DebugUnwind( FatReadEaSet );
  1068. //
  1069. // Unpin the Ea base and offset tables if locked down.
  1070. //
  1071. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  1072. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  1073. DebugTrace(-1, Dbg, "FatReadEaSet: Exit\n", 0);
  1074. }
  1075. return;
  1076. }
  1077. VOID
  1078. FatDeleteEaSet (
  1079. IN PIRP_CONTEXT IrpContext,
  1080. IN PVCB Vcb,
  1081. IN PBCB EaBcb,
  1082. OUT PDIRENT EaDirent,
  1083. IN USHORT EaHandle,
  1084. IN POEM_STRING FileName
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. This routines clips the Ea set for a particular index out of the
  1089. Ea file for a volume. The index is verified as belonging to a valid
  1090. handle. The clusters are removed and the Ea stream file along with
  1091. the Ea base and offset files are updated.
  1092. The caller of this function will have verified that the Ea file
  1093. exists and that the Vcb field points to an initialized cache file.
  1094. The caller will already have gained exclusive access to the
  1095. EaFcb.
  1096. Arguments:
  1097. Vcb - Supplies the Vcb for the volume.
  1098. VirtualEeFile - Pointer to the file object for the virtual Ea file.
  1099. EaFcb - Supplies the pointer to the Fcb for the Ea file.
  1100. EaBcb - Supplies a pointer to the Bcb for the Ea dirent.
  1101. EaDirent - Supplies a pointer to the dirent for the Ea file.
  1102. EaHandle - Supplies the handle for the Ea's to read.
  1103. FileName - Name of the file whose Ea's are being read.
  1104. Return Value:
  1105. None.
  1106. --*/
  1107. {
  1108. ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1109. ULONG CbList;
  1110. LARGE_INTEGER FileOffset;
  1111. LARGE_MCB DataMcb;
  1112. BOOLEAN UnwindInitializeDataMcb = FALSE;
  1113. BOOLEAN UnwindSplitData = FALSE;
  1114. LARGE_MCB TailMcb;
  1115. BOOLEAN UnwindInitializeTailMcb = FALSE;
  1116. BOOLEAN UnwindSplitTail = FALSE;
  1117. BOOLEAN UnwindMergeTail = FALSE;
  1118. BOOLEAN UnwindModifiedEaHeader = FALSE;
  1119. BOOLEAN UnwindCacheValues = FALSE;
  1120. ULONG UnwindPrevFileSize = 0;
  1121. ULONG EaOffsetVbo;
  1122. USHORT EaOffsetIndex;
  1123. EA_RANGE EaOffsetRange;
  1124. USHORT EaOffsetCluster;
  1125. PFILE_OBJECT VirtualEaFile = Vcb->VirtualEaFile;
  1126. PFCB EaFcb = Vcb->EaFcb;
  1127. EA_RANGE EaHeaderRange;
  1128. PEA_FILE_HEADER EaHeader;
  1129. USHORT EaHeaderBaseIndex;
  1130. ULONG EaSetVbo;
  1131. ULONG EaSetLength;
  1132. EA_RANGE EaSetRange;
  1133. PEA_SET_HEADER EaSet;
  1134. USHORT EaSetClusterCount;
  1135. //
  1136. // Verify that the Ea index has a legal value. Raise status
  1137. // STATUS_INVALID_HANDLE if illegal.
  1138. //
  1139. if (EaHandle < MIN_EA_HANDLE
  1140. || EaHandle > MAX_EA_HANDLE) {
  1141. DebugTrace(-1, Dbg, "FatDeleteEaSet: Illegal handle value\n", 0);
  1142. FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
  1143. }
  1144. //
  1145. // Verify that the virtual Ea file is large enough for us to read
  1146. // the EaOffet table for this index.
  1147. //
  1148. EaOffsetVbo = sizeof( EA_FILE_HEADER ) + ((EaHandle >> 7) << 8);
  1149. //
  1150. // Zero the Ea range structures.
  1151. //
  1152. RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
  1153. RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
  1154. RtlZeroMemory( &EaSetRange, sizeof( EA_RANGE ));
  1155. //
  1156. // Use a try to facilitate cleanup.
  1157. //
  1158. try {
  1159. //
  1160. // Pin down the EA file header.
  1161. //
  1162. FatPinEaRange( IrpContext,
  1163. VirtualEaFile,
  1164. EaFcb,
  1165. &EaHeaderRange,
  1166. 0,
  1167. sizeof( EA_FILE_HEADER ),
  1168. STATUS_NONEXISTENT_EA_ENTRY );
  1169. EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
  1170. //
  1171. // Pin down the Ea offset table for the particular index.
  1172. //
  1173. FatPinEaRange( IrpContext,
  1174. VirtualEaFile,
  1175. EaFcb,
  1176. &EaOffsetRange,
  1177. EaOffsetVbo,
  1178. sizeof( EA_OFF_TABLE ),
  1179. STATUS_NONEXISTENT_EA_ENTRY );
  1180. //
  1181. // Check if the specifific handle is currently being used.
  1182. //
  1183. EaOffsetIndex = EaHandle & (MAX_EA_OFFSET_INDEX - 1);
  1184. EaOffsetCluster = *((PUSHORT) EaOffsetRange.Data + EaOffsetIndex);
  1185. if (EaOffsetCluster == UNUSED_EA_HANDLE) {
  1186. DebugTrace(0, Dbg, "FatReadEaSet: Ea handle is unused\n", 0);
  1187. FatRaiseStatus( IrpContext, STATUS_NONEXISTENT_EA_ENTRY );
  1188. }
  1189. //
  1190. // Compute the file offset for the Ea data.
  1191. //
  1192. EaHeaderBaseIndex = EaHandle >> 7;
  1193. EaSetVbo = (EaHeader->EaBaseTable[EaHeaderBaseIndex] + EaOffsetCluster)
  1194. << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1195. //
  1196. // Unpin the file header and offset table.
  1197. //
  1198. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  1199. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  1200. //
  1201. // Try to pin the requested Ea set.
  1202. //
  1203. FatPinEaRange( IrpContext,
  1204. VirtualEaFile,
  1205. EaFcb,
  1206. &EaSetRange,
  1207. EaSetVbo,
  1208. BytesPerCluster,
  1209. STATUS_DATA_ERROR );
  1210. EaSet = (PEA_SET_HEADER) EaSetRange.Data;
  1211. if (EaSet->Signature != EA_SET_SIGNATURE
  1212. || EaSet->OwnEaHandle != EaHandle ) {
  1213. DebugTrace(0, Dbg, "FatReadEaSet: Ea set header is corrupt\n", 0);
  1214. FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
  1215. }
  1216. //
  1217. // At this point we have pinned a single cluster of Ea data. If
  1218. // this represents the entire Ea data for the Ea index, we know
  1219. // the number of clusters to remove. Otherwise we need to check
  1220. // on the entire size of the Ea set header and whether it is
  1221. // contained in the allocated size of the Ea virtual file. At
  1222. // that point we unpin the partial Ea set header and remember the
  1223. // starting cluster offset and number of clusters in both cluster
  1224. // and Vbo formats.
  1225. //
  1226. // At that point the following variables have the described
  1227. // values.
  1228. //
  1229. // EaSetVbo - Vbo to start splice at.
  1230. // EaSetLength - Number of bytes to splice.
  1231. // EaSetClusterCount - Number of clusters to splice.
  1232. //
  1233. CbList = GetcbList( EaSet );
  1234. EaSetClusterCount = (USHORT) ((CbList + EA_CBLIST_OFFSET + BytesPerCluster - 1)
  1235. >> Vcb->AllocationSupport.LogOfBytesPerCluster);
  1236. EaSetLength = EaSetClusterCount << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1237. if (EaSetLength > BytesPerCluster) {
  1238. if (EaFcb->Header.FileSize.LowPart - EaSetVbo < EaSetLength) {
  1239. DebugTrace(0, Dbg, "FatDeleteEaSet: Full Ea set not contained in file\n", 0);
  1240. FatRaiseStatus( IrpContext, STATUS_DATA_ERROR );
  1241. }
  1242. }
  1243. FatUnpinEaRange( IrpContext, &EaSetRange );
  1244. //
  1245. // Update the cache manager for this file. This is done by
  1246. // truncating to the point where the data was spliced and
  1247. // reinitializing with the modified size of the file.
  1248. //
  1249. // NOTE: Even if the all the EA's are removed the Ea file will
  1250. // always exist and the header area will never shrink.
  1251. //
  1252. FileOffset.LowPart = EaSetVbo;
  1253. FileOffset.HighPart = 0;
  1254. //
  1255. // Round the cache map down to a system page boundary.
  1256. //
  1257. FileOffset.LowPart &= ~(PAGE_SIZE - 1);
  1258. //
  1259. // Make sure all the data gets out to the disk.
  1260. //
  1261. {
  1262. IO_STATUS_BLOCK Iosb;
  1263. ULONG PurgeCount = 5;
  1264. while (--PurgeCount) {
  1265. Iosb.Status = STATUS_SUCCESS;
  1266. CcFlushCache( VirtualEaFile->SectionObjectPointer,
  1267. NULL,
  1268. 0,
  1269. &Iosb );
  1270. ASSERT( Iosb.Status == STATUS_SUCCESS );
  1271. //
  1272. // We do not have to worry about a lazy writer firing in parallel
  1273. // with our CcFlushCache since we have the EaFcb exclusive. Thus
  1274. // we know all data is out.
  1275. //
  1276. //
  1277. // We throw the unwanted pages out of the cache and then
  1278. // truncate the Ea File for the new size.
  1279. //
  1280. if (CcPurgeCacheSection( VirtualEaFile->SectionObjectPointer,
  1281. &FileOffset,
  1282. 0,
  1283. FALSE )) {
  1284. break;
  1285. }
  1286. }
  1287. if (!PurgeCount) {
  1288. FatRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION );
  1289. }
  1290. }
  1291. FileOffset.LowPart = EaFcb->Header.FileSize.LowPart - EaSetLength;
  1292. //
  1293. // Perform the splice operation on the FAT chain. This is done
  1294. // by splitting the target clusters out and merging the remaining
  1295. // clusters around them. We can ignore the return value from
  1296. // the merge and splice functions because we are guaranteed
  1297. // to be able to block.
  1298. //
  1299. {
  1300. FsRtlInitializeLargeMcb( &DataMcb, PagedPool );
  1301. UnwindInitializeDataMcb = TRUE;
  1302. FatSplitAllocation( IrpContext,
  1303. Vcb,
  1304. &EaFcb->Mcb,
  1305. EaSetVbo,
  1306. &DataMcb );
  1307. UnwindSplitData = TRUE;
  1308. if (EaSetLength + EaSetVbo != EaFcb->Header.FileSize.LowPart) {
  1309. FsRtlInitializeLargeMcb( &TailMcb, PagedPool );
  1310. UnwindInitializeTailMcb = TRUE;
  1311. FatSplitAllocation( IrpContext,
  1312. Vcb,
  1313. &DataMcb,
  1314. EaSetLength,
  1315. &TailMcb );
  1316. UnwindSplitTail = TRUE;
  1317. FatMergeAllocation( IrpContext,
  1318. Vcb,
  1319. &EaFcb->Mcb,
  1320. &TailMcb );
  1321. UnwindMergeTail = TRUE;
  1322. }
  1323. }
  1324. //
  1325. // Update the Fcb for the Ea file
  1326. //
  1327. UnwindPrevFileSize = EaFcb->Header.FileSize.LowPart;
  1328. (VOID)ExAcquireResourceExclusiveLite( EaFcb->Header.PagingIoResource,
  1329. TRUE );
  1330. EaFcb->Header.FileSize.LowPart = EaFcb->Header.FileSize.LowPart - EaSetLength;
  1331. EaFcb->Header.AllocationSize = EaFcb->Header.FileSize;
  1332. CcSetFileSizes( VirtualEaFile,
  1333. (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
  1334. ExReleaseResourceLite( EaFcb->Header.PagingIoResource );
  1335. UnwindCacheValues = TRUE;
  1336. EaDirent->FileSize = EaFcb->Header.FileSize.LowPart;
  1337. FatSetDirtyBcb( IrpContext, EaBcb, Vcb, TRUE );
  1338. //
  1339. // Update the Ea base and offset tables. For the Ea base table,
  1340. // all subsequent index values must be decremented by the number
  1341. // of clusters removed.
  1342. //
  1343. // For the entries in the relevant Ea offset table, all entries
  1344. // after this index must also be decreased by the number of
  1345. // clusters removed.
  1346. //
  1347. //
  1348. // Pin down the EA file header.
  1349. //
  1350. RtlZeroMemory( &EaHeaderRange,
  1351. sizeof( EA_RANGE ));
  1352. FatPinEaRange( IrpContext,
  1353. VirtualEaFile,
  1354. EaFcb,
  1355. &EaHeaderRange,
  1356. 0,
  1357. sizeof( EA_FILE_HEADER ),
  1358. STATUS_NONEXISTENT_EA_ENTRY );
  1359. EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
  1360. //
  1361. // Pin down the Ea offset table for the particular index.
  1362. //
  1363. RtlZeroMemory( &EaOffsetRange,
  1364. sizeof( EA_RANGE ));
  1365. FatPinEaRange( IrpContext,
  1366. VirtualEaFile,
  1367. EaFcb,
  1368. &EaOffsetRange,
  1369. EaOffsetVbo,
  1370. sizeof( EA_OFF_TABLE ),
  1371. STATUS_NONEXISTENT_EA_ENTRY );
  1372. {
  1373. ULONG Count;
  1374. PUSHORT NextEaIndex;
  1375. Count = MAX_EA_BASE_INDEX - EaHeaderBaseIndex - 1;
  1376. NextEaIndex = &EaHeader->EaBaseTable[EaHeaderBaseIndex + 1];
  1377. while (Count--) {
  1378. *(NextEaIndex++) -= EaSetClusterCount;
  1379. }
  1380. FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaHeaderRange );
  1381. Count = MAX_EA_OFFSET_INDEX - EaOffsetIndex - 1;
  1382. NextEaIndex = (PUSHORT) EaOffsetRange.Data + EaOffsetIndex;
  1383. *(NextEaIndex++) = UNUSED_EA_HANDLE;
  1384. while (Count--) {
  1385. if (*NextEaIndex != UNUSED_EA_HANDLE) {
  1386. *NextEaIndex -= EaSetClusterCount;
  1387. }
  1388. NextEaIndex++;
  1389. }
  1390. FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaOffsetRange );
  1391. }
  1392. UnwindModifiedEaHeader = TRUE;
  1393. //
  1394. // Deallocate the ea set removed
  1395. //
  1396. FatDeallocateDiskSpace( IrpContext,
  1397. Vcb,
  1398. &DataMcb );
  1399. } finally {
  1400. DebugUnwind( FatDeleteEaSet );
  1401. //
  1402. // Restore file if abnormal termination.
  1403. //
  1404. // If we have modified the ea file header we ignore this
  1405. // error. Otherwise we walk through the state variables.
  1406. //
  1407. if (AbnormalTermination()
  1408. && !UnwindModifiedEaHeader) {
  1409. //
  1410. // If we modified the Ea dirent or Fcb, recover the previous
  1411. // values.
  1412. //
  1413. if (UnwindPrevFileSize) {
  1414. EaFcb->Header.FileSize.LowPart = UnwindPrevFileSize;
  1415. EaFcb->Header.AllocationSize.LowPart = UnwindPrevFileSize;
  1416. EaDirent->FileSize = UnwindPrevFileSize;
  1417. if (UnwindCacheValues) {
  1418. CcSetFileSizes( VirtualEaFile,
  1419. (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
  1420. }
  1421. }
  1422. //
  1423. // If we merged the tail with the
  1424. // ea file header. We split it out
  1425. // again.
  1426. //
  1427. if (UnwindMergeTail) {
  1428. FatSplitAllocation( IrpContext,
  1429. Vcb,
  1430. &EaFcb->Mcb,
  1431. EaSetVbo,
  1432. &TailMcb );
  1433. }
  1434. //
  1435. // If we split the tail off we merge the tail back
  1436. // with the ea data to remove.
  1437. //
  1438. if (UnwindSplitTail) {
  1439. FatMergeAllocation( IrpContext,
  1440. Vcb,
  1441. &DataMcb,
  1442. &TailMcb );
  1443. }
  1444. //
  1445. // If the ea set has been split out, we merge that
  1446. // cluster string back in the file. Otherwise we
  1447. // simply uninitialize the local Mcb.
  1448. //
  1449. if (UnwindSplitData) {
  1450. FatMergeAllocation( IrpContext,
  1451. Vcb,
  1452. &EaFcb->Mcb,
  1453. &DataMcb );
  1454. }
  1455. }
  1456. //
  1457. // Unpin any Bcb's still active.
  1458. //
  1459. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  1460. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  1461. FatUnpinEaRange( IrpContext, &EaSetRange );
  1462. //
  1463. // Uninitialize any initialized Mcbs
  1464. //
  1465. if (UnwindInitializeDataMcb) {
  1466. FsRtlUninitializeLargeMcb( &DataMcb );
  1467. }
  1468. if (UnwindInitializeTailMcb) {
  1469. FsRtlUninitializeLargeMcb( &TailMcb );
  1470. }
  1471. DebugTrace(-1, Dbg, "FatDeleteEaSet -> Exit\n", 0);
  1472. }
  1473. return;
  1474. }
  1475. VOID
  1476. FatAddEaSet (
  1477. IN PIRP_CONTEXT IrpContext,
  1478. IN PVCB Vcb,
  1479. IN ULONG EaSetLength,
  1480. IN PBCB EaBcb,
  1481. OUT PDIRENT EaDirent,
  1482. OUT PUSHORT EaHandle,
  1483. OUT PEA_RANGE EaSetRange
  1484. )
  1485. /*++
  1486. Routine Description:
  1487. This routine will add the necessary clusters to support a new
  1488. Ea set of the given size. This is done by splicing a chain of
  1489. clusters into the existing Ea file. An Ea index is assigned to
  1490. this new chain and the Ea base and offset tables are updated to
  1491. include this new handle. This routine also pins the added
  1492. clusters and returns their address and a Bcb.
  1493. The caller of this function will have verified that the Ea file
  1494. exists and that the Vcb field points to an initialized cache file.
  1495. The caller will already have gained exclusive access to the
  1496. EaFcb.
  1497. Arguments:
  1498. Vcb - Supplies the Vcb to fill in.
  1499. EaSetLength - The number of bytes needed to contain the Ea set. This
  1500. routine will round this up the next cluster size.
  1501. EaBcb - Supplies a pointer to the Bcb for the Ea dirent.
  1502. EaDirent - Supplies a pointer to the dirent for the Ea file.
  1503. EaHandle - Supplies the address to store the ea index generated here.
  1504. EaSetRange - This is the structure that describes new range in the Ea file.
  1505. Return Value:
  1506. None.
  1507. --*/
  1508. {
  1509. ULONG BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1510. EA_RANGE EaHeaderRange;
  1511. USHORT EaHeaderIndex;
  1512. PEA_FILE_HEADER EaHeader;
  1513. EA_RANGE EaOffsetRange;
  1514. ULONG EaNewOffsetVbo;
  1515. USHORT EaOffsetIndex;
  1516. ULONG EaOffsetTableSize;
  1517. PUSHORT EaOffsetTable;
  1518. ULONG EaSetClusterOffset;
  1519. ULONG EaSetVbo;
  1520. USHORT EaSetClusterCount;
  1521. PEA_SET_HEADER EaSet;
  1522. PFILE_OBJECT VirtualEaFile = Vcb->VirtualEaFile;
  1523. PFCB EaFcb = Vcb->EaFcb;
  1524. LARGE_MCB EaSetMcb;
  1525. BOOLEAN UnwindInitializedEaSetMcb = FALSE;
  1526. BOOLEAN UnwindAllocatedNewAllocation = FALSE;
  1527. BOOLEAN UnwindMergedNewEaSet = FALSE;
  1528. LARGE_MCB EaOffsetMcb;
  1529. BOOLEAN UnwindInitializedOffsetMcb = FALSE;
  1530. BOOLEAN UnwindSplitNewAllocation = FALSE;
  1531. BOOLEAN UnwindMergedNewOffset = FALSE;
  1532. LARGE_MCB EaTailMcb;
  1533. BOOLEAN UnwindInitializedTailMcb = FALSE;
  1534. BOOLEAN UnwindSplitTail = FALSE;
  1535. BOOLEAN UnwindMergedTail = FALSE;
  1536. LARGE_MCB EaInitialEaMcb;
  1537. BOOLEAN UnwindInitializedInitialEaMcb = FALSE;
  1538. BOOLEAN UnwindSplitInitialEa = FALSE;
  1539. BOOLEAN UnwindMergedInitialEa = FALSE;
  1540. USHORT NewEaIndex;
  1541. PUSHORT NextEaOffset;
  1542. ULONG NewAllocation;
  1543. LARGE_INTEGER FileOffset;
  1544. ULONG Count;
  1545. ULONG UnwindPrevFileSize = 0;
  1546. BOOLEAN UnwindCacheValues = FALSE;
  1547. BOOLEAN TailExists = FALSE;
  1548. BOOLEAN AddedOffsetTableCluster = FALSE;
  1549. BOOLEAN UnwindPurgeCacheMap = FALSE;
  1550. DebugTrace(+1, Dbg, "FatAddEaSet\n", 0);
  1551. DebugTrace( 0, Dbg, " Vcb = %8lx\n", Vcb);
  1552. DebugTrace( 0, Dbg, " EaSetLength = %ul\n", EaSetLength );
  1553. //
  1554. // Zero the Ea range structures.
  1555. //
  1556. RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
  1557. RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
  1558. //
  1559. // Use a try statement to facilitate cleanup.
  1560. //
  1561. try {
  1562. //
  1563. // Pin down the file header.
  1564. //
  1565. FatPinEaRange( IrpContext,
  1566. VirtualEaFile,
  1567. EaFcb,
  1568. &EaHeaderRange,
  1569. 0,
  1570. sizeof( EA_FILE_HEADER ),
  1571. STATUS_DATA_ERROR );
  1572. EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
  1573. //
  1574. // Compute the size of the offset table.
  1575. //
  1576. EaNewOffsetVbo = EaHeader->EaBaseTable[0] << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1577. EaOffsetTableSize = EaNewOffsetVbo - sizeof( EA_FILE_HEADER );
  1578. //
  1579. // Pin down the entire offset table.
  1580. //
  1581. FatPinEaRange( IrpContext,
  1582. VirtualEaFile,
  1583. EaFcb,
  1584. &EaOffsetRange,
  1585. sizeof( EA_FILE_HEADER ),
  1586. EaOffsetTableSize,
  1587. STATUS_DATA_ERROR );
  1588. //
  1589. // We now look for a valid handle out of the existing offset table.
  1590. // We start at the last entry and walk backwards. We stop at the
  1591. // first unused handle which is preceded by a used handle (or handle
  1592. // 1).
  1593. //
  1594. // As we walk backwards, we need to remember the file offset of the
  1595. // cluster which will follow the clusters we add. We initially
  1596. // remember the end of the file. If the end of the offset table
  1597. // consists of a string of used handles, we remember the offset of
  1598. // the handle prior to the transition from used to unused handles.
  1599. //
  1600. EaSetClusterOffset = EaFcb->Header.FileSize.LowPart
  1601. >> Vcb->AllocationSupport.LogOfBytesPerCluster;
  1602. NewEaIndex = (USHORT) ((EaOffsetTableSize >> 1) - 1);
  1603. NextEaOffset = (PUSHORT) EaOffsetRange.Data + NewEaIndex;
  1604. //
  1605. // Walk through the used handles at the end of the offset table.
  1606. //
  1607. if (*NextEaOffset != UNUSED_EA_HANDLE) {
  1608. while (NewEaIndex != 0) {
  1609. if (*(NextEaOffset - 1) == UNUSED_EA_HANDLE) {
  1610. //
  1611. // If the handle is 1, we take no action. Otherwise
  1612. // we save the cluster offset of the current handle
  1613. // knowing we will use a previous handle and insert
  1614. // a chain of clusters.
  1615. //
  1616. if (NewEaIndex != 1) {
  1617. EaSetClusterOffset = *NextEaOffset
  1618. + EaHeader->EaBaseTable[NewEaIndex >> 7];
  1619. TailExists = TRUE;
  1620. }
  1621. NewEaIndex--;
  1622. NextEaOffset--;
  1623. break;
  1624. }
  1625. NewEaIndex--;
  1626. NextEaOffset--;
  1627. }
  1628. }
  1629. //
  1630. // Walk through looking for the first unused handle in a string
  1631. // of unused handles.
  1632. //
  1633. while (NewEaIndex) {
  1634. if (*(NextEaOffset - 1) != UNUSED_EA_HANDLE) {
  1635. break;
  1636. }
  1637. NextEaOffset--;
  1638. NewEaIndex--;
  1639. }
  1640. //
  1641. // If the handle is zero, we do a special test to see if handle 1
  1642. // is available. Otherwise we will use the first handle of a new
  1643. // cluster. A non-zero handle now indicates that a handle was found
  1644. // in an existing offset table cluster.
  1645. //
  1646. if (NewEaIndex == 0) {
  1647. if (*(NextEaOffset + 1) == UNUSED_EA_HANDLE) {
  1648. NewEaIndex = 1;
  1649. } else {
  1650. NewEaIndex = (USHORT) EaOffsetTableSize >> 1;
  1651. AddedOffsetTableCluster = TRUE;
  1652. }
  1653. }
  1654. //
  1655. // If the Ea index is outside the legal range then raise an
  1656. // exception.
  1657. //
  1658. if (NewEaIndex > MAX_EA_HANDLE) {
  1659. DebugTrace(-1, Dbg,
  1660. "FatAddEaSet: Illegal handle value for new handle\n", 0);
  1661. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1662. }
  1663. //
  1664. // Compute the base and offset indexes.
  1665. //
  1666. EaHeaderIndex = NewEaIndex >> 7;
  1667. EaOffsetIndex = NewEaIndex & (MAX_EA_OFFSET_INDEX - 1);
  1668. //
  1669. // Compute the byte offset of the new ea data in the file.
  1670. //
  1671. EaSetVbo = EaSetClusterOffset << Vcb->AllocationSupport.LogOfBytesPerCluster;
  1672. //
  1673. // Allocate all the required disk space together to insure this
  1674. // operation is atomic. We don't want to allocate one block
  1675. // of disk space and then fail on a second allocation.
  1676. //
  1677. EaSetLength = (EaSetLength + BytesPerCluster - 1)
  1678. & ~(BytesPerCluster - 1);
  1679. NewAllocation = EaSetLength
  1680. + (AddedOffsetTableCluster ? BytesPerCluster : 0);
  1681. //
  1682. // Verify that adding these clusters will not grow the Ea file
  1683. // beyond its legal value. The maximum number of clusters is
  1684. // 2^16 since the Ea sets are referenced by a 16 bit cluster
  1685. // offset value.
  1686. //
  1687. if ((ULONG) ((0x0000FFFF << Vcb->AllocationSupport.LogOfBytesPerCluster)
  1688. - EaFcb->Header.FileSize.LowPart)
  1689. < NewAllocation) {
  1690. DebugTrace(-1, Dbg,
  1691. "FatAddEaSet: New Ea file size is too large\n", 0);
  1692. FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1693. }
  1694. FsRtlInitializeLargeMcb( &EaSetMcb, PagedPool );
  1695. UnwindInitializedEaSetMcb = TRUE;
  1696. FatAllocateDiskSpace( IrpContext,
  1697. Vcb,
  1698. 0,
  1699. &NewAllocation,
  1700. FALSE,
  1701. &EaSetMcb );
  1702. UnwindAllocatedNewAllocation = TRUE;
  1703. EaSetClusterCount = (USHORT) (EaSetLength >> Vcb->AllocationSupport.LogOfBytesPerCluster);
  1704. if (AddedOffsetTableCluster) {
  1705. FsRtlInitializeLargeMcb( &EaOffsetMcb, PagedPool );
  1706. UnwindInitializedOffsetMcb = TRUE;
  1707. FatSplitAllocation( IrpContext,
  1708. Vcb,
  1709. &EaSetMcb,
  1710. EaSetLength,
  1711. &EaOffsetMcb );
  1712. UnwindSplitNewAllocation = TRUE;
  1713. }
  1714. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  1715. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  1716. if (AddedOffsetTableCluster) {
  1717. FileOffset.LowPart = EaNewOffsetVbo;
  1718. } else {
  1719. FileOffset.LowPart = EaSetVbo;
  1720. }
  1721. FileOffset.HighPart = 0;
  1722. //
  1723. // Round the cache map down to a system page boundary.
  1724. //
  1725. FileOffset.LowPart &= ~(PAGE_SIZE - 1);
  1726. {
  1727. IO_STATUS_BLOCK Iosb;
  1728. ULONG PurgeCount = 5;
  1729. while (--PurgeCount) {
  1730. Iosb.Status = STATUS_SUCCESS;
  1731. CcFlushCache( VirtualEaFile->SectionObjectPointer,
  1732. NULL,
  1733. 0,
  1734. &Iosb );
  1735. ASSERT( Iosb.Status == STATUS_SUCCESS );
  1736. //
  1737. // We do not have to worry about a lazy writer firing in parallel
  1738. // with our CcFlushCache since we have the EaFcb exclusive. Thus
  1739. // we know all data is out.
  1740. //
  1741. //
  1742. // We throw the unwanted pages out of the cache and then
  1743. // truncate the Ea File for the new size.
  1744. //
  1745. //
  1746. if (CcPurgeCacheSection( VirtualEaFile->SectionObjectPointer,
  1747. &FileOffset,
  1748. 0,
  1749. FALSE )) {
  1750. break;
  1751. }
  1752. }
  1753. if (!PurgeCount) {
  1754. FatRaiseStatus( IrpContext, STATUS_UNABLE_TO_DELETE_SECTION );
  1755. }
  1756. }
  1757. UnwindPurgeCacheMap = TRUE;
  1758. FileOffset.LowPart = EaFcb->Header.FileSize.LowPart + NewAllocation;
  1759. //
  1760. // If there is a tail to the file, then we initialize an Mcb
  1761. // for the file section and split the tail from the file.
  1762. //
  1763. if (TailExists) {
  1764. FsRtlInitializeLargeMcb( &EaTailMcb, PagedPool );
  1765. UnwindInitializedTailMcb = TRUE;
  1766. FatSplitAllocation( IrpContext,
  1767. Vcb,
  1768. &EaFcb->Mcb,
  1769. EaSetVbo,
  1770. &EaTailMcb );
  1771. UnwindSplitTail = TRUE;
  1772. }
  1773. //
  1774. // If there is an initial section of ea data, we initialize an
  1775. // Mcb for that section.
  1776. //
  1777. if (AddedOffsetTableCluster
  1778. && EaSetVbo != EaNewOffsetVbo) {
  1779. FsRtlInitializeLargeMcb( &EaInitialEaMcb, PagedPool );
  1780. UnwindInitializedInitialEaMcb = TRUE;
  1781. FatSplitAllocation( IrpContext,
  1782. Vcb,
  1783. &EaFcb->Mcb,
  1784. EaNewOffsetVbo,
  1785. &EaInitialEaMcb );
  1786. UnwindSplitInitialEa = TRUE;
  1787. }
  1788. //
  1789. // We have now split the new file allocation into the new
  1790. // ea set and possibly a new offset table.
  1791. //
  1792. // We have also split the existing file data into a file
  1793. // header, an initial section of ea data and the tail of the
  1794. // file. These last 2 may not exist.
  1795. //
  1796. // Each section is described by an Mcb.
  1797. //
  1798. //
  1799. // Merge the new offset information if it exists.
  1800. //
  1801. if (AddedOffsetTableCluster) {
  1802. FatMergeAllocation( IrpContext,
  1803. Vcb,
  1804. &EaFcb->Mcb,
  1805. &EaOffsetMcb );
  1806. FsRtlUninitializeLargeMcb( &EaOffsetMcb );
  1807. FsRtlInitializeLargeMcb( &EaOffsetMcb, PagedPool );
  1808. UnwindMergedNewOffset = TRUE;
  1809. }
  1810. //
  1811. // Merge the existing initial ea data if it exists.
  1812. //
  1813. if (UnwindInitializedInitialEaMcb) {
  1814. FatMergeAllocation( IrpContext,
  1815. Vcb,
  1816. &EaFcb->Mcb,
  1817. &EaInitialEaMcb );
  1818. FsRtlUninitializeLargeMcb( &EaInitialEaMcb );
  1819. FsRtlInitializeLargeMcb( &EaInitialEaMcb, PagedPool );
  1820. UnwindMergedInitialEa = TRUE;
  1821. }
  1822. //
  1823. // We modify the offset of the new ea set by one cluster if
  1824. // we added one to the offset table.
  1825. //
  1826. if (AddedOffsetTableCluster) {
  1827. EaSetClusterOffset += 1;
  1828. EaSetVbo += BytesPerCluster;
  1829. }
  1830. //
  1831. // Merge the new ea set.
  1832. //
  1833. FatMergeAllocation( IrpContext,
  1834. Vcb,
  1835. &EaFcb->Mcb,
  1836. &EaSetMcb );
  1837. FsRtlUninitializeLargeMcb( &EaSetMcb );
  1838. FsRtlInitializeLargeMcb( &EaSetMcb, PagedPool );
  1839. UnwindMergedNewEaSet = TRUE;
  1840. //
  1841. // Merge the tail if it exists.
  1842. //
  1843. if (UnwindInitializedTailMcb) {
  1844. FatMergeAllocation( IrpContext,
  1845. Vcb,
  1846. &EaFcb->Mcb,
  1847. &EaTailMcb );
  1848. FsRtlUninitializeLargeMcb( &EaTailMcb );
  1849. FsRtlInitializeLargeMcb( &EaTailMcb, PagedPool );
  1850. UnwindMergedTail = TRUE;
  1851. }
  1852. //
  1853. // If we added a new cluster for the offset table, we need to
  1854. // lock the entire cluster down and initialize all the handles to
  1855. // the unused state except the first one.
  1856. //
  1857. //
  1858. // Update the Fcb information.
  1859. //
  1860. UnwindPrevFileSize = EaFcb->Header.FileSize.LowPart;
  1861. EaFcb->Header.FileSize.LowPart += NewAllocation;
  1862. EaFcb->Header.AllocationSize = EaFcb->Header.FileSize;
  1863. EaDirent->FileSize = EaFcb->Header.FileSize.LowPart;
  1864. FatSetDirtyBcb( IrpContext, EaBcb, Vcb, TRUE );
  1865. //
  1866. // Let Mm and Cc know the new file sizes.
  1867. //
  1868. CcSetFileSizes( VirtualEaFile,
  1869. (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
  1870. UnwindCacheValues = TRUE;
  1871. //
  1872. // Pin down the file header.
  1873. //
  1874. RtlZeroMemory( &EaHeaderRange, sizeof( EA_RANGE ));
  1875. FatPinEaRange( IrpContext,
  1876. VirtualEaFile,
  1877. EaFcb,
  1878. &EaHeaderRange,
  1879. 0,
  1880. sizeof( EA_FILE_HEADER ),
  1881. STATUS_DATA_ERROR );
  1882. EaHeader = (PEA_FILE_HEADER) EaHeaderRange.Data;
  1883. //
  1884. // Pin down the entire offset table.
  1885. //
  1886. RtlZeroMemory( &EaOffsetRange, sizeof( EA_RANGE ));
  1887. FatPinEaRange( IrpContext,
  1888. VirtualEaFile,
  1889. EaFcb,
  1890. &EaOffsetRange,
  1891. sizeof( EA_FILE_HEADER ) + ((NewEaIndex >> 7) << 8),
  1892. sizeof( EA_OFF_TABLE ),
  1893. STATUS_DATA_ERROR );
  1894. EaOffsetTable = (PUSHORT) EaOffsetRange.Data;
  1895. //
  1896. // Pin the Ea set header for the added clusters and initialize
  1897. // the fields of interest. These are the signature field, the
  1898. // owning handle field, the need Ea field and the cbList field.
  1899. // Also mark the data as dirty.
  1900. //
  1901. //
  1902. // Pin the ea set.
  1903. //
  1904. FatPinEaRange( IrpContext,
  1905. VirtualEaFile,
  1906. EaFcb,
  1907. EaSetRange,
  1908. EaSetVbo,
  1909. EaSetLength,
  1910. STATUS_DATA_ERROR );
  1911. EaSet = (PEA_SET_HEADER) EaSetRange->Data;
  1912. EaSet->Signature = EA_SET_SIGNATURE;
  1913. EaSet->OwnEaHandle = NewEaIndex;
  1914. FatMarkEaRangeDirty( IrpContext, VirtualEaFile, EaSetRange );
  1915. //
  1916. // Update the Ea base and offset tables. For the Ea base table,
  1917. // all subsequent index values must be incremented by the number
  1918. // of clusters added.
  1919. //
  1920. // For the entries in the relevant Ea offset table, all entries
  1921. // after this index must also be increased by the number of
  1922. // clusters added.
  1923. //
  1924. // If we added another cluster to the offset table, then we increment
  1925. // all the base table values by 1.
  1926. //
  1927. Count = MAX_EA_BASE_INDEX - EaHeaderIndex - 1;
  1928. NextEaOffset = &EaHeader->EaBaseTable[EaHeaderIndex + 1];
  1929. while (Count--) {
  1930. *(NextEaOffset++) += EaSetClusterCount;
  1931. }
  1932. if (AddedOffsetTableCluster) {
  1933. Count = MAX_EA_BASE_INDEX;
  1934. NextEaOffset = &EaHeader->EaBaseTable[0];
  1935. while (Count--) {
  1936. *(NextEaOffset++) += 1;
  1937. }
  1938. }
  1939. FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaHeaderRange );
  1940. //
  1941. // If we added an offset table cluster, we need to initialize
  1942. // the handles to unused.
  1943. //
  1944. if (AddedOffsetTableCluster) {
  1945. Count = (BytesPerCluster >> 1) - 1;
  1946. NextEaOffset = EaOffsetTable;
  1947. *NextEaOffset++ = 0;
  1948. while (Count--) {
  1949. *NextEaOffset++ = UNUSED_EA_HANDLE;
  1950. }
  1951. }
  1952. //
  1953. // We need to compute the offset of the added Ea set clusters
  1954. // from their base.
  1955. //
  1956. NextEaOffset = EaOffsetTable + EaOffsetIndex;
  1957. *NextEaOffset++ = (USHORT) (EaSetClusterOffset
  1958. - EaHeader->EaBaseTable[EaHeaderIndex]);
  1959. Count = MAX_EA_OFFSET_INDEX - EaOffsetIndex - 1;
  1960. while (Count--) {
  1961. if (*NextEaOffset != UNUSED_EA_HANDLE) {
  1962. *NextEaOffset += EaSetClusterCount;
  1963. }
  1964. NextEaOffset++;
  1965. }
  1966. FatMarkEaRangeDirty( IrpContext, VirtualEaFile, &EaOffsetRange );
  1967. //
  1968. // Update the callers parameters.
  1969. //
  1970. *EaHandle = NewEaIndex;
  1971. DebugTrace(0, Dbg, "FatAddEaSet: Return values\n", 0);
  1972. DebugTrace(0, Dbg, "FatAddEaSet: New Handle -> %x\n",
  1973. *EaHandle);
  1974. } finally {
  1975. DebugUnwind( FatAddEaSet );
  1976. //
  1977. // Handle cleanup for abnormal termination only if we allocated
  1978. // disk space for the new ea set.
  1979. //
  1980. if (AbnormalTermination() && UnwindAllocatedNewAllocation) {
  1981. //
  1982. // If we modified the Ea dirent or Fcb, recover the previous
  1983. // values. Even though we are decreasing FileSize here, we
  1984. // don't need to synchronize to synchronize with paging Io
  1985. // because there was no dirty data generated in the new allocation.
  1986. //
  1987. if (UnwindPrevFileSize) {
  1988. EaFcb->Header.FileSize.LowPart = UnwindPrevFileSize;
  1989. EaFcb->Header.AllocationSize.LowPart = UnwindPrevFileSize;
  1990. EaDirent->FileSize = UnwindPrevFileSize;
  1991. if (UnwindCacheValues) {
  1992. CcSetFileSizes( VirtualEaFile,
  1993. (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize );
  1994. }
  1995. }
  1996. //
  1997. // If we merged the tail then split it off.
  1998. //
  1999. if (UnwindMergedTail) {
  2000. VBO NewTailPosition;
  2001. NewTailPosition = EaSetVbo + EaSetLength;
  2002. FatSplitAllocation( IrpContext,
  2003. Vcb,
  2004. &EaFcb->Mcb,
  2005. NewTailPosition,
  2006. &EaTailMcb );
  2007. }
  2008. //
  2009. // If we merged the new ea data then split it out.
  2010. //
  2011. if (UnwindMergedNewEaSet) {
  2012. FatSplitAllocation( IrpContext,
  2013. Vcb,
  2014. &EaFcb->Mcb,
  2015. EaSetVbo,
  2016. &EaSetMcb );
  2017. }
  2018. //
  2019. // If we merged the initial ea data then split it out.
  2020. //
  2021. if (UnwindMergedInitialEa) {
  2022. FatSplitAllocation( IrpContext,
  2023. Vcb,
  2024. &EaFcb->Mcb,
  2025. EaNewOffsetVbo + BytesPerCluster,
  2026. &EaInitialEaMcb );
  2027. }
  2028. //
  2029. // If we added a new offset cluster, then split it out.
  2030. //
  2031. if (UnwindMergedNewOffset) {
  2032. FatSplitAllocation( IrpContext,
  2033. Vcb,
  2034. &EaFcb->Mcb,
  2035. EaNewOffsetVbo,
  2036. &EaOffsetMcb );
  2037. }
  2038. //
  2039. // If there is an initial ea section prior to the new section, merge
  2040. // it with the rest of the file.
  2041. //
  2042. if (UnwindSplitInitialEa) {
  2043. FatMergeAllocation( IrpContext, Vcb, &EaFcb->Mcb, &EaInitialEaMcb );
  2044. }
  2045. //
  2046. // If there is a file tail split off, merge it with the
  2047. // rest of the file.
  2048. //
  2049. if (UnwindSplitTail) {
  2050. FatMergeAllocation( IrpContext, Vcb, &EaFcb->Mcb, &EaTailMcb );
  2051. }
  2052. //
  2053. // If we modified the cache initialization for the ea file,
  2054. // then throw away the ea file object.
  2055. //
  2056. if (UnwindPurgeCacheMap) {
  2057. Vcb->VirtualEaFile = NULL;
  2058. ObDereferenceObject( VirtualEaFile );
  2059. }
  2060. //
  2061. // If we split the allocation, then deallocate the block for
  2062. // the new offset information.
  2063. //
  2064. if (UnwindSplitNewAllocation) {
  2065. FatDeallocateDiskSpace( IrpContext, Vcb, &EaOffsetMcb );
  2066. }
  2067. //
  2068. // Deallocate the disk space.
  2069. //
  2070. FatDeallocateDiskSpace( IrpContext, Vcb, &EaSetMcb );
  2071. }
  2072. //
  2073. // Unpin the Ea ranges.
  2074. //
  2075. FatUnpinEaRange( IrpContext, &EaHeaderRange );
  2076. FatUnpinEaRange( IrpContext, &EaOffsetRange );
  2077. //
  2078. // Uninitialize any local Mcbs
  2079. //
  2080. if (UnwindInitializedEaSetMcb) {
  2081. FsRtlUninitializeLargeMcb( &EaSetMcb );
  2082. }
  2083. if (UnwindInitializedOffsetMcb) {
  2084. FsRtlUninitializeLargeMcb( &EaOffsetMcb );
  2085. }
  2086. if (UnwindInitializedTailMcb) {
  2087. FsRtlUninitializeLargeMcb( &EaTailMcb );
  2088. }
  2089. if (UnwindInitializedInitialEaMcb) {
  2090. FsRtlUninitializeLargeMcb( &EaInitialEaMcb );
  2091. }
  2092. DebugTrace(-1, Dbg, "FatAddEaSet -> Exit\n", 0);
  2093. }
  2094. return;
  2095. }
  2096. VOID
  2097. FatAppendPackedEa (
  2098. IN PIRP_CONTEXT IrpContext,
  2099. IN OUT PEA_SET_HEADER *EaSetHeader,
  2100. IN OUT PULONG PackedEasLength,
  2101. IN OUT PULONG AllocationLength,
  2102. IN PFILE_FULL_EA_INFORMATION FullEa,
  2103. IN ULONG BytesPerCluster
  2104. )
  2105. /*++
  2106. Routine Description:
  2107. This routine appends a new packed ea onto an existing packed ea list,
  2108. it also will allocate/dealloate pool as necessary to hold the ea list.
  2109. Arguments:
  2110. EaSetHeader - Supplies the address to store the pointer to pool memory
  2111. which contains the Ea list for a file.
  2112. PackedEasLength - Supplies the length of the actual Ea data. The
  2113. new Ea data will be appended at this point.
  2114. AllocationLength - Supplies the allocated length available for Ea
  2115. data.
  2116. FullEa - Supplies a pointer to the new full ea that is to be appended
  2117. (in packed form) to the packed ea list.
  2118. BytesPerCluster - Number of bytes per cluster on this volume.
  2119. NOTE: The EaSetHeader refers to the entire block of Ea data for a
  2120. file. This includes the Ea's and their values as well as the
  2121. header information. The PackedEasLength and AllocationLength
  2122. parameters refer to the name/value pairs only.
  2123. Return Value:
  2124. None.
  2125. --*/
  2126. {
  2127. ULONG PackedEaSize;
  2128. PPACKED_EA ThisPackedEa;
  2129. OEM_STRING EaName;
  2130. DebugTrace(+1, Dbg, "FatAppendPackedEa...\n", 0);
  2131. //
  2132. // As a quick check see if the computed packed ea size plus the
  2133. // current packed ea list size will overflow the buffer. Full Ea and
  2134. // packed Ea only differ by 4 in their size
  2135. //
  2136. PackedEaSize = SizeOfFullEa( FullEa ) - 4;
  2137. if ( PackedEaSize + *PackedEasLength > *AllocationLength ) {
  2138. //
  2139. // We will overflow our current work buffer so allocate a larger
  2140. // one and copy over the current buffer
  2141. //
  2142. PVOID Temp;
  2143. ULONG NewAllocationSize;
  2144. ULONG OldAllocationSize;
  2145. DebugTrace(0, Dbg, "Allocate a new ea list buffer\n", 0);
  2146. //
  2147. // Compute a new size and allocate space. Always increase the
  2148. // allocation in cluster increments.
  2149. //
  2150. NewAllocationSize = (SIZE_OF_EA_SET_HEADER
  2151. + PackedEaSize
  2152. + *PackedEasLength
  2153. + BytesPerCluster - 1)
  2154. & ~(BytesPerCluster - 1);
  2155. Temp = FsRtlAllocatePoolWithTag( PagedPool,
  2156. NewAllocationSize,
  2157. TAG_EA_SET_HEADER );
  2158. //
  2159. // Move over the existing ea list, and deallocate the old one
  2160. //
  2161. RtlCopyMemory( Temp,
  2162. *EaSetHeader,
  2163. OldAllocationSize = *AllocationLength
  2164. + SIZE_OF_EA_SET_HEADER );
  2165. ExFreePool( *EaSetHeader );
  2166. //
  2167. // Set up so we will use the new packed ea list
  2168. //
  2169. *EaSetHeader = Temp;
  2170. //
  2171. // Zero out the added memory.
  2172. //
  2173. RtlZeroMemory( &(*EaSetHeader)->PackedEas[*AllocationLength],
  2174. NewAllocationSize - OldAllocationSize );
  2175. *AllocationLength = NewAllocationSize - SIZE_OF_EA_SET_HEADER;
  2176. }
  2177. //
  2178. // Determine if we need to increment our need ea changes count
  2179. //
  2180. if ( FlagOn(FullEa->Flags, FILE_NEED_EA )) {
  2181. //
  2182. // The NeedEaCount field is long aligned so we will write
  2183. // directly to it.
  2184. //
  2185. (*EaSetHeader)->NeedEaCount++;
  2186. }
  2187. //
  2188. // Now copy over the ea, full ea's and packed ea are identical except
  2189. // that full ea also have a next ea offset that we skip over
  2190. //
  2191. // Before:
  2192. // UsedSize Allocated
  2193. // | |
  2194. // V V
  2195. // +xxxxxxxx+-----------------------------+
  2196. //
  2197. // After:
  2198. // UsedSize Allocated
  2199. // | |
  2200. // V V
  2201. // +xxxxxxxx+yyyyyyyyyyyyyyyy+------------+
  2202. //
  2203. ThisPackedEa = (PPACKED_EA) (RtlOffsetToPointer( (*EaSetHeader)->PackedEas,
  2204. *PackedEasLength ));
  2205. RtlCopyMemory( ThisPackedEa,
  2206. (PUCHAR) FullEa + 4,
  2207. PackedEaSize );
  2208. //
  2209. // Now convert the name to uppercase.
  2210. //
  2211. EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
  2212. EaName.Buffer = ThisPackedEa->EaName;
  2213. FatUpcaseEaName( IrpContext, &EaName, &EaName );
  2214. //
  2215. // Increment the used size in the packed ea list structure
  2216. //
  2217. *PackedEasLength += PackedEaSize;
  2218. //
  2219. // And return to our caller
  2220. //
  2221. DebugTrace(-1, Dbg, "FatAppendPackedEa -> VOID\n", 0);
  2222. UNREFERENCED_PARAMETER( IrpContext );
  2223. return;
  2224. }
  2225. VOID
  2226. FatDeletePackedEa (
  2227. IN PIRP_CONTEXT IrpContext,
  2228. IN OUT PEA_SET_HEADER EaSetHeader,
  2229. IN OUT PULONG PackedEasLength,
  2230. IN ULONG Offset
  2231. )
  2232. /*++
  2233. Routine Description:
  2234. This routine deletes an individual packed ea from the supplied
  2235. packed ea list.
  2236. Arguments:
  2237. EaSetHeader - Supplies the address to store the pointer to pool memory
  2238. which contains the Ea list for a file.
  2239. PackedEasLength - Supplies the length of the actual Ea data. The
  2240. new Ea data will be appended at this point.
  2241. Offset - Supplies the offset to the individual ea in the list to delete
  2242. NOTE: The EaSetHeader refers to the entire block of Ea data for a
  2243. file. This includes the Ea's and their values as well as the
  2244. header information. The PackedEasLength parameter refer to the
  2245. name/value pairs only.
  2246. Return Value:
  2247. None.
  2248. --*/
  2249. {
  2250. PPACKED_EA PackedEa;
  2251. ULONG PackedEaSize;
  2252. DebugTrace(+1, Dbg, "FatDeletePackedEa, Offset = %08lx\n", Offset);
  2253. //
  2254. // Get a reference to the packed ea and figure out its size
  2255. //
  2256. PackedEa = (PPACKED_EA) (&EaSetHeader->PackedEas[Offset]);
  2257. SizeOfPackedEa( PackedEa, &PackedEaSize );
  2258. //
  2259. // Determine if we need to decrement our need ea changes count
  2260. //
  2261. if (FlagOn(PackedEa->Flags, EA_NEED_EA_FLAG)) {
  2262. EaSetHeader->NeedEaCount--;
  2263. }
  2264. //
  2265. // Shrink the ea list over the deleted ea. The amount to copy is the
  2266. // total size of the ea list minus the offset to the end of the ea
  2267. // we're deleting.
  2268. //
  2269. // Before:
  2270. // Offset Offset+PackedEaSize UsedSize Allocated
  2271. // | | | |
  2272. // V V V V
  2273. // +xxxxxxxx+yyyyyyyyyyyyyyyy+zzzzzzzzzzzzzzzzzz+------------+
  2274. //
  2275. // After
  2276. // Offset UsedSize Allocated
  2277. // | | |
  2278. // V V V
  2279. // +xxxxxxxx+zzzzzzzzzzzzzzzzzz+-----------------------------+
  2280. //
  2281. RtlCopyMemory( PackedEa,
  2282. (PUCHAR) PackedEa + PackedEaSize,
  2283. *PackedEasLength - (Offset + PackedEaSize) );
  2284. //
  2285. // And zero out the remaing part of the ea list, to make things
  2286. // nice and more robust
  2287. //
  2288. RtlZeroMemory( &EaSetHeader->PackedEas[*PackedEasLength - PackedEaSize],
  2289. PackedEaSize );
  2290. //
  2291. // Decrement the used size by the amount we just removed
  2292. //
  2293. *PackedEasLength -= PackedEaSize;
  2294. //
  2295. // And return to our caller
  2296. //
  2297. DebugTrace(-1, Dbg, "FatDeletePackedEa -> VOID\n", 0);
  2298. UNREFERENCED_PARAMETER( IrpContext );
  2299. return;
  2300. }
  2301. ULONG
  2302. FatLocateNextEa (
  2303. IN PIRP_CONTEXT IrpContext,
  2304. IN PPACKED_EA FirstPackedEa,
  2305. IN ULONG PackedEasLength,
  2306. IN ULONG PreviousOffset
  2307. )
  2308. /*++
  2309. Routine Description:
  2310. This routine locates the offset for the next individual packed ea
  2311. inside of a packed ea list, given the offset to a previous Ea.
  2312. Instead of returing boolean to indicate if we've found the next one
  2313. we let the return offset be so large that it overuns the used size
  2314. of the packed ea list, and that way it's an easy construct to use
  2315. in a for loop.
  2316. Arguments:
  2317. FirstPackedEa - Supplies a pointer to the packed ea list structure
  2318. PackedEasLength - Supplies the length of the packed ea list
  2319. PreviousOffset - Supplies the offset to a individual packed ea in the
  2320. list
  2321. Return Value:
  2322. ULONG - The offset to the next ea in the list or 0xffffffff of one
  2323. does not exist.
  2324. --*/
  2325. {
  2326. PPACKED_EA PackedEa;
  2327. ULONG PackedEaSize;
  2328. ULONG Offset;
  2329. DebugTrace(+1, Dbg, "FatLocateNextEa, PreviousOffset = %08lx\n",
  2330. PreviousOffset);
  2331. //
  2332. // Make sure the previous offset is within the used size range
  2333. //
  2334. if ( PreviousOffset >= PackedEasLength ) {
  2335. DebugTrace(-1, Dbg, "FatLocateNextEa -> 0xffffffff\n", 0);
  2336. return 0xffffffff;
  2337. }
  2338. //
  2339. // Get a reference to the previous packed ea, and compute its size
  2340. //
  2341. PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + PreviousOffset );
  2342. SizeOfPackedEa( PackedEa, &PackedEaSize );
  2343. //
  2344. // Compute to the next ea
  2345. //
  2346. Offset = PreviousOffset + PackedEaSize;
  2347. //
  2348. // Now, if the new offset is beyond the ea size then we know
  2349. // that there isn't one so, we return an offset of 0xffffffff.
  2350. // otherwise we'll leave the new offset alone.
  2351. //
  2352. if ( Offset >= PackedEasLength ) {
  2353. Offset = 0xffffffff;
  2354. }
  2355. DebugTrace(-1, Dbg, "FatLocateNextEa -> %08lx\n", Offset);
  2356. UNREFERENCED_PARAMETER( IrpContext );
  2357. return Offset;
  2358. }
  2359. BOOLEAN
  2360. FatLocateEaByName (
  2361. IN PIRP_CONTEXT IrpContext,
  2362. IN PPACKED_EA FirstPackedEa,
  2363. IN ULONG PackedEasLength,
  2364. IN POEM_STRING EaName,
  2365. OUT PULONG Offset
  2366. )
  2367. /*++
  2368. Routine Description:
  2369. This routine locates the offset for the next individual packed ea
  2370. inside of a packed ea list, given the name of the ea to locate
  2371. Arguments:
  2372. FirstPackedEa - Supplies a pointer to the packed ea list structure
  2373. PackedEasLength - Supplies the length of the packed ea list
  2374. EaName - Supplies the name of the ea search for
  2375. Offset - Receives the offset to the located individual ea in the list
  2376. if one exists.
  2377. Return Value:
  2378. BOOLEAN - TRUE if the named packed ea exists in the list and FALSE
  2379. otherwise.
  2380. --*/
  2381. {
  2382. PPACKED_EA PackedEa;
  2383. OEM_STRING Name;
  2384. DebugTrace(+1, Dbg, "FatLocateEaByName, EaName = %Z\n", EaName);
  2385. //
  2386. // For each packed ea in the list check its name against the
  2387. // ea name we're searching for
  2388. //
  2389. for ( *Offset = 0;
  2390. *Offset < PackedEasLength;
  2391. *Offset = FatLocateNextEa( IrpContext,
  2392. FirstPackedEa,
  2393. PackedEasLength,
  2394. *Offset )) {
  2395. //
  2396. // Reference the packed ea and get a string to its name
  2397. //
  2398. PackedEa = (PPACKED_EA) ((PUCHAR) FirstPackedEa + *Offset);
  2399. Name.Buffer = &PackedEa->EaName[0];
  2400. Name.Length = PackedEa->EaNameLength;
  2401. Name.MaximumLength = PackedEa->EaNameLength;
  2402. //
  2403. // Compare the two strings, if they are equal then we've
  2404. // found the caller's ea
  2405. //
  2406. if ( RtlCompareString( EaName, &Name, TRUE ) == 0 ) {
  2407. DebugTrace(-1, Dbg, "FatLocateEaByName -> TRUE, *Offset = %08lx\n", *Offset);
  2408. return TRUE;
  2409. }
  2410. }
  2411. //
  2412. // We've exhausted the ea list without finding a match so return false
  2413. //
  2414. DebugTrace(-1, Dbg, "FatLocateEaByName -> FALSE\n", 0);
  2415. return FALSE;
  2416. }
  2417. BOOLEAN
  2418. FatIsEaNameValid (
  2419. IN PIRP_CONTEXT IrpContext,
  2420. IN OEM_STRING Name
  2421. )
  2422. /*++
  2423. Routine Description:
  2424. This routine simple returns whether the specified file names conforms
  2425. to the file system specific rules for legal Ea names.
  2426. For Ea names, the following rules apply:
  2427. A. An Ea name may not contain any of the following characters:
  2428. 0x0000 - 0x001F \ / : * ? " < > | , + = [ ] ;
  2429. Arguments:
  2430. Name - Supllies the name to check.
  2431. Return Value:
  2432. BOOLEAN - TRUE if the name is legal, FALSE otherwise.
  2433. --*/
  2434. {
  2435. ULONG Index;
  2436. UCHAR Char;
  2437. //
  2438. // Empty names are not valid.
  2439. //
  2440. if ( Name.Length == 0 ) { return FALSE; }
  2441. //
  2442. // At this point we should only have a single name, which can't have
  2443. // more than 254 characters
  2444. //
  2445. if ( Name.Length > 254 ) { return FALSE; }
  2446. for ( Index = 0; Index < (ULONG)Name.Length; Index += 1 ) {
  2447. Char = Name.Buffer[ Index ];
  2448. //
  2449. // Skip over and Dbcs chacters
  2450. //
  2451. if ( FsRtlIsLeadDbcsCharacter( Char ) ) {
  2452. ASSERT( Index != (ULONG)(Name.Length - 1) );
  2453. Index += 1;
  2454. continue;
  2455. }
  2456. //
  2457. // Make sure this character is legal, and if a wild card, that
  2458. // wild cards are permissible.
  2459. //
  2460. if ( !FsRtlIsAnsiCharacterLegalFat(Char, FALSE) ) {
  2461. return FALSE;
  2462. }
  2463. }
  2464. return TRUE;
  2465. }
  2466. VOID
  2467. FatPinEaRange (
  2468. IN PIRP_CONTEXT IrpContext,
  2469. IN PFILE_OBJECT VirtualEaFile,
  2470. IN PFCB EaFcb,
  2471. IN OUT PEA_RANGE EaRange,
  2472. IN ULONG StartingVbo,
  2473. IN ULONG Length,
  2474. IN NTSTATUS ErrorStatus
  2475. )
  2476. /*++
  2477. Routine Description:
  2478. This routine is called to pin a range within the Ea file. It will follow all the
  2479. rules required by the cache manager so that we don't have overlapping pin operations.
  2480. If the range being pinned spans a section then the desired data will be copied into
  2481. an auxilary buffer. FatMarkEaRangeDirty will know whether to copy the data back
  2482. into the cache or whether to simply mark the pinned data dirty.
  2483. Arguments:
  2484. VirtualEaFile - This is the stream file for the Ea file.
  2485. EaFcb - This is the Fcb for the Ea file.
  2486. EaRange - This is the Ea range structure for this request.
  2487. StartingVbo - This is the starting offset in the Ea file to read from.
  2488. Length - This is the length of the read.
  2489. ErrorStatus - This is the error status to use if we are reading outside
  2490. of the file.
  2491. Return Value:
  2492. None.
  2493. --*/
  2494. {
  2495. LARGE_INTEGER LargeVbo;
  2496. ULONG ByteCount;
  2497. PBCB *NextBcb;
  2498. PVOID Buffer;
  2499. PCHAR DestinationBuffer;
  2500. BOOLEAN FirstPage = TRUE;
  2501. //
  2502. // Verify that the entire read is contained within the Ea file.
  2503. //
  2504. if (Length == 0
  2505. || StartingVbo >= EaFcb->Header.AllocationSize.LowPart
  2506. || (EaFcb->Header.AllocationSize.LowPart - StartingVbo) < Length) {
  2507. FatRaiseStatus( IrpContext, ErrorStatus );
  2508. }
  2509. //
  2510. // If the read will span a section, the system addresses may not be contiguous.
  2511. // Allocate a separate buffer in this case.
  2512. //
  2513. if (((StartingVbo & (EA_SECTION_SIZE - 1)) + Length) > EA_SECTION_SIZE) {
  2514. EaRange->Data = FsRtlAllocatePoolWithTag( PagedPool,
  2515. Length,
  2516. TAG_EA_DATA );
  2517. EaRange->AuxilaryBuffer = TRUE;
  2518. DestinationBuffer = EaRange->Data;
  2519. } else {
  2520. //
  2521. // PREfix correctly notes that if we don't decide here to have an aux buffer
  2522. // and the flag is up in the EaRange, we'll party on random memory since
  2523. // DestinationBuffer won't be set; however, this will never happen due to
  2524. // initialization of ea ranges and the cleanup in UnpinEaRange.
  2525. //
  2526. ASSERT( EaRange->AuxilaryBuffer == FALSE );
  2527. }
  2528. //
  2529. // If the read will require more pages than our structure will hold then
  2530. // allocate an auxilary buffer. We have to figure the number of pages
  2531. // being requested so we have to include the page offset of the first page of
  2532. // the request.
  2533. //
  2534. EaRange->BcbChainLength = (USHORT) (((StartingVbo & (PAGE_SIZE - 1)) + Length + PAGE_SIZE - 1) / PAGE_SIZE);
  2535. if (EaRange->BcbChainLength > EA_BCB_ARRAY_SIZE) {
  2536. EaRange->BcbChain = FsRtlAllocatePoolWithTag( PagedPool,
  2537. sizeof( PBCB ) * EaRange->BcbChainLength,
  2538. TAG_BCB );
  2539. RtlZeroMemory( EaRange->BcbChain, sizeof( PBCB ) * EaRange->BcbChainLength );
  2540. } else {
  2541. EaRange->BcbChain = (PBCB *) &EaRange->BcbArray;
  2542. }
  2543. //
  2544. // Store the byte range data in the Ea Range structure.
  2545. //
  2546. EaRange->StartingVbo = StartingVbo;
  2547. EaRange->Length = Length;
  2548. //
  2549. // Compute the initial pin length.
  2550. //
  2551. ByteCount = PAGE_SIZE - (StartingVbo & (PAGE_SIZE - 1));
  2552. //
  2553. // For each page in the range; pin the page and update the Bcb count, copy to
  2554. // the auxiliary buffer.
  2555. //
  2556. NextBcb = EaRange->BcbChain;
  2557. while (Length != 0) {
  2558. //
  2559. // Pin the page and remember the data start.
  2560. //
  2561. LargeVbo.QuadPart = StartingVbo;
  2562. if (ByteCount > Length) {
  2563. ByteCount = Length;
  2564. }
  2565. if (!CcPinRead( VirtualEaFile,
  2566. &LargeVbo,
  2567. ByteCount,
  2568. BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
  2569. NextBcb,
  2570. &Buffer )) {
  2571. //
  2572. // Could not read the data without waiting (cache miss).
  2573. //
  2574. FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  2575. }
  2576. //
  2577. // Increment the Bcb pointer and copy to the auxilary buffer if necessary.
  2578. //
  2579. NextBcb += 1;
  2580. if (EaRange->AuxilaryBuffer == TRUE) {
  2581. RtlCopyMemory( DestinationBuffer,
  2582. Buffer,
  2583. ByteCount );
  2584. DestinationBuffer = (PCHAR) Add2Ptr( DestinationBuffer, ByteCount );
  2585. }
  2586. StartingVbo += ByteCount;
  2587. Length -= ByteCount;
  2588. //
  2589. // If this is the first page then update the Ea Range structure.
  2590. //
  2591. if (FirstPage) {
  2592. FirstPage = FALSE;
  2593. ByteCount = PAGE_SIZE;
  2594. if (EaRange->AuxilaryBuffer == FALSE) {
  2595. EaRange->Data = Buffer;
  2596. }
  2597. }
  2598. }
  2599. return;
  2600. }
  2601. VOID
  2602. FatMarkEaRangeDirty (
  2603. IN PIRP_CONTEXT IrpContext,
  2604. IN PFILE_OBJECT EaFileObject,
  2605. IN OUT PEA_RANGE EaRange
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. This routine is called to mark a range of the Ea file as dirty. If the modified
  2610. data is sitting in an auxilary buffer then we will copy it back into the cache.
  2611. In any case we will go through the list of Bcb's and mark them dirty.
  2612. Arguments:
  2613. EaFileObject - This is the file object for the Ea file.
  2614. EaRange - This is the Ea range structure for this request.
  2615. Return Value:
  2616. None.
  2617. --*/
  2618. {
  2619. PBCB *NextBcb;
  2620. ULONG BcbCount;
  2621. //
  2622. // If there is an auxilary buffer we need to copy the data back into the cache.
  2623. //
  2624. if (EaRange->AuxilaryBuffer == TRUE) {
  2625. LARGE_INTEGER LargeVbo;
  2626. LargeVbo.QuadPart = EaRange->StartingVbo;
  2627. CcCopyWrite( EaFileObject,
  2628. &LargeVbo,
  2629. EaRange->Length,
  2630. TRUE,
  2631. EaRange->Data );
  2632. }
  2633. //
  2634. // Now walk through the Bcb chain and mark everything dirty.
  2635. //
  2636. BcbCount = EaRange->BcbChainLength;
  2637. NextBcb = EaRange->BcbChain;
  2638. while (BcbCount--) {
  2639. if (*NextBcb != NULL) {
  2640. CcSetDirtyPinnedData( *NextBcb, NULL );
  2641. }
  2642. NextBcb += 1;
  2643. }
  2644. return;
  2645. }
  2646. VOID
  2647. FatUnpinEaRange (
  2648. IN PIRP_CONTEXT IrpContext,
  2649. IN OUT PEA_RANGE EaRange
  2650. )
  2651. /*++
  2652. Routine Description:
  2653. This routine is called to unpin a range in the Ea file. Any structures allocated
  2654. will be deallocated here.
  2655. Arguments:
  2656. EaRange - This is the Ea range structure for this request.
  2657. Return Value:
  2658. None.
  2659. --*/
  2660. {
  2661. PBCB *NextBcb;
  2662. ULONG BcbCount;
  2663. //
  2664. // If we allocated a auxilary buffer, deallocate it here.
  2665. //
  2666. if (EaRange->AuxilaryBuffer == TRUE) {
  2667. ExFreePool( EaRange->Data );
  2668. EaRange->AuxilaryBuffer = FALSE;
  2669. }
  2670. //
  2671. // Walk through the Bcb chain and unpin the data.
  2672. //
  2673. if (EaRange->BcbChain != NULL) {
  2674. BcbCount = EaRange->BcbChainLength;
  2675. NextBcb = EaRange->BcbChain;
  2676. while (BcbCount--) {
  2677. if (*NextBcb != NULL) {
  2678. CcUnpinData( *NextBcb );
  2679. *NextBcb = NULL;
  2680. }
  2681. NextBcb += 1;
  2682. }
  2683. //
  2684. // If we allocated a Bcb chain, deallocate it here.
  2685. //
  2686. if (EaRange->BcbChain != &EaRange->BcbArray[0]) {
  2687. ExFreePool( EaRange->BcbChain );
  2688. }
  2689. EaRange->BcbChain = NULL;
  2690. }
  2691. return;
  2692. }