Fossil

Check-in [1b9893bd]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Make "win32-longpath" the default VFS on win32, eliminating all path limitations (up to ~32767 chars). TODO: eliminate use of the the function _wstati64(), that appears to be the only Win32 function left which cannot handle such long paths. Everything else needed is done.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | win32-longpath
Files: files | file ages | folders
SHA1:1b9893bdc8e8ec9885f3c181752105259885f8ff
User & Date: jan.nijtmans 2013-12-12 09:37:52
Context
2013-12-12
11:16
Bug-fix: didn't compile on win32, and handle extended UNC paths correctly. check-in: da8d516f user: jan.nijtmans tags: win32-longpath
09:37
Make "win32-longpath" the default VFS on win32, eliminating all path limitations (up to ~32767 chars). TODO: eliminate use of the the function _wstati64(), that appears to be the only Win32 function left which cannot handle such long paths. Everything else needed is done. check-in: 1b9893bd user: jan.nijtmans tags: win32-longpath
08:43
Put back 'win32-longpath' VFS as default for Cygwin: Cygwin doesn't suffer from path limitations (at least, not until 4096 chars), so usage of the 'win32' VFS is not reasonable as default. check-in: a7603981 user: jan.nijtmans tags: trunk
2013-12-11
13:00
As it turns out that _wstati64() cannot handled the special "\\?\" prefix, work around that. Otherwise the win32-longpath VFS is quite useless for fossil. Maybe a better solution should be worked out, not using _wstati64() at all. check-in: bb440899 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/db.c.

713
714
715
716
717
718
719
720




721
722
723
724
725
726
727
  int rc;
  sqlite3 *db;

#if defined(__CYGWIN__)
  zDbName = fossil_utf8_to_filename(zDbName);
#endif
  if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
  rc = sqlite3_open(zDbName, &db);




  if( rc!=SQLITE_OK ){
    db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
  sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,







|
>
>
>
>







713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  int rc;
  sqlite3 *db;

#if defined(__CYGWIN__)
  zDbName = fossil_utf8_to_filename(zDbName);
#endif
  if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
  rc = sqlite3_open_v2(
       zDbName, &db,
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       g.zVfsName
  );
  if( rc!=SQLITE_OK ){
    db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
  sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,

Changes to src/login.c.

693
694
695
696
697
698
699

700



701
702
703
704
705
706
707
....
1370
1371
1372
1373
1374
1375
1376


1377


1378
1379
1380
1381
1382
1383
1384
....
1457
1458
1459
1460
1461
1462
1463
1464




1465
1466
1467
1468
1469
1470
1471

  zOtherRepo = db_text(0, 
       "SELECT value FROM config WHERE name='peer-repo-%q'",
       zCode
  );
  if( zOtherRepo==0 ) return 0;  /* No such peer repository */


  rc = sqlite3_open(zOtherRepo, &pOther);



  if( rc==SQLITE_OK ){
    sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
................................................................................
      const char *zLabel = db_column_text(&q, 0);
      db_multi_exec(
         "DELETE FROM config WHERE name GLOB 'peer-*-%q'",
         &zLabel[10]
      );
      continue;
    }


    rc = sqlite3_open_v2(zRepoName, &pPeer, SQLITE_OPEN_READWRITE, 0);


    if( rc!=SQLITE_OK ){
      blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName,
                   sqlite3_errmsg(pPeer), zSuffix);
      nErr++;
      sqlite3_close(pPeer);
      continue;
    }
................................................................................
  }

  /* Make sure the other repository is a valid Fossil database */
  if( file_size(zRepo)<0 ){
    *pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
    return;
  }
  rc = sqlite3_open(zRepo, &pOther);




  if( rc!=SQLITE_OK ){
    *pzErrMsg = mprintf(sqlite3_errmsg(pOther));
  }else{
    rc = sqlite3_exec(pOther, "SELECT count(*) FROM user", 0, 0, pzErrMsg);
  }
  sqlite3_close(pOther);
  if( rc ) return;







>
|
>
>
>







 







>
>
|
>
>







 







