open
https://gitlab.synchro.net/main/sbbs/-/issues/1171
## Summary
`packmsgs()` in `src/sbbs3/smbutil.c` is not error/crash-safe. It renames the live `.shd/.sdt/.sid` to `*_` **first**, writes the surviving messages to `*$`, then performs the final swap. If reading any single message's data fails mid-copy, it takes a **bare `return` with no error message**, *before* the swap — leaving the base with **no `.shd`** (renamed to `.shd_` and never restored). One unreadable/corrupt message destroys the whole base, silently.
## Root-caused incident (2026-06-23)
`smbutil -a mp mail` was run on a 2 GB `mail` base. Message `#711730` had a corrupt `data_offset` of `0xFFFFFF88` (see the companion "header committed on allocation failure" issue). During pack:
```c
fseek(smb.sdt_fp, msg.hdr.offset, SEEK_SET); // seek to 0xFFFFFF88 (~4.3GB) ...
for (m = 0; m < n; m++)
if (fread(buf, 1, SDT_BLOCK_LEN, smb.sdt_fp) < 1) {
free(datoffset);
return; // <-- past-EOF read → silent return, before the swap
}
```
Result: `.shd/.sdt/.sid` left as `*_`/`*$`, no live `.shd`; the lock was released on exit; `mailsrvr` then opened the base, found no header, and **created a fresh empty base**. (Recovered from the `_`/`$` temp files + `fixsmb`; no messages were actually lost.)
## Specific problems
1. **Silent failure** — the data-block read-failure path prints nothing (no `fprintf(errfp, ...)`, unlike the neighbouring length/alloc checks which `continue`).
2. **No rollback** — on any failure after the rename, the `*_` originals are not restored, so the base is left header-less.
3. **All-or-nothing** — a single corrupt/unreadable message aborts the entire pack; it should log and `continue` past it (like the existing >16 MB "invalid data length" case) and/or roll back.
4. **(minor/related)** the `-a` (`NOANALYSIS`) flag also makes `maint()` skip the "Freeing allocated header and data blocks for deleted messages" step, leaving orphaned blocks (later reclaimed by a successful pack).
## Suggested fix
On any error after the rename, restore `*_` → live (rollback) before returning; log the offending message number/offset; consider skipping unreadable messages rather than abandoning the pack.
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)