Create / -XXXXXX exclusively and return a stream on the * descriptor. On failure `path_out` is emptied so cleanup skips it. */
| 9593 | /* Create <scratch>/<basename>-XXXXXX exclusively and return a stream on the |
| 9594 | * descriptor. On failure `path_out` is emptied so cleanup skips it. */ |
| 9595 | static FILE *search_scratch_file(const char *dir, const char *basename, char *path_out, |
| 9596 | size_t path_sz) { |
| 9597 | path_out[0] = '\0'; |
| 9598 | int written = snprintf(path_out, path_sz, "%s/%s-XXXXXX", dir, basename); |
| 9599 | if (written <= 0 || (size_t)written >= path_sz) { |
| 9600 | path_out[0] = '\0'; |
| 9601 | return NULL; |
| 9602 | } |
| 9603 | int descriptor = cbm_mkstemp(path_out); |
| 9604 | if (descriptor < 0) { |
| 9605 | path_out[0] = '\0'; |
| 9606 | return NULL; |
| 9607 | } |
| 9608 | /* Binary mode: the file list uses an explicit per-platform record separator |
| 9609 | * (NUL for xargs -0, newline for PowerShell) that CRLF translation would |
| 9610 | * corrupt — the same reason the previous code opened it "wb". */ |
| 9611 | FILE *stream = mcp_fdopen(descriptor, "wb"); |
| 9612 | if (!stream) { |
| 9613 | (void)mcp_close(descriptor); |
| 9614 | (void)cbm_unlink(path_out); |
| 9615 | path_out[0] = '\0'; |
| 9616 | } |
| 9617 | return stream; |
| 9618 | } |
| 9619 | |
| 9620 | /* Anchored cleanup: removes both scratch files and the private directory. Safe |
| 9621 | * to call more than once and on any partially-initialised scratch, so every |
no test coverage detected