|
>
>
>
>







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
....
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
....
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483

  zOtherRepo = db_text(0, 
       "SELECT value FROM config WHERE name='peer-repo-%q'",
       zCode
  );
  if( zOtherRepo==0 ) return 0;  /* No such peer repository */

  rc = sqlite3_open_v2(
       zOtherRepo, &pOther,
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       g.zVfsName
  );
  if( rc==SQLITE_OK ){
    sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
    sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
    sqlite3_busy_timeout(pOther, 5000);
    zSQL = mprintf(
      "SELECT cexpire FROM user"
................................................................................
      const char *zLabel = db_column_text(&q, 0);
      db_multi_exec(
         "DELETE FROM config WHERE name GLOB 'peer-*-%q'",
         &zLabel[10]
      );
      continue;
    }
    rc = sqlite3_open_v2(
         zRepoName, &pPeer,
         SQLITE_OPEN_READWRITE,
         g.zVfsName
    );
    if( rc!=SQLITE_OK ){
      blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName,
                   sqlite3_errmsg(pPeer), zSuffix);
      nErr++;
      sqlite3_close(pPeer);
      continue;
    }
................................................................................
  }

  /* Make sure the other repository is a valid Fossil database */
  if( file_size(zRepo)<0 ){
    *pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
    return;
  }
  rc = sqlite3_open_v2(
       zRepo, &pOther,
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       g.zVfsName
  );
  if( rc!=SQLITE_OK ){
    *pzErrMsg = mprintf(sqlite3_errmsg(pOther));
  }else{
    rc = sqlite3_exec(pOther, "SELECT count(*) FROM user", 0, 0, pzErrMsg);
  }
  sqlite3_close(pOther);
  if( rc ) return;

Changes to src/main.c.

117
118
119
120
121
122
123

124
125
126
127
128
129
130
...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

591
592
593
594
595
596
597
598
599
600
601
602
603
** All global variables are in this structure.
*/
struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */
  char *nameOfExe;        /* Full path of executable. */
  const char *zErrlog;    /* Log errors to this file, if not NULL */
  int isConst;            /* True if the output is unchanging */

  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  int useAttach;          /* True if global_config is attached to repository */
  const char *zConfigDbName;/* Path of the config database. NULL if not open */
  sqlite3_int64 now;      /* Seconds since 1970 */
  int repositoryOpen;     /* True if the main repository database is open */
  char *zRepositoryName;  /* Name of the repository database */
................................................................................
#if defined(_WIN32)
int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
#endif
int main(int argc, char **argv)
#endif
{
  const char *zCmdName = "unknown";
  const char *zVfsName;
  int idx;
  int rc;
  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
  sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
  memset(&g, 0, sizeof(g));
  g.now = time(0);
  g.httpHeader = empty_blob;
................................................................................
  expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
  memset(&g.tcl, 0, sizeof(TclContext));
  g.tcl.argc = g.argc;
  g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
  g.mainTimerId = fossil_timer_start();
  zVfsName = find_option("vfs",0,1);
  if( zVfsName==0 ){
    zVfsName = fossil_getenv("FOSSIL_VFS");
  }
#if defined(_WIN32) || defined(__CYGWIN__)
  if( zVfsName==0 && sqlite3_libversion_number()>=3008001 ){
    zVfsName = "win32-longpath";
  }
#endif

  if( zVfsName ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfsName);
    if( pVfs ){
      sqlite3_vfs_register(pVfs, 1);
    }else{
      fossil_fatal("no such VFS: \"%s\"", zVfsName);
    }
  }
  if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
    zCmdName = "cgi";
    g.isHTTP = 1;
  }else if( g.argc<2 ){
    fossil_print(







>







 







<







 







|
|
|
<

|
|
|

>
|
|



|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
548
549
550
551
552
553
554

555
556
557
558
559
560
561
...
575
576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
** All global variables are in this structure.
*/
struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */
  char *nameOfExe;        /* Full path of executable. */
  const char *zErrlog;    /* Log errors to this file, if not NULL */
  int isConst;            /* True if the output is unchanging */
  const char *zVfsName;   /* The VFS to use for database connections */
  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  int useAttach;          /* True if global_config is attached to repository */
  const char *zConfigDbName;/* Path of the config database. NULL if not open */
  sqlite3_int64 now;      /* Seconds since 1970 */
  int repositoryOpen;     /* True if the main repository database is open */
  char *zRepositoryName;  /* Name of the repository database */
................................................................................
#if defined(_WIN32)
int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
#endif
int main(int argc, char **argv)
#endif
{
  const char *zCmdName = "unknown";

  int idx;
  int rc;
  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
  sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
  memset(&g, 0, sizeof(g));
  g.now = time(0);
  g.httpHeader = empty_blob;
................................................................................
  expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
  memset(&g.tcl, 0, sizeof(TclContext));
  g.tcl.argc = g.argc;
  g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
  g.mainTimerId = fossil_timer_start();
  g.zVfsName = find_option("vfs",0,1);
  if( g.zVfsName==0 ){
    g.zVfsName = fossil_getenv("FOSSIL_VFS");

#if defined(_WIN32) || defined(__CYGWIN__)
    if( g.zVfsName==0 && sqlite3_libversion_number()>=3008001 ){
      g.zVfsName = "win32-longpath";
    }
#endif
  }
  if( g.zVfsName ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
    if( pVfs ){
      sqlite3_vfs_register(pVfs, 1);
    }else{
      fossil_fatal("no such VFS: \"%s\"", g.zVfsName);
    }
  }
  if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
    zCmdName = "cgi";
    g.isHTTP = 1;
  }else if( g.argc<2 ){
    fossil_print(

Changes to src/sqlcmd.c.

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
                          sqlcmd_decompress, 0, 0);
  re_add_sql_func(db);
  g.repositoryOpen = 1;
  g.db = db;
  return SQLITE_OK;
}

static sqlite3_vfs *pDefaultVfs = 0;

/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** If DATABASE is omitted, then the repository that serves the working
................................................................................
** in ways that are unrecoverable.  Be sure you know what you are doing before
** running any SQL commands that modifies the repository database.
*/
void sqlite3_cmd(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);
  /* Determine default VFS and keep it after shutdown */
  pDefaultVfs = sqlite3_vfs_find(0);
  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);
  g.db = 0;
}

