Fossil SCM

Add the new "%$" conversion specifier in mprintf(), for escaping filenames for use in shell commands. Use this feature for added system() security whereever appropriate.

drh 2020-06-09 00:27 trunk
Commit 2209f553233fca8c9519c20d4bffb56b29221b94fe8d71e8316cb90ad4006775
+4 -35
--- src/allrepo.c
+++ src/allrepo.c
@@ -19,52 +19,26 @@
1919
*/
2020
#include "config.h"
2121
#include "allrepo.h"
2222
#include <assert.h>
2323
24
-/*
25
-** The input string is a filename. Return a new copy of this
26
-** filename if the filename requires quoting due to special characters
27
-** such as spaces in the name.
28
-**
29
-** If the filename cannot be safely quoted, return a NULL pointer.
30
-**
31
-** Space to hold the returned string is obtained from malloc. A new
32
-** string is returned even if no quoting is needed.
33
-*/
34
-static char *quoteFilename(const char *zFilename){
35
- int i, c;
36
- int needQuote = 0;
37
- for(i=0; (c = zFilename[i])!=0; i++){
38
- if( c=='"' ) return 0;
39
- if( fossil_isspace(c) ) needQuote = 1;
40
- if( c=='\\' && zFilename[i+1]==0 ) return 0;
41
- if( c=='$' ) return 0;
42
- }
43
- if( needQuote ){
44
- return mprintf("\"%s\"", zFilename);
45
- }else{
46
- return mprintf("%s", zFilename);
47
- }
48
-}
49
-
5024
/*
5125
** Build a string that contains all of the command-line options
5226
** specified as arguments. If the option name begins with "+" then
5327
** it takes an argument. Without the "+" it does not.
5428
*/
55
-static void collect_argument(Blob *pExtra, const char *zArg, const char *zShort){
29
+static void collect_argument(Blob *pExtra,const char *zArg,const char *zShort){
5630
const char *z = find_option(zArg, zShort, 0);
5731
if( z!=0 ){
5832
blob_appendf(pExtra, " %s", z);
5933
}
6034
}
6135
static void collect_argument_value(Blob *pExtra, const char *zArg){
6236
const char *zValue = find_option(zArg, 0, 1);
6337
if( zValue ){
6438
if( zValue[0] ){
65
- blob_appendf(pExtra, " --%s %s", zArg, zValue);
39
+ blob_appendf(pExtra, " --%s %$", zArg, zValue);
6640
}else{
6741
blob_appendf(pExtra, " --%s \"\"", zArg);
6842
}
6943
}
7044
}
@@ -169,12 +143,10 @@
169143
void all_cmd(void){
170144
int n;
171145
Stmt q;
172146
const char *zCmd;
173147
char *zSyscmd;
174
- char *zFossil;
175
- char *zQFilename;
176148
Blob extra;
177149
int useCheckouts = 0;
178150
int quiet = 0;
179151
int dryRunFlag = 0;
180152
int showFile = find_option("showfile",0,0)!=0;
@@ -370,11 +342,10 @@
370342
fossil_fatal("\"all\" subcommand should be one of: "
371343
"add cache changes clean dbstat extras fts-config ignore "
372344
"info list ls pull push rebuild server setting sync ui unset");
373345
}
374346
verify_all_options();
375
- zFossil = quoteFilename(g.nameOfExe);
376347
db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
377348
if( useCheckouts ){
378349
db_multi_exec(
379350
"INSERT INTO repolist "
380351
"SELECT DISTINCT substr(name, 7), name COLLATE nocase"
@@ -412,13 +383,12 @@
412383
continue;
413384
}else if( showFile ){
414385
fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
415386
zFilename);
416387
}
417
- zQFilename = quoteFilename(zFilename);
418
- zSyscmd = mprintf("%s %s %s%s",
419
- zFossil, zCmd, zQFilename, blob_str(&extra));
388
+ zSyscmd = mprintf("%$ %s %$%s",
389
+ g.nameOfExe, zCmd, zFilename, blob_str(&extra));
420390
if( showLabel ){
421391
int len = (int)strlen(zFilename);
422392
int nStar = 80 - (len + 15);
423393
if( nStar<2 ) nStar = 1;
424394
fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*');
@@ -428,11 +398,10 @@
428398
fossil_print("%s\n", zSyscmd);
429399
fflush(stdout);
430400
}
431401
rc = dryRunFlag ? 0 : fossil_system(zSyscmd);
432402
free(zSyscmd);
433
- free(zQFilename);
434403
if( stopOnError && rc ){
435404
break;
436405
}
437406
}
438407
db_finalize(&q);
439408
--- src/allrepo.c
+++ src/allrepo.c
@@ -19,52 +19,26 @@
19 */
20 #include "config.h"
21 #include "allrepo.h"
22 #include <assert.h>
23
24 /*
25 ** The input string is a filename. Return a new copy of this
26 ** filename if the filename requires quoting due to special characters
27 ** such as spaces in the name.
28 **
29 ** If the filename cannot be safely quoted, return a NULL pointer.
30 **
31 ** Space to hold the returned string is obtained from malloc. A new
32 ** string is returned even if no quoting is needed.
33 */
34 static char *quoteFilename(const char *zFilename){
35 int i, c;
36 int needQuote = 0;
37 for(i=0; (c = zFilename[i])!=0; i++){
38 if( c=='"' ) return 0;
39 if( fossil_isspace(c) ) needQuote = 1;
40 if( c=='\\' && zFilename[i+1]==0 ) return 0;
41 if( c=='$' ) return 0;
42 }
43 if( needQuote ){
44 return mprintf("\"%s\"", zFilename);
45 }else{
46 return mprintf("%s", zFilename);
47 }
48 }
49
50 /*
51 ** Build a string that contains all of the command-line options
52 ** specified as arguments. If the option name begins with "+" then
53 ** it takes an argument. Without the "+" it does not.
54 */
55 static void collect_argument(Blob *pExtra, const char *zArg, const char *zShort){
56 const char *z = find_option(zArg, zShort, 0);
57 if( z!=0 ){
58 blob_appendf(pExtra, " %s", z);
59 }
60 }
61 static void collect_argument_value(Blob *pExtra, const char *zArg){
62 const char *zValue = find_option(zArg, 0, 1);
63 if( zValue ){
64 if( zValue[0] ){
65 blob_appendf(pExtra, " --%s %s", zArg, zValue);
66 }else{
67 blob_appendf(pExtra, " --%s \"\"", zArg);
68 }
69 }
70 }
@@ -169,12 +143,10 @@
169 void all_cmd(void){
170 int n;
171 Stmt q;
172 const char *zCmd;
173 char *zSyscmd;
174 char *zFossil;
175 char *zQFilename;
176 Blob extra;
177 int useCheckouts = 0;
178 int quiet = 0;
179 int dryRunFlag = 0;
180 int showFile = find_option("showfile",0,0)!=0;
@@ -370,11 +342,10 @@
370 fossil_fatal("\"all\" subcommand should be one of: "
371 "add cache changes clean dbstat extras fts-config ignore "
372 "info list ls pull push rebuild server setting sync ui unset");
373 }
374 verify_all_options();
375 zFossil = quoteFilename(g.nameOfExe);
376 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
377 if( useCheckouts ){
378 db_multi_exec(
379 "INSERT INTO repolist "
380 "SELECT DISTINCT substr(name, 7), name COLLATE nocase"
@@ -412,13 +383,12 @@
412 continue;
413 }else if( showFile ){
414 fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
415 zFilename);
416 }
417 zQFilename = quoteFilename(zFilename);
418 zSyscmd = mprintf("%s %s %s%s",
419 zFossil, zCmd, zQFilename, blob_str(&extra));
420 if( showLabel ){
421 int len = (int)strlen(zFilename);
422 int nStar = 80 - (len + 15);
423 if( nStar<2 ) nStar = 1;
424 fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*');
@@ -428,11 +398,10 @@
428 fossil_print("%s\n", zSyscmd);
429 fflush(stdout);
430 }
431 rc = dryRunFlag ? 0 : fossil_system(zSyscmd);
432 free(zSyscmd);
433 free(zQFilename);
434 if( stopOnError && rc ){
435 break;
436 }
437 }
438 db_finalize(&q);
439
--- src/allrepo.c
+++ src/allrepo.c
@@ -19,52 +19,26 @@
19 */
20 #include "config.h"
21 #include "allrepo.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24 /*
25 ** Build a string that contains all of the command-line options
26 ** specified as arguments. If the option name begins with "+" then
27 ** it takes an argument. Without the "+" it does not.
28 */
29 static void collect_argument(Blob *pExtra,const char *zArg,const char *zShort){
30 const char *z = find_option(zArg, zShort, 0);
31 if( z!=0 ){
32 blob_appendf(pExtra, " %s", z);
33 }
34 }
35 static void collect_argument_value(Blob *pExtra, const char *zArg){
36 const char *zValue = find_option(zArg, 0, 1);
37 if( zValue ){
38 if( zValue[0] ){
39 blob_appendf(pExtra, " --%s %$", zArg, zValue);
40 }else{
41 blob_appendf(pExtra, " --%s \"\"", zArg);
42 }
43 }
44 }
@@ -169,12 +143,10 @@
143 void all_cmd(void){
144 int n;
145 Stmt q;
146 const char *zCmd;
147 char *zSyscmd;
 
 
148 Blob extra;
149 int useCheckouts = 0;
150 int quiet = 0;
151 int dryRunFlag = 0;
152 int showFile = find_option("showfile",0,0)!=0;
@@ -370,11 +342,10 @@
342 fossil_fatal("\"all\" subcommand should be one of: "
343 "add cache changes clean dbstat extras fts-config ignore "
344 "info list ls pull push rebuild server setting sync ui unset");
345 }
346 verify_all_options();
 
