Fossil

Check-in [4c3e1728e1]
Login

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

Overview
Comment:Minor optimization: replace calls to mprintf("%s", X) with fossil_strdup(X).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 4c3e1728e1b1a9cb8425046aad3f5c753f33abd751a8a365420cf3397ba21ab9
User & Date: danield 2025-07-23 15:58:49.287
References
2025-10-21
13:49
Revert two small sections of [4c3e1728e1b1a9cb] for cases which are not compatible with fsl_strdup()'s passing-on of NULL values. Found while investigating a presumably unrelated crash. check-in: 20adff9572 user: stephan tags: trunk
2025-08-04
23:58
Add a NULL check where a change from [4c3e1728e1b1a9cb] inadvertently changed the semantics from NULL=="" to NULL==NULL, triggering a null pointer deref via backlinks parsing. Triggered by rebuild when encountering a tag with no value. check-in: 441264b759 user: stephan tags: trunk
Context
2025-07-27
11:07
Teach the sync protocol how to work with an out-of-band login card, saving an extra server-side copy of the sync content which is required only to account for an inlined login card. i.e. it saves RAM, potentially lots of it. The new login card mechanism is instead transported via an HTTP header. This also, not coincidentally, simplifies implementation of the login card in non-fossil(1) clients which are currently learning to speak the sync protocol. check-in: 18628904c3 user: stephan tags: trunk
2025-07-23
15:58
Minor optimization: replace calls to mprintf("%s", X) with fossil_strdup(X). check-in: 4c3e1728e1 user: danield tags: trunk
2025-07-21
17:16
Account for [638b7e094b899a] when building with --json, as reported in [forum:9acc3d0022407bfe | forum post 9acc3d0022]. check-in: c6f0d7aecd user: stephan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/bisect.c.
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
        rid = -rid;
      }
    }
    zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
    if( blob_size(&link)>0 ) blob_append(&link, "-", 1);
    blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
  }
  zResult = mprintf("%s", blob_str(&link));
  blob_reset(&link);
  blob_reset(&log);
  blob_reset(&id);
  return zResult;
}

