Login
Check-in [404f376c0e]
Login

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

Overview
Comment:As a late-stage step in the checkin process, ensure that vfile.isexe and vfile.islink match what the new manifest says. This has been a long-missing step which fossil(1) does but libfossil noted in a TODO comment but never implemented. This completes, hopefully, the fix started in [4243008e112140], but it's difficult to _really_ test without doing a genuine checkin (not a dry-run).
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 404f376c0eeebaa1b4d2392b313b998f2ec01b0084bf77b04fbbf778fff0f1cd
User & Date: stephan 2024-09-03 16:44:27
Context
2024-09-12
12:13
Update to latest upstream fnc. check-in: 25a3a7ceea user: stephan tags: trunk
2024-09-03
16:44
As a late-stage step in the checkin process, ensure that vfile.isexe and vfile.islink match what the new manifest says. This has been a long-missing step which fossil(1) does but libfossil noted in a TODO comment but never implemented. This completes, hopefully, the fix started in [4243008e112140], but it's difficult to _really_ test without doing a genuine checkin (not a dry-run). check-in: 404f376c0e user: stephan tags: trunk
15:25
latest upstream autosetup. check-in: 21a48eac26 user: stephan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to include/fossil-scm/db.h.

1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
/**
   The elipsis counterpart of fsl_stmt_bind_fmtv().
*/
FSL_EXPORT int fsl_stmt_bind_fmt( fsl_stmt * const st, char const * fmt, ... );

/**
    Binds a series of values using a formatting string.
   
    The string may contain the following characters, each of which
    refers to the next argument in the args list:
   
    '-': binds a NULL and expects a NULL placeholder
    in the argument list (for consistency's sake).
   
    'i': binds an int32
   
    'I': binds an int64
   
    'R': binds a fsl_id_t ('R' as in 'RID')
   
    'f': binds a double
   
    's': binds a (char const *) as text or NULL.
   
    'S': binds a (char const *) as a blob or NULL.
   
    'b': binds a (fsl_buffer const *) as text or NULL.
   
    'B': binds a (fsl_buffer const *) as a blob or NULL.
   
    ' ': spaces are allowed for readability and are ignored.

    Returns 0 on success, any number of other FSL_RC_xxx codes on
    error.

    ACHTUNG: the "sSbB" bindings assume, because of how this API is
    normally used, that the memory pointed to by the given argument







|


|


|

|

|

|

|

|

|

|

|







1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
/**
   The elipsis counterpart of fsl_stmt_bind_fmtv().
*/
FSL_EXPORT int fsl_stmt_bind_fmt( fsl_stmt * const st, char const * fmt, ... );

/**
    Binds a series of values using a formatting string.

    The string may contain the following characters, each of which
    refers to the next argument in the args list:

    '-': binds a NULL and expects a NULL placeholder
    in the argument list (for consistency's sake).

    'i': binds an int32

    'I': binds an int64

    'R': binds a fsl_id_t ('R' as in 'RID')

    'f': binds a double

    's': binds a (char const *) as text or NULL.

    'S': binds a (char const *) as a blob or NULL.

    'b': binds a (fsl_buffer const *) as text or NULL.

    'B': binds a (fsl_buffer const *) as a blob or NULL.

    ' ': spaces are allowed for readability and are ignored.

    Returns 0 on success, any number of other FSL_RC_xxx codes on
    error.

    ACHTUNG: the "sSbB" bindings assume, because of how this API is
    normally used, that the memory pointed to by the given argument

Changes to src/checkin.c.

1119
1120
1121
1122
1123
1124
1125





































































1126
1127
1128
1129
1130
1131
1132
                       "SELECT 1 FROM tagxref"
                       " WHERE tagid=%d AND rid=%"FSL_ID_T_PFMT
                       " AND tagtype>0"
                       " AND value=%Q",
                       FSL_TAGID_BRANCH, vid, name);
}






































































int fsl_checkin_commit(fsl_cx * f, fsl_checkin_opt const * opt,
                       fsl_id_t * newRid, fsl_uuid_str * newUuid ){
  int rc;
  fsl_deck deck = fsl_deck_empty;
  fsl_deck *d = &deck;
  fsl_db * dbC;
  fsl_db * dbR;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
                       "SELECT 1 FROM tagxref"
                       " WHERE tagid=%d AND rid=%"FSL_ID_T_PFMT
                       " AND tagtype>0"
                       " AND value=%Q",
                       FSL_TAGID_BRANCH, vid, name);
}

/**
   Interal helper for fsl_checkin_commit().

   Update vfile.isexe and vfile.islink to match d's F-cards. We should
   arguably do this while calculating the F-cards, as that would not
   require iterating over d's F-cards again, but having it here is
   currently simpler (and incidentally matches how fossil(1) does it).
*/
static int fsl__commit_update_exelink( fsl_cx * const f,
                                       fsl_db * const dbC,
                                       fsl_deck * const d ) {
  int rc = 0;
  fsl_stmt q = fsl_stmt_empty;
  fsl_card_F const * pFile = NULL;
  assert( dbC );
  assert( d->rid );
  /*
    For reference's sake, the fossil(1) counterpart code:

    // Update the isexe and islink columns of the vfile table
    db_prepare(&q,
      "UPDATE vfile SET isexe=:exec, islink=:link"
      " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)"
    );
    db_bind_int(&q, ":vid", nvid);
    pManifest = manifest_get(nvid, CFTYPE_MANIFEST, 0);
    manifest_file_rewind(pManifest);
    while( (pFile = manifest_file_next(pManifest, 0)) ){
      db_bind_int(&q, ":exec", pFile->zPerm && strstr(pFile->zPerm, "x"));
      db_bind_int(&q, ":link", pFile->zPerm && strstr(pFile->zPerm, "l"));
      db_bind_text(&q, ":path", pFile->zName);
      db_step(&q);
      db_reset(&q);
    }
    db_finalize(&q);
  */
  rc = fsl_db_prepare(
    dbC, &q,
    "UPDATE vfile SET isexe=?1, islink=?2 "
    "WHERE vid=?4 AND pathname=?3 AND (isexe!=?1 OR islink!=?2)"
    /* yes, ?4 and ?3 are intentionally out of order to simplify
       code below */
  );
  if(rc){
    fsl_cx_uplift_db_error(f, dbC);
    return rc;
  }
  fsl_stmt_bind_id(&q, 4, d->rid);
  rc = fsl_deck_F_rewind(d);
  while( 0==rc ){
    rc = fsl_deck_F_next(d, &pFile);
    if(rc || !pFile) break;
    rc = fsl_stmt_bind_fmt(
      &q, "iis",
      FSL_FILE_PERM_EXE==pFile->perm,
      FSL_FILE_PERM_LINK==pFile->perm,
      pFile->name
    );
    if(0==rc){
      if( FSL_RC_STEP_DONE==(rc = fsl_stmt_step(&q)) ){
        rc = 0;
      }
    }
    fsl_stmt_reset(&q);
  }
  fsl_stmt_finalize(&q);
  return rc;
}/* vfile.isexe/islink updates */