347 db_multi_exec("CREATE TEMP TABLE repolist(name,tag);");
348 if( useCheckouts ){
349 db_multi_exec(
350 "INSERT INTO repolist "
351 "SELECT DISTINCT substr(name, 7), name COLLATE nocase"
@@ -412,13 +383,12 @@
383 continue;
384 }else if( showFile ){
385 fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
386 zFilename);
387 }
388 zSyscmd = mprintf("%$ %s %$%s",
389 g.nameOfExe, zCmd, zFilename, blob_str(&extra));
 
390 if( showLabel ){
391 int len = (int)strlen(zFilename);
392 int nStar = 80 - (len + 15);
393 if( nStar<2 ) nStar = 1;
394 fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*');
@@ -428,11 +398,10 @@
398 fossil_print("%s\n", zSyscmd);
399 fflush(stdout);
400 }
401 rc = dryRunFlag ? 0 : fossil_system(zSyscmd);
402 free(zSyscmd);
 
403 if( stopOnError && rc ){
404 break;
405 }
406 }
407 db_finalize(&q);
408
+2 -17
--- src/checkin.c
+++ src/checkin.c
@@ -1174,26 +1174,11 @@
11741174
char *zFile;
11751175
Blob reply, line;
11761176
char *zComment;
11771177
int i;
11781178
1179
- zEditor = db_get("editor", 0);
1180
- if( zEditor==0 ){
1181
- zEditor = fossil_getenv("VISUAL");
1182
- }
1183
- if( zEditor==0 ){
1184
- zEditor = fossil_getenv("EDITOR");
1185
- }
1186
-#if defined(_WIN32) || defined(__CYGWIN__)
1187
- if( zEditor==0 ){
1188
- zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT"));
1189
-#if defined(__CYGWIN__)
1190
- zEditor = fossil_utf8_to_path(zEditor, 0);
1191
- blob_add_cr(pPrompt);
1192
-#endif
1193
- }
1194
-#endif
1179
+ zEditor = fossil_text_editor();db_get("editor", 0);
11951180
if( zEditor==0 ){
11961181
if( blob_size(pPrompt)>0 ){
11971182
blob_append(pPrompt,
11981183
"#\n"
11991184
"# Since no default text editor is set using EDITOR or VISUAL\n"
@@ -1219,11 +1204,11 @@
12191204
#if defined(_WIN32)
12201205
blob_add_cr(pPrompt);
12211206
#endif
12221207
if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);
12231208
if( zEditor ){
1224
- zCmd = mprintf("%s \"%s\"", zEditor, zFile);
1209
+ zCmd = mprintf("%s %$", zEditor, zFile);
12251210
fossil_print("%s\n", zCmd);
12261211
if( fossil_system(zCmd) ){
12271212
fossil_fatal("editor aborted: \"%s\"", zCmd);
12281213
}
12291214
12301215
--- src/checkin.c
+++ src/checkin.c
@@ -1174,26 +1174,11 @@
1174 char *zFile;
1175 Blob reply, line;
1176 char *zComment;
1177 int i;
1178
1179 zEditor = db_get("editor", 0);
1180 if( zEditor==0 ){
1181 zEditor = fossil_getenv("VISUAL");
1182 }
1183 if( zEditor==0 ){
1184 zEditor = fossil_getenv("EDITOR");
1185 }
1186 #if defined(_WIN32) || defined(__CYGWIN__)
1187 if( zEditor==0 ){
1188 zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT"));
1189 #if defined(__CYGWIN__)
1190 zEditor = fossil_utf8_to_path(zEditor, 0);
1191 blob_add_cr(pPrompt);
1192 #endif
1193 }
1194 #endif
1195 if( zEditor==0 ){
1196 if( blob_size(pPrompt)>0 ){
1197 blob_append(pPrompt,
1198 "#\n"
1199 "# Since no default text editor is set using EDITOR or VISUAL\n"
@@ -1219,11 +1204,11 @@
1219 #if defined(_WIN32)
1220 blob_add_cr(pPrompt);
1221 #endif
1222 if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);
1223 if( zEditor ){
1224 zCmd = mprintf("%s \"%s\"", zEditor, zFile);
1225 fossil_print("%s\n", zCmd);
1226 if( fossil_system(zCmd) ){
1227 fossil_fatal("editor aborted: \"%s\"", zCmd);
1228 }
1229
1230
--- src/checkin.c
+++ src/checkin.c
@@ -1174,26 +1174,11 @@
1174 char *zFile;
1175 Blob reply, line;
1176 char *zComment;
1177 int i;
1178
1179 zEditor = fossil_text_editor();db_get("editor", 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1180 if( zEditor==0 ){
1181 if( blob_size(pPrompt)>0 ){
1182 blob_append(pPrompt,
1183 "#\n"
1184 "# Since no default text editor is set using EDITOR or VISUAL\n"
@@ -1219,11 +1204,11 @@
1204 #if defined(_WIN32)
1205 blob_add_cr(pPrompt);
1206 #endif
1207 if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);
1208 if( zEditor ){
1209 zCmd = mprintf("%s %$", zEditor, zFile);
1210 fossil_print("%s\n", zCmd);
1211 if( fossil_system(zCmd) ){
1212 fossil_fatal("editor aborted: \"%s\"", zCmd);
1213 }
1214
1215
+1 -1
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -743,11 +743,11 @@
743743
* dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
744744
* to using the external "tclsh", if available.
745745
*/
746746
#endif
747747
zTempFile = write_blob_to_temp_file(&script);
748
- zCmd = mprintf("\"%s\" \"%s\"", zTclsh, zTempFile);
748
+ zCmd = mprintf("%$ %$", zTclsh, zTempFile);
749749
fossil_system(zCmd);
750750
file_delete(zTempFile);
751751
fossil_free(zCmd);
752752
}
753753
blob_reset(&script);
754754
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -743,11 +743,11 @@
743 * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
744 * to using the external "tclsh", if available.
745 */
746 #endif
747 zTempFile = write_blob_to_temp_file(&script);
748 zCmd = mprintf("\"%s\" \"%s\"", zTclsh, zTempFile);
749 fossil_system(zCmd);
750 file_delete(zTempFile);
751 fossil_free(zCmd);
752 }
753 blob_reset(&script);
754
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -743,11 +743,11 @@
743 * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
744 * to using the external "tclsh", if available.
745 */
746 #endif
747 zTempFile = write_blob_to_temp_file(&script);
748 zCmd = mprintf("%$ %$", zTclsh, zTempFile);
749 fossil_system(zCmd);
750 file_delete(zTempFile);
751 fossil_free(zCmd);
752 }
753 blob_reset(&script);
754
+4 -4
--- src/export.c
+++ src/export.c
@@ -1312,11 +1312,11 @@
13121312
if( rc ) fossil_fatal("cannot create directory \"%s\"", zMirror);
13131313
13141314
/* Make sure GIT has been initialized */
13151315
z = mprintf("%s/.git", zMirror);
13161316
if( !file_isdir(z, ExtFILE) ){
1317
- zCmd = mprintf("git init \"%s\"",zMirror);
1317
+ zCmd = mprintf("git init %$",zMirror);
13181318
gitmirror_message(VERB_NORMAL, "%s\n", zCmd);
13191319
rc = fossil_system(zCmd);
13201320
if( rc ){
13211321
fossil_fatal("cannot initialize the git repository using: \"%s\"", zCmd);
13221322
}
@@ -1510,11 +1510,11 @@
15101510
while( db_step(&q)==SQLITE_ROW ){
15111511
char *zTagname = fossil_strdup(db_column_text(&q,0));
15121512
const char *zObj = db_column_text(&q,1);
15131513
char *zTagCmd;
15141514
gitmirror_sanitize_name(zTagname);
1515
- zTagCmd = mprintf("git tag -f \"%s\" %s", zTagname, zObj);
1515
+ zTagCmd = mprintf("git tag -f %$ %$", zTagname, zObj);
15161516
fossil_free(zTagname);
15171517
gitmirror_message(VERB_NORMAL, "%s\n", zTagCmd);
15181518
fossil_system(zTagCmd);
15191519
fossil_free(zTagCmd);
15201520
}
@@ -1545,11 +1545,11 @@
15451545
fossil_free(zBrname);
15461546
zBrname = fossil_strdup("master");
15471547
}else{
15481548
gitmirror_sanitize_name(zBrname);
15491549
}
1550
- zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %s", zBrname, zObj);
1550
+ zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %$", zBrname, zObj);
15511551
fossil_free(zBrname);
15521552
gitmirror_message(VERB_NORMAL, "%s\n", zRefCmd);
15531553
fossil_system(zRefCmd);
15541554
fossil_free(zRefCmd);
15551555
}
@@ -1582,11 +1582,11 @@
15821582
}else{
15831583
zPushCmd = mprintf("git push --mirror %s", zPushUrl);
15841584
}
15851585
gitmirror_message(VERB_NORMAL, "%s\n", zPushCmd);
15861586
fossil_free(zPushCmd);
1587
- zPushCmd = mprintf("git push --mirror %s", zPushUrl);
1587
+ zPushCmd = mprintf("git push --mirror %$", zPushUrl);
15881588
fossil_system(zPushCmd);
15891589
fossil_free(zPushCmd);
15901590
}
15911591
}
15921592
15931593
--- src/export.c
+++ src/export.c
@@ -1312,11 +1312,11 @@
1312 if( rc ) fossil_fatal("cannot create directory \"%s\"", zMirror);
1313
1314 /* Make sure GIT has been initialized */
1315 z = mprintf("%s/.git", zMirror);
1316 if( !file_isdir(z, ExtFILE) ){
1317 zCmd = mprintf("git init \"%s\"",zMirror);
1318 gitmirror_message(VERB_NORMAL, "%s\n", zCmd);
1319 rc = fossil_system(zCmd);
1320 if( rc ){
1321 fossil_fatal("cannot initialize the git repository using: \"%s\"", zCmd);
1322 }
@@ -1510,11 +1510,11 @@
1510 while( db_step(&q)==SQLITE_ROW ){
1511 char *zTagname = fossil_strdup(db_column_text(&q,0));
1512 const char *zObj = db_column_text(&q,1);
1513 char *zTagCmd;
1514 gitmirror_sanitize_name(zTagname);
1515 zTagCmd = mprintf("git tag -f \"%s\" %s", zTagname, zObj);
1516 fossil_free(zTagname);
1517 gitmirror_message(VERB_NORMAL, "%s\n", zTagCmd);
1518 fossil_system(zTagCmd);
1519 fossil_free(zTagCmd);
1520 }
@@ -1545,11 +1545,11 @@
1545 fossil_free(zBrname);
1546 zBrname = fossil_strdup("master");
1547 }else{
1548 gitmirror_sanitize_name(zBrname);
1549 }
1550 zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %s", zBrname, zObj);
1551 fossil_free(zBrname);
1552 gitmirror_message(VERB_NORMAL, "%s\n", zRefCmd);
1553 fossil_system(zRefCmd);
1554 fossil_free(zRefCmd);
1555 }
@@ -1582,11 +1582,11 @@
1582 }else{
1583 zPushCmd = mprintf("git push --mirror %s", zPushUrl);
1584 }
1585 gitmirror_message(VERB_NORMAL, "%s\n", zPushCmd);
1586 fossil_free(zPushCmd);
1587 zPushCmd = mprintf("git push --mirror %s", zPushUrl);
1588 fossil_system(zPushCmd);
1589 fossil_free(zPushCmd);
1590 }
1591 }
1592
1593
--- src/export.c
+++ src/export.c
@@ -1312,11 +1312,11 @@
1312 if( rc ) fossil_fatal("cannot create directory \"%s\"", zMirror);
1313
1314 /* Make sure GIT has been initialized */
1315 z = mprintf("%s/.git", zMirror);
1316 if( !file_isdir(z, ExtFILE) ){
1317 zCmd = mprintf("git init %$",zMirror);
1318 gitmirror_message(VERB_NORMAL, "%s\n", zCmd);
1319 rc = fossil_system(zCmd);
1320 if( rc ){
1321 fossil_fatal("cannot initialize the git repository using: \"%s\"", zCmd);
1322 }
@@ -1510,11 +1510,11 @@
1510 while( db_step(&q)==SQLITE_ROW ){
1511 char *zTagname = fossil_strdup(db_column_text(&q,0));
1512 const char *zObj = db_column_text(&q,1);
1513 char *zTagCmd;
1514 gitmirror_sanitize_name(zTagname);
1515 zTagCmd = mprintf("git tag -f %$ %$", zTagname, zObj);
1516 fossil_free(zTagname);
1517 gitmirror_message(VERB_NORMAL, "%s\n", zTagCmd);
1518 fossil_system(zTagCmd);
1519 fossil_free(zTagCmd);
1520 }
@@ -1545,11 +1545,11 @@
1545 fossil_free(zBrname);
1546 zBrname = fossil_strdup("master");
1547 }else{
1548 gitmirror_sanitize_name(zBrname);
1549 }
1550 zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %$", zBrname, zObj);
1551 fossil_free(zBrname);
1552 gitmirror_message(VERB_NORMAL, "%s\n", zRefCmd);
1553 fossil_system(zRefCmd);
1554 fossil_free(zRefCmd);
1555 }
@@ -1582,11 +1582,11 @@
1582 }else{
1583 zPushCmd = mprintf("git push --mirror %s", zPushUrl);
1584 }
1585 gitmirror_message(VERB_NORMAL, "%s\n", zPushCmd);
1586 fossil_free(zPushCmd);
1587 zPushCmd = mprintf("git push --mirror %$", zPushUrl);
1588 fossil_system(zPushCmd);
1589 fossil_free(zPushCmd);
1590 }
1591 }
1592
1593
--- src/http_transport.c
+++ src/http_transport.c
@@ -263,18 +263,18 @@
263263
}
264264
}
265265
266266
/*
267267
** This routine is called when the outbound message is complete and
268
-** it is time to being receiving a reply.
268
+** it is time to begin receiving a reply.
269269
*/
270270
void transport_flip(UrlData *pUrlData){
271271
if( pUrlData->isFile ){
272272
char *zCmd;
273273
fclose(transport.pFile);
274
- zCmd = mprintf("\"%s\" http --in \"%s\" --out \"%s\" --ipaddr 127.0.0.1"
275
- " \"%s\" --localauth",
274
+ zCmd = mprintf("%$ http --in %$ --out %$ --ipaddr 127.0.0.1"
275
+ " %$ --localauth",
276276
g.nameOfExe, transport.zOutFile, transport.zInFile, pUrlData->name
277277
);
278278
fossil_system(zCmd);
279279
free(zCmd);
280280
transport.pFile = fossil_fopen(transport.zInFile, "rb");
281281
--- src/http_transport.c
+++ src/http_transport.c
@@ -263,18 +263,18 @@
263 }
264 }
265
266 /*
267 ** This routine is called when the outbound message is complete and
268 ** it is time to being receiving a reply.
269 */
270 void transport_flip(UrlData *pUrlData){
271 if( pUrlData->isFile ){
272 char *zCmd;
273 fclose(transport.pFile);
274 zCmd = mprintf("\"%s\" http --in \"%s\" --out \"%s\" --ipaddr 127.0.0.1"
275 " \"%s\" --localauth",
276 g.nameOfExe, transport.zOutFile, transport.zInFile, pUrlData->name
277 );
278 fossil_system(zCmd);
279 free(zCmd);
280 transport.pFile = fossil_fopen(transport.zInFile, "rb");
281
--- src/http_transport.c
+++ src/http_transport.c
@@ -263,18 +263,18 @@
263 }
264 }
265
266 /*
267 ** This routine is called when the outbound message is complete and
268 ** it is time to begin receiving a reply.
269 */
270 void transport_flip(UrlData *pUrlData){
271 if( pUrlData->isFile ){
272 char *zCmd;
273 fclose(transport.pFile);
274 zCmd = mprintf("%$ http --in %$ --out %$ --ipaddr 127.0.0.1"
275 " %$ --localauth",
276 g.nameOfExe, transport.zOutFile, transport.zInFile, pUrlData->name
277 );
278 fossil_system(zCmd);
279 free(zCmd);
280 transport.pFile = fossil_fopen(transport.zInFile, "rb");
281
--- src/printf.c
+++ src/printf.c
@@ -101,10 +101,12 @@
101101
#define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102102
#define etSTRINGID 23 /* String with length limit for a hash prefix: %S */
103103
#define etROOT 24 /* String value of g.zTop: %R */
104104
#define etJSONSTR 25 /* String encoded as a JSON string literal: %j
105105
Use %!j to include double-quotes around it. */
106
+#define etSHELLESC 26 /* Escape a filename for use in a shell command: %$
107
+ See blob_append_escaped_arg() for details */
106108
107109
108110
/*
109111
** An "etByte" is an 8-bit unsigned value.
110112
*/
@@ -167,10 +169,11 @@
167169
{ 'i', 10, 1, etRADIX, 0, 0 },
168170
{ 'n', 0, 0, etSIZE, 0, 0 },
169171
{ '%', 0, 0, etPERCENT, 0, 0 },
170172
{ 'p', 16, 0, etPOINTER, 0, 1 },
171173
{ '/', 0, 0, etPATH, 0, 0 },
174
+ { '$', 0, 0, etSHELLESC, 0, 0 },
172175
};
173176
#define etNINFO count(fmtinfo)
174177
175178
/*
176179
** "*val" is a double such that 0.1 <= *val < 10.0
@@ -813,10 +816,16 @@
813816
blob_init(&wiki, zWiki, limit);
814817
wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2));
815818
blob_reset(&wiki);
816819
length = width = 0;
817820
break;
821
+ }
822
+ case etSHELLESC: {
823
+ char *zArg = va_arg(ap, char*);
824
+ blob_append_escaped_arg(pBlob, zArg);
825
+ length = width = 0;
826
+ break;
818827
}
819828
case etERROR:
820829
buf[0] = '%';
821830
buf[1] = c;
822831
errorflag = 0;
823832
--- src/printf.c
+++ src/printf.c
@@ -101,10 +101,12 @@
101 #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102 #define etSTRINGID 23 /* String with length limit for a hash prefix: %S */
103 #define etROOT 24 /* String value of g.zTop: %R */
104 #define etJSONSTR 25 /* String encoded as a JSON string literal: %j
105 Use %!j to include double-quotes around it. */
 
 
106
107
108 /*
109 ** An "etByte" is an 8-bit unsigned value.
110 */
@@ -167,10 +169,11 @@
167 { 'i', 10, 1, etRADIX, 0, 0 },
168 { 'n', 0, 0, etSIZE, 0, 0 },
169 { '%', 0, 0, etPERCENT, 0, 0 },
170 { 'p', 16, 0, etPOINTER, 0, 1 },
171 { '/', 0, 0, etPATH, 0, 0 },
 
172 };
173 #define etNINFO count(fmtinfo)
174
175 /*
176 ** "*val" is a double such that 0.1 <= *val < 10.0
@@ -813,10 +816,16 @@
813 blob_init(&wiki, zWiki, limit);
814 wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2));
815 blob_reset(&wiki);
816 length = width = 0;
817 break;
 
 
 
 
 
 
818 }
819 case etERROR:
820 buf[0] = '%';
821 buf[1] = c;
822 errorflag = 0;
823
--- src/printf.c
+++ src/printf.c
@@ -101,10 +101,12 @@
101 #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102 #define etSTRINGID 23 /* String with length limit for a hash prefix: %S */
103 #define etROOT 24 /* String value of g.zTop: %R */
104 #define etJSONSTR 25 /* String encoded as a JSON string literal: %j
105 Use %!j to include double-quotes around it. */
106 #define etSHELLESC 26 /* Escape a filename for use in a shell command: %$
107 See blob_append_escaped_arg() for details */
108
109
110 /*
111 ** An "etByte" is an 8-bit unsigned value.
112 */
@@ -167,10 +169,11 @@
169 { 'i', 10, 1, etRADIX, 0, 0 },
170 { 'n', 0, 0, etSIZE, 0, 0 },
171 { '%', 0, 0, etPERCENT, 0, 0 },
172 { 'p', 16, 0, etPOINTER, 0, 1 },
173 { '/', 0, 0, etPATH, 0, 0 },
174 { '$', 0, 0, etSHELLESC, 0, 0 },
175 };
176 #define etNINFO count(fmtinfo)
177
178 /*
179 ** "*val" is a double such that 0.1 <= *val < 10.0
@@ -813,10 +816,16 @@
816 blob_init(&wiki, zWiki, limit);
817 wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2));
818 blob_reset(&wiki);
819 length = width = 0;
820 break;
821 }
822 case etSHELLESC: {
823 char *zArg = va_arg(ap, char*);
824 blob_append_escaped_arg(pBlob, zArg);
825 length = width = 0;
826 break;
827 }
828 case etERROR:
829 buf[0] = '%';
830 buf[1] = c;
831 errorflag = 0;
832
--- src/unversioned.c
+++ src/unversioned.c
@@ -377,11 +377,11 @@
377377
}
378378
#if defined(_WIN32) || defined(__CYGWIN__)
379379
blob_add_cr(&content);
380380
#endif
381381
blob_write_to_file(&content, zTFile);
382
- zCmd = mprintf("%s \"%s\"", zEditor, zTFile);
382
+ zCmd = mprintf("%s %$", zEditor, zTFile);
383383
if( fossil_system(zCmd) ){
384384
fossil_fatal("editor aborted: %Q", zCmd);
385385
}
386386
fossil_free(zCmd);
387387
blob_reset(&content);
388388
--- src/unversioned.c
+++ src/unversioned.c
@@ -377,11 +377,11 @@
377 }
378 #if defined(_WIN32) || defined(__CYGWIN__)
379 blob_add_cr(&content);
380 #endif
381 blob_write_to_file(&content, zTFile);
382 zCmd = mprintf("%s \"%s\"", zEditor, zTFile);
383 if( fossil_system(zCmd) ){
384 fossil_fatal("editor aborted: %Q", zCmd);
385 }
386 fossil_free(zCmd);
387 blob_reset(&content);
388
--- src/unversioned.c
+++ src/unversioned.c
@@ -377,11 +377,11 @@
377 }
378 #if defined(_WIN32) || defined(__CYGWIN__)
379 blob_add_cr(&content);
380 #endif
381 blob_write_to_file(&content, zTFile);
382 zCmd = mprintf("%s %$", zEditor, zTFile);
383 if( fossil_system(zCmd) ){
384 fossil_fatal("editor aborted: %Q", zCmd);
385 }
386 fossil_free(zCmd);
387 blob_reset(&content);
388

Keyboard Shortcuts

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