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

VxWorks

开发平台:

C/C++

  1. /* dosVDirLib.c - MS-DOS VFAT-style Long File names dir handler */ 
  2. /* Copyright 1999-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01p,10dec01,jkf  SPR#72039, various fixes from Mr. T. Johnson.
  7. 01o,09nov01,jkf  SPR#70968, chkdsk destroys boot sector
  8. 01n,21aug01,jkf  SPR#69031, common code for both AE & 5.x.
  9. 01m,06mar01,jkf  SPR#34704, rootNSec calculation must round up.
  10. 01n,01aug00,dat  SPR 31480, directory cluster corruption fix (neeraj)
  11. 01l,07mar00,jkf  Corrected pentium specific compiler warning "using %eax 
  12.                  instead of %ax due to l" (source of P6 reg stall?)
  13. 01k,29feb00,jkf  T3 changes, cleanup. 
  14. 01j,31aug99,jkf  changes for new CBIO API.
  15. 01i,31jul99,jkf  moved the fix for SPR#28276 from dosVDirFileCreateInDir() 
  16.                  to dosVDirNameEncodeShort because it was only mangling the 
  17.                  name in 01g and not creating an alias for it, no SPR.
  18. 01h,31jul99,jkf  default debug global to zero, no SPR.
  19. 01g,31jul99,jkf  Fixed dosVDirFileCreateInDir to mangle 8.3 names containing 
  20.                  char-space-char, per MS compatability.  MS Scandisk and 
  21.  Norton Disk Doctor stops reporting a false orphaned LFN 
  22.  which they repair by removing it.  SPR#28276
  23. 01f,31jul99,jkf  T2 merge, tidiness & spelling.
  24. 01e,07dec98,lrn  minor Show output cosmetics
  25. 01d,22nov98,vld  all offsets of directory entry changed to be
  26.  counted in absolute offset from parent directory
  27.  start
  28. 01c,28sep98,vld  gnu extensions dropped from DBG_MSG/ERR_MSG macros
  29. 01b,02jul98,lrn  review doc
  30. 01a,18jan98,vld  written,
  31. */
  32. /*
  33. DESCRIPTION
  34. This library is part of dosFsLib and is designed to handle the
  35. VFAT "long filename" standard disk directory structure.
  36. VFAT is the file name format initially introduced with OS/2 operating
  37. system, and subsequently adopted by Microsoft in Windows 95 and NT
  38. operating systems for FAT-based file systems.
  39. With this format, every file has a Long Name which occupies a number of
  40. directory entries, and a short file name which adheres to the vintage
  41. MS-DOS file naming conventions. The later are called aliases.
  42. This handler performs its lookup only by file long names, not by aliases,
  43. in other words, the aliases, are provided only for data interchange with
  44. Microsoft implementations of FAT, and are ignored otherwise.
  45. Aliases, that are created for long file names are Windows95/98 compatible,
  46. that means, they are readable from Windows applications, but they are
  47. not produced from the corresponding long file name.
  48. In this implementation the alias is made of numbers to ensure that
  49. every alias is unique in its directory without having to scan the entire
  50. directory.  This ensure determinism.
  51. Therefore if a volume written with this handler is every transported to
  52. an old MS-DOS system or comparable implementation of dosFs,
  53. which only accepts vintage 8.3 file names, the names of files will not
  54. be readily associated with their original names, and thus practically
  55. unusable. The goal was to ensure determinism and file safety.
  56. Uppercase 8.3 filename that follow strict 8.3 rules such as 
  57. "UPPERFIL.TXT" will not be stored in a long filename.  
  58. Lowercase 8.3 Filenames such as "Upperfil.txt" will have a readable
  59. alias created of "UPPERFIL.TXT"   
  60. Lowercase 8.3 Filenames such as "File   " will have an alias 
  61. created of "FILE    ".
  62. Filenames with a sequence of char, space, char strings. 
  63. Such as "3D Pipes.scr" will also have a munged alias created 
  64. akin to "3~999997".
  65. The routine dosVDirInit() routine has to be called once to install 
  66. this handler into dosFsLib. Once that has been done this directory
  67. handler will be automatically mounted for each new DOS volume being 
  68. mounted and containing VFAT or early DOS directory structure.
  69. SEE ALSO:
  70. dosFsLib.
  71. */
  72. /* includes */
  73. #include "vxWorks.h"
  74. #include "private/dosFsVerP.h"
  75. #include "stat.h"
  76. #include "dirent.h"
  77. #include "time.h"
  78. #include "stdio.h"
  79. #include "ctype.h"
  80. #include "taskLib.h"
  81. #include "stdlib.h"
  82. #include "string.h"
  83. #include "semLib.h"
  84. #include "logLib.h"
  85. #include "errnoLib.h"
  86. #include "time.h"
  87. #include "utime.h"
  88. #include "memLib.h"
  89. #include "private/dosFsLibP.h"
  90. #include "private/dosDirLibP.h"
  91. /* defines */
  92. #undef DBG_PRN_STR
  93. #undef DBG_MSG
  94. #undef ERR_MSG
  95. #undef NDEBUG
  96.  
  97. #ifdef DEBUG
  98. #   undef LOCAL
  99. #   define LOCAL
  100. #   undef ERR_SET_SELF
  101. #   define ERR_SET_SELF
  102. #   define DBG_PRN_STR( lvl, fmt, pStr, len, arg )
  103. { if( (lvl) <= dosVDirDebug ) {
  104.     char cBuf = ((char *)(pStr))[len];
  105.     (pStr)[len] = EOS; 
  106.     printErr( (fmt),(pStr),(arg) );
  107.     ((char *)(pStr))[len] = cBuf;  } }
  108. #   define DBG_MSG( lvl, fmt, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 )
  109. { if( (lvl) <= dosVDirDebug )
  110.     printErr( "%s : %d : " fmt,
  111.                __FILE__, __LINE__, arg1,arg2,
  112.        arg3,arg4,arg5,arg6,arg7,arg8 ); }
  113. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  114.         { logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  115.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  116. #else /* NO DEBUG */
  117. #   define NDEBUG
  118. #   define DBG_PRN_STR( lvl, fmt, pStr, len, arg ) {}
  119. #   define DBG_MSG(lvl,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)  {}
  120. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  121. { if( (lvl) <= dosVDirDebug ) 
  122.             logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  123.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  124. #endif /* DEBUG */
  125.  
  126. #include "assert.h"
  127. #ifdef ERR_SET_SELF
  128. #   define errnoSet( err ) errnoSetOut( __FILE__, __LINE__, #err, (err) )
  129. #endif /* ERR_SET_SELF */
  130. #define VFAT_MAX_ENT ( (DOS_VFAT_NAME_LEN + CHAR_PER_VENTRY - 1) 
  131.   / CHAR_PER_VENTRY )
  132. /* max directory entries required */
  133. /* to store VFAT long name */
  134. #define MAX_VFAT_FULL_DIRENT ( DOS_DIRENT_STD_LEN * (VFAT_MAX_ENT + 1) )
  135. /* max space of long name + alias */
  136. /* may occupy on disk */
  137. #define CHAR_PER_VENTRY 13 /* num of characters of long name */
  138. /* encoded within directory entry */
  139. #define VFAT_ENTNUM_MASK 0x1f /* mask of "entry number within */
  140. /* long name" field */ 
  141. #define DOS_VFAT_CHKSUM_OFF 13
  142. #define DOS_ATTR_VFAT 0x0f /* value of attribute field for */
  143. /* directory entries, that encodes */
  144. /* VFAT long name */
  145. /* special characters */
  146. #define DOS_VLAST_ENTRY 0x40 /* last entry in long name representation */
  147. /* special function argument value */
  148. #define DH_ALLOC (1<<7) /* add cluster to directory chain */
  149. #define PUT_CURRENT (1<<0) /* store currently pointed directory entry */
  150. #define PUT_NEXT (1<<1) /* store next directory entry */
  151. /* macros */
  152. /* typedefs */
  153. typedef enum {RD_FIRST, RD_CURRENT, RD_NEXT, FD_ENTRY} RDE_OPTION;
  154. /* function argument */
  155. typedef enum {STRICT_SHORT, NOT_STRICT_SHORT, NO_SHORT} SHORT_ENCODE;
  156. /* function argument */
  157. typedef struct DOS_VDIR_DESCR /* directory handler's part of */
  158. /* volume descriptor */
  159.     {
  160.     DOS_DIR_PDESCR genDirDesc; /* generic descriptor */
  161.     } DOS_VDIR_DESCR;
  162. typedef DOS_VDIR_DESCR * DOS_VDIR_DESCR_ID;
  163. /* globals */
  164. unsigned int dosVDirDebug = 0;
  165. /* locals */
  166. /* positions of filename characters encoding within VFAT directory entry */
  167. LOCAL const u_char chOffsets[] = { 1, 3, 5, 7, 9,
  168. 14, 16, 18, 20, 22, 24, 
  169. 28, 30 };
  170. /* valid filename characters table ('|' is invalid character) */
  171. static const u_char shortNamesChar[] =
  172.                                         /* 0123456789abcdef */
  173.                                           "||||||||||||||||"
  174.                                           "||||||||||||||||"
  175.                                           " !|#$%&'()|||-||"
  176.                                           "0123456789||||||"
  177.                                           "@ABCDEFGHIJKLMNO"
  178.                                           "PQRSTUVWXYZ|||^_"
  179.                                           "`ABCDEFGHIJKLMNO"
  180.                                           "PQRSTUVWXYZ{|}~|" ,
  181.                         longNamesChar[] =
  182.                                         /* 0123456789abcdef */
  183.                                           "||||||||||||||||"
  184.                                           "||||||||||||||||"
  185.                                           " !|#$%&'()|+,-.|"
  186.                                           "0123456789|;|=||"
  187.                                           "@ABCDEFGHIJKLMNO"
  188.                                           "PQRSTUVWXYZ[|]^_"
  189.                                           "`abcdefghijklmno"
  190.                                           "pqrstuvwxyz{|}~|" ;
  191. #ifdef ERR_SET_SELF
  192. /*******************************************************************************
  193. * errnoSetOut - put error message
  194. *
  195. * This routine is called instead errnoSet during debugging.
  196. */
  197. static VOID errnoSetOut(char * file, int line, const char * str, int errCode )
  198.     {
  199.     if( errCode != OK  && strcmp( str, "errnoBuf" ) != 0 )
  200.         printf( " %s : line %d : %s = %p, task %pn",
  201.                 file, line, str, (void *)errCode,
  202.                 (void *)taskIdSelf() );
  203.     errno = errCode;
  204.     }
  205. #endif  /* ERR_SET_SELF */
  206. /***************************************************************************
  207. *
  208. * dosVDirFillFd - fill file descriptor for directory entry.
  209. *
  210. * RETURNS: N/A.
  211. */
  212. LOCAL void dosVDirFillFd
  213.     (
  214.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  215.     u_char * pDirEnt, /* directory entry from disk */
  216.     DIRENT_PTR_ID pLnPtr /* start of long name */
  217.     )
  218.     {
  219.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  220.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  221.     DIRENT_DESCR_ID pDeDesc;
  222.     
  223.     pDeDesc = &pDirDesc->deDesc;
  224.     
  225.     if( pDirEnt == NULL ) /* root directory */
  226.      {
  227.      DBG_MSG( 600, "root directoryn", 0,0,0,0,0,0,0,0 );
  228.      ROOT_SET( pFd ); /* via <parDirStartCluster> field */
  229.      pFd->curSec = pDirDesc->dirDesc.rootStartSec;
  230.      pFd->nSec = pDirDesc->dirDesc.rootNSec;
  231.      pFd->pos = 0;
  232.      pFd->pFileHdl->attrib = DOS_ATTR_DIRECTORY;
  233.      pFd->pFileHdl->startClust = pDirDesc->rootStartClust;
  234.     
  235.      pDirHdl->sector = NONE;
  236.      pDirHdl->offset = NONE;
  237.      pDirHdl->lnSector = 0;
  238.      pDirHdl->lnOffset = 0;
  239.     
  240.      pFd->cbioCookie = (cookie_t) NULL;
  241.      pDirHdl->cookie = (cookie_t) NULL;
  242.     
  243.      goto rewind;
  244.      }
  245.     
  246.     /* at the beginning fill directory handle using file descriptor */
  247.     
  248.     pDirHdl->parDirStartCluster = pFd->pFileHdl->startClust;
  249.     pDirHdl->sector = pFd->curSec;
  250.     pDirHdl->offset = pFd->pos;
  251.     pDirHdl->cookie = pFd->cbioCookie;
  252.     
  253.     /* long name ptr */
  254.     
  255.     if( pLnPtr != NULL )
  256.      {
  257.      pDirHdl->lnSector = pLnPtr->sector;
  258.      pDirHdl->lnOffset = pLnPtr->offset;
  259.      }
  260.     else /* just a short name */
  261.      {
  262.      pDirHdl->lnSector = 0;
  263.      pDirHdl->lnOffset = 0;
  264.      }
  265.     pFd->cbioCookie = (cookie_t) NULL;
  266.     /* disassemble directory entry */
  267.     
  268.     pFd->pos = 0;    
  269.     pFd->curSec = 0;
  270.     pFd->nSec = 0;
  271.     
  272.     pFd->pFileHdl->attrib = *(pDirEnt + pDeDesc->atrribOff);
  273.     pFd->pFileHdl->startClust =
  274.      START_CLUST_DECODE( pFd->pVolDesc, pDeDesc, pDirEnt );
  275.     
  276.     pFd->pFileHdl->size = DISK_TO_VX_32(pDirEnt + pDeDesc->sizeOff);
  277.     if( pDeDesc->extSizeOff != (u_char) NONE )
  278.      {
  279.      pFd->pFileHdl->size += EXT_SIZE_DECODE( pDeDesc, pDirEnt );
  280.      }
  281.     DBG_MSG( 100, "StartCluster = %u = %p, size = %lun",
  282.      pFd->pFileHdl->startClust, (void *)pFd->pFileHdl->startClust,
  283.      (u_long)pFd->pFileHdl->size & 0xffffffff ,0,0,0,0,0);
  284.         
  285. rewind:
  286.     DBG_MSG( 600, "pFd = %p "
  287.        "dir hdl (sec-of-par = %u sector = %u offset = %u)n"
  288.                   "pFileHdl = %p "
  289.                   "(startClust = %u size = %lu attr = %p)n",
  290.                   pFd, pDirHdl->parDirStartCluster,
  291.                   pDirHdl->sector, pDirHdl->offset,
  292.                   pFd->pFileHdl, pFd->pFileHdl->startClust,
  293.                   pFd->pFileHdl->size,
  294.                   (void *)((int)pFd->pFileHdl->attrib) );
  295.     /*
  296.      * cause FAT to start from start cluster and
  297.      * get start contiguous block
  298.      */
  299.     bzero( (char *)&pFd->fatHdl, sizeof( pFd->fatHdl ) );
  300.     return;
  301.     } /* dosVDirFillFd() */
  302. /***************************************************************************
  303. *
  304. * dosVDirRewindDir - rewind directory pointed by <pFd>.
  305. *
  306. * This routine sets current sector in pFd to directory start sector
  307. * and current position  (offset in sector) to 0.
  308. * RETURNS: N/A.
  309. */
  310. LOCAL void dosVDirRewindDir
  311.     (
  312.     DOS_FILE_DESC_ID pFd /* dos file descriptor to fill */
  313.     )
  314.     {
  315.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  316.     
  317.     pFd->pos = 0;
  318.     pFd->nSec = 0;
  319.     pFd->curSec = 0;
  320.     
  321.     /* for FAT32 curSec = rootNSec = 0 */
  322.     
  323.     if( IS_ROOT( pFd ) && pDirDesc->dirDesc.rootNSec != 0 )
  324.      {
  325.      pFd->curSec = pDirDesc->dirDesc.rootStartSec;
  326.      pFd->nSec = pDirDesc->dirDesc.rootNSec;
  327.      return;
  328.      }
  329.     
  330.     /* regular file or FAT32 root */
  331.     /*
  332.      * cause FAT to start from start cluster and
  333.      * get start contiguous block
  334.      */
  335.     if( pFd->pVolDesc->pFatDesc->seek( pFd, FH_FILE_START, 0 ) == ERROR )
  336.      {
  337.      assert( FALSE );
  338.      }
  339.     } /* dosVDirRewindDir() */
  340.    
  341. /***************************************************************************
  342. *
  343. * dosVDirPathParse - parse a full pathname into an array of names.
  344. *
  345. * This routine is similar to pathParse(), but on the contrary it does not 
  346. * allocate additional buffers nor changes the path string.
  347. *
  348. * Parses a path in directory tree which has directory names
  349. * separated by '/' or ''s.  It fills the supplied array of
  350. * structures with pointers to directory and file names and 
  351. * correspondence name length.
  352. * All occurrences of '//', '.' and '..'
  353. * are right removed from path. All tail dots and spaces are broken from
  354. * each name, that is name like "abc. . ." is treated as just "abc".
  355. *
  356. * For instance, "/usr/vw/data/../dir/file" gets parsed into
  357. *
  358. * .CS
  359. *                          namePtrArray
  360. *                         |---------|
  361. *   ---------------------------o    |
  362. *   |                     |    3    |
  363. *   |                     |---------|
  364. *   |   -----------------------o    |
  365. *   |   |                 |    2    |
  366. *   |   |                 |---------|
  367. *   |   |          ------------o    |
  368. *   |   |          |      |    3    |
  369. *   |   |          |      |---------|
  370. *   |   |          |   --------o    |
  371. *   |   |          |   |  |    4    |
  372. *   |   |          |   |  |---------|
  373. *   v   v          v   v  |   NULL  |
  374. *   |   |          |   |  |    0    |
  375. *   |   |          |   |  |---------|
  376. *   v   v          v   v 
  377. *  |------------------------|
  378. *  |usr/vw/data/../dir/file |
  379. *  |------------/----------|
  380. *          ignored
  381. * .CE
  382. *
  383. * RETURNS: number of levels in path.
  384. *
  385. * ERRNO:
  386. * S_dosFsLib_ILLEGAL_PATH
  387. * S_dosFsLib_ILLEGAL_NAME
  388. */
  389. LOCAL int dosVDirPathParse
  390.     (
  391.     DOS_VOLUME_DESC_ID pVolDesc,
  392.     u_char * path,
  393.     PATH_ARRAY_ID pnamePtrArray
  394.     )
  395.     {
  396.     FAST u_int numPathLevels;
  397.     FAST u_char * pName;
  398.     FAST u_char * pRegChar; /* last not DOT and not SPACE char */
  399.     
  400.     pnamePtrArray[0].pName = NULL;
  401.     /* go throw path string from left to right */
  402.     
  403.     pName = path;
  404.     numPathLevels = 0;
  405.     while( *pName != EOS ) /* there is 'break' in loop also */
  406.      {
  407.      /* pass slashes */
  408.     
  409.      if( *pName == SLASH || *pName == BACK_SLASH )
  410.          {
  411.          pName++;
  412.          continue;
  413.          }
  414.     
  415.      /* process special names ( "." ".." ) */
  416.     
  417.      if( *pName == DOT )
  418.         {
  419.         /* "/./" - ignore "current directory" */
  420.         if( *(pName + 1) == EOS || *(pName + 1) == SLASH ||
  421.             *(pName + 1) == BACK_SLASH )
  422.          {
  423.          pName ++;
  424.          continue;
  425.          }
  426.         
  427.         /* "/../" - goto one level back */
  428.         
  429.         if( (*(pName + 1) == DOT) &&
  430.             ( *(pName + 2) == EOS || *(pName + 2) == SLASH ||
  431.               *(pName + 2) == BACK_SLASH ) )
  432.          {
  433.          if( numPathLevels > 0 )
  434.              numPathLevels --;
  435.          pName +=2;
  436.          continue;
  437.          }
  438.         } /* if( *pName == DOT ) */
  439.         
  440.      /* regular name: insert it into array */
  441.     
  442.      if( numPathLevels >= DOS_MAX_DIR_LEVELS )
  443.          break; /* max level overloaded */
  444.     
  445.      pnamePtrArray[numPathLevels].pName = pName;
  446.      pnamePtrArray[numPathLevels + 1].pName = NULL;
  447.      pRegChar = NULL;
  448.      while( *pName != SLASH && *pName != BACK_SLASH &&
  449.             *pName != EOS )
  450.          {
  451.          if( *pName != DOT || *pName == SPACE )
  452.           pRegChar = pName;
  453.          pName++;
  454.          }
  455.     
  456.      /* name can not contain only dots */
  457.     
  458.      if( pRegChar == NULL )
  459.          {
  460.          errnoSet( S_dosFsLib_ILLEGAL_NAME );
  461.          return ERROR;
  462.          }
  463.     
  464.      pnamePtrArray[numPathLevels].nameLen =
  465.      pRegChar + 1 - pnamePtrArray[numPathLevels].pName;
  466.     
  467.      numPathLevels++;
  468.      } /* while( *pName != EOS ) */
  469.     
  470.     /* check result */
  471.     
  472.     if( *pName != EOS ) /* path termination has not been reached */
  473.      {
  474.      errnoSet( S_dosFsLib_ILLEGAL_PATH );
  475.      return ERROR;
  476.      }
  477. #ifdef DEBUG
  478.     DBG_MSG( 600, "path: %s, result: n", path ,0,0,0,0,0,0,0);
  479.     pName = (void *)pnamePtrArray;
  480.     for( ; pnamePtrArray->pName != NULL; pnamePtrArray++ )
  481.      {
  482.      int i = pnamePtrArray - (PATH_ARRAY_ID)pName + 1;
  483.      DBG_PRN_STR( 600, "%s : %d", pnamePtrArray->pName,
  484.      pnamePtrArray->nameLen, i );
  485.      }
  486.     DBG_PRN_STR(600, "bb n", "", 0, 0);
  487. #endif /* DEBUG */
  488.     return numPathLevels;
  489.     } /* dosVDirPathParse() */
  490.     
  491. /***************************************************************************
  492. *
  493. * dosVDirChkSum - count checksum for long name alias.
  494. *
  495. * RETURNS: N/A.
  496. */
  497. LOCAL u_char dosVDirChkSum
  498.     (
  499.     u_char * alias
  500.     )
  501.     {
  502.     u_int i;
  503.     u_char chkSum;
  504.     
  505.     for( chkSum = 0, i = 0; i < DOS_STDNAME_LEN + DOS_STDEXT_LEN; i++ )
  506.      {
  507.      chkSum = ( ( ( chkSum &    1 ) << 7 ) |
  508.              ( ( chkSum & 0xfe ) >> 1 )
  509.            ) +  alias[ i ];
  510.      }
  511.     return chkSum;
  512.     } /* dosVDirChkSum() */
  513.     
  514. /***************************************************************************
  515. *
  516. * dosVDirTDDecode - decode time-date field from disk format.
  517. *
  518. * This routine decodes required date-time field in the directory
  519. * entry into time_t format.
  520. * Parameter which defines which time field to decode. It
  521. * can be one of:
  522. * DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.
  523. *
  524. * RETURNS: time in time_t format.
  525. *
  526. */
  527. LOCAL time_t dosVDirTDDecode
  528.     (
  529.     DOS_DIR_PDESCR_ID pDirDesc,
  530.     u_char * pDirent, /* directory entry buffer */
  531.     u_int which /* what field to decode: one of */
  532.      /* DH_TIME_CREAT, DH_TIME_MODIFY or DH_TIME_ACCESS */
  533.     )
  534.     {
  535.     struct tm tm = {0}; /* broken down time buffer */
  536.     UINT16 dtBuf; /* 16-bit buffer */
  537.     u_char tOff = 0, dOff = 0; /* field offset */
  538.     
  539.     switch( which )
  540.         {
  541.         case DH_TIME_CREAT:
  542.             tOff = pDirDesc->deDesc.creatTimeOff;
  543.             dOff = pDirDesc->deDesc.creatDateOff;
  544.             break;
  545.         case DH_TIME_MODIFY:
  546.             tOff = pDirDesc->deDesc.modifTimeOff;
  547.             dOff = pDirDesc->deDesc.modifDateOff;
  548.             break;
  549.         case DH_TIME_ACCESS:
  550.             tOff = pDirDesc->deDesc.accessTimeOff;
  551.             dOff = pDirDesc->deDesc.accessDateOff;
  552.             break;
  553.         default:
  554.             assert( FALSE );
  555.         }
  556.     
  557.     if( dOff != (u_char)NONE )
  558.      {
  559.      dtBuf = DISK_TO_VX_16( pDirent + dOff );
  560.     
  561.      tm.tm_mday    = dtBuf & 0x1f;
  562.     
  563. /* ANSI months are zero-based */
  564.      tm.tm_mon     = ((dtBuf >> 5) & 0x0f) - 1;
  565.     
  566. /* DOS starts at 1980, ANSI starts at 1900 */
  567.      tm.tm_year    = ((dtBuf >> 9) & 0x7f) + 1980 - 1900;
  568.      }
  569.     if( tOff != (u_char)NONE )
  570.      {
  571.      dtBuf = DISK_TO_VX_16( pDirent + tOff );
  572.     
  573.      tm.tm_sec     = (dtBuf & 0x1f) << 1;
  574.      tm.tm_min     = (dtBuf >> 5) & 0x3f;
  575.      tm.tm_hour    = (dtBuf >> 11) & 0x1f;
  576.      }
  577.     
  578.     /* encode into time_t format */
  579.     
  580.     return mktime( &tm );
  581.     } /* dosVDirTDDecode() */
  582. /***************************************************************************
  583. *
  584. * dosVDirTDEncode - encode time-date to disk format.
  585. *
  586. * This routine takes time value is provided in <curTime> argument
  587. * and encodes it into directory entry format.
  588. * Parameter <timesMask> defines which time fields to fill. Following
  589. * values can be bitwise or-ed:
  590. * DH_TIME_CREAT, DH_TIME_MODIFY, DH_TIME_ACCESS.
  591. *
  592. * RETURNS: N/A.
  593. */
  594. LOCAL void dosVDirTDEncode
  595.     (
  596.     DOS_DIR_PDESCR_ID pDirDesc,
  597.     u_char * pDirEnt,
  598.     u_int timesMask,
  599.     time_t curTime /* time to encode */
  600.     )
  601.     {
  602.     struct tm   tm; /* buffer for split time-date */
  603.     u_char timeB[2], dateB[2]; /* buffers for encoding */
  604.     
  605.     localtime_r( &curTime, &tm );
  606.     /* encode time */
  607.     
  608.     VX_TO_DISK_16( ( tm.tm_sec >> 1 ) |
  609.        ( tm.tm_min << 5 ) |
  610.        ( tm.tm_hour << 11 ), timeB );
  611.     
  612.     /*
  613.      * encode date;
  614.      * in <pDate> year is related to 1980, but in tm, - to 1900
  615.      */
  616.     tm.tm_year =  ( tm.tm_year < 80 )? 80 : tm.tm_year;
  617.     VX_TO_DISK_16( tm.tm_mday | ( ( tm.tm_mon + 1 ) << 5 ) |
  618.        ( ( tm.tm_year - 80 ) <<  9 ), dateB );
  619.     
  620.     /* put time-date into directory entry buffer */
  621.     
  622.     if( timesMask & DH_TIME_CREAT &&
  623.         pDirDesc->deDesc.creatDateOff != (u_char)NONE  )
  624.      {
  625.      pDirEnt[ pDirDesc->deDesc.creatTimeOff ] = timeB[0];
  626.      pDirEnt[ pDirDesc->deDesc.creatTimeOff + 1 ] = timeB[1];
  627.      pDirEnt[ pDirDesc->deDesc.creatDateOff ] = dateB[0];
  628.      pDirEnt[ pDirDesc->deDesc.creatDateOff + 1 ] = dateB[1];
  629.      }
  630.     if( timesMask & DH_TIME_MODIFY &&
  631.         pDirDesc->deDesc.modifDateOff != (u_char)NONE  )
  632.      {
  633.      pDirEnt[ pDirDesc->deDesc.modifTimeOff ] = timeB[0];
  634.      pDirEnt[ pDirDesc->deDesc.modifTimeOff + 1 ] = timeB[1];
  635.      pDirEnt[ pDirDesc->deDesc.modifDateOff ] = dateB[0];
  636.      pDirEnt[ pDirDesc->deDesc.modifDateOff + 1 ] = dateB[1];
  637.      }
  638.     if( timesMask & DH_TIME_ACCESS &&
  639.         pDirDesc->deDesc.accessDateOff != (u_char)NONE  )
  640.      {
  641.      if( pDirDesc->deDesc.accessTimeOff != (u_char)NONE )
  642.          {
  643.          pDirEnt[ pDirDesc->deDesc.accessTimeOff ] = timeB[0];
  644.          pDirEnt[ pDirDesc->deDesc.accessTimeOff + 1 ] = timeB[1];
  645.          }
  646.      pDirEnt[ pDirDesc->deDesc.accessDateOff ] = dateB[0];
  647.      pDirEnt[ pDirDesc->deDesc.accessDateOff + 1 ] = dateB[1];
  648.      }
  649.     } /* dosVDirTDEncode() */
  650.     
  651. /***************************************************************************
  652. *
  653. * dosVDirCharEncode - validate and encode character.
  654. *
  655. * RETURNS: OK or ERROR.
  656. */
  657. LOCAL STATUS dosVDirCharEncode
  658.     (
  659.     u_char * pSrc,
  660.     u_char * pDst,
  661.     const u_char * codeTbl /* characters table */
  662.      /* ( shortNamesChar or longNamesChar ) */
  663.     )
  664.     {
  665.     /* allow all high characters */
  666.     
  667.     if( *pSrc & 0x80 )
  668.      {
  669.      *pDst = *pSrc;
  670.      }
  671.     else if( codeTbl[ *pSrc ] != INVALID_CHAR )
  672.      {
  673.      *pDst = codeTbl[ *pSrc ];
  674.      }
  675.     else
  676.      {
  677.      return ERROR;
  678.      }
  679.     
  680.     return OK;
  681.     } /* dosVDirCharEncode() */
  682.     
  683. /***************************************************************************
  684. *
  685. * dosVDirNameEncodeShort - encode name in short style.
  686. *
  687. * This routine encodes incoming file name into 8+3 uppercase format.
  688. * During encoding the
  689. * name is verified to be composed of valid characters.
  690. *
  691. * RETURNS: STRICT_SHORT, if name is valid short and uppercase,
  692. *  NOT_STRICT_SHORT, if name is short, but not uppercase,
  693. *  NO_SHORT, if name can not be encoded as short.
  694. */
  695. LOCAL SHORT_ENCODE dosVDirNameEncodeShort
  696.     ( 
  697.     DOS_DIR_PDESCR_ID pDirDesc,
  698.     PATH_ARRAY_ID pNamePtr, /* name buffer */
  699.     u_char * pDstName /* buffer for name in disk format */
  700.     )
  701.     {
  702.     u_char * pSrc; /* source name dynamic ptr */
  703.     u_char * pDstBuf; /* for debug output only */
  704.     int i,j; /* work */
  705.     SHORT_ENCODE retVal = STRICT_SHORT;
  706.     /* extension length (0 - no extension) */
  707.     u_char extLen = pDirDesc->deDesc.extLen;
  708.     
  709.     pDstBuf = pDstName;
  710.     
  711.     bfill( (char *)pDstName,
  712.         pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen, SPACE );
  713.     
  714.     /* encode name and check it by the way */
  715.     
  716.     DBG_MSG( 600, "",0,0,0,0,0,0,0,0 );
  717.     DBG_PRN_STR( 600, "%sn", pNamePtr->pName, pNamePtr->nameLen, 0 );
  718.     for( i = 0, pSrc = pNamePtr->pName;
  719.       i < min( pDirDesc->deDesc.nameLen,
  720.          pNamePtr->nameLen );
  721.       i++, pDstName++, pSrc++  )
  722.      {
  723.      /* check for extension */
  724.     
  725.      if( extLen != 0 && *pSrc == DOT ) 
  726.          break;
  727.     
  728.      if( dosVDirCharEncode( pSrc, pDstName, shortNamesChar ) == ERROR )
  729.          goto error;
  730.     
  731.      if( *pDstName != *pSrc )
  732.          retVal = NOT_STRICT_SHORT;
  733.      }
  734.     /* check state */
  735.     
  736.     if( i == pNamePtr->nameLen )
  737.      goto retOK; /* name finished */
  738.     
  739.     if( *pSrc != DOT ) /* name too long */
  740.         goto error;
  741.     
  742.     pSrc++; /* pass DOT */
  743.     pDstName += pDirDesc->deDesc.nameLen - i;
  744.     i++;
  745.     
  746.     /* encode extension */
  747.     
  748.     for( j = 0; j < extLen && i < pNamePtr->nameLen;
  749.       i++, j++, pDstName++, pSrc++  )
  750.      {
  751.      if( dosVDirCharEncode( pSrc, pDstName, shortNamesChar ) == ERROR )
  752.          goto error;
  753.      if( *pDstName != *pSrc )
  754.          retVal = NOT_STRICT_SHORT;
  755.      }
  756.     
  757.     /* check status */
  758.     
  759.     if( i < pNamePtr->nameLen ) /* extension too long */
  760.      goto error;
  761. retOK:
  762.     /* 
  763.      * A space in a short file name is indeed technically allowed, but
  764.      * in order to be compatible with M$ Scandisk and Norton Disk Doctor 
  765.      * we mangle 8.3 names if they contain a space.  This will prevent 
  766.      * ScanDisk and Norton Disk Doctor from reporting a (false) orphaned 
  767.      * LFN entry on the alias, and offering to correct it.  Both will
  768.      * correct it by marking the LFN invalid (fragmenting the disk...)
  769.      * and simply using the short file name, which destroys the case
  770.      * sensitive part of the filename.
  771.      * Basically, this code is added to appease the windoze tools 
  772.      * that complain about our file system, since that supposedly 
  773.      * looks bad....but windo$e should NOT need to mangle a short
  774.      * filename with a space....but Windows 95 OSR2 does just that..
  775.      * Note only with "3D MAZES.SCR" style.  
  776.      * Not with "NAME    .   " filenames.
  777.      */
  778.     /* check backwards through name, wont be more than 11 chars (0-10) */
  779.     i = pNamePtr->nameLen - 1;
  780.     while (i > 1) /* ignore 0 and 1 chars, name won't begin with space.*/
  781.         {
  782. /* ignore "name   " type filenames */
  783. if (*(pNamePtr->pName + i) != SPACE)
  784.     break;        /* found non-space char, break */ 
  785. i--; 
  786. }
  787.     if (i != 1) /* don't care if "2   " style name */
  788. {
  789. while (i > 0) /* now look for a space */
  790.     {
  791.     if (*(pNamePtr->pName + i) == SPACE)
  792.         {
  793. goto error; /* windoze likes it a longname */
  794. }
  795.     i--;
  796.          }  
  797. }
  798.     
  799.     DBG_PRN_STR( 600, "result: %sn", pDstBuf, 
  800.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  801.     return retVal;
  802.     
  803. error:
  804.     bzero( (char *)pDstBuf, DOS_DIRENT_STD_LEN );
  805.     return NO_SHORT;
  806.     } /* dosVDirNameEncodeShort() */
  807.     
  808. /***************************************************************************
  809. *
  810. * dosVDirNameEncode - encode name to disk format.
  811. *
  812. * This routine encodes incoming file name into Windows-95 long names
  813. * format. During encoding the
  814. * name is verified to be composed of valid characters.
  815. * The source name is
  816. * split into several directory entries, that has valid format,
  817. * unless alias checksum.
  818. * Also src name is attempted to be encoded in short manner.
  819. *
  820. * RETURNS: directory entries per long name include alias or (-1) if name is
  821. *  illegal.
  822. * ERRNO:
  823. * S_dosFsLib_ILLEGAL_NAME
  824. */
  825. LOCAL int dosVDirNameEncode
  826.     ( 
  827.     DOS_DIR_PDESCR_ID pDirDesc,
  828.     PATH_ARRAY_ID pNamePtr, /* name buffer */
  829.     u_char * pDstName, /* buffer for name in disk format */
  830.     SHORT_ENCODE * pShortEncodeStrat /* short name encodding */
  831.       /* strategy/result */
  832.     )
  833.     {
  834.     u_char * pSrc = pNamePtr->pName; /* source name dynamic ptr */
  835.     u_char * pDst; /* ptr to encoded destination entry */
  836.     u_char numEnt; /* entries per long name */
  837.     u_char entNum, chNum; /* loop counters */
  838.     
  839.     if( pNamePtr->nameLen > DOS_VFAT_NAME_LEN )
  840.      goto error;
  841.     
  842.     /* number of entries per long name */
  843.     
  844.     numEnt = ( pNamePtr->nameLen + CHAR_PER_VENTRY  - 1 ) /
  845.           CHAR_PER_VENTRY;
  846.     
  847.     /* try to encode src name as short */
  848.     
  849.     bzero( (char *)pDstName, DOS_DIRENT_STD_LEN );
  850.     if( ( dosVDirNameEncodeShort( pDirDesc, pNamePtr,
  851.                pDstName ) == STRICT_SHORT ) )
  852.     
  853.      {
  854.      if( *pShortEncodeStrat == STRICT_SHORT )
  855.     {
  856.     return 1; 
  857.          }
  858.         *pShortEncodeStrat = STRICT_SHORT;
  859. }
  860.     else
  861.      {
  862.      *pShortEncodeStrat = NOT_STRICT_SHORT;
  863.      }
  864.     
  865.     
  866.     bcopy( (char *)pDstName, (char *)pDstName + numEnt * DOS_DIRENT_STD_LEN,
  867.            DOS_DIRENT_STD_LEN );
  868.     bzero( (char *)pDstName, numEnt * DOS_DIRENT_STD_LEN );
  869.          
  870.     /* start encoding from bottom (first) entry */
  871.     
  872.     pDst = pDstName + (numEnt - 1) * DOS_DIRENT_STD_LEN;
  873.     for( entNum = 1;
  874.       entNum <= numEnt;
  875.       entNum ++, pDst -=  DOS_DIRENT_STD_LEN )
  876.      {
  877.      *pDst = entNum; /* encode entry number */
  878.      *(pDst + pDirDesc->deDesc.atrribOff) = DOS_ATTR_VFAT;
  879.      /* VFAT long name representation */
  880.     
  881.      /* encode characters */
  882.     
  883.      for( chNum = 0;
  884.           chNum < CHAR_PER_VENTRY &&
  885.           pSrc < pNamePtr->pName + pNamePtr->nameLen;
  886.           pSrc ++, chNum ++ )
  887.          {
  888.          if( dosVDirCharEncode( pSrc, pDst + chOffsets[ chNum ],
  889.              longNamesChar ) == ERROR )
  890.           {
  891.           goto error;
  892.           }
  893.          }
  894.     
  895.         /* fill extra characters in last entry with 0xff */
  896.     
  897.      for( chNum ++; chNum < CHAR_PER_VENTRY; chNum ++ )
  898.          {
  899.          assert( pSrc >= pNamePtr->pName + pNamePtr->nameLen );
  900.          
  901.          *(pDst + chOffsets[ chNum ]) = 0xff;
  902.          *(pDst + chOffsets[ chNum ] + 1) = 0xff;
  903.          }
  904.      }
  905.     
  906.     /* mark last entry */
  907.     
  908.     pDst += DOS_DIRENT_STD_LEN;
  909.     *pDst |= DOS_VLAST_ENTRY;
  910.         
  911.     return numEnt + 1;
  912. error:
  913.     errnoSet( S_dosFsLib_ILLEGAL_NAME );
  914.     return (-1);
  915.     } /* dosVDirNameEncode() */
  916.     
  917. /***************************************************************************
  918. *
  919. * dosVDirClustNext - get next or add and init cluster to directory.
  920. *
  921. * RETURNS: OK or ERROR if end of directory is reached or
  922. * no more cluster could be allocated or disk is full.
  923. */
  924. LOCAL STATUS dosVDirClustNext
  925.     (
  926.     DOS_FILE_DESC_ID pFd,
  927.     u_int alloc /* 0 or DH_ALLOC */
  928.     )
  929.     {
  930.     block_t sec; /* work count */
  931.     
  932.     /* get next/allocate cluster */
  933.     
  934.     alloc = ( alloc == 0 ) ? FAT_NOT_ALLOC : FAT_ALLOC_ONE;
  935.     if( pFd->pVolDesc->pFatDesc->getNext( pFd, alloc ) == ERROR )
  936.      return ERROR;
  937.     
  938.     assert( pFd->pFileHdl->startClust != 0 );
  939.     
  940.     if( alloc == FAT_NOT_ALLOC )
  941.      return OK;
  942.     
  943.     /* init cluster */
  944.     for( sec = pFd->curSec; sec < pFd->curSec + pFd->nSec; sec ++ )
  945.      {
  946.      if( cbioIoctl(pFd->pVolDesc->pCbio,
  947. CBIO_CACHE_NEWBLK, (void *)sec ) == ERROR )
  948.          {
  949.          return ERROR;
  950.          }
  951.      }
  952.         
  953.     return (OK);
  954.     } /* dosVDirClustNext() */
  955. /***************************************************************************
  956. *
  957. * dosVDirDirentGet - get bundle directory entry from disk.
  958. *
  959. * This routine reads bundle directory entry from disk. 
  960. * On this level each entry containing part of long name is accepted
  961. * independent of others.
  962. *
  963. * <which> argument defines which entry to get.
  964. * This routine can be
  965. * used for readdir (<which> = RD_FIRST/RD_CURRENT/RD_NEXT),
  966. * in that case <pFd> describes the
  967. * directory is being read, or for getting directory entry
  968. * corresponding to <pFd> (<which> = FD_ENTRY).
  969. *
  970. * RETURNS: OK or ERROR if directory chain end reached or
  971. *  disk access error.
  972. */
  973. LOCAL STATUS dosVDirDirentGet
  974.     (
  975.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  976.     u_char * pDirEnt,
  977.     RDE_OPTION  which /* which entry to get */
  978.     )
  979.     {
  980.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  981.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  982.     int dirEntSize = pDirDesc->deDesc.dirEntSize;
  983.     DOS_FILE_DESC workFd;
  984.     
  985.     /* prepare to operation */
  986.     
  987.     if( which == FD_ENTRY ) /* get directory entry of file */
  988.      {
  989.      DBG_MSG( 600, "pFd = %p, FD_ENTRYn", pFd ,0,0,0,0,0,0,0);
  990.      /*
  991.       * it is being read directory entry of the file/dir,
  992.       * pointed by file descriptor.
  993.       * Prepare working fd.
  994.       */
  995.      workFd = *pFd;
  996.      workFd.curSec = pDirHdl->sector;
  997.      workFd.pos = pDirHdl->offset;
  998.      workFd.cbioCookie = pDirHdl->cookie;
  999.     
  1000.      goto getEntry;
  1001.      }
  1002.     
  1003.     /* readdir */
  1004.     
  1005.     if(  which == RD_CURRENT ) /* read current dir entry */
  1006.      {
  1007.      assert( pFd->nSec != 0 );
  1008.      assert( pFd->curSec != 0 );
  1009.     
  1010.      goto getEntry;
  1011.      }
  1012.     
  1013.     if( which == RD_FIRST ) /* read start dir entry */
  1014.      {
  1015.      DBG_MSG( 600, "pFd = %p, RD_FIRSTn", pFd ,0,0,0,0,0,0,0);
  1016.      dosVDirRewindDir( pFd ); /* rewind directory */
  1017.      }
  1018.     else if( which == RD_NEXT ) /* read next dir entry */
  1019.      {
  1020.      DBG_MSG( 600, "pFd = %p, RD_NEXTn", pFd ,0,0,0,0,0,0,0);
  1021.      assert( pFd->curSec != 0 );
  1022.     
  1023.      /* correct position */
  1024.     
  1025.      pFd->pos += dirEntSize;
  1026.     
  1027.      /* check for sector bounds */
  1028.     
  1029.      if( OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ) == 0 )
  1030.          {
  1031.          pFd->curSec++;
  1032.          pFd->nSec--;
  1033.          }
  1034.      }
  1035.     else /* impossible flag */
  1036.      {
  1037.      assert( which != which );
  1038.      } 
  1039.     
  1040.     /* may be contiguous block finished - get next contiguous block */
  1041.          
  1042.     if( pFd->nSec == 0 )
  1043.      {
  1044.      if( pFd->pVolDesc->pFatDesc->getNext(
  1045.           pFd, FAT_NOT_ALLOC ) == ERROR )
  1046.          {
  1047.          return ERROR;
  1048.          }
  1049.      pFd->cbioCookie = (cookie_t) NULL; /* we jumped to other sector */
  1050.      }
  1051.     
  1052.     workFd = *pFd;
  1053.     
  1054. getEntry:
  1055.     /* read directory entry */
  1056.     
  1057.     if( cbioBytesRW(workFd.pVolDesc->pCbio, workFd.curSec,
  1058.          OFFSET_IN_SEC( workFd.pVolDesc, workFd.pos ),
  1059.     (addr_t)pDirEnt, dirEntSize, CBIO_READ,
  1060.          &workFd.cbioCookie ) == ERROR )
  1061.      {
  1062.      return ERROR;
  1063.      }
  1064.     DBG_PRN_STR( 600, "entry: %sn", pDirEnt,
  1065.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  1066.       
  1067.     return OK;
  1068.     } /* dosVDirDirentGet() */
  1069. /***************************************************************************
  1070. *
  1071. * dosVDirDeStore - store some contiguous fields of directory entry.
  1072. *
  1073. * This routine stores <nBytes> pointed by <pData> starting
  1074. * from offset <offset> in directory entry is currently
  1075. * pointed by <pFd> or next to this one, depending on
  1076. * the <which> argument.
  1077. * <which> can be one of PUT_CURRENT or PUT_NEXT bitwise or-ed with
  1078. * DH_ALLOC, if new directory entry is being created.
  1079. *
  1080. * RETURNS: OK or ERROR if write error occurred.
  1081. */
  1082. LOCAL STATUS dosVDirDeStore
  1083.     (
  1084.     DOS_FILE_DESC_ID pFd, /* directory descriptor */
  1085.     off_t offset, /* offset in directory entry */
  1086.     size_t nBytes, /* num of bytes to write */
  1087.     void * pData, /* ptr to data buffer */
  1088.     u_int which /* (PUT_CURRENT or PUT_NEXT) ored with */
  1089.      /* DH_ALLOC */
  1090.     )
  1091.     {
  1092.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1093.     
  1094.     if( (which & PUT_NEXT) != 0 )
  1095.      {
  1096.      pFd->pos += DOS_DIRENT_STD_LEN;
  1097.      if( OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ) == 0 )
  1098.          {
  1099.          pFd->curSec ++;
  1100.          pFd->nSec --;
  1101.          }
  1102.      }
  1103.     
  1104.     if( pFd->nSec == 0 ) /* current cluster group exhausted */
  1105.      {
  1106.      if( dosVDirClustNext( pFd, (which & DH_ALLOC) ) == ERROR )
  1107.          return ERROR;
  1108.      }
  1109.     
  1110.     /* store data */
  1111.     
  1112.     if( cbioBytesRW( pVolDesc->pCbio, pFd->curSec,
  1113.                      OFFSET_IN_SEC( pVolDesc, pFd->pos ) + offset,
  1114.      pData, nBytes, CBIO_WRITE, &pFd->cbioCookie ) == ERROR )
  1115.      {
  1116.      return ERROR;
  1117.      }
  1118.     
  1119.     return OK;
  1120.     } /* dosVDirDeStore() */
  1121. /***************************************************************************
  1122. *
  1123. * dosVDirEntryDel - mark long name as deleted.
  1124. * This routine marks <nEnt> traditional directory entries as deleted.
  1125. * Entries are started from position is pointed by <pLnPtr>.
  1126. *
  1127. * RETURNS: OK or ERROR if disk access failed.
  1128. */
  1129. LOCAL STATUS dosVDirEntryDel
  1130.     (
  1131.     DOS_VOLUME_DESC_ID pVolDesc,/* dos volume descriptor */
  1132.     DIRENT_PTR_ID pLnPtr, /* long name start ptr */
  1133.     u_int nEnt, /* number of entries to mark as deleted */
  1134.      /* 0 - to accept the number from disk */
  1135.     BOOL always /* delete independent of is check disk */
  1136.      /* in progress or not */
  1137.     )
  1138.     {
  1139.     DOS_DIR_PDESCR_ID pDirDesc;
  1140.     DOS_FILE_DESC workFd = {0}; /* temporary file descriptor */
  1141.     DOS_FILE_HDL workFileHdl; /* temporary file handle */
  1142.     u_char dirent[ DOS_DIRENT_STD_LEN ]; /* directory entry buffer */
  1143.     cookie_t cookie = (cookie_t) NULL; /* temp buffer */
  1144.     u_int which;
  1145.     
  1146.     if( ! always && pVolDesc->chkLevel <= DOS_CHK_ONLY )
  1147.      return OK;
  1148. #if TRUE /* SPR#70968 fix enabled */
  1149.     /* 
  1150.      * 01o,09nov01,jkf  SPR#70968, chkdsk destroys boot sector
  1151.       *
  1152.      * When chkdsk() is in repair mode(DOS_CHK_REPAIR): it can
  1153.      * destroy the boot sector's first byte (sector 0, offset 0) 
  1154.      * by writing DOS_DEL_MARK(0xe5). The cause of the problem is
  1155.      * function dosVDirEntryDel() lacks a sanity check for
  1156.      * pLnPtr->sector being zero.
  1157.      *
  1158.      * Workaround:
  1159.      * 
  1160.      * Add an "if" statement to check if pLnPtr is illegal: 
  1161.      * 
  1162.      * if( ! always && pVolDesc->chkLevel <= DOS_CHK_ONLY )
  1163.      *     return OK;    
  1164.      *
  1165.      * /@ SPR#70968: check if pLnPtr is illegal @/
  1166.      *
  1167.      * if ( 0 == pLnPtr->sector ) 
  1168.      *     return ERROR; 
  1169.      */
  1170.     if ( 0 == pLnPtr->sector ) 
  1171.         {
  1172.         /* return ERROR if long name start pointer is from 0 sector */
  1173.         return (ERROR);
  1174.         }
  1175. #endif /* SPR#70968 fix enabled */
  1176.     pDirDesc = (void *)pVolDesc->pDirDesc;
  1177.     bzero( (char *)&workFileHdl, sizeof( workFileHdl ) );
  1178.     workFd.pVolDesc = pVolDesc;
  1179.     workFd.pFileHdl = &workFileHdl;
  1180.     workFd.curSec = pLnPtr->sector;
  1181.     workFd.pos = pLnPtr->offset;
  1182.     workFileHdl.startClust = NONE; /* don't care */
  1183.     
  1184.     if( workFd.curSec < pVolDesc->dataStartSec )
  1185.      { /* old root */
  1186.      workFd.nSec = pVolDesc->dataStartSec - workFd.curSec;
  1187.      }
  1188.     else if( pVolDesc->pFatDesc->seek(
  1189.      &workFd, workFd.curSec, 0 ) == ERROR )
  1190.         {
  1191.         assert( FALSE );
  1192.         return ERROR;
  1193.         }
  1194.     
  1195.     /* get number of entries per long name */
  1196.     
  1197.     if( nEnt == 0 )
  1198.      {
  1199.         if( cbioBytesRW(pVolDesc->pCbio, workFd.curSec,
  1200. OFFSET_IN_SEC( pVolDesc, workFd.pos ),
  1201.      (addr_t)dirent, DOS_DIRENT_STD_LEN, 
  1202. CBIO_READ, &cookie ) == ERROR )
  1203.          {
  1204.          return ERROR;
  1205.          }
  1206.     
  1207.      assert( dirent[ pDirDesc->deDesc.atrribOff ] == DOS_ATTR_VFAT );
  1208.     
  1209.      nEnt = ( *dirent & VFAT_ENTNUM_MASK ) + 1 /* include alias */;
  1210.      }
  1211.     
  1212.     /* mark all directory entries */
  1213.     
  1214.     *dirent = DOS_DEL_MARK;
  1215.     for( which = PUT_CURRENT; nEnt > 0; nEnt --, which = PUT_NEXT )
  1216.      {
  1217.      if( dosVDirDeStore( &workFd, 0, 1, &dirent, which ) == ERROR )
  1218.          {
  1219.          return ERROR;
  1220.          }
  1221.      }
  1222.     
  1223.     return OK;
  1224.     } /* dosVDirEntryDel() */
  1225.     
  1226. /***************************************************************************
  1227. *
  1228. * dosVDirFullEntGet - get VFAT full directory entry from disk.
  1229. *
  1230. * This routine reads entry out of directory pointed by <pFd>. 
  1231. * It puts into buffer <pEntry> full long name and alias.
  1232. * Invalid entries (with inconsistent checksum and so on)
  1233. * are usually passed, but deleted if check disk is in progress.
  1234. *
  1235. * <which> argument defines which entry to get and may be
  1236. * RD_FIRST, RD_CURRENT and RD_NEXT.
  1237. *
  1238. * RETURNS: OK or ERROR if directory chain end reached.
  1239. */
  1240. LOCAL STATUS dosVDirFullEntGet
  1241.     (
  1242.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  1243.     u_char * pEntry,
  1244.     RDE_OPTION   which, /* which entry to get */
  1245.     DIRENT_PTR_ID pLnPtr, /* to fill with long name start ptr */
  1246.     u_int * nEntries /* entries counter in directory */
  1247.     )
  1248.     {
  1249.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1250.     STATUS status = ERROR;
  1251.     u_char * pDst = pEntry; /* current destination position */
  1252.     int entNum = NONE; /* expected sequence number of */
  1253.      /* current entry per long name */
  1254.     int numEnt = 0; /* number of entries per long name */
  1255.     u_char chkSum = 0; /* alias checksum */
  1256.     u_char atrribOff = pDirDesc->deDesc.atrribOff;
  1257.     
  1258.     assert( nEntries != NULL );
  1259.     
  1260.     pLnPtr->sector = pLnPtr->offset = 0;
  1261.     for( (status = dosVDirDirentGet( pFd, pDst, which ));
  1262.       status != ERROR;
  1263.       (status = dosVDirDirentGet( pFd, pDst, RD_NEXT )) )
  1264.      {
  1265.      if( *pDst != LAST_DIRENT )
  1266.          (*nEntries)++;
  1267.     
  1268.      /*
  1269.       * return just a short name, volume label, deleted
  1270.       * or last entry in directory
  1271.       */
  1272.      if( (entNum == NONE && *(pDst + atrribOff ) != DOS_ATTR_VFAT) ||
  1273.      /* just a short || */
  1274.          *pDst == DOS_DEL_MARK || /* deleted || */
  1275.          *pDst == LAST_DIRENT || /* last */
  1276.          ((*(pDst + atrribOff ) & DOS_ATTR_VOL_LABEL) != 0 &&
  1277.           (*(pDst + atrribOff ) != DOS_ATTR_VFAT)) ) /* vol label */
  1278.          {
  1279.          bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN );
  1280.          goto retShort;
  1281.          }
  1282.     
  1283.      /* === long name representation === */
  1284.     
  1285.      if( *(pDst + atrribOff ) == DOS_ATTR_VFAT )
  1286.          {
  1287.          /* last (top) entry per long name */
  1288.          
  1289.          /* 
  1290.           * TBD:
  1291.           * Windows checks characters following EOS in last
  1292.      * per long name entry to be 0xff, so
  1293.           * some entries, that are accepted by this library
  1294.           * can be ignored as erroneous by Win.
  1295.           */
  1296.          if( (*pDst & DOS_VLAST_ENTRY) != 0 )
  1297.           {
  1298. /* check for erroneous long names */
  1299.          
  1300.           if( entNum != NONE ) /* long name already started */
  1301.               {
  1302.               ERR_MSG( 10, "Bad long name structure (breached))n",
  1303.      0,0,0,0,0,0 );
  1304.               DBG_MSG(0, "Long name interrupted on ent %u by "
  1305.                           "other long name at sec %u, off %un",
  1306.                       entNum, pFd->curSec,
  1307.                             OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1308.                             0,0,0,0,0 );
  1309.               
  1310.               /* remove invalid entries ( if check disk in progress */
  1311.               
  1312.               assert( numEnt != 0 );
  1313.               dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum,
  1314.                     FALSE );
  1315.               
  1316.               /* let now deal with this name */
  1317.               
  1318.               bcopy( (char *)pDst, (char *)pEntry, 
  1319.                      DOS_DIRENT_STD_LEN );
  1320.               pDst = pEntry;
  1321.               }
  1322.          
  1323.           numEnt = entNum = *pDst & VFAT_ENTNUM_MASK;
  1324.           if( entNum > VFAT_MAX_ENT )
  1325.               {
  1326.               ERR_MSG( 10, "Bad long name structure (too long)n",
  1327.      0,0,0,0,0,0 );
  1328.               DBG_MSG( 0, "max number of entries per long name (%u) "
  1329.                            " overloaded (%u); (sec %u, off %u)n",
  1330.                            VFAT_MAX_ENT, entNum,
  1331.                            pFd->curSec,
  1332.                                  OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1333.                                  0,0,0,0);
  1334.               goto errCont;
  1335.               }
  1336.           chkSum = *(pDst + DOS_VFAT_CHKSUM_OFF);
  1337.           pLnPtr->sector = pFd->curSec;
  1338.           pLnPtr->offset = pFd->pos;
  1339.           }
  1340.          else if( entNum == NONE ) /* no long name started yet */
  1341.           {
  1342.           DBG_MSG( 0, "Long name internal entry without first one "
  1343.                "( sec %u, off %u )n",
  1344.           pFd->curSec,
  1345.                                 OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1346.                                 0,0,0,0,0,0 );
  1347.           goto errCont;
  1348.           }
  1349.          else if( entNum != (*pDst & VFAT_ENTNUM_MASK) )
  1350.           {
  1351.           ERR_MSG( 10, "Malformed long name structuren",
  1352.  0,0,0,0,0,0 );
  1353.           DBG_MSG( 0, "invalid entry num in long name "
  1354.                "internal entry (start: sec %u, off %u; "
  1355.                "current: sec %u, off %u)n",
  1356.                pLnPtr->sector, pLnPtr->offset,
  1357.                pFd->curSec,
  1358.      OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1359.      0,0,0,0);
  1360.           goto errCont;
  1361.           }
  1362.          else /* one more entry in long name; check entry number */
  1363.           {
  1364.           /* control checksum */
  1365.          
  1366.           if( chkSum != *(pDst + DOS_VFAT_CHKSUM_OFF) )
  1367.               {
  1368.               ERR_MSG( 10, "Malformed long name structuren",
  1369.      0,0,0,0,0,0 );
  1370.          DBG_MSG( 0, "ChkSum changed in long name internal "
  1371.                "entry (start: sec %u, off %u; "
  1372.                "current: sec %u, off %u)n",
  1373.                pLnPtr->sector, pLnPtr->offset,
  1374.                pFd->curSec,
  1375.      OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1376.      0,0,0,0);
  1377.               goto errCont;
  1378.               }
  1379.           } /* else */
  1380.          
  1381.          /* expected next entry of long name */
  1382.          
  1383.          entNum --; /* next expected */
  1384.          pDst += DOS_DIRENT_STD_LEN; 
  1385.          continue; /* get the next entry in this long name */
  1386.          } /* if( *(pDst + atrribOff ) == DOS_ATTR_VFAT ) */
  1387.     
  1388. /* = long name alias encountered; count and control checksum = */
  1389.     
  1390.      assert( entNum != NONE );
  1391.     
  1392.      if( entNum != 0 || dosVDirChkSum( pDst ) != chkSum )
  1393.          {
  1394.          /*
  1395.           * alias appeared before long name finished or
  1396.           * checksum error.
  1397.           * It is abnormal situation, but in fact the short name
  1398.      * may be OK. So return the short name.
  1399.           */
  1400.          ERR_MSG( 10, "Bad long name structuren", 0,0,0,0,0,0 );
  1401.          DBG_MSG( 0, "start: sec %u, off %u n",
  1402.            pLnPtr->sector, pLnPtr->offset, 0,0,0,0,0,0 );
  1403.          
  1404.          goto retShort;
  1405. #if FALSE /* HELP dead code which followed above goto */
  1406.          /* remove invalid entries ( if check disk in progress */
  1407.          dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum, FALSE );
  1408.          bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN );
  1409.          goto ret;
  1410. #endif 
  1411.          }
  1412.     
  1413.      /* full long name and alias extracted */
  1414.     
  1415.      goto ret;
  1416.     
  1417. errCont:
  1418.      /* remove invalid entries ( if check disk in progress */
  1419.          
  1420.      dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum,
  1421.                 FALSE );
  1422.          
  1423.      entNum = NONE;
  1424.      pDst = pEntry;
  1425.      pLnPtr->sector = pLnPtr->offset = 0;
  1426.      } /* for( (status ... */
  1427.     
  1428. ret:
  1429.     return status;
  1430. retShort:
  1431.     if( entNum != NONE )
  1432.      {
  1433.      ERR_MSG(10, "Erroneous long namen", 0,0,0,0,0,0);
  1434.      DBG_MSG(0, "ent %u at sec %u, off %un",
  1435.               entNum, pFd->curSec,
  1436.     OFFSET_IN_SEC( pFd->pVolDesc, pFd->pos ),
  1437.     0,0,0,0,0);
  1438.               
  1439.      /* remove invalid entries ( if check disk in progress ) */
  1440.               
  1441.         assert( numEnt != 0 );
  1442.      dosVDirEntryDel( pFd->pVolDesc, pLnPtr, numEnt - entNum,
  1443.                 FALSE );
  1444.      bcopy( (char *)pDst, (char *)pEntry, DOS_DIRENT_STD_LEN );
  1445.      }
  1446.     pLnPtr->sector = pLnPtr->offset = 0; /* short name */
  1447.     return OK;
  1448.     } /* dosVDirFullEntGet() */
  1449.     
  1450. /***************************************************************************
  1451. *
  1452. * dosVDirNameCmp - compare long names.
  1453. *
  1454. * This routine compares long names' directory entries.
  1455. *
  1456. * If <caseSens> is TRUE case sensitive comparison is performed.
  1457. *
  1458. * RETURNS: OK if names are identical or ERROR.
  1459. */
  1460. LOCAL STATUS dosVDirNameCmp
  1461.     (
  1462.     DOS_DIR_PDESCR_ID pDirDesc,
  1463.     u_char * pName, /* incoming name */
  1464.     u_char * pDiskName, /* name to compare with */
  1465.     BOOL caseSens /* lkup case sensitively */
  1466.     )
  1467.     {
  1468.     int entNum  = (*pName & VFAT_ENTNUM_MASK);
  1469.     int i  = 0; /* loop counter */
  1470.     
  1471.     if( entNum != (*pDiskName & VFAT_ENTNUM_MASK) )
  1472.      return ERROR;
  1473.     
  1474.     for( ; entNum > 0; pName += DOS_DIRENT_STD_LEN, 
  1475.             pDiskName += DOS_DIRENT_STD_LEN, entNum -- )
  1476.      {
  1477.      for( i = 0; i < CHAR_PER_VENTRY; i++ )
  1478.          {
  1479.          if( caseSens )
  1480.              {
  1481.              if( pName[ chOffsets[ i ] ] !=
  1482.                  pDiskName[ chOffsets[ i ] ] )
  1483.               {
  1484.               return ERROR;
  1485.               }
  1486.           }
  1487.          else if( toupper( pName[ chOffsets[ i ] ] ) !=
  1488.                toupper( pDiskName[ chOffsets[ i ] ] ) )
  1489.           {
  1490.           return ERROR;
  1491.           }
  1492.          if( pName[ chOffsets[ i ] ] == 0 )
  1493.           break;
  1494.          }
  1495.      } /* for( ; entNum ... */
  1496.     return OK;
  1497.     } /* dosVDirNameCmp() */
  1498.     
  1499. /***************************************************************************
  1500. *
  1501. * dosVDirLkupInDir - lookup directory for specified name.
  1502. *
  1503. * This routine searches directory, that is pointed by <pFd> for name, that
  1504. * is pointed by <pNamePtr> structure and fills <pFd> in accordance with
  1505. * directory entry data, if found.
  1506. *
  1507. * If name not found, <pFreeEnt> will be filled with pointer onto
  1508. * deleted entry in directory large enough to create entry
  1509. * with name is being searched for, or onto free space in last directory
  1510. * cluster. If both of them not found, <pFreeEnt->sector> is set to 0.
  1511. *
  1512. * If <caseSens> is TRUE the name is searched case sensitively.
  1513. *
  1514. * RETURNS: OK or ERROR if name not found or invalid name.
  1515. */
  1516. LOCAL STATUS dosVDirLkupInDir
  1517.     (
  1518.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  1519.     PATH_ARRAY_ID pNamePtr, /* name buffer */
  1520.     DIRENT_PTR_ID pFreeEnt, /* empty entry in directory */
  1521.     int *pFreeEntLen, /* Return numbers of free chanks */
  1522.     BOOL caseSens /* lkup case sensitively */
  1523.     )
  1524.     {
  1525.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1526.     u_char * pName = pDirDesc->nameBuf; /* src name in disk format */
  1527.     u_char * pNameAl; /* name alias in <pLName> buffer */
  1528.     u_char * pDiskName = pDirDesc->nameBuf +
  1529.          MAX_VFAT_FULL_DIRENT;
  1530.           /* directory entry buffer */
  1531.     STATUS status = ERROR; /* search result status */
  1532.     u_int nEntries; /* number of entries in directory */
  1533.     size_t freeChankLen = 0; /* num of contiguous deleted entries */
  1534.     DIRENT_PTR lnPtr = {0}; /* ptr to long name start on disk */
  1535.     u_int which;
  1536.     SHORT_ENCODE shortNameEncode; /* encodding of short name */
  1537.     short aliasOff = 0; /* offset of alias in disk name buffer */
  1538.     short nEntInName; /* number of entries per name, */
  1539.      /* if will be created  */
  1540.     
  1541.     *pFreeEntLen = 0; /* No free entries to start with */
  1542.     
  1543.     DBG_MSG( 400, "pFd = %p ", pFd,0,0,0,0,0,0,0 );
  1544.     DBG_PRN_STR( 400, " name: %sn", pNamePtr->pName,
  1545.      pNamePtr->nameLen, 0 );
  1546.     
  1547.     pFreeEnt->deNum = 0;
  1548.     pFreeEnt->sector = 0;
  1549.     pFreeEnt->offset = 0;
  1550.     
  1551.     /* protect buffers */
  1552.     
  1553.     if( semTake( pDirDesc->bufSem, WAIT_FOREVER ) == ERROR )
  1554.      return ERROR;
  1555.     
  1556.     /* prepare name */
  1557.     
  1558.     shortNameEncode = NOT_STRICT_SHORT;
  1559.     nEntInName = dosVDirNameEncode( pDirDesc, pNamePtr, pName,
  1560.          &shortNameEncode );
  1561.     if( nEntInName == (short)ERROR )
  1562.      goto ret;
  1563.     
  1564.     aliasOff = DOS_DIRENT_STD_LEN * (nEntInName - 1);
  1565.     pNameAl = pName + aliasOff;
  1566.     
  1567.     /*
  1568.      * strict short name does not require extra long entries.
  1569.      *
  1570.      * Do not compare short alias, if case sensitive 
  1571.      * lkup in progress for name, that contains lower case characters
  1572.      */
  1573.     if( shortNameEncode ==  STRICT_SHORT )
  1574.      nEntInName = 1;
  1575.     else if( caseSens )
  1576.      *pNameAl = EOS;
  1577.     
  1578.     nEntries = 0;
  1579.     for( which = RD_FIRST; 1; which = RD_NEXT )
  1580.      {
  1581.      status = dosVDirFullEntGet( pFd, pDiskName,
  1582.                                  which, &lnPtr, &nEntries );
  1583.      if( status == ERROR || *pDiskName == LAST_DIRENT )
  1584.          break;
  1585.     
  1586.      /* pass deleted entry, that later can be used to store new entry */
  1587.     
  1588.      if( *pDiskName == DOS_DEL_MARK )
  1589.          {
  1590.          if( freeChankLen == 0 )
  1591.           {
  1592.           pFreeEnt->deNum = nEntries;
  1593.                 pFreeEnt->sector = pFd->curSec; /* new empty chain */
  1594.           pFreeEnt->offset = pFd->pos;
  1595.           }
  1596.          freeChankLen ++;
  1597.          continue;
  1598.          }
  1599.     
  1600.         /* non empty entry interrupts empty chain */
  1601.     
  1602.      if( freeChankLen < (size_t)nEntInName )
  1603.          freeChankLen = 0;
  1604.       
  1605.      /* long name entry */
  1606.     
  1607.      if( *(pDiskName + pDirDesc->deDesc.atrribOff) == DOS_ATTR_VFAT )
  1608.          {
  1609.          /* compare long names */
  1610.          
  1611.          if( dosVDirNameCmp( pDirDesc, pName, pDiskName, caseSens ) == OK )
  1612.              {
  1613.           goto ret;
  1614.           }
  1615.          
  1616.          continue;
  1617.          }
  1618.     
  1619.         /* pass volume label */
  1620.     
  1621.      if( ( *(pDiskName + pDirDesc->deDesc.atrribOff) & 
  1622.            DOS_ATTR_VOL_LABEL ) != 0 )
  1623.          {
  1624.          continue;
  1625.          }
  1626.          
  1627.      /* compare short names, that does not have long version */
  1628.     
  1629.      if( bcmp( (char *)pNameAl, (char *)pDiskName,
  1630.        DOS_STDNAME_LEN + DOS_STDEXT_LEN ) == 0 )
  1631.          {
  1632.          aliasOff = 0;
  1633.          goto ret;
  1634.          }
  1635.      }
  1636.     
  1637.     /* if no appropriate free space found, reset pointers */
  1638.     
  1639.     if( freeChankLen < (size_t)nEntInName )
  1640.      {
  1641.      pFreeEnt->deNum = nEntries + ((status == ERROR)? 1 : 0);
  1642.      pFreeEnt->sector = 0;
  1643.      pFreeEnt->offset = 0;
  1644.      }
  1645.     
  1646.     /* check result */
  1647.     
  1648.     if( status == ERROR )
  1649.      {
  1650.      goto ret;
  1651.      }
  1652.     status = ERROR;
  1653.     
  1654.     /* *pDiskName == LAST_DIRENT */
  1655.     
  1656.     if( IS_ROOT( pFd ) &&
  1657.      nEntries + nEntInName > pDirDesc->rootMaxEntries )
  1658.         {
  1659.      goto ret;
  1660.      }
  1661.     
  1662.     /* will create new entry on this place, if required */
  1663.     
  1664.     if( pFreeEnt->sector == 0 )
  1665.      {
  1666.      pFreeEnt->deNum = nEntries;
  1667.      pFreeEnt->sector = pFd->curSec;
  1668.      pFreeEnt->offset = pFd->pos;
  1669.      }
  1670. ret:
  1671.     if( status != ERROR ) /* file found; fill file descriptor */
  1672.      {
  1673.      dosVDirFillFd( pFd, pDiskName + aliasOff, &lnPtr );
  1674.      }
  1675.     *pFreeEntLen = freeChankLen; /* Return numbers of free ents */
  1676.     
  1677.     semGive( pDirDesc->bufSem );
  1678.     return status; 
  1679.     } /* dosVDirLkupInDir() */
  1680.     
  1681. /***************************************************************************
  1682. *
  1683. * dosVDirAliasCreate - create alias for long file name.
  1684. *
  1685. * This routine takes 1 first byte of file name and expands it
  1686. * with ~ and 6 decimal digits of sequence number of alias's
  1687. * entry in directory. Then it takes three characters of long name
  1688. * following last dot symbol and puts them to alias extension.
  1689. *
  1690. * RETURNS: N/A.
  1691. */
  1692. LOCAL void dosVDirAliasCreate
  1693.     (
  1694.     DOS_DIR_PDESCR_ID pDirDesc,
  1695.     PATH_ARRAY_ID pNamePtr,
  1696.     u_char * pAlias, /* dst alias */
  1697.     u_int entNum /* empty entry in directory */
  1698.     )
  1699.     {
  1700.     u_char * pSrc; /* loop pointer to src name */
  1701.     u_char * pDst; /* loop pointer to dst alias */
  1702.     char entNumBuf[ DOS_STDNAME_LEN + DOS_STDEXT_LEN + 1 ];
  1703.     
  1704.     entNum =  1000000 - entNum % 1000000;
  1705.     
  1706.     bfill( (char *)pAlias, DOS_STDNAME_LEN + DOS_STDEXT_LEN, SPACE );
  1707.     
  1708.     pSrc = pNamePtr->pName;
  1709.     pDst = pAlias;
  1710.     
  1711.     /* pass top dots in name */
  1712.     
  1713.     for( ; *pSrc == DOT; pSrc ++ );
  1714.     assert( *pSrc != EOS );
  1715.     for( ; *pSrc != DOT  &&
  1716.            pSrc != pNamePtr->pName + pNamePtr->nameLen &&
  1717.            pDst != pAlias + DOS_STDNAME_LEN;
  1718.       pSrc++, pDst++ )
  1719.      {
  1720.      if( dosVDirCharEncode( pSrc, pDst, shortNamesChar ) == ERROR )
  1721.          break;
  1722.      }
  1723.       
  1724.     /* encode directory entry number */
  1725.     
  1726.     sprintf( entNumBuf, "%c%u", TILDA, entNum );
  1727.     entNum = strlen( entNumBuf );
  1728.     
  1729.     if( pDst > pAlias + DOS_STDNAME_LEN - entNum )
  1730.      pDst = pAlias + DOS_STDNAME_LEN - entNum;
  1731.     
  1732.     bcopy( entNumBuf, (char *)pDst, entNum );
  1733.     
  1734.     /* === extension === */
  1735.     
  1736.     pDst = pAlias + DOS_STDNAME_LEN;
  1737.     
  1738.     /* find last DOT */
  1739.     
  1740.     for( pSrc = pNamePtr->pName + pNamePtr->nameLen - 1;
  1741.          pSrc != pNamePtr->pName && *pSrc != DOT; pSrc -- );
  1742.     
  1743.     /* encode 3 extension characters */
  1744.     
  1745.     if( pSrc == pNamePtr->pName )
  1746.      return; /* no extension */
  1747.     
  1748.     /* *pSrc == DOT */
  1749.     
  1750.     for( pSrc++;
  1751.       pDst != pAlias + DOS_STDNAME_LEN + DOS_STDEXT_LEN &&
  1752.       pSrc != pNamePtr->pName + pNamePtr->nameLen;
  1753.       pSrc++, pDst++ )
  1754.      {
  1755.      if( dosVDirCharEncode( pSrc, pDst, shortNamesChar ) == ERROR )
  1756.          {
  1757.          *pDst = SPACE;
  1758.          break;
  1759.          }
  1760.      }
  1761.     DBG_PRN_STR( 700, "result: %sn", pAlias, 
  1762.       pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,0 );
  1763.     } /* dosVDirAliasCreate() */
  1764. #ifdef __unused__
  1765. /***************************************************************************
  1766. *
  1767. * dosVDirFullDeUpdate - update fields in long name directory entries.
  1768. *
  1769. * This routine deletes full long name entry or updates.
  1770. *
  1771. * RETURNS: OK or ERROR if disk write error occurred.
  1772. */
  1773. LOCAL STATUS dosVDirFullDeUpdate
  1774.     (
  1775.     DOS_FILE_DESC_ID pFd, /* directory descriptor */
  1776.     u_int operation /* DH_DELETE */
  1777.     )
  1778.     {
  1779.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1780.     DOS_FILE_DESC workFd = {0}; /* temporary file descriptor */
  1781.     DOS_FILE_HDL workFileHdl; /* temporary file handle */
  1782.     UINT32 value = 0; /* start cluster number in disk format */
  1783.     STATUS st = ERROR;
  1784.     u_char nEnt; /* entries per long name */
  1785.     u_char fieldOff = 0, fieldLen = 0;
  1786.     
  1787.     if( operation == DH_DELETE )
  1788.      {
  1789.      fieldOff = 0;
  1790.      fieldLen = 1;
  1791.      *(u_char *)&value = DOS_DEL_MARK;
  1792.      }
  1793.     else
  1794.      {
  1795.      assert( FALSE );
  1796.      }
  1797.     /* init file descriptor */
  1798.     
  1799.     bzero( (char *)&workFileHdl, sizeof( workFileHdl ) );
  1800.     workFd.pVolDesc = pVolDesc;
  1801.     workFd.pFileHdl = &workFileHdl;
  1802.     workFd.pFileHdl->startClust = 
  1803.      pFd->pFileHdl->dirHdl.parDirStartCluster;
  1804.     
  1805.     /* get number of entries per long name */
  1806.     
  1807.     if( pFd->pFileHdl->dirHdl.lnSector == 0 )
  1808.      { /* short name only */
  1809.      nEnt = 0;
  1810.      workFd.curSec = pFd->pFileHdl->dirHdl.sector;
  1811.      workFd.pos = pFd->pFileHdl->dirHdl.offset;
  1812.      }
  1813.     else /* long name */
  1814.      {
  1815.      workFd.curSec = pFd->pFileHdl->dirHdl.lnSector;
  1816.      workFd.pos = pFd->pFileHdl->dirHdl.lnOffset;
  1817.     
  1818.         if( cbioBytesRW(
  1819.      pVolDesc->pCbio, workFd.curSec,
  1820. OFFSET_IN_SET( pVolDesc, workFd.pos ),
  1821.      &nEnt, 1, CBIO_READ, NULL ) == ERROR )
  1822.          {
  1823.          return ERROR;
  1824.          }
  1825.         if( (nEnt & DOS_VLAST_ENTRY) == 0 )
  1826.          {
  1827.          ERR_MSG(10, "Long name terminating flag missingn", 0,0,0,0 );
  1828.          return ERROR;
  1829.          }
  1830.      }    
  1831.     
  1832.     if( workFd.curSec < pVolDesc->dataStartSec )
  1833.      { /* old root */
  1834.      workFd.nSec = pVolDesc->dataStartSec - workFd.curSec;
  1835.      }
  1836.     else if( pVolDesc->pFatDesc->seek(
  1837.      &workFd, workFd.curSec, 0 ) == ERROR )
  1838.         {
  1839.         assert( FALSE );
  1840.         return ERROR;
  1841.         }
  1842.     
  1843.     /* update all directory entries */
  1844.     
  1845.     for( nEnt = (nEnt & VFAT_ENTNUM_MASK),
  1846.          (st = dosVDirDeStore( &workFd, fieldOff, fieldLen, &value,
  1847.                  PUT_CURRENT ));
  1848.          st != ERROR && nEnt > 0; nEnt -- )
  1849.      {
  1850.      st = dosVDirDeStore( &workFd, fieldOff, fieldLen, &value,
  1851.                PUT_NEXT );
  1852.          }
  1853.     return st;
  1854.     } /* dosVDirFullDeUpdate() */
  1855. #endif /* __unused__ */
  1856. /***************************************************************************
  1857. *
  1858. * dosVDirUpdateEntry - set new directory entry contents.
  1859. *
  1860. * This routine pulls file size, attributes and so on out of
  1861. * file descriptor and stores it in the correspondence directory
  1862. * entry.
  1863. * This function is also used for entry deletion. In this
  1864. * case <flags> have to be set to DH_DELETE.
  1865. *
  1866. * Time value provided in <curTime> can be encoded into appropriate
  1867. * fields within directory entry structure in accordance with
  1868. * <flags> argument. <flags> can be or-ed of
  1869. * DH_TIME_CREAT, DH_TIME_MODIFY or DH_TIME_ACCESS.
  1870. * If <curTime> is 0, current system time is used.
  1871. *
  1872. * RETURNS: OK or ERROR if name is invalid or disk access error occurred.
  1873. *
  1874. */
  1875. LOCAL STATUS dosVDirUpdateEntry
  1876.     (
  1877.     DOS_FILE_DESC_ID pFd,
  1878.     u_int flags,
  1879.     time_t curTime /* time to encode */
  1880.     )
  1881.     {
  1882.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1883.     u_char dirent[ DOS_DIRENT_STD_LEN ]; /* directory entry buffer */
  1884.     
  1885.     curTime = ( curTime == 0 )? time( NULL ) : curTime;
  1886.     
  1887.     /* root directory has not its own entry */
  1888.     
  1889.     if( IS_ROOT( pFd ) )
  1890.      {
  1891.      if( (flags & DH_TIME_MODIFY) != 0 )
  1892.          pDirDesc->rootModifTime = curTime;
  1893.      else
  1894.          assert( (flags & DH_TIME_MODIFY) != 0 );
  1895.     
  1896.      return OK;
  1897.      }
  1898.     
  1899.     if( flags & DH_DELETE ) /* delete entry */
  1900.      {
  1901.      DIRENT_PTR dePtr;
  1902.      u_int nEnt = 0;
  1903.     
  1904.      if( pFd->pFileHdl->dirHdl.lnSector == 0 )
  1905.          { /* short name only */
  1906.          dePtr.sector = pFd->pFileHdl->dirHdl.sector;
  1907.          dePtr.offset = pFd->pFileHdl->dirHdl.offset;
  1908.          nEnt = 1;
  1909.          }
  1910.      else /* long name */
  1911.          {
  1912.          dePtr.sector = pFd->pFileHdl->dirHdl.lnSector;
  1913.          dePtr.offset = pFd->pFileHdl->dirHdl.lnOffset;
  1914.          }
  1915.          
  1916.      return dosVDirEntryDel( pFd->pVolDesc, &dePtr, nEnt, TRUE );
  1917.      }
  1918.     
  1919.     /* get directory entry */
  1920.     
  1921.     if( dosVDirDirentGet( pFd, dirent, FD_ENTRY ) == ERROR )
  1922.      return ERROR;
  1923.     
  1924.     /*
  1925.      * encode other fields, but also start cluster, because entire
  1926.      * directory entry will be stored
  1927.      */
  1928.     START_CLUST_ENCODE( &pDirDesc->deDesc,
  1929.              pFd->pFileHdl->startClust,  dirent );
  1930.     dirent[ pDirDesc->deDesc.atrribOff ] = pFd->pFileHdl->attrib;
  1931.     VX_TO_DISK_32( pFd->pFileHdl->size,
  1932.         dirent + pDirDesc->deDesc.sizeOff );
  1933.     if( pDirDesc->deDesc.extSizeOff != (u_char) NONE )
  1934.      {
  1935.      EXT_SIZE_ENCODE( &pDirDesc->deDesc, dirent, pFd->pFileHdl->size );
  1936.      }
  1937.     
  1938.     dosVDirTDEncode( pDirDesc, dirent, flags, curTime );
  1939.     
  1940.     /* store directory entry */
  1941.     return cbioBytesRW( pFd->pVolDesc->pCbio, pFd->pFileHdl->dirHdl.sector,
  1942.      OFFSET_IN_SEC( pFd->pVolDesc, pFd->pFileHdl->dirHdl.offset ),
  1943. (addr_t)dirent, pDirDesc->deDesc.dirEntSize, CBIO_WRITE,
  1944.      &pFd->pFileHdl->dirHdl.cookie );
  1945.     } /* dosVDirUpdateEntry */
  1946. /***************************************************************************
  1947. *
  1948. * dosVDirFileCreateInDir - create new entry in directory.
  1949. *
  1950. * This routine creates new directory entry in place of
  1951. * deleted entry. If no deleted entry large enough found in directory,
  1952. * additional entry created at the directory tail.
  1953. *
  1954. * <pFreeEnt> must contain a pointer into an appropriate deleted entry in
  1955. * the directory or into free space in bottom of the directory.
  1956. * If <pFreeEnt->sector> eq. to 0 indicates,
  1957. * that no free entries found in directory and
  1958. * <pFd> reached directory end. In this case one more cluster is
  1959. * added to directory chain and new file is created in it.
  1960. *
  1961. * RETURNS: OK or ERROR if new entry can not be created.
  1962. *
  1963. * ERRNO:
  1964. * S_dosFsLib_DIR_READ_ONLY
  1965. * S_dosFsLib_INVALID_PARAMETER
  1966. * S_dosFsLib_ROOT_DIR_FULL
  1967. */
  1968. LOCAL STATUS dosVDirFileCreateInDir
  1969.     (
  1970.     DOS_FILE_DESC_ID pFd, /* directory descriptor */
  1971.     PATH_ARRAY_ID pNamePtr,
  1972.     u_int options, /* creat flags */
  1973.     DIRENT_PTR_ID pFreeEnt, /* empty entry in directory */
  1974.     int freeEntLen /* Number of contig empty entries in directory */
  1975.     )
  1976.     {
  1977.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  1978.     DOS_DIR_HDL_ID pDirHdl = (void *)&(pFd->pFileHdl->dirHdl);
  1979.     cookie_t cookie; /* temp buffer */
  1980.     u_char * dirent = pDirDesc->nameBuf; /* directory entry buffer */
  1981.     u_char * alias; /* long name alias */
  1982.     u_int whichEntry;
  1983.     u_int allocFlag;
  1984.     int numEnt; /* directory entries per full VFAT entry */
  1985.     int i;
  1986.     SHORT_ENCODE shortNameEncode = STRICT_SHORT;
  1987.      /* encodding of short name strategy */
  1988.     STATUS retStat = ERROR;
  1989.     u_char chkSum = 0; /* alias checksum */
  1990.     u_char parentIsRoot = 0; /* creation in root */
  1991.     
  1992.     /* check permissions */
  1993.     
  1994.     if( pFd->pFileHdl->attrib & DOS_ATTR_RDONLY )
  1995.      {
  1996.      errnoSet( S_dosFsLib_DIR_READ_ONLY );
  1997.      return ERROR;
  1998.      }
  1999.     
  2000.     /* only file and directory can be created */
  2001.     
  2002.     if( !( S_ISREG( options ) || S_ISDIR( options ) ) )
  2003.      {
  2004.      errnoSet( S_dosFsLib_INVALID_PARAMETER );
  2005.      return ERROR;
  2006.      }
  2007.     
  2008.     if( IS_ROOT( pFd ) )
  2009.      parentIsRoot = 1;
  2010.     
  2011.     /* protect buffers */
  2012.     
  2013.     if( semTake( pDirDesc->bufSem, WAIT_FOREVER ) == ERROR )
  2014.      return ERROR;
  2015.     
  2016.     /* check/encode file name */
  2017.     
  2018.     numEnt = dosVDirNameEncode( pDirDesc, pNamePtr, dirent,
  2019.      &shortNameEncode );
  2020.     if( numEnt == ERROR )
  2021.      goto ret;
  2022.     
  2023.     /* set alias pointer */
  2024.     
  2025.     alias = dirent + ( numEnt - 1 ) * DOS_DIRENT_STD_LEN;
  2026.     
  2027.     /*
  2028.      * if name can not be directly encoded as short,
  2029.      * create special alias. 
  2030.      */
  2031.     
  2032.     if ( *alias ==  EOS ) 
  2033.      {
  2034.      assert( alias != dirent );
  2035.      dosVDirAliasCreate(
  2036.      pDirDesc, pNamePtr, alias, pFreeEnt->deNum + numEnt );
  2037.      }
  2038.     /* encode time fields */
  2039.     
  2040.     dosVDirTDEncode( pDirDesc, alias,
  2041.           DH_TIME_CREAT | DH_TIME_MODIFY | DH_TIME_ACCESS,
  2042.           time( NULL ) );
  2043.     
  2044.     /* alias checksum */
  2045.     
  2046.     chkSum = dosVDirChkSum( alias );
  2047.     
  2048.     /* use empty entry, that was found during path lkup */
  2049.     
  2050.     if( pFreeEnt->sector != 0 )
  2051.      {
  2052.      /* point file descriptor onto the deleted entry position */
  2053.     
  2054.      if( IS_ROOT( pFd ) && pDirDesc->rootMaxEntries < (u_int)(-1) )
  2055.          {
  2056.          pFd->nSec += pFd->curSec - pFreeEnt->sector;
  2057.          pFd->curSec = pFreeEnt->sector;
  2058.          }
  2059.      else if( pFd->pVolDesc->pFatDesc->seek(
  2060.      pFd, pFreeEnt->sector, 0 ) == ERROR )
  2061.          {
  2062.          goto ret;
  2063.          }
  2064.      pFd->pos = pFreeEnt->offset;
  2065.      }
  2066.     else if( IS_ROOT( pFd ) && pDirDesc->rootMaxEntries < (u_int)(-1) )
  2067.      { /* no free entries in directory */
  2068.      errnoSet( S_dosFsLib_ROOT_DIR_FULL );
  2069.      goto ret;
  2070.      }
  2071.     else /* pointer to name start not initialized yet */
  2072.      {
  2073.      /* 
  2074.       * VVV : It may be that the parent directory chain is exhausted
  2075.       * and the new entry will be the first in addition cluster.
  2076.       *  In this case <pFreeEnt> will be set later in order to point
  2077.       * to actual position of first entry of name entries.
  2078.       * (see comment VVV hereafter)
  2079.       */
  2080.      }
  2081.          
  2082.     /* --- create new entry --- */
  2083.     
  2084.     for( i = numEnt, whichEntry = PUT_CURRENT;
  2085.       i  > 0;
  2086.          i--, dirent += DOS_DIRENT_STD_LEN, whichEntry = PUT_NEXT, --freeEntLen )
  2087.      {
  2088.      /* encode checksum and attribute to long name entry */
  2089.       
  2090.      if( i > 1 )
  2091.          {
  2092.          dirent[ DOS_VFAT_CHKSUM_OFF ] = chkSum;
  2093.          dirent[ pDirDesc->deDesc.atrribOff ] = DOS_ATTR_VFAT;
  2094.          }
  2095.     
  2096.     
  2097. /* Allocate new Entry only if no Contig entries available */
  2098. if (freeEntLen > 0)
  2099.    {
  2100.    allocFlag = 0;
  2101.    }
  2102. else
  2103.    {
  2104.    allocFlag = DH_ALLOC;
  2105.    }
  2106.      /* store consecutive directory entry */
  2107.      if( dosVDirDeStore( pFd, 0, DOS_DIRENT_STD_LEN,
  2108.            dirent, whichEntry | allocFlag ) == ERROR )
  2109.          {
  2110.          goto ret;
  2111.          }
  2112.      /* 
  2113.       * VVV: set <pFreeEnt> to point to actual position of first
  2114.       *  entry of name entries. (see comments VVV  above)
  2115.       */
  2116.      if( i == numEnt ) /* (whichEntry == PUT_CURRENT) */
  2117.          {
  2118.          pFreeEnt->sector = pFd->curSec;
  2119.          pFreeEnt->offset = pFd->pos;
  2120.          }
  2121.      }
  2122.     
  2123.     /* correct parent directory modification date/time */
  2124.     
  2125.     dosVDirUpdateEntry( pFd, DH_TIME_MODIFY, time( NULL ) );
  2126.     
  2127.     /* fill file descriptor for the new entry */
  2128.     
  2129.     cookie = pDirHdl->cookie; /* backup cbio qsearch cookie */
  2130.     dosVDirFillFd( pFd, alias, ((numEnt > 1)?pFreeEnt:NULL) );
  2131.         
  2132.     /* write f i l e entry to disk */
  2133.     
  2134.     if( S_ISREG( options ) )
  2135.      {
  2136.      retStat = OK;
  2137.      goto ret;
  2138.      }
  2139.     
  2140.     /* --- now we deal with directory --- */
  2141.     
  2142.     dirent = alias;
  2143.     *(alias + pDirDesc->deDesc.atrribOff) = DOS_ATTR_DIRECTORY;
  2144.     pFd->pFileHdl->attrib = DOS_ATTR_DIRECTORY;
  2145.     /*
  2146.      * for directory we have to create two entries: "." and ".."
  2147.      * start - allocate cluster and init it in structure.
  2148.      */
  2149.     if( dosVDirClustNext( pFd, DH_ALLOC ) == ERROR )
  2150.      goto ret;
  2151.     
  2152.     START_CLUST_ENCODE( &pDirDesc->deDesc,
  2153.              pFd->pFileHdl->startClust,  alias );
  2154.     
  2155.     /*
  2156.      * second - init directory entry for ".";
  2157.      * it is similar to directory entry itself, except name
  2158.      */
  2159.     bcopy( (char *)alias, (char *)dirent, DOS_DIRENT_STD_LEN ); 
  2160.     bfill( (char *)dirent,
  2161.         pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen,
  2162.         SPACE );
  2163.     *dirent = DOT;
  2164.     if( dosVDirDeStore( pFd, 0, DOS_DIRENT_STD_LEN, dirent,
  2165.      PUT_CURRENT ) == ERROR )
  2166.      {
  2167.      goto ret;
  2168.      }
  2169.     
  2170.     /* third - creat ".." entry, that points to the parent directory */
  2171.     
  2172.     if( parentIsRoot )
  2173.      {
  2174.      START_CLUST_ENCODE( &pDirDesc->deDesc, 0,  dirent );
  2175.      }
  2176.     else
  2177.      {
  2178.      START_CLUST_ENCODE( &pDirDesc->deDesc,
  2179.                  pDirHdl->parDirStartCluster,  dirent );
  2180.      }
  2181.     
  2182.     *(dirent + 1) = DOT;
  2183.     if( dosVDirDeStore( pFd, 0, DOS_DIRENT_STD_LEN, dirent,
  2184.      PUT_NEXT | DH_ALLOC ) == ERROR )
  2185.      {
  2186.      goto ret;
  2187.      }
  2188.     
  2189.     /* store start cluster number */
  2190.     
  2191.     if( dosVDirUpdateEntry( pFd, 0, 0 ) == ERROR )
  2192.      {
  2193.      goto ret;
  2194.      }
  2195.     /* now finish directory entry initialization */
  2196.     
  2197.     dosVDirRewindDir( pFd ); /* rewind directory */
  2198.     
  2199.     retStat = OK;
  2200.     
  2201. ret:
  2202.     semGive( pDirDesc->bufSem );
  2203.     return retStat;
  2204.     } /* dosVDirFileCreateInDir() */
  2205.     
  2206. /***************************************************************************
  2207. *
  2208. * dosVDirNameDecodeShort - decode short name from directory entry format.
  2209. *
  2210. * RETURNS: N/A.
  2211. */
  2212. LOCAL void dosVDirNameDecodeShort
  2213.     (
  2214.     DOS_DIR_PDESCR_ID pDirDesc,
  2215.     u_char * pDirent, /* directory entry buffer */
  2216.     u_char * pDstName /* destination name buffer */
  2217.     )
  2218.     {
  2219.     u_char * pNameEnd = pDstName;
  2220.     u_char * pDstBuf; /* for debug output */
  2221.     u_char * pDot = NULL;
  2222.     u_char * pSrc = pDirent;
  2223.     int i, j, nameLen;
  2224.     
  2225.     pDstBuf = pDstName;
  2226.     
  2227.     for( pDot = NULL, nameLen = pDirDesc->deDesc.nameLen, i = 0; i  < 2;
  2228.       i++, nameLen = pDirDesc->deDesc.extLen )
  2229.      { 
  2230.      for( j = 0; j < nameLen; j++, pDstName++ )
  2231.          {
  2232.          *pDstName = *pSrc++;
  2233.          
  2234.          if( *pDstName != SPACE )
  2235.           pNameEnd = pDstName + 1;
  2236.          }
  2237.     
  2238.      if( pDirDesc->deDesc.extLen == 0 ) /* long name */
  2239.          break;
  2240.          
  2241.      /* extension */
  2242.     
  2243.      if( pDot == NULL ) /* separate name and extension */
  2244.          {
  2245.          pDot = pNameEnd;
  2246.          *pNameEnd++ = DOT;
  2247.          pDstName = pNameEnd;
  2248.          }
  2249.      else if( pDot + 1 == pNameEnd )
  2250.          {
  2251.          pNameEnd --; /* empty extension - remove dot */
  2252.          break;
  2253.          }
  2254.      }
  2255.     
  2256.     *pNameEnd = EOS; /* terminate the name */
  2257.     DBG_MSG( 600, "result: %sn", pDstBuf ,0,0,0,0,0,0,0);
  2258.     } /* dosVDirNameDecodeShort() */
  2259.     
  2260. /***************************************************************************
  2261. *
  2262. * dosVDirNameDecode - decode name from VFAT format.
  2263. *
  2264. * RETURNS: N/A.
  2265. */
  2266. LOCAL void dosVDirNameDecode
  2267.     (
  2268.     DOS_DIR_PDESCR_ID pDirDesc,
  2269.     u_char * pDirent, /* directory entry buffer */
  2270.     u_char * pDstName /* destination name buffer */
  2271.     )
  2272.     {
  2273.     int i; /* loop counter */
  2274.     u_char * pDst = pDstName; /* work destination position pointer */
  2275.     u_char * pAlias; /* work destination position pointer */
  2276.     
  2277.     if( pDirent[ pDirDesc->deDesc.atrribOff ] != DOS_ATTR_VFAT )
  2278. {
  2279. dosVDirNameDecodeShort( pDirDesc, pDirent, pDstName );
  2280.      return; 
  2281. }
  2282.     
  2283.     /* start from first (bottom) direntry of long name */
  2284.     
  2285.     pDirent += (*pDirent & VFAT_ENTNUM_MASK) * DOS_DIRENT_STD_LEN;
  2286.     pAlias = pDirent;
  2287.     do {
  2288.      pDirent -= DOS_DIRENT_STD_LEN;
  2289.      for( i = 0;
  2290.           i < CHAR_PER_VENTRY && pDirent[ chOffsets[i] ] != EOS;
  2291.           i++, pDst ++ )
  2292.          {
  2293.          if( pDst - pDstName == NAME_MAX )
  2294.           {
  2295.           ERR_MSG( 10,"Name is too long; use alias insteadn",
  2296.                    0,0,0,0,0,0 );
  2297. dosVDirNameDecodeShort( pDirDesc, pAlias, pDstName );
  2298.           return; 
  2299.           }
  2300.          *pDst = pDirent[ chOffsets[i] ];
  2301.          }
  2302.         
  2303.      } while( (*pDirent & DOS_VLAST_ENTRY) == 0 );
  2304.     
  2305.     *pDst = EOS;
  2306.     return;
  2307.     } /* dosVDirNameDecode() */
  2308.     
  2309. /***************************************************************************
  2310. *
  2311. * dosVDirReaddir - FIOREADDIR backend.
  2312. *
  2313. * Optionally this routine fills file descriptor for the encountered entry,
  2314. * if <pResFd> is not NULL.
  2315. *
  2316. * RETURNS: OK or ERROR if no directory entries remain.
  2317. */
  2318. LOCAL STATUS dosVDirReaddir
  2319.     (
  2320.     DOS_FILE_DESC_ID pFd, /* descriptor of the directory being read */
  2321.     DIR * pDir, /* destination for directory name */
  2322.     DOS_FILE_DESC_ID pResFd /* file descriptor to be filled for the */
  2323.      /* being returned */
  2324.      /* (if pResFd is not NULL) */
  2325.     )
  2326.     {
  2327.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  2328.     int readFlag;
  2329.     DIRENT_PTR lnPtr = {0}; /* ptr to long name start on disk */
  2330.     u_char * dirent = pDirDesc->nameBuf; /* directory entry buffer */
  2331.     u_int nEntries = 0; /* work buffer */
  2332.     STATUS retStat = ERROR;
  2333.     
  2334.     assert( pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY );
  2335.     
  2336.     /* check status of directory */
  2337.     
  2338.     if( (int)pDir->dd_cookie == (-1) )
  2339.      return ERROR;
  2340.     
  2341.     readFlag = ( pDir->dd_cookie == 0 )? RD_FIRST : RD_NEXT;
  2342.     
  2343.     /* position must be directory entry size aligned */
  2344.     if( pFd->pos % DOS_STDNAME_LEN != 0 )
  2345.      {
  2346.      errnoSet( S_dosFsLib_INVALID_PARAMETER );
  2347.      goto ret;
  2348.      }
  2349.     /* protect buffers */
  2350.     
  2351.     if( semTake( pDirDesc->bufSem, WAIT_FOREVER ) == ERROR )
  2352.      return ERROR;
  2353.     do
  2354.      {
  2355.      if( dosVDirFullEntGet( pFd, dirent, readFlag, &lnPtr,
  2356.             &nEntries ) == ERROR )
  2357.             {
  2358.          goto ret;
  2359.          }
  2360.      readFlag = RD_NEXT;
  2361.      }
  2362.     while( *dirent == DOS_DEL_MARK ||
  2363.         ( dirent[ pDirDesc->deDesc.atrribOff ] != DOS_ATTR_VFAT &&
  2364.           (dirent[ pDirDesc->deDesc.atrribOff ] &
  2365.            DOS_ATTR_VOL_LABEL) != 0 ) );
  2366.     
  2367.     if( *dirent == LAST_DIRENT ) /* end of directory */
  2368.      {
  2369.      goto ret;
  2370.      }
  2371.     
  2372.     /* name decode */
  2373.     
  2374.     dosVDirNameDecode( pDirDesc, dirent, (u_char *)pDir->dd_dirent.d_name );
  2375.     
  2376.     /* fill file descriptor for the entry */
  2377.     
  2378.     if( pResFd != NULL )
  2379.      {
  2380.      void * pFileHdl = pResFd->pFileHdl;
  2381.     
  2382.      /* prepare file descriptor contents */
  2383.     
  2384.      *pResFd = *pFd;
  2385.      pResFd->pFileHdl = pFileHdl;
  2386.      *pResFd->pFileHdl = *pFd->pFileHdl;
  2387.     
  2388.      /* point to alias */
  2389.     
  2390.      if( dirent[ pDirDesc->deDesc.atrribOff ] == DOS_ATTR_VFAT )
  2391.          dirent += (*dirent & VFAT_ENTNUM_MASK) * DOS_DIRENT_STD_LEN;
  2392.     
  2393.      dosVDirFillFd( pResFd, dirent, &lnPtr );
  2394.      }
  2395.     
  2396.     retStat = OK;
  2397. ret:
  2398.     /* save current offset in directory */
  2399.     
  2400.     if( retStat == OK )
  2401.      pDir->dd_cookie = POS_TO_DD_COOKIE( pFd->pos );
  2402.     else
  2403.      pDir->dd_cookie = (-1);
  2404.     semGive( pDirDesc->bufSem );
  2405.     return retStat;
  2406.     } /* dosVDirReaddir() */
  2407.     
  2408. /***************************************************************************
  2409. *
  2410. * dosVDirPathLkup - lookup for file/dir in tree.
  2411. *
  2412. * This routine recursively searches directory tree for the <path> and
  2413. * fills file descriptor for the target entry if successful.
  2414. * Optionally new entry may be created in accordance with creatFlags.
  2415. *
  2416. * Generally VFAT creates long names case sensitively,
  2417. * but makes lookup in case insensitive manner. Special option
  2418. * DOS_O_CASENS causes to make a search case sensitively.
  2419. *
  2420. * .CS
  2421. * <options> : O_CREAT - creat file;
  2422. * O_CREAT | DOS_ATTR_DIRECTORY - create directory.
  2423. * <somth> | DOS_O_CASENS - lkup for name in case
  2424. *                          sensitive manner.
  2425. * .CE
  2426. *
  2427. * RETURNS: OK or ERROR if file not found.
  2428. *
  2429. * ERRNO:
  2430. * S_dosFsLib_FILE_NOT_FOUND
  2431. */
  2432. LOCAL STATUS dosVDirPathLkup
  2433.     (
  2434.     DOS_FILE_DESC_ID pFd, /* dos file descriptor to fill */
  2435.     void * path, /* path in tree */
  2436.     u_int options /* optional creat flags */
  2437.     )
  2438.     {
  2439.     PATH_ARRAY namePtrArray [DOS_MAX_DIR_LEVELS + 1];
  2440.     int numPathLevels;
  2441.     int errnoBuf; /* swap errno */
  2442.     DIRENT_PTR freeEnt; /* empty (deleted) entry in directory */
  2443.     int freeEntLen=0; /* Number of empty entries in directory */
  2444.     u_char dirLevel; /* dynamic directory level counter */
  2445.     
  2446.     assert( path != NULL );
  2447.     
  2448.     /* disassemble path */
  2449.     
  2450.     numPathLevels = dosVDirPathParse( pFd->pVolDesc, path, 
  2451.      namePtrArray ); 
  2452.     if( numPathLevels == ERROR )
  2453.      return ERROR;
  2454.     assert( numPathLevels <= DOS_MAX_DIR_LEVELS );
  2455.     
  2456.     /* start from root directory */
  2457.     
  2458.     dosVDirFillFd( pFd, ROOT_DIRENT, NULL );
  2459.     
  2460.     errnoBuf = errnoGet();
  2461.     errnoSet( OK );
  2462.     for( dirLevel = 0; dirLevel < numPathLevels; dirLevel ++  )
  2463.      {
  2464.      /* only directory can be searched */
  2465.     
  2466.      if( ! (pFd->pFileHdl->attrib & DOS_ATTR_DIRECTORY) )
  2467.          break;
  2468.     
  2469.      if( dosVDirLkupInDir( pFd, namePtrArray + dirLevel, &freeEnt, &freeEntLen,
  2470.            ((options & DOS_O_CASENS) != 0) ) == ERROR )
  2471.          {
  2472.          if( errnoGet() != OK ) /* subsequent error */
  2473.           return ERROR;
  2474.          
  2475.          break;
  2476.          }
  2477.      }
  2478.     
  2479.     if( errnoGet() == OK )
  2480.      errnoSet( errnoBuf );
  2481.     
  2482.     /* 
  2483.      * check result if dirLevel == numPathLevels, then we found the file
  2484.      */
  2485.     
  2486.     if( dirLevel == numPathLevels )
  2487.      {
  2488.      return OK;
  2489.      }
  2490.     
  2491.     /* --- file not found --- */
  2492.     
  2493.     /* only last file in path can be created */
  2494.     
  2495.     if( dirLevel == numPathLevels - 1 &&  (options & O_CREAT) )
  2496.      {
  2497.      if( dosVDirFileCreateInDir( pFd,
  2498.            namePtrArray + dirLevel,
  2499.                    options, &freeEnt, freeEntLen ) == OK )
  2500.          return OK;
  2501.      }
  2502.     else
  2503.      {
  2504.      errnoSet( S_dosFsLib_FILE_NOT_FOUND );
  2505.      }
  2506.     
  2507.     /* error; release dir handle */
  2508.     
  2509.     return ERROR;
  2510.     } /* dosVDirPathLkup() */
  2511. /***************************************************************************
  2512. *
  2513. * dosVDirDateGet - fill in date-time fields in stat structure.
  2514. *
  2515. * RETURNS: OK or ERROR if disk access error.
  2516. *
  2517. */
  2518. LOCAL STATUS dosVDirDateGet
  2519.     (
  2520.     DOS_FILE_DESC_ID pFd,
  2521.     struct stat * pStat
  2522.     )
  2523.     {
  2524.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pFd->pVolDesc->pDirDesc;
  2525.     u_char dirent[ DOS_DIRENT_STD_LEN ]; /* directory entry buffer */
  2526.     
  2527.     /* root directory has not its own entry */
  2528.     
  2529.     if( IS_ROOT( pFd ) )
  2530.      {
  2531.      pStat->st_mtime = pDirDesc->rootModifTime;
  2532.      return OK;
  2533.      }
  2534.     
  2535.     /* get directory entry */
  2536.     
  2537.     if( dosVDirDirentGet( pFd, dirent, FD_ENTRY ) == ERROR )
  2538.      return ERROR;
  2539.     
  2540.     pStat->st_ctime = dosVDirTDDecode( pDirDesc, dirent, DH_TIME_CREAT );
  2541.     pStat->st_mtime = dosVDirTDDecode( pDirDesc, dirent, DH_TIME_MODIFY );
  2542.     pStat->st_atime = dosVDirTDDecode( pDirDesc, dirent, DH_TIME_ACCESS );
  2543.     return OK;
  2544.     } /* dosVDirDateGet() */
  2545.     
  2546. /*******************************************************************************
  2547. *
  2548. * dosVDirVolLabel - set/get dos volume label.
  2549. *
  2550. * This routine gets/changes the volume label entry in the root directory of a
  2551. * dosFs volume.
  2552. *
  2553. * Only one volume label entry may exist per volume and in root directory only.
  2554. * When request to change volume label arrives and there is already a volume
  2555. * label, the name is simply
  2556. * replaced.  If there is currently no label, a new volume label entry is
  2557. * created.
  2558. *
  2559. * RETURNS: OK, or ERROR if volume is not available.
  2560. *
  2561. * ERRNO:
  2562. * S_dosFsLib_INVALID_PARAMETER
  2563. * S_dosFsLib_NO_LABEL
  2564. * S_dosFsLib_ROOT_DIR_FULL
  2565. */
  2566. LOCAL STATUS dosVDirVolLabel
  2567.     (
  2568.     DOS_VOLUME_DESC_ID pVolDesc,
  2569.     u_char * label,
  2570.     u_int request /* FIOLABELSET, FIOLABELGET */
  2571.     )
  2572.     {
  2573.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  2574.     u_char dirent[ DOS_DIRENT_STD_LEN ]; /* directory entry buffer */
  2575.     DOS_FILE_DESC fd; /* work file descriptor */
  2576.     DOS_FILE_HDL fHdl; /* work file handle */
  2577.     STATUS status = ERROR; /* search status */
  2578.     u_int numEnt; /* number of passed entries */
  2579.     char * noName = "NO LABLE";
  2580.     u_short labOffInBoot; /* volume label offset in boot sector */
  2581.     
  2582.     assert( request == FIOLABELSET || request == FIOLABELGET );
  2583.     
  2584.     labOffInBoot = ( pVolDesc->fatType == FAT32 )? DOS32_BOOT_VOL_LABEL:
  2585.         DOS_BOOT_VOL_LABEL;
  2586.     if( label == NULL )
  2587.      {
  2588.      if( request == FIOLABELSET )
  2589.          label = (u_char *)noName; /* use default name */
  2590.      else
  2591.          {
  2592.          errnoSet( S_dosFsLib_INVALID_PARAMETER );
  2593.          return ERROR;
  2594.          }
  2595.      }
  2596.     
  2597.     /* init file descriptor */
  2598.     
  2599.     fd.pVolDesc = pVolDesc;
  2600.     fd.pFileHdl = &fHdl;
  2601.     dosVDirFillFd( &fd, ROOT_DIRENT, NULL );
  2602.     
  2603.     /* search for volume label */
  2604.     
  2605.     for( numEnt = 0, (status = dosVDirDirentGet( &fd, dirent, RD_FIRST ));
  2606.       (status != ERROR) && *dirent != LAST_DIRENT;
  2607.       numEnt ++, status = dosVDirDirentGet( &fd, dirent, RD_NEXT ) )
  2608.      {
  2609.      if( dirent[ pDirDesc->deDesc.atrribOff ] != DOS_ATTR_VFAT &&
  2610.          ( dirent[ pDirDesc->deDesc.atrribOff ] &
  2611.            DOS_ATTR_VOL_LABEL ) != 0 )
  2612.          {
  2613.          break;
  2614.          }
  2615.      }
  2616.     
  2617.     /* get label */
  2618.     
  2619.     if( request == FIOLABELGET )
  2620.      {
  2621.      if( status == ERROR || *dirent == LAST_DIRENT )
  2622.          {
  2623.          /*
  2624.           * no volume label found in root dir
  2625.           * extract label out of boot sector
  2626.           */
  2627.          bcopy( pVolDesc->bootVolLab, (char *)dirent, DOS_VOL_LABEL_LEN );
  2628.          }
  2629.      bcopy( (char *)dirent, (char *)label, DOS_VOL_LABEL_LEN );
  2630.      numEnt = DOS_VOL_LABEL_LEN;
  2631.      while( numEnt > 0 && label[ numEnt-1 ] == SPACE )
  2632.          label[ --numEnt ] = EOS;
  2633.     
  2634.      return OK;
  2635.      }
  2636.     
  2637.     /* change/create label */
  2638.     
  2639.     /* 
  2640.      * if no label found and no free entry in root,
  2641.      * add and init one more cluster.
  2642.      */
  2643.     if( status == ERROR ) /* label not found and no free entry */
  2644.      {
  2645.      if( numEnt >= pDirDesc->rootMaxEntries ) /* root dir is full */
  2646.          {
  2647.          errnoSet( S_dosFsLib_ROOT_DIR_FULL );
  2648.          return ERROR;
  2649.          }
  2650.      }
  2651.     
  2652.     /* encode name */
  2653.     
  2654.     bzero( (char *)dirent, sizeof( dirent ) );
  2655.     bfill( (char *)dirent, pDirDesc->deDesc.nameLen + pDirDesc->deDesc.extLen, 
  2656.    SPACE );
  2657.     bcopy( (char *)label, (char *)dirent,
  2658.            min( DOS_VOL_LABEL_LEN, strlen( (char *)label ) ) );
  2659.     dirent[ pDirDesc->deDesc.atrribOff] = DOS_ATTR_VOL_LABEL;
  2660.     
  2661.     /* --- store label --- */
  2662.     
  2663.     /* store in root directory */
  2664.     
  2665.     status = dosVDirDeStore( &fd, 0, DOS_DIRENT_STD_LEN, dirent,
  2666.           PUT_CURRENT | DH_ALLOC );
  2667.    
  2668. #ifdef CHANGE_BOOT
  2669. #warning CHANGE_BOOT defined for dosVDirLib.c
  2670.     /* XXX - avoid changing boot record to avoid false disk-change event */
  2671.     /* store in boot sector */
  2672.     bcopy( (char *)dirent, pVolDesc->bootVolLab, DOS_VOL_LABEL_LEN );
  2673.     status |= cbioBytesRW(
  2674.      pVolDesc->pCbio, DOS_BOOT_SEC_NUM,
  2675.      labOffInBoot, dirent, 
  2676.      DOS_VOL_LABEL_LEN, CBIO_WRITE, NULL );
  2677.     
  2678. #endif /* CHANGE_BOOT */
  2679.     return status;
  2680.     } /* dosVDirVolLabel() */
  2681.     
  2682. /*******************************************************************************
  2683. *
  2684. * dosVDirNameChk - validate file name.
  2685. *
  2686. * This routine validates incoming file name to be composed
  2687. * of valid characters.
  2688. *
  2689. * RETURNS: OK if name is OK or ERROR.
  2690. */
  2691. LOCAL STATUS dosVDirNameChk
  2692.     (
  2693.     DOS_VOLUME_DESC_ID pVolDesc,
  2694.     u_char * name
  2695.     )
  2696.     {
  2697.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  2698.     SHORT_ENCODE shortNameEncode = NOT_STRICT_SHORT;
  2699.     int result;
  2700.     PATH_ARRAY namePtr;
  2701.     
  2702.     namePtr.pName = name;
  2703.     namePtr.nameLen = strlen((char *)name);
  2704.     
  2705.     /* protect buffers */
  2706.     
  2707.     if( semTake( pDirDesc->bufSem, WAIT_FOREVER ) == ERROR )
  2708.      return ERROR;
  2709.     
  2710.     result = dosVDirNameEncode( pDirDesc, &namePtr,
  2711.      pDirDesc->nameBuf, &shortNameEncode );
  2712.     
  2713.     semGive( pDirDesc->bufSem );
  2714.     
  2715.     return ( (result == (-1))? ERROR : OK );
  2716.     } /* dosVDirNameChk() */
  2717.     
  2718. /*******************************************************************************
  2719. *
  2720. * dosVDirShow - display handler specific volume configuration data.
  2721. *
  2722. * RETURNS: N/A.
  2723. */
  2724. LOCAL void dosVDirShow
  2725.     (
  2726.     DOS_VOLUME_DESC_ID pVolDesc
  2727.     )
  2728.     {
  2729.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  2730.     
  2731.     printf(" - directory structure: VFATn" );
  2732.     
  2733.     if( ! pVolDesc->mounted )
  2734.      return;
  2735.     
  2736.     if( pDirDesc->dirDesc.rootStartSec != 0 ) /* FAT12/FAT16 */
  2737.      {
  2738.      printf(" - root dir start sector: %un",
  2739.      pDirDesc->dirDesc.rootStartSec );
  2740.      printf(" - # of sectors per root: %un",
  2741.      pDirDesc->dirDesc.rootNSec );
  2742.      printf(" - max # of entries in root: %un",
  2743.      pDirDesc->rootMaxEntries );
  2744.      }
  2745.     else /* FAT32 */
  2746.      {
  2747.      printf(" - root dir start cluster: %un",
  2748.      pDirDesc->rootStartClust );
  2749.      }
  2750.     
  2751.     return;
  2752.     } /* dosVDirShow() */
  2753. /*******************************************************************************
  2754. *
  2755. * dosVDirVolUnmount - free all allocated resources.
  2756. *
  2757. * This routine only deallocates names buffer.
  2758. *
  2759. * RETURNS: N/A.
  2760. */
  2761. LOCAL void dosVDirVolUnmount
  2762.     (
  2763.     DOS_VOLUME_DESC_ID pVolDesc
  2764.     )
  2765.     {
  2766.     DOS_DIR_PDESCR_ID pDirDesc = (void *)pVolDesc->pDirDesc;
  2767.     
  2768.     if (pDirDesc == NULL)
  2769. return ;
  2770.     semTake( pDirDesc->bufSem, WAIT_FOREVER ); /* XXX */
  2771.     
  2772.     if (pDirDesc->nameBuf != NULL)
  2773.      {
  2774.      KHEAP_FREE (pDirDesc->nameBuf);
  2775.      pDirDesc->nameBuf = NULL;
  2776.      }
  2777.     semGive (pDirDesc->bufSem);
  2778.     
  2779.     return;
  2780.     } /* dosVDirVolUnmount() */
  2781. /*******************************************************************************
  2782. *
  2783. * dosVDirVolMount - init all data required to access the volume.
  2784. *
  2785. * This routine fills all local and shared structures fields, that
  2786. * depend on a directory structure format. All data is updated
  2787. * from boot sector of the volume is being mounted and from
  2788. * volume descriptor argument.
  2789. *
  2790. * RETURNS: OK or ERROR if the volume has inappropriate format.
  2791. *
  2792. * ERRNO:
  2793. * S_dosFsLib_UNSUPPORTED
  2794. * S_dosFsLib_UNKNOWN_VOLUME_FORMAT
  2795. */
  2796. LOCAL STATUS dosVDirVolMount
  2797.     (
  2798.     DOS_VOLUME_DESC_ID pVolDesc,
  2799.     void * arg
  2800.     )
  2801.     {
  2802.     DOS_DIR_PDESCR_ID pDirDesc = NULL;
  2803.     DIRENT_DESCR_ID pDeDesc = NULL;
  2804.     cookie_t cookie = 0;
  2805.     char bootSec[DOS_BOOT_BUF_SIZE];
  2806.     
  2807.     assert( (pVolDesc != NULL) && pVolDesc->magic == DOS_FS_MAGIC );
  2808.     
  2809.     /* check for vxWorks long names */
  2810.     
  2811.     if( cbioBytesRW(
  2812.      pVolDesc->pCbio, pVolDesc->bootSecNum, 0,
  2813.      bootSec,
  2814.      min( sizeof( bootSec ), pVolDesc->bytesPerSec ),
  2815.      CBIO_READ, &cookie ) == ERROR )
  2816.      {
  2817.      return ERROR;
  2818.      }
  2819.     
  2820.     /* 
  2821.      * if previous volume had alternative directory structure,
  2822.      * unmount previous directory handler and
  2823.      * allocate directory handler descriptor
  2824.      */
  2825.     if( pVolDesc->pDirDesc == NULL ||
  2826.      pVolDesc->pDirDesc->volUnmount != dosVDirVolUnmount )
  2827.      {
  2828.      /* unmount previous directory handler */
  2829.          
  2830.      if( pVolDesc->pDirDesc != NULL &&
  2831.          pVolDesc->pDirDesc->volUnmount != NULL )
  2832.          {
  2833.          pVolDesc->pDirDesc->volUnmount( pVolDesc );
  2834.          }
  2835.          
  2836.      /* allocate directory handler descriptor */
  2837.          
  2838.      pVolDesc->pDirDesc = KHEAP_REALLOC((char *) pVolDesc->pDirDesc,
  2839.                 sizeof( DOS_DIR_PDESCR ) );
  2840.      if( pVolDesc->pDirDesc == NULL )
  2841.          return ERROR;
  2842.     
  2843.      bzero( (char *)pVolDesc->pDirDesc, sizeof( DOS_DIR_PDESCR ) );
  2844.      }
  2845.     
  2846.     pDirDesc = (void *)pVolDesc->pDirDesc;
  2847.     pDeDesc = &pDirDesc->deDesc;
  2848.     
  2849.     if( bcmp( bootSec + DOS_BOOT_SYS_ID, DOS_VX_LONG_NAMES_SYS_ID,
  2850.            strlen( DOS_VX_LONG_NAMES_SYS_ID ) ) == 0 )
  2851.      {
  2852.      /* use vxWorks long names */
  2853.     
  2854.      ERR_MSG( 1, "VxWorks proprietary long names not supportedn",
  2855.       0,0,0,0,0,0 );
  2856.      errnoSet( S_dosFsLib_UNSUPPORTED );
  2857.      return ERROR;
  2858.      }
  2859.     else
  2860.      {
  2861.      DBG_MSG( 10, "VFAT long namesn", 0,0,0,0,0,0,0,0 );
  2862.     
  2863.      pDirDesc->nameStyle = STDDOS;
  2864.     
  2865.      pDeDesc->dirEntSize = DOS_DIRENT_STD_LEN;
  2866.      pDeDesc->nameLen = DOS_STDNAME_LEN;
  2867.      pDeDesc->extLen = DOS_STDEXT_LEN;
  2868.      pDeDesc->atrribOff = DOS_ATTRIB_OFF;
  2869.     
  2870.      pDeDesc->creatTimeOff = DOS_CREAT_TIME_OFF;
  2871.      pDeDesc->creatDateOff = DOS_CREAT_DATE_OFF;
  2872.     
  2873.      pDeDesc->accessTimeOff = DOS_LAST_ACCESS_TIME_OFF;
  2874.      pDeDesc->accessDateOff = DOS_LAST_ACCESS_DATE_OFF;
  2875.     
  2876.      pDeDesc->modifTimeOff = DOS_MODIF_TIME_OFF;
  2877.      pDeDesc->modifDateOff = DOS_MODIF_DATE_OFF;
  2878.     
  2879.      pDeDesc->startClustOff = DOS_START_CLUST_OFF;
  2880.      pDeDesc->extStartClustOff = DOS_EXT_START_CLUST_OFF;
  2881.      pDeDesc->sizeOff = DOS_FILE_SIZE_OFF;
  2882.      pDeDesc->extSizeOff = DOS_EXT_FILE_SIZE_OFF;
  2883.      pDeDesc->extSizeLen = DOS_EXT_FILE_SIZE_LEN;
  2884.      }
  2885.     
  2886.     /* check correspondence of cluster and directory entry size */
  2887.     
  2888.     if( pDeDesc->dirEntSize >
  2889.         ( pVolDesc->secPerClust << pVolDesc->secSizeShift ) )
  2890.      {
  2891.      ERR_MSG( 1, "cluster size %d bytes is too small, min = %dn",
  2892.          pVolDesc->secPerClust << pVolDesc->secSizeShift,
  2893.          pDeDesc->dirEntSize, 0,0,0,0 );
  2894.      errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  2895.      return ERROR;
  2896.      }
  2897.     
  2898.     /*
  2899.      * init root directory parameters in accordance with
  2900.      * volume FAT version
  2901.      */
  2902.     if( pVolDesc->fatType == FAT32 ) /* FAT32 */
  2903.      {
  2904.      DBG_MSG( 10, "FAT32 n", 0,0,0,0,0,0,0,0 );
  2905.      /*
  2906.       * init root directory descriptor.
  2907.       * Get root directory start cluster number
  2908.       */
  2909.      pDirDesc->rootStartClust =
  2910.      DISK_TO_VX_32( bootSec + DOS32_BOOT_ROOT_START_CLUST );
  2911.      if( pDirDesc->rootStartClust < 2 )
  2912.          {
  2913.          ERR_MSG( 1, "Malformed volume format (FAT32: rootStartClust "
  2914.      " = %u)n", pDirDesc->rootStartClust, 0,0,0,0,0 );
  2915.          errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  2916.          return ERROR;
  2917.          }
  2918.      pDirDesc->dirDesc.rootStartSec  = 0;
  2919.      pDirDesc->dirDesc.rootNSec  = 0;
  2920.      pDirDesc->rootMaxEntries = (u_int)(-1); /* not restricted */
  2921.      }
  2922.     else /* FAT12/FAT16 */
  2923.      {
  2924.      /*
  2925.       * init root directory descriptor.
  2926.       * Get number of entries-per-root directory
  2927.       */
  2928.      pDirDesc->rootMaxEntries =
  2929.      DISK_TO_VX_16( bootSec  + DOS_BOOT_MAX_ROOT_ENTS);
  2930.      if( pDirDesc->rootMaxEntries == 0 )
  2931.          {
  2932.          ERR_MSG( 1, "Malformed volume format (FAT12/16: "
  2933.      "rootMaxEntries = 0)n", 0,0,0,0,0,0 );
  2934.          errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  2935.          return ERROR;
  2936.          }
  2937.     
  2938. pDirDesc->rootStartClust = 0; /* don't change this 0 ! */
  2939.      /* it is important while */
  2940.      /* creating subdir in root */
  2941. /* SPR#34704 This operation must round up. */
  2942. pDirDesc->dirDesc.rootNSec = 
  2943.         (((pDirDesc->rootMaxEntries * pDeDesc->dirEntSize) + 
  2944.           (pVolDesc->bytesPerSec - 1)) / pVolDesc->bytesPerSec);
  2945.     
  2946.      /* root directory resides ahead regular data area */
  2947.     
  2948.      pDirDesc->dirDesc.rootStartSec = pVolDesc->dataStartSec;
  2949.      pVolDesc->dataStartSec += pDirDesc->dirDesc.rootNSec;
  2950.      }
  2951.     
  2952.     /* init root directory last modification time */
  2953.     
  2954.     pDirDesc->rootModifTime = time( NULL );
  2955.     
  2956.     /* fill functions pointers */
  2957.     
  2958.     pDirDesc->dirDesc.pathLkup = dosVDirPathLkup;
  2959.     pDirDesc->dirDesc.readDir = dosVDirReaddir;
  2960.     pDirDesc->dirDesc.updateEntry = dosVDirUpdateEntry;
  2961.     pDirDesc->dirDesc.dateGet = dosVDirDateGet;
  2962.     pDirDesc->dirDesc.volLabel = dosVDirVolLabel;
  2963.     pDirDesc->dirDesc.nameChk = dosVDirNameChk;
  2964.     pDirDesc->dirDesc.volUnmount = dosVDirVolUnmount;
  2965.     pDirDesc->dirDesc.show = dosVDirShow;
  2966.     /* init long name buffers and semaphore */
  2967.     
  2968.     if (pDirDesc->nameBuf == NULL)
  2969.      {
  2970.      pDirDesc->nameBuf = KHEAP_ALLOC (2 * MAX_VFAT_FULL_DIRENT);
  2971.      if (pDirDesc->nameBuf == NULL)
  2972.     {
  2973.          return ERROR;
  2974.     }
  2975. else
  2976.     {
  2977.     bzero (pDirDesc->nameBuf,  2 * MAX_VFAT_FULL_DIRENT );
  2978.     }
  2979.     
  2980.      pDirDesc->bufSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE);
  2981.      }
  2982.     
  2983.     return OK;
  2984.     }
  2985. /*******************************************************************************
  2986. *
  2987. * dosVDirLibInit - install VFAT directory handler into dosFsLib
  2988. * RETURNS: OK or ERROR if handler installation failed.
  2989. *
  2990. * SEE ALSO: dosFsLib
  2991. *
  2992. * NOMANUAL
  2993. */
  2994. STATUS dosVDirLibInit ( void )
  2995.     {
  2996.     DOS_HDLR_DESC hdlr;
  2997.     
  2998.     hdlr.id = DOS_VDIR_HDLR_ID;
  2999.     hdlr.mountRtn = dosVDirVolMount;
  3000.     hdlr.arg = NULL;
  3001.     
  3002.     return dosFsHdlrInstall( dosDirHdlrsList, &hdlr );
  3003.     } /* dosVDirLibInit() */
  3004. /* End of File */