-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodule_fs.c
More file actions
212 lines (183 loc) · 6.69 KB
/
module_fs.c
File metadata and controls
212 lines (183 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include "quickjs.h"
#include "quickjs-libc.h"
#include <uv.h>
#include <stdlib.h>
#include <string.h>
#define countof(x) (sizeof(x) / sizeof((x)[0]))
typedef struct {
JSContext *ctx;
JSValue promise;
JSValue resolving_funcs[2];
char *path;
char *content;
size_t content_size;
} fs_read_req_t;
static void fs_read_cb(uv_fs_t *req) {
fs_read_req_t *fs_req = (fs_read_req_t *)req->data;
JSContext *ctx = fs_req->ctx;
JSValue ret;
if (req->result < 0) {
// Error handling
ret = JS_NewError(ctx);
JS_SetPropertyStr(ctx, ret, "message",
JS_NewString(ctx, uv_strerror(req->result)));
JS_Call(ctx, fs_req->resolving_funcs[1], JS_UNDEFINED, 1, &ret);
} else if (req->result == 0) {
// End of file reached, resolve with the complete content
ret = JS_NewStringLen(ctx, fs_req->content, fs_req->content_size);
JS_Call(ctx, fs_req->resolving_funcs[0], JS_UNDEFINED, 1, &ret);
} else {
// Data read successfully
ret = JS_NewStringLen(ctx, fs_req->content, req->result);
JS_Call(ctx, fs_req->resolving_funcs[0], JS_UNDEFINED, 1, &ret);
}
// Cleanup
JS_FreeValue(ctx, fs_req->promise);
JS_FreeValue(ctx, fs_req->resolving_funcs[0]);
JS_FreeValue(ctx, fs_req->resolving_funcs[1]);
free(fs_req->content);
free(fs_req->path);
free(fs_req);
uv_fs_req_cleanup(req);
free(req);
}
static void fs_open_cb(uv_fs_t *req) {
fs_read_req_t *fs_req = (fs_read_req_t *)req->data;
if (req->result < 0) {
// Handle error
JSValue error = JS_NewError(fs_req->ctx);
JS_SetPropertyStr(fs_req->ctx, error, "message",
JS_NewString(fs_req->ctx, uv_strerror(req->result)));
JS_Call(fs_req->ctx, fs_req->resolving_funcs[1], JS_UNDEFINED, 1, &error);
// Cleanup
JS_FreeValue(fs_req->ctx, fs_req->promise);
JS_FreeValue(fs_req->ctx, fs_req->resolving_funcs[0]);
JS_FreeValue(fs_req->ctx, fs_req->resolving_funcs[1]);
free(fs_req->path);
free(fs_req);
uv_fs_req_cleanup(req);
free(req);
return;
}
// File is open, now read it
uv_fs_t *read_req = malloc(sizeof(uv_fs_t));
read_req->data = fs_req;
// Get file size
uv_fs_t stat_req;
if (uv_fs_fstat(uv_default_loop(), &stat_req, req->result, NULL) < 0) {
JSValue error = JS_NewError(fs_req->ctx);
JS_SetPropertyStr(fs_req->ctx, error, "message",
JS_NewString(fs_req->ctx, "Failed to get file stats"));
JS_Call(fs_req->ctx, fs_req->resolving_funcs[1], JS_UNDEFINED, 1, &error);
// Cleanup
uv_fs_req_cleanup(&stat_req);
JS_FreeValue(fs_req->ctx, fs_req->promise);
JS_FreeValue(fs_req->ctx, fs_req->resolving_funcs[0]);
JS_FreeValue(fs_req->ctx, fs_req->resolving_funcs[1]);
free(fs_req->path);
free(fs_req);
uv_fs_req_cleanup(req);
free(req);
return;
}
size_t file_size = stat_req.statbuf.st_size;
fs_req->content_size = file_size;
fs_req->content = malloc(file_size);
uv_buf_t buf = uv_buf_init(fs_req->content, file_size);
int read_result = uv_fs_read(uv_default_loop(), read_req, req->result, &buf, 1, 0, fs_read_cb);
if (read_result < 0) {
// Handle read error
JSValue error = JS_NewError(fs_req->ctx);
JS_SetPropertyStr(fs_req->ctx, error, "message",
JS_NewString(fs_req->ctx, uv_strerror(read_result)));
JS_Call(fs_req->ctx, fs_req->resolving_funcs[1], JS_UNDEFINED, 1, &error);
// Cleanup
free(fs_req->content);
free(fs_req->path);
free(fs_req);
uv_fs_req_cleanup(read_req);
free(read_req);
}
uv_fs_req_cleanup(&stat_req);
uv_fs_req_cleanup(req);
free(req);
}
static JSValue js_readFile(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
const char *path;
JSValue promise, resolving_funcs[2];
if (argc < 1)
return JS_EXCEPTION;
path = JS_ToCString(ctx, argv[0]);
if (!path)
return JS_EXCEPTION;
// Create promise and get resolve/reject functions
promise = JS_NewPromiseCapability(ctx, resolving_funcs);
if (JS_IsException(promise)) {
JS_FreeCString(ctx, path);
return JS_EXCEPTION;
}
// Prepare request structure
fs_read_req_t *fs_req = malloc(sizeof(fs_read_req_t));
if (!fs_req) {
JSValue error = JS_NewError(ctx);
JS_SetPropertyStr(ctx, error, "message",
JS_NewString(ctx, "Failed to allocate memory"));
JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, &error);
JS_FreeCString(ctx, path);
JS_FreeValue(ctx, promise);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
}
fs_req->ctx = ctx;
// fs_req->promise = JS_DupValue(ctx, promise);
fs_req->resolving_funcs[0] = resolving_funcs[0];
fs_req->resolving_funcs[1] = resolving_funcs[1];
fs_req->path = strdup(path);
fs_req->content = NULL;
fs_req->content_size = 0;
// Start async file open
uv_fs_t *open_req = malloc(sizeof(uv_fs_t));
if (!open_req) {
JSValue error = JS_NewError(ctx);
JS_SetPropertyStr(ctx, error, "message",
JS_NewString(ctx, "Failed to allocate memory"));
JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, &error);
free(fs_req->path);
free(fs_req);
JS_FreeCString(ctx, path);
JS_FreeValue(ctx, promise);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
}
open_req->data = fs_req;
int ret = uv_fs_open(uv_default_loop(), open_req, path, O_RDONLY, 0, fs_open_cb);
if (ret < 0) {
JSValue error = JS_NewError(ctx);
JS_SetPropertyStr(ctx, error, "message",
JS_NewString(ctx, uv_strerror(ret)));
JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, &error);
free(fs_req->path);
free(fs_req);
free(open_req);
}
JS_FreeCString(ctx, path);
return promise;
}
static const JSCFunctionListEntry js_fs_funcs[] = {
JS_CFUNC_DEF("readFile", 2, js_readFile),
};
static int js_fs_init(JSContext *ctx, JSModuleDef *m) {
return JS_SetModuleExportList(ctx, m, js_fs_funcs,
countof(js_fs_funcs));
}
JSModuleDef *js_init_module_fs(JSContext *ctx, const char *module_name) {
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_fs_init);
if (!m)
return NULL;
JS_AddModuleExportList(ctx, m, js_fs_funcs, countof(js_fs_funcs));
return m;
}