int fsl_checkin_commit(fsl_cx * f, fsl_checkin_opt const * opt,
                       fsl_id_t * newRid, fsl_uuid_str * newUuid ){
  int rc;
  fsl_deck deck = fsl_deck_empty;
  fsl_deck *d = &deck;
  fsl_db * dbC;
  fsl_db * dbR;
1206
1207
1208
1209
1210
1211
1212


1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  if(!rc) rc = fsl__ckout_version_write(f, d->rid, NULL);
  RC;
  assert(d->f == f);
  rc = fsl_checkin_add_unsent(f, d->rid);
  RC;
  rc = fsl__ckout_clear_merge_state(f, true);
  RC;


  /*
    todo(?) from fossil(1) follows. Most of this seems to be what the
    vfile handling does (above).

    db_multi_exec("PRAGMA %s.application_id=252006673;", db_name("repository"));
    db_multi_exec("PRAGMA %s.application_id=252006674;", db_name("localdb"));

    // Update the vfile and vmerge tables
    db_multi_exec(
      "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
      "DELETE FROM vmerge;"
      "UPDATE vfile SET vid=%d;"
      "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
      " WHERE is_selected(id);"
      , vid, nvid
    );
    db_lset_int("checkout", nvid);


    // Update the isexe and islink columns of the vfile table
    db_prepare(&q,
      "UPDATE vfile SET isexe=:exec, islink=:link"
      " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)"
    );
    db_bind_int(&q, ":vid", nvid);
    pManifest = manifest_get(nvid, CFTYPE_MANIFEST, 0);
    manifest_file_rewind(pManifest);
    while( (pFile = manifest_file_next(pManifest, 0)) ){
      db_bind_int(&q, ":exec", pFile->zPerm && strstr(pFile->zPerm, "x"));
      db_bind_int(&q, ":link", pFile->zPerm && strstr(pFile->zPerm, "l"));
      db_bind_text(&q, ":path", pFile->zName);
      db_step(&q);
      db_reset(&q);
    }
    db_finalize(&q);
  */

  if(opt->dumpManifestFile){
    FILE * out;
    /* MARKER(("Dumping generated manifest to file [%s]:\n", opt->dumpManifestFile)); */
    out = fsl_fopen(opt->dumpManifestFile, "w");
    if(out){







>
>

















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300


















1301
1302
1303
1304
1305
1306
1307
  if(!rc) rc = fsl__ckout_version_write(f, d->rid, NULL);
  RC;
  assert(d->f == f);
  rc = fsl_checkin_add_unsent(f, d->rid);
  RC;
  rc = fsl__ckout_clear_merge_state(f, true);
  RC;
  rc = fsl__commit_update_exelink(f, dbC, d);
  RC;
  /*
    todo(?) from fossil(1) follows. Most of this seems to be what the
    vfile handling does (above).

    db_multi_exec("PRAGMA %s.application_id=252006673;", db_name("repository"));
    db_multi_exec("PRAGMA %s.application_id=252006674;", db_name("localdb"));

    // Update the vfile and vmerge tables
    db_multi_exec(
      "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
      "DELETE FROM vmerge;"
      "UPDATE vfile SET vid=%d;"
      "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
      " WHERE is_selected(id);"
      , vid, nvid
    );
    db_lset_int("checkout", nvid);


















  */

  if(opt->dumpManifestFile){
    FILE * out;
    /* MARKER(("Dumping generated manifest to file [%s]:\n", opt->dumpManifestFile)); */
    out = fsl_fopen(opt->dumpManifestFile, "w");
    if(out){
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
  if(rc && !f->error.code){
    if(f->dbMain->error.code) fsl_cx_uplift_db_error(f, f->dbMain);
    else f->error.code = rc;
  }
  fsl_checkin_discard(f);
  fsl_deck_finalize(d);
  return rc;
}


#undef MARKER







|



1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
  if(rc && !f->error.code){
    if(f->dbMain->error.code) fsl_cx_uplift_db_error(f, f->dbMain);
    else f->error.code = rc;
  }
  fsl_checkin_discard(f);
  fsl_deck_finalize(d);
  return rc;
}/*fsl_checkin_commit()*/


#undef MARKER

Changes to src/deck.c.

1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
    while( !rc && !(rc=fsl_deck_F_next(d, &fc)) && fc) {
      rc = cb( fc, visitorState );
    }
    return (FSL_RC_BREAK==rc) ? 0 : rc;
  }
}

  
/**
    Output state for fsl_output_f_mf() and friends. Used for managing
    the output of a fsl_deck.
 */
struct fsl_deck_out_state {
  /**
      The set of cards being output. We use this to delegate certain







<







1437
1438
1439
1440
1441
1442
1443

1444
1445
1446
1447
1448
1449
1450
    while( !rc && !(rc=fsl_deck_F_next(d, &fc)) && fc) {
      rc = cb( fc, visitorState );
    }
    return (FSL_RC_BREAK==rc) ? 0 : rc;
  }
}


/**
    Output state for fsl_output_f_mf() and friends. Used for managing
    the output of a fsl_deck.
 */
struct fsl_deck_out_state {
  /**
      The set of cards being output. We use this to delegate certain
2468
2469
2470
2471
2472
2473
2474
2475

2476
2477
2478
2479
2480
2481
2482
  }
  rc = fsl_deck_unshuffle(d,
                          (FSL_CX_F_CALC_R_CARD & f->flags)
                          ? ((d->F.used && !d->R) ? 1 : 0)
                          : 0);
  /* ^^^^ unshuffling might install an R-card, so we have to
     do that before checking whether all required cards are
     set... */  

  if(rc) return rc;
  else if(!fsl_deck_has_required_cards(d)){
    return FSL_RC_SYNTAX;
  }

  os->d = d;
  os->out = out;







|
>







2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
  }
  rc = fsl_deck_unshuffle(d,
                          (FSL_CX_F_CALC_R_CARD & f->flags)
                          ? ((d->F.used && !d->R) ? 1 : 0)
                          : 0);
  /* ^^^^ unshuffling might install an R-card, so we have to
     do that before checking whether all required cards are
     set... */
  if( !rc ) rc = fsl_deck_F_rewind(d);
  if(rc) return rc;
  else if(!fsl_deck_has_required_cards(d)){
    return FSL_RC_SYNTAX;
  }

  os->d = d;
  os->out = out;
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
                               isPrimary, pParentFile->perm);
      }
    }
    if(rc) goto end;
  }

  fsl__cx_mcache_insert(f, &dOther);
  
  /* If pParent is the primary parent of pChild, also run this analysis
  ** for all merge parents of pChild */
  if( pmid && isPrimary ){
    for(i=1; i<pChild->P.used; i++){
      pmid = fsl_uuid_to_rid(f, (char const*)pChild->P.list[i]);
      if( pmid<=0 ) continue;
      rc = fsl_mlink_add(f, pmid, 0, cid, pChild, false);







|







3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
                               isPrimary, pParentFile->perm);
      }
    }
    if(rc) goto end;
  }

  fsl__cx_mcache_insert(f, &dOther);

  /* If pParent is the primary parent of pChild, also run this analysis
  ** for all merge parents of pChild */
  if( pmid && isPrimary ){
    for(i=1; i<pChild->P.used; i++){
      pmid = fsl_uuid_to_rid(f, (char const*)pChild->P.list[i]);
      if( pmid<=0 ) continue;
      rc = fsl_mlink_add(f, pmid, 0, cid, pChild, false);