• exec/load/door_deploy.js src/doors/syncconquer/build.bat build.sh src/

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Jul 12 05:11:38 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/8e5f359a05d0bfb7f6f0689b
    Modified Files:
    exec/load/door_deploy.js src/doors/syncconquer/build.bat build.sh src/doors/syncdoom/build.bat build.sh src/doors/syncduke/build.bat build.sh src/doors/syncmoo1/build.bat build.sh src/doors/syncretro/deploy.js
    Log Message:
    doors: stop deploy.js from truncating the binary it deploys

    The deploy step could copy a door binary onto itself and destroy it. The
    usual dev install has the door's live entry SYMLINKED to the build output (./build.sh and the change is live, no deploy step) -- and file_copy()
    opens the destination for writing, which through that symlink IS the
    source. It truncated the binary to zero bytes before reading a byte of
    it, leaving a 0-byte door and a 0-byte "copy". The build system then saw
    a target newer than its sources and declined to relink, so the next
    build.sh reported success over a corpse.

    Both guards that were supposed to prevent it are blind to a symlink:

    * fullpath(dst) == fullpath(exe) -- fullpath() NORMALIZES a path, it
    does not RESOLVE it, so a symlink never compares equal to its target.
    * size + mtime -- right on one filesystem, wrong across the SMB mount a
    live install is usually reached through: CIFS reports the same file's
    mtime a second off from the local view, the guard misses, the copy
    runs.

    The deploy.sh scripts this replaced got it right with `[ "$EXE" -ef
    "$DST" ]`, a device+inode identity test. Synchronet's JS has no stat(),
    so compare CONTENT instead: it answers a strictly stronger question, and answers it through symlinks, mounts and clock skew alike. If dst's bytes
    ARE exe's bytes there is nothing to copy -- and the destructive case (dst resolves to exe) is identical BY CONSTRUCTION, so it is always taken by
    that branch and the copy can never eat its own source.

    Also add a post-copy tripwire: if the source's size changed across the
    copy, say so loudly. It cannot undo the damage, but a 0-byte door dies at
    the player's first keystroke and the build that produced it looks clean.

    syncretro/deploy.js had grown a private copy of the same broken guard
    while its comment claimed it shared the common one; it now calls door_deploy_file(). It also only ever scanned this checkout's xtrn/, so
    the live install was never deployed to at all -- it now scans both, and
    keeps an existing flat binary in step with the <os>-<arch> one so a
    removed sub-dir cannot silently resurrect a stale door.

    The build scripts still pointed at the deploy.sh/deploy.bat pair that
    deploy.js replaced.

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