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

VxWorks

开发平台:

C/C++

  1. /* dosChkLib.c - DOS file system sanity check utility */ 
  2. /* Copyright 1999-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,10nov01,jkf  SPR#67890, chkdsk writes to RDONLY device
  8. 01n,18oct01,jkf   warning cleaning.
  9. 01n,18sep00,nrj   Fixed SPR#34108, check the write mode before synchronzing the
  10.                   FAT
  11. 01m,29feb00,jkf   T3 changes
  12. 01l,31aug99,jkf   changes for new CBIO API.  Changed date check logic.
  13.                   Added docs for date check.  Added global for date
  14.                   check.  Default debug global to zero.
  15. 01k,31jul99,jkf   T2 merge, tidiness & spelling.
  16. 01j,28sep98,vld   gnu extensions dropped from DBG_MSG/ERR_MSG macros
  17. 01i,13oct98,vld   fixed message positioning on  screen, - 'b' avoided.
  18. 01h,23sep98,vld   added usage of reserved FAT32 copy for data buffering
  19.   in reduced memory environments, bit map of FAT entries
  20.   is filled in parallel with 4-byte MAP array in this case
  21. 01g,23sep98,vld   fixed bug of backward time setting
  22. 01f,23sep98,vld   disable FAT mirroring while check disk in progress;
  23.   synchronize FAT copies after check disk.
  24. 01e,17sep98,vld   FAT copy number argument added to calls of
  25.   clustValueSet()/clustValueGet();
  26. 01d,08jul98,vld   print64Lib.h moved to h/private directory.
  27. 01c,08jul98,vld   fixed bug in dosFsChkTree() of deletion
  28.   invalid name entry through other file descriptor.
  29. 01b,02jul98,lrn   review doc and messages
  30. 01a,18jan98,vld   written, preliminary
  31. */
  32. /*
  33. DESCRIPTION
  34. This library is part of dosFsLib, it manages the Consistency Checking
  35. procedure, which may be invoked automatically during device mount
  36. procedure, or manual by means of the FIOCHKDSK ioctl.
  37. be checked which is managed by that particular handler.
  38. Check disk requires temporary buffer large enough to store information
  39. on every FAT entry. Memory requirements can be a problem for FAT32
  40. volumes. If no enough available, temporary data is buffered in
  41. second (reserved) FAT copy, that can take extremely long time on a 
  42. slow processors.
  43. The minimum acceptable system time & date is set by the global variable
  44. (time_t) dosChkMinDate.  If the system time is greater than that value, 
  45. it is assumed that a hardware clock mechanism is in place and the time 
  46. setting is honored.  If dosChkLib detects that the system is set to an 
  47. earlier date than dosChkMinDate, the system date will be adjusted to 
  48. either the most recent date found on the file system volume or the minimum 
  49. acceptable system time & date, whichever is later.  A warning indicicating 
  50. the new system time is displayed on the console when this occurs.
  51. Do not set dosChkMinDate prior to 1980!
  52. INTERNAL
  53. */
  54. /* includes */
  55. #include "vxWorks.h"
  56. #include "private/dosFsVerP.h"
  57. #include "stat.h"
  58. #include "time.h"
  59. #include "dirent.h"
  60. #include "stdio.h"
  61. #include "stdlib.h"
  62. #include "string.h"
  63. #include "errnoLib.h"
  64. #include "memLib.h"
  65. #include "taskLib.h"
  66. #include "time.h"
  67. #include "timers.h"
  68. #include "tickLib.h"
  69. #include "dosFsLib.h"
  70. #include "private/print64Lib.h"
  71. #include "private/dosFsLibP.h"
  72. /* defines */
  73. /* macros */
  74. #undef DBG_MSG
  75. #undef ERR_MSG
  76. #undef NDEBUG
  77. #ifdef DEBUG
  78. #   undef LOCAL
  79. #   define LOCAL
  80. #   undef ERR_SET_SELF
  81. #   define ERR_SET_SELF
  82. #   define DBG_MSG( lvl, fmt, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 )
  83. { if( (lvl) <= dosChkDebug )
  84.     printErr( "%s : %d : " fmt,
  85.                __FILE__, __LINE__, arg1,arg2,
  86.        arg3,arg4,arg5,arg6,arg7,arg8 ); }
  87. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  88.         { logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  89.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  90. #else /* NO DEBUG */
  91. #   define NDEBUG
  92. #   define DBG_MSG(lvl,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)  {}
  93. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  94. { if( (lvl) <= dosChkDebug ) 
  95.             logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  96.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  97. #endif /* DEBUG */
  98. #include "assert.h"
  99. #define DOSCHKLIB_YEAR_VALUE (((60*60)*24)*365*21)
  100. int dosChkDebug = 0;
  101. time_t dosChkMinDate = (time_t) DOSCHKLIB_YEAR_VALUE;
  102. /* error messages */
  103. #define CHK_CROSS_L_START_MSG ""%s" is cross-linked on first cluster. "
  104. #define CHK_START_MSG "%s  - disk check in progress ..."
  105. #define CHK_NOT_ROOM_MSG "%s - Not enough room to run check disk.n"
  106. #define CHK_LOST_CHAINS_MSG " - lost chains "
  107. #define CHK_DEL_MSG " Entry will be deleted. "
  108. #define CHK_REMAIN_MSG "Entry remains intact. "
  109. #define CHK_CLUST_VAL "(cluster %lu, value %lu)."
  110. #define CHK_SHORT_CHAIN_MSG ""%s" file larger then its chain of clusters"
  111. #define CHK_BAD_DIR_MSG ""%s" directory has invalid structure."
  112. #define CHK_DIR_LVL_OVERFL "directory nesting limit reached, "%s" skipped"
  113. #define CHK_ROOT_CHAIN  "%s - Root directory cluster chain is corrupted.n"
  114. #define CHK_ROOT_TRUNC_MSG "      Root directory truncated. n"
  115. #define CHK_BAD_NAME ""%s" is an illegal name. "
  116. #define CHK_FAIL_MSG "     Check disk failed. n"
  117.                                 "     Disk should be formatted.n"
  118. #define CHK_NOT_REPAIRED "%s  - Errors detected. "
  119. "To correct disk structure, please start "
  120. "check disk with a permission to repair."
  121. #define CHK_RESTORE_FREE "Errors detected. "
  122. "All corrections stored to disk "
  123. "and lost chains recovered."
  124. #define CHK_BAD_START_MSG ""%s" has illegal start cluster"
  125. #define CHK_CROSS_START_MSG ""%s" cross-linked at start"
  126. #define CHK_BAD_CHAIN_MSG ""%s" has illegal cluster in chain"
  127. #define CHK_CROSS_LINK_MSG ""%s" cross-linked with another chain"
  128. #define CHK_LONG_CHAIN_MSG ""%s" too many clusters in file, adjusted."
  129. #define CHK_BAD_CLUST_MSG "illegal cluster"
  130. #define CHK_NO_ERRORS "%s  - Volume is OK "
  131. #define START_CLUST_MASK 0x80000000
  132. #define LOST_CHAIN_MARK 0xc0000000
  133. #define MARK_SET 1
  134. #define MARK_GET 2
  135. #define IS_BUSY 3
  136. #define MARK_BUF_INIT 255
  137. /* typedefs */
  138. /* check disk status */
  139.  
  140. typedef enum {
  141.              CHK_OK=OK, CHK_SIZE_ERROR,
  142.              CHK_RESTART, CHK_BAD_DIR, CHK_BAD_FILE,
  143.              CHK_CROSS_LINK, CHK_BAD_CHAIN, CHK_BAD_START,
  144.              CHK_ERROR=ERROR
  145.              }  CHK_STATUS;
  146.         
  147. /* dosChkMsg() argument */
  148. typedef enum { CURRENT_PATH, GET_PATH } MSG_PATH;
  149. /* dosChkEntryFind() argument */
  150. typedef enum { FIND_BY_CLUST, FIND_BY_NAME } CHK_SEARCH_KEY_TYPE;
  151. /* globals */
  152. /* locals */
  153. /* forward declarations */
  154. LOCAL void dosChkChainUnmark
  155.     (
  156.     DOS_FILE_DESC_ID    pFd             /* pointer to file descriptor */
  157.     );
  158. LOCAL STATUS dosChkChainStartGet
  159.     (
  160.     DOS_FILE_DESC_ID    pFd,            /* pointer to file descriptor */
  161.     uint32_t            entNum,
  162.     uint32_t *          pParDirStartClust,
  163.     uint32_t *          pStartClust
  164.     );
  165. LOCAL CHK_STATUS dosChkChainVerify
  166.     (
  167.     DOS_FILE_DESC_ID    pFd            /* pointer to file descriptor */
  168.     );
  169. LOCAL STATUS dosChkLostFind
  170.     (
  171.     DOS_FILE_DESC_ID    pFd             /* pointer to file descriptor */
  172.     );
  173. LOCAL STATUS dosChkLostFree
  174.     (
  175.     DOS_FILE_DESC_ID    pFd             /* pointer to file descriptor */
  176.     );
  177. /*******************************************************************************
  178. *
  179. * dosChkStatPrint - print statistics.
  180. *
  181. * RETURNS: N/A.
  182. */
  183. LOCAL void dosChkStatPrint
  184.     (
  185.     DOS_FILE_DESC_ID pFd
  186.     )
  187.     {
  188.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  189.     CHK_DSK_DESC_ID pChkDesc = pFd->pVolDesc->pChkDesc;
  190.     fsize_t valBuf;
  191.     
  192.     if( pVolDesc->chkVerbLevel < (DOS_CHK_VERB_1 >> 8) )
  193.      return;
  194.     
  195.     /* print statistics */
  196.     
  197.     print64Fine(  "n" "   total # of clusters: ", 
  198. pVolDesc->nFatEnts, "n", 10 );
  199.     print64Fine( "    # of free clusters: ", 
  200. pChkDesc->chkNFreeClusts, "n", 10 );
  201.     print64Fine( "     # of bad clusters: ", 
  202. pChkDesc->chkNBadClusts, "n", 10 );
  203.     
  204.     valBuf = pChkDesc->chkNFreeClusts;
  205.     valBuf = ( valBuf * pVolDesc->secPerClust ) <<
  206.           pVolDesc->secSizeShift;
  207.     print64Mult( "      total free space: ",
  208. valBuf, "n", 10 );
  209.     
  210.     valBuf = (fsize_t)pVolDesc->pFatDesc->maxContig( pFd ) << 
  211.           pVolDesc->secSizeShift;
  212.     print64Fine( "     max contiguous free space:  ",
  213. valBuf, " bytesn", 10 );
  214.     print64Fine( "    # of files: ",
  215. pChkDesc->chkNFiles, "n", 10 );
  216.     print64Fine( "  # of folders: ",
  217. pChkDesc->chkNDirs, "n", 10 );
  218.     print64Mult( "  total bytes in files: ",
  219. pChkDesc->chkTotalFSize, "n", 10 );
  220.     print64Fine( "      # of lost chains: ",
  221. pChkDesc->chkNLostChains, "n", 10 );
  222.     print64Mult( "   total bytes in lost chains:  ",
  223.       pChkDesc->chkTotalBytesInLostChains, "n", 10 );
  224.     }
  225.     
  226. /*******************************************************************************
  227. *
  228. * dosChkFinish - print statistics and deallocate resources.
  229. *
  230. * RETURNS: N/A.
  231. */
  232. LOCAL void dosChkFinish
  233.     (
  234.     DOS_FILE_DESC_ID pFd
  235.     )
  236.     {
  237.     if( pFd->pVolDesc->pChkDesc->chkFatMap != NULL )
  238.      KHEAP_FREE(((char *)pFd->pVolDesc->pChkDesc->chkFatMap));
  239.     KHEAP_FREE(((char *)pFd->pVolDesc->pChkDesc));
  240.     pFd->pVolDesc->pChkDesc = NULL;
  241.     
  242.     return;
  243.     } /* dosChkFinish() */
  244.     
  245. /*******************************************************************************
  246. *
  247. * dosChkEntryMark - set/get FAT entry marker.
  248. *
  249. * RETURNS: marker value on MARK_GET operation, STATUS on MARK_SET
  250. *  and MARK_BUF_INIT operation.
  251. */
  252. uint32_t dosChkEntryMark
  253.     (
  254.     DOS_FILE_DESC_ID pFd,
  255.     u_int operation,         /* MARK_SET/MARK_GET/MARK_BUF_INIT */
  256.     uint32_t entryNum,
  257.     uint32_t mark
  258.     )
  259.     {
  260.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  261.     CHK_DSK_DESC_ID pChkDesc = pVolDesc->pChkDesc;
  262.     uint8_t fatCopyNum = 0;
  263.     if (! pChkDesc->bufToDisk)
  264.      {
  265.      switch (operation)
  266.          {
  267.          case MARK_GET :
  268.          case IS_BUSY :
  269.           return pChkDesc->chkFatMap [entryNum];
  270.          case MARK_SET :
  271.           pChkDesc->chkFatMap [entryNum] = mark;
  272.           break;
  273.          case MARK_BUF_INIT :
  274.           bzero ((char *)pChkDesc->chkFatMap,
  275.                pVolDesc->nFatEnts *
  276.                        sizeof( *pVolDesc->pChkDesc->chkFatMap ));
  277.           break;
  278.          default:
  279.           assert (FALSE);
  280.          }
  281.        return OK;
  282.      }
  283.     else /* use reserved FAT copy as buffer */
  284.      {
  285.      fatCopyNum = pVolDesc->pFatDesc->activeCopyNum + 1;
  286.      switch (operation)
  287.          {
  288.          case MARK_GET :
  289.              pVolDesc->pFatDesc->clustValueGet (pFd, fatCopyNum,
  290.    entryNum, &mark );
  291.           return mark;
  292.          case IS_BUSY :
  293.           return pChkDesc->chkFatMap [
  294.                        entryNum / 8 / sizeof(*pChkDesc->chkFatMap)] &
  295.                        (1 <<
  296.                         (entryNum & (sizeof(*pChkDesc->chkFatMap) * 8 - 1)));
  297.          case MARK_SET :
  298.           pChkDesc->chkFatMap [
  299. entryNum / 8 / sizeof(*pChkDesc->chkFatMap)] |=
  300.         1 << (entryNum & (sizeof(*pChkDesc->chkFatMap) * 8 - 1));
  301.              return pVolDesc->pFatDesc->clustValueSet (
  302.     pFd, fatCopyNum, entryNum, DOS_FAT_RAW, mark );
  303.          case MARK_BUF_INIT :
  304.           bzero ((char *)pChkDesc->chkFatMap,
  305.                        pVolDesc->nFatEnts / 8  + 4);
  306.           return pVolDesc->pFatDesc->clustValueSet(
  307.                             pFd, fatCopyNum, 0, DOS_FAT_SET_ALL,  0 );
  308.          default:
  309.           assert (FALSE);
  310.          }
  311.      }
  312.     return ERROR;
  313.     } /* dosChkEntryMark() */
  314. /*******************************************************************************
  315. *
  316. * dosChkEntryFind - find entry in directory.
  317. *
  318. * This routine searches directory, that starts from <dirStartClust>,
  319. * for entry, by entry name or start cluster. File descriptor
  320. * <pFd> is filled for entry found and entry name is placed into
  321. * <pChkDesc->chkDir>.
  322. *
  323. * RETURNS: OK or ERROR if disk access error.
  324. */
  325. LOCAL STATUS dosChkEntryFind
  326.     (
  327.     DOS_FILE_DESC_ID pFd,
  328.     UINT32 dirStartClust,
  329.     void * key, /* start clust value or name buffer */
  330.     CHK_SEARCH_KEY_TYPE keyType
  331.     )
  332.     {
  333.     UINT32 startClust = (UINT32)key;
  334.     DIR * pDir = &pFd->pVolDesc->pChkDesc->chkDir;
  335.     DOS_FILE_DESC fd;
  336.     DOS_FILE_HDL flHdl;
  337.     
  338.     fd = *pFd;
  339.     flHdl = *pFd->pFileHdl;
  340.     fd.pFileHdl = &flHdl;
  341.     
  342.     if( dirStartClust == 0 ) /* parent is root */
  343.      {
  344.      if( pFd->pVolDesc->pDirDesc->pathLkup( &fd, "", 0 ) == ERROR )
  345.          return ERROR;
  346.      }
  347.     else if( dirStartClust == (UINT32)NONE ) /* search for root */
  348.      {
  349.      if( pFd->pVolDesc->pDirDesc->pathLkup( &fd, "", 0 ) == ERROR )
  350.          return ERROR;
  351.      strcpy( pDir->dd_dirent.d_name, pFd->pVolDesc->devHdr.name );
  352.      return OK;
  353.      }
  354.     else
  355.      {
  356.      fd.pFileHdl->startClust = dirStartClust;
  357.      fd.pFileHdl->attrib = DOS_ATTR_DIRECTORY;
  358.      }
  359.     
  360.     /* rewind directory */
  361.     
  362.     pDir->dd_cookie = 0;
  363.     
  364.     while( pFd->pVolDesc->pDirDesc->readDir( &fd, pDir, pFd ) == OK )
  365.      {
  366.      switch( keyType )
  367.          {
  368.          case FIND_BY_CLUST:
  369.           if( pFd->pFileHdl->startClust == startClust )
  370.              return OK;
  371.           break;
  372.          case FIND_BY_NAME:
  373.           if( strcmp( (char *)key, pDir->dd_dirent.d_name ) == 0 )
  374.              return OK;
  375.           break;
  376.          default:
  377.           assert( FALSE );
  378.          }
  379.      }
  380.     assert( FALSE );
  381.     return ERROR;
  382.     } /* dosChkEntryFind() */
  383.     
  384. /*******************************************************************************
  385. *
  386. * dosChkBuildPath - reconstruct file path.
  387. *
  388. * This routine reconstructs full path of the file is described
  389. * by <pFd> and puts it to <pChkDesc->chkPath> buffer.
  390. *
  391. * RETURNS: OK or ERROR if disk access error.
  392. */
  393. LOCAL STATUS dosChkBuildPath
  394.     (
  395.     DOS_FILE_DESC_ID pSrcFd
  396.     )
  397.     {
  398.     DIR * pDir = &pSrcFd->pVolDesc->pChkDesc->chkDir;
  399.     DOS_FILE_DESC fd;
  400.     DOS_FILE_HDL flHdl;
  401.     u_char * pPath;
  402.     u_char * chkPath = pSrcFd->pVolDesc->pChkDesc->chkPath;
  403.     u_short nameLen;
  404.     
  405.     pPath = chkPath + 
  406.             sizeof( pSrcFd->pVolDesc->pChkDesc->chkPath ) - 1;
  407.     bzero( (char *)chkPath,
  408.         sizeof( pSrcFd->pVolDesc->pChkDesc->chkPath ) );
  409.     if( (pSrcFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY) != 0 )
  410.      {
  411.      pPath --;
  412.      *pPath = SLASH;
  413.      }
  414.     
  415.     fd = *pSrcFd;
  416.     flHdl = *pSrcFd->pFileHdl;
  417.     fd.pFileHdl = &flHdl;
  418.     
  419.     FOREVER
  420.      {
  421.      if( dosChkEntryFind( &fd, flHdl.dirHdl.parDirStartCluster,
  422.           (void *)flHdl.startClust,
  423.           FIND_BY_CLUST ) == ERROR )
  424.          {
  425.          return ERROR;
  426.          }
  427.     
  428.      /* insert name to path */
  429.     
  430.      nameLen = strlen( pDir->dd_dirent.d_name );
  431.      if( nameLen > pPath - chkPath )
  432.          {
  433.          do  {
  434.           pPath = memchr( pPath + 1, SLASH, strlen( (char *)pPath ) );
  435.           }
  436.          while( pPath - chkPath < 4 );
  437.          
  438.          pPath -= 4;
  439.          *pPath = DOT, *(pPath + 1) = DOT, *(pPath + 2) = DOT;
  440.          *(pPath + 3) = SLASH;
  441.          break;
  442.          }
  443.     
  444.      pPath -= strlen( pDir->dd_dirent.d_name );
  445.      bcopy( pDir->dd_dirent.d_name, (char *)pPath,
  446.             strlen( pDir->dd_dirent.d_name ) );
  447.     
  448.      if( IS_ROOT( &fd ) )
  449.          break;
  450.     
  451.      pPath --;
  452.      *pPath = SLASH;
  453.     
  454.      /* find cluster containing parent directory */
  455.     
  456.      if( flHdl.dirHdl.parDirStartCluster == 0 )
  457.          { /* current parent directory is root */
  458.          flHdl.dirHdl.parDirStartCluster = (UINT32)NONE;
  459.          }
  460.      else if( dosChkChainStartGet(
  461.      &fd, flHdl.dirHdl.parDirStartCluster, 
  462.      (uint32_t *)&flHdl.dirHdl.parDirStartCluster,
  463.                  (uint32_t *)&flHdl.startClust ) == ERROR )
  464.             {
  465.             assert( FALSE );
  466.             }
  467.      }
  468.     
  469.     memmove( chkPath, pPath, strlen( (char *)pPath ) + 1 );
  470.     return OK;
  471.     } /* dosChkBuildPath() */
  472.     
  473. /*******************************************************************************
  474. *
  475. * dosChkMsg - print message.
  476. *
  477. */
  478. LOCAL void dosChkMsg
  479.     (
  480.     DOS_FILE_DESC_ID pFd,
  481.     char * msgFormat,
  482.     MSG_PATH msgPath, /* whether to build file path or use current path */
  483.     int arg1,
  484.     int arg2,
  485.     int arg3,
  486.     int arg4,
  487.     char * extraMsg
  488.     )
  489.     {
  490.     char * path = NULL;
  491.     
  492.     if( msgPath == CURRENT_PATH )
  493.      path = pFd->pVolDesc->pChkDesc->chkCurPath;
  494.     else if( dosChkBuildPath( pFd ) == OK )
  495.      path = (char *)pFd->pVolDesc->pChkDesc->chkPath;
  496.     else
  497.      return;
  498.     
  499.     printf( "r" );
  500.     printf( msgFormat, path, arg1, arg2, arg3, arg4 );
  501.     if( extraMsg != NULL && *extraMsg != EOS )
  502.      printf("%s", extraMsg );
  503.     printf( "n" );
  504.     return;
  505.     } /* dosChkMsg() */
  506.     
  507. /*******************************************************************************
  508. *
  509. * dosChkEntryDel - delete entry and unmark chain , if required.
  510. *
  511. * This routine deletes entry is described by pFd, unmarks
  512. * associated FAT chain, if <unmark> is TRUE and outputs
  513. * message in accordance with <mess> format string.
  514. *
  515. * RETURNS: CHK_OK, or CHK_ERROR if disk I/O error.
  516. */
  517. LOCAL CHK_STATUS dosChkEntryDel
  518.     (
  519.     DOS_FILE_DESC_ID pFd,
  520.     BOOL unmark,
  521.     u_char * mess,
  522.     MSG_PATH msgPath,
  523.     int msgArg1,
  524.     int msgArg2,
  525.     int msgArg3,
  526.     int msgArg4
  527.     )
  528.     {
  529.     /* put message */
  530.     
  531.     dosChkMsg( pFd, (char *)mess, msgPath, msgArg1, msgArg2, msgArg3, msgArg4,
  532.                CHK_DEL_MSG );
  533.     
  534.     pFd->pVolDesc->pChkDesc->nErrors ++;
  535.     
  536.     if( pFd->pVolDesc->chkLevel > CHK_ONLY )
  537.      {
  538.      if( pFd->pVolDesc->pDirDesc->updateEntry(
  539.      pFd, DH_DELETE, 0 ) == ERROR )
  540.          {
  541.          return CHK_ERROR;
  542.          }
  543.      }
  544.     
  545.     /* unmark chain */
  546.     
  547.     if( unmark )
  548.      dosChkChainUnmark( pFd );
  549.     
  550.     /* mark file descriptor as deleted */
  551.     
  552.     pFd->pFileHdl->deleted = 1;
  553.     
  554.     return CHK_OK;
  555.     } /* dosChkEntryDel() */
  556.     
  557. /*******************************************************************************
  558. *
  559. * dosChkStartCrossProc - process entries are cross linked on start cluster.
  560. *
  561. * This routine deletes entry, that was created earlier.
  562. *
  563. * RETURNS: CHK_OK or CHK_RESTART, if directory has been deleted.
  564. */
  565. LOCAL CHK_STATUS dosChkStartCrossProc
  566.     (
  567.     DOS_FILE_DESC_ID pFd
  568.     )
  569.     {
  570.     DOS_FILE_DESC localFd;
  571.     DOS_FILE_HDL localFlHdl;
  572.     UINT32 entryClust; /* entry location cluster */
  573.     UINT32 startClust; /* file/dir start cluster */
  574.     struct stat fStat; /* used to get creation time */
  575.     time_t creatTime; /* creation time of one of the files */
  576.     BOOL unmark = TRUE; /* whether to unmark chain */
  577.     MSG_PATH msgPath = GET_PATH; /* whether to build file path */
  578.      /* or to use current path */
  579.     
  580.     assert( pFd != NULL && pFd->pVolDesc->magic == DOS_FS_MAGIC );
  581.     
  582.     bzero( (char *)&localFd, sizeof( localFd ) );
  583.     bzero( (char *)&localFlHdl, sizeof( localFlHdl ) );
  584.     
  585.     localFd.busy = 1;
  586.     localFd.pFileHdl = &localFlHdl;
  587.     localFd.pVolDesc = pFd->pVolDesc;
  588.     
  589.     /* find peer entry */
  590.     
  591.     dosChkChainStartGet( pFd, pFd->pFileHdl->startClust,
  592.      (uint32_t *)&entryClust, 
  593.                         (uint32_t *)&startClust );
  594.     
  595.     if( dosChkEntryFind( &localFd, entryClust,
  596.      (void *)startClust, FIND_BY_CLUST ) == ERROR )
  597.      {
  598.      return CHK_ERROR;
  599.      }
  600.     
  601.     assert( pFd->pFileHdl->startClust == localFlHdl.startClust );
  602.     
  603.     /* delete older entry, but never delete ROOT */
  604.     
  605.     pFd->pVolDesc->pDirDesc->dateGet( pFd, &fStat );
  606.     creatTime = fStat.st_ctime;
  607.     pFd->pVolDesc->pDirDesc->dateGet( &localFd, &fStat );
  608.     
  609.     /* let <localFd> describes file to be deleted */
  610.     
  611.     if( IS_ROOT( &localFd ) || creatTime >= fStat.st_ctime )
  612.      {
  613.      dosChkMsg( &localFd, CHK_CROSS_L_START_MSG, GET_PATH,
  614.         0,0,0,0, CHK_REMAIN_MSG );
  615.     
  616.      localFd = *pFd;
  617.      localFlHdl =  *pFd->pFileHdl;
  618.      localFd.pFileHdl = &localFlHdl;
  619.     
  620.      /* the chain already checked. Do not unmark and recheck */
  621.     
  622.      unmark = FALSE;
  623.      msgPath = CURRENT_PATH;
  624.      pFd->pFileHdl->deleted = 1; 
  625.      }
  626.     else
  627.      {
  628.      dosChkMsg( pFd, CHK_CROSS_L_START_MSG, CURRENT_PATH,
  629.         0,0,0,0, CHK_REMAIN_MSG );
  630.      }
  631.     
  632.     /* delete the file */
  633.     
  634.     return dosChkEntryDel( &localFd, unmark, 
  635.         (u_char *)CHK_CROSS_L_START_MSG, msgPath, 0,0,0,0 );
  636.     } /* dosChkStartCrossProc() */
  637.     
  638. /*******************************************************************************
  639. *
  640. * dosChkDirStruct - check internal directory structure.
  641. *
  642. * This routine checks, that directory has valid . and ..
  643. * entries at top of it.
  644. *
  645. * RETURNS: CHK_OK, CHK_RESTART, if the directory has been deleted or
  646. * CHK_ERROR if another error occurred.
  647. */
  648. LOCAL CHK_STATUS dosChkDirStruct
  649.     (
  650.     DOS_FILE_DESC_ID pDirFd,
  651.     DOS_FILE_DESC_ID pLocalFd
  652.     )
  653.     {
  654.     u_char dots;
  655.     DIR * pDir = &pDirFd->pVolDesc->pChkDesc->chkDir;
  656.     
  657.     /* root directory does not contain . and .. entries */
  658.     
  659.     if( IS_ROOT( pDirFd ) )
  660.      return CHK_OK;
  661.     
  662.     for( dots = 1; dots <= 2; dots ++ )
  663.      {
  664.      if( pDirFd->pVolDesc->pDirDesc->readDir(
  665.      pDirFd, pDir, pLocalFd ) != OK )
  666.          {
  667.          break;
  668.          }
  669.      if( *(pDir->dd_dirent.d_name) != '.' ||
  670.          *(pDir->dd_dirent.d_name + dots - 1) != '.' ||
  671.          *(pDir->dd_dirent.d_name + dots) != EOS )
  672.          {
  673.          break;
  674.          }
  675.      if( dots == 1 && /* . */
  676.          pDirFd->pFileHdl->startClust !=
  677.          pLocalFd->pFileHdl->startClust )
  678.          {
  679.          break;
  680.          }
  681.      else if( dots == 2 && /* .. */
  682.              pDirFd->pFileHdl->startClust !=
  683.              pLocalFd->pFileHdl->dirHdl.parDirStartCluster )
  684.          {
  685.          break;
  686.          }
  687.      }
  688.     
  689.     if( dots <= 2 )
  690.      {
  691.      return dosChkEntryDel( pDirFd, TRUE, (u_char *)CHK_BAD_DIR_MSG,
  692.             CURRENT_PATH, 0,0,0,0 );
  693.      }
  694.     
  695.     return CHK_OK;  
  696.     } /* dosChkDirStruct() */
  697.     
  698. /*******************************************************************************
  699. *
  700. * dosFsChkTree - DOS FS sanity check utility.
  701. *
  702. * RETURNS: OK or ERROR if device is not a valid DOS device,
  703. *  corrections can not be written to disk
  704. *  or disk read error.
  705. *
  706. * ERRNO:
  707. * S_dosFsLib_INVALID_PARAMETER
  708. */
  709. CHK_STATUS dosFsChkTree
  710.     (
  711.     DOS_FILE_DESC_ID pFd
  712.     )
  713.     {
  714.     CHK_DSK_DESC_ID pChkDesc = pFd->pVolDesc->pChkDesc;
  715.     DOS_FILE_DESC localFd;
  716.     DOS_FILE_HDL localFlHdl;
  717.     UINT32 work1;
  718.     u_long ddCookie;
  719.     char * pCurPathPos = NULL;
  720.     
  721.     assert( pFd != NULL && pFd->pVolDesc->magic == DOS_FS_MAGIC );
  722.         
  723.     bzero( (char *)&localFd, sizeof( localFd ) );
  724.     bzero( (char *)&localFlHdl, sizeof( localFlHdl ) );
  725.     
  726.     localFd.busy = 1;
  727.     localFd.pFileHdl = &localFlHdl;
  728.     localFd.pVolDesc = pFd->pVolDesc;
  729.     
  730.     /* separately check ROOT directory chain */
  731.     
  732.     if( IS_ROOT( pFd ) )
  733.      {
  734. if( pFd->pFileHdl->startClust != 0 &&
  735.             dosChkChainVerify( pFd ) != CHK_OK )
  736.          {
  737.          return CHK_ERROR;
  738.          }
  739.      }
  740.     
  741.     pCurPathPos = pChkDesc->chkCurPath + 
  742.        strlen( pChkDesc->chkCurPath );
  743.     *pCurPathPos = SLASH;
  744.     pCurPathPos ++;
  745.     
  746.     /* rewind directory */
  747.     
  748.     pChkDesc->chkDir.dd_cookie = 0;
  749.     
  750.     /* check . and .. */
  751.     
  752.     work1 = dosChkDirStruct( pFd, &localFd );
  753.     if( work1 != CHK_OK )
  754.      {
  755.      pChkDesc->nErrors ++;
  756.      return work1;
  757.      }
  758.     
  759.     /* pass directory */
  760.     
  761.     for(  ;
  762.          pFd->pVolDesc->pDirDesc->readDir(
  763.      pFd, &pChkDesc->chkDir, &localFd ) == OK;
  764.       pChkDesc->chkDir.dd_cookie = ddCookie )
  765.      {
  766.      /*
  767.       * backup current position in directory, because
  768.       * other routines use the same DIR structure
  769.       */
  770.      ddCookie = pChkDesc->chkDir.dd_cookie;
  771.     
  772.      work1 = strlen( pCurPathPos );
  773.      strcpy( pCurPathPos, pChkDesc->chkDir.dd_dirent.d_name );
  774.     
  775.      if( pFd->pVolDesc->chkVerbLevel >= (DOS_CHK_VERB_2 >> 8) )
  776.          {
  777.          printf( "r%s", pChkDesc->chkCurPath );
  778.          for(  ; work1 >= strlen( pCurPathPos ); work1 -- )
  779.           printf( " " ); /* clear extra characters */
  780.     
  781.          }
  782.     
  783.      DBG_MSG( 100, "%s : stCl %u, size %u attrib %pn",
  784.      pChkDesc->chkDir.dd_dirent.d_name,
  785.      localFlHdl.startClust, localFlHdl.size,
  786.      (u_int)localFlHdl.attrib,0,0,0,0 );
  787.     
  788.      /* some statistics */
  789.     
  790.      if( (localFlHdl.attrib & DOS_ATTR_DIRECTORY) == 0 )
  791.          pChkDesc->chkNFiles ++;
  792.      else
  793.          pChkDesc->chkNDirs ++;
  794.     
  795.      /* check name */
  796.     
  797.      if( pFd->pVolDesc->pDirDesc->nameChk != NULL &&
  798.          pFd->pVolDesc->pDirDesc->nameChk( pFd->pVolDesc, 
  799.           (u_char *)pChkDesc->chkDir.dd_dirent.d_name) == ERROR)
  800.          {
  801.          if( dosChkEntryDel( &localFd, FALSE, (u_char *)CHK_BAD_NAME, 
  802. CURRENT_PATH, 0,0,0,0 ) == CHK_ERROR )
  803.           {
  804.           return CHK_ERROR;
  805.           }
  806.          
  807.          continue;
  808.          }
  809.     
  810.      /* check chain */
  811.     
  812.      if( dosChkChainVerify( &localFd ) == CHK_ERROR )
  813.          return CHK_ERROR;
  814.     
  815.      if( localFlHdl.deleted )
  816.          {
  817.          if( (localFlHdl.attrib & DOS_ATTR_DIRECTORY) == 0 )
  818.           pChkDesc->chkNFiles --;
  819.          else
  820.           pChkDesc->chkNDirs --;
  821.          continue;
  822.          }
  823.          
  824.     
  825.      /* chain is OK. */
  826.       
  827.      /* total files size */
  828.     
  829.      pChkDesc->chkTotalFSize += localFlHdl.size;
  830.     
  831.      /* absolute max time */
  832.     
  833.      if( pFd->pVolDesc->pDirDesc->dateGet(
  834.      &localFd, &pChkDesc->stat ) == ERROR )
  835.          {
  836.          return CHK_ERROR;
  837.          }
  838.     
  839.      if( pChkDesc->chkMaxCreatTime < pChkDesc->stat.st_ctime )
  840.          pChkDesc->chkMaxCreatTime = pChkDesc->stat.st_ctime;
  841.     
  842.      if( pChkDesc->chkMaxModifTime < pChkDesc->stat.st_mtime )
  843.          pChkDesc->chkMaxModifTime = pChkDesc->stat.st_mtime;
  844.     
  845.      if( pChkDesc->chkMaxAccTime < pChkDesc->stat.st_atime )
  846.          pChkDesc->chkMaxAccTime = pChkDesc->stat.st_atime;
  847.     
  848.      /* recursively check directory */
  849.     
  850.      if( (localFlHdl.attrib & DOS_ATTR_DIRECTORY) != 0 )
  851.          {
  852.          if( pChkDesc->curPathLev ==  DOS_MAX_DIR_LEVELS )
  853.           {
  854.           pChkDesc->nErrors ++;
  855.           dosChkEntryDel( &localFd, TRUE, (u_char *)CHK_DIR_LVL_OVERFL,
  856.           CURRENT_PATH, 0,0,0,0 );
  857.           continue;
  858.           }
  859.          
  860.          pChkDesc->curPathLev ++;
  861.          work1 = dosFsChkTree( &localFd );
  862.          pChkDesc->curPathLev --;
  863.          
  864.          if( work1 != CHK_OK )
  865.           {
  866.           return work1;
  867.           }
  868.          }
  869.      } /* for ... */
  870.     
  871.     
  872.     /* check, that device is OK yet */
  873.     
  874.     if( TRUE == cbioRdyChgdGet (pFd->pVolDesc->pCbio) )
  875.      return CHK_ERROR;
  876.     
  877.     return CHK_OK;
  878.     } /* dosFsChkTree() */
  879. /*******************************************************************************
  880. *
  881. * dosChkInit - allocate resources.
  882. *
  883. * RETURNS: OK or ERROR if KHEAP_ALLOC failed.
  884. */
  885. LOCAL STATUS dosChkInit
  886.     (
  887.     DOS_FILE_DESC_ID pFd
  888.     )
  889.     {
  890.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  891.     void * chkFatMap;
  892.     BOOL bufToDisk;
  893.     
  894.     if( pVolDesc->pChkDesc == NULL )
  895.      {
  896.      /* allocate descriptor */
  897.      pVolDesc->pChkDesc = KHEAP_ALLOC((sizeof(*pVolDesc->pChkDesc)));
  898.      if( pVolDesc->pChkDesc == NULL )
  899.          return ERROR;
  900.     
  901.      pVolDesc->pChkDesc->bufToDisk = FALSE;
  902.      /* check memory size and allocate FAT buffer */
  903.      pVolDesc->pChkDesc->chkFatMap = NULL; /* do not remove this string */
  904.      if( ((u_long) (memFindMax())  <=  
  905.      (u_long) (pVolDesc->nFatEnts * sizeof 
  906. (*pVolDesc->pChkDesc->chkFatMap) +32)) ||
  907.     (NULL == (pVolDesc->pChkDesc->chkFatMap = 
  908. KHEAP_ALLOC( ((pVolDesc->nFatEnts) * 
  909. (sizeof(*pVolDesc->pChkDesc->chkFatMap)))))) )
  910.          {
  911.          /*
  912.              * only FAT32 disks can use reserved FAT copy instead
  913.              * of memory buffer
  914.              */
  915.          if( (pVolDesc->fatType != FAT32)      ||
  916.           (pVolDesc->pFatDesc->activeCopyNum == pVolDesc->nFats - 1)  ||
  917.           ((pVolDesc->pChkDesc->chkFatMap = 
  918. KHEAP_ALIGNED_ALLOC(
  919. (sizeof(*pVolDesc->pChkDesc->chkFatMap)),
  920.                                 (pVolDesc->nFatEnts / 8 + 4))) == NULL))
  921.              {
  922.           printf( CHK_NOT_ROOM_MSG, pVolDesc->devHdr.name );
  923.                 dosChkFinish( pFd );
  924.           return ERROR;
  925.           }
  926.          pVolDesc->pChkDesc->bufToDisk = TRUE;
  927.          }
  928.         if( pVolDesc->chkVerbLevel >= (DOS_CHK_VERB_1 >> 8) )
  929.          dosChkMsg( pFd, CHK_START_MSG, GET_PATH, 0,0,0,0,  NULL );
  930.      }
  931.     
  932.     chkFatMap = pVolDesc->pChkDesc->chkFatMap;
  933.     
  934.     bufToDisk = pVolDesc->pChkDesc->bufToDisk;
  935.     bzero( (char *) pVolDesc->pChkDesc, sizeof( *pVolDesc->pChkDesc ) );
  936.     pVolDesc->pChkDesc->chkFatMap = chkFatMap;
  937.     pVolDesc->pChkDesc->bufToDisk = bufToDisk;
  938.     /* disable FAT mirroring */
  939.     
  940.     pVolDesc->pFatDesc->syncToggle (pVolDesc, FALSE);
  941.     /* zero FAT buffer */
  942.     
  943.     dosChkEntryMark (pFd, MARK_BUF_INIT, 0, 0 );
  944.     
  945.     return OK;
  946.     } /* dosChkInit() */
  947.     
  948. /*******************************************************************************
  949. *
  950. * dosChkDsk - start disk check procedure.
  951. *
  952. * RETURNS: OK or ERROR if device is not a valid DOS device,
  953. *  corrections can not be written to disk
  954. *  or disk read error.
  955. *
  956. * NOMANUAL
  957. */
  958. STATUS dosChkDsk
  959.     (
  960.     DOS_FILE_DESC_ID pFd
  961.     )
  962.     {
  963.     CHK_STATUS result;
  964.     size_t i;
  965.     struct timespec tv;
  966.     
  967.     do
  968.      {
  969.      if( dosChkInit( pFd ) == ERROR )
  970.          return ERROR;
  971.     
  972.      pFd->pVolDesc->pChkDesc->curPathLev = 1;
  973.     
  974.      /* current path is just a device name */
  975.     
  976.      strcpy( pFd->pVolDesc->pChkDesc->chkCurPath,
  977.      pFd->pVolDesc->devHdr.name );
  978.     
  979.      result = dosFsChkTree( pFd );
  980.      }
  981.     while( result == CHK_RESTART );
  982.     
  983.     /* clear current path from screen */
  984.     printf( "r" );
  985.     for( i = 0; i < strlen( pFd->pVolDesc->pChkDesc->chkCurPath ); i ++ )
  986.      {
  987.      printf( "%4c", SPACE );
  988.      }
  989.     printf( "r" );
  990.     
  991.     if( result == CHK_ERROR )
  992.      goto ret;
  993.     
  994.     /*
  995.      * set system clock to be later, than the last time on volume,
  996.      * but only in case it seems a Real-Time Clock chip
  997.      * not present
  998.      */
  999.     if( time( NULL ) < dosChkMinDate )
  1000.      {
  1001.      tv.tv_sec = max (dosChkMinDate, 
  1002.  (max(pFd->pVolDesc->pChkDesc->chkMaxCreatTime,
  1003.      max(pFd->pVolDesc->pChkDesc->chkMaxModifTime,
  1004.             pFd->pVolDesc->pChkDesc->chkMaxAccTime))));
  1005.      if( tv.tv_sec > time( NULL ) )
  1006.          {
  1007.          tv.tv_nsec = time( NULL );
  1008.     /* Let the user know we are adjusting the system time */
  1009.     printf ("dosChkLib : ");
  1010.          printf("CLOCK_REALTIME is being reset to %s", 
  1011.    ctime( &tv.tv_sec ) );
  1012.          printf("Value obtained from file system volume "
  1013.    "descriptor pointer: %pn", pFd->pVolDesc);
  1014.          tv.tv_nsec = time( NULL );
  1015.          printf("The old setting was %s", ctime((time_t *)&tv.tv_nsec ) );
  1016.          tv.tv_nsec = dosChkMinDate;
  1017.          printf("Accepted system dates are greater than %s", 
  1018.    ctime((time_t *)&tv.tv_nsec));
  1019.          tv.tv_nsec = 1;
  1020.          clock_settime( CLOCK_REALTIME, &tv );
  1021.          }
  1022.      }
  1023.     /* before deal with lost chains, store all corrections to disk */
  1024.     
  1025.     if(O_RDONLY != cbioModeGet(pFd->pVolDesc->pCbio))
  1026.         {
  1027.         if( cbioIoctl (pFd->pVolDesc->pCbio, CBIO_CACHE_FLUSH,
  1028.      (void *)(-1) ) == ERROR )
  1029.          {
  1030.          result = CHK_ERROR;
  1031.          goto ret;
  1032.          }
  1033.      }
  1034.     
  1035.     /* compose "current path" for attractive messages */
  1036.     
  1037.     strcpy( pFd->pVolDesc->pChkDesc->chkCurPath,
  1038.          pFd->pVolDesc->devHdr.name );
  1039.     strcat( pFd->pVolDesc->pChkDesc->chkCurPath,
  1040.          CHK_LOST_CHAINS_MSG );
  1041.     
  1042.     if( dosChkLostFind( pFd ) == ERROR /* collect lost chains */ ||
  1043.      pFd->pVolDesc->pChkDesc->nErrors > 0 )
  1044.      {
  1045.         dosChkLostFree( pFd ); /* free/ count lost chains */
  1046.         
  1047.      if( pFd->pVolDesc->chkLevel == DOS_CHK_ONLY )
  1048.          {
  1049.          dosChkMsg( pFd, CHK_NOT_REPAIRED, GET_PATH, 0,0,0,0, NULL );
  1050.          result = CHK_ERROR;
  1051.          }
  1052.      else if( pFd->pVolDesc->chkLevel >= DOS_CHK_REPAIR )
  1053.          {
  1054.          dosChkMsg( pFd, CHK_RESTORE_FREE, GET_PATH, 0,0,0,0, NULL );
  1055.          }
  1056.      }
  1057.     else
  1058.      {
  1059.      dosChkMsg( pFd, CHK_NO_ERRORS, GET_PATH, 0,0,0,0,  NULL );
  1060.      }
  1061.     
  1062.     /* set a random volume Id, if this initialized to a bad value */
  1063.     
  1064.     if ((pFd->pVolDesc->chkLevel > DOS_CHK_ONLY) &&
  1065.         ((pFd->pVolDesc->volId == 0) || 
  1066.          (pFd->pVolDesc->volId == (u_int)(-1))) &&
  1067.         (O_RDONLY != cbioModeGet(pFd->pVolDesc->pCbio)))
  1068.      {
  1069.      printf("Change volume Id from %p ", (void *)pFd->pVolDesc->volId );
  1070.      VX_TO_DISK_32( tickGet(), &pFd->pVolDesc->volId );
  1071.      cbioBytesRW (pFd->pVolDesc->pCbio, pFd->pVolDesc->bootSecNum,
  1072.           pFd->pVolDesc->volIdOff, (void *)&pFd->pVolDesc->volId,
  1073.           sizeof( pFd->pVolDesc->volId ), CBIO_WRITE, NULL );
  1074.      pFd->pVolDesc->volId = DISK_TO_VX_32( &pFd->pVolDesc->volId );
  1075.     
  1076.      printf("to %pn", (void *)pFd->pVolDesc->volId );
  1077.      }
  1078.     
  1079.     dosChkStatPrint( pFd );
  1080.     
  1081. ret:
  1082.     dosChkFinish( pFd );
  1083.     
  1084.      /* If not write protected enable FAT mirroring and synchronize copies */
  1085.     if ((pFd->pVolDesc->chkLevel > DOS_CHK_ONLY) && 
  1086.         (O_RDONLY != cbioModeGet(pFd->pVolDesc->pCbio)))
  1087.        {
  1088.        pFd->pVolDesc->pFatDesc->syncToggle (pFd->pVolDesc, TRUE);
  1089.        }
  1090.     /*
  1091.      * !!! do not set cbioReadyChanged to TRUE here,
  1092.      *    because dosFsLib has to synchronize cache before it
  1093.      */
  1094.     
  1095.     return ( result == CHK_OK )? OK : ERROR;
  1096.     } /* dosChkDsk() */
  1097.     
  1098. /*******************************************************************************
  1099. *
  1100. * dosChkLibInit - install dos sanity check utility.
  1101. *
  1102. * RETURNS: N/A.
  1103. *
  1104. * NOMANUAL
  1105. */
  1106. void dosChkLibInit( void )
  1107.     {
  1108.     dosFsChkRtn = dosChkDsk;
  1109.     }
  1110. /*******************************************************************************
  1111. *
  1112. * dosChkEntryMarkSet - mark entry if it is not market yet
  1113. *
  1114. * RETURNS: if failed to mark the entry
  1115. */
  1116. LOCAL STATUS dosChkEntryMarkSet
  1117.     (
  1118.     DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1119.     uint32_t entryNum, /*  */
  1120.     uint32_t markValue /*  */
  1121.     )
  1122.     {
  1123.     uint32_t mark;
  1124.    /* Check entry status */
  1125.     mark = dosChkEntryMark (pFd, MARK_GET, entryNum, 0);
  1126.     if (mark != 0) /* already marked entry */
  1127.         return ERROR;
  1128.     /* Mark entry */
  1129.     dosChkEntryMark (pFd, MARK_SET, entryNum, markValue);
  1130.     return OK;
  1131.     } /* dosChkEntryMarkSet */
  1132. /*******************************************************************************
  1133. *
  1134. * dosChkChainMark - mark an entire chain
  1135. *
  1136. * RETURNS: size of file represented by this chain
  1137. */
  1138. LOCAL uint32_t dosChkChainMark
  1139.     (
  1140.     DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1141.     uint32_t startClust, /* start cluster of chain */
  1142.     uint32_t entNum, /* valid entry number */
  1143.     uint32_t entCont /* entry contents */
  1144.     )
  1145.     {
  1146.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1147.     DOS_FAT_DESC_ID pFatDesc = pVolDesc->pFatDesc;
  1148.     uint32_t fileSize;
  1149.     uint32_t clustSize;
  1150.     uint32_t entValue; /* sense of entry contents */
  1151.     uint32_t nextEntCont; /* next entry content, if current entry 
  1152.    contents valid cluster number */
  1153.     uint32_t prevEnt; /*  */
  1154.     uint32_t numClusts; /* size of chain in clusters */
  1155.     uint32_t eofClust;
  1156.     char * errMsg;
  1157.     errMsg   = NULL;
  1158.     eofClust = 0;
  1159.     numClusts = 1; /* start cluster */
  1160.     if ( (pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY) == 0 )
  1161.         {
  1162.         clustSize = pVolDesc->secPerClust * pVolDesc->bytesPerSec;
  1163.         fileSize = (pFd->pFileHdl->size + clustSize - 1) / clustSize;
  1164.         }
  1165.     else /* this is a directory */
  1166.         fileSize = 0xffffffff;
  1167.     nextEntCont = entCont;
  1168.     entCont     = entNum;
  1169.     entNum      = startClust;
  1170.     entValue    = DOS_FAT_ALLOC;
  1171.     do  {
  1172.         /* Proceed with next entry */
  1173.         prevEnt = entNum; /* previous entry */
  1174.         entNum  = entCont;      /* entry to check */
  1175.         entCont = nextEntCont;  /* contents of the entry to check */
  1176.         if (fileSize == numClusts)
  1177.             {        /* file size is reached */
  1178.             errMsg = CHK_LONG_CHAIN_MSG;
  1179.             eofClust = prevEnt;
  1180.             break;
  1181.             }
  1182.         /* Check for cross link and mark entry */
  1183.         if (dosChkEntryMarkSet (pFd, entNum, startClust) != OK)
  1184.             {       /* cross-link */
  1185.             if (dosChkEntryMark (pFd, MARK_GET, entNum, 0) == LOST_CHAIN_MARK)
  1186.                 dosChkEntryMark (pFd, MARK_SET, entNum, startClust);
  1187.             else
  1188.                 {
  1189.                 errMsg = CHK_CROSS_LINK_MSG;
  1190.                 eofClust = prevEnt;
  1191.                 }
  1192.             break;
  1193.             }
  1194.         numClusts += 1;  /* increase number of clusters in chain */
  1195.        }  /* while entry content is next entry number */
  1196.        while (( entValue = pFatDesc->clustValueGet (
  1197. pFd, pFatDesc->activeCopyNum,
  1198.                                 entCont, &nextEntCont) ) == DOS_FAT_ALLOC);
  1199.     switch (entValue)
  1200.         {
  1201.         case DOS_FAT_BAD:
  1202.             errMsg = CHK_BAD_CHAIN_MSG; /* ??? */
  1203.             eofClust = prevEnt;
  1204.             numClusts -= 1;
  1205.             break;
  1206.         case DOS_FAT_AVAIL:
  1207.         case DOS_FAT_INVAL:
  1208.         case DOS_FAT_RESERV:
  1209.             errMsg = CHK_BAD_CHAIN_MSG; /* ??? */
  1210.             eofClust = entNum;
  1211.             break;
  1212.         case DOS_FAT_ALLOC:
  1213.         case DOS_FAT_EOF:
  1214. default:
  1215.     break;
  1216.         }
  1217.     if (errMsg != NULL)
  1218.         {
  1219.         dosChkMsg (pFd, errMsg, CURRENT_PATH, 0, 0, 0, 0, NULL);
  1220.         pVolDesc->pChkDesc->nErrors++;
  1221.         }
  1222.     if ( (eofClust != 0) && (pVolDesc->chkLevel >= DOS_CHK_REPAIR) )
  1223.          {
  1224.             pFatDesc->clustValueSet (pFd, pFatDesc->activeCopyNum,
  1225.      eofClust, DOS_FAT_EOF, 0);
  1226.          }
  1227.     if ( ((pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY) == 0) && 
  1228.          (fileSize > numClusts) )
  1229.         dosChkEntryDel (pFd, TRUE, (u_char *)CHK_SHORT_CHAIN_MSG, 
  1230. CURRENT_PATH, 0, 0, 0, 0);
  1231.     return numClusts;
  1232.     } /* dosChkChainMark */
  1233. /*******************************************************************************
  1234. *
  1235. * dosChkChainVerify - verify a cluster chain
  1236. *
  1237. * RETURNS: special status representing the state of this chain
  1238. */
  1239. LOCAL CHK_STATUS dosChkChainVerify
  1240.     (
  1241.     DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1242.     )
  1243.     {
  1244.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1245.     DOS_FAT_DESC_ID pFatDesc = pVolDesc->pFatDesc;
  1246.     DOS_FILE_HDL_ID pFileHdl = pFd->pFileHdl;
  1247.     uint32_t parDirStartClust;
  1248.     uint32_t startClust;
  1249.     uint32_t nextEnt;
  1250.     uint32_t nextEntCont = 0;
  1251.     uint32_t entValue; /* sense of entry contents */
  1252.     parDirStartClust = pFd->pFileHdl->dirHdl.parDirStartCluster;
  1253.     startClust = pFileHdl->startClust;
  1254.     /* Check start cluster pointer */
  1255.     entValue = pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1256. startClust, &nextEnt);
  1257.     if (entValue != DOS_FAT_ALLOC)
  1258.         {
  1259.         if ( (entValue == DOS_FAT_AVAIL) && /* start cluster is 0 */
  1260.              ((pFileHdl->attrib & DOS_ATTR_DIRECTORY) == 0) && /* a file */
  1261.              (pFileHdl->size == 0) ) /* size is 0 */
  1262.             return CHK_OK;
  1263.         return dosChkEntryDel (pFd, FALSE, (u_char *)CHK_BAD_START_MSG, 
  1264.        CURRENT_PATH, 0, 0, 0, 0);
  1265.         }
  1266.     /* Check start cluster contents */
  1267.     entValue = pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1268.                                         nextEnt, &nextEntCont);
  1269.     if ( (entValue & (DOS_FAT_ALLOC | DOS_FAT_EOF)) == 0 )
  1270.         {
  1271.         if (entValue == DOS_FAT_BAD)
  1272.             return dosChkEntryDel (pFd, FALSE, (u_char *)CHK_BAD_START_MSG, 
  1273.    CURRENT_PATH, 0, 0, 0, 0); /* ??? */
  1274.         else
  1275.             {
  1276.             /* ??? */
  1277.             dosChkMsg (pFd, CHK_BAD_START_MSG, CURRENT_PATH, 0, 0, 0, 0, NULL);
  1278.             pVolDesc->pChkDesc->nErrors++;
  1279.             if (pVolDesc->chkLevel >= DOS_CHK_REPAIR)
  1280.           {
  1281.                 pFatDesc->clustValueSet (pFd, pFatDesc->activeCopyNum,
  1282.                                          startClust, DOS_FAT_EOF, 0);
  1283.           }
  1284.             }
  1285.         }
  1286.     if (entValue != DOS_FAT_ALLOC)
  1287.         {
  1288.         /* File consists of 1 start cluster only */
  1289.         if ( ((pFileHdl->attrib & DOS_ATTR_DIRECTORY) == 0) &&
  1290.              (pFileHdl->size > pVolDesc->secPerClust * pVolDesc->bytesPerSec) )
  1291.             return dosChkEntryDel (pFd, FALSE, (u_char *)CHK_SHORT_CHAIN_MSG, 
  1292.                                    CURRENT_PATH, 0, 0, 0, 0);
  1293.         }
  1294.     /* Mark start cluster as file's chain start */
  1295.     if (dosChkEntryMarkSet (pFd, startClust,
  1296.     parDirStartClust | START_CLUST_MASK) 
  1297. != OK)
  1298.         {
  1299.         if ( (dosChkEntryMark (pFd, MARK_GET, startClust, 0) &
  1300.       START_CLUST_MASK) == 0)
  1301.             return dosChkEntryDel (pFd, FALSE, (u_char *)CHK_CROSS_LINK_MSG, 
  1302.    CURRENT_PATH, 0, 0, 0, 0); /* ??? */
  1303.         dosChkStartCrossProc (pFd);
  1304.         if (pFileHdl->deleted)
  1305.             return CHK_OK;
  1306.         dosChkEntryMark (pFd, MARK_SET, startClust,
  1307.       parDirStartClust | START_CLUST_MASK);
  1308.         }
  1309.     if (entValue == DOS_FAT_ALLOC)
  1310.         if (dosChkChainMark (pFd, startClust, nextEnt, nextEntCont) == 
  1311. (uint32_t)CHK_ERROR)
  1312.         return CHK_ERROR;
  1313.     return CHK_OK;
  1314.     } /* dosChkChainVerify */
  1315. /*******************************************************************************
  1316. *
  1317. * dosChkChainStartGet - find where is beginning of a chain
  1318. *
  1319. * RETURNS: OK
  1320. */
  1321. LOCAL STATUS dosChkChainStartGet
  1322.     (
  1323.     DOS_FILE_DESC_ID pFd, /* pointer to file descriptor */
  1324.     uint32_t entNum, /* FAT entry number */
  1325.     uint32_t * pParDirStartClust, /* where to return start cluster
  1326. number of parent directory */
  1327.     uint32_t * pStartClust /* where to return start cluster
  1328. number of chain */
  1329.     )
  1330.     {
  1331.     uint32_t mark;
  1332.     mark = dosChkEntryMark (pFd, MARK_GET, entNum, 0);
  1333.     if ((mark & START_CLUST_MASK) == 0) /* not start cluster */
  1334.         { /* go to start cluster */
  1335.         entNum = mark;
  1336.         mark   = dosChkEntryMark (pFd, MARK_GET, entNum, 0);
  1337.         }
  1338.     *pStartClust       = entNum;
  1339.     *pParDirStartClust = mark & (~START_CLUST_MASK);
  1340.     return OK;
  1341.     } /* dosChkChainStartGet */
  1342. /*******************************************************************************
  1343. *
  1344. * dosChkChainUnmark - Un-mark an entire chain
  1345. *
  1346. * RETURNS:
  1347. */
  1348. LOCAL void dosChkChainUnmark
  1349.     (
  1350.     DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1351.     )
  1352.     {
  1353.     DOS_FAT_DESC_ID pFatDesc = pFd->pVolDesc->pFatDesc;
  1354.     uint32_t entNum;
  1355.     uint32_t nextEnt;
  1356.     entNum = pFd->pFileHdl->startClust; 
  1357.     while ( (pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1358.                                       entNum, &nextEnt) == DOS_FAT_ALLOC) &&
  1359.             (dosChkEntryMark (pFd, MARK_GET, entNum, 0) != 0) )
  1360.         {
  1361.         dosChkEntryMark (pFd, MARK_SET, entNum, 0);
  1362.         entNum = nextEnt;
  1363.         }
  1364.     } /* dosChkChainUnmark */
  1365. /*******************************************************************************
  1366. *
  1367. * dosChkLostFind - find lost chains in the FAT
  1368. *
  1369. * RETURNS:OK or ERROR if any of the chains contained an illegal value
  1370. */
  1371. LOCAL STATUS dosChkLostFind
  1372.     (
  1373.     DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1374.     )
  1375.     {
  1376.     DOS_VOLUME_DESC_ID  pVolDesc = pFd->pVolDesc;
  1377.     DOS_FAT_DESC_ID pFatDesc = pVolDesc->pFatDesc;
  1378.     CHK_DSK_DESC_ID pChkDesc = pVolDesc->pChkDesc;
  1379.     uint32_t entNum;
  1380.     uint32_t entCont;
  1381.     uint32_t nextEntCont;
  1382.     uint32_t entValue;
  1383.     uint32_t retVal = OK;
  1384.     uint32_t lostClusts = 0;
  1385.     cookie_t bufCookie = (cookie_t) NULL, fatCookie = (cookie_t) NULL;
  1386.     for (entNum = DOS_MIN_CLUST; entNum < pFd->pVolDesc->nFatEnts; entNum++)
  1387.         {
  1388.         if (dosChkEntryMark (pFd, IS_BUSY, entNum, 0) == 0)
  1389.             {
  1390.     /* Get content of the entry */
  1391.          bufCookie = pFd->fatHdl.cbioCookie;
  1392.          pFd->fatHdl.cbioCookie = fatCookie;
  1393.             pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1394.                                      entNum, &entCont);
  1395.             /* Value the entry content */
  1396.             entValue = pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1397.                                                 entCont, &nextEntCont);
  1398.          fatCookie = pFd->fatHdl.cbioCookie;
  1399.          pFd->fatHdl.cbioCookie = bufCookie;
  1400.             switch (entValue)
  1401.                 {
  1402.                 case DOS_FAT_ALLOC:
  1403.                 case DOS_FAT_EOF:
  1404.                 case DOS_FAT_INVAL:
  1405.                 case DOS_FAT_RESERV:
  1406.                     pChkDesc->chkNLostChains++;/* Count number of lost chains */
  1407.                     pChkDesc->nErrors++; /* Count number of errors */
  1408.                     retVal = ERROR;
  1409.                     dosChkEntryMark (pFd, MARK_SET, entNum, LOST_CHAIN_MARK);
  1410.                     if (entValue == DOS_FAT_ALLOC)
  1411.                         lostClusts += dosChkChainMark (pFd, entNum, entCont, 
  1412.                                                        nextEntCont);
  1413.                     else
  1414.                         lostClusts += 1;
  1415.                     break;
  1416.                 case DOS_FAT_BAD:
  1417.                     pChkDesc->chkNBadClusts++;
  1418.                     break;
  1419.                 case DOS_FAT_AVAIL:
  1420.                     pChkDesc->chkNFreeClusts++;
  1421.                     break;
  1422.                 } /* switch */
  1423.             }
  1424.         } /* for */
  1425.     pChkDesc->chkTotalBytesInLostChains = lostClusts * pVolDesc->secPerClust *
  1426.                                           pVolDesc->bytesPerSec;;
  1427.     return retVal;
  1428.     } /* dosChkLostFind */
  1429. /*******************************************************************************
  1430. *
  1431. * dosChkLostFree - free all lost chains in the FAT
  1432. *
  1433. * RETURNS: OK.
  1434. */
  1435. LOCAL STATUS dosChkLostFree
  1436.     (
  1437.     DOS_FILE_DESC_ID pFd /* pointer to file descriptor */
  1438.     )
  1439.     {
  1440.     DOS_VOLUME_DESC_ID  pVolDesc = pFd->pVolDesc;
  1441.     DOS_FAT_DESC_ID pFatDesc = pVolDesc->pFatDesc;
  1442.     uint32_t entNum;
  1443.     uint32_t nextEnt;
  1444.     uint32_t nextEntCont;
  1445.     uint32_t entVal;
  1446.     uint32_t i;
  1447.     if (pVolDesc->chkLevel < DOS_CHK_REPAIR)
  1448.         return OK;
  1449.     for (i = DOS_MIN_CLUST; i < pFd->pVolDesc->nFatEnts; i++)
  1450.         {
  1451.         entNum = i;
  1452.         if (dosChkEntryMark (pFd, MARK_GET, entNum, 0) == LOST_CHAIN_MARK)
  1453.             {
  1454.             /* Follow lost chain and free clusters */
  1455.             pFatDesc->clustValueGet (pFd, pFatDesc->activeCopyNum,
  1456.                                      entNum, &nextEnt);
  1457.             /* While entry content is next cluster number */
  1458.             while ( (entVal = pFatDesc->clustValueGet (
  1459. pFd, pFatDesc->activeCopyNum,
  1460.                                 nextEnt, &nextEntCont)) == DOS_FAT_ALLOC )
  1461.                 {
  1462.                 pFatDesc->clustValueSet (pFd, pFatDesc->activeCopyNum,
  1463.                                          entNum, DOS_FAT_AVAIL, 0);
  1464.                 entNum  = nextEnt;
  1465.                 nextEnt = nextEntCont;
  1466.                 }
  1467.             /* For end of file */
  1468.             pFatDesc->clustValueSet (pFd, pFatDesc->activeCopyNum,
  1469.                                      entNum, DOS_FAT_AVAIL, 0);
  1470.             }
  1471.         } /* for */
  1472.     return OK;
  1473.     } /* dosChkLostFree */
  1474. /* End of File */