Leaked source code of windows server 2003
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.

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