Fossil SCM

Add the ability to read and understand SHA3 name hashes.

drh 2017-03-01 16:00 trunk merge
Commit fd9b7bd982f10b63fdd7f5bb536299a976d2099a
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-1.37
1
+2.0
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.37
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.0
2
+1 -1
--- src/attach.c
+++ src/attach.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2010 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
1313
--- src/attach.c
+++ src/attach.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2010 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13
--- src/attach.c
+++ src/attach.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2010 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13
+9 -5
--- src/blob.c
+++ src/blob.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2006 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -647,15 +647,19 @@
647647
}
648648
pFrom->iCursor = i;
649649
}
650650
651651
/*
652
-** Return true if the blob contains a valid UUID_SIZE-digit base16 identifier.
652
+** Return true if the blob contains a valid base16 identifier artifact hash.
653
+**
654
+** The value returned is actually one of HNAME_SHA1 OR HNAME_K256 if the
655
+** hash is valid. Both of these are non-zero and therefore "true".
656
+** If the hash is not valid, then HNAME_ERROR is returned, which is zero or
657
+** false.
653658
*/
654
-int blob_is_uuid(Blob *pBlob){
655
- return blob_size(pBlob)==UUID_SIZE
656
- && validate16(blob_buffer(pBlob), UUID_SIZE);
659
+int blob_is_hname(Blob *pBlob){
660
+ return hname_validate(blob_buffer(pBlob), blob_size(pBlob));
657661
}
658662
659663
/*
660664
** Return true if the blob contains a valid filename
661665
*/
662666
--- src/blob.c
+++ src/blob.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -647,15 +647,19 @@
647 }
648 pFrom->iCursor = i;
649 }
650
651 /*
652 ** Return true if the blob contains a valid UUID_SIZE-digit base16 identifier.
 
 
 
 
 
653 */
654 int blob_is_uuid(Blob *pBlob){
655 return blob_size(pBlob)==UUID_SIZE
656 && validate16(blob_buffer(pBlob), UUID_SIZE);
657 }
658
659 /*
660 ** Return true if the blob contains a valid filename
661 */
662
--- src/blob.c
+++ src/blob.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -647,15 +647,19 @@
647 }
648 pFrom->iCursor = i;
649 }
650
651 /*
652 ** Return true if the blob contains a valid base16 identifier artifact hash.
653 **
654 ** The value returned is actually one of HNAME_SHA1 OR HNAME_K256 if the
655 ** hash is valid. Both of these are non-zero and therefore "true".
656 ** If the hash is not valid, then HNAME_ERROR is returned, which is zero or
657 ** false.
658 */
659 int blob_is_hname(Blob *pBlob){
660 return hname_validate(blob_buffer(pBlob), blob_size(pBlob));
 
661 }
662
663 /*
664 ** Return true if the blob contains a valid filename
665 */
666
+4 -4
--- src/browse.c
+++ src/browse.c
@@ -315,11 +315,11 @@
315315
FileTreeNode *pSibling; /* Next element in the same subdirectory */
316316
FileTreeNode *pChild; /* List of child nodes */
317317
FileTreeNode *pLastChild; /* Last child on the pChild list */
318318
char *zName; /* Name of this entry. The "tail" */
319319
char *zFullName; /* Full pathname of this entry */
320
- char *zUuid; /* SHA1 hash of this file. May be NULL. */
320
+ char *zUuid; /* Artifact hash of this file. May be NULL. */
321321
double mtime; /* Modification time for this entry */
322322
unsigned nFullName; /* Length of zFullName */
323323
unsigned iLevel; /* Levels of parent directories */
324324
};
325325
@@ -345,11 +345,11 @@
345345
** the tree to be constructed properly.
346346
*/
347347
static void tree_add_node(
348348
FileTree *pTree, /* Tree into which nodes are added */
349349
const char *zPath, /* The full pathname of file to add */
350
- const char *zUuid, /* UUID of the file. Might be NULL. */
350
+ const char *zUuid, /* Hash of the file. Might be NULL. */
351351
double mtime /* Modification time for this entry */
352352
){
353353
int i;
354354
FileTreeNode *pParent; /* Parent (directory) of the next node to insert */
355355
@@ -368,20 +368,20 @@
368368
FileTreeNode *pNew;
369369
int iStart = i;
370370
int nByte;
371371
while( zPath[i] && zPath[i]!='/' ){ i++; }
372372
nByte = sizeof(*pNew) + i + 1;
373
- if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1;
373
+ if( zUuid!=0 && zPath[i]==0 ) nByte += HNAME_MAX+1;
374374
pNew = fossil_malloc( nByte );
375375
memset(pNew, 0, sizeof(*pNew));
376376
pNew->zFullName = (char*)&pNew[1];
377377
memcpy(pNew->zFullName, zPath, i);
378378
pNew->zFullName[i] = 0;
379379
pNew->nFullName = i;
380380
if( zUuid!=0 && zPath[i]==0 ){
381381
pNew->zUuid = pNew->zFullName + i + 1;
382
- memcpy(pNew->zUuid, zUuid, UUID_SIZE+1);
382
+ memcpy(pNew->zUuid, zUuid, strlen(zUuid)+1);
383383
}
384384
pNew->zName = pNew->zFullName + iStart;
385385
if( pTree->pLast ){
386386
pTree->pLast->pNext = pNew;
387387
}else{
388388
--- src/browse.c
+++ src/browse.c
@@ -315,11 +315,11 @@
315 FileTreeNode *pSibling; /* Next element in the same subdirectory */
316 FileTreeNode *pChild; /* List of child nodes */
317 FileTreeNode *pLastChild; /* Last child on the pChild list */
318 char *zName; /* Name of this entry. The "tail" */
319 char *zFullName; /* Full pathname of this entry */
320 char *zUuid; /* SHA1 hash of this file. May be NULL. */
321 double mtime; /* Modification time for this entry */
322 unsigned nFullName; /* Length of zFullName */
323 unsigned iLevel; /* Levels of parent directories */
324 };
325
@@ -345,11 +345,11 @@
345 ** the tree to be constructed properly.
346 */
347 static void tree_add_node(
348 FileTree *pTree, /* Tree into which nodes are added */
349 const char *zPath, /* The full pathname of file to add */
350 const char *zUuid, /* UUID of the file. Might be NULL. */
351 double mtime /* Modification time for this entry */
352 ){
353 int i;
354 FileTreeNode *pParent; /* Parent (directory) of the next node to insert */
355
@@ -368,20 +368,20 @@
368 FileTreeNode *pNew;
369 int iStart = i;
370 int nByte;
371 while( zPath[i] && zPath[i]!='/' ){ i++; }
372 nByte = sizeof(*pNew) + i + 1;
373 if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1;
374 pNew = fossil_malloc( nByte );
375 memset(pNew, 0, sizeof(*pNew));
376 pNew->zFullName = (char*)&pNew[1];
377 memcpy(pNew->zFullName, zPath, i);
378 pNew->zFullName[i] = 0;
379 pNew->nFullName = i;
380 if( zUuid!=0 && zPath[i]==0 ){
381 pNew->zUuid = pNew->zFullName + i + 1;
382 memcpy(pNew->zUuid, zUuid, UUID_SIZE+1);
383 }
384 pNew->zName = pNew->zFullName + iStart;
385 if( pTree->pLast ){
386 pTree->pLast->pNext = pNew;
387 }else{
388
--- src/browse.c
+++ src/browse.c
@@ -315,11 +315,11 @@
315 FileTreeNode *pSibling; /* Next element in the same subdirectory */
316 FileTreeNode *pChild; /* List of child nodes */
317 FileTreeNode *pLastChild; /* Last child on the pChild list */
318 char *zName; /* Name of this entry. The "tail" */
319 char *zFullName; /* Full pathname of this entry */
320 char *zUuid; /* Artifact hash of this file. May be NULL. */
321 double mtime; /* Modification time for this entry */
322 unsigned nFullName; /* Length of zFullName */
323 unsigned iLevel; /* Levels of parent directories */
324 };
325
@@ -345,11 +345,11 @@
345 ** the tree to be constructed properly.
346 */
347 static void tree_add_node(
348 FileTree *pTree, /* Tree into which nodes are added */
349 const char *zPath, /* The full pathname of file to add */
350 const char *zUuid, /* Hash of the file. Might be NULL. */
351 double mtime /* Modification time for this entry */
352 ){
353 int i;
354 FileTreeNode *pParent; /* Parent (directory) of the next node to insert */
355
@@ -368,20 +368,20 @@
368 FileTreeNode *pNew;
369 int iStart = i;
370 int nByte;
371 while( zPath[i] && zPath[i]!='/' ){ i++; }
372 nByte = sizeof(*pNew) + i + 1;
373 if( zUuid!=0 && zPath[i]==0 ) nByte += HNAME_MAX+1;
374 pNew = fossil_malloc( nByte );
375 memset(pNew, 0, sizeof(*pNew));
376 pNew->zFullName = (char*)&pNew[1];
377 memcpy(pNew->zFullName, zPath, i);
378 pNew->zFullName[i] = 0;
379 pNew->nFullName = i;
380 if( zUuid!=0 && zPath[i]==0 ){
381 pNew->zUuid = pNew->zFullName + i + 1;
382 memcpy(pNew->zUuid, zUuid, strlen(zUuid)+1);
383 }
384 pNew->zName = pNew->zFullName + iStart;
385 if( pTree->pLast ){
386 pTree->pLast->pNext = pNew;
387 }else{
388
+11 -16
--- src/bundle.c
+++ src/bundle.c
@@ -35,11 +35,11 @@
3535
@ bcname TEXT,
3636
@ bcvalue ANY
3737
@ );
3838
@ CREATE TABLE IF NOT EXISTS "%w".bblob(
3939
@ blobid INTEGER PRIMARY KEY, -- Blob ID
40
-@ uuid TEXT NOT NULL, -- SHA1 hash of expanded blob
40
+@ uuid TEXT NOT NULL, -- hash of expanded blob
4141
@ sz INT NOT NULL, -- Size of blob after expansion
4242
@ delta ANY, -- Delta compression basis, or NULL
4343
@ notes TEXT, -- Description of content
4444
@ data BLOB -- compressed content
4545
@ );
@@ -439,19 +439,19 @@
439439
" WHERE bix.delta=%d"
440440
" AND bix.blobid=bblob.blobid;",
441441
iSrc
442442
);
443443
while( db_step(&q)==SQLITE_ROW ){
444
- Blob h1, h2, c1, c2;
444
+ Blob h1, c1, c2;
445445
int rid;
446446
blob_zero(&h1);
447447
db_column_blob(&q, 0, &h1);
448448
blob_zero(&c1);
449449
db_column_blob(&q, 1, &c1);
450450
blob_uncompress(&c1, &c1);
451451
blob_zero(&c2);
452
- if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)==40 ){
452
+ if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)>=HNAME_MIN ){
453453
Blob basis;
454454
rid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
455455
db_column_text(&q,2));
456456
content_get(rid, &basis);
457457
blob_delta_apply(&basis, &c1, &c2);
@@ -461,16 +461,13 @@
461461
blob_delta_apply(pBasis, &c1, &c2);
462462
blob_reset(&c1);
463463
}else{
464464
c2 = c1;
465465
}
466
- sha1sum_blob(&c2, &h2);
467
- if( blob_compare(&h1, &h2)!=0 ){
468
- fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
469
- blob_str(&h1), blob_str(&h2));
466
+ if( hname_verify_hash(&c2, blob_buffer(&h1), blob_size(&h1))==0 ){
467
+ fossil_fatal("artifact hash error on %b", &h1);
470468
}
471
- blob_reset(&h2);
472469
rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
473470
if( rid==0 ){
474471
fossil_fatal("%s", g.zErrMsg);
475472
}else{
476473
if( !isPriv ) content_make_public(rid);
@@ -491,11 +488,11 @@
491488
static void bundle_extract_item(
492489
int blobid, /* ID of the item to extract */
493490
Blob *pOut /* Write the content into this blob */
494491
){
495492
Stmt q;
496
- Blob x, basis, h1, h2;
493
+ Blob x, basis, h1;
497494
static Bag busy;
498495
499496
db_prepare(&q, "SELECT uuid, delta, data FROM bblob"
500497
" WHERE blobid=%d", blobid);
501498
if( db_step(&q)!=SQLITE_ROW ){
@@ -525,17 +522,14 @@
525522
}else{
526523
*pOut = x;
527524
}
528525
blob_zero(&h1);
529526
db_column_blob(&q, 0, &h1);
530
- sha1sum_blob(pOut, &h2);
531
- if( blob_compare(&h1, &h2)!=0 ){
532
- fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
533
- blob_str(&h1), blob_str(&h2));
527
+ if( hname_verify_hash(pOut, blob_buffer(&h1), blob_size(&h1))==0 ){
528
+ fossil_fatal("incorrect hash for artifact %b", &h1);
534529
}
535530
blob_reset(&h1);
536
- blob_reset(&h2);
537531
bag_remove(&busy, blobid);
538532
db_finalize(&q);
539533
}
540534
541535
/* fossil bundle cat BUNDLE UUID...
@@ -597,12 +591,13 @@
597591
** repo, then the delta encodings cannot be decoded and the bundle cannot
598592
** be extracted. */
599593
zMissingDeltas = db_text(0,
600594
"SELECT group_concat(substr(delta,1,10),' ')"
601595
" FROM bblob"
602
- " WHERE typeof(delta)='text' AND length(delta)=40"
603
- " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)");
596
+ " WHERE typeof(delta)='text' AND length(delta)>=%d"
597
+ " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)",
598
+ HNAME_MIN);
604599
if( zMissingDeltas && zMissingDeltas[0] ){
605600
fossil_fatal("delta basis artifacts not found in repository: %s",
606601
zMissingDeltas);
607602
}
608603
609604
--- src/bundle.c
+++ src/bundle.c
@@ -35,11 +35,11 @@
35 @ bcname TEXT,
36 @ bcvalue ANY
37 @ );
38 @ CREATE TABLE IF NOT EXISTS "%w".bblob(
39 @ blobid INTEGER PRIMARY KEY, -- Blob ID
40 @ uuid TEXT NOT NULL, -- SHA1 hash of expanded blob
41 @ sz INT NOT NULL, -- Size of blob after expansion
42 @ delta ANY, -- Delta compression basis, or NULL
43 @ notes TEXT, -- Description of content
44 @ data BLOB -- compressed content
45 @ );
@@ -439,19 +439,19 @@
439 " WHERE bix.delta=%d"
440 " AND bix.blobid=bblob.blobid;",
441 iSrc
442 );
443 while( db_step(&q)==SQLITE_ROW ){
444 Blob h1, h2, c1, c2;
445 int rid;
446 blob_zero(&h1);
447 db_column_blob(&q, 0, &h1);
448 blob_zero(&c1);
449 db_column_blob(&q, 1, &c1);
450 blob_uncompress(&c1, &c1);
451 blob_zero(&c2);
452 if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)==40 ){
453 Blob basis;
454 rid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
455 db_column_text(&q,2));
456 content_get(rid, &basis);
457 blob_delta_apply(&basis, &c1, &c2);
@@ -461,16 +461,13 @@
461 blob_delta_apply(pBasis, &c1, &c2);
462 blob_reset(&c1);
463 }else{
464 c2 = c1;
465 }
466 sha1sum_blob(&c2, &h2);
467 if( blob_compare(&h1, &h2)!=0 ){
468 fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
469 blob_str(&h1), blob_str(&h2));
470 }
471 blob_reset(&h2);
472 rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
473 if( rid==0 ){
474 fossil_fatal("%s", g.zErrMsg);
475 }else{
476 if( !isPriv ) content_make_public(rid);
@@ -491,11 +488,11 @@
491 static void bundle_extract_item(
492 int blobid, /* ID of the item to extract */
493 Blob *pOut /* Write the content into this blob */
494 ){
495 Stmt q;
496 Blob x, basis, h1, h2;
497 static Bag busy;
498
499 db_prepare(&q, "SELECT uuid, delta, data FROM bblob"
500 " WHERE blobid=%d", blobid);
501 if( db_step(&q)!=SQLITE_ROW ){
@@ -525,17 +522,14 @@
525 }else{
526 *pOut = x;
527 }
528 blob_zero(&h1);
529 db_column_blob(&q, 0, &h1);
530 sha1sum_blob(pOut, &h2);
531 if( blob_compare(&h1, &h2)!=0 ){
532 fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
533 blob_str(&h1), blob_str(&h2));
534 }
535 blob_reset(&h1);
536 blob_reset(&h2);
537 bag_remove(&busy, blobid);
538 db_finalize(&q);
539 }
540
541 /* fossil bundle cat BUNDLE UUID...
@@ -597,12 +591,13 @@
597 ** repo, then the delta encodings cannot be decoded and the bundle cannot
598 ** be extracted. */
599 zMissingDeltas = db_text(0,
600 "SELECT group_concat(substr(delta,1,10),' ')"
601 " FROM bblob"
602 " WHERE typeof(delta)='text' AND length(delta)=40"
603 " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)");
 
604 if( zMissingDeltas && zMissingDeltas[0] ){
605 fossil_fatal("delta basis artifacts not found in repository: %s",
606 zMissingDeltas);
607 }
608
609
--- src/bundle.c
+++ src/bundle.c
@@ -35,11 +35,11 @@
35 @ bcname TEXT,
36 @ bcvalue ANY
37 @ );
38 @ CREATE TABLE IF NOT EXISTS "%w".bblob(
39 @ blobid INTEGER PRIMARY KEY, -- Blob ID
40 @ uuid TEXT NOT NULL, -- hash of expanded blob
41 @ sz INT NOT NULL, -- Size of blob after expansion
42 @ delta ANY, -- Delta compression basis, or NULL
43 @ notes TEXT, -- Description of content
44 @ data BLOB -- compressed content
45 @ );
@@ -439,19 +439,19 @@
439 " WHERE bix.delta=%d"
440 " AND bix.blobid=bblob.blobid;",
441 iSrc
442 );
443 while( db_step(&q)==SQLITE_ROW ){
444 Blob h1, c1, c2;
445 int rid;
446 blob_zero(&h1);
447 db_column_blob(&q, 0, &h1);
448 blob_zero(&c1);
449 db_column_blob(&q, 1, &c1);
450 blob_uncompress(&c1, &c1);
451 blob_zero(&c2);
452 if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)>=HNAME_MIN ){
453 Blob basis;
454 rid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
455 db_column_text(&q,2));
456 content_get(rid, &basis);
457 blob_delta_apply(&basis, &c1, &c2);
@@ -461,16 +461,13 @@
461 blob_delta_apply(pBasis, &c1, &c2);
462 blob_reset(&c1);
463 }else{
464 c2 = c1;
465 }
466 if( hname_verify_hash(&c2, blob_buffer(&h1), blob_size(&h1))==0 ){
467 fossil_fatal("artifact hash error on %b", &h1);
 
 
468 }
 
469 rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
470 if( rid==0 ){
471 fossil_fatal("%s", g.zErrMsg);
472 }else{
473 if( !isPriv ) content_make_public(rid);
@@ -491,11 +488,11 @@
488 static void bundle_extract_item(
489 int blobid, /* ID of the item to extract */
490 Blob *pOut /* Write the content into this blob */
491 ){
492 Stmt q;
493 Blob x, basis, h1;
494 static Bag busy;
495
496 db_prepare(&q, "SELECT uuid, delta, data FROM bblob"
497 " WHERE blobid=%d", blobid);
498 if( db_step(&q)!=SQLITE_ROW ){
@@ -525,17 +522,14 @@
522 }else{
523 *pOut = x;
524 }
525 blob_zero(&h1);
526 db_column_blob(&q, 0, &h1);
527 if( hname_verify_hash(pOut, blob_buffer(&h1), blob_size(&h1))==0 ){
528 fossil_fatal("incorrect hash for artifact %b", &h1);
 
 
529 }
530 blob_reset(&h1);
 
531 bag_remove(&busy, blobid);
532 db_finalize(&q);
533 }
534
535 /* fossil bundle cat BUNDLE UUID...
@@ -597,12 +591,13 @@
591 ** repo, then the delta encodings cannot be decoded and the bundle cannot
592 ** be extracted. */
593 zMissingDeltas = db_text(0,
594 "SELECT group_concat(substr(delta,1,10),' ')"
595 " FROM bblob"
596 " WHERE typeof(delta)='text' AND length(delta)>=%d"
597 " AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)",
598 HNAME_MIN);
599 if( zMissingDeltas && zMissingDeltas[0] ){
600 fossil_fatal("delta basis artifacts not found in repository: %s",
601 zMissingDeltas);
602 }
603
604
+10 -10
--- src/checkin.c
+++ src/checkin.c
@@ -377,11 +377,11 @@
377377
** As a special case, the --no-merge option does not inhibit this default.
378378
** This default shows exactly the set of changes that would be checked
379379
** in by the commit command.
380380
**
381381
** If no filter options are used, or if the --merge option is used, the
382
-** SHA1 hash of each merge contributor check-in version is displayed at
382
+** artifact hash of each merge contributor check-in version is displayed at
383383
** the end of the report. The --no-merge option is useful to display the
384384
** default set of changed files without the merge contributors.
385385
**
386386
** If change type classification is enabled, each output line starts with
387387
** a code describing the file's change type, e.g. EDITED or RENAMED. It
@@ -412,11 +412,11 @@
412412
**
413413
** General options:
414414
** --abs-paths Display absolute pathnames.
415415
** --rel-paths Display pathnames relative to the current working
416416
** directory.
417
-** --sha1sum Verify file status using SHA1 hashing rather than
417
+** --hash Verify file status using hashing rather than
418418
** relying on file mtimes.
419419
** --case-sensitive <BOOL> Override case-sensitive setting.
420420
** --dotfiles Include unmanaged files beginning with a dot.
421421
** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
422422
** --no-dir-symlinks Disables support for directory symlinks.
@@ -464,11 +464,11 @@
464464
{"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY },
465465
};
466466
467467
Blob report = BLOB_INITIALIZER;
468468
enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES;
469
- int useSha1sum = find_option("sha1sum", 0, 0)!=0;
469
+ int useHash = find_option("hash", 0, 0)!=0;
470470
int showHdr = command==CHANGES && find_option("header", 0, 0);
471471
int verboseFlag = command==CHANGES && find_option("verbose", "v", 0);
472472
const char *zIgnoreFlag = find_option("ignore", 0, 1);
473473
unsigned scanFlags = 0;
474474
unsigned flags = 0;
@@ -528,11 +528,11 @@
528528
529529
/* We should be done with options. */
530530
verify_all_options();
531531
532532
/* Check for changed files. */
533
- vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
533
+ vfile_check_signature(vid, useHash ? CKSIG_HASH : 0);
534534
535535
/* Search for unmanaged files if requested. */
536536
if( flags & C_EXTRA ){
537537
Glob *pIgnore = glob_create(zIgnoreFlag);
538538
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
@@ -1985,12 +1985,12 @@
19851985
** The --private option creates a private check-in that is never synced.
19861986
** Children of private check-ins are automatically private.
19871987
**
19881988
** The --tag option applies the symbolic tag name to the check-in.
19891989
**
1990
-** The --sha1sum option detects edited files by computing each file's
1991
-** SHA1 hash rather than just checking for changes to its size or mtime.
1990
+** The --hash option detects edited files by computing each file's
1991
+** artifact hash rather than just checking for changes to its size or mtime.
19921992
**
19931993
** Options:
19941994
** --allow-conflict allow unresolved merge conflicts
19951995
** --allow-empty allow a commit with no changes
19961996
** --allow-fork allow the commit to fork
@@ -2010,11 +2010,11 @@
20102010
** input and assumes an answer of 'No' for every
20112011
** question.
20122012
** --no-warnings omit all warnings about file contents
20132013
** --nosign do not attempt to sign this commit with gpg
20142014
** --private do not sync changes and their descendants
2015
-** --sha1sum verify file status using SHA1 hashing rather
2015
+** --hash verify file status using hashing rather
20162016
** than relying on file mtimes
20172017
** --tag TAG-NAME assign given tag TAG-NAME to the check-in
20182018
** --date-override DATETIME DATE to use instead of 'now'
20192019
** --user-override USER USER to use instead of the current default
20202020
**
@@ -2033,11 +2033,11 @@
20332033
int nvid; /* Blob-id of the new check-in */
20342034
Blob comment; /* Check-in comment */
20352035
const char *zComment; /* Check-in comment */
20362036
Stmt q; /* Various queries */
20372037
char *zUuid; /* UUID of the new check-in */
2038
- int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
2038
+ int useHash = 0; /* True to verify file status using hashing */
20392039
int noSign = 0; /* True to omit signing the manifest using GPG */
20402040
int isAMerge = 0; /* True if checking in a merge */
20412041
int noWarningFlag = 0; /* True if skipping all warnings */
20422042
int noPrompt = 0; /* True if skipping all prompts */
20432043
int forceFlag = 0; /* Undocumented: Disables all checks */
@@ -2068,11 +2068,11 @@
20682068
Blob ans;
20692069
char cReply;
20702070
20712071
memset(&sCiInfo, 0, sizeof(sCiInfo));
20722072
url_proxy_options();
2073
- useSha1sum = find_option("sha1sum", 0, 0)!=0;
2073
+ useHash = find_option("hash", 0, 0)!=0;
20742074
noSign = find_option("nosign",0,0)!=0;
20752075
forceDelta = find_option("delta",0,0)!=0;
20762076
forceBaseline = find_option("baseline",0,0)!=0;
20772077
if( forceDelta && forceBaseline ){
20782078
fossil_fatal("cannot use --delta and --baseline together");
@@ -2232,11 +2232,11 @@
22322232
*/
22332233
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
22342234
fossil_fatal("no such user: %s", g.zLogin);
22352235
}
22362236
2237
- hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
2237
+ hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
22382238
db_begin_transaction();
22392239
db_record_repository_filename(0);
22402240
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
22412241
fossil_fatal("nothing has changed; use --allow-empty to override");
22422242
}
22432243
--- src/checkin.c
+++ src/checkin.c
@@ -377,11 +377,11 @@
377 ** As a special case, the --no-merge option does not inhibit this default.
378 ** This default shows exactly the set of changes that would be checked
379 ** in by the commit command.
380 **
381 ** If no filter options are used, or if the --merge option is used, the
382 ** SHA1 hash of each merge contributor check-in version is displayed at
383 ** the end of the report. The --no-merge option is useful to display the
384 ** default set of changed files without the merge contributors.
385 **
386 ** If change type classification is enabled, each output line starts with
387 ** a code describing the file's change type, e.g. EDITED or RENAMED. It
@@ -412,11 +412,11 @@
412 **
413 ** General options:
414 ** --abs-paths Display absolute pathnames.
415 ** --rel-paths Display pathnames relative to the current working
416 ** directory.
417 ** --sha1sum Verify file status using SHA1 hashing rather than
418 ** relying on file mtimes.
419 ** --case-sensitive <BOOL> Override case-sensitive setting.
420 ** --dotfiles Include unmanaged files beginning with a dot.
421 ** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
422 ** --no-dir-symlinks Disables support for directory symlinks.
@@ -464,11 +464,11 @@
464 {"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY },
465 };
466
467 Blob report = BLOB_INITIALIZER;
468 enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES;
469 int useSha1sum = find_option("sha1sum", 0, 0)!=0;
470 int showHdr = command==CHANGES && find_option("header", 0, 0);
471 int verboseFlag = command==CHANGES && find_option("verbose", "v", 0);
472 const char *zIgnoreFlag = find_option("ignore", 0, 1);
473 unsigned scanFlags = 0;
474 unsigned flags = 0;
@@ -528,11 +528,11 @@
528
529 /* We should be done with options. */
530 verify_all_options();
531
532 /* Check for changed files. */
533 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
534
535 /* Search for unmanaged files if requested. */
536 if( flags & C_EXTRA ){
537 Glob *pIgnore = glob_create(zIgnoreFlag);
538 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
@@ -1985,12 +1985,12 @@
1985 ** The --private option creates a private check-in that is never synced.
1986 ** Children of private check-ins are automatically private.
1987 **
1988 ** The --tag option applies the symbolic tag name to the check-in.
1989 **
1990 ** The --sha1sum option detects edited files by computing each file's
1991 ** SHA1 hash rather than just checking for changes to its size or mtime.
1992 **
1993 ** Options:
1994 ** --allow-conflict allow unresolved merge conflicts
1995 ** --allow-empty allow a commit with no changes
1996 ** --allow-fork allow the commit to fork
@@ -2010,11 +2010,11 @@
2010 ** input and assumes an answer of 'No' for every
2011 ** question.
2012 ** --no-warnings omit all warnings about file contents
2013 ** --nosign do not attempt to sign this commit with gpg
2014 ** --private do not sync changes and their descendants
2015 ** --sha1sum verify file status using SHA1 hashing rather
2016 ** than relying on file mtimes
2017 ** --tag TAG-NAME assign given tag TAG-NAME to the check-in
2018 ** --date-override DATETIME DATE to use instead of 'now'
2019 ** --user-override USER USER to use instead of the current default
2020 **
@@ -2033,11 +2033,11 @@
2033 int nvid; /* Blob-id of the new check-in */
2034 Blob comment; /* Check-in comment */
2035 const char *zComment; /* Check-in comment */
2036 Stmt q; /* Various queries */
2037 char *zUuid; /* UUID of the new check-in */
2038 int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
2039 int noSign = 0; /* True to omit signing the manifest using GPG */
2040 int isAMerge = 0; /* True if checking in a merge */
2041 int noWarningFlag = 0; /* True if skipping all warnings */
2042 int noPrompt = 0; /* True if skipping all prompts */
2043 int forceFlag = 0; /* Undocumented: Disables all checks */
@@ -2068,11 +2068,11 @@
2068 Blob ans;
2069 char cReply;
2070
2071 memset(&sCiInfo, 0, sizeof(sCiInfo));
2072 url_proxy_options();
2073 useSha1sum = find_option("sha1sum", 0, 0)!=0;
2074 noSign = find_option("nosign",0,0)!=0;
2075 forceDelta = find_option("delta",0,0)!=0;
2076 forceBaseline = find_option("baseline",0,0)!=0;
2077 if( forceDelta && forceBaseline ){
2078 fossil_fatal("cannot use --delta and --baseline together");
@@ -2232,11 +2232,11 @@
2232 */
2233 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2234 fossil_fatal("no such user: %s", g.zLogin);
2235 }
2236
2237 hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
2238 db_begin_transaction();
2239 db_record_repository_filename(0);
2240 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2241 fossil_fatal("nothing has changed; use --allow-empty to override");
2242 }
2243
--- src/checkin.c
+++ src/checkin.c
@@ -377,11 +377,11 @@
377 ** As a special case, the --no-merge option does not inhibit this default.
378 ** This default shows exactly the set of changes that would be checked
379 ** in by the commit command.
380 **
381 ** If no filter options are used, or if the --merge option is used, the
382 ** artifact hash of each merge contributor check-in version is displayed at
383 ** the end of the report. The --no-merge option is useful to display the
384 ** default set of changed files without the merge contributors.
385 **
386 ** If change type classification is enabled, each output line starts with
387 ** a code describing the file's change type, e.g. EDITED or RENAMED. It
@@ -412,11 +412,11 @@
412 **
413 ** General options:
414 ** --abs-paths Display absolute pathnames.
415 ** --rel-paths Display pathnames relative to the current working
416 ** directory.
417 ** --hash Verify file status using hashing rather than
418 ** relying on file mtimes.
419 ** --case-sensitive <BOOL> Override case-sensitive setting.
420 ** --dotfiles Include unmanaged files beginning with a dot.
421 ** --ignore <CSG> Ignore unmanaged files matching CSG glob patterns.
422 ** --no-dir-symlinks Disables support for directory symlinks.
@@ -464,11 +464,11 @@
464 {"no-merge", C_MERGE }, {"no-classify", C_CLASSIFY },
465 };
466
467 Blob report = BLOB_INITIALIZER;
468 enum {CHANGES, STATUS} command = *g.argv[1]=='s' ? STATUS : CHANGES;
469 int useHash = find_option("hash", 0, 0)!=0;
470 int showHdr = command==CHANGES && find_option("header", 0, 0);
471 int verboseFlag = command==CHANGES && find_option("verbose", "v", 0);
472 const char *zIgnoreFlag = find_option("ignore", 0, 1);
473 unsigned scanFlags = 0;
474 unsigned flags = 0;
@@ -528,11 +528,11 @@
528
529 /* We should be done with options. */
530 verify_all_options();
531
532 /* Check for changed files. */
533 vfile_check_signature(vid, useHash ? CKSIG_HASH : 0);
534
535 /* Search for unmanaged files if requested. */
536 if( flags & C_EXTRA ){
537 Glob *pIgnore = glob_create(zIgnoreFlag);
538 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
@@ -1985,12 +1985,12 @@
1985 ** The --private option creates a private check-in that is never synced.
1986 ** Children of private check-ins are automatically private.
1987 **
1988 ** The --tag option applies the symbolic tag name to the check-in.
1989 **
1990 ** The --hash option detects edited files by computing each file's
1991 ** artifact hash rather than just checking for changes to its size or mtime.
1992 **
1993 ** Options:
1994 ** --allow-conflict allow unresolved merge conflicts
1995 ** --allow-empty allow a commit with no changes
1996 ** --allow-fork allow the commit to fork
@@ -2010,11 +2010,11 @@
2010 ** input and assumes an answer of 'No' for every
2011 ** question.
2012 ** --no-warnings omit all warnings about file contents
2013 ** --nosign do not attempt to sign this commit with gpg
2014 ** --private do not sync changes and their descendants
2015 ** --hash verify file status using hashing rather
2016 ** than relying on file mtimes
2017 ** --tag TAG-NAME assign given tag TAG-NAME to the check-in
2018 ** --date-override DATETIME DATE to use instead of 'now'
2019 ** --user-override USER USER to use instead of the current default
2020 **
@@ -2033,11 +2033,11 @@
2033 int nvid; /* Blob-id of the new check-in */
2034 Blob comment; /* Check-in comment */
2035 const char *zComment; /* Check-in comment */
2036 Stmt q; /* Various queries */
2037 char *zUuid; /* UUID of the new check-in */
2038 int useHash = 0; /* True to verify file status using hashing */
2039 int noSign = 0; /* True to omit signing the manifest using GPG */
2040 int isAMerge = 0; /* True if checking in a merge */
2041 int noWarningFlag = 0; /* True if skipping all warnings */
2042 int noPrompt = 0; /* True if skipping all prompts */
2043 int forceFlag = 0; /* Undocumented: Disables all checks */
@@ -2068,11 +2068,11 @@
2068 Blob ans;
2069 char cReply;
2070
2071 memset(&sCiInfo, 0, sizeof(sCiInfo));
2072 url_proxy_options();
2073 useHash = find_option("hash", 0, 0)!=0;
2074 noSign = find_option("nosign",0,0)!=0;
2075 forceDelta = find_option("delta",0,0)!=0;
2076 forceBaseline = find_option("baseline",0,0)!=0;
2077 if( forceDelta && forceBaseline ){
2078 fossil_fatal("cannot use --delta and --baseline together");
@@ -2232,11 +2232,11 @@
2232 */
2233 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2234 fossil_fatal("no such user: %s", g.zLogin);
2235 }
2236
2237 hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
2238 db_begin_transaction();
2239 db_record_repository_filename(0);
2240 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2241 fossil_fatal("nothing has changed; use --allow-empty to override");
2242 }
2243
+18 -12
--- src/content.c
+++ src/content.c
@@ -312,11 +312,11 @@
312312
/*
313313
** COMMAND: artifact*
314314
**
315315
** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
316316
**
317
-** Extract an artifact by its SHA1 hash and write the results on
317
+** Extract an artifact by its artifact hash and write the results on
318318
** standard output, or if the optional 4th argument is given, in
319319
** the named output file.
320320
**
321321
** Options:
322322
** -R|--repository FILE Extract artifacts from repository FILE
@@ -497,11 +497,11 @@
497497
** to be responsible for pBlob. This routine does *not* take over
498498
** responsibility for freeing pBlob.
499499
*/
500500
int content_put_ex(
501501
Blob *pBlob, /* Content to add to the repository */
502
- const char *zUuid, /* SHA1 hash of reconstructed pBlob */
502
+ const char *zUuid, /* artifact hash of reconstructed pBlob */
503503
int srcId, /* pBlob is a delta from this entry */
504504
int nBlob, /* pBlob is compressed. Original size is this */
505505
int isPrivate /* The content should be marked private */
506506
){
507507
int size;
@@ -513,13 +513,23 @@
513513
int isDephantomize = 0;
514514
515515
assert( g.repositoryOpen );
516516
assert( pBlob!=0 );
517517
assert( srcId==0 || zUuid!=0 );
518
+ db_begin_transaction();
518519
if( zUuid==0 ){
519520
assert( nBlob==0 );
520
- sha1sum_blob(pBlob, &hash);
521
+ /* First check the auxiliary hash to see if there is already an artifact
522
+ ** that uses the auxiliary hash name */
523
+ hname_hash(pBlob, 1, &hash);
524
+ rid = fast_uuid_to_rid(blob_str(&hash));
525
+ if( rid==0 ){
526
+ /* No existing artifact with the auxiliary hash name. Therefore, use
527
+ ** the primary hash name. */
528
+ blob_reset(&hash);
529
+ hname_hash(pBlob, 0, &hash);
530
+ }
521531
}else{
522532
blob_init(&hash, zUuid, -1);
523533
}
524534
if( nBlob ){
525535
size = nBlob;
@@ -527,11 +537,10 @@
527537
size = blob_size(pBlob);
528538
if( srcId ){
529539
size = delta_output_size(blob_buffer(pBlob), size);
530540
}
531541
}
532
- db_begin_transaction();
533542
534543
/* Check to see if the entry already exists and if it does whether
535544
** or not the entry is a phantom
536545
*/
537546
db_prepare(&s1, "SELECT rid, size FROM blob WHERE uuid=%B", &hash);
@@ -868,11 +877,10 @@
868877
** so forth, reporting any errors found.
869878
*/
870879
void test_integrity(void){
871880
Stmt q;
872881
Blob content;
873
- Blob cksum;
874882
int n1 = 0;
875883
int n2 = 0;
876884
int nErr = 0;
877885
int total;
878886
int nCA = 0;
@@ -905,10 +913,11 @@
905913
db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid");
906914
total = db_int(0, "SELECT max(rid) FROM blob");
907915
while( db_step(&q)==SQLITE_ROW ){
908916
int rid = db_column_int(&q, 0);
909917
const char *zUuid = db_column_text(&q, 1);
918
+ int nUuid = db_column_bytes(&q, 1);
910919
int size = db_column_int(&q, 2);
911920
n1++;
912921
fossil_print(" %d/%d\r", n1, total);
913922
fflush(stdout);
914923
if( size<0 ){
@@ -919,14 +928,12 @@
919928
if( blob_size(&content)!=size ){
920929
fossil_print("size mismatch on artifact %d: wanted %d but got %d\n",
921930
rid, size, blob_size(&content));
922931
nErr++;
923932
}
924
- sha1sum_blob(&content, &cksum);
925
- if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
926
- fossil_print("wrong hash on artifact %d: wanted %s but got %s\n",
927
- rid, zUuid, blob_str(&cksum));
933
+ if( !hname_verify_hash(&content, zUuid, nUuid) ){
934
+ fossil_print("wrong hash on artifact %d\n",rid);
928935
nErr++;
929936
}
930937
if( bParse && looks_like_control_artifact(&content) ){
931938
Blob err;
932939
int i, n;
@@ -941,11 +948,11 @@
941948
memcpy(zFirstLine, z, i);
942949
zFirstLine[i] = 0;
943950
p = manifest_parse(&content, 0, &err);
944951
if( p==0 ){
945952
fossil_print("manifest_parse failed for %s:\n%s\n",
946
- blob_str(&cksum), blob_str(&err));
953
+ zUuid, blob_str(&err));
947954
if( strncmp(blob_str(&err), "line 1:", 7)==0 ){
948955
fossil_print("\"%s\"\n", zFirstLine);
949956
}
950957
}else{
951958
anCA[p->type]++;
@@ -954,11 +961,10 @@
954961
}
955962
blob_reset(&err);
956963
}else{
957964
blob_reset(&content);
958965
}
959
- blob_reset(&cksum);
960966
n2++;
961967
}
962968
db_finalize(&q);
963969
fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n",
964970
n2, n1, nErr);
@@ -1157,11 +1163,11 @@
11571163
**
11581164
** WARNING: You must run "fossil rebuild" after this command to rebuild
11591165
** the metadata.
11601166
**
11611167
** Note that the arguments are the integer raw RID values from the BLOB table,
1162
-** not SHA1 hashs or labels.
1168
+** not artifact hashs or labels.
11631169
*/
11641170
void test_content_erase(void){
11651171
int i;
11661172
Blob x;
11671173
char c;
11681174
--- src/content.c
+++ src/content.c
@@ -312,11 +312,11 @@
312 /*
313 ** COMMAND: artifact*
314 **
315 ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
316 **
317 ** Extract an artifact by its SHA1 hash and write the results on
318 ** standard output, or if the optional 4th argument is given, in
319 ** the named output file.
320 **
321 ** Options:
322 ** -R|--repository FILE Extract artifacts from repository FILE
@@ -497,11 +497,11 @@
497 ** to be responsible for pBlob. This routine does *not* take over
498 ** responsibility for freeing pBlob.
499 */
500 int content_put_ex(
501 Blob *pBlob, /* Content to add to the repository */
502 const char *zUuid, /* SHA1 hash of reconstructed pBlob */
503 int srcId, /* pBlob is a delta from this entry */
504 int nBlob, /* pBlob is compressed. Original size is this */
505 int isPrivate /* The content should be marked private */
506 ){
507 int size;
@@ -513,13 +513,23 @@
513 int isDephantomize = 0;
514
515 assert( g.repositoryOpen );
516 assert( pBlob!=0 );
517 assert( srcId==0 || zUuid!=0 );
 
518 if( zUuid==0 ){
519 assert( nBlob==0 );
520 sha1sum_blob(pBlob, &hash);
 
 
 
 
 
 
 
 
 
521 }else{
522 blob_init(&hash, zUuid, -1);
523 }
524 if( nBlob ){
525 size = nBlob;
@@ -527,11 +537,10 @@
527 size = blob_size(pBlob);
528 if( srcId ){
529 size = delta_output_size(blob_buffer(pBlob), size);
530 }
531 }
532 db_begin_transaction();
533
534 /* Check to see if the entry already exists and if it does whether
535 ** or not the entry is a phantom
536 */
537 db_prepare(&s1, "SELECT rid, size FROM blob WHERE uuid=%B", &hash);
@@ -868,11 +877,10 @@
868 ** so forth, reporting any errors found.
869 */
870 void test_integrity(void){
871 Stmt q;
872 Blob content;
873 Blob cksum;
874 int n1 = 0;
875 int n2 = 0;
876 int nErr = 0;
877 int total;
878 int nCA = 0;
@@ -905,10 +913,11 @@
905 db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid");
906 total = db_int(0, "SELECT max(rid) FROM blob");
907 while( db_step(&q)==SQLITE_ROW ){
908 int rid = db_column_int(&q, 0);
909 const char *zUuid = db_column_text(&q, 1);
 
910 int size = db_column_int(&q, 2);
911 n1++;
912 fossil_print(" %d/%d\r", n1, total);
913 fflush(stdout);
914 if( size<0 ){
@@ -919,14 +928,12 @@
919 if( blob_size(&content)!=size ){
920 fossil_print("size mismatch on artifact %d: wanted %d but got %d\n",
921 rid, size, blob_size(&content));
922 nErr++;
923 }
924 sha1sum_blob(&content, &cksum);
925 if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
926 fossil_print("wrong hash on artifact %d: wanted %s but got %s\n",
927 rid, zUuid, blob_str(&cksum));
928 nErr++;
929 }
930 if( bParse && looks_like_control_artifact(&content) ){
931 Blob err;
932 int i, n;
@@ -941,11 +948,11 @@
941 memcpy(zFirstLine, z, i);
942 zFirstLine[i] = 0;
943 p = manifest_parse(&content, 0, &err);
944 if( p==0 ){
945 fossil_print("manifest_parse failed for %s:\n%s\n",
946 blob_str(&cksum), blob_str(&err));
947 if( strncmp(blob_str(&err), "line 1:", 7)==0 ){
948 fossil_print("\"%s\"\n", zFirstLine);
949 }
950 }else{
951 anCA[p->type]++;
@@ -954,11 +961,10 @@
954 }
955 blob_reset(&err);
956 }else{
957 blob_reset(&content);
958 }
959 blob_reset(&cksum);
960 n2++;
961 }
962 db_finalize(&q);
963 fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n",
964 n2, n1, nErr);
@@ -1157,11 +1163,11 @@
1157 **
1158 ** WARNING: You must run "fossil rebuild" after this command to rebuild
1159 ** the metadata.
1160 **
1161 ** Note that the arguments are the integer raw RID values from the BLOB table,
1162 ** not SHA1 hashs or labels.
1163 */
1164 void test_content_erase(void){
1165 int i;
1166 Blob x;
1167 char c;
1168
--- src/content.c
+++ src/content.c
@@ -312,11 +312,11 @@
312 /*
313 ** COMMAND: artifact*
314 **
315 ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
316 **
317 ** Extract an artifact by its artifact hash and write the results on
318 ** standard output, or if the optional 4th argument is given, in
319 ** the named output file.
320 **
321 ** Options:
322 ** -R|--repository FILE Extract artifacts from repository FILE
@@ -497,11 +497,11 @@
497 ** to be responsible for pBlob. This routine does *not* take over
498 ** responsibility for freeing pBlob.
499 */
500 int content_put_ex(
501 Blob *pBlob, /* Content to add to the repository */
502 const char *zUuid, /* artifact hash of reconstructed pBlob */
503 int srcId, /* pBlob is a delta from this entry */
504 int nBlob, /* pBlob is compressed. Original size is this */
505 int isPrivate /* The content should be marked private */
506 ){
507 int size;
@@ -513,13 +513,23 @@
513 int isDephantomize = 0;
514
515 assert( g.repositoryOpen );
516 assert( pBlob!=0 );
517 assert( srcId==0 || zUuid!=0 );
518 db_begin_transaction();
519 if( zUuid==0 ){
520 assert( nBlob==0 );
521 /* First check the auxiliary hash to see if there is already an artifact
522 ** that uses the auxiliary hash name */
523 hname_hash(pBlob, 1, &hash);
524 rid = fast_uuid_to_rid(blob_str(&hash));
525 if( rid==0 ){
526 /* No existing artifact with the auxiliary hash name. Therefore, use
527 ** the primary hash name. */
528 blob_reset(&hash);
529 hname_hash(pBlob, 0, &hash);
530 }
531 }else{
532 blob_init(&hash, zUuid, -1);
533 }
534 if( nBlob ){
535 size = nBlob;
@@ -527,11 +537,10 @@
537 size = blob_size(pBlob);
538 if( srcId ){
539 size = delta_output_size(blob_buffer(pBlob), size);
540 }
541 }
 
542
543 /* Check to see if the entry already exists and if it does whether
544 ** or not the entry is a phantom
545 */
546 db_prepare(&s1, "SELECT rid, size FROM blob WHERE uuid=%B", &hash);
@@ -868,11 +877,10 @@
877 ** so forth, reporting any errors found.
878 */
879 void test_integrity(void){
880 Stmt q;
881 Blob content;
 
882 int n1 = 0;
883 int n2 = 0;
884 int nErr = 0;
885 int total;
886 int nCA = 0;
@@ -905,10 +913,11 @@
913 db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid");
914 total = db_int(0, "SELECT max(rid) FROM blob");
915 while( db_step(&q)==SQLITE_ROW ){
916 int rid = db_column_int(&q, 0);
917 const char *zUuid = db_column_text(&q, 1);
918 int nUuid = db_column_bytes(&q, 1);
919 int size = db_column_int(&q, 2);
920 n1++;
921 fossil_print(" %d/%d\r", n1, total);
922 fflush(stdout);
923 if( size<0 ){
@@ -919,14 +928,12 @@
928 if( blob_size(&content)!=size ){
929 fossil_print("size mismatch on artifact %d: wanted %d but got %d\n",
930 rid, size, blob_size(&content));
931 nErr++;
932 }
933 if( !hname_verify_hash(&content, zUuid, nUuid) ){
934 fossil_print("wrong hash on artifact %d\n",rid);
 
 
935 nErr++;
936 }
937 if( bParse && looks_like_control_artifact(&content) ){
938 Blob err;
939 int i, n;
@@ -941,11 +948,11 @@
948 memcpy(zFirstLine, z, i);
949 zFirstLine[i] = 0;
950 p = manifest_parse(&content, 0, &err);
951 if( p==0 ){
952 fossil_print("manifest_parse failed for %s:\n%s\n",
953 zUuid, blob_str(&err));
954 if( strncmp(blob_str(&err), "line 1:", 7)==0 ){
955 fossil_print("\"%s\"\n", zFirstLine);
956 }
957 }else{
958 anCA[p->type]++;
@@ -954,11 +961,10 @@
961 }
962 blob_reset(&err);
963 }else{
964 blob_reset(&content);
965 }
 
966 n2++;
967 }
968 db_finalize(&q);
969 fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n",
970 n2, n1, nErr);
@@ -1157,11 +1163,11 @@
1163 **
1164 ** WARNING: You must run "fossil rebuild" after this command to rebuild
1165 ** the metadata.
1166 **
1167 ** Note that the arguments are the integer raw RID values from the BLOB table,
1168 ** not artifact hashs or labels.
1169 */
1170 void test_content_erase(void){
1171 int i;
1172 Blob x;
1173 char c;
1174
+10 -30
--- src/db.c
+++ src/db.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2006 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -1486,34 +1486,14 @@
14861486
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
14871487
g.allowSymlinks = db_get_boolean("allow-symlinks",
14881488
db_allow_symlinks_by_default());
14891489
g.zAuxSchema = db_get("aux-schema","");
14901490
1491
- /* Verify that the PLINK table has a new column added by the
1492
- ** 2014-11-28 schema change. Create it if necessary. This code
1493
- ** can be removed in the future, once all users have upgraded to the
1494
- ** 2014-11-28 or later schema.
1495
- */
1496
- if( !db_table_has_column("repository","plink","baseid") ){
1497
- db_multi_exec(
1498
- "ALTER TABLE repository.plink ADD COLUMN baseid;"
1499
- );
1500
- }
1501
-
1502
- /* Verify that the MLINK table has the newer columns added by the
1503
- ** 2015-01-24 schema change. Create them if necessary. This code
1504
- ** can be removed in the future, once all users have upgraded to the
1505
- ** 2015-01-24 or later schema.
1506
- */
1507
- if( !db_table_has_column("repository","mlink","isaux") ){
1508
- db_begin_transaction();
1509
- db_multi_exec(
1510
- "ALTER TABLE repository.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
1511
- "ALTER TABLE repository.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;"
1512
- );
1513
- db_end_transaction(0);
1514
- }
1491
+ /* If the ALIAS table is not present, then some on-the-fly schema
1492
+ ** updates might be required.
1493
+ */
1494
+ rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
15151495
}
15161496
15171497
/*
15181498
** Flags for the db_find_and_open_repository() function.
15191499
*/
@@ -2082,29 +2062,29 @@
20822062
sqlite3_result_value(context, argv[2-rc]);
20832063
}
20842064
}
20852065
20862066
/*
2087
-** Convert the input string into an SHA1. Make a notation in the
2067
+** Convert the input string into a artifact hash. Make a notation in the
20882068
** CONCEALED table so that the hash can be undo using the db_reveal()
20892069
** function at some later time.
20902070
**
20912071
** The value returned is stored in static space and will be overwritten
20922072
** on subsequent calls.
20932073
**
2094
-** If zContent is already a well-formed SHA1 hash, then return a copy
2074
+** If zContent is already a well-formed artifact hash, then return a copy
20952075
** of that hash, not a hash of the hash.
20962076
**
20972077
** The CONCEALED table is meant to obscure email addresses. Every valid
20982078
** email address will contain a "@" character and "@" is not valid within
2099
-** an SHA1 hash so there is no chance that a valid email address will go
2079
+** a SHA1 hash so there is no chance that a valid email address will go
21002080
** unconcealed.
21012081
*/
21022082
char *db_conceal(const char *zContent, int n){
2103
- static char zHash[42];
2083
+ static char zHash[HNAME_MAX+1];
21042084
Blob out;
2105
- if( n==40 && validate16(zContent, n) ){
2085
+ if( hname_validate(zContent, n) ){
21062086
memcpy(zHash, zContent, n);
21072087
zHash[n] = 0;
21082088
}else{
21092089
sha1sum_step_text(zContent, n);
21102090
sha1sum_finish(&out);
21112091
--- src/db.c
+++ src/db.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -1486,34 +1486,14 @@
1486 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1487 g.allowSymlinks = db_get_boolean("allow-symlinks",
1488 db_allow_symlinks_by_default());
1489 g.zAuxSchema = db_get("aux-schema","");
1490
1491 /* Verify that the PLINK table has a new column added by the
1492 ** 2014-11-28 schema change. Create it if necessary. This code
1493 ** can be removed in the future, once all users have upgraded to the
1494 ** 2014-11-28 or later schema.
1495 */
1496 if( !db_table_has_column("repository","plink","baseid") ){
1497 db_multi_exec(
1498 "ALTER TABLE repository.plink ADD COLUMN baseid;"
1499 );
1500 }
1501
1502 /* Verify that the MLINK table has the newer columns added by the
1503 ** 2015-01-24 schema change. Create them if necessary. This code
1504 ** can be removed in the future, once all users have upgraded to the
1505 ** 2015-01-24 or later schema.
1506 */
1507 if( !db_table_has_column("repository","mlink","isaux") ){
1508 db_begin_transaction();
1509 db_multi_exec(
1510 "ALTER TABLE repository.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
1511 "ALTER TABLE repository.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;"
1512 );
1513 db_end_transaction(0);
1514 }
1515 }
1516
1517 /*
1518 ** Flags for the db_find_and_open_repository() function.
1519 */
@@ -2082,29 +2062,29 @@
2082 sqlite3_result_value(context, argv[2-rc]);
2083 }
2084 }
2085
2086 /*
2087 ** Convert the input string into an SHA1. Make a notation in the
2088 ** CONCEALED table so that the hash can be undo using the db_reveal()
2089 ** function at some later time.
2090 **
2091 ** The value returned is stored in static space and will be overwritten
2092 ** on subsequent calls.
2093 **
2094 ** If zContent is already a well-formed SHA1 hash, then return a copy
2095 ** of that hash, not a hash of the hash.
2096 **
2097 ** The CONCEALED table is meant to obscure email addresses. Every valid
2098 ** email address will contain a "@" character and "@" is not valid within
2099 ** an SHA1 hash so there is no chance that a valid email address will go
2100 ** unconcealed.
2101 */
2102 char *db_conceal(const char *zContent, int n){
2103 static char zHash[42];
2104 Blob out;
2105 if( n==40 && validate16(zContent, n) ){
2106 memcpy(zHash, zContent, n);
2107 zHash[n] = 0;
2108 }else{
2109 sha1sum_step_text(zContent, n);
2110 sha1sum_finish(&out);
2111
--- src/db.c
+++ src/db.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -1486,34 +1486,14 @@
1486 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1487 g.allowSymlinks = db_get_boolean("allow-symlinks",
1488 db_allow_symlinks_by_default());
1489 g.zAuxSchema = db_get("aux-schema","");
1490
1491 /* If the ALIAS table is not present, then some on-the-fly schema
1492 ** updates might be required.
1493 */
1494 rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1495 }
1496
1497 /*
1498 ** Flags for the db_find_and_open_repository() function.
1499 */
@@ -2082,29 +2062,29 @@
2062 sqlite3_result_value(context, argv[2-rc]);
2063 }
2064 }
2065
2066 /*
2067 ** Convert the input string into a artifact hash. Make a notation in the
2068 ** CONCEALED table so that the hash can be undo using the db_reveal()
2069 ** function at some later time.
2070 **
2071 ** The value returned is stored in static space and will be overwritten
2072 ** on subsequent calls.
2073 **
2074 ** If zContent is already a well-formed artifact hash, then return a copy
2075 ** of that hash, not a hash of the hash.
2076 **
2077 ** The CONCEALED table is meant to obscure email addresses. Every valid
2078 ** email address will contain a "@" character and "@" is not valid within
2079 ** a SHA1 hash so there is no chance that a valid email address will go
2080 ** unconcealed.
2081 */
2082 char *db_conceal(const char *zContent, int n){
2083 static char zHash[HNAME_MAX+1];
2084 Blob out;
2085 if( hname_validate(zContent, n) ){
2086 memcpy(zHash, zContent, n);
2087 zHash[n] = 0;
2088 }else{
2089 sha1sum_step_text(zContent, n);
2090 sha1sum_finish(&out);
2091
+1 -1
--- src/diff.c
+++ src/diff.c
@@ -2278,11 +2278,11 @@
22782278
** URL: /annotate?checkin=ID&filename=FILENAME
22792279
** URL: /blame?checkin=ID&filename=FILENAME
22802280
** URL: /praise?checkin=ID&filename=FILENAME
22812281
**
22822282
** Show the most recent change to each line of a text file. /annotate shows
2283
-** the date of the changes and the check-in SHA1 hash (with a link to the
2283
+** the date of the changes and the check-in hash (with a link to the
22842284
** check-in). /blame and /praise also show the user who made the check-in.
22852285
**
22862286
** Query parameters:
22872287
**
22882288
** checkin=ID The manifest ID at which to start the annotation
22892289
--- src/diff.c
+++ src/diff.c
@@ -2278,11 +2278,11 @@
2278 ** URL: /annotate?checkin=ID&filename=FILENAME
2279 ** URL: /blame?checkin=ID&filename=FILENAME
2280 ** URL: /praise?checkin=ID&filename=FILENAME
2281 **
2282 ** Show the most recent change to each line of a text file. /annotate shows
2283 ** the date of the changes and the check-in SHA1 hash (with a link to the
2284 ** check-in). /blame and /praise also show the user who made the check-in.
2285 **
2286 ** Query parameters:
2287 **
2288 ** checkin=ID The manifest ID at which to start the annotation
2289
--- src/diff.c
+++ src/diff.c
@@ -2278,11 +2278,11 @@
2278 ** URL: /annotate?checkin=ID&filename=FILENAME
2279 ** URL: /blame?checkin=ID&filename=FILENAME
2280 ** URL: /praise?checkin=ID&filename=FILENAME
2281 **
2282 ** Show the most recent change to each line of a text file. /annotate shows
2283 ** the date of the changes and the check-in hash (with a link to the
2284 ** check-in). /blame and /praise also show the user who made the check-in.
2285 **
2286 ** Query parameters:
2287 **
2288 ** checkin=ID The manifest ID at which to start the annotation
2289
+1 -1
--- src/doc.c
+++ src/doc.c
@@ -527,11 +527,11 @@
527527
** WEBPAGE: uv
528528
** WEBPAGE: doc
529529
** URL: /uv/FILE
530530
** URL: /doc/CHECKIN/FILE
531531
**
532
-** CHECKIN can be either tag or SHA1 hash or timestamp identifying a
532
+** CHECKIN can be either tag or hash prefix or timestamp identifying a
533533
** particular check, or the name of a branch (meaning the most recent
534534
** check-in on that branch) or one of various magic words:
535535
**
536536
** "tip" means the most recent check-in
537537
**
538538
--- src/doc.c
+++ src/doc.c
@@ -527,11 +527,11 @@
527 ** WEBPAGE: uv
528 ** WEBPAGE: doc
529 ** URL: /uv/FILE
530 ** URL: /doc/CHECKIN/FILE
531 **
532 ** CHECKIN can be either tag or SHA1 hash or timestamp identifying a
533 ** particular check, or the name of a branch (meaning the most recent
534 ** check-in on that branch) or one of various magic words:
535 **
536 ** "tip" means the most recent check-in
537 **
538
--- src/doc.c
+++ src/doc.c
@@ -527,11 +527,11 @@
527 ** WEBPAGE: uv
528 ** WEBPAGE: doc
529 ** URL: /uv/FILE
530 ** URL: /doc/CHECKIN/FILE
531 **
532 ** CHECKIN can be either tag or hash prefix or timestamp identifying a
533 ** particular check, or the name of a branch (meaning the most recent
534 ** check-in on that branch) or one of various magic words:
535 **
536 ** "tip" means the most recent check-in
537 **
538
+1 -1
--- src/event.c
+++ src/event.c
@@ -384,11 +384,11 @@
384384
rid = db_int(0,
385385
"SELECT rid FROM tagxref"
386386
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname GLOB '%q*')"
387387
" ORDER BY mtime DESC", zTag
388388
);
389
- if( rid && strlen(zId)<40 ){
389
+ if( rid && strlen(zId)<HNAME_MIN ){
390390
zId = db_text(0,
391391
"SELECT substr(tagname,7) FROM tag WHERE tagname GLOB '%q*'",
392392
zTag
393393
);
394394
}
395395
--- src/event.c
+++ src/event.c
@@ -384,11 +384,11 @@
384 rid = db_int(0,
385 "SELECT rid FROM tagxref"
386 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname GLOB '%q*')"
387 " ORDER BY mtime DESC", zTag
388 );
389 if( rid && strlen(zId)<40 ){
390 zId = db_text(0,
391 "SELECT substr(tagname,7) FROM tag WHERE tagname GLOB '%q*'",
392 zTag
393 );
394 }
395
--- src/event.c
+++ src/event.c
@@ -384,11 +384,11 @@
384 rid = db_int(0,
385 "SELECT rid FROM tagxref"
386 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname GLOB '%q*')"
387 " ORDER BY mtime DESC", zTag
388 );
389 if( rid && strlen(zId)<HNAME_MIN ){
390 zId = db_text(0,
391 "SELECT substr(tagname,7) FROM tag WHERE tagname GLOB '%q*'",
392 zTag
393 );
394 }
395
+1 -1
--- src/export.c
+++ src/export.c
@@ -261,11 +261,11 @@
261261
cur_tok = strtok(NULL, " \t");
262262
if( !cur_tok ){
263263
/* This mark was generated by an older version of Fossil and doesn't
264264
** include the mark name and uuid. create_mark() will name the new mark
265265
** exactly as it was when exported to git, so that we should have a
266
- ** valid mapping from git sha1<->mark name<->fossil sha1. */
266
+ ** valid mapping from git hash<->mark name<->fossil hash. */
267267
unsigned int mid;
268268
if( type_=='c' ){
269269
mid = COMMITMARK(mark->rid);
270270
}
271271
else{
272272
--- src/export.c
+++ src/export.c
@@ -261,11 +261,11 @@
261 cur_tok = strtok(NULL, " \t");
262 if( !cur_tok ){
263 /* This mark was generated by an older version of Fossil and doesn't
264 ** include the mark name and uuid. create_mark() will name the new mark
265 ** exactly as it was when exported to git, so that we should have a
266 ** valid mapping from git sha1<->mark name<->fossil sha1. */
267 unsigned int mid;
268 if( type_=='c' ){
269 mid = COMMITMARK(mark->rid);
270 }
271 else{
272
--- src/export.c
+++ src/export.c
@@ -261,11 +261,11 @@
261 cur_tok = strtok(NULL, " \t");
262 if( !cur_tok ){
263 /* This mark was generated by an older version of Fossil and doesn't
264 ** include the mark name and uuid. create_mark() will name the new mark
265 ** exactly as it was when exported to git, so that we should have a
266 ** valid mapping from git hash<->mark name<->fossil hash. */
267 unsigned int mid;
268 if( type_=='c' ){
269 mid = COMMITMARK(mark->rid);
270 }
271 else{
272
+2 -2
--- src/foci.c
+++ src/foci.c
@@ -28,11 +28,11 @@
2828
** The "schema" for the temp.foci table is:
2929
**
3030
** CREATE TABLE files_of_checkin(
3131
** checkinID INTEGER, -- RID for the check-in manifest
3232
** filename TEXT, -- Name of a file
33
-** uuid TEXT, -- SHA1 hash of the file
33
+** uuid TEXT, -- hash of the file
3434
** previousName TEXT, -- Name of the file in previous check-in
3535
** perm TEXT, -- Permissions on the file
3636
** symname TEXT HIDDEN -- Symbolic name of the check-in.
3737
** );
3838
**
@@ -54,11 +54,11 @@
5454
*/
5555
static const char zFociSchema[] =
5656
@ CREATE TABLE files_of_checkin(
5757
@ checkinID INTEGER, -- RID for the check-in manifest
5858
@ filename TEXT, -- Name of a file
59
-@ uuid TEXT, -- SHA1 hash of the file
59
+@ uuid TEXT, -- hash of the file
6060
@ previousName TEXT, -- Name of the file in previous check-in
6161
@ perm TEXT, -- Permissions on the file
6262
@ symname TEXT HIDDEN -- Symbolic name of the check-in
6363
@ );
6464
;
6565
--- src/foci.c
+++ src/foci.c
@@ -28,11 +28,11 @@
28 ** The "schema" for the temp.foci table is:
29 **
30 ** CREATE TABLE files_of_checkin(
31 ** checkinID INTEGER, -- RID for the check-in manifest
32 ** filename TEXT, -- Name of a file
33 ** uuid TEXT, -- SHA1 hash of the file
34 ** previousName TEXT, -- Name of the file in previous check-in
35 ** perm TEXT, -- Permissions on the file
36 ** symname TEXT HIDDEN -- Symbolic name of the check-in.
37 ** );
38 **
@@ -54,11 +54,11 @@
54 */
55 static const char zFociSchema[] =
56 @ CREATE TABLE files_of_checkin(
57 @ checkinID INTEGER, -- RID for the check-in manifest
58 @ filename TEXT, -- Name of a file
59 @ uuid TEXT, -- SHA1 hash of the file
60 @ previousName TEXT, -- Name of the file in previous check-in
61 @ perm TEXT, -- Permissions on the file
62 @ symname TEXT HIDDEN -- Symbolic name of the check-in
63 @ );
64 ;
65
--- src/foci.c
+++ src/foci.c
@@ -28,11 +28,11 @@
28 ** The "schema" for the temp.foci table is:
29 **
30 ** CREATE TABLE files_of_checkin(
31 ** checkinID INTEGER, -- RID for the check-in manifest
32 ** filename TEXT, -- Name of a file
33 ** uuid TEXT, -- hash of the file
34 ** previousName TEXT, -- Name of the file in previous check-in
35 ** perm TEXT, -- Permissions on the file
36 ** symname TEXT HIDDEN -- Symbolic name of the check-in.
37 ** );
38 **
@@ -54,11 +54,11 @@
54 */
55 static const char zFociSchema[] =
56 @ CREATE TABLE files_of_checkin(
57 @ checkinID INTEGER, -- RID for the check-in manifest
58 @ filename TEXT, -- Name of a file
59 @ uuid TEXT, -- hash of the file
60 @ previousName TEXT, -- Name of the file in previous check-in
61 @ perm TEXT, -- Permissions on the file
62 @ symname TEXT HIDDEN -- Symbolic name of the check-in
63 @ );
64 ;
65
+1 -1
--- src/fusefs.c
+++ src/fusefs.c
@@ -294,11 +294,11 @@
294294
** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295295
** at DIRECTORY that contains the content of all check-ins in the
296296
** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297297
** where DIRECTORY is the root of the mount, VERSION is any valid
298298
** check-in name (examples: "trunk" or "tip" or a tag or any unique
299
-** prefix of a SHA1 hash, etc) and PATH is the pathname of the file in
299
+** prefix of an artifact hash, etc) and PATH is the pathname of the file in
300300
** the check-in. If DIRECTORY does not exist, then an attempt is made
301301
** to create it.
302302
**
303303
** The DIRECTORY/checkins directory is not searchable so one cannot
304304
** do "ls DIRECTORY/checkins" to get a listing of all possible check-in
305305
--- src/fusefs.c
+++ src/fusefs.c
@@ -294,11 +294,11 @@
294 ** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295 ** at DIRECTORY that contains the content of all check-ins in the
296 ** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297 ** where DIRECTORY is the root of the mount, VERSION is any valid
298 ** check-in name (examples: "trunk" or "tip" or a tag or any unique
299 ** prefix of a SHA1 hash, etc) and PATH is the pathname of the file in
300 ** the check-in. If DIRECTORY does not exist, then an attempt is made
301 ** to create it.
302 **
303 ** The DIRECTORY/checkins directory is not searchable so one cannot
304 ** do "ls DIRECTORY/checkins" to get a listing of all possible check-in
305
--- src/fusefs.c
+++ src/fusefs.c
@@ -294,11 +294,11 @@
294 ** This command uses the Fuse Filesystem (FuseFS) to mount a directory
295 ** at DIRECTORY that contains the content of all check-ins in the
296 ** repository. The names of files are DIRECTORY/checkins/VERSION/PATH
297 ** where DIRECTORY is the root of the mount, VERSION is any valid
298 ** check-in name (examples: "trunk" or "tip" or a tag or any unique
299 ** prefix of an artifact hash, etc) and PATH is the pathname of the file in
300 ** the check-in. If DIRECTORY does not exist, then an attempt is made
301 ** to create it.
302 **
303 ** The DIRECTORY/checkins directory is not searchable so one cannot
304 ** do "ls DIRECTORY/checkins" to get a listing of all possible check-in
305
+1 -1
--- src/graph.c
+++ src/graph.c
@@ -179,11 +179,11 @@
179179
int rid, /* RID for the check-in */
180180
int nParent, /* Number of parents */
181181
int *aParent, /* Array of parents */
182182
const char *zBranch, /* Branch for this check-in */
183183
const char *zBgClr, /* Background color. NULL or "" for white. */
184
- const char *zUuid, /* SHA1 hash of the object being graphed */
184
+ const char *zUuid, /* hash name of the object being graphed */
185185
int isLeaf /* True if this row is a leaf */
186186
){
187187
GraphRow *pRow;
188188
int nByte;
189189
190190
191191
ADDED src/hname.c
--- src/graph.c
+++ src/graph.c
@@ -179,11 +179,11 @@
179 int rid, /* RID for the check-in */
180 int nParent, /* Number of parents */
181 int *aParent, /* Array of parents */
182 const char *zBranch, /* Branch for this check-in */
183 const char *zBgClr, /* Background color. NULL or "" for white. */
184 const char *zUuid, /* SHA1 hash of the object being graphed */
185 int isLeaf /* True if this row is a leaf */
186 ){
187 GraphRow *pRow;
188 int nByte;
189
190
191 DDED src/hname.c
--- src/graph.c
+++ src/graph.c
@@ -179,11 +179,11 @@
179 int rid, /* RID for the check-in */
180 int nParent, /* Number of parents */
181 int *aParent, /* Array of parents */
182 const char *zBranch, /* Branch for this check-in */
183 const char *zBgClr, /* Background color. NULL or "" for white. */
184 const char *zUuid, /* hash name of the object being graphed */
185 int isLeaf /* True if this row is a leaf */
186 ){
187 GraphRow *pRow;
188 int nByte;
189
190
191 DDED src/hname.c
+26
--- a/src/hname.c
+++ b/src/hname.c
@@ -0,0 +1,26 @@
1
+/*
2
+** Copyright (c) 2017 D. Richard Hipp
3
+**
4
+** This program is free software; you can redistribute it and/or
5
+** modify it under the teno SHA3
6
+** repository, and mare one or more
7
+** SHA3 artifactscode, and various alternative hashes
8
+** are used for iHType>0 && iHType<NHAME_COUNT.
9
+*/
10
+void#if RELEASE_VERSION_NUMBER>=20100
11
+ /* For Fossil 2.1 and later, the preferred hash algorithm is SHA3-256 and
12
+ ** SHA1 is the secondary hash algorithm. */
13
+ sw break;
14
+ case 1: break;
15
+ }
16
+#else
17
+ /* Prior to Fossil 2.1, the preferred hash algorithm is SHA1 (for backwards
18
+ ** compatibility with Fossil 1.x) and SHA3-256 is the only auxiliary
19
+ ** algorithm */
20
+ switch( iHType ){
21
+ case 0: break;
22
+ case 1: break;
23
+ }
24
+#endif
25
+}
26
+242424
--- a/src/hname.c
+++ b/src/hname.c
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/hname.c
+++ b/src/hname.c
@@ -0,0 +1,26 @@
1 /*
2 ** Copyright (c) 2017 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the teno SHA3
6 ** repository, and mare one or more
7 ** SHA3 artifactscode, and various alternative hashes
8 ** are used for iHType>0 && iHType<NHAME_COUNT.
9 */
10 void#if RELEASE_VERSION_NUMBER>=20100
11 /* For Fossil 2.1 and later, the preferred hash algorithm is SHA3-256 and
12 ** SHA1 is the secondary hash algorithm. */
13 sw break;
14 case 1: break;
15 }
16 #else
17 /* Prior to Fossil 2.1, the preferred hash algorithm is SHA1 (for backwards
18 ** compatibility with Fossil 1.x) and SHA3-256 is the only auxiliary
19 ** algorithm */
20 switch( iHType ){
21 case 0: break;
22 case 1: break;
23 }
24 #endif
25 }
26 242424
+2 -2
--- src/import.c
+++ src/import.c
@@ -149,18 +149,18 @@
149149
** UUID in gg.zPrevCheckin.
150150
*/
151151
static int fast_insert_content(
152152
Blob *pContent, /* Content to insert */
153153
const char *zMark, /* Label using this mark, if not NULL */
154
- int saveUuid, /* Save SHA1 hash in gg.zPrevCheckin */
154
+ int saveUuid, /* Save artifact hash in gg.zPrevCheckin */
155155
int doParse /* Invoke manifest_crosslink() */
156156
){
157157
Blob hash;
158158
Blob cmpr;
159159
int rid;
160160
161
- sha1sum_blob(pContent, &hash);
161
+ hname_hash(pContent, 0, &hash);
162162
rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &hash);
163163
if( rid==0 ){
164164
static Stmt ins;
165165
db_static_prepare(&ins,
166166
"INSERT INTO blob(uuid, size, content) VALUES(:uuid, :size, :content)"
167167
--- src/import.c
+++ src/import.c
@@ -149,18 +149,18 @@
149 ** UUID in gg.zPrevCheckin.
150 */
151 static int fast_insert_content(
152 Blob *pContent, /* Content to insert */
153 const char *zMark, /* Label using this mark, if not NULL */
154 int saveUuid, /* Save SHA1 hash in gg.zPrevCheckin */
155 int doParse /* Invoke manifest_crosslink() */
156 ){
157 Blob hash;
158 Blob cmpr;
159 int rid;
160
161 sha1sum_blob(pContent, &hash);
162 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &hash);
163 if( rid==0 ){
164 static Stmt ins;
165 db_static_prepare(&ins,
166 "INSERT INTO blob(uuid, size, content) VALUES(:uuid, :size, :content)"
167
--- src/import.c
+++ src/import.c
@@ -149,18 +149,18 @@
149 ** UUID in gg.zPrevCheckin.
150 */
151 static int fast_insert_content(
152 Blob *pContent, /* Content to insert */
153 const char *zMark, /* Label using this mark, if not NULL */
154 int saveUuid, /* Save artifact hash in gg.zPrevCheckin */
155 int doParse /* Invoke manifest_crosslink() */
156 ){
157 Blob hash;
158 Blob cmpr;
159 int rid;
160
161 hname_hash(pContent, 0, &hash);
162 rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &hash);
163 if( rid==0 ){
164 static Stmt ins;
165 db_static_prepare(&ins,
166 "INSERT INTO blob(uuid, size, content) VALUES(:uuid, :size, :content)"
167
+2 -1
--- src/info.c
+++ src/info.c
@@ -1385,10 +1385,11 @@
13851385
" ORDER BY mtime DESC /*sort*/",
13861386
rid
13871387
);
13881388
while( db_step(&q)==SQLITE_ROW ){
13891389
const char *zTarget = db_column_text(&q, 0);
1390
+ int nTarget = db_column_bytes(&q, 0);
13901391
const char *zFilename = db_column_text(&q, 1);
13911392
const char *zDate = db_column_text(&q, 2);
13921393
const char *zUser = db_column_text(&q, 3);
13931394
/* const char *zSrc = db_column_text(&q, 4); */
13941395
if( cnt>0 ){
@@ -1395,11 +1396,11 @@
13951396
@ Also attachment "%h(zFilename)" to
13961397
}else{
13971398
@ Attachment "%h(zFilename)" to
13981399
}
13991400
objType |= OBJTYPE_ATTACHMENT;
1400
- if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1401
+ if( nTarget==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
14011402
if ( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
14021403
zTarget)
14031404
){
14041405
if( g.perm.Hyperlink && g.anon.RdTkt ){
14051406
@ ticket [%z(href("%R/tktview?name=%!S",zTarget))%S(zTarget)</a>]
14061407
--- src/info.c
+++ src/info.c
@@ -1385,10 +1385,11 @@
1385 " ORDER BY mtime DESC /*sort*/",
1386 rid
1387 );
1388 while( db_step(&q)==SQLITE_ROW ){
1389 const char *zTarget = db_column_text(&q, 0);
 
1390 const char *zFilename = db_column_text(&q, 1);
1391 const char *zDate = db_column_text(&q, 2);
1392 const char *zUser = db_column_text(&q, 3);
1393 /* const char *zSrc = db_column_text(&q, 4); */
1394 if( cnt>0 ){
@@ -1395,11 +1396,11 @@
1395 @ Also attachment "%h(zFilename)" to
1396 }else{
1397 @ Attachment "%h(zFilename)" to
1398 }
1399 objType |= OBJTYPE_ATTACHMENT;
1400 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1401 if ( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
1402 zTarget)
1403 ){
1404 if( g.perm.Hyperlink && g.anon.RdTkt ){
1405 @ ticket [%z(href("%R/tktview?name=%!S",zTarget))%S(zTarget)</a>]
1406
--- src/info.c
+++ src/info.c
@@ -1385,10 +1385,11 @@
1385 " ORDER BY mtime DESC /*sort*/",
1386 rid
1387 );
1388 while( db_step(&q)==SQLITE_ROW ){
1389 const char *zTarget = db_column_text(&q, 0);
1390 int nTarget = db_column_bytes(&q, 0);
1391 const char *zFilename = db_column_text(&q, 1);
1392 const char *zDate = db_column_text(&q, 2);
1393 const char *zUser = db_column_text(&q, 3);
1394 /* const char *zSrc = db_column_text(&q, 4); */
1395 if( cnt>0 ){
@@ -1395,11 +1396,11 @@
1396 @ Also attachment "%h(zFilename)" to
1397 }else{
1398 @ Attachment "%h(zFilename)" to
1399 }
1400 objType |= OBJTYPE_ATTACHMENT;
1401 if( nTarget==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1402 if ( db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
1403 zTarget)
1404 ){
1405 if( g.perm.Hyperlink && g.anon.RdTkt ){
1406 @ ticket [%z(href("%R/tktview?name=%!S",zTarget))%S(zTarget)</a>]
1407
+6 -1
--- src/main.c
+++ src/main.c
@@ -50,11 +50,16 @@
5050
# include "cson_amalgamation.h" /* JSON API. */
5151
# include "json_detail.h"
5252
#endif
5353
5454
/*
55
-** Size of a UUID in characters
55
+** Size of a UUID in characters. A UUID is a randomly generated
56
+** lower-case hexadecimal number used to identify tickets.
57
+**
58
+** In Fossil 1.x, UUID also referred to a SHA1 artifact hash. But that
59
+** usage is now obsolete. The term UUID should now mean only a very large
60
+** random number used as a unique identifier for tickets or other objects.
5661
*/
5762
#define UUID_SIZE 40
5863
5964
/*
6065
** Maximum number of auxiliary parameters on reports
6166
--- src/main.c
+++ src/main.c
@@ -50,11 +50,16 @@
50 # include "cson_amalgamation.h" /* JSON API. */
51 # include "json_detail.h"
52 #endif
53
54 /*
55 ** Size of a UUID in characters
 
 
 
 
 
56 */
57 #define UUID_SIZE 40
58
59 /*
60 ** Maximum number of auxiliary parameters on reports
61
--- src/main.c
+++ src/main.c
@@ -50,11 +50,16 @@
50 # include "cson_amalgamation.h" /* JSON API. */
51 # include "json_detail.h"
52 #endif
53
54 /*
55 ** Size of a UUID in characters. A UUID is a randomly generated
56 ** lower-case hexadecimal number used to identify tickets.
57 **
58 ** In Fossil 1.x, UUID also referred to a SHA1 artifact hash. But that
59 ** usage is now obsolete. The term UUID should now mean only a very large
60 ** random number used as a unique identifier for tickets or other objects.
61 */
62 #define UUID_SIZE 40
63
64 /*
65 ** Maximum number of auxiliary parameters on reports
66
+12
--- src/main.mk
+++ src/main.mk
@@ -52,10 +52,11 @@
5252
$(SRCDIR)/fshell.c \
5353
$(SRCDIR)/fusefs.c \
5454
$(SRCDIR)/glob.c \
5555
$(SRCDIR)/graph.c \
5656
$(SRCDIR)/gzip.c \
57
+ $(SRCDIR)/hname.c \
5758
$(SRCDIR)/http.c \
5859
$(SRCDIR)/http_socket.c \
5960
$(SRCDIR)/http_ssl.c \
6061
$(SRCDIR)/http_transport.c \
6162
$(SRCDIR)/import.c \
@@ -228,10 +229,11 @@
228229
$(OBJDIR)/fshell_.c \
229230
$(OBJDIR)/fusefs_.c \
230231
$(OBJDIR)/glob_.c \
231232
$(OBJDIR)/graph_.c \
232233
$(OBJDIR)/gzip_.c \
234
+ $(OBJDIR)/hname_.c \
233235
$(OBJDIR)/http_.c \
234236
$(OBJDIR)/http_socket_.c \
235237
$(OBJDIR)/http_ssl_.c \
236238
$(OBJDIR)/http_transport_.c \
237239
$(OBJDIR)/import_.c \
@@ -353,10 +355,11 @@
353355
$(OBJDIR)/fshell.o \
354356
$(OBJDIR)/fusefs.o \
355357
$(OBJDIR)/glob.o \
356358
$(OBJDIR)/graph.o \
357359
$(OBJDIR)/gzip.o \
360
+ $(OBJDIR)/hname.o \
358361
$(OBJDIR)/http.o \
359362
$(OBJDIR)/http_socket.o \
360363
$(OBJDIR)/http_ssl.o \
361364
$(OBJDIR)/http_transport.o \
362365
$(OBJDIR)/import.o \
@@ -639,10 +642,11 @@
639642
$(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
640643
$(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
641644
$(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
642645
$(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
643646
$(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
647
+ $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \
644648
$(OBJDIR)/http_.c:$(OBJDIR)/http.h \
645649
$(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
646650
$(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
647651
$(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
648652
$(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1041,10 +1045,18 @@
10411045
10421046
$(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
10431047
$(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
10441048
10451049
$(OBJDIR)/gzip.h: $(OBJDIR)/headers
1050
+
1051
+$(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(OBJDIR)/translate
1052
+ $(OBJDIR)/translate $(SRCDIR)/hname.c >$@
1053
+
1054
+$(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h
1055
+ $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c
1056
+
1057
+$(OBJDIR)/hname.h: $(OBJDIR)/headers
10461058
10471059
$(OBJDIR)/http_.c: $(SRCDIR)/http.c $(OBJDIR)/translate
10481060
$(OBJDIR)/translate $(SRCDIR)/http.c >$@
10491061
10501062
$(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
10511063
--- src/main.mk
+++ src/main.mk
@@ -52,10 +52,11 @@
52 $(SRCDIR)/fshell.c \
53 $(SRCDIR)/fusefs.c \
54 $(SRCDIR)/glob.c \
55 $(SRCDIR)/graph.c \
56 $(SRCDIR)/gzip.c \
 
57 $(SRCDIR)/http.c \
58 $(SRCDIR)/http_socket.c \
59 $(SRCDIR)/http_ssl.c \
60 $(SRCDIR)/http_transport.c \
61 $(SRCDIR)/import.c \
@@ -228,10 +229,11 @@
228 $(OBJDIR)/fshell_.c \
229 $(OBJDIR)/fusefs_.c \
230 $(OBJDIR)/glob_.c \
231 $(OBJDIR)/graph_.c \
232 $(OBJDIR)/gzip_.c \
 
233 $(OBJDIR)/http_.c \
234 $(OBJDIR)/http_socket_.c \
235 $(OBJDIR)/http_ssl_.c \
236 $(OBJDIR)/http_transport_.c \
237 $(OBJDIR)/import_.c \
@@ -353,10 +355,11 @@
353 $(OBJDIR)/fshell.o \
354 $(OBJDIR)/fusefs.o \
355 $(OBJDIR)/glob.o \
356 $(OBJDIR)/graph.o \
357 $(OBJDIR)/gzip.o \
 
358 $(OBJDIR)/http.o \
359 $(OBJDIR)/http_socket.o \
360 $(OBJDIR)/http_ssl.o \
361 $(OBJDIR)/http_transport.o \
362 $(OBJDIR)/import.o \
@@ -639,10 +642,11 @@
639 $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
640 $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
641 $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
642 $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
643 $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
 
644 $(OBJDIR)/http_.c:$(OBJDIR)/http.h \
645 $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
646 $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
647 $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
648 $(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1041,10 +1045,18 @@
1041
1042 $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
1043 $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
1044
1045 $(OBJDIR)/gzip.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1046
1047 $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(OBJDIR)/translate
1048 $(OBJDIR)/translate $(SRCDIR)/http.c >$@
1049
1050 $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
1051
--- src/main.mk
+++ src/main.mk
@@ -52,10 +52,11 @@
52 $(SRCDIR)/fshell.c \
53 $(SRCDIR)/fusefs.c \
54 $(SRCDIR)/glob.c \
55 $(SRCDIR)/graph.c \
56 $(SRCDIR)/gzip.c \
57 $(SRCDIR)/hname.c \
58 $(SRCDIR)/http.c \
59 $(SRCDIR)/http_socket.c \
60 $(SRCDIR)/http_ssl.c \
61 $(SRCDIR)/http_transport.c \
62 $(SRCDIR)/import.c \
@@ -228,10 +229,11 @@
229 $(OBJDIR)/fshell_.c \
230 $(OBJDIR)/fusefs_.c \
231 $(OBJDIR)/glob_.c \
232 $(OBJDIR)/graph_.c \
233 $(OBJDIR)/gzip_.c \
234 $(OBJDIR)/hname_.c \
235 $(OBJDIR)/http_.c \
236 $(OBJDIR)/http_socket_.c \
237 $(OBJDIR)/http_ssl_.c \
238 $(OBJDIR)/http_transport_.c \
239 $(OBJDIR)/import_.c \
@@ -353,10 +355,11 @@
355 $(OBJDIR)/fshell.o \
356 $(OBJDIR)/fusefs.o \
357 $(OBJDIR)/glob.o \
358 $(OBJDIR)/graph.o \
359 $(OBJDIR)/gzip.o \
360 $(OBJDIR)/hname.o \
361 $(OBJDIR)/http.o \
362 $(OBJDIR)/http_socket.o \
363 $(OBJDIR)/http_ssl.o \
364 $(OBJDIR)/http_transport.o \
365 $(OBJDIR)/import.o \
@@ -639,10 +642,11 @@
642 $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
643 $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
644 $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
645 $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
646 $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
647 $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \
648 $(OBJDIR)/http_.c:$(OBJDIR)/http.h \
649 $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
650 $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
651 $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
652 $(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1041,10 +1045,18 @@
1045
1046 $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
1047 $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
1048
1049 $(OBJDIR)/gzip.h: $(OBJDIR)/headers
1050
1051 $(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(OBJDIR)/translate
1052 $(OBJDIR)/translate $(SRCDIR)/hname.c >$@
1053
1054 $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h
1055 $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c
1056
1057 $(OBJDIR)/hname.h: $(OBJDIR)/headers
1058
1059 $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(OBJDIR)/translate
1060 $(OBJDIR)/translate $(SRCDIR)/http.c >$@
1061
1062 $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
1063
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -58,10 +58,11 @@
5858
fshell
5959
fusefs
6060
glob
6161
graph
6262
gzip
63
+ hname
6364
http
6465
http_socket
6566
http_transport
6667
import
6768
info
6869
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -58,10 +58,11 @@
58 fshell
59 fusefs
60 glob
61 graph
62 gzip
 
63 http
64 http_socket
65 http_transport
66 import
67 info
68
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -58,10 +58,11 @@
58 fshell
59 fusefs
60 glob
61 graph
62 gzip
63 hname
64 http
65 http_socket
66 http_transport
67 import
68 info
69
+80 -80
--- src/manifest.c
+++ src/manifest.c
@@ -54,11 +54,11 @@
5454
/*
5555
** A single F-card within a manifest
5656
*/
5757
struct ManifestFile {
5858
char *zName; /* Name of a file */
59
- char *zUuid; /* UUID of the file */
59
+ char *zUuid; /* Artifact hash for the file */
6060
char *zPerm; /* File permissions */
6161
char *zPrior; /* Prior name if the name was changed */
6262
};
6363
6464
@@ -77,35 +77,35 @@
7777
char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */
7878
char *zWiki; /* Text of the wiki page. W card. */
7979
char *zWikiTitle; /* Name of the wiki page. L card. */
8080
char *zMimetype; /* Mime type of wiki or comment text. N card. */
8181
double rEventDate; /* Date of an event. E card. */
82
- char *zEventId; /* UUID for an event. E card. */
82
+ char *zEventId; /* Artifact hash for an event. E card. */
8383
char *zTicketUuid; /* UUID for a ticket. K card. */
8484
char *zAttachName; /* Filename of an attachment. A card. */
85
- char *zAttachSrc; /* UUID of document being attached. A card. */
85
+ char *zAttachSrc; /* Artifact hash for document being attached. A card. */
8686
char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */
8787
int nFile; /* Number of F cards */
8888
int nFileAlloc; /* Slots allocated in aFile[] */
8989
int iFile; /* Index of current file in iterator */
9090
ManifestFile *aFile; /* One entry for each F-card */
9191
int nParent; /* Number of parents. */
9292
int nParentAlloc; /* Slots allocated in azParent[] */
93
- char **azParent; /* UUIDs of parents. One for each P card argument */
93
+ char **azParent; /* Hashes of parents. One for each P card argument */
9494
int nCherrypick; /* Number of entries in aCherrypick[] */
9595
struct {
96
- char *zCPTarget; /* UUID of cherry-picked version w/ +|- prefix */
97
- char *zCPBase; /* UUID of cherry-pick baseline. NULL for singletons */
96
+ char *zCPTarget; /* Hash for cherry-picked version w/ +|- prefix */
97
+ char *zCPBase; /* Hash for cherry-pick baseline. NULL for singletons */
9898
} *aCherrypick;
9999
int nCChild; /* Number of cluster children */
100100
int nCChildAlloc; /* Number of closts allocated in azCChild[] */
101
- char **azCChild; /* UUIDs of referenced objects in a cluster. M cards */
101
+ char **azCChild; /* Hashes of referenced objects in a cluster. M cards */
102102
int nTag; /* Number of T Cards */
103103
int nTagAlloc; /* Slots allocated in aTag[] */
104104
struct TagType {
105105
char *zName; /* Name of the tag */
106
- char *zUuid; /* UUID that the tag is applied to */
106
+ char *zUuid; /* Hash of artifact that the tag is applied to */
107107
char *zValue; /* Value if the tag is really a property */
108108
} *aTag; /* One for each T card */
109109
int nField; /* Number of J cards */
110110
int nFieldAlloc; /* Slots allocated in aField[] */
111111
struct {
@@ -327,26 +327,27 @@
327327
** takes over the input blob and will free it when the
328328
** Manifest object is freed. Zeros are inserted into the blob
329329
** as string terminators so that blob should not be used again.
330330
**
331331
** Return a pointer to an allocated Manifest object if the content
332
-** really is a control file of some kind. This object needs to be
333
-** freed by a subsequent call to manifest_destroy(). Return NULL
334
-** if there are syntax errors.
332
+** really is a structural artifact of some kind. The returned Manifest
333
+** object needs to be freed by a subsequent call to manifest_destroy().
334
+** Return NULL if there are syntax errors or if the input blob does
335
+** not describe a valid structural artifact.
335336
**
336
-** This routine is strict about the format of a control file.
337
+** This routine is strict about the format of a structural artifacts.
337338
** The format must match exactly or else it is rejected. This
338
-** rule minimizes the risk that a content file will be mistaken
339
-** for a control file simply because they look the same.
339
+** rule minimizes the risk that a content artifact will be mistaken
340
+** for a structural artifact simply because they look the same.
340341
**
341342
** The pContent is reset. If a pointer is returned, then pContent will
342343
** be reset when the Manifest object is cleared. If NULL is
343344
** returned then the Manifest object is cleared automatically
344345
** and pContent is reset before the return.
345346
**
346
-** The entire file can be PGP clear-signed. The signature is ignored.
347
-** The file consists of zero or more cards, one card per line.
347
+** The entire input blob can be PGP clear-signed. The signature is ignored.
348
+** The artifact consists of zero or more cards, one card per line.
348349
** (Except: the content of the W card can extend of multiple lines.)
349350
** Each card is divided into tokens by a single space character.
350351
** The first token is a single upper-case letter which is the card type.
351352
** The card type determines the other parameters to the card.
352353
** Cards must occur in lexicographical order.
@@ -361,11 +362,10 @@
361362
char *z;
362363
int n;
363364
char *zUuid;
364365
int sz = 0;
365366
int isRepeat, hasSelfRefTag = 0;
366
- Blob bUuid = BLOB_INITIALIZER;
367367
static Bag seen;
368368
const char *zErr = 0;
369369
370370
if( rid==0 ){
371371
isRepeat = 1;
@@ -374,11 +374,11 @@
374374
}else{
375375
isRepeat = 0;
376376
bag_insert(&seen, rid);
377377
}
378378
379
- /* Every control artifact ends with a '\n' character. Exit early
379
+ /* Every structural artifact ends with a '\n' character. Exit early
380380
** if that is not the case for this artifact.
381381
*/
382382
if( !isRepeat ) g.parseCnt[0]++;
383383
z = blob_materialize(pContent);
384384
n = blob_size(pContent);
@@ -406,15 +406,10 @@
406406
blob_reset(pContent);
407407
blob_appendf(pErr, "incorrect Z-card cksum");
408408
return 0;
409409
}
410410
411
- /* Store the UUID (before modifying the blob) only for error
412
- ** reporting purposes.
413
- */
414
- sha1sum_blob(pContent, &bUuid);
415
-
416411
/* Allocate a Manifest object to hold the parsed control artifact.
417412
*/
418413
p = fossil_malloc( sizeof(*p) );
419414
memset(p, 0, sizeof(*p));
420415
memcpy(&p->content, pContent, sizeof(p->content));
@@ -449,15 +444,15 @@
449444
defossilize(zName);
450445
if( !file_is_simple_pathname(zName, 0) ){
451446
SYNTAX("invalid filename on A-card");
452447
}
453448
defossilize(zTarget);
454
- if( (nTarget!=UUID_SIZE || !validate16(zTarget, UUID_SIZE))
449
+ if( !hname_validate(zTarget,nTarget)
455450
&& !wiki_name_is_wellformed((const unsigned char *)zTarget) ){
456451
SYNTAX("invalid target on A-card");
457452
}
458
- if( zSrc && (nSrc!=UUID_SIZE || !validate16(zSrc, UUID_SIZE)) ){
453
+ if( zSrc && !hname_validate(zSrc,nSrc) ){
459454
SYNTAX("invalid source on A-card");
460455
}
461456
p->zAttachName = (char*)file_tail(zName);
462457
p->zAttachSrc = zSrc;
463458
p->zAttachTarget = zTarget;
@@ -465,18 +460,18 @@
465460
}
466461
467462
/*
468463
** B <uuid>
469464
**
470
- ** A B-line gives the UUID for the baseline of a delta-manifest.
465
+ ** A B-line gives the artifact hash for the baseline of a delta-manifest.
471466
*/
472467
case 'B': {
473468
if( p->zBaseline ) SYNTAX("more than one B-card");
474469
p->zBaseline = next_token(&x, &sz);
475
- if( p->zBaseline==0 ) SYNTAX("missing UUID on B-card");
476
- if( sz!=UUID_SIZE || !validate16(p->zBaseline, UUID_SIZE) ){
477
- SYNTAX("invalid UUID on B-card");
470
+ if( p->zBaseline==0 ) SYNTAX("missing hash on B-card");
471
+ if( !hname_validate(p->zBaseline,sz) ){
472
+ SYNTAX("invalid hash on B-card");
478473
}
479474
break;
480475
}
481476
482477
@@ -522,12 +517,12 @@
522517
case 'E': {
523518
if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
524519
p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
525520
if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
526521
p->zEventId = next_token(&x, &sz);
527
- if( sz!=UUID_SIZE || !validate16(p->zEventId, UUID_SIZE) ){
528
- SYNTAX("malformed UUID on E-card");
522
+ if( !hname_validate(p->zEventId, sz) ){
523
+ SYNTAX("malformed hash on E-card");
529524
}
530525
break;
531526
}
532527
533528
/*
@@ -545,12 +540,13 @@
545540
if( !file_is_simple_pathname(zName, 0) ){
546541
SYNTAX("F-card filename is not a simple path");
547542
}
548543
zUuid = next_token(&x, &sz);
549544
if( p->zBaseline==0 || zUuid!=0 ){
550
- if( sz!=UUID_SIZE ) SYNTAX("F-card UUID is the wrong size");
551
- if( !validate16(zUuid, UUID_SIZE) ) SYNTAX("F-card UUID invalid");
545
+ if( !hname_validate(zUuid,sz) ){
546
+ SYNTAX("F-card hash invalid");
547
+ }
552548
}
553549
zPerm = next_token(&x,0);
554550
zPriorName = next_token(&x,0);
555551
if( zPriorName ){
556552
defossilize(zPriorName);
@@ -636,20 +632,21 @@
636632
}
637633
break;
638634
}
639635
640636
/*
641
- ** M <uuid>
637
+ ** M <hash>
642638
**
643
- ** An M-line identifies another artifact by its UUID. M-lines
639
+ ** An M-line identifies another artifact by its hash. M-lines
644640
** occur in clusters only.
645641
*/
646642
case 'M': {
647643
zUuid = next_token(&x, &sz);
648
- if( zUuid==0 ) SYNTAX("missing UUID on M-card");
649
- if( sz!=UUID_SIZE ) SYNTAX("wrong size for UUID on M-card");
650
- if( !validate16(zUuid, UUID_SIZE) ) SYNTAX("UUID invalid on M-card");
644
+ if( zUuid==0 ) SYNTAX("missing hash on M-card");
645
+ if( !hname_validate(zUuid,sz) ){
646
+ SYNTAX("Invalid hash on M-card");
647
+ }
651648
if( p->nCChild>=p->nCChildAlloc ){
652649
p->nCChildAlloc = p->nCChildAlloc*2 + 10;
653650
p->azCChild = fossil_realloc(p->azCChild
654651
, p->nCChildAlloc*sizeof(p->azCChild[0]) );
655652
}
@@ -683,12 +680,13 @@
683680
** check-in historically has an empty P-card, so empty P-cards
684681
** must be accepted.
685682
*/
686683
case 'P': {
687684
while( (zUuid = next_token(&x, &sz))!=0 ){
688
- if( sz!=UUID_SIZE ) SYNTAX("wrong size UUID on P-card");
689
- if( !validate16(zUuid, UUID_SIZE) )SYNTAX("invalid UUID on P-card");
685
+ if( !hname_validate(zUuid, sz) ){
686
+ SYNTAX("invalid hash on P-card");
687
+ }
690688
if( p->nParent>=p->nParentAlloc ){
691689
p->nParentAlloc = p->nParentAlloc*2 + 5;
692690
p->azParent = fossil_realloc(p->azParent,
693691
p->nParentAlloc*sizeof(char*));
694692
}
@@ -703,29 +701,25 @@
703701
**
704702
** Specify one or a range of check-ins that are cherrypicked into
705703
** this check-in ("+") or backed out of this check-in ("-").
706704
*/
707705
case 'Q': {
708
- if( (zUuid=next_token(&x, &sz))==0 ) SYNTAX("missing UUID on Q-card");
709
- if( sz!=UUID_SIZE+1 ) SYNTAX("wrong size UUID on Q-card");
706
+ if( (zUuid=next_token(&x, &sz))==0 ) SYNTAX("missing hash on Q-card");
710707
if( zUuid[0]!='+' && zUuid[0]!='-' ){
711708
SYNTAX("Q-card does not begin with '+' or '-'");
712709
}
713
- if( !validate16(&zUuid[1], UUID_SIZE) ){
714
- SYNTAX("invalid UUID on Q-card");
710
+ if( !hname_validate(&zUuid[1], sz-1) ){
711
+ SYNTAX("invalid hash on Q-card");
715712
}
716713
n = p->nCherrypick;
717714
p->nCherrypick++;
718715
p->aCherrypick = fossil_realloc(p->aCherrypick,
719716
p->nCherrypick*sizeof(p->aCherrypick[0]));
720717
p->aCherrypick[n].zCPTarget = zUuid;
721718
p->aCherrypick[n].zCPBase = zUuid = next_token(&x, &sz);
722
- if( zUuid ){
723
- if( sz!=UUID_SIZE ) SYNTAX("wrong size second UUID in Q-card");
724
- if( !validate16(zUuid, UUID_SIZE) ){
725
- SYNTAX("invalid second UUID on Q-card");
726
- }
719
+ if( zUuid && !hname_validate(zUuid,sz) ){
720
+ SYNTAX("invalid second hash on Q-card");
727721
}
728722
break;
729723
}
730724
731725
/*
@@ -760,32 +754,32 @@
760754
case 'T': {
761755
char *zName, *zValue;
762756
zName = next_token(&x, 0);
763757
if( zName==0 ) SYNTAX("missing name on T-card");
764758
zUuid = next_token(&x, &sz);
765
- if( zUuid==0 ) SYNTAX("missing UUID on T-card");
759
+ if( zUuid==0 ) SYNTAX("missing artifact hash on T-card");
766760
zValue = next_token(&x, 0);
767761
if( zValue ) defossilize(zValue);
768
- if( sz==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
769
- /* A valid uuid */
762
+ if( hname_validate(zUuid, sz) ){
763
+ /* A valid artifact hash */
770764
if( p->zEventId ) SYNTAX("non-self-referential T-card in event");
771765
}else if( sz==1 && zUuid[0]=='*' ){
772766
zUuid = 0;
773767
hasSelfRefTag = 1;
774768
if( p->zEventId && zName[0]!='+' ){
775769
SYNTAX("propagating T-card in event");
776770
}
777771
}else{
778
- SYNTAX("malformed UUID on T-card");
772
+ SYNTAX("malformed artifact hash on T-card");
779773
}
780774
defossilize(zName);
781775
if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
782776
SYNTAX("T-card name does not begin with '-', '+', or '*'");
783777
}
784778
if( validate16(&zName[1], strlen(&zName[1])) ){
785
- /* Do not allow tags whose names look like UUIDs */
786
- SYNTAX("T-card name looks like a UUID");
779
+ /* Do not allow tags whose names look like a hash */
780
+ SYNTAX("T-card name looks like a hexadecimal hash");
787781
}
788782
if( p->nTag>=p->nTagAlloc ){
789783
p->nTagAlloc = p->nTagAlloc*2 + 10;
790784
p->aTag = fossil_realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) );
791785
}
@@ -951,17 +945,19 @@
951945
if( !seenZ ) SYNTAX("missing Z-card on control");
952946
p->type = CFTYPE_CONTROL;
953947
}
954948
md5sum_init();
955949
if( !isRepeat ) g.parseCnt[p->type]++;
956
- blob_reset(&bUuid);
957950
return p;
958951
959952
manifest_syntax_error:
960
- if(bUuid.nUsed){
961
- blob_appendf(pErr, "manifest [%.40s] ", blob_str(&bUuid));
962
- blob_reset(&bUuid);
953
+ {
954
+ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
955
+ if( zUuid ){
956
+ blob_appendf(pErr, "manifest [%s] ", zUuid);
957
+ fossil_free(zUuid);
958
+ }
963959
}
964960
if( zErr ){
965961
blob_appendf(pErr, "line %d: %s", lineNo, zErr);
966962
}else{
967963
blob_appendf(pErr, "unknown error on line %d", lineNo);
@@ -1193,13 +1189,13 @@
11931189
** then the mlink entry is only created if there is already an mlink
11941190
** from primary parent for the same file.
11951191
*/
11961192
static void add_one_mlink(
11971193
int pmid, /* The parent manifest */
1198
- const char *zFromUuid, /* UUID for content in parent */
1194
+ const char *zFromUuid, /* Artifact hash for content in parent */
11991195
int mid, /* The record ID of the manifest */
1200
- const char *zToUuid, /* UUID for content in child */
1196
+ const char *zToUuid, /* artifact hash for content in child */
12011197
const char *zFilename, /* Filename */
12021198
const char *zPrior, /* Previous filename. NULL if unchanged */
12031199
int isPublic, /* True if mid is not a private manifest */
12041200
int isPrimary, /* pmid is the primary parent of mid */
12051201
int mperm /* 1: exec, 2: symlink */
@@ -1545,22 +1541,22 @@
15451541
}
15461542
}
15471543
15481544
/*
15491545
** For a check-in with RID "rid" that has nParent parent check-ins given
1550
-** by the UUIDs in azParent[], create all appropriate plink and mlink table
1546
+** by the hashes in azParent[], create all appropriate plink and mlink table
15511547
** entries.
15521548
**
1553
-** The primary parent is the first UUID on the azParent[] list.
1549
+** The primary parent is the first hash on the azParent[] list.
15541550
**
15551551
** Return the RID of the primary parent.
15561552
*/
15571553
static int manifest_add_checkin_linkages(
15581554
int rid, /* The RID of the check-in */
15591555
Manifest *p, /* Manifest for this check-in */
15601556
int nParent, /* Number of parents for this check-in */
1561
- char **azParent /* UUIDs for each parent */
1557
+ char **azParent /* hashes for each parent */
15621558
){
15631559
int i;
15641560
int parentid = 0;
15651561
char zBaseId[30]; /* Baseline manifest RID for deltas. "NULL" otherwise */
15661562
Stmt q;
@@ -1611,33 +1607,36 @@
16111607
return parentid;
16121608
}
16131609
16141610
/*
16151611
** There exists a "parent" tag against checkin rid that has value zValue.
1616
-** If value is well-formed (meaning that it is a list of UUIDs), then use
1612
+** If value is well-formed (meaning that it is a list of hashes), then use
16171613
** zValue to reparent check-in rid.
16181614
*/
16191615
void manifest_reparent_checkin(int rid, const char *zValue){
1620
- int nParent;
1616
+ int nParent = 0;
16211617
char *zCopy = 0;
16221618
char **azParent = 0;
16231619
Manifest *p = 0;
1624
- int i;
1620
+ int i, j;
16251621
int n = (int)strlen(zValue);
1626
- nParent = (n+1)/(UUID_SIZE+1);
1627
- if( nParent*(UUID_SIZE+1) - 1 !=n ) return;
1628
- if( nParent<1 ) return;
1622
+ int mxParent = (n+1)/(HNAME_MIN+1);
1623
+
1624
+ if( mxParent<1 ) return;
16291625
zCopy = fossil_strdup(zValue);
1630
- azParent = fossil_malloc( sizeof(azParent[0])*nParent );
1631
- for(i=0; i<nParent; i++){
1632
- azParent[i] = &zCopy[i*(UUID_SIZE+1)];
1633
- if( i<nParent-1 && azParent[i][UUID_SIZE]!=' ' ) break;
1634
- azParent[i][UUID_SIZE] = 0;
1635
- if( !validate16(azParent[i],UUID_SIZE) ) break;
1636
- }
1637
- if( i==nParent
1638
- && !db_exists("SELECT 1 FROM plink WHERE cid=%d AND pid=%d",
1626
+ azParent = fossil_malloc( sizeof(azParent[0])*mxParent );
1627
+ for(nParent=0, i=0; zCopy[i]; i++){
1628
+ char *z = &zCopy[i];
1629
+ azParent[nParent++] = z;
1630
+ if( nParent>mxParent ) goto reparent_abort;
1631
+ for(j=HNAME_MIN; z[j]>' '; j++){}
1632
+ if( !hname_validate(z, j) ) goto reparent_abort;
1633
+ if( z[j]==0 ) break;
1634
+ z[j] = 0;
1635
+ i += j;
1636
+ }
1637
+ if( !db_exists("SELECT 1 FROM plink WHERE cid=%d AND pid=%d",
16391638
rid, uuid_to_rid(azParent[0],0))
16401639
){
16411640
p = manifest_get(rid, CFTYPE_MANIFEST, 0);
16421641
}
16431642
if( p!=0 ){
@@ -1647,10 +1646,11 @@
16471646
rid, rid
16481647
);
16491648
manifest_add_checkin_linkages(rid,p,nParent,azParent);
16501649
}
16511650
manifest_destroy(p);
1651
+reparent_abort:
16521652
fossil_free(azParent);
16531653
fossil_free(zCopy);
16541654
}
16551655
16561656
/*
@@ -2280,11 +2280,11 @@
22802280
int branchMove = 0;
22812281
blob_zero(&comment);
22822282
if( p->zComment ){
22832283
blob_appendf(&comment, " %s.", p->zComment);
22842284
}
2285
- /* Next loop expects tags to be sorted on UUID, so sort it. */
2285
+ /* Next loop expects tags to be sorted on hash, so sort it. */
22862286
qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
22872287
for(i=0; i<p->nTag; i++){
22882288
zTagUuid = p->aTag[i].zUuid;
22892289
if( !zTagUuid ) continue;
22902290
if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
22912291
--- src/manifest.c
+++ src/manifest.c
@@ -54,11 +54,11 @@
54 /*
55 ** A single F-card within a manifest
56 */
57 struct ManifestFile {
58 char *zName; /* Name of a file */
59 char *zUuid; /* UUID of the file */
60 char *zPerm; /* File permissions */
61 char *zPrior; /* Prior name if the name was changed */
62 };
63
64
@@ -77,35 +77,35 @@
77 char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */
78 char *zWiki; /* Text of the wiki page. W card. */
79 char *zWikiTitle; /* Name of the wiki page. L card. */
80 char *zMimetype; /* Mime type of wiki or comment text. N card. */
81 double rEventDate; /* Date of an event. E card. */
82 char *zEventId; /* UUID for an event. E card. */
83 char *zTicketUuid; /* UUID for a ticket. K card. */
84 char *zAttachName; /* Filename of an attachment. A card. */
85 char *zAttachSrc; /* UUID of document being attached. A card. */
86 char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */
87 int nFile; /* Number of F cards */
88 int nFileAlloc; /* Slots allocated in aFile[] */
89 int iFile; /* Index of current file in iterator */
90 ManifestFile *aFile; /* One entry for each F-card */
91 int nParent; /* Number of parents. */
92 int nParentAlloc; /* Slots allocated in azParent[] */
93 char **azParent; /* UUIDs of parents. One for each P card argument */
94 int nCherrypick; /* Number of entries in aCherrypick[] */
95 struct {
96 char *zCPTarget; /* UUID of cherry-picked version w/ +|- prefix */
97 char *zCPBase; /* UUID of cherry-pick baseline. NULL for singletons */
98 } *aCherrypick;
99 int nCChild; /* Number of cluster children */
100 int nCChildAlloc; /* Number of closts allocated in azCChild[] */
101 char **azCChild; /* UUIDs of referenced objects in a cluster. M cards */
102 int nTag; /* Number of T Cards */
103 int nTagAlloc; /* Slots allocated in aTag[] */
104 struct TagType {
105 char *zName; /* Name of the tag */
106 char *zUuid; /* UUID that the tag is applied to */
107 char *zValue; /* Value if the tag is really a property */
108 } *aTag; /* One for each T card */
109 int nField; /* Number of J cards */
110 int nFieldAlloc; /* Slots allocated in aField[] */
111 struct {
@@ -327,26 +327,27 @@
327 ** takes over the input blob and will free it when the
328 ** Manifest object is freed. Zeros are inserted into the blob
329 ** as string terminators so that blob should not be used again.
330 **
331 ** Return a pointer to an allocated Manifest object if the content
332 ** really is a control file of some kind. This object needs to be
333 ** freed by a subsequent call to manifest_destroy(). Return NULL
334 ** if there are syntax errors.
 
335 **
336 ** This routine is strict about the format of a control file.
337 ** The format must match exactly or else it is rejected. This
338 ** rule minimizes the risk that a content file will be mistaken
339 ** for a control file simply because they look the same.
340 **
341 ** The pContent is reset. If a pointer is returned, then pContent will
342 ** be reset when the Manifest object is cleared. If NULL is
343 ** returned then the Manifest object is cleared automatically
344 ** and pContent is reset before the return.
345 **
346 ** The entire file can be PGP clear-signed. The signature is ignored.
347 ** The file consists of zero or more cards, one card per line.
348 ** (Except: the content of the W card can extend of multiple lines.)
349 ** Each card is divided into tokens by a single space character.
350 ** The first token is a single upper-case letter which is the card type.
351 ** The card type determines the other parameters to the card.
352 ** Cards must occur in lexicographical order.
@@ -361,11 +362,10 @@
361 char *z;
362 int n;
363 char *zUuid;
364 int sz = 0;
365 int isRepeat, hasSelfRefTag = 0;
366 Blob bUuid = BLOB_INITIALIZER;
367 static Bag seen;
368 const char *zErr = 0;
369
370 if( rid==0 ){
371 isRepeat = 1;
@@ -374,11 +374,11 @@
374 }else{
375 isRepeat = 0;
376 bag_insert(&seen, rid);
377 }
378
379 /* Every control artifact ends with a '\n' character. Exit early
380 ** if that is not the case for this artifact.
381 */
382 if( !isRepeat ) g.parseCnt[0]++;
383 z = blob_materialize(pContent);
384 n = blob_size(pContent);
@@ -406,15 +406,10 @@
406 blob_reset(pContent);
407 blob_appendf(pErr, "incorrect Z-card cksum");
408 return 0;
409 }
410
411 /* Store the UUID (before modifying the blob) only for error
412 ** reporting purposes.
413 */
414 sha1sum_blob(pContent, &bUuid);
415
416 /* Allocate a Manifest object to hold the parsed control artifact.
417 */
418 p = fossil_malloc( sizeof(*p) );
419 memset(p, 0, sizeof(*p));
420 memcpy(&p->content, pContent, sizeof(p->content));
@@ -449,15 +444,15 @@
449 defossilize(zName);
450 if( !file_is_simple_pathname(zName, 0) ){
451 SYNTAX("invalid filename on A-card");
452 }
453 defossilize(zTarget);
454 if( (nTarget!=UUID_SIZE || !validate16(zTarget, UUID_SIZE))
455 && !wiki_name_is_wellformed((const unsigned char *)zTarget) ){
456 SYNTAX("invalid target on A-card");
457 }
458 if( zSrc && (nSrc!=UUID_SIZE || !validate16(zSrc, UUID_SIZE)) ){
459 SYNTAX("invalid source on A-card");
460 }
461 p->zAttachName = (char*)file_tail(zName);
462 p->zAttachSrc = zSrc;
463 p->zAttachTarget = zTarget;
@@ -465,18 +460,18 @@
465 }
466
467 /*
468 ** B <uuid>
469 **
470 ** A B-line gives the UUID for the baseline of a delta-manifest.
471 */
472 case 'B': {
473 if( p->zBaseline ) SYNTAX("more than one B-card");
474 p->zBaseline = next_token(&x, &sz);
475 if( p->zBaseline==0 ) SYNTAX("missing UUID on B-card");
476 if( sz!=UUID_SIZE || !validate16(p->zBaseline, UUID_SIZE) ){
477 SYNTAX("invalid UUID on B-card");
478 }
479 break;
480 }
481
482
@@ -522,12 +517,12 @@
522 case 'E': {
523 if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
524 p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
525 if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
526 p->zEventId = next_token(&x, &sz);
527 if( sz!=UUID_SIZE || !validate16(p->zEventId, UUID_SIZE) ){
528 SYNTAX("malformed UUID on E-card");
529 }
530 break;
531 }
532
533 /*
@@ -545,12 +540,13 @@
545 if( !file_is_simple_pathname(zName, 0) ){
546 SYNTAX("F-card filename is not a simple path");
547 }
548 zUuid = next_token(&x, &sz);
549 if( p->zBaseline==0 || zUuid!=0 ){
550 if( sz!=UUID_SIZE ) SYNTAX("F-card UUID is the wrong size");
551 if( !validate16(zUuid, UUID_SIZE) ) SYNTAX("F-card UUID invalid");
 
552 }
553 zPerm = next_token(&x,0);
554 zPriorName = next_token(&x,0);
555 if( zPriorName ){
556 defossilize(zPriorName);
@@ -636,20 +632,21 @@
636 }
637 break;
638 }
639
640 /*
641 ** M <uuid>
642 **
643 ** An M-line identifies another artifact by its UUID. M-lines
644 ** occur in clusters only.
645 */
646 case 'M': {
647 zUuid = next_token(&x, &sz);
648 if( zUuid==0 ) SYNTAX("missing UUID on M-card");
649 if( sz!=UUID_SIZE ) SYNTAX("wrong size for UUID on M-card");
650 if( !validate16(zUuid, UUID_SIZE) ) SYNTAX("UUID invalid on M-card");
 
651 if( p->nCChild>=p->nCChildAlloc ){
652 p->nCChildAlloc = p->nCChildAlloc*2 + 10;
653 p->azCChild = fossil_realloc(p->azCChild
654 , p->nCChildAlloc*sizeof(p->azCChild[0]) );
655 }
@@ -683,12 +680,13 @@
683 ** check-in historically has an empty P-card, so empty P-cards
684 ** must be accepted.
685 */
686 case 'P': {
687 while( (zUuid = next_token(&x, &sz))!=0 ){
688 if( sz!=UUID_SIZE ) SYNTAX("wrong size UUID on P-card");
689 if( !validate16(zUuid, UUID_SIZE) )SYNTAX("invalid UUID on P-card");
 
690 if( p->nParent>=p->nParentAlloc ){
691 p->nParentAlloc = p->nParentAlloc*2 + 5;
692 p->azParent = fossil_realloc(p->azParent,
693 p->nParentAlloc*sizeof(char*));
694 }
@@ -703,29 +701,25 @@
703 **
704 ** Specify one or a range of check-ins that are cherrypicked into
705 ** this check-in ("+") or backed out of this check-in ("-").
706 */
707 case 'Q': {
708 if( (zUuid=next_token(&x, &sz))==0 ) SYNTAX("missing UUID on Q-card");
709 if( sz!=UUID_SIZE+1 ) SYNTAX("wrong size UUID on Q-card");
710 if( zUuid[0]!='+' && zUuid[0]!='-' ){
711 SYNTAX("Q-card does not begin with '+' or '-'");
712 }
713 if( !validate16(&zUuid[1], UUID_SIZE) ){
714 SYNTAX("invalid UUID on Q-card");
715 }
716 n = p->nCherrypick;
717 p->nCherrypick++;
718 p->aCherrypick = fossil_realloc(p->aCherrypick,
719 p->nCherrypick*sizeof(p->aCherrypick[0]));
720 p->aCherrypick[n].zCPTarget = zUuid;
721 p->aCherrypick[n].zCPBase = zUuid = next_token(&x, &sz);
722 if( zUuid ){
723 if( sz!=UUID_SIZE ) SYNTAX("wrong size second UUID in Q-card");
724 if( !validate16(zUuid, UUID_SIZE) ){
725 SYNTAX("invalid second UUID on Q-card");
726 }
727 }
728 break;
729 }
730
731 /*
@@ -760,32 +754,32 @@
760 case 'T': {
761 char *zName, *zValue;
762 zName = next_token(&x, 0);
763 if( zName==0 ) SYNTAX("missing name on T-card");
764 zUuid = next_token(&x, &sz);
765 if( zUuid==0 ) SYNTAX("missing UUID on T-card");
766 zValue = next_token(&x, 0);
767 if( zValue ) defossilize(zValue);
768 if( sz==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
769 /* A valid uuid */
770 if( p->zEventId ) SYNTAX("non-self-referential T-card in event");
771 }else if( sz==1 && zUuid[0]=='*' ){
772 zUuid = 0;
773 hasSelfRefTag = 1;
774 if( p->zEventId && zName[0]!='+' ){
775 SYNTAX("propagating T-card in event");
776 }
777 }else{
778 SYNTAX("malformed UUID on T-card");
779 }
780 defossilize(zName);
781 if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
782 SYNTAX("T-card name does not begin with '-', '+', or '*'");
783 }
784 if( validate16(&zName[1], strlen(&zName[1])) ){
785 /* Do not allow tags whose names look like UUIDs */
786 SYNTAX("T-card name looks like a UUID");
787 }
788 if( p->nTag>=p->nTagAlloc ){
789 p->nTagAlloc = p->nTagAlloc*2 + 10;
790 p->aTag = fossil_realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) );
791 }
@@ -951,17 +945,19 @@
951 if( !seenZ ) SYNTAX("missing Z-card on control");
952 p->type = CFTYPE_CONTROL;
953 }
954 md5sum_init();
955 if( !isRepeat ) g.parseCnt[p->type]++;
956 blob_reset(&bUuid);
957 return p;
958
959 manifest_syntax_error:
960 if(bUuid.nUsed){
961 blob_appendf(pErr, "manifest [%.40s] ", blob_str(&bUuid));
962 blob_reset(&bUuid);
 
 
 
963 }
964 if( zErr ){
965 blob_appendf(pErr, "line %d: %s", lineNo, zErr);
966 }else{
967 blob_appendf(pErr, "unknown error on line %d", lineNo);
@@ -1193,13 +1189,13 @@
1193 ** then the mlink entry is only created if there is already an mlink
1194 ** from primary parent for the same file.
1195 */
1196 static void add_one_mlink(
1197 int pmid, /* The parent manifest */
1198 const char *zFromUuid, /* UUID for content in parent */
1199 int mid, /* The record ID of the manifest */
1200 const char *zToUuid, /* UUID for content in child */
1201 const char *zFilename, /* Filename */
1202 const char *zPrior, /* Previous filename. NULL if unchanged */
1203 int isPublic, /* True if mid is not a private manifest */
1204 int isPrimary, /* pmid is the primary parent of mid */
1205 int mperm /* 1: exec, 2: symlink */
@@ -1545,22 +1541,22 @@
1545 }
1546 }
1547
1548 /*
1549 ** For a check-in with RID "rid" that has nParent parent check-ins given
1550 ** by the UUIDs in azParent[], create all appropriate plink and mlink table
1551 ** entries.
1552 **
1553 ** The primary parent is the first UUID on the azParent[] list.
1554 **
1555 ** Return the RID of the primary parent.
1556 */
1557 static int manifest_add_checkin_linkages(
1558 int rid, /* The RID of the check-in */
1559 Manifest *p, /* Manifest for this check-in */
1560 int nParent, /* Number of parents for this check-in */
1561 char **azParent /* UUIDs for each parent */
1562 ){
1563 int i;
1564 int parentid = 0;
1565 char zBaseId[30]; /* Baseline manifest RID for deltas. "NULL" otherwise */
1566 Stmt q;
@@ -1611,33 +1607,36 @@
1611 return parentid;
1612 }
1613
1614 /*
1615 ** There exists a "parent" tag against checkin rid that has value zValue.
1616 ** If value is well-formed (meaning that it is a list of UUIDs), then use
1617 ** zValue to reparent check-in rid.
1618 */
1619 void manifest_reparent_checkin(int rid, const char *zValue){
1620 int nParent;
1621 char *zCopy = 0;
1622 char **azParent = 0;
1623 Manifest *p = 0;
1624 int i;
1625 int n = (int)strlen(zValue);
1626 nParent = (n+1)/(UUID_SIZE+1);
1627 if( nParent*(UUID_SIZE+1) - 1 !=n ) return;
1628 if( nParent<1 ) return;
1629 zCopy = fossil_strdup(zValue);
1630 azParent = fossil_malloc( sizeof(azParent[0])*nParent );
1631 for(i=0; i<nParent; i++){
1632 azParent[i] = &zCopy[i*(UUID_SIZE+1)];
1633 if( i<nParent-1 && azParent[i][UUID_SIZE]!=' ' ) break;
1634 azParent[i][UUID_SIZE] = 0;
1635 if( !validate16(azParent[i],UUID_SIZE) ) break;
1636 }
1637 if( i==nParent
1638 && !db_exists("SELECT 1 FROM plink WHERE cid=%d AND pid=%d",
 
 
 
1639 rid, uuid_to_rid(azParent[0],0))
1640 ){
1641 p = manifest_get(rid, CFTYPE_MANIFEST, 0);
1642 }
1643 if( p!=0 ){
@@ -1647,10 +1646,11 @@
1647 rid, rid
1648 );
1649 manifest_add_checkin_linkages(rid,p,nParent,azParent);
1650 }
1651 manifest_destroy(p);
 
1652 fossil_free(azParent);
1653 fossil_free(zCopy);
1654 }
1655
1656 /*
@@ -2280,11 +2280,11 @@
2280 int branchMove = 0;
2281 blob_zero(&comment);
2282 if( p->zComment ){
2283 blob_appendf(&comment, " %s.", p->zComment);
2284 }
2285 /* Next loop expects tags to be sorted on UUID, so sort it. */
2286 qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
2287 for(i=0; i<p->nTag; i++){
2288 zTagUuid = p->aTag[i].zUuid;
2289 if( !zTagUuid ) continue;
2290 if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
2291
--- src/manifest.c
+++ src/manifest.c
@@ -54,11 +54,11 @@
54 /*
55 ** A single F-card within a manifest
56 */
57 struct ManifestFile {
58 char *zName; /* Name of a file */
59 char *zUuid; /* Artifact hash for the file */
60 char *zPerm; /* File permissions */
61 char *zPrior; /* Prior name if the name was changed */
62 };
63
64
@@ -77,35 +77,35 @@
77 char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */
78 char *zWiki; /* Text of the wiki page. W card. */
79 char *zWikiTitle; /* Name of the wiki page. L card. */
80 char *zMimetype; /* Mime type of wiki or comment text. N card. */
81 double rEventDate; /* Date of an event. E card. */
82 char *zEventId; /* Artifact hash for an event. E card. */
83 char *zTicketUuid; /* UUID for a ticket. K card. */
84 char *zAttachName; /* Filename of an attachment. A card. */
85 char *zAttachSrc; /* Artifact hash for document being attached. A card. */
86 char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */
87 int nFile; /* Number of F cards */
88 int nFileAlloc; /* Slots allocated in aFile[] */
89 int iFile; /* Index of current file in iterator */
90 ManifestFile *aFile; /* One entry for each F-card */
91 int nParent; /* Number of parents. */
92 int nParentAlloc; /* Slots allocated in azParent[] */
93 char **azParent; /* Hashes of parents. One for each P card argument */
94 int nCherrypick; /* Number of entries in aCherrypick[] */
95 struct {
96 char *zCPTarget; /* Hash for cherry-picked version w/ +|- prefix */
97 char *zCPBase; /* Hash for cherry-pick baseline. NULL for singletons */
98 } *aCherrypick;
99 int nCChild; /* Number of cluster children */
100 int nCChildAlloc; /* Number of closts allocated in azCChild[] */
101 char **azCChild; /* Hashes of referenced objects in a cluster. M cards */
102 int nTag; /* Number of T Cards */
103 int nTagAlloc; /* Slots allocated in aTag[] */
104 struct TagType {
105 char *zName; /* Name of the tag */
106 char *zUuid; /* Hash of artifact that the tag is applied to */
107 char *zValue; /* Value if the tag is really a property */
108 } *aTag; /* One for each T card */
109 int nField; /* Number of J cards */
110 int nFieldAlloc; /* Slots allocated in aField[] */
111 struct {
@@ -327,26 +327,27 @@
327 ** takes over the input blob and will free it when the
328 ** Manifest object is freed. Zeros are inserted into the blob
329 ** as string terminators so that blob should not be used again.
330 **
331 ** Return a pointer to an allocated Manifest object if the content
332 ** really is a structural artifact of some kind. The returned Manifest
333 ** object needs to be freed by a subsequent call to manifest_destroy().
334 ** Return NULL if there are syntax errors or if the input blob does
335 ** not describe a valid structural artifact.
336 **
337 ** This routine is strict about the format of a structural artifacts.
338 ** The format must match exactly or else it is rejected. This
339 ** rule minimizes the risk that a content artifact will be mistaken
340 ** for a structural artifact simply because they look the same.
341 **
342 ** The pContent is reset. If a pointer is returned, then pContent will
343 ** be reset when the Manifest object is cleared. If NULL is
344 ** returned then the Manifest object is cleared automatically
345 ** and pContent is reset before the return.
346 **
347 ** The entire input blob can be PGP clear-signed. The signature is ignored.
348 ** The artifact consists of zero or more cards, one card per line.
349 ** (Except: the content of the W card can extend of multiple lines.)
350 ** Each card is divided into tokens by a single space character.
351 ** The first token is a single upper-case letter which is the card type.
352 ** The card type determines the other parameters to the card.
353 ** Cards must occur in lexicographical order.
@@ -361,11 +362,10 @@
362 char *z;
363 int n;
364 char *zUuid;
365 int sz = 0;
366 int isRepeat, hasSelfRefTag = 0;
 
367 static Bag seen;
368 const char *zErr = 0;
369
370 if( rid==0 ){
371 isRepeat = 1;
@@ -374,11 +374,11 @@
374 }else{
375 isRepeat = 0;
376 bag_insert(&seen, rid);
377 }
378
379 /* Every structural artifact ends with a '\n' character. Exit early
380 ** if that is not the case for this artifact.
381 */
382 if( !isRepeat ) g.parseCnt[0]++;
383 z = blob_materialize(pContent);
384 n = blob_size(pContent);
@@ -406,15 +406,10 @@
406 blob_reset(pContent);
407 blob_appendf(pErr, "incorrect Z-card cksum");
408 return 0;
409 }
410
 
 
 
 
 
411 /* Allocate a Manifest object to hold the parsed control artifact.
412 */
413 p = fossil_malloc( sizeof(*p) );
414 memset(p, 0, sizeof(*p));
415 memcpy(&p->content, pContent, sizeof(p->content));
@@ -449,15 +444,15 @@
444 defossilize(zName);
445 if( !file_is_simple_pathname(zName, 0) ){
446 SYNTAX("invalid filename on A-card");
447 }
448 defossilize(zTarget);
449 if( !hname_validate(zTarget,nTarget)
450 && !wiki_name_is_wellformed((const unsigned char *)zTarget) ){
451 SYNTAX("invalid target on A-card");
452 }
453 if( zSrc && !hname_validate(zSrc,nSrc) ){
454 SYNTAX("invalid source on A-card");
455 }
456 p->zAttachName = (char*)file_tail(zName);
457 p->zAttachSrc = zSrc;
458 p->zAttachTarget = zTarget;
@@ -465,18 +460,18 @@
460 }
461
462 /*
463 ** B <uuid>
464 **
465 ** A B-line gives the artifact hash for the baseline of a delta-manifest.
466 */
467 case 'B': {
468 if( p->zBaseline ) SYNTAX("more than one B-card");
469 p->zBaseline = next_token(&x, &sz);
470 if( p->zBaseline==0 ) SYNTAX("missing hash on B-card");
471 if( !hname_validate(p->zBaseline,sz) ){
472 SYNTAX("invalid hash on B-card");
473 }
474 break;
475 }
476
477
@@ -522,12 +517,12 @@
517 case 'E': {
518 if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
519 p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
520 if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
521 p->zEventId = next_token(&x, &sz);
522 if( !hname_validate(p->zEventId, sz) ){
523 SYNTAX("malformed hash on E-card");
524 }
525 break;
526 }
527
528 /*
@@ -545,12 +540,13 @@
540 if( !file_is_simple_pathname(zName, 0) ){
541 SYNTAX("F-card filename is not a simple path");
542 }
543 zUuid = next_token(&x, &sz);
544 if( p->zBaseline==0 || zUuid!=0 ){
545 if( !hname_validate(zUuid,sz) ){
546 SYNTAX("F-card hash invalid");
547 }
548 }
549 zPerm = next_token(&x,0);
550 zPriorName = next_token(&x,0);
551 if( zPriorName ){
552 defossilize(zPriorName);
@@ -636,20 +632,21 @@
632 }
633 break;
634 }
635
636 /*
637 ** M <hash>
638 **
639 ** An M-line identifies another artifact by its hash. M-lines
640 ** occur in clusters only.
641 */
642 case 'M': {
643 zUuid = next_token(&x, &sz);
644 if( zUuid==0 ) SYNTAX("missing hash on M-card");
645 if( !hname_validate(zUuid,sz) ){
646 SYNTAX("Invalid hash on M-card");
647 }
648 if( p->nCChild>=p->nCChildAlloc ){
649 p->nCChildAlloc = p->nCChildAlloc*2 + 10;
650 p->azCChild = fossil_realloc(p->azCChild
651 , p->nCChildAlloc*sizeof(p->azCChild[0]) );
652 }
@@ -683,12 +680,13 @@
680 ** check-in historically has an empty P-card, so empty P-cards
681 ** must be accepted.
682 */
683 case 'P': {
684 while( (zUuid = next_token(&x, &sz))!=0 ){
685 if( !hname_validate(zUuid, sz) ){
686 SYNTAX("invalid hash on P-card");
687 }
688 if( p->nParent>=p->nParentAlloc ){
689 p->nParentAlloc = p->nParentAlloc*2 + 5;
690 p->azParent = fossil_realloc(p->azParent,
691 p->nParentAlloc*sizeof(char*));
692 }
@@ -703,29 +701,25 @@
701 **
702 ** Specify one or a range of check-ins that are cherrypicked into
703 ** this check-in ("+") or backed out of this check-in ("-").
704 */
705 case 'Q': {
706 if( (zUuid=next_token(&x, &sz))==0 ) SYNTAX("missing hash on Q-card");
 
707 if( zUuid[0]!='+' && zUuid[0]!='-' ){
708 SYNTAX("Q-card does not begin with '+' or '-'");
709 }
710 if( !hname_validate(&zUuid[1], sz-1) ){
711 SYNTAX("invalid hash on Q-card");
712 }
713 n = p->nCherrypick;
714 p->nCherrypick++;
715 p->aCherrypick = fossil_realloc(p->aCherrypick,
716 p->nCherrypick*sizeof(p->aCherrypick[0]));
717 p->aCherrypick[n].zCPTarget = zUuid;
718 p->aCherrypick[n].zCPBase = zUuid = next_token(&x, &sz);
719 if( zUuid && !hname_validate(zUuid,sz) ){
720 SYNTAX("invalid second hash on Q-card");
 
 
 
721 }
722 break;
723 }
724
725 /*
@@ -760,32 +754,32 @@
754 case 'T': {
755 char *zName, *zValue;
756 zName = next_token(&x, 0);
757 if( zName==0 ) SYNTAX("missing name on T-card");
758 zUuid = next_token(&x, &sz);
759 if( zUuid==0 ) SYNTAX("missing artifact hash on T-card");
760 zValue = next_token(&x, 0);
761 if( zValue ) defossilize(zValue);
762 if( hname_validate(zUuid, sz) ){
763 /* A valid artifact hash */
764 if( p->zEventId ) SYNTAX("non-self-referential T-card in event");
765 }else if( sz==1 && zUuid[0]=='*' ){
766 zUuid = 0;
767 hasSelfRefTag = 1;
768 if( p->zEventId && zName[0]!='+' ){
769 SYNTAX("propagating T-card in event");
770 }
771 }else{
772 SYNTAX("malformed artifact hash on T-card");
773 }
774 defossilize(zName);
775 if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
776 SYNTAX("T-card name does not begin with '-', '+', or '*'");
777 }
778 if( validate16(&zName[1], strlen(&zName[1])) ){
779 /* Do not allow tags whose names look like a hash */
780 SYNTAX("T-card name looks like a hexadecimal hash");
781 }
782 if( p->nTag>=p->nTagAlloc ){
783 p->nTagAlloc = p->nTagAlloc*2 + 10;
784 p->aTag = fossil_realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) );
785 }
@@ -951,17 +945,19 @@
945 if( !seenZ ) SYNTAX("missing Z-card on control");
946 p->type = CFTYPE_CONTROL;
947 }
948 md5sum_init();
949 if( !isRepeat ) g.parseCnt[p->type]++;
 
950 return p;
951
952 manifest_syntax_error:
953 {
954 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
955 if( zUuid ){
956 blob_appendf(pErr, "manifest [%s] ", zUuid);
957 fossil_free(zUuid);
958 }
959 }
960 if( zErr ){
961 blob_appendf(pErr, "line %d: %s", lineNo, zErr);
962 }else{
963 blob_appendf(pErr, "unknown error on line %d", lineNo);
@@ -1193,13 +1189,13 @@
1189 ** then the mlink entry is only created if there is already an mlink
1190 ** from primary parent for the same file.
1191 */
1192 static void add_one_mlink(
1193 int pmid, /* The parent manifest */
1194 const char *zFromUuid, /* Artifact hash for content in parent */
1195 int mid, /* The record ID of the manifest */
1196 const char *zToUuid, /* artifact hash for content in child */
1197 const char *zFilename, /* Filename */
1198 const char *zPrior, /* Previous filename. NULL if unchanged */
1199 int isPublic, /* True if mid is not a private manifest */
1200 int isPrimary, /* pmid is the primary parent of mid */
1201 int mperm /* 1: exec, 2: symlink */
@@ -1545,22 +1541,22 @@
1541 }
1542 }
1543
1544 /*
1545 ** For a check-in with RID "rid" that has nParent parent check-ins given
1546 ** by the hashes in azParent[], create all appropriate plink and mlink table
1547 ** entries.
1548 **
1549 ** The primary parent is the first hash on the azParent[] list.
1550 **
1551 ** Return the RID of the primary parent.
1552 */
1553 static int manifest_add_checkin_linkages(
1554 int rid, /* The RID of the check-in */
1555 Manifest *p, /* Manifest for this check-in */
1556 int nParent, /* Number of parents for this check-in */
1557 char **azParent /* hashes for each parent */
1558 ){
1559 int i;
1560 int parentid = 0;
1561 char zBaseId[30]; /* Baseline manifest RID for deltas. "NULL" otherwise */
1562 Stmt q;
@@ -1611,33 +1607,36 @@
1607 return parentid;
1608 }
1609
1610 /*
1611 ** There exists a "parent" tag against checkin rid that has value zValue.
1612 ** If value is well-formed (meaning that it is a list of hashes), then use
1613 ** zValue to reparent check-in rid.
1614 */
1615 void manifest_reparent_checkin(int rid, const char *zValue){
1616 int nParent = 0;
1617 char *zCopy = 0;
1618 char **azParent = 0;
1619 Manifest *p = 0;
1620 int i, j;
1621 int n = (int)strlen(zValue);
1622 int mxParent = (n+1)/(HNAME_MIN+1);
1623
1624 if( mxParent<1 ) return;
1625 zCopy = fossil_strdup(zValue);
1626 azParent = fossil_malloc( sizeof(azParent[0])*mxParent );
1627 for(nParent=0, i=0; zCopy[i]; i++){
1628 char *z = &zCopy[i];
1629 azParent[nParent++] = z;
1630 if( nParent>mxParent ) goto reparent_abort;
1631 for(j=HNAME_MIN; z[j]>' '; j++){}
1632 if( !hname_validate(z, j) ) goto reparent_abort;
1633 if( z[j]==0 ) break;
1634 z[j] = 0;
1635 i += j;
1636 }
1637 if( !db_exists("SELECT 1 FROM plink WHERE cid=%d AND pid=%d",
1638 rid, uuid_to_rid(azParent[0],0))
1639 ){
1640 p = manifest_get(rid, CFTYPE_MANIFEST, 0);
1641 }
1642 if( p!=0 ){
@@ -1647,10 +1646,11 @@
1646 rid, rid
1647 );
1648 manifest_add_checkin_linkages(rid,p,nParent,azParent);
1649 }
1650 manifest_destroy(p);
1651 reparent_abort:
1652 fossil_free(azParent);
1653 fossil_free(zCopy);
1654 }
1655
1656 /*
@@ -2280,11 +2280,11 @@
2280 int branchMove = 0;
2281 blob_zero(&comment);
2282 if( p->zComment ){
2283 blob_appendf(&comment, " %s.", p->zComment);
2284 }
2285 /* Next loop expects tags to be sorted on hash, so sort it. */
2286 qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
2287 for(i=0; i<p->nTag; i++){
2288 zTagUuid = p->aTag[i].zUuid;
2289 if( !zTagUuid ) continue;
2290 if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
2291
+6 -5
--- src/mkversion.c
+++ src/mkversion.c
@@ -12,11 +12,12 @@
1212
#include <stdlib.h>
1313
1414
int main(int argc, char *argv[]){
1515
FILE *m,*u,*v;
1616
char *z;
17
- int i, x, d;
17
+ int i, j, x, d;
18
+ int vn[3];
1819
char b[1000];
1920
char vx[1000];
2021
memset(b,0,sizeof(b));
2122
memset(vx,0,sizeof(vx));
2223
u = fopen(argv[1],"r");
@@ -45,25 +46,25 @@
4546
fclose(v);
4647
for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
4748
*z = 0;
4849
printf("#define RELEASE_VERSION \"%s\"\n", b);
4950
x=0;
50
- i=0;
51
+ i=j=0;
5152
z=b;
53
+ vn[0] = vn[1] = vn[2] = 0;
5254
while(1){
5355
if( z[0]>='0' && z[0]<='9' ){
5456
x = x*10 + z[0] - '0';
5557
}else{
56
- sprintf(&vx[i],"%02d",x);
57
- i += 2;
58
+ if( j<3 ) vn[j++] = x;
5859
x = 0;
5960
if( z[0]==0 ) break;
6061
}
6162
z++;
6263
}
6364
for(z=vx; z[0]=='0'; z++){}
64
- printf("#define RELEASE_VERSION_NUMBER %s\n", z);
65
+ printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]);
6566
memset(vx,0,sizeof(vx));
6667
strcpy(vx,b);
6768
d = 0;
6869
for(z=vx; z[0]; z++){
6970
if( z[0]=='-' ){
7071
--- src/mkversion.c
+++ src/mkversion.c
@@ -12,11 +12,12 @@
12 #include <stdlib.h>
13
14 int main(int argc, char *argv[]){
15 FILE *m,*u,*v;
16 char *z;
17 int i, x, d;
 
18 char b[1000];
19 char vx[1000];
20 memset(b,0,sizeof(b));
21 memset(vx,0,sizeof(vx));
22 u = fopen(argv[1],"r");
@@ -45,25 +46,25 @@
45 fclose(v);
46 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
47 *z = 0;
48 printf("#define RELEASE_VERSION \"%s\"\n", b);
49 x=0;
50 i=0;
51 z=b;
 
52 while(1){
53 if( z[0]>='0' && z[0]<='9' ){
54 x = x*10 + z[0] - '0';
55 }else{
56 sprintf(&vx[i],"%02d",x);
57 i += 2;
58 x = 0;
59 if( z[0]==0 ) break;
60 }
61 z++;
62 }
63 for(z=vx; z[0]=='0'; z++){}
64 printf("#define RELEASE_VERSION_NUMBER %s\n", z);
65 memset(vx,0,sizeof(vx));
66 strcpy(vx,b);
67 d = 0;
68 for(z=vx; z[0]; z++){
69 if( z[0]=='-' ){
70
--- src/mkversion.c
+++ src/mkversion.c
@@ -12,11 +12,12 @@
12 #include <stdlib.h>
13
14 int main(int argc, char *argv[]){
15 FILE *m,*u,*v;
16 char *z;
17 int i, j, x, d;
18 int vn[3];
19 char b[1000];
20 char vx[1000];
21 memset(b,0,sizeof(b));
22 memset(vx,0,sizeof(vx));
23 u = fopen(argv[1],"r");
@@ -45,25 +46,25 @@
46 fclose(v);
47 for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
48 *z = 0;
49 printf("#define RELEASE_VERSION \"%s\"\n", b);
50 x=0;
51 i=j=0;
52 z=b;
53 vn[0] = vn[1] = vn[2] = 0;
54 while(1){
55 if( z[0]>='0' && z[0]<='9' ){
56 x = x*10 + z[0] - '0';
57 }else{
58 if( j<3 ) vn[j++] = x;
 
59 x = 0;
60 if( z[0]==0 ) break;
61 }
62 z++;
63 }
64 for(z=vx; z[0]=='0'; z++){}
65 printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]);
66 memset(vx,0,sizeof(vx));
67 strcpy(vx,b);
68 d = 0;
69 for(z=vx; z[0]; z++){
70 if( z[0]=='-' ){
71
+24 -28
--- src/name.c
+++ src/name.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2006 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -13,15 +13,11 @@
1313
** [email protected]
1414
** http://www.hwaci.com/drh/
1515
**
1616
*******************************************************************************
1717
**
18
-** This file contains code used to convert user-supplied object names into
19
-** canonical UUIDs.
20
-**
21
-** A user-supplied object name is any unique prefix of a valid UUID but
22
-** not necessarily in canonical form.
18
+** This file contains code used to resolved user-supplied object names.
2319
*/
2420
#include "config.h"
2521
#include "name.h"
2622
#include <assert.h>
2723
@@ -80,12 +76,12 @@
8076
}
8177
8278
/*
8379
** Convert a symbolic name into a RID. Acceptable forms:
8480
**
85
-** * SHA1 hash
86
-** * SHA1 hash prefix of at least 4 characters
81
+** * artifact hash
82
+** * 4-character or larger prefix of a artifact
8783
** * Symbolic Name
8884
** * "tag:" + symbolic name
8985
** * Date or date-time
9086
** * "date:" + Date or date-time
9187
** * symbolic-name ":" date-time
@@ -105,11 +101,11 @@
105101
** If zType is "br" then find the first check-in of the named branch
106102
** rather than the last.
107103
** zType is "ci" in most use cases since we are usually searching for
108104
** a check-in.
109105
**
110
-** Note that the input zTag for types "t" and "e" is the SHA1 hash of
106
+** Note that the input zTag for types "t" and "e" is the artifact hash of
111107
** the ticket-change or event-change artifact, not the randomly generated
112108
** hexadecimal identifier assigned to tickets and events. Those identifiers
113109
** live in a separate namespace.
114110
*/
115111
int symbolic_name_to_rid(const char *zTag, const char *zType){
@@ -232,14 +228,14 @@
232228
zTagBase, zDate, zType
233229
);
234230
return rid;
235231
}
236232
237
- /* SHA1 hash or prefix */
238
- if( nTag>=4 && nTag<=UUID_SIZE && validate16(zTag, nTag) ){
233
+ /* artifact hash or prefix */
234
+ if( nTag>=4 && nTag<=HNAME_MAX && validate16(zTag, nTag) ){
239235
Stmt q;
240
- char zUuid[UUID_SIZE+1];
236
+ char zUuid[HNAME_MAX+1];
241237
memcpy(zUuid, zTag, nTag+1);
242238
canonical16(zUuid, nTag);
243239
rid = 0;
244240
if( zType[0]=='*' ){
245241
db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
@@ -354,11 +350,11 @@
354350
*/
355351
int name_collisions(const char *zName){
356352
int c = 0; /* count of collisions for zName */
357353
int nLen; /* length of zName */
358354
nLen = strlen(zName);
359
- if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){
355
+ if( nLen>=4 && nLen<=HNAME_MAX && validate16(zName, nLen) ){
360356
c = db_int(0,
361357
"SELECT"
362358
" (SELECT count(*) FROM ticket"
363359
" WHERE tkt_uuid GLOB '%q*') +"
364360
" (SELECT count(*) FROM tag"
@@ -396,11 +392,11 @@
396392
397393
/*
398394
** Convert a name to a rid. If the name can be any of the various forms
399395
** accepted:
400396
**
401
-** * SHA1 hash or prefix thereof
397
+** * artifact hash or prefix thereof
402398
** * symbolic name
403399
** * date
404400
** * label:date
405401
** * prev, previous
406402
** * next
@@ -425,13 +421,13 @@
425421
return name_to_typed_rid(zName, "*");
426422
}
427423
428424
/*
429425
** WEBPAGE: ambiguous
430
-** URL: /ambiguous?name=UUID&src=WEBPAGE
426
+** URL: /ambiguous?name=NAME&src=WEBPAGE
431427
**
432
-** The UUID given by the name parameter is ambiguous. Display a page
428
+** The NAME given by the name parameter is ambiguous. Display a page
433429
** that shows all possible choices and let the user select between them.
434430
*/
435431
void ambiguous_page(void){
436432
Stmt q;
437433
const char *zName = P("name");
@@ -668,11 +664,11 @@
668664
/*
669665
** COMMAND: whatis*
670666
**
671667
** Usage: %fossil whatis NAME
672668
**
673
-** Resolve the symbol NAME into its canonical 40-character SHA1-hash
669
+** Resolve the symbol NAME into its canonical artifact hash
674670
** artifact name and provide a description of what role that artifact
675671
** plays.
676672
**
677673
** Options:
678674
**
@@ -744,11 +740,11 @@
744740
/*
745741
** COMMAND: test-ambiguous
746742
**
747743
** Usage: %fossil test-ambiguous [--minsize N]
748744
**
749
-** Show a list of ambiguous SHA1-hash abbreviations of N characters or
745
+** Show a list of ambiguous artifact hash abbreviations of N characters or
750746
** more where N defaults to 4. Change N to a different value using
751747
** the "--minsize N" command-line option.
752748
*/
753749
void test_ambiguous_cmd(void){
754750
Stmt q, ins;
@@ -794,11 +790,11 @@
794790
** Schema for the description table
795791
*/
796792
static const char zDescTab[] =
797793
@ CREATE TEMP TABLE IF NOT EXISTS description(
798794
@ rid INTEGER PRIMARY KEY, -- RID of the object
799
-@ uuid TEXT, -- SHA1 hash of the object
795
+@ uuid TEXT, -- hash of the object
800796
@ ctime DATETIME, -- Time of creation
801797
@ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts
802798
@ type TEXT, -- file, checkin, wiki, ticket, etc.
803799
@ summary TEXT, -- Summary comment for the object
804800
@ detail TEXT -- File name, check-in comment, etc
@@ -1084,11 +1080,11 @@
10841080
" WHERE description.rid=blob.rid"
10851081
" ORDER BY length(content) DESC"
10861082
);
10871083
@ <table cellpadding="2" cellspacing="0" border="1" id="bigblobtab">
10881084
@ <thead><tr><th align="right">Size<th align="right">RID
1089
- @ <th align="right">Delta From<th>SHA1<th>Description<th>Date</tr></thead>
1085
+ @ <th align="right">Delta From<th>Hash<th>Description<th>Date</tr></thead>
10901086
@ <tbody>
10911087
while( db_step(&q)==SQLITE_ROW ){
10921088
int rid = db_column_int(&q,0);
10931089
const char *zUuid = db_column_text(&q, 1);
10941090
const char *zDesc = db_column_text(&q, 2);
@@ -1147,33 +1143,33 @@
11471143
11481144
/* Maximum number of collision examples to remember */
11491145
#define MAX_COLLIDE 25
11501146
11511147
/*
1152
-** Generate a report on the number of collisions in SHA1 hashes
1148
+** Generate a report on the number of collisions in artifact hashes
11531149
** generated by the SQL given in the argument.
11541150
*/
11551151
static void collision_report(const char *zSql){
11561152
int i, j, kk;
11571153
int nHash = 0;
11581154
Stmt q;
1159
- char zPrev[UUID_SIZE+1];
1155
+ char zPrev[HNAME_MAX+1];
11601156
struct {
11611157
int cnt;
11621158
char *azHit[MAX_COLLIDE];
1163
- char z[UUID_SIZE+1];
1164
- } aCollide[UUID_SIZE+1];
1159
+ char z[HNAME_MAX+1];
1160
+ } aCollide[HNAME_MAX+1];
11651161
memset(aCollide, 0, sizeof(aCollide));
11661162
memset(zPrev, 0, sizeof(zPrev));
11671163
db_prepare(&q,"%s",zSql/*safe-for-%s*/);
11681164
while( db_step(&q)==SQLITE_ROW ){
11691165
const char *zUuid = db_column_text(&q,0);
11701166
int n = db_column_bytes(&q,0);
11711167
int i;
11721168
nHash++;
11731169
for(i=0; zPrev[i] && zPrev[i]==zUuid[i]; i++){}
1174
- if( i>0 && i<=UUID_SIZE ){
1170
+ if( i>0 && i<=HNAME_MAX ){
11751171
if( i>=4 && aCollide[i].cnt<MAX_COLLIDE ){
11761172
aCollide[i].azHit[aCollide[i].cnt] = mprintf("%.*s", i, zPrev);
11771173
}
11781174
aCollide[i].cnt++;
11791175
if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
@@ -1182,18 +1178,18 @@
11821178
}
11831179
db_finalize(&q);
11841180
@ <table border=1><thead>
11851181
@ <tr><th>Length<th>Instances<th>First Instance</tr>
11861182
@ </thead><tbody>
1187
- for(i=1; i<=UUID_SIZE; i++){
1183
+ for(i=1; i<=HNAME_MAX; i++){
11881184
if( aCollide[i].cnt==0 ) continue;
11891185
@ <tr><td>%d(i)<td>%d(aCollide[i].cnt)<td>%h(aCollide[i].z)</tr>
11901186
}
11911187
@ </tbody></table>
11921188
@ <p>Total number of hashes: %d(nHash)</p>
11931189
kk = 0;
1194
- for(i=UUID_SIZE; i>=4; i--){
1190
+ for(i=HNAME_MAX; i>=4; i--){
11951191
if( aCollide[i].cnt==0 ) continue;
11961192
if( aCollide[i].cnt>200 ) break;
11971193
kk += aCollide[i].cnt;
11981194
if( aCollide[i].cnt<25 ){
11991195
@ <p>Collisions of length %d(i):
@@ -1219,11 +1215,11 @@
12191215
** Show the number of hash collisions for hash prefixes of various lengths.
12201216
*/
12211217
void hash_collisions_webpage(void){
12221218
login_check_credentials();
12231219
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1224
- style_header("SHA1 Prefix Collisions");
1220
+ style_header("Hash Prefix Collisions");
12251221
style_submenu_element("Activity Reports", "reports");
12261222
style_submenu_element("Stats", "stat");
12271223
@ <h1>Hash Prefix Collisions on Check-ins</h1>
12281224
collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
12291225
" FROM event WHERE event.type='ci'"
12301226
--- src/name.c
+++ src/name.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -13,15 +13,11 @@
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to convert user-supplied object names into
19 ** canonical UUIDs.
20 **
21 ** A user-supplied object name is any unique prefix of a valid UUID but
22 ** not necessarily in canonical form.
23 */
24 #include "config.h"
25 #include "name.h"
26 #include <assert.h>
27
@@ -80,12 +76,12 @@
80 }
81
82 /*
83 ** Convert a symbolic name into a RID. Acceptable forms:
84 **
85 ** * SHA1 hash
86 ** * SHA1 hash prefix of at least 4 characters
87 ** * Symbolic Name
88 ** * "tag:" + symbolic name
89 ** * Date or date-time
90 ** * "date:" + Date or date-time
91 ** * symbolic-name ":" date-time
@@ -105,11 +101,11 @@
105 ** If zType is "br" then find the first check-in of the named branch
106 ** rather than the last.
107 ** zType is "ci" in most use cases since we are usually searching for
108 ** a check-in.
109 **
110 ** Note that the input zTag for types "t" and "e" is the SHA1 hash of
111 ** the ticket-change or event-change artifact, not the randomly generated
112 ** hexadecimal identifier assigned to tickets and events. Those identifiers
113 ** live in a separate namespace.
114 */
115 int symbolic_name_to_rid(const char *zTag, const char *zType){
@@ -232,14 +228,14 @@
232 zTagBase, zDate, zType
233 );
234 return rid;
235 }
236
237 /* SHA1 hash or prefix */
238 if( nTag>=4 && nTag<=UUID_SIZE && validate16(zTag, nTag) ){
239 Stmt q;
240 char zUuid[UUID_SIZE+1];
241 memcpy(zUuid, zTag, nTag+1);
242 canonical16(zUuid, nTag);
243 rid = 0;
244 if( zType[0]=='*' ){
245 db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
@@ -354,11 +350,11 @@
354 */
355 int name_collisions(const char *zName){
356 int c = 0; /* count of collisions for zName */
357 int nLen; /* length of zName */
358 nLen = strlen(zName);
359 if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){
360 c = db_int(0,
361 "SELECT"
362 " (SELECT count(*) FROM ticket"
363 " WHERE tkt_uuid GLOB '%q*') +"
364 " (SELECT count(*) FROM tag"
@@ -396,11 +392,11 @@
396
397 /*
398 ** Convert a name to a rid. If the name can be any of the various forms
399 ** accepted:
400 **
401 ** * SHA1 hash or prefix thereof
402 ** * symbolic name
403 ** * date
404 ** * label:date
405 ** * prev, previous
406 ** * next
@@ -425,13 +421,13 @@
425 return name_to_typed_rid(zName, "*");
426 }
427
428 /*
429 ** WEBPAGE: ambiguous
430 ** URL: /ambiguous?name=UUID&src=WEBPAGE
431 **
432 ** The UUID given by the name parameter is ambiguous. Display a page
433 ** that shows all possible choices and let the user select between them.
434 */
435 void ambiguous_page(void){
436 Stmt q;
437 const char *zName = P("name");
@@ -668,11 +664,11 @@
668 /*
669 ** COMMAND: whatis*
670 **
671 ** Usage: %fossil whatis NAME
672 **
673 ** Resolve the symbol NAME into its canonical 40-character SHA1-hash
674 ** artifact name and provide a description of what role that artifact
675 ** plays.
676 **
677 ** Options:
678 **
@@ -744,11 +740,11 @@
744 /*
745 ** COMMAND: test-ambiguous
746 **
747 ** Usage: %fossil test-ambiguous [--minsize N]
748 **
749 ** Show a list of ambiguous SHA1-hash abbreviations of N characters or
750 ** more where N defaults to 4. Change N to a different value using
751 ** the "--minsize N" command-line option.
752 */
753 void test_ambiguous_cmd(void){
754 Stmt q, ins;
@@ -794,11 +790,11 @@
794 ** Schema for the description table
795 */
796 static const char zDescTab[] =
797 @ CREATE TEMP TABLE IF NOT EXISTS description(
798 @ rid INTEGER PRIMARY KEY, -- RID of the object
799 @ uuid TEXT, -- SHA1 hash of the object
800 @ ctime DATETIME, -- Time of creation
801 @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts
802 @ type TEXT, -- file, checkin, wiki, ticket, etc.
803 @ summary TEXT, -- Summary comment for the object
804 @ detail TEXT -- File name, check-in comment, etc
@@ -1084,11 +1080,11 @@
1084 " WHERE description.rid=blob.rid"
1085 " ORDER BY length(content) DESC"
1086 );
1087 @ <table cellpadding="2" cellspacing="0" border="1" id="bigblobtab">
1088 @ <thead><tr><th align="right">Size<th align="right">RID
1089 @ <th align="right">Delta From<th>SHA1<th>Description<th>Date</tr></thead>
1090 @ <tbody>
1091 while( db_step(&q)==SQLITE_ROW ){
1092 int rid = db_column_int(&q,0);
1093 const char *zUuid = db_column_text(&q, 1);
1094 const char *zDesc = db_column_text(&q, 2);
@@ -1147,33 +1143,33 @@
1147
1148 /* Maximum number of collision examples to remember */
1149 #define MAX_COLLIDE 25
1150
1151 /*
1152 ** Generate a report on the number of collisions in SHA1 hashes
1153 ** generated by the SQL given in the argument.
1154 */
1155 static void collision_report(const char *zSql){
1156 int i, j, kk;
1157 int nHash = 0;
1158 Stmt q;
1159 char zPrev[UUID_SIZE+1];
1160 struct {
1161 int cnt;
1162 char *azHit[MAX_COLLIDE];
1163 char z[UUID_SIZE+1];
1164 } aCollide[UUID_SIZE+1];
1165 memset(aCollide, 0, sizeof(aCollide));
1166 memset(zPrev, 0, sizeof(zPrev));
1167 db_prepare(&q,"%s",zSql/*safe-for-%s*/);
1168 while( db_step(&q)==SQLITE_ROW ){
1169 const char *zUuid = db_column_text(&q,0);
1170 int n = db_column_bytes(&q,0);
1171 int i;
1172 nHash++;
1173 for(i=0; zPrev[i] && zPrev[i]==zUuid[i]; i++){}
1174 if( i>0 && i<=UUID_SIZE ){
1175 if( i>=4 && aCollide[i].cnt<MAX_COLLIDE ){
1176 aCollide[i].azHit[aCollide[i].cnt] = mprintf("%.*s", i, zPrev);
1177 }
1178 aCollide[i].cnt++;
1179 if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
@@ -1182,18 +1178,18 @@
1182 }
1183 db_finalize(&q);
1184 @ <table border=1><thead>
1185 @ <tr><th>Length<th>Instances<th>First Instance</tr>
1186 @ </thead><tbody>
1187 for(i=1; i<=UUID_SIZE; i++){
1188 if( aCollide[i].cnt==0 ) continue;
1189 @ <tr><td>%d(i)<td>%d(aCollide[i].cnt)<td>%h(aCollide[i].z)</tr>
1190 }
1191 @ </tbody></table>
1192 @ <p>Total number of hashes: %d(nHash)</p>
1193 kk = 0;
1194 for(i=UUID_SIZE; i>=4; i--){
1195 if( aCollide[i].cnt==0 ) continue;
1196 if( aCollide[i].cnt>200 ) break;
1197 kk += aCollide[i].cnt;
1198 if( aCollide[i].cnt<25 ){
1199 @ <p>Collisions of length %d(i):
@@ -1219,11 +1215,11 @@
1219 ** Show the number of hash collisions for hash prefixes of various lengths.
1220 */
1221 void hash_collisions_webpage(void){
1222 login_check_credentials();
1223 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1224 style_header("SHA1 Prefix Collisions");
1225 style_submenu_element("Activity Reports", "reports");
1226 style_submenu_element("Stats", "stat");
1227 @ <h1>Hash Prefix Collisions on Check-ins</h1>
1228 collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1229 " FROM event WHERE event.type='ci'"
1230
--- src/name.c
+++ src/name.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -13,15 +13,11 @@
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to resolved user-supplied object names.
 
 
 
 
19 */
20 #include "config.h"
21 #include "name.h"
22 #include <assert.h>
23
@@ -80,12 +76,12 @@
76 }
77
78 /*
79 ** Convert a symbolic name into a RID. Acceptable forms:
80 **
81 ** * artifact hash
82 ** * 4-character or larger prefix of a artifact
83 ** * Symbolic Name
84 ** * "tag:" + symbolic name
85 ** * Date or date-time
86 ** * "date:" + Date or date-time
87 ** * symbolic-name ":" date-time
@@ -105,11 +101,11 @@
101 ** If zType is "br" then find the first check-in of the named branch
102 ** rather than the last.
103 ** zType is "ci" in most use cases since we are usually searching for
104 ** a check-in.
105 **
106 ** Note that the input zTag for types "t" and "e" is the artifact hash of
107 ** the ticket-change or event-change artifact, not the randomly generated
108 ** hexadecimal identifier assigned to tickets and events. Those identifiers
109 ** live in a separate namespace.
110 */
111 int symbolic_name_to_rid(const char *zTag, const char *zType){
@@ -232,14 +228,14 @@
228 zTagBase, zDate, zType
229 );
230 return rid;
231 }
232
233 /* artifact hash or prefix */
234 if( nTag>=4 && nTag<=HNAME_MAX && validate16(zTag, nTag) ){
235 Stmt q;
236 char zUuid[HNAME_MAX+1];
237 memcpy(zUuid, zTag, nTag+1);
238 canonical16(zUuid, nTag);
239 rid = 0;
240 if( zType[0]=='*' ){
241 db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
@@ -354,11 +350,11 @@
350 */
351 int name_collisions(const char *zName){
352 int c = 0; /* count of collisions for zName */
353 int nLen; /* length of zName */
354 nLen = strlen(zName);
355 if( nLen>=4 && nLen<=HNAME_MAX && validate16(zName, nLen) ){
356 c = db_int(0,
357 "SELECT"
358 " (SELECT count(*) FROM ticket"
359 " WHERE tkt_uuid GLOB '%q*') +"
360 " (SELECT count(*) FROM tag"
@@ -396,11 +392,11 @@
392
393 /*
394 ** Convert a name to a rid. If the name can be any of the various forms
395 ** accepted:
396 **
397 ** * artifact hash or prefix thereof
398 ** * symbolic name
399 ** * date
400 ** * label:date
401 ** * prev, previous
402 ** * next
@@ -425,13 +421,13 @@
421 return name_to_typed_rid(zName, "*");
422 }
423
424 /*
425 ** WEBPAGE: ambiguous
426 ** URL: /ambiguous?name=NAME&src=WEBPAGE
427 **
428 ** The NAME given by the name parameter is ambiguous. Display a page
429 ** that shows all possible choices and let the user select between them.
430 */
431 void ambiguous_page(void){
432 Stmt q;
433 const char *zName = P("name");
@@ -668,11 +664,11 @@
664 /*
665 ** COMMAND: whatis*
666 **
667 ** Usage: %fossil whatis NAME
668 **
669 ** Resolve the symbol NAME into its canonical artifact hash
670 ** artifact name and provide a description of what role that artifact
671 ** plays.
672 **
673 ** Options:
674 **
@@ -744,11 +740,11 @@
740 /*
741 ** COMMAND: test-ambiguous
742 **
743 ** Usage: %fossil test-ambiguous [--minsize N]
744 **
745 ** Show a list of ambiguous artifact hash abbreviations of N characters or
746 ** more where N defaults to 4. Change N to a different value using
747 ** the "--minsize N" command-line option.
748 */
749 void test_ambiguous_cmd(void){
750 Stmt q, ins;
@@ -794,11 +790,11 @@
790 ** Schema for the description table
791 */
792 static const char zDescTab[] =
793 @ CREATE TEMP TABLE IF NOT EXISTS description(
794 @ rid INTEGER PRIMARY KEY, -- RID of the object
795 @ uuid TEXT, -- hash of the object
796 @ ctime DATETIME, -- Time of creation
797 @ isPrivate BOOLEAN DEFAULT 0, -- True for unpublished artifacts
798 @ type TEXT, -- file, checkin, wiki, ticket, etc.
799 @ summary TEXT, -- Summary comment for the object
800 @ detail TEXT -- File name, check-in comment, etc
@@ -1084,11 +1080,11 @@
1080 " WHERE description.rid=blob.rid"
1081 " ORDER BY length(content) DESC"
1082 );
1083 @ <table cellpadding="2" cellspacing="0" border="1" id="bigblobtab">
1084 @ <thead><tr><th align="right">Size<th align="right">RID
1085 @ <th align="right">Delta From<th>Hash<th>Description<th>Date</tr></thead>
1086 @ <tbody>
1087 while( db_step(&q)==SQLITE_ROW ){
1088 int rid = db_column_int(&q,0);
1089 const char *zUuid = db_column_text(&q, 1);
1090 const char *zDesc = db_column_text(&q, 2);
@@ -1147,33 +1143,33 @@
1143
1144 /* Maximum number of collision examples to remember */
1145 #define MAX_COLLIDE 25
1146
1147 /*
1148 ** Generate a report on the number of collisions in artifact hashes
1149 ** generated by the SQL given in the argument.
1150 */
1151 static void collision_report(const char *zSql){
1152 int i, j, kk;
1153 int nHash = 0;
1154 Stmt q;
1155 char zPrev[HNAME_MAX+1];
1156 struct {
1157 int cnt;
1158 char *azHit[MAX_COLLIDE];
1159 char z[HNAME_MAX+1];
1160 } aCollide[HNAME_MAX+1];
1161 memset(aCollide, 0, sizeof(aCollide));
1162 memset(zPrev, 0, sizeof(zPrev));
1163 db_prepare(&q,"%s",zSql/*safe-for-%s*/);
1164 while( db_step(&q)==SQLITE_ROW ){
1165 const char *zUuid = db_column_text(&q,0);
1166 int n = db_column_bytes(&q,0);
1167 int i;
1168 nHash++;
1169 for(i=0; zPrev[i] && zPrev[i]==zUuid[i]; i++){}
1170 if( i>0 && i<=HNAME_MAX ){
1171 if( i>=4 && aCollide[i].cnt<MAX_COLLIDE ){
1172 aCollide[i].azHit[aCollide[i].cnt] = mprintf("%.*s", i, zPrev);
1173 }
1174 aCollide[i].cnt++;
1175 if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
@@ -1182,18 +1178,18 @@
1178 }
1179 db_finalize(&q);
1180 @ <table border=1><thead>
1181 @ <tr><th>Length<th>Instances<th>First Instance</tr>
1182 @ </thead><tbody>
1183 for(i=1; i<=HNAME_MAX; i++){
1184 if( aCollide[i].cnt==0 ) continue;
1185 @ <tr><td>%d(i)<td>%d(aCollide[i].cnt)<td>%h(aCollide[i].z)</tr>
1186 }
1187 @ </tbody></table>
1188 @ <p>Total number of hashes: %d(nHash)</p>
1189 kk = 0;
1190 for(i=HNAME_MAX; i>=4; i--){
1191 if( aCollide[i].cnt==0 ) continue;
1192 if( aCollide[i].cnt>200 ) break;
1193 kk += aCollide[i].cnt;
1194 if( aCollide[i].cnt<25 ){
1195 @ <p>Collisions of length %d(i):
@@ -1219,11 +1215,11 @@
1215 ** Show the number of hash collisions for hash prefixes of various lengths.
1216 */
1217 void hash_collisions_webpage(void){
1218 login_check_credentials();
1219 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1220 style_header("Hash Prefix Collisions");
1221 style_submenu_element("Activity Reports", "reports");
1222 style_submenu_element("Stats", "stat");
1223 @ <h1>Hash Prefix Collisions on Check-ins</h1>
1224 collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1225 " FROM event WHERE event.type='ci'"
1226
+2 -2
--- src/printf.c
+++ src/printf.c
@@ -24,11 +24,11 @@
2424
# include <io.h>
2525
# include <fcntl.h>
2626
#endif
2727
#include <time.h>
2828
29
-/* Two custom conversions are used to show a prefix of SHA1 hashes:
29
+/* Two custom conversions are used to show a prefix of artifact hashes:
3030
**
3131
** %!S Prefix of a length appropriate for URLs
3232
** %S Prefix of a length appropriate for human display
3333
**
3434
** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
@@ -44,11 +44,11 @@
4444
#ifndef FOSSIL_HASH_DIGITS_URL
4545
# define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */
4646
#endif
4747
4848
/*
49
-** Return the number of SHA1 hash digits to display. The number is for
49
+** Return the number of artifact hash digits to display. The number is for
5050
** human output if the bForUrl is false and is destined for a URL if
5151
** bForUrl is false.
5252
*/
5353
static int hashDigits(int bForUrl){
5454
static int nDigitHuman = 0;
5555
--- src/printf.c
+++ src/printf.c
@@ -24,11 +24,11 @@
24 # include <io.h>
25 # include <fcntl.h>
26 #endif
27 #include <time.h>
28
29 /* Two custom conversions are used to show a prefix of SHA1 hashes:
30 **
31 ** %!S Prefix of a length appropriate for URLs
32 ** %S Prefix of a length appropriate for human display
33 **
34 ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
@@ -44,11 +44,11 @@
44 #ifndef FOSSIL_HASH_DIGITS_URL
45 # define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */
46 #endif
47
48 /*
49 ** Return the number of SHA1 hash digits to display. The number is for
50 ** human output if the bForUrl is false and is destined for a URL if
51 ** bForUrl is false.
52 */
53 static int hashDigits(int bForUrl){
54 static int nDigitHuman = 0;
55
--- src/printf.c
+++ src/printf.c
@@ -24,11 +24,11 @@
24 # include <io.h>
25 # include <fcntl.h>
26 #endif
27 #include <time.h>
28
29 /* Two custom conversions are used to show a prefix of artifact hashes:
30 **
31 ** %!S Prefix of a length appropriate for URLs
32 ** %S Prefix of a length appropriate for human display
33 **
34 ** The following macros help determine those lengths. FOSSIL_HASH_DIGITS
@@ -44,11 +44,11 @@
44 #ifndef FOSSIL_HASH_DIGITS_URL
45 # define FOSSIL_HASH_DIGITS_URL 16 /* For %!S (embedded in URLs) */
46 #endif
47
48 /*
49 ** Return the number of artifact hash digits to display. The number is for
50 ** human output if the bForUrl is false and is destined for a URL if
51 ** bForUrl is false.
52 */
53 static int hashDigits(int bForUrl){
54 static int nDigitHuman = 0;
55
+7 -13
--- src/purge.c
+++ src/purge.c
@@ -43,11 +43,11 @@
4343
@ );
4444
@ CREATE TABLE IF NOT EXISTS "%w".purgeitem(
4545
@ piid INTEGER PRIMARY KEY, -- ID for the purge item
4646
@ peid INTEGER REFERENCES purgeevent ON DELETE CASCADE, -- Purge event
4747
@ orid INTEGER, -- Original RID before purged
48
-@ uuid TEXT NOT NULL, -- SHA1 hash of the purged artifact
48
+@ uuid TEXT NOT NULL, -- hash of the purged artifact
4949
@ srcid INTEGER, -- Basis purgeitem for delta compression
5050
@ isPrivate BOOLEAN, -- True if artifact was originally private
5151
@ sz INT NOT NULL, -- Uncompressed size of the purged artifact
5252
@ desc TEXT, -- Brief description of this artifact
5353
@ data BLOB -- Compressed artifact content
@@ -347,11 +347,11 @@
347347
int piid, /* ID of the item to extract */
348348
Blob *pOut /* Write the content into this blob */
349349
){
350350
Stmt q;
351351
int srcid;
352
- Blob h1, h2, x;
352
+ Blob h1, x;
353353
static Bag busy;
354354
355355
db_prepare(&q, "SELECT uuid, srcid, data FROM purgeitem"
356356
" WHERE piid=%d", piid);
357357
if( db_step(&q)!=SQLITE_ROW ){
@@ -376,17 +376,14 @@
376376
blob_reset(&baseline);
377377
}
378378
bag_remove(&busy, piid);
379379
blob_zero(&h1);
380380
db_column_blob(&q, 0, &h1);
381
- sha1sum_blob(pOut, &h2);
382
- if( blob_compare(&h1, &h2)!=0 ){
383
- fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
384
- blob_str(&h1), blob_str(&h2));
381
+ if( hname_verify_hash(pOut, blob_buffer(&h1), blob_size(&h1))==0 ){
382
+ fossil_fatal("incorrect artifact hash on %b", &h1);
385383
}
386384
blob_reset(&h1);
387
- blob_reset(&h2);
388385
db_finalize(&q);
389386
return 0;
390387
}
391388
392389
/*
@@ -411,11 +408,11 @@
411408
" WHERE ix.srcid=%d"
412409
" AND ix.piid=purgeitem.piid;",
413410
iSrc
414411
);
415412
while( db_step(&q)==SQLITE_ROW ){
416
- Blob h1, h2, c1, c2;
413
+ Blob h1, c1, c2;
417414
int isPriv, rid;
418415
blob_zero(&h1);
419416
db_column_blob(&q, 0, &h1);
420417
blob_zero(&c1);
421418
db_column_blob(&q, 1, &c1);
@@ -425,16 +422,13 @@
425422
blob_delta_apply(pBasis, &c1, &c2);
426423
blob_reset(&c1);
427424
}else{
428425
c2 = c1;
429426
}
430
- sha1sum_blob(&c2, &h2);
431
- if( blob_compare(&h1, &h2)!=0 ){
432
- fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
433
- blob_str(&h1), blob_str(&h2));
427
+ if( hname_verify_hash(&c2, blob_buffer(&h1), blob_size(&h1))==0 ){
428
+ fossil_fatal("incorrect hash on %b", &h1);
434429
}
435
- blob_reset(&h2);
436430
isPriv = db_column_int(&q, 2);
437431
rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
438432
if( rid==0 ){
439433
fossil_fatal("%s", g.zErrMsg);
440434
}else{
441435
--- src/purge.c
+++ src/purge.c
@@ -43,11 +43,11 @@
43 @ );
44 @ CREATE TABLE IF NOT EXISTS "%w".purgeitem(
45 @ piid INTEGER PRIMARY KEY, -- ID for the purge item
46 @ peid INTEGER REFERENCES purgeevent ON DELETE CASCADE, -- Purge event
47 @ orid INTEGER, -- Original RID before purged
48 @ uuid TEXT NOT NULL, -- SHA1 hash of the purged artifact
49 @ srcid INTEGER, -- Basis purgeitem for delta compression
50 @ isPrivate BOOLEAN, -- True if artifact was originally private
51 @ sz INT NOT NULL, -- Uncompressed size of the purged artifact
52 @ desc TEXT, -- Brief description of this artifact
53 @ data BLOB -- Compressed artifact content
@@ -347,11 +347,11 @@
347 int piid, /* ID of the item to extract */
348 Blob *pOut /* Write the content into this blob */
349 ){
350 Stmt q;
351 int srcid;
352 Blob h1, h2, x;
353 static Bag busy;
354
355 db_prepare(&q, "SELECT uuid, srcid, data FROM purgeitem"
356 " WHERE piid=%d", piid);
357 if( db_step(&q)!=SQLITE_ROW ){
@@ -376,17 +376,14 @@
376 blob_reset(&baseline);
377 }
378 bag_remove(&busy, piid);
379 blob_zero(&h1);
380 db_column_blob(&q, 0, &h1);
381 sha1sum_blob(pOut, &h2);
382 if( blob_compare(&h1, &h2)!=0 ){
383 fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
384 blob_str(&h1), blob_str(&h2));
385 }
386 blob_reset(&h1);
387 blob_reset(&h2);
388 db_finalize(&q);
389 return 0;
390 }
391
392 /*
@@ -411,11 +408,11 @@
411 " WHERE ix.srcid=%d"
412 " AND ix.piid=purgeitem.piid;",
413 iSrc
414 );
415 while( db_step(&q)==SQLITE_ROW ){
416 Blob h1, h2, c1, c2;
417 int isPriv, rid;
418 blob_zero(&h1);
419 db_column_blob(&q, 0, &h1);
420 blob_zero(&c1);
421 db_column_blob(&q, 1, &c1);
@@ -425,16 +422,13 @@
425 blob_delta_apply(pBasis, &c1, &c2);
426 blob_reset(&c1);
427 }else{
428 c2 = c1;
429 }
430 sha1sum_blob(&c2, &h2);
431 if( blob_compare(&h1, &h2)!=0 ){
432 fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
433 blob_str(&h1), blob_str(&h2));
434 }
435 blob_reset(&h2);
436 isPriv = db_column_int(&q, 2);
437 rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
438 if( rid==0 ){
439 fossil_fatal("%s", g.zErrMsg);
440 }else{
441
--- src/purge.c
+++ src/purge.c
@@ -43,11 +43,11 @@
43 @ );
44 @ CREATE TABLE IF NOT EXISTS "%w".purgeitem(
45 @ piid INTEGER PRIMARY KEY, -- ID for the purge item
46 @ peid INTEGER REFERENCES purgeevent ON DELETE CASCADE, -- Purge event
47 @ orid INTEGER, -- Original RID before purged
48 @ uuid TEXT NOT NULL, -- hash of the purged artifact
49 @ srcid INTEGER, -- Basis purgeitem for delta compression
50 @ isPrivate BOOLEAN, -- True if artifact was originally private
51 @ sz INT NOT NULL, -- Uncompressed size of the purged artifact
52 @ desc TEXT, -- Brief description of this artifact
53 @ data BLOB -- Compressed artifact content
@@ -347,11 +347,11 @@
347 int piid, /* ID of the item to extract */
348 Blob *pOut /* Write the content into this blob */
349 ){
350 Stmt q;
351 int srcid;
352 Blob h1, x;
353 static Bag busy;
354
355 db_prepare(&q, "SELECT uuid, srcid, data FROM purgeitem"
356 " WHERE piid=%d", piid);
357 if( db_step(&q)!=SQLITE_ROW ){
@@ -376,17 +376,14 @@
376 blob_reset(&baseline);
377 }
378 bag_remove(&busy, piid);
379 blob_zero(&h1);
380 db_column_blob(&q, 0, &h1);
381 if( hname_verify_hash(pOut, blob_buffer(&h1), blob_size(&h1))==0 ){
382 fossil_fatal("incorrect artifact hash on %b", &h1);
 
 
383 }
384 blob_reset(&h1);
 
385 db_finalize(&q);
386 return 0;
387 }
388
389 /*
@@ -411,11 +408,11 @@
408 " WHERE ix.srcid=%d"
409 " AND ix.piid=purgeitem.piid;",
410 iSrc
411 );
412 while( db_step(&q)==SQLITE_ROW ){
413 Blob h1, c1, c2;
414 int isPriv, rid;
415 blob_zero(&h1);
416 db_column_blob(&q, 0, &h1);
417 blob_zero(&c1);
418 db_column_blob(&q, 1, &c1);
@@ -425,16 +422,13 @@
422 blob_delta_apply(pBasis, &c1, &c2);
423 blob_reset(&c1);
424 }else{
425 c2 = c1;
426 }
427 if( hname_verify_hash(&c2, blob_buffer(&h1), blob_size(&h1))==0 ){
428 fossil_fatal("incorrect hash on %b", &h1);
 
 
429 }
 
430 isPriv = db_column_int(&q, 2);
431 rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
432 if( rid==0 ){
433 fossil_fatal("%s", g.zErrMsg);
434 }else{
435
+106 -93
--- src/rebuild.c
+++ src/rebuild.c
@@ -21,76 +21,41 @@
2121
#include "rebuild.h"
2222
#include <assert.h>
2323
#include <errno.h>
2424
2525
/*
26
-** Make changes to the stable part of the schema (the part that is not
27
-** simply deleted and reconstructed on a rebuild) to bring the schema
28
-** up to the latest.
26
+** Update the schema as necessary
2927
*/
30
-static const char zSchemaUpdates1[] =
31
-@ -- Index on the delta table
32
-@ --
33
-@ CREATE INDEX IF NOT EXISTS delta_i1 ON delta(srcid);
34
-@
35
-@ -- Artifacts that should not be processed are identified in the
36
-@ -- "shun" table. Artifacts that are control-file forgeries or
37
-@ -- spam or artifacts whose contents violate administrative policy
38
-@ -- can be shunned in order to prevent them from contaminating
39
-@ -- the repository.
40
-@ --
41
-@ -- Shunned artifacts do not exist in the blob table. Hence they
42
-@ -- have not artifact ID (rid) and we thus must store their full
43
-@ -- UUID.
44
-@ --
45
-@ CREATE TABLE IF NOT EXISTS shun(
46
-@ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form
47
-@ mtime INTEGER, -- When added. Seconds since 1970
48
-@ scom TEXT -- Optional text explaining why the shun occurred
49
-@ );
50
-@
51
-@ -- Artifacts that should not be pushed are stored in the "private"
52
-@ -- table.
53
-@ --
54
-@ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY);
55
-@
56
-@ -- Some ticket content (such as the originators email address or contact
57
-@ -- information) needs to be obscured to protect privacy. This is achieved
58
-@ -- by storing an SHA1 hash of the content. For display, the hash is
59
-@ -- mapped back into the original text using this table.
60
-@ --
61
-@ -- This table contains sensitive information and should not be shared
62
-@ -- with unauthorized users.
63
-@ --
64
-@ CREATE TABLE IF NOT EXISTS concealed(
65
-@ hash TEXT PRIMARY KEY, -- The SHA1 hash of content
66
-@ mtime INTEGER, -- Time created. Seconds since 1970
67
-@ content TEXT -- Content intended to be concealed
68
-@ );
69
-;
70
-static const char zSchemaUpdates2[] =
71
-@ -- An entry in this table describes a database query that generates a
72
-@ -- table of tickets.
73
-@ --
74
-@ CREATE TABLE IF NOT EXISTS reportfmt(
75
-@ rn INTEGER PRIMARY KEY, -- Report number
76
-@ owner TEXT, -- Owner of this report format (not used)
77
-@ title TEXT UNIQUE, -- Title of this report
78
-@ mtime INTEGER, -- Time last modified. Seconds since 1970
79
-@ cols TEXT, -- A color-key specification
80
-@ sqlcode TEXT -- An SQL SELECT statement for this report
81
-@ );
82
-;
83
-
8428
static void rebuild_update_schema(void){
85
- int rc;
86
- db_multi_exec("%s", zSchemaUpdates1 /*safe-for-%s*/);
87
- db_multi_exec("%s", zSchemaUpdates2 /*safe-for-%s*/);
29
+ /* Verify that the PLINK table has a new column added by the
30
+ ** 2014-11-28 schema change. Create it if necessary. This code
31
+ ** can be removed in the future, once all users have upgraded to the
32
+ ** 2014-11-28 or later schema.
33
+ */
34
+ if( !db_table_has_column("repository","plink","baseid") ){
35
+ db_multi_exec(
36
+ "ALTER TABLE repository.plink ADD COLUMN baseid;"
37
+ );
38
+ }
39
+
40
+ /* Verify that the MLINK table has the newer columns added by the
41
+ ** 2015-01-24 schema change. Create them if necessary. This code
42
+ ** can be removed in the future, once all users have upgraded to the
43
+ ** 2015-01-24 or later schema.
44
+ */
45
+ if( !db_table_has_column("repository","mlink","isaux") ){
46
+ db_begin_transaction();
47
+ db_multi_exec(
48
+ "ALTER TABLE repository.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
49
+ "ALTER TABLE repository.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;"
50
+ );
51
+ db_end_transaction(0);
52
+ }
8853
89
- rc = db_exists("SELECT 1 FROM sqlite_master"
90
- " WHERE name='user' AND sql GLOB '* mtime *'");
91
- if( rc==0 ){
54
+ /* Add the user.mtime column if it is missing. (2011-04-27)
55
+ */
56
+ if( !db_table_has_column("repository", "user", "mtime") ){
9257
db_multi_exec(
9358
"CREATE TEMP TABLE temp_user AS SELECT * FROM user;"
9459
"DROP TABLE user;"
9560
"CREATE TABLE user(\n"
9661
" uid INTEGER PRIMARY KEY,\n"
@@ -109,54 +74,99 @@
10974
" ipaddr, cexpire, info, now(), photo FROM temp_user;"
11075
"DROP TABLE temp_user;"
11176
);
11277
}
11378
114
- rc = db_exists("SELECT 1 FROM sqlite_master"
115
- " WHERE name='config' AND sql GLOB '* mtime *'");
116
- if( rc==0 ){
79
+ /* Add the config.mtime column if it is missing. (2011-04-27)
80
+ */
81
+ if( !db_table_has_column("repository", "config", "mtime") ){
11782
db_multi_exec(
11883
"ALTER TABLE config ADD COLUMN mtime INTEGER;"
11984
"UPDATE config SET mtime=now();"
12085
);
12186
}
12287
123
- rc = db_exists("SELECT 1 FROM sqlite_master"
124
- " WHERE name='shun' AND sql GLOB '* mtime *'");
125
- if( rc==0 ){
88
+ /* Add the shun.mtime and shun.scom columns if they are missing.
89
+ ** (2011-04-27)
90
+ */
91
+ if( !db_table_has_column("repository", "shun", "mtime") ){
12692
db_multi_exec(
12793
"ALTER TABLE shun ADD COLUMN mtime INTEGER;"
12894
"ALTER TABLE shun ADD COLUMN scom TEXT;"
12995
"UPDATE shun SET mtime=now();"
13096
);
13197
}
13298
133
- rc = db_exists("SELECT 1 FROM sqlite_master"
134
- " WHERE name='reportfmt' AND sql GLOB '* mtime *'");
135
- if( rc==0 ){
99
+ /* Add the reportfmt.mtime column if it is missing. (2011-04-27)
100
+ */
101
+ if( !db_table_has_column("repository", "reportfmt", "mtime") ){
102
+ static const char zCreateReportFmtTable[] =
103
+ @ -- An entry in this table describes a database query that generates a
104
+ @ -- table of tickets.
105
+ @ --
106
+ @ CREATE TABLE IF NOT EXISTS reportfmt(
107
+ @ rn INTEGER PRIMARY KEY, -- Report number
108
+ @ owner TEXT, -- Owner of this report format (not used)
109
+ @ title TEXT UNIQUE, -- Title of this report
110
+ @ mtime INTEGER, -- Time last modified. Seconds since 1970
111
+ @ cols TEXT, -- A color-key specification
112
+ @ sqlcode TEXT -- An SQL SELECT statement for this report
113
+ @ );
114
+ ;
136115
db_multi_exec(
137116
"CREATE TEMP TABLE old_fmt AS SELECT * FROM reportfmt;"
138117
"DROP TABLE reportfmt;"
139118
);
140
- db_multi_exec("%s", zSchemaUpdates2/*safe-for-%s*/);
119
+ db_multi_exec("%s", zCreateReportFmtTable/*safe-for-%s*/);
141120
db_multi_exec(
142121
"INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
143122
" SELECT rn, owner, title, cols, sqlcode, now() FROM old_fmt;"
144123
"INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
145124
" SELECT rn, owner, title || ' (' || rn || ')', cols, sqlcode, now()"
146125
" FROM old_fmt;"
147126
);
148127
}
149128
150
- rc = db_exists("SELECT 1 FROM sqlite_master"
151
- " WHERE name='concealed' AND sql GLOB '* mtime *'");
152
- if( rc==0 ){
129
+ /* Add the concealed.mtime column if it is missing. (2011-04-27)
130
+ */
131
+ if( !db_table_has_column("repository", "concealed", "mtime") ){
153132
db_multi_exec(
154133
"ALTER TABLE concealed ADD COLUMN mtime INTEGER;"
155134
"UPDATE concealed SET mtime=now();"
156135
);
157136
}
137
+
138
+ /* Do the fossil-2.0 updates to the schema. (2017-02-28)
139
+ */
140
+ rebuild_schema_update_2_0();
141
+}
142
+
143
+/*
144
+** Update the repository schema for Fossil version 2.0. (2017-02-28)
145
+** (1) Change the CHECK constraint on BLOB.UUID so that the length
146
+** is greater than or equal to 40, not exactly equal to 40.
147
+*/
148
+void rebuild_schema_update_2_0(void){
149
+ char *z = db_text(0, "SELECT sql FROM repository.sqlite_master WHERE name='blob'");
150
+ if( z ){
151
+ /* Search for: length(uuid)==40
152
+ ** 0123456789 12345 */
153
+ int i;
154
+ for(i=10; z[i]; i++){
155
+ if( z[i]=='=' && strncmp(&z[i-6],"(uuid)==40",10)==0 ){
156
+ z[i] = '>';
157
+ db_multi_exec(
158
+ "PRAGMA writable_schema=ON;"
159
+ "UPDATE repository.sqlite_master SET sql=%Q WHERE name LIKE 'blob';"
160
+ "PRAGMA writable_schema=OFF;",
161
+ z
162
+ );
163
+ break;
164
+ }
165
+ }
166
+ fossil_free(z);
167
+ }
158168
}
159169
160170
/*
161171
** Variables used to store state information about an on-going "rebuild"
162172
** or "deconstruct".
@@ -330,37 +340,40 @@
330340
** extracted in a random order. This feature is used to test the
331341
** ability of fossil to accept records in any order and still
332342
** construct a sane repository.
333343
*/
334344
int rebuild_db(int randomize, int doOut, int doClustering){
335
- Stmt s;
345
+ Stmt s, q;
336346
int errCnt = 0;
337347
char *zTable;
338348
int incrSize;
349
+ Blob sql;
339350
340351
bag_init(&bagDone);
341352
ttyOutput = doOut;
342353
processCnt = 0;
343354
if (ttyOutput && !g.fQuiet) {
344355
percent_complete(0);
345356
}
346357
rebuild_update_schema();
347
- for(;;){
348
- zTable = db_text(0,
349
- "SELECT name FROM sqlite_master /*scan*/"
350
- " WHERE type='table'"
351
- " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user',"
352
- "'config','shun','private','reportfmt',"
353
- "'concealed','accesslog','modreq',"
354
- "'purgeevent','purgeitem','unversioned')"
355
- " AND name NOT GLOB 'sqlite_*'"
356
- " AND name NOT GLOB 'fx_*'"
357
- );
358
- if( zTable==0 ) break;
359
- db_multi_exec("DROP TABLE %Q", zTable);
360
- free(zTable);
361
- }
358
+ blob_init(&sql, 0, 0);
359
+ db_prepare(&q,
360
+ "SELECT name FROM sqlite_master /*scan*/"
361
+ " WHERE type='table'"
362
+ " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
363
+ "'config','shun','private','reportfmt',"
364
+ "'concealed','accesslog','modreq',"
365
+ "'purgeevent','purgeitem','unversioned')"
366
+ " AND name NOT GLOB 'sqlite_*'"
367
+ " AND name NOT GLOB 'fx_*'"
368
+ );
369
+ while( db_step(&q)==SQLITE_ROW ){
370
+ blob_appendf(&sql, "DROP TABLE \"%w\";\n", db_column_text(&q,0));
371
+ }
372
+ db_finalize(&q);
373
+ db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
374
+ blob_reset(&sql);
362375
db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
363376
ticket_create_table(0);
364377
shun_artifacts();
365378
366379
db_multi_exec(
@@ -994,11 +1007,11 @@
9941007
**
9951008
**
9961009
** This command exports all artifacts of a given repository and
9971010
** writes all artifacts to the file system. The DESTINATION directory
9981011
** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
999
-** AABBBBBBBBB.. is the 40 character artifact ID, AA the first 2 characters.
1012
+** AABBBBBBBBB.. is the 40+ character artifact ID, AA the first 2 characters.
10001013
** If -L|--prefixlength is given, the length (default 2) of the directory
10011014
** prefix can be set to 0,1,..,9 characters.
10021015
**
10031016
** Options:
10041017
** -R|--repository REPOSITORY deconstruct given REPOSITORY
10051018
--- src/rebuild.c
+++ src/rebuild.c
@@ -21,76 +21,41 @@
21 #include "rebuild.h"
22 #include <assert.h>
23 #include <errno.h>
24
25 /*
26 ** Make changes to the stable part of the schema (the part that is not
27 ** simply deleted and reconstructed on a rebuild) to bring the schema
28 ** up to the latest.
29 */
30 static const char zSchemaUpdates1[] =
31 @ -- Index on the delta table
32 @ --
33 @ CREATE INDEX IF NOT EXISTS delta_i1 ON delta(srcid);
34 @
35 @ -- Artifacts that should not be processed are identified in the
36 @ -- "shun" table. Artifacts that are control-file forgeries or
37 @ -- spam or artifacts whose contents violate administrative policy
38 @ -- can be shunned in order to prevent them from contaminating
39 @ -- the repository.
40 @ --
41 @ -- Shunned artifacts do not exist in the blob table. Hence they
42 @ -- have not artifact ID (rid) and we thus must store their full
43 @ -- UUID.
44 @ --
45 @ CREATE TABLE IF NOT EXISTS shun(
46 @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form
47 @ mtime INTEGER, -- When added. Seconds since 1970
48 @ scom TEXT -- Optional text explaining why the shun occurred
49 @ );
50 @
51 @ -- Artifacts that should not be pushed are stored in the "private"
52 @ -- table.
53 @ --
54 @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY);
55 @
56 @ -- Some ticket content (such as the originators email address or contact
57 @ -- information) needs to be obscured to protect privacy. This is achieved
58 @ -- by storing an SHA1 hash of the content. For display, the hash is
59 @ -- mapped back into the original text using this table.
60 @ --
61 @ -- This table contains sensitive information and should not be shared
62 @ -- with unauthorized users.
63 @ --
64 @ CREATE TABLE IF NOT EXISTS concealed(
65 @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content
66 @ mtime INTEGER, -- Time created. Seconds since 1970
67 @ content TEXT -- Content intended to be concealed
68 @ );
69 ;
70 static const char zSchemaUpdates2[] =
71 @ -- An entry in this table describes a database query that generates a
72 @ -- table of tickets.
73 @ --
74 @ CREATE TABLE IF NOT EXISTS reportfmt(
75 @ rn INTEGER PRIMARY KEY, -- Report number
76 @ owner TEXT, -- Owner of this report format (not used)
77 @ title TEXT UNIQUE, -- Title of this report
78 @ mtime INTEGER, -- Time last modified. Seconds since 1970
79 @ cols TEXT, -- A color-key specification
80 @ sqlcode TEXT -- An SQL SELECT statement for this report
81 @ );
82 ;
83
84 static void rebuild_update_schema(void){
85 int rc;
86 db_multi_exec("%s", zSchemaUpdates1 /*safe-for-%s*/);
87 db_multi_exec("%s", zSchemaUpdates2 /*safe-for-%s*/);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
89 rc = db_exists("SELECT 1 FROM sqlite_master"
90 " WHERE name='user' AND sql GLOB '* mtime *'");
91 if( rc==0 ){
92 db_multi_exec(
93 "CREATE TEMP TABLE temp_user AS SELECT * FROM user;"
94 "DROP TABLE user;"
95 "CREATE TABLE user(\n"
96 " uid INTEGER PRIMARY KEY,\n"
@@ -109,54 +74,99 @@
109 " ipaddr, cexpire, info, now(), photo FROM temp_user;"
110 "DROP TABLE temp_user;"
111 );
112 }
113
114 rc = db_exists("SELECT 1 FROM sqlite_master"
115 " WHERE name='config' AND sql GLOB '* mtime *'");
116 if( rc==0 ){
117 db_multi_exec(
118 "ALTER TABLE config ADD COLUMN mtime INTEGER;"
119 "UPDATE config SET mtime=now();"
120 );
121 }
122
123 rc = db_exists("SELECT 1 FROM sqlite_master"
124 " WHERE name='shun' AND sql GLOB '* mtime *'");
125 if( rc==0 ){
 
126 db_multi_exec(
127 "ALTER TABLE shun ADD COLUMN mtime INTEGER;"
128 "ALTER TABLE shun ADD COLUMN scom TEXT;"
129 "UPDATE shun SET mtime=now();"
130 );
131 }
132
133 rc = db_exists("SELECT 1 FROM sqlite_master"
134 " WHERE name='reportfmt' AND sql GLOB '* mtime *'");
135 if( rc==0 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
136 db_multi_exec(
137 "CREATE TEMP TABLE old_fmt AS SELECT * FROM reportfmt;"
138 "DROP TABLE reportfmt;"
139 );
140 db_multi_exec("%s", zSchemaUpdates2/*safe-for-%s*/);
141 db_multi_exec(
142 "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
143 " SELECT rn, owner, title, cols, sqlcode, now() FROM old_fmt;"
144 "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
145 " SELECT rn, owner, title || ' (' || rn || ')', cols, sqlcode, now()"
146 " FROM old_fmt;"
147 );
148 }
149
150 rc = db_exists("SELECT 1 FROM sqlite_master"
151 " WHERE name='concealed' AND sql GLOB '* mtime *'");
152 if( rc==0 ){
153 db_multi_exec(
154 "ALTER TABLE concealed ADD COLUMN mtime INTEGER;"
155 "UPDATE concealed SET mtime=now();"
156 );
157 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158 }
159
160 /*
161 ** Variables used to store state information about an on-going "rebuild"
162 ** or "deconstruct".
@@ -330,37 +340,40 @@
330 ** extracted in a random order. This feature is used to test the
331 ** ability of fossil to accept records in any order and still
332 ** construct a sane repository.
333 */
334 int rebuild_db(int randomize, int doOut, int doClustering){
335 Stmt s;
336 int errCnt = 0;
337 char *zTable;
338 int incrSize;
 
339
340 bag_init(&bagDone);
341 ttyOutput = doOut;
342 processCnt = 0;
343 if (ttyOutput && !g.fQuiet) {
344 percent_complete(0);
345 }
346 rebuild_update_schema();
347 for(;;){
348 zTable = db_text(0,
349 "SELECT name FROM sqlite_master /*scan*/"
350 " WHERE type='table'"
351 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user',"
352 "'config','shun','private','reportfmt',"
353 "'concealed','accesslog','modreq',"
354 "'purgeevent','purgeitem','unversioned')"
355 " AND name NOT GLOB 'sqlite_*'"
356 " AND name NOT GLOB 'fx_*'"
357 );
358 if( zTable==0 ) break;
359 db_multi_exec("DROP TABLE %Q", zTable);
360 free(zTable);
361 }
 
 
362 db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
363 ticket_create_table(0);
364 shun_artifacts();
365
366 db_multi_exec(
@@ -994,11 +1007,11 @@
994 **
995 **
996 ** This command exports all artifacts of a given repository and
997 ** writes all artifacts to the file system. The DESTINATION directory
998 ** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
999 ** AABBBBBBBBB.. is the 40 character artifact ID, AA the first 2 characters.
1000 ** If -L|--prefixlength is given, the length (default 2) of the directory
1001 ** prefix can be set to 0,1,..,9 characters.
1002 **
1003 ** Options:
1004 ** -R|--repository REPOSITORY deconstruct given REPOSITORY
1005
--- src/rebuild.c
+++ src/rebuild.c
@@ -21,76 +21,41 @@
21 #include "rebuild.h"
22 #include <assert.h>
23 #include <errno.h>
24
25 /*
26 ** Update the schema as necessary
 
 
27 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28 static void rebuild_update_schema(void){
29 /* Verify that the PLINK table has a new column added by the
30 ** 2014-11-28 schema change. Create it if necessary. This code
31 ** can be removed in the future, once all users have upgraded to the
32 ** 2014-11-28 or later schema.
33 */
34 if( !db_table_has_column("repository","plink","baseid") ){
35 db_multi_exec(
36 "ALTER TABLE repository.plink ADD COLUMN baseid;"
37 );
38 }
39
40 /* Verify that the MLINK table has the newer columns added by the
41 ** 2015-01-24 schema change. Create them if necessary. This code
42 ** can be removed in the future, once all users have upgraded to the
43 ** 2015-01-24 or later schema.
44 */
45 if( !db_table_has_column("repository","mlink","isaux") ){
46 db_begin_transaction();
47 db_multi_exec(
48 "ALTER TABLE repository.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
49 "ALTER TABLE repository.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;"
50 );
51 db_end_transaction(0);
52 }
53
54 /* Add the user.mtime column if it is missing. (2011-04-27)
55 */
56 if( !db_table_has_column("repository", "user", "mtime") ){
57 db_multi_exec(
58 "CREATE TEMP TABLE temp_user AS SELECT * FROM user;"
59 "DROP TABLE user;"
60 "CREATE TABLE user(\n"
61 " uid INTEGER PRIMARY KEY,\n"
@@ -109,54 +74,99 @@
74 " ipaddr, cexpire, info, now(), photo FROM temp_user;"
75 "DROP TABLE temp_user;"
76 );
77 }
78
79 /* Add the config.mtime column if it is missing. (2011-04-27)
80 */
81 if( !db_table_has_column("repository", "config", "mtime") ){
82 db_multi_exec(
83 "ALTER TABLE config ADD COLUMN mtime INTEGER;"
84 "UPDATE config SET mtime=now();"
85 );
86 }
87
88 /* Add the shun.mtime and shun.scom columns if they are missing.
89 ** (2011-04-27)
90 */
91 if( !db_table_has_column("repository", "shun", "mtime") ){
92 db_multi_exec(
93 "ALTER TABLE shun ADD COLUMN mtime INTEGER;"
94 "ALTER TABLE shun ADD COLUMN scom TEXT;"
95 "UPDATE shun SET mtime=now();"
96 );
97 }
98
99 /* Add the reportfmt.mtime column if it is missing. (2011-04-27)
100 */
101 if( !db_table_has_column("repository", "reportfmt", "mtime") ){
102 static const char zCreateReportFmtTable[] =
103 @ -- An entry in this table describes a database query that generates a
104 @ -- table of tickets.
105 @ --
106 @ CREATE TABLE IF NOT EXISTS reportfmt(
107 @ rn INTEGER PRIMARY KEY, -- Report number
108 @ owner TEXT, -- Owner of this report format (not used)
109 @ title TEXT UNIQUE, -- Title of this report
110 @ mtime INTEGER, -- Time last modified. Seconds since 1970
111 @ cols TEXT, -- A color-key specification
112 @ sqlcode TEXT -- An SQL SELECT statement for this report
113 @ );
114 ;
115 db_multi_exec(
116 "CREATE TEMP TABLE old_fmt AS SELECT * FROM reportfmt;"
117 "DROP TABLE reportfmt;"
118 );
119 db_multi_exec("%s", zCreateReportFmtTable/*safe-for-%s*/);
120 db_multi_exec(
121 "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
122 " SELECT rn, owner, title, cols, sqlcode, now() FROM old_fmt;"
123 "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)"
124 " SELECT rn, owner, title || ' (' || rn || ')', cols, sqlcode, now()"
125 " FROM old_fmt;"
126 );
127 }
128
129 /* Add the concealed.mtime column if it is missing. (2011-04-27)
130 */
131 if( !db_table_has_column("repository", "concealed", "mtime") ){
132 db_multi_exec(
133 "ALTER TABLE concealed ADD COLUMN mtime INTEGER;"
134 "UPDATE concealed SET mtime=now();"
135 );
136 }
137
138 /* Do the fossil-2.0 updates to the schema. (2017-02-28)
139 */
140 rebuild_schema_update_2_0();
141 }
142
143 /*
144 ** Update the repository schema for Fossil version 2.0. (2017-02-28)
145 ** (1) Change the CHECK constraint on BLOB.UUID so that the length
146 ** is greater than or equal to 40, not exactly equal to 40.
147 */
148 void rebuild_schema_update_2_0(void){
149 char *z = db_text(0, "SELECT sql FROM repository.sqlite_master WHERE name='blob'");
150 if( z ){
151 /* Search for: length(uuid)==40
152 ** 0123456789 12345 */
153 int i;
154 for(i=10; z[i]; i++){
155 if( z[i]=='=' && strncmp(&z[i-6],"(uuid)==40",10)==0 ){
156 z[i] = '>';
157 db_multi_exec(
158 "PRAGMA writable_schema=ON;"
159 "UPDATE repository.sqlite_master SET sql=%Q WHERE name LIKE 'blob';"
160 "PRAGMA writable_schema=OFF;",
161 z
162 );
163 break;
164 }
165 }
166 fossil_free(z);
167 }
168 }
169
170 /*
171 ** Variables used to store state information about an on-going "rebuild"
172 ** or "deconstruct".
@@ -330,37 +340,40 @@
340 ** extracted in a random order. This feature is used to test the
341 ** ability of fossil to accept records in any order and still
342 ** construct a sane repository.
343 */
344 int rebuild_db(int randomize, int doOut, int doClustering){
345 Stmt s, q;
346 int errCnt = 0;
347 char *zTable;
348 int incrSize;
349 Blob sql;
350
351 bag_init(&bagDone);
352 ttyOutput = doOut;
353 processCnt = 0;
354 if (ttyOutput && !g.fQuiet) {
355 percent_complete(0);
356 }
357 rebuild_update_schema();
358 blob_init(&sql, 0, 0);
359 db_prepare(&q,
360 "SELECT name FROM sqlite_master /*scan*/"
361 " WHERE type='table'"
362 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
363 "'config','shun','private','reportfmt',"
364 "'concealed','accesslog','modreq',"
365 "'purgeevent','purgeitem','unversioned')"
366 " AND name NOT GLOB 'sqlite_*'"
367 " AND name NOT GLOB 'fx_*'"
368 );
369 while( db_step(&q)==SQLITE_ROW ){
370 blob_appendf(&sql, "DROP TABLE \"%w\";\n", db_column_text(&q,0));
371 }
372 db_finalize(&q);
373 db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
374 blob_reset(&sql);
375 db_multi_exec("%s", zRepositorySchema2/*safe-for-%s*/);
376 ticket_create_table(0);
377 shun_artifacts();
378
379 db_multi_exec(
@@ -994,11 +1007,11 @@
1007 **
1008 **
1009 ** This command exports all artifacts of a given repository and
1010 ** writes all artifacts to the file system. The DESTINATION directory
1011 ** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
1012 ** AABBBBBBBBB.. is the 40+ character artifact ID, AA the first 2 characters.
1013 ** If -L|--prefixlength is given, the length (default 2) of the directory
1014 ** prefix can be set to 0,1,..,9 characters.
1015 **
1016 ** Options:
1017 ** -R|--repository REPOSITORY deconstruct given REPOSITORY
1018
+2 -2
--- src/schema.c
+++ src/schema.c
@@ -79,13 +79,13 @@
7979
@ --
8080
@ CREATE TABLE blob(
8181
@ rid INTEGER PRIMARY KEY, -- Record ID
8282
@ rcvid INTEGER, -- Origin of this record
8383
@ size INTEGER, -- Size of content. -1 for a phantom.
84
-@ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content
84
+@ uuid TEXT UNIQUE NOT NULL, -- hash of the content
8585
@ content BLOB, -- Compressed content of this record
86
-@ CHECK( length(uuid)==40 AND rid>0 )
86
+@ CHECK( length(uuid)>=40 AND rid>0 )
8787
@ );
8888
@ CREATE TABLE delta(
8989
@ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
9090
@ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
9191
@ );
9292
--- src/schema.c
+++ src/schema.c
@@ -79,13 +79,13 @@
79 @ --
80 @ CREATE TABLE blob(
81 @ rid INTEGER PRIMARY KEY, -- Record ID
82 @ rcvid INTEGER, -- Origin of this record
83 @ size INTEGER, -- Size of content. -1 for a phantom.
84 @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content
85 @ content BLOB, -- Compressed content of this record
86 @ CHECK( length(uuid)==40 AND rid>0 )
87 @ );
88 @ CREATE TABLE delta(
89 @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
90 @ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
91 @ );
92
--- src/schema.c
+++ src/schema.c
@@ -79,13 +79,13 @@
79 @ --
80 @ CREATE TABLE blob(
81 @ rid INTEGER PRIMARY KEY, -- Record ID
82 @ rcvid INTEGER, -- Origin of this record
83 @ size INTEGER, -- Size of content. -1 for a phantom.
84 @ uuid TEXT UNIQUE NOT NULL, -- hash of the content
85 @ content BLOB, -- Compressed content of this record
86 @ CHECK( length(uuid)>=40 AND rid>0 )
87 @ );
88 @ CREATE TABLE delta(
89 @ rid INTEGER PRIMARY KEY, -- BLOB that is delta-compressed
90 @ srcid INTEGER NOT NULL REFERENCES blob -- Baseline for delta-compression
91 @ );
92
+16
--- src/sha1.c
+++ src/sha1.c
@@ -1,6 +1,22 @@
11
/*
2
+** Copyright (c) 2006 D. Richard Hipp
3
+**
4
+** This program is free software; you can redistribute it and/or
5
+** modify it under the terms of the Simplified BSD License (also
6
+** known as the "2-Clause License" or "FreeBSD License".)
7
+**
8
+** This program is distributed in the hope that it will be useful,
9
+** but without any warranty; without even the implied warranty of
10
+** merchantability or fitness for a particular purpose.
11
+**
12
+** Author contact information:
13
+** [email protected]
14
+** http://www.hwaci.com/drh/
15
+**
16
+*******************************************************************************
17
+**
218
** This implementation of SHA1.
319
*/
420
#include "config.h"
521
#include <sys/types.h>
622
#include "sha1.h"
723
--- src/sha1.c
+++ src/sha1.c
@@ -1,6 +1,22 @@
1 /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2 ** This implementation of SHA1.
3 */
4 #include "config.h"
5 #include <sys/types.h>
6 #include "sha1.h"
7
--- src/sha1.c
+++ src/sha1.c
@@ -1,6 +1,22 @@
1 /*
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This implementation of SHA1.
19 */
20 #include "config.h"
21 #include <sys/types.h>
22 #include "sha1.h"
23
+20 -4
--- src/sha3.c
+++ src/sha3.c
@@ -1,6 +1,22 @@
11
/*
2
+** Copyright (c) 2017 D. Richard Hipp
3
+**
4
+** This program is free software; you can redistribute it and/or
5
+** modify it under the terms of the Simplified BSD License (also
6
+** known as the "2-Clause License" or "FreeBSD License".)
7
+**
8
+** This program is distributed in the hope that it will be useful,
9
+** but without any warranty; without even the implied warranty of
10
+** merchantability or fitness for a particular purpose.
11
+**
12
+** Author contact information:
13
+** [email protected]
14
+** http://www.hwaci.com/drh/
15
+**
16
+*******************************************************************************
17
+**
218
** This file contains an implementation of SHA3 (Keccak) hashing.
319
*/
420
#include "config.h"
521
#include "sha3.h"
622
@@ -401,11 +417,11 @@
401417
unsigned int nData
402418
){
403419
unsigned int i = 0;
404420
#if SHA3_BYTEORDER==1234
405421
if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
406
- for(; i<nData-7; i+=8){
422
+ for(; i+7<nData; i+=8){
407423
p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
408424
p->nLoaded += 8;
409425
if( p->nLoaded>=p->nRate ){
410426
KeccakF1600Step(p);
411427
p->nLoaded = 0;
@@ -608,22 +624,22 @@
608624
** Compute an SHA3 checksum of all files named on the command-line.
609625
** If a file is named "-" then take its content from standard input.
610626
**
611627
** Options:
612628
**
613
-** --224 Compute a SHA3-224 hash (the default)
614
-** --256 Compute a SHA3-256 hash
629
+** --224 Compute a SHA3-224 hash
630
+** --256 Compute a SHA3-256 hash (the default)
615631
** --384 Compute a SHA3-384 hash
616632
** --512 Compute a SHA3-512 hash
617633
** --size N An N-bit hash. N must be a multiple of 32 between 128
618634
** and 512.
619635
*/
620636
void sha3sum_test(void){
621637
int i;
622638
Blob in;
623639
Blob cksum;
624
- int iSize = 224;
640
+ int iSize = 256;
625641
626642
if( find_option("224",0,0)!=0 ) iSize = 224;
627643
else if( find_option("256",0,0)!=0 ) iSize = 256;
628644
else if( find_option("384",0,0)!=0 ) iSize = 384;
629645
else if( find_option("512",0,0)!=0 ) iSize = 512;
630646
--- src/sha3.c
+++ src/sha3.c
@@ -1,6 +1,22 @@
1 /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2 ** This file contains an implementation of SHA3 (Keccak) hashing.
3 */
4 #include "config.h"
5 #include "sha3.h"
6
@@ -401,11 +417,11 @@
401 unsigned int nData
402 ){
403 unsigned int i = 0;
404 #if SHA3_BYTEORDER==1234
405 if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
406 for(; i<nData-7; i+=8){
407 p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
408 p->nLoaded += 8;
409 if( p->nLoaded>=p->nRate ){
410 KeccakF1600Step(p);
411 p->nLoaded = 0;
@@ -608,22 +624,22 @@
608 ** Compute an SHA3 checksum of all files named on the command-line.
609 ** If a file is named "-" then take its content from standard input.
610 **
611 ** Options:
612 **
613 ** --224 Compute a SHA3-224 hash (the default)
614 ** --256 Compute a SHA3-256 hash
615 ** --384 Compute a SHA3-384 hash
616 ** --512 Compute a SHA3-512 hash
617 ** --size N An N-bit hash. N must be a multiple of 32 between 128
618 ** and 512.
619 */
620 void sha3sum_test(void){
621 int i;
622 Blob in;
623 Blob cksum;
624 int iSize = 224;
625
626 if( find_option("224",0,0)!=0 ) iSize = 224;
627 else if( find_option("256",0,0)!=0 ) iSize = 256;
628 else if( find_option("384",0,0)!=0 ) iSize = 384;
629 else if( find_option("512",0,0)!=0 ) iSize = 512;
630
--- src/sha3.c
+++ src/sha3.c
@@ -1,6 +1,22 @@
1 /*
2 ** Copyright (c) 2017 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains an implementation of SHA3 (Keccak) hashing.
19 */
20 #include "config.h"
21 #include "sha3.h"
22
@@ -401,11 +417,11 @@
417 unsigned int nData
418 ){
419 unsigned int i = 0;
420 #if SHA3_BYTEORDER==1234
421 if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
422 for(; i+7<nData; i+=8){
423 p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
424 p->nLoaded += 8;
425 if( p->nLoaded>=p->nRate ){
426 KeccakF1600Step(p);
427 p->nLoaded = 0;
@@ -608,22 +624,22 @@
624 ** Compute an SHA3 checksum of all files named on the command-line.
625 ** If a file is named "-" then take its content from standard input.
626 **
627 ** Options:
628 **
629 ** --224 Compute a SHA3-224 hash
630 ** --256 Compute a SHA3-256 hash (the default)
631 ** --384 Compute a SHA3-384 hash
632 ** --512 Compute a SHA3-512 hash
633 ** --size N An N-bit hash. N must be a multiple of 32 between 128
634 ** and 512.
635 */
636 void sha3sum_test(void){
637 int i;
638 Blob in;
639 Blob cksum;
640 int iSize = 256;
641
642 if( find_option("224",0,0)!=0 ) iSize = 224;
643 else if( find_option("256",0,0)!=0 ) iSize = 256;
644 else if( find_option("384",0,0)!=0 ) iSize = 384;
645 else if( find_option("512",0,0)!=0 ) iSize = 512;
646
+13 -13
--- src/shun.c
+++ src/shun.c
@@ -36,11 +36,11 @@
3636
}
3737
3838
/*
3939
** WEBPAGE: shun
4040
**
41
-** View the SHA1 hashes of all shunned artifacts. Add new hashes
41
+** View the hashes of all shunned artifacts. Add new hashes
4242
** to the shun set. Requires Admin privilege.
4343
*/
4444
void shun_page(void){
4545
Stmt q;
4646
int cnt = 0;
@@ -84,18 +84,18 @@
8484
}
8585
zCanonical[j+1] = zCanonical[j] = 0;
8686
p = zCanonical;
8787
while( *p ){
8888
int nUuid = strlen(p);
89
- if( nUuid!=UUID_SIZE || !validate16(p, nUuid) ){
89
+ if( !hname_validate(p, nUuid) ){
9090
@ <p class="generalError">Error: Bad artifact IDs.</p>
9191
fossil_free(zCanonical);
9292
zCanonical = 0;
9393
break;
9494
}else{
95
- canonical16(p, UUID_SIZE);
96
- p += UUID_SIZE+1;
95
+ canonical16(p, nUuid);
96
+ p += nUuid+1;
9797
}
9898
}
9999
zUuid = zCanonical;
100100
}
101101
style_header("Shunned Artifacts");
@@ -107,21 +107,21 @@
107107
db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
108108
if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
109109
allExist = 0;
110110
}
111111
admin_log("Unshunned %Q", p);
112
- p += UUID_SIZE+1;
112
+ p += strlen(p)+1;
113113
}
114114
if( allExist ){
115115
@ <p class="noMoreShun">Artifact(s)<br />
116
- for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
116
+ for( p = zUuid ; *p ; p += strlen(p)+1 ){
117117
@ <a href="%R/artifact/%s(p)">%s(p)</a><br />
118118
}
119119
@ are no longer being shunned.</p>
120120
}else{
121121
@ <p class="noMoreShun">Artifact(s)<br />
122
- for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
122
+ for( p = zUuid ; *p ; p += strlen(p)+1 ){
123123
@ %s(p)<br />
124124
}
125125
@ will no longer be shunned. But they may not exist in the repository.
126126
@ It may be necessary to rebuild the repository using the
127127
@ <b>fossil rebuild</b> command-line before the artifact content
@@ -146,14 +146,14 @@
146146
db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p);
147147
db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid);
148148
db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid);
149149
}
150150
admin_log("Shunned %Q", p);
151
- p += UUID_SIZE+1;
151
+ p += strlen(p)+1;
152152
}
153153
@ <p class="shunned">Artifact(s)<br />
154
- for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
154
+ for( p = zUuid ; *p ; p += strlen(p)+1 ){
155155
@ <a href="%R/artifact/%s(p)">%s(p)</a><br />
156156
}
157157
@ have been shunned. They will no longer be pushed.
158158
@ They will be removed from the repository the next time the repository
159159
@ is rebuilt using the <b>fossil rebuild</b> command-line</p>
@@ -167,18 +167,18 @@
167167
@ artifact content will be purged from the repository the next time the
168168
@ repository is rebuilt. A list of shunned artifacts can be seen at the
169169
@ bottom of this page.</p>
170170
@
171171
@ <a name="addshun"></a>
172
- @ <p>To shun artifacts, enter their artifact IDs (the 40-character SHA1
173
- @ hash of the artifacts) in the
172
+ @ <p>To shun artifacts, enter their artifact hashes (the 40- or
173
+ @ 64-character lowercase hexadecimal hash of the artifact content) in the
174174
@ following box and press the "Shun" button. This will cause the artifacts
175175
@ to be removed from the repository and will prevent the artifacts from being
176176
@ readded to the repository by subsequent sync operation.</p>
177177
@
178
- @ <p>Note that you must enter the full 40-character artifact IDs, not
179
- @ an abbreviation or a symbolic tag.</p>
178
+ @ <p>Note that you must enter the full 40- or 64-character artifact hashes,
179
+ @ not an abbreviation or a symbolic tag.</p>
180180
@
181181
@ <p>Warning: Shunning should only be used to remove inappropriate content
182182
@ from the repository. Inappropriate content includes such things as
183183
@ spam added to Wiki, files that violate copyright or patent agreements,
184184
@ or artifacts that by design or accident interfere with the processing
185185
--- src/shun.c
+++ src/shun.c
@@ -36,11 +36,11 @@
36 }
37
38 /*
39 ** WEBPAGE: shun
40 **
41 ** View the SHA1 hashes of all shunned artifacts. Add new hashes
42 ** to the shun set. Requires Admin privilege.
43 */
44 void shun_page(void){
45 Stmt q;
46 int cnt = 0;
@@ -84,18 +84,18 @@
84 }
85 zCanonical[j+1] = zCanonical[j] = 0;
86 p = zCanonical;
87 while( *p ){
88 int nUuid = strlen(p);
89 if( nUuid!=UUID_SIZE || !validate16(p, nUuid) ){
90 @ <p class="generalError">Error: Bad artifact IDs.</p>
91 fossil_free(zCanonical);
92 zCanonical = 0;
93 break;
94 }else{
95 canonical16(p, UUID_SIZE);
96 p += UUID_SIZE+1;
97 }
98 }
99 zUuid = zCanonical;
100 }
101 style_header("Shunned Artifacts");
@@ -107,21 +107,21 @@
107 db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
108 if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
109 allExist = 0;
110 }
111 admin_log("Unshunned %Q", p);
112 p += UUID_SIZE+1;
113 }
114 if( allExist ){
115 @ <p class="noMoreShun">Artifact(s)<br />
116 for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
117 @ <a href="%R/artifact/%s(p)">%s(p)</a><br />
118 }
119 @ are no longer being shunned.</p>
120 }else{
121 @ <p class="noMoreShun">Artifact(s)<br />
122 for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
123 @ %s(p)<br />
124 }
125 @ will no longer be shunned. But they may not exist in the repository.
126 @ It may be necessary to rebuild the repository using the
127 @ <b>fossil rebuild</b> command-line before the artifact content
@@ -146,14 +146,14 @@
146 db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p);
147 db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid);
148 db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid);
149 }
150 admin_log("Shunned %Q", p);
151 p += UUID_SIZE+1;
152 }
153 @ <p class="shunned">Artifact(s)<br />
154 for( p = zUuid ; *p ; p += UUID_SIZE+1 ){
155 @ <a href="%R/artifact/%s(p)">%s(p)</a><br />
156 }
157 @ have been shunned. They will no longer be pushed.
158 @ They will be removed from the repository the next time the repository
159 @ is rebuilt using the <b>fossil rebuild</b> command-line</p>
@@ -167,18 +167,18 @@
167 @ artifact content will be purged from the repository the next time the
168 @ repository is rebuilt. A list of shunned artifacts can be seen at the
169 @ bottom of this page.</p>
170 @
171 @ <a name="addshun"></a>
172 @ <p>To shun artifacts, enter their artifact IDs (the 40-character SHA1
173 @ hash of the artifacts) in the
174 @ following box and press the "Shun" button. This will cause the artifacts
175 @ to be removed from the repository and will prevent the artifacts from being
176 @ readded to the repository by subsequent sync operation.</p>
177 @
178 @ <p>Note that you must enter the full 40-character artifact IDs, not
179 @ an abbreviation or a symbolic tag.</p>
180 @
181 @ <p>Warning: Shunning should only be used to remove inappropriate content
182 @ from the repository. Inappropriate content includes such things as
183 @ spam added to Wiki, files that violate copyright or patent agreements,
184 @ or artifacts that by design or accident interfere with the processing
185
--- src/shun.c
+++ src/shun.c
@@ -36,11 +36,11 @@
36 }
37
38 /*
39 ** WEBPAGE: shun
40 **
41 ** View the hashes of all shunned artifacts. Add new hashes
42 ** to the shun set. Requires Admin privilege.
43 */
44 void shun_page(void){
45 Stmt q;
46 int cnt = 0;
@@ -84,18 +84,18 @@
84 }
85 zCanonical[j+1] = zCanonical[j] = 0;
86 p = zCanonical;
87 while( *p ){
88 int nUuid = strlen(p);
89 if( !hname_validate(p, nUuid) ){
90 @ <p class="generalError">Error: Bad artifact IDs.</p>
91 fossil_free(zCanonical);
92 zCanonical = 0;
93 break;
94 }else{
95 canonical16(p, nUuid);
96 p += nUuid+1;
97 }
98 }
99 zUuid = zCanonical;
100 }
101 style_header("Shunned Artifacts");
@@ -107,21 +107,21 @@
107 db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
108 if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
109 allExist = 0;
110 }
111 admin_log("Unshunned %Q", p);
112 p += strlen(p)+1;
113 }
114 if( allExist ){
115 @ <p class="noMoreShun">Artifact(s)<br />
116 for( p = zUuid ; *p ; p += strlen(p)+1 ){
117 @ <a href="%R/artifact/%s(p)">%s(p)</a><br />
118 }
119 @ are no longer being shunned.</p>
120 }else{
121 @ <p class="noMoreShun">Artifact(s)<br />
122 for( p = zUuid ; *p ; p += strlen(p)+1 ){
123 @ %s(p)<br />
124 }
125 @ will no longer be shunned. But they may not exist in the repository.
126 @ It may be necessary to rebuild the repository using the
127 @ <b>fossil rebuild</b> command-line before the artifact content
@@ -146,14 +146,14 @@
146 db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p);
147 db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid);
148 db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid);
149 }
150 admin_log("Shunned %Q", p);
151 p += strlen(p)+1;
152 }
153 @ <p class="shunned">Artifact(s)<br />
154 for( p = zUuid ; *p ; p += strlen(p)+1 ){
155 @ <a href="%R/artifact/%s(p)">%s(p)</a><br />
156 }
157 @ have been shunned. They will no longer be pushed.
158 @ They will be removed from the repository the next time the repository
159 @ is rebuilt using the <b>fossil rebuild</b> command-line</p>
@@ -167,18 +167,18 @@
167 @ artifact content will be purged from the repository the next time the
168 @ repository is rebuilt. A list of shunned artifacts can be seen at the
169 @ bottom of this page.</p>
170 @
171 @ <a name="addshun"></a>
172 @ <p>To shun artifacts, enter their artifact hashes (the 40- or
173 @ 64-character lowercase hexadecimal hash of the artifact content) in the
174 @ following box and press the "Shun" button. This will cause the artifacts
175 @ to be removed from the repository and will prevent the artifacts from being
176 @ readded to the repository by subsequent sync operation.</p>
177 @
178 @ <p>Note that you must enter the full 40- or 64-character artifact hashes,
179 @ not an abbreviation or a symbolic tag.</p>
180 @
181 @ <p>Warning: Shunning should only be used to remove inappropriate content
182 @ from the repository. Inappropriate content includes such things as
183 @ spam added to Wiki, files that violate copyright or patent agreements,
184 @ or artifacts that by design or accident interfere with the processing
185
+1 -2
--- src/sitemap.c
+++ src/sitemap.c
@@ -111,12 +111,11 @@
111111
}
112112
@ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
113113
if( g.perm.Read ){
114114
@ <li>%z(href("%R/stat"))Repository Status</a>
115115
@ <ul>
116
- @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
117
- @ prefixes</a></li>
116
+ @ <li>%z(href("%R/hash-collisions"))Collisions on hash prefixes</a></li>
118117
if( g.perm.Admin ){
119118
@ <li>%z(href("%R/urllist"))List of URLs used to access
120119
@ this repository</a></li>
121120
}
122121
@ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
123122
--- src/sitemap.c
+++ src/sitemap.c
@@ -111,12 +111,11 @@
111 }
112 @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
113 if( g.perm.Read ){
114 @ <li>%z(href("%R/stat"))Repository Status</a>
115 @ <ul>
116 @ <li>%z(href("%R/hash-collisions"))Collisions on SHA1 hash
117 @ prefixes</a></li>
118 if( g.perm.Admin ){
119 @ <li>%z(href("%R/urllist"))List of URLs used to access
120 @ this repository</a></li>
121 }
122 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
123
--- src/sitemap.c
+++ src/sitemap.c
@@ -111,12 +111,11 @@
111 }
112 @ <li>%z(href("%R/login"))Login/Logout/Change Password</a></li>
113 if( g.perm.Read ){
114 @ <li>%z(href("%R/stat"))Repository Status</a>
115 @ <ul>
116 @ <li>%z(href("%R/hash-collisions"))Collisions on hash prefixes</a></li>
 
117 if( g.perm.Admin ){
118 @ <li>%z(href("%R/urllist"))List of URLs used to access
119 @ this repository</a></li>
120 }
121 @ <li>%z(href("%R/bloblist"))List of Artifacts</a></li>
122
+2 -2
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -185,12 +185,12 @@
185185
** in ways that are unrecoverable. Be sure you know what you are doing before
186186
** running any SQL commands that modify the repository database.
187187
**
188188
** The following extensions to the usual SQLite commands are provided:
189189
**
190
-** content(X) Return the content of artifact X. X can be a
191
-** SHA1 hash or prefix or a tag.
190
+** content(X) Return the content of artifact X. X can be an
191
+** artifact hash or prefix or a tag.
192192
**
193193
** compress(X) Compress text X.
194194
**
195195
** decompress(X) Decompress text X. Undoes the work of
196196
** compress(X).
197197
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -185,12 +185,12 @@
185 ** in ways that are unrecoverable. Be sure you know what you are doing before
186 ** running any SQL commands that modify the repository database.
187 **
188 ** The following extensions to the usual SQLite commands are provided:
189 **
190 ** content(X) Return the content of artifact X. X can be a
191 ** SHA1 hash or prefix or a tag.
192 **
193 ** compress(X) Compress text X.
194 **
195 ** decompress(X) Decompress text X. Undoes the work of
196 ** compress(X).
197
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -185,12 +185,12 @@
185 ** in ways that are unrecoverable. Be sure you know what you are doing before
186 ** running any SQL commands that modify the repository database.
187 **
188 ** The following extensions to the usual SQLite commands are provided:
189 **
190 ** content(X) Return the content of artifact X. X can be an
191 ** artifact hash or prefix or a tag.
192 **
193 ** compress(X) Compress text X.
194 **
195 ** decompress(X) Decompress text X. Undoes the work of
196 ** compress(X).
197
+1 -1
--- src/stat.c
+++ src/stat.c
@@ -76,11 +76,11 @@
7676
style_submenu_element("URLs", "urllist");
7777
style_submenu_element("Schema", "repo_schema");
7878
style_submenu_element("Web-Cache", "cachestat");
7979
}
8080
style_submenu_element("Activity Reports", "reports");
81
- style_submenu_element("SHA1 Collisions", "hash-collisions");
81
+ style_submenu_element("Hash Collisions", "hash-collisions");
8282
if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
8383
style_submenu_element("Table Sizes", "repo-tabsize");
8484
}
8585
if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){
8686
style_submenu_element("Environment", "test_env");
8787
--- src/stat.c
+++ src/stat.c
@@ -76,11 +76,11 @@
76 style_submenu_element("URLs", "urllist");
77 style_submenu_element("Schema", "repo_schema");
78 style_submenu_element("Web-Cache", "cachestat");
79 }
80 style_submenu_element("Activity Reports", "reports");
81 style_submenu_element("SHA1 Collisions", "hash-collisions");
82 if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
83 style_submenu_element("Table Sizes", "repo-tabsize");
84 }
85 if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){
86 style_submenu_element("Environment", "test_env");
87
--- src/stat.c
+++ src/stat.c
@@ -76,11 +76,11 @@
76 style_submenu_element("URLs", "urllist");
77 style_submenu_element("Schema", "repo_schema");
78 style_submenu_element("Web-Cache", "cachestat");
79 }
80 style_submenu_element("Activity Reports", "reports");
81 style_submenu_element("Hash Collisions", "hash-collisions");
82 if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){
83 style_submenu_element("Table Sizes", "repo-tabsize");
84 }
85 if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){
86 style_submenu_element("Environment", "test_env");
87
+1 -1
--- src/tag.c
+++ src/tag.c
@@ -627,11 +627,11 @@
627627
blob_init(&value, 0, 0);
628628
for(i=3; i<g.argc; i++){
629629
int pid = name_to_typed_rid(g.argv[i], "ci");
630630
if( i>3 ) blob_append(&value, " ", 1);
631631
zUuid = rid_to_uuid(pid);
632
- blob_append(&value, zUuid, UUID_SIZE);
632
+ blob_append(&value, zUuid, strlen(zUuid));
633633
fossil_free(zUuid);
634634
}
635635
if( bTest && !dryRun ){
636636
tag_insert("parent", 1, blob_str(&value), -1, 0.0, rid);
637637
}else{
638638
--- src/tag.c
+++ src/tag.c
@@ -627,11 +627,11 @@
627 blob_init(&value, 0, 0);
628 for(i=3; i<g.argc; i++){
629 int pid = name_to_typed_rid(g.argv[i], "ci");
630 if( i>3 ) blob_append(&value, " ", 1);
631 zUuid = rid_to_uuid(pid);
632 blob_append(&value, zUuid, UUID_SIZE);
633 fossil_free(zUuid);
634 }
635 if( bTest && !dryRun ){
636 tag_insert("parent", 1, blob_str(&value), -1, 0.0, rid);
637 }else{
638
--- src/tag.c
+++ src/tag.c
@@ -627,11 +627,11 @@
627 blob_init(&value, 0, 0);
628 for(i=3; i<g.argc; i++){
629 int pid = name_to_typed_rid(g.argv[i], "ci");
630 if( i>3 ) blob_append(&value, " ", 1);
631 zUuid = rid_to_uuid(pid);
632 blob_append(&value, zUuid, strlen(zUuid));
633 fossil_free(zUuid);
634 }
635 if( bTest && !dryRun ){
636 tag_insert("parent", 1, blob_str(&value), -1, 0.0, rid);
637 }else{
638
+3 -6
--- src/tar.c
+++ src/tar.c
@@ -476,18 +476,19 @@
476476
Manifest *pManifest;
477477
ManifestFile *pFile;
478478
Blob filename;
479479
int nPrefix;
480480
char *zName = 0;
481
+ char *zUuid;
481482
unsigned int mTime;
482483
483484
content_get(rid, &mfile);
484485
if( blob_size(&mfile)==0 ){
485486
blob_zero(pTar);
486487
return;
487488
}
488
- blob_zero(&hash);
489
+ blob_set_dynamic(&hash, rid_to_uuid(rid));
489490
blob_zero(&filename);
490491
491492
if( zDir && zDir[0] ){
492493
blob_appendf(&filename, "%s/", zDir);
493494
}
@@ -520,13 +521,10 @@
520521
if( eflg & (MFESTFLG_RAW|MFESTFLG_UUID) ){
521522
if( eflg & MFESTFLG_RAW ){
522523
blob_append(&filename, "manifest", -1);
523524
zName = blob_str(&filename);
524525
}
525
- if( eflg & MFESTFLG_UUID ){
526
- sha1sum_blob(&mfile, &hash);
527
- }
528526
if( eflg & MFESTFLG_RAW ) {
529527
sterilize_manifest(&mfile);
530528
tar_add_file(zName, &mfile, 0, mTime);
531529
}
532530
}
@@ -535,11 +533,10 @@
535533
blob_append(&hash, "\n", 1);
536534
blob_resize(&filename, nPrefix);
537535
blob_append(&filename, "manifest.uuid", -1);
538536
zName = blob_str(&filename);
539537
tar_add_file(zName, &hash, 0, mTime);
540
- blob_reset(&hash);
541538
}
542539
if( eflg & MFESTFLG_TAGS ){
543540
Blob tagslist;
544541
blob_zero(&tagslist);
545542
get_checkin_taglist(rid, &tagslist);
@@ -564,19 +561,19 @@
564561
tar_add_file(zName, &file, manifest_file_mperm(pFile), mTime);
565562
blob_reset(&file);
566563
}
567564
}
568565
}else{
569
- sha1sum_blob(&mfile, &hash);
570566
blob_append(&filename, blob_str(&hash), 16);
571567
zName = blob_str(&filename);
572568
mTime = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0;");
573569
tar_begin(mTime);
574570
tar_add_file(zName, &mfile, 0, mTime);
575571
}
576572
manifest_destroy(pManifest);
577573
blob_reset(&mfile);
574
+ blob_reset(&hash);
578575
blob_reset(&filename);
579576
tar_finish(pTar);
580577
}
581578
582579
/*
583580
--- src/tar.c
+++ src/tar.c
@@ -476,18 +476,19 @@
476 Manifest *pManifest;
477 ManifestFile *pFile;
478 Blob filename;
479 int nPrefix;
480 char *zName = 0;
 
481 unsigned int mTime;
482
483 content_get(rid, &mfile);
484 if( blob_size(&mfile)==0 ){
485 blob_zero(pTar);
486 return;
487 }
488 blob_zero(&hash);
489 blob_zero(&filename);
490
491 if( zDir && zDir[0] ){
492 blob_appendf(&filename, "%s/", zDir);
493 }
@@ -520,13 +521,10 @@
520 if( eflg & (MFESTFLG_RAW|MFESTFLG_UUID) ){
521 if( eflg & MFESTFLG_RAW ){
522 blob_append(&filename, "manifest", -1);
523 zName = blob_str(&filename);
524 }
525 if( eflg & MFESTFLG_UUID ){
526 sha1sum_blob(&mfile, &hash);
527 }
528 if( eflg & MFESTFLG_RAW ) {
529 sterilize_manifest(&mfile);
530 tar_add_file(zName, &mfile, 0, mTime);
531 }
532 }
@@ -535,11 +533,10 @@
535 blob_append(&hash, "\n", 1);
536 blob_resize(&filename, nPrefix);
537 blob_append(&filename, "manifest.uuid", -1);
538 zName = blob_str(&filename);
539 tar_add_file(zName, &hash, 0, mTime);
540 blob_reset(&hash);
541 }
542 if( eflg & MFESTFLG_TAGS ){
543 Blob tagslist;
544 blob_zero(&tagslist);
545 get_checkin_taglist(rid, &tagslist);
@@ -564,19 +561,19 @@
564 tar_add_file(zName, &file, manifest_file_mperm(pFile), mTime);
565 blob_reset(&file);
566 }
567 }
568 }else{
569 sha1sum_blob(&mfile, &hash);
570 blob_append(&filename, blob_str(&hash), 16);
571 zName = blob_str(&filename);
572 mTime = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0;");
573 tar_begin(mTime);
574 tar_add_file(zName, &mfile, 0, mTime);
575 }
576 manifest_destroy(pManifest);
577 blob_reset(&mfile);
 
578 blob_reset(&filename);
579 tar_finish(pTar);
580 }
581
582 /*
583
--- src/tar.c
+++ src/tar.c
@@ -476,18 +476,19 @@
476 Manifest *pManifest;
477 ManifestFile *pFile;
478 Blob filename;
479 int nPrefix;
480 char *zName = 0;
481 char *zUuid;
482 unsigned int mTime;
483
484 content_get(rid, &mfile);
485 if( blob_size(&mfile)==0 ){
486 blob_zero(pTar);
487 return;
488 }
489 blob_set_dynamic(&hash, rid_to_uuid(rid));
490 blob_zero(&filename);
491
492 if( zDir && zDir[0] ){
493 blob_appendf(&filename, "%s/", zDir);
494 }
@@ -520,13 +521,10 @@
521 if( eflg & (MFESTFLG_RAW|MFESTFLG_UUID) ){
522 if( eflg & MFESTFLG_RAW ){
523 blob_append(&filename, "manifest", -1);
524 zName = blob_str(&filename);
525 }
 
 
 
526 if( eflg & MFESTFLG_RAW ) {
527 sterilize_manifest(&mfile);
528 tar_add_file(zName, &mfile, 0, mTime);
529 }
530 }
@@ -535,11 +533,10 @@
533 blob_append(&hash, "\n", 1);
534 blob_resize(&filename, nPrefix);
535 blob_append(&filename, "manifest.uuid", -1);
536 zName = blob_str(&filename);
537 tar_add_file(zName, &hash, 0, mTime);
 
538 }
539 if( eflg & MFESTFLG_TAGS ){
540 Blob tagslist;
541 blob_zero(&tagslist);
542 get_checkin_taglist(rid, &tagslist);
@@ -564,19 +561,19 @@
561 tar_add_file(zName, &file, manifest_file_mperm(pFile), mTime);
562 blob_reset(&file);
563 }
564 }
565 }else{
 
566 blob_append(&filename, blob_str(&hash), 16);
567 zName = blob_str(&filename);
568 mTime = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0;");
569 tar_begin(mTime);
570 tar_add_file(zName, &mfile, 0, mTime);
571 }
572 manifest_destroy(pManifest);
573 blob_reset(&mfile);
574 blob_reset(&hash);
575 blob_reset(&filename);
576 tar_finish(pTar);
577 }
578
579 /*
580
+2 -2
--- src/timeline.c
+++ src/timeline.c
@@ -723,11 +723,11 @@
723723
** mi: "merge-in". An array of integer rail positions from which
724724
** merge arrows should be drawn into this node. If the value is
725725
** negative, then the rail position is the absolute value of mi[]
726726
** and a thin merge-arrow descender is drawn to the bottom of
727727
** the screen.
728
- ** h: The SHA1 hash of the object being graphed
728
+ ** h: The artifact hash of the object being graphed
729729
*/
730730
cgi_printf("var rowinfo = [\n");
731731
for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
732732
cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
733733
pRow->idx, /* id */
@@ -1461,11 +1461,11 @@
14611461
** v Show details of files changed
14621462
** f=CHECKIN Show family (immediate parents and children) of CHECKIN
14631463
** from=CHECKIN Path from...
14641464
** to=CHECKIN ... to this
14651465
** shortest ... show only the shortest path
1466
-** uf=FILE_SHA1 Show only check-ins that contain the given file version
1466
+** uf=FILE_HASH Show only check-ins that contain the given file version
14671467
** chng=GLOBLIST Show only check-ins that involve changes to a file whose
14681468
** name matches one of the comma-separate GLOBLIST
14691469
** brbg Background color from branch name
14701470
** ubg Background color from user
14711471
** namechng Show only check-ins that have filename changes
14721472
--- src/timeline.c
+++ src/timeline.c
@@ -723,11 +723,11 @@
723 ** mi: "merge-in". An array of integer rail positions from which
724 ** merge arrows should be drawn into this node. If the value is
725 ** negative, then the rail position is the absolute value of mi[]
726 ** and a thin merge-arrow descender is drawn to the bottom of
727 ** the screen.
728 ** h: The SHA1 hash of the object being graphed
729 */
730 cgi_printf("var rowinfo = [\n");
731 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
732 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
733 pRow->idx, /* id */
@@ -1461,11 +1461,11 @@
1461 ** v Show details of files changed
1462 ** f=CHECKIN Show family (immediate parents and children) of CHECKIN
1463 ** from=CHECKIN Path from...
1464 ** to=CHECKIN ... to this
1465 ** shortest ... show only the shortest path
1466 ** uf=FILE_SHA1 Show only check-ins that contain the given file version
1467 ** chng=GLOBLIST Show only check-ins that involve changes to a file whose
1468 ** name matches one of the comma-separate GLOBLIST
1469 ** brbg Background color from branch name
1470 ** ubg Background color from user
1471 ** namechng Show only check-ins that have filename changes
1472
--- src/timeline.c
+++ src/timeline.c
@@ -723,11 +723,11 @@
723 ** mi: "merge-in". An array of integer rail positions from which
724 ** merge arrows should be drawn into this node. If the value is
725 ** negative, then the rail position is the absolute value of mi[]
726 ** and a thin merge-arrow descender is drawn to the bottom of
727 ** the screen.
728 ** h: The artifact hash of the object being graphed
729 */
730 cgi_printf("var rowinfo = [\n");
731 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
732 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
733 pRow->idx, /* id */
@@ -1461,11 +1461,11 @@
1461 ** v Show details of files changed
1462 ** f=CHECKIN Show family (immediate parents and children) of CHECKIN
1463 ** from=CHECKIN Path from...
1464 ** to=CHECKIN ... to this
1465 ** shortest ... show only the shortest path
1466 ** uf=FILE_HASH Show only check-ins that contain the given file version
1467 ** chng=GLOBLIST Show only check-ins that involve changes to a file whose
1468 ** name matches one of the comma-separate GLOBLIST
1469 ** brbg Background color from branch name
1470 ** ubg Background color from user
1471 ** namechng Show only check-ins that have filename changes
1472
+5 -7
--- src/verify.c
+++ src/verify.c
@@ -40,21 +40,19 @@
4040
if( content_size(rid, 0)<0 ){
4141
return; /* No way to verify phantoms */
4242
}
4343
blob_zero(&uuid);
4444
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
45
- if( blob_size(&uuid)!=UUID_SIZE ){
45
+ if( !hname_validate(blob_buffer(&uuid), blob_size(&uuid)) ){
4646
fossil_fatal("not a valid rid: %d", rid);
4747
}
4848
if( content_get(rid, &content) ){
49
- sha1sum_blob(&content, &hash);
50
- blob_reset(&content);
51
- if( blob_compare(&uuid, &hash) ){
52
- fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53
- rid, &hash, &uuid);
49
+ if( !hname_verify_hash(&content, blob_buffer(&uuid), blob_size(&uuid)) ){
50
+ fossil_fatal("hash of rid %d does not match its uuid (%b)",
51
+ rid, &uuid);
5452
}
55
- blob_reset(&hash);
53
+ blob_reset(&content);
5654
}
5755
blob_reset(&uuid);
5856
}
5957
6058
/*
6159
--- src/verify.c
+++ src/verify.c
@@ -40,21 +40,19 @@
40 if( content_size(rid, 0)<0 ){
41 return; /* No way to verify phantoms */
42 }
43 blob_zero(&uuid);
44 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
45 if( blob_size(&uuid)!=UUID_SIZE ){
46 fossil_fatal("not a valid rid: %d", rid);
47 }
48 if( content_get(rid, &content) ){
49 sha1sum_blob(&content, &hash);
50 blob_reset(&content);
51 if( blob_compare(&uuid, &hash) ){
52 fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53 rid, &hash, &uuid);
54 }
55 blob_reset(&hash);
56 }
57 blob_reset(&uuid);
58 }
59
60 /*
61
--- src/verify.c
+++ src/verify.c
@@ -40,21 +40,19 @@
40 if( content_size(rid, 0)<0 ){
41 return; /* No way to verify phantoms */
42 }
43 blob_zero(&uuid);
44 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
45 if( !hname_validate(blob_buffer(&uuid), blob_size(&uuid)) ){
46 fossil_fatal("not a valid rid: %d", rid);
47 }
48 if( content_get(rid, &content) ){
49 if( !hname_verify_hash(&content, blob_buffer(&uuid), blob_size(&uuid)) ){
50 fossil_fatal("hash of rid %d does not match its uuid (%b)",
51 rid, &uuid);
 
 
52 }
53 blob_reset(&content);
54 }
55 blob_reset(&uuid);
56 }
57
58 /*
59
+19 -29
--- src/vfile.c
+++ src/vfile.c
@@ -21,12 +21,12 @@
2121
#include "vfile.h"
2222
#include <assert.h>
2323
#include <sys/types.h>
2424
2525
/*
26
-** The input is guaranteed to be a 40-character well-formed UUID.
27
-** Find its rid.
26
+** The input is guaranteed to be a 40- or 64-character well-formed
27
+** artifact hash. Find its rid.
2828
*/
2929
int fast_uuid_to_rid(const char *zUuid){
3030
static Stmt q;
3131
int rid;
3232
db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
@@ -51,17 +51,17 @@
5151
** create a phantom record. A private phantom is created for 2 and
5252
** a public phantom is created for 1.
5353
*/
5454
int uuid_to_rid(const char *zUuid, int phantomize){
5555
int rid, sz;
56
- char z[UUID_SIZE+1];
56
+ char z[HNAME_MAX+1];
5757
5858
sz = strlen(zUuid);
59
- if( sz!=UUID_SIZE || !validate16(zUuid, sz) ){
60
- return 0;
59
+ if( !hname_validate(zUuid, sz) ){
60
+ return 0; /* Not a valid hash */
6161
}
62
- memcpy(z, zUuid, UUID_SIZE+1);
62
+ memcpy(z, zUuid, sz+1);
6363
canonical16(z, sz);
6464
rid = fast_uuid_to_rid(z);
6565
if( rid==0 && phantomize ){
6666
rid = content_new(zUuid, phantomize-1);
6767
}
@@ -130,11 +130,11 @@
130130
/*
131131
** The cksigFlags parameter to vfile_check_signature() is an OR-ed
132132
** combination of the following bits:
133133
*/
134134
#define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */
135
-#define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */
135
+#define CKSIG_HASH 0x002 /* Verify file content using hashing */
136136
#define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137137
138138
#endif /* INTERFACE */
139139
140140
/*
@@ -159,12 +159,12 @@
159159
**
160160
** If the size of the file has changed, then we always know that the file
161161
** changed without having to look at the mtime or on-disk content.
162162
**
163163
** The mtime of the file is only a factor if the mtime-changes setting
164
-** is false and the useSha1sum flag is false. If the mtime-changes
165
-** setting is true (or undefined - it defaults to true) or if useSha1sum
164
+** is false and the CKSIG_HASH flag is false. If the mtime-changes
165
+** setting is true (or undefined - it defaults to true) or if CKSIG_HASH
166166
** is true, then we do not trust the mtime and will examine the on-disk
167167
** content to determine if a file really is the same.
168168
**
169169
** If the mtime is used, it is used only to determine if files are the same.
170170
** If the mtime of a file has changed, we still examine the on-disk content
@@ -172,11 +172,11 @@
172172
*/
173173
void vfile_check_signature(int vid, unsigned int cksigFlags){
174174
int nErr = 0;
175175
Stmt q;
176176
Blob fileCksum, origCksum;
177
- int useMtime = (cksigFlags & CKSIG_SHA1)==0
177
+ int useMtime = (cksigFlags & CKSIG_HASH)==0
178178
&& db_get_boolean("mtime-changes", 1);
179179
180180
db_begin_transaction();
181181
db_prepare(&q, "SELECT id, %Q || pathname,"
182182
" vfile.mrid, deleted, chnged, uuid, size, mtime,"
@@ -222,40 +222,30 @@
222222
chnged = 1;
223223
}
224224
if( origSize!=currentSize ){
225225
if( chnged!=1 ){
226226
/* A file size change is definitive - the file has changed. No
227
- ** need to check the mtime or sha1sum */
227
+ ** need to check the mtime or hash */
228228
chnged = 1;
229229
}
230230
}else if( chnged==1 && rid!=0 && !isDeleted ){
231231
/* File is believed to have changed but it is the same size.
232232
** Double check that it really has changed by looking at content. */
233
+ const char *zUuid = db_column_text(&q, 5);
234
+ int nUuid = db_column_bytes(&q, 5);
233235
assert( origSize==currentSize );
234
- db_ephemeral_blob(&q, 5, &origCksum);
235
- if( sha1sum_file(zName, &fileCksum) ){
236
- blob_zero(&fileCksum);
237
- }
238
- if( blob_compare(&fileCksum, &origCksum)==0 ) chnged = 0;
239
- blob_reset(&origCksum);
240
- blob_reset(&fileCksum);
236
+ if( hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 0;
241237
}else if( (chnged==0 || chnged==2 || chnged==4)
242238
&& (useMtime==0 || currentMtime!=oldMtime) ){
243239
/* For files that were formerly believed to be unchanged or that were
244240
** changed by merging, if their mtime changes, or unconditionally
245
- ** if --sha1sum is used, check to see if they have been edited by
246
- ** looking at their SHA1 sum */
241
+ ** if --hash is used, check to see if they have been edited by
242
+ ** looking at their artifact hashes */
243
+ const char *zUuid = db_column_text(&q, 5);
244
+ int nUuid = db_column_bytes(&q, 5);
247245
assert( origSize==currentSize );
248
- db_ephemeral_blob(&q, 5, &origCksum);
249
- if( sha1sum_file(zName, &fileCksum) ){
250
- blob_zero(&fileCksum);
251
- }
252
- if( blob_compare(&fileCksum, &origCksum) ){
253
- chnged = 1;
254
- }
255
- blob_reset(&origCksum);
256
- blob_reset(&fileCksum);
246
+ if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1;
257247
}
258248
if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
259249
i64 desiredMtime;
260250
if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
261251
if( currentMtime!=desiredMtime ){
262252
--- src/vfile.c
+++ src/vfile.c
@@ -21,12 +21,12 @@
21 #include "vfile.h"
22 #include <assert.h>
23 #include <sys/types.h>
24
25 /*
26 ** The input is guaranteed to be a 40-character well-formed UUID.
27 ** Find its rid.
28 */
29 int fast_uuid_to_rid(const char *zUuid){
30 static Stmt q;
31 int rid;
32 db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
@@ -51,17 +51,17 @@
51 ** create a phantom record. A private phantom is created for 2 and
52 ** a public phantom is created for 1.
53 */
54 int uuid_to_rid(const char *zUuid, int phantomize){
55 int rid, sz;
56 char z[UUID_SIZE+1];
57
58 sz = strlen(zUuid);
59 if( sz!=UUID_SIZE || !validate16(zUuid, sz) ){
60 return 0;
61 }
62 memcpy(z, zUuid, UUID_SIZE+1);
63 canonical16(z, sz);
64 rid = fast_uuid_to_rid(z);
65 if( rid==0 && phantomize ){
66 rid = content_new(zUuid, phantomize-1);
67 }
@@ -130,11 +130,11 @@
130 /*
131 ** The cksigFlags parameter to vfile_check_signature() is an OR-ed
132 ** combination of the following bits:
133 */
134 #define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */
135 #define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */
136 #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137
138 #endif /* INTERFACE */
139
140 /*
@@ -159,12 +159,12 @@
159 **
160 ** If the size of the file has changed, then we always know that the file
161 ** changed without having to look at the mtime or on-disk content.
162 **
163 ** The mtime of the file is only a factor if the mtime-changes setting
164 ** is false and the useSha1sum flag is false. If the mtime-changes
165 ** setting is true (or undefined - it defaults to true) or if useSha1sum
166 ** is true, then we do not trust the mtime and will examine the on-disk
167 ** content to determine if a file really is the same.
168 **
169 ** If the mtime is used, it is used only to determine if files are the same.
170 ** If the mtime of a file has changed, we still examine the on-disk content
@@ -172,11 +172,11 @@
172 */
173 void vfile_check_signature(int vid, unsigned int cksigFlags){
174 int nErr = 0;
175 Stmt q;
176 Blob fileCksum, origCksum;
177 int useMtime = (cksigFlags & CKSIG_SHA1)==0
178 && db_get_boolean("mtime-changes", 1);
179
180 db_begin_transaction();
181 db_prepare(&q, "SELECT id, %Q || pathname,"
182 " vfile.mrid, deleted, chnged, uuid, size, mtime,"
@@ -222,40 +222,30 @@
222 chnged = 1;
223 }
224 if( origSize!=currentSize ){
225 if( chnged!=1 ){
226 /* A file size change is definitive - the file has changed. No
227 ** need to check the mtime or sha1sum */
228 chnged = 1;
229 }
230 }else if( chnged==1 && rid!=0 && !isDeleted ){
231 /* File is believed to have changed but it is the same size.
232 ** Double check that it really has changed by looking at content. */
 
 
233 assert( origSize==currentSize );
234 db_ephemeral_blob(&q, 5, &origCksum);
235 if( sha1sum_file(zName, &fileCksum) ){
236 blob_zero(&fileCksum);
237 }
238 if( blob_compare(&fileCksum, &origCksum)==0 ) chnged = 0;
239 blob_reset(&origCksum);
240 blob_reset(&fileCksum);
241 }else if( (chnged==0 || chnged==2 || chnged==4)
242 && (useMtime==0 || currentMtime!=oldMtime) ){
243 /* For files that were formerly believed to be unchanged or that were
244 ** changed by merging, if their mtime changes, or unconditionally
245 ** if --sha1sum is used, check to see if they have been edited by
246 ** looking at their SHA1 sum */
 
 
247 assert( origSize==currentSize );
248 db_ephemeral_blob(&q, 5, &origCksum);
249 if( sha1sum_file(zName, &fileCksum) ){
250 blob_zero(&fileCksum);
251 }
252 if( blob_compare(&fileCksum, &origCksum) ){
253 chnged = 1;
254 }
255 blob_reset(&origCksum);
256 blob_reset(&fileCksum);
257 }
258 if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
259 i64 desiredMtime;
260 if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
261 if( currentMtime!=desiredMtime ){
262
--- src/vfile.c
+++ src/vfile.c
@@ -21,12 +21,12 @@
21 #include "vfile.h"
22 #include <assert.h>
23 #include <sys/types.h>
24
25 /*
26 ** The input is guaranteed to be a 40- or 64-character well-formed
27 ** artifact hash. Find its rid.
28 */
29 int fast_uuid_to_rid(const char *zUuid){
30 static Stmt q;
31 int rid;
32 db_static_prepare(&q, "SELECT rid FROM blob WHERE uuid=:uuid");
@@ -51,17 +51,17 @@
51 ** create a phantom record. A private phantom is created for 2 and
52 ** a public phantom is created for 1.
53 */
54 int uuid_to_rid(const char *zUuid, int phantomize){
55 int rid, sz;
56 char z[HNAME_MAX+1];
57
58 sz = strlen(zUuid);
59 if( !hname_validate(zUuid, sz) ){
60 return 0; /* Not a valid hash */
61 }
62 memcpy(z, zUuid, sz+1);
63 canonical16(z, sz);
64 rid = fast_uuid_to_rid(z);
65 if( rid==0 && phantomize ){
66 rid = content_new(zUuid, phantomize-1);
67 }
@@ -130,11 +130,11 @@
130 /*
131 ** The cksigFlags parameter to vfile_check_signature() is an OR-ed
132 ** combination of the following bits:
133 */
134 #define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */
135 #define CKSIG_HASH 0x002 /* Verify file content using hashing */
136 #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137
138 #endif /* INTERFACE */
139
140 /*
@@ -159,12 +159,12 @@
159 **
160 ** If the size of the file has changed, then we always know that the file
161 ** changed without having to look at the mtime or on-disk content.
162 **
163 ** The mtime of the file is only a factor if the mtime-changes setting
164 ** is false and the CKSIG_HASH flag is false. If the mtime-changes
165 ** setting is true (or undefined - it defaults to true) or if CKSIG_HASH
166 ** is true, then we do not trust the mtime and will examine the on-disk
167 ** content to determine if a file really is the same.
168 **
169 ** If the mtime is used, it is used only to determine if files are the same.
170 ** If the mtime of a file has changed, we still examine the on-disk content
@@ -172,11 +172,11 @@
172 */
173 void vfile_check_signature(int vid, unsigned int cksigFlags){
174 int nErr = 0;
175 Stmt q;
176 Blob fileCksum, origCksum;
177 int useMtime = (cksigFlags & CKSIG_HASH)==0
178 && db_get_boolean("mtime-changes", 1);
179
180 db_begin_transaction();
181 db_prepare(&q, "SELECT id, %Q || pathname,"
182 " vfile.mrid, deleted, chnged, uuid, size, mtime,"
@@ -222,40 +222,30 @@
222 chnged = 1;
223 }
224 if( origSize!=currentSize ){
225 if( chnged!=1 ){
226 /* A file size change is definitive - the file has changed. No
227 ** need to check the mtime or hash */
228 chnged = 1;
229 }
230 }else if( chnged==1 && rid!=0 && !isDeleted ){
231 /* File is believed to have changed but it is the same size.
232 ** Double check that it really has changed by looking at content. */
233 const char *zUuid = db_column_text(&q, 5);
234 int nUuid = db_column_bytes(&q, 5);
235 assert( origSize==currentSize );
236 if( hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 0;
 
 
 
 
 
 
237 }else if( (chnged==0 || chnged==2 || chnged==4)
238 && (useMtime==0 || currentMtime!=oldMtime) ){
239 /* For files that were formerly believed to be unchanged or that were
240 ** changed by merging, if their mtime changes, or unconditionally
241 ** if --hash is used, check to see if they have been edited by
242 ** looking at their artifact hashes */
243 const char *zUuid = db_column_text(&q, 5);
244 int nUuid = db_column_bytes(&q, 5);
245 assert( origSize==currentSize );
246 if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1;
 
 
 
 
 
 
 
 
247 }
248 if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
249 i64 desiredMtime;
250 if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
251 if( currentMtime!=desiredMtime ){
252
+2 -2
--- src/wiki.c
+++ src/wiki.c
@@ -1122,12 +1122,12 @@
11221122
*/
11231123
int wiki_technote_to_rid(const char *zETime) {
11241124
int rid=0; /* Artifact ID of the tech note */
11251125
int nETime = strlen(zETime);
11261126
Stmt q;
1127
- if( nETime>=4 && nETime<=UUID_SIZE && validate16(zETime, nETime) ){
1128
- char zUuid[UUID_SIZE+1];
1127
+ if( nETime>=4 && hname_validate(zETime, nETime) ){
1128
+ char zUuid[HNAME_MAX+1];
11291129
memcpy(zUuid, zETime, nETime+1);
11301130
canonical16(zUuid, nETime);
11311131
db_prepare(&q,
11321132
"SELECT e.objid"
11331133
" FROM event e, tag t"
11341134
--- src/wiki.c
+++ src/wiki.c
@@ -1122,12 +1122,12 @@
1122 */
1123 int wiki_technote_to_rid(const char *zETime) {
1124 int rid=0; /* Artifact ID of the tech note */
1125 int nETime = strlen(zETime);
1126 Stmt q;
1127 if( nETime>=4 && nETime<=UUID_SIZE && validate16(zETime, nETime) ){
1128 char zUuid[UUID_SIZE+1];
1129 memcpy(zUuid, zETime, nETime+1);
1130 canonical16(zUuid, nETime);
1131 db_prepare(&q,
1132 "SELECT e.objid"
1133 " FROM event e, tag t"
1134
--- src/wiki.c
+++ src/wiki.c
@@ -1122,12 +1122,12 @@
1122 */
1123 int wiki_technote_to_rid(const char *zETime) {
1124 int rid=0; /* Artifact ID of the tech note */
1125 int nETime = strlen(zETime);
1126 Stmt q;
1127 if( nETime>=4 && hname_validate(zETime, nETime) ){
1128 char zUuid[HNAME_MAX+1];
1129 memcpy(zUuid, zETime, nETime+1);
1130 canonical16(zUuid, nETime);
1131 db_prepare(&q,
1132 "SELECT e.objid"
1133 " FROM event e, tag t"
1134
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1067,11 +1067,11 @@
10671067
** If the input string corresponds to an existing baseline,
10681068
** return true.
10691069
*/
10701070
static int is_valid_uuid(const char *z){
10711071
int n = strlen(z);
1072
- if( n<4 || n>UUID_SIZE ) return 0;
1072
+ if( n<4 || n>HNAME_MAX ) return 0;
10731073
if( !validate16(z, n) ) return 0;
10741074
return 1;
10751075
}
10761076
10771077
/*
10781078
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1067,11 +1067,11 @@
1067 ** If the input string corresponds to an existing baseline,
1068 ** return true.
1069 */
1070 static int is_valid_uuid(const char *z){
1071 int n = strlen(z);
1072 if( n<4 || n>UUID_SIZE ) return 0;
1073 if( !validate16(z, n) ) return 0;
1074 return 1;
1075 }
1076
1077 /*
1078
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1067,11 +1067,11 @@
1067 ** If the input string corresponds to an existing baseline,
1068 ** return true.
1069 */
1070 static int is_valid_uuid(const char *z){
1071 int n = strlen(z);
1072 if( n<4 || n>HNAME_MAX ) return 0;
1073 if( !validate16(z, n) ) return 0;
1074 return 1;
1075 }
1076
1077 /*
1078
+69 -65
--- src/xfer.c
+++ src/xfer.c
@@ -54,11 +54,11 @@
5454
time_t maxTime; /* Time when this transfer should be finished */
5555
};
5656
5757
5858
/*
59
-** The input blob contains a UUID. Convert it into a record ID.
59
+** The input blob contains an artifact. Convert it into a record ID.
6060
** Create a phantom record if no prior record exists and
6161
** phantomize is true.
6262
**
6363
** Compare to uuid_to_rid(). This routine takes a blob argument
6464
** and does less error checking.
@@ -100,12 +100,12 @@
100100
** message. This routine finishes parsing that message and does
101101
** a record insert of the file.
102102
**
103103
** The file line is in one of the following two forms:
104104
**
105
-** file UUID SIZE \n CONTENT
106
-** file UUID DELTASRC SIZE \n CONTENT
105
+** file HASH SIZE \n CONTENT
106
+** file HASH DELTASRC SIZE \n CONTENT
107107
**
108108
** The content is SIZE bytes immediately following the newline.
109109
** If DELTASRC exists, then the CONTENT is a delta against the
110110
** content of DELTASRC.
111111
**
@@ -122,29 +122,30 @@
122122
int *pnUuidList
123123
){
124124
int n;
125125
int rid;
126126
int srcid = 0;
127
- Blob content, hash;
127
+ Blob content;
128128
int isPriv;
129
+ Blob *pUuid;
129130
130131
isPriv = pXfer->nextIsPrivate;
131132
pXfer->nextIsPrivate = 0;
132133
if( pXfer->nToken<3
133134
|| pXfer->nToken>4
134
- || !blob_is_uuid(&pXfer->aToken[1])
135
+ || !blob_is_hname(&pXfer->aToken[1])
135136
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
136137
|| n<0
137
- || (pXfer->nToken==4 && !blob_is_uuid(&pXfer->aToken[2]))
138
+ || (pXfer->nToken==4 && !blob_is_hname(&pXfer->aToken[2]))
138139
){
139140
blob_appendf(&pXfer->err, "malformed file line");
140141
return;
141142
}
142143
blob_zero(&content);
143
- blob_zero(&hash);
144144
blob_extract(pXfer->pIn, n, &content);
145
- if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
145
+ pUuid = &pXfer->aToken[1];
146
+ if( !cloneFlag && uuid_is_shunned(blob_str(pUuid)) ){
146147
/* Ignore files that have been shunned */
147148
blob_reset(&content);
148149
return;
149150
}
150151
if( isPriv && !g.perm.Private ){
@@ -158,26 +159,26 @@
158159
pXfer->nDeltaRcvd++;
159160
}else{
160161
srcid = 0;
161162
pXfer->nFileRcvd++;
162163
}
163
- rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
164
+ rid = content_put_ex(&content, blob_str(pUuid), srcid,
164165
0, isPriv);
165
- Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]),
166
- blob_size(&pXfer->aToken[1]));
166
+ Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid),
167
+ blob_size(pUuid));
167168
remote_has(rid);
168169
blob_reset(&content);
169170
return;
170171
}
171172
if( pXfer->nToken==4 ){
172173
Blob src, next;
173174
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
174175
if( content_get(srcid, &src)==0 ){
175
- rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
176
+ rid = content_put_ex(&content, blob_str(pUuid), srcid,
176177
0, isPriv);
177
- Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]),
178
- blob_size(&pXfer->aToken[1]));
178
+ Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid),
179
+ blob_size(pUuid));
179180
pXfer->nDanglingFile++;
180181
db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
181182
if( !isPriv ) content_make_public(rid);
182183
blob_reset(&src);
183184
blob_reset(&content);
@@ -189,19 +190,15 @@
189190
blob_reset(&content);
190191
content = next;
191192
}else{
192193
pXfer->nFileRcvd++;
193194
}
194
- sha1sum_blob(&content, &hash);
195
- if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
196
- blob_appendf(&pXfer->err,
197
- "wrong hash on received artifact: expected %s but got %s",
198
- blob_str(&pXfer->aToken[1]), blob_str(&hash));
199
- }
200
- rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
201
- Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash));
202
- blob_reset(&hash);
195
+ if( hname_verify_hash(&content, blob_buffer(pUuid), blob_size(pUuid))==0 ){
196
+ blob_appendf(&pXfer->err, "wrong hash on received artifact: %b", pUuid);
197
+ }
198
+ rid = content_put_ex(&content, blob_str(pUuid), 0, 0, isPriv);
199
+ Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid), blob_size(pUuid));
203200
if( rid==0 ){
204201
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
205202
blob_reset(&content);
206203
}else{
207204
if( !isPriv ) content_make_public(rid);
@@ -217,18 +214,18 @@
217214
** a record insert of the file. The difference between "file" and
218215
** "cfile" is that with "cfile" the content is already compressed.
219216
**
220217
** The file line is in one of the following two forms:
221218
**
222
-** cfile UUID USIZE CSIZE \n CONTENT
223
-** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
219
+** cfile HASH USIZE CSIZE \n CONTENT
220
+** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
224221
**
225222
** The content is CSIZE bytes immediately following the newline.
226223
** If DELTASRC exists, then the CONTENT is a delta against the
227224
** content of DELTASRC.
228225
**
229
-** The original size of the UUID artifact is USIZE.
226
+** The original size of the HASH artifact is USIZE.
230227
**
231228
** If any error occurs, write a message into pErr which has already
232229
** be initialized to an empty string.
233230
**
234231
** Any artifact successfully received by this routine is considered to
@@ -248,15 +245,15 @@
248245
249246
isPriv = pXfer->nextIsPrivate;
250247
pXfer->nextIsPrivate = 0;
251248
if( pXfer->nToken<4
252249
|| pXfer->nToken>5
253
- || !blob_is_uuid(&pXfer->aToken[1])
250
+ || !blob_is_hname(&pXfer->aToken[1])
254251
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
255252
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
256253
|| szC<0 || szU<0
257
- || (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
254
+ || (pXfer->nToken==5 && !blob_is_hname(&pXfer->aToken[2]))
258255
){
259256
blob_appendf(&pXfer->err, "malformed cfile line");
260257
return;
261258
}
262259
if( isPriv && !g.perm.Private ){
@@ -297,11 +294,11 @@
297294
**
298295
** If the 0x0001 bit of FLAGS is set, that means the file has been
299296
** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted.
300297
**
301298
** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
302
-** HASH is the SHA1 hash of CONTENT.
299
+** HASH is the artifact hash of CONTENT.
303300
**
304301
** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted.
305302
** The sender might have omitted the content because it is too big to
306303
** transmit, or because it is unchanged and this record exists purely
307304
** to update the MTIME.
@@ -310,11 +307,10 @@
310307
sqlite3_int64 mtime; /* The MTIME */
311308
Blob *pHash; /* The HASH value */
312309
int sz; /* The SIZE */
313310
int flags; /* The FLAGS */
314311
Blob content; /* The CONTENT */
315
- Blob hash; /* Hash computed from CONTENT to compare with HASH */
316312
Blob x; /* Compressed content */
317313
Stmt q; /* SQL statements for comparison and insert */
318314
int isDelete; /* HASH is "-" indicating this is a delete */
319315
int nullContent; /* True of CONTENT is NULL */
320316
int iStatus; /* Result from unversioned_status() */
@@ -321,25 +317,23 @@
321317
322318
pHash = &pXfer->aToken[3];
323319
if( pXfer->nToken==5
324320
|| !blob_is_filename(&pXfer->aToken[1])
325321
|| !blob_is_int64(&pXfer->aToken[2], &mtime)
326
- || (!blob_eq(pHash,"-") && !blob_is_uuid(pHash))
322
+ || (!blob_eq(pHash,"-") && !blob_is_hname(pHash))
327323
|| !blob_is_int(&pXfer->aToken[4], &sz)
328324
|| !blob_is_int(&pXfer->aToken[5], &flags)
329325
){
330326
blob_appendf(&pXfer->err, "malformed uvfile line");
331327
return;
332328
}
333329
blob_init(&content, 0, 0);
334
- blob_init(&hash, 0, 0);
335330
blob_init(&x, 0, 0);
336331
if( sz>0 && (flags & 0x0005)==0 ){
337332
blob_extract(pXfer->pIn, sz, &content);
338333
nullContent = 0;
339
- sha1sum_blob(&content, &hash);
340
- if( blob_compare(&hash, pHash)!=0 ){
334
+ if( hname_verify_hash(&content, blob_buffer(pHash), blob_size(pHash))==0 ){
341335
blob_appendf(&pXfer->err, "in uvfile line, HASH does not match CONTENT");
342336
goto end_accept_unversioned_file;
343337
}
344338
}else{
345339
nullContent = 1;
@@ -399,11 +393,10 @@
399393
db_unset("uv-hash", 0);
400394
401395
end_accept_unversioned_file:
402396
blob_reset(&x);
403397
blob_reset(&content);
404
- blob_reset(&hash);
405398
}
406399
407400
/*
408401
** Try to send a file as a delta against its parent.
409402
** If successful, return the number of bytes in the delta.
@@ -415,11 +408,11 @@
415408
static int send_delta_parent(
416409
Xfer *pXfer, /* The transfer context */
417410
int rid, /* record id of the file to send */
418411
int isPrivate, /* True if rid is a private artifact */
419412
Blob *pContent, /* The content of the file to send */
420
- Blob *pUuid /* The UUID of the file to send */
413
+ Blob *pUuid /* The HASH of the file to send */
421414
){
422415
static const char *const azQuery[] = {
423416
"SELECT pid FROM plink x"
424417
" WHERE cid=%d"
425418
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
@@ -469,11 +462,11 @@
469462
*/
470463
static int send_delta_native(
471464
Xfer *pXfer, /* The transfer context */
472465
int rid, /* record id of the file to send */
473466
int isPrivate, /* True if rid is a private artifact */
474
- Blob *pUuid /* The UUID of the file to send */
467
+ Blob *pUuid /* The HASH of the file to send */
475468
){
476469
Blob src, delta;
477470
int size = 0;
478471
int srcId;
479472
@@ -504,11 +497,11 @@
504497
}
505498
506499
/*
507500
** Send the file identified by rid.
508501
**
509
-** The pUuid can be NULL in which case the correct UUID is computed
502
+** The pUuid can be NULL in which case the correct hash is computed
510503
** from the rid.
511504
**
512505
** Try to send the file as a native delta if nativeDelta is true, or
513506
** as a parent delta if nativeDelta is false.
514507
**
@@ -728,23 +721,24 @@
728721
}
729722
db_finalize(&q);
730723
}
731724
732725
/*
733
-** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the
726
+** Compute an hash on the tail of pMsg. Verify that it matches the
734727
** the hash given in pHash. Return non-zero for an error and 0 on success.
728
+**
729
+** The type of hash computed (SHA1, SHA3-224, SHA3-256) is determined by
730
+** the length of the input hash in pHash.
735731
*/
736732
static int check_tail_hash(Blob *pHash, Blob *pMsg){
737733
Blob tail;
738734
Blob h2;
739735
int rc;
740736
blob_tail(pMsg, &tail);
741
- sha1sum_blob(&tail, &h2);
742
- rc = blob_compare(pHash, &h2);
743
- blob_reset(&h2);
737
+ rc = hname_verify_hash(&tail, blob_buffer(pHash), blob_size(pHash));
744738
blob_reset(&tail);
745
- return rc;
739
+ return rc==HNAME_ERROR;
746740
}
747741
748742
/*
749743
** Check the signature on an application/x-fossil payload received by
750744
** the HTTP server. The signature is a line of the following form:
@@ -1153,10 +1147,11 @@
11531147
char *zUuidList = 0;
11541148
int nUuidList = 0;
11551149
char **pzUuidList = 0;
11561150
int *pnUuidList = 0;
11571151
int uvCatalogSent = 0;
1152
+ int clientVersion = 0; /* Version number of the client */
11581153
11591154
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
11601155
fossil_redirect_home();
11611156
}
11621157
g.zLogin = "anonymous";
@@ -1198,12 +1193,12 @@
11981193
while( blob_line(xfer.pIn, &xfer.line) ){
11991194
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
12001195
if( blob_size(&xfer.line)==0 ) continue;
12011196
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
12021197
1203
- /* file UUID SIZE \n CONTENT
1204
- ** file UUID DELTASRC SIZE \n CONTENT
1198
+ /* file HASH SIZE \n CONTENT
1199
+ ** file HASH DELTASRC SIZE \n CONTENT
12051200
**
12061201
** Accept a file from the client.
12071202
*/
12081203
if( blob_eq(&xfer.aToken[0], "file") ){
12091204
if( !isPush ){
@@ -1219,12 +1214,12 @@
12191214
nErr++;
12201215
break;
12211216
}
12221217
}else
12231218
1224
- /* cfile UUID USIZE CSIZE \n CONTENT
1225
- ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
1219
+ /* cfile HASH USIZE CSIZE \n CONTENT
1220
+ ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
12261221
**
12271222
** Accept a file from the client.
12281223
*/
12291224
if( blob_eq(&xfer.aToken[0], "cfile") ){
12301225
if( !isPush ){
@@ -1254,17 +1249,17 @@
12541249
nErr++;
12551250
break;
12561251
}
12571252
}else
12581253
1259
- /* gimme UUID
1254
+ /* gimme HASH
12601255
**
12611256
** Client is requesting a file. Send it.
12621257
*/
12631258
if( blob_eq(&xfer.aToken[0], "gimme")
12641259
&& xfer.nToken==2
1265
- && blob_is_uuid(&xfer.aToken[1])
1260
+ && blob_is_hname(&xfer.aToken[1])
12661261
){
12671262
nGimme++;
12681263
if( isPull ){
12691264
int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
12701265
if( rid ){
@@ -1282,18 +1277,18 @@
12821277
&& blob_is_filename(&xfer.aToken[1])
12831278
){
12841279
send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
12851280
}else
12861281
1287
- /* igot UUID ?ISPRIVATE?
1282
+ /* igot HASH ?ISPRIVATE?
12881283
**
12891284
** Client announces that it has a particular file. If the ISPRIVATE
12901285
** argument exists and is non-zero, then the file is a private file.
12911286
*/
12921287
if( xfer.nToken>=2
12931288
&& blob_eq(&xfer.aToken[0], "igot")
1294
- && blob_is_uuid(&xfer.aToken[1])
1289
+ && blob_is_hname(&xfer.aToken[1])
12951290
){
12961291
if( isPush ){
12971292
if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
12981293
rid_from_uuid(&xfer.aToken[1], 1, 0);
12991294
}else if( g.perm.Private ){
@@ -1307,16 +1302,15 @@
13071302
13081303
/* pull SERVERCODE PROJECTCODE
13091304
** push SERVERCODE PROJECTCODE
13101305
**
13111306
** The client wants either send or receive. The server should
1312
- ** verify that the project code matches.
1307
+ ** verify that the project code matches. The server code is ignored.
13131308
*/
13141309
if( xfer.nToken==3
13151310
&& (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
1316
- && blob_is_uuid(&xfer.aToken[1])
1317
- && blob_is_uuid(&xfer.aToken[2])
1311
+ && blob_is_hname(&xfer.aToken[2])
13181312
){
13191313
const char *zPCode;
13201314
zPCode = db_get("project-code", 0);
13211315
if( zPCode==0 ){
13221316
fossil_panic("missing project code");
@@ -1534,19 +1528,27 @@
15341528
** Send igot cards for all known artifacts.
15351529
*/
15361530
if( blob_eq(&xfer.aToken[1], "send-catalog") ){
15371531
xfer.resync = 0x7fffffff;
15381532
}
1533
+
1534
+ /* pragma client-version VERSION
1535
+ **
1536
+ ** Let the server know what version of Fossil is running on the client.
1537
+ */
1538
+ if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
1539
+ clientVersion = atoi(blob_str(&xfer.aToken[2]));
1540
+ }
15391541
15401542
/* pragma uv-hash HASH
15411543
**
15421544
** The client wants to make sure that unversioned files are all synced.
15431545
** If the HASH does not match, send a complete catalog of
15441546
** "uvigot" cards.
15451547
*/
15461548
if( blob_eq(&xfer.aToken[1], "uv-hash")
1547
- && blob_is_uuid(&xfer.aToken[2])
1549
+ && blob_is_hname(&xfer.aToken[2])
15481550
){
15491551
if( !uvCatalogSent ){
15501552
if( g.perm.Read && g.perm.WrUnver ){
15511553
@ pragma uv-push-ok
15521554
send_unversioned_catalog(&xfer);
@@ -1783,10 +1785,11 @@
17831785
}
17841786
17851787
/*
17861788
** Always begin with a clone, pull, or push message
17871789
*/
1790
+ blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER);
17881791
if( syncFlags & SYNC_CLONE ){
17891792
blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
17901793
syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
17911794
nCardSent++;
17921795
/* TBD: Request all transferable configuration values */
@@ -1819,10 +1822,11 @@
18191822
db_record_repository_filename(0);
18201823
db_multi_exec(
18211824
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
18221825
);
18231826
manifest_crosslink_begin();
1827
+
18241828
18251829
/* Send back the most recently received cookie. Let the server
18261830
** figure out if this is a cookie that it cares about.
18271831
*/
18281832
zCookie = db_get("cookie", 0);
@@ -2028,22 +2032,22 @@
20282032
lastPctDone = pctDone;
20292033
fflush(stdout);
20302034
}
20312035
}
20322036
2033
- /* file UUID SIZE \n CONTENT
2034
- ** file UUID DELTASRC SIZE \n CONTENT
2037
+ /* file HASH SIZE \n CONTENT
2038
+ ** file HASH DELTASRC SIZE \n CONTENT
20352039
**
20362040
** Receive a file transmitted from the server.
20372041
*/
20382042
if( blob_eq(&xfer.aToken[0],"file") ){
20392043
xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0);
20402044
nArtifactRcvd++;
20412045
}else
20422046
2043
- /* cfile UUID USIZE CSIZE \n CONTENT
2044
- ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
2047
+ /* cfile HASH USIZE CSIZE \n CONTENT
2048
+ ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
20452049
**
20462050
** Receive a compressed file transmitted from the server.
20472051
*/
20482052
if( blob_eq(&xfer.aToken[0],"cfile") ){
20492053
xfer_accept_compressed_file(&xfer, 0, 0);
@@ -2062,27 +2066,27 @@
20622066
fossil_print("\rUnversioned-file received: %s\n",
20632067
blob_str(&xfer.aToken[1]));
20642068
}
20652069
}else
20662070
2067
- /* gimme UUID
2071
+ /* gimme HASH
20682072
**
20692073
** Server is requesting a file. If the file is a manifest, assume
20702074
** that the server will also want to know all of the content files
20712075
** associated with the manifest and send those too.
20722076
*/
20732077
if( blob_eq(&xfer.aToken[0], "gimme")
20742078
&& xfer.nToken==2
2075
- && blob_is_uuid(&xfer.aToken[1])
2079
+ && blob_is_hname(&xfer.aToken[1])
20762080
){
20772081
if( syncFlags & SYNC_PUSH ){
20782082
int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
20792083
if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
20802084
}
20812085
}else
20822086
2083
- /* igot UUID ?PRIVATEFLAG?
2087
+ /* igot HASH ?PRIVATEFLAG?
20842088
**
20852089
** Server announces that it has a particular file. If this is
20862090
** not a file that we have and we are pulling, then create a
20872091
** phantom to cause this file to be requested on the next cycle.
20882092
** Always remember that the server has this file so that we do
@@ -2092,11 +2096,11 @@
20922096
** private. Pretend it does not exists if we are not pulling
20932097
** private files.
20942098
*/
20952099
if( xfer.nToken>=2
20962100
&& blob_eq(&xfer.aToken[0], "igot")
2097
- && blob_is_uuid(&xfer.aToken[1])
2101
+ && blob_is_hname(&xfer.aToken[1])
20982102
){
20992103
int rid;
21002104
int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
21012105
rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
21022106
if( rid>0 ){
@@ -2126,11 +2130,11 @@
21262130
if( xfer.nToken==5
21272131
&& blob_eq(&xfer.aToken[0], "uvigot")
21282132
&& blob_is_filename(&xfer.aToken[1])
21292133
&& blob_is_int64(&xfer.aToken[2], &mtime)
21302134
&& blob_is_int(&xfer.aToken[4], &size)
2131
- && (blob_eq(&xfer.aToken[3],"-") || blob_is_uuid(&xfer.aToken[3]))
2135
+ && (blob_eq(&xfer.aToken[3],"-") || blob_is_hname(&xfer.aToken[3]))
21322136
){
21332137
const char *zName = blob_str(&xfer.aToken[1]);
21342138
const char *zHash = blob_str(&xfer.aToken[3]);
21352139
int iStatus;
21362140
iStatus = unversioned_status(zName, mtime, zHash);
@@ -2188,11 +2192,11 @@
21882192
** the client what product to use for the new database.
21892193
*/
21902194
if( blob_eq(&xfer.aToken[0],"push")
21912195
&& xfer.nToken==3
21922196
&& (syncFlags & SYNC_CLONE)!=0
2193
- && blob_is_uuid(&xfer.aToken[2])
2197
+ && blob_is_hname(&xfer.aToken[2])
21942198
){
21952199
if( zPCode==0 ){
21962200
zPCode = mprintf("%b", &xfer.aToken[2]);
21972201
db_set("project-code", zPCode, 0);
21982202
}
21992203
--- src/xfer.c
+++ src/xfer.c
@@ -54,11 +54,11 @@
54 time_t maxTime; /* Time when this transfer should be finished */
55 };
56
57
58 /*
59 ** The input blob contains a UUID. Convert it into a record ID.
60 ** Create a phantom record if no prior record exists and
61 ** phantomize is true.
62 **
63 ** Compare to uuid_to_rid(). This routine takes a blob argument
64 ** and does less error checking.
@@ -100,12 +100,12 @@
100 ** message. This routine finishes parsing that message and does
101 ** a record insert of the file.
102 **
103 ** The file line is in one of the following two forms:
104 **
105 ** file UUID SIZE \n CONTENT
106 ** file UUID DELTASRC SIZE \n CONTENT
107 **
108 ** The content is SIZE bytes immediately following the newline.
109 ** If DELTASRC exists, then the CONTENT is a delta against the
110 ** content of DELTASRC.
111 **
@@ -122,29 +122,30 @@
122 int *pnUuidList
123 ){
124 int n;
125 int rid;
126 int srcid = 0;
127 Blob content, hash;
128 int isPriv;
 
129
130 isPriv = pXfer->nextIsPrivate;
131 pXfer->nextIsPrivate = 0;
132 if( pXfer->nToken<3
133 || pXfer->nToken>4
134 || !blob_is_uuid(&pXfer->aToken[1])
135 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
136 || n<0
137 || (pXfer->nToken==4 && !blob_is_uuid(&pXfer->aToken[2]))
138 ){
139 blob_appendf(&pXfer->err, "malformed file line");
140 return;
141 }
142 blob_zero(&content);
143 blob_zero(&hash);
144 blob_extract(pXfer->pIn, n, &content);
145 if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
 
146 /* Ignore files that have been shunned */
147 blob_reset(&content);
148 return;
149 }
150 if( isPriv && !g.perm.Private ){
@@ -158,26 +159,26 @@
158 pXfer->nDeltaRcvd++;
159 }else{
160 srcid = 0;
161 pXfer->nFileRcvd++;
162 }
163 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
164 0, isPriv);
165 Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]),
166 blob_size(&pXfer->aToken[1]));
167 remote_has(rid);
168 blob_reset(&content);
169 return;
170 }
171 if( pXfer->nToken==4 ){
172 Blob src, next;
173 srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
174 if( content_get(srcid, &src)==0 ){
175 rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
176 0, isPriv);
177 Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]),
178 blob_size(&pXfer->aToken[1]));
179 pXfer->nDanglingFile++;
180 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
181 if( !isPriv ) content_make_public(rid);
182 blob_reset(&src);
183 blob_reset(&content);
@@ -189,19 +190,15 @@
189 blob_reset(&content);
190 content = next;
191 }else{
192 pXfer->nFileRcvd++;
193 }
194 sha1sum_blob(&content, &hash);
195 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
196 blob_appendf(&pXfer->err,
197 "wrong hash on received artifact: expected %s but got %s",
198 blob_str(&pXfer->aToken[1]), blob_str(&hash));
199 }
200 rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
201 Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash));
202 blob_reset(&hash);
203 if( rid==0 ){
204 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
205 blob_reset(&content);
206 }else{
207 if( !isPriv ) content_make_public(rid);
@@ -217,18 +214,18 @@
217 ** a record insert of the file. The difference between "file" and
218 ** "cfile" is that with "cfile" the content is already compressed.
219 **
220 ** The file line is in one of the following two forms:
221 **
222 ** cfile UUID USIZE CSIZE \n CONTENT
223 ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
224 **
225 ** The content is CSIZE bytes immediately following the newline.
226 ** If DELTASRC exists, then the CONTENT is a delta against the
227 ** content of DELTASRC.
228 **
229 ** The original size of the UUID artifact is USIZE.
230 **
231 ** If any error occurs, write a message into pErr which has already
232 ** be initialized to an empty string.
233 **
234 ** Any artifact successfully received by this routine is considered to
@@ -248,15 +245,15 @@
248
249 isPriv = pXfer->nextIsPrivate;
250 pXfer->nextIsPrivate = 0;
251 if( pXfer->nToken<4
252 || pXfer->nToken>5
253 || !blob_is_uuid(&pXfer->aToken[1])
254 || !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
255 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
256 || szC<0 || szU<0
257 || (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
258 ){
259 blob_appendf(&pXfer->err, "malformed cfile line");
260 return;
261 }
262 if( isPriv && !g.perm.Private ){
@@ -297,11 +294,11 @@
297 **
298 ** If the 0x0001 bit of FLAGS is set, that means the file has been
299 ** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted.
300 **
301 ** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
302 ** HASH is the SHA1 hash of CONTENT.
303 **
304 ** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted.
305 ** The sender might have omitted the content because it is too big to
306 ** transmit, or because it is unchanged and this record exists purely
307 ** to update the MTIME.
@@ -310,11 +307,10 @@
310 sqlite3_int64 mtime; /* The MTIME */
311 Blob *pHash; /* The HASH value */
312 int sz; /* The SIZE */
313 int flags; /* The FLAGS */
314 Blob content; /* The CONTENT */
315 Blob hash; /* Hash computed from CONTENT to compare with HASH */
316 Blob x; /* Compressed content */
317 Stmt q; /* SQL statements for comparison and insert */
318 int isDelete; /* HASH is "-" indicating this is a delete */
319 int nullContent; /* True of CONTENT is NULL */
320 int iStatus; /* Result from unversioned_status() */
@@ -321,25 +317,23 @@
321
322 pHash = &pXfer->aToken[3];
323 if( pXfer->nToken==5
324 || !blob_is_filename(&pXfer->aToken[1])
325 || !blob_is_int64(&pXfer->aToken[2], &mtime)
326 || (!blob_eq(pHash,"-") && !blob_is_uuid(pHash))
327 || !blob_is_int(&pXfer->aToken[4], &sz)
328 || !blob_is_int(&pXfer->aToken[5], &flags)
329 ){
330 blob_appendf(&pXfer->err, "malformed uvfile line");
331 return;
332 }
333 blob_init(&content, 0, 0);
334 blob_init(&hash, 0, 0);
335 blob_init(&x, 0, 0);
336 if( sz>0 && (flags & 0x0005)==0 ){
337 blob_extract(pXfer->pIn, sz, &content);
338 nullContent = 0;
339 sha1sum_blob(&content, &hash);
340 if( blob_compare(&hash, pHash)!=0 ){
341 blob_appendf(&pXfer->err, "in uvfile line, HASH does not match CONTENT");
342 goto end_accept_unversioned_file;
343 }
344 }else{
345 nullContent = 1;
@@ -399,11 +393,10 @@
399 db_unset("uv-hash", 0);
400
401 end_accept_unversioned_file:
402 blob_reset(&x);
403 blob_reset(&content);
404 blob_reset(&hash);
405 }
406
407 /*
408 ** Try to send a file as a delta against its parent.
409 ** If successful, return the number of bytes in the delta.
@@ -415,11 +408,11 @@
415 static int send_delta_parent(
416 Xfer *pXfer, /* The transfer context */
417 int rid, /* record id of the file to send */
418 int isPrivate, /* True if rid is a private artifact */
419 Blob *pContent, /* The content of the file to send */
420 Blob *pUuid /* The UUID of the file to send */
421 ){
422 static const char *const azQuery[] = {
423 "SELECT pid FROM plink x"
424 " WHERE cid=%d"
425 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
@@ -469,11 +462,11 @@
469 */
470 static int send_delta_native(
471 Xfer *pXfer, /* The transfer context */
472 int rid, /* record id of the file to send */
473 int isPrivate, /* True if rid is a private artifact */
474 Blob *pUuid /* The UUID of the file to send */
475 ){
476 Blob src, delta;
477 int size = 0;
478 int srcId;
479
@@ -504,11 +497,11 @@
504 }
505
506 /*
507 ** Send the file identified by rid.
508 **
509 ** The pUuid can be NULL in which case the correct UUID is computed
510 ** from the rid.
511 **
512 ** Try to send the file as a native delta if nativeDelta is true, or
513 ** as a parent delta if nativeDelta is false.
514 **
@@ -728,23 +721,24 @@
728 }
729 db_finalize(&q);
730 }
731
732 /*
733 ** Compute an SHA1 hash on the tail of pMsg. Verify that it matches the
734 ** the hash given in pHash. Return non-zero for an error and 0 on success.
 
 
 
735 */
736 static int check_tail_hash(Blob *pHash, Blob *pMsg){
737 Blob tail;
738 Blob h2;
739 int rc;
740 blob_tail(pMsg, &tail);
741 sha1sum_blob(&tail, &h2);
742 rc = blob_compare(pHash, &h2);
743 blob_reset(&h2);
744 blob_reset(&tail);
745 return rc;
746 }
747
748 /*
749 ** Check the signature on an application/x-fossil payload received by
750 ** the HTTP server. The signature is a line of the following form:
@@ -1153,10 +1147,11 @@
1153 char *zUuidList = 0;
1154 int nUuidList = 0;
1155 char **pzUuidList = 0;
1156 int *pnUuidList = 0;
1157 int uvCatalogSent = 0;
 
1158
1159 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1160 fossil_redirect_home();
1161 }
1162 g.zLogin = "anonymous";
@@ -1198,12 +1193,12 @@
1198 while( blob_line(xfer.pIn, &xfer.line) ){
1199 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
1200 if( blob_size(&xfer.line)==0 ) continue;
1201 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
1202
1203 /* file UUID SIZE \n CONTENT
1204 ** file UUID DELTASRC SIZE \n CONTENT
1205 **
1206 ** Accept a file from the client.
1207 */
1208 if( blob_eq(&xfer.aToken[0], "file") ){
1209 if( !isPush ){
@@ -1219,12 +1214,12 @@
1219 nErr++;
1220 break;
1221 }
1222 }else
1223
1224 /* cfile UUID USIZE CSIZE \n CONTENT
1225 ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
1226 **
1227 ** Accept a file from the client.
1228 */
1229 if( blob_eq(&xfer.aToken[0], "cfile") ){
1230 if( !isPush ){
@@ -1254,17 +1249,17 @@
1254 nErr++;
1255 break;
1256 }
1257 }else
1258
1259 /* gimme UUID
1260 **
1261 ** Client is requesting a file. Send it.
1262 */
1263 if( blob_eq(&xfer.aToken[0], "gimme")
1264 && xfer.nToken==2
1265 && blob_is_uuid(&xfer.aToken[1])
1266 ){
1267 nGimme++;
1268 if( isPull ){
1269 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1270 if( rid ){
@@ -1282,18 +1277,18 @@
1282 && blob_is_filename(&xfer.aToken[1])
1283 ){
1284 send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
1285 }else
1286
1287 /* igot UUID ?ISPRIVATE?
1288 **
1289 ** Client announces that it has a particular file. If the ISPRIVATE
1290 ** argument exists and is non-zero, then the file is a private file.
1291 */
1292 if( xfer.nToken>=2
1293 && blob_eq(&xfer.aToken[0], "igot")
1294 && blob_is_uuid(&xfer.aToken[1])
1295 ){
1296 if( isPush ){
1297 if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
1298 rid_from_uuid(&xfer.aToken[1], 1, 0);
1299 }else if( g.perm.Private ){
@@ -1307,16 +1302,15 @@
1307
1308 /* pull SERVERCODE PROJECTCODE
1309 ** push SERVERCODE PROJECTCODE
1310 **
1311 ** The client wants either send or receive. The server should
1312 ** verify that the project code matches.
1313 */
1314 if( xfer.nToken==3
1315 && (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
1316 && blob_is_uuid(&xfer.aToken[1])
1317 && blob_is_uuid(&xfer.aToken[2])
1318 ){
1319 const char *zPCode;
1320 zPCode = db_get("project-code", 0);
1321 if( zPCode==0 ){
1322 fossil_panic("missing project code");
@@ -1534,19 +1528,27 @@
1534 ** Send igot cards for all known artifacts.
1535 */
1536 if( blob_eq(&xfer.aToken[1], "send-catalog") ){
1537 xfer.resync = 0x7fffffff;
1538 }
 
 
 
 
 
 
 
 
1539
1540 /* pragma uv-hash HASH
1541 **
1542 ** The client wants to make sure that unversioned files are all synced.
1543 ** If the HASH does not match, send a complete catalog of
1544 ** "uvigot" cards.
1545 */
1546 if( blob_eq(&xfer.aToken[1], "uv-hash")
1547 && blob_is_uuid(&xfer.aToken[2])
1548 ){
1549 if( !uvCatalogSent ){
1550 if( g.perm.Read && g.perm.WrUnver ){
1551 @ pragma uv-push-ok
1552 send_unversioned_catalog(&xfer);
@@ -1783,10 +1785,11 @@
1783 }
1784
1785 /*
1786 ** Always begin with a clone, pull, or push message
1787 */
 
1788 if( syncFlags & SYNC_CLONE ){
1789 blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
1790 syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
1791 nCardSent++;
1792 /* TBD: Request all transferable configuration values */
@@ -1819,10 +1822,11 @@
1819 db_record_repository_filename(0);
1820 db_multi_exec(
1821 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1822 );
1823 manifest_crosslink_begin();
 
1824
1825 /* Send back the most recently received cookie. Let the server
1826 ** figure out if this is a cookie that it cares about.
1827 */
1828 zCookie = db_get("cookie", 0);
@@ -2028,22 +2032,22 @@
2028 lastPctDone = pctDone;
2029 fflush(stdout);
2030 }
2031 }
2032
2033 /* file UUID SIZE \n CONTENT
2034 ** file UUID DELTASRC SIZE \n CONTENT
2035 **
2036 ** Receive a file transmitted from the server.
2037 */
2038 if( blob_eq(&xfer.aToken[0],"file") ){
2039 xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0);
2040 nArtifactRcvd++;
2041 }else
2042
2043 /* cfile UUID USIZE CSIZE \n CONTENT
2044 ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
2045 **
2046 ** Receive a compressed file transmitted from the server.
2047 */
2048 if( blob_eq(&xfer.aToken[0],"cfile") ){
2049 xfer_accept_compressed_file(&xfer, 0, 0);
@@ -2062,27 +2066,27 @@
2062 fossil_print("\rUnversioned-file received: %s\n",
2063 blob_str(&xfer.aToken[1]));
2064 }
2065 }else
2066
2067 /* gimme UUID
2068 **
2069 ** Server is requesting a file. If the file is a manifest, assume
2070 ** that the server will also want to know all of the content files
2071 ** associated with the manifest and send those too.
2072 */
2073 if( blob_eq(&xfer.aToken[0], "gimme")
2074 && xfer.nToken==2
2075 && blob_is_uuid(&xfer.aToken[1])
2076 ){
2077 if( syncFlags & SYNC_PUSH ){
2078 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
2079 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
2080 }
2081 }else
2082
2083 /* igot UUID ?PRIVATEFLAG?
2084 **
2085 ** Server announces that it has a particular file. If this is
2086 ** not a file that we have and we are pulling, then create a
2087 ** phantom to cause this file to be requested on the next cycle.
2088 ** Always remember that the server has this file so that we do
@@ -2092,11 +2096,11 @@
2092 ** private. Pretend it does not exists if we are not pulling
2093 ** private files.
2094 */
2095 if( xfer.nToken>=2
2096 && blob_eq(&xfer.aToken[0], "igot")
2097 && blob_is_uuid(&xfer.aToken[1])
2098 ){
2099 int rid;
2100 int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
2101 rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
2102 if( rid>0 ){
@@ -2126,11 +2130,11 @@
2126 if( xfer.nToken==5
2127 && blob_eq(&xfer.aToken[0], "uvigot")
2128 && blob_is_filename(&xfer.aToken[1])
2129 && blob_is_int64(&xfer.aToken[2], &mtime)
2130 && blob_is_int(&xfer.aToken[4], &size)
2131 && (blob_eq(&xfer.aToken[3],"-") || blob_is_uuid(&xfer.aToken[3]))
2132 ){
2133 const char *zName = blob_str(&xfer.aToken[1]);
2134 const char *zHash = blob_str(&xfer.aToken[3]);
2135 int iStatus;
2136 iStatus = unversioned_status(zName, mtime, zHash);
@@ -2188,11 +2192,11 @@
2188 ** the client what product to use for the new database.
2189 */
2190 if( blob_eq(&xfer.aToken[0],"push")
2191 && xfer.nToken==3
2192 && (syncFlags & SYNC_CLONE)!=0
2193 && blob_is_uuid(&xfer.aToken[2])
2194 ){
2195 if( zPCode==0 ){
2196 zPCode = mprintf("%b", &xfer.aToken[2]);
2197 db_set("project-code", zPCode, 0);
2198 }
2199
--- src/xfer.c
+++ src/xfer.c
@@ -54,11 +54,11 @@
54 time_t maxTime; /* Time when this transfer should be finished */
55 };
56
57
58 /*
59 ** The input blob contains an artifact. Convert it into a record ID.
60 ** Create a phantom record if no prior record exists and
61 ** phantomize is true.
62 **
63 ** Compare to uuid_to_rid(). This routine takes a blob argument
64 ** and does less error checking.
@@ -100,12 +100,12 @@
100 ** message. This routine finishes parsing that message and does
101 ** a record insert of the file.
102 **
103 ** The file line is in one of the following two forms:
104 **
105 ** file HASH SIZE \n CONTENT
106 ** file HASH DELTASRC SIZE \n CONTENT
107 **
108 ** The content is SIZE bytes immediately following the newline.
109 ** If DELTASRC exists, then the CONTENT is a delta against the
110 ** content of DELTASRC.
111 **
@@ -122,29 +122,30 @@
122 int *pnUuidList
123 ){
124 int n;
125 int rid;
126 int srcid = 0;
127 Blob content;
128 int isPriv;
129 Blob *pUuid;
130
131 isPriv = pXfer->nextIsPrivate;
132 pXfer->nextIsPrivate = 0;
133 if( pXfer->nToken<3
134 || pXfer->nToken>4
135 || !blob_is_hname(&pXfer->aToken[1])
136 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
137 || n<0
138 || (pXfer->nToken==4 && !blob_is_hname(&pXfer->aToken[2]))
139 ){
140 blob_appendf(&pXfer->err, "malformed file line");
141 return;
142 }
143 blob_zero(&content);
 
144 blob_extract(pXfer->pIn, n, &content);
145 pUuid = &pXfer->aToken[1];
146 if( !cloneFlag && uuid_is_shunned(blob_str(pUuid)) ){
147 /* Ignore files that have been shunned */
148 blob_reset(&content);
149 return;
150 }
151 if( isPriv && !g.perm.Private ){
@@ -158,26 +159,26 @@
159 pXfer->nDeltaRcvd++;
160 }else{
161 srcid = 0;
162 pXfer->nFileRcvd++;
163 }
164 rid = content_put_ex(&content, blob_str(pUuid), srcid,
165 0, isPriv);
166 Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid),
167 blob_size(pUuid));
168 remote_has(rid);
169 blob_reset(&content);
170 return;
171 }
172 if( pXfer->nToken==4 ){
173 Blob src, next;
174 srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
175 if( content_get(srcid, &src)==0 ){
176 rid = content_put_ex(&content, blob_str(pUuid), srcid,
177 0, isPriv);
178 Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid),
179 blob_size(pUuid));
180 pXfer->nDanglingFile++;
181 db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
182 if( !isPriv ) content_make_public(rid);
183 blob_reset(&src);
184 blob_reset(&content);
@@ -189,19 +190,15 @@
190 blob_reset(&content);
191 content = next;
192 }else{
193 pXfer->nFileRcvd++;
194 }
195 if( hname_verify_hash(&content, blob_buffer(pUuid), blob_size(pUuid))==0 ){
196 blob_appendf(&pXfer->err, "wrong hash on received artifact: %b", pUuid);
197 }
198 rid = content_put_ex(&content, blob_str(pUuid), 0, 0, isPriv);
199 Th_AppendToList(pzUuidList, pnUuidList, blob_str(pUuid), blob_size(pUuid));
 
 
 
 
200 if( rid==0 ){
201 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
202 blob_reset(&content);
203 }else{
204 if( !isPriv ) content_make_public(rid);
@@ -217,18 +214,18 @@
214 ** a record insert of the file. The difference between "file" and
215 ** "cfile" is that with "cfile" the content is already compressed.
216 **
217 ** The file line is in one of the following two forms:
218 **
219 ** cfile HASH USIZE CSIZE \n CONTENT
220 ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
221 **
222 ** The content is CSIZE bytes immediately following the newline.
223 ** If DELTASRC exists, then the CONTENT is a delta against the
224 ** content of DELTASRC.
225 **
226 ** The original size of the HASH artifact is USIZE.
227 **
228 ** If any error occurs, write a message into pErr which has already
229 ** be initialized to an empty string.
230 **
231 ** Any artifact successfully received by this routine is considered to
@@ -248,15 +245,15 @@
245
246 isPriv = pXfer->nextIsPrivate;
247 pXfer->nextIsPrivate = 0;
248 if( pXfer->nToken<4
249 || pXfer->nToken>5
250 || !blob_is_hname(&pXfer->aToken[1])
251 || !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
252 || !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
253 || szC<0 || szU<0
254 || (pXfer->nToken==5 && !blob_is_hname(&pXfer->aToken[2]))
255 ){
256 blob_appendf(&pXfer->err, "malformed cfile line");
257 return;
258 }
259 if( isPriv && !g.perm.Private ){
@@ -297,11 +294,11 @@
294 **
295 ** If the 0x0001 bit of FLAGS is set, that means the file has been
296 ** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted.
297 **
298 ** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
299 ** HASH is the artifact hash of CONTENT.
300 **
301 ** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted.
302 ** The sender might have omitted the content because it is too big to
303 ** transmit, or because it is unchanged and this record exists purely
304 ** to update the MTIME.
@@ -310,11 +307,10 @@
307 sqlite3_int64 mtime; /* The MTIME */
308 Blob *pHash; /* The HASH value */
309 int sz; /* The SIZE */
310 int flags; /* The FLAGS */
311 Blob content; /* The CONTENT */
 
312 Blob x; /* Compressed content */
313 Stmt q; /* SQL statements for comparison and insert */
314 int isDelete; /* HASH is "-" indicating this is a delete */
315 int nullContent; /* True of CONTENT is NULL */
316 int iStatus; /* Result from unversioned_status() */
@@ -321,25 +317,23 @@
317
318 pHash = &pXfer->aToken[3];
319 if( pXfer->nToken==5
320 || !blob_is_filename(&pXfer->aToken[1])
321 || !blob_is_int64(&pXfer->aToken[2], &mtime)
322 || (!blob_eq(pHash,"-") && !blob_is_hname(pHash))
323 || !blob_is_int(&pXfer->aToken[4], &sz)
324 || !blob_is_int(&pXfer->aToken[5], &flags)
325 ){
326 blob_appendf(&pXfer->err, "malformed uvfile line");
327 return;
328 }
329 blob_init(&content, 0, 0);
 
330 blob_init(&x, 0, 0);
331 if( sz>0 && (flags & 0x0005)==0 ){
332 blob_extract(pXfer->pIn, sz, &content);
333 nullContent = 0;
334 if( hname_verify_hash(&content, blob_buffer(pHash), blob_size(pHash))==0 ){
 
335 blob_appendf(&pXfer->err, "in uvfile line, HASH does not match CONTENT");
336 goto end_accept_unversioned_file;
337 }
338 }else{
339 nullContent = 1;
@@ -399,11 +393,10 @@
393 db_unset("uv-hash", 0);
394
395 end_accept_unversioned_file:
396 blob_reset(&x);
397 blob_reset(&content);
 
398 }
399
400 /*
401 ** Try to send a file as a delta against its parent.
402 ** If successful, return the number of bytes in the delta.
@@ -415,11 +408,11 @@
408 static int send_delta_parent(
409 Xfer *pXfer, /* The transfer context */
410 int rid, /* record id of the file to send */
411 int isPrivate, /* True if rid is a private artifact */
412 Blob *pContent, /* The content of the file to send */
413 Blob *pUuid /* The HASH of the file to send */
414 ){
415 static const char *const azQuery[] = {
416 "SELECT pid FROM plink x"
417 " WHERE cid=%d"
418 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
@@ -469,11 +462,11 @@
462 */
463 static int send_delta_native(
464 Xfer *pXfer, /* The transfer context */
465 int rid, /* record id of the file to send */
466 int isPrivate, /* True if rid is a private artifact */
467 Blob *pUuid /* The HASH of the file to send */
468 ){
469 Blob src, delta;
470 int size = 0;
471 int srcId;
472
@@ -504,11 +497,11 @@
497 }
498
499 /*
500 ** Send the file identified by rid.
501 **
502 ** The pUuid can be NULL in which case the correct hash is computed
503 ** from the rid.
504 **
505 ** Try to send the file as a native delta if nativeDelta is true, or
506 ** as a parent delta if nativeDelta is false.
507 **
@@ -728,23 +721,24 @@
721 }
722 db_finalize(&q);
723 }
724
725 /*
726 ** Compute an hash on the tail of pMsg. Verify that it matches the
727 ** the hash given in pHash. Return non-zero for an error and 0 on success.
728 **
729 ** The type of hash computed (SHA1, SHA3-224, SHA3-256) is determined by
730 ** the length of the input hash in pHash.
731 */
732 static int check_tail_hash(Blob *pHash, Blob *pMsg){
733 Blob tail;
734 Blob h2;
735 int rc;
736 blob_tail(pMsg, &tail);
737 rc = hname_verify_hash(&tail, blob_buffer(pHash), blob_size(pHash));
 
 
738 blob_reset(&tail);
739 return rc==HNAME_ERROR;
740 }
741
742 /*
743 ** Check the signature on an application/x-fossil payload received by
744 ** the HTTP server. The signature is a line of the following form:
@@ -1153,10 +1147,11 @@
1147 char *zUuidList = 0;
1148 int nUuidList = 0;
1149 char **pzUuidList = 0;
1150 int *pnUuidList = 0;
1151 int uvCatalogSent = 0;
1152 int clientVersion = 0; /* Version number of the client */
1153
1154 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1155 fossil_redirect_home();
1156 }
1157 g.zLogin = "anonymous";
@@ -1198,12 +1193,12 @@
1193 while( blob_line(xfer.pIn, &xfer.line) ){
1194 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
1195 if( blob_size(&xfer.line)==0 ) continue;
1196 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
1197
1198 /* file HASH SIZE \n CONTENT
1199 ** file HASH DELTASRC SIZE \n CONTENT
1200 **
1201 ** Accept a file from the client.
1202 */
1203 if( blob_eq(&xfer.aToken[0], "file") ){
1204 if( !isPush ){
@@ -1219,12 +1214,12 @@
1214 nErr++;
1215 break;
1216 }
1217 }else
1218
1219 /* cfile HASH USIZE CSIZE \n CONTENT
1220 ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
1221 **
1222 ** Accept a file from the client.
1223 */
1224 if( blob_eq(&xfer.aToken[0], "cfile") ){
1225 if( !isPush ){
@@ -1254,17 +1249,17 @@
1249 nErr++;
1250 break;
1251 }
1252 }else
1253
1254 /* gimme HASH
1255 **
1256 ** Client is requesting a file. Send it.
1257 */
1258 if( blob_eq(&xfer.aToken[0], "gimme")
1259 && xfer.nToken==2
1260 && blob_is_hname(&xfer.aToken[1])
1261 ){
1262 nGimme++;
1263 if( isPull ){
1264 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1265 if( rid ){
@@ -1282,18 +1277,18 @@
1277 && blob_is_filename(&xfer.aToken[1])
1278 ){
1279 send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
1280 }else
1281
1282 /* igot HASH ?ISPRIVATE?
1283 **
1284 ** Client announces that it has a particular file. If the ISPRIVATE
1285 ** argument exists and is non-zero, then the file is a private file.
1286 */
1287 if( xfer.nToken>=2
1288 && blob_eq(&xfer.aToken[0], "igot")
1289 && blob_is_hname(&xfer.aToken[1])
1290 ){
1291 if( isPush ){
1292 if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
1293 rid_from_uuid(&xfer.aToken[1], 1, 0);
1294 }else if( g.perm.Private ){
@@ -1307,16 +1302,15 @@
1302
1303 /* pull SERVERCODE PROJECTCODE
1304 ** push SERVERCODE PROJECTCODE
1305 **
1306 ** The client wants either send or receive. The server should
1307 ** verify that the project code matches. The server code is ignored.
1308 */
1309 if( xfer.nToken==3
1310 && (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
1311 && blob_is_hname(&xfer.aToken[2])
 
1312 ){
1313 const char *zPCode;
1314 zPCode = db_get("project-code", 0);
1315 if( zPCode==0 ){
1316 fossil_panic("missing project code");
@@ -1534,19 +1528,27 @@
1528 ** Send igot cards for all known artifacts.
1529 */
1530 if( blob_eq(&xfer.aToken[1], "send-catalog") ){
1531 xfer.resync = 0x7fffffff;
1532 }
1533
1534 /* pragma client-version VERSION
1535 **
1536 ** Let the server know what version of Fossil is running on the client.
1537 */
1538 if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
1539 clientVersion = atoi(blob_str(&xfer.aToken[2]));
1540 }
1541
1542 /* pragma uv-hash HASH
1543 **
1544 ** The client wants to make sure that unversioned files are all synced.
1545 ** If the HASH does not match, send a complete catalog of
1546 ** "uvigot" cards.
1547 */
1548 if( blob_eq(&xfer.aToken[1], "uv-hash")
1549 && blob_is_hname(&xfer.aToken[2])
1550 ){
1551 if( !uvCatalogSent ){
1552 if( g.perm.Read && g.perm.WrUnver ){
1553 @ pragma uv-push-ok
1554 send_unversioned_catalog(&xfer);
@@ -1783,10 +1785,11 @@
1785 }
1786
1787 /*
1788 ** Always begin with a clone, pull, or push message
1789 */
1790 blob_appendf(&send, "pragma client-version %d\n", RELEASE_VERSION_NUMBER);
1791 if( syncFlags & SYNC_CLONE ){
1792 blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
1793 syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
1794 nCardSent++;
1795 /* TBD: Request all transferable configuration values */
@@ -1819,10 +1822,11 @@
1822 db_record_repository_filename(0);
1823 db_multi_exec(
1824 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1825 );
1826 manifest_crosslink_begin();
1827
1828
1829 /* Send back the most recently received cookie. Let the server
1830 ** figure out if this is a cookie that it cares about.
1831 */
1832 zCookie = db_get("cookie", 0);
@@ -2028,22 +2032,22 @@
2032 lastPctDone = pctDone;
2033 fflush(stdout);
2034 }
2035 }
2036
2037 /* file HASH SIZE \n CONTENT
2038 ** file HASH DELTASRC SIZE \n CONTENT
2039 **
2040 ** Receive a file transmitted from the server.
2041 */
2042 if( blob_eq(&xfer.aToken[0],"file") ){
2043 xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0);
2044 nArtifactRcvd++;
2045 }else
2046
2047 /* cfile HASH USIZE CSIZE \n CONTENT
2048 ** cfile HASH DELTASRC USIZE CSIZE \n CONTENT
2049 **
2050 ** Receive a compressed file transmitted from the server.
2051 */
2052 if( blob_eq(&xfer.aToken[0],"cfile") ){
2053 xfer_accept_compressed_file(&xfer, 0, 0);
@@ -2062,27 +2066,27 @@
2066 fossil_print("\rUnversioned-file received: %s\n",
2067 blob_str(&xfer.aToken[1]));
2068 }
2069 }else
2070
2071 /* gimme HASH
2072 **
2073 ** Server is requesting a file. If the file is a manifest, assume
2074 ** that the server will also want to know all of the content files
2075 ** associated with the manifest and send those too.
2076 */
2077 if( blob_eq(&xfer.aToken[0], "gimme")
2078 && xfer.nToken==2
2079 && blob_is_hname(&xfer.aToken[1])
2080 ){
2081 if( syncFlags & SYNC_PUSH ){
2082 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
2083 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
2084 }
2085 }else
2086
2087 /* igot HASH ?PRIVATEFLAG?
2088 **
2089 ** Server announces that it has a particular file. If this is
2090 ** not a file that we have and we are pulling, then create a
2091 ** phantom to cause this file to be requested on the next cycle.
2092 ** Always remember that the server has this file so that we do
@@ -2092,11 +2096,11 @@
2096 ** private. Pretend it does not exists if we are not pulling
2097 ** private files.
2098 */
2099 if( xfer.nToken>=2
2100 && blob_eq(&xfer.aToken[0], "igot")
2101 && blob_is_hname(&xfer.aToken[1])
2102 ){
2103 int rid;
2104 int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
2105 rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
2106 if( rid>0 ){
@@ -2126,11 +2130,11 @@
2130 if( xfer.nToken==5
2131 && blob_eq(&xfer.aToken[0], "uvigot")
2132 && blob_is_filename(&xfer.aToken[1])
2133 && blob_is_int64(&xfer.aToken[2], &mtime)
2134 && blob_is_int(&xfer.aToken[4], &size)
2135 && (blob_eq(&xfer.aToken[3],"-") || blob_is_hname(&xfer.aToken[3]))
2136 ){
2137 const char *zName = blob_str(&xfer.aToken[1]);
2138 const char *zHash = blob_str(&xfer.aToken[3]);
2139 int iStatus;
2140 iStatus = unversioned_status(zName, mtime, zHash);
@@ -2188,11 +2192,11 @@
2192 ** the client what product to use for the new database.
2193 */
2194 if( blob_eq(&xfer.aToken[0],"push")
2195 && xfer.nToken==3
2196 && (syncFlags & SYNC_CLONE)!=0
2197 && blob_is_hname(&xfer.aToken[2])
2198 ){
2199 if( zPCode==0 ){
2200 zPCode = mprintf("%b", &xfer.aToken[2]);
2201 db_set("project-code", zPCode, 0);
2202 }
2203
+2 -5
--- src/zip.c
+++ src/zip.c
@@ -339,11 +339,11 @@
339339
content_get(rid, &mfile);
340340
if( blob_size(&mfile)==0 ){
341341
blob_zero(pZip);
342342
return;
343343
}
344
- blob_zero(&hash);
344
+ blob_set_dynamic(&hash, rid_to_uuid(rid));
345345
blob_zero(&filename);
346346
zip_open();
347347
348348
if( zDir && zDir[0] ){
349349
blob_appendf(&filename, "%s/", zDir);
@@ -378,13 +378,10 @@
378378
if( eflg & MFESTFLG_RAW ){
379379
blob_append(&filename, "manifest", -1);
380380
zName = blob_str(&filename);
381381
zip_add_folders(zName);
382382
}
383
- if( eflg & MFESTFLG_UUID ){
384
- sha1sum_blob(&mfile, &hash);
385
- }
386383
if( eflg & MFESTFLG_RAW ){
387384
sterilize_manifest(&mfile);
388385
zip_add_file(zName, &mfile, 0);
389386
}
390387
}
@@ -394,11 +391,10 @@
394391
blob_resize(&filename, nPrefix);
395392
blob_append(&filename, "manifest.uuid", -1);
396393
zName = blob_str(&filename);
397394
zip_add_folders(zName);
398395
zip_add_file(zName, &hash, 0);
399
- blob_reset(&hash);
400396
}
401397
if( eflg & MFESTFLG_TAGS ){
402398
Blob tagslist;
403399
blob_zero(&tagslist);
404400
get_checkin_taglist(rid, &tagslist);
@@ -429,10 +425,11 @@
429425
}else{
430426
blob_reset(&mfile);
431427
}
432428
manifest_destroy(pManifest);
433429
blob_reset(&filename);
430
+ blob_reset(&hash);
434431
zip_close(pZip);
435432
}
436433
437434
/*
438435
** COMMAND: zip*
439436
--- src/zip.c
+++ src/zip.c
@@ -339,11 +339,11 @@
339 content_get(rid, &mfile);
340 if( blob_size(&mfile)==0 ){
341 blob_zero(pZip);
342 return;
343 }
344 blob_zero(&hash);
345 blob_zero(&filename);
346 zip_open();
347
348 if( zDir && zDir[0] ){
349 blob_appendf(&filename, "%s/", zDir);
@@ -378,13 +378,10 @@
378 if( eflg & MFESTFLG_RAW ){
379 blob_append(&filename, "manifest", -1);
380 zName = blob_str(&filename);
381 zip_add_folders(zName);
382 }
383 if( eflg & MFESTFLG_UUID ){
384 sha1sum_blob(&mfile, &hash);
385 }
386 if( eflg & MFESTFLG_RAW ){
387 sterilize_manifest(&mfile);
388 zip_add_file(zName, &mfile, 0);
389 }
390 }
@@ -394,11 +391,10 @@
394 blob_resize(&filename, nPrefix);
395 blob_append(&filename, "manifest.uuid", -1);
396 zName = blob_str(&filename);
397 zip_add_folders(zName);
398 zip_add_file(zName, &hash, 0);
399 blob_reset(&hash);
400 }
401 if( eflg & MFESTFLG_TAGS ){
402 Blob tagslist;
403 blob_zero(&tagslist);
404 get_checkin_taglist(rid, &tagslist);
@@ -429,10 +425,11 @@
429 }else{
430 blob_reset(&mfile);
431 }
432 manifest_destroy(pManifest);
433 blob_reset(&filename);
 
434 zip_close(pZip);
435 }
436
437 /*
438 ** COMMAND: zip*
439
--- src/zip.c
+++ src/zip.c
@@ -339,11 +339,11 @@
339 content_get(rid, &mfile);
340 if( blob_size(&mfile)==0 ){
341 blob_zero(pZip);
342 return;
343 }
344 blob_set_dynamic(&hash, rid_to_uuid(rid));
345 blob_zero(&filename);
346 zip_open();
347
348 if( zDir && zDir[0] ){
349 blob_appendf(&filename, "%s/", zDir);
@@ -378,13 +378,10 @@
378 if( eflg & MFESTFLG_RAW ){
379 blob_append(&filename, "manifest", -1);
380 zName = blob_str(&filename);
381 zip_add_folders(zName);
382 }
 
 
 
383 if( eflg & MFESTFLG_RAW ){
384 sterilize_manifest(&mfile);
385 zip_add_file(zName, &mfile, 0);
386 }
387 }
@@ -394,11 +391,10 @@
391 blob_resize(&filename, nPrefix);
392 blob_append(&filename, "manifest.uuid", -1);
393 zName = blob_str(&filename);
394 zip_add_folders(zName);
395 zip_add_file(zName, &hash, 0);
 
396 }
397 if( eflg & MFESTFLG_TAGS ){
398 Blob tagslist;
399 blob_zero(&tagslist);
400 get_checkin_taglist(rid, &tagslist);
@@ -429,10 +425,11 @@
425 }else{
426 blob_reset(&mfile);
427 }
428 manifest_destroy(pManifest);
429 blob_reset(&filename);
430 blob_reset(&hash);
431 zip_close(pZip);
432 }
433
434 /*
435 ** COMMAND: zip*
436
+10 -4
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
2828
2929
SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
3030
3131
SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
3232
33
-SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c sha3_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
33
+SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c sha3_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
3434
35
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
35
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
3636
3737
3838
RC=$(DMDIR)\bin\rcc
3939
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
4040
@@ -49,11 +49,11 @@
4949
5050
$(OBJDIR)\fossil.res: $B\win\fossil.rc
5151
$(RC) $(RCFLAGS) -o$@ $**
5252
5353
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54
- +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd dispatch doc encode event export file finfo foci fshell fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 sha3 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
54
+ +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd dispatch doc encode event export file finfo foci fshell fusefs glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 sha3 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
5555
+echo fossil >> $@
5656
+echo fossil >> $@
5757
+echo $(LIBS) >> $@
5858
+echo. >> $@
5959
+echo fossil >> $@
@@ -356,10 +356,16 @@
356356
$(OBJDIR)\gzip$O : gzip_.c gzip.h
357357
$(TCC) -o$@ -c gzip_.c
358358
359359
gzip_.c : $(SRCDIR)\gzip.c
360360
+translate$E $** > $@
361
+
362
+$(OBJDIR)\hname$O : hname_.c hname.h
363
+ $(TCC) -o$@ -c hname_.c
364
+
365
+hname_.c : $(SRCDIR)\hname.c
366
+ +translate$E $** > $@
361367
362368
$(OBJDIR)\http$O : http_.c http.h
363369
$(TCC) -o$@ -c http_.c
364370
365371
http_.c : $(SRCDIR)\http.c
@@ -862,7 +868,7 @@
862868
863869
zip_.c : $(SRCDIR)\zip.c
864870
+translate$E $** > $@
865871
866872
headers: makeheaders$E page_index.h builtin_data.h VERSION.h
867
- +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
873
+ +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
868874
@copy /Y nul: headers
869875
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c sha3_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd dispatch doc encode event export file finfo foci fshell fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 sha3 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -356,10 +356,16 @@
356 $(OBJDIR)\gzip$O : gzip_.c gzip.h
357 $(TCC) -o$@ -c gzip_.c
358
359 gzip_.c : $(SRCDIR)\gzip.c
360 +translate$E $** > $@
 
 
 
 
 
 
361
362 $(OBJDIR)\http$O : http_.c http.h
363 $(TCC) -o$@ -c http_.c
364
365 http_.c : $(SRCDIR)\http.c
@@ -862,7 +868,7 @@
862
863 zip_.c : $(SRCDIR)\zip.c
864 +translate$E $** > $@
865
866 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
867 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
868 @copy /Y nul: headers
869
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c sha3_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd dispatch doc encode event export file finfo foci fshell fusefs glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 sha3 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -356,10 +356,16 @@
356 $(OBJDIR)\gzip$O : gzip_.c gzip.h
357 $(TCC) -o$@ -c gzip_.c
358
359 gzip_.c : $(SRCDIR)\gzip.c
360 +translate$E $** > $@
361
362 $(OBJDIR)\hname$O : hname_.c hname.h
363 $(TCC) -o$@ -c hname_.c
364
365 hname_.c : $(SRCDIR)\hname.c
366 +translate$E $** > $@
367
368 $(OBJDIR)\http$O : http_.c http.h
369 $(TCC) -o$@ -c http_.c
370
371 http_.c : $(SRCDIR)\http.c
@@ -862,7 +868,7 @@
868
869 zip_.c : $(SRCDIR)\zip.c
870 +translate$E $** > $@
871
872 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
873 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
874 @copy /Y nul: headers
875
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -461,10 +461,11 @@
461461
$(SRCDIR)/fshell.c \
462462
$(SRCDIR)/fusefs.c \
463463
$(SRCDIR)/glob.c \
464464
$(SRCDIR)/graph.c \
465465
$(SRCDIR)/gzip.c \
466
+ $(SRCDIR)/hname.c \
466467
$(SRCDIR)/http.c \
467468
$(SRCDIR)/http_socket.c \
468469
$(SRCDIR)/http_ssl.c \
469470
$(SRCDIR)/http_transport.c \
470471
$(SRCDIR)/import.c \
@@ -637,10 +638,11 @@
637638
$(OBJDIR)/fshell_.c \
638639
$(OBJDIR)/fusefs_.c \
639640
$(OBJDIR)/glob_.c \
640641
$(OBJDIR)/graph_.c \
641642
$(OBJDIR)/gzip_.c \
643
+ $(OBJDIR)/hname_.c \
642644
$(OBJDIR)/http_.c \
643645
$(OBJDIR)/http_socket_.c \
644646
$(OBJDIR)/http_ssl_.c \
645647
$(OBJDIR)/http_transport_.c \
646648
$(OBJDIR)/import_.c \
@@ -762,10 +764,11 @@
762764
$(OBJDIR)/fshell.o \
763765
$(OBJDIR)/fusefs.o \
764766
$(OBJDIR)/glob.o \
765767
$(OBJDIR)/graph.o \
766768
$(OBJDIR)/gzip.o \
769
+ $(OBJDIR)/hname.o \
767770
$(OBJDIR)/http.o \
768771
$(OBJDIR)/http_socket.o \
769772
$(OBJDIR)/http_ssl.o \
770773
$(OBJDIR)/http_transport.o \
771774
$(OBJDIR)/import.o \
@@ -1098,10 +1101,11 @@
10981101
$(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
10991102
$(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
11001103
$(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
11011104
$(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
11021105
$(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
1106
+ $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \
11031107
$(OBJDIR)/http_.c:$(OBJDIR)/http.h \
11041108
$(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
11051109
$(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
11061110
$(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
11071111
$(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1502,10 +1506,18 @@
15021506
15031507
$(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
15041508
$(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
15051509
15061510
$(OBJDIR)/gzip.h: $(OBJDIR)/headers
1511
+
1512
+$(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(TRANSLATE)
1513
+ $(TRANSLATE) $(SRCDIR)/hname.c >$@
1514
+
1515
+$(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h
1516
+ $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c
1517
+
1518
+$(OBJDIR)/hname.h: $(OBJDIR)/headers
15071519
15081520
$(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE)
15091521
$(TRANSLATE) $(SRCDIR)/http.c >$@
15101522
15111523
$(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
15121524
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -461,10 +461,11 @@
461 $(SRCDIR)/fshell.c \
462 $(SRCDIR)/fusefs.c \
463 $(SRCDIR)/glob.c \
464 $(SRCDIR)/graph.c \
465 $(SRCDIR)/gzip.c \
 
466 $(SRCDIR)/http.c \
467 $(SRCDIR)/http_socket.c \
468 $(SRCDIR)/http_ssl.c \
469 $(SRCDIR)/http_transport.c \
470 $(SRCDIR)/import.c \
@@ -637,10 +638,11 @@
637 $(OBJDIR)/fshell_.c \
638 $(OBJDIR)/fusefs_.c \
639 $(OBJDIR)/glob_.c \
640 $(OBJDIR)/graph_.c \
641 $(OBJDIR)/gzip_.c \
 
642 $(OBJDIR)/http_.c \
643 $(OBJDIR)/http_socket_.c \
644 $(OBJDIR)/http_ssl_.c \
645 $(OBJDIR)/http_transport_.c \
646 $(OBJDIR)/import_.c \
@@ -762,10 +764,11 @@
762 $(OBJDIR)/fshell.o \
763 $(OBJDIR)/fusefs.o \
764 $(OBJDIR)/glob.o \
765 $(OBJDIR)/graph.o \
766 $(OBJDIR)/gzip.o \
 
767 $(OBJDIR)/http.o \
768 $(OBJDIR)/http_socket.o \
769 $(OBJDIR)/http_ssl.o \
770 $(OBJDIR)/http_transport.o \
771 $(OBJDIR)/import.o \
@@ -1098,10 +1101,11 @@
1098 $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
1099 $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
1100 $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
1101 $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
1102 $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
 
1103 $(OBJDIR)/http_.c:$(OBJDIR)/http.h \
1104 $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
1105 $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
1106 $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
1107 $(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1502,10 +1506,18 @@
1502
1503 $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
1504 $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
1505
1506 $(OBJDIR)/gzip.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1507
1508 $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE)
1509 $(TRANSLATE) $(SRCDIR)/http.c >$@
1510
1511 $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
1512
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -461,10 +461,11 @@
461 $(SRCDIR)/fshell.c \
462 $(SRCDIR)/fusefs.c \
463 $(SRCDIR)/glob.c \
464 $(SRCDIR)/graph.c \
465 $(SRCDIR)/gzip.c \
466 $(SRCDIR)/hname.c \
467 $(SRCDIR)/http.c \
468 $(SRCDIR)/http_socket.c \
469 $(SRCDIR)/http_ssl.c \
470 $(SRCDIR)/http_transport.c \
471 $(SRCDIR)/import.c \
@@ -637,10 +638,11 @@
638 $(OBJDIR)/fshell_.c \
639 $(OBJDIR)/fusefs_.c \
640 $(OBJDIR)/glob_.c \
641 $(OBJDIR)/graph_.c \
642 $(OBJDIR)/gzip_.c \
643 $(OBJDIR)/hname_.c \
644 $(OBJDIR)/http_.c \
645 $(OBJDIR)/http_socket_.c \
646 $(OBJDIR)/http_ssl_.c \
647 $(OBJDIR)/http_transport_.c \
648 $(OBJDIR)/import_.c \
@@ -762,10 +764,11 @@
764 $(OBJDIR)/fshell.o \
765 $(OBJDIR)/fusefs.o \
766 $(OBJDIR)/glob.o \
767 $(OBJDIR)/graph.o \
768 $(OBJDIR)/gzip.o \
769 $(OBJDIR)/hname.o \
770 $(OBJDIR)/http.o \
771 $(OBJDIR)/http_socket.o \
772 $(OBJDIR)/http_ssl.o \
773 $(OBJDIR)/http_transport.o \
774 $(OBJDIR)/import.o \
@@ -1098,10 +1101,11 @@
1101 $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \
1102 $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \
1103 $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \
1104 $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \
1105 $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \
1106 $(OBJDIR)/hname_.c:$(OBJDIR)/hname.h \
1107 $(OBJDIR)/http_.c:$(OBJDIR)/http.h \
1108 $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h \
1109 $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h \
1110 $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h \
1111 $(OBJDIR)/import_.c:$(OBJDIR)/import.h \
@@ -1502,10 +1506,18 @@
1506
1507 $(OBJDIR)/gzip.o: $(OBJDIR)/gzip_.c $(OBJDIR)/gzip.h $(SRCDIR)/config.h
1508 $(XTCC) -o $(OBJDIR)/gzip.o -c $(OBJDIR)/gzip_.c
1509
1510 $(OBJDIR)/gzip.h: $(OBJDIR)/headers
1511
1512 $(OBJDIR)/hname_.c: $(SRCDIR)/hname.c $(TRANSLATE)
1513 $(TRANSLATE) $(SRCDIR)/hname.c >$@
1514
1515 $(OBJDIR)/hname.o: $(OBJDIR)/hname_.c $(OBJDIR)/hname.h $(SRCDIR)/config.h
1516 $(XTCC) -o $(OBJDIR)/hname.o -c $(OBJDIR)/hname_.c
1517
1518 $(OBJDIR)/hname.h: $(OBJDIR)/headers
1519
1520 $(OBJDIR)/http_.c: $(SRCDIR)/http.c $(TRANSLATE)
1521 $(TRANSLATE) $(SRCDIR)/http.c >$@
1522
1523 $(OBJDIR)/http.o: $(OBJDIR)/http_.c $(OBJDIR)/http.h $(SRCDIR)/config.h
1524
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -386,10 +386,11 @@
386386
fshell_.c \
387387
fusefs_.c \
388388
glob_.c \
389389
graph_.c \
390390
gzip_.c \
391
+ hname_.c \
391392
http_.c \
392393
http_socket_.c \
393394
http_ssl_.c \
394395
http_transport_.c \
395396
import_.c \
@@ -561,10 +562,11 @@
561562
$(OX)\fshell$O \
562563
$(OX)\fusefs$O \
563564
$(OX)\glob$O \
564565
$(OX)\graph$O \
565566
$(OX)\gzip$O \
567
+ $(OX)\hname$O \
566568
$(OX)\http$O \
567569
$(OX)\http_socket$O \
568570
$(OX)\http_ssl$O \
569571
$(OX)\http_transport$O \
570572
$(OX)\import$O \
@@ -745,10 +747,11 @@
745747
echo $(OX)\fshell.obj >> $@
746748
echo $(OX)\fusefs.obj >> $@
747749
echo $(OX)\glob.obj >> $@
748750
echo $(OX)\graph.obj >> $@
749751
echo $(OX)\gzip.obj >> $@
752
+ echo $(OX)\hname.obj >> $@
750753
echo $(OX)\http.obj >> $@
751754
echo $(OX)\http_socket.obj >> $@
752755
echo $(OX)\http_ssl.obj >> $@
753756
echo $(OX)\http_transport.obj >> $@
754757
echo $(OX)\import.obj >> $@
@@ -1178,10 +1181,16 @@
11781181
$(OX)\gzip$O : gzip_.c gzip.h
11791182
$(TCC) /Fo$@ -c gzip_.c
11801183
11811184
gzip_.c : $(SRCDIR)\gzip.c
11821185
translate$E $** > $@
1186
+
1187
+$(OX)\hname$O : hname_.c hname.h
1188
+ $(TCC) /Fo$@ -c hname_.c
1189
+
1190
+hname_.c : $(SRCDIR)\hname.c
1191
+ translate$E $** > $@
11831192
11841193
$(OX)\http$O : http_.c http.h
11851194
$(TCC) /Fo$@ -c http_.c
11861195
11871196
http_.c : $(SRCDIR)\http.c
@@ -1726,10 +1735,11 @@
17261735
fshell_.c:fshell.h \
17271736
fusefs_.c:fusefs.h \
17281737
glob_.c:glob.h \
17291738
graph_.c:graph.h \
17301739
gzip_.c:gzip.h \
1740
+ hname_.c:hname.h \
17311741
http_.c:http.h \
17321742
http_socket_.c:http_socket.h \
17331743
http_ssl_.c:http_ssl.h \
17341744
http_transport_.c:http_transport.h \
17351745
import_.c:import.h \
17361746
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -386,10 +386,11 @@
386 fshell_.c \
387 fusefs_.c \
388 glob_.c \
389 graph_.c \
390 gzip_.c \
 
391 http_.c \
392 http_socket_.c \
393 http_ssl_.c \
394 http_transport_.c \
395 import_.c \
@@ -561,10 +562,11 @@
561 $(OX)\fshell$O \
562 $(OX)\fusefs$O \
563 $(OX)\glob$O \
564 $(OX)\graph$O \
565 $(OX)\gzip$O \
 
566 $(OX)\http$O \
567 $(OX)\http_socket$O \
568 $(OX)\http_ssl$O \
569 $(OX)\http_transport$O \
570 $(OX)\import$O \
@@ -745,10 +747,11 @@
745 echo $(OX)\fshell.obj >> $@
746 echo $(OX)\fusefs.obj >> $@
747 echo $(OX)\glob.obj >> $@
748 echo $(OX)\graph.obj >> $@
749 echo $(OX)\gzip.obj >> $@
 
750 echo $(OX)\http.obj >> $@
751 echo $(OX)\http_socket.obj >> $@
752 echo $(OX)\http_ssl.obj >> $@
753 echo $(OX)\http_transport.obj >> $@
754 echo $(OX)\import.obj >> $@
@@ -1178,10 +1181,16 @@
1178 $(OX)\gzip$O : gzip_.c gzip.h
1179 $(TCC) /Fo$@ -c gzip_.c
1180
1181 gzip_.c : $(SRCDIR)\gzip.c
1182 translate$E $** > $@
 
 
 
 
 
 
1183
1184 $(OX)\http$O : http_.c http.h
1185 $(TCC) /Fo$@ -c http_.c
1186
1187 http_.c : $(SRCDIR)\http.c
@@ -1726,10 +1735,11 @@
1726 fshell_.c:fshell.h \
1727 fusefs_.c:fusefs.h \
1728 glob_.c:glob.h \
1729 graph_.c:graph.h \
1730 gzip_.c:gzip.h \
 
1731 http_.c:http.h \
1732 http_socket_.c:http_socket.h \
1733 http_ssl_.c:http_ssl.h \
1734 http_transport_.c:http_transport.h \
1735 import_.c:import.h \
1736
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -386,10 +386,11 @@
386 fshell_.c \
387 fusefs_.c \
388 glob_.c \
389 graph_.c \
390 gzip_.c \
391 hname_.c \
392 http_.c \
393 http_socket_.c \
394 http_ssl_.c \
395 http_transport_.c \
396 import_.c \
@@ -561,10 +562,11 @@
562 $(OX)\fshell$O \
563 $(OX)\fusefs$O \
564 $(OX)\glob$O \
565 $(OX)\graph$O \
566 $(OX)\gzip$O \
567 $(OX)\hname$O \
568 $(OX)\http$O \
569 $(OX)\http_socket$O \
570 $(OX)\http_ssl$O \
571 $(OX)\http_transport$O \
572 $(OX)\import$O \
@@ -745,10 +747,11 @@
747 echo $(OX)\fshell.obj >> $@
748 echo $(OX)\fusefs.obj >> $@
749 echo $(OX)\glob.obj >> $@
750 echo $(OX)\graph.obj >> $@
751 echo $(OX)\gzip.obj >> $@
752 echo $(OX)\hname.obj >> $@
753 echo $(OX)\http.obj >> $@
754 echo $(OX)\http_socket.obj >> $@
755 echo $(OX)\http_ssl.obj >> $@
756 echo $(OX)\http_transport.obj >> $@
757 echo $(OX)\import.obj >> $@
@@ -1178,10 +1181,16 @@
1181 $(OX)\gzip$O : gzip_.c gzip.h
1182 $(TCC) /Fo$@ -c gzip_.c
1183
1184 gzip_.c : $(SRCDIR)\gzip.c
1185 translate$E $** > $@
1186
1187 $(OX)\hname$O : hname_.c hname.h
1188 $(TCC) /Fo$@ -c hname_.c
1189
1190 hname_.c : $(SRCDIR)\hname.c
1191 translate$E $** > $@
1192
1193 $(OX)\http$O : http_.c http.h
1194 $(TCC) /Fo$@ -c http_.c
1195
1196 http_.c : $(SRCDIR)\http.c
@@ -1726,10 +1735,11 @@
1735 fshell_.c:fshell.h \
1736 fusefs_.c:fusefs.h \
1737 glob_.c:glob.h \
1738 graph_.c:graph.h \
1739 gzip_.c:gzip.h \
1740 hname_.c:hname.h \
1741 http_.c:http.h \
1742 http_socket_.c:http_socket.h \
1743 http_ssl_.c:http_ssl.h \
1744 http_transport_.c:http_transport.h \
1745 import_.c:import.h \
1746
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,13 @@
11
<title>Change Log</title>
22
3
-<a name='v1_38'></a>
4
-<h2>Changes for Version 1.38 (2017-??-??)</h2>
3
+<a name='v2_0'></a>
4
+<h2>Changes for Version 2.0 (2017-03-??)</h2>
55
6
+ * Added support for SHA3 hashes used as
7
+ [./fileformat.wiki#names|artifact names].
8
+ * Added support for the [/help?cmd=sha3sum|sha3sum] command.
69
* Update the built-in SQLite to version 3.17.0.
710
811
<a name='v1_37'></a>
912
<h2>Changes for Version 1.37 (2017-01-16)</h2>
1013
1114
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,13 @@
1 <title>Change Log</title>
2
3 <a name='v1_38'></a>
4 <h2>Changes for Version 1.38 (2017-??-??)</h2>
5
 
 
 
6 * Update the built-in SQLite to version 3.17.0.
7
8 <a name='v1_37'></a>
9 <h2>Changes for Version 1.37 (2017-01-16)</h2>
10
11
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,13 @@
1 <title>Change Log</title>
2
3 <a name='v2_0'></a>
4 <h2>Changes for Version 2.0 (2017-03-??)</h2>
5
6 * Added support for SHA3 hashes used as
7 [./fileformat.wiki#names|artifact names].
8 * Added support for the [/help?cmd=sha3sum|sha3sum] command.
9 * Update the built-in SQLite to version 3.17.0.
10
11 <a name='v1_37'></a>
12 <h2>Changes for Version 1.37 (2017-01-16)</h2>
13
14
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -9,14 +9,19 @@
99
searchable, and extensible by people not yet born.
1010
1111
The global state of a fossil repository is an unordered
1212
set of <i>artifacts</i>.
1313
An artifact might be a source code file, the text of a wiki page,
14
-part of a trouble ticket, or one of several special control artifacts
15
-used to show the relationships between other artifacts within the
16
-project. Each artifact is normally represented on disk as a separate
17
-file. Artifacts can be text or binary.
14
+part of a trouble ticket, a description of a check-in including all
15
+the files in that check-in with the check-in comment and so forth.
16
+Artifacts are broadly grouped into two types: content artifacts and
17
+structural artifacts. Content artifacts are the raw project source-code
18
+files that are checked into the repository. Structural artifacts have
19
+special formatting rules and are used to show the relationships between
20
+other artifacts in the repository. It is possible for an artifact to
21
+be both a structure artifact and a content artifact, though this is
22
+rare. Artifacts can be text or binary.
1823
1924
In addition to the global state,
2025
each fossil repository also contains local state.
2126
The local state consists of web-page formatting
2227
preferences, authorized users, ticket display and reporting formats,
@@ -27,18 +32,45 @@
2732
with the global state.
2833
The local state is not composed of artifacts and is not intended to be enduring.
2934
This document is concerned with global state only. Local state is only
3035
mentioned here in order to distinguish it from global state.
3136
32
-Each artifact in the repository is named by its SHA1 hash.
33
-No prefixes or meta information is added to an artifact before
34
-its hash is computed. The name of an artifact in the repository
35
-is exactly the same SHA1 hash that is computed by sha1sum
36
-on the file as it exists in your source tree.</p>
37
-
38
-Some artifacts have a particular format which gives them special
39
-meaning to fossil. Fossil recognizes:
37
+<a name="names"></a>
38
+<h2>1.0 Artifact Names</h2>
39
+
40
+Each artifact in the repository is named by a hash of its content.
41
+No prefixes, suffixes, or other information is added to an artifact before
42
+the hash is computed. The artifact name is just the (lower-case
43
+hexadecimal) hash of the raw artifact.
44
+
45
+Fossil supports multiple hash algorithms including SHA1 and various
46
+lengths of SHA3. Because an artifact can be hashed using multiple algorithms,
47
+a single artifact can have multiple names. Usually, Fossil knows
48
+each artifact by just a single name called the "display name". But it is
49
+possible for Fossil to know an artifact by multiple names from different
50
+hashes. In that case, Fossil uses the display name for output, but continues
51
+to accept the alternative names as command-line arguments or as parameters to
52
+webpage URLs.
53
+
54
+When referring to artifacts in using tty commands or webpage URLs, it is
55
+sufficient to specify a unique prefix for the artifact name. If the input
56
+prefix is not unique, Fossil will show an error. Within a structural
57
+artifact, however, all references to other artifacts must be the complete
58
+hash.
59
+
60
+Prior to Fossil version 2.0, all names were formed from the SHA1 hash of
61
+the artifact. The key innovation in Fossil 2.0 was adding support for
62
+alternative hash algorithms.
63
+
64
+<a name="structural"></a>
65
+<h2>2.0 Structural Artifacts</h2>
66
+
67
+A structural artifact is an artifact that has a particular format and
68
+that is used to define the relationships between other artifacts in the
69
+repository.
70
+Fossil recognizes the following kinds of structural
71
+artifacts:
4072
4173
<ul>
4274
<li> [#manifest | Manifests] </li>
4375
<li> [#cluster | Clusters] </li>
4476
<li> [#ctrl | Control Artifacts] </li>
@@ -46,66 +78,55 @@
4678
<li> [#tktchng | Ticket Changes] </li>
4779
<li> [#attachment | Attachments] </li>
4880
<li> [#event | TechNotes] </li>
4981
</ul>
5082
51
-These seven artifact types are described in the following sections.
83
+These seven structural artifact types are described in subsections below.
5284
53
-In the current implementation (as of 2009-01-25) the artifacts that
85
+Structural artifacts are ASCII text. The artifact may be PGP clearsigned.
86
+After removal of the PGP clearsign header and suffix (if any) a structural
87
+artifact consists of one or more "cards" separated by a single newline
88
+(ASCII: 0x0a) character. Each card begins with a single
89
+character "card type". Zero or more arguments may follow
90
+the card type. All arguments are separated from each other
91
+and from the card-type character by a single space
92
+character. There is no surplus white space between arguments
93
+and no leading or trailing whitespace except for the newline
94
+character that acts as the card separator. All cards must be in strict
95
+lexicographical order. There may not be any duplicate cards.
96
+
97
+In the current implementation (as of 2017-02-27) the artifacts that
5498
make up a fossil repository are stored as delta- and zlib-compressed
5599
blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56100
is an implementation detail and might change in a future release. For
57101
the purpose of this article "file format" means the format of the artifacts,
58102
not how the artifacts are stored on disk. It is the artifact format that
59103
is intended to be enduring. The specifics of how artifacts are stored on
60104
disk, though stable, is not intended to live as long as the
61105
artifact format.
62106
63
-All of the artifacts can be extracted from a Fossil repository using
64
-the "fossil deconstruct" command.
65
-
66107
<a name="manifest"></a>
67
-<h2>1.0 The Manifest</h2>
108
+<h3>2.1 The Manifest</h3>
68109
69
-A manifest defines a check-in or version of the project
70
-source tree. The manifest contains a list of artifacts for
110
+A manifest defines a check-in.
111
+A manifest contains a list of artifacts for
71112
each file in the project and the corresponding filenames, as
72
-well as information such as parent check-ins, the name of the
113
+well as information such as parent check-ins, the username of the
73114
programmer who created the check-in, the date and time when
74115
the check-in was created, and any check-in comments associated
75116
with the check-in.
76117
77
-Any artifact in the repository that follows the syntactic rules
78
-of a manifest is a manifest. Note that a manifest can
79
-be both a real manifest and also a content file, though this
80
-is rare.
81
-
82
-A manifest is a text file. Newline characters
83
-(ASCII 0x0a) separate the file into "cards".
84
-Each card begins with a single
85
-character "card type". Zero or more arguments may follow
86
-the card type. All arguments are separated from each other
87
-and from the card-type character by a single space
88
-character. There is no surplus white space between arguments
89
-and no leading or trailing whitespace except for the newline
90
-character that acts as the card separator.
91
-
92
-All cards of the manifest occur in strict sorted lexicographical order.
93
-No card may be duplicated.
94
-The entire manifest may be PGP clear-signed, but otherwise it
95
-may contain no additional text or data beyond what is described here.
96
-
97118
Allowed cards in the manifest are as follows:
98119
99120
<blockquote>
100121
<b>B</b> <i>baseline-manifest</i><br>
101122
<b>C</b> <i>checkin-comment</i><br>
102123
<b>D</b> <i>time-and-date-stamp</i><br>
103
-<b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
124
+<b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
104125
<b>N</b> <i>mimetype</i><br>
105
-<b>P</b> <i>SHA1-hash</i>+<br>
106
-<b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br>
126
+<b>P</b> <i>artifact-hash</i>+<br>
127
+<b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br>
107128
<b>R</b> <i>repository-checksum</i><br>
108129
<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
109130
<b>U</b> <i>user-login</i><br>
110131
<b>Z</b> <i>manifest-checksum</i>
111132
</blockquote>
@@ -145,11 +166,11 @@
145166
check-in relative to the root of the project file hierarchy. No ".."
146167
or "." directories are allowed within the filename. Space characters
147168
are escaped as in C-card comment text. Backslash characters and
148169
newlines are not allowed within filenames. The directory separator
149170
character is a forward slash (ASCII 0x2F). The second argument to the
150
-F-card is the full 40-character lower-case hexadecimal SHA1 hash of
171
+F-card is the lower-case hexadecimal artifact hash of
151172
the content artifact. The second argument is required for baseline
152173
manifests but is optional for delta manifests. When the second
153174
argument to the F-card is omitted, it means that the file has been
154175
deleted relative to the baseline (files removed in baseline manifests
155176
versions are <em>not</em> added as F-cards). The optional 3rd argument
@@ -167,14 +188,14 @@
167188
is used.
168189
169190
A manifest has zero or one P-cards. Most manifests have one P-card.
170191
The P-card has a varying number of arguments that
171192
define other manifests from which the current manifest
172
-is derived. Each argument is a 40-character lowercase
173
-hexadecimal SHA1 of a predecessor manifest. All arguments
193
+is derived. Each argument is a lowercase
194
+hexadecimal artifact hash of a predecessor manifest. All arguments
174195
to the P-card must be unique within that card.
175
-The first argument is the SHA1 of the direct ancestor of the manifest.
196
+The first argument is the artifact hash of the direct ancestor of the manifest.
176197
Other arguments define manifests with which the first was
177198
merged to yield the current manifest. Most manifests have
178199
a P-card with a single argument. The first manifest in the
179200
project has no ancestors and thus has no P-card or (depending
180201
on the Fossil version) an empty P-card (no arguments).
@@ -229,41 +250,27 @@
229250
check-in comment argument to the C-card.
230251
231252
A manifest must have a single Z-card as its last line. The argument
232253
to the Z-card is a 32-character lowercase hexadecimal MD5 hash
233254
of all prior lines of the manifest up to and including the newline
234
-character that immediately precedes the "Z". The Z-card is
255
+character that immediately precedes the "Z", excluding any PGP
256
+clear-signing prefix. The Z-card is
235257
a sanity check to prove that the manifest is well-formed and
236258
consistent.
237259
238260
A sample manifest from Fossil itself can be seen
239261
[/artifact/28987096ac | here].
240262
241263
<a name="cluster"></a>
242
-<h2>2.0 Clusters</h2>
264
+<h3>2.2 Clusters</h3>
243265
244266
A cluster is an artifact that declares the existence of other artifacts.
245267
Clusters are used during repository synchronization to help
246268
reduce network traffic. As such, clusters are an optimization and
247269
may be removed from a repository without loss or damage to the
248270
underlying project code.
249271
250
-Clusters follow a syntax that is very similar to manifests.
251
-A cluster is a line-oriented text file. Newline characters
252
-(ASCII 0x0a) separate the artifact into cards. Each card begins with a single
253
-character "card type". Zero or more arguments may follow
254
-the card type. All arguments are separated from each other
255
-and from the card-type character by a single space
256
-character. There is no surplus white space between arguments
257
-and no leading or trailing whitespace except for the newline
258
-character that acts as the card separator.
259
-All cards of a cluster occur in strict sorted lexicographical order.
260
-No card may be duplicated.
261
-The cluster may not contain additional text or data beyond
262
-what is described here.
263
-Unlike manifests, clusters are never PGP signed.
264
-
265272
Allowed cards in the cluster are as follows:
266273
267274
<blockquote>
268275
<b>M</b> <i>artifact-id</i><br />
269276
<b>Z</b> <i>checksum</i>
@@ -278,20 +285,14 @@
278285
279286
An example cluster from Fossil can be seen
280287
[/artifact/d03dbdd73a2a8 | here].
281288
282289
<a name="ctrl"></a>
283
-<h2>3.0 Control Artifacts</h2>
290
+<h3>2.3 Control Artifacts</h3>
284291
285292
Control artifacts are used to assign properties to other artifacts
286
-within the repository. The basic format of a control artifact is
287
-the same as a manifest or cluster. A control artifact is a text
288
-file divided into cards by newline characters. Each card has a
289
-single-character card type followed by arguments. Spaces separate
290
-the card type and the arguments. No surplus whitespace is allowed.
291
-All cards must occur in strict lexicographical order.
292
-
293
+within the repository.
293294
Allowed cards in a control artifact are as follows:
294295
295296
<blockquote>
296297
<b>D</b> <i>time-and-date-stamp</i><br />
297298
<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
@@ -338,16 +339,15 @@
338339
339340
An example control artifacts can be seen [/info/9d302ccda8 | here].
340341
341342
342343
<a name="wikichng"></a>
343
-<h2>4.0 Wiki Pages</h2>
344
+<h3>2.4 Wiki Pages</h3>
344345
345
-A wiki page is an artifact with a format similar to manifests,
346
-clusters, and control artifacts. The artifact is divided into
347
-cards by newline characters. The format of each card is as in
348
-manifests, clusters, and control artifacts. Wiki artifacts accept
346
+A wiki artifact defines a single version of a
347
+single wiki page.
348
+Wiki artifacts accept
349349
the following card types:
350350
351351
<blockquote>
352352
<b>D</b> <i>time-and-date-stamp</i><br />
353353
<b>L</b> <i>wiki-title</i><br />
@@ -375,11 +375,11 @@
375375
376376
An example wiki artifact can be seen
377377
[/artifact?name=7b2f5fd0e0&txt=1 | here].
378378
379379
<a name="tktchng"></a>
380
-<h2>5.0 Ticket Changes</h2>
380
+<h3>2.5 Ticket Changes</h3>
381381
382382
A ticket-change artifact represents a change to a trouble ticket.
383383
The following cards are allowed on a ticket change artifact:
384384
385385
<blockquote>
@@ -421,11 +421,11 @@
421421
422422
An example ticket-change artifact can be seen
423423
[/artifact/91f1ec6af053 | here].
424424
425425
<a name="attachment"></a>
426
-<h2>6.0 Attachments</h2>
426
+<h3>2.6 Attachments</h3>
427427
428428
An attachment artifact associates some other artifact that is the
429429
attachment (the source artifact) with a ticket or wiki page or
430430
technical note to which
431431
the attachment is connected (the target artifact).
@@ -463,11 +463,11 @@
463463
The Z card is the usual checksum over the rest of the attachment artifact.
464464
The Z card is required.
465465
466466
467467
<a name="event"></a>
468
-<h2>7.0 Technical Notes</h2>
468
+<h3>2.7 Technical Notes</h3>
469469
470470
A technical note or "technote" artifact (formerly known as an "event" artifact)
471471
associates a timeline comment and a page of text
472472
(similar to a wiki page) with a point in time. Technotes can be used
473473
to record project milestones, release notes, blog entries, process
@@ -532,11 +532,11 @@
532532
533533
The Z card is the required checksum over the rest of the artifact.
534534
535535
536536
<a name="summary"></a>
537
-<h2>8.0 Card Summary</h2>
537
+<h2>3.0 Card Summary</h2>
538538
539539
The following table summarizes the various kinds of cards that appear
540540
on Fossil artifacts. A blank entry means that combination of card and
541541
artifact is not legal. A number or range of numbers indicates the number
542542
of times a card may (or must) appear in the corresponding artifact type.
@@ -739,16 +739,16 @@
739739
</tr>
740740
</table>
741741
742742
743743
<a name="addenda"></a>
744
-<h2>9.0 Addenda</h2>
744
+<h2>4.0 Addenda</h2>
745745
746746
This section contains additional information which may be useful when
747747
implementing algorithms described above.
748748
749
-<h3>R Card Hash Calculation</h3>
749
+<h3>4.1 R-Card Hash Calculation</h3>
750750
751751
Given a manifest file named <tt>MF</tt>, the following Bash shell code
752752
demonstrates how to compute the value of the R card in that manifest.
753753
This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
754754
shell input and other lines are output. This demonstration assumes that the
755755
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -9,14 +9,19 @@
9 searchable, and extensible by people not yet born.
10
11 The global state of a fossil repository is an unordered
12 set of <i>artifacts</i>.
13 An artifact might be a source code file, the text of a wiki page,
14 part of a trouble ticket, or one of several special control artifacts
15 used to show the relationships between other artifacts within the
16 project. Each artifact is normally represented on disk as a separate
17 file. Artifacts can be text or binary.
 
 
 
 
 
18
19 In addition to the global state,
20 each fossil repository also contains local state.
21 The local state consists of web-page formatting
22 preferences, authorized users, ticket display and reporting formats,
@@ -27,18 +32,45 @@
27 with the global state.
28 The local state is not composed of artifacts and is not intended to be enduring.
29 This document is concerned with global state only. Local state is only
30 mentioned here in order to distinguish it from global state.
31
32 Each artifact in the repository is named by its SHA1 hash.
33 No prefixes or meta information is added to an artifact before
34 its hash is computed. The name of an artifact in the repository
35 is exactly the same SHA1 hash that is computed by sha1sum
36 on the file as it exists in your source tree.</p>
37
38 Some artifacts have a particular format which gives them special
39 meaning to fossil. Fossil recognizes:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
41 <ul>
42 <li> [#manifest | Manifests] </li>
43 <li> [#cluster | Clusters] </li>
44 <li> [#ctrl | Control Artifacts] </li>
@@ -46,66 +78,55 @@
46 <li> [#tktchng | Ticket Changes] </li>
47 <li> [#attachment | Attachments] </li>
48 <li> [#event | TechNotes] </li>
49 </ul>
50
51 These seven artifact types are described in the following sections.
52
53 In the current implementation (as of 2009-01-25) the artifacts that
 
 
 
 
 
 
 
 
 
 
 
 
54 make up a fossil repository are stored as delta- and zlib-compressed
55 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56 is an implementation detail and might change in a future release. For
57 the purpose of this article "file format" means the format of the artifacts,
58 not how the artifacts are stored on disk. It is the artifact format that
59 is intended to be enduring. The specifics of how artifacts are stored on
60 disk, though stable, is not intended to live as long as the
61 artifact format.
62
63 All of the artifacts can be extracted from a Fossil repository using
64 the "fossil deconstruct" command.
65
66 <a name="manifest"></a>
67 <h2>1.0 The Manifest</h2>
68
69 A manifest defines a check-in or version of the project
70 source tree. The manifest contains a list of artifacts for
71 each file in the project and the corresponding filenames, as
72 well as information such as parent check-ins, the name of the
73 programmer who created the check-in, the date and time when
74 the check-in was created, and any check-in comments associated
75 with the check-in.
76
77 Any artifact in the repository that follows the syntactic rules
78 of a manifest is a manifest. Note that a manifest can
79 be both a real manifest and also a content file, though this
80 is rare.
81
82 A manifest is a text file. Newline characters
83 (ASCII 0x0a) separate the file into "cards".
84 Each card begins with a single
85 character "card type". Zero or more arguments may follow
86 the card type. All arguments are separated from each other
87 and from the card-type character by a single space
88 character. There is no surplus white space between arguments
89 and no leading or trailing whitespace except for the newline
90 character that acts as the card separator.
91
92 All cards of the manifest occur in strict sorted lexicographical order.
93 No card may be duplicated.
94 The entire manifest may be PGP clear-signed, but otherwise it
95 may contain no additional text or data beyond what is described here.
96
97 Allowed cards in the manifest are as follows:
98
99 <blockquote>
100 <b>B</b> <i>baseline-manifest</i><br>
101 <b>C</b> <i>checkin-comment</i><br>
102 <b>D</b> <i>time-and-date-stamp</i><br>
103 <b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
104 <b>N</b> <i>mimetype</i><br>
105 <b>P</b> <i>SHA1-hash</i>+<br>
106 <b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br>
107 <b>R</b> <i>repository-checksum</i><br>
108 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
109 <b>U</b> <i>user-login</i><br>
110 <b>Z</b> <i>manifest-checksum</i>
111 </blockquote>
@@ -145,11 +166,11 @@
145 check-in relative to the root of the project file hierarchy. No ".."
146 or "." directories are allowed within the filename. Space characters
147 are escaped as in C-card comment text. Backslash characters and
148 newlines are not allowed within filenames. The directory separator
149 character is a forward slash (ASCII 0x2F). The second argument to the
150 F-card is the full 40-character lower-case hexadecimal SHA1 hash of
151 the content artifact. The second argument is required for baseline
152 manifests but is optional for delta manifests. When the second
153 argument to the F-card is omitted, it means that the file has been
154 deleted relative to the baseline (files removed in baseline manifests
155 versions are <em>not</em> added as F-cards). The optional 3rd argument
@@ -167,14 +188,14 @@
167 is used.
168
169 A manifest has zero or one P-cards. Most manifests have one P-card.
170 The P-card has a varying number of arguments that
171 define other manifests from which the current manifest
172 is derived. Each argument is a 40-character lowercase
173 hexadecimal SHA1 of a predecessor manifest. All arguments
174 to the P-card must be unique within that card.
175 The first argument is the SHA1 of the direct ancestor of the manifest.
176 Other arguments define manifests with which the first was
177 merged to yield the current manifest. Most manifests have
178 a P-card with a single argument. The first manifest in the
179 project has no ancestors and thus has no P-card or (depending
180 on the Fossil version) an empty P-card (no arguments).
@@ -229,41 +250,27 @@
229 check-in comment argument to the C-card.
230
231 A manifest must have a single Z-card as its last line. The argument
232 to the Z-card is a 32-character lowercase hexadecimal MD5 hash
233 of all prior lines of the manifest up to and including the newline
234 character that immediately precedes the "Z". The Z-card is
 
235 a sanity check to prove that the manifest is well-formed and
236 consistent.
237
238 A sample manifest from Fossil itself can be seen
239 [/artifact/28987096ac | here].
240
241 <a name="cluster"></a>
242 <h2>2.0 Clusters</h2>
243
244 A cluster is an artifact that declares the existence of other artifacts.
245 Clusters are used during repository synchronization to help
246 reduce network traffic. As such, clusters are an optimization and
247 may be removed from a repository without loss or damage to the
248 underlying project code.
249
250 Clusters follow a syntax that is very similar to manifests.
251 A cluster is a line-oriented text file. Newline characters
252 (ASCII 0x0a) separate the artifact into cards. Each card begins with a single
253 character "card type". Zero or more arguments may follow
254 the card type. All arguments are separated from each other
255 and from the card-type character by a single space
256 character. There is no surplus white space between arguments
257 and no leading or trailing whitespace except for the newline
258 character that acts as the card separator.
259 All cards of a cluster occur in strict sorted lexicographical order.
260 No card may be duplicated.
261 The cluster may not contain additional text or data beyond
262 what is described here.
263 Unlike manifests, clusters are never PGP signed.
264
265 Allowed cards in the cluster are as follows:
266
267 <blockquote>
268 <b>M</b> <i>artifact-id</i><br />
269 <b>Z</b> <i>checksum</i>
@@ -278,20 +285,14 @@
278
279 An example cluster from Fossil can be seen
280 [/artifact/d03dbdd73a2a8 | here].
281
282 <a name="ctrl"></a>
283 <h2>3.0 Control Artifacts</h2>
284
285 Control artifacts are used to assign properties to other artifacts
286 within the repository. The basic format of a control artifact is
287 the same as a manifest or cluster. A control artifact is a text
288 file divided into cards by newline characters. Each card has a
289 single-character card type followed by arguments. Spaces separate
290 the card type and the arguments. No surplus whitespace is allowed.
291 All cards must occur in strict lexicographical order.
292
293 Allowed cards in a control artifact are as follows:
294
295 <blockquote>
296 <b>D</b> <i>time-and-date-stamp</i><br />
297 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
@@ -338,16 +339,15 @@
338
339 An example control artifacts can be seen [/info/9d302ccda8 | here].
340
341
342 <a name="wikichng"></a>
343 <h2>4.0 Wiki Pages</h2>
344
345 A wiki page is an artifact with a format similar to manifests,
346 clusters, and control artifacts. The artifact is divided into
347 cards by newline characters. The format of each card is as in
348 manifests, clusters, and control artifacts. Wiki artifacts accept
349 the following card types:
350
351 <blockquote>
352 <b>D</b> <i>time-and-date-stamp</i><br />
353 <b>L</b> <i>wiki-title</i><br />
@@ -375,11 +375,11 @@
375
376 An example wiki artifact can be seen
377 [/artifact?name=7b2f5fd0e0&txt=1 | here].
378
379 <a name="tktchng"></a>
380 <h2>5.0 Ticket Changes</h2>
381
382 A ticket-change artifact represents a change to a trouble ticket.
383 The following cards are allowed on a ticket change artifact:
384
385 <blockquote>
@@ -421,11 +421,11 @@
421
422 An example ticket-change artifact can be seen
423 [/artifact/91f1ec6af053 | here].
424
425 <a name="attachment"></a>
426 <h2>6.0 Attachments</h2>
427
428 An attachment artifact associates some other artifact that is the
429 attachment (the source artifact) with a ticket or wiki page or
430 technical note to which
431 the attachment is connected (the target artifact).
@@ -463,11 +463,11 @@
463 The Z card is the usual checksum over the rest of the attachment artifact.
464 The Z card is required.
465
466
467 <a name="event"></a>
468 <h2>7.0 Technical Notes</h2>
469
470 A technical note or "technote" artifact (formerly known as an "event" artifact)
471 associates a timeline comment and a page of text
472 (similar to a wiki page) with a point in time. Technotes can be used
473 to record project milestones, release notes, blog entries, process
@@ -532,11 +532,11 @@
532
533 The Z card is the required checksum over the rest of the artifact.
534
535
536 <a name="summary"></a>
537 <h2>8.0 Card Summary</h2>
538
539 The following table summarizes the various kinds of cards that appear
540 on Fossil artifacts. A blank entry means that combination of card and
541 artifact is not legal. A number or range of numbers indicates the number
542 of times a card may (or must) appear in the corresponding artifact type.
@@ -739,16 +739,16 @@
739 </tr>
740 </table>
741
742
743 <a name="addenda"></a>
744 <h2>9.0 Addenda</h2>
745
746 This section contains additional information which may be useful when
747 implementing algorithms described above.
748
749 <h3>R Card Hash Calculation</h3>
750
751 Given a manifest file named <tt>MF</tt>, the following Bash shell code
752 demonstrates how to compute the value of the R card in that manifest.
753 This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
754 shell input and other lines are output. This demonstration assumes that the
755
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -9,14 +9,19 @@
9 searchable, and extensible by people not yet born.
10
11 The global state of a fossil repository is an unordered
12 set of <i>artifacts</i>.
13 An artifact might be a source code file, the text of a wiki page,
14 part of a trouble ticket, a description of a check-in including all
15 the files in that check-in with the check-in comment and so forth.
16 Artifacts are broadly grouped into two types: content artifacts and
17 structural artifacts. Content artifacts are the raw project source-code
18 files that are checked into the repository. Structural artifacts have
19 special formatting rules and are used to show the relationships between
20 other artifacts in the repository. It is possible for an artifact to
21 be both a structure artifact and a content artifact, though this is
22 rare. Artifacts can be text or binary.
23
24 In addition to the global state,
25 each fossil repository also contains local state.
26 The local state consists of web-page formatting
27 preferences, authorized users, ticket display and reporting formats,
@@ -27,18 +32,45 @@
32 with the global state.
33 The local state is not composed of artifacts and is not intended to be enduring.
34 This document is concerned with global state only. Local state is only
35 mentioned here in order to distinguish it from global state.
36
37 <a name="names"></a>
38 <h2>1.0 Artifact Names</h2>
39
40 Each artifact in the repository is named by a hash of its content.
41 No prefixes, suffixes, or other information is added to an artifact before
42 the hash is computed. The artifact name is just the (lower-case
43 hexadecimal) hash of the raw artifact.
44
45 Fossil supports multiple hash algorithms including SHA1 and various
46 lengths of SHA3. Because an artifact can be hashed using multiple algorithms,
47 a single artifact can have multiple names. Usually, Fossil knows
48 each artifact by just a single name called the "display name". But it is
49 possible for Fossil to know an artifact by multiple names from different
50 hashes. In that case, Fossil uses the display name for output, but continues
51 to accept the alternative names as command-line arguments or as parameters to
52 webpage URLs.
53
54 When referring to artifacts in using tty commands or webpage URLs, it is
55 sufficient to specify a unique prefix for the artifact name. If the input
56 prefix is not unique, Fossil will show an error. Within a structural
57 artifact, however, all references to other artifacts must be the complete
58 hash.
59
60 Prior to Fossil version 2.0, all names were formed from the SHA1 hash of
61 the artifact. The key innovation in Fossil 2.0 was adding support for
62 alternative hash algorithms.
63
64 <a name="structural"></a>
65 <h2>2.0 Structural Artifacts</h2>
66
67 A structural artifact is an artifact that has a particular format and
68 that is used to define the relationships between other artifacts in the
69 repository.
70 Fossil recognizes the following kinds of structural
71 artifacts:
72
73 <ul>
74 <li> [#manifest | Manifests] </li>
75 <li> [#cluster | Clusters] </li>
76 <li> [#ctrl | Control Artifacts] </li>
@@ -46,66 +78,55 @@
78 <li> [#tktchng | Ticket Changes] </li>
79 <li> [#attachment | Attachments] </li>
80 <li> [#event | TechNotes] </li>
81 </ul>
82
83 These seven structural artifact types are described in subsections below.
84
85 Structural artifacts are ASCII text. The artifact may be PGP clearsigned.
86 After removal of the PGP clearsign header and suffix (if any) a structural
87 artifact consists of one or more "cards" separated by a single newline
88 (ASCII: 0x0a) character. Each card begins with a single
89 character "card type". Zero or more arguments may follow
90 the card type. All arguments are separated from each other
91 and from the card-type character by a single space
92 character. There is no surplus white space between arguments
93 and no leading or trailing whitespace except for the newline
94 character that acts as the card separator. All cards must be in strict
95 lexicographical order. There may not be any duplicate cards.
96
97 In the current implementation (as of 2017-02-27) the artifacts that
98 make up a fossil repository are stored as delta- and zlib-compressed
99 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
100 is an implementation detail and might change in a future release. For
101 the purpose of this article "file format" means the format of the artifacts,
102 not how the artifacts are stored on disk. It is the artifact format that
103 is intended to be enduring. The specifics of how artifacts are stored on
104 disk, though stable, is not intended to live as long as the
105 artifact format.
106
 
 
 
107 <a name="manifest"></a>
108 <h3>2.1 The Manifest</h3>
109
110 A manifest defines a check-in.
111 A manifest contains a list of artifacts for
112 each file in the project and the corresponding filenames, as
113 well as information such as parent check-ins, the username of the
114 programmer who created the check-in, the date and time when
115 the check-in was created, and any check-in comments associated
116 with the check-in.
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118 Allowed cards in the manifest are as follows:
119
120 <blockquote>
121 <b>B</b> <i>baseline-manifest</i><br>
122 <b>C</b> <i>checkin-comment</i><br>
123 <b>D</b> <i>time-and-date-stamp</i><br>
124 <b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
125 <b>N</b> <i>mimetype</i><br>
126 <b>P</b> <i>artifact-hash</i>+<br>
127 <b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br>
128 <b>R</b> <i>repository-checksum</i><br>
129 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
130 <b>U</b> <i>user-login</i><br>
131 <b>Z</b> <i>manifest-checksum</i>
132 </blockquote>
@@ -145,11 +166,11 @@
166 check-in relative to the root of the project file hierarchy. No ".."
167 or "." directories are allowed within the filename. Space characters
168 are escaped as in C-card comment text. Backslash characters and
169 newlines are not allowed within filenames. The directory separator
170 character is a forward slash (ASCII 0x2F). The second argument to the
171 F-card is the lower-case hexadecimal artifact hash of
172 the content artifact. The second argument is required for baseline
173 manifests but is optional for delta manifests. When the second
174 argument to the F-card is omitted, it means that the file has been
175 deleted relative to the baseline (files removed in baseline manifests
176 versions are <em>not</em> added as F-cards). The optional 3rd argument
@@ -167,14 +188,14 @@
188 is used.
189
190 A manifest has zero or one P-cards. Most manifests have one P-card.
191 The P-card has a varying number of arguments that
192 define other manifests from which the current manifest
193 is derived. Each argument is a lowercase
194 hexadecimal artifact hash of a predecessor manifest. All arguments
195 to the P-card must be unique within that card.
196 The first argument is the artifact hash of the direct ancestor of the manifest.
197 Other arguments define manifests with which the first was
198 merged to yield the current manifest. Most manifests have
199 a P-card with a single argument. The first manifest in the
200 project has no ancestors and thus has no P-card or (depending
201 on the Fossil version) an empty P-card (no arguments).
@@ -229,41 +250,27 @@
250 check-in comment argument to the C-card.
251
252 A manifest must have a single Z-card as its last line. The argument
253 to the Z-card is a 32-character lowercase hexadecimal MD5 hash
254 of all prior lines of the manifest up to and including the newline
255 character that immediately precedes the "Z", excluding any PGP
256 clear-signing prefix. The Z-card is
257 a sanity check to prove that the manifest is well-formed and
258 consistent.
259
260 A sample manifest from Fossil itself can be seen
261 [/artifact/28987096ac | here].
262
263 <a name="cluster"></a>
264 <h3>2.2 Clusters</h3>
265
266 A cluster is an artifact that declares the existence of other artifacts.
267 Clusters are used during repository synchronization to help
268 reduce network traffic. As such, clusters are an optimization and
269 may be removed from a repository without loss or damage to the
270 underlying project code.
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272 Allowed cards in the cluster are as follows:
273
274 <blockquote>
275 <b>M</b> <i>artifact-id</i><br />
276 <b>Z</b> <i>checksum</i>
@@ -278,20 +285,14 @@
285
286 An example cluster from Fossil can be seen
287 [/artifact/d03dbdd73a2a8 | here].
288
289 <a name="ctrl"></a>
290 <h3>2.3 Control Artifacts</h3>
291
292 Control artifacts are used to assign properties to other artifacts
293 within the repository.
 
 
 
 
 
 
294 Allowed cards in a control artifact are as follows:
295
296 <blockquote>
297 <b>D</b> <i>time-and-date-stamp</i><br />
298 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
@@ -338,16 +339,15 @@
339
340 An example control artifacts can be seen [/info/9d302ccda8 | here].
341
342
343 <a name="wikichng"></a>
344 <h3>2.4 Wiki Pages</h3>
345
346 A wiki artifact defines a single version of a
347 single wiki page.
348 Wiki artifacts accept
 
349 the following card types:
350
351 <blockquote>
352 <b>D</b> <i>time-and-date-stamp</i><br />
353 <b>L</b> <i>wiki-title</i><br />
@@ -375,11 +375,11 @@
375
376 An example wiki artifact can be seen
377 [/artifact?name=7b2f5fd0e0&txt=1 | here].
378
379 <a name="tktchng"></a>
380 <h3>2.5 Ticket Changes</h3>
381
382 A ticket-change artifact represents a change to a trouble ticket.
383 The following cards are allowed on a ticket change artifact:
384
385 <blockquote>
@@ -421,11 +421,11 @@
421
422 An example ticket-change artifact can be seen
423 [/artifact/91f1ec6af053 | here].
424
425 <a name="attachment"></a>
426 <h3>2.6 Attachments</h3>
427
428 An attachment artifact associates some other artifact that is the
429 attachment (the source artifact) with a ticket or wiki page or
430 technical note to which
431 the attachment is connected (the target artifact).
@@ -463,11 +463,11 @@
463 The Z card is the usual checksum over the rest of the attachment artifact.
464 The Z card is required.
465
466
467 <a name="event"></a>
468 <h3>2.7 Technical Notes</h3>
469
470 A technical note or "technote" artifact (formerly known as an "event" artifact)
471 associates a timeline comment and a page of text
472 (similar to a wiki page) with a point in time. Technotes can be used
473 to record project milestones, release notes, blog entries, process
@@ -532,11 +532,11 @@
532
533 The Z card is the required checksum over the rest of the artifact.
534
535
536 <a name="summary"></a>
537 <h2>3.0 Card Summary</h2>
538
539 The following table summarizes the various kinds of cards that appear
540 on Fossil artifacts. A blank entry means that combination of card and
541 artifact is not legal. A number or range of numbers indicates the number
542 of times a card may (or must) appear in the corresponding artifact type.
@@ -739,16 +739,16 @@
739 </tr>
740 </table>
741
742
743 <a name="addenda"></a>
744 <h2>4.0 Addenda</h2>
745
746 This section contains additional information which may be useful when
747 implementing algorithms described above.
748
749 <h3>4.1 R-Card Hash Calculation</h3>
750
751 Given a manifest file named <tt>MF</tt>, the following Bash shell code
752 demonstrates how to compute the value of the R card in that manifest.
753 This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
754 shell input and other lines are output. This demonstration assumes that the
755

Keyboard Shortcuts

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