/*







|







334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
        rid = -rid;
      }
    }
    zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
    if( blob_size(&link)>0 ) blob_append(&link, "-", 1);
    blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
  }
  zResult = fossil_strdup(blob_str(&link));
  blob_reset(&link);
  blob_reset(&log);
  blob_reset(&id);
  return zResult;
}

/*
Changes to src/chat.c.
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
                       "\r\n%z\r\n%s", obscure(zPw), zBoundary);
    }
    if( zMsg && zMsg[0] ){
      blob_appendf(&up,"\r\nContent-Disposition: form-data; name=\"msg\"\r\n"
                       "\r\n%s\r\n%s", zMsg, zBoundary);
    }
    if( zFilename && blob_read_from_file(&fcontent, zFilename, ExtFILE)>0 ){
      char *zFN = mprintf("%s", file_tail(zAs ? zAs : zFilename));
      int i;
      const char *zMime = mimetype_from_name(zFN);
      for(i=0; zFN[i]; i++){
        char c = zFN[i];
        if( fossil_isalnum(c) ) continue;
        if( c=='.' ) continue;
        if( c=='-' ) continue;







|







1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
                       "\r\n%z\r\n%s", obscure(zPw), zBoundary);
    }
    if( zMsg && zMsg[0] ){
      blob_appendf(&up,"\r\nContent-Disposition: form-data; name=\"msg\"\r\n"
                       "\r\n%s\r\n%s", zMsg, zBoundary);
    }
    if( zFilename && blob_read_from_file(&fcontent, zFilename, ExtFILE)>0 ){
      char *zFN = fossil_strdup(file_tail(zAs ? zAs : zFilename));
      int i;
      const char *zMime = mimetype_from_name(zFN);
      for(i=0; zFN[i]; i++){
        char c = zFN[i];
        if( fossil_isalnum(c) ) continue;
        if( c=='.' ) continue;
        if( c=='-' ) continue;
Changes to src/checkin.c.
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
    blob_zero(&fname);
    if( g.zLocalRoot!=0 ){
      file_relative_name(g.zLocalRoot, &fname, 1);
      zFile = db_text(0, "SELECT '%qci-comment-'||hex(randomblob(6))||'.txt'",
                      blob_str(&fname));
    }else{
      file_tempname(&fname, "ci-comment",0);
      zFile = mprintf("%s", blob_str(&fname));
    }
    blob_reset(&fname);
  }
#if defined(_WIN32)
  blob_add_cr(pPrompt);
#endif
  if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);







|







1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
    blob_zero(&fname);
    if( g.zLocalRoot!=0 ){
      file_relative_name(g.zLocalRoot, &fname, 1);
      zFile = db_text(0, "SELECT '%qci-comment-'||hex(randomblob(6))||'.txt'",
                      blob_str(&fname));
    }else{
      file_tempname(&fname, "ci-comment",0);
      zFile = fossil_strdup(blob_str(&fname));
    }
    blob_reset(&fname);
  }
#if defined(_WIN32)
  blob_add_cr(pPrompt);
#endif
  if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);
Changes to src/clone.c.
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
*/
void remember_or_get_http_auth(
  const char *zHttpAuth,  /* Credentials in the form "user:password" */
  int fRemember,          /* True to remember credentials for later reuse */
  const char *zUrl        /* URL for which these credentials apply */
){
  if( zHttpAuth && zHttpAuth[0] ){
    g.zHttpAuth = mprintf("%s", zHttpAuth);
  }
  if( fRemember ){
    if( g.zHttpAuth && g.zHttpAuth[0] ){
      set_httpauth(g.zHttpAuth);
    }else if( zUrl && zUrl[0] ){
      db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
    }else{







|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
*/
void remember_or_get_http_auth(
  const char *zHttpAuth,  /* Credentials in the form "user:password" */
  int fRemember,          /* True to remember credentials for later reuse */
  const char *zUrl        /* URL for which these credentials apply */
){
  if( zHttpAuth && zHttpAuth[0] ){
    g.zHttpAuth = fossil_strdup(zHttpAuth);
  }
  if( fRemember ){
    if( g.zHttpAuth && g.zHttpAuth[0] ){
      set_httpauth(g.zHttpAuth);
    }else if( zUrl && zUrl[0] ){
      db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
    }else{
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
** Look for SSH clone command line options and setup in globals.
*/
void clone_ssh_find_options(void){
  const char *zSshCmd;        /* SSH command string */

  zSshCmd = find_option("ssh-command","c",1);
  if( zSshCmd && zSshCmd[0] ){
    g.zSshCmd = mprintf("%s", zSshCmd);
  }
}

/*
** Set SSH options discovered in global variables (set from command line
** options).
*/







|







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
** Look for SSH clone command line options and setup in globals.
*/
void clone_ssh_find_options(void){
  const char *zSshCmd;        /* SSH command string */

  zSshCmd = find_option("ssh-command","c",1);
  if( zSshCmd && zSshCmd[0] ){
    g.zSshCmd = fossil_strdup(zSshCmd);
  }
}

/*
** Set SSH options discovered in global variables (set from command line
** options).
*/
Changes to src/comformat.c.
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
    indent = -1; /* automatic */
  }
  verify_all_options();
  zPrefix = zText = zOrigText = 0;
  if( fromFile ){
    Blob fileData;
    blob_read_from_file(&fileData, fromFile, ExtFILE);
    zText = mprintf("%s", blob_str(&fileData));
    blob_reset(&fileData);
  }
  if( fromOrig ){
    Blob fileData;
    blob_read_from_file(&fileData, fromOrig, ExtFILE);
    zOrigText = mprintf("%s", blob_str(&fileData));
    blob_reset(&fileData);
  }
  for(i=2; i<g.argc; i++){
    if( zText==0 ){
      zText = g.argv[i];
      continue;
    }







|





|







805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
    indent = -1; /* automatic */
  }
  verify_all_options();
  zPrefix = zText = zOrigText = 0;
  if( fromFile ){
    Blob fileData;
    blob_read_from_file(&fileData, fromFile, ExtFILE);
    zText = fossil_strdup(blob_str(&fileData));
    blob_reset(&fileData);
  }
  if( fromOrig ){
    Blob fileData;
    blob_read_from_file(&fileData, fromOrig, ExtFILE);
    zOrigText = fossil_strdup(blob_str(&fileData));
    blob_reset(&fileData);
  }
  for(i=2; i<g.argc; i++){
    if( zText==0 ){
      zText = g.argv[i];
      continue;
    }
Changes to src/cookies.c.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
** by DISPLAY_SETTINGS_COOKIE
*/
void cookie_parse(void){
  char *z;
  if( cookies.bIsInit ) return;
  z = (char*)P(DISPLAY_SETTINGS_COOKIE);
  if( z==0 ) z = "";
  cookies.zCookieValue = z = mprintf("%s", z);
  cookies.bIsInit = 1;
  while( cookies.nParam<COOKIE_NPARAM ){
    while( fossil_isspace(z[0]) ) z++;
    if( z[0]==0 ) break;
    cookies.aParam[cookies.nParam].zPName = z;
    while( *z && *z!='=' && *z!=',' ){ z++; }
    if( *z=='=' ){







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
** by DISPLAY_SETTINGS_COOKIE
*/
void cookie_parse(void){
  char *z;
  if( cookies.bIsInit ) return;
  z = (char*)P(DISPLAY_SETTINGS_COOKIE);
  if( z==0 ) z = "";
  cookies.zCookieValue = z = fossil_strdup(z);
  cookies.bIsInit = 1;
  while( cookies.nParam<COOKIE_NPARAM ){
    while( fossil_isspace(z[0]) ) z++;
    if( z[0]==0 ) break;
    cookies.aParam[cookies.nParam].zPName = z;
    while( *z && *z!='=' && *z!=',' ){ z++; }
    if( *z=='=' ){
Changes to src/event.c.
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  const char *zTags = P("g");              /* Tags added to this technote */
  const char *zClrFlag = "";               /* "checked" for bg color */
  const char *zClr;                        /* Name of the background color */
  const char *zMimetype = P("mimetype");   /* Mimetype of zBody */
  int isNew = 0;

  if( zBody ){
    zBody = mprintf("%s", zBody);
  }
  login_check_credentials();
  zId = P("name");
  if( zId==0 ){
    zId = db_text(0, "SELECT lower(hex(randomblob(20)))");
    isNew = 1;
  }else{







|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  const char *zTags = P("g");              /* Tags added to this technote */
  const char *zClrFlag = "";               /* "checked" for bg color */
  const char *zClr;                        /* Name of the background color */
  const char *zMimetype = P("mimetype");   /* Mimetype of zBody */
  int isNew = 0;

  if( zBody ){
    zBody = fossil_strdup(zBody);
  }
  login_check_credentials();
  zId = P("name");
  if( zId==0 ){
    zId = db_text(0, "SELECT lower(hex(randomblob(20)))");
    isNew = 1;
  }else{
Changes to src/export.c.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    printf(" <unknown>");
    return;
  }
  db_static_prepare(&q, "SELECT info FROM user WHERE login=:user");
  db_bind_text(&q, ":user", zUser);
  if( db_step(&q)!=SQLITE_ROW ){
    db_reset(&q);
    zName = mprintf("%s", zUser);
    for(i=j=0; zName[i]; i++){
      if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
        zName[j++] = zName[i];
      }
    }
    zName[j] = 0;
    printf(" %s <%s>", zName, zName);







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    printf(" <unknown>");
    return;
  }
  db_static_prepare(&q, "SELECT info FROM user WHERE login=:user");
  db_bind_text(&q, ":user", zUser);
  if( db_step(&q)!=SQLITE_ROW ){
    db_reset(&q);
    zName = fossil_strdup(zUser);
    for(i=j=0; zName[i]; i++){
      if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
        zName[j++] = zName[i];
      }
    }
    zName[j] = 0;
    printf(" %s <%s>", zName, zName);
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
     }
     else if( zContact[i]==' ' && !isBracketed ){
        atEmailFirst = i+1;
     }
  }
  if( zContact[i]==0 ){
    /* No email address found. Take as user info if not empty */
    zName = mprintf("%s", zContact[0] ? zContact : zUser);
    for(i=j=0; zName[i]; i++){
      if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
        zName[j++] = zName[i];
      }
    }
    zName[j] = 0;








|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
     }
     else if( zContact[i]==' ' && !isBracketed ){
        atEmailFirst = i+1;
     }
  }
  if( zContact[i]==0 ){
    /* No email address found. Take as user info if not empty */
    zName = fossil_strdup(zContact[0] ? zContact : zUser);
    for(i=j=0; zName[i]; i++){
      if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
        zName[j++] = zName[i];
      }
    }
    zName[j] = 0;

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
     for(i=atEmailFirst-2; i>=0 && zContact[i] && zContact[i]==' '; i--){}
     if( i>=0 ){
         for(j=0; j<i && zContact[j] && zContact[j]==' '; j++){}
         zName = mprintf("%.*s", i-j+1, &zContact[j]);
     }
  }

  if( zName==NULL ) zName = mprintf("%s", zUser);
  for(i=j=0; zName[i]; i++){
     if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
         zName[j++] = zName[i];
     }
  }
  zName[j] = 0;








|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
     for(i=atEmailFirst-2; i>=0 && zContact[i] && zContact[i]==' '; i--){}
     if( i>=0 ){
         for(j=0; j<i && zContact[j] && zContact[j]==' '; j++){}
         zName = mprintf("%.*s", i-j+1, &zContact[j]);
     }
  }

  if( zName==NULL ) zName = fossil_strdup(zUser);
  for(i=j=0; zName[i]; i++){
     if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
         zName[j++] = zName[i];
     }
  }
  zName[j] = 0;

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
** Output a sanitized git named reference.
** https://git-scm.com/docs/git-check-ref-format
** This implementation assumes we are only printing
** the branch or tag part of the reference.
*/
static void print_ref(const char *zRef){
  char *zEncoded = mprintf("%s", zRef);
  int i, w;
  if (zEncoded[0]=='@' && zEncoded[1]=='\0'){
    putchar(REFREPLACEMENT);
    return;
  }
  for(i=0, w=0; zEncoded[i]; i++, w++){
    if( i!=0 ){ /* Two letter tests */







|







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
** Output a sanitized git named reference.
** https://git-scm.com/docs/git-check-ref-format
** This implementation assumes we are only printing
** the branch or tag part of the reference.
*/
static void print_ref(const char *zRef){
  char *zEncoded = fossil_strdup(zRef);
  int i, w;
  if (zEncoded[0]=='@' && zEncoded[1]=='\0'){
    putchar(REFREPLACEMENT);
    return;
  }
  for(i=0, w=0; zEncoded[i]; i++, w++){
    if( i!=0 ){ /* Two letter tests */
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
  zBranch = db_text(0,
    "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=%d",
    TAG_BRANCH, rid
  );
  if( fossil_strcmp(zBranch,"trunk")==0 ){
    assert( gitmirror_mainbranch!=0 );
    fossil_free(zBranch);
    zBranch = mprintf("%s",gitmirror_mainbranch);
  }else if( zBranch==0 ){
    zBranch = mprintf("unknown");
  }else{
    gitmirror_sanitize_name(zBranch);
  }

  /* Export the check-in */







|







1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
  zBranch = db_text(0,
    "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=%d",
    TAG_BRANCH, rid
  );
  if( fossil_strcmp(zBranch,"trunk")==0 ){
    assert( gitmirror_mainbranch!=0 );
    fossil_free(zBranch);
    zBranch = fossil_strdup(gitmirror_mainbranch);
  }else if( zBranch==0 ){
    zBranch = mprintf("unknown");
  }else{
    gitmirror_sanitize_name(zBranch);
  }

  /* Export the check-in */
Changes to src/file.c.
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#if !defined(_WIN32)
  if( db_allow_symlinks() ){
    int i, nName;
    char *zName, zBuf[1000];

    nName = strlen(zLinkFile);
    if( nName>=(int)sizeof(zBuf) ){
      zName = mprintf("%s", zLinkFile);
    }else{
      zName = zBuf;
      memcpy(zName, zLinkFile, nName+1);
    }
    nName = file_simplify_name(zName, nName, 0);
    for(i=1; i<nName; i++){
      if( zName[i]=='/' ){







|







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#if !defined(_WIN32)
  if( db_allow_symlinks() ){
    int i, nName;
    char *zName, zBuf[1000];

    nName = strlen(zLinkFile);
    if( nName>=(int)sizeof(zBuf) ){
      zName = fossil_strdup(zLinkFile);
    }else{
      zName = zBuf;
      memcpy(zName, zLinkFile, nName+1);
    }
    nName = file_simplify_name(zName, nName, 0);
    for(i=1; i<nName; i++){
      if( zName[i]=='/' ){
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
** does not exist.  Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
  int rc;
  char *zFN;

  zFN = mprintf("%s", zFilename);
  file_simplify_name(zFN, -1, 0);
  rc = getStat(zFN, eFType);
  if( rc ){
    rc = 0; /* It does not exist at all. */
  }else if( S_ISDIR(fx.fileStat.st_mode) ){
    rc = 1; /* It exists and is a real directory. */
  }else{







|







423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
** does not exist.  Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
  int rc;
  char *zFN;

  zFN = fossil_strdup(zFilename);
  file_simplify_name(zFN, -1, 0);
  rc = getStat(zFN, eFType);
  if( rc ){
    rc = 0; /* It does not exist at all. */
  }else if( S_ISDIR(fx.fileStat.st_mode) ){
    rc = 1; /* It exists and is a real directory. */
  }else{
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  int forceFlag,           /* Delete non-directory objects in the way */
  int errorReturn          /* What to do when an error is seen */
){
  int nName, rc = 0;
  char *zName;

  nName = strlen(zFilename);
  zName = mprintf("%s", zFilename);
  nName = file_simplify_name(zName, nName, 0);
  while( nName>0 && zName[nName-1]!='/' ){ nName--; }
  if( nName>1 ){
    zName[nName-1] = 0;
    if( file_isdir(zName, eFType)!=1 ){
      rc = file_mkfolder(zName, eFType, forceFlag, errorReturn);
      if( rc==0 ){







|







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  int forceFlag,           /* Delete non-directory objects in the way */
  int errorReturn          /* What to do when an error is seen */
){
  int nName, rc = 0;
  char *zName;

  nName = strlen(zFilename);
  zName = fossil_strdup(zFilename);
  nName = file_simplify_name(zName, nName, 0);
  while( nName>0 && zName[nName-1]!='/' ){ nName--; }
  if( nName>1 ){
    zName[nName-1] = 0;
    if( file_isdir(zName, eFType)!=1 ){
      rc = file_mkfolder(zName, eFType, forceFlag, errorReturn);
      if( rc==0 ){
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  int i;
  char *z;
  const char *zTail;
  for(i=2; i<g.argc; i++){
    zTail = file_skip_userhost(g.argv[i]);
    if( zTail ){
      fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]);
      z = mprintf("%s", zTail);
    }else{
      z = mprintf("%s", g.argv[i]);
    }
    fossil_print("[%s] -> ", z);
    file_simplify_name(z, -1, 0);
    fossil_print("[%s]\n", z);
    fossil_free(z);
  }
}







|

|







1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  int i;
  char *z;
  const char *zTail;
  for(i=2; i<g.argc; i++){
    zTail = file_skip_userhost(g.argv[i]);
    if( zTail ){
      fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]);
      z = fossil_strdup(zTail);
    }else{
      z = fossil_strdup(g.argv[i]);
    }
    fossil_print("[%s] -> ", z);
    file_simplify_name(z, -1, 0);
    fossil_print("[%s]\n", z);
    fossil_free(z);
  }
}
Changes to src/fileedit.c.
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
      fossil_fatal("Non-empty check-in comment is required.");
    }
  }
  db_begin_transaction();
  zFilename = g.argv[2];
  cimi.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename);
  cimi.filePerm = file_perm(zFilename, ExtFILE);
  cimi.zUser = mprintf("%s", zUser ? zUser : login_name());
  if(zDate){
    cimi.zDate = mprintf("%s", zDate);
  }
  if(zRevision==0 || zRevision[0]==0){
    if(g.localOpen/*check-out*/){
      zRevision = db_lget("checkout-hash", 0)/*leak*/;
    }else{
      zRevision = "trunk";
    }







|

|







823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
      fossil_fatal("Non-empty check-in comment is required.");
    }
  }
  db_begin_transaction();
  zFilename = g.argv[2];
  cimi.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename);
  cimi.filePerm = file_perm(zFilename, ExtFILE);
  cimi.zUser = fossil_strdup(zUser ? zUser : login_name());
  if(zDate){
    cimi.zDate = fossil_strdup(zDate);
  }
  if(zRevision==0 || zRevision[0]==0){
    if(g.localOpen/*check-out*/){
      zRevision = db_lget("checkout-hash", 0)/*leak*/;
    }else{
      zRevision = "trunk";
    }
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
                                int vid, int *pFilePerm){
  Stmt stmt = empty_Stmt;
  char * zFileUuid = 0;
  db_prepare(&stmt, "SELECT uuid, perm FROM files_of_checkin "
             "WHERE filename=%Q %s AND checkinID=%d",
             zFilename, filename_collation(), vid);
  if(SQLITE_ROW==db_step(&stmt)){
    zFileUuid = mprintf("%s",db_column_text(&stmt, 0));
    if(pFilePerm){
      *pFilePerm = mfile_permstr_int(db_column_text(&stmt, 1));
    }
  }
  db_finalize(&stmt);
  return zFileUuid;
}







|







926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
                                int vid, int *pFilePerm){
  Stmt stmt = empty_Stmt;
  char * zFileUuid = 0;
  db_prepare(&stmt, "SELECT uuid, perm FROM files_of_checkin "
             "WHERE filename=%Q %s AND checkinID=%d",
             zFilename, filename_collation(), vid);
  if(SQLITE_ROW==db_step(&stmt)){
    zFileUuid = fossil_strdup(db_column_text(&stmt, 0));
    if(pFilePerm){
      *pFilePerm = mfile_permstr_int(db_column_text(&stmt, 1));
    }
  }
  db_finalize(&stmt);
  return zFileUuid;
}
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  if(zFlag==0 || !*zFlag){
    rc = 400;
    if(bIsMissingArg){
      *bIsMissingArg = 1;
    }
    fail((pErr,"Missing required 'filename' parameter."));
  }
  p->zFilename = mprintf("%s",zFlag);

  if(0==fileedit_is_editable(p->zFilename)){
    rc = 403;
    fail((pErr,"Filename [%h] is disallowed "
          "by the [fileedit-glob] repository "
          "setting.",
          p->zFilename));







|







1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  if(zFlag==0 || !*zFlag){
    rc = 400;
    if(bIsMissingArg){
      *bIsMissingArg = 1;
    }
    fail((pErr,"Missing required 'filename' parameter."));
  }
  p->zFilename = fossil_strdup(zFlag);

  if(0==fileedit_is_editable(p->zFilename)){
    rc = 403;
    fail((pErr,"Filename [%h] is disallowed "
          "by the [fileedit-glob] repository "
          "setting.",
          p->zFilename));
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260

  zFlag = PT("comment");
  if(zFlag!=0 && *zFlag!=0){
    blob_append(&p->comment, zFlag, -1);
  }
  zFlag = P("comment_mimetype");
  if(zFlag){
    p->zCommentMimetype = mprintf("%s",zFlag);
    zFlag = 0;
  }
#define p_int(K) atoi(PD(K,"0"))
  if(p_int("dry_run")!=0){
    p->flags |= CIMINI_DRY_RUN;
  }
  if(p_int("allow_fork")!=0){







|







1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260

  zFlag = PT("comment");
  if(zFlag!=0 && *zFlag!=0){
    blob_append(&p->comment, zFlag, -1);
  }
  zFlag = P("comment_mimetype");
  if(zFlag){
    p->zCommentMimetype = fossil_strdup(zFlag);
    zFlag = 0;
  }
#define p_int(K) atoi(PD(K,"0"))
  if(p_int("dry_run")!=0){
    p->flags |= CIMINI_DRY_RUN;
  }
  if(p_int("allow_fork")!=0){
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
    default: p->flags |= CIMINI_CONVERT_EOL_INHERIT; break;
  }
#undef p_int
  /*
  ** TODO?: date-override date selection field. Maybe use
  ** an input[type=datetime-local].
  */
  p->zUser = mprintf("%s",g.zLogin);
  return 0;
end_fail:
#undef fail
  fossil_free(zFileUuid);
  return rc ? rc : 500;
}








|







1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
    default: p->flags |= CIMINI_CONVERT_EOL_INHERIT; break;
  }
#undef p_int
  /*
  ** TODO?: date-override date selection field. Maybe use
  ** an input[type=datetime-local].
  */
  p->zUser = fossil_strdup(g.zLogin);
  return 0;
end_fail:
#undef fail
  fossil_free(zFileUuid);
  return rc ? rc : 500;
}

Changes to src/graph.c.
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
static char *persistBranchName(GraphContext *p, const char *zBranch){
  int i;
  for(i=0; i<p->nBranch; i++){
    if( fossil_strcmp(zBranch, p->azBranch[i])==0 ) return p->azBranch[i];
  }
  p->nBranch++;
  p->azBranch = fossil_realloc(p->azBranch, sizeof(char*)*p->nBranch);
  p->azBranch[p->nBranch-1] = mprintf("%s", zBranch);
  return p->azBranch[p->nBranch-1];
}

/*
** Add a new row to the graph context.  Rows are added from top to bottom.
*/
int graph_add_row(







|







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
static char *persistBranchName(GraphContext *p, const char *zBranch){
  int i;
  for(i=0; i<p->nBranch; i++){
    if( fossil_strcmp(zBranch, p->azBranch[i])==0 ) return p->azBranch[i];
  }
  p->nBranch++;
  p->azBranch = fossil_realloc(p->azBranch, sizeof(char*)*p->nBranch);
  p->azBranch[p->nBranch-1] = fossil_strdup(zBranch);
  return p->azBranch[p->nBranch-1];
}

/*
** Add a new row to the graph context.  Rows are added from top to bottom.
*/
int graph_add_row(
Changes to src/http_socket.c.
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    }
    rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
                     0, 0, NI_NUMERICHOST);
    if( rc ){
      socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
      goto end_socket_open;
    }
    g.zIpAddr = mprintf("%s", zRemote);
    break;
  }
  if( p==0 ){
    socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
                      pUrlData->port);
    rc = 1;
  }







|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    }
    rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
                     0, 0, NI_NUMERICHOST);
    if( rc ){
      socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
      goto end_socket_open;
    }
    g.zIpAddr = fossil_strdup(zRemote);
    break;
  }
  if( p==0 ){
    socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
                      pUrlData->port);
    rc = 1;
  }
Changes to src/http_ssl.c.
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  /* As soon as libressl implements
  ** BIO_ADDR_hostname_string/BIO_get_conn_address.
  ** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
  */
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
      && !defined(LIBRESSL_VERSION_NUMBER)
    char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
    g.zIpAddr = mprintf("%s", ip);
    OPENSSL_free(ip);
#else
    /* IPv4 only code */
    const unsigned char *ip;
    ip = (const unsigned char*)BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2);
    g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
#endif







|







636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  /* As soon as libressl implements
  ** BIO_ADDR_hostname_string/BIO_get_conn_address.
  ** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
  */
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
      && !defined(LIBRESSL_VERSION_NUMBER)
    char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
    g.zIpAddr = fossil_strdup(ip);
    OPENSSL_free(ip);
#else
    /* IPv4 only code */
    const unsigned char *ip;
    ip = (const unsigned char*)BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2);
    g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
#endif
Changes to src/http_transport.c.
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  /* For SSH we need to create and run SSH fossil http
  ** to talk to the remote machine.
  */
  Blob zCmd;         /* The SSH command */
  char *zHost;       /* The host name to contact */

  fossil_free(g.zIpAddr);
  g.zIpAddr = mprintf("%s", pUrlData->name);
  transport_ssh_command(&zCmd);
  if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
    blob_appendf(&zCmd, " -p %d", pUrlData->port);
  }
  blob_appendf(&zCmd, " -T --");  /* End of switches */
  if( pUrlData->user && pUrlData->user[0] ){
    zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);







|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  /* For SSH we need to create and run SSH fossil http
  ** to talk to the remote machine.
  */
  Blob zCmd;         /* The SSH command */
  char *zHost;       /* The host name to contact */

  fossil_free(g.zIpAddr);
  g.zIpAddr = fossil_strdup(pUrlData->name);
  transport_ssh_command(&zCmd);
  if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
    blob_appendf(&zCmd, " -p %d", pUrlData->port);
  }
  blob_appendf(&zCmd, " -T --");  /* End of switches */
  if( pUrlData->user && pUrlData->user[0] ){
    zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
Changes to src/import.c.
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  if( feof(pIn) ) return 0;
  do{
    char *sep;
    if( zLine[0]=='\n' ) break;
    rec->nHeaders += 1;
    rec->aHeaders = fossil_realloc(rec->aHeaders,
      sizeof(rec->aHeaders[0])*rec->nHeaders);
    rec->aHeaders[rec->nHeaders-1].zKey = mprintf("%s", zLine);
    sep = strchr(rec->aHeaders[rec->nHeaders-1].zKey, ':');
    if( !sep ){
      trim_newline(zLine);
      fossil_fatal("bad header line: [%s]", zLine);
    }
    *sep = 0;
    rec->aHeaders[rec->nHeaders-1].zVal = sep+1;







|







893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  if( feof(pIn) ) return 0;
  do{
    char *sep;
    if( zLine[0]=='\n' ) break;
    rec->nHeaders += 1;
    rec->aHeaders = fossil_realloc(rec->aHeaders,
      sizeof(rec->aHeaders[0])*rec->nHeaders);
    rec->aHeaders[rec->nHeaders-1].zKey = fossil_strdup(zLine);
    sep = strchr(rec->aHeaders[rec->nHeaders-1].zKey, ':');
    if( !sep ){
      trim_newline(zLine);
      fossil_fatal("bad header line: [%s]", zLine);
    }
    *sep = 0;
    rec->aHeaders[rec->nHeaders-1].zVal = sep+1;
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
        fossil_free(gsvn.zUser);
        fossil_free(gsvn.zComment);
        fossil_free(gsvn.zDate);
        bag_clear(&gsvn.newBranches);
      }
      /* start new revision */
      gsvn.rev = atoi(zTemp);
      gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author"));
      gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log"));
      zDate = svn_find_prop(rec, "svn:date");
      if( zDate ){
        gsvn.zDate = date_in_standard_format(zDate);
      }else{
        gsvn.zDate = date_in_standard_format("now");
      }
      db_bind_int(&addRev, ":rev", gsvn.rev);







|
|







1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
        fossil_free(gsvn.zUser);
        fossil_free(gsvn.zComment);
        fossil_free(gsvn.zDate);
        bag_clear(&gsvn.newBranches);
      }
      /* start new revision */
      gsvn.rev = atoi(zTemp);
      gsvn.zUser = fossil_strdup(svn_find_prop(rec, "svn:author"));
      gsvn.zComment = fossil_strdup(svn_find_prop(rec, "svn:log"));
      zDate = svn_find_prop(rec, "svn:date");
      if( zDate ){
        gsvn.zDate = date_in_standard_format(zDate);
      }else{
        gsvn.zDate = date_in_standard_format("now");
      }
      db_bind_int(&addRev, ":rev", gsvn.rev);
Changes to src/info.c.
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
    if( isSymbolicCI ){
      zHeader = mprintf("%s at %s", file_tail(zName), zCI);
      style_set_current_page("doc/%t/%T", zCI, zName);
    }else if( zCIUuid && zCIUuid[0] ){
      zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
      style_set_current_page("doc/%S/%T", zCIUuid, zName);
    }else{
      zHeader = mprintf("%s", file_tail(zName));
      style_set_current_page("doc/tip/%T", zName);
    }
  }else if( descOnly ){
    zHeader = mprintf("Artifact Description [%S]", zUuid);
  }else{
    zHeader = mprintf("Artifact [%S]", zUuid);
  }







|







2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
    if( isSymbolicCI ){
      zHeader = mprintf("%s at %s", file_tail(zName), zCI);
      style_set_current_page("doc/%t/%T", zCI, zName);
    }else if( zCIUuid && zCIUuid[0] ){
      zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
      style_set_current_page("doc/%S/%T", zCIUuid, zName);
    }else{
      zHeader = fossil_strdup(file_tail(zName));
      style_set_current_page("doc/tip/%T", zName);
    }
  }else if( descOnly ){
    zHeader = mprintf("Artifact Description [%S]", zUuid);
  }else{
    zHeader = mprintf("Artifact [%S]", zUuid);
  }
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
    descr->nCommitsSince = -1;
    descr->zCommitHash = mprintf("");
    descr->isDirty = -1;
    return (rid-1);
  }

  zUuid = rid_to_uuid(rid);
  descr->zCommitHash = mprintf("%s", zUuid);
  descr->isDirty = unsaved_changes(0);

  db_multi_exec(
    "DROP TABLE IF EXISTS temp.singletonTag;"
    "CREATE TEMP TABLE singletonTag("
    "  rid INT,"
    "  tagname TEXT,"







|







4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
    descr->nCommitsSince = -1;
    descr->zCommitHash = mprintf("");
    descr->isDirty = -1;
    return (rid-1);
  }

  zUuid = rid_to_uuid(rid);
  descr->zCommitHash = fossil_strdup(zUuid);
  descr->isDirty = unsaved_changes(0);

  db_multi_exec(
    "DROP TABLE IF EXISTS temp.singletonTag;"
    "CREATE TEMP TABLE singletonTag("
    "  rid INT,"
    "  tagname TEXT,"
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
    " WHERE tagname IS NOT NULL"
    " ORDER BY n LIMIT 1;",
    rid, rid
  );

  if( db_step(&q)==SQLITE_ROW ){
    const char *lastTag = db_column_text(&q, 0);
    descr->zRelTagname = mprintf("%s", lastTag);
    descr->nCommitsSince = db_column_int(&q, 1);
    nRet = 0;
  }else{
    /* no ancestor commit with a fitting singleton tag found */
    descr->zRelTagname = mprintf("");
    descr->nCommitsSince = -1;
    nRet = -3;







|







4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
    " WHERE tagname IS NOT NULL"
    " ORDER BY n LIMIT 1;",
    rid, rid
  );

  if( db_step(&q)==SQLITE_ROW ){
    const char *lastTag = db_column_text(&q, 0);
    descr->zRelTagname = fossil_strdup(lastTag);
    descr->nCommitsSince = db_column_int(&q, 1);
    nRet = 0;
  }else{
    /* no ancestor commit with a fitting singleton tag found */
    descr->zRelTagname = mprintf("");
    descr->nCommitsSince = -1;
    nRet = -3;
Changes to src/json.c.
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
  assert( (code>=1000) && (code<=9999) );
  fossil_free(g.zErrMsg);
  g.json.resultCode = code;
  if(!fmt || !*fmt){
    g.zErrMsg = mprintf("%s", json_err_cstr(code));
  }else{
    va_list vargs;
    char * msg;
    va_start(vargs,fmt);
    msg = vmprintf(fmt, vargs);
    va_end(vargs);
    g.zErrMsg = msg;







|







1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
  assert( (code>=1000) && (code<=9999) );
  fossil_free(g.zErrMsg);
  g.json.resultCode = code;
  if(!fmt || !*fmt){
    g.zErrMsg = fossil_strdup(json_err_cstr(code));
  }else{
    va_list vargs;
    char * msg;
    va_start(vargs,fmt);
    msg = vmprintf(fmt, vargs);
    va_end(vargs);
    g.zErrMsg = msg;
Changes to src/json_report.c.
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  }

  limit = json_find_option_int("limit",NULL,"n",-1);


  /* Copy over report's SQL...*/
  blob_append(&sql, db_column_text(&q,0), -1);
  zTitle = mprintf("%s", db_column_text(&q,1));
  db_finalize(&q);
  db_prepare(&q, "%s", blob_sql_text(&sql));

  /** Build the response... */
  pay = cson_new_object();

  cson_object_set(pay, "report", json_new_int(nReport));







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  }

  limit = json_find_option_int("limit",NULL,"n",-1);


  /* Copy over report's SQL...*/
  blob_append(&sql, db_column_text(&q,0), -1);
  zTitle = fossil_strdup(db_column_text(&q,1));
  db_finalize(&q);
  db_prepare(&q, "%s", blob_sql_text(&sql));

  /** Build the response... */
  pay = cson_new_object();

  cson_object_set(pay, "report", json_new_int(nReport));
Changes to src/main.c.
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
** the global state and return the new pointer, freeing any previous value.
** If absent and there is no cached value, return NULL.
*/
const char *find_repository_option(){
  const char *zRepository = find_option("repository", "R", 1);
  if( zRepository ){
    if( g.zRepositoryOption ) fossil_free(g.zRepositoryOption);
    g.zRepositoryOption = mprintf("%s", zRepository);
  }
  return g.zRepositoryOption;
}

/*
** Verify that there are no unprocessed command-line options.  If
** Any remaining command-line argument begins with "-" print







|







1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
** the global state and return the new pointer, freeing any previous value.
** If absent and there is no cached value, return NULL.
*/
const char *find_repository_option(){
  const char *zRepository = find_option("repository", "R", 1);
  if( zRepository ){
    if( g.zRepositoryOption ) fossil_free(g.zRepositoryOption);
    g.zRepositoryOption = fossil_strdup(zRepository);
  }
  return g.zRepositoryOption;
}

/*
** Verify that there are no unprocessed command-line options.  If
** Any remaining command-line argument begins with "-" print
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
  const char *zHost;
  const char *zMode;
  const char *zCur;

  if( g.zBaseURL!=0 ) return;
  if( zAltBase ){
    int i, n, c;
    g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
    i = (int)strlen(g.zBaseURL);
    while( i>3 && g.zBaseURL[i-1]=='/' ){ i--; }
    g.zBaseURL[i] = 0;
    if( strncmp(g.zTop, "http://", 7)==0 ){
      /* it is HTTP, replace prefix with HTTPS. */
      g.zHttpsURL = mprintf("https://%s", &g.zTop[7]);
    }else if( strncmp(g.zTop, "https://", 8)==0 ){
      /* it is already HTTPS, use it. */
      g.zHttpsURL = mprintf("%s", g.zTop);
    }else{
      fossil_fatal("argument to --baseurl should be 'http://host/path'"
                   " or 'https://host/path'");
    }
    for(i=n=0; (c = g.zTop[i])!=0; i++){
      if( c=='/' ){
        n++;







|








|







1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
  const char *zHost;
  const char *zMode;
  const char *zCur;

  if( g.zBaseURL!=0 ) return;
  if( zAltBase ){
    int i, n, c;
    g.zTop = g.zBaseURL = fossil_strdup(zAltBase);
    i = (int)strlen(g.zBaseURL);
    while( i>3 && g.zBaseURL[i-1]=='/' ){ i--; }
    g.zBaseURL[i] = 0;
    if( strncmp(g.zTop, "http://", 7)==0 ){
      /* it is HTTP, replace prefix with HTTPS. */
      g.zHttpsURL = mprintf("https://%s", &g.zTop[7]);
    }else if( strncmp(g.zTop, "https://", 8)==0 ){
      /* it is already HTTPS, use it. */
      g.zHttpsURL = fossil_strdup(g.zTop);
    }else{
      fossil_fatal("argument to --baseurl should be 'http://host/path'"
                   " or 'https://host/path'");
    }
    for(i=n=0; (c = g.zTop[i])!=0; i++){
      if( c=='/' ){
        n++;
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
#endif
    if( g.useLocalauth && g.localOpen ){
      cgi_redirectf("%R/ckout");
    }else{
      fossil_redirect_home() /*does not return*/;
    }
  }else{
    zPath = mprintf("%s", zPathInfo);
  }

  /* Make g.zPath point to the first element of the path.  Make
  ** g.zExtra point to everything past that point.
  */
  g.zPath = &zPath[1];
  for(i=1; zPath[i] && zPath[i]!='/'; i++){}







|







2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
#endif
    if( g.useLocalauth && g.localOpen ){
      cgi_redirectf("%R/ckout");
    }else{
      fossil_redirect_home() /*does not return*/;
    }
  }else{
    zPath = fossil_strdup(zPathInfo);
  }

  /* Make g.zPath point to the first element of the path.  Make
  ** g.zExtra point to everything past that point.
  */
  g.zPath = &zPath[1];
  for(i=1; zPath[i] && zPath[i]!='/'; i++){}
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
      /* directory: DIRECTORY
      **
      ** If repository: is omitted, then terms of the PATH_INFO cgi parameter
      ** are appended to DIRECTORY looking for a repository (whose name ends
      ** in ".fossil") or a file in "files:".
      */
      db_close(1);
      g.zRepositoryName = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
      /* notfound: URL
      **
      ** If using directory: and no suitable repository or file is found,
      ** then redirect to URL.
      */
      zNotFound = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "localauth") ){
      /* localauth
      **
      ** Grant "administrator" privileges to users connecting with HTTP







|









|







2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
      /* directory: DIRECTORY
      **
      ** If repository: is omitted, then terms of the PATH_INFO cgi parameter
      ** are appended to DIRECTORY looking for a repository (whose name ends
      ** in ".fossil") or a file in "files:".
      */
      db_close(1);
      g.zRepositoryName = fossil_strdup(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
      /* notfound: URL
      **
      ** If using directory: and no suitable repository or file is found,
      ** then redirect to URL.
      */
      zNotFound = fossil_strdup(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "localauth") ){
      /* localauth
      **
      ** Grant "administrator" privileges to users connecting with HTTP
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
    }
    if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
            && blob_token(&line, &value2) ){
      /* See the header comment on the redirect_web_page() function
      ** above for details. */
      nRedirect++;
      azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
      azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
      azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
      /* files: GLOBLIST
      **







|
|







2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
    }
    if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
            && blob_token(&line, &value2) ){
      /* See the header comment on the redirect_web_page() function
      ** above for details. */
      nRedirect++;
      azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
      azRedirect[nRedirect*2-2] = fossil_strdup(blob_str(&value));
      azRedirect[nRedirect*2-1] = fossil_strdup(blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
      /* files: GLOBLIST
      **
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
    }
    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      /* errorlog: FILENAME
      **
      ** Causes messages from warnings, errors, and panics to be appended
      ** to FILENAME.
      */
      g.zErrlog = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "extroot:") && blob_token(&line, &value) ){
      /* extroot: DIRECTORY
      **
      ** Enables the /ext webpage to use sub-cgi rooted at DIRECTORY
      */
      g.zExtRoot = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "timeout:") && blob_token(&line, &value) ){
      /* timeout: SECONDS
      **
      ** Set an alarm() that kills the process after SECONDS.  The







|








|







2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
    }
    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      /* errorlog: FILENAME
      **
      ** Causes messages from warnings, errors, and panics to be appended
      ** to FILENAME.
      */
      g.zErrlog = fossil_strdup(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "extroot:") && blob_token(&line, &value) ){
      /* extroot: DIRECTORY
      **
      ** Enables the /ext webpage to use sub-cgi rooted at DIRECTORY
      */
      g.zExtRoot = fossil_strdup(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "timeout:") && blob_token(&line, &value) ){
      /* timeout: SECONDS
      **
      ** Set an alarm() that kills the process after SECONDS.  The
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
    if( blob_eq(&key, "mainmenu:") && blob_token(&line, &value) ){
      /* mainmenu: FILENAME
      **
      ** Use the contents of FILENAME as the value of the site's
      ** "mainmenu" setting, overriding the contents (for this
      ** request) of the db-side setting or the hard-coded default.
      */
      g.zMainMenuFile = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
      /* cgi-debug: FILENAME
      **
      ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go







|







2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
    if( blob_eq(&key, "mainmenu:") && blob_token(&line, &value) ){
      /* mainmenu: FILENAME
      **
      ** Use the contents of FILENAME as the value of the site's
      ** "mainmenu" setting, overriding the contents (for this
      ** request) of the db-side setting or the hard-coded default.
      */
      g.zMainMenuFile = fossil_strdup(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
      /* cgi-debug: FILENAME
      **
      ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
static void find_server_repository(int arg, int fCreate){
  if( g.argc<=arg ){
    db_must_be_within_tree();
  }else{
    const char *zRepo = g.argv[arg];
    int isDir = file_isdir(zRepo, ExtFILE);
    if( isDir==1 ){
      g.zRepositoryName = mprintf("%s", zRepo);
      file_simplify_name(g.zRepositoryName, -1, 0);
    }else{
      if( isDir==0 && fCreate ){
        const char *zPassword;
        db_create_repository(zRepo);
        db_open_repository(zRepo);
        db_begin_transaction();







|







2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
static void find_server_repository(int arg, int fCreate){
  if( g.argc<=arg ){
    db_must_be_within_tree();
  }else{
    const char *zRepo = g.argv[arg];
    int isDir = file_isdir(zRepo, ExtFILE);
    if( isDir==1 ){
      g.zRepositoryName = fossil_strdup(zRepo);
      file_simplify_name(g.zRepositoryName, -1, 0);
    }else{
      if( isDir==0 && fCreate ){
        const char *zPassword;
        db_create_repository(zRepo);
        db_open_repository(zRepo);
        db_begin_transaction();
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931

  /* The winhttp module passes the --files option as --files-urlenc with
  ** the argument being URL encoded, to avoid wildcard expansion in the
  ** shell.  This option is for internal use and is undocumented.
  */
  zFileGlob = find_option("files-urlenc",0,1);
  if( zFileGlob ){
    char *z = mprintf("%s", zFileGlob);
    dehttpize(z);
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  skin_override();
  zNotFound = find_option("notfound", 0, 1);







|







2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931

  /* The winhttp module passes the --files option as --files-urlenc with
  ** the argument being URL encoded, to avoid wildcard expansion in the
  ** shell.  This option is for internal use and is undocumented.
  */
  zFileGlob = find_option("files-urlenc",0,1);
  if( zFileGlob ){
    char *z = fossil_strdup(zFileGlob);
    dehttpize(z);
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  skin_override();
  zNotFound = find_option("notfound", 0, 1);
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
    g.zErrlog = "-";
  }
  g.zExtRoot = find_option("extroot",0,1);
  zJsMode = find_option("jsmode",0,1);
  builtin_set_js_delivery_mode(zJsMode,0);
  zFileGlob = find_option("files-urlenc",0,1);
  if( zFileGlob ){
    char *z = mprintf("%s", zFileGlob);
    dehttpize(z);
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  skin_override();
#if !defined(_WIN32)







|







3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
    g.zErrlog = "-";
  }
  g.zExtRoot = find_option("extroot",0,1);
  zJsMode = find_option("jsmode",0,1);
  builtin_set_js_delivery_mode(zJsMode,0);
  zFileGlob = find_option("files-urlenc",0,1);
  if( zFileGlob ){
    char *z = fossil_strdup(zFileGlob);
    dehttpize(z);
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  skin_override();
#if !defined(_WIN32)
Changes to src/merge.c.
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
     "  FROM event WHERE objid=%d", rid, rid, rid);
  if( db_step(&q)==SQLITE_ROW ){
    const char *zTagList = db_column_text(&q, 4);
    char *zCom;
    if( zTagList && zTagList[0] ){
      zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
    }else{
      zCom = mprintf("%s", db_column_text(&q,2));
    }
    fossil_print("%-*s [%S] by %s on %s\n%*s",
       indent-1, zLabel,
       db_column_text(&q, 3),
       db_column_text(&q, 1),
       db_column_text(&q, 0),
       indent, "");







|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
     "  FROM event WHERE objid=%d", rid, rid, rid);
  if( db_step(&q)==SQLITE_ROW ){
    const char *zTagList = db_column_text(&q, 4);
    char *zCom;
    if( zTagList && zTagList[0] ){
      zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
    }else{
      zCom = fossil_strdup(db_column_text(&q,2));
    }
    fossil_print("%-*s [%S] by %s on %s\n%*s",
       indent-1, zLabel,
       db_column_text(&q, 3),
       db_column_text(&q, 1),
       db_column_text(&q, 0),
       indent, "");
Changes to src/name.c.
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

  /* symbolic-name ":" date-time */
  nTag = strlen(zTag);
  for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
  if( zTag[i]==':'
   && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0)
  ){
    char *zDate = mprintf("%s", &zTag[i+1]);
    char *zTagBase = mprintf("%.*s", i, zTag);
    char *zXDate;
    int nDate = strlen(zDate);
    if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
      zDate[nDate-3] = 'z';
      zDate[nDate-2] = 0;
    }







|







579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

  /* symbolic-name ":" date-time */
  nTag = strlen(zTag);
  for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
  if( zTag[i]==':'
   && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0)
  ){
    char *zDate = fossil_strdup(&zTag[i+1]);
    char *zTagBase = mprintf("%.*s", i, zTag);
    char *zXDate;
    int nDate = strlen(zDate);
    if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
      zDate[nDate-3] = 'z';
      zDate[nDate-2] = 0;
    }
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
  if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){
    fossil_redirect_home();
  }
  style_header("Ambiguous Artifact ID");
  @ <p>The artifact hash prefix <b>%h(zName)</b> is ambiguous and might
  @ mean any of the following:
  @ <ol>
  z = mprintf("%s", zName);
  canonical16(z, strlen(z));
  db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zUuid = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
    @ %s(zUuid)</a> -







|







984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
  if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){
    fossil_redirect_home();
  }
  style_header("Ambiguous Artifact ID");
  @ <p>The artifact hash prefix <b>%h(zName)</b> is ambiguous and might
  @ mean any of the following:
  @ <ol>
  z = fossil_strdup(zName);
  canonical16(z, strlen(z));
  db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zUuid = db_column_text(&q, 0);
    int rid = db_column_int(&q, 1);
    @ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
    @ %s(zUuid)</a> -
Changes to src/repolist.c.
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
      if( nName<nSuffix ) continue;
      zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
      if( zName[0]=='/'
#ifdef _WIN32
          || sqlite3_strglob("[a-zA-Z]:/*", zName)==0
#endif
      ){
        zFull = mprintf("%s", zName);
      }else if ( allRepo ){
        zFull = mprintf("/%s", zName);
      }else{
        zFull = mprintf("%s/%s", g.zRepositoryName, zName);
      }
      x.zRepoName = zFull;
      remote_repo_info(&x);
      if( x.isRepolistSkin ){
        if( zSkinRepo==0 ){
          zSkinRepo = mprintf("%s", x.zRepoName);
          zSkinUrl = mprintf("%s", zUrl);
        }
      }
      fossil_free(zFull);
      if( !x.isValid
#if USE_SEE
       && !bEncrypted
#endif







|









|
|







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
      if( nName<nSuffix ) continue;
      zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
      if( zName[0]=='/'
#ifdef _WIN32
          || sqlite3_strglob("[a-zA-Z]:/*", zName)==0
#endif
      ){
        zFull = fossil_strdup(zName);
      }else if ( allRepo ){
        zFull = mprintf("/%s", zName);
      }else{
        zFull = mprintf("%s/%s", g.zRepositoryName, zName);
      }
      x.zRepoName = zFull;
      remote_repo_info(&x);
      if( x.isRepolistSkin ){
        if( zSkinRepo==0 ){
          zSkinRepo = fossil_strdup(x.zRepoName);
          zSkinUrl = fossil_strdup(zUrl);
        }
      }
      fossil_free(zFull);
      if( !x.isValid
#if USE_SEE
       && !bEncrypted
#endif
Changes to src/search.c.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  if( fSrchFlg & SRCHFLG_STATIC ){
    p = &gSearch;
    search_end(p);
  }else{
    p = fossil_malloc(sizeof(*p));
    memset(p, 0, sizeof(*p));
  }
  p->zPattern = z = mprintf("%s", zPattern);
  p->zMarkBegin = mprintf("%s", zMarkBegin);
  p->zMarkEnd = mprintf("%s", zMarkEnd);
  p->zMarkGap = mprintf("%s", zMarkGap);
  p->fSrchFlg = fSrchFlg;
  blob_init(&p->snip, 0, 0);
  while( *z && p->nTerm<SEARCH_MAX_TERM ){
    while( *z && !ISALNUM(*z) ){ z++; }
    if( *z==0 ) break;
    p->a[p->nTerm].z = z;
    for(i=1; ISALNUM(z[i]); i++){}







|
|
|
|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  if( fSrchFlg & SRCHFLG_STATIC ){
    p = &gSearch;
    search_end(p);
  }else{
    p = fossil_malloc(sizeof(*p));
    memset(p, 0, sizeof(*p));
  }
  p->zPattern = z = fossil_strdup(zPattern);
  p->zMarkBegin = fossil_strdup(zMarkBegin);
  p->zMarkEnd = fossil_strdup(zMarkEnd);
  p->zMarkGap = fossil_strdup(zMarkGap);
  p->fSrchFlg = fSrchFlg;
  blob_init(&p->snip, 0, 0);
  while( *z && p->nTerm<SEARCH_MAX_TERM ){
    while( *z && !ISALNUM(*z) ){ z++; }
    if( *z==0 ) break;
    p->a[p->nTerm].z = z;
    for(i=1; ISALNUM(z[i]); i++){}
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
** replaces all non-alphanum ASCII characters with a space, and
** lower-cases all upper-case ASCII characters. The intent is to avoid
** causing errors in FTS5 searches with inputs which contain AND, OR,
** and symbols like #. The caller is responsible for passing the
** result to fossil_free().
*/
char *search_simplify_pattern(const char * zPattern){
  char *zPat = mprintf("%s",zPattern);
  int i;
  for(i=0; zPat[i]; i++){
    if( (zPat[i]&0x80)==0 && !fossil_isalnum(zPat[i]) ) zPat[i] = ' ';
    if( fossil_isupper(zPat[i]) ) zPat[i] = fossil_tolower(zPat[i]);
  }
  for(i--; i>=0 && zPat[i]==' '; i--){}
  if( i<0 ){







|







1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
** replaces all non-alphanum ASCII characters with a space, and
** lower-cases all upper-case ASCII characters. The intent is to avoid
** causing errors in FTS5 searches with inputs which contain AND, OR,
** and symbols like #. The caller is responsible for passing the
** result to fossil_free().
*/
char *search_simplify_pattern(const char * zPattern){
  char *zPat = fossil_strdup(zPattern);
  int i;
  for(i=0; zPat[i]; i++){
    if( (zPat[i]&0x80)==0 && !fossil_isalnum(zPat[i]) ) zPat[i] = ' ';
    if( fossil_isupper(zPat[i]) ) zPat[i] = fossil_tolower(zPat[i]);
  }
  for(i--; i>=0 && zPat[i]==' '; i--){}
  if( i<0 ){
Changes to src/sha1.c.
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  unsigned char zResult[20];
  char zDigest[41];

  SHA1Init(&ctx);
  SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
  SHA1Final(zResult, &ctx);
  DigestToBase16(zResult, zDigest);
  return mprintf("%s", zDigest);
}

/*
** Convert a cleartext password for a specific user into a SHA1 hash.
**
** The algorithm here is:
**







|







418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  unsigned char zResult[20];
  char zDigest[41];

  SHA1Init(&ctx);
  SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
  SHA1Final(zResult, &ctx);
  DigestToBase16(zResult, zDigest);
  return fossil_strdup(zDigest);
}

/*
** Convert a cleartext password for a specific user into a SHA1 hash.
**
** The algorithm here is:
**
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
    if( zProjectId==0 ){
      zProjectId = db_get("project-code", 0);

      /* On the first xfer request of a clone, the project-code is not yet
      ** known.  Use the cleartext password, since that is all we have.
      */
      if( zProjectId==0 ){
        return mprintf("%s", zPw);
      }
    }
    zProjCode = zProjectId;
  }
  SHA1Update(&ctx, (unsigned char*)zProjCode, strlen(zProjCode));
  SHA1Update(&ctx, (unsigned char*)"/", 1);
  SHA1Update(&ctx, (unsigned char*)zLogin, strlen(zLogin));
  SHA1Update(&ctx, (unsigned char*)"/", 1);
  SHA1Update(&ctx, (unsigned const char*)zPw, strlen(zPw));
  SHA1Final(zResult, &ctx);
  DigestToBase16(zResult, zDigest);
  return mprintf("%s", zDigest);
}

/*
** Implement the shared_secret() SQL function.  shared_secret() takes two or
** three arguments; the third argument is optional.
**
** (1) The cleartext password







|











|







457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
    if( zProjectId==0 ){
      zProjectId = db_get("project-code", 0);

      /* On the first xfer request of a clone, the project-code is not yet
      ** known.  Use the cleartext password, since that is all we have.
      */
      if( zProjectId==0 ){
        return fossil_strdup(zPw);
      }
    }
    zProjCode = zProjectId;
  }
  SHA1Update(&ctx, (unsigned char*)zProjCode, strlen(zProjCode));
  SHA1Update(&ctx, (unsigned char*)"/", 1);
  SHA1Update(&ctx, (unsigned char*)zLogin, strlen(zLogin));
  SHA1Update(&ctx, (unsigned char*)"/", 1);
  SHA1Update(&ctx, (unsigned const char*)zPw, strlen(zPw));
  SHA1Final(zResult, &ctx);
  DigestToBase16(zResult, zDigest);
  return fossil_strdup(zDigest);
}

/*
** Implement the shared_secret() SQL function.  shared_secret() takes two or
** three arguments; the third argument is optional.
**
** (1) The cleartext password
Changes to src/sha3.c.
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
char *sha3sum(const char *zIn, int iSize){
  SHA3Context ctx;
  char zDigest[132];

  SHA3Init(&ctx, iSize);
  SHA3Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
  DigestToBase16(SHA3Final(&ctx), zDigest, iSize/8);
  return mprintf("%s", zDigest);
}
#endif

/*
** COMMAND: sha3sum*
**
** Usage: %fossil sha3sum FILE...







|







610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
char *sha3sum(const char *zIn, int iSize){
  SHA3Context ctx;
  char zDigest[132];

  SHA3Init(&ctx, iSize);
  SHA3Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
  DigestToBase16(SHA3Final(&ctx), zDigest, iSize/8);
  return fossil_strdup(zDigest);
}
#endif

/*
** COMMAND: sha3sum*
**
** Usage: %fossil sha3sum FILE...
Changes to src/tag.c.
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
      );
    }
  }
  if( zCol ){
    db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
                  zCol, zValue, rid);
    if( tagid==TAG_COMMENT ){
      char *zCopy = mprintf("%s", zValue);
      backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
      free(zCopy);
    }
  }
  if( tagid==TAG_DATE ){
    db_multi_exec("UPDATE event "
                  "   SET mtime=julianday(%Q),"







|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
      );
    }
  }
  if( zCol ){
    db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
                  zCol, zValue, rid);
    if( tagid==TAG_COMMENT ){
      char *zCopy = fossil_strdup(zValue);
      backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
      free(zCopy);
    }
  }
  if( tagid==TAG_DATE ){
    db_multi_exec("UPDATE event "
                  "   SET mtime=julianday(%Q),"
Changes to src/th_main.c.
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  int argc,
  const char **argv,
  int *argl
){
  if( argc!=3 ){
    return Th_WrongNumArgs(interp, "setParameter NAME VALUE");
  }
  cgi_replace_parameter(mprintf("%s", argv[1]), mprintf("%s", argv[2]));
  return TH_OK;
}

/*
** TH1 command: reinitialize ?FLAGS?
**
** Reinitializes the TH1 interpreter using the specified flags.







|







1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  int argc,
  const char **argv,
  int *argl
){
  if( argc!=3 ){
    return Th_WrongNumArgs(interp, "setParameter NAME VALUE");
  }
  cgi_replace_parameter(fossil_strdup(argv[1]), fossil_strdup(argv[2]));
  return TH_OK;
}

/*
** TH1 command: reinitialize ?FLAGS?
**
** Reinitializes the TH1 interpreter using the specified flags.
Changes to src/timeline.c.
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
      static const char *const azMatchStyles[] = {
        "exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp",
        "brlist", "List"
      };
      double rDate;
      zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
      if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
        zDate = mprintf("%s", (zAfter ? zAfter : zBefore));
      }
      if( zDate ){
        rDate = symbolic_name_to_mtime(zDate, 0, 0);
        if( db_int(0,
            "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
            " WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
            rDate-ONE_SECOND, blob_sql_text(&cond))
        ){
          zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
          zOlderButtonLabel = "More";
        }
        free(zDate);
      }
      zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
      if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
        zDate = mprintf("%s", (zBefore ? zBefore : zAfter));
      }
      if( zDate ){
        rDate = symbolic_name_to_mtime(zDate, 0, 0);
        if( db_int(0,
            "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
            " WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
            rDate+ONE_SECOND, blob_sql_text(&cond))







|















|







3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
      static const char *const azMatchStyles[] = {
        "exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp",
        "brlist", "List"
      };
      double rDate;
      zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
      if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
        zDate = fossil_strdup((zAfter ? zAfter : zBefore));
      }
      if( zDate ){
        rDate = symbolic_name_to_mtime(zDate, 0, 0);
        if( db_int(0,
            "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
            " WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
            rDate-ONE_SECOND, blob_sql_text(&cond))
        ){
          zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
          zOlderButtonLabel = "More";
        }
        free(zDate);
      }
      zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
      if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
        zDate = fossil_strdup((zBefore ? zBefore : zAfter));
      }
      if( zDate ){
        rDate = symbolic_name_to_mtime(zDate, 0, 0);
        if( db_int(0,
            "SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
            " WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
            rDate+ONE_SECOND, blob_sql_text(&cond))
Changes to src/tkt.c.
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      continue;
    }
    if( strchr(zFieldName,' ')!=0 ) continue;
    if( nField%10==0 ){
      aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
    }
    aField[nField].zBsln = 0;
    aField[nField].zName = mprintf("%s", zFieldName);
    aField[nField].mUsed = USEDBY_TICKET;
    nField++;
  }
  db_finalize(&q);
  if( nBaselines ){
    db_prepare(&q, "SELECT 1 FROM pragma_table_info('ticket') "
                   "WHERE type = 'INTEGER' AND name = :n");







|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      continue;
    }
    if( strchr(zFieldName,' ')!=0 ) continue;
    if( nField%10==0 ){
      aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
    }
    aField[nField].zBsln = 0;
    aField[nField].zName = fossil_strdup(zFieldName);
    aField[nField].mUsed = USEDBY_TICKET;
    nField++;
  }
  db_finalize(&q);
  if( nBaselines ){
    db_prepare(&q, "SELECT 1 FROM pragma_table_info('ticket') "
                   "WHERE type = 'INTEGER' AND name = :n");
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
      aField[i].mUsed |= USEDBY_TICKETCHNG;
      continue;
    }
    if( nField%10==0 ){
      aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
    }
    aField[nField].zBsln = 0;
    aField[nField].zName = mprintf("%s", zFieldName);
    aField[nField].mUsed = USEDBY_TICKETCHNG;
    nField++;
  }
  db_finalize(&q);
  qsort(aField, nField, sizeof(aField[0]), nameCmpr);
  noRegularMimetype = 1;
  for(i=0; i<nField; i++){







|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
      aField[i].mUsed |= USEDBY_TICKETCHNG;
      continue;
    }
    if( nField%10==0 ){
      aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
    }
    aField[nField].zBsln = 0;
    aField[nField].zName = fossil_strdup(zFieldName);
    aField[nField].mUsed = USEDBY_TICKETCHNG;
    nField++;
  }
  db_finalize(&q);
  qsort(aField, nField, sizeof(aField[0]), nameCmpr);
  noRegularMimetype = 1;
  for(i=0; i<nField; i++){
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
      char *zRevealed = 0;
      if( zVal==0 ){
        zVal = "";
      }else if( strncmp(zName, "private_", 8)==0 ){
        zVal = zRevealed = db_reveal(zVal);
      }
      if( (j = fieldId(zName))>=0 ){
        aField[j].zValue = mprintf("%s", zVal);
      }else if( memcmp(zName, "tkt_", 4)==0 && Th_Fetch(zName, &size)==0 ){
        /* TICKET table columns that begin with "tkt_" are always safe */
        Th_Store(zName, zVal);
      }
      free(zRevealed);
    }
    Th_Store("tkt_mage", human_readable_age(db_column_double(&q, 2)));







