Fossil SCM
Correctly handle partial commits even when files have been deleted and/or renamed and are not part of the partial commit. Tickets [ad15a8e2af8c3162d6] and [5cc33a6aa0621be8936f].
Commit
2ceeeca19dfea6ed61424dd374dd7812f65f10e6
Parent
b4687be448ba0c3…
2 files changed
+16
-8
+36
-14
+16
-8
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -583,13 +583,15 @@ | ||
| 583 | 583 | blob_appendf(pOut, "C %F\n", blob_str(pComment)); |
| 584 | 584 | zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now"); |
| 585 | 585 | blob_appendf(pOut, "D %s\n", zDate); |
| 586 | 586 | zDate[10] = ' '; |
| 587 | 587 | db_prepare(&q, |
| 588 | - "SELECT pathname, uuid, origname, blob.rid, isexe" | |
| 588 | + "SELECT pathname, uuid, origname, blob.rid, isexe," | |
| 589 | + " file_is_selected(vfile.id)" | |
| 589 | 590 | " FROM vfile JOIN blob ON vfile.mrid=blob.rid" |
| 590 | - " WHERE NOT deleted AND vfile.vid=%d" | |
| 591 | + " WHERE (NOT deleted OR NOT file_is_selected(vfile.id))" | |
| 592 | + " AND vfile.vid=%d" | |
| 591 | 593 | " ORDER BY 1", vid); |
| 592 | 594 | blob_zero(&filename); |
| 593 | 595 | blob_appendf(&filename, "%s", g.zLocalRoot); |
| 594 | 596 | nBasename = blob_size(&filename); |
| 595 | 597 | while( db_step(&q)==SQLITE_ROW ){ |
| @@ -596,10 +598,11 @@ | ||
| 596 | 598 | const char *zName = db_column_text(&q, 0); |
| 597 | 599 | const char *zUuid = db_column_text(&q, 1); |
| 598 | 600 | const char *zOrig = db_column_text(&q, 2); |
| 599 | 601 | int frid = db_column_int(&q, 3); |
| 600 | 602 | int isexe = db_column_int(&q, 4); |
| 603 | + int isSelected = db_column_int(&q, 5); | |
| 601 | 604 | const char *zPerm; |
| 602 | 605 | int cmp; |
| 603 | 606 | blob_append(&filename, zName, -1); |
| 604 | 607 | #if !defined(_WIN32) |
| 605 | 608 | /* For unix, extract the "executable" permission bit directly from |
| @@ -622,10 +625,11 @@ | ||
| 622 | 625 | if( pFile==0 |
| 623 | 626 | || (cmp = strcmp(pFile->zName,zName))!=0 |
| 624 | 627 | || strcmp(pFile->zUuid, zUuid)!=0 |
| 625 | 628 | ){ |
| 626 | 629 | blob_resize(&filename, nBasename); |
| 630 | + if( zOrig && !isSelected ){ zName = zOrig; zOrig = 0; } | |
| 627 | 631 | if( zOrig==0 || strcmp(zOrig,zName)==0 ){ |
| 628 | 632 | blob_appendf(pOut, "F %F %s%s\n", zName, zUuid, zPerm); |
| 629 | 633 | }else{ |
| 630 | 634 | if( zPerm[0]==0 ){ zPerm = " w"; } |
| 631 | 635 | blob_appendf(pOut, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig); |
| @@ -868,11 +872,12 @@ | ||
| 868 | 872 | if( g.aCommitFile ){ |
| 869 | 873 | Blob unmodified; |
| 870 | 874 | memset(&unmodified, 0, sizeof(Blob)); |
| 871 | 875 | blob_init(&unmodified, 0, 0); |
| 872 | 876 | db_blob(&unmodified, |
| 873 | - "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)" | |
| 877 | + "SELECT pathname FROM vfile" | |
| 878 | + " WHERE chnged = 0 AND origname IS NULL AND file_is_selected(id)" | |
| 874 | 879 | ); |
| 875 | 880 | if( strlen(blob_str(&unmodified)) ){ |
| 876 | 881 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 877 | 882 | } |
| 878 | 883 | } |
| @@ -1067,28 +1072,31 @@ | ||
| 1067 | 1072 | ** of the manifest file). |
| 1068 | 1073 | */ |
| 1069 | 1074 | vfile_aggregate_checksum_repository(nvid, &cksum2); |
| 1070 | 1075 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1071 | 1076 | vfile_compare_repository_to_disk(nvid); |
| 1072 | - fossil_panic("tree checksum does not match repository after commit"); | |
| 1077 | + fossil_fatal("working checkout does not match what would have ended " | |
| 1078 | + "up in the repository: %b versus %b", | |
| 1079 | + &cksum1, &cksum2); | |
| 1073 | 1080 | } |
| 1074 | 1081 | |
| 1075 | 1082 | /* Verify that the manifest checksum matches the expected checksum */ |
| 1076 | 1083 | vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); |
| 1077 | 1084 | if( blob_compare(&cksum1, &cksum1b) ){ |
| 1078 | - fossil_panic("manifest checksum does not agree with manifest: " | |
| 1085 | + fossil_fatal("manifest checksum self-test failed: " | |
| 1079 | 1086 | "%b versus %b", &cksum1, &cksum1b); |
| 1080 | 1087 | } |
| 1081 | 1088 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1082 | - fossil_panic("tree checksum does not match manifest after commit: " | |
| 1083 | - "%b versus %b", &cksum1, &cksum2); | |
| 1089 | + fossil_fatal( | |
| 1090 | + "working checkout does not match manifest after commit: " | |
| 1091 | + "%b versus %b", &cksum1, &cksum2); | |
| 1084 | 1092 | } |
| 1085 | 1093 | |
| 1086 | 1094 | /* Verify that the commit did not modify any disk images. */ |
| 1087 | 1095 | vfile_aggregate_checksum_disk(nvid, &cksum2); |
| 1088 | 1096 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1089 | - fossil_panic("tree checksums before and after commit do not match"); | |
| 1097 | + fossil_fatal("working check before and after commit does not match"); | |
| 1090 | 1098 | } |
| 1091 | 1099 | } |
| 1092 | 1100 | |
| 1093 | 1101 | /* Clear the undo/redo stack */ |
| 1094 | 1102 | undo_reset(); |
| 1095 | 1103 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -583,13 +583,15 @@ | |
| 583 | blob_appendf(pOut, "C %F\n", blob_str(pComment)); |
| 584 | zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now"); |
| 585 | blob_appendf(pOut, "D %s\n", zDate); |
| 586 | zDate[10] = ' '; |
| 587 | db_prepare(&q, |
| 588 | "SELECT pathname, uuid, origname, blob.rid, isexe" |
| 589 | " FROM vfile JOIN blob ON vfile.mrid=blob.rid" |
| 590 | " WHERE NOT deleted AND vfile.vid=%d" |
| 591 | " ORDER BY 1", vid); |
| 592 | blob_zero(&filename); |
| 593 | blob_appendf(&filename, "%s", g.zLocalRoot); |
| 594 | nBasename = blob_size(&filename); |
| 595 | while( db_step(&q)==SQLITE_ROW ){ |
| @@ -596,10 +598,11 @@ | |
| 596 | const char *zName = db_column_text(&q, 0); |
| 597 | const char *zUuid = db_column_text(&q, 1); |
| 598 | const char *zOrig = db_column_text(&q, 2); |
| 599 | int frid = db_column_int(&q, 3); |
| 600 | int isexe = db_column_int(&q, 4); |
| 601 | const char *zPerm; |
| 602 | int cmp; |
| 603 | blob_append(&filename, zName, -1); |
| 604 | #if !defined(_WIN32) |
| 605 | /* For unix, extract the "executable" permission bit directly from |
| @@ -622,10 +625,11 @@ | |
| 622 | if( pFile==0 |
| 623 | || (cmp = strcmp(pFile->zName,zName))!=0 |
| 624 | || strcmp(pFile->zUuid, zUuid)!=0 |
| 625 | ){ |
| 626 | blob_resize(&filename, nBasename); |
| 627 | if( zOrig==0 || strcmp(zOrig,zName)==0 ){ |
| 628 | blob_appendf(pOut, "F %F %s%s\n", zName, zUuid, zPerm); |
| 629 | }else{ |
| 630 | if( zPerm[0]==0 ){ zPerm = " w"; } |
| 631 | blob_appendf(pOut, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig); |
| @@ -868,11 +872,12 @@ | |
| 868 | if( g.aCommitFile ){ |
| 869 | Blob unmodified; |
| 870 | memset(&unmodified, 0, sizeof(Blob)); |
| 871 | blob_init(&unmodified, 0, 0); |
| 872 | db_blob(&unmodified, |
| 873 | "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)" |
| 874 | ); |
| 875 | if( strlen(blob_str(&unmodified)) ){ |
| 876 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 877 | } |
| 878 | } |
| @@ -1067,28 +1072,31 @@ | |
| 1067 | ** of the manifest file). |
| 1068 | */ |
| 1069 | vfile_aggregate_checksum_repository(nvid, &cksum2); |
| 1070 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1071 | vfile_compare_repository_to_disk(nvid); |
| 1072 | fossil_panic("tree checksum does not match repository after commit"); |
| 1073 | } |
| 1074 | |
| 1075 | /* Verify that the manifest checksum matches the expected checksum */ |
| 1076 | vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); |
| 1077 | if( blob_compare(&cksum1, &cksum1b) ){ |
| 1078 | fossil_panic("manifest checksum does not agree with manifest: " |
| 1079 | "%b versus %b", &cksum1, &cksum1b); |
| 1080 | } |
| 1081 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1082 | fossil_panic("tree checksum does not match manifest after commit: " |
| 1083 | "%b versus %b", &cksum1, &cksum2); |
| 1084 | } |
| 1085 | |
| 1086 | /* Verify that the commit did not modify any disk images. */ |
| 1087 | vfile_aggregate_checksum_disk(nvid, &cksum2); |
| 1088 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1089 | fossil_panic("tree checksums before and after commit do not match"); |
| 1090 | } |
| 1091 | } |
| 1092 | |
| 1093 | /* Clear the undo/redo stack */ |
| 1094 | undo_reset(); |
| 1095 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -583,13 +583,15 @@ | |
| 583 | blob_appendf(pOut, "C %F\n", blob_str(pComment)); |
| 584 | zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now"); |
| 585 | blob_appendf(pOut, "D %s\n", zDate); |
| 586 | zDate[10] = ' '; |
| 587 | db_prepare(&q, |
| 588 | "SELECT pathname, uuid, origname, blob.rid, isexe," |
| 589 | " file_is_selected(vfile.id)" |
| 590 | " FROM vfile JOIN blob ON vfile.mrid=blob.rid" |
| 591 | " WHERE (NOT deleted OR NOT file_is_selected(vfile.id))" |
| 592 | " AND vfile.vid=%d" |
| 593 | " ORDER BY 1", vid); |
| 594 | blob_zero(&filename); |
| 595 | blob_appendf(&filename, "%s", g.zLocalRoot); |
| 596 | nBasename = blob_size(&filename); |
| 597 | while( db_step(&q)==SQLITE_ROW ){ |
| @@ -596,10 +598,11 @@ | |
| 598 | const char *zName = db_column_text(&q, 0); |
| 599 | const char *zUuid = db_column_text(&q, 1); |
| 600 | const char *zOrig = db_column_text(&q, 2); |
| 601 | int frid = db_column_int(&q, 3); |
| 602 | int isexe = db_column_int(&q, 4); |
| 603 | int isSelected = db_column_int(&q, 5); |
| 604 | const char *zPerm; |
| 605 | int cmp; |
| 606 | blob_append(&filename, zName, -1); |
| 607 | #if !defined(_WIN32) |
| 608 | /* For unix, extract the "executable" permission bit directly from |
| @@ -622,10 +625,11 @@ | |
| 625 | if( pFile==0 |
| 626 | || (cmp = strcmp(pFile->zName,zName))!=0 |
| 627 | || strcmp(pFile->zUuid, zUuid)!=0 |
| 628 | ){ |
| 629 | blob_resize(&filename, nBasename); |
| 630 | if( zOrig && !isSelected ){ zName = zOrig; zOrig = 0; } |
| 631 | if( zOrig==0 || strcmp(zOrig,zName)==0 ){ |
| 632 | blob_appendf(pOut, "F %F %s%s\n", zName, zUuid, zPerm); |
| 633 | }else{ |
| 634 | if( zPerm[0]==0 ){ zPerm = " w"; } |
| 635 | blob_appendf(pOut, "F %F %s%s %F\n", zName, zUuid, zPerm, zOrig); |
| @@ -868,11 +872,12 @@ | |
| 872 | if( g.aCommitFile ){ |
| 873 | Blob unmodified; |
| 874 | memset(&unmodified, 0, sizeof(Blob)); |
| 875 | blob_init(&unmodified, 0, 0); |
| 876 | db_blob(&unmodified, |
| 877 | "SELECT pathname FROM vfile" |
| 878 | " WHERE chnged = 0 AND origname IS NULL AND file_is_selected(id)" |
| 879 | ); |
| 880 | if( strlen(blob_str(&unmodified)) ){ |
| 881 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 882 | } |
| 883 | } |
| @@ -1067,28 +1072,31 @@ | |
| 1072 | ** of the manifest file). |
| 1073 | */ |
| 1074 | vfile_aggregate_checksum_repository(nvid, &cksum2); |
| 1075 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1076 | vfile_compare_repository_to_disk(nvid); |
| 1077 | fossil_fatal("working checkout does not match what would have ended " |
| 1078 | "up in the repository: %b versus %b", |
| 1079 | &cksum1, &cksum2); |
| 1080 | } |
| 1081 | |
| 1082 | /* Verify that the manifest checksum matches the expected checksum */ |
| 1083 | vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b); |
| 1084 | if( blob_compare(&cksum1, &cksum1b) ){ |
| 1085 | fossil_fatal("manifest checksum self-test failed: " |
| 1086 | "%b versus %b", &cksum1, &cksum1b); |
| 1087 | } |
| 1088 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1089 | fossil_fatal( |
| 1090 | "working checkout does not match manifest after commit: " |
| 1091 | "%b versus %b", &cksum1, &cksum2); |
| 1092 | } |
| 1093 | |
| 1094 | /* Verify that the commit did not modify any disk images. */ |
| 1095 | vfile_aggregate_checksum_disk(nvid, &cksum2); |
| 1096 | if( blob_compare(&cksum1, &cksum2) ){ |
| 1097 | fossil_fatal("working check before and after commit does not match"); |
| 1098 | } |
| 1099 | } |
| 1100 | |
| 1101 | /* Clear the undo/redo stack */ |
| 1102 | undo_reset(); |
| 1103 |
+36
-14
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -320,18 +320,26 @@ | ||
| 320 | 320 | closedir(d); |
| 321 | 321 | } |
| 322 | 322 | |
| 323 | 323 | /* |
| 324 | 324 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 325 | -** file in vid. The file names are part of the checksum. | |
| 325 | +** file in vid. The file names are part of the checksum. The resulting | |
| 326 | +** checksum is the same as is expected on the R-card of a manifest. | |
| 326 | 327 | ** |
| 327 | 328 | ** This function operates differently if the Global.aCommitFile |
| 328 | 329 | ** variable is not NULL. In that case, the disk image is used for |
| 329 | -** each file in aCommitFile[] and the repository image (see | |
| 330 | -** vfile_aggregate_checksum_repository() is used for all others). | |
| 330 | +** each file in aCommitFile[] and the repository image | |
| 331 | +** is used for all others). | |
| 332 | +** | |
| 331 | 333 | ** Newly added files that are not contained in the repository are |
| 332 | -** omitted from the checksum if they are not in Global.aCommitFile. | |
| 334 | +** omitted from the checksum if they are not in Global.aCommitFile[]. | |
| 335 | +** | |
| 336 | +** Newly deleted files are included in the checksum if they are not | |
| 337 | +** part of Global.aCommitFile[] | |
| 338 | +** | |
| 339 | +** Renamed files use their new name if they are in Global.aCommitFile[] | |
| 340 | +** and their original name if they are not in Global.aCommitFile[] | |
| 333 | 341 | ** |
| 334 | 342 | ** Return the resulting checksum in blob pOut. |
| 335 | 343 | */ |
| 336 | 344 | void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ |
| 337 | 345 | FILE *in; |
| @@ -338,20 +346,21 @@ | ||
| 338 | 346 | Stmt q; |
| 339 | 347 | char zBuf[4096]; |
| 340 | 348 | |
| 341 | 349 | db_must_be_within_tree(); |
| 342 | 350 | db_prepare(&q, |
| 343 | - "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" | |
| 344 | - " WHERE NOT deleted AND vid=%d" | |
| 351 | + "SELECT %Q || pathname, pathname, origname, file_is_selected(id), rid" | |
| 352 | + " FROM vfile" | |
| 353 | + " WHERE (NOT deleted OR NOT file_is_selected(id)) AND vid=%d" | |
| 345 | 354 | " ORDER BY pathname /*scan*/", |
| 346 | 355 | g.zLocalRoot, vid |
| 347 | 356 | ); |
| 348 | 357 | md5sum_init(); |
| 349 | 358 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | 359 | const char *zFullpath = db_column_text(&q, 0); |
| 351 | 360 | const char *zName = db_column_text(&q, 1); |
| 352 | - int isSelected = db_column_int(&q, 2); | |
| 361 | + int isSelected = db_column_int(&q, 3); | |
| 353 | 362 | |
| 354 | 363 | if( isSelected ){ |
| 355 | 364 | md5sum_step_text(zName, -1); |
| 356 | 365 | in = fopen(zFullpath,"rb"); |
| 357 | 366 | if( in==0 ){ |
| @@ -369,14 +378,16 @@ | ||
| 369 | 378 | if( n<=0 ) break; |
| 370 | 379 | md5sum_step_text(zBuf, n); |
| 371 | 380 | } |
| 372 | 381 | fclose(in); |
| 373 | 382 | }else{ |
| 374 | - int rid = db_column_int(&q, 3); | |
| 383 | + int rid = db_column_int(&q, 4); | |
| 384 | + const char *zOrigName = db_column_text(&q, 2); | |
| 375 | 385 | char zBuf[100]; |
| 376 | 386 | Blob file; |
| 377 | 387 | |
| 388 | + if( zOrigName ) zName = zOrigName; | |
| 378 | 389 | if( rid>0 ){ |
| 379 | 390 | md5sum_step_text(zName, -1); |
| 380 | 391 | blob_zero(&file); |
| 381 | 392 | content_get(rid, &file); |
| 382 | 393 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| @@ -437,11 +448,12 @@ | ||
| 437 | 448 | db_finalize(&q); |
| 438 | 449 | } |
| 439 | 450 | |
| 440 | 451 | /* |
| 441 | 452 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 442 | -** file in vid. The file names are part of the checksum. | |
| 453 | +** file in vid. The file names are part of the checksum. The resulting | |
| 454 | +** checksum is suitable for the R-card of a manifest. | |
| 443 | 455 | ** |
| 444 | 456 | ** Return the resulting checksum in blob pOut. |
| 445 | 457 | */ |
| 446 | 458 | void vfile_aggregate_checksum_repository(int vid, Blob *pOut){ |
| 447 | 459 | Blob file; |
| @@ -448,19 +460,24 @@ | ||
| 448 | 460 | Stmt q; |
| 449 | 461 | char zBuf[100]; |
| 450 | 462 | |
| 451 | 463 | db_must_be_within_tree(); |
| 452 | 464 | |
| 453 | - db_prepare(&q, "SELECT pathname, rid FROM vfile" | |
| 454 | - " WHERE NOT deleted AND rid>0 AND vid=%d" | |
| 465 | + db_prepare(&q, "SELECT pathname, origname, rid, file_is_selected(id)" | |
| 466 | + " FROM vfile" | |
| 467 | + " WHERE (NOT deleted OR NOT file_is_selected(id))" | |
| 468 | + " AND rid>0 AND vid=%d" | |
| 455 | 469 | " ORDER BY pathname /*scan*/", |
| 456 | 470 | vid); |
| 457 | 471 | blob_zero(&file); |
| 458 | 472 | md5sum_init(); |
| 459 | 473 | while( db_step(&q)==SQLITE_ROW ){ |
| 460 | 474 | const char *zName = db_column_text(&q, 0); |
| 461 | - int rid = db_column_int(&q, 1); | |
| 475 | + const char *zOrigName = db_column_text(&q, 1); | |
| 476 | + int rid = db_column_int(&q, 2); | |
| 477 | + int isSelected = db_column_int(&q, 3); | |
| 478 | + if( zOrigName && !isSelected ) zName = zOrigName; | |
| 462 | 479 | md5sum_step_text(zName, -1); |
| 463 | 480 | content_get(rid, &file); |
| 464 | 481 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| 465 | 482 | md5sum_step_text(zBuf, -1); |
| 466 | 483 | /*printf("%s %s %s",md5sum_current_state(),zName,zBuf); fflush(stdout);*/ |
| @@ -471,15 +488,20 @@ | ||
| 471 | 488 | md5sum_finish(pOut); |
| 472 | 489 | } |
| 473 | 490 | |
| 474 | 491 | /* |
| 475 | 492 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 476 | -** file in manifest vid. The file names are part of the checksum. | |
| 493 | +** file in manifest vid. The file names are part of the checksum. The | |
| 494 | +** resulting checksum is suitable for use as the R-card of a manifest. | |
| 495 | +** | |
| 477 | 496 | ** Return the resulting checksum in blob pOut. |
| 478 | 497 | ** |
| 479 | 498 | ** If pManOut is not NULL then fill it with the checksum found in the |
| 480 | -** "R" card near the end of the manifest. | |
| 499 | +** "R" card near the end of the manifest. | |
| 500 | +** | |
| 501 | +** In a well-formed manifest, the two checksums computed here, pOut and | |
| 502 | +** pManOut, should be identical. | |
| 481 | 503 | */ |
| 482 | 504 | void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ |
| 483 | 505 | int fid; |
| 484 | 506 | Blob file; |
| 485 | 507 | Manifest *pManifest; |
| 486 | 508 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -320,18 +320,26 @@ | |
| 320 | closedir(d); |
| 321 | } |
| 322 | |
| 323 | /* |
| 324 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 325 | ** file in vid. The file names are part of the checksum. |
| 326 | ** |
| 327 | ** This function operates differently if the Global.aCommitFile |
| 328 | ** variable is not NULL. In that case, the disk image is used for |
| 329 | ** each file in aCommitFile[] and the repository image (see |
| 330 | ** vfile_aggregate_checksum_repository() is used for all others). |
| 331 | ** Newly added files that are not contained in the repository are |
| 332 | ** omitted from the checksum if they are not in Global.aCommitFile. |
| 333 | ** |
| 334 | ** Return the resulting checksum in blob pOut. |
| 335 | */ |
| 336 | void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ |
| 337 | FILE *in; |
| @@ -338,20 +346,21 @@ | |
| 338 | Stmt q; |
| 339 | char zBuf[4096]; |
| 340 | |
| 341 | db_must_be_within_tree(); |
| 342 | db_prepare(&q, |
| 343 | "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" |
| 344 | " WHERE NOT deleted AND vid=%d" |
| 345 | " ORDER BY pathname /*scan*/", |
| 346 | g.zLocalRoot, vid |
| 347 | ); |
| 348 | md5sum_init(); |
| 349 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | const char *zFullpath = db_column_text(&q, 0); |
| 351 | const char *zName = db_column_text(&q, 1); |
| 352 | int isSelected = db_column_int(&q, 2); |
| 353 | |
| 354 | if( isSelected ){ |
| 355 | md5sum_step_text(zName, -1); |
| 356 | in = fopen(zFullpath,"rb"); |
| 357 | if( in==0 ){ |
| @@ -369,14 +378,16 @@ | |
| 369 | if( n<=0 ) break; |
| 370 | md5sum_step_text(zBuf, n); |
| 371 | } |
| 372 | fclose(in); |
| 373 | }else{ |
| 374 | int rid = db_column_int(&q, 3); |
| 375 | char zBuf[100]; |
| 376 | Blob file; |
| 377 | |
| 378 | if( rid>0 ){ |
| 379 | md5sum_step_text(zName, -1); |
| 380 | blob_zero(&file); |
| 381 | content_get(rid, &file); |
| 382 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| @@ -437,11 +448,12 @@ | |
| 437 | db_finalize(&q); |
| 438 | } |
| 439 | |
| 440 | /* |
| 441 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 442 | ** file in vid. The file names are part of the checksum. |
| 443 | ** |
| 444 | ** Return the resulting checksum in blob pOut. |
| 445 | */ |
| 446 | void vfile_aggregate_checksum_repository(int vid, Blob *pOut){ |
| 447 | Blob file; |
| @@ -448,19 +460,24 @@ | |
| 448 | Stmt q; |
| 449 | char zBuf[100]; |
| 450 | |
| 451 | db_must_be_within_tree(); |
| 452 | |
| 453 | db_prepare(&q, "SELECT pathname, rid FROM vfile" |
| 454 | " WHERE NOT deleted AND rid>0 AND vid=%d" |
| 455 | " ORDER BY pathname /*scan*/", |
| 456 | vid); |
| 457 | blob_zero(&file); |
| 458 | md5sum_init(); |
| 459 | while( db_step(&q)==SQLITE_ROW ){ |
| 460 | const char *zName = db_column_text(&q, 0); |
| 461 | int rid = db_column_int(&q, 1); |
| 462 | md5sum_step_text(zName, -1); |
| 463 | content_get(rid, &file); |
| 464 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| 465 | md5sum_step_text(zBuf, -1); |
| 466 | /*printf("%s %s %s",md5sum_current_state(),zName,zBuf); fflush(stdout);*/ |
| @@ -471,15 +488,20 @@ | |
| 471 | md5sum_finish(pOut); |
| 472 | } |
| 473 | |
| 474 | /* |
| 475 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 476 | ** file in manifest vid. The file names are part of the checksum. |
| 477 | ** Return the resulting checksum in blob pOut. |
| 478 | ** |
| 479 | ** If pManOut is not NULL then fill it with the checksum found in the |
| 480 | ** "R" card near the end of the manifest. |
| 481 | */ |
| 482 | void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ |
| 483 | int fid; |
| 484 | Blob file; |
| 485 | Manifest *pManifest; |
| 486 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -320,18 +320,26 @@ | |
| 320 | closedir(d); |
| 321 | } |
| 322 | |
| 323 | /* |
| 324 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 325 | ** file in vid. The file names are part of the checksum. The resulting |
| 326 | ** checksum is the same as is expected on the R-card of a manifest. |
| 327 | ** |
| 328 | ** This function operates differently if the Global.aCommitFile |
| 329 | ** variable is not NULL. In that case, the disk image is used for |
| 330 | ** each file in aCommitFile[] and the repository image |
| 331 | ** is used for all others). |
| 332 | ** |
| 333 | ** Newly added files that are not contained in the repository are |
| 334 | ** omitted from the checksum if they are not in Global.aCommitFile[]. |
| 335 | ** |
| 336 | ** Newly deleted files are included in the checksum if they are not |
| 337 | ** part of Global.aCommitFile[] |
| 338 | ** |
| 339 | ** Renamed files use their new name if they are in Global.aCommitFile[] |
| 340 | ** and their original name if they are not in Global.aCommitFile[] |
| 341 | ** |
| 342 | ** Return the resulting checksum in blob pOut. |
| 343 | */ |
| 344 | void vfile_aggregate_checksum_disk(int vid, Blob *pOut){ |
| 345 | FILE *in; |
| @@ -338,20 +346,21 @@ | |
| 346 | Stmt q; |
| 347 | char zBuf[4096]; |
| 348 | |
| 349 | db_must_be_within_tree(); |
| 350 | db_prepare(&q, |
| 351 | "SELECT %Q || pathname, pathname, origname, file_is_selected(id), rid" |
| 352 | " FROM vfile" |
| 353 | " WHERE (NOT deleted OR NOT file_is_selected(id)) AND vid=%d" |
| 354 | " ORDER BY pathname /*scan*/", |
| 355 | g.zLocalRoot, vid |
| 356 | ); |
| 357 | md5sum_init(); |
| 358 | while( db_step(&q)==SQLITE_ROW ){ |
| 359 | const char *zFullpath = db_column_text(&q, 0); |
| 360 | const char *zName = db_column_text(&q, 1); |
| 361 | int isSelected = db_column_int(&q, 3); |
| 362 | |
| 363 | if( isSelected ){ |
| 364 | md5sum_step_text(zName, -1); |
| 365 | in = fopen(zFullpath,"rb"); |
| 366 | if( in==0 ){ |
| @@ -369,14 +378,16 @@ | |
| 378 | if( n<=0 ) break; |
| 379 | md5sum_step_text(zBuf, n); |
| 380 | } |
| 381 | fclose(in); |
| 382 | }else{ |
| 383 | int rid = db_column_int(&q, 4); |
| 384 | const char *zOrigName = db_column_text(&q, 2); |
| 385 | char zBuf[100]; |
| 386 | Blob file; |
| 387 | |
| 388 | if( zOrigName ) zName = zOrigName; |
| 389 | if( rid>0 ){ |
| 390 | md5sum_step_text(zName, -1); |
| 391 | blob_zero(&file); |
| 392 | content_get(rid, &file); |
| 393 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| @@ -437,11 +448,12 @@ | |
| 448 | db_finalize(&q); |
| 449 | } |
| 450 | |
| 451 | /* |
| 452 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 453 | ** file in vid. The file names are part of the checksum. The resulting |
| 454 | ** checksum is suitable for the R-card of a manifest. |
| 455 | ** |
| 456 | ** Return the resulting checksum in blob pOut. |
| 457 | */ |
| 458 | void vfile_aggregate_checksum_repository(int vid, Blob *pOut){ |
| 459 | Blob file; |
| @@ -448,19 +460,24 @@ | |
| 460 | Stmt q; |
| 461 | char zBuf[100]; |
| 462 | |
| 463 | db_must_be_within_tree(); |
| 464 | |
| 465 | db_prepare(&q, "SELECT pathname, origname, rid, file_is_selected(id)" |
| 466 | " FROM vfile" |
| 467 | " WHERE (NOT deleted OR NOT file_is_selected(id))" |
| 468 | " AND rid>0 AND vid=%d" |
| 469 | " ORDER BY pathname /*scan*/", |
| 470 | vid); |
| 471 | blob_zero(&file); |
| 472 | md5sum_init(); |
| 473 | while( db_step(&q)==SQLITE_ROW ){ |
| 474 | const char *zName = db_column_text(&q, 0); |
| 475 | const char *zOrigName = db_column_text(&q, 1); |
| 476 | int rid = db_column_int(&q, 2); |
| 477 | int isSelected = db_column_int(&q, 3); |
| 478 | if( zOrigName && !isSelected ) zName = zOrigName; |
| 479 | md5sum_step_text(zName, -1); |
| 480 | content_get(rid, &file); |
| 481 | sprintf(zBuf, " %d\n", blob_size(&file)); |
| 482 | md5sum_step_text(zBuf, -1); |
| 483 | /*printf("%s %s %s",md5sum_current_state(),zName,zBuf); fflush(stdout);*/ |
| @@ -471,15 +488,20 @@ | |
| 488 | md5sum_finish(pOut); |
| 489 | } |
| 490 | |
| 491 | /* |
| 492 | ** Compute an aggregate MD5 checksum over the repository image of every |
| 493 | ** file in manifest vid. The file names are part of the checksum. The |
| 494 | ** resulting checksum is suitable for use as the R-card of a manifest. |
| 495 | ** |
| 496 | ** Return the resulting checksum in blob pOut. |
| 497 | ** |
| 498 | ** If pManOut is not NULL then fill it with the checksum found in the |
| 499 | ** "R" card near the end of the manifest. |
| 500 | ** |
| 501 | ** In a well-formed manifest, the two checksums computed here, pOut and |
| 502 | ** pManOut, should be identical. |
| 503 | */ |
| 504 | void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){ |
| 505 | int fid; |
| 506 | Blob file; |
| 507 | Manifest *pManifest; |
| 508 |