| 634 | #include <dirent.h> |
| 635 | |
| 636 | static void append_roots_json(char *buf, size_t bufsz, int *pos) { |
| 637 | http_appendf(buf, bufsz, pos, ",\"roots\":["); |
| 638 | #ifdef _WIN32 |
| 639 | DWORD drives = GetLogicalDrives(); |
| 640 | int count = 0; |
| 641 | for (int i = 0; i < 26; i++) { |
| 642 | if (!(drives & (1u << i))) { |
| 643 | continue; |
| 644 | } |
| 645 | /* Advertise exactly what /api/browse will accept: a mounted letter |
| 646 | * without a readable medium (empty optical drive, unformatted or |
| 647 | * offline volume) fails the same cbm_is_dir gate browse applies, and |
| 648 | * a root the picker cannot open must not be offered. */ |
| 649 | char root[4] = {(char)('A' + i), ':', '/', '\0'}; |
| 650 | if (!cbm_is_dir(root)) { |
| 651 | continue; |
| 652 | } |
| 653 | if (count++ > 0) { |
| 654 | /* Once a wide listing saturates buf, http_appendf has already |
| 655 | * pinned *pos to bufsz, so this separator goes through it too. */ |
| 656 | http_appendf(buf, bufsz, pos, ","); |
| 657 | } |
| 658 | http_appendf(buf, bufsz, pos, "\"%c:/\"", 'A' + i); |
| 659 | } |
| 660 | #else |
| 661 | http_appendf(buf, bufsz, pos, "\"/\""); |
| 662 | #endif |
| 663 | http_appendf(buf, bufsz, pos, "]"); |
| 664 | } |
| 665 | |
| 666 | /* GET /api/browse?path=/some/dir — list subdirectories for file picker */ |
| 667 | static void handle_browse(cbm_http_conn_t *c, const cbm_http_req_t *req) { |
no test coverage detected