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