Fossil SCM

Add the --private option to the "fossil commit" command. This option creates a private branch which is never pushed.

drh 2009-08-26 18:25 trunk
Commit 02a584f7f5e58808cc8260b2914345d8a72ed430
+36 -9
--- src/checkin.c
+++ src/checkin.c
@@ -260,10 +260,17 @@
260260
"\n"
261261
"# Enter comments on this check-in. Lines beginning with # are ignored.\n"
262262
"# The check-in comment follows wiki formatting rules.\n"
263263
"#\n"
264264
);
265
+ if( g.markPrivate ){
266
+ blob_append(&text,
267
+ "# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
268
+ "# repositories.\n"
269
+ "#\n", -1
270
+ );
271
+ }
265272
status_report(&text, "# ");
266273
zEditor = db_get("editor", 0);
267274
if( zEditor==0 ){
268275
zEditor = getenv("VISUAL");
269276
}
@@ -385,17 +392,21 @@
385392
** entries in the new branch when shown in the web timeline interface.
386393
**
387394
** A check-in is not permitted to fork unless the --force or -f
388395
** option appears. A check-in is not allowed against a closed check-in.
389396
**
397
+** The --private option creates a private check-in that is never synced.
398
+** Children of private check-ins are automatically private.
399
+**
390400
** Options:
391401
**
392402
** --comment|-m COMMENT-TEXT
393403
** --branch NEW-BRANCH-NAME
394404
** --bgcolor COLOR
395405
** --nosign
396406
** --force|-f
407
+** --private
397408
**
398409
*/
399410
void commit_cmd(void){
400411
int rc;
401412
int vid, nrid, nvid;
@@ -424,21 +435,34 @@
424435
noSign = find_option("nosign",0,0)!=0;
425436
zComment = find_option("comment","m",1);
426437
forceFlag = find_option("force", "f", 0)!=0;
427438
zBranch = find_option("branch","b",1);
428439
zBgColor = find_option("bgcolor",0,1);
440
+ if( find_option("private",0,0) ){
441
+ g.markPrivate = 1;
442
+ if( zBranch==0 ) zBranch = "private";
443
+ if( zBgColor==0 ) zBgColor = "#fec084"; /* Orange */
444
+ }
429445
zDateOvrd = find_option("date-override",0,1);
430446
zUserOvrd = find_option("user-override",0,1);
431447
db_must_be_within_tree();
432448
noSign = db_get_boolean("omitsign", 0)|noSign;
433449
if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; }
434450
verify_all_options();
451
+
452
+ /* Get the ID of the parent manifest artifact */
453
+ vid = db_lget_int("checkout", 0);
454
+ if( content_is_private(vid) ){
455
+ g.markPrivate = 1;
456
+ }
435457
436458
/*
437
- ** Autosync if requested.
459
+ ** Autosync if autosync is enabled and this is not a private check-in.
438460
*/
439
- autosync(AUTOSYNC_PULL);
461
+ if( !g.markPrivate ){
462
+ autosync(AUTOSYNC_PULL);
463
+ }
440464
441465
/* There are two ways this command may be executed. If there are
442466
** no arguments following the word "commit", then all modified files
443467
** in the checked out directory are committed. If one or more arguments
444468
** follows "commit", then only those files are committed.
@@ -482,17 +506,15 @@
482506
if( strlen(blob_str(&unmodified)) ){
483507
fossil_panic("file %s has not changed", blob_str(&unmodified));
484508
}
485509
}
486510
487
- vid = db_lget_int("checkout", 0);
488
-
489511
/*
490512
** Do not allow a commit that will cause a fork unless the --force flag
491
- ** is used.
513
+ ** is used or unless this is a private check-in.
492514
*/
493
- if( zBranch==0 && forceFlag==0 && !is_a_leaf(vid) ){
515
+ if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
494516
fossil_fatal("would fork. \"update\" first or use -f or --force.");
495517
}
496518
497519
/*
498520
** Do not allow a commit against a closed leaf
@@ -558,11 +580,11 @@
558580
blob_appendf(&manifest, "C %F\n", blob_str(&comment));
559581
zDate = db_text(0, "SELECT datetime('%q')", zDateOvrd ? zDateOvrd : "now");
560582
zDate[10] = 'T';
561583
blob_appendf(&manifest, "D %s\n", zDate);
562584
db_prepare(&q,
563
- "SELECT pathname, uuid, origname"
585
+ "SELECT pathname, uuid, origname, blob.rid"
564586
" FROM vfile JOIN blob ON vfile.mrid=blob.rid"
565587
" WHERE NOT deleted AND vfile.vid=%d"
566588
" ORDER BY 1", vid);
567589
blob_zero(&filename);
568590
blob_appendf(&filename, "%s/", g.zLocalRoot);
@@ -569,10 +591,11 @@
569591
nBasename = blob_size(&filename);
570592
while( db_step(&q)==SQLITE_ROW ){
571593
const char *zName = db_column_text(&q, 0);
572594
const char *zUuid = db_column_text(&q, 1);
573595
const char *zOrig = db_column_text(&q, 2);
596
+ int frid = db_column_int(&q, 3);
574597
const char *zPerm;
575598
blob_append(&filename, zName, -1);
576599
if( file_isexe(blob_str(&filename)) ){
577600
zPerm = " x";
578601
}else{
@@ -583,10 +606,11 @@
583606
blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
584607
}else{
585608
if( zPerm[0]==0 ){ zPerm = " w"; }
586609
blob_appendf(&manifest, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig);
587610
}
611
+ if( !g.markPrivate ) content_make_public(frid);
588612
}
589613
blob_reset(&filename);
590614
db_finalize(&q);
591615
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
592616
blob_appendf(&manifest, "P %s", zUuid);
@@ -593,10 +617,11 @@
593617
594618
db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
595619
db_bind_int(&q2, ":id", 0);
596620
while( db_step(&q2)==SQLITE_ROW ){
597621
int mid = db_column_int(&q2, 0);
622
+ if( !g.markPrivate && content_is_private(mid) ) continue;
598623
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
599624
if( zUuid ){
600625
blob_appendf(&manifest, " %s", zUuid);
601626
free(zUuid);
602627
}
@@ -629,11 +654,11 @@
629654
}
630655
blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
631656
md5sum_blob(&manifest, &mcksum);
632657
blob_appendf(&manifest, "Z %b\n", &mcksum);
633658
zManifestFile = mprintf("%smanifest", g.zLocalRoot);
634
- if( !noSign && clearsign(&manifest, &manifest) ){
659
+ if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){
635660
Blob ans;
636661
blob_zero(&ans);
637662
prompt_user("unable to sign manifest. continue [y/N]? ", &ans);
638663
if( blob_str(&ans)[0]!='y' ){
639664
db_end_transaction(1);
@@ -702,11 +727,13 @@
702727
undo_reset();
703728
704729
/* Commit */
705730
db_end_transaction(0);
706731
707
- autosync(AUTOSYNC_PUSH);
732
+ if( !g.markPrivate ){
733
+ autosync(AUTOSYNC_PUSH);
734
+ }
708735
if( count_nonbranch_children(vid)>1 ){
709736
printf("**** warning: a fork has occurred *****\n");
710737
}
711738
}
712739
713740
--- src/checkin.c
+++ src/checkin.c
@@ -260,10 +260,17 @@
260 "\n"
261 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
262 "# The check-in comment follows wiki formatting rules.\n"
263 "#\n"
264 );
 
 
 
 
 
 
 
