Fossil

Check-in [932825bc6a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Take care to close the connection to the database file before existing. This gives the database a chance to clean up (and, for example, delete WAL and shared-memory files).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 932825bc6a2510ace4ba295f4f5462fe2fc054c4
User & Date: drh 2010-07-08 17:53:14.000
Context
2010-07-08
17:57
Update the built-in sqlite3 to the latest development version. ... (check-in: 1e6ded9856 user: drh tags: trunk)
17:53
Take care to close the connection to the database file before existing. This gives the database a chance to clean up (and, for example, delete WAL and shared-memory files). ... (check-in: 932825bc6a user: drh tags: trunk)
2010-07-07
14:57
Update the built-in SQLite to the latest 3.7.0 beta snapshot that includes fixes for large databases in WAL mode. ... (check-in: f0cd78c1a3 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/blob.c.
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
** This routine is called if a blob operation fails because we
** have run out of memory.
*/
static void blob_panic(void){
  static const char zErrMsg[] = "out of memory\n";
  write(2, zErrMsg, sizeof(zErrMsg)-1);
  exit(1);
}

/*
** A reallocation function that assumes that aData came from malloc().
** This function attempts to resize the buffer of the blob to hold
** newSize bytes.  
**







|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
** This routine is called if a blob operation fails because we
** have run out of memory.
*/
static void blob_panic(void){
  static const char zErrMsg[] = "out of memory\n";
  write(2, zErrMsg, sizeof(zErrMsg)-1);
  fossil_exit(1);
}

/*
** A reallocation function that assumes that aData came from malloc().
** This function attempts to resize the buffer of the blob to hold
** newSize bytes.  
**
Changes to src/branch.c.
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  blob_appendf(&branch, "Z %b\n", &mcksum);
  if( !noSign && clearsign(&branch, &branch) ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      exit(1);
    }
  }

  brid = content_put(&branch, 0, 0);
  if( brid==0 ){
    fossil_panic("trouble committing manifest: %s", g.zErrMsg);
  }







|







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  blob_appendf(&branch, "Z %b\n", &mcksum);
  if( !noSign && clearsign(&branch, &branch) ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      fossil_exit(1);
    }
  }

  brid = content_put(&branch, 0, 0);
  if( brid==0 ){
    fossil_panic("trouble committing manifest: %s", g.zErrMsg);
  }
Changes to src/cgi.c.
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  }
  cgi_append_header(zLocation);
  cgi_reset_content();
  cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zURL);
  cgi_set_status(302, "Moved Temporarily");
  free(zLocation);
  cgi_reply();
  exit(0);
}
void cgi_redirectf(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
  cgi_redirect(vmprintf(zFormat, ap));
  va_end(ap);
}







|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  }
  cgi_append_header(zLocation);
  cgi_reset_content();
  cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zURL);
  cgi_set_status(302, "Moved Temporarily");
  free(zLocation);
  cgi_reply();
  fossil_exit(0);
}
void cgi_redirectf(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
  cgi_redirect(vmprintf(zFormat, ap));
  va_end(ap);
}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
** zName and zValue are not copied and must not change or be
** deallocated after this routine returns.
*/
void cgi_set_parameter_nocopy(const char *zName, const char *zValue){
  if( nAllocQP<=nUsedQP ){
    nAllocQP = nAllocQP*2 + 10;
    aParamQP = realloc( aParamQP, nAllocQP*sizeof(aParamQP[0]) );
    if( aParamQP==0 ) exit(1);
  }
  aParamQP[nUsedQP].zName = zName;
  aParamQP[nUsedQP].zValue = zValue;
  if( g.fHttpTrace ){
    fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
  }
  aParamQP[nUsedQP].seq = seqQP++;







|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
** zName and zValue are not copied and must not change or be
** deallocated after this routine returns.
*/
void cgi_set_parameter_nocopy(const char *zName, const char *zValue){
  if( nAllocQP<=nUsedQP ){
    nAllocQP = nAllocQP*2 + 10;
    aParamQP = realloc( aParamQP, nAllocQP*sizeof(aParamQP[0]) );
    if( aParamQP==0 ) fossil_exit(1);
  }
  aParamQP[nUsedQP].zName = zName;
  aParamQP[nUsedQP].zValue = zValue;
  if( g.fHttpTrace ){
    fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
  }
  aParamQP[nUsedQP].seq = seqQP++;
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  len = atoi(PD("CONTENT_LENGTH", "0"));
  g.zContentType = zType = P("CONTENT_TYPE");
  if( len>0 && zType ){
    blob_zero(&g.cgiIn);
    if( strcmp(zType,"application/x-www-form-urlencoded")==0 
         || strncmp(zType,"multipart/form-data",19)==0 ){
      z = malloc( len+1 );
      if( z==0 ) exit(1);
      len = fread(z, 1, len, g.httpIn);
      z[len] = 0;
      if( zType[0]=='a' ){
        add_param_list(z, '&');
      }else{
        process_multipart_form_data(z, len);
      }







|







676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  len = atoi(PD("CONTENT_LENGTH", "0"));
  g.zContentType = zType = P("CONTENT_TYPE");
  if( len>0 && zType ){
    blob_zero(&g.cgiIn);
    if( strcmp(zType,"application/x-www-form-urlencoded")==0 
         || strncmp(zType,"multipart/form-data",19)==0 ){
      z = malloc( len+1 );
      if( z==0 ) fossil_exit(1);
      len = fread(z, 1, len, g.httpIn);
      z[len] = 0;
      if( zType[0]=='a' ){
        add_param_list(z, '&');
      }else{
        process_multipart_form_data(z, len);
      }
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
*/
static void malformed_request(void){
  cgi_set_status(501, "Not Implemented");
  cgi_printf(
    "<html><body>Unrecognized HTTP Request</body></html>\n"
  );
  cgi_reply();
  exit(0);
}

/*
** Panic and die while processing a webpage.
*/
void cgi_panic(const char *zFormat, ...){
  va_list ap;
  cgi_reset_content();
  cgi_set_status(500, "Internal Server Error");
  cgi_printf(
    "<html><body><h1>Internal Server Error</h1>\n"
    "<plaintext>"
  );
  va_start(ap, zFormat);
  vxprintf(pContent,zFormat,ap);
  va_end(ap);
  cgi_reply();
  exit(1);
}

/*
** Remove the first space-delimited token from a string and return
** a pointer to it.  Add a NULL to the string to terminate the token.
** Make *zLeftOver point to the start of the next token.
*/







|

















|







1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
*/
static void malformed_request(void){
  cgi_set_status(501, "Not Implemented");
  cgi_printf(
    "<html><body>Unrecognized HTTP Request</body></html>\n"
  );
  cgi_reply();
  fossil_exit(0);
}

/*
** Panic and die while processing a webpage.
*/
void cgi_panic(const char *zFormat, ...){
  va_list ap;
  cgi_reset_content();
  cgi_set_status(500, "Internal Server Error");
  cgi_printf(
    "<html><body><h1>Internal Server Error</h1>\n"
    "<plaintext>"
  );
  va_start(ap, zFormat);
  vxprintf(pContent,zFormat,ap);
  va_end(ap);
  cgi_reply();
  fossil_exit(1);
}

/*
** Remove the first space-delimited token from a string and return
** a pointer to it.  Add a NULL to the string to terminate the token.
** Make *zLeftOver point to the start of the next token.
*/
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
**
** Return 0 to each child as it runs.  If unable to establish a
** listening socket, return non-zero.
*/
int cgi_http_server(int mnPort, int mxPort, char *zBrowser){
#ifdef __MINGW32__
  /* Use win32_http_server() instead */
  exit(1);
#else
  int listener = -1;           /* The server socket */
  int connection;              /* A socket for each individual connection */
  fd_set readfds;              /* Set of file descriptors for select() */
  size_t lenaddr;              /* Length of the inaddr structure */
  int child;                   /* PID of the child process */
  int nchildren = 0;           /* Number of child processes */







|







1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
**
** Return 0 to each child as it runs.  If unable to establish a
** listening socket, return non-zero.
*/
int cgi_http_server(int mnPort, int mxPort, char *zBrowser){
#ifdef __MINGW32__
  /* Use win32_http_server() instead */
  fossil_exit(1);
#else
  int listener = -1;           /* The server socket */
  int connection;              /* A socket for each individual connection */
  fd_set readfds;              /* Set of file descriptors for select() */
  size_t lenaddr;              /* Length of the inaddr structure */
  int child;                   /* PID of the child process */
  int nchildren = 0;           /* Number of child processes */
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
    }
    /* Bury dead children */
    while( waitpid(0, 0, WNOHANG)>0 ){
      nchildren--;
    }
  }
  /* NOT REACHED */  
  exit(1);
#endif
}


/*
** Name of days and months.
*/







|







1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
    }
    /* Bury dead children */
    while( waitpid(0, 0, WNOHANG)>0 ){
      nchildren--;
    }
  }
  /* NOT REACHED */  
  fossil_exit(1);
#endif
}


/*
** Name of days and months.
*/
1354
1355
1356
1357
1358
1359
1360
1361
1362
void cgi_modified_since(time_t objectTime){
  const char *zIf = P("HTTP_IF_MODIFIED_SINCE");
  if( zIf==0 ) return;
  if( objectTime > cgi_rfc822_parsedate(zIf) ) return;
  cgi_set_status(304,"Not Modified");
  cgi_reset_content();
  cgi_reply();
  exit(0);
}







|

1354
1355
1356
1357
1358
1359
1360
1361
1362
void cgi_modified_since(time_t objectTime){
  const char *zIf = P("HTTP_IF_MODIFIED_SINCE");
  if( zIf==0 ) return;
  if( objectTime > cgi_rfc822_parsedate(zIf) ) return;
  cgi_set_status(304,"Not Modified");
  cgi_reset_content();
  cgi_reply();
  fossil_exit(0);
}
Changes to src/checkin.c.
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
    free(zInit);
  }
  if( blob_size(&comment)==0 ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("empty check-in comment.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      exit(1);
    }
  }else{
    db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
    db_end_transaction(0);
    db_begin_transaction();
  }








<
|







689
690
691
692
693
694
695

696
697
698
699
700
701
702
703
    free(zInit);
  }
  if( blob_size(&comment)==0 ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("empty check-in comment.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){

      fossil_exit(1);
    }
  }else{
    db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
    db_end_transaction(0);
    db_begin_transaction();
  }

827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
  blob_appendf(&manifest, "Z %b\n", &mcksum);
  zManifestFile = mprintf("%smanifest", g.zLocalRoot);
  if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      exit(1);
    }
  }
  blob_write_to_file(&manifest, zManifestFile);
  blob_reset(&manifest);
  blob_read_from_file(&manifest, zManifestFile);
  free(zManifestFile);
  nvid = content_put(&manifest, 0, 0);







