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.

1089 lines
19 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. fat.hxx
  5. Abstract:
  6. This class models a file allocation table. The composition is of
  7. virtual functions because there are two different kinds of file
  8. allocation tables. A user of this class will be able to manipulate
  9. the FAT regardless of the implementation.
  10. Author:
  11. Norbert P. Kusters (norbertk) 6-Dec-90
  12. --*/
  13. #if !defined(FAT_DEFN)
  14. #define FAT_DEFN
  15. #include "secrun.hxx"
  16. #if defined ( _AUTOCHECK_ )
  17. #define UFAT_EXPORT
  18. #elif defined ( _UFAT_MEMBER_ )
  19. #define UFAT_EXPORT __declspec(dllexport)
  20. #else
  21. #define UFAT_EXPORT __declspec(dllimport)
  22. #endif
  23. //
  24. // Forward references
  25. //
  26. DECLARE_CLASS( FAT );
  27. DECLARE_CLASS( BITVECTOR );
  28. CONST ULONG FirstDiskCluster = 2;
  29. CONST ULONG MaxNumClusForSmallFat = 4086;
  30. // - flags to denote three state FAT type
  31. CONST ULONG MinNumClusForFat32 = 65526; // Min # Fat32 clusters is 65525
  32. // The largest FAT16 entry goes
  33. // up to 65527
  34. CONST fFat12 = 12;
  35. CONST fFat16 = 16;
  36. CONST fFat32 = 32;
  37. class FAT : public SECRUN {
  38. public:
  39. DECLARE_CONSTRUCTOR(FAT);
  40. VIRTUAL
  41. ~FAT(
  42. );
  43. NONVIRTUAL
  44. BOOLEAN
  45. Initialize(
  46. IN OUT PMEM Mem,
  47. IN OUT PLOG_IO_DP_DRIVE Drive,
  48. IN LBN StartSector,
  49. IN ULONG NumOfEntries,
  50. IN ULONG NumSectors DEFAULT 0
  51. );
  52. NONVIRTUAL
  53. BOOLEAN
  54. Initialize(
  55. IN OUT PSECRUN Srun,
  56. IN OUT PMEM Mem,
  57. IN OUT PLOG_IO_DP_DRIVE Drive,
  58. IN LBN StartSector,
  59. IN ULONG NumOfEntries,
  60. IN ULONG NumSectors DEFAULT 0
  61. );
  62. NONVIRTUAL
  63. ULONG
  64. QueryEntry(
  65. IN ULONG ClusterNumber
  66. ) CONST;
  67. NONVIRTUAL
  68. VOID
  69. SetEntry(
  70. IN ULONG ClusterNumber,
  71. IN ULONG Value
  72. );
  73. NONVIRTUAL
  74. BOOLEAN
  75. IsInRange(
  76. IN ULONG ClusterNumber
  77. ) CONST;
  78. NONVIRTUAL
  79. BOOLEAN
  80. IsClusterFree(
  81. IN ULONG ClusterNumber
  82. ) CONST;
  83. NONVIRTUAL
  84. VOID
  85. SetClusterFree(
  86. IN ULONG ClusterNumber
  87. );
  88. NONVIRTUAL
  89. BOOLEAN
  90. IsEndOfChain(
  91. IN ULONG ClusterNumber
  92. ) CONST;
  93. NONVIRTUAL
  94. VOID
  95. SetEndOfChain(
  96. IN ULONG ClusterNumber
  97. );
  98. NONVIRTUAL
  99. BOOLEAN
  100. IsClusterBad(
  101. IN ULONG ClusterNumber
  102. ) CONST;
  103. NONVIRTUAL
  104. VOID
  105. SetClusterBad(
  106. IN ULONG ClusterNumber
  107. );
  108. NONVIRTUAL
  109. BOOLEAN
  110. IsClusterReserved(
  111. IN ULONG ClusterNumber
  112. ) CONST;
  113. NONVIRTUAL
  114. VOID
  115. SetClusterReserved(
  116. IN ULONG ClusterNumber
  117. );
  118. NONVIRTUAL
  119. VOID
  120. SetEarlyEntries(
  121. IN UCHAR MediaByte
  122. );
  123. NONVIRTUAL
  124. UCHAR
  125. QueryMediaByte(
  126. ) CONST;
  127. NONVIRTUAL
  128. ULONG
  129. QueryFreeClusters(
  130. ) CONST;
  131. NONVIRTUAL
  132. ULONG
  133. QueryBadClusters(
  134. ) CONST;
  135. NONVIRTUAL
  136. ULONG
  137. QueryReservedClusters(
  138. ) CONST;
  139. NONVIRTUAL
  140. UFAT_EXPORT
  141. ULONG
  142. QueryAllocatedClusters(
  143. ) CONST;
  144. NONVIRTUAL
  145. UFAT_EXPORT
  146. ULONG
  147. QueryNthCluster(
  148. IN ULONG StartingCluster,
  149. IN ULONG Index
  150. ) CONST;
  151. NONVIRTUAL
  152. UFAT_EXPORT
  153. ULONG
  154. QueryLengthOfChain(
  155. IN ULONG StartingCluster,
  156. OUT PULONG LastCluster DEFAULT NULL
  157. ) CONST;
  158. NONVIRTUAL
  159. ULONG
  160. QueryLengthOfChain(
  161. IN ULONG StartingCluster,
  162. IN ULONG EndingCluster
  163. ) CONST;
  164. NONVIRTUAL
  165. ULONG
  166. QueryPrevious(
  167. IN ULONG Cluster
  168. ) CONST;
  169. NONVIRTUAL
  170. VOID
  171. Scrub(
  172. OUT PBOOLEAN ChangesMade DEFAULT NULL
  173. );
  174. NONVIRTUAL
  175. VOID
  176. ScrubChain(
  177. IN ULONG StartingCluster,
  178. OUT PBOOLEAN ChangesMade
  179. );
  180. NONVIRTUAL
  181. VOID
  182. ScrubChain(
  183. IN ULONG StartingCluster,
  184. OUT PBITVECTOR UsedClusters,
  185. OUT PBOOLEAN ChangesMade,
  186. OUT PBOOLEAN CrossLinkDetected,
  187. OUT PULONG CrossLinkPreviousCluster
  188. );
  189. NONVIRTUAL
  190. BOOLEAN
  191. IsValidChain(
  192. IN ULONG StartingCluster
  193. ) CONST;
  194. NONVIRTUAL
  195. UFAT_EXPORT
  196. ULONG
  197. AllocChain(
  198. IN ULONG Length,
  199. OUT PULONG LastCluster DEFAULT NULL
  200. );
  201. NONVIRTUAL
  202. ULONG
  203. ReAllocChain(
  204. IN ULONG StartOfChain,
  205. IN ULONG NewLength,
  206. OUT PULONG LastCluster DEFAULT NULL
  207. );
  208. NONVIRTUAL
  209. UFAT_EXPORT
  210. VOID
  211. FreeChain(
  212. IN ULONG StartOfChain
  213. );
  214. NONVIRTUAL
  215. ULONG
  216. RemoveChain(
  217. IN ULONG PreceedingCluster,
  218. IN ULONG LastCluster
  219. );
  220. NONVIRTUAL
  221. VOID
  222. InsertChain(
  223. IN ULONG StartOfChain,
  224. IN ULONG EndOfChain,
  225. IN ULONG PreceedingCluster
  226. );
  227. NONVIRTUAL
  228. ULONG
  229. InsertChain(
  230. IN ULONG StartOfChain,
  231. IN ULONG Cluster
  232. );
  233. NONVIRTUAL
  234. ULONG
  235. QueryAllocatedClusterCount(
  236. VOID
  237. ) ;
  238. NONVIRTUAL
  239. VOID
  240. InvalidateAllocatedClusterCount(
  241. VOID
  242. ) ;
  243. private:
  244. NONVIRTUAL
  245. VOID
  246. Construct(
  247. );
  248. NONVIRTUAL
  249. VOID
  250. Destroy(
  251. );
  252. NONVIRTUAL
  253. ULONG
  254. Index(
  255. IN ULONG ClusterNumber
  256. ) CONST;
  257. NONVIRTUAL
  258. UFAT_EXPORT
  259. ULONG
  260. Index12(
  261. IN ULONG ClusterNumber
  262. ) CONST;
  263. NONVIRTUAL
  264. ULONG
  265. Index16(
  266. IN ULONG ClusterNumber
  267. ) CONST;
  268. NONVIRTUAL
  269. ULONG
  270. Index32(
  271. IN ULONG ClusterNumber
  272. ) CONST;
  273. NONVIRTUAL
  274. VOID
  275. Set(
  276. IN ULONG ClusterNumber,
  277. IN ULONG Value
  278. );
  279. NONVIRTUAL
  280. UFAT_EXPORT
  281. VOID
  282. Set12(
  283. IN ULONG ClusterNumber,
  284. IN ULONG Value
  285. );
  286. NONVIRTUAL
  287. VOID
  288. Set16(
  289. IN ULONG ClusterNumber,
  290. IN ULONG Value
  291. );
  292. NONVIRTUAL
  293. VOID
  294. Set32(
  295. IN ULONG ClusterNumber,
  296. IN ULONG Value
  297. );
  298. PVOID _fat;
  299. ULONG _num_entries;
  300. ULONG _low_end_of_chain; // 0xFFF8 or 0x0FF8
  301. ULONG _end_of_chain; // 0xFFFF or 0x0FFF
  302. ULONG _bad_cluster; // 0xFFF7 or 0x0FF7
  303. ULONG _low_reserved; // 0xFFF0 or 0x0FF0
  304. ULONG _high_reserved; // 0xFFF6 or 0x0FF6
  305. UCHAR _fat_bits; // Replacing _is_big with count of bits in FAT entry
  306. // BOOLEAN _is_big; // Boolean TRUE for FAT16, FALSE for FAT12
  307. ULONG _AllocatedClusters; // Count of allocated clusters
  308. };
  309. INLINE
  310. BOOLEAN
  311. FAT::IsInRange(
  312. IN ULONG ClusterNumber
  313. ) CONST
  314. /*++
  315. Routine Description:
  316. This routine computes whether or not ClusterNumber is a cluster on
  317. the disk.
  318. Arguments:
  319. ClusterNumber - Supplies the cluster to be checked.
  320. Return Value:
  321. FALSE - The cluster is not on the disk.
  322. TRUE - The cluster is on the disk.
  323. --*/
  324. {
  325. return (FirstDiskCluster <= ClusterNumber && ClusterNumber < _num_entries);
  326. }
  327. INLINE
  328. ULONG
  329. FAT::Index16(
  330. IN ULONG ClusterNumber
  331. ) CONST
  332. /*++
  333. Routine Description:
  334. This routine indexes the FAT as 16 bit little endian entries.
  335. Arguments:
  336. ClusterNumber - Supplies the FAT entry desired.
  337. Return Value:
  338. The value of the FAT entry at ClusterNumber.
  339. --*/
  340. {
  341. //DebugAssert(IsInRange(ClusterNumber));
  342. return (ULONG )(((PUSHORT) _fat)[ClusterNumber]);
  343. }
  344. INLINE
  345. ULONG
  346. FAT::Index32(
  347. IN ULONG ClusterNumber
  348. ) CONST
  349. /*++
  350. Routine Description:
  351. This routine indexes the FAT as 32 bit little endian entries.
  352. Arguments:
  353. ClusterNumber - Supplies the FAT entry desired.
  354. Return Value:
  355. The value of the 32 (actually 28) bit FAT entry at ClusterNumber.
  356. --*/
  357. {
  358. //DebugAssert(IsInRange(ClusterNumber));
  359. return (((PULONG) _fat)[ClusterNumber]) & 0x0FFFFFFF;
  360. }
  361. INLINE
  362. ULONG
  363. FAT::Index(
  364. IN ULONG ClusterNumber
  365. ) CONST
  366. /*++
  367. Routine Description:
  368. This routine indexes the FAT as 16 bit or 12 bit little endian entries.
  369. Arguments:
  370. ClusterNumber - Supplies the FAT entry desired.
  371. Return Value:
  372. The value of the FAT entry at ClusterNumber.
  373. --*/
  374. {
  375. if (fFat12 == _fat_bits)
  376. return Index12(ClusterNumber);
  377. else if (fFat16 == _fat_bits)
  378. return Index16(ClusterNumber);
  379. else
  380. return Index32(ClusterNumber);
  381. }
  382. INLINE
  383. VOID
  384. FAT::Set16(
  385. IN ULONG ClusterNumber,
  386. IN ULONG Value
  387. )
  388. /*++
  389. Routine Description:
  390. This routine sets the ClusterNumber'th 16 bit FAT entry to Value.
  391. Arguments:
  392. ClusterNumber - Supplies the FAT entry to set.
  393. Value - Supplies the value to set the FAT entry to.
  394. Return Value:
  395. None.
  396. --*/
  397. {
  398. //DebugAssert(IsInRange(ClusterNumber));
  399. ((PUSHORT) _fat)[ClusterNumber] = (USHORT)Value;
  400. _AllocatedClusters = 0xFFFFFFFF;
  401. }
  402. INLINE
  403. VOID
  404. FAT::Set32(
  405. IN ULONG ClusterNumber,
  406. IN ULONG Value
  407. )
  408. /*++
  409. Routine Description:
  410. This routine sets the ClusterNumber'th 32 (actually 28) bit FAT entry to Value.
  411. Arguments:
  412. ClusterNumber - Supplies the FAT entry to set.
  413. Value - Supplies the value to set the FAT entry to.
  414. Return Value:
  415. None.
  416. --*/
  417. {
  418. //DebugAssert(IsInRange(ClusterNumber));
  419. ((PULONG) _fat)[ClusterNumber] &= 0xF0000000;
  420. ((PULONG) _fat)[ClusterNumber] |= (Value & 0x0FFFFFFF);
  421. _AllocatedClusters = 0xFFFFFFFF;
  422. }
  423. INLINE
  424. VOID
  425. FAT::Set(
  426. IN ULONG ClusterNumber,
  427. IN ULONG Value
  428. )
  429. /*++
  430. Routine Description:
  431. This routine sets the ClusterNumber'th 12 bit or 16 bit FAT entry to Value.
  432. Arguments:
  433. ClusterNumber - Supplies the FAT entry to set.
  434. Value - Supplies the value to set the FAT entry to.
  435. Return Value:
  436. None.
  437. --*/
  438. {
  439. if (fFat12 == _fat_bits)
  440. Set12(ClusterNumber, Value);
  441. else if (fFat16 == _fat_bits)
  442. Set16(ClusterNumber, Value);
  443. else
  444. Set32(ClusterNumber, Value);
  445. }
  446. INLINE
  447. ULONG
  448. FAT::QueryEntry(
  449. IN ULONG ClusterNumber
  450. ) CONST
  451. /*++
  452. Routine Description:
  453. This routine returns the FAT value for ClusterNumber.
  454. Arguments:
  455. ClusterNumber - Supplies an index into the FAT.
  456. Return Value:
  457. The FAT table entry at offset ClusterNumber.
  458. --*/
  459. {
  460. return Index(ClusterNumber);
  461. }
  462. INLINE
  463. ULONG
  464. FAT::QueryAllocatedClusterCount(
  465. )
  466. /*++
  467. Routine Description:
  468. This routine computes the total number of clusters for the volume.
  469. which are allocated.
  470. Arguments:
  471. None.
  472. Return Value:
  473. The total number of allocated clusters for the volume.
  474. --*/
  475. {
  476. if(_AllocatedClusters == 0xFFFFFFFF)
  477. {
  478. if(_fat == NULL) {
  479. return(0);
  480. }
  481. _AllocatedClusters = FAT::QueryAllocatedClusters();
  482. }
  483. return _AllocatedClusters;
  484. }
  485. INLINE
  486. VOID
  487. FAT::InvalidateAllocatedClusterCount(
  488. )
  489. /*++
  490. Routine Description:
  491. This routine invalidates trhe cached allocated clusters count so that the next
  492. call to QueryAllocatedClusterCount will re-compute it.
  493. Arguments:
  494. None.
  495. Return Value:
  496. None.
  497. --*/
  498. {
  499. _AllocatedClusters = 0xFFFFFFFF;
  500. return;
  501. }
  502. INLINE
  503. VOID
  504. FAT::SetEntry(
  505. IN ULONG ClusterNumber,
  506. IN ULONG Value
  507. )
  508. /*++
  509. Routine Description:
  510. This routine sets the FAT entry at ClusterNumber to Value.
  511. Arguments:
  512. ClusterNumber - Supplies the position in the FAT to update.
  513. Value - Supplies the new value for that position.
  514. Return Value:
  515. None.
  516. --*/
  517. {
  518. Set(ClusterNumber, Value);
  519. }
  520. INLINE
  521. BOOLEAN
  522. FAT::IsClusterFree(
  523. IN ULONG ClusterNumber
  524. ) CONST
  525. /*++
  526. Routine Description:
  527. This routine computes whether of not ClusterNumber is a free cluster.
  528. Arguments:
  529. ClusterNumber - Supplies the cluster to be checked.
  530. Return Value:
  531. FALSE - The cluster is not free.
  532. TRUE - The cluster is free.
  533. --*/
  534. {
  535. return Index(ClusterNumber) == 0;
  536. }
  537. INLINE
  538. VOID
  539. FAT::SetClusterFree(
  540. IN ULONG ClusterNumber
  541. )
  542. /*++
  543. Routine Description:
  544. This routine marks the cluster ClusterNumber as free on the FAT.
  545. Arguments:
  546. ClusterNumber - Supplies the number of the cluster to mark free.
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. Set(ClusterNumber, 0);
  552. }
  553. INLINE
  554. BOOLEAN
  555. FAT::IsEndOfChain(
  556. IN ULONG ClusterNumber
  557. ) CONST
  558. /*++
  559. Routine Description:
  560. This routine computes whether or not the cluster ClusterNumber is the
  561. end of its cluster chain.
  562. Arguments:
  563. ClusterNumber - Supplies the cluster to be checked.
  564. Return Value:
  565. FALSE - The cluster is not the end of a chain.
  566. TRUE - The cluster is the end of a chain.
  567. --*/
  568. {
  569. return Index(ClusterNumber) >= _low_end_of_chain;
  570. }
  571. INLINE
  572. VOID
  573. FAT::SetEndOfChain(
  574. IN ULONG ClusterNumber
  575. )
  576. /*++
  577. Routine Description:
  578. This routine sets the cluster ClusterNumber to the end of its cluster
  579. chain.
  580. Arguments:
  581. ClusterNumber - Supplies the cluster to be set to end of chain.
  582. Return Value:
  583. None.
  584. --*/
  585. {
  586. Set(ClusterNumber, _end_of_chain);
  587. }
  588. INLINE
  589. BOOLEAN
  590. FAT::IsClusterBad(
  591. IN ULONG ClusterNumber
  592. ) CONST
  593. /*++
  594. Routine Description:
  595. This routine computes whether or not cluster ClusterNumber is bad.
  596. Arguments:
  597. ClusterNumber - Supplies the number of the cluster to be checked.
  598. Return Value:
  599. FALSE - The cluster is good.
  600. TRUE - The cluster is bad.
  601. --*/
  602. {
  603. return Index(ClusterNumber) == _bad_cluster;
  604. }
  605. INLINE
  606. VOID
  607. FAT::SetClusterBad(
  608. IN ULONG ClusterNumber
  609. )
  610. /*++
  611. Routine Description:
  612. This routine sets the cluster ClusterNumber to bad on the FAT.
  613. Arguments:
  614. ClusterNumber - Supplies the cluster number to mark bad.
  615. Return Value:
  616. None.
  617. --*/
  618. {
  619. Set(ClusterNumber, _bad_cluster);
  620. }
  621. INLINE
  622. BOOLEAN
  623. FAT::IsClusterReserved(
  624. IN ULONG ClusterNumber
  625. ) CONST
  626. /*++
  627. Routine Description:
  628. This routine computes whether or not the cluster ClusterNumber is
  629. a reserved cluster.
  630. Arguments:
  631. ClusterNumber - Supplies the cluster to check.
  632. Return Value:
  633. FALSE - The cluster is not reserved.
  634. TRUE - The cluster is reserved.
  635. --*/
  636. {
  637. return Index(ClusterNumber) >= _low_reserved &&
  638. Index(ClusterNumber) <= _high_reserved;
  639. }
  640. INLINE
  641. VOID
  642. FAT::SetClusterReserved(
  643. IN ULONG ClusterNumber
  644. )
  645. /*++
  646. Routine Description:
  647. This routine marks the cluster ClusterNumber as reserved in the FAT.
  648. Arguments:
  649. ClusterNumber - Supplies the cluster to mark reserved.
  650. Return Value:
  651. None.
  652. --*/
  653. {
  654. Set(ClusterNumber, _low_reserved);
  655. }
  656. INLINE
  657. UCHAR
  658. FAT::QueryMediaByte(
  659. ) CONST
  660. /*++
  661. Routine Description:
  662. The media byte for the partition is stored in the first character of the
  663. FAT. This routine will return its value provided that the two following
  664. bytes are 0xFF.
  665. Arguments:
  666. None.
  667. Return Value:
  668. The media byte for the partition.
  669. --*/
  670. {
  671. PUCHAR p;
  672. p = (PUCHAR) _fat;
  673. DebugAssert(p);
  674. return (p[2] == 0xFF && p[1] == 0xFF && ((fFat12 != _fat_bits) ? (0x0F == (p[3] & 0x0F)) : TRUE)) ? p[0] : 0;
  675. }
  676. INLINE
  677. VOID
  678. FAT::SetEarlyEntries(
  679. IN UCHAR MediaByte
  680. )
  681. /*++
  682. Routine Description:
  683. This routine sets the first two FAT entries as required by the
  684. FAT file system. The first byte gets set to the media descriptor.
  685. The remaining bytes gets set to FF.
  686. Arguments:
  687. MediaByte - Supplies the media byte for the volume.
  688. Return Value:
  689. None.
  690. --*/
  691. {
  692. PUCHAR p;
  693. p = (PUCHAR) _fat;
  694. DebugAssert(p);
  695. p[0] = MediaByte;
  696. p[1] = p[2] = 0xFF;
  697. if (fFat32 == _fat_bits) {
  698. p[3] = 0x0F;
  699. p[4] = 0xFF;
  700. p[5] = 0xFF;
  701. p[6] = 0xFF;
  702. p[7] = 0x0F;
  703. #if 0
  704. // allocate cluster 2 for the root (set 2=end of chain)
  705. p[8] = 0xFF;
  706. p[9] = 0xFF;
  707. p[10] = 0xFF;
  708. p[11] = 0x0F;
  709. #endif
  710. } else if (fFat16 == _fat_bits) {
  711. p[3] = 0xFF;
  712. }
  713. _AllocatedClusters = 0xFFFFFFFF;
  714. }
  715. INLINE
  716. ULONG
  717. FAT::RemoveChain(
  718. IN ULONG PreceedingCluster,
  719. IN ULONG LastCluster
  720. )
  721. /*++
  722. Routine Description:
  723. This routine removes a subchain of length 'Length' from a containing
  724. chain. This routine cannot remove subchains beginning at the head
  725. of the containing chain. To do this use the routine named
  726. 'SplitChain'.
  727. This routine returns the number of the first cluster of the
  728. removed subchain. The FAT is edited so that the removed subchain
  729. is promoted to a full chain.
  730. Arguments:
  731. PreceedingCluster - Supplies the cluster which preceeds the one to be
  732. removed in the chain.
  733. LastCluster - Supplies the last cluster of the chain to remove.
  734. Return Value:
  735. The cluster number for the head of the chain removed.
  736. --*/
  737. {
  738. ULONG r;
  739. r = QueryEntry(PreceedingCluster);
  740. SetEntry(PreceedingCluster, QueryEntry(LastCluster));
  741. SetEndOfChain(LastCluster);
  742. return r;
  743. }
  744. INLINE
  745. VOID
  746. FAT::InsertChain(
  747. IN ULONG StartOfChain,
  748. IN ULONG EndOfChain,
  749. IN ULONG PreceedingCluster
  750. )
  751. /*++
  752. Routine Description:
  753. This routine inserts one chain into another chain. This routine
  754. cannot insert a chain at the head of another chain. To do this
  755. use the routine named 'JoinChains'.
  756. Arguments:
  757. StartOfChain - Supplies the first cluster of the chain to insert.
  758. EndOfChain - Supplies the last cluster of the chain to insert.
  759. PreceedingCluster - Supplies the cluster immediately preceeding the
  760. position where the chain is to be inserted.
  761. Return Value:
  762. None.
  763. --*/
  764. {
  765. SetEntry(EndOfChain, QueryEntry(PreceedingCluster));
  766. SetEntry(PreceedingCluster, StartOfChain);
  767. }
  768. INLINE
  769. ULONG
  770. FAT::InsertChain(
  771. IN ULONG StartOfChain,
  772. IN ULONG Cluster
  773. )
  774. /*++
  775. Routine Description:
  776. This routine inserts one cluster at the head of a chain.
  777. Arguments:
  778. StartOfChain - Supplies the first cluster of the chain to insert.
  779. Cluster - Supplies the cluster to be inserted
  780. Return Value:
  781. ULONG - The new head of the chain (i.e. Cluster )
  782. --*/
  783. {
  784. if ( StartOfChain ) {
  785. SetEntry( Cluster, StartOfChain );
  786. } else {
  787. SetEndOfChain( Cluster );
  788. }
  789. return Cluster;
  790. }
  791. #endif // FAT_DEFN