Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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();
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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
}
Esempio n. 13
0
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;
}