/*
** This routine is called by the patched sqlite3 command-line shell in order
** to load the name and database connection for the open Fossil database.
*/
void fossil_open(const char **pzRepoName){
  if( pDefaultVfs ) sqlite3_vfs_register(pDefaultVfs, 1);
  sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit);
  *pzRepoName = g.zRepositoryName;
}







<
<







 







<
<










<



122
123
124
125
126
127
128


129
130
131
132
133
134
135
...
139
140
141
142
143
144
145


146
147
148
149
150
151
152
153
154
155

156
157
158
                          sqlcmd_decompress, 0, 0);
  re_add_sql_func(db);
  g.repositoryOpen = 1;
  g.db = db;
  return SQLITE_OK;
}



/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** If DATABASE is omitted, then the repository that serves the working
................................................................................
** in ways that are unrecoverable.  Be sure you know what you are doing before
** running any SQL commands that modifies the repository database.
*/
void sqlite3_cmd(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);


  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);
  g.db = 0;
}

/*
** This routine is called by the patched sqlite3 command-line shell in order
** to load the name and database connection for the open Fossil database.
*/
void fossil_open(const char **pzRepoName){

  sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit);
  *pzRepoName = g.zRepositoryName;
}

Changes to src/sqlite3.c.

35123
35124
35125
35126
35127
35128
35129
35130

35131
35132
35133
35134




























35135
35136
35137
35138
35139
35140
35141
35142
.....
36059
36060
36061
36062
36063
36064
36065
36066




36067
36068
36069
36070
36071
36072
36073
}
#endif

/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in.  Space to hold the result
** is obtained from malloc and must be freed by the calling
** function.

