| 236 | |
| 237 | #ifdef _WIN32 |
| 238 | int cbm_mkstemp(char *tmpl) { |
| 239 | /* Rewrite /tmp/ to %TEMP%\ like cbm_mkdtemp */ |
| 240 | /* Per-call storage: daemon project workers can create staging files |
| 241 | * concurrently, so a process-global scratch buffer is a data race. */ |
| 242 | char buf[CBM_SZ_4K]; |
| 243 | int written; |
| 244 | if (strncmp(tmpl, "/tmp/", 5) == 0) { |
| 245 | const char *tmp = getenv("TEMP"); |
| 246 | if (!tmp) |
| 247 | tmp = getenv("TMP"); |
| 248 | if (!tmp) |
| 249 | tmp = "."; |
| 250 | written = snprintf(buf, sizeof(buf), "%s\\%s", tmp, tmpl + 5); |
| 251 | } else { |
| 252 | written = snprintf(buf, sizeof(buf), "%s", tmpl); |
| 253 | } |
| 254 | if (written < 0 || (size_t)written >= sizeof(buf)) { |
| 255 | errno = ENAMETOOLONG; |
| 256 | return CBM_NOT_FOUND; |
| 257 | } |
| 258 | /* Wide-API expansion and open: worker staging files land inside |
| 259 | * CBM_CACHE_DIR, which users may place at non-ASCII paths; the ANSI CRT |
| 260 | * (_mktemp/_open) mangles those bytes in the local codepage. */ |
| 261 | wchar_t *wide_template = cbm_utf8_to_wide(buf); |
| 262 | if (!wide_template || !_wmktemp(wide_template)) { |
| 263 | free(wide_template); |
| 264 | return CBM_NOT_FOUND; |
| 265 | } |
| 266 | char *expanded_for_open = cbm_wide_to_utf8(wide_template); |
| 267 | wchar_t *wide_open = expanded_for_open ? cbm_path_to_wide(expanded_for_open) : NULL; |
| 268 | free(expanded_for_open); |
| 269 | if (!wide_open) { |
| 270 | free(wide_template); |
| 271 | return CBM_NOT_FOUND; |
| 272 | } |
| 273 | int fd = _wopen(wide_open, _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE); |
| 274 | free(wide_open); |
| 275 | if (fd >= 0) { |
| 276 | char *expanded = cbm_wide_to_utf8(wide_template); |
| 277 | if (!expanded || strlen(expanded) >= sizeof(buf)) { |
| 278 | free(expanded); |
| 279 | free(wide_template); |
| 280 | (void)_close(fd); |
| 281 | return CBM_NOT_FOUND; |
| 282 | } |
| 283 | strcpy(tmpl, expanded); |
| 284 | free(expanded); |
| 285 | } |
| 286 | free(wide_template); |
| 287 | return fd; |
| 288 | } |
| 289 | #endif |
| 290 | |
| 291 | /* ── clock_gettime (Windows lacks it) ─────────────────────────── */ |