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.
Commit
2209f553233fca8c9519c20d4bffb56b29221b94fe8d71e8316cb90ad4006775
Parent
a046f916d3e3be3…
7 files changed
+4
-35
+2
-17
+1
-1
+4
-4
+3
-3
+9
+1
-1
+4
-35
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -19,52 +19,26 @@ | ||
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "allrepo.h" |
| 22 | 22 | #include <assert.h> |
| 23 | 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 | 24 | /* |
| 51 | 25 | ** Build a string that contains all of the command-line options |
| 52 | 26 | ** specified as arguments. If the option name begins with "+" then |
| 53 | 27 | ** it takes an argument. Without the "+" it does not. |
| 54 | 28 | */ |
| 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){ | |
| 56 | 30 | const char *z = find_option(zArg, zShort, 0); |
| 57 | 31 | if( z!=0 ){ |
| 58 | 32 | blob_appendf(pExtra, " %s", z); |
| 59 | 33 | } |
| 60 | 34 | } |
| 61 | 35 | static void collect_argument_value(Blob *pExtra, const char *zArg){ |
| 62 | 36 | const char *zValue = find_option(zArg, 0, 1); |
| 63 | 37 | if( zValue ){ |
| 64 | 38 | if( zValue[0] ){ |
| 65 | - blob_appendf(pExtra, " --%s %s", zArg, zValue); | |
| 39 | + blob_appendf(pExtra, " --%s %$", zArg, zValue); | |
| 66 | 40 | }else{ |
| 67 | 41 | blob_appendf(pExtra, " --%s \"\"", zArg); |
| 68 | 42 | } |
| 69 | 43 | } |
| 70 | 44 | } |
| @@ -169,12 +143,10 @@ | ||
| 169 | 143 | void all_cmd(void){ |
| 170 | 144 | int n; |
| 171 | 145 | Stmt q; |
| 172 | 146 | const char *zCmd; |
| 173 | 147 | char *zSyscmd; |
| 174 | - char *zFossil; | |
| 175 | - char *zQFilename; | |
| 176 | 148 | Blob extra; |
| 177 | 149 | int useCheckouts = 0; |
| 178 | 150 | int quiet = 0; |
| 179 | 151 | int dryRunFlag = 0; |
| 180 | 152 | int showFile = find_option("showfile",0,0)!=0; |
| @@ -370,11 +342,10 @@ | ||
| 370 | 342 | fossil_fatal("\"all\" subcommand should be one of: " |
| 371 | 343 | "add cache changes clean dbstat extras fts-config ignore " |
| 372 | 344 | "info list ls pull push rebuild server setting sync ui unset"); |
| 373 | 345 | } |
| 374 | 346 | verify_all_options(); |
| 375 | - zFossil = quoteFilename(g.nameOfExe); | |
| 376 | 347 | db_multi_exec("CREATE TEMP TABLE repolist(name,tag);"); |
| 377 | 348 | if( useCheckouts ){ |
| 378 | 349 | db_multi_exec( |
| 379 | 350 | "INSERT INTO repolist " |
| 380 | 351 | "SELECT DISTINCT substr(name, 7), name COLLATE nocase" |
| @@ -412,13 +383,12 @@ | ||
| 412 | 383 | continue; |
| 413 | 384 | }else if( showFile ){ |
| 414 | 385 | fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository", |
| 415 | 386 | zFilename); |
| 416 | 387 | } |
| 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)); | |
| 420 | 390 | if( showLabel ){ |
| 421 | 391 | int len = (int)strlen(zFilename); |
| 422 | 392 | int nStar = 80 - (len + 15); |
| 423 | 393 | if( nStar<2 ) nStar = 1; |
| 424 | 394 | fossil_print("%.13c %s %.*c\n", '*', zFilename, nStar, '*'); |
| @@ -428,11 +398,10 @@ | ||
| 428 | 398 | fossil_print("%s\n", zSyscmd); |
| 429 | 399 | fflush(stdout); |
| 430 | 400 | } |
| 431 | 401 | rc = dryRunFlag ? 0 : fossil_system(zSyscmd); |
| 432 | 402 | free(zSyscmd); |
| 433 | - free(zQFilename); | |
| 434 | 403 | if( stopOnError && rc ){ |
| 435 | 404 | break; |
| 436 | 405 | } |
| 437 | 406 | } |
| 438 | 407 | db_finalize(&q); |
| 439 | 408 |
| --- 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 @@ | ||
| 1174 | 1174 | char *zFile; |
| 1175 | 1175 | Blob reply, line; |
| 1176 | 1176 | char *zComment; |
| 1177 | 1177 | int i; |
| 1178 | 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 | |
| 1179 | + zEditor = fossil_text_editor();db_get("editor", 0); | |
| 1195 | 1180 | if( zEditor==0 ){ |
| 1196 | 1181 | if( blob_size(pPrompt)>0 ){ |
| 1197 | 1182 | blob_append(pPrompt, |
| 1198 | 1183 | "#\n" |
| 1199 | 1184 | "# Since no default text editor is set using EDITOR or VISUAL\n" |
| @@ -1219,11 +1204,11 @@ | ||
| 1219 | 1204 | #if defined(_WIN32) |
| 1220 | 1205 | blob_add_cr(pPrompt); |
| 1221 | 1206 | #endif |
| 1222 | 1207 | if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile); |
| 1223 | 1208 | if( zEditor ){ |
| 1224 | - zCmd = mprintf("%s \"%s\"", zEditor, zFile); | |
| 1209 | + zCmd = mprintf("%s %$", zEditor, zFile); | |
| 1225 | 1210 | fossil_print("%s\n", zCmd); |
| 1226 | 1211 | if( fossil_system(zCmd) ){ |
| 1227 | 1212 | fossil_fatal("editor aborted: \"%s\"", zCmd); |
| 1228 | 1213 | } |
| 1229 | 1214 | |
| 1230 | 1215 |
| --- 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 @@ | ||
| 743 | 743 | * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback |
| 744 | 744 | * to using the external "tclsh", if available. |
| 745 | 745 | */ |
| 746 | 746 | #endif |
| 747 | 747 | zTempFile = write_blob_to_temp_file(&script); |
| 748 | - zCmd = mprintf("\"%s\" \"%s\"", zTclsh, zTempFile); | |
| 748 | + zCmd = mprintf("%$ %$", zTclsh, zTempFile); | |
| 749 | 749 | fossil_system(zCmd); |
| 750 | 750 | file_delete(zTempFile); |
| 751 | 751 | fossil_free(zCmd); |
| 752 | 752 | } |
| 753 | 753 | blob_reset(&script); |
| 754 | 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("\"%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 @@ | ||
| 1312 | 1312 | if( rc ) fossil_fatal("cannot create directory \"%s\"", zMirror); |
| 1313 | 1313 | |
| 1314 | 1314 | /* Make sure GIT has been initialized */ |
| 1315 | 1315 | z = mprintf("%s/.git", zMirror); |
| 1316 | 1316 | if( !file_isdir(z, ExtFILE) ){ |
| 1317 | - zCmd = mprintf("git init \"%s\"",zMirror); | |
| 1317 | + zCmd = mprintf("git init %$",zMirror); | |
| 1318 | 1318 | gitmirror_message(VERB_NORMAL, "%s\n", zCmd); |
| 1319 | 1319 | rc = fossil_system(zCmd); |
| 1320 | 1320 | if( rc ){ |
| 1321 | 1321 | fossil_fatal("cannot initialize the git repository using: \"%s\"", zCmd); |
| 1322 | 1322 | } |
| @@ -1510,11 +1510,11 @@ | ||
| 1510 | 1510 | while( db_step(&q)==SQLITE_ROW ){ |
| 1511 | 1511 | char *zTagname = fossil_strdup(db_column_text(&q,0)); |
| 1512 | 1512 | const char *zObj = db_column_text(&q,1); |
| 1513 | 1513 | char *zTagCmd; |
| 1514 | 1514 | gitmirror_sanitize_name(zTagname); |
| 1515 | - zTagCmd = mprintf("git tag -f \"%s\" %s", zTagname, zObj); | |
| 1515 | + zTagCmd = mprintf("git tag -f %$ %$", zTagname, zObj); | |
| 1516 | 1516 | fossil_free(zTagname); |
| 1517 | 1517 | gitmirror_message(VERB_NORMAL, "%s\n", zTagCmd); |
| 1518 | 1518 | fossil_system(zTagCmd); |
| 1519 | 1519 | fossil_free(zTagCmd); |
| 1520 | 1520 | } |
| @@ -1545,11 +1545,11 @@ | ||
| 1545 | 1545 | fossil_free(zBrname); |
| 1546 | 1546 | zBrname = fossil_strdup("master"); |
| 1547 | 1547 | }else{ |
| 1548 | 1548 | gitmirror_sanitize_name(zBrname); |
| 1549 | 1549 | } |
| 1550 | - zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %s", zBrname, zObj); | |
| 1550 | + zRefCmd = mprintf("git update-ref \"refs/heads/%s\" %$", zBrname, zObj); | |
| 1551 | 1551 | fossil_free(zBrname); |
| 1552 | 1552 | gitmirror_message(VERB_NORMAL, "%s\n", zRefCmd); |
| 1553 | 1553 | fossil_system(zRefCmd); |
| 1554 | 1554 | fossil_free(zRefCmd); |
| 1555 | 1555 | } |
| @@ -1582,11 +1582,11 @@ | ||
| 1582 | 1582 | }else{ |
| 1583 | 1583 | zPushCmd = mprintf("git push --mirror %s", zPushUrl); |
| 1584 | 1584 | } |
| 1585 | 1585 | gitmirror_message(VERB_NORMAL, "%s\n", zPushCmd); |
| 1586 | 1586 | fossil_free(zPushCmd); |
| 1587 | - zPushCmd = mprintf("git push --mirror %s", zPushUrl); | |
| 1587 | + zPushCmd = mprintf("git push --mirror %$", zPushUrl); | |
| 1588 | 1588 | fossil_system(zPushCmd); |
| 1589 | 1589 | fossil_free(zPushCmd); |
| 1590 | 1590 | } |
| 1591 | 1591 | } |
| 1592 | 1592 | |
| 1593 | 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 \"%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 |
+3
-3
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -263,18 +263,18 @@ | ||
| 263 | 263 | } |
| 264 | 264 | } |
| 265 | 265 | |
| 266 | 266 | /* |
| 267 | 267 | ** 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. | |
| 269 | 269 | */ |
| 270 | 270 | void transport_flip(UrlData *pUrlData){ |
| 271 | 271 | if( pUrlData->isFile ){ |
| 272 | 272 | char *zCmd; |
| 273 | 273 | 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", | |
| 276 | 276 | g.nameOfExe, transport.zOutFile, transport.zInFile, pUrlData->name |
| 277 | 277 | ); |
| 278 | 278 | fossil_system(zCmd); |
| 279 | 279 | free(zCmd); |
| 280 | 280 | transport.pFile = fossil_fopen(transport.zInFile, "rb"); |
| 281 | 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 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 |
+9
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -101,10 +101,12 @@ | ||
| 101 | 101 | #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */ |
| 102 | 102 | #define etSTRINGID 23 /* String with length limit for a hash prefix: %S */ |
| 103 | 103 | #define etROOT 24 /* String value of g.zTop: %R */ |
| 104 | 104 | #define etJSONSTR 25 /* String encoded as a JSON string literal: %j |
| 105 | 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 */ | |
| 106 | 108 | |
| 107 | 109 | |
| 108 | 110 | /* |
| 109 | 111 | ** An "etByte" is an 8-bit unsigned value. |
| 110 | 112 | */ |
| @@ -167,10 +169,11 @@ | ||
| 167 | 169 | { 'i', 10, 1, etRADIX, 0, 0 }, |
| 168 | 170 | { 'n', 0, 0, etSIZE, 0, 0 }, |
| 169 | 171 | { '%', 0, 0, etPERCENT, 0, 0 }, |
| 170 | 172 | { 'p', 16, 0, etPOINTER, 0, 1 }, |
| 171 | 173 | { '/', 0, 0, etPATH, 0, 0 }, |
| 174 | + { '$', 0, 0, etSHELLESC, 0, 0 }, | |
| 172 | 175 | }; |
| 173 | 176 | #define etNINFO count(fmtinfo) |
| 174 | 177 | |
| 175 | 178 | /* |
| 176 | 179 | ** "*val" is a double such that 0.1 <= *val < 10.0 |
| @@ -813,10 +816,16 @@ | ||
| 813 | 816 | blob_init(&wiki, zWiki, limit); |
| 814 | 817 | wiki_convert(&wiki, pBlob, wiki_convert_flags(flag_altform2)); |
| 815 | 818 | blob_reset(&wiki); |
| 816 | 819 | length = width = 0; |
| 817 | 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; | |
| 818 | 827 | } |
| 819 | 828 | case etERROR: |
| 820 | 829 | buf[0] = '%'; |
| 821 | 830 | buf[1] = c; |
| 822 | 831 | errorflag = 0; |
| 823 | 832 |
| --- 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 |
+1
-1
| --- src/unversioned.c | ||
| +++ src/unversioned.c | ||
| @@ -377,11 +377,11 @@ | ||
| 377 | 377 | } |
| 378 | 378 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 379 | 379 | blob_add_cr(&content); |
| 380 | 380 | #endif |
| 381 | 381 | blob_write_to_file(&content, zTFile); |
| 382 | - zCmd = mprintf("%s \"%s\"", zEditor, zTFile); | |
| 382 | + zCmd = mprintf("%s %$", zEditor, zTFile); | |
| 383 | 383 | if( fossil_system(zCmd) ){ |
| 384 | 384 | fossil_fatal("editor aborted: %Q", zCmd); |
| 385 | 385 | } |
| 386 | 386 | fossil_free(zCmd); |
| 387 | 387 | blob_reset(&content); |
| 388 | 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 \"%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 |