Fossil SCM

Follow-up to [8ab08d32c7]: Fossil still doesn't handle the extended path prefix on win32 ('\\?\') right, mainly in checking paths. e.g.: "fossil add //\?/C:/Localdata/workspace/fossil/foo.c". Fossil cannot know that this path is correct. Solution: Strip the extended path prefix in file_simplify_name(), and only add it back when needed. Latest "winhttp.c" changes could be reverted with this change when compiling with MSVC or MinGW-w64 (as the repository path after simplicifation doesn't contain '?' any more), but when using MinGW the command-line handling cannot be thrusted.

jan.nijtmans 2014-02-25 13:31 UTC trunk
Commit ce4afc891c4982769f1e2e73c22162e07934ba8a
2 files changed +10 -5 +14 -1
+10 -5
--- src/file.c
+++ src/file.c
@@ -654,17 +654,22 @@
654654
** Changes are made in-place. Return the new name length.
655655
** If the slash parameter is non-zero, the trailing slash, if any,
656656
** is retained.
657657
*/
658658
int file_simplify_name(char *z, int n, int slash){
659
- int i, j;
659
+ int i = 1, j;
660660
if( n<0 ) n = strlen(z);
661661
662
- /* On windows and cygwin convert all \ characters to / */
662
+ /* On windows and cygwin convert all \ characters to /
663
+ * and remove extended path prefix if present */
663664
#if defined(_WIN32) || defined(__CYGWIN__)
664
- for(i=0; i<n; i++){
665
- if( z[i]=='\\' ) z[i] = '/';
665
+ for(j=0; j<n; j++){
666
+ if( z[j]=='\\' ) z[j] = '/';
667
+ }
668
+ if( n>3 && !memcmp(z, "//?/", 4) ){
669
+ i += 4;
670
+ z[0] = z[4];
666671
}
667672
#endif
668673
669674
/* Removing trailing "/" characters */
670675
if( !slash ){
@@ -671,11 +676,11 @@
671676
while( n>1 && z[n-1]=='/' ){ n--; }
672677
}
673678
674679
/* Remove duplicate '/' characters. Except, two // at the beginning
675680
** of a pathname is allowed since this is important on windows. */
676
- for(i=j=1; i<n; i++){
681
+ for(j=1; i<n; i++){
677682
z[j++] = z[i];
678683
while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
679684
}
680685
n = j;
681686
682687
--- src/file.c
+++ src/file.c
@@ -654,17 +654,22 @@
654 ** Changes are made in-place. Return the new name length.
655 ** If the slash parameter is non-zero, the trailing slash, if any,
656 ** is retained.
657 */
658 int file_simplify_name(char *z, int n, int slash){
659 int i, j;
660 if( n<0 ) n = strlen(z);
661
662 /* On windows and cygwin convert all \ characters to / */
 
663 #if defined(_WIN32) || defined(__CYGWIN__)
664 for(i=0; i<n; i++){
665 if( z[i]=='\\' ) z[i] = '/';
 
 
 
 
666 }
667 #endif
668
669 /* Removing trailing "/" characters */
670 if( !slash ){
@@ -671,11 +676,11 @@
671 while( n>1 && z[n-1]=='/' ){ n--; }
672 }
673
674 /* Remove duplicate '/' characters. Except, two // at the beginning
675 ** of a pathname is allowed since this is important on windows. */
676 for(i=j=1; i<n; i++){
677 z[j++] = z[i];
678 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
679 }
680 n = j;
681
682
--- src/file.c
+++ src/file.c
@@ -654,17 +654,22 @@
654 ** Changes are made in-place. Return the new name length.
655 ** If the slash parameter is non-zero, the trailing slash, if any,
656 ** is retained.
657 */
658 int file_simplify_name(char *z, int n, int slash){
659 int i = 1, j;
660 if( n<0 ) n = strlen(z);
661
662 /* On windows and cygwin convert all \ characters to /
663 * and remove extended path prefix if present */
664 #if defined(_WIN32) || defined(__CYGWIN__)
665 for(j=0; j<n; j++){
666 if( z[j]=='\\' ) z[j] = '/';
667 }
668 if( n>3 && !memcmp(z, "//?/", 4) ){
669 i += 4;
670 z[0] = z[4];
671 }
672 #endif
673
674 /* Removing trailing "/" characters */
675 if( !slash ){
@@ -671,11 +676,11 @@
676 while( n>1 && z[n-1]=='/' ){ n--; }
677 }
678
679 /* Remove duplicate '/' characters. Except, two // at the beginning
680 ** of a pathname is allowed since this is important on windows. */
681 for(j=1; i<n; i++){
682 z[j++] = z[i];
683 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
684 }
685 n = j;
686
687
+14 -1
--- src/utf8.c
+++ src/utf8.c
@@ -190,11 +190,12 @@
190190
**
191191
*/
192192
void *fossil_utf8_to_filename(const char *zUtf8){
193193
#ifdef _WIN32
194194
int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
195
- wchar_t *zUnicode = sqlite3_malloc( nChar * 2 );
195
+ /* Overallocate 4 chars, making some room for extended paths */
196
+ wchar_t *zUnicode = sqlite3_malloc( (nChar+4) * sizeof(wchar_t) );
196197
wchar_t *wUnicode = zUnicode;
197198
if( zUnicode==0 ){
198199
return 0;
199200
}
200201
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
@@ -212,10 +213,22 @@
212213
** If (remainder of) path starts with "<drive>:/" or "<drive>:\",
213214
** leave the ':' intact
214215
*/
215216
if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
216217
&& (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
218
+ if( wUnicode==zUnicode && nChar>MAX_PATH){
219
+ /*
220
+ ** If there is no "\\?\" prefix but there is a drive
221
+ ** prefix and the path is larger than MAX_PATH chars,
222
+ ** no Win32 API function can handle that unless it is
223
+ ** prefixed with the extended path prefix. See:
224
+ ** <http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath>
225
+ **/
226
+ memmove(wUnicode+4, wUnicode, nChar*sizeof(wchar_t));
227
+ memcpy(wUnicode, L"\\\\?\\", 4*sizeof(wchar_t));
228
+ wUnicode += 4;
229
+ }
217230
wUnicode[2] = '\\';
218231
wUnicode += 3;
219232
}
220233
/*
221234
** In the remainder of the path, translate invalid characters to
222235
--- src/utf8.c
+++ src/utf8.c
@@ -190,11 +190,12 @@
190 **
191 */
192 void *fossil_utf8_to_filename(const char *zUtf8){
193 #ifdef _WIN32
194 int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
195 wchar_t *zUnicode = sqlite3_malloc( nChar * 2 );
 
196 wchar_t *wUnicode = zUnicode;
197 if( zUnicode==0 ){
198 return 0;
199 }
200 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
@@ -212,10 +213,22 @@
212 ** If (remainder of) path starts with "<drive>:/" or "<drive>:\",
213 ** leave the ':' intact
214 */
215 if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
216 && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
 
 
 
 
 
 
 
 
 
 
 
 
217 wUnicode[2] = '\\';
218 wUnicode += 3;
219 }
220 /*
221 ** In the remainder of the path, translate invalid characters to
222
--- src/utf8.c
+++ src/utf8.c
@@ -190,11 +190,12 @@
190 **
191 */
192 void *fossil_utf8_to_filename(const char *zUtf8){
193 #ifdef _WIN32
194 int nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
195 /* Overallocate 4 chars, making some room for extended paths */
196 wchar_t *zUnicode = sqlite3_malloc( (nChar+4) * sizeof(wchar_t) );
197 wchar_t *wUnicode = zUnicode;
198 if( zUnicode==0 ){
199 return 0;
200 }
201 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
@@ -212,10 +213,22 @@
213 ** If (remainder of) path starts with "<drive>:/" or "<drive>:\",
214 ** leave the ':' intact
215 */
216 if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
217 && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
218 if( wUnicode==zUnicode && nChar>MAX_PATH){
219 /*
220 ** If there is no "\\?\" prefix but there is a drive
221 ** prefix and the path is larger than MAX_PATH chars,
222 ** no Win32 API function can handle that unless it is
223 ** prefixed with the extended path prefix. See:
224 ** <http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath>
225 **/
226 memmove(wUnicode+4, wUnicode, nChar*sizeof(wchar_t));
227 memcpy(wUnicode, L"\\\\?\\", 4*sizeof(wchar_t));
228 wUnicode += 4;
229 }
230 wUnicode[2] = '\\';
231 wUnicode += 3;
232 }
233 /*
234 ** In the remainder of the path, translate invalid characters to
235

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button