Fossil SCM

First cut at code to enable syncing private branches. Code compiles but is otherwise untested. The "x" privilege is required on the server in order to sync privately.

drh 2011-02-26 21:49 UTC trunk
Commit 4a17f851820a266bd4454eb145e4ecb4ad82872f
+5 -2
--- src/clone.c
+++ src/clone.c
@@ -35,18 +35,21 @@
3535
** admin user. This can be overridden using the -A|--admin-user
3636
** parameter.
3737
**
3838
** Options:
3939
**
40
-** --admin-user|-A USERNAME
40
+** --admin-user|-A USERNAME Make USERNAME the administrator
41
+** --private Also clone private branches
4142
**
4243
*/
4344
void clone_cmd(void){
4445
char *zPassword;
4546
const char *zDefaultUser; /* Optional name of the default user */
4647
int nErr = 0;
48
+ int bPrivate; /* Also clone private branches */
4749
50
+ bPrivate = find_option("private",0,0)!=0;
4851
url_proxy_options();
4952
if( g.argc < 4 ){
5053
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
5154
}
5255
db_open_config(0);
@@ -94,11 +97,11 @@
9497
"REPLACE INTO config(name,value)"
9598
" VALUES('server-code', lower(hex(randomblob(20))));"
9699
);
97100
url_enable_proxy(0);
98101
g.xlinkClusterOnly = 1;
99
- nErr = client_sync(0,0,1,CONFIGSET_ALL,0);
102
+ nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0);
100103
g.xlinkClusterOnly = 0;
101104
verify_cancel();
102105
db_end_transaction(0);
103106
db_close(1);
104107
if( nErr ){
105108
--- src/clone.c
+++ src/clone.c
@@ -35,18 +35,21 @@
35 ** admin user. This can be overridden using the -A|--admin-user
36 ** parameter.
37 **
38 ** Options:
39 **
40 ** --admin-user|-A USERNAME
 
41 **
42 */
43 void clone_cmd(void){
44 char *zPassword;
45 const char *zDefaultUser; /* Optional name of the default user */
46 int nErr = 0;
 
47
 
48 url_proxy_options();
49 if( g.argc < 4 ){
50 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
51 }
52 db_open_config(0);
@@ -94,11 +97,11 @@
94 "REPLACE INTO config(name,value)"
95 " VALUES('server-code', lower(hex(randomblob(20))));"
96 );
97 url_enable_proxy(0);
98 g.xlinkClusterOnly = 1;
99 nErr = client_sync(0,0,1,CONFIGSET_ALL,0);
100 g.xlinkClusterOnly = 0;
101 verify_cancel();
102 db_end_transaction(0);
103 db_close(1);
104 if( nErr ){
105
--- src/clone.c
+++ src/clone.c
@@ -35,18 +35,21 @@
35 ** admin user. This can be overridden using the -A|--admin-user
36 ** parameter.
37 **
38 ** Options:
39 **
40 ** --admin-user|-A USERNAME Make USERNAME the administrator
41 ** --private Also clone private branches
42 **
43 */
44 void clone_cmd(void){
45 char *zPassword;
46 const char *zDefaultUser; /* Optional name of the default user */
47 int nErr = 0;
48 int bPrivate; /* Also clone private branches */
49
50 bPrivate = find_option("private",0,0)!=0;
51 url_proxy_options();
52 if( g.argc < 4 ){
53 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
54 }
55 db_open_config(0);
@@ -94,11 +97,11 @@
97 "REPLACE INTO config(name,value)"
98 " VALUES('server-code', lower(hex(randomblob(20))));"
99 );
100 url_enable_proxy(0);
101 g.xlinkClusterOnly = 1;
102 nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0);
103 g.xlinkClusterOnly = 0;
104 verify_cancel();
105 db_end_transaction(0);
106 db_close(1);
107 if( nErr ){
108
+2 -2
--- src/configure.c
+++ src/configure.c
@@ -464,13 +464,13 @@
464464
url_parse(zServer);
465465
if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
466466
user_select();
467467
url_enable_proxy("via proxy: ");
468468
if( strncmp(zMethod, "push", n)==0 ){
469
- client_sync(0,0,0,0,mask);
469
+ client_sync(0,0,0,0,0,mask);
470470
}else{
471
- client_sync(0,0,0,mask,0);
471
+ client_sync(0,0,0,0,mask,0);
472472
}
473473
}else
474474
if( strncmp(zMethod, "reset", n)==0 ){
475475
int mask, i;
476476
char *zBackup;
477477
--- src/configure.c
+++ src/configure.c
@@ -464,13 +464,13 @@
464 url_parse(zServer);
465 if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
466 user_select();
467 url_enable_proxy("via proxy: ");
468 if( strncmp(zMethod, "push", n)==0 ){
469 client_sync(0,0,0,0,mask);
470 }else{
471 client_sync(0,0,0,mask,0);
472 }
473 }else
474 if( strncmp(zMethod, "reset", n)==0 ){
475 int mask, i;
476 char *zBackup;
477
--- src/configure.c
+++ src/configure.c
@@ -464,13 +464,13 @@
464 url_parse(zServer);
465 if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
466 user_select();
467 url_enable_proxy("via proxy: ");
468 if( strncmp(zMethod, "push", n)==0 ){
469 client_sync(0,0,0,0,0,mask);
470 }else{
471 client_sync(0,0,0,0,mask,0);
472 }
473 }else
474 if( strncmp(zMethod, "reset", n)==0 ){
475 int mask, i;
476 char *zBackup;
477
--- src/login.c
+++ src/login.c
@@ -535,10 +535,11 @@
535535
case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
536536
g.okApndTkt = 1; break;
537537
case 'c': g.okApndTkt = 1; break;
538538
case 't': g.okTktFmt = 1; break;
539539
case 'b': g.okAttach = 1; break;
540
+ case 'x': g.okPrivate = 1; break;
540541
541542
/* The "u" privileges is a little different. It recursively
542543
** inherits all privileges of the user named "reader" */
543544
case 'u': {
544545
if( zUser==0 ){
545546
--- src/login.c
+++ src/login.c
@@ -535,10 +535,11 @@
535 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
536 g.okApndTkt = 1; break;
537 case 'c': g.okApndTkt = 1; break;
538 case 't': g.okTktFmt = 1; break;
539 case 'b': g.okAttach = 1; break;
 
540
541 /* The "u" privileges is a little different. It recursively
542 ** inherits all privileges of the user named "reader" */
543 case 'u': {
544 if( zUser==0 ){
545
--- src/login.c
+++ src/login.c
@@ -535,10 +535,11 @@
535 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
536 g.okApndTkt = 1; break;
537 case 'c': g.okApndTkt = 1; break;
538 case 't': g.okTktFmt = 1; break;
539 case 'b': g.okAttach = 1; break;
540 case 'x': g.okPrivate = 1; break;
541
542 /* The "u" privileges is a little different. It recursively
543 ** inherits all privileges of the user named "reader" */
544 case 'u': {
545 if( zUser==0 ){
546
+1
--- src/main.c
+++ src/main.c
@@ -134,10 +134,11 @@
134134
int okWrTkt; /* w: make changes to tickets via web */
135135
int okAttach; /* b: add attachments */
136136
int okTktFmt; /* t: create new ticket report formats */
137137
int okRdAddr; /* e: read email addresses or other private data */
138138
int okZip; /* z: download zipped artifact via /zip URL */
139
+ int okPrivate; /* x: can send and receive private content */
139140
140141
/* For defense against Cross-site Request Forgery attacks */
141142
char zCsrfToken[12]; /* Value of the anti-CSRF token */
142143
int okCsrf; /* Anti-CSRF token is present and valid */
143144
144145
--- src/main.c
+++ src/main.c
@@ -134,10 +134,11 @@
134 int okWrTkt; /* w: make changes to tickets via web */
135 int okAttach; /* b: add attachments */
136 int okTktFmt; /* t: create new ticket report formats */
137 int okRdAddr; /* e: read email addresses or other private data */
138 int okZip; /* z: download zipped artifact via /zip URL */
 
139
140 /* For defense against Cross-site Request Forgery attacks */
141 char zCsrfToken[12]; /* Value of the anti-CSRF token */
142 int okCsrf; /* Anti-CSRF token is present and valid */
143
144
--- src/main.c
+++ src/main.c
@@ -134,10 +134,11 @@
134 int okWrTkt; /* w: make changes to tickets via web */
135 int okAttach; /* b: add attachments */
136 int okTktFmt; /* t: create new ticket report formats */
137 int okRdAddr; /* e: read email addresses or other private data */
138 int okZip; /* z: download zipped artifact via /zip URL */
139 int okPrivate; /* x: can send and receive private content */
140
141 /* For defense against Cross-site Request Forgery attacks */
142 char zCsrfToken[12]; /* Value of the anti-CSRF token */
143 int okCsrf; /* Anti-CSRF token is present and valid */
144
145
+8 -2
--- src/setup.c
+++ src/setup.c
@@ -188,10 +188,12 @@
188188
@ <tr><td valign="top"><b>v</b></td>
189189
@ <td><i>Developer:</i> Inherit privileges of
190190
@ user <tt>developer</tt></td></tr>
191191
@ <tr><td valign="top"><b>w</b></td>
192192
@ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
193
+ @ <tr><td valign="top"><b>x</b></td>
194
+ @ <td><i>Private:</i> Push and/or pull private branches</td></tr>
193195
@ <tr><td valign="top"><b>z</b></td>
194196
@ <td><i>Zip download:</i> Download a baseline via the
195197
@ <tt>/zip</tt> URL even without
196198
@ check<span class="capability">o</span>ut
197199
@ and <span class="capability">h</span>istory permissions</td></tr>
@@ -243,11 +245,11 @@
243245
*/
244246
void user_edit(void){
245247
const char *zId, *zLogin, *zInfo, *zCap, *zPw;
246248
char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
247249
char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
248
- char *oat, *oau, *oav, *oab, *oaz;
250
+ char *oat, *oau, *oav, *oab, *oax, *oaz;
249251
const char *inherit[128];
250252
int doWrite;
251253
int uid;
252254
int higherUser = 0; /* True if user being edited is SETUP and the */
253255
/* user doing the editing is ADMIN. Disallow editing */
@@ -300,10 +302,11 @@
300302
int ah = P("ah")!=0;
301303
int ag = P("ag")!=0;
302304
int at = P("at")!=0;
303305
int au = P("au")!=0;
304306
int av = P("av")!=0;
307
+ int ax = P("ax")!=0;
305308
int az = P("az")!=0;
306309
if( aa ){ zCap[i++] = 'a'; }
307310
if( ab ){ zCap[i++] = 'b'; }
308311
if( ac ){ zCap[i++] = 'c'; }
309312
if( ad ){ zCap[i++] = 'd'; }
@@ -322,10 +325,11 @@
322325
if( as ){ zCap[i++] = 's'; }
323326
if( at ){ zCap[i++] = 't'; }
324327
if( au ){ zCap[i++] = 'u'; }
325328
if( av ){ zCap[i++] = 'v'; }
326329
if( aw ){ zCap[i++] = 'w'; }
330
+ if( ax ){ zCap[i++] = 'x'; }
327331
if( az ){ zCap[i++] = 'z'; }
328332
329333
zCap[i] = 0;
330334
zPw = P("pw");
331335
zLogin = P("login");
@@ -360,11 +364,11 @@
360364
zLogin = "";
361365
zInfo = "";
362366
zCap = "";
363367
zPw = "";
364368
oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
365
- oan = oao = oap = oar = oas = oat = oau = oav = oaw = oaz = "";
369
+ oan = oao = oap = oar = oas = oat = oau = oav = oaw = oax = oaz = "";
366370
if( uid ){
367371
zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
368372
zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
369373
zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
370374
zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
@@ -387,10 +391,11 @@
387391
if( strchr(zCap, 's') ) oas = " checked=\"checked\"";
388392
if( strchr(zCap, 't') ) oat = " checked=\"checked\"";
389393
if( strchr(zCap, 'u') ) oau = " checked=\"checked\"";
390394
if( strchr(zCap, 'v') ) oav = " checked=\"checked\"";
391395
if( strchr(zCap, 'w') ) oaw = " checked=\"checked\"";
396
+ if( strchr(zCap, 'x') ) oax = " checked=\"checked\"";
392397
if( strchr(zCap, 'z') ) oaz = " checked=\"checked\"";
393398
}
394399
395400
/* figure out inherited permissions */
396401
memset(inherit, 0, sizeof(inherit));
@@ -484,10 +489,11 @@
484489
@ <input type="checkbox" name="ar"%s(oar) />%s(B('r'))Read Ticket<br />
485490
@ <input type="checkbox" name="an"%s(oan) />%s(B('n'))New Ticket<br />
486491
@ <input type="checkbox" name="ac"%s(oac) />%s(B('c'))Append Ticket<br />
487492
@ <input type="checkbox" name="aw"%s(oaw) />%s(B('w'))Write Ticket<br />
488493
@ <input type="checkbox" name="at"%s(oat) />%s(B('t'))Ticket Report<br />
494
+ @ <input type="checkbox" name="ax"%s(oax) />%s(B('x'))Private<br />
489495
@ <input type="checkbox" name="az"%s(oaz) />%s(B('z'))Download Zip
490496
@ </td>
491497
@ </tr>
492498
@ <tr>
493499
@ <td align="right">Password:</td>
494500
--- src/setup.c
+++ src/setup.c
@@ -188,10 +188,12 @@
188 @ <tr><td valign="top"><b>v</b></td>
189 @ <td><i>Developer:</i> Inherit privileges of
190 @ user <tt>developer</tt></td></tr>
191 @ <tr><td valign="top"><b>w</b></td>
192 @ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
 
 
193 @ <tr><td valign="top"><b>z</b></td>
194 @ <td><i>Zip download:</i> Download a baseline via the
195 @ <tt>/zip</tt> URL even without
196 @ check<span class="capability">o</span>ut
197 @ and <span class="capability">h</span>istory permissions</td></tr>
@@ -243,11 +245,11 @@
243 */
244 void user_edit(void){
245 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
246 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
247 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
248 char *oat, *oau, *oav, *oab, *oaz;
249 const char *inherit[128];
250 int doWrite;
251 int uid;
252 int higherUser = 0; /* True if user being edited is SETUP and the */
253 /* user doing the editing is ADMIN. Disallow editing */
@@ -300,10 +302,11 @@
300 int ah = P("ah")!=0;
301 int ag = P("ag")!=0;
302 int at = P("at")!=0;
303 int au = P("au")!=0;
304 int av = P("av")!=0;
 
305 int az = P("az")!=0;
306 if( aa ){ zCap[i++] = 'a'; }
307 if( ab ){ zCap[i++] = 'b'; }
308 if( ac ){ zCap[i++] = 'c'; }
309 if( ad ){ zCap[i++] = 'd'; }
@@ -322,10 +325,11 @@
322 if( as ){ zCap[i++] = 's'; }
323 if( at ){ zCap[i++] = 't'; }
324 if( au ){ zCap[i++] = 'u'; }
325 if( av ){ zCap[i++] = 'v'; }
326 if( aw ){ zCap[i++] = 'w'; }
 
327 if( az ){ zCap[i++] = 'z'; }
328
329 zCap[i] = 0;
330 zPw = P("pw");
331 zLogin = P("login");
@@ -360,11 +364,11 @@
360 zLogin = "";
361 zInfo = "";
362 zCap = "";
363 zPw = "";
364 oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
365 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oaz = "";
366 if( uid ){
367 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
368 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
369 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
370 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
@@ -387,10 +391,11 @@
387 if( strchr(zCap, 's') ) oas = " checked=\"checked\"";
388 if( strchr(zCap, 't') ) oat = " checked=\"checked\"";
389 if( strchr(zCap, 'u') ) oau = " checked=\"checked\"";
390 if( strchr(zCap, 'v') ) oav = " checked=\"checked\"";
391 if( strchr(zCap, 'w') ) oaw = " checked=\"checked\"";
 
392 if( strchr(zCap, 'z') ) oaz = " checked=\"checked\"";
393 }
394
395 /* figure out inherited permissions */
396 memset(inherit, 0, sizeof(inherit));
@@ -484,10 +489,11 @@
484 @ <input type="checkbox" name="ar"%s(oar) />%s(B('r'))Read Ticket<br />
485 @ <input type="checkbox" name="an"%s(oan) />%s(B('n'))New Ticket<br />
486 @ <input type="checkbox" name="ac"%s(oac) />%s(B('c'))Append Ticket<br />
487 @ <input type="checkbox" name="aw"%s(oaw) />%s(B('w'))Write Ticket<br />
488 @ <input type="checkbox" name="at"%s(oat) />%s(B('t'))Ticket Report<br />
 
489 @ <input type="checkbox" name="az"%s(oaz) />%s(B('z'))Download Zip
490 @ </td>
491 @ </tr>
492 @ <tr>
493 @ <td align="right">Password:</td>
494
--- src/setup.c
+++ src/setup.c
@@ -188,10 +188,12 @@
188 @ <tr><td valign="top"><b>v</b></td>
189 @ <td><i>Developer:</i> Inherit privileges of
190 @ user <tt>developer</tt></td></tr>
191 @ <tr><td valign="top"><b>w</b></td>
192 @ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
193 @ <tr><td valign="top"><b>x</b></td>
194 @ <td><i>Private:</i> Push and/or pull private branches</td></tr>
195 @ <tr><td valign="top"><b>z</b></td>
196 @ <td><i>Zip download:</i> Download a baseline via the
197 @ <tt>/zip</tt> URL even without
198 @ check<span class="capability">o</span>ut
199 @ and <span class="capability">h</span>istory permissions</td></tr>
@@ -243,11 +245,11 @@
245 */
246 void user_edit(void){
247 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
248 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
249 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
250 char *oat, *oau, *oav, *oab, *oax, *oaz;
251 const char *inherit[128];
252 int doWrite;
253 int uid;
254 int higherUser = 0; /* True if user being edited is SETUP and the */
255 /* user doing the editing is ADMIN. Disallow editing */
@@ -300,10 +302,11 @@
302 int ah = P("ah")!=0;
303 int ag = P("ag")!=0;
304 int at = P("at")!=0;
305 int au = P("au")!=0;
306 int av = P("av")!=0;
307 int ax = P("ax")!=0;
308 int az = P("az")!=0;
309 if( aa ){ zCap[i++] = 'a'; }
310 if( ab ){ zCap[i++] = 'b'; }
311 if( ac ){ zCap[i++] = 'c'; }
312 if( ad ){ zCap[i++] = 'd'; }
@@ -322,10 +325,11 @@
325 if( as ){ zCap[i++] = 's'; }
326 if( at ){ zCap[i++] = 't'; }
327 if( au ){ zCap[i++] = 'u'; }
328 if( av ){ zCap[i++] = 'v'; }
329 if( aw ){ zCap[i++] = 'w'; }
330 if( ax ){ zCap[i++] = 'x'; }
331 if( az ){ zCap[i++] = 'z'; }
332
333 zCap[i] = 0;
334 zPw = P("pw");
335 zLogin = P("login");
@@ -360,11 +364,11 @@
364 zLogin = "";
365 zInfo = "";
366 zCap = "";
367 zPw = "";
368 oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
369 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oax = oaz = "";
370 if( uid ){
371 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
372 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
373 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
374 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
@@ -387,10 +391,11 @@
391 if( strchr(zCap, 's') ) oas = " checked=\"checked\"";
392 if( strchr(zCap, 't') ) oat = " checked=\"checked\"";
393 if( strchr(zCap, 'u') ) oau = " checked=\"checked\"";
394 if( strchr(zCap, 'v') ) oav = " checked=\"checked\"";
395 if( strchr(zCap, 'w') ) oaw = " checked=\"checked\"";
396 if( strchr(zCap, 'x') ) oax = " checked=\"checked\"";
397 if( strchr(zCap, 'z') ) oaz = " checked=\"checked\"";
398 }
399
400 /* figure out inherited permissions */
401 memset(inherit, 0, sizeof(inherit));
@@ -484,10 +489,11 @@
489 @ <input type="checkbox" name="ar"%s(oar) />%s(B('r'))Read Ticket<br />
490 @ <input type="checkbox" name="an"%s(oan) />%s(B('n'))New Ticket<br />
491 @ <input type="checkbox" name="ac"%s(oac) />%s(B('c'))Append Ticket<br />
492 @ <input type="checkbox" name="aw"%s(oaw) />%s(B('w'))Write Ticket<br />
493 @ <input type="checkbox" name="at"%s(oat) />%s(B('t'))Ticket Report<br />
494 @ <input type="checkbox" name="ax"%s(oax) />%s(B('x'))Private<br />
495 @ <input type="checkbox" name="az"%s(oaz) />%s(B('z'))Download Zip
496 @ </td>
497 @ </tr>
498 @ <tr>
499 @ <td align="right">Password:</td>
500
+25 -9
--- src/sync.c
+++ src/sync.c
@@ -78,11 +78,11 @@
7878
configSync = CONFIGSET_SHUN;
7979
}
8080
#endif
8181
printf("Autosync: %s\n", g.urlCanonical);
8282
url_enable_proxy("via proxy: ");
83
- rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, configSync, 0);
83
+ rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0);
8484
if( rc ) fossil_warning("Autosync failed");
8585
return rc;
8686
}
8787
8888
/*
@@ -89,16 +89,17 @@
8989
** This routine processes the command-line argument for push, pull,
9090
** and sync. If a command-line argument is given, that is the URL
9191
** of a server to sync against. If no argument is given, use the
9292
** most recently synced URL. Remember the current URL for next time.
9393
*/
94
-static int process_sync_args(void){
94
+static void process_sync_args(int *pConfigSync, int *pPrivate){
9595
const char *zUrl = 0;
9696
const char *zPw = 0;
9797
int configSync = 0;
9898
int urlOptional = find_option("autourl",0,0)!=0;
9999
g.dontKeepUrl = find_option("once",0,0)!=0;
100
+ *pPrivate = find_option("private",0,0)!=0;
100101
url_proxy_options();
101102
db_find_and_open_repository(0, 0);
102103
db_open_config(0);
103104
if( g.argc==2 ){
104105
zUrl = db_get("last-sync-url", 0);
@@ -126,11 +127,11 @@
126127
user_select();
127128
if( g.argc==2 ){
128129
printf("Server: %s\n", g.urlCanonical);
129130
}
130131
url_enable_proxy("via proxy: ");
131
- return configSync;
132
+ *pConfigSync = configSync;
132133
}
133134
134135
/*
135136
** COMMAND: pull
136137
**
@@ -145,16 +146,21 @@
145146
**
146147
** The URL specified normally becomes the new "remote-url" used for
147148
** subsequent push, pull, and sync operations. However, the "--once"
148149
** command-line option makes the URL a one-time-use URL that is not
149150
** saved.
151
+**
152
+** Use the --private option to pull private branches from the
153
+** remote repository.
150154
**
151155
** See also: clone, push, sync, remote-url
152156
*/
153157
void pull_cmd(void){
154
- int syncFlags = process_sync_args();
155
- client_sync(0,1,0,syncFlags,0);
158
+ int syncFlags;
159
+ int bPrivate;
160
+ process_sync_args(&syncFlags, &bPrivate);
161
+ client_sync(0,1,0,bPrivate,syncFlags,0);
156162
}
157163
158164
/*
159165
** COMMAND: push
160166
**
@@ -169,16 +175,21 @@
169175
**
170176
** The URL specified normally becomes the new "remote-url" used for
171177
** subsequent push, pull, and sync operations. However, the "--once"
172178
** command-line option makes the URL a one-time-use URL that is not
173179
** saved.
180
+**
181
+** Use the --private option to push private branches to the
182
+** remote repository.
174183
**
175184
** See also: clone, pull, sync, remote-url
176185
*/
177186
void push_cmd(void){
178
- process_sync_args();
179
- client_sync(1,0,0,0,0);
187
+ int syncFlags;
188
+ int bPrivate;
189
+ process_sync_args(&syncFlags, &bPrivate);
190
+ client_sync(1,0,0,bPrivate,0,0);
180191
}
181192
182193
183194
/*
184195
** COMMAND: sync
@@ -199,16 +210,21 @@
199210
**
200211
** The URL specified normally becomes the new "remote-url" used for
201212
** subsequent push, pull, and sync operations. However, the "--once"
202213
** command-line option makes the URL a one-time-use URL that is not
203214
** saved.
215
+**
216
+** Use the --private option to sync private branches with the
217
+** remote repository.
204218
**
205219
** See also: clone, push, pull, remote-url
206220
*/
207221
void sync_cmd(void){
208
- int syncFlags = process_sync_args();
209
- client_sync(1,1,0,syncFlags,0);
222
+ int syncFlags;
223
+ int bPrivate;
224
+ process_sync_args(&syncFlags, &bPrivate);
225
+ client_sync(1,1,0,bPrivate,syncFlags,0);
210226
}
211227
212228
/*
213229
** COMMAND: remote-url
214230
**
215231
--- src/sync.c
+++ src/sync.c
@@ -78,11 +78,11 @@
78 configSync = CONFIGSET_SHUN;
79 }
80 #endif
81 printf("Autosync: %s\n", g.urlCanonical);
82 url_enable_proxy("via proxy: ");
83 rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, configSync, 0);
84 if( rc ) fossil_warning("Autosync failed");
85 return rc;
86 }
87
88 /*
@@ -89,16 +89,17 @@
89 ** This routine processes the command-line argument for push, pull,
90 ** and sync. If a command-line argument is given, that is the URL
91 ** of a server to sync against. If no argument is given, use the
92 ** most recently synced URL. Remember the current URL for next time.
93 */
94 static int process_sync_args(void){
95 const char *zUrl = 0;
96 const char *zPw = 0;
97 int configSync = 0;
98 int urlOptional = find_option("autourl",0,0)!=0;
99 g.dontKeepUrl = find_option("once",0,0)!=0;
 
100 url_proxy_options();
101 db_find_and_open_repository(0, 0);
102 db_open_config(0);
103 if( g.argc==2 ){
104 zUrl = db_get("last-sync-url", 0);
@@ -126,11 +127,11 @@
126 user_select();
127 if( g.argc==2 ){
128 printf("Server: %s\n", g.urlCanonical);
129 }
130 url_enable_proxy("via proxy: ");
131 return configSync;
132 }
133
134 /*
135 ** COMMAND: pull
136 **
@@ -145,16 +146,21 @@
145 **
146 ** The URL specified normally becomes the new "remote-url" used for
147 ** subsequent push, pull, and sync operations. However, the "--once"
148 ** command-line option makes the URL a one-time-use URL that is not
149 ** saved.
 
 
 
150 **
151 ** See also: clone, push, sync, remote-url
152 */
153 void pull_cmd(void){
154 int syncFlags = process_sync_args();
155 client_sync(0,1,0,syncFlags,0);
 
 
156 }
157
158 /*
159 ** COMMAND: push
160 **
@@ -169,16 +175,21 @@
169 **
170 ** The URL specified normally becomes the new "remote-url" used for
171 ** subsequent push, pull, and sync operations. However, the "--once"
172 ** command-line option makes the URL a one-time-use URL that is not
173 ** saved.
 
 
 
174 **
175 ** See also: clone, pull, sync, remote-url
176 */
177 void push_cmd(void){
178 process_sync_args();
179 client_sync(1,0,0,0,0);
 
 
180 }
181
182
183 /*
184 ** COMMAND: sync
@@ -199,16 +210,21 @@
199 **
200 ** The URL specified normally becomes the new "remote-url" used for
201 ** subsequent push, pull, and sync operations. However, the "--once"
202 ** command-line option makes the URL a one-time-use URL that is not
203 ** saved.
 
 
 
204 **
205 ** See also: clone, push, pull, remote-url
206 */
207 void sync_cmd(void){
208 int syncFlags = process_sync_args();
209 client_sync(1,1,0,syncFlags,0);
 
 
210 }
211
212 /*
213 ** COMMAND: remote-url
214 **
215
--- src/sync.c
+++ src/sync.c
@@ -78,11 +78,11 @@
78 configSync = CONFIGSET_SHUN;
79 }
80 #endif
81 printf("Autosync: %s\n", g.urlCanonical);
82 url_enable_proxy("via proxy: ");
83 rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0);
84 if( rc ) fossil_warning("Autosync failed");
85 return rc;
86 }
87
88 /*
@@ -89,16 +89,17 @@
89 ** This routine processes the command-line argument for push, pull,
90 ** and sync. If a command-line argument is given, that is the URL
91 ** of a server to sync against. If no argument is given, use the
92 ** most recently synced URL. Remember the current URL for next time.
93 */
94 static void process_sync_args(int *pConfigSync, int *pPrivate){
95 const char *zUrl = 0;
96 const char *zPw = 0;
97 int configSync = 0;
98 int urlOptional = find_option("autourl",0,0)!=0;
99 g.dontKeepUrl = find_option("once",0,0)!=0;
100 *pPrivate = find_option("private",0,0)!=0;
101 url_proxy_options();
102 db_find_and_open_repository(0, 0);
103 db_open_config(0);
104 if( g.argc==2 ){
105 zUrl = db_get("last-sync-url", 0);
@@ -126,11 +127,11 @@
127 user_select();
128 if( g.argc==2 ){
129 printf("Server: %s\n", g.urlCanonical);
130 }
131 url_enable_proxy("via proxy: ");
132 *pConfigSync = configSync;
133 }
134
135 /*
136 ** COMMAND: pull
137 **
@@ -145,16 +146,21 @@
146 **
147 ** The URL specified normally becomes the new "remote-url" used for
148 ** subsequent push, pull, and sync operations. However, the "--once"
149 ** command-line option makes the URL a one-time-use URL that is not
150 ** saved.
151 **
152 ** Use the --private option to pull private branches from the
153 ** remote repository.
154 **
155 ** See also: clone, push, sync, remote-url
156 */
157 void pull_cmd(void){
158 int syncFlags;
159 int bPrivate;
160 process_sync_args(&syncFlags, &bPrivate);
161 client_sync(0,1,0,bPrivate,syncFlags,0);
162 }
163
164 /*
165 ** COMMAND: push
166 **
@@ -169,16 +175,21 @@
175 **
176 ** The URL specified normally becomes the new "remote-url" used for
177 ** subsequent push, pull, and sync operations. However, the "--once"
178 ** command-line option makes the URL a one-time-use URL that is not
179 ** saved.
180 **
181 ** Use the --private option to push private branches to the
182 ** remote repository.
183 **
184 ** See also: clone, pull, sync, remote-url
185 */
186 void push_cmd(void){
187 int syncFlags;
188 int bPrivate;
189 process_sync_args(&syncFlags, &bPrivate);
190 client_sync(1,0,0,bPrivate,0,0);
191 }
192
193
194 /*
195 ** COMMAND: sync
@@ -199,16 +210,21 @@
210 **
211 ** The URL specified normally becomes the new "remote-url" used for
212 ** subsequent push, pull, and sync operations. However, the "--once"
213 ** command-line option makes the URL a one-time-use URL that is not
214 ** saved.
215 **
216 ** Use the --private option to sync private branches with the
217 ** remote repository.
218 **
219 ** See also: clone, push, pull, remote-url
220 */
221 void sync_cmd(void){
222 int syncFlags;
223 int bPrivate;
224 process_sync_args(&syncFlags, &bPrivate);
225 client_sync(1,1,0,bPrivate,syncFlags,0);
226 }
227
228 /*
229 ** COMMAND: remote-url
230 **
231
+131 -27
--- src/xfer.c
+++ src/xfer.c
@@ -38,10 +38,12 @@
3838
int nDeltaSent; /* Number of deltas sent */
3939
int nFileRcvd; /* Number of files received */
4040
int nDeltaRcvd; /* Number of deltas received */
4141
int nDanglingFile; /* Number of dangling deltas received */
4242
int mxSend; /* Stop sending "file" with pOut reaches this size */
43
+ u8 sendPrivate; /* True to enable sending private content */
44
+ u8 nextIsPrivate; /* If true, next "file" received is a private */
4345
};
4446
4547
4648
/*
4749
** The input blob contains a UUID. Convert it into a record ID.
@@ -49,11 +51,11 @@
4951
** phantomize is true.
5052
**
5153
** Compare to uuid_to_rid(). This routine takes a blob argument
5254
** and does less error checking.
5355
*/
54
-static int rid_from_uuid(Blob *pUuid, int phantomize){
56
+static int rid_from_uuid(Blob *pUuid, int phantomize, int isPrivate){
5557
static Stmt q;
5658
int rid;
5759
5860
db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
5961
db_bind_str(&q, ":uuid", pUuid);
@@ -62,11 +64,11 @@
6264
}else{
6365
rid = 0;
6466
}
6567
db_reset(&q);
6668
if( rid==0 && phantomize ){
67
- rid = content_new(blob_str(pUuid), 0);
69
+ rid = content_new(blob_str(pUuid), isPrivate);
6870
}
6971
return rid;
7072
}
7173
7274
/*
@@ -106,11 +108,14 @@
106108
static void xfer_accept_file(Xfer *pXfer, int cloneFlag){
107109
int n;
108110
int rid;
109111
int srcid = 0;
110112
Blob content, hash;
113
+ int isPriv;
111114
115
+ isPriv = pXfer->nextIsPrivate;
116
+ pXfer->nextIsPrivate = 0;
112117
if( pXfer->nToken<3
113118
|| pXfer->nToken>4
114119
|| !blob_is_uuid(&pXfer->aToken[1])
115120
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
116121
|| n<0
@@ -123,29 +128,35 @@
123128
blob_zero(&hash);
124129
blob_extract(pXfer->pIn, n, &content);
125130
if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
126131
/* Ignore files that have been shunned */
127132
return;
133
+ }
134
+ if( isPriv && !g.okPrivate ){
135
+ /* Do not accept private files if not authorized */
136
+ return;
128137
}
129138
if( cloneFlag ){
130139
if( pXfer->nToken==4 ){
131
- srcid = rid_from_uuid(&pXfer->aToken[2], 1);
140
+ srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
132141
pXfer->nDeltaRcvd++;
133142
}else{
134143
srcid = 0;
135144
pXfer->nFileRcvd++;
136145
}
137
- rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, 0, 0);
146
+ rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
147
+ 0, isPriv);
138148
remote_has(rid);
139149
blob_reset(&content);
140150
return;
141151
}
142152
if( pXfer->nToken==4 ){
143153
Blob src, next;
144
- srcid = rid_from_uuid(&pXfer->aToken[2], 1);
154
+ srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
145155
if( content_get(srcid, &src)==0 ){
146
- rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, 0, 0);
156
+ rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
157
+ 0, isPriv);
147158
pXfer->nDanglingFile++;
148159
db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
149160
content_make_public(rid);
150161
return;
151162
}
@@ -159,17 +170,17 @@
159170
}
160171
sha1sum_blob(&content, &hash);
161172
if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
162173
blob_appendf(&pXfer->err, "content does not match sha1 hash");
163174
}
164
- rid = content_put_ex(&content, blob_str(&hash), 0, 0, 0);
175
+ rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
165176
blob_reset(&hash);
166177
if( rid==0 ){
167178
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
168179
blob_reset(&content);
169180
}else{
170
- content_make_public(rid);
181
+ if( !isPriv ) content_make_public(rid);
171182
manifest_crosslink(rid, &content);
172183
}
173184
assert( blob_is_reset(&content) );
174185
remote_has(rid);
175186
}
@@ -201,11 +212,14 @@
201212
int szC; /* CSIZE */
202213
int szU; /* USIZE */
203214
int rid;
204215
int srcid = 0;
205216
Blob content;
217
+ int isPriv;
206218
219
+ isPriv = pXfer->nextIsPrivate;
220
+ pXfer->nextIsPrivate = 0;
207221
if( pXfer->nToken<4
208222
|| pXfer->nToken>5
209223
|| !blob_is_uuid(&pXfer->aToken[1])
210224
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
211225
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
@@ -212,25 +226,30 @@
212226
|| szC<0 || szU<0
213227
|| (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
214228
){
215229
blob_appendf(&pXfer->err, "malformed cfile line");
216230
return;
231
+ }
232
+ if( isPriv && !g.okPrivate ){
233
+ /* Do not accept private files if not authorized */
234
+ return;
217235
}
218236
blob_zero(&content);
219237
blob_extract(pXfer->pIn, szC, &content);
220238
if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
221239
/* Ignore files that have been shunned */
222240
return;
223241
}
224242
if( pXfer->nToken==5 ){
225
- srcid = rid_from_uuid(&pXfer->aToken[2], 1);
243
+ srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
226244
pXfer->nDeltaRcvd++;
227245
}else{
228246
srcid = 0;
229247
pXfer->nFileRcvd++;
230248
}
231
- rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, szC, 0);
249
+ rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
250
+ szC, isPriv);
232251
remote_has(rid);
233252
blob_reset(&content);
234253
}
235254
236255
/*
@@ -445,19 +464,20 @@
445464
}
446465
447466
/*
448467
** Send a gimme message for every phantom.
449468
**
450
-** It should not be possible to have a private phantom. But just to be
451
-** sure, take care not to send any "gimme" messagse on private artifacts.
469
+** Except: do not request shunned artifacts. And do not request
470
+** private artifacts if we are not doing a private transfer.
452471
*/
453472
static void request_phantoms(Xfer *pXfer, int maxReq){
454473
Stmt q;
455474
db_prepare(&q,
456475
"SELECT uuid FROM phantom JOIN blob USING(rid)"
457
- " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
458
- " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
476
+ " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
477
+ (pXfer->sendPrivate ? "" :
478
+ " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)")
459479
);
460480
while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
461481
const char *zUuid = db_column_text(&q, 0);
462482
blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
463483
pXfer->nGimmeSent++;
@@ -641,10 +661,27 @@
641661
content_put(&cluster);
642662
blob_reset(&cluster);
643663
}
644664
}
645665
}
666
+
667
+/*
668
+** Send igot messages for every private artifact
669
+*/
670
+static int send_private(Xfer *pXfer){
671
+ int cnt = 0;
672
+ Stmt q;
673
+ if( pXfer->sendPrivate ){
674
+ db_prepare(&q, "SELECT uuid FROM private JOIN blob USING(rid)");
675
+ while( db_step(&q)==SQLITE_ROW ){
676
+ blob_appendf(pXfer->pOut, "igot %s 1\n", db_column_text(&q,0));
677
+ cnt++;
678
+ }
679
+ db_finalize(&q);
680
+ }
681
+ return cnt;
682
+}
646683
647684
/*
648685
** Send an igot message for every entry in unclustered table.
649686
** Return the number of cards sent.
650687
*/
@@ -652,12 +689,12 @@
652689
Stmt q;
653690
int cnt = 0;
654691
db_prepare(&q,
655692
"SELECT uuid FROM unclustered JOIN blob USING(rid)"
656693
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
657
- " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
658694
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
695
+ " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
659696
);
660697
while( db_step(&q)==SQLITE_ROW ){
661698
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
662699
cnt++;
663700
}
@@ -811,27 +848,32 @@
811848
&& xfer.nToken==2
812849
&& blob_is_uuid(&xfer.aToken[1])
813850
){
814851
nGimme++;
815852
if( isPull ){
816
- int rid = rid_from_uuid(&xfer.aToken[1], 0);
853
+ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
817854
if( rid ){
818855
send_file(&xfer, rid, &xfer.aToken[1], deltaFlag);
819856
}
820857
}
821858
}else
822859
823
- /* igot UUID
860
+ /* igot UUID ?ISPRIVATE?
824861
**
825
- ** Client announces that it has a particular file.
862
+ ** Client announces that it has a particular file. If the ISPRIVATE
863
+ ** argument exists and is non-zero, then the file is a private file.
826864
*/
827
- if( xfer.nToken==2
865
+ if( xfer.nToken>=2
828866
&& blob_eq(&xfer.aToken[0], "igot")
829867
&& blob_is_uuid(&xfer.aToken[1])
830868
){
831869
if( isPush ){
832
- rid_from_uuid(&xfer.aToken[1], 1);
870
+ if( xfer.nToken==2 || blob_eq(&xfer.aToken[1],"1")==0 ){
871
+ rid_from_uuid(&xfer.aToken[1], 1, 0);
872
+ }else if( g.okPrivate ){
873
+ rid_from_uuid(&xfer.aToken[1], 1, 1);
874
+ }
833875
}
834876
}else
835877
836878
837879
/* pull SERVERCODE PROJECTCODE
@@ -929,11 +971,11 @@
929971
*/
930972
if( blob_eq(&xfer.aToken[0], "login")
931973
&& xfer.nToken==4
932974
){
933975
if( disableLogin ){
934
- g.okRead = g.okWrite = 1;
976
+ g.okRead = g.okWrite = g.okPrivate = 1;
935977
}else{
936978
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
937979
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
938980
){
939981
cgi_reset_content();
@@ -1029,10 +1071,39 @@
10291071
*/
10301072
if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
10311073
/* Process the cookie */
10321074
}else
10331075
1076
+
1077
+ /* private
1078
+ **
1079
+ ** This card indicates that the next "file" or "cfile" will contain
1080
+ ** private content.
1081
+ */
1082
+ if( blob_eq(&xfer.aToken[0], "private") ){
1083
+ xfer.nextIsPrivate = 1;
1084
+ }else
1085
+
1086
+
1087
+ /* pragma NAME VALUE...
1088
+ **
1089
+ ** The client issue pragmas to try to influence the behavior of the
1090
+ ** server. These are requests only. Unknown pragmas are silently
1091
+ ** ignored.
1092
+ */
1093
+ if( blob_eq(&xfer.aToken[0], "set") && xfer.nToken>=2 ){
1094
+ /* pragma send-private
1095
+ **
1096
+ ** If the user has the "x" privilege (which must be set explicitly -
1097
+ ** it is not automatic with "a" or "s") then this pragma causes
1098
+ ** private information to be pulled in addition to public records.
1099
+ */
1100
+ if( blob_eq(&xfer.aToken[1], "send-private") ){
1101
+ if( g.okPrivate ) xfer.sendPrivate = 1;
1102
+ }
1103
+ }else
1104
+
10341105
/* Unknown message
10351106
*/
10361107
{
10371108
cgi_reset_content();
10381109
@ error bad\scommand:\s%F(blob_str(&xfer.line))
@@ -1049,13 +1120,15 @@
10491120
** cause the client to create phantoms for all artifacts, which will
10501121
** in turn make sure that the entire repository is sent efficiently
10511122
** and expeditiously.
10521123
*/
10531124
send_all(&xfer);
1125
+ if( xfer.sendPrivate ) send_private(&xfer);
10541126
}else if( isPull ){
10551127
create_cluster();
10561128
send_unclustered(&xfer);
1129
+ if( xfer.sendPrivate ) send_private(&xfer);
10571130
}
10581131
if( recvConfig ){
10591132
configure_finalize_receive();
10601133
}
10611134
manifest_crosslink_end();
@@ -1120,10 +1193,11 @@
11201193
*/
11211194
int client_sync(
11221195
int pushFlag, /* True to do a push (or a sync) */
11231196
int pullFlag, /* True to do a pull (or a sync) */
11241197
int cloneFlag, /* True if this is a clone */
1198
+ int privateFlag, /* True to exchange private branches */
11251199
int configRcvMask, /* Receive these configuration items */
11261200
int configSendMask /* Send these configuration items */
11271201
){
11281202
int go = 1; /* Loop until zero */
11291203
int nCardSent = 0; /* Number of cards sent */
@@ -1155,10 +1229,14 @@
11551229
socket_global_init();
11561230
memset(&xfer, 0, sizeof(xfer));
11571231
xfer.pIn = &recv;
11581232
xfer.pOut = &send;
11591233
xfer.mxSend = db_get_int("max-upload", 250000);
1234
+ if( privateFlag ){
1235
+ g.okPrivate = 1;
1236
+ xfer.sendPrivate = 1;
1237
+ }
11601238
11611239
assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
11621240
db_begin_transaction();
11631241
db_record_repository_filename(0);
11641242
db_multi_exec(
@@ -1202,10 +1280,17 @@
12021280
*/
12031281
zCookie = db_get("cookie", 0);
12041282
if( zCookie ){
12051283
blob_appendf(&send, "cookie %s\n", zCookie);
12061284
}
1285
+
1286
+ /* Send a pragma to alert the server that we want private content if
1287
+ ** doing a private push, pull, sync, or clone.
1288
+ */
1289
+ if( privateFlag ){
1290
+ blob_append(&send, "pragma send-private\n", -1);
1291
+ }
12071292
12081293
/* Generate gimme cards for phantoms and leaf cards
12091294
** for all leaves.
12101295
*/
12111296
if( pullFlag || (cloneFlag && cloneSeqno==1) ){
@@ -1349,32 +1434,40 @@
13491434
if( blob_eq(&xfer.aToken[0], "gimme")
13501435
&& xfer.nToken==2
13511436
&& blob_is_uuid(&xfer.aToken[1])
13521437
){
13531438
if( pushFlag ){
1354
- int rid = rid_from_uuid(&xfer.aToken[1], 0);
1439
+ int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
13551440
if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
13561441
}
13571442
}else
13581443
1359
- /* igot UUID
1444
+ /* igot UUID ?PRIVATEFLAG?
13601445
**
13611446
** Server announces that it has a particular file. If this is
13621447
** not a file that we have and we are pulling, then create a
13631448
** phantom to cause this file to be requested on the next cycle.
13641449
** Always remember that the server has this file so that we do
13651450
** not transmit it by accident.
1451
+ **
1452
+ ** If the PRIVATE argument exists and is 1, then the file is
1453
+ ** private. Pretend it does not exists if we are not pulling
1454
+ ** private files.
13661455
*/
1367
- if( xfer.nToken==2
1456
+ if( xfer.nToken>=2
13681457
&& blob_eq(&xfer.aToken[0], "igot")
13691458
&& blob_is_uuid(&xfer.aToken[1])
13701459
){
1371
- int rid = rid_from_uuid(&xfer.aToken[1], 0);
1460
+ int rid;
1461
+ int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[1],"1");
1462
+ rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
13721463
if( rid>0 ){
1373
- content_make_public(rid);
1464
+ if( !isPriv ) content_make_public(rid);
1465
+ }else if( !g.okPrivate ){
1466
+ /* ignore private files */
13741467
}else if( pullFlag || cloneFlag ){
1375
- rid = content_new(blob_str(&xfer.aToken[1]), 0);
1468
+ rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
13761469
if( rid ) newPhantom = 1;
13771470
}
13781471
remote_has(rid);
13791472
}else
13801473
@@ -1454,10 +1547,21 @@
14541547
** same server.
14551548
*/
14561549
if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
14571550
db_set("cookie", blob_str(&xfer.aToken[1]), 0);
14581551
}else
1552
+
1553
+
1554
+ /* private
1555
+ **
1556
+ ** This card indicates that the next "file" or "cfile" will contain
1557
+ ** private content.
1558
+ */
1559
+ if( blob_eq(&xfer.aToken[0], "private") ){
1560
+ xfer.nextIsPrivate = 1;
1561
+ }else
1562
+
14591563
14601564
/* clone_seqno N
14611565
**
14621566
** When doing a clone, the server tries to send all of its artifacts
14631567
** in sequence. This card indicates the sequence number of the next
14641568
--- src/xfer.c
+++ src/xfer.c
@@ -38,10 +38,12 @@
38 int nDeltaSent; /* Number of deltas sent */
39 int nFileRcvd; /* Number of files received */
40 int nDeltaRcvd; /* Number of deltas received */
41 int nDanglingFile; /* Number of dangling deltas received */
42 int mxSend; /* Stop sending "file" with pOut reaches this size */
 
 
43 };
44
45
46 /*
47 ** The input blob contains a UUID. Convert it into a record ID.
@@ -49,11 +51,11 @@
49 ** phantomize is true.
50 **
51 ** Compare to uuid_to_rid(). This routine takes a blob argument
52 ** and does less error checking.
53 */
54 static int rid_from_uuid(Blob *pUuid, int phantomize){
55 static Stmt q;
56 int rid;
57
58 db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
59 db_bind_str(&q, ":uuid", pUuid);
@@ -62,11 +64,11 @@
62 }else{
63 rid = 0;
64 }
65 db_reset(&q);
66 if( rid==0 && phantomize ){
67 rid = content_new(blob_str(pUuid), 0);
68 }
69 return rid;
70 }
71
72 /*
@@ -106,11 +108,14 @@
106 static void xfer_accept_file(Xfer *pXfer, int cloneFlag){
107 int n;
108 int rid;
109 int srcid = 0;
110 Blob content, hash;
 
111
 
 
112 if( pXfer->nToken<3
113 || pXfer->nToken>4
114 || !blob_is_uuid(&pXfer->aToken[1])
115 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
116 || n<0
@@ -123,29 +128,35 @@
123 blob_zero(&hash);
124 blob_extract(pXfer->pIn, n, &content);
125 if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
126 /* Ignore files that have been shunned */
127 return;
 
 
 
 
128 }
129 if( cloneFlag ){
130 if( pXfer->nToken==4 ){
131 srcid = rid_from_uuid(&pXfer->aToken[2], 1);
132 pXfer->nDeltaRcvd++;
133 }else{
134 srcid = 0;
135 pXfer->nFileRcvd++;
136 }
137 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, 0, 0);
 
138 remote_has(rid);
139 blob_reset(&content);
140 return;
141 }
142 if( pXfer->nToken==4 ){
143 Blob src, next;
144 srcid = rid_from_uuid(&pXfer->aToken[2], 1);
145 if( content_get(srcid, &src)==0 ){
146 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, 0, 0);
 
147 pXfer->nDanglingFile++;
148 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
149 content_make_public(rid);
150 return;
151 }
@@ -159,17 +170,17 @@
159 }
160 sha1sum_blob(&content, &hash);
161 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
162 blob_appendf(&pXfer->err, "content does not match sha1 hash");
163 }
164 rid = content_put_ex(&content, blob_str(&hash), 0, 0, 0);
165 blob_reset(&hash);
166 if( rid==0 ){
167 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
168 blob_reset(&content);
169 }else{
170 content_make_public(rid);
171 manifest_crosslink(rid, &content);
172 }
173 assert( blob_is_reset(&content) );
174 remote_has(rid);
175 }
@@ -201,11 +212,14 @@
201 int szC; /* CSIZE */
202 int szU; /* USIZE */
203 int rid;
204 int srcid = 0;
205 Blob content;
 
