Fossil SCM
Updated to include all the latest changes (for which we hold clear title) from the trunk.
Commit
390b4146053df5abc53db66fc36795117e42953b
Parent
a3161f5f1f7d8bb…
15 files changed
+14
-1
+14
-1
+5
+1
-1
+1
-1
+69
-57
+10
-18
+1
+34
-20
+1
-1
+27
-23
+26
-5
+4
-3
+29
-11
+1
-1
+14
-1
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -52,13 +52,20 @@ | ||
| 52 | 52 | fossil_warning("cannot add %s", zPath); |
| 53 | 53 | }else{ |
| 54 | 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | 56 | } |
| 57 | +#ifdef __MINGW32__ | |
| 58 | + if( db_exists("SELECT 1 FROM vfile WHERE pathname LIKE %Q", zPath) ){ | |
| 59 | + db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname LIKE %Q", zPath); | |
| 60 | + } | |
| 61 | +#else | |
| 57 | 62 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 58 | 63 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 59 | - }else{ | |
| 64 | + } | |
| 65 | +#endif | |
| 66 | + else{ | |
| 60 | 67 | db_multi_exec( |
| 61 | 68 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 62 | 69 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 63 | 70 | } |
| 64 | 71 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | ||
| 142 | 149 | db_begin_transaction(); |
| 143 | 150 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 144 | 151 | blob_zero(&repo); |
| 145 | 152 | } |
| 146 | 153 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 154 | +#ifdef __MINGW32__ | |
| 155 | + db_multi_exec( | |
| 156 | + "CREATE INDEX IF NOT EXISTS vfile_pathname " | |
| 157 | + " ON vfile(pathname COLLATE nocase)" | |
| 158 | + ); | |
| 159 | +#endif | |
| 147 | 160 | for(i=2; i<g.argc; i++){ |
| 148 | 161 | char *zName; |
| 149 | 162 | int isDir; |
| 150 | 163 | |
| 151 | 164 | zName = mprintf("%/", g.argv[i]); |
| 152 | 165 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -52,13 +52,20 @@ | |
| 52 | fossil_warning("cannot add %s", zPath); |
| 53 | }else{ |
| 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | } |
| 57 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 58 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 59 | }else{ |
| 60 | db_multi_exec( |
| 61 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 62 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 63 | } |
| 64 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | |
| 142 | db_begin_transaction(); |
| 143 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 144 | blob_zero(&repo); |
| 145 | } |
| 146 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 147 | for(i=2; i<g.argc; i++){ |
| 148 | char *zName; |
| 149 | int isDir; |
| 150 | |
| 151 | zName = mprintf("%/", g.argv[i]); |
| 152 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -52,13 +52,20 @@ | |
| 52 | fossil_warning("cannot add %s", zPath); |
| 53 | }else{ |
| 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | } |
| 57 | #ifdef __MINGW32__ |
| 58 | if( db_exists("SELECT 1 FROM vfile WHERE pathname LIKE %Q", zPath) ){ |
| 59 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname LIKE %Q", zPath); |
| 60 | } |
| 61 | #else |
| 62 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 63 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 64 | } |
| 65 | #endif |
| 66 | else{ |
| 67 | db_multi_exec( |
| 68 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 69 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 70 | } |
| 71 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | |
| 149 | db_begin_transaction(); |
| 150 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 151 | blob_zero(&repo); |
| 152 | } |
| 153 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 154 | #ifdef __MINGW32__ |
| 155 | db_multi_exec( |
| 156 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 157 | " ON vfile(pathname COLLATE nocase)" |
| 158 | ); |
| 159 | #endif |
| 160 | for(i=2; i<g.argc; i++){ |
| 161 | char *zName; |
| 162 | int isDir; |
| 163 | |
| 164 | zName = mprintf("%/", g.argv[i]); |
| 165 |
+14
-1
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -52,13 +52,20 @@ | ||
| 52 | 52 | fossil_warning("cannot add %s", zPath); |
| 53 | 53 | }else{ |
| 54 | 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | 56 | } |
| 57 | +#ifdef __MINGW32__ | |
| 58 | + if( db_exists("SELECT 1 FROM vfile WHERE pathname LIKE %Q", zPath) ){ | |
| 59 | + db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname LIKE %Q", zPath); | |
| 60 | + } | |
| 61 | +#else | |
| 57 | 62 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 58 | 63 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 59 | - }else{ | |
| 64 | + } | |
| 65 | +#endif | |
| 66 | + else{ | |
| 60 | 67 | db_multi_exec( |
| 61 | 68 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 62 | 69 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 63 | 70 | } |
| 64 | 71 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | ||
| 142 | 149 | db_begin_transaction(); |
| 143 | 150 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 144 | 151 | blob_zero(&repo); |
| 145 | 152 | } |
| 146 | 153 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 154 | +#ifdef __MINGW32__ | |
| 155 | + db_multi_exec( | |
| 156 | + "CREATE INDEX IF NOT EXISTS vfile_pathname " | |
| 157 | + " ON vfile(pathname COLLATE nocase)" | |
| 158 | + ); | |
| 159 | +#endif | |
| 147 | 160 | for(i=2; i<g.argc; i++){ |
| 148 | 161 | char *zName; |
| 149 | 162 | int isDir; |
| 150 | 163 | |
| 151 | 164 | zName = mprintf("%/", g.argv[i]); |
| 152 | 165 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -52,13 +52,20 @@ | |
| 52 | fossil_warning("cannot add %s", zPath); |
| 53 | }else{ |
| 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | } |
| 57 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 58 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 59 | }else{ |
| 60 | db_multi_exec( |
| 61 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 62 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 63 | } |
| 64 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | |
| 142 | db_begin_transaction(); |
| 143 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 144 | blob_zero(&repo); |
| 145 | } |
| 146 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 147 | for(i=2; i<g.argc; i++){ |
| 148 | char *zName; |
| 149 | int isDir; |
| 150 | |
| 151 | zName = mprintf("%/", g.argv[i]); |
| 152 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -52,13 +52,20 @@ | |
| 52 | fossil_warning("cannot add %s", zPath); |
| 53 | }else{ |
| 54 | if( !file_is_simple_pathname(zPath) ){ |
| 55 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 56 | } |
| 57 | #ifdef __MINGW32__ |
| 58 | if( db_exists("SELECT 1 FROM vfile WHERE pathname LIKE %Q", zPath) ){ |
| 59 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname LIKE %Q", zPath); |
| 60 | } |
| 61 | #else |
| 62 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 63 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 64 | } |
| 65 | #endif |
| 66 | else{ |
| 67 | db_multi_exec( |
| 68 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" |
| 69 | "VALUES(%d,0,0,0,%Q)", vid, zPath); |
| 70 | } |
| 71 | printf("ADDED %s\n", zPath); |
| @@ -142,10 +149,16 @@ | |
| 149 | db_begin_transaction(); |
| 150 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 151 | blob_zero(&repo); |
| 152 | } |
| 153 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 154 | #ifdef __MINGW32__ |
| 155 | db_multi_exec( |
| 156 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 157 | " ON vfile(pathname COLLATE nocase)" |
| 158 | ); |
| 159 | #endif |
| 160 | for(i=2; i<g.argc; i++){ |
| 161 | char *zName; |
| 162 | int isDir; |
| 163 | |
| 164 | zName = mprintf("%/", g.argv[i]); |
| 165 |
+5
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -445,24 +445,29 @@ | ||
| 445 | 445 | db_end_transaction(0); |
| 446 | 446 | }else |
| 447 | 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | 448 | int mask; |
| 449 | 449 | const char *zServer; |
| 450 | + const char *zPw; | |
| 450 | 451 | url_proxy_options(); |
| 451 | 452 | if( g.argc!=4 && g.argc!=5 ){ |
| 452 | 453 | usage("pull AREA ?URL?"); |
| 453 | 454 | } |
| 454 | 455 | mask = find_area(g.argv[3]); |
| 455 | 456 | if( g.argc==5 ){ |
| 456 | 457 | zServer = g.argv[4]; |
| 458 | + zPw = 0; | |
| 459 | + g.dontKeepUrl = 1; | |
| 457 | 460 | }else{ |
| 458 | 461 | zServer = db_get("last-sync-url", 0); |
| 459 | 462 | if( zServer==0 ){ |
| 460 | 463 | fossil_fatal("no server specified"); |
| 461 | 464 | } |
| 465 | + zPw = db_get("last-sync-pw", 0); | |
| 462 | 466 | } |
| 463 | 467 | url_parse(zServer); |
| 468 | + if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); | |
| 464 | 469 | user_select(); |
| 465 | 470 | if( strncmp(zMethod, "push", n)==0 ){ |
| 466 | 471 | client_sync(0,0,0,0,mask); |
| 467 | 472 | }else{ |
| 468 | 473 | client_sync(0,0,0,mask,0); |
| 469 | 474 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -445,24 +445,29 @@ | |
| 445 | db_end_transaction(0); |
| 446 | }else |
| 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | int mask; |
| 449 | const char *zServer; |
| 450 | url_proxy_options(); |
| 451 | if( g.argc!=4 && g.argc!=5 ){ |
| 452 | usage("pull AREA ?URL?"); |
| 453 | } |
| 454 | mask = find_area(g.argv[3]); |
| 455 | if( g.argc==5 ){ |
| 456 | zServer = g.argv[4]; |
| 457 | }else{ |
| 458 | zServer = db_get("last-sync-url", 0); |
| 459 | if( zServer==0 ){ |
| 460 | fossil_fatal("no server specified"); |
| 461 | } |
| 462 | } |
| 463 | url_parse(zServer); |
| 464 | user_select(); |
| 465 | if( strncmp(zMethod, "push", n)==0 ){ |
| 466 | client_sync(0,0,0,0,mask); |
| 467 | }else{ |
| 468 | client_sync(0,0,0,mask,0); |
| 469 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -445,24 +445,29 @@ | |
| 445 | db_end_transaction(0); |
| 446 | }else |
| 447 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 448 | int mask; |
| 449 | const char *zServer; |
| 450 | const char *zPw; |
| 451 | url_proxy_options(); |
| 452 | if( g.argc!=4 && g.argc!=5 ){ |
| 453 | usage("pull AREA ?URL?"); |
| 454 | } |
| 455 | mask = find_area(g.argv[3]); |
| 456 | if( g.argc==5 ){ |
| 457 | zServer = g.argv[4]; |
| 458 | zPw = 0; |
| 459 | g.dontKeepUrl = 1; |
| 460 | }else{ |
| 461 | zServer = db_get("last-sync-url", 0); |
| 462 | if( zServer==0 ){ |
| 463 | fossil_fatal("no server specified"); |
| 464 | } |
| 465 | zPw = db_get("last-sync-pw", 0); |
| 466 | } |
| 467 | url_parse(zServer); |
| 468 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 469 | user_select(); |
| 470 | if( strncmp(zMethod, "push", n)==0 ){ |
| 471 | client_sync(0,0,0,0,mask); |
| 472 | }else{ |
| 473 | client_sync(0,0,0,mask,0); |
| 474 |
M
src/db.c
+1
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1492,11 +1492,11 @@ | ||
| 1492 | 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | 1493 | ** false, all HTTP requests from localhost have |
| 1494 | 1494 | ** unrestricted access to the repository. |
| 1495 | 1495 | ** |
| 1496 | 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | -** files have been modified. | |
| 1497 | +** files have been modified. (Default "on".) | |
| 1498 | 1498 | ** |
| 1499 | 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | 1501 | ** |
| 1502 | 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 | 1503 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1492,11 +1492,11 @@ | |
| 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | ** false, all HTTP requests from localhost have |
| 1494 | ** unrestricted access to the repository. |
| 1495 | ** |
| 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | ** files have been modified. |
| 1498 | ** |
| 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | ** |
| 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1492,11 +1492,11 @@ | |
| 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | ** false, all HTTP requests from localhost have |
| 1494 | ** unrestricted access to the repository. |
| 1495 | ** |
| 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | ** files have been modified. (Default "on".) |
| 1498 | ** |
| 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | ** |
| 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 |
M
src/db.c
+1
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1492,11 +1492,11 @@ | ||
| 1492 | 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | 1493 | ** false, all HTTP requests from localhost have |
| 1494 | 1494 | ** unrestricted access to the repository. |
| 1495 | 1495 | ** |
| 1496 | 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | -** files have been modified. | |
| 1497 | +** files have been modified. (Default "on".) | |
| 1498 | 1498 | ** |
| 1499 | 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | 1501 | ** |
| 1502 | 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 | 1503 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1492,11 +1492,11 @@ | |
| 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | ** false, all HTTP requests from localhost have |
| 1494 | ** unrestricted access to the repository. |
| 1495 | ** |
| 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | ** files have been modified. |
| 1498 | ** |
| 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | ** |
| 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1492,11 +1492,11 @@ | |
| 1492 | ** 127.0.0.1 be authenticated by password. If |
| 1493 | ** false, all HTTP requests from localhost have |
| 1494 | ** unrestricted access to the repository. |
| 1495 | ** |
| 1496 | ** mtime-changes Use file modification times (mtimes) to detect when |
| 1497 | ** files have been modified. (Default "on".) |
| 1498 | ** |
| 1499 | ** pgp-command Command used to clear-sign manifests at check-in. |
| 1500 | ** The default is "gpg --clearsign -o ". |
| 1501 | ** |
| 1502 | ** proxy URL of the HTTP proxy. If undefined or "off" then |
| 1503 |
+69
-57
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -27,33 +27,91 @@ | ||
| 27 | 27 | #include <sys/types.h> |
| 28 | 28 | #include <sys/stat.h> |
| 29 | 29 | #include <unistd.h> |
| 30 | 30 | #include "file.h" |
| 31 | 31 | |
| 32 | +/* | |
| 33 | +** The file status information from the most recent stat() call. | |
| 34 | +*/ | |
| 35 | +static struct stat fileStat; | |
| 36 | +static int fileStatValid = 0; | |
| 37 | + | |
| 38 | +/* | |
| 39 | +** Fill in the fileStat variable for the file named zFilename. | |
| 40 | +** If zFilename==0, then use the previous value of fileStat if | |
| 41 | +** there is a previous value. | |
| 42 | +** | |
| 43 | +** Return the number of errors. No error messages are generated. | |
| 44 | +*/ | |
| 45 | +static int getStat(const char *zFilename){ | |
| 46 | + if( zFilename==0 ){ | |
| 47 | + if( fileStatValid==0 ) return 1; | |
| 48 | + }else{ | |
| 49 | + if( stat(zFilename, &fileStat)!=0 ) return 1; | |
| 50 | + fileStatValid = 1; | |
| 51 | + } | |
| 52 | + return 0; | |
| 53 | +} | |
| 54 | + | |
| 32 | 55 | |
| 33 | 56 | /* |
| 34 | 57 | ** Return the size of a file in bytes. Return -1 if the file does not |
| 35 | -** exist. | |
| 58 | +** exist. If zFilename is NULL, return the size of the most recently | |
| 59 | +** stat-ed file. | |
| 36 | 60 | */ |
| 37 | 61 | i64 file_size(const char *zFilename){ |
| 38 | - struct stat buf; | |
| 39 | - if( stat(zFilename, &buf)!=0 ){ | |
| 40 | - return -1; | |
| 41 | - } | |
| 42 | - return buf.st_size; | |
| 62 | + return getStat(zFilename) ? -1 : fileStat.st_size; | |
| 43 | 63 | } |
| 44 | 64 | |
| 45 | 65 | /* |
| 46 | 66 | ** Return the modification time for a file. Return -1 if the file |
| 47 | -** does not exist. | |
| 67 | +** does not exist. If zFilename is NULL return the size of the most | |
| 68 | +** recently stat-ed file. | |
| 48 | 69 | */ |
| 49 | 70 | i64 file_mtime(const char *zFilename){ |
| 50 | - struct stat buf; | |
| 51 | - if( stat(zFilename, &buf)!=0 ){ | |
| 52 | - return -1; | |
| 71 | + return getStat(zFilename) ? -1 : fileStat.st_mtime; | |
| 72 | +} | |
| 73 | + | |
| 74 | +/* | |
| 75 | +** Return TRUE if the named file is an ordinary file. Return false | |
| 76 | +** for directories, devices, fifos, symlinks, etc. | |
| 77 | +*/ | |
| 78 | +int file_isfile(const char *zFilename){ | |
| 79 | + return getStat(zFilename) ? 0 : S_ISREG(fileStat.st_mode); | |
| 80 | +} | |
| 81 | + | |
| 82 | +/* | |
| 83 | +** Return TRUE if the named file is an executable. Return false | |
| 84 | +** for directories, devices, fifos, symlinks, etc. | |
| 85 | +*/ | |
| 86 | +int file_isexe(const char *zFilename){ | |
| 87 | + if( getStat(zFilename) || !S_ISREG(fileStat.st_mode) ) return 0; | |
| 88 | +#ifdef __MINGW32__ | |
| 89 | + return ((S_IXUSR)&fileStat.st_mode)!=0; | |
| 90 | +#else | |
| 91 | + return ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0; | |
| 92 | +#endif | |
| 93 | +} | |
| 94 | + | |
| 95 | + | |
| 96 | +/* | |
| 97 | +** Return 1 if zFilename is a directory. Return 0 if zFilename | |
| 98 | +** does not exist. Return 2 if zFilename exists but is something | |
| 99 | +** other than a directory. | |
| 100 | +*/ | |
| 101 | +int file_isdir(const char *zFilename){ | |
| 102 | + int rc; | |
| 103 | + | |
| 104 | + if( zFilename ){ | |
| 105 | + char *zFN = mprintf("%s", zFilename); | |
| 106 | + file_simplify_name(zFN, strlen(zFN)); | |
| 107 | + rc = getStat(zFN); | |
| 108 | + free(zFN); | |
| 109 | + }else{ | |
| 110 | + rc = getStat(0); | |
| 53 | 111 | } |
| 54 | - return buf.st_mtime; | |
| 112 | + return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); | |
| 55 | 113 | } |
| 56 | 114 | |
| 57 | 115 | /* |
| 58 | 116 | ** Return the tail of a file pathname. The tail is the last component |
| 59 | 117 | ** of the path. For example, the tail of "/a/b/c.d" is "c.d". |
| @@ -83,39 +141,10 @@ | ||
| 83 | 141 | } |
| 84 | 142 | fclose(in); |
| 85 | 143 | fclose(out); |
| 86 | 144 | } |
| 87 | 145 | |
| 88 | -/* | |
| 89 | -** Return TRUE if the named file is an ordinary file. Return false | |
| 90 | -** for directories, devices, fifos, symlinks, etc. | |
| 91 | -*/ | |
| 92 | -int file_isfile(const char *zFilename){ | |
| 93 | - struct stat buf; | |
| 94 | - if( stat(zFilename, &buf)!=0 ){ | |
| 95 | - return 0; | |
| 96 | - } | |
| 97 | - return S_ISREG(buf.st_mode); | |
| 98 | -} | |
| 99 | - | |
| 100 | -/* | |
| 101 | -** Return TRUE if the named file is an executable. Return false | |
| 102 | -** for directories, devices, fifos, symlinks, etc. | |
| 103 | -*/ | |
| 104 | -int file_isexe(const char *zFilename){ | |
| 105 | - struct stat buf; | |
| 106 | - if( stat(zFilename, &buf)!=0 ){ | |
| 107 | - return 0; | |
| 108 | - } | |
| 109 | - if( !S_ISREG(buf.st_mode) ) return 0; | |
| 110 | -#ifdef __MINGW32__ | |
| 111 | - return ((S_IXUSR)&buf.st_mode)!=0; | |
| 112 | -#else | |
| 113 | - return ((S_IXUSR|S_IXGRP|S_IXOTH)&buf.st_mode)!=0; | |
| 114 | -#endif | |
| 115 | -} | |
| 116 | - | |
| 117 | 146 | /* |
| 118 | 147 | ** Set or clear the execute bit on a file. |
| 119 | 148 | */ |
| 120 | 149 | void file_setexe(const char *zFilename, int onoff){ |
| 121 | 150 | #ifndef __MINGW32__ |
| @@ -131,27 +160,10 @@ | ||
| 131 | 160 | } |
| 132 | 161 | } |
| 133 | 162 | #endif |
| 134 | 163 | } |
| 135 | 164 | |
| 136 | -/* | |
| 137 | -** Return 1 if zFilename is a directory. Return 0 if zFilename | |
| 138 | -** does not exist. Return 2 if zFilename exists but is something | |
| 139 | -** other than a directory. | |
| 140 | -*/ | |
| 141 | -int file_isdir(const char *zFilename){ | |
| 142 | - struct stat buf; | |
| 143 | - int rc; | |
| 144 | - char *zFN; | |
| 145 | - | |
| 146 | - zFN = mprintf("%s", zFilename); | |
| 147 | - file_simplify_name(zFN, strlen(zFN)); | |
| 148 | - rc = stat(zFN, &buf); | |
| 149 | - free(zFN); | |
| 150 | - return rc!=0 ? 0 : (S_ISDIR(buf.st_mode) ? 1 : 2); | |
| 151 | -} | |
| 152 | - | |
| 153 | 165 | /* |
| 154 | 166 | ** Create the directory named in the argument, if it does not already |
| 155 | 167 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 156 | 168 | ** with the same name. |
| 157 | 169 | ** |
| 158 | 170 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -27,33 +27,91 @@ | |
| 27 | #include <sys/types.h> |
| 28 | #include <sys/stat.h> |
| 29 | #include <unistd.h> |
| 30 | #include "file.h" |
| 31 | |
| 32 | |
| 33 | /* |
| 34 | ** Return the size of a file in bytes. Return -1 if the file does not |
| 35 | ** exist. |
| 36 | */ |
| 37 | i64 file_size(const char *zFilename){ |
| 38 | struct stat buf; |
| 39 | if( stat(zFilename, &buf)!=0 ){ |
| 40 | return -1; |
| 41 | } |
| 42 | return buf.st_size; |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | ** Return the modification time for a file. Return -1 if the file |
| 47 | ** does not exist. |
| 48 | */ |
| 49 | i64 file_mtime(const char *zFilename){ |
| 50 | struct stat buf; |
| 51 | if( stat(zFilename, &buf)!=0 ){ |
| 52 | return -1; |
| 53 | } |
| 54 | return buf.st_mtime; |
| 55 | } |
| 56 | |
| 57 | /* |
| 58 | ** Return the tail of a file pathname. The tail is the last component |
| 59 | ** of the path. For example, the tail of "/a/b/c.d" is "c.d". |
| @@ -83,39 +141,10 @@ | |
| 83 | } |
| 84 | fclose(in); |
| 85 | fclose(out); |
| 86 | } |
| 87 | |
| 88 | /* |
| 89 | ** Return TRUE if the named file is an ordinary file. Return false |
| 90 | ** for directories, devices, fifos, symlinks, etc. |
| 91 | */ |
| 92 | int file_isfile(const char *zFilename){ |
| 93 | struct stat buf; |
| 94 | if( stat(zFilename, &buf)!=0 ){ |
| 95 | return 0; |
| 96 | } |
| 97 | return S_ISREG(buf.st_mode); |
| 98 | } |
| 99 | |
| 100 | /* |
| 101 | ** Return TRUE if the named file is an executable. Return false |
| 102 | ** for directories, devices, fifos, symlinks, etc. |
| 103 | */ |
| 104 | int file_isexe(const char *zFilename){ |
| 105 | struct stat buf; |
| 106 | if( stat(zFilename, &buf)!=0 ){ |
| 107 | return 0; |
| 108 | } |
| 109 | if( !S_ISREG(buf.st_mode) ) return 0; |
| 110 | #ifdef __MINGW32__ |
| 111 | return ((S_IXUSR)&buf.st_mode)!=0; |
| 112 | #else |
| 113 | return ((S_IXUSR|S_IXGRP|S_IXOTH)&buf.st_mode)!=0; |
| 114 | #endif |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | ** Set or clear the execute bit on a file. |
| 119 | */ |
| 120 | void file_setexe(const char *zFilename, int onoff){ |
| 121 | #ifndef __MINGW32__ |
| @@ -131,27 +160,10 @@ | |
| 131 | } |
| 132 | } |
| 133 | #endif |
| 134 | } |
| 135 | |
| 136 | /* |
| 137 | ** Return 1 if zFilename is a directory. Return 0 if zFilename |
| 138 | ** does not exist. Return 2 if zFilename exists but is something |
| 139 | ** other than a directory. |
| 140 | */ |
| 141 | int file_isdir(const char *zFilename){ |
| 142 | struct stat buf; |
| 143 | int rc; |
| 144 | char *zFN; |
| 145 | |
| 146 | zFN = mprintf("%s", zFilename); |
| 147 | file_simplify_name(zFN, strlen(zFN)); |
| 148 | rc = stat(zFN, &buf); |
| 149 | free(zFN); |
| 150 | return rc!=0 ? 0 : (S_ISDIR(buf.st_mode) ? 1 : 2); |
| 151 | } |
| 152 | |
| 153 | /* |
| 154 | ** Create the directory named in the argument, if it does not already |
| 155 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 156 | ** with the same name. |
| 157 | ** |
| 158 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -27,33 +27,91 @@ | |
| 27 | #include <sys/types.h> |
| 28 | #include <sys/stat.h> |
| 29 | #include <unistd.h> |
| 30 | #include "file.h" |
| 31 | |
| 32 | /* |
| 33 | ** The file status information from the most recent stat() call. |
| 34 | */ |
| 35 | static struct stat fileStat; |
| 36 | static int fileStatValid = 0; |
| 37 | |
| 38 | /* |
| 39 | ** Fill in the fileStat variable for the file named zFilename. |
| 40 | ** If zFilename==0, then use the previous value of fileStat if |
| 41 | ** there is a previous value. |
| 42 | ** |
| 43 | ** Return the number of errors. No error messages are generated. |
| 44 | */ |
| 45 | static int getStat(const char *zFilename){ |
| 46 | if( zFilename==0 ){ |
| 47 | if( fileStatValid==0 ) return 1; |
| 48 | }else{ |
| 49 | if( stat(zFilename, &fileStat)!=0 ) return 1; |
| 50 | fileStatValid = 1; |
| 51 | } |
| 52 | return 0; |
| 53 | } |
| 54 | |
| 55 | |
| 56 | /* |
| 57 | ** Return the size of a file in bytes. Return -1 if the file does not |
| 58 | ** exist. If zFilename is NULL, return the size of the most recently |
| 59 | ** stat-ed file. |
| 60 | */ |
| 61 | i64 file_size(const char *zFilename){ |
| 62 | return getStat(zFilename) ? -1 : fileStat.st_size; |
| 63 | } |
| 64 | |
| 65 | /* |
| 66 | ** Return the modification time for a file. Return -1 if the file |
| 67 | ** does not exist. If zFilename is NULL return the size of the most |
| 68 | ** recently stat-ed file. |
| 69 | */ |
| 70 | i64 file_mtime(const char *zFilename){ |
| 71 | return getStat(zFilename) ? -1 : fileStat.st_mtime; |
| 72 | } |
| 73 | |
| 74 | /* |
| 75 | ** Return TRUE if the named file is an ordinary file. Return false |
| 76 | ** for directories, devices, fifos, symlinks, etc. |
| 77 | */ |
| 78 | int file_isfile(const char *zFilename){ |
| 79 | return getStat(zFilename) ? 0 : S_ISREG(fileStat.st_mode); |
| 80 | } |
| 81 | |
| 82 | /* |
| 83 | ** Return TRUE if the named file is an executable. Return false |
| 84 | ** for directories, devices, fifos, symlinks, etc. |
| 85 | */ |
| 86 | int file_isexe(const char *zFilename){ |
| 87 | if( getStat(zFilename) || !S_ISREG(fileStat.st_mode) ) return 0; |
| 88 | #ifdef __MINGW32__ |
| 89 | return ((S_IXUSR)&fileStat.st_mode)!=0; |
| 90 | #else |
| 91 | return ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0; |
| 92 | #endif |
| 93 | } |
| 94 | |
| 95 | |
| 96 | /* |
| 97 | ** Return 1 if zFilename is a directory. Return 0 if zFilename |
| 98 | ** does not exist. Return 2 if zFilename exists but is something |
| 99 | ** other than a directory. |
| 100 | */ |
| 101 | int file_isdir(const char *zFilename){ |
| 102 | int rc; |
| 103 | |
| 104 | if( zFilename ){ |
| 105 | char *zFN = mprintf("%s", zFilename); |
| 106 | file_simplify_name(zFN, strlen(zFN)); |
| 107 | rc = getStat(zFN); |
| 108 | free(zFN); |
| 109 | }else{ |
| 110 | rc = getStat(0); |
| 111 | } |
| 112 | return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** Return the tail of a file pathname. The tail is the last component |
| 117 | ** of the path. For example, the tail of "/a/b/c.d" is "c.d". |
| @@ -83,39 +141,10 @@ | |
| 141 | } |
| 142 | fclose(in); |
| 143 | fclose(out); |
| 144 | } |
| 145 | |
| 146 | /* |
| 147 | ** Set or clear the execute bit on a file. |
| 148 | */ |
| 149 | void file_setexe(const char *zFilename, int onoff){ |
| 150 | #ifndef __MINGW32__ |
| @@ -131,27 +160,10 @@ | |
| 160 | } |
| 161 | } |
| 162 | #endif |
| 163 | } |
| 164 | |
| 165 | /* |
| 166 | ** Create the directory named in the argument, if it does not already |
| 167 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 168 | ** with the same name. |
| 169 | ** |
| 170 |
+10
-18
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -44,33 +44,25 @@ | ||
| 44 | 44 | const char *zLogin; /* The user login name */ |
| 45 | 45 | const char *zPw; /* The user password */ |
| 46 | 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | 47 | Blob sig; /* The signature field */ |
| 48 | 48 | |
| 49 | + blob_zero(pLogin); | |
| 50 | + if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){ | |
| 51 | + return; /* If no login card for users "nobody" and "anonymous" */ | |
| 52 | + } | |
| 49 | 53 | blob_zero(&nonce); |
| 50 | 54 | blob_zero(&pw); |
| 51 | 55 | sha1sum_blob(pPayload, &nonce); |
| 52 | 56 | blob_copy(&pw, &nonce); |
| 53 | - blob_zero(pLogin); | |
| 54 | - if( g.urlUser==0 ){ | |
| 55 | - user_select(); | |
| 56 | - zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", g.userUid); | |
| 57 | - zLogin = g.zLogin; | |
| 58 | - }else{ | |
| 59 | - if( g.urlPasswd==0 ){ | |
| 60 | - if( strcmp(g.urlUser,"anonymous")!=0 ){ | |
| 61 | - char *zPrompt = mprintf("password for %s: ", g.urlUser); | |
| 62 | - Blob x; | |
| 63 | - prompt_for_password(zPrompt, &x, 0); | |
| 64 | - free(zPrompt); | |
| 65 | - g.urlPasswd = blob_str(&x); | |
| 66 | - }else{ | |
| 67 | - g.urlPasswd = ""; | |
| 68 | - } | |
| 69 | - } | |
| 57 | + zLogin = g.urlUser; | |
| 58 | + if( g.urlPasswd ){ | |
| 59 | + zPw = g.urlPasswd; | |
| 60 | + }else{ | |
| 61 | + url_prompt_for_password(); | |
| 70 | 62 | zPw = g.urlPasswd; |
| 71 | - zLogin = g.urlUser; | |
| 63 | + if( !g.dontKeepUrl ) db_set("last-sync-pw", zPw, 0); | |
| 72 | 64 | } |
| 73 | 65 | |
| 74 | 66 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | 67 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | 68 | ** |
| 77 | 69 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -44,33 +44,25 @@ | |
| 44 | const char *zLogin; /* The user login name */ |
| 45 | const char *zPw; /* The user password */ |
| 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | Blob sig; /* The signature field */ |
| 48 | |
| 49 | blob_zero(&nonce); |
| 50 | blob_zero(&pw); |
| 51 | sha1sum_blob(pPayload, &nonce); |
| 52 | blob_copy(&pw, &nonce); |
| 53 | blob_zero(pLogin); |
| 54 | if( g.urlUser==0 ){ |
| 55 | user_select(); |
| 56 | zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", g.userUid); |
| 57 | zLogin = g.zLogin; |
| 58 | }else{ |
| 59 | if( g.urlPasswd==0 ){ |
| 60 | if( strcmp(g.urlUser,"anonymous")!=0 ){ |
| 61 | char *zPrompt = mprintf("password for %s: ", g.urlUser); |
| 62 | Blob x; |
| 63 | prompt_for_password(zPrompt, &x, 0); |
| 64 | free(zPrompt); |
| 65 | g.urlPasswd = blob_str(&x); |
| 66 | }else{ |
| 67 | g.urlPasswd = ""; |
| 68 | } |
| 69 | } |
| 70 | zPw = g.urlPasswd; |
| 71 | zLogin = g.urlUser; |
| 72 | } |
| 73 | |
| 74 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | ** |
| 77 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -44,33 +44,25 @@ | |
| 44 | const char *zLogin; /* The user login name */ |
| 45 | const char *zPw; /* The user password */ |
| 46 | Blob pw; /* The nonce with user password appended */ |
| 47 | Blob sig; /* The signature field */ |
| 48 | |
| 49 | blob_zero(pLogin); |
| 50 | if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){ |
| 51 | return; /* If no login card for users "nobody" and "anonymous" */ |
| 52 | } |
| 53 | blob_zero(&nonce); |
| 54 | blob_zero(&pw); |
| 55 | sha1sum_blob(pPayload, &nonce); |
| 56 | blob_copy(&pw, &nonce); |
| 57 | zLogin = g.urlUser; |
| 58 | if( g.urlPasswd ){ |
| 59 | zPw = g.urlPasswd; |
| 60 | }else{ |
| 61 | url_prompt_for_password(); |
| 62 | zPw = g.urlPasswd; |
| 63 | if( !g.dontKeepUrl ) db_set("last-sync-pw", zPw, 0); |
| 64 | } |
| 65 | |
| 66 | /* The login card wants the SHA1 hash of the password, so convert the |
| 67 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 68 | ** |
| 69 |
+1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -101,10 +101,11 @@ | ||
| 101 | 101 | char *urlPath; /* Pathname for http: */ |
| 102 | 102 | char *urlUser; /* User id for http: */ |
| 103 | 103 | char *urlPasswd; /* Password for http: */ |
| 104 | 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | + int dontKeepUrl; /* Do not persist the URL */ | |
| 106 | 107 | |
| 107 | 108 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 108 | 109 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 109 | 110 | int userUid; /* Integer user id */ |
| 110 | 111 | |
| 111 | 112 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -101,10 +101,11 @@ | |
| 101 | char *urlPath; /* Pathname for http: */ |
| 102 | char *urlUser; /* User id for http: */ |
| 103 | char *urlPasswd; /* Password for http: */ |
| 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | |
| 107 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 108 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 109 | int userUid; /* Integer user id */ |
| 110 | |
| 111 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -101,10 +101,11 @@ | |
| 101 | char *urlPath; /* Pathname for http: */ |
| 102 | char *urlUser; /* User id for http: */ |
| 103 | char *urlPasswd; /* Password for http: */ |
| 104 | char *urlCanonical; /* Canonical representation of the URL */ |
| 105 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| 106 | int dontKeepUrl; /* Do not persist the URL */ |
| 107 | |
| 108 | const char *zLogin; /* Login name. "" if not logged in. */ |
| 109 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 110 | int userUid; /* Integer user id */ |
| 111 | |
| 112 |
+34
-20
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -30,56 +30,68 @@ | ||
| 30 | 30 | |
| 31 | 31 | |
| 32 | 32 | /* |
| 33 | 33 | ** COMMAND: merge |
| 34 | 34 | ** |
| 35 | -** Usage: %fossil merge VERSION | |
| 35 | +** Usage: %fossil merge [--cherrypick] VERSION | |
| 36 | 36 | ** |
| 37 | 37 | ** The argument is a version that should be merged into the current |
| 38 | -** checkout. | |
| 38 | +** checkout. All changes from VERSION back to the nearest common | |
| 39 | +** ancestor are merged. Except, if the --cherrypick option is used | |
| 40 | +** only the changes associated with the single check-in VERSION are | |
| 41 | +** merged. | |
| 39 | 42 | ** |
| 40 | 43 | ** Only file content is merged. The result continues to use the |
| 41 | 44 | ** file and directory names from the current check-out even if those |
| 42 | 45 | ** names might have been changed in the branch being merged in. |
| 43 | 46 | */ |
| 44 | 47 | void merge_cmd(void){ |
| 45 | 48 | int vid; /* Current version */ |
| 46 | 49 | int mid; /* Version we are merging against */ |
| 47 | 50 | int pid; /* The pivot version - most recent common ancestor */ |
| 51 | + int detailFlag; /* True if the --detail option is present */ | |
| 52 | + int pickFlag; /* True if the --cherrypick option is present */ | |
| 48 | 53 | Stmt q; |
| 49 | - int detailFlag; | |
| 50 | 54 | |
| 51 | 55 | detailFlag = find_option("detail",0,0)!=0; |
| 56 | + pickFlag = find_option("cherrypick",0,0)!=0; | |
| 52 | 57 | if( g.argc!=3 ){ |
| 53 | 58 | usage("VERSION"); |
| 54 | 59 | } |
| 55 | 60 | db_must_be_within_tree(); |
| 56 | 61 | vid = db_lget_int("checkout", 0); |
| 57 | 62 | if( vid==0 ){ |
| 58 | - fossil_panic("nothing is checked out"); | |
| 63 | + fossil_fatal("nothing is checked out"); | |
| 59 | 64 | } |
| 60 | 65 | mid = name_to_rid(g.argv[2]); |
| 61 | 66 | if( mid==0 ){ |
| 62 | - fossil_panic("not a version: %s", g.argv[2]); | |
| 67 | + fossil_fatal("not a version: %s", g.argv[2]); | |
| 63 | 68 | } |
| 64 | 69 | if( mid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", mid) ){ |
| 65 | - fossil_panic("not a version: %s", g.argv[2]); | |
| 66 | - } | |
| 67 | - pivot_set_primary(mid); | |
| 68 | - pivot_set_secondary(vid); | |
| 69 | - db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); | |
| 70 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 71 | - pivot_set_secondary(db_column_int(&q,0)); | |
| 72 | - } | |
| 73 | - db_finalize(&q); | |
| 74 | - pid = pivot_find(); | |
| 75 | - if( pid<=0 ){ | |
| 76 | - fossil_panic("cannot find a common ancestor between the current" | |
| 77 | - "checkout and %s", g.argv[2]); | |
| 70 | + fossil_fatal("not a version: %s", g.argv[2]); | |
| 71 | + } | |
| 72 | + if( pickFlag ){ | |
| 73 | + pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); | |
| 74 | + if( pid<=0 ){ | |
| 75 | + fossil_fatal("cannot find an ancestor for %s", g.argv[2]); | |
| 76 | + } | |
| 77 | + }else{ | |
| 78 | + pivot_set_primary(mid); | |
| 79 | + pivot_set_secondary(vid); | |
| 80 | + db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); | |
| 81 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 82 | + pivot_set_secondary(db_column_int(&q,0)); | |
| 83 | + } | |
| 84 | + db_finalize(&q); | |
| 85 | + pid = pivot_find(); | |
| 86 | + if( pid<=0 ){ | |
| 87 | + fossil_fatal("cannot find a common ancestor between the current" | |
| 88 | + "checkout and %s", g.argv[2]); | |
| 89 | + } | |
| 78 | 90 | } |
| 79 | 91 | if( pid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", pid) ){ |
| 80 | - fossil_panic("not a version: record #%d", mid); | |
| 92 | + fossil_fatal("not a version: record #%d", mid); | |
| 81 | 93 | } |
| 82 | 94 | vfile_check_signature(vid, 1); |
| 83 | 95 | db_begin_transaction(); |
| 84 | 96 | undo_begin(); |
| 85 | 97 | load_vfile_from_rid(mid); |
| @@ -285,9 +297,11 @@ | ||
| 285 | 297 | |
| 286 | 298 | /* |
| 287 | 299 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 288 | 300 | */ |
| 289 | 301 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 290 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); | |
| 302 | + if( !pickFlag ){ | |
| 303 | + db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); | |
| 304 | + } | |
| 291 | 305 | undo_finish(); |
| 292 | 306 | db_end_transaction(0); |
| 293 | 307 | } |
| 294 | 308 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -30,56 +30,68 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: merge |
| 34 | ** |
| 35 | ** Usage: %fossil merge VERSION |
| 36 | ** |
| 37 | ** The argument is a version that should be merged into the current |
| 38 | ** checkout. |
| 39 | ** |
| 40 | ** Only file content is merged. The result continues to use the |
| 41 | ** file and directory names from the current check-out even if those |
| 42 | ** names might have been changed in the branch being merged in. |
| 43 | */ |
| 44 | void merge_cmd(void){ |
| 45 | int vid; /* Current version */ |
| 46 | int mid; /* Version we are merging against */ |
| 47 | int pid; /* The pivot version - most recent common ancestor */ |
| 48 | Stmt q; |
| 49 | int detailFlag; |
| 50 | |
| 51 | detailFlag = find_option("detail",0,0)!=0; |
| 52 | if( g.argc!=3 ){ |
| 53 | usage("VERSION"); |
| 54 | } |
| 55 | db_must_be_within_tree(); |
| 56 | vid = db_lget_int("checkout", 0); |
| 57 | if( vid==0 ){ |
| 58 | fossil_panic("nothing is checked out"); |
| 59 | } |
| 60 | mid = name_to_rid(g.argv[2]); |
| 61 | if( mid==0 ){ |
| 62 | fossil_panic("not a version: %s", g.argv[2]); |
| 63 | } |
| 64 | if( mid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", mid) ){ |
| 65 | fossil_panic("not a version: %s", g.argv[2]); |
| 66 | } |
| 67 | pivot_set_primary(mid); |
| 68 | pivot_set_secondary(vid); |
| 69 | db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); |
| 70 | while( db_step(&q)==SQLITE_ROW ){ |
| 71 | pivot_set_secondary(db_column_int(&q,0)); |
| 72 | } |
| 73 | db_finalize(&q); |
| 74 | pid = pivot_find(); |
| 75 | if( pid<=0 ){ |
| 76 | fossil_panic("cannot find a common ancestor between the current" |
| 77 | "checkout and %s", g.argv[2]); |
| 78 | } |
| 79 | if( pid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", pid) ){ |
| 80 | fossil_panic("not a version: record #%d", mid); |
| 81 | } |
| 82 | vfile_check_signature(vid, 1); |
| 83 | db_begin_transaction(); |
| 84 | undo_begin(); |
| 85 | load_vfile_from_rid(mid); |
| @@ -285,9 +297,11 @@ | |
| 285 | |
| 286 | /* |
| 287 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 288 | */ |
| 289 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 290 | db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); |
| 291 | undo_finish(); |
| 292 | db_end_transaction(0); |
| 293 | } |
| 294 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -30,56 +30,68 @@ | |
| 30 | |
| 31 | |
| 32 | /* |
| 33 | ** COMMAND: merge |
| 34 | ** |
| 35 | ** Usage: %fossil merge [--cherrypick] VERSION |
| 36 | ** |
| 37 | ** The argument is a version that should be merged into the current |
| 38 | ** checkout. All changes from VERSION back to the nearest common |
| 39 | ** ancestor are merged. Except, if the --cherrypick option is used |
| 40 | ** only the changes associated with the single check-in VERSION are |
| 41 | ** merged. |
| 42 | ** |
| 43 | ** Only file content is merged. The result continues to use the |
| 44 | ** file and directory names from the current check-out even if those |
| 45 | ** names might have been changed in the branch being merged in. |
| 46 | */ |
| 47 | void merge_cmd(void){ |
| 48 | int vid; /* Current version */ |
| 49 | int mid; /* Version we are merging against */ |
| 50 | int pid; /* The pivot version - most recent common ancestor */ |
| 51 | int detailFlag; /* True if the --detail option is present */ |
| 52 | int pickFlag; /* True if the --cherrypick option is present */ |
| 53 | Stmt q; |
| 54 | |
| 55 | detailFlag = find_option("detail",0,0)!=0; |
| 56 | pickFlag = find_option("cherrypick",0,0)!=0; |
| 57 | if( g.argc!=3 ){ |
| 58 | usage("VERSION"); |
| 59 | } |
| 60 | db_must_be_within_tree(); |
| 61 | vid = db_lget_int("checkout", 0); |
| 62 | if( vid==0 ){ |
| 63 | fossil_fatal("nothing is checked out"); |
| 64 | } |
| 65 | mid = name_to_rid(g.argv[2]); |
| 66 | if( mid==0 ){ |
| 67 | fossil_fatal("not a version: %s", g.argv[2]); |
| 68 | } |
| 69 | if( mid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", mid) ){ |
| 70 | fossil_fatal("not a version: %s", g.argv[2]); |
| 71 | } |
| 72 | if( pickFlag ){ |
| 73 | pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
| 74 | if( pid<=0 ){ |
| 75 | fossil_fatal("cannot find an ancestor for %s", g.argv[2]); |
| 76 | } |
| 77 | }else{ |
| 78 | pivot_set_primary(mid); |
| 79 | pivot_set_secondary(vid); |
| 80 | db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); |
| 81 | while( db_step(&q)==SQLITE_ROW ){ |
| 82 | pivot_set_secondary(db_column_int(&q,0)); |
| 83 | } |
| 84 | db_finalize(&q); |
| 85 | pid = pivot_find(); |
| 86 | if( pid<=0 ){ |
| 87 | fossil_fatal("cannot find a common ancestor between the current" |
| 88 | "checkout and %s", g.argv[2]); |
| 89 | } |
| 90 | } |
| 91 | if( pid>1 && !db_exists("SELECT 1 FROM plink WHERE cid=%d", pid) ){ |
| 92 | fossil_fatal("not a version: record #%d", mid); |
| 93 | } |
| 94 | vfile_check_signature(vid, 1); |
| 95 | db_begin_transaction(); |
| 96 | undo_begin(); |
| 97 | load_vfile_from_rid(mid); |
| @@ -285,9 +297,11 @@ | |
| 297 | |
| 298 | /* |
| 299 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 300 | */ |
| 301 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 302 | if( !pickFlag ){ |
| 303 | db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); |
| 304 | } |
| 305 | undo_finish(); |
| 306 | db_end_transaction(0); |
| 307 | } |
| 308 |
+1
-1
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -384,11 +384,11 @@ | ||
| 384 | 384 | } |
| 385 | 385 | } |
| 386 | 386 | db_begin_transaction(); |
| 387 | 387 | db_multi_exec( |
| 388 | 388 | "UPDATE user SET pw='';" |
| 389 | - "DELETE FROM config WHERE name='last-sync-url';" | |
| 389 | + "DELETE FROM config WHERE name GLOB 'last-sync-*';" | |
| 390 | 390 | ); |
| 391 | 391 | if( bVerily ){ |
| 392 | 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | 393 | db_multi_exec( |
| 394 | 394 | "DELETE FROM concealed;" |
| 395 | 395 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -384,11 +384,11 @@ | |
| 384 | } |
| 385 | } |
| 386 | db_begin_transaction(); |
| 387 | db_multi_exec( |
| 388 | "UPDATE user SET pw='';" |
| 389 | "DELETE FROM config WHERE name='last-sync-url';" |
| 390 | ); |
| 391 | if( bVerily ){ |
| 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | db_multi_exec( |
| 394 | "DELETE FROM concealed;" |
| 395 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -384,11 +384,11 @@ | |
| 384 | } |
| 385 | } |
| 386 | db_begin_transaction(); |
| 387 | db_multi_exec( |
| 388 | "UPDATE user SET pw='';" |
| 389 | "DELETE FROM config WHERE name GLOB 'last-sync-*';" |
| 390 | ); |
| 391 | if( bVerily ){ |
| 392 | bNeedRebuild = db_exists("SELECT 1 FROM private"); |
| 393 | db_multi_exec( |
| 394 | "DELETE FROM concealed;" |
| 395 |
+27
-23
| --- src/sync.c | ||
| +++ src/sync.c | ||
| @@ -42,10 +42,11 @@ | ||
| 42 | 42 | ** if the argument is false. |
| 43 | 43 | */ |
| 44 | 44 | void autosync(int flags){ |
| 45 | 45 | const char *zUrl; |
| 46 | 46 | const char *zAutosync; |
| 47 | + const char *zPw; | |
| 47 | 48 | if( g.fNoSync ){ |
| 48 | 49 | return; |
| 49 | 50 | } |
| 50 | 51 | zAutosync = db_get("autosync", 0); |
| 51 | 52 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | ||
| 60 | 61 | } |
| 61 | 62 | zUrl = db_get("last-sync-url", 0); |
| 62 | 63 | if( zUrl==0 ){ |
| 63 | 64 | return; /* No default server */ |
| 64 | 65 | } |
| 66 | + zPw = db_get("last-sync-pw", 0); | |
| 65 | 67 | url_parse(zUrl); |
| 66 | - if( g.urlPort!=g.urlDfltPort ){ | |
| 67 | - printf("Autosync: %s://%s:%d%s\n", | |
| 68 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 69 | - }else{ | |
| 70 | - printf("Autosync: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); | |
| 68 | + if( g.urlUser!=0 && g.urlPasswd==0 ){ | |
| 69 | + g.urlPasswd = mprintf("%s", zPw); | |
| 71 | 70 | } |
| 71 | + printf("Autosync: %s\n", g.urlCanonical); | |
| 72 | 72 | url_enable_proxy("via proxy: "); |
| 73 | 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | /* |
| @@ -79,35 +79,36 @@ | ||
| 79 | 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | 81 | */ |
| 82 | 82 | void process_sync_args(void){ |
| 83 | 83 | const char *zUrl = 0; |
| 84 | + const char *zPw = 0; | |
| 84 | 85 | int urlOptional = find_option("autourl",0,0)!=0; |
| 85 | - int dontKeepUrl = find_option("once",0,0)!=0; | |
| 86 | + g.dontKeepUrl = find_option("once",0,0)!=0; | |
| 86 | 87 | url_proxy_options(); |
| 87 | 88 | db_find_and_open_repository(1); |
| 88 | 89 | if( g.argc==2 ){ |
| 89 | 90 | zUrl = db_get("last-sync-url", 0); |
| 91 | + zPw = db_get("last-sync-pw", 0); | |
| 90 | 92 | }else if( g.argc==3 ){ |
| 91 | 93 | zUrl = g.argv[2]; |
| 92 | 94 | } |
| 93 | 95 | if( zUrl==0 ){ |
| 94 | 96 | if( urlOptional ) exit(0); |
| 95 | 97 | usage("URL"); |
| 96 | 98 | } |
| 97 | 99 | url_parse(zUrl); |
| 98 | - if( !dontKeepUrl ){ | |
| 99 | - db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : zUrl, 0); | |
| 100 | + if( !g.dontKeepUrl ){ | |
| 101 | + db_set("last-sync-url", g.urlCanonical, 0); | |
| 102 | + if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0); | |
| 103 | + } | |
| 104 | + if( g.urlUser!=0 && g.urlPasswd==0 ){ | |
| 105 | + g.urlPasswd = mprintf("%s", zPw); | |
| 100 | 106 | } |
| 101 | 107 | user_select(); |
| 102 | 108 | if( g.argc==2 ){ |
| 103 | - if( g.urlPort!=g.urlDfltPort ){ | |
| 104 | - printf("Server: %s://%s:%d%s\n", | |
| 105 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 106 | - }else{ | |
| 107 | - printf("Server: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); | |
| 108 | - } | |
| 109 | + printf("Server: %s\n", g.urlCanonical); | |
| 109 | 110 | } |
| 110 | 111 | url_enable_proxy("via proxy: "); |
| 111 | 112 | } |
| 112 | 113 | |
| 113 | 114 | /* |
| @@ -189,46 +190,49 @@ | ||
| 189 | 190 | } |
| 190 | 191 | |
| 191 | 192 | /* |
| 192 | 193 | ** COMMAND: remote-url |
| 193 | 194 | ** |
| 194 | -** Usage: %fossil remote-url ?URL|off? --show-pw | |
| 195 | +** Usage: %fossil remote-url ?URL|off? | |
| 195 | 196 | ** |
| 196 | 197 | ** Query and/or change the default server URL used by the "pull", "push", |
| 197 | 198 | ** and "sync" commands. |
| 198 | 199 | ** |
| 199 | -** The userid and password are of the URL are not printed unless | |
| 200 | -** the --show-pw option is used on the command-line. | |
| 201 | -** | |
| 202 | 200 | ** The remote-url is set automatically by a "clone" command or by any |
| 203 | 201 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 204 | 202 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 205 | 203 | ** "pull" that omit the server URL. |
| 206 | 204 | ** |
| 207 | 205 | ** See also: clone, push, pull, sync |
| 208 | 206 | */ |
| 209 | 207 | void remote_url_cmd(void){ |
| 210 | 208 | char *zUrl; |
| 211 | - int showPw = find_option("show-pw",0,0)!=0; | |
| 212 | 209 | db_find_and_open_repository(1); |
| 213 | 210 | if( g.argc!=2 && g.argc!=3 ){ |
| 214 | 211 | usage("remote-url ?URL|off?"); |
| 215 | 212 | } |
| 216 | 213 | if( g.argc==3 ){ |
| 217 | 214 | if( strcmp(g.argv[2],"off")==0 ){ |
| 218 | 215 | db_unset("last-sync-url", 0); |
| 216 | + db_unset("last-sync-pw", 0); | |
| 219 | 217 | }else{ |
| 220 | 218 | url_parse(g.argv[2]); |
| 221 | - db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : g.argv[2], 0); | |
| 219 | + if( g.urlUser && g.urlPasswd==0 ){ | |
| 220 | + url_prompt_for_password(); | |
| 221 | + } | |
| 222 | + db_set("last-sync-url", g.urlCanonical, 0); | |
| 223 | + if( g.urlPasswd ){ | |
| 224 | + db_set("last-sync-pw", g.urlPasswd, 0); | |
| 225 | + }else{ | |
| 226 | + db_unset("last-sync-pw", 0); | |
| 227 | + } | |
| 222 | 228 | } |
| 223 | 229 | } |
| 224 | 230 | zUrl = db_get("last-sync-url", 0); |
| 225 | 231 | if( zUrl==0 ){ |
| 226 | 232 | printf("off\n"); |
| 227 | 233 | return; |
| 228 | - }else if( showPw ){ | |
| 229 | - g.urlCanonical = zUrl; | |
| 230 | 234 | }else{ |
| 231 | 235 | url_parse(zUrl); |
| 236 | + printf("%s\n", g.urlCanonical); | |
| 232 | 237 | } |
| 233 | - printf("%s\n", g.urlCanonical); | |
| 234 | 238 | } |
| 235 | 239 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -42,10 +42,11 @@ | |
| 42 | ** if the argument is false. |
| 43 | */ |
| 44 | void autosync(int flags){ |
| 45 | const char *zUrl; |
| 46 | const char *zAutosync; |
| 47 | if( g.fNoSync ){ |
| 48 | return; |
| 49 | } |
| 50 | zAutosync = db_get("autosync", 0); |
| 51 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | |
| 60 | } |
| 61 | zUrl = db_get("last-sync-url", 0); |
| 62 | if( zUrl==0 ){ |
| 63 | return; /* No default server */ |
| 64 | } |
| 65 | url_parse(zUrl); |
| 66 | if( g.urlPort!=g.urlDfltPort ){ |
| 67 | printf("Autosync: %s://%s:%d%s\n", |
| 68 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 69 | }else{ |
| 70 | printf("Autosync: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); |
| 71 | } |
| 72 | url_enable_proxy("via proxy: "); |
| 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | } |
| 75 | |
| 76 | /* |
| @@ -79,35 +79,36 @@ | |
| 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | */ |
| 82 | void process_sync_args(void){ |
| 83 | const char *zUrl = 0; |
| 84 | int urlOptional = find_option("autourl",0,0)!=0; |
| 85 | int dontKeepUrl = find_option("once",0,0)!=0; |
| 86 | url_proxy_options(); |
| 87 | db_find_and_open_repository(1); |
| 88 | if( g.argc==2 ){ |
| 89 | zUrl = db_get("last-sync-url", 0); |
| 90 | }else if( g.argc==3 ){ |
| 91 | zUrl = g.argv[2]; |
| 92 | } |
| 93 | if( zUrl==0 ){ |
| 94 | if( urlOptional ) exit(0); |
| 95 | usage("URL"); |
| 96 | } |
| 97 | url_parse(zUrl); |
| 98 | if( !dontKeepUrl ){ |
| 99 | db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : zUrl, 0); |
| 100 | } |
| 101 | user_select(); |
| 102 | if( g.argc==2 ){ |
| 103 | if( g.urlPort!=g.urlDfltPort ){ |
| 104 | printf("Server: %s://%s:%d%s\n", |
| 105 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 106 | }else{ |
| 107 | printf("Server: %s://%s%s\n", g.urlProtocol, g.urlName, g.urlPath); |
| 108 | } |
| 109 | } |
| 110 | url_enable_proxy("via proxy: "); |
| 111 | } |
| 112 | |
| 113 | /* |
| @@ -189,46 +190,49 @@ | |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | ** COMMAND: remote-url |
| 193 | ** |
| 194 | ** Usage: %fossil remote-url ?URL|off? --show-pw |
| 195 | ** |
| 196 | ** Query and/or change the default server URL used by the "pull", "push", |
| 197 | ** and "sync" commands. |
| 198 | ** |
| 199 | ** The userid and password are of the URL are not printed unless |
| 200 | ** the --show-pw option is used on the command-line. |
| 201 | ** |
| 202 | ** The remote-url is set automatically by a "clone" command or by any |
| 203 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 204 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 205 | ** "pull" that omit the server URL. |
| 206 | ** |
| 207 | ** See also: clone, push, pull, sync |
| 208 | */ |
| 209 | void remote_url_cmd(void){ |
| 210 | char *zUrl; |
| 211 | int showPw = find_option("show-pw",0,0)!=0; |
| 212 | db_find_and_open_repository(1); |
| 213 | if( g.argc!=2 && g.argc!=3 ){ |
| 214 | usage("remote-url ?URL|off?"); |
| 215 | } |
| 216 | if( g.argc==3 ){ |
| 217 | if( strcmp(g.argv[2],"off")==0 ){ |
| 218 | db_unset("last-sync-url", 0); |
| 219 | }else{ |
| 220 | url_parse(g.argv[2]); |
| 221 | db_set("last-sync-url", g.urlIsFile ? g.urlCanonical : g.argv[2], 0); |
| 222 | } |
| 223 | } |
| 224 | zUrl = db_get("last-sync-url", 0); |
| 225 | if( zUrl==0 ){ |
| 226 | printf("off\n"); |
| 227 | return; |
| 228 | }else if( showPw ){ |
| 229 | g.urlCanonical = zUrl; |
| 230 | }else{ |
| 231 | url_parse(zUrl); |
| 232 | } |
| 233 | printf("%s\n", g.urlCanonical); |
| 234 | } |
| 235 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -42,10 +42,11 @@ | |
| 42 | ** if the argument is false. |
| 43 | */ |
| 44 | void autosync(int flags){ |
| 45 | const char *zUrl; |
| 46 | const char *zAutosync; |
| 47 | const char *zPw; |
| 48 | if( g.fNoSync ){ |
| 49 | return; |
| 50 | } |
| 51 | zAutosync = db_get("autosync", 0); |
| 52 | if( zAutosync ){ |
| @@ -60,17 +61,16 @@ | |
| 61 | } |
| 62 | zUrl = db_get("last-sync-url", 0); |
| 63 | if( zUrl==0 ){ |
| 64 | return; /* No default server */ |
| 65 | } |
| 66 | zPw = db_get("last-sync-pw", 0); |
| 67 | url_parse(zUrl); |
| 68 | if( g.urlUser!=0 && g.urlPasswd==0 ){ |
| 69 | g.urlPasswd = mprintf("%s", zPw); |
| 70 | } |
| 71 | printf("Autosync: %s\n", g.urlCanonical); |
| 72 | url_enable_proxy("via proxy: "); |
| 73 | client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, 0); |
| 74 | } |
| 75 | |
| 76 | /* |
| @@ -79,35 +79,36 @@ | |
| 79 | ** of a server to sync against. If no argument is given, use the |
| 80 | ** most recently synced URL. Remember the current URL for next time. |
| 81 | */ |
| 82 | void process_sync_args(void){ |
| 83 | const char *zUrl = 0; |
| 84 | const char *zPw = 0; |
| 85 | int urlOptional = find_option("autourl",0,0)!=0; |
| 86 | g.dontKeepUrl = find_option("once",0,0)!=0; |
| 87 | url_proxy_options(); |
| 88 | db_find_and_open_repository(1); |
| 89 | if( g.argc==2 ){ |
| 90 | zUrl = db_get("last-sync-url", 0); |
| 91 | zPw = db_get("last-sync-pw", 0); |
| 92 | }else if( g.argc==3 ){ |
| 93 | zUrl = g.argv[2]; |
| 94 | } |
| 95 | if( zUrl==0 ){ |
| 96 | if( urlOptional ) exit(0); |
| 97 | usage("URL"); |
| 98 | } |
| 99 | url_parse(zUrl); |
| 100 | if( !g.dontKeepUrl ){ |
| 101 | db_set("last-sync-url", g.urlCanonical, 0); |
| 102 | if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0); |
| 103 | } |
| 104 | if( g.urlUser!=0 && g.urlPasswd==0 ){ |
| 105 | g.urlPasswd = mprintf("%s", zPw); |
| 106 | } |
| 107 | user_select(); |
| 108 | if( g.argc==2 ){ |
| 109 | printf("Server: %s\n", g.urlCanonical); |
| 110 | } |
| 111 | url_enable_proxy("via proxy: "); |
| 112 | } |
| 113 | |
| 114 | /* |
| @@ -189,46 +190,49 @@ | |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | ** COMMAND: remote-url |
| 194 | ** |
| 195 | ** Usage: %fossil remote-url ?URL|off? |
| 196 | ** |
| 197 | ** Query and/or change the default server URL used by the "pull", "push", |
| 198 | ** and "sync" commands. |
| 199 | ** |
| 200 | ** The remote-url is set automatically by a "clone" command or by any |
| 201 | ** "sync", "push", or "pull" command that specifies an explicit URL. |
| 202 | ** The default remote-url is used by auto-syncing and by "sync", "push", |
| 203 | ** "pull" that omit the server URL. |
| 204 | ** |
| 205 | ** See also: clone, push, pull, sync |
| 206 | */ |
| 207 | void remote_url_cmd(void){ |
| 208 | char *zUrl; |
| 209 | db_find_and_open_repository(1); |
| 210 | if( g.argc!=2 && g.argc!=3 ){ |
| 211 | usage("remote-url ?URL|off?"); |
| 212 | } |
| 213 | if( g.argc==3 ){ |
| 214 | if( strcmp(g.argv[2],"off")==0 ){ |
| 215 | db_unset("last-sync-url", 0); |
| 216 | db_unset("last-sync-pw", 0); |
| 217 | }else{ |
| 218 | url_parse(g.argv[2]); |
| 219 | if( g.urlUser && g.urlPasswd==0 ){ |
| 220 | url_prompt_for_password(); |
| 221 | } |
| 222 | db_set("last-sync-url", g.urlCanonical, 0); |
| 223 | if( g.urlPasswd ){ |
| 224 | db_set("last-sync-pw", g.urlPasswd, 0); |
| 225 | }else{ |
| 226 | db_unset("last-sync-pw", 0); |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | zUrl = db_get("last-sync-url", 0); |
| 231 | if( zUrl==0 ){ |
| 232 | printf("off\n"); |
| 233 | return; |
| 234 | }else{ |
| 235 | url_parse(zUrl); |
| 236 | printf("%s\n", g.urlCanonical); |
| 237 | } |
| 238 | } |
| 239 |
+26
-5
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -37,11 +37,11 @@ | ||
| 37 | 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | 39 | ** g.urlUser Userid. |
| 40 | 40 | ** g.urlPasswd Password. |
| 41 | 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | -** g.urlCanonical The URL in canonical form, omitting userid/password | |
| 42 | +** g.urlCanonical The URL in canonical form, omitting the password | |
| 43 | 43 | ** |
| 44 | 44 | ** HTTP url format is: |
| 45 | 45 | ** |
| 46 | 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | 47 | ** |
| @@ -49,10 +49,11 @@ | ||
| 49 | 49 | void url_parse(const char *zUrl){ |
| 50 | 50 | int i, j, c; |
| 51 | 51 | char *zFile = 0; |
| 52 | 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | 53 | int iStart; |
| 54 | + char *zLogin; | |
| 54 | 55 | g.urlIsFile = 0; |
| 55 | 56 | if( zUrl[4]=='s' ){ |
| 56 | 57 | g.urlIsHttps = 1; |
| 57 | 58 | g.urlProtocol = "https"; |
| 58 | 59 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | ||
| 73 | 74 | dehttpize(g.urlPasswd); |
| 74 | 75 | } |
| 75 | 76 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 76 | 77 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 77 | 78 | i = j; |
| 79 | + zLogin = mprintf("%t@", g.urlUser); | |
| 78 | 80 | }else{ |
| 79 | 81 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 80 | 82 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 83 | + zLogin = mprintf(""); | |
| 81 | 84 | } |
| 82 | 85 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 83 | 86 | if( c==':' ){ |
| 84 | 87 | g.urlPort = 0; |
| 85 | 88 | i++; |
| @@ -94,16 +97,21 @@ | ||
| 94 | 97 | } |
| 95 | 98 | g.urlPath = mprintf(&zUrl[i]); |
| 96 | 99 | dehttpize(g.urlName); |
| 97 | 100 | dehttpize(g.urlPath); |
| 98 | 101 | if( g.urlDfltPort==g.urlPort ){ |
| 99 | - g.urlCanonical = mprintf("%s://%T%T", | |
| 100 | - g.urlProtocol, g.urlName, g.urlPath); | |
| 102 | + g.urlCanonical = mprintf( | |
| 103 | + "%s://%s%T%T", | |
| 104 | + g.urlProtocol, zLogin, g.urlName, g.urlPath | |
| 105 | + ); | |
| 101 | 106 | }else{ |
| 102 | - g.urlCanonical = mprintf("%s://%T:%d%T", | |
| 103 | - g.urlProtocol, g.urlName, g.urlPort, g.urlPath); | |
| 107 | + g.urlCanonical = mprintf( | |
| 108 | + "%s://%s%T:%d%T", | |
| 109 | + g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath | |
| 110 | + ); | |
| 104 | 111 | } |
| 112 | + free(zLogin); | |
| 105 | 113 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 106 | 114 | g.urlIsFile = 1; |
| 107 | 115 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 108 | 116 | i = 7; |
| 109 | 117 | }else{ |
| @@ -296,5 +304,18 @@ | ||
| 296 | 304 | if( zName2 && zValue2 ){ |
| 297 | 305 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 298 | 306 | } |
| 299 | 307 | return blob_str(&p->url); |
| 300 | 308 | } |
| 309 | + | |
| 310 | +/* | |
| 311 | +** Prompt the user for the password for g.urlUser. Store the result | |
| 312 | +** in g.urlPasswd. | |
| 313 | +*/ | |
| 314 | +void url_prompt_for_password(void){ | |
| 315 | + char *zPrompt = mprintf("password for %s: ", g.urlUser); | |
| 316 | + Blob x; | |
| 317 | + prompt_for_password(zPrompt, &x, 0); | |
| 318 | + free(zPrompt); | |
| 319 | + g.urlPasswd = mprintf("%b", &x); | |
| 320 | + blob_reset(&x); | |
| 321 | +} | |
| 301 | 322 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -37,11 +37,11 @@ | |
| 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | ** g.urlUser Userid. |
| 40 | ** g.urlPasswd Password. |
| 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | ** g.urlCanonical The URL in canonical form, omitting userid/password |
| 43 | ** |
| 44 | ** HTTP url format is: |
| 45 | ** |
| 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | ** |
| @@ -49,10 +49,11 @@ | |
| 49 | void url_parse(const char *zUrl){ |
| 50 | int i, j, c; |
| 51 | char *zFile = 0; |
| 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | int iStart; |
| 54 | g.urlIsFile = 0; |
| 55 | if( zUrl[4]=='s' ){ |
| 56 | g.urlIsHttps = 1; |
| 57 | g.urlProtocol = "https"; |
| 58 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | |
| 73 | dehttpize(g.urlPasswd); |
| 74 | } |
| 75 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 76 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 77 | i = j; |
| 78 | }else{ |
| 79 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 80 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 81 | } |
| 82 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 83 | if( c==':' ){ |
| 84 | g.urlPort = 0; |
| 85 | i++; |
| @@ -94,16 +97,21 @@ | |
| 94 | } |
| 95 | g.urlPath = mprintf(&zUrl[i]); |
| 96 | dehttpize(g.urlName); |
| 97 | dehttpize(g.urlPath); |
| 98 | if( g.urlDfltPort==g.urlPort ){ |
| 99 | g.urlCanonical = mprintf("%s://%T%T", |
| 100 | g.urlProtocol, g.urlName, g.urlPath); |
| 101 | }else{ |
| 102 | g.urlCanonical = mprintf("%s://%T:%d%T", |
| 103 | g.urlProtocol, g.urlName, g.urlPort, g.urlPath); |
| 104 | } |
| 105 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 106 | g.urlIsFile = 1; |
| 107 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 108 | i = 7; |
| 109 | }else{ |
| @@ -296,5 +304,18 @@ | |
| 296 | if( zName2 && zValue2 ){ |
| 297 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 298 | } |
| 299 | return blob_str(&p->url); |
| 300 | } |
| 301 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -37,11 +37,11 @@ | |
| 37 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 38 | ** g.urlPath Path name for HTTP or HTTPS. |
| 39 | ** g.urlUser Userid. |
| 40 | ** g.urlPasswd Password. |
| 41 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 42 | ** g.urlCanonical The URL in canonical form, omitting the password |
| 43 | ** |
| 44 | ** HTTP url format is: |
| 45 | ** |
| 46 | ** http://userid:password@host:port/path?query#fragment |
| 47 | ** |
| @@ -49,10 +49,11 @@ | |
| 49 | void url_parse(const char *zUrl){ |
| 50 | int i, j, c; |
| 51 | char *zFile = 0; |
| 52 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| 53 | int iStart; |
| 54 | char *zLogin; |
| 55 | g.urlIsFile = 0; |
| 56 | if( zUrl[4]=='s' ){ |
| 57 | g.urlIsHttps = 1; |
| 58 | g.urlProtocol = "https"; |
| 59 | g.urlDfltPort = 443; |
| @@ -73,13 +74,15 @@ | |
| 74 | dehttpize(g.urlPasswd); |
| 75 | } |
| 76 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 77 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 78 | i = j; |
| 79 | zLogin = mprintf("%t@", g.urlUser); |
| 80 | }else{ |
| 81 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 82 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 83 | zLogin = mprintf(""); |
| 84 | } |
| 85 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 86 | if( c==':' ){ |
| 87 | g.urlPort = 0; |
| 88 | i++; |
| @@ -94,16 +97,21 @@ | |
| 97 | } |
| 98 | g.urlPath = mprintf(&zUrl[i]); |
| 99 | dehttpize(g.urlName); |
| 100 | dehttpize(g.urlPath); |
| 101 | if( g.urlDfltPort==g.urlPort ){ |
| 102 | g.urlCanonical = mprintf( |
| 103 | "%s://%s%T%T", |
| 104 | g.urlProtocol, zLogin, g.urlName, g.urlPath |
| 105 | ); |
| 106 | }else{ |
| 107 | g.urlCanonical = mprintf( |
| 108 | "%s://%s%T:%d%T", |
| 109 | g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath |
| 110 | ); |
| 111 | } |
| 112 | free(zLogin); |
| 113 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 114 | g.urlIsFile = 1; |
| 115 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 116 | i = 7; |
| 117 | }else{ |
| @@ -296,5 +304,18 @@ | |
| 304 | if( zName2 && zValue2 ){ |
| 305 | blob_appendf(&p->url, "%s%s=%T", zSep, zName2, zValue2); |
| 306 | } |
| 307 | return blob_str(&p->url); |
| 308 | } |
| 309 | |
| 310 | /* |
| 311 | ** Prompt the user for the password for g.urlUser. Store the result |
| 312 | ** in g.urlPasswd. |
| 313 | */ |
| 314 | void url_prompt_for_password(void){ |
| 315 | char *zPrompt = mprintf("password for %s: ", g.urlUser); |
| 316 | Blob x; |
| 317 | prompt_for_password(zPrompt, &x, 0); |
| 318 | free(zPrompt); |
| 319 | g.urlPasswd = mprintf("%b", &x); |
| 320 | blob_reset(&x); |
| 321 | } |
| 322 |
+4
-3
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -146,11 +146,11 @@ | ||
| 146 | 146 | */ |
| 147 | 147 | void vfile_check_signature(int vid, int notFileIsFatal){ |
| 148 | 148 | int nErr = 0; |
| 149 | 149 | Stmt q; |
| 150 | 150 | Blob fileCksum, origCksum; |
| 151 | - int checkMtime = db_get_boolean("mtime-changes", 0); | |
| 151 | + int checkMtime = db_get_boolean("mtime-changes", 1); | |
| 152 | 152 | |
| 153 | 153 | db_begin_transaction(); |
| 154 | 154 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 155 | 155 | " vfile.mrid, deleted, chnged, uuid, mtime" |
| 156 | 156 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -167,11 +167,11 @@ | ||
| 167 | 167 | zName = db_column_text(&q, 1); |
| 168 | 168 | rid = db_column_int(&q, 2); |
| 169 | 169 | isDeleted = db_column_int(&q, 3); |
| 170 | 170 | oldChnged = db_column_int(&q, 4); |
| 171 | 171 | oldMtime = db_column_int64(&q, 6); |
| 172 | - if( !file_isfile(zName) && file_size(zName)>=0 ){ | |
| 172 | + if( !file_isfile(zName) && file_size(0)>=0 ){ | |
| 173 | 173 | if( notFileIsFatal ){ |
| 174 | 174 | fossil_warning("not a ordinary file: %s", zName); |
| 175 | 175 | nErr++; |
| 176 | 176 | } |
| 177 | 177 | chnged = 1; |
| @@ -179,11 +179,12 @@ | ||
| 179 | 179 | chnged = oldChnged; |
| 180 | 180 | }else if( isDeleted || rid==0 ){ |
| 181 | 181 | chnged = 1; |
| 182 | 182 | } |
| 183 | 183 | if( chnged!=1 ){ |
| 184 | - currentMtime = file_mtime(zName); | |
| 184 | + currentMtime = file_mtime(0); | |
| 185 | + assert( currentMtime>0 ); | |
| 185 | 186 | } |
| 186 | 187 | if( chnged!=1 && (checkMtime==0 || currentMtime!=oldMtime) ){ |
| 187 | 188 | db_ephemeral_blob(&q, 5, &origCksum); |
| 188 | 189 | if( sha1sum_file(zName, &fileCksum) ){ |
| 189 | 190 | blob_zero(&fileCksum); |
| 190 | 191 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -146,11 +146,11 @@ | |
| 146 | */ |
| 147 | void vfile_check_signature(int vid, int notFileIsFatal){ |
| 148 | int nErr = 0; |
| 149 | Stmt q; |
| 150 | Blob fileCksum, origCksum; |
| 151 | int checkMtime = db_get_boolean("mtime-changes", 0); |
| 152 | |
| 153 | db_begin_transaction(); |
| 154 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 155 | " vfile.mrid, deleted, chnged, uuid, mtime" |
| 156 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -167,11 +167,11 @@ | |
| 167 | zName = db_column_text(&q, 1); |
| 168 | rid = db_column_int(&q, 2); |
| 169 | isDeleted = db_column_int(&q, 3); |
| 170 | oldChnged = db_column_int(&q, 4); |
| 171 | oldMtime = db_column_int64(&q, 6); |
| 172 | if( !file_isfile(zName) && file_size(zName)>=0 ){ |
| 173 | if( notFileIsFatal ){ |
| 174 | fossil_warning("not a ordinary file: %s", zName); |
| 175 | nErr++; |
| 176 | } |
| 177 | chnged = 1; |
| @@ -179,11 +179,12 @@ | |
| 179 | chnged = oldChnged; |
| 180 | }else if( isDeleted || rid==0 ){ |
| 181 | chnged = 1; |
| 182 | } |
| 183 | if( chnged!=1 ){ |
| 184 | currentMtime = file_mtime(zName); |
| 185 | } |
| 186 | if( chnged!=1 && (checkMtime==0 || currentMtime!=oldMtime) ){ |
| 187 | db_ephemeral_blob(&q, 5, &origCksum); |
| 188 | if( sha1sum_file(zName, &fileCksum) ){ |
| 189 | blob_zero(&fileCksum); |
| 190 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -146,11 +146,11 @@ | |
| 146 | */ |
| 147 | void vfile_check_signature(int vid, int notFileIsFatal){ |
| 148 | int nErr = 0; |
| 149 | Stmt q; |
| 150 | Blob fileCksum, origCksum; |
| 151 | int checkMtime = db_get_boolean("mtime-changes", 1); |
| 152 | |
| 153 | db_begin_transaction(); |
| 154 | db_prepare(&q, "SELECT id, %Q || pathname," |
| 155 | " vfile.mrid, deleted, chnged, uuid, mtime" |
| 156 | " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid" |
| @@ -167,11 +167,11 @@ | |
| 167 | zName = db_column_text(&q, 1); |
| 168 | rid = db_column_int(&q, 2); |
| 169 | isDeleted = db_column_int(&q, 3); |
| 170 | oldChnged = db_column_int(&q, 4); |
| 171 | oldMtime = db_column_int64(&q, 6); |
| 172 | if( !file_isfile(zName) && file_size(0)>=0 ){ |
| 173 | if( notFileIsFatal ){ |
| 174 | fossil_warning("not a ordinary file: %s", zName); |
| 175 | nErr++; |
| 176 | } |
| 177 | chnged = 1; |
| @@ -179,11 +179,12 @@ | |
| 179 | chnged = oldChnged; |
| 180 | }else if( isDeleted || rid==0 ){ |
| 181 | chnged = 1; |
| 182 | } |
| 183 | if( chnged!=1 ){ |
| 184 | currentMtime = file_mtime(0); |
| 185 | assert( currentMtime>0 ); |
| 186 | } |
| 187 | if( chnged!=1 && (checkMtime==0 || currentMtime!=oldMtime) ){ |
| 188 | db_ephemeral_blob(&q, 5, &origCksum); |
| 189 | if( sha1sum_file(zName, &fileCksum) ){ |
| 190 | blob_zero(&fileCksum); |
| 191 |
+29
-11
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -342,12 +342,11 @@ | ||
| 342 | 342 | db_finalize(&q); |
| 343 | 343 | } |
| 344 | 344 | |
| 345 | 345 | /* |
| 346 | 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | -** the hash given in pHash. Return 1 on a successful match. Return 0 | |
| 348 | -** if there is a mismatch. | |
| 347 | +** the hash given in pHash. Return non-zero for an error and 0 on success. | |
| 349 | 348 | */ |
| 350 | 349 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 351 | 350 | Blob tail; |
| 352 | 351 | Blob h2; |
| 353 | 352 | int rc; |
| @@ -354,11 +353,11 @@ | ||
| 354 | 353 | blob_tail(pMsg, &tail); |
| 355 | 354 | sha1sum_blob(&tail, &h2); |
| 356 | 355 | rc = blob_compare(pHash, &h2); |
| 357 | 356 | blob_reset(&h2); |
| 358 | 357 | blob_reset(&tail); |
| 359 | - return rc==0; | |
| 358 | + return rc; | |
| 360 | 359 | } |
| 361 | 360 | |
| 362 | 361 | /* |
| 363 | 362 | ** Check the signature on an application/x-fossil payload received by |
| 364 | 363 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | ||
| 378 | 377 | ** |
| 379 | 378 | ** If anything fails to check out, no changes are made to privileges. |
| 380 | 379 | ** |
| 381 | 380 | ** Signature generation on the client side is handled by the |
| 382 | 381 | ** http_exchange() routine. |
| 382 | +** | |
| 383 | +** Return non-zero for a login failure and zero for success. | |
| 383 | 384 | */ |
| 384 | -void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ | |
| 385 | +int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ | |
| 385 | 386 | Stmt q; |
| 386 | 387 | int rc = -1; |
| 387 | 388 | char *zLogin = blob_terminate(pLogin); |
| 388 | 389 | defossilize(zLogin); |
| 389 | 390 | |
| @@ -440,10 +441,11 @@ | ||
| 440 | 441 | |
| 441 | 442 | if( rc==0 ){ |
| 442 | 443 | /* If the login was successful. */ |
| 443 | 444 | login_set_anon_nobody_capabilities(); |
| 444 | 445 | } |
| 446 | + return rc; | |
| 445 | 447 | } |
| 446 | 448 | |
| 447 | 449 | /* |
| 448 | 450 | ** Send the content of all files in the unsent table. |
| 449 | 451 | ** |
| @@ -741,12 +743,19 @@ | ||
| 741 | 743 | if( blob_eq(&xfer.aToken[0], "login") |
| 742 | 744 | && xfer.nToken==4 |
| 743 | 745 | ){ |
| 744 | 746 | if( disableLogin ){ |
| 745 | 747 | g.okRead = g.okWrite = 1; |
| 746 | - }else if( check_tail_hash(&xfer.aToken[2], xfer.pIn) ){ | |
| 747 | - check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]); | |
| 748 | + }else{ | |
| 749 | + if( check_tail_hash(&xfer.aToken[2], xfer.pIn) | |
| 750 | + || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) | |
| 751 | + ){ | |
| 752 | + cgi_reset_content(); | |
| 753 | + @ error login\sfailed | |
| 754 | + nErr++; | |
| 755 | + break; | |
| 756 | + } | |
| 748 | 757 | } |
| 749 | 758 | }else |
| 750 | 759 | |
| 751 | 760 | /* reqconfig NAME |
| 752 | 761 | ** |
| @@ -1067,10 +1076,11 @@ | ||
| 1067 | 1076 | } |
| 1068 | 1077 | if( pushFlag ){ |
| 1069 | 1078 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1070 | 1079 | nCardSent++; |
| 1071 | 1080 | } |
| 1081 | + go = 0; | |
| 1072 | 1082 | |
| 1073 | 1083 | /* Process the reply that came back from the server */ |
| 1074 | 1084 | while( blob_line(&recv, &xfer.line) ){ |
| 1075 | 1085 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1076 | 1086 | continue; |
| @@ -1208,16 +1218,19 @@ | ||
| 1208 | 1218 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1209 | 1219 | }else |
| 1210 | 1220 | |
| 1211 | 1221 | /* message MESSAGE |
| 1212 | 1222 | ** |
| 1213 | - ** Print a message. Similar to "error" but does not stop processing | |
| 1223 | + ** Print a message. Similar to "error" but does not stop processing. | |
| 1224 | + ** | |
| 1225 | + ** If the "login failed" message is seen, clear the sync password prior | |
| 1226 | + ** to the next cycle. | |
| 1214 | 1227 | */ |
| 1215 | 1228 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1216 | 1229 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1217 | 1230 | defossilize(zMsg); |
| 1218 | - printf("\rServer says: %s\n", zMsg); | |
| 1231 | + if( zMsg ) printf("\rServer says: %s\n", zMsg); | |
| 1219 | 1232 | }else |
| 1220 | 1233 | |
| 1221 | 1234 | /* error MESSAGE |
| 1222 | 1235 | ** |
| 1223 | 1236 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | ||
| 1231 | 1244 | */ |
| 1232 | 1245 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1233 | 1246 | if( !cloneFlag || nCycle>0 ){ |
| 1234 | 1247 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1235 | 1248 | defossilize(zMsg); |
| 1236 | - blob_appendf(&xfer.err, "server says: %s", zMsg); | |
| 1237 | - printf("Server Error: %s\n", zMsg); | |
| 1249 | + if( strcmp(zMsg, "login failed")==0 ){ | |
| 1250 | + if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0); | |
| 1251 | + g.urlPasswd = 0; | |
| 1252 | + if( nCycle<2 ) go = 1; | |
| 1253 | + }else{ | |
| 1254 | + blob_appendf(&xfer.err, "\rserver says: %s", zMsg); | |
| 1255 | + } | |
| 1256 | + printf("\rServer Error: %s\n", zMsg); | |
| 1238 | 1257 | } |
| 1239 | 1258 | }else |
| 1240 | 1259 | |
| 1241 | 1260 | /* Unknown message */ |
| 1242 | 1261 | { |
| @@ -1264,11 +1283,10 @@ | ||
| 1264 | 1283 | blob_size(&recv), nCardRcvd, |
| 1265 | 1284 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1266 | 1285 | } |
| 1267 | 1286 | blob_reset(&recv); |
| 1268 | 1287 | nCycle++; |
| 1269 | - go = 0; | |
| 1270 | 1288 | |
| 1271 | 1289 | /* If we received one or more files on the previous exchange but |
| 1272 | 1290 | ** there are still phantoms, then go another round. |
| 1273 | 1291 | */ |
| 1274 | 1292 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1275 | 1293 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -342,12 +342,11 @@ | |
| 342 | db_finalize(&q); |
| 343 | } |
| 344 | |
| 345 | /* |
| 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | ** the hash given in pHash. Return 1 on a successful match. Return 0 |
| 348 | ** if there is a mismatch. |
| 349 | */ |
| 350 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 351 | Blob tail; |
| 352 | Blob h2; |
| 353 | int rc; |
| @@ -354,11 +353,11 @@ | |
| 354 | blob_tail(pMsg, &tail); |
| 355 | sha1sum_blob(&tail, &h2); |
| 356 | rc = blob_compare(pHash, &h2); |
| 357 | blob_reset(&h2); |
| 358 | blob_reset(&tail); |
| 359 | return rc==0; |
| 360 | } |
| 361 | |
| 362 | /* |
| 363 | ** Check the signature on an application/x-fossil payload received by |
| 364 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | |
| 378 | ** |
| 379 | ** If anything fails to check out, no changes are made to privileges. |
| 380 | ** |
| 381 | ** Signature generation on the client side is handled by the |
| 382 | ** http_exchange() routine. |
| 383 | */ |
| 384 | void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ |
| 385 | Stmt q; |
| 386 | int rc = -1; |
| 387 | char *zLogin = blob_terminate(pLogin); |
| 388 | defossilize(zLogin); |
| 389 | |
| @@ -440,10 +441,11 @@ | |
| 440 | |
| 441 | if( rc==0 ){ |
| 442 | /* If the login was successful. */ |
| 443 | login_set_anon_nobody_capabilities(); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | /* |
| 448 | ** Send the content of all files in the unsent table. |
| 449 | ** |
| @@ -741,12 +743,19 @@ | |
| 741 | if( blob_eq(&xfer.aToken[0], "login") |
| 742 | && xfer.nToken==4 |
| 743 | ){ |
| 744 | if( disableLogin ){ |
| 745 | g.okRead = g.okWrite = 1; |
| 746 | }else if( check_tail_hash(&xfer.aToken[2], xfer.pIn) ){ |
| 747 | check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]); |
| 748 | } |
| 749 | }else |
| 750 | |
| 751 | /* reqconfig NAME |
| 752 | ** |
| @@ -1067,10 +1076,11 @@ | |
| 1067 | } |
| 1068 | if( pushFlag ){ |
| 1069 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1070 | nCardSent++; |
| 1071 | } |
| 1072 | |
| 1073 | /* Process the reply that came back from the server */ |
| 1074 | while( blob_line(&recv, &xfer.line) ){ |
| 1075 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1076 | continue; |
| @@ -1208,16 +1218,19 @@ | |
| 1208 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1209 | }else |
| 1210 | |
| 1211 | /* message MESSAGE |
| 1212 | ** |
| 1213 | ** Print a message. Similar to "error" but does not stop processing |
| 1214 | */ |
| 1215 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1216 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1217 | defossilize(zMsg); |
| 1218 | printf("\rServer says: %s\n", zMsg); |
| 1219 | }else |
| 1220 | |
| 1221 | /* error MESSAGE |
| 1222 | ** |
| 1223 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | |
| 1231 | */ |
| 1232 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1233 | if( !cloneFlag || nCycle>0 ){ |
| 1234 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1235 | defossilize(zMsg); |
| 1236 | blob_appendf(&xfer.err, "server says: %s", zMsg); |
| 1237 | printf("Server Error: %s\n", zMsg); |
| 1238 | } |
| 1239 | }else |
| 1240 | |
| 1241 | /* Unknown message */ |
| 1242 | { |
| @@ -1264,11 +1283,10 @@ | |
| 1264 | blob_size(&recv), nCardRcvd, |
| 1265 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1266 | } |
| 1267 | blob_reset(&recv); |
| 1268 | nCycle++; |
| 1269 | go = 0; |
| 1270 | |
| 1271 | /* If we received one or more files on the previous exchange but |
| 1272 | ** there are still phantoms, then go another round. |
| 1273 | */ |
| 1274 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1275 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -342,12 +342,11 @@ | |
| 342 | db_finalize(&q); |
| 343 | } |
| 344 | |
| 345 | /* |
| 346 | ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the |
| 347 | ** the hash given in pHash. Return non-zero for an error and 0 on success. |
| 348 | */ |
| 349 | static int check_tail_hash(Blob *pHash, Blob *pMsg){ |
| 350 | Blob tail; |
| 351 | Blob h2; |
| 352 | int rc; |
| @@ -354,11 +353,11 @@ | |
| 353 | blob_tail(pMsg, &tail); |
| 354 | sha1sum_blob(&tail, &h2); |
| 355 | rc = blob_compare(pHash, &h2); |
| 356 | blob_reset(&h2); |
| 357 | blob_reset(&tail); |
| 358 | return rc; |
| 359 | } |
| 360 | |
| 361 | /* |
| 362 | ** Check the signature on an application/x-fossil payload received by |
| 363 | ** the HTTP server. The signature is a line of the following form: |
| @@ -378,12 +377,14 @@ | |
| 377 | ** |
| 378 | ** If anything fails to check out, no changes are made to privileges. |
| 379 | ** |
| 380 | ** Signature generation on the client side is handled by the |
| 381 | ** http_exchange() routine. |
| 382 | ** |
| 383 | ** Return non-zero for a login failure and zero for success. |
| 384 | */ |
| 385 | int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){ |
| 386 | Stmt q; |
| 387 | int rc = -1; |
| 388 | char *zLogin = blob_terminate(pLogin); |
| 389 | defossilize(zLogin); |
| 390 | |
| @@ -440,10 +441,11 @@ | |
| 441 | |
| 442 | if( rc==0 ){ |
| 443 | /* If the login was successful. */ |
| 444 | login_set_anon_nobody_capabilities(); |
| 445 | } |
| 446 | return rc; |
| 447 | } |
| 448 | |
| 449 | /* |
| 450 | ** Send the content of all files in the unsent table. |
| 451 | ** |
| @@ -741,12 +743,19 @@ | |
| 743 | if( blob_eq(&xfer.aToken[0], "login") |
| 744 | && xfer.nToken==4 |
| 745 | ){ |
| 746 | if( disableLogin ){ |
| 747 | g.okRead = g.okWrite = 1; |
| 748 | }else{ |
| 749 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) |
| 750 | || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) |
| 751 | ){ |
| 752 | cgi_reset_content(); |
| 753 | @ error login\sfailed |
| 754 | nErr++; |
| 755 | break; |
| 756 | } |
| 757 | } |
| 758 | }else |
| 759 | |
| 760 | /* reqconfig NAME |
| 761 | ** |
| @@ -1067,10 +1076,11 @@ | |
| 1076 | } |
| 1077 | if( pushFlag ){ |
| 1078 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 1079 | nCardSent++; |
| 1080 | } |
| 1081 | go = 0; |
| 1082 | |
| 1083 | /* Process the reply that came back from the server */ |
| 1084 | while( blob_line(&recv, &xfer.line) ){ |
| 1085 | if( blob_buffer(&xfer.line)[0]=='#' ){ |
| 1086 | continue; |
| @@ -1208,16 +1218,19 @@ | |
| 1218 | db_set("cookie", blob_str(&xfer.aToken[1]), 0); |
| 1219 | }else |
| 1220 | |
| 1221 | /* message MESSAGE |
| 1222 | ** |
| 1223 | ** Print a message. Similar to "error" but does not stop processing. |
| 1224 | ** |
| 1225 | ** If the "login failed" message is seen, clear the sync password prior |
| 1226 | ** to the next cycle. |
| 1227 | */ |
| 1228 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1229 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1230 | defossilize(zMsg); |
| 1231 | if( zMsg ) printf("\rServer says: %s\n", zMsg); |
| 1232 | }else |
| 1233 | |
| 1234 | /* error MESSAGE |
| 1235 | ** |
| 1236 | ** Report an error and abandon the sync session. |
| @@ -1231,12 +1244,18 @@ | |
| 1244 | */ |
| 1245 | if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){ |
| 1246 | if( !cloneFlag || nCycle>0 ){ |
| 1247 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1248 | defossilize(zMsg); |
| 1249 | if( strcmp(zMsg, "login failed")==0 ){ |
| 1250 | if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0); |
| 1251 | g.urlPasswd = 0; |
| 1252 | if( nCycle<2 ) go = 1; |
| 1253 | }else{ |
| 1254 | blob_appendf(&xfer.err, "\rserver says: %s", zMsg); |
| 1255 | } |
| 1256 | printf("\rServer Error: %s\n", zMsg); |
| 1257 | } |
| 1258 | }else |
| 1259 | |
| 1260 | /* Unknown message */ |
| 1261 | { |
| @@ -1264,11 +1283,10 @@ | |
| 1283 | blob_size(&recv), nCardRcvd, |
| 1284 | xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile); |
| 1285 | } |
| 1286 | blob_reset(&recv); |
| 1287 | nCycle++; |
| 1288 | |
| 1289 | /* If we received one or more files on the previous exchange but |
| 1290 | ** there are still phantoms, then go another round. |
| 1291 | */ |
| 1292 | nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; |
| 1293 |
+1
-1
| --- src/zip.c | ||
| +++ src/zip.c | ||
| @@ -408,11 +408,11 @@ | ||
| 408 | 408 | char *zName, *zRid; |
| 409 | 409 | int nName, nRid; |
| 410 | 410 | Blob zip; |
| 411 | 411 | |
| 412 | 412 | login_check_credentials(); |
| 413 | - if( !g.okZip && (!g.okRead || !g.okHistory) ){ login_needed(); return; } | |
| 413 | + if( !g.okZip ){ login_needed(); return; } | |
| 414 | 414 | zName = mprintf("%s", PD("name","")); |
| 415 | 415 | nName = strlen(zName); |
| 416 | 416 | zRid = mprintf("%s", PD("uuid","")); |
| 417 | 417 | nRid = strlen(zRid); |
| 418 | 418 | for(nName=strlen(zName)-1; nName>5; nName--){ |
| 419 | 419 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -408,11 +408,11 @@ | |
| 408 | char *zName, *zRid; |
| 409 | int nName, nRid; |
| 410 | Blob zip; |
| 411 | |
| 412 | login_check_credentials(); |
| 413 | if( !g.okZip && (!g.okRead || !g.okHistory) ){ login_needed(); return; } |
| 414 | zName = mprintf("%s", PD("name","")); |
| 415 | nName = strlen(zName); |
| 416 | zRid = mprintf("%s", PD("uuid","")); |
| 417 | nRid = strlen(zRid); |
| 418 | for(nName=strlen(zName)-1; nName>5; nName--){ |
| 419 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -408,11 +408,11 @@ | |
| 408 | char *zName, *zRid; |
| 409 | int nName, nRid; |
| 410 | Blob zip; |
| 411 | |
| 412 | login_check_credentials(); |
| 413 | if( !g.okZip ){ login_needed(); return; } |
| 414 | zName = mprintf("%s", PD("name","")); |
| 415 | nName = strlen(zName); |
| 416 | zRid = mprintf("%s", PD("uuid","")); |
| 417 | nRid = strlen(zRid); |
| 418 | for(nName=strlen(zName)-1; nName>5; nName--){ |
| 419 |