• src/sbbs3/download.cpp file.cpp ftpsrvr.cpp listfile.cpp upload.cpp us

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Aug 9 07:19:11 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/672fc7e217976d587960b0f5
    Modified Files:
    src/sbbs3/download.cpp file.cpp ftpsrvr.cpp listfile.cpp upload.cpp userdat.c websrvr.cpp
    Log Message:
    Report file-database write failures instead of failing silently

    A file directory whose .sid index has been truncated (the status header counting more files than the index actually holds) causes
    smb_new_msghdr() to reject every new record with SMB_ERR_FILE_LEN. That
    state went unnoticed here until six file bases had quietly stopped
    accepting uploads: a single terminal session transferred 64 files
    totalling 2.6 GB, created no records at all, and logged neither an error
    nor the usual "U+ uploaded" lines.

    sbbs_t::uploadfile() passed NULL for addfile()'s result argument and
    returned false with no bputs() and no log entry, so a database failure
    was indistinguishable from success to every caller. It also credited
    the upload before attempting the add: logon_ulb/logon_uls and inc_upload_stats() ran unconditionally and were never rolled back, which
    is why the session footer reported 64 uploads that did not exist.

    Audited every caller of addfile(), updatefile() and removefile(), and
    fixed the sites that discarded the outcome:

    - uploadfile(): report the failure via errormsg(), and only credit the
    upload once the record is actually in the database.
    - listfileinfo(): check the add-to-offline-directory result.
    - editfilename(), editfiledesc(), editfileinfo(): each returned the
    updatefile() result as a bool that also encodes "user aborted" and
    "nothing changed", so no caller could distinguish a write failure from
    either. Report inside the function instead.
    - FTP DELE: the file is unlinked before its record is removed, so an
    unchecked removefile() leaves a record with no file behind it.
    - user_downloaded_file(): same unlink-then-remove ordering; when the
    record cannot be removed, return false rather than falling through and
    updating a dangling record. Its callers in download.cpp and
    websrvr.cpp now check the result.

    The FTP upload path and sbbs_t::movefile() already handled this
    correctly and were used as the model.

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

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