Conversation
…ility EmbeddedCli redirects std::cout/std::cin to stringstreams, but libarchive's archive_write_open_FILE(stdout) and archive_read_open_fd(STDIN_FILENO) operate on C-level handles that bypass that redirection. On Windows GUI apps these handles are disconnected, so spratpack's multi-atlas TAR output was silently lost and _setmode calls on the invalid fd caused a fatal exit. Replace direct FILE*/fd usage with archive_write_open/archive_read_open callbacks that go through std::cout/std::cin, matching the approach already used in spratunpack. Make _setmode failures non-fatal since the C-level handles are irrelevant in embedded mode.
PR Summary
|
There was a problem hiding this comment.
Code Review
This pull request updates the spratlayout and spratpack commands to route archive I/O through std::cin and std::cout instead of OS-level file descriptors, ensuring compatibility with embedded environments where standard streams are redirected. Feedback on these changes suggests improving error handling in the custom read and write callbacks by explicitly calling archive_set_error and returning -1 when stream operations fail, rather than silently treating read errors as EOF or omitting error details on write failures.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| auto tar_read_cb = [](struct archive* /*unused*/, void* /*client_data*/, | ||
| const void** buffer) -> la_ssize_t { | ||
| static thread_local std::vector<char> buf(k_tar_read_buffer_size); | ||
| std::cin.read(buf.data(), static_cast<std::streamsize>(buf.size())); | ||
| auto n = std::cin.gcount(); | ||
| *buffer = buf.data(); | ||
| return static_cast<la_ssize_t>(n); | ||
| }; |
There was a problem hiding this comment.
When a read error occurs on std::cin, the callback currently returns 0 (via std::cin.gcount()), which libarchive interprets as a clean End-Of-File (EOF). To prevent silent failures or truncated extractions on actual I/O errors, we should check std::cin.bad() or std::cin.fail() and report the error to libarchive using archive_set_error before returning -1.
auto tar_read_cb = [](struct archive* a, void* /*client_data*/,
const void** buffer) -> la_ssize_t {
static thread_local std::vector<char> buf(k_tar_read_buffer_size);
std::cin.read(buf.data(), static_cast<std::streamsize>(buf.size()));
if (std::cin.bad() || (std::cin.fail() && !std::cin.eof())) {
archive_set_error(a, EIO, "std::cin read error");
return -1;
}
auto n = std::cin.gcount();
*buffer = buf.data();
return static_cast<la_ssize_t>(n);
};| auto tar_write_cb = [](struct archive* /*unused*/, void* /*client_data*/, | ||
| const void* buffer, size_t length) -> la_ssize_t { | ||
| std::cout.write(static_cast<const char*>(buffer), | ||
| static_cast<std::streamsize>(length)); | ||
| if (std::cout.fail()) return -1; | ||
| return static_cast<la_ssize_t>(length); | ||
| }; |
There was a problem hiding this comment.
When a write error occurs on std::cout, the callback returns -1 but does not set an error on the archive object. To ensure that libarchive can report a meaningful error message (e.g., via archive_error_string), we should call archive_set_error with a proper error code (like EIO) before returning -1.
auto tar_write_cb = [](struct archive* a, void* /*client_data*/,
const void* buffer, size_t length) -> la_ssize_t {
std::cout.write(static_cast<const char*>(buffer),
static_cast<std::streamsize>(length));
if (std::cout.fail()) {
archive_set_error(a, EIO, "std::cout write error");
return -1;
}
return static_cast<la_ssize_t>(length);
};
…ility
EmbeddedCli redirects std::cout/std::cin to stringstreams, but
libarchive's archive_write_open_FILE(stdout) and
archive_read_open_fd(STDIN_FILENO) operate on C-level handles that
bypass that redirection. On Windows GUI apps these handles are
disconnected, so spratpack's multi-atlas TAR output was silently lost
and _setmode calls on the invalid fd caused a fatal exit.
Replace direct FILE*/fd usage with archive_write_open/archive_read_open
callbacks that go through std::cout/std::cin, matching the approach
already used in spratunpack. Make _setmode failures non-fatal since
the C-level handles are irrelevant in embedded mode.