<
|







826
827
828
829
830
831
832

833
834
835
836
837
838
839
840
  blob_appendf(&manifest, "Z %b\n", &mcksum);
  zManifestFile = mprintf("%smanifest", g.zLocalRoot);
  if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){

      fossil_exit(1);
    }
  }
  blob_write_to_file(&manifest, zManifestFile);
  blob_reset(&manifest);
  blob_read_from_file(&manifest, zManifestFile);
  free(zManifestFile);
  nvid = content_put(&manifest, 0, 0);
Changes to src/db.c.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    cgi_printf("<h1>Database Error</h1>\n"
               "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
  }
  db_force_rollback();
  exit(1);
}

static int nBegin = 0;      /* Nesting depth of BEGIN */
static int isNewRepo = 0;   /* True if the repository is newly created */
static int doRollback = 0;  /* True to force a rollback */
static int nCommitHook = 0; /* Number of commit hooks */
static struct sCommitHook {







|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    cgi_printf("<h1>Database Error</h1>\n"
               "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
  }
  db_force_rollback();
  fossil_exit(1);
}

static int nBegin = 0;      /* Nesting depth of BEGIN */
static int isNewRepo = 0;   /* True if the repository is newly created */
static int doRollback = 0;  /* True to force a rollback */
static int nCommitHook = 0; /* Number of commit hooks */
static struct sCommitHook {
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  if( nBegin==0 ){
    db_multi_exec("BEGIN");
    sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
  }
  nBegin++;
}
void db_end_transaction(int rollbackFlag){

  if( nBegin<=0 ) return;
  if( rollbackFlag ) doRollback = 1;
  nBegin--;
  if( nBegin==0 ){
    int i;
    for(i=0; doRollback==0 && i<nCommitHook; i++){
      doRollback |= aHook[i].xHook();
    }
    db_multi_exec(doRollback ? "ROLLBACK" : "COMMIT");
    doRollback = 0;
  }
}
void db_force_rollback(void){
  static int busy = 0;
  if( busy ) return;
  busy = 1;
  undo_rollback();
  if( nBegin ){
    sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
    if( isNewRepo ){
      db_close();
      unlink(g.zRepositoryName);







>














|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  if( nBegin==0 ){
    db_multi_exec("BEGIN");
    sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
  }
  nBegin++;
}
void db_end_transaction(int rollbackFlag){
  if( g.db==0 ) return;
  if( nBegin<=0 ) return;
  if( rollbackFlag ) doRollback = 1;
  nBegin--;
  if( nBegin==0 ){
    int i;
    for(i=0; doRollback==0 && i<nCommitHook; i++){
      doRollback |= aHook[i].xHook();
    }
    db_multi_exec(doRollback ? "ROLLBACK" : "COMMIT");
    doRollback = 0;
  }
}
void db_force_rollback(void){
  static int busy = 0;
  if( busy || g.db==0 ) return;
  busy = 1;
  undo_rollback();
  if( nBegin ){
    sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
    if( isNewRepo ){
      db_close();
      unlink(g.zRepositoryName);
596
597
598
599
600
601
602

603
604
605
606
607
608
609
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       zVfs
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000); 

  return db;
}


/*
** zDbName is the name of a database file.  If no other database
** file is open, then open this one.  If another database file is







>







597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       zVfs
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000); 
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  return db;
}


/*
** zDbName is the name of a database file.  If no other database
** file is open, then open this one.  If another database file is
894
895
896
897
898
899
900

901
902
903
904
905
906
907
** Close the database connection.
*/
void db_close(void){
  if( g.db==0 ) return;
  while( pAllStmt ){
    db_finalize(pAllStmt);
  }

  g.repositoryOpen = 0;
  g.localOpen = 0;
  g.configOpen = 0;
  sqlite3_close(g.db);
  g.db = 0;
}








>







896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
** Close the database connection.
*/
void db_close(void){
  if( g.db==0 ) return;
  while( pAllStmt ){
    db_finalize(pAllStmt);
  }
  db_end_transaction(1);
  g.repositoryOpen = 0;
  g.localOpen = 0;
  g.configOpen = 0;
  sqlite3_close(g.db);
  g.db = 0;
}

Changes to src/deltacmd.c.
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
** Given two input files, create and output a delta that carries
** the first file into the second.
*/
void delta_create_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    fprintf(stderr,"Usage: %s %s ORIGIN TARGET DELTA\n", g.argv[0], g.argv[1]);
    exit(1);
  }
  if( blob_read_from_file(&orig, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    exit(1);
  }
  if( blob_read_from_file(&target, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    exit(1);
  }
  blob_delta_create(&orig, &target, &delta);
  if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    exit(1);
  }
  blob_reset(&orig);
  blob_reset(&target);
  blob_reset(&delta);
}

/*







|



|



|




|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
** Given two input files, create and output a delta that carries
** the first file into the second.
*/
void delta_create_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    fprintf(stderr,"Usage: %s %s ORIGIN TARGET DELTA\n", g.argv[0], g.argv[1]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&orig, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&target, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    fossil_exit(1);
  }
  blob_delta_create(&orig, &target, &delta);
  if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    fossil_exit(1);
  }
  blob_reset(&orig);
  blob_reset(&target);
  blob_reset(&delta);
}

