Changes On Branch ticket-d17d6e5b17
Not logged in

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

Changes In Branch ticket-d17d6e5b17 Excluding Merge-Ins

This is equivalent to a diff from a98467b661 to fdd51b617c

2013-02-18
13:46
Fixed ticket [5df2715635b99bd46a] (check-in count mismatch). check-in: b27c0d6d3f user: stephan tags: trunk
10:03
New function fossil_utf8_to_filename, such that fossil_unicode_to_utf8/fossil_utf8_to_unicode/fossil_unicode_free are not used on UNIX/MAC any more: On UNIX those 3 functions were only no-ops, but this allows to re-implement then for real unicode <-> utf-8 conversions. There is an "#ifdef _WIN32" around those 3 functions and 2 more (fossil_mbcs_to... Leaf check-in: cc3976fd30 user: jan.nijtmans tags: fossil_utf8_to_filename
08:30
merge trunk Leaf check-in: fdd51b617c user: jan.nijtmans tags: ticket-d17d6e5b17
2013-02-17
21:37
merge trunk Leaf check-in: fdf9050c4b user: jan.nijtmans tags: improve_commit_warning
14:47
More simplification in UTF-16 bom detection Leaf check-in: 1e70f211f9 user: jan.nijtmans tags: utf16Bom
14:43
Remove two unused variables check-in: a98467b661 user: jan.nijtmans tags: trunk
2013-02-16
14:12
Limit the complexity of the diff display on check-in information pages. check-in: 4f95ea8c56 user: drh tags: trunk
2013-01-28
13:09
win32: files with invalid chars were not deleted sometimes with "fossil update" check-in: d9aa512e20 user: jan.nijtmans tags: ticket-d17d6e5b17

Changes to src/file.c.

    62     62   
    63     63   /*
    64     64   ** Fill stat buf with information received from stat() or lstat().
    65     65   ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
    66     66   **
    67     67   */
    68     68   static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){
           69  +  int rc;
    69     70   #if !defined(_WIN32)
           71  +  char *zMbcs = fossil_utf8_to_filename(zFilename);
    70     72     if( isWd && g.allowSymlinks ){
    71         -    return lstat(zFilename, buf);
           73  +    rc = lstat(zMbcs, buf);
    72     74     }else{
    73         -    return stat(zFilename, buf);
           75  +    rc = stat(zMbcs, buf);
    74     76     }
    75     77   #else
    76         -  int rc = 0;
    77         -  wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
           78  +  wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
    78     79     rc = _wstati64(zMbcs, buf);
    79         -  fossil_unicode_free(zMbcs);
           80  +#endif
           81  +  fossil_filename_free(zMbcs);
    80     82     return rc;
    81         -#endif
    82     83   }
    83     84   
    84     85   /*
    85     86   ** Fill in the fileStat variable for the file named zFilename.
    86     87   ** If zFilename==0, then use the previous value of fileStat if
    87     88   ** there is a previous value.
    88     89   **
................................................................................
   301    302   
   302    303   
   303    304   /*
   304    305   ** Wrapper around the access() system call.
   305    306   */
   306    307   int file_access(const char *zFilename, int flags){
   307    308   #ifdef _WIN32
   308         -  wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
          309  +  wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
   309    310     int rc = _waccess(zMbcs, flags);
   310         -  fossil_unicode_free(zMbcs);
   311    311   #else
   312         -  int rc = access(zFilename, flags);
          312  +  char *zMbcs = fossil_utf8_to_filename(zFilename);
          313  +  int rc = access(zMbcs, flags);
   313    314   #endif
          315  +  fossil_filename_free(zMbcs);
   314    316     return rc;
   315    317   }
   316    318   
   317    319   /*
   318    320   ** Find an unused filename similar to zBase with zSuffix appended.
   319    321   **
   320    322   ** Make the name relative to the working directory if relFlag is true.
................................................................................
   400    402   */
   401    403   void file_set_mtime(const char *zFilename, i64 newMTime){
   402    404   #if !defined(_WIN32)
   403    405     struct timeval tv[2];
   404    406     memset(tv, 0, sizeof(tv[0])*2);
   405    407     tv[0].tv_sec = newMTime;
   406    408     tv[1].tv_sec = newMTime;
   407         -  utimes(zFilename, tv);
          409  +  char *zMbcs = fossil_utf8_to_filename(zFilename);
          410  +  utimes(zMbcs, tv);
   408    411   #else
   409    412     struct _utimbuf tb;
   410         -  wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
          413  +  wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
   411    414     tb.actime = newMTime;
   412    415     tb.modtime = newMTime;
   413    416     _wutime(zMbcs, &tb);
   414         -  fossil_unicode_free(zMbcs);
   415    417   #endif
          418  +  fossil_filename_free(zMbcs);
   416    419   }
   417    420   
   418    421   /*
   419    422   ** COMMAND: test-set-mtime
   420    423   **
   421    424   ** Usage: %fossil test-set-mtime FILENAME DATE/TIME
   422    425   **
................................................................................
   439    442   }
   440    443   
   441    444   /*
   442    445   ** Delete a file.
   443    446   */
   444    447   void file_delete(const char *zFilename){
   445    448   #ifdef _WIN32
   446         -  wchar_t *z = fossil_utf8_to_unicode(zFilename);
          449  +  wchar_t *z = fossil_utf8_to_filename(zFilename);
   447    450     _wunlink(z);
   448         -  fossil_unicode_free(z);
   449    451   #else
          452  +  char *z = fossil_utf8_to_filename(zFilename);
   450    453     unlink(zFilename);
   451    454   #endif
          455  +  fossil_filename_free(z);
   452    456   }
   453    457   
   454    458   /*
   455    459   ** Create the directory named in the argument, if it does not already
   456    460   ** exist.  If forceFlag is 1, delete any prior non-directory object
   457    461   ** with the same name.
   458    462   **
................................................................................
   462    466     int rc = file_wd_isdir(zName);
   463    467     if( rc==2 ){
   464    468       if( !forceFlag ) return 1;
   465    469       file_delete(zName);
   466    470     }
   467    471     if( rc!=1 ){
   468    472   #if defined(_WIN32)
   469         -    int rc;
   470         -    wchar_t *zMbcs = fossil_utf8_to_unicode(zName);
          473  +    wchar_t *zMbcs = fossil_utf8_to_filename(zName);
   471    474       rc = _wmkdir(zMbcs);
   472         -    fossil_unicode_free(zMbcs);
   473         -    return rc;
   474    475   #else
   475         -    return mkdir(zName, 0755);
          476  +    char *zMbcs = fossil_utf8_to_filename(zName);
          477  +    rc = mkdir(zName, 0755);
   476    478   #endif
          479  +    fossil_filename_free(zMbcs);
          480  +    return rc;
   477    481     }
   478    482     return 0;
   479    483   }
   480    484   
   481    485   /*
   482    486   ** Return true if the filename given is a valid filename for
   483    487   ** a file in a repository.  Valid filenames follow all of the
   484    488   ** following rules:
   485    489   **
   486    490   **     *  Does not begin with "/"
   487    491   **     *  Does not contain any path element named "." or ".."
   488         -**     *  Does not contain any of these characters in the path: "\"
   489    492   **     *  Does not end with "/".
   490    493   **     *  Does not contain two or more "/" characters in a row.
   491    494   **     *  Contains at least one character
   492    495   **
   493    496   ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
   494    497   ** true.  If bStrictUtf8 is false, invalid UTF8 characters are silently
   495    498   ** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
................................................................................
   545    548             return 0;
   546    549           }
   547    550           if( (z[++i]&0xc0)!=0x80 ){
   548    551             /* Invalid second continuation byte */
   549    552             return 0;
   550    553           }
   551    554         }
   552         -    }else if( bStrictUtf8 && (c=='\\') ){
   553         -      return 0;
   554    555       }
   555    556       if( c=='/' ){
   556    557         if( z[i+1]=='/' ) return 0;
   557    558         if( z[i+1]=='.' ){
   558    559           if( z[i+2]=='/' || z[i+2]==0 ) return 0;
   559    560           if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
   560    561         }
................................................................................
   578    579     *pJ = i-1;
   579    580     return 1;
   580    581   }
   581    582   
   582    583   /*
   583    584   ** Simplify a filename by
   584    585   **
   585         -**  * Convert all \ into / on windows
          586  +**  * Convert all \ into / on windows and cygwin
   586    587   **  * removing any trailing and duplicate /
   587    588   **  * removing /./
   588    589   **  * removing /A/../
   589    590   **
   590    591   ** Changes are made in-place.  Return the new name length.
   591    592   ** If the slash parameter is non-zero, the trailing slash, if any,
   592    593   ** is retained.
   593    594   */
   594    595   int file_simplify_name(char *z, int n, int slash){
   595    596     int i, j;
   596    597     if( n<0 ) n = strlen(z);
   597    598   
   598         -  /* On windows convert all \ characters to / */
   599         -#if defined(_WIN32)
          599  +  /* On windows/cygwin convert all \ characters to / */
          600  +#if defined(_WIN32) || defined(__CYGWIN__)
   600    601     for(i=0; i<n; i++){
   601    602       if( z[i]=='\\' ) z[i] = '/';
   602    603     }
   603    604   #endif
   604    605   
   605    606     /* Removing trailing "/" characters */
   606    607     if( !slash ){
................................................................................
   703    704   
   704    705   /*
   705    706   ** Return true if zPath is an absolute pathname.  Return false
   706    707   ** if it is relative.
   707    708   */
   708    709   int file_is_absolute_path(const char *zPath){
   709    710     if( zPath[0]=='/'
   710         -#if defined(_WIN32)
          711  +#if defined(__CYGWIN__)
          712  +      || zPath[0]=='\\'
          713  +#elif defined(_WIN32)
   711    714         || zPath[0]=='\\'
   712    715         || (strlen(zPath)>3 && zPath[1]==':'
   713    716              && (zPath[2]=='\\' || zPath[2]=='/'))
   714    717   #endif
   715    718     ){
   716    719       return 1;
   717    720     }else{
................................................................................
  1135   1138   
  1136   1139   /*
  1137   1140   ** Like fopen() but always takes a UTF8 argument.
  1138   1141   */
  1139   1142   FILE *fossil_fopen(const char *zName, const char *zMode){
  1140   1143   #ifdef _WIN32
  1141   1144     wchar_t *uMode = fossil_utf8_to_unicode(zMode);
  1142         -  wchar_t *uName = fossil_utf8_to_unicode(zName);
         1145  +  wchar_t *uName = fossil_utf8_to_filename(zName);
  1143   1146     FILE *f = _wfopen(uName, uMode);
  1144         -  fossil_unicode_free(uName);
         1147  +  fossil_filename_free(uName);
  1145   1148     fossil_unicode_free(uMode);
  1146   1149   #else
  1147   1150     FILE *f = fopen(zName, zMode);
  1148   1151   #endif
  1149   1152     return f;
  1150   1153   }

Changes to src/rebuild.c.

   839    839     DIR *d;
   840    840     struct dirent *pEntry;
   841    841     Blob aContent; /* content of the just read artifact */
   842    842     static int nFileRead = 0;
   843    843     void *zUnicodePath;
   844    844     char *zUtf8Name;
   845    845   
   846         -  zUnicodePath = fossil_utf8_to_unicode(zPath);
          846  +  zUnicodePath = fossil_utf8_to_filename(zPath);
   847    847     d = opendir(zUnicodePath);
   848    848     if( d ){
   849    849       while( (pEntry=readdir(d))!=0 ){
   850    850         Blob path;
   851    851         char *zSubpath;
   852    852   
   853    853         if( pEntry->d_name[0]=='.' ){
................................................................................
   873    873         fflush(stdout);
   874    874       }
   875    875       closedir(d);
   876    876     }else {
   877    877       fossil_panic("encountered error %d while trying to open \"%s\".",
   878    878                     errno, g.argv[3]);
   879    879     }
   880         -  fossil_unicode_free(zUnicodePath);
          880  +  fossil_filename_free(zUnicodePath);
   881    881   }
   882    882   
   883    883   /*
   884    884   ** COMMAND: reconstruct*
   885    885   **
   886    886   ** Usage: %fossil reconstruct FILENAME DIRECTORY
   887    887   **

Changes to src/utf8.c.

   109    109   
   110    110   /*
   111    111   ** Translate text from the filename character set into
   112    112   ** to precomposed UTF8.  Return a pointer to the translated text.
   113    113   ** Call fossil_filename_free() to deallocate any memory used to store the
   114    114   ** returned pointer when done.
   115    115   */
   116         -char *fossil_filename_to_utf8(const void *zFilename){
          116  +char *fossil_filename_to_utf8(void *zFilename){
   117    117   #if defined(_WIN32)
   118         -  int nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0);
   119         -  char *zUtf = sqlite3_malloc( nByte );
          118  +  int nByte;
          119  +  char *zUtf;
          120  +  WCHAR *wUnicode = zFilename;
          121  +  while( *wUnicode != 0 ){
          122  +    if ( (*wUnicode & 0xFF80) == 0xF000 ){
          123  +      WCHAR converted = (*wUnicode & 0x7F);
          124  +      /* Only really convert it when the resulting char is in the given range*/
          125  +      if ( (converted < 32) || wcschr(L"\"*<>?|:", converted) ){
          126  +        *wUnicode = converted;
          127  +      }
          128  +    }
          129  +    ++wUnicode;
          130  +  }
          131  +  nByte = WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, 0, 0, 0, 0);
          132  +  zUtf = sqlite3_malloc( nByte );
   120    133     if( zUtf==0 ){
   121    134       return 0;
   122    135     }
   123    136     WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
   124    137     return zUtf;
          138  +#elif defined(__CYGWIN__)
          139  +  char *zOut;
          140  +  zOut = fossil_strdup(zFilename);
          141  +  return zOut;
   125    142   #elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
   126    143     char *zIn = (char*)zFilename;
   127    144     char *zOut;
   128    145     iconv_t cd;
   129    146     size_t n, x;
   130    147     for(n=0; zIn[n]>0 && zIn[n]<=0x7f; n++){}
   131    148     if( zIn[n]!=0 && (cd = iconv_open("UTF-8", "UTF-8-MAC"))!=(iconv_t)-1 ){
................................................................................
   147    164       zOut = fossil_strdup(zFilename);
   148    165     }
   149    166     return zOut;
   150    167   #else
   151    168     return (char *)zFilename;  /* No-op on non-mac unix */
   152    169   #endif
   153    170   }
          171  +
          172  +/*
          173  +** Translate UTF8 to unicode for use in filename translations.
          174  +** Return a pointer to the translated text..  Call fossil_filename_free()
          175  +** to deallocate any memory used to store the returned pointer when done.
          176  +**
          177  +** On Windows, characters in the range U+0001 to U+0031 and the
          178  +** characters '"', '*', ':', '<', '>', '?' and '|' are invalid
          179  +** to be used. Therefore, translated those to characters in the
          180  +** (private use area), in the range U+F001 - U+F07F, so those
          181  +** characters never arrive in any Windows API. The filenames might
          182  +** look strange in Windows explorer, but in the cygwin shell
          183  +** everything looks as expected.
          184  +**
          185  +** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
          186  +**
          187  +*/
          188  +void *fossil_utf8_to_filename(const char *zUtf8){
          189  +#ifdef _WIN32
          190  +  WCHAR *zUnicode = fossil_utf8_to_unicode(zUtf8);
          191  +  WCHAR *wUnicode = zUnicode;
          192  +  /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */
          193  +  if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
          194  +           && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
          195  +    zUnicode[2] = '\\';
          196  +    wUnicode += 3;
          197  +  }
          198  +  while( *wUnicode != '\0' ){
          199  +    if ( (*wUnicode < 32) || wcschr(L"\"*<>?|:", *wUnicode) ){
          200  +      *wUnicode |= 0xF000;
          201  +    }else if( *wUnicode == '/' ){
          202  +      *wUnicode = '\\';
          203  +    }
          204  +    ++wUnicode;
          205  +  }
          206  +
          207  +  return zUnicode;
          208  +#elif defined(__CYGWIN__)
          209  +  char *zPath = fossil_strdup(zUtf8);
          210  +  char *p = zPath;
          211  +  while( (*p = *zUtf8++) != 0){
          212  +    if (*p++ == '\\' ) {
          213  +      p[-1] = '/';
          214  +    }
          215  +  }
          216  +  return zPath;
          217  +#elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
          218  +  return fossil_strdup(zUtf8);
          219  +#else
          220  +  return (void *)zUtf8;  /* No-op on unix */
          221  +#endif
          222  +}
   154    223   
   155    224   /*
   156    225   ** Deallocate any memory that was previously allocated by
   157         -** fossil_filename_to_utf8().
          226  +** fossil_filename_to_utf8() or fossil_utf8_to_filename().
   158    227   */
   159         -void fossil_filename_free(char *pOld){
          228  +void fossil_filename_free(void *pOld){
   160    229   #if defined(_WIN32)
   161    230     sqlite3_free(pOld);
   162         -#elif defined(__APPLE__) && !defined(WITHOUT_ICONV)
          231  +#elif (defined(__APPLE__) && !defined(WITHOUT_ICONV)) || defined(__CYGWIN__)
   163    232     fossil_free(pOld);
   164    233   #else
   165    234     /* No-op on all other unix */
   166    235   #endif
   167    236   }
   168    237   
   169    238   /*

Changes to src/vfile.c.

   457    457          "INSERT OR IGNORE INTO sfile(x) SELECT :file"
   458    458          "  WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=:file)"
   459    459       );
   460    460     }
   461    461     depth++;
   462    462   
   463    463     zDir = blob_str(pPath);
   464         -  zNative = fossil_utf8_to_unicode(zDir);
          464  +  zNative = fossil_utf8_to_filename(zDir);
   465    465     d = opendir(zNative);
   466    466     if( d ){
   467    467       while( (pEntry=readdir(d))!=0 ){
   468    468         char *zPath;
   469    469         char *zUtf8;
   470    470         if( pEntry->d_name[0]=='.' ){
   471    471           if( (scanFlags & SCAN_ALL)==0 ) continue;
................................................................................
   489    489           }
   490    490         }
   491    491         fossil_filename_free(zUtf8);
   492    492         blob_resize(pPath, origSize);
   493    493       }
   494    494       closedir(d);
   495    495     }
   496         -  fossil_unicode_free(zNative);
          496  +  fossil_filename_free(zNative);
   497    497   
   498    498     depth--;
   499    499     if( depth==0 ){
   500    500       db_finalize(&ins);
   501    501     }
   502    502   }
   503    503