265 status_report(&text, "# ");
266 zEditor = db_get("editor", 0);
267 if( zEditor==0 ){
268 zEditor = getenv("VISUAL");
269 }
@@ -385,17 +392,21 @@
385 ** entries in the new branch when shown in the web timeline interface.
386 **
387 ** A check-in is not permitted to fork unless the --force or -f
388 ** option appears. A check-in is not allowed against a closed check-in.
389 **
 
 
 
390 ** Options:
391 **
392 ** --comment|-m COMMENT-TEXT
393 ** --branch NEW-BRANCH-NAME
394 ** --bgcolor COLOR
395 ** --nosign
396 ** --force|-f
 
397 **
398 */
399 void commit_cmd(void){
400 int rc;
401 int vid, nrid, nvid;
@@ -424,21 +435,34 @@
424 noSign = find_option("nosign",0,0)!=0;
425 zComment = find_option("comment","m",1);
426 forceFlag = find_option("force", "f", 0)!=0;
427 zBranch = find_option("branch","b",1);
428 zBgColor = find_option("bgcolor",0,1);
 
 
 
 
 
429 zDateOvrd = find_option("date-override",0,1);
430 zUserOvrd = find_option("user-override",0,1);
431 db_must_be_within_tree();
432 noSign = db_get_boolean("omitsign", 0)|noSign;
433 if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; }
434 verify_all_options();
 
 
 
 
 
 
435
436 /*
437 ** Autosync if requested.
438 */
439 autosync(AUTOSYNC_PULL);
 
 
440
441 /* There are two ways this command may be executed. If there are
442 ** no arguments following the word "commit", then all modified files
443 ** in the checked out directory are committed. If one or more arguments
444 ** follows "commit", then only those files are committed.
@@ -482,17 +506,15 @@
482 if( strlen(blob_str(&unmodified)) ){
483 fossil_panic("file %s has not changed", blob_str(&unmodified));
484 }
485 }
486
487 vid = db_lget_int("checkout", 0);
488
489 /*
490 ** Do not allow a commit that will cause a fork unless the --force flag
491 ** is used.
492 */
493 if( zBranch==0 && forceFlag==0 && !is_a_leaf(vid) ){
494 fossil_fatal("would fork. \"update\" first or use -f or --force.");
495 }
496
497 /*
498 ** Do not allow a commit against a closed leaf
@@ -558,11 +580,11 @@
558 blob_appendf(&manifest, "C %F\n", blob_str(&comment));
559 zDate = db_text(0, "SELECT datetime('%q')", zDateOvrd ? zDateOvrd : "now");
560 zDate[10] = 'T';
561 blob_appendf(&manifest, "D %s\n", zDate);
562 db_prepare(&q,
563 "SELECT pathname, uuid, origname"
564 " FROM vfile JOIN blob ON vfile.mrid=blob.rid"
565 " WHERE NOT deleted AND vfile.vid=%d"
566 " ORDER BY 1", vid);
567 blob_zero(&filename);
568 blob_appendf(&filename, "%s/", g.zLocalRoot);
@@ -569,10 +591,11 @@
569 nBasename = blob_size(&filename);
570 while( db_step(&q)==SQLITE_ROW ){
571 const char *zName = db_column_text(&q, 0);
572 const char *zUuid = db_column_text(&q, 1);
573 const char *zOrig = db_column_text(&q, 2);
 
574 const char *zPerm;
575 blob_append(&filename, zName, -1);
576 if( file_isexe(blob_str(&filename)) ){
577 zPerm = " x";
578 }else{
@@ -583,10 +606,11 @@
583 blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
584 }else{
585 if( zPerm[0]==0 ){ zPerm = " w"; }
586 blob_appendf(&manifest, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig);
587 }
 
588 }
589 blob_reset(&filename);
590 db_finalize(&q);
591 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
592 blob_appendf(&manifest, "P %s", zUuid);
@@ -593,10 +617,11 @@
593
594 db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
595 db_bind_int(&q2, ":id", 0);
596 while( db_step(&q2)==SQLITE_ROW ){
597 int mid = db_column_int(&q2, 0);
 
598 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
599 if( zUuid ){
600 blob_appendf(&manifest, " %s", zUuid);
601 free(zUuid);
602 }
@@ -629,11 +654,11 @@
629 }
630 blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
631 md5sum_blob(&manifest, &mcksum);
632 blob_appendf(&manifest, "Z %b\n", &mcksum);
633 zManifestFile = mprintf("%smanifest", g.zLocalRoot);
634 if( !noSign && clearsign(&manifest, &manifest) ){
635 Blob ans;
636 blob_zero(&ans);
637 prompt_user("unable to sign manifest. continue [y/N]? ", &ans);
638 if( blob_str(&ans)[0]!='y' ){
639 db_end_transaction(1);
@@ -702,11 +727,13 @@
702 undo_reset();
703
704 /* Commit */
705 db_end_transaction(0);
706
707 autosync(AUTOSYNC_PUSH);
 
 
708 if( count_nonbranch_children(vid)>1 ){
709 printf("**** warning: a fork has occurred *****\n");
710 }
711 }
712
713
--- src/checkin.c
+++ src/checkin.c
@@ -260,10 +260,17 @@
260 "\n"
261 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
262 "# The check-in comment follows wiki formatting rules.\n"
263 "#\n"
264 );
265 if( g.markPrivate ){
266 blob_append(&text,
267 "# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
268 "# repositories.\n"
269 "#\n", -1
270 );
271 }
272 status_report(&text, "# ");
273 zEditor = db_get("editor", 0);
274 if( zEditor==0 ){
275 zEditor = getenv("VISUAL");
276 }
@@ -385,17 +392,21 @@
392 ** entries in the new branch when shown in the web timeline interface.
393 **
394 ** A check-in is not permitted to fork unless the --force or -f
395 ** option appears. A check-in is not allowed against a closed check-in.
396 **
397 ** The --private option creates a private check-in that is never synced.
398 ** Children of private check-ins are automatically private.
399 **
400 ** Options:
401 **
402 ** --comment|-m COMMENT-TEXT
403 ** --branch NEW-BRANCH-NAME
404 ** --bgcolor COLOR
405 ** --nosign
406 ** --force|-f
407 ** --private
408 **
409 */
410 void commit_cmd(void){
411 int rc;
412 int vid, nrid, nvid;
@@ -424,21 +435,34 @@
435 noSign = find_option("nosign",0,0)!=0;
436 zComment = find_option("comment","m",1);
437 forceFlag = find_option("force", "f", 0)!=0;
438 zBranch = find_option("branch","b",1);
439 zBgColor = find_option("bgcolor",0,1);
440 if( find_option("private",0,0) ){
441 g.markPrivate = 1;
442 if( zBranch==0 ) zBranch = "private";
443 if( zBgColor==0 ) zBgColor = "#fec084"; /* Orange */
444 }
445 zDateOvrd = find_option("date-override",0,1);
446 zUserOvrd = find_option("user-override",0,1);
447 db_must_be_within_tree();
448 noSign = db_get_boolean("omitsign", 0)|noSign;
449 if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; }
450 verify_all_options();
451
452 /* Get the ID of the parent manifest artifact */
453 vid = db_lget_int("checkout", 0);
454 if( content_is_private(vid) ){
455 g.markPrivate = 1;
456 }
457
458 /*
459 ** Autosync if autosync is enabled and this is not a private check-in.
460 */
461 if( !g.markPrivate ){
462 autosync(AUTOSYNC_PULL);
463 }
464
465 /* There are two ways this command may be executed. If there are
466 ** no arguments following the word "commit", then all modified files
467 ** in the checked out directory are committed. If one or more arguments
468 ** follows "commit", then only those files are committed.
@@ -482,17 +506,15 @@
506 if( strlen(blob_str(&unmodified)) ){
507 fossil_panic("file %s has not changed", blob_str(&unmodified));
508 }
509 }
510
 
 
511 /*
512 ** Do not allow a commit that will cause a fork unless the --force flag
513 ** is used or unless this is a private check-in.
514 */
515 if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
516 fossil_fatal("would fork. \"update\" first or use -f or --force.");
517 }
518
519 /*
520 ** Do not allow a commit against a closed leaf
@@ -558,11 +580,11 @@
580 blob_appendf(&manifest, "C %F\n", blob_str(&comment));
581 zDate = db_text(0, "SELECT datetime('%q')", zDateOvrd ? zDateOvrd : "now");
582 zDate[10] = 'T';
583 blob_appendf(&manifest, "D %s\n", zDate);
584 db_prepare(&q,
585 "SELECT pathname, uuid, origname, blob.rid"
586 " FROM vfile JOIN blob ON vfile.mrid=blob.rid"
587 " WHERE NOT deleted AND vfile.vid=%d"
588 " ORDER BY 1", vid);
589 blob_zero(&filename);
590 blob_appendf(&filename, "%s/", g.zLocalRoot);
@@ -569,10 +591,11 @@
591 nBasename = blob_size(&filename);
592 while( db_step(&q)==SQLITE_ROW ){
593 const char *zName = db_column_text(&q, 0);
594 const char *zUuid = db_column_text(&q, 1);
595 const char *zOrig = db_column_text(&q, 2);
596 int frid = db_column_int(&q, 3);
597 const char *zPerm;
598 blob_append(&filename, zName, -1);
599 if( file_isexe(blob_str(&filename)) ){
600 zPerm = " x";
601 }else{
@@ -583,10 +606,11 @@
606 blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
607 }else{
608 if( zPerm[0]==0 ){ zPerm = " w"; }
609 blob_appendf(&manifest, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig);
610 }
611 if( !g.markPrivate ) content_make_public(frid);
612 }
613 blob_reset(&filename);
614 db_finalize(&q);
615 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
616 blob_appendf(&manifest, "P %s", zUuid);
@@ -593,10 +617,11 @@
617
618 db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
619 db_bind_int(&q2, ":id", 0);
620 while( db_step(&q2)==SQLITE_ROW ){
621 int mid = db_column_int(&q2, 0);
622 if( !g.markPrivate && content_is_private(mid) ) continue;
623 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
624 if( zUuid ){
625 blob_appendf(&manifest, " %s", zUuid);
626 free(zUuid);
627 }
@@ -629,11 +654,11 @@
654 }
655 blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
656 md5sum_blob(&manifest, &mcksum);
657 blob_appendf(&manifest, "Z %b\n", &mcksum);
658 zManifestFile = mprintf("%smanifest", g.zLocalRoot);
659 if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){
660 Blob ans;
661 blob_zero(&ans);
662 prompt_user("unable to sign manifest. continue [y/N]? ", &ans);
663 if( blob_str(&ans)[0]!='y' ){
664 db_end_transaction(1);
@@ -702,11 +727,13 @@
727 undo_reset();
728
729 /* Commit */
730 db_end_transaction(0);
731
732 if( !g.markPrivate ){
733 autosync(AUTOSYNC_PUSH);
734 }
735 if( count_nonbranch_children(vid)>1 ){
736 printf("**** warning: a fork has occurred *****\n");
737 }
738 }
739
740
--- src/clone.c
+++ src/clone.c
@@ -58,10 +58,16 @@
5858
" VALUES('server-code', lower(hex(randomblob(20))));"
5959
"REPLACE INTO config(name,value)"
6060
" VALUES('last-sync-url', '%q');",
6161
g.urlCanonical
6262
);
63
+ db_multi_exec(
64
+ "DELETE FROM blob WHERE rid IN private;"
65
+ "DELETE FROM delta wHERE rid IN private;"
66
+ "DELETE FROM private;"
67
+ );
68
+ shun_artifacts();
6369
g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
6470
if( g.zLogin==0 ){
6571
db_create_default_users(1);
6672
}
6773
printf("Repository cloned into %s\n", g.argv[3]);
6874
--- src/clone.c
+++ src/clone.c
@@ -58,10 +58,16 @@
58 " VALUES('server-code', lower(hex(randomblob(20))));"
59 "REPLACE INTO config(name,value)"
60 " VALUES('last-sync-url', '%q');",
61 g.urlCanonical
62 );
 
 
 
 
 
 
63 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
64 if( g.zLogin==0 ){
65 db_create_default_users(1);
66 }
67 printf("Repository cloned into %s\n", g.argv[3]);
68
--- src/clone.c
+++ src/clone.c
@@ -58,10 +58,16 @@
58 " VALUES('server-code', lower(hex(randomblob(20))));"
59 "REPLACE INTO config(name,value)"
60 " VALUES('last-sync-url', '%q');",
61 g.urlCanonical
62 );
63 db_multi_exec(
64 "DELETE FROM blob WHERE rid IN private;"
65 "DELETE FROM delta wHERE rid IN private;"
66 "DELETE FROM private;"
67 );
68 shun_artifacts();
69 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
70 if( g.zLogin==0 ){
71 db_create_default_users(1);
72 }
73 printf("Repository cloned into %s\n", g.argv[3]);
74
+59 -12
--- src/content.c
+++ src/content.c
@@ -450,10 +450,14 @@
450450
db_exec(&s1);
451451
rid = db_last_insert_rowid();
452452
if( !pBlob ){
453453
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
454454
}
455
+ if( g.markPrivate ){
456
+ db_multi_exec("INSERT INTO private VALUES(%d)", rid);
457
+ markAsUnclustered = 0;
458
+ }
455459
}
456460
blob_reset(&cmpr);
457461
458462
/* If the srcId is specified, then the data we just added is
459463
** really a delta. Record this fact in the delta table.
@@ -510,15 +514,19 @@
510514
db_static_prepare(&s2,
511515
"INSERT INTO phantom VALUES(:rid)"
512516
);
513517
db_bind_int(&s2, ":rid", rid);
514518
db_exec(&s2);
515
- db_static_prepare(&s3,
516
- "INSERT INTO unclustered VALUES(:rid)"
517
- );
518
- db_bind_int(&s3, ":rid", rid);
519
- db_exec(&s3);
519
+ if( g.markPrivate ){
520
+ db_multi_exec("INSERT INTO private VALUES(%d)", rid);
521
+ }else{
522
+ db_static_prepare(&s3,
523
+ "INSERT INTO unclustered VALUES(:rid)"
524
+ );
525
+ db_bind_int(&s3, ":rid", rid);
526
+ db_exec(&s3);
527
+ }
520528
bag_insert(&contentCache.missing, rid);
521529
db_end_transaction(0);
522530
return rid;
523531
}
524532
@@ -570,47 +578,86 @@
570578
if( g.argc!=2 ) usage("RECORDID");
571579
db_must_be_within_tree();
572580
rid = atoi(g.argv[2]);
573581
content_undelta(rid);
574582
}
583
+
584
+/*
585
+** Return true if the given RID is marked as PRIVATE.
586
+*/
587
+int content_is_private(int rid){
588
+ static Stmt s1;
589
+ int rc;
590
+ db_static_prepare(&s1,
591
+ "SELECT 1 FROM private WHERE rid=:rid"
592
+ );
593
+ db_bind_int(&s1, ":rid", rid);
594
+ rc = db_step(&s1);
595
+ db_reset(&s1);
596
+ return rc==SQLITE_ROW;
597
+}
598
+
599
+/*
600
+** Make sure an artifact is public.
601
+*/
602
+void content_make_public(int rid){
603
+ static Stmt s1;
604
+ db_static_prepare(&s1,
605
+ "DELETE FROM private WHERE rid=:rid"
606
+ );
607
+ db_bind_int(&s1, ":rid", rid);
608
+ db_exec(&s1);
609
+}
575610
576611
/*
577612
** Change the storage of rid so that it is a delta of srcid.
578613
**
579614
** If rid is already a delta from some other place then no
580615
** conversion occurs and this is a no-op unless force==1.
616
+**
617
+** Never generate a delta that carries a private artifact into a public
618
+** artifact. Otherwise, when we go to send the public artifact on a
619
+** sync operation, the other end of the sync will never be able to receive
620
+** the source of the delta. It is OK to delta private->private and
621
+** public->private and public->public. Just no private->public delta.
581622
**
582623
** If srcid is a delta that depends on rid, then srcid is
583624
** converted to undeltaed text.
584625
**
585626
** If either rid or srcid contain less than 50 bytes, or if the
586627
** resulting delta does not achieve a compression of at least 25% on
587628
** its own the rid is left untouched.
588
-**
589
-** NOTE: IMHO the creation of the delta should be defered until after
590
-** the blob sizes have been checked. Doing it before the check as is
591
-** done now the code will generate a delta just to immediately throw
592
-** it away, wasting space and time.
593629
*/
594630
void content_deltify(int rid, int srcid, int force){
595631
int s;
596632
Blob data, src, delta;
597633
Stmt s1, s2;
598634
if( srcid==rid ) return;
599635
if( !force && findSrcid(rid)>0 ) return;
636
+ if( content_is_private(srcid) && !content_is_private(rid) ){
637
+ return;
638
+ }
600639
s = srcid;
601640
while( (s = findSrcid(s))>0 ){
602641
if( s==rid ){
603642
content_undelta(srcid);
604643
break;
605644
}
606645
}
607646
content_get(srcid, &src);
647
+ if( blob_size(&src)<50 ){
648
+ blob_reset(&src);
649
+ return;
650
+ }
608651
content_get(rid, &data);
652
+ if( blob_size(&data)<50 ){
653
+ blob_reset(&src);
654
+ blob_reset(&data);
655
+ return;
656
+ }
609657
blob_delta_create(&src, &data, &delta);
610
- if( blob_size(&src)>=50 && blob_size(&data)>=50 &&
611
- blob_size(&delta) < blob_size(&data)*0.75 ){
658
+ if( blob_size(&delta) < blob_size(&data)*0.75 ){
612659
blob_compress(&delta, &delta);
613660
db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
614661
db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, srcid);
615662
db_bind_blob(&s1, ":data", &delta);
616663
db_begin_transaction();
617664
--- src/content.c
+++ src/content.c
@@ -450,10 +450,14 @@
450 db_exec(&s1);
451 rid = db_last_insert_rowid();
452 if( !pBlob ){
453 db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
454 }
 
 
 
 
455 }
456 blob_reset(&cmpr);
457
458 /* If the srcId is specified, then the data we just added is
459 ** really a delta. Record this fact in the delta table.
@@ -510,15 +514,19 @@
510 db_static_prepare(&s2,
511 "INSERT INTO phantom VALUES(:rid)"
512 );
513 db_bind_int(&s2, ":rid", rid);
514 db_exec(&s2);
515 db_static_prepare(&s3,
516 "INSERT INTO unclustered VALUES(:rid)"
517 );
518 db_bind_int(&s3, ":rid", rid);
519 db_exec(&s3);
 
 
 
 
520 bag_insert(&contentCache.missing, rid);
521 db_end_transaction(0);
522 return rid;
523 }
524
@@ -570,47 +578,86 @@
570 if( g.argc!=2 ) usage("RECORDID");
571 db_must_be_within_tree();
572 rid = atoi(g.argv[2]);
573 content_undelta(rid);
574 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
575
576 /*
577 ** Change the storage of rid so that it is a delta of srcid.
578 **
579 ** If rid is already a delta from some other place then no
580 ** conversion occurs and this is a no-op unless force==1.
 
 
 
 
 
 
581 **
582 ** If srcid is a delta that depends on rid, then srcid is
583 ** converted to undeltaed text.
584 **
585 ** If either rid or srcid contain less than 50 bytes, or if the
586 ** resulting delta does not achieve a compression of at least 25% on
587 ** its own the rid is left untouched.
588 **
589 ** NOTE: IMHO the creation of the delta should be defered until after
590 ** the blob sizes have been checked. Doing it before the check as is
591 ** done now the code will generate a delta just to immediately throw
592 ** it away, wasting space and time.
593 */
594 void content_deltify(int rid, int srcid, int force){
595 int s;
596 Blob data, src, delta;
597 Stmt s1, s2;
598 if( srcid==rid ) return;
599 if( !force && findSrcid(rid)>0 ) return;
 
 
 
600 s = srcid;
601 while( (s = findSrcid(s))>0 ){
602 if( s==rid ){
603 content_undelta(srcid);
604 break;
605 }
606 }
607 content_get(srcid, &src);
 
 
 
 
608 content_get(rid, &data);
 
 
 
 
 
609 blob_delta_create(&src, &data, &delta);
610 if( blob_size(&src)>=50 && blob_size(&data)>=50 &&
611 blob_size(&delta) < blob_size(&data)*0.75 ){
612 blob_compress(&delta, &delta);
613 db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
614 db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, srcid);
615 db_bind_blob(&s1, ":data", &delta);
616 db_begin_transaction();
617
--- src/content.c
+++ src/content.c
@@ -450,10 +450,14 @@
450 db_exec(&s1);
451 rid = db_last_insert_rowid();
452 if( !pBlob ){
453 db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
454 }
455 if( g.markPrivate ){
456 db_multi_exec("INSERT INTO private VALUES(%d)", rid);
457 markAsUnclustered = 0;
458 }
459 }
460 blob_reset(&cmpr);
461
462 /* If the srcId is specified, then the data we just added is
463 ** really a delta. Record this fact in the delta table.
@@ -510,15 +514,19 @@
514 db_static_prepare(&s2,
515 "INSERT INTO phantom VALUES(:rid)"
516 );
517 db_bind_int(&s2, ":rid", rid);
518 db_exec(&s2);
519 if( g.markPrivate ){
520 db_multi_exec("INSERT INTO private VALUES(%d)", rid);
521 }else{
522 db_static_prepare(&s3,
523 "INSERT INTO unclustered VALUES(:rid)"
524 );
525 db_bind_int(&s3, ":rid", rid);
526 db_exec(&s3);
527 }
528 bag_insert(&contentCache.missing, rid);
529 db_end_transaction(0);
530 return rid;
531 }
532
@@ -570,47 +578,86 @@
578 if( g.argc!=2 ) usage("RECORDID");
579 db_must_be_within_tree();
580 rid = atoi(g.argv[2]);
581 content_undelta(rid);
582 }
583
584 /*
585 ** Return true if the given RID is marked as PRIVATE.
586 */
587 int content_is_private(int rid){
588 static Stmt s1;
589 int rc;
590 db_static_prepare(&s1,
591 "SELECT 1 FROM private WHERE rid=:rid"
592 );
593 db_bind_int(&s1, ":rid", rid);
594 rc = db_step(&s1);
595 db_reset(&s1);
596 return rc==SQLITE_ROW;
597 }
598
599 /*
600 ** Make sure an artifact is public.
601 */
602 void content_make_public(int rid){
603 static Stmt s1;
604 db_static_prepare(&s1,
605 "DELETE FROM private WHERE rid=:rid"
606 );
607 db_bind_int(&s1, ":rid", rid);
608 db_exec(&s1);
609 }
610
611 /*
612 ** Change the storage of rid so that it is a delta of srcid.
613 **
614 ** If rid is already a delta from some other place then no
615 ** conversion occurs and this is a no-op unless force==1.
616 **
617 ** Never generate a delta that carries a private artifact into a public
618 ** artifact. Otherwise, when we go to send the public artifact on a
619 ** sync operation, the other end of the sync will never be able to receive
620 ** the source of the delta. It is OK to delta private->private and
621 ** public->private and public->public. Just no private->public delta.
622 **
623 ** If srcid is a delta that depends on rid, then srcid is
624 ** converted to undeltaed text.
625 **
626 ** If either rid or srcid contain less than 50 bytes, or if the
627 ** resulting delta does not achieve a compression of at least 25% on
628 ** its own the rid is left untouched.
 
 
 
 
 
629 */
630 void content_deltify(int rid, int srcid, int force){
631 int s;
632 Blob data, src, delta;
633 Stmt s1, s2;
634 if( srcid==rid ) return;
635 if( !force && findSrcid(rid)>0 ) return;
636 if( content_is_private(srcid) && !content_is_private(rid) ){
637 return;
638 }
639 s = srcid;
640 while( (s = findSrcid(s))>0 ){
641 if( s==rid ){
642 content_undelta(srcid);
643 break;
644 }
645 }
646 content_get(srcid, &src);
647 if( blob_size(&src)<50 ){
648 blob_reset(&src);
649 return;
650 }
651 content_get(rid, &data);
652 if( blob_size(&data)<50 ){
653 blob_reset(&src);
654 blob_reset(&data);
655 return;
656 }
657 blob_delta_create(&src, &data, &delta);
658 if( blob_size(&delta) < blob_size(&data)*0.75 ){
 
659 blob_compress(&delta, &delta);
660 db_prepare(&s1, "UPDATE blob SET content=:data WHERE rid=%d", rid);
661 db_prepare(&s2, "REPLACE INTO delta(rid,srcid)VALUES(%d,%d)", rid, srcid);
662 db_bind_blob(&s1, ":data", &delta);
663 db_begin_transaction();
664
+1
--- src/info.c
+++ src/info.c
@@ -1394,10 +1394,11 @@
13941394
Blob cksum;
13951395
blob_appendf(&ctrl, "U %F\n", g.zLogin);
13961396
md5sum_blob(&ctrl, &cksum);
13971397
blob_appendf(&ctrl, "Z %b\n", &cksum);
13981398
db_begin_transaction();
1399
+ g.markPrivate = content_is_private(rid);
13991400
nrid = content_put(&ctrl, 0, 0);
14001401
manifest_crosslink(nrid, &ctrl);
14011402
db_end_transaction(0);
14021403
}
14031404
cgi_redirectf("ci?name=%d", rid);
14041405
--- src/info.c
+++ src/info.c
@@ -1394,10 +1394,11 @@
1394 Blob cksum;
1395 blob_appendf(&ctrl, "U %F\n", g.zLogin);
1396 md5sum_blob(&ctrl, &cksum);
1397 blob_appendf(&ctrl, "Z %b\n", &cksum);
1398 db_begin_transaction();
 
1399 nrid = content_put(&ctrl, 0, 0);
1400 manifest_crosslink(nrid, &ctrl);
1401 db_end_transaction(0);
1402 }
1403 cgi_redirectf("ci?name=%d", rid);
1404
--- src/info.c
+++ src/info.c
@@ -1394,10 +1394,11 @@
1394 Blob cksum;
1395 blob_appendf(&ctrl, "U %F\n", g.zLogin);
1396 md5sum_blob(&ctrl, &cksum);
1397 blob_appendf(&ctrl, "Z %b\n", &cksum);
1398 db_begin_transaction();
1399 g.markPrivate = content_is_private(rid);
1400 nrid = content_put(&ctrl, 0, 0);
1401 manifest_crosslink(nrid, &ctrl);
1402 db_end_transaction(0);
1403 }
1404 cgi_redirectf("ci?name=%d", rid);
1405
+1 -1
--- src/main.c
+++ src/main.c
@@ -81,12 +81,12 @@
8181
Th_Interp *interp; /* The TH1 interpreter */
8282
FILE *httpIn; /* Accept HTTP input from here */
8383
FILE *httpOut; /* Send HTTP output here */
8484
int xlinkClusterOnly; /* Set when cloning. Only process clusters */
8585
int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
86
-
8786
int *aCommitFile; /* Array of files to be committed */
87
+ int markPrivate; /* All new artifacts are private if true */
8888
8989
int urlIsFile; /* True if a "file:" url */
9090
int urlIsHttps; /* True if a "https:" url */
9191
char *urlName; /* Hostname for http: or filename for file: */
9292
char *urlHostname; /* The HOST: parameter on http headers */
9393
--- src/main.c
+++ src/main.c
@@ -81,12 +81,12 @@
81 Th_Interp *interp; /* The TH1 interpreter */
82 FILE *httpIn; /* Accept HTTP input from here */
83 FILE *httpOut; /* Send HTTP output here */
84 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
85 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
86
87 int *aCommitFile; /* Array of files to be committed */
 
