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

VxWorks

开发平台:

C/C++

  1. /* dosDirOldLib.c - MS-DOS old style names dir handler */ 
  2. /* Copyright 1999-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01j,29apr02,jkf  SPR#72255, upon file creation, set the create, modification,
  7.                  and access time fields to match creation rather than using
  8.                  the epoch (0).
  9. 01i,10dec01,jkf  SPR#72039, various fixes from Mr. T. Johnson.
  10. 01h,21aug01,jkf  SPR#69031, common code for both AE & 5.x.
  11. 01g,06mar01,jkf  SPR#34704, rootNSec calculation must round up.
  12. 01f,29feb00,jkf  T3 merge
  13. 01e,31jul99,jkf  T2 merge, tidiness & spelling.
  14. 01d,22nov98,vld  all offsets of directory entry changed to be
  15.  counted in absolute offset from parent directory
  16.  start
  17. 01c,28sep98,vld  gnu extensions dropped from DBG_MSG/ERR_MSG macros
  18. 01b,02jul98,lrn  doc review
  19. 01a,18jan98,vld  written
  20. */
  21. /*
  22. DESCRIPTION
  23. This library is part of dosFsLib and  is designed to handle
  24. the DOS4.0 standard disk directory structure as well as
  25. vxWorks proprietary long names in case sensitive manner.
  26. File names in DOS4.0 are composed of a 8 characters name and
  27. 3 characters extension separated by dot character.
  28. They are stored on disk in uppercase mode, and name lookup
  29. is case insensitive. New VFAT file name standard also
  30. supports DOS4.0 directory structure, and if both handlers
  31. (this one and dosVDirLib) are installed, VFAT handler take precedence,
  32. and will be used for such a volume by default.
  33. VxWorks proprietary long names are composed of up to 40 characters
  34. and are fully case sensitive. Also, files with length greater, than
  35. 4GB can be stored on the volume is formatted with VxWorks proprietary
  36. long names directory structure.
  37. Routine dosDirOldLibInit() has to be called once to install this
  38. into dosFsLib directory handlers list. Once it has been done this directory
  39. handler will be automatically mounted on each new appropriate volume
  40. being mounted.
  41. SEE ALSO:
  42. dosFsLib.
  43. */
  44. /* includes */
  45. #include "vxWorks.h"
  46. #include "private/dosFsVerP.h"
  47. #include "stat.h"
  48. #include "dirent.h"
  49. #include "time.h"
  50. #include "stdio.h"
  51. #include "ctype.h"
  52. #include "taskLib.h"
  53. #include "stdlib.h"
  54. #include "string.h"
  55. #include "semLib.h"
  56. #include "logLib.h"
  57. #include "errnoLib.h"
  58. #include "time.h"
  59. #include "utime.h"
  60. #include "memLib.h"
  61. #include "private/dosFsLibP.h"
  62. #include "private/dosDirLibP.h"
  63. /* defines */
  64. /* macros */
  65. #undef DBG_PRN_STR
  66. #undef DBG_MSG
  67. #undef ERR_MSG
  68. #undef NDEBUG
  69.  
  70. #ifdef DEBUG
  71. #   undef LOCAL
  72. #   define LOCAL
  73. #   undef ERR_SET_SELF
  74. #   define ERR_SET_SELF
  75. #   define DBG_PRN_STR( lvl, fmt, pStr, len, arg )
  76. { if( (lvl) <= dosDirOldDebug ) {
  77.     char cBuf = ((char *)(pStr))[len];
  78.     (pStr)[len] = EOS; 
  79.     printErr( (fmt),(pStr),(arg) );
  80.     ((char *)(pStr))[len] = cBuf;  } }
  81. #   define DBG_MSG( lvl, fmt, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 )
  82. { if( (lvl) <= dosDirOldDebug )
  83.     printErr( "%s : %d : " fmt,
  84.                __FILE__, __LINE__, arg1,arg2,
  85.        arg3,arg4,arg5,arg6,arg7,arg8 ); }
  86. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  87.         { logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  88.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  89. #else /* NO DEBUG */
  90. #   define NDEBUG
  91. #   define DBG_PRN_STR( lvl, fmt, pStr, len, arg ) {}
  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) <= dosDirOldDebug ) 
  95.             logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  96.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  97. #endif /* DEBUG */
  98.  
  99. #include "assert.h"
  100. #ifdef ERR_SET_SELF
  101. #   define errnoSet( err ) errnoSetOut( __FILE__, __LINE__, #err, (err) )
  102. #endif /* ERR_SET_SELF */
  103. /* vxWorks long names specific  */
  104. /* typedefs */
  105. typedef enum {RD_FIRST, RD_CURRENT, RD_NEXT, FD_ENTRY} RDE_OPTION;
  106. /* function argument */
  107. typedef struct DOS_DIROLD_DESC /* directory handler's part of */
  108. /* volume descriptor */
  109.     {
  110.     DOS_DIR_PDESCR genDirDesc; /* generic descriptor */
  111.     } DOS_DIROLD_DESC;
  112. typedef DOS_DIROLD_DESC * DOS_DIROLD_DESC_ID;
  113. /* globals */
  114. int dosDirOldDebug = 1;
  115. /* locals */
  116. /* valid filename characters table ('|' is invalid character) */
  117. static const u_char shortNamesChar[] =
  118.                                         /* 0123456789abcdef */
  119.                                           "||||||||||||||||"
  120.                                           "||||||||||||||||"
  121.                                           " !|#$%&'()|||-||"
  122.                                           "0123456789||||||"
  123.                                           "@ABCDEFGHIJKLMNO"
  124.                                           "PQRSTUVWXYZ|||^_"
  125.                                           "`ABCDEFGHIJKLMNO"
  126.                                           "PQRSTUVWXYZ{|}~|" ,
  127.                         longNamesChar[] =
  128.                                         /* 0123456789abcdef */
  129.                                           "||||||||||||||||"
  130.                                           "||||||||||||||||"
  131.                                           " !|#$%&'()|+,-.|"
  132.                                           "0123456789|;|=||"
  133.                                           "@ABCDEFGHIJKLMNO"
  134.                                           "PQRSTUVWXYZ[|]^_"
  135.                                           "`abcdefghijklmno"
  136.                                           "pqrstuvwxyz{|}~|" ;
  137. /* forward declarations */
  138. #ifdef ERR_SET_SELF
  139. /*******************************************************************************
  140. * errnoSetOut - put error message
  141. *
  142. * This routine is called instead errnoSet during debugging.
  143. */
  144. static VOID errnoSetOut(char * pFile, int line, const char * pStr, int errCode )
  145.     {
  146.     if( errCode != OK  && strcmp( str, "errnoBuf" ) != 0 )
  147.         printf( " %s : line %d : %s = %p, task %pn",
  148.                 pFile, line, pStr, (void *)errCode,
  149.                 (void *)taskIdSelf() );
  150.     errno = errCode;
  151.     }
  152. #endif  /* ERR_SET_SELF */
  153.  /***************************************************************************
  154. *
  155. * dosDirOldFillFd - fill file descriptor for directory entry.
  156. *
  157. * RETURNS: N/A.
  158. */
  159. LOCAL void dosDirOldFillFd
  160.     (
  161.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  162.     u_char * pDirEnt /* directory entry from disk */
  163.     )
  164.     {
  165.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  166.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  167.     DIRENT_DESCR_ID pDeDesc;
  168.     
  169.     pDeDesc = &pDirDesc->deDesc;
  170.     
  171.     if( pDirEnt == (u_char *) NULL ) /* root directory */
  172.      {
  173.      DBG_MSG( 600, "root directoryn", 0,0,0,0,0,0,0,0 );
  174.      ROOT_SET( pFd ); /* via <parDirStartCluster> field */
  175.      pFd->curSec = pDirDesc->dirDesc.rootStartSec;
  176.      pFd->nSec = pDirDesc->dirDesc.rootNSec;
  177.      pFd->pos = 0;
  178.      pFd->pFileHdl->attrib = DOS_ATTR_DIRECTORY;
  179.      pFd->pFileHdl->startClust = pDirDesc->rootStartClust;
  180.     
  181.      pDirHdl->sector = NONE;
  182.      pDirHdl->offset = NONE;
  183.     
  184.      pFd->cbioCookie = (cookie_t) NULL;
  185.      pDirHdl->cookie = (cookie_t) NULL;
  186.     
  187.      goto rewind;
  188.      }
  189.     
  190.     /* at the beginning fill directory handle using file descriptor */
  191.     
  192.     pDirHdl->parDirStartCluster = pFd->pFileHdl->startClust;
  193.     pDirHdl->sector = pFd->curSec;
  194.     pDirHdl->offset = pFd->pos;
  195.     pDirHdl->cookie = pFd->cbioCookie;
  196.     pFd->cbioCookie = (cookie_t) NULL;
  197.     /* disassemble directory entry */
  198.     
  199.     pFd->pos = 0;
  200.     
  201.     pFd->curSec = 0;
  202.     pFd->nSec = 0;
  203.     
  204.     pFd->pFileHdl->attrib = *(pDirEnt + pDeDesc->atrribOff);
  205.     pFd->pFileHdl->startClust =
  206.      START_CLUST_DECODE( pFd->pVolDesc, pDeDesc, pDirEnt );
  207.     
  208.     pFd->pFileHdl->size = DISK_TO_VX_32(pDirEnt + pDeDesc->sizeOff);
  209.     
  210.     if( pDeDesc->extSizeOff != (u_char) NONE )
  211.      {
  212.      pFd->pFileHdl->size += EXT_SIZE_DECODE( pDeDesc, pDirEnt );
  213.      }
  214.         
  215. rewind:
  216.     DBG_MSG( 600, "pFd = %p "
  217.        "dir hdl (sec-of-par = %u sector = %u offset = %u)n"
  218.                   "pFileHdl = %p "
  219.                   "(startClust = %u size = %lu attr = %p)n",
  220.                   pFd, pDirHdl->parDirStartCluster,
  221.                   pDirHdl->sector, pDirHdl->offset,
  222.                   pFd->pFileHdl, pFd->pFileHdl->startClust,
  223.                   pFd->pFileHdl->size,
  224.                   (void *)((int)pFd->pFileHdl->attrib) );
  225.     /*
  226.      * cause FAT to start from start cluster and
  227.      * get start contiguous block
  228.      */
  229.     bzero( (char *)&pFd->fatHdl, sizeof( pFd->fatHdl ) );
  230.     return;
  231.     } /* dosDirOldFillFd() */
  232. /***************************************************************************
  233. *
  234. * dosDirOldRewindDir - rewind directory pointed by pFd.
  235. *
  236. * This routine sets current sector in pFd to directory start sector
  237. * and current position  (offset in sector) to 0.
  238. *
  239. * RETURNS: N/A.
  240. */
  241. LOCAL void dosDirOldRewindDir
  242.     (
  243.     DOS_FILE_DESC_ID pFd /* dos file descriptor to fill */
  244.     )
  245.     {
  246.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  247.     
  248.     pFd->pos = 0;
  249.     pFd->nSec = 0;
  250.     pFd->curSec = 0;
  251.     
  252.     /* for FAT32 curSec = rootNSec = 0 */
  253.     
  254.     if( IS_ROOT( pFd ) && pDirDesc->dirDesc.rootNSec != 0 )
  255.      {
  256.      pFd->curSec = pDirDesc->dirDesc.rootStartSec;
  257.      pFd->nSec = pDirDesc->dirDesc.rootNSec;
  258.      return;
  259.      }
  260.     
  261.     /* regular file or FAT32 root */
  262.     /*
  263.      * cause FAT to start from start cluster and
  264.      * get start contiguous block
  265.      */
  266.     if( pFd->pVolDesc->pFatDesc->seek( pFd, FH_FILE_START, 0 ) == ERROR )
  267.      {
  268.      assert( FALSE );
  269.      }
  270.     } /* dosDirOldRewindDir() */
  271.    
  272. /***************************************************************************
  273. *
  274. * dosDirOldPathParse - parse a full pathname into an array of names.
  275. *
  276. * This routine is similar to pathParse(), except it does not 
  277. * allocate additional buffers nor changes the path string.
  278. *
  279. * Parses a path in directory tree which has directory names
  280. * separated by '/' or '\'s.  It fills the supplied array of
  281. * structures with pointers to directory and file names and 
  282. * corresponding name length.
  283. *
  284. * All occurrences of '//', '.' and '..'
  285. * are right removed from path. All tail dots and spaces are broken from
  286. * each name, that is name like "abc. . ." is treated as just "abc".
  287. *
  288. * For instance, "/usr/vw/data/../dir/file" gets parsed into
  289. *
  290. * .CS
  291. *                          namePtrArray
  292. *                         |---------|
  293. *   ---------------------------o    |
  294. *   |                     |    3    |
  295. *   |                     |---------|
  296. *   |   -----------------------o    |
  297. *   |   |                 |    2    |
  298. *   |   |                 |---------|
  299. *   |   |          ------------o    |
  300. *   |   |          |      |    3    |
  301. *   |   |          |      |---------|
  302. *   |   |          |   --------o    |
  303. *   |   |          |   |  |    4    |
  304. *   |   |          |   |  |---------|
  305. *   v   v          v   v  |   NULL  |
  306. *   |   |          |   |  |    0    |
  307. *   |   |          |   |  |---------|
  308. *   v   v          v   v 
  309. *  |------------------------|
  310. *  |usr/vw/data/../dir/file |
  311. *  |------------/----------|
  312. *          ignored
  313. *
  314. * .CE
  315. *
  316. * RETURNS: number of levels in path.
  317. *
  318. * ERRNO:
  319. * S_dosFsLib_ILLEGAL_PATH
  320. * S_dosFsLib_ILLEGAL_NAME
  321. */
  322. LOCAL int dosDirOldPathParse
  323.     (
  324.     DOS_VOLUME_DESC_ID pVolDesc,
  325.     u_char * path,
  326.     PATH_ARRAY_ID pnamePtrArray
  327.     )
  328.     {
  329.     FAST u_int numPathLevels;
  330.     FAST u_char * pName;
  331.     FAST u_char * pRegChar; /* last not DOT and not SPACE char */
  332.     
  333.     pnamePtrArray[0].pName = NULL;
  334.     /* go throw path string from left to right */
  335.     
  336.     pName = path;
  337.     numPathLevels = 0;
  338.     while( *pName != EOS ) /* there is 'break' in loop also */
  339.      {
  340.      /* pass slashes */
  341.     
  342.      if( *pName == SLASH || *pName == BACK_SLASH )
  343.          {
  344.          pName++;
  345.          continue;
  346.          }
  347.     
  348.      /* process special names ( "." ".." ) */
  349.     
  350.      if( *pName == DOT )
  351.         {
  352.         /* "/./" - ignore "current directory" */
  353.         if( *(pName + 1) == EOS || *(pName + 1) == SLASH ||
  354.             *(pName + 1) == BACK_SLASH )
  355.          {
  356.          pName ++;
  357.          continue;
  358.          }
  359.         
  360.         /* "/../" - goto one level back */
  361.         
  362.         if( (*(pName + 1) == DOT) &&
  363.             ( *(pName + 2) == EOS || *(pName + 2) == SLASH ||
  364.               *(pName + 2) == BACK_SLASH ) )
  365.          {
  366.          if( numPathLevels > 0 )
  367.              numPathLevels --;
  368.          pName +=2;
  369.          continue;
  370.          }
  371.         } /* if( *pName == DOT ) */
  372.         
  373.      /* regular name: insert it into array */
  374.     
  375.      if( numPathLevels >= DOS_MAX_DIR_LEVELS )
  376.          break; /* max level overloaded */
  377.     
  378.      pnamePtrArray[numPathLevels].pName = pName;
  379.      pnamePtrArray[numPathLevels + 1].pName = NULL;
  380.      pRegChar = NULL;
  381.      while( *pName != SLASH && *pName != BACK_SLASH && *pName != EOS )
  382.          {
  383.          if( *pName != DOT || *pName == SPACE )
  384.           pRegChar = pName;
  385.          pName++;
  386.          }
  387.     
  388.      /* name can not contain only dots */
  389.     
  390.      if( pRegChar == NULL )
  391.          {
  392.          errnoSet( S_dosFsLib_ILLEGAL_NAME );
  393.          return ERROR;
  394.          }
  395.     
  396.      pnamePtrArray[numPathLevels].nameLen =
  397.      pRegChar + 1 - pnamePtrArray[numPathLevels].pName;
  398.     
  399.      numPathLevels++;
  400.      } /* while( *pName != EOS ) */
  401.     
  402.     /* check result */
  403.     
  404.     if( *pName != EOS ) /* path termination has not been reached */
  405.      {
  406.      errnoSet( S_dosFsLib_ILLEGAL_PATH );
  407.      return ERROR;
  408.      }
  409. #ifdef DEBUG
  410.     DBG_MSG( 600, "path: %s, result: n", path ,0,0,0,0,0,0,0);
  411.     pName = (void *)pnamePtrArray;
  412.     for( ; pnamePtrArray->pName != NULL; pnamePtrArray++ )
  413.      {
  414.      int i = pnamePtrArray - (PATH_ARRAY_ID)pName + 1;
  415.      DBG_PRN_STR( 600, "%s : %d", pnamePtrArray->pName,
  416.      pnamePtrArray->nameLen, i );
  417.      }
  418.     DBG_PRN_STR(600, "bb n", "", 0, 0);
  419. #endif /* DEBUG */
  420.     return numPathLevels;
  421.     } /* dosDirOldPathParse() */
  422.     
  423. /***************************************************************************
  424. *
  425. * dosDirOldTDDecode - decode time-date field from disk format.
  426. *
  427. * This routine decodes required date-time field in the directory
  428. * entry into time_t format.
  429. * Parameter which defines which time field to decode. It
  430. * can be one of:
  431. * DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.
  432. *
  433. * RETURNS: time in time_t format.
  434. *
  435. */
  436. LOCAL time_t dosDirOldTDDecode
  437.     (
  438.     DOS_DIR_PDESCR_ID pDirDesc,
  439.     u_char * pDirent, /* directory entry buffer */
  440.     u_int which /* what field to decode: one of */
  441.      /* DH_TIME_CREAT, DH_TIME_MODIFY or DH_TIME_ACCESS */
  442.     )
  443.     {
  444.     struct tm tm = {0}; /* broken down time buffer */
  445.     UINT16 dtBuf; /* 16-bit buffer */
  446.     u_char tOff = 0, dOff = 0; /* field offset */
  447.     
  448.     switch( which )
  449.         {
  450.         case DH_TIME_CREAT:
  451.             tOff = pDirDesc->deDesc.creatTimeOff;
  452.             dOff = pDirDesc->deDesc.creatDateOff;
  453.             break;
  454.         case DH_TIME_MODIFY:
  455.             tOff = pDirDesc->deDesc.modifTimeOff;
  456.             dOff = pDirDesc->deDesc.modifDateOff;
  457.             break;
  458.         case DH_TIME_ACCESS:
  459.             tOff = pDirDesc->deDesc.accessTimeOff;
  460.             dOff = pDirDesc->deDesc.accessDateOff;
  461.             break;
  462.         default:
  463.             assert( FALSE );
  464.         }
  465.     
  466.     if( dOff != (u_char)NONE )
  467.      {
  468.      dtBuf = DISK_TO_VX_16( pDirent + dOff );
  469.     
  470.      tm.tm_mday    = dtBuf & 0x1f;
  471.     
  472. /* ANSI months are zero-based */
  473.      tm.tm_mon     = ((dtBuf >> 5) & 0x0f) - 1;
  474.     
  475. /* DOS starts at 1980, ANSI starts at 1900 */
  476.      tm.tm_year    = ((dtBuf >> 9) & 0x7f) + 1980 - 1900;
  477.      }
  478.     if( tOff != (u_char)NONE )
  479.      {
  480.      dtBuf = DISK_TO_VX_16( pDirent + tOff );
  481.     
  482.      tm.tm_sec     = (dtBuf & 0x1f) << 1;
  483.      tm.tm_min     = (dtBuf >> 5) & 0x3f;
  484.      tm.tm_hour    = (dtBuf >> 11) & 0x1f;
  485.      }
  486.     
  487.     /* encode into time_t format */
  488.     
  489.     return mktime( &tm );
  490.     } /* dosDirOldTDDecode() */
  491. /***************************************************************************
  492. *
  493. * dosDirOldTDEncode - encode time-date to disk format.
  494. *
  495. * This routine takes time value is provided in <curTime> argument
  496. * and encodes it into directory entry format.
  497. * Parameter <timesMask> defines which time fields to fill. Following
  498. * values can be bitwise or-ed:
  499. * DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.
  500. *
  501. * RETURNS: N/A.
  502. */
  503. LOCAL void dosDirOldTDEncode
  504.     (
  505.     DOS_DIR_PDESCR_ID pDirDesc,
  506.     u_char * pDirEnt,
  507.     u_int timesMask,
  508.     time_t curTime /* time to encode */
  509.     )
  510.     {
  511.     struct tm   tm; /* buffer for split time-date */
  512.     u_char timeB[2], dateB[2]; /* buffers for encoding */
  513.     
  514.     localtime_r( &curTime, &tm );
  515.     /* encode time */
  516.     
  517.     VX_TO_DISK_16( ( tm.tm_sec >> 1 ) |
  518.        ( tm.tm_min << 5 ) |
  519.        ( tm.tm_hour << 11 ), timeB );
  520.     
  521.     /*
  522.      * encode date;
  523.      * in <pDate> year is related to 1980, but in tm,-to 1900
  524.      */
  525.     tm.tm_year =  ( tm.tm_year < 80 )? 80 : tm.tm_year;
  526.     VX_TO_DISK_16( tm.tm_mday | ( ( tm.tm_mon + 1 ) << 5 ) |
  527.        ( ( tm.tm_year - 80 ) <<  9 ), dateB );
  528.     
  529.     /* put time-date into directory entry buffer */
  530.     
  531.     if( timesMask & DH_TIME_CREAT &&
  532.         pDirDesc->deDesc.creatDateOff != (u_char)NONE  )
  533.      {
  534.      pDirEnt[ pDirDesc->deDesc.creatTimeOff ] = timeB[0];
  535.      pDirEnt[ pDirDesc->deDesc.creatTimeOff + 1 ] = timeB[1];
  536.      pDirEnt[ pDirDesc->deDesc.creatDateOff ] = dateB[0];
  537.      pDirEnt[ pDirDesc->deDesc.creatDateOff + 1 ] = dateB[1];
  538.      }
  539.     if( timesMask & DH_TIME_MODIFY &&
  540.         pDirDesc->deDesc.modifDateOff != (u_char)NONE  )
  541.      {
  542.      pDirEnt[ pDirDesc->deDesc.modifTimeOff ] = timeB[0];
  543.      pDirEnt[ pDirDesc->deDesc.modifTimeOff + 1 ] = timeB[1];
  544.      pDirEnt[ pDirDesc->deDesc.modifDateOff ] = dateB[0];
  545.      pDirEnt[ pDirDesc->deDesc.modifDateOff + 1 ] = dateB[1];
  546.      }
  547.     if( timesMask & DH_TIME_ACCESS &&
  548.         pDirDesc->deDesc.accessDateOff != (u_char)NONE  )
  549.      {
  550.      if( pDirDesc->deDesc.accessTimeOff != (u_char)NONE )
  551.          {
  552.          pDirEnt[ pDirDesc->deDesc.accessTimeOff ] = timeB[0];
  553.          pDirEnt[ pDirDesc->deDesc.accessTimeOff + 1 ] = timeB[1];
  554.          }
  555.      pDirEnt[ pDirDesc->deDesc.accessDateOff ] = dateB[0];
  556.      pDirEnt[ pDirDesc->deDesc.accessDateOff + 1 ] = dateB[1];
  557.      }
  558.     } /* dosDirOldTDEncode() */
  559.     
  560. /***************************************************************************
  561. *
  562. * dosDirOldNameEncode - encode name to disk format.
  563. *
  564. * This routine encodes incoming file name to current volume
  565. * directory structure format
  566. * (8+3 uppercase or VxLong names). in the same time incoming
  567. * name is verified to be composed of valid characters.
  568. *
  569. * RETURNS: OK or ERROR if name is invalid.
  570. * ERRNO:
  571. * S_dosFsLib_ILLEGAL_NAME
  572. */
  573. LOCAL STATUS dosDirOldNameEncode
  574.     ( 
  575.     DOS_DIR_PDESCR_ID pDirDesc,
  576.     PATH_ARRAY_ID pNamePtr, /* name buffer */
  577.     u_char * pDstName /* buffer for name in disk format */
  578.     )
  579.     {
  580.     u_char const * nameTransTbl; /* name translation table */
  581.     u_char * pSrc; /* source name dynamic ptr */
  582.     u_char * pDstBuf; /* for debug output only */
  583.     int i,j; /* work */
  584.     u_char extLen = pDirDesc->deDesc.extLen;
  585.      /* extension length (0 - no extension) */
  586.     
  587.     pDstBuf = pDstName;
  588.     nameTransTbl = ( pDirDesc->nameStyle == STDDOS )?
  589.      shortNamesChar : longNamesChar;
  590.     
  591.     bfill( (char *) pDstName,
  592.         pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen, 
  593.            SPACE );
  594.     
  595.     /* encode name and check it by the way */
  596.     
  597.     DBG_MSG( 600, "",0 ,0,0,0,0,0,0,0);
  598.     DBG_PRN_STR( 600, "%sn", pNamePtr->pName, pNamePtr->nameLen, 0 );
  599.     for( i = 0, pSrc = pNamePtr->pName;
  600.       i < min( pDirDesc->deDesc.nameLen,
  601.          pNamePtr->nameLen );
  602.       i++, pDstName++, pSrc++  )
  603.      {
  604.      /* check for extension */
  605.     
  606.      if( extLen != 0 && *pSrc == DOT )
  607.          break;
  608.     
  609.      /* allow all high characters */
  610.     
  611.      if( *pSrc & 0x80 )
  612.          {
  613.          *pDstName = *pSrc;
  614.          continue;
  615.          }
  616.     
  617.      *pDstName = nameTransTbl[ *pSrc ];
  618.      if( *pDstName == INVALID_CHAR )
  619.          goto error;
  620.      }
  621.     /* check state */
  622.     
  623.     if( i == pNamePtr->nameLen )
  624.      goto retOK; /* name finished */
  625.     
  626.     if( extLen != 0 ) /* traditional DOS: 8.3 */
  627.      {
  628.      if( *pSrc != DOT ) /* name too long */
  629.          goto error;
  630.      pSrc++; /* pass DOT */
  631.      pDstName += pDirDesc->deDesc.nameLen - i;
  632.      i++;
  633.      }
  634.     else /* vxWorks old long names */
  635.      goto error; /* name too long */
  636.     
  637.     /* encode extension */
  638.     
  639.     for( j = 0; j < extLen && i < pNamePtr->nameLen;
  640.       i++, j++, pDstName++, pSrc++  )
  641.      {
  642.      /* allow all high characters */
  643.     
  644.      if( *pSrc & 0x80 )
  645.          {
  646.          *pDstName = *pSrc;
  647.          continue;
  648.          }
  649.     
  650.      *pDstName = nameTransTbl[ *pSrc ];
  651.      if( *pDstName == INVALID_CHAR )
  652.          goto error;
  653.      }
  654.     
  655.     /* check status */
  656.     
  657.     if( i < pNamePtr->nameLen ) /* extension too long */
  658.      goto error;
  659. retOK:
  660.     DBG_PRN_STR( 600, "result: %sn", pDstBuf, 
  661.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  662.     return OK;
  663.     
  664. error:
  665.     errnoSet( S_dosFsLib_ILLEGAL_NAME );
  666.     return ERROR;
  667.     } /* dosDirOldNameEncode() */
  668.     
  669. /***************************************************************************
  670. *
  671. * dosDirOldDirentGet - get directory entry from disk.
  672. *
  673. * This routine reads directory entry from disk. 
  674. *
  675. * <which> argument defines which entry to get.
  676. * This routine can be
  677. * used for readdir (<which> = RD_FIRST/RD_CURRENT/RD_NEXT),
  678. * in what case <pFd> describes the
  679. * directory is being read, or for getting directory entry
  680. * corresponding to <pFd> (<which> = FD_ENTRY).
  681. *
  682. * RETURNS: OK or ERROR if directory chain end reached or
  683. *  disk access error.
  684. */
  685. LOCAL STATUS dosDirOldDirentGet
  686.     (
  687.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  688.     u_char * pDirEnt,
  689.     RDE_OPTION  which /* which entry to get */
  690.     )
  691.     {
  692.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  693.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  694.     int dirEntSize = pDirDesc->deDesc.dirEntSize;
  695.     DOS_FILE_DESC workFd;
  696.     
  697.     /* prepare to operation */
  698.     
  699.     if( which == FD_ENTRY ) /* get directory entry of file */
  700.      {
  701.      DBG_MSG( 600, "pFd = %p, FD_ENTRYn", pFd ,0,0,0,0,0,0,0);
  702.      /*
  703.       * it is being read directory entry of the file/dir,
  704.       * pointed by file descriptor.
  705.       * Prepare working fd.
  706.       */
  707.      workFd = *pFd;
  708.      workFd.curSec = pDirHdl->sector;
  709.      workFd.pos = pDirHdl->offset;
  710.      workFd.cbioCookie = pDirHdl->cookie;
  711.     
  712.      goto getEntry;
  713.      }
  714.     
  715.     /* readdir */
  716.     
  717.     if(  which == RD_CURRENT ) /* read current dir entry */
  718.      {
  719.      assert( pFd->nSec != 0 );
  720.      assert( pFd->curSec != 0 );
  721.     
  722.      goto getEntry;
  723.      }
  724.     
  725.     if( which == RD_FIRST ) /* read start dir entry */
  726.      {
  727.      DBG_MSG( 600, "pFd = %p, RD_FIRSTn", pFd ,0,0,0,0,0,0,0);
  728.      dosDirOldRewindDir( pFd ); /* rewind directory */
  729.      }
  730.     else if( which == RD_NEXT ) /* read next dir entry */
  731.      {
  732.      DBG_MSG( 600, "pFd = %p, RD_NEXTn", pFd ,0,0,0,0,0,0,0);
  733.      assert( pFd->curSec != 0 );
  734.     
  735.      /* correct position */
  736.     
  737.      pFd->pos += dirEntSize;
  738.     
  739.      /* check for sector bounds */
  740.     
  741.      if( OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ) == 0 )
  742.          {
  743.          pFd->curSec++;
  744.          pFd->nSec--;
  745.          }
  746.      }
  747.     else /* impossible flag */
  748.      {
  749.      assert( which != which );
  750.      } 
  751.     
  752.     /* may be contiguous block finished - get next contiguous block */
  753.          
  754.     if( pFd->nSec == 0 )
  755.      {
  756.      if( pFd->pVolDesc->pFatDesc->getNext(
  757.           pFd, FAT_NOT_ALLOC ) == ERROR )
  758.          {
  759.          return ERROR;
  760.          }
  761.      pFd->cbioCookie = (cookie_t) NULL; /* we jumped to other sector */
  762.      }
  763.     
  764.     workFd = *pFd;
  765.     
  766. getEntry:
  767.     assert( OFFSET_IN_SEC( workFd.pVolDesc, workFd.pos ) <=
  768. workFd.pVolDesc->bytesPerSec - dirEntSize );
  769.     
  770.     /* read directory entry */
  771.     
  772.     if( cbioBytesRW( workFd.pVolDesc->pCbio, workFd.curSec,
  773.           OFFSET_IN_SEC( workFd.pVolDesc, workFd.pos),
  774.      (addr_t)pDirEnt, dirEntSize, CBIO_READ,
  775.           &workFd.cbioCookie ) == ERROR )
  776.      {
  777.      return ERROR;
  778.      }
  779.     DBG_PRN_STR( 600, "entry: %sn", pDirEnt,
  780.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  781.       
  782.     return OK;
  783.     } /* dosDirOldDirentGet() */
  784.     
  785. /***************************************************************************
  786. *
  787. * dosDirOldLkupInDir - look in directory for specified name.
  788. *
  789. * This routine searches directory, that is pointed by <pFd> for name, that
  790. * is pointed by <pNamePtr> structure and fills <pFd> in accordance with
  791. * directory entry data, if found.
  792. *
  793. * If name not found, <pFreeEnt> will be filled with pointer onto
  794. * some deleted entry in directory or onto free space in last directory
  795. * cluster. If both not found,
  796. * <pFreeEnt->sector> is set to 0.
  797. *
  798. * RETURNS: OK or ERROR if name not found or invalid name.
  799. */
  800. LOCAL STATUS dosDirOldLkupInDir
  801.     (
  802.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  803.     PATH_ARRAY_ID pNamePtr, /* name buffer */
  804.     DIRENT_PTR_ID pFreeEnt /* empty entry in directory */
  805.     )
  806.     {
  807.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  808.     STATUS status; /* search result status */
  809.     u_int nEntries; /* number of entries in directory */
  810.     u_short nameLen; /* name length on disk */
  811.     u_char name[  DOS_VX_LONG_NAME_LEN ]; /* name in disk format */
  812.     u_char dirent[ DOS_VX_DIRENT_LEN ]; /* directory entry buffer */
  813.     
  814.     nameLen = pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen;
  815.     DBG_MSG( 400, "pFd = %p", pFd ,0,0,0,0,0,0,0);
  816.     DBG_PRN_STR( 400, "name: %sn", pNamePtr->pName,
  817.      pNamePtr->nameLen, 0 );
  818.     
  819.     pFreeEnt->sector = 0;
  820.     pFreeEnt->offset = 0;
  821.     
  822.     /* prepare name */
  823.     
  824.     if( dosDirOldNameEncode( pDirDesc, pNamePtr, name ) == ERROR )
  825.      return ERROR;
  826.     
  827.     for( nEntries = 0, (status = dosDirOldDirentGet( pFd, dirent, RD_FIRST ));
  828.       (status != ERROR) && *dirent != LAST_DIRENT;
  829.       status = dosDirOldDirentGet( pFd, dirent, RD_NEXT ), nEntries++ )
  830.      {
  831.      /* pass volume label */
  832.     
  833.      if( *(dirent + pDirDesc->deDesc.atrribOff) & DOS_ATTR_VOL_LABEL )
  834.          continue;
  835.     
  836.      /* pass deleted entry, that later can be used to store new entry */
  837.     
  838.      if( *dirent == DOS_DEL_MARK )
  839.          {
  840.          pFreeEnt->sector = pFd->curSec;
  841.          pFreeEnt->offset = pFd->pos;
  842.          continue;
  843.          }
  844.     
  845.      /* compare names */
  846.     
  847.      if( bcmp( (char *)name, (char *)dirent, nameLen ) == 0 )
  848.          {
  849.          break;
  850.          }
  851.      }
  852.     
  853.     /* check result */
  854.     
  855.     if( status == ERROR ||
  856.         ( IS_ROOT( pFd ) && nEntries > pDirDesc->rootMaxEntries ) )
  857.         {
  858.      return ERROR;
  859.      }
  860.     
  861.     if(  *dirent == LAST_DIRENT )
  862.      {
  863.         /* will create new entry on this place, if required */
  864.     
  865.      if( pFreeEnt->sector == 0 )
  866.          {
  867.          pFreeEnt->sector = pFd->curSec;
  868.          pFreeEnt->offset = pFd->pos;
  869.          }
  870.      return ERROR;
  871.      }
  872.     
  873.     /* file found; fill file descriptor */
  874.     
  875.     dosDirOldFillFd( pFd, dirent );
  876.     return OK; 
  877.     } /* dosDirOldLkupInDir() */
  878.     
  879. /***************************************************************************
  880. *
  881. * dosDirOldClustAdd - add and init cluster to directory.
  882. *
  883. * RETURNS: OK or ERROR if no more cluster could be allocated.
  884. */
  885. LOCAL STATUS dosDirOldClustAdd
  886.     (
  887.     DOS_FILE_DESC_ID pFd
  888.     )
  889.     {
  890.     block_t sec; /* work count */
  891.     
  892.     /* allocate cluster */
  893.     
  894.     if( pFd->pVolDesc->pFatDesc->getNext( pFd, FAT_ALLOC_ONE ) == ERROR )
  895.      return ERROR;
  896.     
  897.     assert( pFd->pFileHdl->startClust != 0 );
  898.     
  899.     /* fill cluster: */
  900.     for( sec = pFd->curSec; sec < pFd->curSec + pFd->nSec;
  901.          sec ++ )
  902.      {
  903.      if( cbioIoctl(pFd->pVolDesc->pCbio, CBIO_CACHE_NEWBLK,
  904. (void *)sec ) == ERROR )
  905.          {
  906.          return ERROR;
  907.          }
  908.      }
  909.         
  910.     return OK;
  911.     } /* dosDirOldClustAdd() */
  912. /***************************************************************************
  913. *
  914. * dosDirOldUpdateEntry - set new directory entry contents.
  915. *
  916. * This routine pulls file size, attributes and so on out of
  917. * file descriptor and stores in the file directory entry.
  918. * This function is also used for entry deletion. In this
  919. * case <flags> have to be set to DH_DELETE.
  920. *
  921. * Time value provided in <curTime> can be encoded into appropriate
  922. * fields within directory entry structure in accordance with
  923. * <flags> argument. <flags> can be or-ed of
  924. * DH_TIME_CREAT, DH_TIME_MODIFY or DH_TIME_ACCESS.
  925. * If <curTime> is 0, current system time is used.
  926. *
  927. * RETURNS: OK or ERROR if name is invalid or disk access error
  928. *  occurred.
  929. *
  930. */
  931. LOCAL STATUS dosDirOldUpdateEntry
  932.     (
  933.     DOS_FILE_DESC_ID pFd,
  934.     u_int flags,
  935.     time_t curTime /* time to encode */
  936.     )
  937.     {
  938.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  939.     u_char dirent[ DOS_VX_DIRENT_LEN ]; /* directory entry buffer */
  940.     
  941.     curTime = ( curTime == 0 )? time( NULL ) : curTime;
  942.     
  943.     /* root directory has not its own entry */
  944.     
  945.     if( IS_ROOT( pFd ) )
  946.      {
  947.      if( (flags & DH_TIME_MODIFY) != 0 )
  948.          pDirDesc->rootModifTime = curTime;
  949.      else
  950.          assert( (flags & DH_TIME_MODIFY) != 0 );
  951.     
  952.      return OK;
  953.      }
  954.     
  955.     /* get directory entry */
  956.     
  957.     if( dosDirOldDirentGet( pFd, dirent, FD_ENTRY ) == ERROR )
  958.      return ERROR;
  959.     
  960.     if( flags & DH_DELETE ) /* delete entry */
  961.      {
  962.      *dirent = DOS_DEL_MARK;
  963.      goto store;
  964.      }
  965.     
  966.     /* encode other fields */
  967.     
  968.     dirent[ pDirDesc->deDesc.atrribOff ] = pFd->pFileHdl->attrib;
  969.     START_CLUST_ENCODE( &pDirDesc->deDesc,
  970.              pFd->pFileHdl->startClust,  dirent );
  971.     VX_TO_DISK_32( pFd->pFileHdl->size,
  972.         dirent + pDirDesc->deDesc.sizeOff );
  973.         
  974.     if( pDirDesc->deDesc.extSizeOff != (u_char) NONE )
  975.      {
  976.      EXT_SIZE_ENCODE( &pDirDesc->deDesc, dirent, pFd->pFileHdl->size );
  977.      }
  978.     
  979.     dosDirOldTDEncode( pDirDesc, dirent, flags, curTime );
  980.     
  981. store:    
  982.     /* store directory entry */
  983.     return cbioBytesRW(
  984.      pFd->pVolDesc->pCbio, pFd->pFileHdl->dirHdl.sector,
  985.      OFFSET_IN_SEC( pFd->pVolDesc, pFd->pFileHdl->dirHdl.offset ),
  986. (addr_t)dirent, pDirDesc->deDesc.dirEntSize, CBIO_WRITE,
  987.      &pFd->pFileHdl->dirHdl.cookie );
  988.     } /* dosDirOldUpdateEntry */
  989. /***************************************************************************
  990. *
  991. * dosDirOldFileCreateInDir - create new entry in directory.
  992. *
  993. * This routine creates new directory entry in place of
  994. * deleted entry. If no deleted entry found in directory,
  995. * additional entry created at the directory tail.
  996. *
  997. * <pFreeEnt> contains pointer onto a deleted entry in
  998. * directory or onto free space in last directory
  999. * cluster, that have been already allocated. If <pFreeEnt->sector> is 0,
  1000. * suppose, that no unallocated entry exists in directory and
  1001. * <pFd> reached directory FAT chain end. In this case one more cluster is
  1002. * connected to directory chain and new entry is created in it.
  1003. *
  1004. * RETURNS: OK or ERROR if new entry can not be created.
  1005. *
  1006. * ERRNO:
  1007. * S_dosFsLib_DIR_READ_ONLY
  1008. * S_dosFsLib_INVALID_PARAMETER
  1009. * S_dosFsLib_ROOT_DIR_FULL
  1010. */
  1011. LOCAL STATUS dosDirOldFileCreateInDir
  1012.     (
  1013.     DOS_FILE_DESC_ID pFd, /* directory descriptor */
  1014.     PATH_ARRAY_ID pNamePtr,
  1015.     u_int creatOpt, /* creat flags */
  1016.     DIRENT_PTR_ID pFreeEnt /* empty entry in directory */
  1017.     )
  1018.     {
  1019.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1020.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  1021.     cookie_t cookie; /* temp buffer */
  1022.     u_char dirent[ DOS_VX_DIRENT_LEN ] = {0}; /* directory entry buffer */
  1023.     u_char dirEntSize;
  1024.     u_char parentIsRoot = 0; /* creation in root */
  1025.     
  1026.     dirEntSize = pDirDesc->deDesc.dirEntSize;
  1027.     
  1028.     /* check permissions */
  1029.     
  1030.     if( pFd->pFileHdl->attrib & DOS_ATTR_RDONLY )
  1031.      {
  1032.      errnoSet( S_dosFsLib_DIR_READ_ONLY );
  1033.      return ERROR;
  1034.      }
  1035.     
  1036.     /* only file and directory can be created */
  1037.     
  1038.     if( !( S_ISREG( creatOpt ) || S_ISDIR( creatOpt ) ) )
  1039.      {
  1040.      errnoSet( S_dosFsLib_INVALID_PARAMETER );
  1041.      return ERROR;
  1042.      }
  1043.     
  1044.     if( IS_ROOT( pFd ) )
  1045.      parentIsRoot = 1;
  1046.     
  1047.     
  1048.     /* check/encode file name */
  1049.     
  1050.     if( dosDirOldNameEncode( pDirDesc, pNamePtr, dirent ) == ERROR )
  1051.      return ERROR;
  1052.     
  1053.     /* use empty entry, that was found during path lkup */
  1054.     
  1055.     if( pFreeEnt->sector == 0 ) /* no free entries in directory */
  1056.      {
  1057.      if( IS_ROOT( pFd ) && pDirDesc->rootMaxEntries < (u_int)(-1) )
  1058.          {
  1059.          errnoSet( S_dosFsLib_ROOT_DIR_FULL );
  1060.          return ERROR;
  1061.          }
  1062.     
  1063.      /*  allocate one more cluster */
  1064.     
  1065.      if( dosDirOldClustAdd( pFd ) == ERROR )
  1066.          return ERROR;
  1067.     
  1068.      pFreeEnt->sector = pFd->curSec;
  1069.      pFreeEnt->offset = pFd->pos;
  1070.      }
  1071.     /* correct parent directory modification date/time */
  1072.     
  1073.     dosDirOldUpdateEntry( pFd, DH_TIME_MODIFY, time( NULL ) );
  1074.     
  1075.     /* --- create new entry --- */
  1076.     
  1077.     /* at the beginning create generic (file) entry */
  1078.     
  1079.     dosDirOldTDEncode(pDirDesc, 
  1080.                       dirent, 
  1081.                       (DH_TIME_CREAT | DH_TIME_MODIFY | DH_TIME_ACCESS), 
  1082.                       time( NULL ) );
  1083.     
  1084.     cookie = pDirHdl->cookie; /* backup cbio qsearch cookie */
  1085.     /*
  1086.      * point file descriptor on the new entree's position and
  1087.      * fill file descriptor for new file
  1088.      */
  1089.     pFd->curSec = pFreeEnt->sector;
  1090.     pFd->pos = pFreeEnt->offset;
  1091.     dosDirOldFillFd( pFd, dirent );
  1092.     
  1093.     DBG_MSG( 400, "create %s at: sector = %u offset = %un",
  1094.      ( S_ISREG( creatOpt )? "FILE" : "DIRECTORY" ),
  1095.      pFreeEnt->sector, pFreeEnt->offset ,0,0,0,0,0);
  1096.     DBG_PRN_STR( 400, "tname: %sn", dirent,
  1097.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  1098.     
  1099.     /* write f i l e entry to disk */
  1100.     
  1101.     if( S_ISREG( creatOpt ) )
  1102.      {
  1103.      return cbioBytesRW(
  1104.      pFd->pVolDesc->pCbio, pFreeEnt->sector,
  1105. OFFSET_IN_SEC( pFd->pVolDesc, pFreeEnt->offset ),
  1106.      (addr_t)dirent, dirEntSize, CBIO_WRITE, &cookie );
  1107.      }
  1108.     
  1109.     /* --- now we deal with directory --- */
  1110.     
  1111.     *(dirent + pDirDesc->deDesc.atrribOff) = DOS_ATTR_DIRECTORY;
  1112.     pFd->pFileHdl->attrib = DOS_ATTR_DIRECTORY;
  1113.     
  1114.     /*
  1115.      * for directory we have to create two entries: "." and ".."
  1116.      * start - allocate cluster and init it in structure.
  1117.      */
  1118.     if( dosDirOldClustAdd( pFd ) == ERROR )
  1119.      return ERROR;
  1120.     
  1121.     START_CLUST_ENCODE( &pDirDesc->deDesc,
  1122.              pFd->pFileHdl->startClust,  dirent );
  1123.     
  1124.     /*
  1125.      * second - init directory entry for ".";
  1126.      * it is similar to directory entry itself, except name
  1127.      */
  1128.     bfill( (char *)dirent,
  1129.         pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,
  1130.         SPACE );
  1131.     *dirent = DOT;
  1132.     if( cbioBytesRW(
  1133.      pFd->pVolDesc->pCbio, pFd->curSec, 0, (addr_t)dirent,
  1134.      dirEntSize, CBIO_WRITE, &pDirHdl->cookie ) == ERROR )
  1135.      {
  1136.      return ERROR;
  1137.      }
  1138.     
  1139.     pFd->pos += dirEntSize;
  1140.     if( OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ) == 0 )
  1141.      {
  1142.      pFd->nSec --;
  1143.      pFd->curSec ++;
  1144.      }
  1145.     
  1146.     /* if only one directory entry can be stored in cluster */
  1147.     
  1148.     if( pFd->nSec == 0 )
  1149.      {
  1150.      if( dosDirOldClustAdd( pFd ) == ERROR )
  1151.          return ERROR;
  1152.      }
  1153.     
  1154.     /* third - creat ".." entry, that points to the parent directory */
  1155.     
  1156.     if( parentIsRoot )
  1157.      {
  1158.      START_CLUST_ENCODE( &pDirDesc->deDesc, 0,  dirent );
  1159.      }
  1160.     else
  1161.      {
  1162.      START_CLUST_ENCODE( &pDirDesc->deDesc,
  1163.                  pDirHdl->parDirStartCluster,  dirent );
  1164.      }
  1165.     
  1166.     *(dirent + 1) = DOT;
  1167.     if( cbioBytesRW(
  1168.      pFd->pVolDesc->pCbio, pFd->curSec,
  1169. OFFSET_IN_SEC(  pFd->pVolDesc, pFd->pos ), (addr_t)dirent,
  1170.      dirEntSize, CBIO_WRITE, &pDirHdl->cookie ) == ERROR )
  1171.      {
  1172.      return ERROR;
  1173.      }
  1174.     
  1175.     /* now finish directory entry initialization */
  1176.     
  1177.     dosDirOldRewindDir( pFd ); /* rewind directory */
  1178.     
  1179.     dosDirOldNameEncode( pDirDesc, pNamePtr, dirent );
  1180.     START_CLUST_ENCODE( &pDirDesc->deDesc,
  1181.              pFd->pFileHdl->startClust,  dirent );
  1182.     if( cbioBytesRW(
  1183.      pFd->pVolDesc->pCbio, pDirHdl->sector,
  1184. OFFSET_IN_SEC( pFd->pVolDesc, pDirHdl->offset ), 
  1185.      (addr_t)dirent, dirEntSize, CBIO_WRITE,
  1186.      &pDirHdl->cookie ) == ERROR )
  1187.      {
  1188.      return ERROR;
  1189.      }
  1190.     return OK;
  1191.     } /* dosDirOldFileCreateInDir() */
  1192.     
  1193. /***************************************************************************
  1194. *
  1195. * dosDirOldNameDecode - decode name from directory entry format.
  1196. *
  1197. * RETURNS: OK or ERROR if no disk entries remain.
  1198. */
  1199. LOCAL void dosDirOldNameDecode
  1200.     (
  1201.     DOS_DIR_PDESCR_ID pDirDesc,
  1202.     u_char * pDirent, /* directory entry buffer */
  1203.     u_char * pDstName /* destination for directory name */
  1204.     )
  1205.     {
  1206.     u_char * pNameEnd = pDstName;
  1207.     u_char * pDstBuf; /* for debug output */
  1208.     u_char * pDot = NULL;
  1209.     u_char * pSrc = pDirent;
  1210.     int i, j, nameLen;
  1211.     
  1212.     pDstBuf = pDstName;
  1213.     
  1214.     for( pDot = NULL, nameLen = pDirDesc->deDesc.nameLen, i = 0; i  < 2;
  1215.       i++, nameLen = pDirDesc->deDesc.extLen )
  1216.      { 
  1217.      for( j = 0; j < nameLen; j++, pDstName++ )
  1218.          {
  1219.          *pDstName = *pSrc++;
  1220.          
  1221.          if( *pDstName != SPACE )
  1222.           pNameEnd = pDstName + 1;
  1223.          }
  1224.     
  1225.      if( pDirDesc->deDesc.extLen == 0 ) /* long name */
  1226.          break;
  1227.          
  1228.      /* extension */
  1229.     
  1230.      if( pDot == NULL ) /* separate name and extension */
  1231.          {
  1232.          pDot = pNameEnd;
  1233.          *pNameEnd++ = DOT;
  1234.          pDstName = pNameEnd;
  1235.          }
  1236.      else if( pDot + 1 == pNameEnd )
  1237.          {
  1238.          pNameEnd --; /* empty extension - remove dot */
  1239.          break;
  1240.          }
  1241.      }
  1242.     
  1243.     *pNameEnd = EOS; /* terminate the name */
  1244.     DBG_MSG( 600, "result: %sn", pDstBuf ,0,0,0,0,0,0,0);
  1245.     } /* dosDirOldNameDecode() */
  1246.     
  1247. /***************************************************************************
  1248. *
  1249. * dosDirOldReaddir - FIOREADDIR backend.
  1250. *
  1251. * Optionally this routine fills file descriptor for the encountered entry,
  1252. * if <pResFd> is not NULL.
  1253. *
  1254. * RETURNS: OK or ERROR if no disk entries remain.
  1255. */
  1256. LOCAL STATUS dosDirOldReaddir
  1257.     (
  1258.     DOS_FILE_DESC_ID pFd, /* descriptor of the directory being read */
  1259.     DIR * pDir, /* destination for directory name */
  1260.     DOS_FILE_DESC_ID pResFd /* file descriptor to be filled for the */
  1261.      /* being returned */
  1262.      /* (if pResFd is not NULL) */
  1263.     )
  1264.     {
  1265.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1266.     int readFlag;
  1267.     u_char dirent[ DOS_VX_DIRENT_LEN ]; /* directory entry buffer */
  1268.     
  1269.     assert( pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY );
  1270.     
  1271.     /* check status of directory */
  1272.     
  1273.     if( (int)pDir->dd_cookie == (-1) )
  1274.      return ERROR;
  1275.     
  1276.     /* position must be directory entry size aligned */
  1277.     if( pFd->pos % DOS_STDNAME_LEN != 0 )
  1278.      {
  1279.      errnoSet( S_dosFsLib_INVALID_PARAMETER );
  1280.      return ERROR;
  1281.      }
  1282.     readFlag = ( pDir->dd_cookie == 0 )? RD_FIRST : RD_NEXT;
  1283.     
  1284.     do
  1285.      {
  1286.      if( dosDirOldDirentGet( pFd, dirent, readFlag ) == ERROR )
  1287.             {
  1288.             pDir->dd_cookie = (-1);
  1289.          return ERROR;
  1290.          }
  1291.      readFlag = RD_NEXT;
  1292.      }
  1293.     while( *dirent == DOS_DEL_MARK ||
  1294.         (dirent[ pDirDesc->deDesc.atrribOff ] & DOS_ATTR_VOL_LABEL) != 0 );
  1295.     
  1296.     if( *dirent == LAST_DIRENT ) /* end of directory */
  1297.      {
  1298.      pDir->dd_cookie = (-1);
  1299.      return ERROR;
  1300.      }
  1301.     
  1302.     /* name decode */
  1303.     
  1304.     dosDirOldNameDecode( pDirDesc, dirent,(u_char *)pDir->dd_dirent.d_name );
  1305.     
  1306.     /* fill file descriptor for the entry */
  1307.     
  1308.     if( pResFd != NULL )
  1309.      {
  1310.      void * pFileHdl = pResFd->pFileHdl;
  1311.     
  1312.      /* prepare file descriptor contents */
  1313.     
  1314.      *pResFd = *pFd;
  1315.      pResFd->pFileHdl = pFileHdl;
  1316.      *pResFd->pFileHdl = *pFd->pFileHdl;
  1317.     
  1318.      dosDirOldFillFd( pResFd, dirent );
  1319.      }
  1320.     
  1321.     pDir->dd_cookie = POS_TO_DD_COOKIE( pFd->pos );
  1322.     return OK;
  1323.     } /* dosDirOldReaddir() */
  1324.     
  1325. /***************************************************************************
  1326. *
  1327. * dosDirOldPathLkup - lookup for file/dir in tree.
  1328. *
  1329. * This routine recursively searches directory tree for the <path> and
  1330. * fills file descriptor for the target entry if successful.
  1331. * Optionally new entry may be created in accordance with flags
  1332. * in argument <options>.
  1333. *
  1334. * DOS4.0 style names are always case insensitive in contrary to
  1335. * VxLong name, that always are compared case sensitively. So
  1336. * DOS_O_CASENS is ignored in  <options> argument.
  1337. *
  1338. * <options> : O_CREAT - creat file;
  1339. * O_CREAT | DOS_ATTR_DIRECTORY - creat directory.
  1340. * <somth> | DOS_O_CASENS - lkup for name in case
  1341.                          sensitive manner (ignored).
  1342. *
  1343. * RETURNS: OK or ERROR if file not found.
  1344. *
  1345. * ERRNO:
  1346. * S_dosFsLib_FILE_NOT_FOUND
  1347. */
  1348. LOCAL STATUS dosDirOldPathLkup
  1349.     (
  1350.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  1351.     void * path, /* path in tree */
  1352.     u_int options /* optional creat flags */
  1353.     )
  1354.     {
  1355.     PATH_ARRAY namePtrArray [DOS_MAX_DIR_LEVELS + 1];
  1356.     int numPathLevels;
  1357.     int errnoBuf; /* swap errno */
  1358.     DIRENT_PTR freeEnt; /* empty (deleted) entry in directory */
  1359.     u_char dirLevel; /* dynamic directory level counter */
  1360.     
  1361.     assert( path != NULL );
  1362.     
  1363.     /* disassemble path */
  1364.     
  1365.     numPathLevels = dosDirOldPathParse( pFd->pVolDesc, path, 
  1366.      namePtrArray ); 
  1367.     if( numPathLevels == ERROR )
  1368.      return ERROR;
  1369.     assert( numPathLevels <= DOS_MAX_DIR_LEVELS );
  1370.     
  1371.     /* start from root directory */
  1372.     
  1373.     dosDirOldFillFd( pFd, ROOT_DIRENT );
  1374.     
  1375.     errnoBuf = errnoGet();
  1376.     errnoSet( OK );
  1377.     for( dirLevel = 0; dirLevel < numPathLevels; dirLevel ++  )
  1378.      {
  1379.      /* only directory can be searched */
  1380.     
  1381.      if( ! (pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY) )
  1382.          break;
  1383.     
  1384.      if( dosDirOldLkupInDir( pFd, namePtrArray + dirLevel, &freeEnt )
  1385. == ERROR )
  1386.          {
  1387.          if( errnoGet() != OK ) /* subsequent error */
  1388.           return ERROR;
  1389.          
  1390.          break;
  1391.          }
  1392.      }
  1393.     
  1394.     if( errnoGet() == OK )
  1395.      errnoSet( errnoBuf );
  1396.     
  1397.     /* check result */
  1398.     
  1399.     if( dirLevel == numPathLevels )
  1400.      {
  1401.      return OK;
  1402.      }
  1403.     
  1404.     /* --- file not found --- */
  1405.     
  1406.     /* only last file in path can be created */
  1407.     
  1408.     if( dirLevel == numPathLevels - 1 &&  (options & O_CREAT) )
  1409.      {
  1410.      if( dosDirOldFileCreateInDir( pFd,
  1411.            namePtrArray + dirLevel,
  1412.                    options, &freeEnt ) == OK )
  1413.          return OK;
  1414.      }
  1415.     else
  1416.      {
  1417.      errnoSet( S_dosFsLib_FILE_NOT_FOUND );
  1418.      }
  1419.     
  1420.     /* error; release dir handle */
  1421.     
  1422.     return ERROR;
  1423.     } /* dosDirOldPathLkup() */
  1424. /***************************************************************************
  1425. *
  1426. * dosDirOldDateGet - fill in date-time fields in stat structure.
  1427. *
  1428. * RETURNS: OK or ERROR if disk access error.
  1429. *
  1430. */
  1431. LOCAL STATUS dosDirOldDateGet
  1432.     (
  1433.     DOS_FILE_DESC_ID pFd,
  1434.     struct stat * pStat
  1435.     )
  1436.     {
  1437.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1438.     u_char dirent[ DOS_VX_DIRENT_LEN ]; /* directory entry buffer */
  1439.     
  1440.     /* root directory has not its own entry */
  1441.     
  1442.     if( IS_ROOT( pFd ) )
  1443.      {
  1444.      pStat->st_mtime = pDirDesc->rootModifTime;
  1445.      return OK;
  1446.      }
  1447.     
  1448.     /* get directory entry */
  1449.     
  1450.     if( dosDirOldDirentGet( pFd, dirent, FD_ENTRY ) == ERROR )
  1451.      return ERROR;
  1452.     
  1453.     pStat->st_ctime = dosDirOldTDDecode( pDirDesc, dirent, DH_TIME_CREAT );
  1454.     pStat->st_mtime = dosDirOldTDDecode( pDirDesc, dirent, DH_TIME_MODIFY );
  1455.     pStat->st_atime = dosDirOldTDDecode( pDirDesc, dirent, 
  1456.       DH_TIME_ACCESS );
  1457.     return OK;
  1458.     } /* dosDirOldDateGet() */
  1459.     
  1460. /*******************************************************************************
  1461. *
  1462. * dosDirOldVolLabel - set/get dos volume label.
  1463. *
  1464. * This routine gets/changes the volume label entry in the root directory of a
  1465. * dosFs volume.
  1466. *
  1467. * Only one volume label entry may exist per volume and in root directory only.
  1468. * When request to change volume label arrives and there is already a volume
  1469. * label, the name is simply
  1470. * replaced.  If there is currently no label, a new volume label entry is
  1471. * created.
  1472. *
  1473. * RETURNS: OK, or ERROR if volume is not available.
  1474. *
  1475. * ERRNO:
  1476. * S_dosFsLib_INVALID_PARAMETER
  1477. * S_dosFsLib_NO_LABEL
  1478. * S_dosFsLib_ROOT_DIR_FULL
  1479. */
  1480. LOCAL STATUS dosDirOldVolLabel
  1481.     (
  1482.     DOS_VOLUME_DESC_ID pVolDesc,
  1483.     u_char * label,
  1484.     u_int request /* FIOLABELSET, FIOLABELGET */
  1485.     )
  1486.     {
  1487.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  1488.     DOS_FILE_DESC fd; /* work file descriptor */
  1489.     DOS_FILE_HDL fHdl; /* work file handle */
  1490.     u_int numEnt; /* number of passed entries */
  1491.     u_short labOffInBoot; /* volume label offset in boot sector */
  1492.     char * noName = "NO LABEL";
  1493.     STATUS status = ERROR; /* search status */
  1494.     u_char dirent[ DOS_VX_DIRENT_LEN ]; /* directory entry buffer */
  1495.     
  1496.     if( ! ( request == FIOLABELSET || request == FIOLABELGET ) )
  1497.      {
  1498.      errnoSet( S_dosFsLib_INVALID_PARAMETER );
  1499.      return ERROR;
  1500.      }
  1501.     
  1502.     labOffInBoot = ( pVolDesc->fatType == FAT32 )? DOS32_BOOT_VOL_LABEL:
  1503.         DOS_BOOT_VOL_LABEL;
  1504.     if( label == NULL )
  1505.      {
  1506.      if( request == FIOLABELSET )
  1507.          label = (u_char *)noName; /* use default name */
  1508.      else
  1509.          {
  1510.          errnoSet( S_dosFsLib_INVALID_PARAMETER );
  1511.          return ERROR;
  1512.          }
  1513.      }
  1514.     
  1515.     /* init file descriptor */
  1516.     
  1517.     fd.pVolDesc = pVolDesc;
  1518.     fd.pFileHdl = &fHdl;
  1519.     dosDirOldFillFd( &fd, ROOT_DIRENT );
  1520.     
  1521.     /* search for volume label */
  1522.     
  1523.     for( numEnt = 0, (status = dosDirOldDirentGet( &fd, dirent, RD_FIRST ));
  1524.       (status != ERROR) && *dirent != LAST_DIRENT;
  1525.       numEnt ++, status = dosDirOldDirentGet( &fd, dirent, RD_NEXT ) )
  1526.      {
  1527.      if( *(dirent + pDirDesc->deDesc.atrribOff) & DOS_ATTR_VOL_LABEL )
  1528.          break;
  1529.      }
  1530.     
  1531.     /* get label */
  1532.     
  1533.     if( request == FIOLABELGET )
  1534.      {
  1535.      if( status == ERROR || *dirent == LAST_DIRENT )
  1536.          {
  1537.          /*
  1538.           * no volume label found in root dir
  1539.           * extract label out of boot sector
  1540.           */
  1541.          bcopy( pVolDesc->bootVolLab, (char *)dirent, DOS_VOL_LABEL_LEN );
  1542.          }
  1543.      bcopy( (char *)dirent, (char *)label, DOS_VOL_LABEL_LEN );
  1544.      numEnt = DOS_VOL_LABEL_LEN;
  1545.      while( numEnt > 0 && label[ numEnt-1 ] == SPACE )
  1546.          label[ --numEnt ] = EOS;
  1547.     
  1548.      return OK;
  1549.      }
  1550.     
  1551.     /* change/create label */
  1552.     
  1553.     /* 
  1554.      * if no label found and no free entry in root,
  1555.      * add and init one more cluster.
  1556.      */
  1557.     if( status == ERROR ) /* label not found and no free entry */
  1558.      {
  1559.      if( numEnt >= pDirDesc->rootMaxEntries ) /* root dir is full */
  1560.          {
  1561.          errnoSet( S_dosFsLib_ROOT_DIR_FULL );
  1562.          return ERROR;
  1563.          }
  1564.      else if( dosDirOldClustAdd( &fd ) == ERROR )
  1565.          return ERROR;
  1566.      }
  1567.     
  1568.     /* encode name */
  1569.     
  1570.     bzero( (char *)dirent, sizeof( dirent ) );
  1571.     bfill( (char *)dirent, pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen, 
  1572.            SPACE );
  1573.     bcopy( (char *)label, (char *)dirent,
  1574.            min( DOS_VOL_LABEL_LEN, strlen( (char *)label ) ) );
  1575.     dirent[ pDirDesc->deDesc.atrribOff] = DOS_ATTR_VOL_LABEL;
  1576.     
  1577.     /* --- store label --- */
  1578.     
  1579.     /* store in root directory */
  1580.     
  1581.     status = cbioBytesRW(
  1582.      pVolDesc->pCbio, fd.curSec,
  1583. OFFSET_IN_SEC( pVolDesc, fd.pos ), (addr_t)dirent, 
  1584.      pDirDesc->deDesc.dirEntSize, CBIO_WRITE,
  1585.      &fHdl.dirHdl.cookie );
  1586.     
  1587. #ifdef CNANGE_BOOT
  1588.     /* XXX - avoid changing boot block to avoid false disk removal event */
  1589.     /* store in boot sector */
  1590.     bcopy( (char *)dirent, pVolDesc->bootVolLab, DOS_VOL_LABEL_LEN );
  1591.     status |= cbioBytesRW(
  1592.      pVolDesc->pCbio, DOS_BOOT_SEC_NUM,
  1593.      labOffInBoot, (addr_t)dirent, 
  1594.      DOS_VOL_LABEL_LEN, CBIO_WRITE, NULL );
  1595. #endif /* CNANGE_BOOT */
  1596.     
  1597.     return status;
  1598.     } /* dosDirOldVolLabel() */
  1599.     
  1600. /*******************************************************************************
  1601. *
  1602. * dosDirOldNameChk - validate file name.
  1603. *
  1604. * This routine validates incoming file name to be composed
  1605. * of valid characters.
  1606. *
  1607. * RETURNS: OK if name is OK or ERROR.
  1608. */
  1609. LOCAL STATUS dosDirOldNameChk
  1610.     (
  1611.     DOS_VOLUME_DESC_ID pVolDesc,
  1612.     u_char * name
  1613.     )
  1614.     {
  1615.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  1616.     PATH_ARRAY namePtr;
  1617.     u_char dirent[ DOS_VX_DIRENT_LEN ] = {0}; /* directory entry buffer */
  1618.     
  1619.     namePtr.pName = name;
  1620.     namePtr.nameLen = strlen((char *)name);
  1621.     
  1622.     return dosDirOldNameEncode( pDirDesc, &namePtr, dirent );
  1623.     } /* dosDirOldNameChk() */
  1624. /*******************************************************************************
  1625. *
  1626. * dosDirOldShow - display handler specific volume configuration data.
  1627. *
  1628. * RETURNS: N/A.
  1629. */
  1630. LOCAL void dosDirOldShow
  1631.     (
  1632.     DOS_VOLUME_DESC_ID pVolDesc
  1633.     )
  1634.     {
  1635.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  1636.     
  1637.     if( ! pVolDesc->mounted )
  1638.      return;
  1639.     
  1640.     printf(" - names style: %sn",
  1641.          ( (pDirDesc->nameStyle == STDDOS)?
  1642.           "8.3 STD DOS" : "VxLong" ) );
  1643.     
  1644.     if( pDirDesc->dirDesc.rootStartSec != 0 ) /* FAT12/FAT16 */
  1645.      {
  1646.      printf(" - root dir start sector: %un",
  1647.      pDirDesc->dirDesc.rootStartSec );
  1648.      printf(" - # of sectors per root: %un",
  1649.      pDirDesc->dirDesc.rootNSec );
  1650.      printf(" - max # of entries in root: %un",
  1651.      pDirDesc->rootMaxEntries );
  1652.      }
  1653.     else /* FAT32 */
  1654.      {
  1655.      printf(" - root dir start cluster: %un",
  1656.      pDirDesc->rootStartClust );
  1657.      }
  1658.     
  1659.     return;
  1660.     } /* dosDirOldShow() */
  1661. /*******************************************************************************
  1662. *
  1663. * dosDirOldVolUnmount - stub.
  1664. *
  1665. * RETURNS: N/A.
  1666. */
  1667. LOCAL void dosDirOldVolUnmount
  1668.     (
  1669.     DOS_VOLUME_DESC_ID pVolDesc
  1670.     )
  1671.     {
  1672.     return;
  1673.     } /* dosDirOldVolUnmount() */
  1674. /*******************************************************************************
  1675. *
  1676. * dosDirOldVolMount - init all data required to access the volume.
  1677. *
  1678. * This routine fills all local and shared structures fields, that
  1679. * depend on a directory structure format. All data is updated
  1680. * from boot sector of the volume is being mounted and from
  1681. * volume descriptor argument.
  1682. *
  1683. * RETURNS: OK or ERROR if the volume has inappropriate format.
  1684. *
  1685. * ERRNO:
  1686. * S_dosFsLib_UNSUPPORTED
  1687. * S_dosFsLib_UNKNOWN_VOLUME_FORMAT
  1688. */
  1689. LOCAL STATUS dosDirOldVolMount
  1690.     (
  1691.     DOS_VOLUME_DESC_ID pVolDesc,
  1692.     void * arg
  1693.     )
  1694.     {
  1695.     DOS_DIR_PDESCR_ID pDirDesc = NULL;
  1696.     DIRENT_DESCR_ID pDeDesc = NULL;
  1697.     cookie_t cookie = 0;
  1698.     char bootSec[DOS_BOOT_BUF_SIZE];
  1699.     
  1700.     assert( (pVolDesc != NULL) && pVolDesc->magic == DOS_FS_MAGIC );
  1701.     
  1702.     /* check for vxWorks long names */
  1703.     
  1704.     if( cbioBytesRW(
  1705.      pVolDesc->pCbio, pVolDesc->bootSecNum, 0,
  1706.      bootSec,
  1707.      min( sizeof( bootSec ), pVolDesc->bytesPerSec ),
  1708.      CBIO_READ, &cookie ) == ERROR )
  1709.      {
  1710.      return ERROR;
  1711.      }
  1712.     
  1713.     /* 
  1714.      * if previous volume had alternative directory structure,
  1715.      * unmount previous directory handler and
  1716.      * allocate directory handler descriptor
  1717.      */
  1718.     if( pVolDesc->pDirDesc == NULL ||
  1719.      pVolDesc->pDirDesc->volUnmount != dosDirOldVolUnmount )
  1720.      {
  1721.      /* unmount previous directory handler */
  1722.          
  1723.      if( pVolDesc->pDirDesc != NULL &&
  1724.          pVolDesc->pDirDesc->volUnmount != NULL )
  1725.          {
  1726.          pVolDesc->pDirDesc->volUnmount( pVolDesc );
  1727.          }
  1728.          
  1729.      /* allocate directory handler descriptor */
  1730.          
  1731.      pVolDesc->pDirDesc = 
  1732. KHEAP_REALLOC((char *) pVolDesc->pDirDesc,
  1733.                 sizeof( DOS_DIR_PDESCR ) );
  1734.      if( pVolDesc->pDirDesc == NULL )
  1735.          return ERROR;
  1736.      }
  1737.     
  1738.     pDirDesc = (void *)pVolDesc->pDirDesc;
  1739.     pDeDesc = &pDirDesc->deDesc;
  1740.     bzero( (char *)pDirDesc, sizeof( DOS_DIR_PDESCR ) );
  1741.     
  1742.     if( bcmp( bootSec + DOS_BOOT_SYS_ID, DOS_VX_LONG_NAMES_SYS_ID,
  1743.            strlen( DOS_VX_LONG_NAMES_SYS_ID ) ) == 0 )
  1744.      {
  1745.      /* use vxWorks long names */
  1746.     
  1747.      ERR_MSG( 10, "VxLong namesn", 0,0,0,0,0,0 );
  1748.     
  1749.      pDirDesc->nameStyle = VXLONG;
  1750.     
  1751.      pDeDesc->dirEntSize = DOS_VX_DIRENT_LEN;
  1752.      pDeDesc->nameLen = DOS_VX_NAME_LEN;
  1753.      pDeDesc->extLen = DOS_VX_EXT_LEN;
  1754.      pDeDesc->atrribOff = DOS_VX_ATTRIB_OFF;
  1755.      pDeDesc->creatTimeOff = DOS_VX_CREAT_TIME_OFF;
  1756.      pDeDesc->creatDateOff = DOS_VX_CREAT_DATE_OFF;
  1757.      pDeDesc->modifTimeOff = DOS_VX_MODIF_TIME_OFF;
  1758.      pDeDesc->modifDateOff = DOS_VX_MODIF_DATE_OFF;
  1759.      pDeDesc->accessTimeOff = DOS_VX_LAST_ACCESS_TIME_OFF;
  1760.      pDeDesc->accessDateOff = DOS_VX_LAST_ACCESS_DATE_OFF;
  1761.      pDeDesc->startClustOff = DOS_VX_START_CLUST_OFF;
  1762.      pDeDesc->extStartClustOff = DOS_VX_EXT_START_CLUST_OFF;
  1763.      pDeDesc->sizeOff = DOS_VX_FILE_SIZE_OFF;
  1764.      pDeDesc->extSizeOff = DOS_VX_EXT_FILE_SIZE_OFF;
  1765.      pDeDesc->extSizeLen = DOS_VX_EXT_FILE_SIZE_LEN;
  1766.      }
  1767.     else
  1768.      {
  1769.      /* use DOS traditional 8.3 name */
  1770.     
  1771.      ERR_MSG( 10, "DOS 8.3 namesn", 0,0,0,0,0,0 );
  1772.     
  1773.      pDirDesc->nameStyle = STDDOS;
  1774.     
  1775.      pDeDesc->dirEntSize = DOS_DIRENT_STD_LEN;
  1776.      pDeDesc->nameLen = DOS_STDNAME_LEN;
  1777.      pDeDesc->extLen = DOS_STDEXT_LEN;
  1778.      pDeDesc->atrribOff = DOS_ATTRIB_OFF;
  1779.      pDeDesc->creatTimeOff = DOS_MODIF_TIME_OFF;
  1780.      pDeDesc->creatDateOff = DOS_MODIF_DATE_OFF;
  1781.      pDeDesc->modifTimeOff = DOS_MODIF_TIME_OFF;
  1782.      pDeDesc->modifDateOff = DOS_MODIF_DATE_OFF;
  1783.      pDeDesc->accessTimeOff = NONE;
  1784.      pDeDesc->accessDateOff = NONE;
  1785.      pDeDesc->startClustOff = DOS_START_CLUST_OFF;
  1786.      pDeDesc->extStartClustOff = DOS_EXT_START_CLUST_OFF;
  1787.      pDeDesc->sizeOff = DOS_FILE_SIZE_OFF;
  1788.      pDeDesc->extSizeOff = DOS_EXT_FILE_SIZE_OFF;
  1789.      pDeDesc->extSizeLen = DOS_EXT_FILE_SIZE_LEN;
  1790.      }
  1791.     
  1792.     /* check correspondence of cluster and directory entry size */
  1793.     
  1794.     if( pDeDesc->dirEntSize >
  1795.         ( pVolDesc->secPerClust << pVolDesc->secSizeShift ) )
  1796.      {
  1797.      ERR_MSG( 0, "cluster size %d bytes is too small, min = %dn",
  1798.          pVolDesc->secPerClust << pVolDesc->secSizeShift,
  1799.          pDeDesc->dirEntSize, 0,0,0,0 );
  1800.      errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  1801.      return ERROR;
  1802.      }
  1803.     
  1804.     /*
  1805.      * init root directory parameters in accordance with
  1806.       * volume FAT version
  1807.      */
  1808.     if( pVolDesc->fatType == FAT32 ) /* FAT32 */
  1809.      {
  1810.      /*
  1811.       * init root directory descriptor.
  1812.       * Get root directory start cluster number
  1813.       */
  1814.      pDirDesc->rootStartClust =
  1815.      DISK_TO_VX_32( bootSec + DOS32_BOOT_ROOT_START_CLUST );
  1816.      if( pDirDesc->rootStartClust < 2 )
  1817.          {
  1818.          ERR_MSG( 1, "Malformed volume format (FAT32: rootStartClust "
  1819.      " = %u)n", pDirDesc->rootStartClust, 0,0,0,0,0 );
  1820.          errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  1821.          return ERROR;
  1822.          }
  1823.      pDirDesc->dirDesc.rootStartSec  = 0;
  1824.      pDirDesc->dirDesc.rootNSec  = 0;
  1825.      pDirDesc->rootMaxEntries = (u_int)(-1); /* not restricted */
  1826.      }
  1827.     else /* FAT12/FAT16 */
  1828.      {
  1829.      /*
  1830.       * init root directory descriptor.
  1831.       * Get number of entries-per-root directory
  1832.       */
  1833.      pDirDesc->rootMaxEntries =
  1834.      DISK_TO_VX_16( bootSec  + DOS_BOOT_MAX_ROOT_ENTS);
  1835.      if( pDirDesc->rootMaxEntries == 0 )
  1836.          {
  1837.          ERR_MSG( 1, "Malformed volume format (FAT12/16: "
  1838.      "rootMaxEntries = 0)n", 0,0,0,0,0,0 );
  1839.          errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  1840.          return ERROR;
  1841.          }
  1842.     
  1843.      pDirDesc->rootStartClust = 0; /* don't change this 0 ! */
  1844.      /* it is important while */
  1845.      /* creating subdir in root */
  1846.     
  1847.         /* SPR#34704 This operation must round up. */
  1848.         pDirDesc->dirDesc.rootNSec = 
  1849.                 (((pDirDesc->rootMaxEntries * pDeDesc->dirEntSize) + 
  1850.                   (pVolDesc->bytesPerSec - 1)) / pVolDesc->bytesPerSec);
  1851.      /* root directory resides ahead regular data area */
  1852.     
  1853.      pDirDesc->dirDesc.rootStartSec = pVolDesc->dataStartSec;
  1854.      pVolDesc->dataStartSec += pDirDesc->dirDesc.rootNSec;
  1855.      }
  1856.     
  1857.     /* init root directory last modification time */
  1858.     
  1859.     pDirDesc->rootModifTime = time( NULL );
  1860.     
  1861.     /* fill functions pointers */
  1862.     
  1863.     pDirDesc->dirDesc.pathLkup = dosDirOldPathLkup;
  1864.     pDirDesc->dirDesc.readDir = dosDirOldReaddir;
  1865.     pDirDesc->dirDesc.updateEntry = dosDirOldUpdateEntry;
  1866.     pDirDesc->dirDesc.dateGet = dosDirOldDateGet;
  1867.     pDirDesc->dirDesc.volLabel = dosDirOldVolLabel;
  1868.     pDirDesc->dirDesc.nameChk = dosDirOldNameChk;
  1869.     pDirDesc->dirDesc.volUnmount = dosDirOldVolUnmount;
  1870.     pDirDesc->dirDesc.show = dosDirOldShow;
  1871.     return OK;
  1872.     } /* dosDirOldVolMount() */
  1873. /*******************************************************************************
  1874. *
  1875. * dosDirOldLibInit - install <8.3> and VxLong names handler into dosFsLib
  1876. *
  1877. * RETURNS: OK or ERROR if handler installation failed.
  1878. *
  1879. * NOMANUAL
  1880. */
  1881. STATUS dosDirOldLibInit ( void )
  1882.     {
  1883.     DOS_HDLR_DESC hdlr;
  1884.     
  1885.     hdlr.id = DOS_DIROLD_HDLR_ID;
  1886.     hdlr.mountRtn = dosDirOldVolMount;
  1887.     hdlr.arg = NULL;
  1888.     
  1889.     return dosFsHdlrInstall( dosDirHdlrsList, &hdlr );
  1890.     } /* dosDirOldLibInit() */
  1891. /* End of File */