|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
      char *zRevealed = 0;
      if( zVal==0 ){
        zVal = "";
      }else if( strncmp(zName, "private_", 8)==0 ){
        zVal = zRevealed = db_reveal(zVal);
      }
      if( (j = fieldId(zName))>=0 ){
        aField[j].zValue = fossil_strdup(zVal);
      }else if( memcmp(zName, "tkt_", 4)==0 && Th_Fetch(zName, &size)==0 ){
        /* TICKET table columns that begin with "tkt_" are always safe */
        Th_Store(zName, zVal);
      }
      free(zRevealed);
    }
    Th_Store("tkt_mage", human_readable_age(db_column_double(&q, 2)));
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799

        zFName = g.argv[i++];
        if( i==g.argc ){
          fossil_fatal("missing value for '%s'!",zFName);
        }
        zFValue = g.argv[i++];
        if( tktEncoding == tktFossilize ){
          zFValue=mprintf("%s",zFValue);
          defossilize(zFValue);
        }
        append = (zFName[0] == '+');
        if( append ){
          zFName++;
        }
        j = fieldId(zFName);







|







1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799

        zFName = g.argv[i++];
        if( i==g.argc ){
          fossil_fatal("missing value for '%s'!",zFName);
        }
        zFValue = g.argv[i++];
        if( tktEncoding == tktFossilize ){
          zFValue=fossil_strdup(zFValue);
          defossilize(zFValue);
        }
        append = (zFName[0] == '+');
        if( append ){
          zFName++;
        }
        j = fieldId(zFName);
