Fossil SCM

Enhance the 'reconstruct' command to set the correct hash policy (SHA1 or SHA3-256) for artifacts read from disk, inferred from the length of the path name. Also enhance the 'deconstruct' and 'reconstruct' commands with an option to ensure the artifact with RID=1 is a valid manifest. See the wiki page linked to this branch for more information and tests.

florian 2019-01-28 10:12 trunk
Commit 62a00bc7284a82762e40d75df247c1039e318ff13372aec926bc561ad6024e08
1 file changed +96 -2
+96 -2
--- src/rebuild.c
+++ src/rebuild.c
@@ -182,11 +182,14 @@
182182
static int processCnt; /* Number processed so far */
183183
static int ttyOutput; /* Do progress output */
184184
static Bag bagDone; /* Bag of records rebuilt */
185185
186186
static char *zFNameFormat; /* Format string for filenames on deconstruct */
187
+static int cchFNamePrefix; /* Length of directory prefix in zFNameFormat */
188
+static char *zDestDir; /* Destination directory on deconstruct */
187189
static int prefixLength; /* Length of directory prefix for deconstruct */
190
+static int fKeepRid1; /* Flag to preserve RID=1 on de- and reconstruct */
188191
189192
190193
/*
191194
** Draw the percent-complete message.
192195
** The input is actually the permill complete.
@@ -274,10 +277,21 @@
274277
/* We are doing "fossil deconstruct" */
275278
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
276279
char *zFile = mprintf(zFNameFormat /*works-like:"%s:%s"*/,
277280
zUuid, zUuid+prefixLength);
278281
blob_write_to_file(pUse,zFile);
282
+ if( rid==1 && fKeepRid1!=0 ){
283
+ char *zFnDotRid1 = mprintf("%s/.rid1", zDestDir);
284
+ char *zFnRid1 = zFile + cchFNamePrefix + 1; /* Skip directory slash */
285
+ Blob bFileContents = empty_blob;
286
+ blob_appendf(&bFileContents,
287
+ "# The file holding the artifact with RID=1\n"
288
+ "%s\n", zFnRid1);
289
+ blob_write_to_file(&bFileContents, zFnDotRid1);
290
+ blob_reset(&bFileContents);
291
+ free(zFnDotRid1);
292
+ }
279293
free(zFile);
280294
free(zUuid);
281295
blob_reset(pUse);
282296
}
283297
assert( blob_is_reset(pUse) );
@@ -931,11 +945,50 @@
931945
struct dirent *pEntry;
932946
Blob aContent; /* content of the just read artifact */
933947
static int nFileRead = 0;
934948
void *zUnicodePath;
935949
char *zUtf8Name;
950
+ static int recursionLevel = 0; /* Bookkeeping about the recursion level */
951
+ static char *zFnRid1 = 0; /* The file holding the artifact with RID=1 */
952
+ static int cchPathInitial = 0; /* The length of zPath on first recursion */
936953
954
+ recursionLevel++;
955
+ if( recursionLevel==1 ){
956
+ cchPathInitial = strlen(zPath);
957
+ if( fKeepRid1!=0 ){
958
+ char *zFnDotRid1 = mprintf("%s/.rid1", zPath);
959
+ Blob bFileContents;
960
+ if( blob_read_from_file(&bFileContents, zFnDotRid1, ExtFILE)!=-1 ){
961
+ Blob line, value;
962
+ while( blob_line(&bFileContents, &line)>0 ){
963
+ if( blob_token(&line, &value)==0 ) continue; /* Empty line */
964
+ if( blob_buffer(&value)[0]=='#' ) continue; /* Comment */
965
+ blob_trim(&value);
966
+ zFnRid1 = mprintf("%s/%s", zPath, blob_str(&value));
967
+ break;
968
+ }
969
+ blob_reset(&bFileContents);
970
+ if( zFnRid1 ){
971
+ if( blob_read_from_file(&aContent, zFnRid1, ExtFILE)==-1 ){
972
+ fossil_fatal("some unknown error occurred while reading \"%s\"",
973
+ zFnRid1);
974
+ }else{
975
+ recon_set_hash_policy(0, zFnRid1);
976
+ content_put(&aContent);
977
+ recon_restore_hash_policy();
978
+ blob_reset(&aContent);
979
+ fossil_print("\r%d", ++nFileRead);
980
+ fflush(stdout);
981
+ }
982
+ }else{
983
+ fossil_fatal("an error occurred while reading or parsing \"%s\"",
984
+ zFnDotRid1);
985
+ }
986
+ }
987
+ free(zFnDotRid1);
988
+ }
989
+ }
937990
zUnicodePath = fossil_utf8_to_path(zPath, 1);
938991
d = opendir(zUnicodePath);
939992
if( d ){
940993
while( (pEntry=readdir(d))!=0 ){
941994
Blob path;
@@ -953,18 +1006,20 @@
9531006
#else
9541007
if( file_isdir(zSubpath, ExtFILE)==1 )
9551008
#endif
9561009
{
9571010
recon_read_dir(zSubpath);
958
- }else{
1011
+ }else if( fossil_strcmp(zSubpath, zFnRid1)!=0 ){
9591012
blob_init(&path, 0, 0);
9601013
blob_appendf(&path, "%s", zSubpath);
9611014
if( blob_read_from_file(&aContent, blob_str(&path), ExtFILE)==-1 ){
9621015
fossil_fatal("some unknown error occurred while reading \"%s\"",
9631016
blob_str(&path));
9641017
}
1018
+ recon_set_hash_policy(cchPathInitial, blob_str(&path));
9651019
content_put(&aContent);
1020
+ recon_restore_hash_policy();
9661021
blob_reset(&path);
9671022
blob_reset(&aContent);
9681023
fossil_print("\r%d", ++nFileRead);
9691024
fflush(stdout);
9701025
}
@@ -974,10 +1029,49 @@
9741029
}else {
9751030
fossil_fatal("encountered error %d while trying to open \"%s\".",
9761031
errno, g.argv[3]);
9771032
}
9781033
fossil_path_free(zUnicodePath);
1034
+ if( recursionLevel==1 && zFnRid1!=0 ) free(zFnRid1);
1035
+ recursionLevel--;
1036
+}
1037
+
1038
+/*
1039
+** Helper functions called from recon_read_dir() to set and restore the correct
1040
+** hash policy for an artifact read from disk, inferred from the length of the
1041
+** path name.
1042
+*/
1043
+#define HPOLICY_NOTDEFINED -1
1044
+static int saved_eHashPolicy = HPOLICY_NOTDEFINED;
1045
+
1046
+void recon_set_hash_policy(
1047
+ const int cchPathPrefix, /* Directory prefix length for zUuidAsFilePath */
1048
+ const char *zUuidAsFilePath /* Relative, well-formed, from recon_read_dir() */
1049
+){
1050
+ int cchTotal, cchHashPart;
1051
+ int new_eHashPolicy = HPOLICY_NOTDEFINED;
1052
+ assert( HNAME_COUNT==2 ); /* Review function if new hashes are implemented. */
1053
+ if( zUuidAsFilePath==0 ) return;
1054
+ cchTotal = strlen(zUuidAsFilePath);
1055
+ if( cchTotal==0 ) return;
1056
+ if( cchPathPrefix>=cchTotal) return;
1057
+ cchHashPart = cchTotal - cchPathPrefix;
1058
+ if( cchHashPart>=HNAME_LEN_K256 ){
1059
+ new_eHashPolicy = HPOLICY_SHA3;
1060
+ }else if( cchHashPart>=HNAME_LEN_SHA1 ){
1061
+ new_eHashPolicy = HPOLICY_SHA1;
1062
+ }
1063
+ if( new_eHashPolicy!=HPOLICY_NOTDEFINED ){
1064
+ saved_eHashPolicy = g.eHashPolicy;
1065
+ g.eHashPolicy = new_eHashPolicy;
1066
+ }
1067
+}
1068
+
1069
+void recon_restore_hash_policy(){
1070
+ if( saved_eHashPolicy!=HPOLICY_NOTDEFINED ){
1071
+ g.eHashPolicy = saved_eHashPolicy;
1072
+ }
9791073
}
9801074
9811075
/*
9821076
** COMMAND: reconstruct*
9831077
**
@@ -1049,11 +1143,10 @@
10491143
** --private Include private artifacts.
10501144
**
10511145
** See also: rebuild, reconstruct
10521146
*/
10531147
void deconstruct_cmd(void){
1054
- const char *zDestDir;
10551148
const char *zPrefixOpt;
10561149
Stmt s;
10571150
int privateFlag;
10581151
10591152
/* get and check prefix length argument and build format string */
@@ -1092,10 +1185,11 @@
10921185
if( prefixLength ){
10931186
zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
10941187
}else{
10951188
zFNameFormat = mprintf("%s/%%s",zDestDir);
10961189
}
1190
+ cchFNamePrefix = strlen(zDestDir);
10971191
10981192
bag_init(&bagDone);
10991193
ttyOutput = 1;
11001194
processCnt = 0;
11011195
if (!g.fQuiet) {
11021196
--- src/rebuild.c
+++ src/rebuild.c
@@ -182,11 +182,14 @@
182 static int processCnt; /* Number processed so far */
183 static int ttyOutput; /* Do progress output */
184 static Bag bagDone; /* Bag of records rebuilt */
185
186 static char *zFNameFormat; /* Format string for filenames on deconstruct */
 
 
187 static int prefixLength; /* Length of directory prefix for deconstruct */
 
188
189
190 /*
191 ** Draw the percent-complete message.
192 ** The input is actually the permill complete.
@@ -274,10 +277,21 @@
274 /* We are doing "fossil deconstruct" */
275 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
276 char *zFile = mprintf(zFNameFormat /*works-like:"%s:%s"*/,
277 zUuid, zUuid+prefixLength);
278 blob_write_to_file(pUse,zFile);
 
 
 
 
 
 
 
 
 
 
 
279 free(zFile);
280 free(zUuid);
281 blob_reset(pUse);
282 }
283 assert( blob_is_reset(pUse) );
@@ -931,11 +945,50 @@
931 struct dirent *pEntry;
932 Blob aContent; /* content of the just read artifact */
933 static int nFileRead = 0;
934 void *zUnicodePath;
935 char *zUtf8Name;
 
 
 
936
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
937 zUnicodePath = fossil_utf8_to_path(zPath, 1);
938 d = opendir(zUnicodePath);
939 if( d ){
940 while( (pEntry=readdir(d))!=0 ){
941 Blob path;
@@ -953,18 +1006,20 @@
953 #else
954 if( file_isdir(zSubpath, ExtFILE)==1 )
955 #endif
956 {
957 recon_read_dir(zSubpath);
958 }else{
959 blob_init(&path, 0, 0);
960 blob_appendf(&path, "%s", zSubpath);
961 if( blob_read_from_file(&aContent, blob_str(&path), ExtFILE)==-1 ){
962 fossil_fatal("some unknown error occurred while reading \"%s\"",
963 blob_str(&path));
964 }
 
965 content_put(&aContent);
 
966 blob_reset(&path);
967 blob_reset(&aContent);
968 fossil_print("\r%d", ++nFileRead);
969 fflush(stdout);
970 }
@@ -974,10 +1029,49 @@
974 }else {
975 fossil_fatal("encountered error %d while trying to open \"%s\".",
976 errno, g.argv[3]);
977 }
978 fossil_path_free(zUnicodePath);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
979 }
980
981 /*
982 ** COMMAND: reconstruct*
983 **
@@ -1049,11 +1143,10 @@
1049 ** --private Include private artifacts.
1050 **
1051 ** See also: rebuild, reconstruct
1052 */
1053 void deconstruct_cmd(void){
1054 const char *zDestDir;
1055 const char *zPrefixOpt;
1056 Stmt s;
1057 int privateFlag;
1058
1059 /* get and check prefix length argument and build format string */
@@ -1092,10 +1185,11 @@
1092 if( prefixLength ){
1093 zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
1094 }else{
1095 zFNameFormat = mprintf("%s/%%s",zDestDir);
1096 }
 
1097
1098 bag_init(&bagDone);
1099 ttyOutput = 1;
1100 processCnt = 0;
1101 if (!g.fQuiet) {
1102
--- src/rebuild.c
+++ src/rebuild.c
@@ -182,11 +182,14 @@
182 static int processCnt; /* Number processed so far */
183 static int ttyOutput; /* Do progress output */
184 static Bag bagDone; /* Bag of records rebuilt */
185
186 static char *zFNameFormat; /* Format string for filenames on deconstruct */
187 static int cchFNamePrefix; /* Length of directory prefix in zFNameFormat */
188 static char *zDestDir; /* Destination directory on deconstruct */
189 static int prefixLength; /* Length of directory prefix for deconstruct */
190 static int fKeepRid1; /* Flag to preserve RID=1 on de- and reconstruct */
191
192
193 /*
194 ** Draw the percent-complete message.
195 ** The input is actually the permill complete.
@@ -274,10 +277,21 @@
277 /* We are doing "fossil deconstruct" */
278 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
279 char *zFile = mprintf(zFNameFormat /*works-like:"%s:%s"*/,
280 zUuid, zUuid+prefixLength);
281 blob_write_to_file(pUse,zFile);
282 if( rid==1 && fKeepRid1!=0 ){
283 char *zFnDotRid1 = mprintf("%s/.rid1", zDestDir);
284 char *zFnRid1 = zFile + cchFNamePrefix + 1; /* Skip directory slash */
285 Blob bFileContents = empty_blob;
286 blob_appendf(&bFileContents,
287 "# The file holding the artifact with RID=1\n"
288 "%s\n", zFnRid1);
289 blob_write_to_file(&bFileContents, zFnDotRid1);
290 blob_reset(&bFileContents);
291 free(zFnDotRid1);
292 }
293 free(zFile);
294 free(zUuid);
295 blob_reset(pUse);
296 }
297 assert( blob_is_reset(pUse) );
@@ -931,11 +945,50 @@
945 struct dirent *pEntry;
946 Blob aContent; /* content of the just read artifact */
947 static int nFileRead = 0;
948 void *zUnicodePath;
949 char *zUtf8Name;
950 static int recursionLevel = 0; /* Bookkeeping about the recursion level */
951 static char *zFnRid1 = 0; /* The file holding the artifact with RID=1 */
952 static int cchPathInitial = 0; /* The length of zPath on first recursion */
953
954 recursionLevel++;
955 if( recursionLevel==1 ){
956 cchPathInitial = strlen(zPath);
957 if( fKeepRid1!=0 ){
958 char *zFnDotRid1 = mprintf("%s/.rid1", zPath);
959 Blob bFileContents;
960 if( blob_read_from_file(&bFileContents, zFnDotRid1, ExtFILE)!=-1 ){
961 Blob line, value;
962 while( blob_line(&bFileContents, &line)>0 ){
963 if( blob_token(&line, &value)==0 ) continue; /* Empty line */
964 if( blob_buffer(&value)[0]=='#' ) continue; /* Comment */
965 blob_trim(&value);
966 zFnRid1 = mprintf("%s/%s", zPath, blob_str(&value));
967 break;
968 }
969 blob_reset(&bFileContents);
970 if( zFnRid1 ){
971 if( blob_read_from_file(&aContent, zFnRid1, ExtFILE)==-1 ){
972 fossil_fatal("some unknown error occurred while reading \"%s\"",
973 zFnRid1);
974 }else{
975 recon_set_hash_policy(0, zFnRid1);
976 content_put(&aContent);
977 recon_restore_hash_policy();
978 blob_reset(&aContent);
979 fossil_print("\r%d", ++nFileRead);
980 fflush(stdout);
981 }
982 }else{
983 fossil_fatal("an error occurred while reading or parsing \"%s\"",
984 zFnDotRid1);
985 }
986 }
987 free(zFnDotRid1);
988 }
989 }
990 zUnicodePath = fossil_utf8_to_path(zPath, 1);
991 d = opendir(zUnicodePath);
992 if( d ){
993 while( (pEntry=readdir(d))!=0 ){
994 Blob path;
@@ -953,18 +1006,20 @@
1006 #else
1007 if( file_isdir(zSubpath, ExtFILE)==1 )
1008 #endif
1009 {
1010 recon_read_dir(zSubpath);
1011 }else if( fossil_strcmp(zSubpath, zFnRid1)!=0 ){
1012 blob_init(&path, 0, 0);
1013 blob_appendf(&path, "%s", zSubpath);
1014 if( blob_read_from_file(&aContent, blob_str(&path), ExtFILE)==-1 ){
1015 fossil_fatal("some unknown error occurred while reading \"%s\"",
1016 blob_str(&path));
1017 }
1018 recon_set_hash_policy(cchPathInitial, blob_str(&path));
1019 content_put(&aContent);
1020 recon_restore_hash_policy();
1021 blob_reset(&path);
1022 blob_reset(&aContent);
1023 fossil_print("\r%d", ++nFileRead);
1024 fflush(stdout);
1025 }
@@ -974,10 +1029,49 @@
1029 }else {
1030 fossil_fatal("encountered error %d while trying to open \"%s\".",
1031 errno, g.argv[3]);
1032 }
1033 fossil_path_free(zUnicodePath);
1034 if( recursionLevel==1 && zFnRid1!=0 ) free(zFnRid1);
1035 recursionLevel--;
1036 }
1037
1038 /*
1039 ** Helper functions called from recon_read_dir() to set and restore the correct
1040 ** hash policy for an artifact read from disk, inferred from the length of the
1041 ** path name.
1042 */
1043 #define HPOLICY_NOTDEFINED -1
1044 static int saved_eHashPolicy = HPOLICY_NOTDEFINED;
1045
1046 void recon_set_hash_policy(
1047 const int cchPathPrefix, /* Directory prefix length for zUuidAsFilePath */
1048 const char *zUuidAsFilePath /* Relative, well-formed, from recon_read_dir() */
1049 ){
1050 int cchTotal, cchHashPart;
1051 int new_eHashPolicy = HPOLICY_NOTDEFINED;
1052 assert( HNAME_COUNT==2 ); /* Review function if new hashes are implemented. */
1053 if( zUuidAsFilePath==0 ) return;
1054 cchTotal = strlen(zUuidAsFilePath);
1055 if( cchTotal==0 ) return;
1056 if( cchPathPrefix>=cchTotal) return;
1057 cchHashPart = cchTotal - cchPathPrefix;
1058 if( cchHashPart>=HNAME_LEN_K256 ){
1059 new_eHashPolicy = HPOLICY_SHA3;
1060 }else if( cchHashPart>=HNAME_LEN_SHA1 ){
1061 new_eHashPolicy = HPOLICY_SHA1;
1062 }
1063 if( new_eHashPolicy!=HPOLICY_NOTDEFINED ){
1064 saved_eHashPolicy = g.eHashPolicy;
1065 g.eHashPolicy = new_eHashPolicy;
1066 }
1067 }
1068
1069 void recon_restore_hash_policy(){
1070 if( saved_eHashPolicy!=HPOLICY_NOTDEFINED ){
1071 g.eHashPolicy = saved_eHashPolicy;
1072 }
1073 }
1074
1075 /*
1076 ** COMMAND: reconstruct*
1077 **
@@ -1049,11 +1143,10 @@
1143 ** --private Include private artifacts.
1144 **
1145 ** See also: rebuild, reconstruct
1146 */
1147 void deconstruct_cmd(void){
 
1148 const char *zPrefixOpt;
1149 Stmt s;
1150 int privateFlag;
1151
1152 /* get and check prefix length argument and build format string */
@@ -1092,10 +1185,11 @@
1185 if( prefixLength ){
1186 zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
1187 }else{
1188 zFNameFormat = mprintf("%s/%%s",zDestDir);
1189 }
1190 cchFNamePrefix = strlen(zDestDir);
1191
1192 bag_init(&bagDone);
1193 ttyOutput = 1;
1194 processCnt = 0;
1195 if (!g.fQuiet) {
1196

Keyboard Shortcuts

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