dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copyright (c) 2007 D. Richard Hipp dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is free software; you can redistribute it and/or dbda8d6ce9 2007-07-21 drh: ** modify it under the terms of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License version 2 as published by the Free Software Foundation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is distributed in the hope that it will be useful, dbda8d6ce9 2007-07-21 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of dbda8d6ce9 2007-07-21 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dbda8d6ce9 2007-07-21 drh: ** General Public License for more details. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** You should have received a copy of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License along with this library; if not, write to the dbda8d6ce9 2007-07-21 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, dbda8d6ce9 2007-07-21 drh: ** Boston, MA 02111-1307, USA. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Author contact information: dbda8d6ce9 2007-07-21 drh: ** drh@hwaci.com dbda8d6ce9 2007-07-21 drh: ** http://www.hwaci.com/drh/ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ******************************************************************************* dbda8d6ce9 2007-07-21 drh: ** 3b5514ed82 2007-09-22 drh: ** This file contains code used to cross link control files and 09c4adeb6f 2007-09-22 drh: ** manifests. The file is named "manifest.c" because it was 09c4adeb6f 2007-09-22 drh: ** original only used to parse manifests. Then later clusters 2ab2db0bd3 2007-10-05 drh: ** and control files and wiki pages and tickets were added. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include "config.h" dbda8d6ce9 2007-07-21 drh: #include "manifest.h" dbda8d6ce9 2007-07-21 drh: #include <assert.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: #if INTERFACE dbda8d6ce9 2007-07-21 drh: /* 3b5514ed82 2007-09-22 drh: ** Types of control files 3b5514ed82 2007-09-22 drh: */ 3b5514ed82 2007-09-22 drh: #define CFTYPE_MANIFEST 1 3b5514ed82 2007-09-22 drh: #define CFTYPE_CLUSTER 2 3b5514ed82 2007-09-22 drh: #define CFTYPE_CONTROL 3 2ab2db0bd3 2007-10-05 drh: #define CFTYPE_WIKI 4 2ab2db0bd3 2007-10-05 drh: #define CFTYPE_TICKET 5 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: /* 2ab2db0bd3 2007-10-05 drh: ** Mode parameter values 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: #define CFMODE_READ 1 2ab2db0bd3 2007-10-05 drh: #define CFMODE_APPEND 2 2ab2db0bd3 2007-10-05 drh: #define CFMODE_WRITE 3 3b5514ed82 2007-09-22 drh: 3b5514ed82 2007-09-22 drh: /* ba486fec5a 2007-09-03 drh: ** A parsed manifest or cluster. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Manifest { dbda8d6ce9 2007-07-21 drh: Blob content; /* The original content blob */ 3b5514ed82 2007-09-22 drh: int type; /* Type of file */ 2ab2db0bd3 2007-10-05 drh: int mode; /* Access mode */ dbda8d6ce9 2007-07-21 drh: char *zComment; /* Decoded comment */ dbda8d6ce9 2007-07-21 drh: double rDate; /* Time in the "D" line */ dbda8d6ce9 2007-07-21 drh: char *zUser; /* Name of the user */ dbda8d6ce9 2007-07-21 drh: char *zRepoCksum; /* MD5 checksum of the baseline content */ 2ab2db0bd3 2007-10-05 drh: char *zWiki; /* Text of the wiki page */ 2ab2db0bd3 2007-10-05 drh: char *zWikiTitle; /* Name of the wiki page */ 2ab2db0bd3 2007-10-05 drh: char *zTicketUuid; /* UUID for a ticket */ dbda8d6ce9 2007-07-21 drh: int nFile; /* Number of F lines */ dbda8d6ce9 2007-07-21 drh: int nFileAlloc; /* Slots allocated in aFile[] */ dbda8d6ce9 2007-07-21 drh: struct { dbda8d6ce9 2007-07-21 drh: char *zName; /* Name of a file */ dbda8d6ce9 2007-07-21 drh: char *zUuid; /* UUID of the file */ 33c31f73cd 2008-02-21 drh: char *zPerm; /* File permissions */ dbda8d6ce9 2007-07-21 drh: } *aFile; dbda8d6ce9 2007-07-21 drh: int nParent; /* Number of parents */ dbda8d6ce9 2007-07-21 drh: int nParentAlloc; /* Slots allocated in azParent[] */ dbda8d6ce9 2007-07-21 drh: char **azParent; /* UUIDs of parents */ ba486fec5a 2007-09-03 drh: int nCChild; /* Number of cluster children */ ba486fec5a 2007-09-03 drh: int nCChildAlloc; /* Number of closts allocated in azCChild[] */ ba486fec5a 2007-09-03 drh: char **azCChild; /* UUIDs of referenced objects in a cluster */ 3dc92fdb7f 2007-09-21 drh: int nTag; /* Number of T lines */ 3dc92fdb7f 2007-09-21 drh: int nTagAlloc; /* Slots allocated in aTag[] */ 3dc92fdb7f 2007-09-21 drh: struct { 3dc92fdb7f 2007-09-21 drh: char *zName; /* Name of the tag */ 3dc92fdb7f 2007-09-21 drh: char *zUuid; /* UUID that the tag is applied to */ f73c0e792b 2007-09-22 drh: char *zValue; /* Value if the tag is really a property */ 3dc92fdb7f 2007-09-21 drh: } *aTag; 2ab2db0bd3 2007-10-05 drh: int nField; /* Number of J lines */ 2ab2db0bd3 2007-10-05 drh: int nFieldAlloc; /* Slots allocated in aField[] */ 2ab2db0bd3 2007-10-05 drh: struct { 2ab2db0bd3 2007-10-05 drh: char *zName; /* Key or field name */ 2ab2db0bd3 2007-10-05 drh: char *zValue; /* Value of the field */ 2ab2db0bd3 2007-10-05 drh: } *aField; 2ab2db0bd3 2007-10-05 drh: int nAttach; /* Number of A lines */ 2ab2db0bd3 2007-10-05 drh: int nAttachAlloc; /* Slots allocated in aAttach[] */ 2ab2db0bd3 2007-10-05 drh: struct { 2ab2db0bd3 2007-10-05 drh: char *zUuid; /* UUID of the attachment */ 2ab2db0bd3 2007-10-05 drh: char *zName; /* Name of the attachment */ 2ab2db0bd3 2007-10-05 drh: char *zDesc; /* Description of the attachment */ 2ab2db0bd3 2007-10-05 drh: } *aAttach; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Clear the memory allocated in a manifest object dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void manifest_clear(Manifest *p){ dbda8d6ce9 2007-07-21 drh: blob_reset(&p->content); dbda8d6ce9 2007-07-21 drh: free(p->aFile); dbda8d6ce9 2007-07-21 drh: free(p->azParent); ba486fec5a 2007-09-03 drh: free(p->azCChild); 2ab2db0bd3 2007-10-05 drh: free(p->aTag); 2ab2db0bd3 2007-10-05 drh: free(p->aField); 2ab2db0bd3 2007-10-05 drh: free(p->aAttach); dbda8d6ce9 2007-07-21 drh: memset(p, 0, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* 2ab2db0bd3 2007-10-05 drh: ** Parse a blob into a Manifest object. The Manifest object 2ab2db0bd3 2007-10-05 drh: ** takes over the input blob and will free it when the dbda8d6ce9 2007-07-21 drh: ** Manifest object is freed. Zeros are inserted into the blob dbda8d6ce9 2007-07-21 drh: ** as string terminators so that blob should not be used again. dbda8d6ce9 2007-07-21 drh: ** 2ab2db0bd3 2007-10-05 drh: ** Return TRUE if the content really is a control file of some 2ab2db0bd3 2007-10-05 drh: ** kind. Return FALSE if there are syntax errors. 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** This routine is strict about the format of a control file. 2ab2db0bd3 2007-10-05 drh: ** The format must match exactly or else it is rejected. This 2ab2db0bd3 2007-10-05 drh: ** rule minimizes the risk that a content file will be mistaken 2ab2db0bd3 2007-10-05 drh: ** for a control file simply because they look the same. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** The pContent is reset. If TRUE is returned, then pContent will dbda8d6ce9 2007-07-21 drh: ** be reset when the Manifest object is cleared. If FALSE is dbda8d6ce9 2007-07-21 drh: ** returned then the Manifest object is cleared automatically dbda8d6ce9 2007-07-21 drh: ** and pContent is reset before the return. 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** The entire file can be PGP clear-signed. The signature is ignored. 2ab2db0bd3 2007-10-05 drh: ** The file consists of zero or more cards, one card per line. 2ab2db0bd3 2007-10-05 drh: ** (Except: the content of the W card can extend of multiple lines.) 2ab2db0bd3 2007-10-05 drh: ** Each card is divided into tokens by a single space character. 2ab2db0bd3 2007-10-05 drh: ** The first token is a single upper-case letter which is the card type. 2ab2db0bd3 2007-10-05 drh: ** The card type determines the other parameters to the card. 2ab2db0bd3 2007-10-05 drh: ** Cards must occur in lexicographical order. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int manifest_parse(Manifest *p, Blob *pContent){ dbda8d6ce9 2007-07-21 drh: int seenHeader = 0; 2ab2db0bd3 2007-10-05 drh: int seenZ = 0; 2ad378d065 2007-09-23 jnc: int i, lineNo=0; dbda8d6ce9 2007-07-21 drh: Blob line, token, a1, a2, a3; dea1ae50d3 2007-09-23 drh: char cPrevType = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memset(p, 0, sizeof(*p)); dbda8d6ce9 2007-07-21 drh: memcpy(&p->content, pContent, sizeof(p->content)); dbda8d6ce9 2007-07-21 drh: blob_zero(pContent); dbda8d6ce9 2007-07-21 drh: pContent = &p->content; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: blob_zero(&a1); dbda8d6ce9 2007-07-21 drh: blob_zero(&a2); 33c31f73cd 2008-02-21 drh: blob_zero(&a3); dbda8d6ce9 2007-07-21 drh: md5sum_init(); dbda8d6ce9 2007-07-21 drh: while( blob_line(pContent, &line) ){ dbda8d6ce9 2007-07-21 drh: char *z = blob_buffer(&line); 2ad378d065 2007-09-23 jnc: lineNo++; dbda8d6ce9 2007-07-21 drh: if( z[0]=='-' ){ dbda8d6ce9 2007-07-21 drh: if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){ dbda8d6ce9 2007-07-21 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( seenHeader ){ dbda8d6ce9 2007-07-21 drh: break; dbda8d6ce9 2007-07-21 drh: } f030c0aea7 2007-08-30 drh: while( blob_line(pContent, &line)>2 ){} dbda8d6ce9 2007-07-21 drh: if( blob_line(pContent, &line)==0 ) break; e37451d9c2 2007-08-01 drh: z = blob_buffer(&line); e37451d9c2 2007-08-01 drh: } dea1ae50d3 2007-09-23 drh: if( z[0]<cPrevType ){ 3dc92fdb7f 2007-09-21 drh: /* Lines of a manifest must occur in lexicographical order */ 3dc92fdb7f 2007-09-21 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } dea1ae50d3 2007-09-23 drh: cPrevType = z[0]; dbda8d6ce9 2007-07-21 drh: seenHeader = 1; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: switch( z[0] ){ 2ab2db0bd3 2007-10-05 drh: /* 2ab2db0bd3 2007-10-05 drh: ** A <uuid> <filename> <description> 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** Identifies an attachment to either a wiki page or a ticket. 2ab2db0bd3 2007-10-05 drh: ** <uuid> is the artifact that is the attachment. 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'A': { 2ab2db0bd3 2007-10-05 drh: char *zName, *zUuid, *zDesc; 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a3)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: zUuid = blob_terminate(&a1); 2ab2db0bd3 2007-10-05 drh: zName = blob_terminate(&a2); 2ab2db0bd3 2007-10-05 drh: zDesc = blob_terminate(&a3); 2ab2db0bd3 2007-10-05 drh: if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: defossilize(zName); 2ab2db0bd3 2007-10-05 drh: if( !file_is_simple_pathname(zName) ){ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: defossilize(zDesc); 2ab2db0bd3 2007-10-05 drh: if( p->nAttach>=p->nAttachAlloc ){ 2ab2db0bd3 2007-10-05 drh: p->nAttachAlloc = p->nAttachAlloc*2 + 10; 2ab2db0bd3 2007-10-05 drh: p->aAttach = realloc(p->aAttach, 2ab2db0bd3 2007-10-05 drh: p->nAttachAlloc*sizeof(p->aAttach[0]) ); 2ab2db0bd3 2007-10-05 drh: if( p->aAttach==0 ) fossil_panic("out of memory"); 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: i = p->nAttach++; 2ab2db0bd3 2007-10-05 drh: p->aAttach[i].zUuid = zUuid; 2ab2db0bd3 2007-10-05 drh: p->aAttach[i].zName = zName; 2ab2db0bd3 2007-10-05 drh: p->aAttach[i].zDesc = zDesc; 2ab2db0bd3 2007-10-05 drh: if( i>0 && strcmp(p->aAttach[i-1].zUuid, zUuid)>=0 ){ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: break; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: 3dc92fdb7f 2007-09-21 drh: /* 3dc92fdb7f 2007-09-21 drh: ** C <comment> 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** Comment text is fossil-encoded. There may be no more than 3dc92fdb7f 2007-09-21 drh: ** one C line. C lines are required for manifests and are 3dc92fdb7f 2007-09-21 drh: ** disallowed on all other control files. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'C': { 3dc92fdb7f 2007-09-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 3dc92fdb7f 2007-09-21 drh: if( p->zComment!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: p->zComment = blob_terminate(&a1); 3dc92fdb7f 2007-09-21 drh: defossilize(p->zComment); 3dc92fdb7f 2007-09-21 drh: break; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: /* 3dc92fdb7f 2007-09-21 drh: ** D <timestamp> 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** The timestamp should be ISO 8601. YYYY-MM-DDtHH:MM:SS 3dc92fdb7f 2007-09-21 drh: ** There can be no more than 1 D line. D lines are required 3dc92fdb7f 2007-09-21 drh: ** for all control files except for clusters. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'D': { 3dc92fdb7f 2007-09-21 drh: char *zDate; 3dc92fdb7f 2007-09-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 3dc92fdb7f 2007-09-21 drh: if( p->rDate!=0.0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: zDate = blob_terminate(&a1); 3dc92fdb7f 2007-09-21 drh: p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); 3dc92fdb7f 2007-09-21 drh: break; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: /* 2ab2db0bd3 2007-10-05 drh: ** E <mode> 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** Access mode. <mode> can be one of "read", "append", 2ab2db0bd3 2007-10-05 drh: ** or "write". 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'E': { 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( p->mode!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_eq(&a1, "write") ){ 2ab2db0bd3 2007-10-05 drh: p->mode = CFMODE_WRITE; 2ab2db0bd3 2007-10-05 drh: }else if( blob_eq(&a1, "append") ){ 2ab2db0bd3 2007-10-05 drh: p->mode = CFMODE_APPEND; 2ab2db0bd3 2007-10-05 drh: }else if( blob_eq(&a1, "read") ){ 2ab2db0bd3 2007-10-05 drh: p->mode = CFMODE_READ; 2ab2db0bd3 2007-10-05 drh: }else{ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: break; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: /* 33c31f73cd 2008-02-21 drh: ** F <filename> <uuid> ?<permissions>? 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** Identifies a file in a manifest. Multiple F lines are 3dc92fdb7f 2007-09-21 drh: ** allowed in a manifest. F lines are not allowed in any 3dc92fdb7f 2007-09-21 drh: ** other control file. The filename is fossil-encoded. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'F': { 33c31f73cd 2008-02-21 drh: char *zName, *zUuid, *zPerm; 3dc92fdb7f 2007-09-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: zName = blob_terminate(&a1); 3dc92fdb7f 2007-09-21 drh: zUuid = blob_terminate(&a2); 33c31f73cd 2008-02-21 drh: blob_token(&line, &a3); 33c31f73cd 2008-02-21 drh: zPerm = blob_terminate(&a3); 3dc92fdb7f 2007-09-21 drh: if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: defossilize(zName); 3dc92fdb7f 2007-09-21 drh: if( !file_is_simple_pathname(zName) ){ 3dc92fdb7f 2007-09-21 drh: goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: if( p->nFile>=p->nFileAlloc ){ 3dc92fdb7f 2007-09-21 drh: p->nFileAlloc = p->nFileAlloc*2 + 10; 3dc92fdb7f 2007-09-21 drh: p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); 3dc92fdb7f 2007-09-21 drh: if( p->aFile==0 ) fossil_panic("out of memory"); 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: i = p->nFile++; 3dc92fdb7f 2007-09-21 drh: p->aFile[i].zName = zName; 3dc92fdb7f 2007-09-21 drh: p->aFile[i].zUuid = zUuid; 33c31f73cd 2008-02-21 drh: p->aFile[i].zPerm = zPerm; 3dc92fdb7f 2007-09-21 drh: if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: break; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: /* d5e7891b07 2007-11-18 drh: ** J '+'?<name> <value> d5e7891b07 2007-11-18 drh: ** d5e7891b07 2007-11-18 drh: ** Specifies a name value pair for ticket. If the first character d5e7891b07 2007-11-18 drh: ** of <name> is "+" then the value is appended to any preexisting d5e7891b07 2007-11-18 drh: ** value. 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'J': { 2ab2db0bd3 2007-10-05 drh: char *zName, *zValue; 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: zName = blob_terminate(&a1); 2ab2db0bd3 2007-10-05 drh: zValue = blob_terminate(&a2); 2ab2db0bd3 2007-10-05 drh: defossilize(zValue); 2ab2db0bd3 2007-10-05 drh: if( p->nField>=p->nFieldAlloc ){ 2ab2db0bd3 2007-10-05 drh: p->nFieldAlloc = p->nFieldAlloc*2 + 10; 2ab2db0bd3 2007-10-05 drh: p->aField = realloc(p->aField, 2ab2db0bd3 2007-10-05 drh: p->nFieldAlloc*sizeof(p->aField[0]) ); 2ab2db0bd3 2007-10-05 drh: if( p->aField==0 ) fossil_panic("out of memory"); 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: i = p->nField++; 2ab2db0bd3 2007-10-05 drh: p->aField[i].zName = zName; 2ab2db0bd3 2007-10-05 drh: p->aField[i].zValue = zValue; 2ab2db0bd3 2007-10-05 drh: if( i>0 && strcmp(p->aField[i-1].zName, zName)>=0 ){ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: break; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: /* 2ab2db0bd3 2007-10-05 drh: ** K <uuid> 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** A K-line gives the UUID for the ticket which this control file 2ab2db0bd3 2007-10-05 drh: ** is amending. 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'K': { 2ab2db0bd3 2007-10-05 drh: char *zUuid; 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: zUuid = blob_terminate(&a1); 2ab2db0bd3 2007-10-05 drh: if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->zTicketUuid = zUuid; 2ab2db0bd3 2007-10-05 drh: break; 2ab2db0bd3 2007-10-05 drh: } 2ab2db0bd3 2007-10-05 drh: 2ab2db0bd3 2007-10-05 drh: /* d5e7891b07 2007-11-18 drh: ** L <wikititle> 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** The wiki page title is fossil-encoded. There may be no more than 2ab2db0bd3 2007-10-05 drh: ** one L line. 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'L': { 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->zWikiTitle = blob_terminate(&a1); 2ab2db0bd3 2007-10-05 drh: defossilize(p->zWikiTitle); 488afb9746 2007-10-06 drh: if( !wiki_name_is_wellformed(p->zWikiTitle) ){ 3dc92fdb7f 2007-09-21 drh: goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: break; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: /* 3dc92fdb7f 2007-09-21 drh: ** M <uuid> 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** An M-line identifies another artifact by its UUID. M-lines 3dc92fdb7f 2007-09-21 drh: ** occur in clusters only. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'M': { dbda8d6ce9 2007-07-21 drh: char *zUuid; 3dc92fdb7f 2007-09-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: zUuid = blob_terminate(&a1); 3dc92fdb7f 2007-09-21 drh: if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->nCChild>=p->nCChildAlloc ){ 3dc92fdb7f 2007-09-21 drh: p->nCChildAlloc = p->nCChildAlloc*2 + 10; 3dc92fdb7f 2007-09-21 drh: p->azCChild = 3dc92fdb7f 2007-09-21 drh: realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) ); 3dc92fdb7f 2007-09-21 drh: if( p->azCChild==0 ) fossil_panic("out of memory"); 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: i = p->nCChild++; 3dc92fdb7f 2007-09-21 drh: p->azCChild[i] = zUuid; 3dc92fdb7f 2007-09-21 drh: if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){ 3dc92fdb7f 2007-09-21 drh: goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: break; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: /* 3dc92fdb7f 2007-09-21 drh: ** P <uuid> ... 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** Specify one or more other artifacts where are the parents of 3dc92fdb7f 2007-09-21 drh: ** this artifact. The first parent is the primary parent. All 3dc92fdb7f 2007-09-21 drh: ** others are parents by merge. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'P': { 3dc92fdb7f 2007-09-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 3dc92fdb7f 2007-09-21 drh: while( blob_token(&line, &a1) ){ 3dc92fdb7f 2007-09-21 drh: char *zUuid; 3dc92fdb7f 2007-09-21 drh: if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: zUuid = blob_terminate(&a1); 3dc92fdb7f 2007-09-21 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->nParent>=p->nParentAlloc ){ 3dc92fdb7f 2007-09-21 drh: p->nParentAlloc = p->nParentAlloc*2 + 5; 3dc92fdb7f 2007-09-21 drh: p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); 3dc92fdb7f 2007-09-21 drh: if( p->azParent==0 ) fossil_panic("out of memory"); 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: i = p->nParent++; 3dc92fdb7f 2007-09-21 drh: p->azParent[i] = zUuid; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: break; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: /* 2ab2db0bd3 2007-10-05 drh: ** R <md5sum> 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** Specify the MD5 checksum of the entire baseline in a 2ab2db0bd3 2007-10-05 drh: ** manifest. 2ab2db0bd3 2007-10-05 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'R': { 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ab2db0bd3 2007-10-05 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( blob_size(&a1)!=32 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->zRepoCksum = blob_terminate(&a1); 2ab2db0bd3 2007-10-05 drh: if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; 2ad378d065 2007-09-23 jnc: break; 2ad378d065 2007-09-23 jnc: } 2ad378d065 2007-09-23 jnc: 2ad378d065 2007-09-23 jnc: /* 09c4adeb6f 2007-09-22 drh: ** T (+|*|-)<tagname> <uuid> ?<value>? f73c0e792b 2007-09-22 drh: ** f73c0e792b 2007-09-22 drh: ** Create or cancel a tag or property. The tagname is fossil-encoded. 09c4adeb6f 2007-09-22 drh: ** The first character of the name must be either "+" to create a 09c4adeb6f 2007-09-22 drh: ** singleton tag, "*" to create a propagating tag, or "-" to create 09c4adeb6f 2007-09-22 drh: ** anti-tag that undoes a prior "+" or blocks propagation of of 09c4adeb6f 2007-09-22 drh: ** a "*". 09c4adeb6f 2007-09-22 drh: ** 09c4adeb6f 2007-09-22 drh: ** The tag is applied to <uuid>. If <uuid> is "*" then the tag is 09c4adeb6f 2007-09-22 drh: ** applied to the current manifest. If <value> is provided then 09c4adeb6f 2007-09-22 drh: ** the tag is really a property with the given value. 09c4adeb6f 2007-09-22 drh: ** f73c0e792b 2007-09-22 drh: ** Tags are not allowed in clusters. Multiple T lines are allowed. f73c0e792b 2007-09-22 drh: */ f73c0e792b 2007-09-22 drh: case 'T': { f73c0e792b 2007-09-22 drh: char *zName, *zUuid, *zValue; f73c0e792b 2007-09-22 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); 2ad378d065 2007-09-23 jnc: if( blob_token(&line, &a1)==0 ){ 2ad378d065 2007-09-23 jnc: goto manifest_syntax_error; 2ad378d065 2007-09-23 jnc: } 2ad378d065 2007-09-23 jnc: if( blob_token(&line, &a2)==0 ){ 2ad378d065 2007-09-23 jnc: goto manifest_syntax_error; 2ad378d065 2007-09-23 jnc: } f73c0e792b 2007-09-22 drh: zName = blob_terminate(&a1); f73c0e792b 2007-09-22 drh: zUuid = blob_terminate(&a2); f73c0e792b 2007-09-22 drh: if( blob_token(&line, &a3)==0 ){ f73c0e792b 2007-09-22 drh: zValue = 0; f73c0e792b 2007-09-22 drh: }else{ f73c0e792b 2007-09-22 drh: zValue = blob_terminate(&a3); f73c0e792b 2007-09-22 drh: defossilize(zValue); f73c0e792b 2007-09-22 drh: } 09c4adeb6f 2007-09-22 drh: if( blob_size(&a2)==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){ 09c4adeb6f 2007-09-22 drh: /* A valid uuid */ 09c4adeb6f 2007-09-22 drh: }else if( blob_size(&a2)==1 && zUuid[0]=='*' ){ 0afb5e8e39 2008-03-08 drh: zUuid = 0; 09c4adeb6f 2007-09-22 drh: }else{ 09c4adeb6f 2007-09-22 drh: goto manifest_syntax_error; 09c4adeb6f 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: defossilize(zName); 09c4adeb6f 2007-09-22 drh: if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){ 3b5514ed82 2007-09-22 drh: goto manifest_syntax_error; 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: if( validate16(&zName[1], strlen(&zName[1])) ){ 3b5514ed82 2007-09-22 drh: /* Do not allow tags whose names look like UUIDs */ f73c0e792b 2007-09-22 drh: goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: if( p->nTag>=p->nTagAlloc ){ f73c0e792b 2007-09-22 drh: p->nTagAlloc = p->nTagAlloc*2 + 10; f73c0e792b 2007-09-22 drh: p->aTag = realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) ); f73c0e792b 2007-09-22 drh: if( p->aTag==0 ) fossil_panic("out of memory"); f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: i = p->nTag++; f73c0e792b 2007-09-22 drh: p->aTag[i].zName = zName; f73c0e792b 2007-09-22 drh: p->aTag[i].zUuid = zUuid; f73c0e792b 2007-09-22 drh: p->aTag[i].zValue = zValue; f73c0e792b 2007-09-22 drh: if( i>0 && strcmp(p->aTag[i-1].zName, zName)>=0 ){ f73c0e792b 2007-09-22 drh: goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: break; f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: f73c0e792b 2007-09-22 drh: /* f73c0e792b 2007-09-22 drh: ** U <login> f73c0e792b 2007-09-22 drh: ** f73c0e792b 2007-09-22 drh: ** Identify the user who created this control file by their f73c0e792b 2007-09-22 drh: ** login. Only one U line is allowed. Prohibited in clusters. f73c0e792b 2007-09-22 drh: */ f73c0e792b 2007-09-22 drh: case 'U': { f73c0e792b 2007-09-22 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); f73c0e792b 2007-09-22 drh: if( p->zUser!=0 ) goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: p->zUser = blob_terminate(&a1); f73c0e792b 2007-09-22 drh: defossilize(p->zUser); f73c0e792b 2007-09-22 drh: break; f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: f73c0e792b 2007-09-22 drh: /* 2ab2db0bd3 2007-10-05 drh: ** W <size> f73c0e792b 2007-09-22 drh: ** 2ab2db0bd3 2007-10-05 drh: ** The next <size> bytes of the file contain the text of the wiki 2ab2db0bd3 2007-10-05 drh: ** page. There is always an extra \n before the start of the next 2ab2db0bd3 2007-10-05 drh: ** record. f73c0e792b 2007-09-22 drh: */ 2ab2db0bd3 2007-10-05 drh: case 'W': { 2ab2db0bd3 2007-10-05 drh: int size; 2ab2db0bd3 2007-10-05 drh: Blob wiki; 2ab2db0bd3 2007-10-05 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)); f73c0e792b 2007-09-22 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; f73c0e792b 2007-09-22 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !blob_is_int(&a1, &size) ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( size<0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWiki!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: blob_zero(&wiki); 2ab2db0bd3 2007-10-05 drh: if( blob_extract(pContent, size+1, &wiki)!=size+1 ){ 2ab2db0bd3 2007-10-05 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } 2ab2db0bd3 2007-10-05 drh: p->zWiki = blob_buffer(&wiki); bf428e6854 2007-10-06 drh: md5sum_step_text(p->zWiki, size+1); 2ab2db0bd3 2007-10-05 drh: if( p->zWiki[size]!='\n' ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->zWiki[size] = 0; f73c0e792b 2007-09-22 drh: break; f73c0e792b 2007-09-22 drh: } f73c0e792b 2007-09-22 drh: f73c0e792b 2007-09-22 drh: f73c0e792b 2007-09-22 drh: /* 3dc92fdb7f 2007-09-21 drh: ** Z <md5sum> 3dc92fdb7f 2007-09-21 drh: ** 3dc92fdb7f 2007-09-21 drh: ** MD5 checksum on this control file. The checksum is over all 3dc92fdb7f 2007-09-21 drh: ** lines (other than PGP-signature lines) prior to the current 3dc92fdb7f 2007-09-21 drh: ** line. This must be the last record. 2ab2db0bd3 2007-10-05 drh: ** 2ab2db0bd3 2007-10-05 drh: ** This card is required for all control file types except for 2ab2db0bd3 2007-10-05 drh: ** Manifest. It is not required for manifest only for historical 2ab2db0bd3 2007-10-05 drh: ** compatibility reasons. 3dc92fdb7f 2007-09-21 drh: */ 3dc92fdb7f 2007-09-21 drh: case 'Z': { 3dc92fdb7f 2007-09-21 drh: int rc; 3dc92fdb7f 2007-09-21 drh: Blob hash; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( blob_size(&a1)!=32 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: md5sum_finish(&hash); 3dc92fdb7f 2007-09-21 drh: rc = blob_compare(&hash, &a1); 3dc92fdb7f 2007-09-21 drh: blob_reset(&hash); 3dc92fdb7f 2007-09-21 drh: if( rc!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: seenZ = 1; 3dc92fdb7f 2007-09-21 drh: break; dbda8d6ce9 2007-07-21 drh: } 3dc92fdb7f 2007-09-21 drh: default: { 3dc92fdb7f 2007-09-21 drh: goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !seenHeader ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: 3dc92fdb7f 2007-09-21 drh: if( p->nFile>0 ){ 3dc92fdb7f 2007-09-21 drh: if( p->nCChild>0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->rDate==0.0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nField>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nAttach>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWiki ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid ) goto manifest_syntax_error; 3b5514ed82 2007-09-22 drh: p->type = CFTYPE_MANIFEST; 3dc92fdb7f 2007-09-21 drh: }else if( p->nCChild>0 ){ 3dc92fdb7f 2007-09-21 drh: if( p->rDate>0.0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->zComment!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->zUser!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->nTag>0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->nParent>0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nField>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nAttach>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWiki ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !seenZ ) goto manifest_syntax_error; 3b5514ed82 2007-09-22 drh: p->type = CFTYPE_CLUSTER; 2ab2db0bd3 2007-10-05 drh: }else if( p->nField>0 ){ 2ab2db0bd3 2007-10-05 drh: if( p->rDate==0.0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWiki ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nCChild>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nTag>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zUser==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !seenZ ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->type = CFTYPE_TICKET; 2ab2db0bd3 2007-10-05 drh: }else if( p->zWiki!=0 ){ 2ab2db0bd3 2007-10-05 drh: if( p->rDate==0.0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nCChild>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nTag>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid!=0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle==0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !seenZ ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: p->type = CFTYPE_WIKI; 3dc92fdb7f 2007-09-21 drh: }else if( p->nTag>0 ){ 3dc92fdb7f 2007-09-21 drh: if( p->rDate<=0.0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; 3dc92fdb7f 2007-09-21 drh: if( p->nParent>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nAttach>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->nField>0 ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWiki ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zWikiTitle ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( p->zTicketUuid ) goto manifest_syntax_error; 2ab2db0bd3 2007-10-05 drh: if( !seenZ ) goto manifest_syntax_error; 3b5514ed82 2007-09-22 drh: p->type = CFTYPE_CONTROL; 3dc92fdb7f 2007-09-21 drh: }else{ c8da83ca36 2008-02-04 drh: if( p->nCChild>0 ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->rDate==0.0 ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->nField>0 ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->zTicketUuid ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->nAttach>0 ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->zWiki ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->zWikiTitle ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: if( p->zTicketUuid ) goto manifest_syntax_error; c8da83ca36 2008-02-04 drh: p->type = CFTYPE_MANIFEST; 3dc92fdb7f 2007-09-21 drh: } 3dc92fdb7f 2007-09-21 drh: dbda8d6ce9 2007-07-21 drh: md5sum_init(); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: manifest_syntax_error: 2ad378d065 2007-09-23 jnc: /*fprintf(stderr, "Manifest error on line %i\n", lineNo);fflush(stderr);*/ dbda8d6ce9 2007-07-21 drh: md5sum_init(); dbda8d6ce9 2007-07-21 drh: manifest_clear(p); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add a single entry to the mlink table. Also add the filename to dbda8d6ce9 2007-07-21 drh: ** the filename table if it is not there already. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void add_one_mlink( dbda8d6ce9 2007-07-21 drh: int mid, /* The record ID of the manifest */ dbda8d6ce9 2007-07-21 drh: const char *zFromUuid, /* UUID for the mlink.pid field */ dbda8d6ce9 2007-07-21 drh: const char *zToUuid, /* UUID for the mlink.fid field */ dbda8d6ce9 2007-07-21 drh: const char *zFilename /* Filename */ dbda8d6ce9 2007-07-21 drh: ){ dbda8d6ce9 2007-07-21 drh: int fnid, pid, fid; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); dbda8d6ce9 2007-07-21 drh: if( fnid==0 ){ dbda8d6ce9 2007-07-21 drh: db_multi_exec("INSERT INTO filename(name) VALUES(%Q)", zFilename); dbda8d6ce9 2007-07-21 drh: fnid = db_last_insert_rowid(); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zFromUuid==0 ){ dbda8d6ce9 2007-07-21 drh: pid = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pid = uuid_to_rid(zFromUuid, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( zToUuid==0 ){ dbda8d6ce9 2007-07-21 drh: fid = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: fid = uuid_to_rid(zToUuid, 1); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db_multi_exec( dbda8d6ce9 2007-07-21 drh: "INSERT INTO mlink(mid,pid,fid,fnid)" dbda8d6ce9 2007-07-21 drh: "VALUES(%d,%d,%d,%d)", mid, pid, fid, fnid dbda8d6ce9 2007-07-21 drh: ); dbda8d6ce9 2007-07-21 drh: if( pid && fid ){ dbda8d6ce9 2007-07-21 drh: content_deltify(pid, fid, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add mlink table entries associated with manifest cid. dbda8d6ce9 2007-07-21 drh: ** There is an mlink entry for every file that changed going dbda8d6ce9 2007-07-21 drh: ** from pid to cid. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Deleted files have mlink.fid=0. dbda8d6ce9 2007-07-21 drh: ** Added files have mlink.pid=0. dbda8d6ce9 2007-07-21 drh: ** Edited files have both mlink.pid!=0 and mlink.fid!=0 dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void add_mlink(int pid, Manifest *pParent, int cid, Manifest *pChild){ dbda8d6ce9 2007-07-21 drh: Manifest other; dbda8d6ce9 2007-07-21 drh: Blob otherContent; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", cid) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: assert( pParent==0 || pChild==0 ); dbda8d6ce9 2007-07-21 drh: if( pParent==0 ){ dbda8d6ce9 2007-07-21 drh: pParent = &other; dbda8d6ce9 2007-07-21 drh: content_get(pid, &otherContent); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: pChild = &other; dbda8d6ce9 2007-07-21 drh: content_get(cid, &otherContent); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( blob_size(&otherContent)==0 ) return; dbda8d6ce9 2007-07-21 drh: if( manifest_parse(&other, &otherContent)==0 ) return; dbda8d6ce9 2007-07-21 drh: content_deltify(pid, cid, 0); 5b58559c0c 2007-07-31 drh: for(i=j=0; i<pParent->nFile && j<pChild->nFile; ){ dbda8d6ce9 2007-07-21 drh: int c = strcmp(pParent->aFile[i].zName, pChild->aFile[j].zName); dbda8d6ce9 2007-07-21 drh: if( c<0 ){ dbda8d6ce9 2007-07-21 drh: add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName); dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: }else if( c>0 ){ dbda8d6ce9 2007-07-21 drh: add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName); dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: if( strcmp(pParent->aFile[i].zUuid, pChild->aFile[j].zUuid)!=0 ){ dbda8d6ce9 2007-07-21 drh: add_one_mlink(cid, pParent->aFile[i].zUuid, pChild->aFile[j].zUuid, dbda8d6ce9 2007-07-21 drh: pChild->aFile[j].zName); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( i<pParent->nFile ){ dbda8d6ce9 2007-07-21 drh: add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName); dbda8d6ce9 2007-07-21 drh: i++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: while( j<pChild->nFile ){ dbda8d6ce9 2007-07-21 drh: add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName); dbda8d6ce9 2007-07-21 drh: j++; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: manifest_clear(&other); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* 243e02bfbd 2008-05-18 drh: ** Scan artifact rid/pContent to see if it is a control artifact of 243e02bfbd 2008-05-18 drh: ** any key: 243e02bfbd 2008-05-18 drh: ** 243e02bfbd 2008-05-18 drh: ** * Manifest 243e02bfbd 2008-05-18 drh: ** * Control 243e02bfbd 2008-05-18 drh: ** * Wiki Page 243e02bfbd 2008-05-18 drh: ** * Ticket Change 243e02bfbd 2008-05-18 drh: ** * Cluster 243e02bfbd 2008-05-18 drh: ** 243e02bfbd 2008-05-18 drh: ** If the input is a control artifact, then make appropriate entries 243e02bfbd 2008-05-18 drh: ** in the auxiliary tables of the database in order to crosslink the 243e02bfbd 2008-05-18 drh: ** artifact. 243e02bfbd 2008-05-18 drh: ** 243e02bfbd 2008-05-18 drh: ** If global variable g.xlinkClusterOnly is true, then ignore all 243e02bfbd 2008-05-18 drh: ** control artifacts other than clusters. ba486fec5a 2007-09-03 drh: ** 243e02bfbd 2008-05-18 drh: ** Historical note: This routine original processed manifests only. 243e02bfbd 2008-05-18 drh: ** Processing for other control artifacts was added later. The name 243e02bfbd 2008-05-18 drh: ** of the routine, "manifest_crosslink", and the name of this source 243e02bfbd 2008-05-18 drh: ** file, is a legacy of its original use. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int manifest_crosslink(int rid, Blob *pContent){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Manifest m; dbda8d6ce9 2007-07-21 drh: Stmt q; 913608a5a6 2007-09-25 drh: int parentid = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( manifest_parse(&m, pContent)==0 ){ dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } 243e02bfbd 2008-05-18 drh: if( g.xlinkClusterOnly && m.type!=CFTYPE_CLUSTER ){ 243e02bfbd 2008-05-18 drh: manifest_clear(&m); 3b5514ed82 2007-09-22 drh: return 0; 3b5514ed82 2007-09-22 drh: } dbda8d6ce9 2007-07-21 drh: db_begin_transaction(); 3b5514ed82 2007-09-22 drh: if( m.type==CFTYPE_MANIFEST ){ 3b5514ed82 2007-09-22 drh: if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ 3b5514ed82 2007-09-22 drh: for(i=0; i<m.nParent; i++){ 3b5514ed82 2007-09-22 drh: int pid = uuid_to_rid(m.azParent[i], 1); 3b5514ed82 2007-09-22 drh: db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)" 3b5514ed82 2007-09-22 drh: "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate); 3b5514ed82 2007-09-22 drh: if( i==0 ){ 3b5514ed82 2007-09-22 drh: add_mlink(pid, 0, rid, &m); 913608a5a6 2007-09-25 drh: parentid = pid; 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid); 3b5514ed82 2007-09-22 drh: while( db_step(&q)==SQLITE_ROW ){ 3b5514ed82 2007-09-22 drh: int cid = db_column_int(&q, 0); 3b5514ed82 2007-09-22 drh: add_mlink(rid, &m, cid, 0); 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: db_finalize(&q); 3b5514ed82 2007-09-22 drh: db_multi_exec( 6af8fdc230 2007-12-04 drh: "REPLACE INTO event(type,mtime,objid,user,comment," ce7900a0b6 2007-09-25 drh: " bgcolor,brbgcolor,euser,ecomment)" ce7900a0b6 2007-09-25 drh: "VALUES('ci',%.17g,%d,%Q,%Q," ce7900a0b6 2007-09-25 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype=1)," ce7900a0b6 2007-09-25 drh: "(SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype!=1)," ce7900a0b6 2007-09-25 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," ce7900a0b6 2007-09-25 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", ce7900a0b6 2007-09-25 drh: m.rDate, rid, m.zUser, m.zComment, ce7900a0b6 2007-09-25 drh: TAG_BGCOLOR, rid, ce7900a0b6 2007-09-25 drh: TAG_BGCOLOR, rid, ce7900a0b6 2007-09-25 drh: TAG_USER, rid, ce7900a0b6 2007-09-25 drh: TAG_COMMENT, rid 3b5514ed82 2007-09-22 drh: ); 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: if( m.type==CFTYPE_CLUSTER ){ a48474bc75 2008-05-29 drh: tag_insert("cluster", 1, 0, rid, m.rDate, rid); 3b5514ed82 2007-09-22 drh: for(i=0; i<m.nCChild; i++){ 3b5514ed82 2007-09-22 drh: int mid; 3b5514ed82 2007-09-22 drh: mid = uuid_to_rid(m.azCChild[i], 1); 3b5514ed82 2007-09-22 drh: if( mid>0 ){ 3b5514ed82 2007-09-22 drh: db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid); 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: } 3b5514ed82 2007-09-22 drh: if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){ 3b5514ed82 2007-09-22 drh: for(i=0; i<m.nTag; i++){ 3b5514ed82 2007-09-22 drh: int tid; 09c4adeb6f 2007-09-22 drh: int type; 0afb5e8e39 2008-03-08 drh: if( m.aTag[i].zUuid ){ 0afb5e8e39 2008-03-08 drh: tid = uuid_to_rid(m.aTag[i].zUuid, 1); 0afb5e8e39 2008-03-08 drh: }else{ 0afb5e8e39 2008-03-08 drh: tid = rid; 913608a5a6 2007-09-25 drh: } a48474bc75 2008-05-29 drh: if( tid ){ a48474bc75 2008-05-29 drh: switch( m.aTag[i].zName[0] ){ a48474bc75 2008-05-29 drh: case '+': type = 1; break; a48474bc75 2008-05-29 drh: case '*': type = 2; break; a48474bc75 2008-05-29 drh: case '-': type = 0; break; a48474bc75 2008-05-29 drh: default: a48474bc75 2008-05-29 drh: fossil_fatal("unknown tag type in manifest: %s", m.aTag); a48474bc75 2008-05-29 drh: return 0; a48474bc75 2008-05-29 drh: } a48474bc75 2008-05-29 drh: tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue, a48474bc75 2008-05-29 drh: rid, m.rDate, tid); 18b1f6788d 2007-08-28 drh: } ba486fec5a 2007-09-03 drh: } 913608a5a6 2007-09-25 drh: if( parentid ){ 913608a5a6 2007-09-25 drh: tag_propagate_all(parentid); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } 2ab2db0bd3 2007-10-05 drh: if( m.type==CFTYPE_WIKI ){ 2ab2db0bd3 2007-10-05 drh: char *zTag = mprintf("wiki-%s", m.zWikiTitle); 2ab2db0bd3 2007-10-05 drh: int tagid = tag_findid(zTag, 1); 2ab2db0bd3 2007-10-05 drh: int prior; 6d58613757 2007-10-06 drh: char *zComment; 2ab2db0bd3 2007-10-05 drh: tag_insert(zTag, 1, 0, rid, m.rDate, rid); 2ab2db0bd3 2007-10-05 drh: free(zTag); 70d5cc86b7 2007-10-05 drh: prior = db_int(0, 70d5cc86b7 2007-10-05 drh: "SELECT rid FROM tagxref" 70d5cc86b7 2007-10-05 drh: " WHERE tagid=%d AND mtime<%.17g" 70d5cc86b7 2007-10-05 drh: " ORDER BY mtime DESC", 70d5cc86b7 2007-10-05 drh: tagid, m.rDate 70d5cc86b7 2007-10-05 drh: ); 2ab2db0bd3 2007-10-05 drh: if( prior ){ 2ab2db0bd3 2007-10-05 drh: content_deltify(prior, rid, 0); 18b1f6788d 2007-08-28 drh: } 6d58613757 2007-10-06 drh: zComment = mprintf("Changes to wiki page [%h]", m.zWikiTitle); ba486fec5a 2007-09-03 drh: db_multi_exec( 6af8fdc230 2007-12-04 drh: "REPLACE INTO event(type,mtime,objid,user,comment," 6d58613757 2007-10-06 drh: " bgcolor,brbgcolor,euser,ecomment)" 6d58613757 2007-10-06 drh: "VALUES('w',%.17g,%d,%Q,%Q," a48474bc75 2008-05-29 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype=1)," a48474bc75 2008-05-29 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype!=1)," 6d58613757 2007-10-06 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," 6d58613757 2007-10-06 drh: " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", 6d58613757 2007-10-06 drh: m.rDate, rid, m.zUser, zComment, 6d58613757 2007-10-06 drh: TAG_BGCOLOR, rid, 6d58613757 2007-10-06 drh: TAG_BGCOLOR, rid, 6d58613757 2007-10-06 drh: TAG_USER, rid, 6d58613757 2007-10-06 drh: TAG_COMMENT, rid ba486fec5a 2007-09-03 drh: ); 6d58613757 2007-10-06 drh: free(zComment); dbda8d6ce9 2007-07-21 drh: } fb358ca492 2007-11-24 drh: if( m.type==CFTYPE_TICKET ){ fb358ca492 2007-11-24 drh: char *zTag; b3ee50c946 2008-07-15 drh: Blob comment; fb358ca492 2007-11-24 drh: fb358ca492 2007-11-24 drh: ticket_insert(&m, 1, 1); fb358ca492 2007-11-24 drh: zTag = mprintf("tkt-%s", m.zTicketUuid); fb358ca492 2007-11-24 drh: tag_insert(zTag, 1, 0, rid, m.rDate, rid); fb358ca492 2007-11-24 drh: free(zTag); b3ee50c946 2008-07-15 drh: blob_zero(&comment); b3ee50c946 2008-07-15 drh: if( m.nField==1 ){ b3ee50c946 2008-07-15 drh: if( m.aField[0].zName[0]=='+' ){ b3ee50c946 2008-07-15 drh: blob_appendf(&comment, b3ee50c946 2008-07-15 drh: "Appended to %h in ticket [%.10s]", b3ee50c946 2008-07-15 drh: &m.aField[0].zName[1], m.zTicketUuid b3ee50c946 2008-07-15 drh: ); b3ee50c946 2008-07-15 drh: }else if( strlen(m.aField[0].zValue)<40 ){ b3ee50c946 2008-07-15 drh: blob_appendf(&comment, b3ee50c946 2008-07-15 drh: "Changed %h to \"%h\" in ticket [%.10s]", b3ee50c946 2008-07-15 drh: m.aField[0].zName, m.aField[0].zValue, m.zTicketUuid b3ee50c946 2008-07-15 drh: ); b3ee50c946 2008-07-15 drh: }else{ b3ee50c946 2008-07-15 drh: blob_appendf(&comment, b3ee50c946 2008-07-15 drh: "Changed %h in ticket [%.10s]", b3ee50c946 2008-07-15 drh: m.aField[0].zName, m.zTicketUuid b3ee50c946 2008-07-15 drh: ); b3ee50c946 2008-07-15 drh: } b3ee50c946 2008-07-15 drh: }else{ ac3f1f2ba7 2008-10-18 drh: #if 0 ac3f1f2ba7 2008-10-18 drh: int i; b3ee50c946 2008-07-15 drh: const char *z; b3ee50c946 2008-07-15 drh: const char *zSep = " "; b3ee50c946 2008-07-15 drh: blob_appendf(&comment, "%d changes to ticket [%.10s]:", b3ee50c946 2008-07-15 drh: m.nField, m.zTicketUuid); b3ee50c946 2008-07-15 drh: for(i=0; i<m.nField; i++){ b3ee50c946 2008-07-15 drh: z = m.aField[i].zName; b3ee50c946 2008-07-15 drh: if( z[0]=='+' ) z++; b3ee50c946 2008-07-15 drh: blob_appendf(&comment, "%s%h", zSep, z); b3ee50c946 2008-07-15 drh: zSep = ", "; 09c4adeb6f 2007-09-22 drh: } ac3f1f2ba7 2008-10-18 drh: #endif ac3f1f2ba7 2008-10-18 drh: blob_appendf(&comment, "Edits to ticket [%.10s]", m.zTicketUuid); 18b1f6788d 2007-08-28 drh: } 18b1f6788d 2007-08-28 drh: db_multi_exec( 6af8fdc230 2007-12-04 drh: "REPLACE INTO event(type,mtime,objid,user,comment)" fb358ca492 2007-11-24 drh: "VALUES('t',%.17g,%d,%Q,%Q)", b3ee50c946 2008-07-15 drh: m.rDate, rid, m.zUser, blob_str(&comment) 18b1f6788d 2007-08-28 drh: ); b3ee50c946 2008-07-15 drh: blob_reset(&comment); 18b1f6788d 2007-08-28 drh: } dbda8d6ce9 2007-07-21 drh: db_end_transaction(0); dbda8d6ce9 2007-07-21 drh: manifest_clear(&m); dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: }