Changes to src/url.c.
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
      if( c!=0 && c!='/' ) fossil_fatal("url missing '/' after port number");
      pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    }else{
      pUrlData->port = pUrlData->dfltPort;
      pUrlData->hostname = pUrlData->name;
    }
    dehttpize(pUrlData->name);
    pUrlData->path = mprintf("%s", &zUrl[i]);
    for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
    if( pUrlData->path[i] ){
      pUrlData->path[i] = 0;
      i++;
    }
    zExe = mprintf("");
    while( pUrlData->path[i]!=0 ){







|







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
      if( c!=0 && c!='/' ) fossil_fatal("url missing '/' after port number");
      pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    }else{
      pUrlData->port = pUrlData->dfltPort;
      pUrlData->hostname = pUrlData->name;
    }
    dehttpize(pUrlData->name);
    pUrlData->path = fossil_strdup(&zUrl[i]);
    for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
    if( pUrlData->path[i] ){
      pUrlData->path[i] = 0;
      i++;
    }
    zExe = mprintf("");
    while( pUrlData->path[i]!=0 ){
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
        "%s://%s%T:%d%T%z",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
        pUrlData->path, zExe
      );
    }
    if( pUrlData->isSsh && pUrlData->path[1] ){
      char *zOld = pUrlData->path;
      pUrlData->path = mprintf("%s", zOld+1);
      fossil_free(zOld);
    }
    free(zLogin);
  }else if( strncmp(zUrl, "file:", 5)==0 ){
    pUrlData->isFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }
    zFile = mprintf("%s", &zUrl[i]);
  }else if( file_isfile(zUrl, ExtFILE) ){
    pUrlData->isFile = 1;
    zFile = mprintf("%s", zUrl);
  }else if( file_isdir(zUrl, ExtFILE)==1 ){
    zFile = mprintf("%s/FOSSIL", zUrl);
    if( file_isfile(zFile, ExtFILE) ){
      pUrlData->isFile = 1;
    }else{
      free(zFile);
      zFile = 0;







|










|


|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
        "%s://%s%T:%d%T%z",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
        pUrlData->path, zExe
      );
    }
    if( pUrlData->isSsh && pUrlData->path[1] ){
      char *zOld = pUrlData->path;
      pUrlData->path = fossil_strdup(zOld+1);
      fossil_free(zOld);
    }
    free(zLogin);
  }else if( strncmp(zUrl, "file:", 5)==0 ){
    pUrlData->isFile = 1;
    if( zUrl[5]=='/' && zUrl[6]=='/' ){
      i = 7;
    }else{
      i = 5;
    }
    zFile = fossil_strdup(&zUrl[i]);
  }else if( file_isfile(zUrl, ExtFILE) ){
    pUrlData->isFile = 1;
    zFile = fossil_strdup(zUrl);
  }else if( file_isdir(zUrl, ExtFILE)==1 ){
    zFile = mprintf("%s/FOSSIL", zUrl);
    if( file_isfile(zFile, ExtFILE) ){
      pUrlData->isFile = 1;
    }else{
      free(zFile);
      zFile = 0;
Changes to src/user.c.
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

  if( zLogin==0 ){
    return 0;
  }
  uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
  if( uid ){
    g.userUid = uid;
    g.zLogin = mprintf("%s", zLogin);
    return 1;
  }
  return 0;
}

/*
** Figure out what user is at the controls.







|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

  if( zLogin==0 ){
    return 0;
  }
  uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
  if( uid ){
    g.userUid = uid;
    g.zLogin = fossil_strdup(zLogin);
    return 1;
  }
  return 0;
}

/*
** Figure out what user is at the controls.
Changes to src/vfile.c.
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
      char *zPath;
      char *zUtf8;
      if( pEntry->d_name[0]=='.' ){
        if( (scanFlags & SCAN_ALL)==0 ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      zOrigPath = mprintf("%s", blob_str(pPath));
      zUtf8 = fossil_path_to_utf8(pEntry->d_name);
      blob_appendf(pPath, "/%s", zUtf8);
      zPath = blob_str(pPath);
      if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
          glob_match(pIgnore2, &zPath[nPrefix+1]) ){
        /* do nothing */
#ifdef _DIRENT_HAVE_D_TYPE
      }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
          ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
