• src/sbbs3/nopen.c nopen.h qwkjob.cpp

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Oct 26 17:38:19 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/9021d114d289bcf7e191e525
    Modified Files:
    src/sbbs3/nopen.c nopen.h qwkjob.cpp
    Log Message:
    fmutex_close(): retry an unlink another host blocks; read QWK lock text shared

    When two hosts' event threads act on the same QWK pack semaphore (both glob data/pack*.now), the one that finds the user's lock busy opens the lock file briefly: to stat it, to try creating it, and to read the holder's text for
    the log. On Windows those opens don't permit deletion, so the holder's unlink over SMB/CIFS fails with EBUSY if it lands inside one. This happened on 2026-10-26 between VERT and a Linux host: the Linux host's older build (from before 251c99b699 (camera-37-lies, 2026-10-25)) returned from fmutex_close() without closing the lock file, and that user's QWK packets
    stayed blocked on every host until the process was restarted.

    The current fmutex_close() already closes the descriptor when the unlink
    fails, but leaves a lock file nobody holds, so the user waits for it to age
    out (an hour for a QWK user lock).

    - fmutex_close() now retries an unlink that fails with EBUSY, up to
    FMUTEX_UNLINK_RETRIES (10) times, LOCK_RETRY_DELAY (100 ms) apart, and
    treats the file vanishing meanwhile as removed.
    - qwkjob_lock_busy() on Windows reads the holder's text through a handle
    that permits FILE_SHARE_DELETE (the read added by 4365e08932
    (fuel-0-know, 2026-10-25)), so reading the text no longer blocks the
    holder's removal. Its stat and create attempts still can, which the retry
    covers.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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