int async_fs_writeall(uv_file const file, uv_buf_t bufs[], unsigned int const nbufs, int64_t const offset) { async_pool_enter(NULL); int64_t pos = offset; unsigned used = 0; int rc = 0; for(;;) { ssize_t len = async_fs_write(file, bufs+used, nbufs-used, pos); if(len < 0) { rc = len; goto cleanup; } if(pos >= 0) pos += len; for(;;) { if(used >= nbufs) { rc = 0; goto cleanup; } size_t const x = len < bufs[used].len ? len : bufs[used].len; bufs[used].base += x; bufs[used].len -= x; len -= x; if(bufs[used].len) break; used++; } } cleanup: async_pool_leave(NULL); return rc; }
int HTTPConnectionWriteChunkFile(HTTPConnectionRef const conn, strarg_t const path) { bool worker = false; uv_file file = -1; byte_t *buf = NULL; int rc; async_pool_enter(NULL); worker = true; rc = async_fs_open(path, O_RDONLY, 0000); if(rc < 0) goto cleanup; file = rc; buf = malloc(BUFFER_SIZE); if(!buf) rc = UV_ENOMEM; if(rc < 0) goto cleanup; uv_buf_t const chunk = uv_buf_init((char *)buf, BUFFER_SIZE); ssize_t len = async_fs_readall_simple(file, &chunk); if(len < 0) rc = len; if(rc < 0) goto cleanup; // Fast path for small files. if(len < BUFFER_SIZE) { str_t pfx[16]; int const pfxlen = snprintf(pfx, sizeof(pfx), "%llx\r\n", (unsigned long long)len); if(pfxlen < 0) rc = UV_UNKNOWN; if(rc < 0) goto cleanup; uv_buf_t parts[] = { uv_buf_init(pfx, pfxlen), uv_buf_init((char *)buf, len), uv_buf_init((char *)STR_LEN("\r\n")), }; async_fs_close(file); file = -1; async_pool_leave(NULL); worker = false; rc = HTTPConnectionWritev(conn, parts, numberof(parts)); goto cleanup; } uv_fs_t req[1]; rc = async_fs_fstat(file, req); if(rc < 0) goto cleanup; if(0 == req->statbuf.st_size) goto cleanup; async_pool_leave(NULL); worker = false; // TODO: HACK, WriteFile continues from where we left off rc = rc < 0 ? rc : HTTPConnectionWriteChunkLength(conn, req->statbuf.st_size); rc = rc < 0 ? rc : HTTPConnectionWritev(conn, &chunk, 1); rc = rc < 0 ? rc : HTTPConnectionWriteFile(conn, file); rc = rc < 0 ? rc : HTTPConnectionWrite(conn, (byte_t const *)STR_LEN("\r\n")); cleanup: FREE(&buf); if(file >= 0) { async_fs_close(file); file = -1; } if(worker) { async_pool_leave(NULL); worker = false; } assert(file < 0); assert(!worker); return rc; }
int async_fs_stat_mode(const char* path, uv_fs_t *const req) { async_pool_enter(NULL); uv_fs_t _req[1]; int const err = uv_fs_stat(async_loop, req ? req : _req, path, NULL); uv_fs_req_cleanup(req ? req : _req); async_pool_leave(NULL); return err; }
int async_fs_fstat(uv_file file, uv_fs_t *const req) { async_pool_enter(NULL); uv_fs_t _req[1]; int const err = uv_fs_fstat(async_loop, req ? req : _req, file, NULL); uv_fs_req_cleanup(req ? req : _req); async_pool_leave(NULL); return err; }
int async_fs_mkdir_sync(const char* path, int mode) { async_pool_enter(NULL); int rc = async_fs_mkdir_nosync(path, mode); if(rc >= 0) { rc = async_fs_sync_dirname(path); } async_pool_leave(NULL); return rc; }
int async_fs_sync_dirname(const char* path) { async_pool_enter(NULL); int rc = async_fs_open_dirname(path, O_RDONLY, 0000); if(rc >= 0) { uv_file parent = rc; rc = async_fs_fdatasync(parent); async_fs_close(parent); parent = -1; } async_pool_leave(NULL); return rc; }
void valogf(char const *const fmt, va_list ap) { async_pool_enter(NULL); char t[31+1]; int rc = time_iso8601(t, sizeof(t)); assert(rc >= 0); flockfile(stderr); fprintf(stderr, "%s ", t); vfprintf(stderr, fmt, ap); funlockfile(stderr); async_pool_leave(NULL); }
int SLNSubmissionEnd(SLNSubmissionRef const sub) { if(!sub) return 0; if(sub->size <= 0) return UV_EINVAL; assert(sub->tmppath); assert(sub->tmpfile >= 0); assert(sub->type); sub->URIs = SLNHasherEnd(sub->hasher); sub->internalHash = strdup(SLNHasherGetInternalHash(sub->hasher)); SLNHasherFree(&sub->hasher); if(!sub->URIs || !sub->internalHash) return UV_ENOMEM; SLNRepoRef const repo = SLNSubmissionGetRepo(sub); str_t *internalPath = NULL; bool worker = false; int rc = 0; rc = verify(sub); if(rc < 0) goto cleanup; internalPath = SLNRepoCopyInternalPath(repo, sub->internalHash); if(!internalPath) rc = UV_ENOMEM; if(rc < 0) goto cleanup; async_pool_enter(NULL); worker = true; rc = async_fs_fdatasync(sub->tmpfile); if(rc < 0) goto cleanup; // We use link(2) rather than rename(2) because link gives an error // if there's a name collision, rather than overwriting. We want to // keep the oldest file for any given hash, rather than the newest. rc = async_fs_link_mkdirp(sub->tmppath, internalPath); if(UV_EEXIST == rc) { rc = 0; goto cleanup; } if(rc < 0) { alogf("SLNSubmission couldn't move '%s' to '%s' (%s)\n", sub->tmppath, internalPath, sln_strerror(rc)); goto cleanup; } rc = async_fs_sync_dirname(internalPath); cleanup: if(worker) { async_pool_leave(NULL); worker = false; } FREE(&internalPath); async_fs_unlink(sub->tmppath); FREE(&sub->tmppath); return rc; }
static void cleanup(void *const unused) { HTTPServerFree(&server_raw); HTTPServerFree(&server_tls); RSSServerFree(&rss); BlogFree(&blog); SLNRepoFree(&repo); async_pool_enter(NULL); fflush(NULL); // Everything. async_pool_leave(NULL); async_pool_destroy_shared(); }
ssize_t async_fs_readall_simple(uv_file const file, uv_buf_t const *const buf) { async_pool_enter(NULL); size_t pos = 0; ssize_t rc; for(;;) { uv_buf_t b2 = uv_buf_init(buf->base+pos, buf->len-pos); rc = async_fs_read(file, &b2, 1, -1); if(rc < 0) break; if(0 == rc) { rc = pos; break; } pos += rc; if(pos >= buf->len) { rc = pos; break; } } async_pool_leave(NULL); return rc; }
static void term(void *const unused) { fprintf(stderr, "\n"); alogf("Stopping StrongLink server...\n"); uv_ref((uv_handle_t *)sigint); uv_signal_stop(sigint); async_close((uv_handle_t *)sigint); SLNRepoPullsStop(repo); HTTPServerClose(server_raw); HTTPServerClose(server_tls); async_pool_enter(NULL); fflush(NULL); // Everything. async_pool_leave(NULL); uv_ref((uv_handle_t *)sigpipe); uv_signal_stop(sigpipe); uv_close((uv_handle_t *)sigpipe, NULL); }
int async_getaddrinfo(char const *const node, char const *const service, struct addrinfo const *const hints, struct addrinfo **const res) { // uv_getaddrinfo kind of sucks so we try to avoid it. // TODO: We don't ever define __POSIX__ currently. #if defined(__POSIX__) || defined(CORO_USE_VALGRIND) async_pool_enter(NULL); int rc = getaddrinfo(node, service, hints, res); async_pool_leave(NULL); return rc; #else getaddrinfo_state state[1]; uv_getaddrinfo_t req[1]; req->data = state; uv_getaddrinfo_cb cb = NULL; if(async_main) { state->thread = async_active(); cb = getaddrinfo_cb; } int rc = uv_getaddrinfo(async_loop, req, cb, node, service, hints); if(rc < 0) return rc; if(cb) async_yield(); if(res) *res = state->res; return state->status; #endif }
static int convert(BlogRef const blog, SLNSessionRef const session, char const *const htmlpath, SLNSubmissionRef *const outmeta, strarg_t const URI, SLNFileInfo const *const src, BlogTypeCheck const types, BlogConverter const converter) { int rc = types(src->type); if(rc < 0) return UV_EINVAL; str_t *tmp = NULL; uv_file html = -1; uv_file file = -1; char const *buf = NULL; SLNSubmissionRef meta = NULL; yajl_gen json = NULL; tmp = SLNRepoCopyTempPath(blog->repo); if(!tmp) rc = UV_ENOMEM; if(rc < 0) goto cleanup; rc = async_fs_open_mkdirp(tmp, O_CREAT | O_EXCL | O_WRONLY, 0400); if(rc < 0) goto cleanup; html = rc; rc = async_fs_open(src->path, O_RDONLY, 0000); if(rc < 0) goto cleanup; file = rc; // We use size+1 to get nul-termination. Kind of a hack. buf = mmap(NULL, src->size+1, PROT_READ, MAP_SHARED, file, 0); if(MAP_FAILED == buf) rc = -errno; if(rc < 0) goto cleanup; if('\0' != buf[src->size]) rc = UV_EIO; // Slightly paranoid. if(rc < 0) goto cleanup; async_fs_close(file); file = -1; if(outmeta) { rc = SLNSubmissionCreate(session, NULL, URI, &meta); if(rc < 0) goto cleanup; rc = SLNSubmissionSetType(meta, SLN_META_TYPE); if(rc < 0) goto cleanup; } SLNSubmissionWrite(meta, (byte_t const *)URI, strlen(URI)); SLNSubmissionWrite(meta, (byte_t const *)STR_LEN("\n\n")); json = yajl_gen_alloc(NULL); if(!json) rc = UV_ENOMEM; if(rc < 0) goto cleanup; yajl_gen_config(json, yajl_gen_print_callback, (void (*)())SLNSubmissionWrite, meta); yajl_gen_config(json, yajl_gen_beautify, (int)true); async_pool_enter(NULL); yajl_gen_map_open(json); rc = converter(html, json, buf, src->size, src->type); yajl_gen_map_close(json); async_pool_leave(NULL); if(rc < 0) goto cleanup; rc = async_fs_fdatasync(html); if(rc < 0) goto cleanup; rc = async_fs_link_mkdirp(tmp, htmlpath); if(rc < 0) goto cleanup; rc = SLNSubmissionEnd(meta); if(rc < 0) goto cleanup; if(outmeta) { *outmeta = meta; meta = NULL; } cleanup: async_fs_unlink(tmp); FREE(&tmp); if(html >= 0) { async_fs_close(html); html = -1; } if(file >= 0) { async_fs_close(file); file = -1; } if(buf) { munmap((void *)buf, src->size+1); buf = NULL; } if(json) { yajl_gen_free(json); json = NULL; } SLNSubmissionFree(&meta); assert(html < 0); assert(file < 0); return rc; }