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: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code used to cross link manifests 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: /* dbda8d6ce9 2007-07-21 drh: ** A parsed manifest dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: struct Manifest { dbda8d6ce9 2007-07-21 drh: Blob content; /* The original content blob */ 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 */ 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 */ 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 */ 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); 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: /* dbda8d6ce9 2007-07-21 drh: ** Parse a manifest blob into a Manifest object. The Manifest dbda8d6ce9 2007-07-21 drh: ** object 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: ** dbda8d6ce9 2007-07-21 drh: ** Return TRUE if the content really is a manifest. Return FALSE dbda8d6ce9 2007-07-21 drh: ** if there are syntax errors. 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. 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; dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Blob line, token, a1, a2, a3; 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); 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); 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: } dbda8d6ce9 2007-07-21 drh: while( blob_line(pContent, &line)>1 ){} dbda8d6ce9 2007-07-21 drh: if( blob_line(pContent, &line)==0 ) break; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: seenHeader = 1; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( z[0]=='F' ){ dbda8d6ce9 2007-07-21 drh: char *zName, *zUuid; dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: zName = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: zUuid = blob_terminate(&a2); dbda8d6ce9 2007-07-21 drh: if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: defossilize(zName); dbda8d6ce9 2007-07-21 drh: if( !file_is_simple_pathname(zName) ){ dbda8d6ce9 2007-07-21 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( p->nFile>=p->nFileAlloc ){ dbda8d6ce9 2007-07-21 drh: p->nFileAlloc = p->nFileAlloc*2 + 10; dbda8d6ce9 2007-07-21 drh: p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) ); dbda8d6ce9 2007-07-21 drh: if( p->aFile==0 ) fossil_panic("out of memory"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i = p->nFile++; dbda8d6ce9 2007-07-21 drh: p->aFile[i].zName = zName; dbda8d6ce9 2007-07-21 drh: p->aFile[i].zUuid = zUuid; dbda8d6ce9 2007-07-21 drh: if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){ dbda8d6ce9 2007-07-21 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='C' ){ dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: if( p->zComment!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: p->zComment = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: defossilize(p->zComment); dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='D' ){ dbda8d6ce9 2007-07-21 drh: char *zDate; dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: if( p->rDate!=0.0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: zDate = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='U' ){ dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: if( p->zUser!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: p->zUser = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: defossilize(p->zUser); dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='R' ){ dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: if( p->zRepoCksum!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_size(&a1)!=32 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: p->zRepoCksum = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='P' ){ dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(&line), blob_size(&line)+1); dbda8d6ce9 2007-07-21 drh: while( blob_token(&line, &a1) ){ dbda8d6ce9 2007-07-21 drh: char *zUuid; dbda8d6ce9 2007-07-21 drh: if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: zUuid = blob_terminate(&a1); dbda8d6ce9 2007-07-21 drh: if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( p->nParent>=p->nParentAlloc ){ dbda8d6ce9 2007-07-21 drh: p->nParentAlloc = p->nParentAlloc*2 + 5; dbda8d6ce9 2007-07-21 drh: p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*)); dbda8d6ce9 2007-07-21 drh: if( p->azParent==0 ) fossil_panic("out of memory"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: i = p->nParent++; dbda8d6ce9 2007-07-21 drh: p->azParent[i] = zUuid; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }else if( z[0]=='Z' ){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: Blob hash; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( blob_size(&a1)!=32 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: md5sum_finish(&hash); dbda8d6ce9 2007-07-21 drh: rc = blob_compare(&hash, &a1); dbda8d6ce9 2007-07-21 drh: blob_reset(&hash); dbda8d6ce9 2007-07-21 drh: if( rc!=0 ) goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: goto manifest_syntax_error; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !seenHeader ) goto manifest_syntax_error; 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: 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); dbda8d6ce9 2007-07-21 drh: for(i=j=0; pParent->nFile<i && pChild->nFile<j; ){ 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: /* dbda8d6ce9 2007-07-21 drh: ** Scan record rid/pContent to see if it is a manifest. If dbda8d6ce9 2007-07-21 drh: ** it is a manifest, then populate tables the mlink, plink, dbda8d6ce9 2007-07-21 drh: ** filename, and event tables with cross-reference information. 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; 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: } dbda8d6ce9 2007-07-21 drh: db_begin_transaction(); dbda8d6ce9 2007-07-21 drh: for(i=0; i<m.nParent; i++){ dbda8d6ce9 2007-07-21 drh: int pid = uuid_to_rid(m.azParent[i], 1); dbda8d6ce9 2007-07-21 drh: db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)" dbda8d6ce9 2007-07-21 drh: "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate); dbda8d6ce9 2007-07-21 drh: if( i==0 ){ dbda8d6ce9 2007-07-21 drh: add_mlink(pid, 0, rid, &m); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid); dbda8d6ce9 2007-07-21 drh: while( db_step(&q)==SQLITE_ROW ){ dbda8d6ce9 2007-07-21 drh: int cid = db_column_int(&q, 0); dbda8d6ce9 2007-07-21 drh: add_mlink(rid, &m, cid, 0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db_finalize(&q); dbda8d6ce9 2007-07-21 drh: db_multi_exec( dbda8d6ce9 2007-07-21 drh: "INSERT INTO event(type,mtime,objid,user,comment)" dbda8d6ce9 2007-07-21 drh: "VALUES('ci',%.17g,%d,%Q,%Q)", dbda8d6ce9 2007-07-21 drh: m.rDate, rid, m.zUser, m.zComment dbda8d6ce9 2007-07-21 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: }