Fossil SCM

Allow repository to reside on an extended windows path, prefixed with "//?/". There were two problems. 1) The '?' doesn't survive fossil's command line globbing, therefore use a temporary file to hold the repository name when running "fossil ui" or "fossil server" on Windows. 2) In fossil_utf8_to_filename(), '?' was translated to another Unicode character, which shouldn't happen in the extended path prefix. testcase: "fossil test-move-repository //\?/C:/fossil/fossil.fossil" (the backslash is absorbed by cmd.exe, using quotes doesn't work)

jan.nijtmans 2014-02-12 11:20 trunk
Commit 8ab08d32c7771298d21dfc7e664257260d6d665d
2 files changed +24 -4 +15 -3
+24 -4
--- src/utf8.c
+++ src/utf8.c
@@ -177,12 +177,13 @@
177177
** Call fossil_filename_free() to deallocate any memory used to store the
178178
** returned pointer when done.
179179
**
180180
** On Windows, characters in the range U+0001 to U+0031 and the
181181
** characters '"', '*', ':', '<', '>', '?' and '|' are invalid
182
-** to be used. Therefore, translate those to characters in the
183
-** in the range U+F001 - U+F07F (private use area), so those
182
+** to be used, except in the 'extended path' prefix ('?') and
183
+** as drive specifier (':'). Therefore, translate those to characters
184
+** in the in the range U+F001 - U+F07F (private use area), so those
184185
** characters never arrive in any Windows API. The filenames might
185186
** look strange in Windows explorer, but in the cygwin shell
186187
** everything looks as expected.
187188
**
188189
** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
@@ -195,16 +196,35 @@
195196
wchar_t *wUnicode = zUnicode;
196197
if( zUnicode==0 ){
197198
return 0;
198199
}
199200
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
200
- /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */
201
+ /*
202
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
203
+ ** any slashes to backslashes but leave the '?' intact
204
+ */
205
+ if( (zUtf8[0]=='\\' || zUtf8[0]=='/') && (zUtf8[1]=='\\' || zUtf8[1]=='/')
206
+ && zUtf8[2]=='?' && (zUtf8[3]=='\\' || zUtf8[3]=='/')) {
207
+ wUnicode[0] = wUnicode[1] = wUnicode[3] = '\\';
208
+ zUtf8 += 4;
209
+ wUnicode += 4;
210
+ }
211
+ /*
212
+ ** If (remainder of) path starts with "<drive>:/" or "<drive>:\",
213
+ ** leave the ':' intact
214
+ */
201215
if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
202216
&& (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
203
- zUnicode[2] = '\\';
217
+ wUnicode[2] = '\\';
204218
wUnicode += 3;
205219
}
220
+ /*
221
+ ** In the remainder of the path, translate invalid characters to
222
+ ** characters in the Unicode private use area. This is what makes
223
+ ** Win32 fossil.exe work well in a Cygwin environment even when a
224
+ ** filename contains characters which are invalid for Win32.
225
+ */
206226
while( *wUnicode != '\0' ){
207227
if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
208228
*wUnicode |= 0xF000;
209229
}else if( *wUnicode == '/' ){
210230
*wUnicode = '\\';
211231
--- src/utf8.c
+++ src/utf8.c
@@ -177,12 +177,13 @@
177 ** Call fossil_filename_free() to deallocate any memory used to store the
178 ** returned pointer when done.
179 **
180 ** On Windows, characters in the range U+0001 to U+0031 and the
181 ** characters '"', '*', ':', '<', '>', '?' and '|' are invalid
182 ** to be used. Therefore, translate those to characters in the
183 ** in the range U+F001 - U+F07F (private use area), so those
 
184 ** characters never arrive in any Windows API. The filenames might
185 ** look strange in Windows explorer, but in the cygwin shell
186 ** everything looks as expected.
187 **
188 ** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
@@ -195,16 +196,35 @@
195 wchar_t *wUnicode = zUnicode;
196 if( zUnicode==0 ){
197 return 0;
198 }
199 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
200 /* If path starts with "<drive>:/" or "<drive>:\", don't translate the ':' */
 
 
 
 
 
 
 
 
 
 
 
 
 
201 if( fossil_isalpha(zUtf8[0]) && zUtf8[1]==':'
202 && (zUtf8[2]=='\\' || zUtf8[2]=='/')) {
203 zUnicode[2] = '\\';
204 wUnicode += 3;
205 }
 
 
 
 
 
 
206 while( *wUnicode != '\0' ){
207 if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
208 *wUnicode |= 0xF000;
209 }else if( *wUnicode == '/' ){
210 *wUnicode = '\\';
211
--- src/utf8.c
+++ src/utf8.c
@@ -177,12 +177,13 @@
177 ** Call fossil_filename_free() to deallocate any memory used to store the
178 ** returned pointer when done.
179 **
180 ** On Windows, characters in the range U+0001 to U+0031 and the
181 ** characters '"', '*', ':', '<', '>', '?' and '|' are invalid
182 ** to be used, except in the 'extended path' prefix ('?') and
183 ** as drive specifier (':'). Therefore, translate those to characters
184 ** in the in the range U+F001 - U+F07F (private use area), so those
185 ** characters never arrive in any Windows API. The filenames might
186 ** look strange in Windows explorer, but in the cygwin shell
187 ** everything looks as expected.
188 **
189 ** See: <http://cygwin.com/cygwin-ug-net/using-specialnames.html>
@@ -195,16 +196,35 @@
196 wchar_t *wUnicode = zUnicode;
197 if( zUnicode==0 ){
198 return 0;
199 }
200 MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar);
201 /*
202 ** If path starts with "//?/" or "\\?\" (extended path), translate
203 ** any slashes to backslashes but leave the '?' intact
204 */
205 if( (zUtf8[0]=='\\' || zUtf8[0]=='/') && (zUtf8[1]=='\\' || zUtf8[1]=='/')
206 && zUtf8[2]=='?' && (zUtf8[3]=='\\' || zUtf8[3]=='/')) {
207 wUnicode[0] = wUnicode[1] = wUnicode[3] = '\\';
208 zUtf8 += 4;
209 wUnicode += 4;
210 }
211 /*
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 ** characters in the Unicode private use area. This is what makes
223 ** Win32 fossil.exe work well in a Cygwin environment even when a
224 ** filename contains characters which are invalid for Win32.
225 */
226 while( *wUnicode != '\0' ){
227 if ( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
228 *wUnicode |= 0xF000;
229 }else if( *wUnicode == '/' ){
230 *wUnicode = '\\';
231
+15 -3
--- src/winhttp.c
+++ src/winhttp.c
@@ -67,15 +67,18 @@
6767
HttpRequest *p = (HttpRequest*)pAppData;
6868
FILE *in = 0, *out = 0;
6969
int amt, got;
7070
int wanted = 0;
7171
char *z;
72
+ char zCmdFName[MAX_PATH];
7273
char zRequestFName[MAX_PATH];
7374
char zReplyFName[MAX_PATH];
7475
char zCmd[2000]; /* Command-line to process the request */
7576
char zHdr[2000]; /* The HTTP request header */
7677
78
+ sqlite3_snprintf(MAX_PATH, zCmdFName,
79
+ "%s_cmd%d.txt", zTempPrefix, p->id);
7780
sqlite3_snprintf(MAX_PATH, zRequestFName,
7881
"%s_in%d.txt", zTempPrefix, p->id);
7982
sqlite3_snprintf(MAX_PATH, zReplyFName,
8083
"%s_out%d.txt", zTempPrefix, p->id);
8184
amt = 0;
@@ -108,13 +111,21 @@
108111
}
109112
wanted -= got;
110113
}
111114
fclose(out);
112115
out = 0;
113
- sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s",
114
- g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
115
- inet_ntoa(p->addr.sin_addr), p->zOptions
116
+ sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
117
+ get_utf8_bom(0), g.zRepositoryName, zRequestFName, zReplyFName,
118
+ inet_ntoa(p->addr.sin_addr)
119
+ );
120
+ out = fossil_fopen(zCmdFName, "wb");
121
+ if( out==0 ) goto end_request;
122
+ fwrite(zCmd, 1, strlen(zCmd), out);
123
+ fclose(out);
124
+
125
+ sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http -args \"%s\" --nossl%s",
126
+ g.nameOfExe, zCmdFName, p->zOptions
116127
);
117128
fossil_system(zCmd);
118129
in = fossil_fopen(zReplyFName, "rb");
119130
if( in ){
120131
while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -126,10 +137,11 @@
126137
if( out ) fclose(out);
127138
if( in ) fclose(in);
128139
closesocket(p->s);
129140
file_delete(zRequestFName);
130141
file_delete(zReplyFName);
142
+ file_delete(zCmdFName);
131143
free(p);
132144
}
133145
134146
/*
135147
** Process a single incoming SCGI request.
136148
--- src/winhttp.c
+++ src/winhttp.c
@@ -67,15 +67,18 @@
67 HttpRequest *p = (HttpRequest*)pAppData;
68 FILE *in = 0, *out = 0;
69 int amt, got;
70 int wanted = 0;
71 char *z;
 
72 char zRequestFName[MAX_PATH];
73 char zReplyFName[MAX_PATH];
74 char zCmd[2000]; /* Command-line to process the request */
75 char zHdr[2000]; /* The HTTP request header */
76
 
 
77 sqlite3_snprintf(MAX_PATH, zRequestFName,
78 "%s_in%d.txt", zTempPrefix, p->id);
79 sqlite3_snprintf(MAX_PATH, zReplyFName,
80 "%s_out%d.txt", zTempPrefix, p->id);
81 amt = 0;
@@ -108,13 +111,21 @@
108 }
109 wanted -= got;
110 }
111 fclose(out);
112 out = 0;
113 sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s",
114 g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
115 inet_ntoa(p->addr.sin_addr), p->zOptions
 
 
 
 
 
 
 
 
116 );
117 fossil_system(zCmd);
118 in = fossil_fopen(zReplyFName, "rb");
119 if( in ){
120 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -126,10 +137,11 @@
126 if( out ) fclose(out);
127 if( in ) fclose(in);
128 closesocket(p->s);
129 file_delete(zRequestFName);
130 file_delete(zReplyFName);
 
131 free(p);
132 }
133
134 /*
135 ** Process a single incoming SCGI request.
136
--- src/winhttp.c
+++ src/winhttp.c
@@ -67,15 +67,18 @@
67 HttpRequest *p = (HttpRequest*)pAppData;
68 FILE *in = 0, *out = 0;
69 int amt, got;
70 int wanted = 0;
71 char *z;
72 char zCmdFName[MAX_PATH];
73 char zRequestFName[MAX_PATH];
74 char zReplyFName[MAX_PATH];
75 char zCmd[2000]; /* Command-line to process the request */
76 char zHdr[2000]; /* The HTTP request header */
77
78 sqlite3_snprintf(MAX_PATH, zCmdFName,
79 "%s_cmd%d.txt", zTempPrefix, p->id);
80 sqlite3_snprintf(MAX_PATH, zRequestFName,
81 "%s_in%d.txt", zTempPrefix, p->id);
82 sqlite3_snprintf(MAX_PATH, zReplyFName,
83 "%s_out%d.txt", zTempPrefix, p->id);
84 amt = 0;
@@ -108,13 +111,21 @@
111 }
112 wanted -= got;
113 }
114 fclose(out);
115 out = 0;
116 sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
117 get_utf8_bom(0), g.zRepositoryName, zRequestFName, zReplyFName,
118 inet_ntoa(p->addr.sin_addr)
119 );
120 out = fossil_fopen(zCmdFName, "wb");
121 if( out==0 ) goto end_request;
122 fwrite(zCmd, 1, strlen(zCmd), out);
123 fclose(out);
124
125 sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http -args \"%s\" --nossl%s",
126 g.nameOfExe, zCmdFName, p->zOptions
127 );
128 fossil_system(zCmd);
129 in = fossil_fopen(zReplyFName, "rb");
130 if( in ){
131 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -126,10 +137,11 @@
137 if( out ) fclose(out);
138 if( in ) fclose(in);
139 closesocket(p->s);
140 file_delete(zRequestFName);
141 file_delete(zReplyFName);
142 file_delete(zCmdFName);
143 free(p);
144 }
145
146 /*
147 ** Process a single incoming SCGI request.
148

Keyboard Shortcuts

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