Fossil SCM

Merge from trunk

brickviking 2024-10-16 07:36 bv-corrections01 merge
Commit 073e0b6bdbf18e6c468a7cf79bdbd4776d63284d4354fca1cc4ef03d52a51a38
+28 -9
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118118
{ "adunit-omit-if-user", CONFIGSET_SKIN },
119119
{ "default-csp", CONFIGSET_SKIN },
120120
{ "sitemap-extra", CONFIGSET_SKIN },
121121
{ "safe-html", CONFIGSET_SKIN },
122122
123
-#ifdef FOSSIL_ENABLE_TH1_DOCS
124
- { "th1-docs", CONFIGSET_TH1 },
125
-#endif
126123
#ifdef FOSSIL_ENABLE_TH1_HOOKS
127124
{ "th1-hooks", CONFIGSET_TH1 },
128125
#endif
129
- { "th1-setup", CONFIGSET_TH1 },
130126
{ "th1-uri-regexp", CONFIGSET_TH1 },
131127
132
-#ifdef FOSSIL_ENABLE_TCL
133
- { "tcl", CONFIGSET_TH1 },
134
- { "tcl-setup", CONFIGSET_TH1 },
135
-#endif
136
-
137128
{ "project-name", CONFIGSET_PROJ },
138129
{ "short-project-name", CONFIGSET_PROJ },
139130
{ "project-description", CONFIGSET_PROJ },
140131
{ "index-page", CONFIGSET_PROJ },
141132
{ "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239230
**
240231
** "Safe" in the previous paragraph means the permission is granted to
241232
** export the property. In other words, the requesting side has presented
242233
** login credentials and has sufficient capabilities to access the requested
243234
** information.
235
+**
236
+** Settings which are specifically flagged as sensitive will (as of
237
+** 2024-10-15) cause this function to return 0, regardless of user
238
+** permissions. As an example, if the th1-setup setting were not
239
+** sensitive then a malicious repo admin could set that to include
240
+** arbitrary TCL code and affect users who configure fossil with the
241
+** --with-tcl flag.
244242
*/
245243
int configure_is_exportable(const char *zName){
246244
int i;
247245
int n = strlen(zName);
246
+ Setting *pSet;
248247
if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248
+ char * zCpy;
249249
zName++;
250250
n -= 2;
251
+ zCpy = fossil_strndup(zName, (ssize_t)n);
252
+ pSet = db_find_setting(zCpy, 0);
253
+ fossil_free(zCpy);
254
+ }else{
255
+ pSet = db_find_setting(zName, 0);
256
+ }
257
+ if( pSet && pSet->sensitive ){
258
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259
+ return 0;
251260
}
252261
for(i=0; i<count(aConfig); i++){
253262
if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254263
int m = aConfig[i].groupMask;
255264
if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414423
if( nToken>=count(azToken)-1 ) break;
415424
}
416425
if( nToken<2 ) return;
417426
if( aType[ii].zName[0]=='/' ){
418427
thisMask = configure_is_exportable(azToken[1]);
428
+ if( 0==thisMask ){
429
+ fossil_warning("Skipping non-exportable setting: %s = %s",
430
+ azToken[1], nToken>3 ? azToken[3] : "?");
431
+ /* Will be skipped below */
432
+ }
419433
}else{
420434
thisMask = configure_is_exportable(aType[ii].zName);
421435
}
422436
if( (thisMask & groupMask)==0 ) return;
423437
if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681695
}
682696
db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683697
" WHERE name=:name AND mtime>=%lld", iStart);
684698
for(ii=0; ii<count(aConfig); ii++){
685699
if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700
+ const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701
+ if( pSet && pSet->sensitive ){
702
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703
+ continue;
704
+ }
686705
db_bind_text(&q, ":name", aConfig[ii].zName);
687706
while( db_step(&q)==SQLITE_ROW ){
688707
blob_appendf(&rec,"%s %s value %s",
689708
db_column_text(&q, 0),
690709
db_column_text(&q, 1),
691710
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
123 #ifdef FOSSIL_ENABLE_TH1_DOCS
124 { "th1-docs", CONFIGSET_TH1 },
125 #endif
126 #ifdef FOSSIL_ENABLE_TH1_HOOKS
127 { "th1-hooks", CONFIGSET_TH1 },
128 #endif
129 { "th1-setup", CONFIGSET_TH1 },
130 { "th1-uri-regexp", CONFIGSET_TH1 },
131
132 #ifdef FOSSIL_ENABLE_TCL
133 { "tcl", CONFIGSET_TH1 },
134 { "tcl-setup", CONFIGSET_TH1 },
135 #endif
136
137 { "project-name", CONFIGSET_PROJ },
138 { "short-project-name", CONFIGSET_PROJ },
139 { "project-description", CONFIGSET_PROJ },
140 { "index-page", CONFIGSET_PROJ },
141 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239 **
240 ** "Safe" in the previous paragraph means the permission is granted to
241 ** export the property. In other words, the requesting side has presented
242 ** login credentials and has sufficient capabilities to access the requested
243 ** information.
 
 
 
 
 
 
 
244 */
245 int configure_is_exportable(const char *zName){
246 int i;
247 int n = strlen(zName);
 
248 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
 
249 zName++;
250 n -= 2;
 
 
 
 
 
 
 
 
 
251 }
252 for(i=0; i<count(aConfig); i++){
253 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254 int m = aConfig[i].groupMask;
255 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414 if( nToken>=count(azToken)-1 ) break;
415 }
416 if( nToken<2 ) return;
417 if( aType[ii].zName[0]=='/' ){
418 thisMask = configure_is_exportable(azToken[1]);
 
 
 
 
 
419 }else{
420 thisMask = configure_is_exportable(aType[ii].zName);
421 }
422 if( (thisMask & groupMask)==0 ) return;
423 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681 }
682 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683 " WHERE name=:name AND mtime>=%lld", iStart);
684 for(ii=0; ii<count(aConfig); ii++){
685 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
 
 
 
 
 
686 db_bind_text(&q, ":name", aConfig[ii].zName);
687 while( db_step(&q)==SQLITE_ROW ){
688 blob_appendf(&rec,"%s %s value %s",
689 db_column_text(&q, 0),
690 db_column_text(&q, 1),
691
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
 
 
 
123 #ifdef FOSSIL_ENABLE_TH1_HOOKS
124 { "th1-hooks", CONFIGSET_TH1 },
125 #endif
 
126 { "th1-uri-regexp", CONFIGSET_TH1 },
127
 
 
 
 
 
128 { "project-name", CONFIGSET_PROJ },
129 { "short-project-name", CONFIGSET_PROJ },
130 { "project-description", CONFIGSET_PROJ },
131 { "index-page", CONFIGSET_PROJ },
132 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
230 **
231 ** "Safe" in the previous paragraph means the permission is granted to
232 ** export the property. In other words, the requesting side has presented
233 ** login credentials and has sufficient capabilities to access the requested
234 ** information.
235 **
236 ** Settings which are specifically flagged as sensitive will (as of
237 ** 2024-10-15) cause this function to return 0, regardless of user
238 ** permissions. As an example, if the th1-setup setting were not
239 ** sensitive then a malicious repo admin could set that to include
240 ** arbitrary TCL code and affect users who configure fossil with the
241 ** --with-tcl flag.
242 */
243 int configure_is_exportable(const char *zName){
244 int i;
245 int n = strlen(zName);
246 Setting *pSet;
247 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248 char * zCpy;
249 zName++;
250 n -= 2;
251 zCpy = fossil_strndup(zName, (ssize_t)n);
252 pSet = db_find_setting(zCpy, 0);
253 fossil_free(zCpy);
254 }else{
255 pSet = db_find_setting(zName, 0);
256 }
257 if( pSet && pSet->sensitive ){
258 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259 return 0;
260 }
261 for(i=0; i<count(aConfig); i++){
262 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
263 int m = aConfig[i].groupMask;
264 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
423 if( nToken>=count(azToken)-1 ) break;
424 }
425 if( nToken<2 ) return;
426 if( aType[ii].zName[0]=='/' ){
427 thisMask = configure_is_exportable(azToken[1]);
428 if( 0==thisMask ){
429 fossil_warning("Skipping non-exportable setting: %s = %s",
430 azToken[1], nToken>3 ? azToken[3] : "?");
431 /* Will be skipped below */
432 }
433 }else{
434 thisMask = configure_is_exportable(aType[ii].zName);
435 }
436 if( (thisMask & groupMask)==0 ) return;
437 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
695 }
696 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
697 " WHERE name=:name AND mtime>=%lld", iStart);
698 for(ii=0; ii<count(aConfig); ii++){
699 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700 const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701 if( pSet && pSet->sensitive ){
702 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703 continue;
704 }
705 db_bind_text(&q, ":name", aConfig[ii].zName);
706 while( db_step(&q)==SQLITE_ROW ){
707 blob_appendf(&rec,"%s %s value %s",
708 db_column_text(&q, 0),
709 db_column_text(&q, 1),
710
+1 -1
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
49674967
** If enabled, special TH1 commands will be called before and
49684968
** after any Fossil command or web page.
49694969
*/
49704970
#endif
49714971
/*
4972
-** SETTING: th1-setup width=40 block-text
4972
+** SETTING: th1-setup width=40 block-text sensitive
49734973
** This is the setup script to be evaluated after creating
49744974
** and initializing the TH1 interpreter. By default, this
49754975
** is empty and no extra setup is performed.
49764976
*/
49774977
/*
49784978
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
4967 ** If enabled, special TH1 commands will be called before and
4968 ** after any Fossil command or web page.
4969 */
4970 #endif
4971 /*
4972 ** SETTING: th1-setup width=40 block-text
4973 ** This is the setup script to be evaluated after creating
4974 ** and initializing the TH1 interpreter. By default, this
4975 ** is empty and no extra setup is performed.
4976 */
4977 /*
4978
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
4967 ** If enabled, special TH1 commands will be called before and
4968 ** after any Fossil command or web page.
4969 */
4970 #endif
4971 /*
4972 ** SETTING: th1-setup width=40 block-text sensitive
4973 ** This is the setup script to be evaluated after creating
4974 ** and initializing the TH1 interpreter. By default, this
4975 ** is empty and no extra setup is performed.
4976 */
4977 /*
4978
+2 -2
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
3434
** Commas and whitespace are considered to be element delimters. Each
3535
** element of the GLOB list may optionally be enclosed in either '...' or
3636
** "...". This allows commas and/or whitespace to be used in the elements
3737
** themselves.
3838
**
39
-** This routine makes no effort to free the memory space it uses, which
40
-** currently consists of a blob object and its contents.
39
+** The returned string is owned by the caller, who must fossil_free()
40
+** it.
4141
*/
4242
char *glob_expr(const char *zVal, const char *zGlobList){
4343
Blob expr;
4444
const char *zSep = "(";
4545
int nTerm = 0;
4646
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
34 ** Commas and whitespace are considered to be element delimters. Each
35 ** element of the GLOB list may optionally be enclosed in either '...' or
36 ** "...". This allows commas and/or whitespace to be used in the elements
37 ** themselves.
38 **
39 ** This routine makes no effort to free the memory space it uses, which
40 ** currently consists of a blob object and its contents.
41 */
42 char *glob_expr(const char *zVal, const char *zGlobList){
43 Blob expr;
44 const char *zSep = "(";
45 int nTerm = 0;
46
--- src/glob.c
+++ src/glob.c
@@ -34,12 +34,12 @@
34 ** Commas and whitespace are considered to be element delimters. Each
35 ** element of the GLOB list may optionally be enclosed in either '...' or
36 ** "...". This allows commas and/or whitespace to be used in the elements
37 ** themselves.
38 **
39 ** The returned string is owned by the caller, who must fossil_free()
40 ** it.
41 */
42 char *glob_expr(const char *zVal, const char *zGlobList){
43 Blob expr;
44 const char *zSep = "(";
45 int nTerm = 0;
46
+5 -3
--- src/search.c
+++ src/search.c
@@ -804,21 +804,23 @@
804804
" SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
805805
" printf('/doc/%T/%%s',foci.filename),"
806806
" search_score(),"
807807
" 'd'||blob.rid,"
808808
" (SELECT datetime(event.mtime) FROM event"
809
- " WHERE objid=symbolic_name_to_rid('trunk')),"
809
+ " WHERE objid=symbolic_name_to_rid(%Q)),"
810810
" search_snippet()"
811811
" FROM foci CROSS JOIN blob"
812
- " WHERE checkinID=symbolic_name_to_rid('trunk')"
812
+ " WHERE checkinID=symbolic_name_to_rid(%Q)"
813813
" AND blob.uuid=foci.uuid"
814814
" AND search_match(title('d',blob.rid,foci.filename),"
815815
" body('d',blob.rid,foci.filename))"
816816
" AND %z",
817
- zDocBr, glob_expr("foci.filename", zDocGlob)
817
+ zDocBr, zDocBr, zDocBr, glob_expr("foci.filename", zDocGlob)
818818
);
819819
}
820
+ fossil_free(zDocGlob);
821
+ fossil_free(zDocBr);
820822
}
821823
if( (srchFlags & SRCH_WIKI)!=0 ){
822824
db_multi_exec(
823825
"WITH wiki(name,rid,mtime) AS ("
824826
" SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
825827
--- src/search.c
+++ src/search.c
@@ -804,21 +804,23 @@
804 " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
805 " printf('/doc/%T/%%s',foci.filename),"
806 " search_score(),"
807 " 'd'||blob.rid,"
808 " (SELECT datetime(event.mtime) FROM event"
809 " WHERE objid=symbolic_name_to_rid('trunk')),"
810 " search_snippet()"
811 " FROM foci CROSS JOIN blob"
812 " WHERE checkinID=symbolic_name_to_rid('trunk')"
813 " AND blob.uuid=foci.uuid"
814 " AND search_match(title('d',blob.rid,foci.filename),"
815 " body('d',blob.rid,foci.filename))"
816 " AND %z",
817 zDocBr, glob_expr("foci.filename", zDocGlob)
818 );
819 }
 
 
820 }
821 if( (srchFlags & SRCH_WIKI)!=0 ){
822 db_multi_exec(
823 "WITH wiki(name,rid,mtime) AS ("
824 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
825
--- src/search.c
+++ src/search.c
@@ -804,21 +804,23 @@
804 " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
805 " printf('/doc/%T/%%s',foci.filename),"
806 " search_score(),"
807 " 'd'||blob.rid,"
808 " (SELECT datetime(event.mtime) FROM event"
809 " WHERE objid=symbolic_name_to_rid(%Q)),"
810 " search_snippet()"
811 " FROM foci CROSS JOIN blob"
812 " WHERE checkinID=symbolic_name_to_rid(%Q)"
813 " AND blob.uuid=foci.uuid"
814 " AND search_match(title('d',blob.rid,foci.filename),"
815 " body('d',blob.rid,foci.filename))"
816 " AND %z",
817 zDocBr, zDocBr, zDocBr, glob_expr("foci.filename", zDocGlob)
818 );
819 }
820 fossil_free(zDocGlob);
821 fossil_free(zDocBr);
822 }
823 if( (srchFlags & SRCH_WIKI)!=0 ){
824 db_multi_exec(
825 "WITH wiki(name,rid,mtime) AS ("
826 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
827
+12 -8
--- src/winfile.c
+++ src/winfile.c
@@ -349,17 +349,17 @@
349349
const char *zBase,
350350
const char *zPath
351351
){
352352
int cchBase = strlen(zBase);
353353
int cchPath = strlen(zPath);
354
- int cchBuf = cchBase + cchPath + 1;
355
- int cchRes = cchPath + 1;
354
+ int cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
355
+ int cchRes = cchPath + 1; /* + NULL */
356356
char *zBuf = fossil_malloc(cchBuf);
357357
char *zRes = fossil_malloc(cchRes);
358
+ int ncUsed = 0;
358359
int i, j;
359360
memcpy(zBuf,zBase,cchBase);
360
- cchRes = 0;
361361
if( !IS_DIRSEP(zBuf,cchBase-1) ){
362362
zBuf[cchBase++]=L'/';
363363
}
364364
memcpy(zBuf+cchBase,zPath,cchPath+1);
365365
i = j = cchBase;
@@ -371,21 +371,21 @@
371371
char *zComp = &zBuf[i];
372372
int cchComp;
373373
char chSep;
374374
int fDone;
375375
if( IS_DIRSEP(zBuf,i) ){
376
- zRes[cchRes++] = zBuf[i];
376
+ zRes[ncUsed++] = zBuf[i];
377377
i = j = i+1;
378378
continue;
379379
}
380380
NEXT_DIRSEP(zBuf,j);
381381
fDone = zBuf[j]==0;
382382
chSep = zBuf[j];
383383
zBuf[j] = 0; /* Truncate working buffer. */
384384
wzBuf = fossil_utf8_to_path(zBuf,0);
385385
hFind = FindFirstFileW(wzBuf,&fd);
386
- if( hFind!= INVALID_HANDLE_VALUE ){
386
+ if( hFind!=INVALID_HANDLE_VALUE ){
387387
wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
388388
FindClose(hFind);
389389
/* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
390390
if( win32_compare_filenames_nocase(wzComp,fd.cFileName)==0 ){
391391
zCompBuf = fossil_path_to_utf8(fd.cFileName);
@@ -393,21 +393,25 @@
393393
}
394394
fossil_path_free(wzComp);
395395
}
396396
fossil_path_free(wzBuf);
397397
cchComp = strlen(zComp);
398
- memcpy(zRes+cchRes,zComp,cchComp);
399
- cchRes += cchComp;
398
+ if( ncUsed+cchComp+1>cchRes ){
399
+ cchRes = ncUsed + cchComp + 32; /* While at it, add some extra space. */
400
+ zRes = fossil_realloc(zRes,cchRes);
401
+ }
402
+ memcpy(zRes+ncUsed,zComp,cchComp);
403
+ ncUsed += cchComp;
400404
if( zCompBuf ){
401405
fossil_path_free(zCompBuf);
402406
}
403407
if( fDone ){
404
- zRes[cchRes] = 0;
408
+ zRes[ncUsed] = 0;
405409
break;
406410
}
407411
zBuf[j] = chSep; /* Undo working buffer truncation. */
408412
i = j;
409413
}
410414
fossil_free(zBuf);
411415
return zRes;
412416
}
413417
#endif /* _WIN32 -- This code is for win32 only */
414418
--- src/winfile.c
+++ src/winfile.c
@@ -349,17 +349,17 @@
349 const char *zBase,
350 const char *zPath
351 ){
352 int cchBase = strlen(zBase);
353 int cchPath = strlen(zPath);
354 int cchBuf = cchBase + cchPath + 1;
355 int cchRes = cchPath + 1;
356 char *zBuf = fossil_malloc(cchBuf);
357 char *zRes = fossil_malloc(cchRes);
 
358 int i, j;
359 memcpy(zBuf,zBase,cchBase);
360 cchRes = 0;
361 if( !IS_DIRSEP(zBuf,cchBase-1) ){
362 zBuf[cchBase++]=L'/';
363 }
364 memcpy(zBuf+cchBase,zPath,cchPath+1);
365 i = j = cchBase;
@@ -371,21 +371,21 @@
371 char *zComp = &zBuf[i];
372 int cchComp;
373 char chSep;
374 int fDone;
375 if( IS_DIRSEP(zBuf,i) ){
376 zRes[cchRes++] = zBuf[i];
377 i = j = i+1;
378 continue;
379 }
380 NEXT_DIRSEP(zBuf,j);
381 fDone = zBuf[j]==0;
382 chSep = zBuf[j];
383 zBuf[j] = 0; /* Truncate working buffer. */
384 wzBuf = fossil_utf8_to_path(zBuf,0);
385 hFind = FindFirstFileW(wzBuf,&fd);
386 if( hFind!= INVALID_HANDLE_VALUE ){
387 wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
388 FindClose(hFind);
389 /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
390 if( win32_compare_filenames_nocase(wzComp,fd.cFileName)==0 ){
391 zCompBuf = fossil_path_to_utf8(fd.cFileName);
@@ -393,21 +393,25 @@
393 }
394 fossil_path_free(wzComp);
395 }
396 fossil_path_free(wzBuf);
397 cchComp = strlen(zComp);
398 memcpy(zRes+cchRes,zComp,cchComp);
399 cchRes += cchComp;
 
 
 
 
400 if( zCompBuf ){
401 fossil_path_free(zCompBuf);
402 }
403 if( fDone ){
404 zRes[cchRes] = 0;
405 break;
406 }
407 zBuf[j] = chSep; /* Undo working buffer truncation. */
408 i = j;
409 }
410 fossil_free(zBuf);
411 return zRes;
412 }
413 #endif /* _WIN32 -- This code is for win32 only */
414
--- src/winfile.c
+++ src/winfile.c
@@ -349,17 +349,17 @@
349 const char *zBase,
350 const char *zPath
351 ){
352 int cchBase = strlen(zBase);
353 int cchPath = strlen(zPath);
354 int cchBuf = cchBase + cchPath + 2; /* + NULL + optional directory slash */
355 int cchRes = cchPath + 1; /* + NULL */
356 char *zBuf = fossil_malloc(cchBuf);
357 char *zRes = fossil_malloc(cchRes);
358 int ncUsed = 0;
359 int i, j;
360 memcpy(zBuf,zBase,cchBase);
 
361 if( !IS_DIRSEP(zBuf,cchBase-1) ){
362 zBuf[cchBase++]=L'/';
363 }
364 memcpy(zBuf+cchBase,zPath,cchPath+1);
365 i = j = cchBase;
@@ -371,21 +371,21 @@
371 char *zComp = &zBuf[i];
372 int cchComp;
373 char chSep;
374 int fDone;
375 if( IS_DIRSEP(zBuf,i) ){
376 zRes[ncUsed++] = zBuf[i];
377 i = j = i+1;
378 continue;
379 }
380 NEXT_DIRSEP(zBuf,j);
381 fDone = zBuf[j]==0;
382 chSep = zBuf[j];
383 zBuf[j] = 0; /* Truncate working buffer. */
384 wzBuf = fossil_utf8_to_path(zBuf,0);
385 hFind = FindFirstFileW(wzBuf,&fd);
386 if( hFind!=INVALID_HANDLE_VALUE ){
387 wchar_t *wzComp = fossil_utf8_to_path(zComp,0);
388 FindClose(hFind);
389 /* Test fd.cFileName, not fd.cAlternateFileName (classic 8.3 format). */
390 if( win32_compare_filenames_nocase(wzComp,fd.cFileName)==0 ){
391 zCompBuf = fossil_path_to_utf8(fd.cFileName);
@@ -393,21 +393,25 @@
393 }
394 fossil_path_free(wzComp);
395 }
396 fossil_path_free(wzBuf);
397 cchComp = strlen(zComp);
398 if( ncUsed+cchComp+1>cchRes ){
399 cchRes = ncUsed + cchComp + 32; /* While at it, add some extra space. */
400 zRes = fossil_realloc(zRes,cchRes);
401 }
402 memcpy(zRes+ncUsed,zComp,cchComp);
403 ncUsed += cchComp;
404 if( zCompBuf ){
405 fossil_path_free(zCompBuf);
406 }
407 if( fDone ){
408 zRes[ncUsed] = 0;
409 break;
410 }
411 zBuf[j] = chSep; /* Undo working buffer truncation. */
412 i = j;
413 }
414 fossil_free(zBuf);
415 return zRes;
416 }
417 #endif /* _WIN32 -- This code is for win32 only */
418

Keyboard Shortcuts

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