Replace a binary file. Unlinks the old file first (handles read-only and * running binaries on Unix where unlink succeeds on open files). On all * platforms, the caller should tell the user to restart after update. */
| 398 | * running binaries on Unix where unlink succeeds on open files). On all |
| 399 | * platforms, the caller should tell the user to restart after update. */ |
| 400 | int cbm_replace_binary(const char *path, const unsigned char *data, int len, int mode) { |
| 401 | if (!path || !data || len <= 0) { |
| 402 | return CLI_ERR; |
| 403 | } |
| 404 | |
| 405 | /* Remove existing file if it exists. On Unix, unlink works even if the |
| 406 | * binary is running (inode stays alive until the process exits). On Windows, |
| 407 | * unlink fails on running .exe — rename it aside as fallback. */ |
| 408 | struct stat st_check; |
| 409 | if (stat(path, &st_check) == 0) { |
| 410 | /* File exists — remove or rename it */ |
| 411 | if (cbm_unlink(path) != 0) { |
| 412 | #ifdef _WIN32 |
| 413 | /* Windows: can't unlink running .exe — rename aside */ |
| 414 | char old_path[CLI_BUF_1K]; |
| 415 | snprintf(old_path, sizeof(old_path), "%s.old", path); |
| 416 | (void)cbm_unlink(old_path); |
| 417 | if (rename(path, old_path) != 0) { |
| 418 | return CLI_ERR; |
| 419 | } |
| 420 | #else |
| 421 | return CLI_ERR; |
| 422 | #endif |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | #ifndef _WIN32 |
| 427 | int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, (mode_t)mode); |
| 428 | if (fd < 0) { |
| 429 | return CLI_ERR; |
| 430 | } |
| 431 | FILE *f = fdopen(fd, "wb"); |
| 432 | if (!f) { |
| 433 | close(fd); |
| 434 | return CLI_ERR; |
| 435 | } |
| 436 | #else |
| 437 | (void)mode; |
| 438 | FILE *f = fopen(path, "wb"); |
| 439 | if (!f) { |
| 440 | return CLI_ERR; |
| 441 | } |
| 442 | #endif |
| 443 | |
| 444 | size_t written = fwrite(data, CLI_ELEM_SIZE, (size_t)len, f); |
| 445 | (void)fclose(f); |
| 446 | return written == (size_t)len ? 0 : CLI_ERR; |
| 447 | } |
| 448 | |
| 449 | /* ── Skill file content (embedded) ────────────────────────────── */ |
| 450 |
no test coverage detected