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; }
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; }
int BlogGeneric(BlogRef const blog, SLNSessionRef const session, strarg_t const htmlpath, strarg_t const URI, SLNFileInfo const *const src) { str_t *tmp = NULL; uv_file html = -1; int rc = 0; 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; preview_state const state = { .blog = blog, .session = session, .fileURI = URI, }; rc = TemplateWriteFile(blog->preview, &preview_cbs, &state, html); 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; cleanup: async_fs_unlink(tmp); FREE(&tmp); if(html >= 0) { async_fs_close(html); html = -1; } assert(html < 0); return rc; }
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; }