88
89 int urlIsFile; /* True if a "file:" url */
90 int urlIsHttps; /* True if a "https:" url */
91 char *urlName; /* Hostname for http: or filename for file: */
92 char *urlHostname; /* The HOST: parameter on http headers */
93
--- src/main.c
+++ src/main.c
@@ -81,12 +81,12 @@
81 Th_Interp *interp; /* The TH1 interpreter */
82 FILE *httpIn; /* Accept HTTP input from here */
83 FILE *httpOut; /* Send HTTP output here */
84 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
85 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
 
86 int *aCommitFile; /* Array of files to be committed */
87 int markPrivate; /* All new artifacts are private if true */
88
89 int urlIsFile; /* True if a "file:" url */
90 int urlIsHttps; /* True if a "https:" url */
91 char *urlName; /* Hostname for http: or filename for file: */
92 char *urlHostname; /* The HOST: parameter on http headers */
93
+2
--- src/shun.c
+++ src/shun.c
@@ -192,10 +192,12 @@
192192
db_finalize(&q);
193193
db_multi_exec(
194194
"DELETE FROM delta WHERE rid IN toshun;"
195195
"DELETE FROM blob WHERE rid IN toshun;"
196196
"DROP TABLE toshun;"
197
+ "DELETE FROM private "
198
+ " WHERE NOT EXISTS (SELECT 1 FROM blob WHERE rid=private.rid);"
197199
);
198200
}
199201
200202
/*
201203
** WEBPAGE: rcvfromlist
202204
--- src/shun.c
+++ src/shun.c
@@ -192,10 +192,12 @@
192 db_finalize(&q);
193 db_multi_exec(
194 "DELETE FROM delta WHERE rid IN toshun;"
195 "DELETE FROM blob WHERE rid IN toshun;"
196 "DROP TABLE toshun;"
 
 
197 );
198 }
199
200 /*
201 ** WEBPAGE: rcvfromlist
202
--- src/shun.c
+++ src/shun.c
@@ -192,10 +192,12 @@
192 db_finalize(&q);
193 db_multi_exec(
194 "DELETE FROM delta WHERE rid IN toshun;"
195 "DELETE FROM blob WHERE rid IN toshun;"
196 "DROP TABLE toshun;"
197 "DELETE FROM private "
198 " WHERE NOT EXISTS (SELECT 1 FROM blob WHERE rid=private.rid);"
199 );
200 }
201
202 /*
203 ** WEBPAGE: rcvfromlist
204
+2
--- src/tag.c
+++ src/tag.c
@@ -242,10 +242,11 @@
242242
}
243243
rid = name_to_rid(g.argv[3]);
244244
if( rid==0 ){
245245
fossil_fatal("no such object: %s", g.argv[3]);
246246
}
247
+ g.markPrivate = content_is_private(rid);
247248
zValue = g.argc==5 ? g.argv[4] : 0;
248249
db_begin_transaction();
249250
tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
250251
db_end_transaction(0);
251252
}
@@ -276,10 +277,11 @@
276277
if( name_to_uuid(&uuid, 9) ){
277278
fossil_fatal("%s", g.zErrMsg);
278279
return;
279280
}
280281
rid = name_to_rid(blob_str(&uuid));
282
+ g.markPrivate = content_is_private(rid);
281283
blob_zero(&ctrl);
282284
283285
#if 0
284286
if( validate16(zTagname, strlen(zTagname)) ){
285287
fossil_fatal(
286288
--- src/tag.c
+++ src/tag.c
@@ -242,10 +242,11 @@
242 }
243 rid = name_to_rid(g.argv[3]);
244 if( rid==0 ){
245 fossil_fatal("no such object: %s", g.argv[3]);
246 }
 
247 zValue = g.argc==5 ? g.argv[4] : 0;
248 db_begin_transaction();
249 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
250 db_end_transaction(0);
251 }
@@ -276,10 +277,11 @@
276 if( name_to_uuid(&uuid, 9) ){
277 fossil_fatal("%s", g.zErrMsg);
278 return;
279 }
280 rid = name_to_rid(blob_str(&uuid));
 
281 blob_zero(&ctrl);
282
283 #if 0
284 if( validate16(zTagname, strlen(zTagname)) ){
285 fossil_fatal(
286
--- src/tag.c
+++ src/tag.c
@@ -242,10 +242,11 @@
242 }
243 rid = name_to_rid(g.argv[3]);
244 if( rid==0 ){
245 fossil_fatal("no such object: %s", g.argv[3]);
246 }
247 g.markPrivate = content_is_private(rid);
248 zValue = g.argc==5 ? g.argv[4] : 0;
249 db_begin_transaction();
250 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
251 db_end_transaction(0);
252 }
@@ -276,10 +277,11 @@
277 if( name_to_uuid(&uuid, 9) ){
278 fossil_fatal("%s", g.zErrMsg);
279 return;
280 }
281 rid = name_to_rid(blob_str(&uuid));
282 g.markPrivate = content_is_private(rid);
283 blob_zero(&ctrl);
284
285 #if 0
286 if( validate16(zTagname, strlen(zTagname)) ){
287 fossil_fatal(
288
+33 -5
--- src/xfer.c
+++ src/xfer.c
@@ -97,10 +97,13 @@
9797
** If DELTASRC exists, then the CONTENT is a delta against the
9898
** content of DELTASRC.
9999
**
100100
** If any error occurs, write a message into pErr which has already
101101
** be initialized to an empty string.
102
+**
103
+** Any artifact successfully received by this routine is considered to
104
+** be public and is therefore removed from the "private" table.
102105
*/
103106
static void xfer_accept_file(Xfer *pXfer){
104107
int n;
105108
int rid;
106109
int srcid = 0;
@@ -128,10 +131,11 @@
128131
srcid = rid_from_uuid(&pXfer->aToken[2], 1);
129132
if( content_get(srcid, &src)==0 ){
130133
rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
131134
pXfer->nDanglingFile++;
132135
db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
136
+ content_make_public(rid);
133137
return;
134138
}
135139
pXfer->nDeltaRcvd++;
136140
blob_delta_apply(&src, &content, &content);
137141
blob_reset(&src);
@@ -145,11 +149,11 @@
145149
rid = content_put(&content, blob_str(&hash), 0);
146150
blob_reset(&hash);
147151
if( rid==0 ){
148152
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
149153
}else{
150
- /* db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); */
154
+ content_make_public(rid);
151155
manifest_crosslink(rid, &content);
152156
}
153157
remote_has(rid);
154158
}
155159
@@ -156,10 +160,12 @@
156160
/*
157161
** Try to send a file as a delta against its parent.
158162
** If successful, return the number of bytes in the delta.
159163
** If we cannot generate an appropriate delta, then send
160164
** nothing and return zero.
165
+**
166
+** Never send a delta against a private artifact.
161167
*/
162168
static int send_delta_parent(
163169
Xfer *pXfer, /* The transfer context */
164170
int rid, /* record id of the file to send */
165171
Blob *pContent, /* The content of the file to send */
@@ -184,11 +190,11 @@
184190
int srcId = 0;
185191
186192
for(i=0; srcId==0 && i<count(azQuery); i++){
187193
srcId = db_int(0, azQuery[i], rid);
188194
}
189
- if( srcId>0 && content_get(srcId, &src) ){
195
+ if( srcId>0 && !content_is_private(srcId) && content_get(srcId, &src) ){
190196
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
191197
blob_delta_create(&src, pContent, &delta);
192198
size = blob_size(&delta);
193199
if( size>=blob_size(pContent)-50 ){
194200
size = 0;
@@ -209,10 +215,12 @@
209215
/*
210216
** Try to send a file as a native delta.
211217
** If successful, return the number of bytes in the delta.
212218
** If we cannot generate an appropriate delta, then send
213219
** nothing and return zero.
220
+**
221
+** Never send a delta against a private artifact.
214222
*/
215223
static int send_delta_native(
216224
Xfer *pXfer, /* The transfer context */
217225
int rid, /* record id of the file to send */
218226
Blob *pUuid /* The UUID of the file to send */
@@ -220,11 +228,11 @@
220228
Blob src, delta;
221229
int size = 0;
222230
int srcId;
223231
224232
srcId = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", rid);
225
- if( srcId>0 ){
233
+ if( srcId>0 && !content_is_private(srcId) ){
226234
blob_zero(&src);
227235
db_blob(&src, "SELECT uuid FROM blob WHERE rid=%d", srcId);
228236
if( uuid_is_shunned(blob_str(&src)) ){
229237
blob_reset(&src);
230238
return 0;
@@ -250,15 +258,20 @@
250258
** The pUuid can be NULL in which case the correct UUID is computed
251259
** from the rid.
252260
**
253261
** Try to send the file as a native delta if nativeDelta is true, or
254262
** as a parent delta if nativeDelta is false.
263
+**
264
+** It should never be the case that rid is a private artifact. But
265
+** as a precaution, this routine does check on rid and if it is private
266
+** this routine becomes a no-op.
255267
*/
256268
static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){
257269
Blob content, uuid;
258270
int size = 0;
259271
272
+ if( content_is_private(rid) ) return;
260273
if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){
261274
return;
262275
}
263276
blob_zero(&uuid);
264277
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid);
@@ -308,16 +321,20 @@
308321
blob_reset(&uuid);
309322
}
310323
311324
/*
312325
** Send a gimme message for every phantom.
326
+**
327
+** It should not be possible to have a private phantom. But just to be
328
+** sure, take care not to send any "gimme" messagse on private artifacts.
313329
*/
314330
static void request_phantoms(Xfer *pXfer, int maxReq){
315331
Stmt q;
316332
db_prepare(&q,
317333
"SELECT uuid FROM phantom JOIN blob USING(rid)"
318334
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
335
+ " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
319336
);
320337
while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
321338
const char *zUuid = db_column_text(&q, 0);
322339
blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
323340
pXfer->nGimmeSent++;
@@ -401,11 +418,11 @@
401418
** unsent table, all the right files will still get transferred.
402419
** It just might require an extra round trip or two.
403420
*/
404421
static void send_unsent(Xfer *pXfer){
405422
Stmt q;
406
- db_prepare(&q, "SELECT rid FROM unsent");
423
+ db_prepare(&q, "SELECT rid FROM unsent EXCEPT SELECT rid FROM private");
407424
while( db_step(&q)==SQLITE_ROW ){
408425
int rid = db_column_int(&q, 0);
409426
send_file(pXfer, rid, 0, 0);
410427
}
411428
db_finalize(&q);
@@ -420,10 +437,17 @@
420437
*/
421438
static void create_cluster(void){
422439
Blob cluster, cksum;
423440
Stmt q;
424441
int nUncl;
442
+
443
+ /* We should not ever get any private artifacts in the unclustered table.
444
+ ** But if we do (because of a bug) now is a good time to delete them. */
445
+ db_multi_exec(
446
+ "DELETE FROM unclustered WHERE rid IN (SELECT rid FROM private)"
447
+ );
448
+
425449
nUncl = db_int(0, "SELECT count(*) FROM unclustered"
426450
" WHERE NOT EXISTS(SELECT 1 FROM phantom"
427451
" WHERE rid=unclustered.rid)");
428452
if( nUncl<100 ){
429453
return;
@@ -455,10 +479,11 @@
455479
Stmt q;
456480
int cnt = 0;
457481
db_prepare(&q,
458482
"SELECT uuid FROM unclustered JOIN blob USING(rid)"
459483
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
484
+ " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
460485
);
461486
while( db_step(&q)==SQLITE_ROW ){
462487
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
463488
cnt++;
464489
}
@@ -472,10 +497,11 @@
472497
static void send_all(Xfer *pXfer){
473498
Stmt q;
474499
db_prepare(&q,
475500
"SELECT uuid FROM blob "
476501
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
502
+ " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
477503
);
478504
while( db_step(&q)==SQLITE_ROW ){
479505
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
480506
}
481507
db_finalize(&q);
@@ -1036,11 +1062,13 @@
10361062
if( xfer.nToken==2
10371063
&& blob_eq(&xfer.aToken[0], "igot")
10381064
&& blob_is_uuid(&xfer.aToken[1])
10391065
){
10401066
int rid = rid_from_uuid(&xfer.aToken[1], 0);
1041
- if( rid==0 && (pullFlag || cloneFlag) ){
1067
+ if( rid>0 ){
1068
+ content_make_public(rid);
1069
+ }else if( pullFlag || cloneFlag ){
10421070
rid = content_new(blob_str(&xfer.aToken[1]));
10431071
if( rid ) newPhantom = 1;
10441072
}
10451073
remote_has(rid);
10461074
}else
10471075
--- src/xfer.c
+++ src/xfer.c
@@ -97,10 +97,13 @@
97 ** If DELTASRC exists, then the CONTENT is a delta against the
98 ** content of DELTASRC.
99 **
100 ** If any error occurs, write a message into pErr which has already
101 ** be initialized to an empty string.
 
 
 
102 */
103 static void xfer_accept_file(Xfer *pXfer){
104 int n;
105 int rid;
106 int srcid = 0;
@@ -128,10 +131,11 @@
128 srcid = rid_from_uuid(&pXfer->aToken[2], 1);
129 if( content_get(srcid, &src)==0 ){
130 rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
131 pXfer->nDanglingFile++;
132 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
 
133 return;
134 }
135 pXfer->nDeltaRcvd++;
136 blob_delta_apply(&src, &content, &content);
137 blob_reset(&src);
@@ -145,11 +149,11 @@
145 rid = content_put(&content, blob_str(&hash), 0);
146 blob_reset(&hash);
147 if( rid==0 ){
148 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
149 }else{
150 /* db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); */
151 manifest_crosslink(rid, &content);
152 }
153 remote_has(rid);
154 }
155
@@ -156,10 +160,12 @@
156 /*
157 ** Try to send a file as a delta against its parent.
158 ** If successful, return the number of bytes in the delta.
159 ** If we cannot generate an appropriate delta, then send
160 ** nothing and return zero.
 
 
161 */
162 static int send_delta_parent(
163 Xfer *pXfer, /* The transfer context */
164 int rid, /* record id of the file to send */
165 Blob *pContent, /* The content of the file to send */
@@ -184,11 +190,11 @@
184 int srcId = 0;
185
186 for(i=0; srcId==0 && i<count(azQuery); i++){
187 srcId = db_int(0, azQuery[i], rid);
188 }
189 if( srcId>0 && content_get(srcId, &src) ){
190 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
191 blob_delta_create(&src, pContent, &delta);
192 size = blob_size(&delta);
193 if( size>=blob_size(pContent)-50 ){
194 size = 0;
@@ -209,10 +215,12 @@
209 /*
210 ** Try to send a file as a native delta.
211 ** If successful, return the number of bytes in the delta.
212 ** If we cannot generate an appropriate delta, then send
213 ** nothing and return zero.
 
 
214 */
215 static int send_delta_native(
216 Xfer *pXfer, /* The transfer context */
217 int rid, /* record id of the file to send */
218 Blob *pUuid /* The UUID of the file to send */
@@ -220,11 +228,11 @@
220 Blob src, delta;
221 int size = 0;
222 int srcId;
223
224 srcId = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", rid);
225 if( srcId>0 ){
226 blob_zero(&src);
227 db_blob(&src, "SELECT uuid FROM blob WHERE rid=%d", srcId);
228 if( uuid_is_shunned(blob_str(&src)) ){
229 blob_reset(&src);
230 return 0;
@@ -250,15 +258,20 @@
250 ** The pUuid can be NULL in which case the correct UUID is computed
251 ** from the rid.
252 **
253 ** Try to send the file as a native delta if nativeDelta is true, or
254 ** as a parent delta if nativeDelta is false.
 
 
 
 
255 */
256 static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){
257 Blob content, uuid;
258 int size = 0;
259
 
260 if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){
261 return;
262 }
263 blob_zero(&uuid);
264 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid);
@@ -308,16 +321,20 @@
308 blob_reset(&uuid);
309 }
310
311 /*
312 ** Send a gimme message for every phantom.
 
 
 
313 */
314 static void request_phantoms(Xfer *pXfer, int maxReq){
315 Stmt q;
316 db_prepare(&q,
317 "SELECT uuid FROM phantom JOIN blob USING(rid)"
318 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
 
319 );
320 while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
321 const char *zUuid = db_column_text(&q, 0);
322 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
323 pXfer->nGimmeSent++;
@@ -401,11 +418,11 @@
401 ** unsent table, all the right files will still get transferred.
402 ** It just might require an extra round trip or two.
403 */
404 static void send_unsent(Xfer *pXfer){
405 Stmt q;
406 db_prepare(&q, "SELECT rid FROM unsent");
407 while( db_step(&q)==SQLITE_ROW ){
408 int rid = db_column_int(&q, 0);
409 send_file(pXfer, rid, 0, 0);
410 }
411 db_finalize(&q);
@@ -420,10 +437,17 @@
420 */
421 static void create_cluster(void){
422 Blob cluster, cksum;
423 Stmt q;
424 int nUncl;
 
 
 
 
 
 
 
425 nUncl = db_int(0, "SELECT count(*) FROM unclustered"
426 " WHERE NOT EXISTS(SELECT 1 FROM phantom"
427 " WHERE rid=unclustered.rid)");
428 if( nUncl<100 ){
429 return;
@@ -455,10 +479,11 @@
455 Stmt q;
456 int cnt = 0;
457 db_prepare(&q,
458 "SELECT uuid FROM unclustered JOIN blob USING(rid)"
459 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
 
460 );
461 while( db_step(&q)==SQLITE_ROW ){
462 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
463 cnt++;
464 }
@@ -472,10 +497,11 @@
472 static void send_all(Xfer *pXfer){
473 Stmt q;
474 db_prepare(&q,
475 "SELECT uuid FROM blob "
476 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
 
477 );
478 while( db_step(&q)==SQLITE_ROW ){
479 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
480 }
481 db_finalize(&q);
@@ -1036,11 +1062,13 @@
1036 if( xfer.nToken==2
1037 && blob_eq(&xfer.aToken[0], "igot")
1038 && blob_is_uuid(&xfer.aToken[1])
1039 ){
1040 int rid = rid_from_uuid(&xfer.aToken[1], 0);
1041 if( rid==0 && (pullFlag || cloneFlag) ){
 
 
1042 rid = content_new(blob_str(&xfer.aToken[1]));
1043 if( rid ) newPhantom = 1;
1044 }
1045 remote_has(rid);
1046 }else
1047
--- src/xfer.c
+++ src/xfer.c
@@ -97,10 +97,13 @@
97 ** If DELTASRC exists, then the CONTENT is a delta against the
98 ** content of DELTASRC.
99 **
100 ** If any error occurs, write a message into pErr which has already
101 ** be initialized to an empty string.
102 **
103 ** Any artifact successfully received by this routine is considered to
104 ** be public and is therefore removed from the "private" table.
105 */
106 static void xfer_accept_file(Xfer *pXfer){
107 int n;
108 int rid;
109 int srcid = 0;
@@ -128,10 +131,11 @@
131 srcid = rid_from_uuid(&pXfer->aToken[2], 1);
132 if( content_get(srcid, &src)==0 ){
133 rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
134 pXfer->nDanglingFile++;
135 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
136 content_make_public(rid);
137 return;
138 }
139 pXfer->nDeltaRcvd++;
140 blob_delta_apply(&src, &content, &content);
141 blob_reset(&src);
@@ -145,11 +149,11 @@
149 rid = content_put(&content, blob_str(&hash), 0);
150 blob_reset(&hash);
151 if( rid==0 ){
152 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
153 }else{
154 content_make_public(rid);
155 manifest_crosslink(rid, &content);
156 }
157 remote_has(rid);
158 }
159
@@ -156,10 +160,12 @@
160 /*
161 ** Try to send a file as a delta against its parent.
162 ** If successful, return the number of bytes in the delta.
163 ** If we cannot generate an appropriate delta, then send
164 ** nothing and return zero.
165 **
166 ** Never send a delta against a private artifact.
167 */
168 static int send_delta_parent(
169 Xfer *pXfer, /* The transfer context */
170 int rid, /* record id of the file to send */
171 Blob *pContent, /* The content of the file to send */
@@ -184,11 +190,11 @@
190 int srcId = 0;
191
192 for(i=0; srcId==0 && i<count(azQuery); i++){
193 srcId = db_int(0, azQuery[i], rid);
194 }
195 if( srcId>0 && !content_is_private(srcId) && content_get(srcId, &src) ){
196 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
197 blob_delta_create(&src, pContent, &delta);
198 size = blob_size(&delta);
199 if( size>=blob_size(pContent)-50 ){
200 size = 0;
@@ -209,10 +215,12 @@
215 /*
216 ** Try to send a file as a native delta.
217 ** If successful, return the number of bytes in the delta.
218 ** If we cannot generate an appropriate delta, then send
219 ** nothing and return zero.
220 **
221 ** Never send a delta against a private artifact.
222 */
223 static int send_delta_native(
224 Xfer *pXfer, /* The transfer context */
225 int rid, /* record id of the file to send */
226 Blob *pUuid /* The UUID of the file to send */
@@ -220,11 +228,11 @@
228 Blob src, delta;
229 int size = 0;
230 int srcId;
231
232 srcId = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", rid);
233 if( srcId>0 && !content_is_private(srcId) ){
234 blob_zero(&src);
235 db_blob(&src, "SELECT uuid FROM blob WHERE rid=%d", srcId);
236 if( uuid_is_shunned(blob_str(&src)) ){
237 blob_reset(&src);
238 return 0;
@@ -250,15 +258,20 @@
258 ** The pUuid can be NULL in which case the correct UUID is computed
259 ** from the rid.
260 **
261 ** Try to send the file as a native delta if nativeDelta is true, or
262 ** as a parent delta if nativeDelta is false.
263 **
264 ** It should never be the case that rid is a private artifact. But
265 ** as a precaution, this routine does check on rid and if it is private
266 ** this routine becomes a no-op.
267 */
268 static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int nativeDelta){
269 Blob content, uuid;
270 int size = 0;
271
272 if( content_is_private(rid) ) return;
273 if( db_exists("SELECT 1 FROM onremote WHERE rid=%d", rid) ){
274 return;
275 }
276 blob_zero(&uuid);
277 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d AND size>=0", rid);
@@ -308,16 +321,20 @@
321 blob_reset(&uuid);
322 }
323
324 /*
325 ** Send a gimme message for every phantom.
326 **
327 ** It should not be possible to have a private phantom. But just to be
328 ** sure, take care not to send any "gimme" messagse on private artifacts.
329 */
330 static void request_phantoms(Xfer *pXfer, int maxReq){
331 Stmt q;
332 db_prepare(&q,
333 "SELECT uuid FROM phantom JOIN blob USING(rid)"
334 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
335 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
336 );
337 while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
338 const char *zUuid = db_column_text(&q, 0);
339 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
340 pXfer->nGimmeSent++;
@@ -401,11 +418,11 @@
418 ** unsent table, all the right files will still get transferred.
419 ** It just might require an extra round trip or two.
420 */
421 static void send_unsent(Xfer *pXfer){
422 Stmt q;
423 db_prepare(&q, "SELECT rid FROM unsent EXCEPT SELECT rid FROM private");
424 while( db_step(&q)==SQLITE_ROW ){
425 int rid = db_column_int(&q, 0);
426 send_file(pXfer, rid, 0, 0);
427 }
428 db_finalize(&q);
@@ -420,10 +437,17 @@
437 */
438 static void create_cluster(void){
439 Blob cluster, cksum;
440 Stmt q;
441 int nUncl;
442
443 /* We should not ever get any private artifacts in the unclustered table.
444 ** But if we do (because of a bug) now is a good time to delete them. */
445 db_multi_exec(
446 "DELETE FROM unclustered WHERE rid IN (SELECT rid FROM private)"
447 );
448
449 nUncl = db_int(0, "SELECT count(*) FROM unclustered"
450 " WHERE NOT EXISTS(SELECT 1 FROM phantom"
451 " WHERE rid=unclustered.rid)");
452 if( nUncl<100 ){
453 return;
@@ -455,10 +479,11 @@
479 Stmt q;
480 int cnt = 0;
481 db_prepare(&q,
482 "SELECT uuid FROM unclustered JOIN blob USING(rid)"
483 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
484 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
485 );
486 while( db_step(&q)==SQLITE_ROW ){
487 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
488 cnt++;
489 }
@@ -472,10 +497,11 @@
497 static void send_all(Xfer *pXfer){
498 Stmt q;
499 db_prepare(&q,
500 "SELECT uuid FROM blob "
501 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
502 " AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
503 );
504 while( db_step(&q)==SQLITE_ROW ){
505 blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
506 }
507 db_finalize(&q);
@@ -1036,11 +1062,13 @@
1062 if( xfer.nToken==2
1063 && blob_eq(&xfer.aToken[0], "igot")
1064 && blob_is_uuid(&xfer.aToken[1])
1065 ){
1066 int rid = rid_from_uuid(&xfer.aToken[1], 0);
1067 if( rid>0 ){
1068 content_make_public(rid);
1069 }else if( pullFlag || cloneFlag ){
1070 rid = content_new(blob_str(&xfer.aToken[1]));
1071 if( rid ) newPhantom = 1;
1072 }
1073 remote_has(rid);
1074 }else
1075

Keyboard Shortcuts

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