home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / IMPORT.C < prev    next >
C/C++ Source or Header  |  1993-09-27  |  35KB  |  860 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    i m p o r t . c                                                 */
  3. /*                                                                    */
  4. /*    File name mapping routines for UUPC/extended                    */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*
  18.  *    $Id: import.c 1.9 1993/09/27 04:04:06 ahd Exp $
  19.  *
  20.  *    $Log: import.c $
  21.  *     Revision 1.9  1993/09/27  04:04:06  ahd
  22.  *     Correct creation of pointer to file system name
  23.  *
  24.  *     Revision 1.8  1993/09/26  03:32:27  dmwatt
  25.  *     Use Standard Windows NT error message module
  26.  *
  27.  *     Revision 1.7  1993/09/20  04:38:11  ahd
  28.  *     TCP/IP support from Dave Watt
  29.  *     't' protocol support
  30.  *     OS/2 2.x support
  31.  *
  32.  *     Revision 1.6  1993/09/03  12:54:55  ahd
  33.  *     Add missing endif
  34.  *
  35.  *     Revision 1.5  1993/09/03  12:18:55  dmwatt
  36.  *     Windows NT support for long names on file systems
  37.  *
  38.  *     Revision 1.4  1993/09/02  12:08:17  ahd
  39.  *     HPFS Support
  40.  *
  41.  *     Revision 1.3  1993/04/11  00:31:31  dmwatt
  42.  *     Global edits for year, TEXT, etc.
  43.  *
  44.  * Revision 1.2  1992/11/22  21:06:14  ahd
  45.  * Correct mapping of dos paths with trailing slashes
  46.  *
  47.  */
  48.  
  49. /*--------------------------------------------------------------------*/
  50. /*                        System include files                        */
  51. /*--------------------------------------------------------------------*/
  52.  
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <time.h>
  58.  
  59. #if defined(FAMILYAPI) || defined(__OS2__)
  60. #define INCL_NOPM             // No need to include OS/2 PM info
  61. #define INCL_BASE
  62. #include <os2.h>
  63. #elif defined(WIN32)
  64. #include <windows.h>
  65. #endif
  66.  
  67. /*--------------------------------------------------------------------*/
  68. /*                    UUPC/extended include files                     */
  69. /*--------------------------------------------------------------------*/
  70.  
  71. #include "lib.h"
  72. #include "import.h"
  73. #include "arbmath.h"
  74. #include "hostable.h"
  75. #include "usertabl.h"
  76. #include "security.h"
  77.  
  78. #ifdef WIN32
  79. #include "pnterr.h"
  80. #endif
  81.  
  82. #define MAX_DIGITS 20         /* Number of digits for arb math */
  83.  
  84. /*--------------------------------------------------------------------*/
  85. /*                    Internal function prototypes                    */
  86. /*--------------------------------------------------------------------*/
  87.  
  88. #define min(x,y) (((x) < (y)) ? (x) : (y))
  89.  
  90. currentfile();
  91.  
  92. /*--------------------------------------------------------------------*/
  93. /*                     Local function prototypes                      */
  94. /*--------------------------------------------------------------------*/
  95.  
  96. static void ImportName( char *local,
  97.                         const char *canon,
  98.                         size_t charsetsize,
  99.                         const boolean longname );
  100.  
  101. static boolean advancedFS( const char *path );
  102.  
  103. /*-------------------------------------------------------------------*/
  104. /*                                                                   */
  105. /*   i m p o r t p a t h                                             */
  106. /*                                                                   */
  107. /*   Convert a canonical name to a format the host can handle        */
  108. /*                                                                   */
  109. /*   These routines convert file name between canonical form, which  */
  110. /*   is defined as a 'unix' style pathname, and the MS-DOS all       */
  111. /*   uppercase "xxxxxxxx.xxx" format.                                */
  112. /*                                                                   */
  113. /*   If the canonical name does not have a path, that is the file is */
  114. /*   destined for the local spool directory, we can assume the UNIX  */
  115. /*   name will normally be in a format like this:                    */
  116. /*                                                                   */
  117. /*                                                                   */
  118. /*       X.hostid#######            (Execute files)                  */
  119. /*       C.hostid#######            (Call files)                     */
  120. /*       D.hostid#######            (Data files)                     */
  121. /*                                                                   */
  122. /*   where "hostid" may be most, but not always all, of the local    */
  123. /*   host or remote host (the file came from or is going to) and     */
  124. /*   "######" can be any character valid for the UNIX file system.   */
  125. /*   Note, however, that the routine has to be generic to allow for  */
  126. /*   other file names to be placed in the spool directory without    */
  127. /*   collisions.                                                     */
  128. /*                                                                   */
  129. /*   Avoiding collisions in the spool directory is important; when   */
  130. /*   receiving files with mixed case names longer than 11            */
  131. /*   characters, sooner or later a file name collision will occur.   */
  132. /*                                                                   */
  133. /*   We can also assume that only UUPC will see these names, which   */
  134. /*   means we can transform the name using any method we choose, so  */
  135. /*   long as the UUPC functions opening the file always call         */
  136. /*   importpath, and that importpath is reducible (that is, two      */
  137. /*   calls to importpath with the same argument always yield the     */
  138. /*   same result).  Note that if end user really wanted the file in  */
  139. /*   the spool directory, all he has to do is rename the file-- far  */
  140. /*   better than losing the data because duplicate file names.       */
  141. /*                                                                   */
  142. /*   For these files, we map the name as follows:                    */
  143. /*                                                                   */
  144. /*   0 - If the name is a valid MS-DOS name, use it without changing */
  145. /*                                                                   */
  146. /*   1 - Begin the output name by inserting up to the first eight    */
  147. /*       characters of the remote host name (followed by a slash) as */
  148. /*       a subdirectory name.                                        */
  149. /*                                                                   */
  150. /*   2 - If the input name begins with an uppercase alphabetic       */
  151. /*       character followed by a period, also insert the alphabetic  */
  152. /*       (followed by a slash) to make this a second subdirectory.   */
  153. /*       Then, move the logical start of the input name past the two */
  154. /*       characters.                                                 */
  155. /*                                                                   */
  156. /*   3 - Determine the number of characters the local host and       */
  157. /*       remote hosts have equal to the next characters of the input */
  158. /*       name, up to a maximum of 8, and zero the lower of the two   */
  159. /*       counts.  Then, step past the number of characters of the    */
  160. /*       larger count.                                               */
  161. /*                                                                   */
  162. /*       For example, if the file name is X.keane22222 and the local */
  163. /*       host name is kendra (2 characters match) and the remote     */
  164. /*       host is keane1 (5 characters match), zero the number of     */
  165. /*       characters matched by kendra, and make the new start of the */
  166. /*       file name five characters further (at the first "2").       */
  167. /*                                                                   */
  168. /*   4 - Convert the remaining string using a base conversion, with  */
  169. /*       the input character size being from ascii "#" to ascii "z"  */
  170. /*       (88 characters) to the allowed set of characters in MS-DOS  */
  171. /*       file names (charset, below, 52 characters).                 */
  172. /*                                                                   */
  173. /*   5 - Prepend to the string to be converted the length of the     */
  174. /*       remote host added to the length of the local host           */
  175. /*       multiplied by 8 (both lengths were computed in step 3,      */
  176. /*       above).  The base conversion is also applied to this        */
  177. /*       "character", we which know will be in the range 1-64.       */
  178. /*                                                                   */
  179. /*   6 - If the string created by steps 4 and 5 exceeds 8            */
  180. /*       characters, insert a period after the eighth character to   */
  181. /*       make it a valid MS-DOS file name.  If the string created by */
  182. /*       steps 4 and 5 exceeds 11 characters, truncate the string by */
  183. /*       using the first eight and last three characters.            */
  184. /*                                                                   */
  185. /*   7 - Append the string created in steps 4 through 6 to the path  */
  186. /*       name created in steps 1 and 2.                              */
  187. /*                                                                   */
  188. /*   If the canonical name has a path, it is destined for an end     */
  189. /*   user, so we should not radically transform it like we do for    */
  190. /*   files in the spool directory.  Thus, if the canonical name has  */
  191. /*   a path, mung the canonical file name as follows:                */
  192. /*                                                                   */
  193. /*   1 - skip any path from the canonical name                       */
  194. /*                                                                   */
  195. /*   2 - copy up to 8 character from the canonical name converting . */
  196. /*       to _ and uppercase to lowercase.                            */
  197. /*                                                                   */
  198. /*   3 - if the name was longer than 8 character copy a . to the     */
  199. /*       host name and then copy the up to three characters from     */
  200. /*       the tail of the canonical name to the host name.            */
  201. /*                                                                   */
  202. /*   Note that this set of rules will cause a collision with names   */
  203. /*   that only differ in case, but leaves the name in a recongizable */
  204. /*   format for the user.                                            */
  205. /*-------------------------------------------------------------------*/
  206.  
  207. void importpath(char *local, char const *canon, char const *remote)
  208. {
  209.    char *s, *out;
  210.    size_t charsetsize;     /* Number of allowed characters in
  211.                               MS-DOS file names                   */
  212.  
  213.    out = local;
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*                       Verify our parameters                        */
  217. /*--------------------------------------------------------------------*/
  218.  
  219.    if ( local == NULL )
  220.       panic();
  221.  
  222.    if ( canon == NULL )
  223.       panic();
  224.  
  225. /*--------------------------------------------------------------------*/
  226. /*                      Define our character set                      */
  227. /*--------------------------------------------------------------------*/
  228.  
  229.     if ( E_charset == NULL )
  230.        E_charset = DOSCHARS;
  231.  
  232.     charsetsize = strlen( E_charset );
  233.  
  234. /*--------------------------------------------------------------------*/
  235. /*                 Determine if spool file directory                  */
  236. /*--------------------------------------------------------------------*/
  237.  
  238.    if ((s = strrchr(canon, '/')) == (char *)NULL)
  239.    {                          /* File for spooling directory, use
  240.                                  internal character set to avoid
  241.                                  collisons                           */
  242.       static size_t range =  UNIX_END_C - UNIX_START_C + 1;
  243.                               /* Determine unique number characters in
  244.                                  the UNIX file names we are mapping  */
  245.  
  246.       size_t remlen = min(HOSTLEN, strlen(remote));
  247.                               /* Length of the remote name passed
  248.                                  in, shortened below to number of
  249.                                  characters matched in name          */
  250.       size_t nodelen = min(HOSTLEN, strlen(E_nodename));
  251.                               /* Length of the local host name,
  252.                                  shortened below to number of
  253.                                  characters matched in name          */
  254.       size_t subscript = 0;   /* Value of UNIX character to be
  255.                                  converted to MS-DOS character set   */
  256.       char *next        = local + remlen;
  257.       char tempname[FILENAME_MAX];
  258.       unsigned char number[MAX_DIGITS];
  259.                               /* Arbitary length number, for base
  260.                                  conversions                        */
  261.  
  262.       boolean longname;
  263.  
  264.       printmsg(4,"importpath: Checking File system for spool directory %s",
  265.                   E_spooldir );
  266.       longname = advancedFS( E_spooldir ) && bflag[B_LONGNAME];
  267.  
  268. /*--------------------------------------------------------------------*/
  269. /*                    Verify we have a remote name                    */
  270. /*--------------------------------------------------------------------*/
  271.  
  272.       if ( remote == NULL )
  273.          panic();
  274.  
  275. /*--------------------------------------------------------------------*/
  276. /*    Put the host name (up to six characters) at the beginning of    */
  277. /*    the MS-DOS file name as a sub-directory name.                   */
  278. /*--------------------------------------------------------------------*/
  279.  
  280.       strncpy(local, remote, remlen);
  281.       *next++ = '/';          /* Add in the sub-directory seperator  */
  282.       s = (char *) canon;     /* Get the beginnging of the UNIX name */
  283.  
  284. /*--------------------------------------------------------------------*/
  285. /*    Files in the spooling directory generally start with "D.",      */
  286. /*    "C.", or "X."; strip off any upper case letter followed by a    */
  287. /*    period into its own directory.                                  */
  288. /*--------------------------------------------------------------------*/
  289.  
  290.       if ((s[0] >= 'A') && (s[0] <= 'Z') && (s[1] == '.'))
  291.       {
  292.          *next++ = *s;        /* Copy the input character            */
  293.          *next++ = '/';       /* Add the sub-directory indicator too */
  294.          s += 2;              /* Step input string past the copied
  295.                                  data                                */
  296.       }
  297.  
  298.       while( remlen > 0 )
  299.       {
  300.          if (equaln(remote,s,remlen))
  301.             break;
  302.          remlen--;
  303.       }
  304.  
  305.       while( nodelen > 0 )
  306.       {
  307.          if (equaln(E_nodename,s,nodelen))
  308.             break;
  309.          nodelen--;
  310.       }
  311.  
  312.       if (nodelen > remlen )
  313.       {
  314.          remlen = 0;
  315.          s += nodelen;
  316.       }
  317.       else {
  318.          nodelen = 0;
  319.          s += remlen;
  320.       }
  321.  
  322.       *next  = '\0';          /* Terminate first part of host string */
  323.  
  324. /*--------------------------------------------------------------------*/
  325. /*       Create a binary number which represents our file name        */
  326. /*--------------------------------------------------------------------*/
  327.  
  328.       for (subscript = 0; subscript < MAX_DIGITS; subscript++ )
  329.          number[subscript] = 0;  /* Initialize number to zero        */
  330.  
  331.       add(number, nodelen + remlen * HOSTLEN, MAX_DIGITS);
  332.                                  /* Append host name info to the
  333.                                     front of the converted string    */
  334.  
  335.       while( (*s != '\0') && (*number == '\0'))
  336.       {
  337.          mult(number, range, MAX_DIGITS); /* Shift the number over   */
  338.          add(number, *s++  - UNIX_START_C , MAX_DIGITS);
  339.                                           /* Add in new low order    */
  340.       } /* while */
  341.  
  342. /*-------------------------------------------------------------------*/
  343. /*   We now have stripped off the leading x. and host name, if any;  */
  344. /*   now, convert the remaining characters in the name by doing a    */
  345. /*   range to charset base conversion.                               */
  346. /*-------------------------------------------------------------------*/
  347.  
  348.       out = &tempname[FILENAME_MAX];
  349.       *--out = '\0';          /* Terminate the string we will build  */
  350.  
  351. /*--------------------------------------------------------------------*/
  352. /*         Here's the loop to actually do the base conversion         */
  353. /*--------------------------------------------------------------------*/
  354.  
  355.       while(adiv( number, charsetsize, &subscript, MAX_DIGITS))
  356.             *--out = E_charset[ subscript ];
  357.  
  358. /*--------------------------------------------------------------------*/
  359. /*    The conversion is done; now squeeze it into an 11 character     */
  360. /*    MS-DOS name with period.                                        */
  361. /*--------------------------------------------------------------------*/
  362.  
  363.       ImportName( next, out, charsetsize, longname );
  364.  
  365.    }
  366.    else {         /* Not file for spooling directory, convert it  */
  367.  
  368.       char *in = (char *) canon;
  369.       boolean longname ;
  370.  
  371.       printmsg(4,"importpath: Checking file system for file %s",
  372.                   canon );
  373.       longname = advancedFS( canon );
  374.  
  375.       if ( ValidDOSName( canon, longname ))
  376.       {
  377.          strcpy( local, canon );
  378.          return;
  379.       }
  380.  
  381. /*--------------------------------------------------------------------*/
  382. /*      Handle leading drive letter (ignore it, assuming valid)       */
  383. /*--------------------------------------------------------------------*/
  384.  
  385.       if ( isalpha( *in ) && (in[1] == ':'))
  386.       {
  387.          *out++ = *in++;      /* The drive letter                    */
  388.          *out++ = *in++;      /* The colon making it a driver letter */
  389.       } /* if */
  390.  
  391.       if ( *in == '/' )       /* Absolute path name?                 */
  392.          *out++ = *in++;      /* Yes, step past it                   */
  393.  
  394.       while( *in == '/')      /* Additional slashes?                 */
  395.          in++;                /* Skip them,  they mean nothing       */
  396.  
  397.       s = strchr( in, '/' );  /* Get end of next path segment        */
  398.  
  399. /*--------------------------------------------------------------------*/
  400. /*              Now convert each simple name in the path              */
  401. /*--------------------------------------------------------------------*/
  402.  
  403.       while ( *in )
  404.       {
  405.          if ( s != NULL )
  406.             *s = '\0';        /* Truncate input string to simple name */
  407.  
  408.          ImportName( out, in , charsetsize, longname );
  409.  
  410.          if ( s == NULL )
  411.             break;
  412.          out = out + strlen( out );
  413.          *out++ = *s++ = '/'; /* Restore path to input and output    */
  414.          in = s;              /* Remember start of this simple name  */
  415.          while( *in == '/')   /* Additional slashes?                 */
  416.             in++;             /* Skip them,  they mean nothing       */
  417.          s = strchr( in , '/' );
  418.       }
  419.  
  420.    } /* else */
  421.  
  422.    printmsg( 3, "ImportPath: Mapped %s to %s", canon, local );
  423.  
  424. } /*importpath*/
  425.  
  426. /*--------------------------------------------------------------------*/
  427. /*    I m p o r t N a m e                                             */
  428. /*                                                                    */
  429. /*    Translate a simple DOS name without the path                    */
  430. /*--------------------------------------------------------------------*/
  431.  
  432. static void ImportName( char *local,
  433.                         const char *canon,
  434.                         size_t charsetsize,
  435.                         const boolean longname )
  436. {
  437.  
  438.    char *in = (char *) canon;
  439.    char *out = local;
  440.    size_t len = strlen( canon );
  441.    size_t column;
  442.    char *best_period = NULL;     /* Assume no prince charming         */
  443.  
  444.    if ( strchr(canon,'/') != NULL )
  445.    {
  446.       printmsg(0,"ImportName: Parameter error, not simple name: %s",
  447.             canon);
  448.       panic();
  449.    }
  450.  
  451.    if ( len == 0 )
  452.    {
  453.       printmsg(0,"ImportName: Parameter error, zero length input");
  454.       panic();
  455.    }
  456.  
  457. /*--------------------------------------------------------------------*/
  458. /*                 If a valid DOS name, use it as-is                  */
  459. /*--------------------------------------------------------------------*/
  460.  
  461.    if (ValidDOSName( canon, longname ))
  462.    {
  463.       strcpy( local, canon );
  464.       return;
  465.    }
  466.  
  467. /*--------------------------------------------------------------------*/
  468. /*    If the dataset name has a period, use it.  The rule we          */
  469. /*    follow is use the last period in the second through ninth       */
  470. /*    characters, otherwise use the last period in the dataset        */
  471. /*    name with the exception of leading period.                      */
  472. /*                                                                    */
  473. /*    In any case, we only copy up to eight characters for the        */
  474. /*    dataset name and up to three characters for the extension.      */
  475. /*--------------------------------------------------------------------*/
  476.  
  477.    for ( column = 1; (column < 9) && (in[column] != '\0') ; column++)
  478.    {
  479.       if ( in[column] == '.')
  480.       {
  481.          strncpy( out, in, column + 5 );
  482.                                     /* Period, 3 char extension,
  483.                                        and terminating \0            */
  484.          best_period = &out[column];/* Remember output location of
  485.                                        period in name                */
  486.  
  487.          if ( len > (column + 4) )  /* Need to trunc extension to 3? */
  488.             strcpy( out + column + 1, in + len - 3 ); /* Yes         */
  489.  
  490.          break;
  491.       } /*if */
  492.    }  /* if */
  493.  
  494. /*--------------------------------------------------------------------*/
  495. /*    No period in the first eight characters, search the rest of     */
  496. /*    the name for the last period (unless period is very last        */
  497. /*    character in the string).                                       */
  498. /*--------------------------------------------------------------------*/
  499.  
  500.    if ( best_period == NULL )
  501.    {
  502.  
  503.       strncpy( out , in , 8);
  504.       best_period = strrchr( in+1 , '.');
  505.  
  506.       if ( (best_period != NULL) && (best_period[1] != '\0') )
  507.       {
  508.          strncpy( &out[8], best_period, 4 ); /* Plus period and 3
  509.                                                 in extension         */
  510.  
  511.          if ( strlen( best_period) > 4 )     /* Long Extension?      */
  512.             out[12] = '\0';                  /* Yes --> Truncate     */
  513.  
  514.       } /* if */
  515.       else {                  /* No periods at all, generate one
  516.                                  if needed for long name          */
  517.  
  518.          if ( len > 8 )
  519.          {
  520.             out[8] = '.';
  521.             strcpy(&out[9], in + max(8,(len - 3))  );
  522.          } /* if ( len > 9 ) */
  523.  
  524.       } /* else */
  525.  
  526.       best_period = &out[8];              /* Remember location of
  527.                                              period, okay if past
  528.                                              end of string           */
  529.  
  530.    } /* if ( best_period == NULL ) */
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*                Now, clean up any invalid characters                */
  534. /*--------------------------------------------------------------------*/
  535.  
  536.    if ( out[ strlen( out ) - 1 ] == '.' ) /* Trailing period?        */
  537.       out[ strlen( out ) - 1 ] = '\0';    /* Just truncate string    */
  538.  
  539.    while( *out != '\0')
  540.    {
  541.       int c ;
  542.       if ( isupper( *out ))
  543.          c = tolower( *out );
  544.       else
  545.          c = *out;
  546.  
  547.       if ((out != best_period) && (strchr( E_charset, c ) == NULL ))
  548.       {
  549.          if ( c > 'z' )
  550.             c -= 62;
  551.          else if ( c > 'Z' )
  552.             c -= 36;
  553.          else if ( c > '9' )
  554.             c -= 10;
  555.          *out = E_charset[ (c - UNIX_START_C) % charsetsize ];
  556.       }
  557.  
  558.       out++;                    /* Step to next character         */
  559.    } /* while( *out != '\0') */
  560.  
  561. /*--------------------------------------------------------------------*/
  562. /*                   Report our results and return                    */
  563. /*--------------------------------------------------------------------*/
  564.  
  565.    printmsg( 5,
  566.             "ImportName: Mapped %s to %s", canon, local );
  567.  
  568. } /* ImportName */
  569.  
  570. /*--------------------------------------------------------------------*/
  571. /*    V a l i d D O S N a m e                                         */
  572. /*                                                                    */
  573. /*    Validate an MS-DOS file name                                    */
  574. /*--------------------------------------------------------------------*/
  575.  
  576. boolean ValidDOSName( const char *s,
  577.                       const boolean longname )
  578. {
  579.    char *ptr;
  580.    size_t len = strlen ( s );
  581.    char tempname[FILENAME_MAX];
  582.  
  583.    static char *longCharSet = NULL;
  584.  
  585. /*--------------------------------------------------------------------*/
  586. /*                      Define our character set                      */
  587. /*--------------------------------------------------------------------*/
  588.  
  589.    if ( E_charset == NULL )
  590.       E_charset = DOSCHARS;
  591.  
  592.    if ( longname )
  593.    {
  594.  
  595. #if defined(FAMILYAPI) || defined(__OS2__)
  596.  
  597. /*--------------------------------------------------------------------*/
  598. /*       Ask OS/2 if the file name is okay.  Because the invoked      */
  599. /*       function accepts wildcards, we pre-test for them and reject  */
  600. /*       them as needed.                                              */
  601. /*--------------------------------------------------------------------*/
  602.  
  603.       if ((strchr( s, '*') == NULL ) && (strchr( s, '?') == NULL))
  604.       {
  605.  
  606. #ifdef __OS2__
  607.          APIRET result = DosQPathInfo( (PSZ) s,
  608.                                        FIL_QUERYFULLNAME,
  609.                                        (PVOID) tempname,
  610.                                        sizeof tempname );
  611. #else
  612.          USHORT result = DosQPathInfo( (PSZ) s,
  613.                                        FIL_NAMEISVALID,
  614.                                        (PBYTE) tempname,
  615.                                        sizeof tempname,
  616.                                        0 );
  617.  
  618. #endif
  619.          if ( result == 0 )
  620.             return TRUE;
  621.  
  622.          printmsg(2,
  623.                   "ValidDOSName: Invalid name %s, syntax error code %d",
  624.                    s,
  625.                    (int) result);
  626.  
  627.       } /* if */
  628.  
  629. #endif
  630.  
  631.       if ( longCharSet == NULL )
  632.       {
  633.          *tempname = '.';
  634.          longCharSet = newstr(strcpy( tempname + 1, E_charset ));
  635.       }
  636.  
  637.       if (strspn(s, longCharSet) == len)
  638.       {
  639.          printmsg(9,"ValidDOSName: \"%s\" is valid long name", s);
  640.          return TRUE;
  641.       }
  642.  
  643.    } /* if ( longname ) */
  644.  
  645. /*--------------------------------------------------------------------*/
  646. /*                 Name must be 12 characters or less                 */
  647. /*--------------------------------------------------------------------*/
  648.  
  649.    if (len > 12)
  650.       return FALSE;
  651.  
  652.    strcpy( tempname, s);      /* Make a temp copy we can alter       */
  653.  
  654. /*--------------------------------------------------------------------*/
  655. /*    Simple file name without extension must be eight chracters      */
  656. /*    or less                                                         */
  657. /*--------------------------------------------------------------------*/
  658.  
  659.    ptr = strrchr(tempname, '.');
  660.    if (ptr == NULL)
  661.    {
  662.       if (len > 8)
  663.          return FALSE;
  664.    }
  665.  
  666. /*--------------------------------------------------------------------*/
  667. /*          Period must be in second through ninth character          */
  668. /*--------------------------------------------------------------------*/
  669.  
  670.    else {
  671.       if ((ptr == tempname) || (ptr > &tempname[8]))
  672.          return FALSE;
  673.  
  674. /*--------------------------------------------------------------------*/
  675. /*             Extension must be three characters or less             */
  676. /*--------------------------------------------------------------------*/
  677.  
  678.       if ( strlen( ptr ) > 4) /* Three characters plus the period?   */
  679.          return FALSE;        /* No --> Too much                     */
  680.  
  681. /*--------------------------------------------------------------------*/
  682. /*                          Only one period                           */
  683. /*--------------------------------------------------------------------*/
  684.  
  685.       if (ptr != strchr(tempname, '.'))
  686.          return FALSE;
  687.    } /* else */
  688.  
  689. /*--------------------------------------------------------------------*/
  690. /*                Must only be valid MS-DOS characters                */
  691. /*--------------------------------------------------------------------*/
  692.  
  693.    strlwr( tempname );        /* Map into our desired character set  */
  694.    if ( ptr != NULL )
  695.       *ptr = 'x';             /* We've already accounted for the
  696.                                  period, don't let it ruin our day   */
  697.  
  698.    if (strspn(tempname, E_charset ) == len)
  699.    {
  700.       printmsg(9,"ValidDOSName: \"%s\" is valid", s);
  701.       return TRUE;
  702.    }
  703.    else
  704.       return FALSE;
  705.  
  706. } /* ValidateDOSName */
  707.  
  708. #if defined(FAMILYAPI) || defined( __OS2__ )
  709.  
  710. /*--------------------------------------------------------------------*/
  711. /*       a d v a n c e d F S                       (OS/2 version)     */
  712. /*                                                                    */
  713. /*       Determine if a file system is advanced (supports better than */
  714. /*       8.3 file names)                                              */
  715. /*--------------------------------------------------------------------*/
  716.  
  717. static boolean advancedFS( const char *path )
  718. {
  719.    char buf[BUFSIZ];             // One generic large buffer
  720.  
  721. #ifdef __OS2__
  722.    ULONG bufSize = sizeof buf;
  723.    FSQBUFFER2 *dataBuffer = (FSQBUFFER2 *) buf;
  724.    ULONG  result;
  725. #else
  726.    SHORT bufSize = sizeof buf;
  727.    FSQBUFFER *dataBuffer = (FSQBUFFER *) buf;
  728.    USHORT result;
  729. #endif
  730.  
  731. /*--------------------------------------------------------------------*/
  732. /*                  Get the drive letter to process                   */
  733. /*--------------------------------------------------------------------*/
  734.  
  735.    char driveInfo[3];
  736.    char *fileSystem;
  737.  
  738.    if ( isalpha( *path ) && (path[1] == ':') )
  739.       strncpy( driveInfo, path, 2 );
  740.    else
  741.       strncpy( driveInfo, E_cwd, 2 );
  742.  
  743.    driveInfo[ sizeof(driveInfo) - 1 ] = '\0';   // Terminate string data
  744.  
  745. /*--------------------------------------------------------------------*/
  746. /*      Query the drive (both 1.x and 2.x calls are supported).       */
  747. /*--------------------------------------------------------------------*/
  748.  
  749. #ifdef __OS2__
  750.    result = DosQueryFSAttach( (PSZ) driveInfo,
  751.                           1,
  752.                           FSAIL_QUERYNAME,
  753.                           dataBuffer,
  754.                           &bufSize );
  755.    fileSystem = (char *) (dataBuffer->szFSDName + dataBuffer->cbName);
  756. #else
  757.    result = DosQFSAttach( driveInfo,
  758.                           0,
  759.                           FSAIL_QUERYNAME,
  760.                           (PBYTE) buf,
  761.                           &bufSize,
  762.                           0L );
  763.    fileSystem = (char *) (dataBuffer->szFSDName + dataBuffer->cbName - 1);
  764. #endif
  765.  
  766.    if ( result != 0 )
  767.    {
  768.       printmsg(0, "advancedFS: Unable to query file system for %s, error = %d",
  769.                   driveInfo,
  770.                   (int)  result );
  771.       return FALSE;
  772.    }
  773.  
  774.  
  775.    printmsg(4,"advancedFS: File system %d, name \"%s\", FS name \"%s\"",
  776.                (int) dataBuffer->iType,
  777.                dataBuffer->szName,
  778.                fileSystem );
  779.  
  780.    if (equal( fileSystem, "FAT"))
  781.       return FALSE;
  782.    else
  783.       return TRUE;
  784.  
  785. } /* advancedFS */
  786.  
  787. #elif WIN32
  788.  
  789. /*--------------------------------------------------------------------*/
  790. /*       a d v a n c e d F S                    (Window NT version)   */
  791. /*                                                                    */
  792. /*       Determine if a file system is advanced (supports better than */
  793. /*       8.3 file names)                                              */
  794. /*--------------------------------------------------------------------*/
  795.  
  796. static boolean advancedFS( const char *path )
  797. {
  798.    char driveInfo[4];
  799.    char fsType[5];
  800.    BOOL result;
  801.    char *shareNameEnd;
  802.  
  803.    if ( !path || *path == '\0' ) {       // use CWD
  804.       strncpy( driveInfo, E_cwd, 3);
  805.       driveInfo[3] = '\0';
  806.    }
  807.    else if ( isalpha( *path ) && (path[1] == ':') )
  808.    {                                   // It's a local drive
  809.  
  810.       printmsg(5, "advancedFS: it's a drive letter");
  811.       strncpy( driveInfo, path, 3 );
  812.       driveInfo[3] = '\0';          // Terminate drive string data
  813.  
  814.    }
  815.    else
  816.       return FALSE;
  817.  
  818. /*--------------------------------------------------------------------*/
  819. /*            We've got the drive letter, query its status            */
  820. /*--------------------------------------------------------------------*/
  821.  
  822.    result = GetVolumeInformation(driveInfo, NULL, 0, NULL, NULL,
  823.          NULL, fsType, 5);
  824.  
  825.    if ( !result )
  826.    {
  827.       DWORD dwError = GetLastError();
  828.       printmsg(0, "advancedFS: Unable to query file system for %s", driveInfo);
  829.       printNTerror("GetVolumeInformation", dwError);
  830.       panic();
  831.    }
  832.  
  833.    printmsg(4,"advancedFS: File system for \"%s\" has name \"%s\"",
  834.                driveInfo,
  835.                fsType );
  836.  
  837.    return strcmp( fsType, "FAT");
  838.  
  839. } /* advancedFS for WIN32 */
  840.  
  841. #else
  842.  
  843. /*--------------------------------------------------------------------*/
  844. /*       a d v a n c e d F S                          (DOS version)   */
  845. /*                                                                    */
  846. /*       Determine if a file system is advanced (supports better than */
  847. /*       8.3 file names)                                              */
  848. /*--------------------------------------------------------------------*/
  849.  
  850. #ifdef __TURBOC__
  851. #pragma argsused
  852. #endif
  853.  
  854. static boolean advancedFS( const char *path )
  855. {
  856.    return FALSE;                 // DOS is always dumb on file systems!
  857. } /* advancedFS for MS-DOS */
  858.  
  859. #endif
  860.