/*
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
** Given an input files and a delta, apply the delta to the input file
** and write the result.
*/
void delta_apply_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    fprintf(stderr,"Usage: %s %s ORIGIN DELTA TARGET\n", g.argv[0], g.argv[1]);
    exit(1);
  }
  if( blob_read_from_file(&orig, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    exit(1);
  }
  if( blob_read_from_file(&delta, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    exit(1);
  }
  blob_delta_apply(&orig, &delta, &target);
  if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    exit(1);
  }
  blob_reset(&orig);
  blob_reset(&target);
  blob_reset(&delta);
}

/*







|



|



|




|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
** Given an input files and a delta, apply the delta to the input file
** and write the result.
*/
void delta_apply_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    fprintf(stderr,"Usage: %s %s ORIGIN DELTA TARGET\n", g.argv[0], g.argv[1]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&orig, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&delta, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    fossil_exit(1);
  }
  blob_delta_apply(&orig, &delta, &target);
  if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    fossil_exit(1);
  }
  blob_reset(&orig);
  blob_reset(&target);
  blob_reset(&delta);
}

/*
Changes to src/file.c.
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  ){
    blob_set(pOut, zOrigName);
    blob_materialize(pOut);
  }else{
    char zPwd[2000];
    if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
      fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20);
      exit(1);
    }
    blob_zero(pOut);
    blob_appendf(pOut, "%//%/", zPwd, zOrigName);
  }
  blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut)));
}








|







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  ){
    blob_set(pOut, zOrigName);
    blob_materialize(pOut);
  }else{
    char zPwd[2000];
    if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
      fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20);
      fossil_exit(1);
    }
    blob_zero(pOut);
    blob_appendf(pOut, "%//%/", zPwd, zOrigName);
  }
  blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut)));
}

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  zPath = blob_buffer(pOut);
  if( zPath[0]=='/' ){
    int i, j;
    Blob tmp;
    char zPwd[2000];
    if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
      fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20);
      exit(1);
    }
    for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){}
    if( zPath[i]==0 ){
      blob_reset(pOut);
      if( zPwd[i]==0 ){
        blob_append(pOut, ".", 1);
      }else{







|







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  zPath = blob_buffer(pOut);
  if( zPath[0]=='/' ){
    int i, j;
    Blob tmp;
    char zPwd[2000];
    if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){
      fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20);
      fossil_exit(1);
    }
    for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){}
    if( zPath[i]==0 ){
      blob_reset(pOut);
      if( zPwd[i]==0 ){
        blob_append(pOut, ".", 1);
      }else{
Changes to src/main.c.
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255


256
257
258
259
260
261
262
263
264








265
266
267
268
269
270
271
}


/*
** This procedure runs first.
*/
int main(int argc, char **argv){
  const char *zCmdName;
  int idx;
  int rc;

  sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
  g.now = time(0);
  g.argc = argc;
  g.argv = argv;
  if( getenv("GATEWAY_INTERFACE")!=0 ){
    zCmdName = "cgi";
  }else if( argc<2 ){
    fprintf(stderr, "Usage: %s COMMAND ...\n", argv[0]);
    exit(1);
  }else{
    g.fQuiet = find_option("quiet", 0, 0)!=0;
    g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
    g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
    g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
    g.zLogin = find_option("user", "U", 1);
    zCmdName = argv[1];
  }
  rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
  if( rc==1 ){
    fprintf(stderr,"%s: unknown command: %s\n"
                   "%s: use \"help\" for more information\n",
                   argv[0], zCmdName, argv[0]);
    return 1;
  }else if( rc==2 ){
    fprintf(stderr,"%s: ambiguous command prefix: %s\n"
                   "%s: use \"help\" for more information\n",
                   argv[0], zCmdName, argv[0]);
    return 1;
  }
  aCommand[idx].xFunc();


  return 0;
}

