-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathvfs.c
302 lines (265 loc) · 9.14 KB
/
vfs.c
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <sqlite3.h>
#include <pcg.h>
#include "imports.h"
#include "debug.h"
// SQLite VFS component.
// Based on demoVFS from SQLlite.
// https://www.sqlite.org/src/doc/trunk/src/test_demovfs.c
#define MAXPATHNAME 1024
#define JS_MAX_SAFE_INTEGER 9007199254740991
// When using this VFS, the sqlite3_file* handles that SQLite uses are
// actually pointers to instances of type DenoFile.
typedef struct DenoFile DenoFile;
struct DenoFile {
sqlite3_file base;
// Deno file resource id
int rid;
};
static int denoClose(sqlite3_file *pFile) {
DenoFile* p = (DenoFile*)pFile;
js_close(p->rid);
debug_printf("closing file (rid %i)\n", p->rid);
return SQLITE_OK;
}
// Read data from a file.
static int denoRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst) {
DenoFile *p = (DenoFile*)pFile;
int read_bytes = 0;
if (iOfst <= JS_MAX_SAFE_INTEGER) {
// Read bytes from buffer
read_bytes = js_read(p->rid, (char*)zBuf, (double)iOfst, iAmt);
debug_printf("attempt to read from file (rid %i, amount %i, offset %lli, read %i)\n",
p->rid, iAmt, iOfst, read_bytes);
} else {
debug_printf("read offset %lli overflows JS_MAX_SAFE_INTEGER\n", iOfst);
}
// Zero memory if read was short
if (read_bytes < iAmt)
memset(&((char*)zBuf)[read_bytes], 0, iAmt-read_bytes);
return read_bytes < iAmt ? SQLITE_IOERR_SHORT_READ : SQLITE_OK;
}
// Write data to a file.
static int denoWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) {
DenoFile *p = (DenoFile*)pFile;
int write_bytes = 0;
if (iOfst <= JS_MAX_SAFE_INTEGER) {
// Write bytes to buffer
write_bytes = js_write(p->rid, (char*)zBuf, (double)iOfst, iAmt);
debug_printf("attempt to write to file (rid %i, amount %i, offset %lli, written %i)\n",
p->rid, iAmt, iOfst, write_bytes);
} else {
debug_printf("write offset %lli overflows JS_MAX_SAFE_INTEGER\n", iOfst);
}
return write_bytes == iAmt ? SQLITE_OK : SQLITE_IOERR_WRITE;
}
// Truncate file.
static int denoTruncate(sqlite3_file *pFile, sqlite_int64 size) {
DenoFile *p = (DenoFile*)pFile;
if (size <= JS_MAX_SAFE_INTEGER) {
js_truncate(p->rid, (double)size);
debug_printf("truncating file (rid %i, size: %lli)\n", p->rid, size);
return SQLITE_OK;
} else {
debug_printf("truncate length %lli overflows JS_MAX_SAFE_INTEGER\n", size);
return SQLITE_IOERR;
}
}
// Deno provides no explicit sync for us, so we
// just have a no-op here.
// TODO(dyedgreen): Investigate if there is a better way
static int denoSync(sqlite3_file *pFile, int flags) {
DenoFile *p = (DenoFile*)pFile;
js_sync(p->rid);
debug_printf("syncing file (rid %i)\n", p->rid);
return SQLITE_OK;
}
// Write the size of the file in bytes to *pSize.
static int denoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) {
DenoFile *p = (DenoFile*)pFile;
*pSize = (sqlite_int64)js_size(p->rid);
debug_printf("read file size: %lli (rid %i)\n", *pSize, p->rid);
return SQLITE_OK;
}
// File locking
static int denoLock(sqlite3_file *pFile, int eLock) {
DenoFile *p = (DenoFile*)pFile;
switch (eLock) {
case SQLITE_LOCK_NONE:
// no op
break;
case SQLITE_LOCK_SHARED:
case SQLITE_LOCK_RESERVED: // one WASM process <-> one open database
js_lock(p->rid, 0);
break;
case SQLITE_LOCK_PENDING:
case SQLITE_LOCK_EXCLUSIVE:
js_lock(p->rid, 1);
break;
}
return SQLITE_OK;
}
static int denoUnlock(sqlite3_file *pFile, int eLock) {
DenoFile *p = (DenoFile*)pFile;
switch (eLock) {
case SQLITE_LOCK_NONE:
// no op
break;
case SQLITE_LOCK_SHARED:
case SQLITE_LOCK_RESERVED:
case SQLITE_LOCK_PENDING:
case SQLITE_LOCK_EXCLUSIVE:
js_unlock(p->rid);
break;
}
return SQLITE_OK;
}
static int denoCheckReservedLock(sqlite3_file *pFile, int *pResOut) {
*pResOut = 0;
return SQLITE_OK;
}
// No xFileControl() verbs are implemented by this VFS.
static int denoFileControl(sqlite3_file *pFile, int op, void *pArg) {
return SQLITE_NOTFOUND;
}
// TODO(dyedgreen): Should we try to get these?
static int denoSectorSize(sqlite3_file *pFile) {
return 0;
}
static int denoDeviceCharacteristics(sqlite3_file *pFile) {
return 0;
}
// Open a file handle.
static int denoOpen(
sqlite3_vfs *pVfs, /* VFS */
const char *zName, /* File to open, or 0 for a temp file */
sqlite3_file *pFile, /* Pointer to DenoFile struct to populate */
int flags, /* Input SQLITE_OPEN_XXX flags */
int *pOutFlags /* Output SQLITE_OPEN_XXX flags (or NULL) */
) {
static const sqlite3_io_methods denoio = {
1, /* iVersion */
denoClose, /* xClose */
denoRead, /* xRead */
denoWrite, /* xWrite */
denoTruncate, /* xTruncate */
denoSync, /* xSync */
denoFileSize, /* xFileSize */
denoLock, /* xLock */
denoUnlock, /* xUnlock */
denoCheckReservedLock, /* xCheckReservedLock */
denoFileControl, /* xFileControl */
denoSectorSize, /* xSectorSize */
denoDeviceCharacteristics /* xDeviceCharacteristics */
};
DenoFile *p = (DenoFile*)pFile;
p->base.pMethods = &denoio;
// TODO(dyedgreen): The current approach is to raise
// the permission error on the vfs.js side of things,
// should the error be propagates through the wrapper
// and be raised on the wrapper side of things?
p->rid = js_open(zName, zName ? 0 : 1, flags);
if (pOutFlags) {
*pOutFlags = flags;
}
debug_printf("opened file (rid %i)\n", p->rid);
debug_printf("file path name: '%s'\n", zName);
return SQLITE_OK;
}
// Delete the file at the path.
static int denoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync) {
js_delete(zPath);
return SQLITE_OK;
}
// All valid id files are accessible.
static int denoAccess(sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut) {
switch (flags) {
case SQLITE_ACCESS_EXISTS:
*pResOut = js_exists(zPath);
break;
default:
*pResOut = js_access(zPath);
break;
}
debug_printf("determining file access (path %s, access %i)\n", zPath, *pResOut);
return SQLITE_OK;
}
// TODO(dyedgreen): Actually resolve the full path name
static int denoFullPathname(sqlite3_vfs *pVfs, const char *zPath, int nPathOut, char *zPathOut) {
sqlite3_snprintf(nPathOut, zPathOut, "%s", zPath);
debug_printf("requesting full path name for path: %s\n", zPath);
return SQLITE_OK;
}
// We don't support shared objects
static void *denoDlOpen(sqlite3_vfs *pVfs, const char *zPath) {
return 0;
}
static void denoDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg) {
sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
zErrMsg[nByte-1] = '\0';
}
static void (*denoDlSym(sqlite3_vfs *pVfs, void *pH, const char *z))(void) {
return 0;
}
static void denoDlClose(sqlite3_vfs *pVfs, void *pHandle) {
return;
}
// Generate pseudo-random data
static int denoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte) {
pcg_bytes(zByte, nByte);
return SQLITE_OK;
}
// TODO(dyedgreen): Can anything be done here?
static int denoSleep(sqlite3_vfs *pVfs, int nMicro) {
return 0;
}
// Retrieve the current time
static int denoCurrentTime(sqlite3_vfs *pVfs, double *pTime) {
*pTime = js_time() / 1000 / 86400.0 + 2440587.5;
return SQLITE_OK;
}
// Implement localtime_r
struct tm* localtime_r(const time_t *time, struct tm *result) {
debug_printf("running localtime_r");
time_t shifted = *time - 60 * js_timezone();
return gmtime_r(&shifted, result);
}
// This function returns a pointer to the VFS implemented in this file.
sqlite3_vfs *sqlite3_denovfs(void) {
static sqlite3_vfs denovfs = {
3, /* iVersion */
sizeof(DenoFile), /* szOsFile */
MAXPATHNAME, /* mxPathname */
0, /* pNext */
"deno", /* zName */
0, /* pAppData */
denoOpen, /* xOpen */
denoDelete, /* xDelete */
denoAccess, /* xAccess */
denoFullPathname, /* xFullPathname */
denoDlOpen, /* xDlOpen */
denoDlError, /* xDlError */
denoDlSym, /* xDlSym */
denoDlClose, /* xDlClose */
denoRandomness, /* xRandomness */
denoSleep, /* xSleep */
denoCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0, /* xCurrentTimeInt64 */
0, /* xSetSystemCall */
0, /* xGetSystemCall */
0, /* xNextSystemCall */
};
return &denovfs;
}
int sqlite3_os_init(void) {
debug_printf("running sqlite3_os_init\n");
// Register VFS
return sqlite3_vfs_register(sqlite3_denovfs(), 1);
}
int sqlite3_os_end(void) {
return SQLITE_OK;
}