• exec/tests/filebase/update.jssrc/sbbs3/js_filebase.cpp src/smblib/smbf

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Sep 21 22:21:21 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/3a687044d32296219e6b142f
    Added Files:
    exec/tests/filebase/update.js
    Modified Files:
    src/sbbs3/js_filebase.cpp src/smblib/smbfile.c smblib.h
    Log Message:
    Update a file record's stored text in place instead of re-adding it

    Changing a file's extended description or auxdata meant removing the
    record and adding it back, because smb_putfile() writes only the header
    and the index entry, and those two fields live in the data blocks. The
    cost of that is paid on the file base as a whole: smb_removefile() reads
    the entire .sid into memory, rewrites it without the entry and truncates
    the file, all under the base-wide lock, and between the remove and the
    add the file does not exist. A failure or a crash in that window loses
    the record, and with it the description, the download counts and the
    import date, while the file itself sits on disk unreferenced.

    smb_updatefile() writes the new text to newly allocated data blocks,
    points the record at them and frees the old blocks afterwards. The
    record keeps its number, its header and its position in the index, and
    the base-wide lock is held for an allocation and a few writes rather
    than a full index rewrite. Because the new blocks are written before
    the old ones are freed, a failure part-way through leaks blocks, which
    chksmb reports and fixsmb reclaims, rather than losing the record. This
    is the opposite order from editmsg(), which frees first.

    FileBase.update() uses it whenever the text differs. readd_always keeps removing and re-adding, which is the point of that option: the file is
    meant to date and list as newly imported, the way addfiles.js -readd and FileBase.renew() expect.

    Measured over 480 updates against a scratch base: content reads back
    correctly, chksmb reports the base as OK with no deleted headers or
    indexes, and the data file ends up the same size as the remove-and-add
    path produced for the same work (158,464 vs 156,160 bytes), so writing
    the new blocks before freeing the old ones costs no meaningful
    fragmentation.

    exec/tests/filebase/update.js covers the preservation rules, the
    in-place rewrite, readd_always, renaming, and repeated growth and
    shrinkage of the stored text.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net