/*
** The following variable becomes true while processing a fatal error
** or a panic.  If additional "recursive-fatal" errors occur while
** shutting down, the recursive errors are silently ignored.
*/
static int mainInFatalError = 0;









/*
** Print an error message, rollback all databases, and quit.  These
** routines never return.
*/
void fossil_panic(const char *zFormat, ...){
  char *z;







|











|













|




|


>
>









>
>
>
>
>
>
>
>







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
}


/*
** This procedure runs first.
*/
int main(int argc, char **argv){
  const char *zCmdName = "unknown";
  int idx;
  int rc;

  sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
  g.now = time(0);
  g.argc = argc;
  g.argv = argv;
  if( getenv("GATEWAY_INTERFACE")!=0 ){
    zCmdName = "cgi";
  }else if( argc<2 ){
    fprintf(stderr, "Usage: %s COMMAND ...\n", argv[0]);
    fossil_exit(1);
  }else{
    g.fQuiet = find_option("quiet", 0, 0)!=0;
    g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
    g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
    g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
    g.zLogin = find_option("user", "U", 1);
    zCmdName = argv[1];
  }
  rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
  if( rc==1 ){
    fprintf(stderr,"%s: unknown command: %s\n"
                   "%s: use \"help\" for more information\n",
                   argv[0], zCmdName, argv[0]);
    fossil_exit(1);
  }else if( rc==2 ){
    fprintf(stderr,"%s: ambiguous command prefix: %s\n"
                   "%s: use \"help\" for more information\n",
                   argv[0], zCmdName, argv[0]);
    fossil_exit(1);
  }
  aCommand[idx].xFunc();
  fossil_exit(0);
  /*NOT_REACHED*/
  return 0;
}

