#include "libphysfs-serve.h" #include #include #include #include #include #include #ifndef SERVE_INIT # define SERVE_INIT 0 #endif static char* strrchr_safe(const char *s, int c) { char *ret = strrchr(s, c); return (ret ? ret : (char*)s + strlen(s)); } static void dirname(char *path) { char *ret; if (!(ret = strrchr(path, '/'))) { *path = 0; return; } *ret = 0; } const bool find_file(const char *root, const char *file, char res_buf[], size_t res_buf_sz) { char **rc; if (!(rc = PHYSFS_enumerateFiles(root))) return false; for (char **i = rc; *i != NULL; ++i) { char fullpath[1024]; snprintf(fullpath, sizeof(fullpath), "%s/%s", root, *i); struct PHYSFS_Stat st = {0}; PHYSFS_stat(fullpath, &st); if (st.filetype == PHYSFS_FILETYPE_DIRECTORY) { if (find_file(fullpath, file, res_buf, res_buf_sz)) { PHYSFS_freeList(rc); return true; } } else { if (strcmp(file, *i)) continue; snprintf(res_buf, res_buf_sz, "%s", fullpath); PHYSFS_freeList(rc); return true; } } PHYSFS_freeList(rc); return false; } struct args { const char *path[32]; unsigned int npaths; unsigned int port; const char *addr; }; bool parse_arg(char *argv[], int argc, struct args *args) { if (*argv[0] != '-') { args->path[args->npaths++] = argv[0]; } else { const char *next = (argc > 1 ? argv[1] : ""); for (const char *s = argv[0] + 1; *s; ++s) { switch (*s) { case 'i': args->addr = next; return true; case 'p': args->port = strtoul(next, NULL, 10); return true; } } } return false; } int main(int argc, char *argv[]) { if (argc < 2) errx(EXIT_FAILURE, "usage: [-i addr] [-p port] archive ..."); struct args args = { .addr = "0.0.0.0", .port = 1337 }; for (int i = 1; i < argc; ++i) i += parse_arg(&argv[i], argc - i, &args); if (!PHYSFS_init(argv[0])) errx(EXIT_FAILURE, "PHYSFS_init failed"); for (unsigned int i = 0; i < args.npaths; ++i) { if (!PHYSFS_mount(args.path[i], NULL, 0)) errx(EXIT_FAILURE, "failed to mount archive: %s", args.path[i]); if (i == 0) { char root[1024]; if (!find_file("", "index.html", root, sizeof(root))) errx(EXIT_FAILURE, "no index.html found in the root archive"); dirname(root); PHYSFS_setRoot(args.path[i], root); } } while (1) { struct physfs_serve serve = { SERVE_INIT }; if (!physfs_serve_init(&serve, args.port, args.addr)) errx(EXIT_FAILURE, "couldn't listen"); while (1) { struct pollfd pfd[ARRAY_SIZE(serve.fd)]; for (int i = 0; i < ARRAY_SIZE(serve.fd); ++i) pfd[i] = (struct pollfd){ .fd = serve.fd[i], .events = POLLIN }; poll(pfd, serve.nfds, -1); for (int i = 0; i < serve.nfds; ++i) if (pfd[i].revents & POLLIN && !physfs_serve_event(&serve, i)) break; } physfs_serve_free(&serve); } PHYSFS_deinit(); return EXIT_SUCCESS; }