#else
      }else if( file_isdir(zPath, eFType)==1 ){
#endif
        if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
          char *zSavePath = mprintf("%s", zPath);
          int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
                                     pIgnore2, eFType);
          db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
          db_bind_int(&ins, ":count", count);
          db_step(&ins);
          db_reset(&ins);
          fossil_free(zSavePath);







|













|







641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
      char *zPath;
      char *zUtf8;
      if( pEntry->d_name[0]=='.' ){
        if( (scanFlags & SCAN_ALL)==0 ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      zOrigPath = fossil_strdup(blob_str(pPath));
      zUtf8 = fossil_path_to_utf8(pEntry->d_name);
      blob_appendf(pPath, "/%s", zUtf8);
      zPath = blob_str(pPath);
      if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
          glob_match(pIgnore2, &zPath[nPrefix+1]) ){
        /* do nothing */
#ifdef _DIRENT_HAVE_D_TYPE
      }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
          ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
#else
      }else if( file_isdir(zPath, eFType)==1 ){
#endif
        if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
          char *zSavePath = fossil_strdup(zPath);
          int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
                                     pIgnore2, eFType);
          db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
          db_bind_int(&ins, ":count", count);
          db_step(&ins);
          db_reset(&ins);
          fossil_free(zSavePath);
Changes to src/wiki.c.
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  int isSandbox;
  unsigned submenuFlags = W_HELP;
  Blob wiki;
  Manifest *pWiki = 0;
  const char *zPageName;
  const char *zMimetype = 0;
  int isPopup = P("popup")!=0;
  char *zBody = mprintf("%s","<i>Empty Page</i>");
  int noSubmenu = P("nsm")!=0 || g.isHome;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  (void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
  cgi_check_for_malice();







|







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  int isSandbox;
  unsigned submenuFlags = W_HELP;
  Blob wiki;
  Manifest *pWiki = 0;
  const char *zPageName;
  const char *zMimetype = 0;
  int isPopup = P("popup")!=0;
  char *zBody = fossil_strdup("<i>Empty Page</i>");
  int noSubmenu = P("nsm")!=0 || g.isHome;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  (void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
  cgi_check_for_malice();
Changes to src/winhttp.c.
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
    if( zPort && (atoi(zPort)<=0) ){
      winhttp_fatal("create", zSvcName,
                   "port number must be in the range 1 - 65535.");
    }
    if( !zRepository ){
      db_must_be_within_tree();
    }else if( file_isdir(zRepository, ExtFILE)==1 ){
      g.zRepositoryName = mprintf("%s", zRepository);
      file_simplify_name(g.zRepositoryName, -1, 0);
    }else{
      db_open_repository(zRepository);
    }
    db_close(0);
    /* Build the fully-qualified path to the service binary file. */
    blob_zero(&binPath);







|







1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
    if( zPort && (atoi(zPort)<=0) ){
      winhttp_fatal("create", zSvcName,
                   "port number must be in the range 1 - 65535.");
    }
    if( !zRepository ){
      db_must_be_within_tree();
    }else if( file_isdir(zRepository, ExtFILE)==1 ){
      g.zRepositoryName = fossil_strdup(zRepository);
      file_simplify_name(g.zRepositoryName, -1, 0);
    }else{
      db_open_repository(zRepository);
    }
    db_close(0);
    /* Build the fully-qualified path to the service binary file. */
    blob_zero(&binPath);
Changes to src/zip.c.
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
      zName[i+1] = 0;
      for(j=0; j<nDir; j++){
        if( fossil_strcmp(zName, azDir[j])==0 ) break;
      }
      if( j>=nDir ){
        nDir++;
        azDir = fossil_realloc(azDir, sizeof(azDir[0])*nDir);
        azDir[j] = mprintf("%s", zName);
        zip_add_file(p, zName, 0, 0);
      }
      zName[i+1] = c;
    }
  }
}








|







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
      zName[i+1] = 0;
      for(j=0; j<nDir; j++){
        if( fossil_strcmp(zName, azDir[j])==0 ) break;
      }
      if( j>=nDir ){
        nDir++;
        azDir = fossil_realloc(azDir, sizeof(azDir[0])*nDir);
        azDir[j] = fossil_strdup(zName);
        zip_add_file(p, zName, 0, 0);
      }
      zName[i+1] = c;
    }
  }
}