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.

3752 lines
98 KiB

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