@k13engineering/linux-fuse 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/abi.d.ts +331 -0
- package/dist/lib/abi.js +1019 -0
- package/dist/lib/constants.d.ts +225 -0
- package/dist/lib/constants.js +272 -0
- package/dist/lib/convenience.d.ts +63 -0
- package/dist/lib/convenience.js +463 -0
- package/dist/lib/dirent.d.ts +13 -0
- package/dist/lib/dirent.js +128 -0
- package/dist/lib/fuse-lowlevel.d.ts +42 -0
- package/dist/lib/fuse-lowlevel.js +133 -0
- package/dist/lib/index.d.ts +43 -0
- package/dist/lib/index.js +325 -0
- package/dist/lib/linux.d.ts +12 -0
- package/dist/lib/linux.js +32 -0
- package/dist/lib/message.d.ts +50 -0
- package/dist/lib/message.js +177 -0
- package/dist/lib/mount.d.ts +33 -0
- package/dist/lib/mount.js +149 -0
- package/dist/lib/protocol.d.ts +755 -0
- package/dist/lib/protocol.js +3797 -0
- package/dist/lib/server.d.ts +18 -0
- package/dist/lib/server.js +73 -0
- package/dist/lib/syscalls.d.ts +73 -0
- package/dist/lib/syscalls.js +275 -0
- package/package.json +2 -2
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
/*import type { TFuseRequest, TFuseResponse } from "./protocol.ts";*/
|
|
2
|
+
/*import type { TRequestHandler } from "./server.ts";*/
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
/*type DistributiveOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;*/
|
|
6
|
+
|
|
7
|
+
/*type TConvenienceRequest<T extends string> = Extract<TFuseRequest, { opcode: T }>;*/
|
|
8
|
+
/*type TConvenienceResponse<T extends string> = DistributiveOmit<Extract<TFuseResponse, { forOpcode: T }>, "unique">;*/
|
|
9
|
+
|
|
10
|
+
/*type TFuseServerInterface = {
|
|
11
|
+
init: (req: TConvenienceRequest<"INIT">) => Promise<TConvenienceResponse<"INIT">>;
|
|
12
|
+
forget: (req: TConvenienceRequest<"FORGET">) => Promise<void>;
|
|
13
|
+
batchForget: (req: TConvenienceRequest<"BATCH_FORGET">) => Promise<void>;
|
|
14
|
+
getattr: (req: Extract<TConvenienceRequest<"GETATTR">, { getattrMode: "node" }>) => Promise<TConvenienceResponse<"GETATTR">>;
|
|
15
|
+
fgetattr: (req: Extract<TConvenienceRequest<"GETATTR">, { getattrMode: "fileHandle" }>) => Promise<TConvenienceResponse<"GETATTR">>;
|
|
16
|
+
setattr: (req: TConvenienceRequest<"SETATTR">) => Promise<TConvenienceResponse<"SETATTR">>;
|
|
17
|
+
listxattr: (req: TConvenienceRequest<"LISTXATTR">) => Promise<TConvenienceResponse<"LISTXATTR">>;
|
|
18
|
+
getxattr: (req: TConvenienceRequest<"GETXATTR">) => Promise<TConvenienceResponse<"GETXATTR">>;
|
|
19
|
+
readlink: (req: TConvenienceRequest<"READLINK">) => Promise<TConvenienceResponse<"READLINK">>;
|
|
20
|
+
symlink: (req: TConvenienceRequest<"SYMLINK">) => Promise<TConvenienceResponse<"SYMLINK">>;
|
|
21
|
+
mknod: (req: TConvenienceRequest<"MKNOD">) => Promise<TConvenienceResponse<"MKNOD">>;
|
|
22
|
+
mkdir: (req: TConvenienceRequest<"MKDIR">) => Promise<TConvenienceResponse<"MKDIR">>;
|
|
23
|
+
unlink: (req: TConvenienceRequest<"UNLINK">) => Promise<TConvenienceResponse<"UNLINK">>;
|
|
24
|
+
rmdir: (req: TConvenienceRequest<"RMDIR">) => Promise<TConvenienceResponse<"RMDIR">>;
|
|
25
|
+
rename: (req: TConvenienceRequest<"RENAME">) => Promise<TConvenienceResponse<"RENAME">>;
|
|
26
|
+
link: (req: TConvenienceRequest<"LINK">) => Promise<TConvenienceResponse<"LINK">>;
|
|
27
|
+
opendir: (req: TConvenienceRequest<"OPENDIR">) => Promise<TConvenienceResponse<"OPENDIR">>;
|
|
28
|
+
readdir: (req: TConvenienceRequest<"READDIR">) => Promise<TConvenienceResponse<"READDIR">>;
|
|
29
|
+
release: (req: TConvenienceRequest<"RELEASE">) => Promise<TConvenienceResponse<"RELEASE">>;
|
|
30
|
+
releasedir: (req: TConvenienceRequest<"RELEASEDIR">) => Promise<TConvenienceResponse<"RELEASEDIR">>;
|
|
31
|
+
fsyncdir: (req: TConvenienceRequest<"FSYNCDIR">) => Promise<TConvenienceResponse<"FSYNCDIR">>;
|
|
32
|
+
statfs: (req: TConvenienceRequest<"STATFS">) => Promise<TConvenienceResponse<"STATFS">>;
|
|
33
|
+
lookup: (req: TConvenienceRequest<"LOOKUP">) => Promise<TConvenienceResponse<"LOOKUP">>;
|
|
34
|
+
open: (req: TConvenienceRequest<"OPEN">) => Promise<TConvenienceResponse<"OPEN">>;
|
|
35
|
+
read: (req: TConvenienceRequest<"READ">) => Promise<TConvenienceResponse<"READ">>;
|
|
36
|
+
write: (req: TConvenienceRequest<"WRITE">) => Promise<TConvenienceResponse<"WRITE">>;
|
|
37
|
+
flush: (req: TConvenienceRequest<"FLUSH">) => Promise<TConvenienceResponse<"FLUSH">>;
|
|
38
|
+
fsync: (req: TConvenienceRequest<"FSYNC">) => Promise<TConvenienceResponse<"FSYNC">>;
|
|
39
|
+
access: (req: TConvenienceRequest<"ACCESS">) => Promise<TConvenienceResponse<"ACCESS">>;
|
|
40
|
+
setxattr: (req: TConvenienceRequest<"SETXATTR">) => Promise<TConvenienceResponse<"SETXATTR">>;
|
|
41
|
+
removexattr: (req: TConvenienceRequest<"REMOVEXATTR">) => Promise<TConvenienceResponse<"REMOVEXATTR">>;
|
|
42
|
+
create: (req: TConvenienceRequest<"CREATE">) => Promise<TConvenienceResponse<"CREATE">>;
|
|
43
|
+
destroy: (req: TConvenienceRequest<"DESTROY">) => Promise<TConvenienceResponse<"DESTROY">>;
|
|
44
|
+
getlk: (req: TConvenienceRequest<"GETLK">) => Promise<TConvenienceResponse<"GETLK">>;
|
|
45
|
+
setlk: (req: TConvenienceRequest<"SETLK">) => Promise<TConvenienceResponse<"SETLK">>;
|
|
46
|
+
setlkw: (req: TConvenienceRequest<"SETLKW">) => Promise<TConvenienceResponse<"SETLKW">>;
|
|
47
|
+
interrupt: (req: TConvenienceRequest<"INTERRUPT">) => Promise<void>;
|
|
48
|
+
bmap: (req: TConvenienceRequest<"BMAP">) => Promise<TConvenienceResponse<"BMAP">>;
|
|
49
|
+
ioctl: (req: TConvenienceRequest<"IOCTL">) => Promise<TConvenienceResponse<"IOCTL">>;
|
|
50
|
+
poll: (req: TConvenienceRequest<"POLL">) => Promise<TConvenienceResponse<"POLL">>;
|
|
51
|
+
notifyReply: (req: TConvenienceRequest<"NOTIFY_REPLY">) => Promise<void>;
|
|
52
|
+
fallocate: (req: TConvenienceRequest<"FALLOCATE">) => Promise<TConvenienceResponse<"FALLOCATE">>;
|
|
53
|
+
readdirplus: (req: TConvenienceRequest<"READDIRPLUS">) => Promise<TConvenienceResponse<"READDIRPLUS">>;
|
|
54
|
+
};*/
|
|
55
|
+
|
|
56
|
+
const createConvenienceRequestHandler = ({
|
|
57
|
+
serverInterface
|
|
58
|
+
}/*: {
|
|
59
|
+
serverInterface: TFuseServerInterface
|
|
60
|
+
}*/)/*: TRequestHandler*/ => {
|
|
61
|
+
// eslint-disable-next-line max-statements, complexity
|
|
62
|
+
const handleRequest/*: TRequestHandler["handleRequest"]*/ = async ({ request }) => {
|
|
63
|
+
switch (request.opcode) {
|
|
64
|
+
case "INIT": {
|
|
65
|
+
const response = await serverInterface.init(request);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...response,
|
|
69
|
+
unique: request.unique,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case "FORGET": {
|
|
74
|
+
await serverInterface.forget(request);
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
case "BATCH_FORGET": {
|
|
79
|
+
await serverInterface.batchForget(request);
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
case "GETATTR": {
|
|
84
|
+
|
|
85
|
+
switch (request.getattrMode) {
|
|
86
|
+
case "node": {
|
|
87
|
+
const response = await serverInterface.getattr(request);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
...response,
|
|
91
|
+
unique: request.unique,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case "fileHandle": {
|
|
96
|
+
const response = await serverInterface.fgetattr(request);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
...response,
|
|
100
|
+
unique: request.unique,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
default: {
|
|
105
|
+
// @ts-expect-error exhaustive check
|
|
106
|
+
throw Error(`unsupported getattr mode: ${request.getattrMode}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
case "SETATTR": {
|
|
112
|
+
const response = await serverInterface.setattr(request);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
...response,
|
|
116
|
+
unique: request.unique,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case "LISTXATTR": {
|
|
121
|
+
const response = await serverInterface.listxattr(request);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
...response,
|
|
125
|
+
unique: request.unique,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
case "GETXATTR": {
|
|
130
|
+
const response = await serverInterface.getxattr(request);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
...response,
|
|
134
|
+
unique: request.unique,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
case "READLINK": {
|
|
139
|
+
const response = await serverInterface.readlink(request);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
...response,
|
|
143
|
+
unique: request.unique,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
case "SYMLINK": {
|
|
148
|
+
const response = await serverInterface.symlink(request);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
...response,
|
|
152
|
+
unique: request.unique,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
case "MKNOD": {
|
|
157
|
+
const response = await serverInterface.mknod(request);
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
...response,
|
|
161
|
+
unique: request.unique,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
case "MKDIR": {
|
|
166
|
+
const response = await serverInterface.mkdir(request);
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
...response,
|
|
170
|
+
unique: request.unique,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
case "UNLINK": {
|
|
175
|
+
const response = await serverInterface.unlink(request);
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
...response,
|
|
179
|
+
unique: request.unique,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
case "RMDIR": {
|
|
184
|
+
const response = await serverInterface.rmdir(request);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
...response,
|
|
188
|
+
unique: request.unique,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
case "RENAME": {
|
|
193
|
+
const response = await serverInterface.rename(request);
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
...response,
|
|
197
|
+
unique: request.unique,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
case "LINK": {
|
|
202
|
+
const response = await serverInterface.link(request);
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
...response,
|
|
206
|
+
unique: request.unique,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
case "OPENDIR": {
|
|
211
|
+
const response = await serverInterface.opendir(request);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
...response,
|
|
215
|
+
unique: request.unique,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
case "READDIR": {
|
|
220
|
+
const response = await serverInterface.readdir(request);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
...response,
|
|
224
|
+
unique: request.unique,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case "RELEASE": {
|
|
229
|
+
const response = await serverInterface.release(request);
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
...response,
|
|
233
|
+
unique: request.unique,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
case "RELEASEDIR": {
|
|
238
|
+
const response = await serverInterface.releasedir(request);
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
...response,
|
|
242
|
+
unique: request.unique,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
case "FSYNCDIR": {
|
|
247
|
+
const response = await serverInterface.fsyncdir(request);
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
...response,
|
|
251
|
+
unique: request.unique,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
case "STATFS": {
|
|
256
|
+
const response = await serverInterface.statfs(request);
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
...response,
|
|
260
|
+
unique: request.unique,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
case "LOOKUP": {
|
|
265
|
+
const response = await serverInterface.lookup(request);
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
...response,
|
|
269
|
+
unique: request.unique,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
case "OPEN": {
|
|
274
|
+
const response = await serverInterface.open(request);
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
...response,
|
|
278
|
+
unique: request.unique,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
case "READ": {
|
|
283
|
+
const response = await serverInterface.read(request);
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
...response,
|
|
287
|
+
unique: request.unique,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
case "WRITE": {
|
|
292
|
+
const response = await serverInterface.write(request);
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
...response,
|
|
296
|
+
unique: request.unique,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
case "FLUSH": {
|
|
301
|
+
const response = await serverInterface.flush(request);
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
...response,
|
|
305
|
+
unique: request.unique,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
case "FSYNC": {
|
|
310
|
+
const response = await serverInterface.fsync(request);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
...response,
|
|
314
|
+
unique: request.unique,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
case "ACCESS": {
|
|
319
|
+
const response = await serverInterface.access(request);
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
...response,
|
|
323
|
+
unique: request.unique,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case "SETXATTR": {
|
|
328
|
+
const response = await serverInterface.setxattr(request);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
...response,
|
|
332
|
+
unique: request.unique,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
case "REMOVEXATTR": {
|
|
337
|
+
const response = await serverInterface.removexattr(request);
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
...response,
|
|
341
|
+
unique: request.unique,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
case "CREATE": {
|
|
346
|
+
const response = await serverInterface.create(request);
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
...response,
|
|
350
|
+
unique: request.unique,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
case "DESTROY": {
|
|
355
|
+
const response = await serverInterface.destroy(request);
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
...response,
|
|
359
|
+
unique: request.unique,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
case "GETLK": {
|
|
364
|
+
const response = await serverInterface.getlk(request);
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
...response,
|
|
368
|
+
unique: request.unique,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
case "SETLK": {
|
|
373
|
+
const response = await serverInterface.setlk(request);
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
...response,
|
|
377
|
+
unique: request.unique,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
case "SETLKW": {
|
|
382
|
+
const response = await serverInterface.setlkw(request);
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
...response,
|
|
386
|
+
unique: request.unique,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
case "INTERRUPT": {
|
|
391
|
+
await serverInterface.interrupt(request);
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
case "BMAP": {
|
|
396
|
+
const response = await serverInterface.bmap(request);
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
...response,
|
|
400
|
+
unique: request.unique,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
case "IOCTL": {
|
|
405
|
+
const response = await serverInterface.ioctl(request);
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
...response,
|
|
409
|
+
unique: request.unique,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
case "POLL": {
|
|
414
|
+
const response = await serverInterface.poll(request);
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
...response,
|
|
418
|
+
unique: request.unique,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
case "NOTIFY_REPLY": {
|
|
423
|
+
await serverInterface.notifyReply(request);
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
case "FALLOCATE": {
|
|
428
|
+
const response = await serverInterface.fallocate(request);
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
...response,
|
|
432
|
+
unique: request.unique,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
case "READDIRPLUS": {
|
|
437
|
+
const response = await serverInterface.readdirplus(request);
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
...response,
|
|
441
|
+
unique: request.unique,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
default: {
|
|
446
|
+
// @ts-expect-error exhaustive check
|
|
447
|
+
throw Error(`unsupported opcode: ${request.opcode}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
return {
|
|
453
|
+
handleRequest
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
export {
|
|
458
|
+
createConvenienceRequestHandler
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/*export type {
|
|
462
|
+
TFuseServerInterface,
|
|
463
|
+
};*/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type TDirentFileType = "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" | "DT_SOCK" | "DT_UNKNOWN";
|
|
2
|
+
type TDirent = {
|
|
3
|
+
inode: bigint;
|
|
4
|
+
nextOffset: bigint;
|
|
5
|
+
fileType: TDirentFileType;
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
declare const direntsToBuffer: ({ entries, maxLength }: {
|
|
9
|
+
entries: TDirent[];
|
|
10
|
+
maxLength: number;
|
|
11
|
+
}) => Uint8Array;
|
|
12
|
+
export { direntsToBuffer };
|
|
13
|
+
export type { TDirent };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*type TDirentFileType = "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" | "DT_SOCK" | "DT_UNKNOWN";*/
|
|
2
|
+
|
|
3
|
+
/*type TDirent = {
|
|
4
|
+
inode: bigint;
|
|
5
|
+
nextOffset: bigint;
|
|
6
|
+
fileType: TDirentFileType;
|
|
7
|
+
name: string;
|
|
8
|
+
};*/
|
|
9
|
+
|
|
10
|
+
/*type TNativeDirent = {
|
|
11
|
+
inode: bigint;
|
|
12
|
+
nextOffset: bigint;
|
|
13
|
+
fileTypeNative: number;
|
|
14
|
+
encodedName: Uint8Array;
|
|
15
|
+
};*/
|
|
16
|
+
|
|
17
|
+
const align = ({ value, alignment }/*: { value: number; alignment: number }*/)/*: number*/ => {
|
|
18
|
+
const remainder = value % alignment;
|
|
19
|
+
if (remainder === 0) {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return value + (alignment - remainder);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line complexity
|
|
27
|
+
const direntFileTypeToNative = ({ fileType }/*: { fileType: TDirentFileType }*/)/*: number*/ => {
|
|
28
|
+
switch (fileType) {
|
|
29
|
+
case "DT_FIFO": return 1;
|
|
30
|
+
case "DT_CHR": return 2;
|
|
31
|
+
case "DT_DIR": return 4;
|
|
32
|
+
case "DT_BLK": return 6;
|
|
33
|
+
case "DT_REG": return 8;
|
|
34
|
+
case "DT_LNK": return 10;
|
|
35
|
+
case "DT_SOCK": return 12;
|
|
36
|
+
default: return 0;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const determineAlignedDirentRecordLength = ({ nameLength }/*: { nameLength: number }*/)/*: number*/ => {
|
|
41
|
+
const headerLength = 24;
|
|
42
|
+
const recordLength = headerLength + nameLength;
|
|
43
|
+
return align({ value: recordLength, alignment: 8 });
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const textEncoder = new TextEncoder();
|
|
47
|
+
let direntBuffer = new Uint8Array(0);
|
|
48
|
+
|
|
49
|
+
const encodeName = ({ name }/*: { name: string }*/)/*: Uint8Array*/ => {
|
|
50
|
+
if (name.includes("\0")) {
|
|
51
|
+
throw Error("name may not contain null bytes");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (name.includes("/")) {
|
|
55
|
+
throw Error("name may not contain slashes");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return textEncoder.encode(name);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const direntToNative = ({ entry }/*: { entry: TDirent }*/)/*: TNativeDirent*/ => {
|
|
62
|
+
return {
|
|
63
|
+
inode: entry.inode,
|
|
64
|
+
nextOffset: entry.nextOffset,
|
|
65
|
+
fileTypeNative: direntFileTypeToNative({ fileType: entry.fileType }),
|
|
66
|
+
encodedName: encodeName({ name: entry.name })
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// eslint-disable-next-line max-statements
|
|
71
|
+
const direntsToBuffer = ({ entries, maxLength }/*: { entries: TDirent[], maxLength: number }*/)/*: Uint8Array*/ => {
|
|
72
|
+
|
|
73
|
+
if (maxLength > direntBuffer.length) {
|
|
74
|
+
direntBuffer = new Uint8Array(maxLength);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let offset = 0;
|
|
78
|
+
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
|
|
81
|
+
const nativeEntry = direntToNative({ entry });
|
|
82
|
+
|
|
83
|
+
const view = new DataView(direntBuffer.buffer, direntBuffer.byteOffset + offset);
|
|
84
|
+
|
|
85
|
+
const recordLength = determineAlignedDirentRecordLength({ nameLength: nativeEntry.encodedName.length });
|
|
86
|
+
|
|
87
|
+
const newOffset = offset + recordLength;
|
|
88
|
+
|
|
89
|
+
if (newOffset > maxLength) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// struct fuse_dirent {
|
|
94
|
+
|
|
95
|
+
// uint64_t ino
|
|
96
|
+
view.setBigUint64(0, nativeEntry.inode, true);
|
|
97
|
+
|
|
98
|
+
// uint64_t off
|
|
99
|
+
// this is filesystem-interal offset and not used for offset calculation etc.
|
|
100
|
+
// this parameter will be provided by seek / read offset of readdir
|
|
101
|
+
view.setBigUint64(8, nativeEntry.nextOffset, true);
|
|
102
|
+
|
|
103
|
+
// uint32_t namelen
|
|
104
|
+
view.setUint32(16, nativeEntry.encodedName.length, true);
|
|
105
|
+
|
|
106
|
+
// uint32_t type
|
|
107
|
+
view.setUint32(20, nativeEntry.fileTypeNative, true);
|
|
108
|
+
|
|
109
|
+
// char[] name
|
|
110
|
+
direntBuffer.set(nativeEntry.encodedName, offset + 24);
|
|
111
|
+
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
direntBuffer.fill(0, offset + 24 + nativeEntry.encodedName.length, newOffset);
|
|
115
|
+
|
|
116
|
+
offset = newOffset;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return direntBuffer.slice(0, offset);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
direntsToBuffer
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/*export type {
|
|
127
|
+
TDirent
|
|
128
|
+
};*/
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
type TIncomingRequest = {
|
|
2
|
+
header: {
|
|
3
|
+
opcode: bigint;
|
|
4
|
+
unique: bigint;
|
|
5
|
+
nodeid: bigint;
|
|
6
|
+
uid: bigint;
|
|
7
|
+
gid: bigint;
|
|
8
|
+
pid: bigint;
|
|
9
|
+
};
|
|
10
|
+
payload: Uint8Array;
|
|
11
|
+
};
|
|
12
|
+
type TOutgoingResponse = {
|
|
13
|
+
header: {
|
|
14
|
+
error: bigint;
|
|
15
|
+
unique: bigint;
|
|
16
|
+
};
|
|
17
|
+
payload: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
type TTryReadIncomingMessageResult = {
|
|
20
|
+
error: Error;
|
|
21
|
+
incomingMessage: undefined;
|
|
22
|
+
end: undefined;
|
|
23
|
+
} | {
|
|
24
|
+
error: undefined;
|
|
25
|
+
incomingMessage: Uint8Array;
|
|
26
|
+
end: false;
|
|
27
|
+
} | {
|
|
28
|
+
error: undefined;
|
|
29
|
+
incomingMessage: undefined;
|
|
30
|
+
end: false | true;
|
|
31
|
+
};
|
|
32
|
+
declare const createFuseLowLevel: ({ fuseFd, maxMessageSize }: {
|
|
33
|
+
fuseFd: number;
|
|
34
|
+
maxMessageSize: number;
|
|
35
|
+
}) => {
|
|
36
|
+
tryReadIncomingMessage: () => TTryReadIncomingMessageResult;
|
|
37
|
+
writeOutgoingMessage: ({ rawMessage }: {
|
|
38
|
+
rawMessage: Uint8Array;
|
|
39
|
+
}) => void;
|
|
40
|
+
};
|
|
41
|
+
export { createFuseLowLevel };
|
|
42
|
+
export type { TIncomingRequest, TOutgoingResponse };
|