206
 
 
207 if( pXfer->nToken<4
208 || pXfer->nToken>5
209 || !blob_is_uuid(&pXfer->aToken[1])
210 || !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
211 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
@@ -212,25 +226,30 @@
212 || szC<0 || szU<0
213 || (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
214 ){
215 blob_appendf(&pXfer->err, "malformed cfile line");
216 return;
 
 
 
 
217 }
218 blob_zero(&content);
219 blob_extract(pXfer->pIn, szC, &content);
220 if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
221 /* Ignore files that have been shunned */
222 return;
223 }
224 if( pXfer->nToken==5 ){
225 srcid = rid_from_uuid(&pXfer->aToken[2], 1);
226 pXfer->nDeltaRcvd++;
227 }else{
228 srcid = 0;
229 pXfer->nFileRcvd++;
230 }
231 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, szC, 0);
 
232 remote_has(rid);
233 blob_reset(&content);
234 }
235
236 /*
@@ -445,19 +464,20 @@
445 }
446
447 /*
448 ** Send a gimme message for every phantom.
449 **
450 ** It should not be possible to have a private phantom. But just to be
451 ** sure, take care not to send any "gimme" messagse on private artifacts.
452 */
453 static void request_phantoms(Xfer *pXfer, int maxReq){
454 Stmt q;
455 db_prepare(&q,
456 "SELECT uuid FROM phantom JOIN blob USING(rid)"
457 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
458 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
 
459 );
460 while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
461 const char *zUuid = db_column_text(&q, 0);
462 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
463 pXfer->nGimmeSent++;
@@ -641,10 +661,27 @@
641 content_put(&cluster);
642 blob_reset(&cluster);
643 }
644 }
645 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
647 /*
648 ** Send an igot message for every entry in unclustered table.
649 ** Return the number of cards sent.
650 */
@@ -652,12 +689,12 @@
652 Stmt q;
653 int cnt = 0;
654 db_prepare(&q,
655 "SELECT uuid FROM unclustered JOIN blob USING(rid)"
656 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
657 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
658 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
 
659 );
660 while( db_step(&q)==SQLITE_ROW ){
661 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
662 cnt++;
663 }
@@ -811,27 +848,32 @@
811 && xfer.nToken==2
812 && blob_is_uuid(&xfer.aToken[1])
813 ){
814 nGimme++;
815 if( isPull ){
816 int rid = rid_from_uuid(&xfer.aToken[1], 0);
817 if( rid ){
818 send_file(&xfer, rid, &xfer.aToken[1], deltaFlag);
819 }
820 }
821 }else
822
823 /* igot UUID
824 **
825 ** Client announces that it has a particular file.
 
826 */
827 if( xfer.nToken==2
828 && blob_eq(&xfer.aToken[0], "igot")
829 && blob_is_uuid(&xfer.aToken[1])
830 ){
831 if( isPush ){
832 rid_from_uuid(&xfer.aToken[1], 1);
 
 
 
 
833 }
834 }else
835
836
837 /* pull SERVERCODE PROJECTCODE
@@ -929,11 +971,11 @@
929 */
930 if( blob_eq(&xfer.aToken[0], "login")
931 && xfer.nToken==4
932 ){
933 if( disableLogin ){
934 g.okRead = g.okWrite = 1;
935 }else{
936 if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
937 || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
938 ){
939 cgi_reset_content();
@@ -1029,10 +1071,39 @@
1029 */
1030 if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
1031 /* Process the cookie */
1032 }else
1033
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1034 /* Unknown message
1035 */
1036 {
1037 cgi_reset_content();
1038 @ error bad\scommand:\s%F(blob_str(&xfer.line))
@@ -1049,13 +1120,15 @@
1049 ** cause the client to create phantoms for all artifacts, which will
1050 ** in turn make sure that the entire repository is sent efficiently
1051 ** and expeditiously.
1052 */
1053 send_all(&xfer);
 
1054 }else if( isPull ){
1055 create_cluster();
1056 send_unclustered(&xfer);
 
1057 }
1058 if( recvConfig ){
1059 configure_finalize_receive();
1060 }
1061 manifest_crosslink_end();
@@ -1120,10 +1193,11 @@
1120 */
1121 int client_sync(
1122 int pushFlag, /* True to do a push (or a sync) */
1123 int pullFlag, /* True to do a pull (or a sync) */
1124 int cloneFlag, /* True if this is a clone */
 
1125 int configRcvMask, /* Receive these configuration items */
1126 int configSendMask /* Send these configuration items */
1127 ){
1128 int go = 1; /* Loop until zero */
1129 int nCardSent = 0; /* Number of cards sent */
@@ -1155,10 +1229,14 @@
1155 socket_global_init();
1156 memset(&xfer, 0, sizeof(xfer));
1157 xfer.pIn = &recv;
1158 xfer.pOut = &send;
1159 xfer.mxSend = db_get_int("max-upload", 250000);
 
 
 
 
1160
1161 assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
1162 db_begin_transaction();
1163 db_record_repository_filename(0);
1164 db_multi_exec(
@@ -1202,10 +1280,17 @@
1202 */
1203 zCookie = db_get("cookie", 0);
1204 if( zCookie ){
1205 blob_appendf(&send, "cookie %s\n", zCookie);
1206 }
 
 
 
 
 
 
 
1207
1208 /* Generate gimme cards for phantoms and leaf cards
1209 ** for all leaves.
1210 */
1211 if( pullFlag || (cloneFlag && cloneSeqno==1) ){
@@ -1349,32 +1434,40 @@
1349 if( blob_eq(&xfer.aToken[0], "gimme")
1350 && xfer.nToken==2
1351 && blob_is_uuid(&xfer.aToken[1])
1352 ){
1353 if( pushFlag ){
1354 int rid = rid_from_uuid(&xfer.aToken[1], 0);
1355 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
1356 }
1357 }else
1358
1359 /* igot UUID
1360 **
1361 ** Server announces that it has a particular file. If this is
1362 ** not a file that we have and we are pulling, then create a
1363 ** phantom to cause this file to be requested on the next cycle.
1364 ** Always remember that the server has this file so that we do
1365 ** not transmit it by accident.
 
 
 
 
1366 */
1367 if( xfer.nToken==2
1368 && blob_eq(&xfer.aToken[0], "igot")
1369 && blob_is_uuid(&xfer.aToken[1])
1370 ){
1371 int rid = rid_from_uuid(&xfer.aToken[1], 0);
 
 
1372 if( rid>0 ){
1373 content_make_public(rid);
 
 
1374 }else if( pullFlag || cloneFlag ){
1375 rid = content_new(blob_str(&xfer.aToken[1]), 0);
1376 if( rid ) newPhantom = 1;
1377 }
1378 remote_has(rid);
1379 }else
1380
@@ -1454,10 +1547,21 @@
1454 ** same server.
1455 */
1456 if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
1457 db_set("cookie", blob_str(&xfer.aToken[1]), 0);
1458 }else
 
 
 
 
 
 
 
 
 
 
 
1459
1460 /* clone_seqno N
1461 **
1462 ** When doing a clone, the server tries to send all of its artifacts
1463 ** in sequence. This card indicates the sequence number of the next
1464
--- src/xfer.c
+++ src/xfer.c
@@ -38,10 +38,12 @@
38 int nDeltaSent; /* Number of deltas sent */
39 int nFileRcvd; /* Number of files received */
40 int nDeltaRcvd; /* Number of deltas received */
41 int nDanglingFile; /* Number of dangling deltas received */
42 int mxSend; /* Stop sending "file" with pOut reaches this size */
43 u8 sendPrivate; /* True to enable sending private content */
44 u8 nextIsPrivate; /* If true, next "file" received is a private */
45 };
46
47
48 /*
49 ** The input blob contains a UUID. Convert it into a record ID.
@@ -49,11 +51,11 @@
51 ** phantomize is true.
52 **
53 ** Compare to uuid_to_rid(). This routine takes a blob argument
54 ** and does less error checking.
55 */
56 static int rid_from_uuid(Blob *pUuid, int phantomize, int isPrivate){
57 static Stmt q;
58 int rid;
59
60 db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
61 db_bind_str(&q, ":uuid", pUuid);
@@ -62,11 +64,11 @@
64 }else{
65 rid = 0;
66 }
67 db_reset(&q);
68 if( rid==0 && phantomize ){
69 rid = content_new(blob_str(pUuid), isPrivate);
70 }
71 return rid;
72 }
73
74 /*
@@ -106,11 +108,14 @@
108 static void xfer_accept_file(Xfer *pXfer, int cloneFlag){
109 int n;
110 int rid;
111 int srcid = 0;
112 Blob content, hash;
113 int isPriv;
114
115 isPriv = pXfer->nextIsPrivate;
116 pXfer->nextIsPrivate = 0;
117 if( pXfer->nToken<3
118 || pXfer->nToken>4
119 || !blob_is_uuid(&pXfer->aToken[1])
120 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
121 || n<0
@@ -123,29 +128,35 @@
128 blob_zero(&hash);
129 blob_extract(pXfer->pIn, n, &content);
130 if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
131 /* Ignore files that have been shunned */
132 return;
133 }
134 if( isPriv && !g.okPrivate ){
135 /* Do not accept private files if not authorized */
136 return;
137 }
138 if( cloneFlag ){
139 if( pXfer->nToken==4 ){
140 srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
141 pXfer->nDeltaRcvd++;
142 }else{
143 srcid = 0;
144 pXfer->nFileRcvd++;
145 }
146 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
147 0, isPriv);
148 remote_has(rid);
149 blob_reset(&content);
150 return;
151 }
152 if( pXfer->nToken==4 ){
153 Blob src, next;
154 srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
155 if( content_get(srcid, &src)==0 ){
156 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
157 0, isPriv);
158 pXfer->nDanglingFile++;
159 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
160 content_make_public(rid);
161 return;
162 }
@@ -159,17 +170,17 @@
170 }
171 sha1sum_blob(&content, &hash);
172 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
173 blob_appendf(&pXfer->err, "content does not match sha1 hash");
174 }
175 rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
176 blob_reset(&hash);
177 if( rid==0 ){
178 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
179 blob_reset(&content);
180 }else{
181 if( !isPriv ) content_make_public(rid);
182 manifest_crosslink(rid, &content);
183 }
184 assert( blob_is_reset(&content) );
185 remote_has(rid);
186 }
@@ -201,11 +212,14 @@
212 int szC; /* CSIZE */
213 int szU; /* USIZE */
214 int rid;
215 int srcid = 0;
216 Blob content;
217 int isPriv;
218
219 isPriv = pXfer->nextIsPrivate;
220 pXfer->nextIsPrivate = 0;
221 if( pXfer->nToken<4
222 || pXfer->nToken>5
223 || !blob_is_uuid(&pXfer->aToken[1])
224 || !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
225 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
@@ -212,25 +226,30 @@
226 || szC<0 || szU<0
227 || (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
228 ){
229 blob_appendf(&pXfer->err, "malformed cfile line");
230 return;
231 }
232 if( isPriv && !g.okPrivate ){
233 /* Do not accept private files if not authorized */
234 return;
235 }
236 blob_zero(&content);
237 blob_extract(pXfer->pIn, szC, &content);
238 if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
239 /* Ignore files that have been shunned */
240 return;
241 }
242 if( pXfer->nToken==5 ){
243 srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
244 pXfer->nDeltaRcvd++;
245 }else{
246 srcid = 0;
247 pXfer->nFileRcvd++;
248 }
249 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
250 szC, isPriv);
251 remote_has(rid);
252 blob_reset(&content);
253 }
254
255 /*
@@ -445,19 +464,20 @@
464 }
465
466 /*
467 ** Send a gimme message for every phantom.
468 **
469 ** Except: do not request shunned artifacts. And do not request
470 ** private artifacts if we are not doing a private transfer.
471 */
472 static void request_phantoms(Xfer *pXfer, int maxReq){
473 Stmt q;
474 db_prepare(&q,
475 "SELECT uuid FROM phantom JOIN blob USING(rid)"
476 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
477 (pXfer->sendPrivate ? "" :
478 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)")
479 );
480 while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
481 const char *zUuid = db_column_text(&q, 0);
482 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
483 pXfer->nGimmeSent++;
@@ -641,10 +661,27 @@
661 content_put(&cluster);
662 blob_reset(&cluster);
663 }
664 }
665 }
666
667 /*
668 ** Send igot messages for every private artifact
669 */
670 static int send_private(Xfer *pXfer){
671 int cnt = 0;
672 Stmt q;
673 if( pXfer->sendPrivate ){
674 db_prepare(&q, "SELECT uuid FROM private JOIN blob USING(rid)");
675 while( db_step(&q)==SQLITE_ROW ){
676 blob_appendf(pXfer->pOut, "igot %s 1\n", db_column_text(&q,0));
677 cnt++;
678 }
679 db_finalize(&q);
680 }
681 return cnt;
682 }
683
684 /*
685 ** Send an igot message for every entry in unclustered table.
686 ** Return the number of cards sent.
687 */
@@ -652,12 +689,12 @@
689 Stmt q;
690 int cnt = 0;
691 db_prepare(&q,
692 "SELECT uuid FROM unclustered JOIN blob USING(rid)"
693 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
 
694 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
695 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
696 );
697 while( db_step(&q)==SQLITE_ROW ){
698 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
699 cnt++;
700 }
@@ -811,27 +848,32 @@
848 && xfer.nToken==2
849 && blob_is_uuid(&xfer.aToken[1])
850 ){
851 nGimme++;
852 if( isPull ){
853 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
854 if( rid ){
855 send_file(&xfer, rid, &xfer.aToken[1], deltaFlag);
856 }
857 }
858 }else
859
860 /* igot UUID ?ISPRIVATE?
861 **
862 ** Client announces that it has a particular file. If the ISPRIVATE
863 ** argument exists and is non-zero, then the file is a private file.
864 */
865 if( xfer.nToken>=2
866 && blob_eq(&xfer.aToken[0], "igot")
867 && blob_is_uuid(&xfer.aToken[1])
868 ){
869 if( isPush ){
870 if( xfer.nToken==2 || blob_eq(&xfer.aToken[1],"1")==0 ){
871 rid_from_uuid(&xfer.aToken[1], 1, 0);
872 }else if( g.okPrivate ){
873 rid_from_uuid(&xfer.aToken[1], 1, 1);
874 }
875 }
876 }else
877
878
879 /* pull SERVERCODE PROJECTCODE
@@ -929,11 +971,11 @@
971 */
972 if( blob_eq(&xfer.aToken[0], "login")
973 && xfer.nToken==4
974 ){
975 if( disableLogin ){
976 g.okRead = g.okWrite = g.okPrivate = 1;
977 }else{
978 if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
979 || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
980 ){
981 cgi_reset_content();
@@ -1029,10 +1071,39 @@
1071 */
1072 if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
1073 /* Process the cookie */
1074 }else
1075
1076
1077 /* private
1078 **
1079 ** This card indicates that the next "file" or "cfile" will contain
1080 ** private content.
1081 */
1082 if( blob_eq(&xfer.aToken[0], "private") ){
1083 xfer.nextIsPrivate = 1;
1084 }else
1085
1086
1087 /* pragma NAME VALUE...
1088 **
1089 ** The client issue pragmas to try to influence the behavior of the
1090 ** server. These are requests only. Unknown pragmas are silently
1091 ** ignored.
1092 */
1093 if( blob_eq(&xfer.aToken[0], "set") && xfer.nToken>=2 ){
1094 /* pragma send-private
1095 **
1096 ** If the user has the "x" privilege (which must be set explicitly -
1097 ** it is not automatic with "a" or "s") then this pragma causes
1098 ** private information to be pulled in addition to public records.
1099 */
1100 if( blob_eq(&xfer.aToken[1], "send-private") ){
1101 if( g.okPrivate ) xfer.sendPrivate = 1;
1102 }
1103 }else
1104
1105 /* Unknown message
1106 */
1107 {
1108 cgi_reset_content();
1109 @ error bad\scommand:\s%F(blob_str(&xfer.line))
@@ -1049,13 +1120,15 @@
1120 ** cause the client to create phantoms for all artifacts, which will
1121 ** in turn make sure that the entire repository is sent efficiently
1122 ** and expeditiously.
1123 */
1124 send_all(&xfer);
1125 if( xfer.sendPrivate ) send_private(&xfer);
1126 }else if( isPull ){
1127 create_cluster();
1128 send_unclustered(&xfer);
1129 if( xfer.sendPrivate ) send_private(&xfer);
1130 }
1131 if( recvConfig ){
1132 configure_finalize_receive();
1133 }
1134 manifest_crosslink_end();
@@ -1120,10 +1193,11 @@
1193 */
1194 int client_sync(
1195 int pushFlag, /* True to do a push (or a sync) */
1196 int pullFlag, /* True to do a pull (or a sync) */
1197 int cloneFlag, /* True if this is a clone */
1198 int privateFlag, /* True to exchange private branches */
1199 int configRcvMask, /* Receive these configuration items */
1200 int configSendMask /* Send these configuration items */
1201 ){
1202 int go = 1; /* Loop until zero */
1203 int nCardSent = 0; /* Number of cards sent */
@@ -1155,10 +1229,14 @@
1229 socket_global_init();
1230 memset(&xfer, 0, sizeof(xfer));
1231 xfer.pIn = &recv;
1232 xfer.pOut = &send;
1233 xfer.mxSend = db_get_int("max-upload", 250000);
1234 if( privateFlag ){
1235 g.okPrivate = 1;
1236 xfer.sendPrivate = 1;
1237 }
1238
1239 assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
1240 db_begin_transaction();
1241 db_record_repository_filename(0);
1242 db_multi_exec(
@@ -1202,10 +1280,17 @@
1280 */
1281 zCookie = db_get("cookie", 0);
1282 if( zCookie ){
1283 blob_appendf(&send, "cookie %s\n", zCookie);
1284 }
1285
1286 /* Send a pragma to alert the server that we want private content if
1287 ** doing a private push, pull, sync, or clone.
1288 */
1289 if( privateFlag ){
1290 blob_append(&send, "pragma send-private\n", -1);
1291 }
1292
1293 /* Generate gimme cards for phantoms and leaf cards
1294 ** for all leaves.
1295 */
1296 if( pullFlag || (cloneFlag && cloneSeqno==1) ){
@@ -1349,32 +1434,40 @@
1434 if( blob_eq(&xfer.aToken[0], "gimme")
1435 && xfer.nToken==2
1436 && blob_is_uuid(&xfer.aToken[1])
1437 ){
1438 if( pushFlag ){
1439 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1440 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
1441 }
1442 }else
1443
1444 /* igot UUID ?PRIVATEFLAG?
1445 **
1446 ** Server announces that it has a particular file. If this is
1447 ** not a file that we have and we are pulling, then create a
1448 ** phantom to cause this file to be requested on the next cycle.
1449 ** Always remember that the server has this file so that we do
1450 ** not transmit it by accident.
1451 **
1452 ** If the PRIVATE argument exists and is 1, then the file is
1453 ** private. Pretend it does not exists if we are not pulling
1454 ** private files.
1455 */
1456 if( xfer.nToken>=2
1457 && blob_eq(&xfer.aToken[0], "igot")
1458 && blob_is_uuid(&xfer.aToken[1])
1459 ){
1460 int rid;
1461 int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[1],"1");
1462 rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1463 if( rid>0 ){
1464 if( !isPriv ) content_make_public(rid);
1465 }else if( !g.okPrivate ){
1466 /* ignore private files */
1467 }else if( pullFlag || cloneFlag ){
1468 rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
1469 if( rid ) newPhantom = 1;
1470 }
1471 remote_has(rid);
1472 }else
1473
@@ -1454,10 +1547,21 @@
1547 ** same server.
1548 */
1549 if( blob_eq(&xfer.aToken[0], "cookie") && xfer.nToken==2 ){
1550 db_set("cookie", blob_str(&xfer.aToken[1]), 0);
1551 }else
1552
1553
1554 /* private
1555 **
1556 ** This card indicates that the next "file" or "cfile" will contain
1557 ** private content.
1558 */
1559 if( blob_eq(&xfer.aToken[0], "private") ){
1560 xfer.nextIsPrivate = 1;
1561 }else
1562
1563
1564 /* clone_seqno N
1565 **
1566 ** When doing a clone, the server tries to send all of its artifacts
1567 ** in sequence. This card indicates the sequence number of the next
1568

Keyboard Shortcuts

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