dosFsFat.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:62k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* dosFsFat.c - DOS file system File Allocation Table Handler */
  2. /* Copyright 1987-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01q,10jan02,chn  Renamed some functions to clear up sector/cluster confusion
  8. 01p,10dec01,jkf  SPR#72039, various fixes from Mr. T. Johnson.
  9. 01o,12oct01,jkf  adapted debugging code to be more portable. 
  10. 01n,02oct01,jkf  replaced diab changes lost in 01m.
  11. 01m,20sep01,jkf  SPR#69031, common code for both AE & 5.x.
  12. 01l,08oct99,jkf  added ifdef for HP native tools to ignore GNUish debug macro's
  13. 01k,31aug99,jkf  changes for new CBIO API.
  14. 01j,31jul99,jkf  T2 merge, tidiness & spelling.
  15. 01i,21dec98,mjc  fixed bug in fat16Seek(), changed name of <contigEnd> 
  16.                  field in structure <DOS_FILE_HDL> to <contigEndPlus1>
  17. 01h,23nov98,mjc  avoided disk access for seek within contiguous file area;
  18. 01j,23sep98,vld  added FAT mirroring disabling;
  19.  added routine fat16SyncToggle()
  20. 01f,20sep98,mjc  descriptor structure name changed from DOS_FAT16_DESC
  21.                  to MS_FAT_DESC
  22. 01e,17sep98,vld  added argument "number of FAT copy" to cluster read/write
  23.                  routines;
  24. cluster writing routines extended with a"raw" data
  25.  write to FAT copies other, then active one;
  26.            routine fat16ClustValueSet() extended to support
  27.                  FAT copy initialization;
  28. 01d,12jul98,mjc  cluster group allocation factor changed from
  29.                  constant to global variable fatClugFac.
  30.                  Assert header files including was moved 
  31.                  to be after #ifdef DEBUG statement to allow
  32.                  NDEBUG definition  in case when DEBUG is undefined.
  33.                  fat16ContigAlloc() algorithm was changed to 1st fit.
  34. 01c,01jul98,lrn  doc reviewed
  35. 01b,29jun98,mjc  added FAT32, tested
  36. 01a,23feb98,mjc  initially written written.
  37. */
  38. /*
  39. DESCRIPTION
  40. This module is part of dosFsLib and is designed to manage the three
  41. different File Allocation Table formats: FAT12, FAT16 and FAT32.
  42. These formats are similar thus are implemented in a single module
  43. without the ability to scale out one of these formats for systems which
  44. do not intend to use them.
  45. IMPLEMENTATION
  46. This FAT handler does not keep any part of the File Allocation Table in
  47. memory, depending entirely on the underlying CBIO module, typically the
  48. Disk Cache for the ability to access any FAT entry of any size, i.e.
  49. byte-wise access to any particular disk sector.
  50. INITIALIZATION
  51. */
  52. /* includes */
  53. #include "vxWorks.h"
  54. #include "private/dosFsVerP.h"
  55. #include "semLib.h"
  56. #include "errnoLib.h"
  57. #include "logLib.h"
  58. #include "string.h"
  59. #include "memLib.h"
  60. #include "stdlib.h"
  61. #include "stdio.h"
  62. #include "taskLib.h"
  63. #include "private/print64Lib.h"
  64. #include "private/dosFsLibP.h"
  65. #include "private/dosFsFatP.h"
  66. /* macros */
  67. #define _TO_STR(z) _TO_TMP(z)
  68. #define _TO_TMP(z) #z
  69. #undef ERR_MSG
  70. #undef DBG_MSG
  71. #undef ERR_PRINT
  72. #ifdef DEBUG
  73. #   undef  LOCAL
  74. #   define LOCAL
  75. #   define ERR_PRINT /* include errnoSetOut() */
  76. #   define errnoSet( err ) errnoSetOut( __FILE__, __LINE__, #err, (err) )
  77. #   define DBG_MSG(lvl, fmt, a1, a2, a3, a4, a5, a6)                       
  78.         { if ((lvl) <= fat16Debug)                                         
  79.             printErr (__FILE__" : "_TO_STR(__LINE__)" : "fmt, a1, a2,      
  80.                       a3, a4, a5, a6); }
  81. #   define ERR_MSG(lvl, fmt, a1, a2, a3, a4, a5, a6)    
  82.         { logMsg (__FILE__" : "_TO_STR(__LINE__)" : "fmt, (int)(a1),       
  83.                   (int)(a2), (int)(a3), (int)(a4), (int)(a5), (int)(a6)); }
  84. #else   /* NO DEBUG */
  85. #   undef  NDEBUG
  86. #   define NDEBUG
  87. /* fixme: quick dirty hack for native HP native tools build, HP simulator */
  88. #   if (CPU == SIMHPPA)
  89.     /* Allow TOOL=hp to build, will cause no effect warnings when TOOL=gnu */
  90. #        define DBG_MSG
  91. #        define ERR_MSG
  92. #   else
  93. #        define DBG_MSG(lvl, fmt, a1, a2, a3, a4, a5, a6) {}
  94. #        define ERR_MSG(lvl, fmt, a1, a2, a3, a4, a5, a6)                    
  95.              { if ((lvl) <= fat16Debug)                                      
  96.                  logMsg (__FILE__" : "_TO_STR(__LINE__)" : %s : "fmt,        
  97.                  (int)(a1), (int)(a2), (int)(a3), (int)(a4), (int)(a5),      
  98.  (int)(a6)); }
  99. #   endif /* (CPU == SIMHPPA) */
  100. #endif /* DEBUG */
  101.                                                                              
  102. #include "assert.h"
  103. /* defines */
  104. /* File System Information Sector number */
  105. #define FSINFO_SEC_NUM 1
  106. /* Offset of free clusters count field in the File System Information Sector */
  107. #define FSINFO_SIGN 484
  108. #define FSINFO_FREE_CLUSTS 488
  109. #define FSINFO_NEXT_FREE        492
  110. /* Read FAT entry error code */
  111. #define FAT_CBIO_ERR 1
  112. /* Mutex semaphore options */
  113. #define ALLOC_SEM_OPTIONS SEM_Q_PRIORITY | SEM_DELETE_SAFE | 
  114. SEM_INVERSION_SAFE
  115. #define ENTRY_READ(pFd, copy, entry)
  116. pFatDesc->entryRead ((pFd), (copy), (entry))
  117. #define ENTRY_WRITE(pFd, copy, entry, value)
  118. pFatDesc->entryWrite ((pFd), (copy), (entry), (value))
  119. /* typedefs */
  120. /* globals */
  121. int     fat16Debug = 0; /* debug level */
  122. int fatClugFac = 10000; /* cluster allocation group size factor */
  123. /* locals */
  124. #ifdef ERR_PRINT
  125. /*******************************************************************************
  126. * errnoSetOut - put error message
  127. *
  128. * This routine is called instead errnoSet during debugging.
  129. */
  130. LOCAL VOID errnoSetOut(char * pFile, int line, const char * pStr, int errCode )
  131.     {
  132.     /* If it is not errno clearing or setting to previously stored value 
  133.      * (in <errnoBuf> variable), print the error information.
  134.      */
  135.     if( errCode != OK  && strcmp( pStr, "errnoBuf" ) != 0 )
  136.         printf( "ERROR from %s : line %d : %s = %p, task %pn",
  137.                 pFile, line, pStr, (void *)errCode, (void *)taskIdSelf() );
  138.     errno = errCode;
  139.     }
  140. #endif  /* ERR_PRINT */
  141. /*******************************************************************************
  142. *
  143. * fat16MirrorSect - mirror FAT sector
  144. *
  145. * This routine copies last modified sector of Primary FAT copy to appropriate 
  146. * sectors of another FAT copies.
  147. *
  148. * RETURNS: OK or ERROR.
  149. */
  150. LOCAL STATUS fat16MirrorSect
  151.     (
  152.     FAST DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  153.     )
  154.     {
  155.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  156. /* pointer to volume descriptor */
  157.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  158. /* pointer to FAT descriptor */
  159.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  160. /* pointer to CBIO device */
  161.     FAST uint32_t srcSecNum = pFd->pFileHdl->fatSector;
  162.     FAST uint32_t dstSecNum;
  163.     FAST int fatNum; /* FAT copy number */
  164.          uint8_t fsinfoBuf [8];
  165.     if (srcSecNum == 0)
  166.         return OK;
  167.     /* FAT copies synchronization might be disabled */
  168.     if ( ! pFatDesc->syncEnabled)
  169.      return OK;
  170.     /* 
  171.      * TBD: mirroring disabled (FAT32)
  172.      * ? Maybe it is worth adding callbacks to process CBIO write errors ?
  173.      */
  174.     for (fatNum = 1, dstSecNum = srcSecNum + pVolDesc->secPerFat; 
  175.          fatNum < pVolDesc->nFats; 
  176.          fatNum++, dstSecNum += pVolDesc->secPerFat)
  177.         {
  178.         if (cbioBlkCopy (pCbio, srcSecNum, dstSecNum, 1) != OK)
  179.             return ERROR;
  180.         /* ...??? */
  181.         }
  182.     if (pVolDesc->fatType == FAT32)
  183.         {
  184.         VX_TO_DISK_32 (pFatDesc->fatEntFreeCnt, &fsinfoBuf[0]);
  185.         VX_TO_DISK_32 (pFatDesc->groupAllocStart, &fsinfoBuf[4]);
  186.         if (OK != cbioBytesRW (pCbio, FSINFO_SEC_NUM, FSINFO_FREE_CLUSTS, 
  187. (addr_t)fsinfoBuf, sizeof (fsinfoBuf), CBIO_WRITE, NULL))
  188.             return ERROR;
  189.         }
  190.     return OK;
  191.     } /* fat16MirrorSect */
  192. /*******************************************************************************
  193. *
  194. * fat16SyncToggle - toggle FAT copies mirroring.
  195. * This routine enables/disables FAT copes mirroring. When mirroring
  196. * is enabled all reserved FAT copes are synchronized with active one.
  197. * RETURNES: N/A.
  198. */
  199. LOCAL void fat16SyncToggle
  200.     (
  201.     DOS_VOLUME_DESC_ID pVolDesc,
  202.     BOOL syncEnable
  203.     )
  204.     {
  205.     MS_FAT_DESC_ID pFatDesc = (MS_FAT_DESC_ID)pVolDesc->pFatDesc;
  206.     block_t srcSec, dstSec, secNum;
  207.     uint8_t copyNum;
  208.     
  209.     pFatDesc->syncEnabled = syncEnable;
  210.     
  211.     if (! syncEnable)
  212.      return;
  213.     
  214.     /* synchronize FAT copies */
  215.     
  216.     /* copy by one sector. It permits always one read - multi write */
  217.     srcSec = pFatDesc->fatStartSec +
  218.              pVolDesc->pFatDesc->activeCopyNum * pVolDesc->secPerFat;
  219.     for (secNum = 0; secNum < pVolDesc->secPerFat; secNum ++, srcSec ++ )
  220.      {
  221.      for (dstSec = pFatDesc->fatStartSec + secNum, copyNum = 0;
  222.      copyNum < pVolDesc->nFats;
  223.      dstSec += pVolDesc->secPerFat, copyNum ++ )
  224.          {
  225.          if (copyNum == pVolDesc->pFatDesc->activeCopyNum)
  226.           continue;
  227.          
  228.          cbioBlkCopy (pVolDesc->pCbio, srcSec, dstSec, 1);
  229.          }
  230.      }
  231.     } /* fat16SyncToggle() */
  232. /*******************************************************************************
  233. *
  234. * fat12EntRead - read FAT entry from disk
  235. * This routine reads the file allocation table (FAT) entry from a dosFs
  236. * volume.
  237. *
  238. * This routine only reads from the first copy of the FAT on disk, even if
  239. * other copies exist.
  240. * RETURNS: Contents of the entry, or FAT_CBIO_ERR if error accessing disk.
  241. */
  242. LOCAL uint32_t fat12EntRead
  243.     (
  244.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  245.     FAST uint32_t copyNum,/* fat copy number */
  246.     FAST uint32_t cluster /* entry number */
  247.     )
  248.     {
  249.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  250. /* pointer to volume descriptor */
  251.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  252. /* pointer to CBIO device */
  253.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  254. /* pointer to FAT descriptor */
  255.     FAST uint32_t fatEntry;/* FAT entry */
  256.     FAST uint32_t fatOff; /* offset in the FAT */
  257.     FAST block_t secNum; /* sector number to read/write */
  258.     FAST off_t secOff; /* offset in the sector */
  259.     FAST uint32_t nBytes; /* number of bytes */
  260.          uint8_t valBuf [2];
  261. /* buffer for value in the entry */
  262.     assert ( copyNum < pVolDesc->nFats);
  263.     assert ( (cluster >= DOS_MIN_CLUST) && (cluster < pFatDesc->nFatEnts) );
  264.     /* Offset of the entry in the FAT in bytes */
  265.     fatOff = cluster + (cluster >> 1); /* index = cluster * 1.5 */
  266.     /* Number of sector containing the entry */
  267.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  268.             (fatOff >> pVolDesc->secSizeShift);
  269.     /* Offset of the entry in the sector */
  270.     secOff = fatOff & (pVolDesc->bytesPerSec - 1);
  271.     /* Number of bytes to read */
  272.     nBytes = pVolDesc->bytesPerSec - secOff;
  273.     if (nBytes > 2)
  274.         nBytes = 2;
  275.     /* Read entry from disk */
  276.     if (cbioBytesRW (pCbio, secNum, secOff, (addr_t)valBuf, nBytes, CBIO_READ, 
  277. &pFd->fatHdl.cbioCookie) != OK)
  278.         {
  279.         pFd->fatHdl.errCode = FAT_CBIO_ERR;
  280.         return FAT_CBIO_ERR; /* read error */
  281.         }
  282.     if (nBytes == 1)
  283.         if (cbioBytesRW (pCbio, secNum + 1, 0, (addr_t)(&valBuf[1]), 1, 
  284. CBIO_READ, &pFd->fatHdl.cbioCookie) != OK)
  285.             {
  286.             pFd->fatHdl.errCode = FAT_CBIO_ERR;
  287.             return FAT_CBIO_ERR; /* read error */
  288.             }
  289.     fatEntry = valBuf [0] | (valBuf [1] << 8);
  290. /* copy word, swapping bytes */
  291.     if (cluster & 0x1) /* if cluster number is ODD */
  292.         fatEntry = (fatEntry >> 4) & 0xfff; /*  keep high order 12 bits */
  293.     else /* if cluster number is EVEN */
  294.         fatEntry &= 0xfff; /*  keep low order 12 bits */
  295.     return fatEntry;
  296.     } /* fat12EntRead */
  297. /*******************************************************************************
  298. *
  299. * fat12EntWrite - write FAT entry to disk
  300. * This routine writes the file allocation table (FAT) entry to a dosFs
  301. * volume.
  302. *
  303. * This routine reads the file allocation table (FAT) entry for the
  304. * specified cluster and returns it to the caller.
  305. *
  306. * If the value to be written is too large to fit in a FAT entry
  307. * (12 bits), it is truncated (high order bits are discarded).
  308. *
  309. * This routine only writes to the first copy of the FAT on disk, even if
  310. * other copies exist.
  311. * RETURNS: OK, or ERROR if error accessing disk.
  312. */
  313. LOCAL STATUS fat12EntWrite
  314.     (
  315.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  316.     FAST uint32_t copyNum,/* fat copy number */
  317.     FAST uint32_t cluster,/* entry number */
  318.     FAST uint32_t value /* value to write */
  319.     )
  320.     {
  321.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  322. /* pointer to volume descriptor */
  323.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  324. /* pointer to CBIO device */
  325.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  326. /* pointer to FAT descriptor */
  327.     FAST uint32_t fatOff; /* offset in the FAT */
  328.     FAST block_t secNum; /* sector number to read/write */
  329.     FAST off_t secOff; /* offset in the sector */
  330.     FAST uint32_t nBytes; /* number of bytes */
  331.          cookie_t     cookie; /* CBIO dev. cookie */
  332.          uint8_t valBuf [2];
  333. /* buffer for value in the entry */
  334.     assert ( copyNum < pVolDesc->nFats);
  335.     assert ( (cluster >= DOS_MIN_CLUST) && (cluster < pFatDesc->nFatEnts) );
  336.     assert ( copyNum != pVolDesc->pFatDesc->activeCopyNum ||
  337.              ( (value == pFatDesc->dos_fat_avail) || 
  338.                ((value >= DOS_MIN_CLUST) && (value < pFatDesc->nFatEnts)) || 
  339.                (value == pFatDesc->dos_fat_eof) ) );
  340.     cookie = pFd->fatHdl.cbioCookie;
  341.     /* Offset of the entry in the FAT in bytes */
  342.     fatOff = cluster + (cluster >> 1); /* index = cluster * 1.5 */
  343.     /* Number of sector containing the entry */
  344.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  345.             (fatOff >> pVolDesc->secSizeShift);
  346.     /* Mirror last modified FAT sector if entry is situated in other sector */
  347.     if (pFd->pFileHdl->fatSector != secNum &&
  348.         copyNum == pVolDesc->pFatDesc->activeCopyNum)
  349.         {
  350.         fat16MirrorSect (pFd);
  351.         pFd->pFileHdl->fatSector = secNum;
  352.         }
  353.     /* Offset of the entry in the sector */
  354.     secOff = fatOff & (pVolDesc->bytesPerSec - 1);
  355.     /* Number of bytes to write */
  356.     nBytes = pVolDesc->bytesPerSec - secOff;
  357.     if (nBytes > 2)
  358.         nBytes = 2;
  359.     /* Read previous entry value */
  360.     if (cbioBytesRW (pCbio, secNum, secOff,(addr_t) valBuf, nBytes, 
  361. CBIO_READ, &cookie) != OK)
  362.         return ERROR; /* read error */
  363.     if (nBytes == 1)
  364.         if (cbioBytesRW (pCbio, secNum + 1, 0,(addr_t) (&valBuf[1]), 1, 
  365. CBIO_READ, &pFd->fatHdl.cbioCookie) != OK)
  366.             return ERROR; /* read error */
  367.     if (cluster & 0x1) /* if cluster number is ODD */
  368.         {
  369.         valBuf [0] &= 0x0f; /* clear high order 4 bits */
  370.         valBuf [0] |= (value << 4); /* put in low bits of value */
  371.         valBuf [1]  = (value >> 4); /* next byte is high bits */
  372.         }
  373.     else /* if cluster number is EVEN */
  374.         {
  375.         valBuf [0]  = value; /* this byte gets low bits */
  376.         valBuf [1] &= 0xf0; /* clear low bits next byte */
  377.         valBuf [1] |= (value >> 8) & 0x0f; /* put in high bits */
  378.         }
  379.     /* Write entry to disk */
  380.     if (cbioBytesRW (pCbio, secNum, secOff,(addr_t)valBuf, nBytes, CBIO_WRITE, 
  381. &cookie) != OK)
  382.         return ERROR;
  383.     if (nBytes == 1)
  384.         if (cbioBytesRW (pCbio, secNum + 1, 0, (addr_t)(&valBuf [1]), 1, 
  385. CBIO_WRITE, &pFd->fatHdl.cbioCookie) != OK)
  386.         return ERROR;
  387.     return OK;
  388.     } /* fat12EntWrite */
  389. /*******************************************************************************
  390. * fat16EntRead - read FAT entry from disk
  391. * This routine reads the file allocation table (FAT) entry from a dosFs
  392. * volume.
  393. *
  394. * This routine only reads from the first copy of the FAT on disk, even if
  395. * other copies exist.
  396. * RETURNS: Contents of the entry, or FAT_CBIO_ERR if error accessing disk.
  397. */
  398. LOCAL uint32_t fat16EntRead
  399.     (
  400.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  401.     FAST uint32_t copyNum,/* fat copy number */
  402.     FAST uint32_t entry /* entry number */
  403.     )
  404.     {
  405.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  406. /* pointer to volume descriptor */
  407.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  408. /* pointer to CBIO device */
  409.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  410. /* pointer to FAT descriptor */
  411.     FAST block_t secNum; /* sector number to read/write */
  412.     FAST off_t secOff; /* offset in the sector */
  413.          uint8_t valBuf [2];
  414. /* buffer for value in the entry */
  415.     assert ( copyNum < pVolDesc->nFats);
  416.     assert ( (entry >= DOS_MIN_CLUST) && (entry < pFatDesc->nFatEnts) );
  417.     /* Offset of the entry in the FAT in bytes */
  418.     entry <<= 1;
  419.     /* Number of sector containing the entry */
  420.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  421.             (entry >> pVolDesc->secSizeShift);
  422.     /* Offset of the entry in the sector */
  423.     secOff = entry & (pVolDesc->bytesPerSec - 1);
  424.     /* Read entry from disk */
  425.     if (cbioBytesRW (pCbio, secNum, secOff, (addr_t)valBuf, 2, CBIO_READ, 
  426. &pFd->fatHdl.cbioCookie) != OK)
  427.         {
  428.         pFd->fatHdl.errCode = FAT_CBIO_ERR;
  429.         return FAT_CBIO_ERR; /* read error */
  430.         }
  431.     return (valBuf [0] | (valBuf [1] << 8));
  432. /* copy word, swapping bytes */
  433.     } /* fat16EntRead */
  434. /*******************************************************************************
  435. * fat16EntWrite - write FAT entry to disk
  436. * This routine writes the file allocation table (FAT) entry to a dosFs
  437. * volume.
  438. *
  439. * This routine only writes to the first copy of the FAT on disk, even if
  440. * other copies exist.
  441. * RETURNS: OK, or ERROR if error accessing disk.
  442. */
  443. LOCAL STATUS fat16EntWrite
  444.     (
  445.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  446.     FAST uint32_t copyNum,/* fat copy number */
  447.     FAST uint32_t entry, /* entry number */
  448.     FAST uint32_t value /* value to write */
  449.     )
  450.     {
  451.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  452. /* pointer to volume descriptor */
  453.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  454. /* pointer to CBIO device */
  455.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  456. /* pointer to FAT descriptor */
  457.     FAST block_t secNum; /* sector number to read/write */
  458.     FAST off_t secOff; /* offset in the sector */
  459.          uint8_t valBuf [2];
  460. /* buffer for value in the entry */
  461.     assert ( copyNum < pVolDesc->nFats);
  462.     assert ( (entry >= DOS_MIN_CLUST) && (entry < pFatDesc->nFatEnts) );
  463.     assert ( copyNum != pVolDesc->pFatDesc->activeCopyNum ||
  464.              ( (value == pFatDesc->dos_fat_avail) || 
  465.                ((value >= DOS_MIN_CLUST) && (value < pFatDesc->nFatEnts)) || 
  466.                (value == pFatDesc->dos_fat_eof) ) );
  467.     /* Offset of the entry in the FAT in bytes */
  468.     entry <<= 1;
  469.     /* Number of sector containing the entry */
  470.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  471.             (entry >> pVolDesc->secSizeShift);
  472.     /* Mirror last modified FAT sector if entry is situated in other sector */
  473.     if (pFd->pFileHdl->fatSector != secNum &&
  474.         copyNum == pVolDesc->pFatDesc->activeCopyNum)
  475.         {
  476.         fat16MirrorSect (pFd);
  477.         pFd->pFileHdl->fatSector = secNum;
  478.         }
  479.     /* Offset of the entry in the sector */
  480.     secOff = entry & (pVolDesc->bytesPerSec - 1);
  481.     valBuf [0] = value        & 0xff; /* this byte gets low bits */
  482.     valBuf [1] = (value >> 8) & 0xff; /* next byte gets high bits */
  483.     /* Write entry to disk */
  484.     return cbioBytesRW (pCbio, secNum, secOff, (addr_t)valBuf, 2, CBIO_WRITE, 
  485. &pFd->fatHdl.cbioCookie);
  486.     } /* fat16EntWrite */
  487. /*******************************************************************************
  488. * fat32EntRead - read FAT entry from disk
  489. * This routine reads the file allocation table (FAT) entry from a dosFs
  490. * volume.
  491. *
  492. * This routine only reads from the first copy of the FAT on disk, even if
  493. * other copies exist.
  494. * RETURNS: Contents of the entry, or FAT_CBIO_ERR if error accessing disk.
  495. */
  496. LOCAL uint32_t fat32EntRead
  497.     (
  498.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  499.     FAST uint32_t copyNum,/* fat copy number */
  500.     FAST uint32_t entry /* entry number */
  501.     )
  502.     {
  503.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  504. /* pointer to volume descriptor */
  505.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  506. /* pointer to CBIO device */
  507.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  508. /* pointer to FAT descriptor */
  509.     FAST block_t secNum; /* sector number to read/write */
  510.     FAST off_t secOff; /* offset in the sector */
  511.          uint8_t valBuf [4];
  512.          uint8_t highByteMask = 0x0f;
  513.     /* do not mask high bits when non active copy is being written */
  514.     if (copyNum != pVolDesc->pFatDesc->activeCopyNum)
  515.      highByteMask = 0xff;
  516. /* buffer for value in the entry */
  517.     assert ( copyNum < pVolDesc->nFats);
  518.     assert ( (entry >= DOS_MIN_CLUST) && (entry < pFatDesc->nFatEnts) );
  519.     /* Offset of the entry in the FAT in bytes */
  520.     entry <<= 2;
  521.     /* Number of sector containing the entry */
  522.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  523.             (entry >> pVolDesc->secSizeShift);
  524.     /* Offset of the entry in the sector */
  525.     secOff = entry & (pVolDesc->bytesPerSec - 1);
  526.     /* Read entry from disk */
  527.     if (cbioBytesRW (pCbio, secNum, secOff, (addr_t)valBuf, 4, CBIO_READ, 
  528.      &pFd->fatHdl.cbioCookie) != OK)
  529.         {
  530.         pFd->fatHdl.errCode = FAT_CBIO_ERR;
  531.         return FAT_CBIO_ERR; /* read error */
  532.         }
  533.     return (valBuf [0] | (valBuf [1] << 8) | (valBuf [2] << 16) | 
  534.             ((valBuf [3] & highByteMask) << 24));/* mask highest 4 bits */
  535.     } /* fat32EntRead */
  536. /*******************************************************************************
  537. * fat32EntWrite - write FAT entry to disk
  538. * This routine writes the file allocation table (FAT) entry to a dosFs
  539. * volume.
  540. *
  541. * This routine only writes to the first copy of the FAT on disk, even if
  542. * other copies exist.
  543. * RETURNS: OK, or ERROR if error accessing disk.
  544. */
  545. LOCAL STATUS fat32EntWrite
  546.     (
  547.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  548.     FAST uint32_t copyNum,/* fat copy number */
  549.     FAST uint32_t entry, /* entry number */
  550.     FAST uint32_t value /* value to write */
  551.     )
  552.     {
  553.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  554. /* pointer to volume descriptor */
  555.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  556. /* pointer to CBIO device */
  557.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  558. /* pointer to FAT descriptor */
  559.     FAST block_t secNum; /* sector number to read/write */
  560.     FAST off_t secOff; /* offset in the sector */
  561.          uint8_t valBuf [4];
  562. /* buffer for value in the entry */
  563.          uint8_t highByteMask = 0x0f;
  564.     /* do not mask high bits when non active copy is being written */
  565.     if (copyNum != pVolDesc->pFatDesc->activeCopyNum)
  566.      highByteMask = 0xff;
  567.     assert ( copyNum < pVolDesc->nFats);
  568.     assert ( (entry >= DOS_MIN_CLUST) && (entry < pFatDesc->nFatEnts) );
  569.     assert ( highByteMask == 0xff ||
  570.              ( (value == pFatDesc->dos_fat_avail) || 
  571.                ((value >= DOS_MIN_CLUST) && (value < pFatDesc->nFatEnts)) || 
  572.                (value == pFatDesc->dos_fat_eof) ) );
  573.     /* Offset of the entry in the FAT in bytes */
  574.     entry <<= 2;
  575.     /* Number of sector containing the entry */
  576.     secNum = pFatDesc->fatStartSec + copyNum * pVolDesc->secPerFat +
  577.             (entry >> pVolDesc->secSizeShift);
  578.     /* Mirror last modified FAT sector if entry is situated in other sector */
  579.     if (pFd->pFileHdl->fatSector != secNum && highByteMask != 0xff )
  580.         {
  581.         fat16MirrorSect (pFd);
  582.         pFd->pFileHdl->fatSector = secNum;
  583.         }
  584.     /* Offset of the entry in the sector */
  585.     secOff = entry & (pVolDesc->bytesPerSec - 1);
  586.     valBuf [0] = value         & 0xff; /*  */
  587.     valBuf [1] = (value >> 8)  & 0xff; /*  */
  588.     valBuf [2] = (value >> 16) & 0xff; /*  */
  589.     valBuf [3] = (value >> 24) & highByteMask; /*  */
  590.     /* Write entry to disk */
  591.     return cbioBytesRW (pCbio, secNum, secOff, (addr_t)valBuf, 4, CBIO_WRITE, 
  592. &pFd->fatHdl.cbioCookie);
  593.     } /* fat32EntWrite */
  594. /*******************************************************************************
  595. *
  596. * fat16ContigGet - get next section of contiguous clusters in file chain
  597. * This routine reads FAT entries starting from the passed cluster number, and 
  598. * returns number of contiguous clusters in the file chain starting from the 
  599. * passed one up to number of clusters requested.
  600. *
  601. * If starting cluster number is out of legal cluster number range, a 0 is 
  602. * returned, except of the following 2 cases:
  603. *
  604. * 1) If start cluster number is 0 .
  605. *
  606. * 2) If start cluster number is end of file .
  607. *
  608. * This routine checks the File Allocation Table (FAT) to determine the
  609. * length, in clusters, of a contiguous section of a file.  The starting
  610. * cluster to check is passed as an input parameter.  The number of
  611. * contiguous clusters beginning with that cluster (including the starting
  612. * cluster itself) is returned.  The minimum returned value is 1.
  613. *
  614. * RETURNS: Number of contiguous clusters in chain starting from the passed one,
  615. *          or 0 if starting cluster number is illegal or disk access error.
  616. */
  617. LOCAL STATUS fat16ContigGet
  618.     (
  619.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  620.     FAST uint32_t   numClusts /* num. of clusters to follow */
  621.     )
  622.     {
  623.     FAST DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  624. /* pointer to file handle */
  625.     FAST DOS_FAT_HDL_ID pFatHdl = &(pFd->fatHdl);
  626. /* pointer to FAT handle */
  627.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  628. /* pointer to volume descriptor */
  629.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  630. /* pointer to FAT handler descriptor */
  631.     FAST uint32_t startClust; /* starting cluster number */
  632.     FAST uint32_t nextClust; /* next cluster number */
  633.     FAST uint32_t cluster; /* cluster number */
  634.     FAST uint32_t maxClust; /* maximum cluster number */
  635.     startClust = nextClust = pFatHdl->nextClust;
  636.     cluster    = pFatHdl->lastClust;
  637.     if ((startClust < DOS_MIN_CLUST) || (startClust >= pFatDesc->nFatEnts))
  638.         {
  639.         if ((startClust == 0) && (cluster == 0)) /* file just open */
  640.             startClust = pFileHdl->startClust;
  641.         if (startClust > pFatDesc->dos_fat_bad) /* end of file chain */
  642.          {
  643.             startClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  644.                                      cluster);
  645.          }
  646.         if ((startClust < DOS_MIN_CLUST) || (startClust >= pFatDesc->nFatEnts))
  647.             {
  648.             assert ((startClust == 0) || (startClust > pFatDesc->dos_fat_bad));
  649.             pFatHdl->nextClust = startClust;
  650.             return ERROR;
  651.             }
  652.         }
  653.     if ( (startClust < pFileHdl->contigEndPlus1) && 
  654.          (startClust >= pFileHdl->startClust) )
  655.         { /* in contiguous area */
  656.         cluster = startClust + numClusts; /* lastClust + 1 */
  657. /* numClusts can be avoided in the function calls and changed 
  658.  * to pFatDesc->fatGroupSize inside the function 
  659.  */
  660.         if (cluster >= pFileHdl->contigEndPlus1)
  661.             {
  662.             cluster = pFileHdl->contigEndPlus1; /* lastClust + 1 */
  663.             nextClust = pFatDesc->dos_fat_eof;
  664.             }
  665.         else
  666.             nextClust = cluster;
  667.         DBG_MSG (2, "Get from contiguous area.n", 1,2,3,4,5,6);
  668.         }
  669.     else
  670.         { /* out of contiguous area */
  671.         /* Count number of contiguous clusters starting from <startClust> */
  672.         maxClust = startClust + numClusts;
  673.         if (maxClust > pFatDesc->nFatEnts)
  674.             maxClust = pFatDesc->nFatEnts;
  675.         cluster = startClust; /* initialize cluster number */
  676.         while (cluster < maxClust)
  677.             {
  678.             nextClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  679.                                     cluster); /* follow chain */
  680.             if (nextClust != ++cluster)
  681.                 break; /* end of contiguous area */
  682.             }
  683.         if (pFatHdl->errCode == FAT_CBIO_ERR)
  684.             return ERROR;
  685.         }
  686. #ifdef __unused
  687.     assert ( ((nextClust >= DOS_MIN_CLUST)&&
  688.               (nextClust < pFatDesc->nFatEnts)) ||
  689.              ((nextClust > pFatDesc->dos_fat_bad) && 
  690.               (nextClust <= pFatDesc->dos_fat_eof)) );
  691. #endif
  692.     /* Store contents of last entry in contiguous section */
  693.     pFatHdl->nextClust = nextClust;
  694.     pFatHdl->lastClust = cluster - 1;
  695.     pFd->curSec = CLUST_TO_SEC (pVolDesc, startClust);
  696.     pFd->nSec   = (cluster - startClust) * pVolDesc->secPerClust;
  697.     DBG_MSG (2, "Get %ld clusters starting from cluster %ldn", 
  698.              cluster - startClust, startClust,3,4,5,6);
  699.     return OK;
  700.     } /* fat16ContigGet */
  701. /*******************************************************************************
  702. *
  703. * fat16MarkAlloc - allocate a contiguous set of clusters
  704. *
  705. *
  706. * RETURNS: ERROR if was unable to allocate requested amount of space
  707. */
  708. LOCAL STATUS fat16MarkAlloc
  709.     (
  710.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  711.     FAST uint32_t firstClust, /* initial cluster to search */
  712.     FAST uint32_t numClusts /* number of clusters needed */
  713.     )
  714.     {
  715.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pFd->pVolDesc->pFatDesc;
  716. /* pointer to FAT descriptor */
  717.     FAST uint32_t curClust; /* current cluster number */
  718.     assert ((firstClust >= DOS_MIN_CLUST) && 
  719.             (firstClust < pFatDesc->nFatEnts));
  720.     assert (numClusts <= (pFatDesc->nFatEnts - DOS_MIN_CLUST));
  721.     /* Build cluster chain in FAT */
  722.     for (curClust = firstClust; 
  723.          curClust < (firstClust + numClusts - 1); 
  724.          curClust++)
  725.         {
  726.         /* Each entry = next clust. num. */
  727.         if (ENTRY_WRITE (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  728.                          curClust, curClust + 1) != OK)
  729.             return ERROR; /* disk access error */
  730.         /* Update free clusters counter */
  731.         pFatDesc->fatEntFreeCnt--;
  732.         }
  733.     /* Mark last entry as end of file cluster chain */
  734.     if (ENTRY_WRITE (pFd, pFatDesc->dosFatDesc.activeCopyNum, curClust,
  735.                      pFatDesc->dos_fat_eof) != OK)
  736.         return ERROR; /* disk access error */
  737.     pFatDesc->fatEntFreeCnt--;
  738.     return OK;
  739.     } /* fat16MarkAlloc */
  740. /*******************************************************************************
  741. *
  742. * fat16GetNext - get/allocate next cluster for file
  743. *
  744. * This routine searches the File Allocation Table (FAT) for a sequence
  745. * of contiguous free clusters, and allocates clusters to extend the
  746. * current chain if requested to do so.
  747. *
  748. * RETURNS: resulting chain of sectors in the File Descriptor structure.
  749. */
  750. LOCAL STATUS fat16GetNext
  751.     (
  752.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  753.     FAST uint_t   allocPolicy /* allocation policy */
  754.     )
  755.     {
  756.     FAST DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  757. /* pointer to file handle */
  758.     FAST DOS_FAT_HDL_ID pFatHdl = &pFd->fatHdl;
  759. /* pointer to FAT handle */
  760.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  761. /* pointer to volume descriptor */
  762.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  763. /* pointer to FAT descriptor */
  764.     FAST uint32_t startClust; /*  */
  765.     FAST uint32_t numClusts; /*  */
  766.     FAST uint32_t prevClust; /*  */
  767.     FAST uint32_t firstClust; /*  */
  768.     FAST uint32_t contigCount; /* count of fit clusters */
  769.     FAST uint32_t curClust; /* current cluster number */
  770.     FAST uint32_t fatEntry; /* FAT entry */
  771.     FAST uint32_t maxClust; /* maximum cluster number */
  772.     FAST uint32_t pass; /*  */
  773.     /* Try to follow file chain */
  774.     if (fat16ContigGet (pFd, pFatDesc->fatGroupSize) == OK)
  775.         return OK;
  776.     if (pFatHdl->errCode == FAT_CBIO_ERR)
  777.         return ERROR;
  778.     /* Can't follow file chain */
  779.     if ((allocPolicy & FAT_ALLOC) == 0) /* not alloc */
  780.         return ERROR;
  781.     firstClust = pFatHdl->nextClust;
  782.     prevClust  = pFatHdl->lastClust;
  783.     startClust = 0;
  784.     /* Set number of clusters to allocate.
  785.      */
  786.     if (pFatDesc->groupAllocStart == 0) /* no free groups in prev. alloc. */
  787.         allocPolicy = FAT_ALLOC_ONE;
  788.     numClusts = (allocPolicy == (uint_t)FAT_ALLOC_ONE) ? 
  789. 1 : pFatDesc->fatGroupSize;
  790.     /* Set initial cluster number to try allocation from.
  791.      */
  792.     if (firstClust > pFatDesc->dos_fat_bad) /* end of file chain */
  793.         startClust = prevClust;
  794.     else if ((firstClust == 0) && (prevClust == 0)) /* it is a new file */
  795.         startClust = (allocPolicy == (uint_t)FAT_ALLOC_ONE) ?
  796.                      pFatDesc->clustAllocStart : pFatDesc->groupAllocStart;
  797.     if (startClust == 0)
  798.         {
  799.         errnoSet (S_dosFsLib_ILLEGAL_CLUSTER_NUMBER);
  800.         return ERROR;
  801.         }
  802.     /* Try finding a set of clusters starting at or after the initial one.
  803.      *   Continue searching upwards until end of FAT.
  804.      */
  805.     maxClust    = pFatDesc->nFatEnts - 1;
  806.     curClust    = startClust; /* start from initial cluster number */
  807.     firstClust  = 0;
  808.     contigCount = 0;
  809.     semTake (pFatDesc->allocSem, WAIT_FOREVER);
  810.     for (pass = 0; pass < 2; pass++)
  811.         {
  812.         while (curClust <= maxClust)
  813.             {
  814.             fatEntry = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  815.                                    curClust);
  816.             if ((fatEntry == FAT_CBIO_ERR)&&(pFatHdl->errCode == FAT_CBIO_ERR))
  817.                 goto group_alloc_error;
  818.             if (fatEntry == pFatDesc->dos_fat_avail)
  819.                 { /* free space */
  820.                 if (contigCount == 0)
  821.                     firstClust = curClust;/* this one will be new start */
  822.                 if (++contigCount == numClusts) /* one more found */
  823.                     goto group_alloc; /* quit if enough found */
  824.                 }
  825.             else /* allocated space */
  826.                 {
  827.                 contigCount = 0;
  828.                 }
  829.             curClust++;
  830.             } /* while */
  831.         /* 
  832.  * Try finding a contiguous area starting before the current cluster
  833.          * Note that the new contiguous area could include the initial cluster
  834.          */
  835.         maxClust    = startClust - 1;
  836.         curClust    = DOS_MIN_CLUST; /* start from lowest cluster number */
  837.         contigCount = 0;
  838.         } /* for */
  839.     if (firstClust == 0)
  840.         {
  841.         errnoSet (S_dosFsLib_DISK_FULL);
  842.         ERR_MSG (1, "!!! DISK FULL !!!n", 1,2,3,4,5,6);
  843.         goto group_alloc_error; /* could not find space */
  844.         }
  845.     pFatDesc->groupAllocStart = 0;
  846.     numClusts = 1;
  847. group_alloc: /* Allocate the found chain */
  848.     if (fat16MarkAlloc (pFd, firstClust, numClusts) != OK)
  849.         goto group_alloc_error;
  850.     semGive (pFatDesc->allocSem);
  851.     DBG_MSG (1, "Allocated %ld clusters starting from cluster %ldn", 
  852.              contigCount, firstClust,3,4,5,6);
  853.     /*  */
  854.     if (startClust == prevClust)
  855.         {
  856.         /* Add just allocated contiguous section to the file chain */
  857.         if (ENTRY_WRITE (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  858.                         prevClust, firstClust) != OK)
  859.             return ERROR;
  860.         if (firstClust == pFileHdl->contigEndPlus1)
  861.             pFileHdl->contigEndPlus1 = firstClust + numClusts;
  862.         DBG_MSG (1, " ----- Old end %ld -----n", prevClust,2,3,4,5,6);
  863.         }
  864.     else
  865.         {
  866.         /* Advance start allocation cluster number */
  867.         if (allocPolicy == (uint_t)FAT_ALLOC_ONE)
  868.             pFatDesc->clustAllocStart = firstClust + 1;
  869.         else
  870.             if (pFatDesc->groupAllocStart != 0)
  871.                 pFatDesc->groupAllocStart = firstClust + numClusts;
  872.         DBG_MSG (1, " ----- Old start %ld -----n", startClust,2,3,4,5,6);
  873.         DBG_MSG (1, " ----- New start %ld -----n", firstClust,2,3,4,5,6);
  874.         pFileHdl->startClust = firstClust;
  875.         pFileHdl->contigEndPlus1  = firstClust + numClusts;
  876.         }
  877.     pFatHdl->nextClust = pFatDesc->dos_fat_eof;
  878.     pFatHdl->lastClust = firstClust + numClusts - 1;
  879.     pFd->curSec = CLUST_TO_SEC (pVolDesc, firstClust);
  880.     pFd->nSec   = numClusts * pVolDesc->secPerClust;
  881.     return OK;
  882. group_alloc_error:
  883.     semGive (pFatDesc->allocSem);
  884.     return ERROR;
  885.     } /* fat16GetNext */
  886. /*******************************************************************************
  887. *
  888. * fat16Truncate - truncate chain starting from cluster
  889. *
  890. * This routine is used when removing files and directories as well as
  891. * when truncating files. It will follow
  892. * a chain of cluster entries in the file allocation table (FAT), freeing each
  893. * as it goes.
  894. *
  895. * RETURNS: OK or ERROR if invalid cluster encountered in chain
  896. */
  897. LOCAL STATUS fat16Truncate
  898.     (
  899.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  900.     FAST uint32_t sector, /* sector to truncate from */
  901.     FAST uint32_t flag /* FH_INCLUDE or FH_EXCLUDE */
  902.     )
  903.     {
  904.     FAST DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  905. /* pointer to file handle */
  906.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  907. /* pointer to volume descriptor */
  908.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  909. /* pointer to FAT descriptor */
  910.     FAST uint32_t curClust; /* current cluster */
  911.     FAST uint32_t nextClust; /* next cluster in chain */
  912.     FAST uint32_t cluster; /* cluster to truncate from */
  913.     if (sector == FH_FILE_START)
  914.         {
  915.         cluster = pFileHdl->startClust;
  916.         pFileHdl->contigEndPlus1 = 0;
  917.         if (cluster < DOS_MIN_CLUST)
  918.             {
  919.             errnoSet (S_dosFsLib_INVALID_PARAMETER); /* ??? */
  920.             return ERROR;
  921.             }
  922.         }
  923.     else
  924.         {
  925.         if (sector < pVolDesc->dataStartSec)
  926.             {
  927.             errnoSet (S_dosFsLib_INVALID_PARAMETER);
  928.             return ERROR;
  929.             }
  930.         cluster = SEC_TO_CLUST (pVolDesc, sector);
  931.         }
  932.     if (cluster >= pFatDesc->nFatEnts)
  933.         {
  934.         errnoSet (S_dosFsLib_INVALID_PARAMETER); /* ??? */
  935.         return ERROR;
  936.         }
  937.     switch (flag )
  938.         {
  939.         case FH_INCLUDE:
  940.             if ((sector == FH_FILE_START) || 
  941.                (((sector - pVolDesc->dataStartSec) % 
  942.                     pVolDesc->secPerClust) == 0))
  943.                 {
  944.                 curClust = cluster;
  945.                 break;
  946.                 }
  947.         case FH_EXCLUDE:
  948.             /* Read cluster to truncate from, including this one */
  949.     
  950.             curClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  951.                                    cluster);
  952.     
  953.             if (curClust > pFatDesc->dos_fat_bad)
  954.                 return OK; /* end of file */
  955.             if ((curClust < DOS_MIN_CLUST) || (curClust >= pFatDesc->nFatEnts))
  956.                 return ERROR; /*  */
  957.     
  958.             /* Mark passed cluster as end of file */
  959.     
  960.             if (ENTRY_WRITE (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  961.                              cluster, pFatDesc->dos_fat_eof) != OK)
  962.                 return ERROR; /* disk access error */
  963.             break;
  964.         default:
  965.             {
  966.             errnoSet (S_dosFsLib_INVALID_PARAMETER);
  967.             return ERROR;
  968.             }
  969.         }
  970.     if ( (curClust < pFileHdl->contigEndPlus1) && 
  971.          (curClust >= pFileHdl->startClust) )
  972.         pFileHdl->contigEndPlus1 = curClust;
  973.     if (pFatDesc->groupAllocStart == 0)
  974.         pFatDesc->groupAllocStart = curClust;
  975.    /* Adjust single cluster allocation start point to start of the disk */
  976.     if (pFatDesc->clustAllocStart > curClust)
  977.         pFatDesc->clustAllocStart = curClust;
  978.     /* Free a chain of clusters */
  979.     while ((curClust >= DOS_MIN_CLUST) && (curClust < pFatDesc->nFatEnts))
  980.         {
  981.         /* get next cluster in chain */
  982.         nextClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  983.                                 curClust);
  984.         /* free current cluster (mark cluster in FAT as available) */
  985.         if (ENTRY_WRITE (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  986.                          curClust, pFatDesc->dos_fat_avail) != OK)
  987.             return ERROR;
  988.         /* Update free clusters counter */
  989.         pFatDesc->fatEntFreeCnt++;
  990.         curClust = nextClust; /* do next cluster */
  991.         }
  992.     if (curClust <= pFatDesc->dos_fat_bad) /* If not end of file */
  993.         return ERROR;
  994.     return OK;
  995.     } /* fat16Truncate */
  996. /*******************************************************************************
  997. *
  998. * fat16Seek - seek cluster within file chain
  999. *
  1000. * Returns a particular cluster relative to the cluster chain beginning
  1001. * which is noted in the file descriptor structure.
  1002. * It is used to seek in to a file.
  1003. *
  1004. * RETURNS: requested position is returned in the file descriptor structure
  1005. */
  1006. LOCAL STATUS fat16Seek
  1007.     (
  1008.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1009.     FAST uint32_t sector, /* sector to seek from */
  1010.     FAST uint32_t sectOff /* sector offset within file */
  1011.     )
  1012.     {
  1013.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1014. /* pointer to volume descriptor */
  1015.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  1016. /* pointer to FAT descriptor */
  1017.     FAST uint32_t nextClust; /* next cluster number */
  1018.     FAST uint32_t count; /* count of clusters */
  1019.     FAST uint32_t cluster; /* cluster to seek from */
  1020.     FAST uint32_t clustOff; /*  */
  1021.     if (sector == FH_FILE_START)
  1022.         {
  1023.         pFd->fatHdl.nextClust  = 0;
  1024.         pFd->fatHdl.lastClust  = 0;
  1025.         pFd->fatHdl.cbioCookie = 0;
  1026.         pFd->curSec = 0;
  1027.         pFd->nSec   = 0;
  1028.         cluster = pFd->pFileHdl->startClust;
  1029.         if (cluster == 0)
  1030.             return OK;
  1031.         if (cluster < DOS_MIN_CLUST)
  1032.             return ERROR;
  1033.         }
  1034.     else
  1035.         {
  1036.         if (sector < pVolDesc->dataStartSec)
  1037.             return ERROR;
  1038.         /* cluster to seek from */
  1039.         cluster = SEC_TO_CLUST (pVolDesc, sector);
  1040.         /* offset from start of cluster */
  1041.         sectOff += (sector - pVolDesc->dataStartSec) % pVolDesc->secPerClust;
  1042.         }
  1043.     if (cluster >= pFatDesc->nFatEnts)
  1044.         return ERROR;
  1045.     clustOff = sectOff / pVolDesc->secPerClust;
  1046.     sectOff %= pVolDesc->secPerClust;
  1047.     /* Skip contiguous area */
  1048.     if ( (cluster < pFd->pFileHdl->contigEndPlus1) && 
  1049.          (cluster >= pFd->pFileHdl->startClust) )
  1050.         {
  1051.         count = min (clustOff, pFd->pFileHdl->contigEndPlus1 - cluster - 1);
  1052.         cluster += count;
  1053.         clustOff -= count;
  1054.         }
  1055.     for (count = 0; count < clustOff; count++)
  1056.         {
  1057.         nextClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  1058.                                 cluster); /* follow chain */
  1059.         /* If end of cluster chain, bad cluster number or disk access error */
  1060.         if ((nextClust < DOS_MIN_CLUST) || (nextClust >= pFatDesc->nFatEnts))
  1061.             return ERROR;
  1062.         cluster = nextClust; /* do next cluster */
  1063.         }
  1064.     pFd->fatHdl.nextClust = cluster;
  1065.     if (fat16ContigGet (pFd, pFatDesc->fatGroupSize) != OK)
  1066.         return ERROR;
  1067.     pFd->curSec += sectOff;
  1068.     pFd->nSec   -= sectOff;
  1069.     return OK;
  1070.     } /* fat16Seek */
  1071. /*******************************************************************************
  1072. *
  1073. * fat16NFree - count number of free bytes on disk
  1074. *
  1075. *
  1076. * RETURNS: amount of free space is returned in file descriptor handle
  1077. */
  1078. LOCAL fsize_t fat16NFree
  1079.     (
  1080.     FAST DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1081.     )
  1082.     {
  1083.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1084. /* pointer to volume descriptor */
  1085.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  1086. /* pointer to FAT descriptor */
  1087.     FAST uint32_t clustNum; /* cluster number */
  1088.     FAST uint32_t fatEntry; /*  */
  1089.     FAST uint32_t freeCount; /*  */
  1090.     freeCount = pFatDesc->fatEntFreeCnt;
  1091.     if(freeCount == 0xffffffff)
  1092.         {
  1093.         freeCount = 0;
  1094.         /* Read file allocation table (FAT) to find unused clusters */
  1095.         for (clustNum=DOS_MIN_CLUST; clustNum < pFatDesc->nFatEnts; clustNum++)
  1096.             {
  1097.             fatEntry = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  1098.                                    clustNum);
  1099.             if ((fatEntry == FAT_CBIO_ERR)&&
  1100.                 (pFd->fatHdl.errCode == FAT_CBIO_ERR))
  1101.                 return ERROR;
  1102.             if (fatEntry == pFatDesc->dos_fat_avail)
  1103.                 freeCount++;
  1104.             }
  1105.         pFatDesc->fatEntFreeCnt = freeCount;
  1106.         }
  1107.     return ( (((fsize_t)freeCount) * pVolDesc->secPerClust) << 
  1108.              pVolDesc->secSizeShift );
  1109.     } /* fat16NFree */
  1110. /*******************************************************************************
  1111. *
  1112. * fat16ContigChk - check file chain for contiguity
  1113. *
  1114. * RETURNS: ERROR if an illegal cluster number is encountered
  1115. */
  1116. LOCAL STATUS fat16ContigChk
  1117.     (
  1118.     FAST DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1119.     )
  1120.     {
  1121.     FAST DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  1122. /* pointer to file handle */
  1123.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pFd->pVolDesc->pFatDesc;
  1124. /* pointer to FAT handler descriptor */
  1125.     FAST uint32_t nextClust; /* next cluster number */
  1126.     FAST uint32_t cluster; /* cluster number */
  1127.     cluster = pFileHdl->startClust;
  1128.     if (cluster == 0)
  1129.         return OK;
  1130.     if ((cluster < DOS_MIN_CLUST) || (cluster >= pFatDesc->nFatEnts))
  1131.         {
  1132.         errnoSet (S_dosFsLib_ILLEGAL_CLUSTER_NUMBER);
  1133.         return ERROR;
  1134.         }
  1135.     FOREVER
  1136.         {
  1137.         nextClust = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  1138.                                 cluster); /* follow chain */
  1139.         if (nextClust != ++cluster)
  1140.             break; /* end of contiguous area */
  1141.         }
  1142.     if (pFd->fatHdl.errCode == FAT_CBIO_ERR)
  1143.         return ERROR;
  1144.     pFileHdl->contigEndPlus1 = cluster;
  1145.     if (nextClust > pFatDesc->dos_fat_bad) /* end of file chain */
  1146.         return OK;
  1147.     if ((nextClust < DOS_MIN_CLUST) || (nextClust >= pFatDesc->nFatEnts))
  1148. {
  1149.         errnoSet (S_dosFsLib_ILLEGAL_CLUSTER_NUMBER);
  1150. }
  1151.     return ERROR;
  1152.     } /* fat16ContigChk */
  1153. /*******************************************************************************
  1154. *
  1155. * fat16MaxContigClustersGet - return size of largest contiguous space on disk
  1156. * RETURNS: max contiguous space in clusters
  1157. */ 
  1158.  
  1159. LOCAL size_t fat16MaxContigClustersGet
  1160.     (
  1161.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1162.     FAST uint32_t * pMaxStart /* were to return start clust */
  1163.     )
  1164.     {
  1165.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pFd->pVolDesc->pFatDesc;
  1166. /* pointer to FAT handler descriptor */
  1167.     FAST uint32_t fatEntry; /*  */
  1168.     FAST uint32_t curClust; /*  */
  1169.     FAST uint32_t firstContig; /* 1st clust. of contig area */
  1170.     FAST uint32_t contigCount; /* count of fit clusters */
  1171.     FAST uint32_t maxStart; /*  */
  1172.     FAST uint32_t maxCount; /*  */
  1173.     firstContig = DOS_MIN_CLUST;
  1174.     contigCount = 0;
  1175.     maxStart    = 0;
  1176.     maxCount    = 0;
  1177.     for (curClust = DOS_MIN_CLUST; curClust < pFatDesc->nFatEnts; curClust++)
  1178.         {
  1179.         fatEntry = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  1180.                                curClust);
  1181.         if ((fatEntry == FAT_CBIO_ERR)&&(pFd->fatHdl.errCode == FAT_CBIO_ERR))
  1182.             return 0;
  1183.         if (fatEntry == pFatDesc->dos_fat_avail)
  1184.             { /* free space */
  1185.             contigCount++; /* one more found */
  1186.             }
  1187.         else
  1188.             {
  1189.             /* Check for maximum */
  1190.             if (contigCount > maxCount)
  1191.                 {
  1192.                 maxStart = firstContig;
  1193.                 maxCount = contigCount;
  1194.                 }
  1195.             firstContig = curClust + 1; /* next one will be new start */
  1196.             contigCount = 0;
  1197.             }
  1198.         } /* for */
  1199.     if (contigCount > maxCount)
  1200.         {
  1201.         maxStart = firstContig;
  1202.         maxCount = contigCount;
  1203.         }
  1204.     *pMaxStart = maxStart;
  1205.     return (maxCount);
  1206.     } /* fat16MaxContigClustersGet */
  1207. /*******************************************************************************
  1208. *
  1209. * fat16ContigAlloc - allocate <numSect> contiguous chain
  1210. *
  1211. * This function employs the Best Fit algorithm to locate a
  1212. * contiguous fragment of space for the requested size
  1213. *
  1214. * RETURNS: ERROR if requested space is not available
  1215. */
  1216. LOCAL STATUS fat16ContigAlloc
  1217.     (
  1218.     FAST DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1219.     FAST uint32_t number /* number of sectors needed */
  1220.     )
  1221.     {
  1222.     FAST DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  1223. /* pointer to file handle */
  1224.     FAST DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1225. /* pointer to volume descriptor */
  1226.     FAST MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  1227. /* pointer to FAT handler descriptor */
  1228.     FAST uint32_t fatEntry; /*  */
  1229.     FAST uint32_t curClust; /*  */
  1230.     FAST uint32_t firstContig; /* 1st clust. of contig area */
  1231.     FAST uint32_t contigCount; /* count of fit clusters */
  1232.     FAST uint32_t bestCount; /*  */
  1233.          uint32_t bestStart; /*  */
  1234.     if (number == (uint32_t)CONTIG_MAX)
  1235.         {
  1236.         semTake (pFatDesc->allocSem, WAIT_FOREVER);
  1237.         number = fat16MaxContigClustersGet (pFd, &bestStart);
  1238.         if (number == 0)
  1239.             {
  1240.             errnoSet (S_dosFsLib_DISK_FULL);
  1241.             goto contig_alloc_error;
  1242.             }
  1243.         goto contig_alloc;
  1244.         }
  1245.     /* Convert number of sectors needed to number of clusters */
  1246.     number = (number + pVolDesc->secPerClust - 1) / pVolDesc->secPerClust;
  1247.     firstContig = DOS_MIN_CLUST;
  1248.     contigCount = 0;
  1249.     bestStart   = 0;
  1250.     bestCount   = pFatDesc->nFatEnts;
  1251.     semTake (pFatDesc->allocSem, WAIT_FOREVER);
  1252.     for (curClust = DOS_MIN_CLUST; 
  1253.     /* firstContig <= (pFatDesc->nFatEnts - number); ??? for 1st fit ??? */
  1254.          curClust < (pFatDesc->nFatEnts - number);
  1255.          curClust++)
  1256.         {
  1257.         fatEntry = ENTRY_READ (pFd, pFatDesc->dosFatDesc.activeCopyNum,
  1258.                                curClust);
  1259.         if ((fatEntry == FAT_CBIO_ERR)&&(pFd->fatHdl.errCode == FAT_CBIO_ERR))
  1260.             goto contig_alloc_error;
  1261. #if FALSE /* best fit */
  1262.         if (fatEntry == pFatDesc->dos_fat_avail)
  1263.             { /* free space */
  1264.             contigCount++; /* one more found */
  1265.             }
  1266.         else
  1267.             {
  1268.             /* Check for best fit */
  1269.             if ((contigCount >= number) && (contigCount < bestCount))
  1270.                 { /* most close from above */
  1271.                 bestStart = firstContig;
  1272.                 bestCount = contigCount;
  1273.                 if (contigCount == number)
  1274.                     break; /* fit exactly */
  1275.                 }
  1276.             firstContig = curClust + 1; /* next one will be new start */
  1277.             contigCount = 0;
  1278.             }
  1279. #else /* 1st fit */
  1280.         if (fatEntry == pFatDesc->dos_fat_avail)
  1281.             { /* free space */
  1282.             if (++contigCount == number) /* one more found */
  1283.                 {
  1284.                 bestStart = firstContig; /* ??? temporary solution */
  1285.                 bestCount = contigCount; /* ??? temporary solution */
  1286.                 goto contig_alloc; /* quit if enough found */
  1287.                 }
  1288.             }
  1289.         else /* allocated space */
  1290.             {
  1291.             firstContig = curClust + 1; /* next one will be new start */
  1292.             contigCount = 0;
  1293.             }
  1294. #endif /* FALSE */
  1295.         } /* for */
  1296.     if (bestStart == 0)
  1297.         {
  1298.         if (contigCount < number)
  1299.             {
  1300.             errnoSet (S_dosFsLib_NO_CONTIG_SPACE);
  1301.             goto contig_alloc_error;
  1302.             }
  1303.         bestStart = firstContig;
  1304.         }
  1305. contig_alloc:
  1306.     if (fat16MarkAlloc (pFd, bestStart, number) != OK)
  1307.         goto contig_alloc_error;
  1308.     semGive (pFatDesc->allocSem);
  1309.     DBG_MSG (1, "Allocated %ld clusters starting from cluster %ldn", 
  1310.              number, bestStart,3,4,5,6);
  1311.     pFileHdl->startClust = bestStart;
  1312.     pFileHdl->contigEndPlus1 = bestStart + number;
  1313.     return OK;
  1314. contig_alloc_error:
  1315.     semGive (pFatDesc->allocSem);
  1316.     return ERROR;
  1317.     } /* fat16ContigAlloc */
  1318. /*******************************************************************************
  1319. *
  1320. * fat16MaxContigSectors - max free contiguous chain length in sectors
  1321. * RETURNS: size of the max contiguous free space in sectors
  1322. */ 
  1323.  
  1324. static size_t fat16MaxContigSectors
  1325.     (
  1326.     FAST DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1327.     )
  1328.     {
  1329.     uint32_t maxStart;
  1330.     return (fat16MaxContigClustersGet (pFd, &maxStart) * pFd->pVolDesc->secPerClust);
  1331.     } /* fat16MaxContigSectors */
  1332. /*******************************************************************************
  1333. *
  1334. * fat16Show - display handler specific data
  1335. *
  1336. * RETURNS: N/A.
  1337. */
  1338. LOCAL void fat16Show 
  1339.     (
  1340.     DOS_VOLUME_DESC_ID pVolDesc /* pointer to volume descriptor */
  1341.     )
  1342.     {
  1343.     MS_FAT_DESC_ID pFatDesc = (MS_FAT_DESC_ID) pVolDesc->pFatDesc;
  1344.     DOS_FILE_DESC fileDesc = { 0 }; /* pointer to file descriptor */
  1345.     fileDesc.pVolDesc = pVolDesc;
  1346.     printf ("FAT handler information:n");
  1347.     printf ("------------------------n");
  1348.     printf      (" - allocation group size: %ld clustersn", 
  1349. pFatDesc->fatGroupSize);
  1350.     print64Fine (" - free space on volume: ", fat16NFree (&fileDesc), 
  1351.                 " bytesn", 10);
  1352.     } /* fat16Show */
  1353. /*******************************************************************************
  1354. *
  1355. * fat16ClustValueSet - set value to a particular FAT entry
  1356. *
  1357. * RETURNS: OK or ERROR
  1358. */
  1359. STATUS fat16ClustValueSet
  1360.     (
  1361.     DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1362.     uint32_t copyNum, /* fat copy number */
  1363.     uint32_t clustNum, /* cluster number to check */
  1364.     uint32_t value,
  1365.     uint32_t nextClust
  1366.     )
  1367.     {
  1368.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1369.     MS_FAT_DESC_ID pFatDesc = (void *) pVolDesc->pFatDesc;
  1370.     
  1371.     switch (value)
  1372.         {
  1373.         case DOS_FAT_AVAIL:
  1374.             value = pFatDesc->dos_fat_avail;
  1375.             break;
  1376.         case DOS_FAT_EOF:
  1377.             value = pFatDesc->dos_fat_eof;
  1378.             break;
  1379.         case DOS_FAT_BAD:
  1380.             assert (FALSE);
  1381.             value = pFatDesc->dos_fat_bad;
  1382.             break;
  1383.         case DOS_FAT_RESERV:
  1384.             assert (FALSE);
  1385.             value = pFatDesc->dos_fat_reserv;
  1386.             break;
  1387.         case DOS_FAT_ALLOC:
  1388.             assert ((nextClust >= DOS_MIN_CLUST) &&
  1389.                     (nextClust < pFd->pVolDesc->nFatEnts));
  1390.             value = nextClust;
  1391.             break;
  1392.     
  1393.       case DOS_FAT_RAW:
  1394.          value = nextClust;
  1395.          break;
  1396.       case DOS_FAT_SET_ALL:
  1397.          {
  1398.          CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  1399.          cookie_t cookie = (cookie_t) NULL;
  1400.          uint8_t wBuf [64];
  1401.          /* fill one sector (<value> = sector number) */
  1402.          value = pFatDesc->fatStartSec + (copyNum * pVolDesc->secPerFat);
  1403.          bfill ((char *)wBuf, sizeof (wBuf), nextClust );
  1404.          for ( clustNum = 0;
  1405.   clustNum < pFd->pVolDesc->bytesPerSec;
  1406.                   clustNum += sizeof (wBuf) )
  1407.           {
  1408.           if (cbioBytesRW (pCbio, value, clustNum, (addr_t)wBuf,
  1409.                                          sizeof (wBuf), CBIO_WRITE,
  1410.                                          &cookie) != OK)
  1411.               {
  1412.               return ERROR;
  1413.               }
  1414.           }
  1415.          /* copy first sector to other FAT sectors */
  1416.          for ( nextClust = value++;
  1417.                   value < nextClust + pVolDesc->secPerFat;
  1418.             value ++ )
  1419.           {
  1420.           if (cbioBlkCopy (pCbio, nextClust, value, 1) != OK)
  1421.               return ERROR;
  1422.           }
  1423.          return (OK);
  1424.          }
  1425.         case DOS_FAT_INVAL:
  1426.         default:
  1427.             assert (FALSE);
  1428.         }
  1429.     return ENTRY_WRITE (pFd, copyNum, clustNum, value);
  1430.     } /* fat16ClustValueSet */
  1431. /*******************************************************************************
  1432. *
  1433. * fat16ClustValueGet - get value corresponding to this cluster number in FAT
  1434. *
  1435. * Get the value of a particular FAT entry, resulting in the
  1436. * number of the next cluster in chain, or one of the following:
  1437. *
  1438. * DOS_FAT_AVAIL  - available cluster
  1439. * DOS_FAT_EOF    - end of file's cluster chain
  1440. * DOS_FAT_BAD    - bad cluster (damaged media)
  1441. * DOS_FAT_ALLOC  - allocated cluster
  1442. * DOS_FAT_INVAL  - invalid cluster (illegal value)
  1443. * DOS_FAT_RESERV - reserved cluster
  1444. *
  1445. * RETURNS: cluster number or special value above
  1446. */
  1447. uint32_t fat16ClustValueGet 
  1448.     (
  1449.     DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1450.     uint32_t copyNum, /* fat copy number */
  1451.     uint32_t clustNum, /* cluster number to check */
  1452.     uint32_t * pNextClust /*  */
  1453.     )
  1454.     {
  1455.     MS_FAT_DESC_ID pFatDesc = (void *) pFd->pVolDesc->pFatDesc;
  1456.     clustNum &= 0x0fffffff; /* high 4 bits in FAT32 are reserved */
  1457.     if (clustNum == 0)
  1458.         return DOS_FAT_AVAIL;
  1459.     if (clustNum > pFatDesc->dos_fat_bad)
  1460.         return DOS_FAT_EOF;
  1461.     if (clustNum == pFatDesc->dos_fat_bad)
  1462.         return DOS_FAT_BAD;
  1463.     if (clustNum >= pFatDesc->dos_fat_reserv)
  1464.         return DOS_FAT_RESERV;
  1465.     if ((clustNum < DOS_MIN_CLUST) || (clustNum >= pFd->pVolDesc->nFatEnts))
  1466.         return DOS_FAT_INVAL;
  1467.     *pNextClust = ENTRY_READ (pFd, copyNum, clustNum);
  1468.     if (pFd->fatHdl.errCode == FAT_CBIO_ERR)
  1469.         return DOS_FAT_ERROR;
  1470.     return DOS_FAT_ALLOC;
  1471.     } /* fat16ClustValueGet */
  1472. /*******************************************************************************
  1473. *
  1474. * fat16VolUnmount - unmount volume
  1475. *
  1476. * This routine frees all resources, that were allocated for the volume.
  1477. *
  1478. * RETURNS: N/A
  1479. */
  1480. LOCAL void fat16VolUnmount 
  1481.     (
  1482.     DOS_VOLUME_DESC_ID pVolDesc /*  */
  1483.     )
  1484.     {
  1485.     return;
  1486.     } /* fat16VolUnmount */
  1487. /*******************************************************************************
  1488. *
  1489. * fat16VolMount - mount volume
  1490. *
  1491. * Initialize a new volume
  1492. *
  1493. * RETURNS: ERROR if FAT is illegal
  1494. */
  1495. STATUS fat16VolMount 
  1496.     (
  1497.     DOS_VOLUME_DESC_ID pVolDesc, /*  */
  1498.     void * arg /* unused */
  1499.     )
  1500.     {
  1501.     FAST CBIO_DEV_ID pCbio = pVolDesc->pCbio;
  1502. /* pointer to CBIO device */
  1503.     MS_FAT_DESC_ID pFat16Desc;
  1504.     DOS_FILE_DESC fileDesc = { 0 }; /* file descriptor */
  1505.     uint8_t fsinfoBuf [8]; /* FSINFO sector data */
  1506.     /*
  1507.      * if previous volume had alternative FAT structure,
  1508.      * unmount previous FAT handler and
  1509.      * allocate FAT handler descriptor
  1510.      */
  1511.     if (pVolDesc->pFatDesc != NULL &&
  1512.         pVolDesc->pFatDesc->volUnmount != fat16VolUnmount &&
  1513.         pVolDesc->pFatDesc->volUnmount != NULL)
  1514.         {
  1515.         /* Unmount previous FAT handler */
  1516.         pVolDesc->pFatDesc->volUnmount( pVolDesc );
  1517.         }
  1518.     /* Allocate FAT handler descriptor */
  1519.     pVolDesc->pFatDesc = 
  1520. KHEAP_REALLOC((char *)pVolDesc->pFatDesc, sizeof( *pFat16Desc));
  1521.     if (pVolDesc->pFatDesc == NULL)
  1522.         return ERROR;
  1523.     pFat16Desc = (void *)pVolDesc->pFatDesc;
  1524.     bzero( (void *)pFat16Desc, sizeof( *pFat16Desc) ); 
  1525.     fileDesc.pVolDesc = pVolDesc; /* for fat16NFree() */
  1526.  
  1527.     /* Number of FAT entries = count of clusters available for files + 2 */
  1528.     pVolDesc->nFatEnts = pFat16Desc->nFatEnts = 
  1529. ( ((pVolDesc->totalSec - pVolDesc->dataStartSec) / 
  1530. pVolDesc->secPerClust) + DOS_MIN_CLUST );
  1531.     if (pVolDesc->fatType == FAT32)
  1532.         {
  1533.         /* activeFatStart ??? */
  1534.         if (cbioBytesRW (pCbio, FSINFO_SEC_NUM, FSINFO_FREE_CLUSTS, 
  1535. (addr_t)fsinfoBuf, sizeof (fsinfoBuf), CBIO_READ, NULL) != OK)
  1536.             goto mount_error;
  1537.         /* Fill free FAT entries count */
  1538.         pFat16Desc->fatEntFreeCnt   = DISK_TO_VX_32 (&fsinfoBuf[0]);
  1539.         /* Fill start cluster for cluster groups allocation */
  1540.         pFat16Desc->groupAllocStart = DISK_TO_VX_32 (&fsinfoBuf[4]);
  1541.         if ( (pFat16Desc->groupAllocStart < DOS_MIN_CLUST) ||
  1542.              (pFat16Desc->groupAllocStart >= pFat16Desc->nFatEnts) )
  1543.             pFat16Desc->groupAllocStart = DOS_MIN_CLUST;
  1544.         pFat16Desc->entryRead       = fat32EntRead;
  1545.         pFat16Desc->entryWrite      = fat32EntWrite;
  1546.         pFat16Desc->dos_fat_reserv  = 0x0ffffff0;
  1547.         pFat16Desc->dos_fat_bad     = 0x0ffffff7;
  1548.         pFat16Desc->dos_fat_eof     = 0x0fffffff;
  1549.         }
  1550.     else
  1551.         {
  1552.         /* activeFatStart ??? */
  1553.         /* -1 in fatEntFreeCnt cause fat16NFree() to fill this field */
  1554.         pFat16Desc->fatEntFreeCnt = -1;
  1555.         /* Fill cluster groups allocation start cluster */
  1556.         pFat16Desc->groupAllocStart = DOS_MIN_CLUST;
  1557.  
  1558.         if (pVolDesc->fatType == FAT16)
  1559.             {
  1560.             pFat16Desc->entryRead       = fat16EntRead;
  1561.             pFat16Desc->entryWrite      = fat16EntWrite;
  1562.             pFat16Desc->dos_fat_reserv  = 0xfff0;
  1563.             pFat16Desc->dos_fat_bad     = 0xfff7;
  1564.             pFat16Desc->dos_fat_eof     = 0xffff;
  1565.             }
  1566.         else if (pVolDesc->fatType == FAT12)
  1567.             {
  1568.             pFat16Desc->entryRead       = fat12EntRead;
  1569.             pFat16Desc->entryWrite      = fat12EntWrite;
  1570.             pFat16Desc->dos_fat_reserv  = 0xff0;
  1571.             pFat16Desc->dos_fat_bad     = 0xff7;
  1572.             pFat16Desc->dos_fat_eof     = 0xfff;
  1573.             }
  1574.         else
  1575.             goto mount_error;
  1576.         }
  1577.     pFat16Desc->dosFatDesc.volUnmount  = fat16VolUnmount;
  1578.     pFat16Desc->dosFatDesc.getNext     = fat16GetNext;
  1579.     pFat16Desc->dosFatDesc.contigChk   = fat16ContigChk;
  1580.     pFat16Desc->dosFatDesc.show        = fat16Show;
  1581.     pFat16Desc->dosFatDesc.truncate    = fat16Truncate;   /*FIOTRUNC*/
  1582.     pFat16Desc->dosFatDesc.seek        = fat16Seek;       /*FIOSEEK*/
  1583.     pFat16Desc->dosFatDesc.contigAlloc = fat16ContigAlloc;/*FIOCONTIG*/
  1584.     pFat16Desc->dosFatDesc.maxContig   
  1585.                                  = fat16MaxContigSectors; /*FIONCONTIG*/
  1586.     pFat16Desc->dosFatDesc.nFree       = fat16NFree;      /*FIONFREE*/
  1587.     pFat16Desc->dosFatDesc.flush       = fat16MirrorSect; /*FIOFLUSH*/
  1588.     pFat16Desc->dosFatDesc.syncToggle  = fat16SyncToggle;
  1589.     pFat16Desc->dosFatDesc.clustValueSet = fat16ClustValueSet;
  1590.     pFat16Desc->dosFatDesc.clustValueGet = fat16ClustValueGet;
  1591.     pFat16Desc->fatStartSec     = pVolDesc->nReservedSecs;
  1592.     /* current version uses only fat copy 0 as active */
  1593.     
  1594.     pFat16Desc->dosFatDesc.activeCopyNum = 0;
  1595.     /* Number of clusters in allocation group = ??? 
  1596.      * must be calculated in future
  1597.      */
  1598.     pFat16Desc->fatGroupSize    = pFat16Desc->nFatEnts / fatClugFac + 1;
  1599.     pFat16Desc->dos_fat_avail   = 0x00000000;
  1600.     pFat16Desc->syncEnabled = TRUE; /* enable FAT copies mirroring */
  1601.     pFat16Desc->allocSem = semMCreate (ALLOC_SEM_OPTIONS);
  1602.     if (NULL == pFat16Desc->allocSem)
  1603. {
  1604.         goto mount_error;
  1605. }
  1606.     pFat16Desc->clustAllocStart = DOS_MIN_CLUST;
  1607.     
  1608.     fat16NFree (&fileDesc); /* fill 'fatEntFreeCnt' if it equals -1 */
  1609.     return OK;
  1610. mount_error:
  1611.     fat16VolUnmount (pVolDesc);
  1612.     return ERROR;
  1613.     } /* fat16VolMount */
  1614. /*****************************************************************************
  1615. *
  1616. * dosFsFatInit - init handler and install it into dosFsLib
  1617. *
  1618. * This function must be called to install the FAT handler,
  1619. * which is mandatory, once during system initialization.
  1620. *
  1621. * RETURNS: OK or ERROR if failed to install
  1622. */
  1623. STATUS dosFsFatInit ( void )
  1624.     {
  1625.     DOS_HDLR_DESC hdlr;
  1626.     hdlr.id       = DOS_FATALL_HDLR_ID;
  1627.     hdlr.mountRtn = fat16VolMount;
  1628.     hdlr.arg      = NULL;
  1629.     return dosFsHdlrInstall (dosFatHdlrsList, &hdlr);
  1630.     } /* dosFsFatInit() */