*/
static void *winConvertFromUtf8Filename(const char *zFilename){
  void *zConverted = 0;
  if( osIsNT() ){




























    zConverted = winUtf8ToUnicode(zFilename);
  }
#ifdef SQLITE_WIN32_HAS_ANSI
  else{
    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
  }
#endif
  /* caller will handle out of memory */
................................................................................
    **       for converting the relative path name to an absolute
    **       one by prepending the data directory and a backslash.
    */
    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
                     sqlite3_data_directory, winGetDirSep(), zRelative);
    return SQLITE_OK;
  }
  zConverted = winConvertFromUtf8Filename(zRelative);




  if( zConverted==0 ){
    return SQLITE_IOERR_NOMEM;
  }
  if( osIsNT() ){
    LPWSTR zTemp;
    nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
    if( nByte==0 ){







|
>




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







 







|
>
>
>
>







35123
35124
35125
35126
35127
35128
35129
35130
35131
35132
35133
35134
35135
35136
35137
35138
35139
35140
35141
35142
35143
35144
35145
35146
35147
35148
35149
35150
35151
35152
35153
35154
35155
35156
35157
35158
35159
35160
35161
35162
35163
35164
35165
35166
35167
35168
35169
35170
35171
.....
36088
36089
36090
36091
36092
36093
36094
36095
36096
36097
36098
36099
36100
36101
36102
36103
36104
36105
36106
}
#endif

/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in.  Space to hold the result
** is obtained from malloc and must be freed by the calling
** function. When running on NT and zFilename is absolute, the
** resulting path is guaranteed to start with "\\?\".
*/
static void *winConvertFromUtf8Filename(const char *zFilename){
  void *zConverted = 0;
  if( osIsNT() ){
    int nChar;
    LPWSTR zWideFilename;

    nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
    if( nChar==0 ){
      return 0;
    }
    zWideFilename = sqlite3MallocZero( (nChar*sizeof(zWideFilename[0]))+12 );
    if( zWideFilename==0 ){
      return 0;
    }
    if( winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) ){
      memcpy(zWideFilename, L"\\\\?\\UNC\\", 16);
      nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename+6,
                                    nChar);
    }else if( winIsDriveLetterAndColon(zFilename) && winIsDirSep(zFilename[2])) {
      memcpy(zWideFilename, L"\\\\?\\", 8);
      nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename+4,
                                    nChar);
      zWideFilename[6] = '\\';
    }else{
      nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
                                    nChar);
    }
    if( nChar==0 ){
      sqlite3_free(zWideFilename);
      zWideFilename = 0;
    }
    zConverted = zWideFilename;
  }
#ifdef SQLITE_WIN32_HAS_ANSI
  else{
    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
  }
#endif
  /* caller will handle out of memory */
................................................................................
    **       for converting the relative path name to an absolute
    **       one by prepending the data directory and a backslash.
    */
    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
                     sqlite3_data_directory, winGetDirSep(), zRelative);
    return SQLITE_OK;
  }
  if( osIsNT() ){
    zConverted = winUtf8ToUnicode(zRelative);
  }else{
    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);;
  }
  if( zConverted==0 ){
    return SQLITE_IOERR_NOMEM;
  }
  if( osIsNT() ){
    LPWSTR zTemp;
    nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
    if( nByte==0 ){

Changes to src/utf8.c.

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204




205
206








207
208
209
210
211
212
213
**
** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
**
*/
void *fossil_utf8_to_filename(const char *zUtf8){
#ifdef _WIN32
  int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
  wchar_t *zUnicode = sqlite3_malloc( nChar * 2 );
  wchar_t *wUnicode = zUnicode;
  if( zUnicode==0 ){
    return 0;
  }
  MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
  /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */
  if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
           && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {




    zUnicode[2] = '\\';
    wUnicode += 3;








  }
  while( *wUnicode != '\0' ){
    if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
      *wUnicode |= 0xF000;
    }else if( *wUnicode == '/' ){
      *wUnicode = '\\';
    }







|




<



>
>
>
>
|

>
>
>
>
>
>
>
>







189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
**
** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
**
*/
void *fossil_utf8_to_filename(const char *zUtf8){
#ifdef _WIN32
  int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
  wchar_t *zUnicode = sqlite3_malloc( (nChar+6) * 2 );
  wchar_t *wUnicode = zUnicode;
  if( zUnicode==0 ){
    return 0;
  }

  /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */
  if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
           && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
    /* Convert to extended path. */
    memcpy(zUnicode, L"\\\\?\\", 8);
    wUnicode += 4;
    MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, wUnicode, nChar);
    wUnicode[2] = '\\';
    wUnicode += 3;
  }else if( (zUtf8[0]=='\\' || zUtf8[0]=='/') &&
      (zUtf8[1]=='\\' || zUtf8[1]=='/') && zUtf8[2]!='?' ) {
    /* Convert to extended UNC path. */
    memcpy(zUnicode, L"\\\\?\\UNC\\", 16);
    wUnicode += 8;
    MultiByteToWideChar(CP_UTF8, 0, zUtf8+2, -1, wUnicode, nChar);
  }else{
    MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, wUnicode, nChar);
  }
  while( *wUnicode != '\0' ){
    if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
      *wUnicode |= 0xF000;
    }else if( *wUnicode == '/' ){
      *wUnicode = '\\';
    }