open
https://gitlab.synchro.net/main/sbbs/-/work_items/1278
## Summary
Bare single-file compressed files (`.gz`, and by the same mechanism `.bz2`, `.xz`, `.zst`, `.lz4`, ...) can't be opened by the `Archive` JS class or the file-base archive code, even after the sysop adds the extension to the supported archive types in SCFG. libarchive can read them, but only when the "raw" format is enabled, and Synchronet never enables it.
Reported by Nelgin (EOTLBBS) on DOVE-Net Synchronet Discussion ("Adding supported_formats to Archive", Oct 3 2026):
```
$ jsexec -n -r 'Archive.supported_formats.forEach(function(f){ print(f); })' zip
7z
tgz
gz
$ jsexec -n archive read /var/log/sbbs/web.sbbs.log.1.gz
!JavaScript /sbbs/exec/archive.js line 49: Error: archive_read_open_filename() returned -30: Unrecognized archive format
```
## Cause
Every libarchive read site enables `archive_read_support_filter_all()` + `archive_read_support_format_all()` only:
- `src/sbbs3/js_archive.cpp` (two sites: list and extract/read)
- `src/sbbs3/filedat.c` (two sites)
`archive_read_support_format_all()` deliberately excludes the "raw" (and "empty") formats, because "raw" matches any input. The libarchive README says decompression without archiving requires explicitly selecting "raw".
Verified against libarchive 3.7.4 with a small test program:
| enabled | `t.txt.gz` | `t.tgz` |
|---|---|---|
| filter_all + format_all | `-30 Unrecognized archive format` | GNU tar |
| + `archive_read_support_format_raw()` | 1 entry `t.txt` (name from the gzip header), format=raw, filter=gzip, data decompressed OK, size not set | still GNU tar ("raw" only wins when nothing else matches) |
## Proposed fix
Enable `archive_read_support_format_raw()` at each read site, but **only accept a raw result when a decompression filter was actually applied**. Otherwise every non-archive file (`.txt`, `.jpg`, ...) would "open" as a one-entry archive, and the file-base archive listing would treat all files as archives. After `archive_read_next_header()`, something like:
```c
if (archive_format(ar) == ARCHIVE_FORMAT_RAW
&& archive_filter_code(ar, 0) == ARCHIVE_FILTER_NONE)
/* not compressed: treat as unrecognized, as before */
```
Other details to handle:
- The entry name comes from the gzip header when present; otherwise libarchive reports `data`. Deriving the name from the filename minus its compression extension would be friendlier.
- The entry size isn't known until the data is decompressed (`archive_entry_size_is_set()` is 0), so listings have to cope with an unknown size.
- Should a bare `.gz` be a valid "archive" type in SCFG at all, or should this be handled implicitly? Today SCFG accepts `gz` in the list and then it always fails.
See also #453 (bare `.bz2` hang in libarchive on Windows).
- *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.38-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)