/*
** The following variable becomes true while processing a fatal error
** or a panic.  If additional "recursive-fatal" errors occur while
** shutting down, the recursive errors are silently ignored.
*/
static int mainInFatalError = 0;

/*
** Exit.  Take care to close the database first.
*/
void fossil_exit(int rc){
  db_close();
  exit(rc);
}

/*
** Print an error message, rollback all databases, and quit.  These
** routines never return.
*/
void fossil_panic(const char *zFormat, ...){
  char *z;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    once = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  exit(1);
}
void fossil_fatal(const char *zFormat, ...){
  char *z;
  va_list ap;
  mainInFatalError = 1;
  va_start(ap, zFormat);
  z = vmprintf(zFormat, ap);
  va_end(ap);
  if( g.cgiOutput ){
    g.cgiOutput = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  exit(1);
}

/* This routine works like fossil_fatal() except that if called
** recursively, the recursive call is a no-op.
**
** Use this in places where an error might occur while doing
** fatal error shutdown processing.  Unlike fossil_panic() and







|
















|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
    once = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  fossil_exit(1);
}
void fossil_fatal(const char *zFormat, ...){
  char *z;
  va_list ap;
  mainInFatalError = 1;
  va_start(ap, zFormat);
  z = vmprintf(zFormat, ap);
  va_end(ap);
  if( g.cgiOutput ){
    g.cgiOutput = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  fossil_exit(1);
}

/* This routine works like fossil_fatal() except that if called
** recursively, the recursive call is a no-op.
**
** Use this in places where an error might occur while doing
** fatal error shutdown processing.  Unlike fossil_panic() and
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
    g.cgiOutput = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  exit(1);
}


/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
  char *z;
  va_list ap;







|







334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
    g.cgiOutput = 0;
    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
    cgi_reply();
  }else{
    fprintf(stderr, "%s: %s\n", g.argv[0], z);
  }
  db_force_rollback();
  fossil_exit(1);
}


/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
  char *z;
  va_list ap;
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
}

/*
** Print a usage comment and quit
*/
void usage(const char *zFormat){
  fprintf(stderr, "Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
  exit(1);
}

/*
** Remove n elements from g.argv beginning with the i-th element.
*/
void remove_from_argv(int i, int n){
  int j;







|







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
}

/*
** Print a usage comment and quit
*/
void usage(const char *zFormat){
  fprintf(stderr, "Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
  fossil_exit(1);
}

/*
** Remove n elements from g.argv beginning with the i-th element.
*/
void remove_from_argv(int i, int n){
  int j;
Changes to src/merge3.c.
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
** Combine change in going from PIVOT->VERSION1 with the change going
** from PIVOT->VERSION2 and write the combined changes into MERGED.
*/
void delta_3waymerge_cmd(void){
  Blob pivot, v1, v2, merged;
  if( g.argc!=6 ){
    fprintf(stderr,"Usage: %s %s PIVOT V1 V2 MERGED\n", g.argv[0], g.argv[1]);
    exit(1);
  }
  if( blob_read_from_file(&pivot, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    exit(1);
  }
  if( blob_read_from_file(&v1, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    exit(1);
  }
  if( blob_read_from_file(&v2, g.argv[4])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[4]);
    exit(1);
  }
  blob_merge(&pivot, &v1, &v2, &merged);
  if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    exit(1);
  }
  blob_reset(&pivot);
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&merged);
}







|



|



|



|




|






301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
** Combine change in going from PIVOT->VERSION1 with the change going
** from PIVOT->VERSION2 and write the combined changes into MERGED.
*/
void delta_3waymerge_cmd(void){
  Blob pivot, v1, v2, merged;
  if( g.argc!=6 ){
    fprintf(stderr,"Usage: %s %s PIVOT V1 V2 MERGED\n", g.argv[0], g.argv[1]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&pivot, g.argv[2])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[2]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&v1, g.argv[3])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[3]);
    fossil_exit(1);
  }
  if( blob_read_from_file(&v2, g.argv[4])<0 ){
    fprintf(stderr,"cannot read %s\n", g.argv[4]);
    fossil_exit(1);
  }
  blob_merge(&pivot, &v1, &v2, &merged);
  if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){
    fprintf(stderr,"cannot write %s\n", g.argv[4]);
    fossil_exit(1);
  }
  blob_reset(&pivot);
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&merged);
}
Changes to src/name.c.
363
364
365
366
367
368
369
370
    return 0;
  }else{
    rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
    blob_reset(&name);
  }
  return rid;
}








