open
https://gitlab.synchro.net/main/sbbs/-/work_items/1269
## Summary
Editing a file's extended description from the terminal server (`sbbs_t::editfileinfo()`, reached from the file lister and the file viewer) replaces the record's data through `sbbs_t::editmsg()`, which only handles the message layout. A file record keeps its `auxdata` (including the stored archive content listing) in a `TEXT_TAIL` data field, and `editmsg()` loses it:
1. **Record with an extended description and auxdata** (body + tail): the old
body and tail are both freed, only the new description is written, and the
tail's data field is left in the header unchanged. Its offset is relative to
the header's data offset, which now points at the new allocation, so the
tail refers to whatever follows the new description: unallocated blocks or
another record's data.
2. **Record with auxdata but no extended description** (tail only): the tail is
freed and its data field is overwritten with the new description. The
auxdata is silently gone.
## Mechanism
`src/sbbs3/writemsg.cpp`, `sbbs_t::editmsg()` (line 1699):
* `is_msg` is false for a file record (`SMB_MSG_TYPE_FILE`), so only the body
is exported to the editor (`GETMSGTXT_BODY_ONLY`).
* `smb_freemsg_dfields(smb, msg, 1)` then frees **every** data field, tail
included.
* `dfield[0]` is rewritten as a single `TEXT_BODY` of the new length at
offset 0 (line 1747).
* The loop that clears the remaining data fields to `UNUSED` runs only
`if (is_msg)` (line 1750), so for a file record `dfield[1]` keeps its
`TEXT_TAIL` type, old relative offset and old length.
* New data is allocated, `msg->hdr.offset` is updated, and the header is
written with `smb_putmsghdr()`.
`editfileinfo()` (`src/sbbs3/file.cpp`, the `editmsg(&smb, f)` call at line 346) then calls `updatefile()`, which is `smb_updatemsg()`: a header rewrite from the same in-memory data fields, so nothing repairs the tail afterwards.
For messages the same function behaves correctly: the tail is exported to the editor along with the body, and the extra data fields are cleared.
## Exposure
Only the extended-description editor in the terminal server calls `editmsg()` on a file record (`listfile.cpp:882`, `viewfile.cpp:68` -> `editfileinfo()`). JavaScript `FileBase.update()` goes through `smb_updatefile()`, which writes extdesc and auxdata together and is not affected.
A read-only scan of the file bases on one production system (1794 bases, 147,375 live records, 66,583 with a `TEXT_TAIL`, 19,356 of those tail-only) found **no** record whose tail offset differs from where its body ends, so
case 1 has not happened there. Case 2 leaves no trace in the header and cannot be detected after the fact.
Found by reading the code; not yet reproduced in a running terminal session.
## Suggested fix
Route file records through `smb_updatefile()` instead of rewriting the data in `editmsg()`: take the edited text as the new extdesc and pass the record's existing auxdata unchanged. `smb_updatefile()` already writes both fields, allocates before freeing, and handles the tail-only and body-only layouts. The record must be loaded with auxdata (`file_detail_auxdata`) for that to work.
Related: #1252 (the free-before-allocate ordering in `editmsg()`), #1253 (how data fields are reference-counted), #1247 (archive listings in auxdata).
-- *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)