Fossil SCM
Improvements to the control-file parser. Not recognizes the T-line for tags.
Commit
3dc92fdb7f45b8a6fe22430bd260a943a72ee4dd
Parent
ce1c1a2907e9aa1…
1 file changed
+246
-101
+246
-101
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -47,10 +47,16 @@ | ||
| 47 | 47 | int nParentAlloc; /* Slots allocated in azParent[] */ |
| 48 | 48 | char **azParent; /* UUIDs of parents */ |
| 49 | 49 | int nCChild; /* Number of cluster children */ |
| 50 | 50 | int nCChildAlloc; /* Number of closts allocated in azCChild[] */ |
| 51 | 51 | char **azCChild; /* UUIDs of referenced objects in a cluster */ |
| 52 | + int nTag; /* Number of T lines */ | |
| 53 | + int nTagAlloc; /* Slots allocated in aTag[] */ | |
| 54 | + struct { | |
| 55 | + char *zName; /* Name of the tag */ | |
| 56 | + char *zUuid; /* UUID that the tag is applied to */ | |
| 57 | + } *aTag; | |
| 52 | 58 | }; |
| 53 | 59 | #endif |
| 54 | 60 | |
| 55 | 61 | |
| 56 | 62 | /* |
| @@ -80,19 +86,21 @@ | ||
| 80 | 86 | */ |
| 81 | 87 | int manifest_parse(Manifest *p, Blob *pContent){ |
| 82 | 88 | int seenHeader = 0; |
| 83 | 89 | int i; |
| 84 | 90 | Blob line, token, a1, a2, a3; |
| 91 | + char zPrevLine[10]; | |
| 85 | 92 | |
| 86 | 93 | memset(p, 0, sizeof(*p)); |
| 87 | 94 | memcpy(&p->content, pContent, sizeof(p->content)); |
| 88 | 95 | blob_zero(pContent); |
| 89 | 96 | pContent = &p->content; |
| 90 | 97 | |
| 91 | 98 | blob_zero(&a1); |
| 92 | 99 | blob_zero(&a2); |
| 93 | 100 | md5sum_init(); |
| 101 | + zPrevLine[0] = 0; | |
| 94 | 102 | while( blob_line(pContent, &line) ){ |
| 95 | 103 | char *z = blob_buffer(&line); |
| 96 | 104 | if( z[0]=='-' ){ |
| 97 | 105 | if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){ |
| 98 | 106 | goto manifest_syntax_error; |
| @@ -102,116 +110,253 @@ | ||
| 102 | 110 | } |
| 103 | 111 | while( blob_line(pContent, &line)>2 ){} |
| 104 | 112 | if( blob_line(pContent, &line)==0 ) break; |
| 105 | 113 | z = blob_buffer(&line); |
| 106 | 114 | } |
| 115 | + if( strcmp(z, zPrevLine)<0 ){ | |
| 116 | + /* Lines of a manifest must occur in lexicographical order */ | |
| 117 | + goto manifest_syntax_error; | |
| 118 | + } | |
| 119 | + sqlite3_snprintf(sizeof(zPrevLine), zPrevLine, "%s", z); | |
| 107 | 120 | seenHeader = 1; |
| 108 | 121 | if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error; |
| 109 | - if( z[0]=='F' ){ | |
| 110 | - char *zName, *zUuid; | |
| 111 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 112 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 113 | - if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; | |
| 114 | - if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; | |
| 115 | - zName = blob_terminate(&a1); | |
| 116 | - zUuid = blob_terminate(&a2); | |
| 117 | - if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 118 | - if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 119 | - defossilize(zName); | |
| 120 | - if( !file_is_simple_pathname(zName) ){ | |
| 121 | - goto manifest_syntax_error; | |
| 122 | - } | |
| 123 | - if( p->nFile>=p->nFileAlloc ){ | |
| 124 | - p->nFileAlloc = p->nFileAlloc*2 + 10; | |
| 125 | - p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); | |
| 126 | - if( p->aFile==0 ) fossil_panic("out of memory"); | |
| 127 | - } | |
| 128 | - i = p->nFile++; | |
| 129 | - p->aFile[i].zName = zName; | |
| 130 | - p->aFile[i].zUuid = zUuid; | |
| 131 | - if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ | |
| 132 | - goto manifest_syntax_error; | |
| 133 | - } | |
| 134 | - }else if( z[0]=='C' ){ | |
| 135 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 136 | - if( p->zComment!=0 ) goto manifest_syntax_error; | |
| 137 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 138 | - if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 139 | - p->zComment = blob_terminate(&a1); | |
| 140 | - defossilize(p->zComment); | |
| 141 | - }else if( z[0]=='D' ){ | |
| 142 | - char *zDate; | |
| 143 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 144 | - if( p->rDate!=0.0 ) goto manifest_syntax_error; | |
| 145 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 146 | - if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 147 | - zDate = blob_terminate(&a1); | |
| 148 | - p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); | |
| 149 | - }else if( z[0]=='M' ){ | |
| 150 | - char *zUuid; | |
| 151 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 152 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 153 | - zUuid = blob_terminate(&a1); | |
| 154 | - if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 155 | - if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 156 | - if( p->nCChild>=p->nCChildAlloc ){ | |
| 157 | - p->nCChildAlloc = p->nCChildAlloc*2 + 10; | |
| 158 | - p->azCChild = | |
| 159 | - realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) ); | |
| 160 | - if( p->azCChild==0 ) fossil_panic("out of memory"); | |
| 161 | - } | |
| 162 | - i = p->nCChild++; | |
| 163 | - p->azCChild[i] = zUuid; | |
| 164 | - if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){ | |
| 165 | - goto manifest_syntax_error; | |
| 166 | - } | |
| 167 | - }else if( z[0]=='U' ){ | |
| 168 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 169 | - if( p->zUser!=0 ) goto manifest_syntax_error; | |
| 170 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 171 | - if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 172 | - p->zUser = blob_terminate(&a1); | |
| 173 | - defossilize(p->zUser); | |
| 174 | - }else if( z[0]=='R' ){ | |
| 175 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 176 | - if( p->zRepoCksum!=0 ) goto manifest_syntax_error; | |
| 177 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 178 | - if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 179 | - if( blob_size(&a1)!=32 ) goto manifest_syntax_error; | |
| 180 | - p->zRepoCksum = blob_terminate(&a1); | |
| 181 | - if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; | |
| 182 | - }else if( z[0]=='P' ){ | |
| 183 | - md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 184 | - while( blob_token(&line, &a1) ){ | |
| 185 | - char *zUuid; | |
| 186 | - if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 187 | - zUuid = blob_terminate(&a1); | |
| 188 | - if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 189 | - if( p->nParent>=p->nParentAlloc ){ | |
| 190 | - p->nParentAlloc = p->nParentAlloc*2 + 5; | |
| 191 | - p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); | |
| 192 | - if( p->azParent==0 ) fossil_panic("out of memory"); | |
| 193 | - } | |
| 194 | - i = p->nParent++; | |
| 195 | - p->azParent[i] = zUuid; | |
| 196 | - } | |
| 197 | - }else if( z[0]=='Z' ){ | |
| 198 | - int rc; | |
| 199 | - Blob hash; | |
| 200 | - if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 201 | - if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 202 | - if( blob_size(&a1)!=32 ) goto manifest_syntax_error; | |
| 203 | - if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; | |
| 204 | - md5sum_finish(&hash); | |
| 205 | - rc = blob_compare(&hash, &a1); | |
| 206 | - blob_reset(&hash); | |
| 207 | - if( rc!=0 ) goto manifest_syntax_error; | |
| 208 | - }else{ | |
| 209 | - goto manifest_syntax_error; | |
| 122 | + switch( z[0] ){ | |
| 123 | + /* | |
| 124 | + ** C <comment> | |
| 125 | + ** | |
| 126 | + ** Comment text is fossil-encoded. There may be no more than | |
| 127 | + ** one C line. C lines are required for manifests and are | |
| 128 | + ** disallowed on all other control files. | |
| 129 | + */ | |
| 130 | + case 'C': { | |
| 131 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 132 | + if( p->zComment!=0 ) goto manifest_syntax_error; | |
| 133 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 134 | + if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 135 | + p->zComment = blob_terminate(&a1); | |
| 136 | + defossilize(p->zComment); | |
| 137 | + break; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /* | |
| 141 | + ** D <timestamp> | |
| 142 | + ** | |
| 143 | + ** The timestamp should be ISO 8601. YYYY-MM-DDtHH:MM:SS | |
| 144 | + ** There can be no more than 1 D line. D lines are required | |
| 145 | + ** for all control files except for clusters. | |
| 146 | + */ | |
| 147 | + case 'D': { | |
| 148 | + char *zDate; | |
| 149 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 150 | + if( p->rDate!=0.0 ) goto manifest_syntax_error; | |
| 151 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 152 | + if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 153 | + zDate = blob_terminate(&a1); | |
| 154 | + p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); | |
| 155 | + break; | |
| 156 | + } | |
| 157 | + | |
| 158 | + /* | |
| 159 | + ** F <filename> <uuid> | |
| 160 | + ** | |
| 161 | + ** Identifies a file in a manifest. Multiple F lines are | |
| 162 | + ** allowed in a manifest. F lines are not allowed in any | |
| 163 | + ** other control file. The filename is fossil-encoded. | |
| 164 | + */ | |
| 165 | + case 'F': { | |
| 166 | + char *zName, *zUuid; | |
| 167 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 168 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 169 | + if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; | |
| 170 | + if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; | |
| 171 | + zName = blob_terminate(&a1); | |
| 172 | + zUuid = blob_terminate(&a2); | |
| 173 | + if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 174 | + if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 175 | + defossilize(zName); | |
| 176 | + if( !file_is_simple_pathname(zName) ){ | |
| 177 | + goto manifest_syntax_error; | |
| 178 | + } | |
| 179 | + if( p->nFile>=p->nFileAlloc ){ | |
| 180 | + p->nFileAlloc = p->nFileAlloc*2 + 10; | |
| 181 | + p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); | |
| 182 | + if( p->aFile==0 ) fossil_panic("out of memory"); | |
| 183 | + } | |
| 184 | + i = p->nFile++; | |
| 185 | + p->aFile[i].zName = zName; | |
| 186 | + p->aFile[i].zUuid = zUuid; | |
| 187 | + if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ | |
| 188 | + goto manifest_syntax_error; | |
| 189 | + } | |
| 190 | + break; | |
| 191 | + } | |
| 192 | + | |
| 193 | + /* | |
| 194 | + ** M <uuid> | |
| 195 | + ** | |
| 196 | + ** An M-line identifies another artifact by its UUID. M-lines | |
| 197 | + ** occur in clusters only. | |
| 198 | + */ | |
| 199 | + case 'M': { | |
| 200 | + char *zUuid; | |
| 201 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 202 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 203 | + zUuid = blob_terminate(&a1); | |
| 204 | + if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 205 | + if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 206 | + if( p->nCChild>=p->nCChildAlloc ){ | |
| 207 | + p->nCChildAlloc = p->nCChildAlloc*2 + 10; | |
| 208 | + p->azCChild = | |
| 209 | + realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) ); | |
| 210 | + if( p->azCChild==0 ) fossil_panic("out of memory"); | |
| 211 | + } | |
| 212 | + i = p->nCChild++; | |
| 213 | + p->azCChild[i] = zUuid; | |
| 214 | + if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){ | |
| 215 | + goto manifest_syntax_error; | |
| 216 | + } | |
| 217 | + break; | |
| 218 | + } | |
| 219 | + | |
| 220 | + /* | |
| 221 | + ** T (+|-)<tagname> <uuid> | |
| 222 | + ** | |
| 223 | + ** Create or cancel a tag. The tagname is fossil-encoded. The | |
| 224 | + ** first character must be either "+" to create or "-" to delete. | |
| 225 | + ** Tags are not allowed in clusters. Multiple T lines are allowed. | |
| 226 | + */ | |
| 227 | + case 'T': { | |
| 228 | + char *zName, *zUuid; | |
| 229 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 230 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 231 | + if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; | |
| 232 | + if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; | |
| 233 | + zName = blob_terminate(&a1); | |
| 234 | + zUuid = blob_terminate(&a2); | |
| 235 | + if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 236 | + if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 237 | + defossilize(zName); | |
| 238 | + if( zName[0]!='-' && zName[0]!='+' ){ | |
| 239 | + goto manifest_syntax_error; | |
| 240 | + } | |
| 241 | + if( p->nTag>=p->nTagAlloc ){ | |
| 242 | + p->nTagAlloc = p->nTagAlloc*2 + 10; | |
| 243 | + p->aTag = realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) ); | |
| 244 | + if( p->aTag==0 ) fossil_panic("out of memory"); | |
| 245 | + } | |
| 246 | + i = p->nTag++; | |
| 247 | + p->aTag[i].zName = zName; | |
| 248 | + p->aTag[i].zUuid = zUuid; | |
| 249 | + if( i>0 && strcmp(p->aTag[i-1].zName, zName)>=0 ){ | |
| 250 | + goto manifest_syntax_error; | |
| 251 | + } | |
| 252 | + break; | |
| 253 | + } | |
| 254 | + | |
| 255 | + /* | |
| 256 | + ** U <login> | |
| 257 | + ** | |
| 258 | + ** Identify the user who created this control file by their | |
| 259 | + ** login. Only one U line is allowed. Prohibited in clusters. | |
| 260 | + */ | |
| 261 | + case 'U': { | |
| 262 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 263 | + if( p->zUser!=0 ) goto manifest_syntax_error; | |
| 264 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 265 | + if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 266 | + p->zUser = blob_terminate(&a1); | |
| 267 | + defossilize(p->zUser); | |
| 268 | + break; | |
| 269 | + } | |
| 270 | + | |
| 271 | + /* | |
| 272 | + ** R <md5sum> | |
| 273 | + ** | |
| 274 | + ** Specify the MD5 checksum of the entire baseline in a | |
| 275 | + ** manifest. | |
| 276 | + */ | |
| 277 | + case 'R': { | |
| 278 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 279 | + if( p->zRepoCksum!=0 ) goto manifest_syntax_error; | |
| 280 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 281 | + if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 282 | + if( blob_size(&a1)!=32 ) goto manifest_syntax_error; | |
| 283 | + p->zRepoCksum = blob_terminate(&a1); | |
| 284 | + if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; | |
| 285 | + break; | |
| 286 | + } | |
| 287 | + | |
| 288 | + /* | |
| 289 | + ** P <uuid> ... | |
| 290 | + ** | |
| 291 | + ** Specify one or more other artifacts where are the parents of | |
| 292 | + ** this artifact. The first parent is the primary parent. All | |
| 293 | + ** others are parents by merge. | |
| 294 | + */ | |
| 295 | + case 'P': { | |
| 296 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 297 | + while( blob_token(&line, &a1) ){ | |
| 298 | + char *zUuid; | |
| 299 | + if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 300 | + zUuid = blob_terminate(&a1); | |
| 301 | + if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; | |
| 302 | + if( p->nParent>=p->nParentAlloc ){ | |
| 303 | + p->nParentAlloc = p->nParentAlloc*2 + 5; | |
| 304 | + p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); | |
| 305 | + if( p->azParent==0 ) fossil_panic("out of memory"); | |
| 306 | + } | |
| 307 | + i = p->nParent++; | |
| 308 | + p->azParent[i] = zUuid; | |
| 309 | + } | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + | |
| 313 | + /* | |
| 314 | + ** Z <md5sum> | |
| 315 | + ** | |
| 316 | + ** MD5 checksum on this control file. The checksum is over all | |
| 317 | + ** lines (other than PGP-signature lines) prior to the current | |
| 318 | + ** line. This must be the last record. | |
| 319 | + */ | |
| 320 | + case 'Z': { | |
| 321 | + int rc; | |
| 322 | + Blob hash; | |
| 323 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 324 | + if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; | |
| 325 | + if( blob_size(&a1)!=32 ) goto manifest_syntax_error; | |
| 326 | + if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; | |
| 327 | + md5sum_finish(&hash); | |
| 328 | + rc = blob_compare(&hash, &a1); | |
| 329 | + blob_reset(&hash); | |
| 330 | + if( rc!=0 ) goto manifest_syntax_error; | |
| 331 | + break; | |
| 332 | + } | |
| 333 | + default: { | |
| 334 | + goto manifest_syntax_error; | |
| 335 | + } | |
| 210 | 336 | } |
| 211 | 337 | } |
| 212 | 338 | if( !seenHeader ) goto manifest_syntax_error; |
| 339 | + | |
| 340 | + if( p->nFile>0 ){ | |
| 341 | + if( p->nCChild>0 ) goto manifest_syntax_error; | |
| 342 | + if( p->rDate==0.0 ) goto manifest_syntax_error; | |
| 343 | + }else if( p->nCChild>0 ){ | |
| 344 | + if( p->rDate>0.0 ) goto manifest_syntax_error; | |
| 345 | + if( p->zComment!=0 ) goto manifest_syntax_error; | |
| 346 | + if( p->zUser!=0 ) goto manifest_syntax_error; | |
| 347 | + if( p->nTag>0 ) goto manifest_syntax_error; | |
| 348 | + if( p->nParent>0 ) goto manifest_syntax_error; | |
| 349 | + if( p->zRepoCksum!=0 ) goto manifest_syntax_error; | |
| 350 | + }else if( p->nTag>0 ){ | |
| 351 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 352 | + if( p->zRepoCksum!=0 ) goto manifest_syntax_error; | |
| 353 | + if( p->nParent>0 ) goto manifest_syntax_error; | |
| 354 | + }else{ | |
| 355 | + goto manifest_syntax_error; | |
| 356 | + } | |
| 357 | + | |
| 213 | 358 | md5sum_init(); |
| 214 | 359 | return 1; |
| 215 | 360 | |
| 216 | 361 | manifest_syntax_error: |
| 217 | 362 | md5sum_init(); |
| 218 | 363 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -47,10 +47,16 @@ | |
| 47 | int nParentAlloc; /* Slots allocated in azParent[] */ |
| 48 | char **azParent; /* UUIDs of parents */ |
| 49 | int nCChild; /* Number of cluster children */ |
| 50 | int nCChildAlloc; /* Number of closts allocated in azCChild[] */ |
| 51 | char **azCChild; /* UUIDs of referenced objects in a cluster */ |
| 52 | }; |
| 53 | #endif |
| 54 | |
| 55 | |
| 56 | /* |
| @@ -80,19 +86,21 @@ | |
| 80 | */ |
| 81 | int manifest_parse(Manifest *p, Blob *pContent){ |
| 82 | int seenHeader = 0; |
| 83 | int i; |
| 84 | Blob line, token, a1, a2, a3; |
| 85 | |
| 86 | memset(p, 0, sizeof(*p)); |
| 87 | memcpy(&p->content, pContent, sizeof(p->content)); |
| 88 | blob_zero(pContent); |
| 89 | pContent = &p->content; |
| 90 | |
| 91 | blob_zero(&a1); |
| 92 | blob_zero(&a2); |
| 93 | md5sum_init(); |
| 94 | while( blob_line(pContent, &line) ){ |
| 95 | char *z = blob_buffer(&line); |
| 96 | if( z[0]=='-' ){ |
| 97 | if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){ |
| 98 | goto manifest_syntax_error; |
| @@ -102,116 +110,253 @@ | |
| 102 | } |
| 103 | while( blob_line(pContent, &line)>2 ){} |
| 104 | if( blob_line(pContent, &line)==0 ) break; |
| 105 | z = blob_buffer(&line); |
| 106 | } |
| 107 | seenHeader = 1; |
| 108 | if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error; |
| 109 | if( z[0]=='F' ){ |
| 110 | char *zName, *zUuid; |
| 111 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 112 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 113 | if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; |
| 114 | if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; |
| 115 | zName = blob_terminate(&a1); |
| 116 | zUuid = blob_terminate(&a2); |
| 117 | if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; |
| 118 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 119 | defossilize(zName); |
| 120 | if( !file_is_simple_pathname(zName) ){ |
| 121 | goto manifest_syntax_error; |
| 122 | } |
| 123 | if( p->nFile>=p->nFileAlloc ){ |
| 124 | p->nFileAlloc = p->nFileAlloc*2 + 10; |
| 125 | p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); |
| 126 | if( p->aFile==0 ) fossil_panic("out of memory"); |
| 127 | } |
| 128 | i = p->nFile++; |
| 129 | p->aFile[i].zName = zName; |
| 130 | p->aFile[i].zUuid = zUuid; |
| 131 | if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ |
| 132 | goto manifest_syntax_error; |
| 133 | } |
| 134 | }else if( z[0]=='C' ){ |
| 135 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 136 | if( p->zComment!=0 ) goto manifest_syntax_error; |
| 137 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 138 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 139 | p->zComment = blob_terminate(&a1); |
| 140 | defossilize(p->zComment); |
| 141 | }else if( z[0]=='D' ){ |
| 142 | char *zDate; |
| 143 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 144 | if( p->rDate!=0.0 ) goto manifest_syntax_error; |
| 145 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 146 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 147 | zDate = blob_terminate(&a1); |
| 148 | p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); |
| 149 | }else if( z[0]=='M' ){ |
| 150 | char *zUuid; |
| 151 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 152 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 153 | zUuid = blob_terminate(&a1); |
| 154 | if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; |
| 155 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 156 | if( p->nCChild>=p->nCChildAlloc ){ |
| 157 | p->nCChildAlloc = p->nCChildAlloc*2 + 10; |
| 158 | p->azCChild = |
| 159 | realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) ); |
| 160 | if( p->azCChild==0 ) fossil_panic("out of memory"); |
| 161 | } |
| 162 | i = p->nCChild++; |
| 163 | p->azCChild[i] = zUuid; |
| 164 | if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){ |
| 165 | goto manifest_syntax_error; |
| 166 | } |
| 167 | }else if( z[0]=='U' ){ |
| 168 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 169 | if( p->zUser!=0 ) goto manifest_syntax_error; |
| 170 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 171 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 172 | p->zUser = blob_terminate(&a1); |
| 173 | defossilize(p->zUser); |
| 174 | }else if( z[0]=='R' ){ |
| 175 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 176 | if( p->zRepoCksum!=0 ) goto manifest_syntax_error; |
| 177 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 178 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 179 | if( blob_size(&a1)!=32 ) goto manifest_syntax_error; |
| 180 | p->zRepoCksum = blob_terminate(&a1); |
| 181 | if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; |
| 182 | }else if( z[0]=='P' ){ |
| 183 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 184 | while( blob_token(&line, &a1) ){ |
| 185 | char *zUuid; |
| 186 | if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; |
| 187 | zUuid = blob_terminate(&a1); |
| 188 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 189 | if( p->nParent>=p->nParentAlloc ){ |
| 190 | p->nParentAlloc = p->nParentAlloc*2 + 5; |
| 191 | p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); |
| 192 | if( p->azParent==0 ) fossil_panic("out of memory"); |
| 193 | } |
| 194 | i = p->nParent++; |
| 195 | p->azParent[i] = zUuid; |
| 196 | } |
| 197 | }else if( z[0]=='Z' ){ |
| 198 | int rc; |
| 199 | Blob hash; |
| 200 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 201 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 202 | if( blob_size(&a1)!=32 ) goto manifest_syntax_error; |
| 203 | if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; |
| 204 | md5sum_finish(&hash); |
| 205 | rc = blob_compare(&hash, &a1); |
| 206 | blob_reset(&hash); |
| 207 | if( rc!=0 ) goto manifest_syntax_error; |
| 208 | }else{ |
| 209 | goto manifest_syntax_error; |
| 210 | } |
| 211 | } |
| 212 | if( !seenHeader ) goto manifest_syntax_error; |
| 213 | md5sum_init(); |
| 214 | return 1; |
| 215 | |
| 216 | manifest_syntax_error: |
| 217 | md5sum_init(); |
| 218 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -47,10 +47,16 @@ | |
| 47 | int nParentAlloc; /* Slots allocated in azParent[] */ |
| 48 | char **azParent; /* UUIDs of parents */ |
| 49 | int nCChild; /* Number of cluster children */ |
| 50 | int nCChildAlloc; /* Number of closts allocated in azCChild[] */ |
| 51 | char **azCChild; /* UUIDs of referenced objects in a cluster */ |
| 52 | int nTag; /* Number of T lines */ |
| 53 | int nTagAlloc; /* Slots allocated in aTag[] */ |
| 54 | struct { |
| 55 | char *zName; /* Name of the tag */ |
| 56 | char *zUuid; /* UUID that the tag is applied to */ |
| 57 | } *aTag; |
| 58 | }; |
| 59 | #endif |
| 60 | |
| 61 | |
| 62 | /* |
| @@ -80,19 +86,21 @@ | |
| 86 | */ |
| 87 | int manifest_parse(Manifest *p, Blob *pContent){ |
| 88 | int seenHeader = 0; |
| 89 | int i; |
| 90 | Blob line, token, a1, a2, a3; |
| 91 | char zPrevLine[10]; |
| 92 | |
| 93 | memset(p, 0, sizeof(*p)); |
| 94 | memcpy(&p->content, pContent, sizeof(p->content)); |
| 95 | blob_zero(pContent); |
| 96 | pContent = &p->content; |
| 97 | |
| 98 | blob_zero(&a1); |
| 99 | blob_zero(&a2); |
| 100 | md5sum_init(); |
| 101 | zPrevLine[0] = 0; |
| 102 | while( blob_line(pContent, &line) ){ |
| 103 | char *z = blob_buffer(&line); |
| 104 | if( z[0]=='-' ){ |
| 105 | if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){ |
| 106 | goto manifest_syntax_error; |
| @@ -102,116 +110,253 @@ | |
| 110 | } |
| 111 | while( blob_line(pContent, &line)>2 ){} |
| 112 | if( blob_line(pContent, &line)==0 ) break; |
| 113 | z = blob_buffer(&line); |
| 114 | } |
| 115 | if( strcmp(z, zPrevLine)<0 ){ |
| 116 | /* Lines of a manifest must occur in lexicographical order */ |
| 117 | goto manifest_syntax_error; |
| 118 | } |
| 119 | sqlite3_snprintf(sizeof(zPrevLine), zPrevLine, "%s", z); |
| 120 | seenHeader = 1; |
| 121 | if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error; |
| 122 | switch( z[0] ){ |
| 123 | /* |
| 124 | ** C <comment> |
| 125 | ** |
| 126 | ** Comment text is fossil-encoded. There may be no more than |
| 127 | ** one C line. C lines are required for manifests and are |
| 128 | ** disallowed on all other control files. |
| 129 | */ |
| 130 | case 'C': { |
| 131 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 132 | if( p->zComment!=0 ) goto manifest_syntax_error; |
| 133 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 134 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 135 | p->zComment = blob_terminate(&a1); |
| 136 | defossilize(p->zComment); |
| 137 | break; |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | ** D <timestamp> |
| 142 | ** |
| 143 | ** The timestamp should be ISO 8601. YYYY-MM-DDtHH:MM:SS |
| 144 | ** There can be no more than 1 D line. D lines are required |
| 145 | ** for all control files except for clusters. |
| 146 | */ |
| 147 | case 'D': { |
| 148 | char *zDate; |
| 149 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 150 | if( p->rDate!=0.0 ) goto manifest_syntax_error; |
| 151 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 152 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 153 | zDate = blob_terminate(&a1); |
| 154 | p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); |
| 155 | break; |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | ** F <filename> <uuid> |
| 160 | ** |
| 161 | ** Identifies a file in a manifest. Multiple F lines are |
| 162 | ** allowed in a manifest. F lines are not allowed in any |
| 163 | ** other control file. The filename is fossil-encoded. |
| 164 | */ |
| 165 | case 'F': { |
| 166 | char *zName, *zUuid; |
| 167 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 168 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 169 | if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; |
| 170 | if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; |
| 171 | zName = blob_terminate(&a1); |
| 172 | zUuid = blob_terminate(&a2); |
| 173 | if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; |
| 174 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 175 | defossilize(zName); |
| 176 | if( !file_is_simple_pathname(zName) ){ |
| 177 | goto manifest_syntax_error; |
| 178 | } |
| 179 | if( p->nFile>=p->nFileAlloc ){ |
| 180 | p->nFileAlloc = p->nFileAlloc*2 + 10; |
| 181 | p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); |
| 182 | if( p->aFile==0 ) fossil_panic("out of memory"); |
| 183 | } |
| 184 | i = p->nFile++; |
| 185 | p->aFile[i].zName = zName; |
| 186 | p->aFile[i].zUuid = zUuid; |
| 187 | if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ |
| 188 | goto manifest_syntax_error; |
| 189 | } |
| 190 | break; |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | ** M <uuid> |
| 195 | ** |
| 196 | ** An M-line identifies another artifact by its UUID. M-lines |
| 197 | ** occur in clusters only. |
| 198 | */ |
| 199 | case 'M': { |
| 200 | char *zUuid; |
| 201 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 202 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 203 | zUuid = blob_terminate(&a1); |
| 204 | if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; |
| 205 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 206 | if( p->nCChild>=p->nCChildAlloc ){ |
| 207 | p->nCChildAlloc = p->nCChildAlloc*2 + 10; |
| 208 | p->azCChild = |
| 209 | realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) ); |
| 210 | if( p->azCChild==0 ) fossil_panic("out of memory"); |
| 211 | } |
| 212 | i = p->nCChild++; |
| 213 | p->azCChild[i] = zUuid; |
| 214 | if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){ |
| 215 | goto manifest_syntax_error; |
| 216 | } |
| 217 | break; |
| 218 | } |
| 219 | |
| 220 | /* |
| 221 | ** T (+|-)<tagname> <uuid> |
| 222 | ** |
| 223 | ** Create or cancel a tag. The tagname is fossil-encoded. The |
| 224 | ** first character must be either "+" to create or "-" to delete. |
| 225 | ** Tags are not allowed in clusters. Multiple T lines are allowed. |
| 226 | */ |
| 227 | case 'T': { |
| 228 | char *zName, *zUuid; |
| 229 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 230 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 231 | if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; |
| 232 | if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; |
| 233 | zName = blob_terminate(&a1); |
| 234 | zUuid = blob_terminate(&a2); |
| 235 | if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; |
| 236 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 237 | defossilize(zName); |
| 238 | if( zName[0]!='-' && zName[0]!='+' ){ |
| 239 | goto manifest_syntax_error; |
| 240 | } |
| 241 | if( p->nTag>=p->nTagAlloc ){ |
| 242 | p->nTagAlloc = p->nTagAlloc*2 + 10; |
| 243 | p->aTag = realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) ); |
| 244 | if( p->aTag==0 ) fossil_panic("out of memory"); |
| 245 | } |
| 246 | i = p->nTag++; |
| 247 | p->aTag[i].zName = zName; |
| 248 | p->aTag[i].zUuid = zUuid; |
| 249 | if( i>0 && strcmp(p->aTag[i-1].zName, zName)>=0 ){ |
| 250 | goto manifest_syntax_error; |
| 251 | } |
| 252 | break; |
| 253 | } |
| 254 | |
| 255 | /* |
| 256 | ** U <login> |
| 257 | ** |
| 258 | ** Identify the user who created this control file by their |
| 259 | ** login. Only one U line is allowed. Prohibited in clusters. |
| 260 | */ |
| 261 | case 'U': { |
| 262 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 263 | if( p->zUser!=0 ) goto manifest_syntax_error; |
| 264 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 265 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 266 | p->zUser = blob_terminate(&a1); |
| 267 | defossilize(p->zUser); |
| 268 | break; |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | ** R <md5sum> |
| 273 | ** |
| 274 | ** Specify the MD5 checksum of the entire baseline in a |
| 275 | ** manifest. |
| 276 | */ |
| 277 | case 'R': { |
| 278 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 279 | if( p->zRepoCksum!=0 ) goto manifest_syntax_error; |
| 280 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 281 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 282 | if( blob_size(&a1)!=32 ) goto manifest_syntax_error; |
| 283 | p->zRepoCksum = blob_terminate(&a1); |
| 284 | if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; |
| 285 | break; |
| 286 | } |
| 287 | |
| 288 | /* |
| 289 | ** P <uuid> ... |
| 290 | ** |
| 291 | ** Specify one or more other artifacts where are the parents of |
| 292 | ** this artifact. The first parent is the primary parent. All |
| 293 | ** others are parents by merge. |
| 294 | */ |
| 295 | case 'P': { |
| 296 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 297 | while( blob_token(&line, &a1) ){ |
| 298 | char *zUuid; |
| 299 | if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; |
| 300 | zUuid = blob_terminate(&a1); |
| 301 | if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; |
| 302 | if( p->nParent>=p->nParentAlloc ){ |
| 303 | p->nParentAlloc = p->nParentAlloc*2 + 5; |
| 304 | p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); |
| 305 | if( p->azParent==0 ) fossil_panic("out of memory"); |
| 306 | } |
| 307 | i = p->nParent++; |
| 308 | p->azParent[i] = zUuid; |
| 309 | } |
| 310 | break; |
| 311 | } |
| 312 | |
| 313 | /* |
| 314 | ** Z <md5sum> |
| 315 | ** |
| 316 | ** MD5 checksum on this control file. The checksum is over all |
| 317 | ** lines (other than PGP-signature lines) prior to the current |
| 318 | ** line. This must be the last record. |
| 319 | */ |
| 320 | case 'Z': { |
| 321 | int rc; |
| 322 | Blob hash; |
| 323 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 324 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 325 | if( blob_size(&a1)!=32 ) goto manifest_syntax_error; |
| 326 | if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; |
| 327 | md5sum_finish(&hash); |
| 328 | rc = blob_compare(&hash, &a1); |
| 329 | blob_reset(&hash); |
| 330 | if( rc!=0 ) goto manifest_syntax_error; |
| 331 | break; |
| 332 | } |
| 333 | default: { |
| 334 | goto manifest_syntax_error; |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | if( !seenHeader ) goto manifest_syntax_error; |
| 339 | |
| 340 | if( p->nFile>0 ){ |
| 341 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 342 | if( p->rDate==0.0 ) goto manifest_syntax_error; |
| 343 | }else if( p->nCChild>0 ){ |
| 344 | if( p->rDate>0.0 ) goto manifest_syntax_error; |
| 345 | if( p->zComment!=0 ) goto manifest_syntax_error; |
| 346 | if( p->zUser!=0 ) goto manifest_syntax_error; |
| 347 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 348 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 349 | if( p->zRepoCksum!=0 ) goto manifest_syntax_error; |
| 350 | }else if( p->nTag>0 ){ |
| 351 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 352 | if( p->zRepoCksum!=0 ) goto manifest_syntax_error; |
| 353 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 354 | }else{ |
| 355 | goto manifest_syntax_error; |
| 356 | } |
| 357 | |
| 358 | md5sum_init(); |
| 359 | return 1; |
| 360 | |
| 361 | manifest_syntax_error: |
| 362 | md5sum_init(); |
| 363 |