<
363
364
365
366
367
368
369

    return 0;
  }else{
    rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &name);
    blob_reset(&name);
  }
  return rid;
}

Changes to src/rebuild.c.
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  if( !bForce ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("Scrubbing the repository will permanently remove user\n"
                "passwords and other information. Changes cannot be undone.\n"
                "Continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      exit(1);
    }
  }
  db_begin_transaction();
  db_multi_exec(
    "UPDATE user SET pw='';"
    "DELETE FROM config WHERE name GLOB 'last-sync-*';"
  );







|







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  if( !bForce ){
    Blob ans;
    blob_zero(&ans);
    prompt_user("Scrubbing the repository will permanently remove user\n"
                "passwords and other information. Changes cannot be undone.\n"
                "Continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      fossil_exit(1);
    }
  }
  db_begin_transaction();
  db_multi_exec(
    "UPDATE user SET pw='';"
    "DELETE FROM config WHERE name GLOB 'last-sync-*';"
  );
Changes to src/sync.c.
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    zUrl = db_get("last-sync-url", 0);
    zPw = db_get("last-sync-pw", 0);
    if( db_get_boolean("auto-sync",1) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){
    zUrl = g.argv[2];
  }
  if( zUrl==0 ){
    if( urlOptional ) exit(0);
    usage("URL");
  }
  url_parse(zUrl);
  if( !g.dontKeepUrl ){
    db_set("last-sync-url", g.urlCanonical, 0);
    if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0);
  }







|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    zUrl = db_get("last-sync-url", 0);
    zPw = db_get("last-sync-pw", 0);
    if( db_get_boolean("auto-sync",1) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){
    zUrl = g.argv[2];
  }
  if( zUrl==0 ){
    if( urlOptional ) fossil_exit(0);
    usage("URL");
  }
  url_parse(zUrl);
  if( !g.dontKeepUrl ){
    db_set("last-sync-url", g.urlCanonical, 0);
    if( g.urlPasswd ) db_set("last-sync-pw", g.urlPasswd, 0);
  }