forked from cory/tildefriends
Serve core static files without leaving C.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4833 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
160
src/file.js.c
160
src/file.js.c
@ -1,5 +1,6 @@
|
||||
#include "file.js.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "mem.h"
|
||||
#include "task.h"
|
||||
#include "trace.h"
|
||||
@ -51,7 +52,7 @@ void tf_file_register(JSContext* context)
|
||||
JS_FreeValue(context, global);
|
||||
}
|
||||
|
||||
static const int k_file_read_max = 8 * 1024 * 1024;
|
||||
enum { k_file_read_max = 8 * 1024 * 1024 };
|
||||
|
||||
static void _file_async_close_callback(uv_fs_t* req)
|
||||
{
|
||||
@ -426,3 +427,160 @@ static void _file_on_stat_complete(uv_fs_t* request)
|
||||
uv_fs_req_cleanup(request);
|
||||
tf_free(data);
|
||||
}
|
||||
|
||||
typedef struct _stat_t
|
||||
{
|
||||
uv_fs_t request;
|
||||
tf_task_t* task;
|
||||
void (*callback)(tf_task_t* task, const char* path, int result, const uv_stat_t* stat, void* user_data);
|
||||
void* user_data;
|
||||
char path[];
|
||||
} stat_t;
|
||||
|
||||
static void _file_stat_complete(uv_fs_t* request)
|
||||
{
|
||||
stat_t* data = request->data;
|
||||
data->callback(data->task, data->path, request->result, &request->statbuf, data->user_data);
|
||||
uv_fs_req_cleanup(request);
|
||||
tf_free(data);
|
||||
}
|
||||
|
||||
void tf_file_stat(tf_task_t* task, const char* path, void (*callback)(tf_task_t* task, const char* path, int result, const uv_stat_t* stat, void* user_data), void* user_data)
|
||||
{
|
||||
const char* zip = tf_task_get_zip_path(task);
|
||||
size_t path_length = strlen(path) + 1;
|
||||
stat_t* data = tf_malloc(sizeof(stat_t) + path_length);
|
||||
*data = (stat_t) { .request = { .data = data }, .task = task, .callback = callback, .user_data = user_data };
|
||||
memcpy(data->path, path, path_length);
|
||||
|
||||
int result = uv_fs_stat(tf_task_get_loop(task), &data->request, zip ? zip : path, _file_stat_complete);
|
||||
if (result)
|
||||
{
|
||||
callback(task, path, result, NULL, user_data);
|
||||
uv_fs_req_cleanup(&data->request);
|
||||
tf_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _read_t
|
||||
{
|
||||
uv_work_t work;
|
||||
tf_task_t* task;
|
||||
void (*callback)(tf_task_t* task, const char* path, int result, const void* data, void* user_data);
|
||||
void* user_data;
|
||||
int64_t result;
|
||||
char buffer[k_file_read_max];
|
||||
char path[];
|
||||
} read_t;
|
||||
|
||||
static void _file_read_work(uv_work_t* work)
|
||||
{
|
||||
read_t* data = work->data;
|
||||
const char* zip_path = tf_task_get_zip_path(data->task);
|
||||
if (zip_path)
|
||||
{
|
||||
tf_trace_t* trace = tf_task_get_trace(data->task);
|
||||
tf_trace_begin(trace, "file_read_zip_work");
|
||||
unzFile zip = unzOpen(zip_path);
|
||||
if (zip)
|
||||
{
|
||||
data->result = unzLocateFile(zip, data->path, 1);
|
||||
if (data->result == UNZ_OK)
|
||||
{
|
||||
unz_file_info64 info = { 0 };
|
||||
data->result = unzGetCurrentFileInfo64(zip, &info, NULL, 0, NULL, 0, NULL, 0);
|
||||
if (data->result == UNZ_OK && info.uncompressed_size > sizeof(data->buffer))
|
||||
{
|
||||
data->result = -EFBIG;
|
||||
}
|
||||
else if (data->result == UNZ_OK)
|
||||
{
|
||||
data->result = unzOpenCurrentFile(zip);
|
||||
if (data->result == UNZ_OK)
|
||||
{
|
||||
data->result = unzReadCurrentFile(zip, data->buffer, info.uncompressed_size);
|
||||
if (data->result == (int64_t)info.uncompressed_size)
|
||||
{
|
||||
int r = unzCloseCurrentFile(zip);
|
||||
if (r != UNZ_OK)
|
||||
{
|
||||
data->result = r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data->result = EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unzClose(zip);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->result = errno;
|
||||
}
|
||||
tf_trace_end(trace);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_trace_t* trace = tf_task_get_trace(data->task);
|
||||
tf_trace_begin(trace, "file_read_zip_work");
|
||||
uv_loop_t* loop = tf_task_get_loop(data->task);
|
||||
uv_fs_t open_req = { 0 };
|
||||
int open_result = uv_fs_open(loop, &open_req, data->path, UV_FS_O_RDONLY, 0, NULL);
|
||||
if (open_result >= 0)
|
||||
{
|
||||
uv_buf_t buf = { .base = data->buffer, .len = sizeof(data->buffer) };
|
||||
uv_fs_t read_req = { 0 };
|
||||
int result = uv_fs_read(loop, &read_req, open_result, &buf, 1, 0, NULL);
|
||||
if ((size_t)result >= sizeof(data->buffer))
|
||||
{
|
||||
data->result = -EFBIG;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->result = result;
|
||||
}
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
uv_fs_t close_req = { 0 };
|
||||
result = uv_fs_close(loop, &close_req, open_result, NULL);
|
||||
if (result && data->result >= 0)
|
||||
{
|
||||
data->result = result;
|
||||
}
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->result = errno;
|
||||
}
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
tf_trace_end(trace);
|
||||
}
|
||||
}
|
||||
|
||||
static void _file_read_after_work(uv_work_t* work, int result)
|
||||
{
|
||||
read_t* data = work->data;
|
||||
data->callback(data->task, data->path, data->result, data->buffer, data->user_data);
|
||||
tf_free(data);
|
||||
}
|
||||
|
||||
void tf_file_read(tf_task_t* task, const char* path, void (*callback)(tf_task_t* task, const char* path, int result, const void* data, void* user_data), void* user_data)
|
||||
{
|
||||
size_t path_length = strlen(path) + 1;
|
||||
read_t* data = tf_malloc(sizeof(read_t) + path_length);
|
||||
memset(data, 0, sizeof(read_t));
|
||||
data->callback = callback;
|
||||
data->user_data = user_data;
|
||||
data->work.data = data;
|
||||
data->task = task;
|
||||
memcpy(data->path, path, path_length);
|
||||
int r = uv_queue_work(tf_task_get_loop(task), &data->work, _file_read_work, _file_read_after_work);
|
||||
if (r)
|
||||
{
|
||||
_file_read_after_work(&data->work, r);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user