@k13engineering/linux-fuse 0.0.4 → 0.0.5
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 +88 -2
- package/dist/lib/abi.js +270 -0
- package/dist/lib/constants.d.ts +13 -1
- package/dist/lib/constants.js +16 -0
- package/dist/lib/convenience.d.ts +7 -0
- package/dist/lib/convenience.js +70 -0
- package/dist/lib/protocol.d.ts +155 -1
- package/dist/lib/protocol.js +797 -4
- package/package.json +1 -1
package/dist/lib/protocol.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
fuseBatchForgetInParser,
|
|
9
9
|
fuseBmapInParser,
|
|
10
10
|
fuseBmapOutParser,
|
|
11
|
+
fuseCopyFileRangeInParser,
|
|
11
12
|
fuseCreateInParser,
|
|
12
13
|
fuseEntryOutParser,
|
|
13
14
|
fuseFallocateInParser,
|
|
@@ -26,6 +27,8 @@ import {
|
|
|
26
27
|
fuseLinkInParser,
|
|
27
28
|
fuseLkInParser,
|
|
28
29
|
fuseLkOutParser,
|
|
30
|
+
fuseLseekInParser,
|
|
31
|
+
fuseLseekOutParser,
|
|
29
32
|
fuseMkdirInParser,
|
|
30
33
|
fuseMknodInParser,
|
|
31
34
|
fuseOpenInParser,
|
|
@@ -34,11 +37,17 @@ import {
|
|
|
34
37
|
fusePollOutParser,
|
|
35
38
|
fuseReadInParser,
|
|
36
39
|
fuseReleaseInParser,
|
|
40
|
+
fuseRemovemappingInParser,
|
|
41
|
+
fuseRemovemappingOneParser,
|
|
37
42
|
fuseRename2InParser,
|
|
38
43
|
fuseRenameInParser,
|
|
39
44
|
fuseSetattrInParser,
|
|
45
|
+
fuseSetupmappingInParser,
|
|
40
46
|
fuseSetxattrInParser,
|
|
41
47
|
fuseStatfsOutParser,
|
|
48
|
+
fuseStatxInParser,
|
|
49
|
+
fuseStatxOutParser,
|
|
50
|
+
fuseSyncfsInParser,
|
|
42
51
|
fuseWriteInParser,
|
|
43
52
|
fuseWriteOutParser,
|
|
44
53
|
} from "./abi.js";
|
|
@@ -101,6 +110,33 @@ import {
|
|
|
101
110
|
size: bigint;
|
|
102
111
|
};*/
|
|
103
112
|
|
|
113
|
+
/*type TFuseSxTime = {
|
|
114
|
+
sec: bigint;
|
|
115
|
+
nsec: bigint;
|
|
116
|
+
};*/
|
|
117
|
+
|
|
118
|
+
/*type TFuseStatx = {
|
|
119
|
+
mask: bigint;
|
|
120
|
+
blksize: bigint;
|
|
121
|
+
attributes: bigint;
|
|
122
|
+
nlink: bigint;
|
|
123
|
+
uid: bigint;
|
|
124
|
+
gid: bigint;
|
|
125
|
+
mode: bigint;
|
|
126
|
+
ino: bigint;
|
|
127
|
+
size: bigint;
|
|
128
|
+
blocks: bigint;
|
|
129
|
+
attributesMask: bigint;
|
|
130
|
+
atime: TFuseSxTime;
|
|
131
|
+
btime: TFuseSxTime;
|
|
132
|
+
ctime: TFuseSxTime;
|
|
133
|
+
mtime: TFuseSxTime;
|
|
134
|
+
rdevMajor: bigint;
|
|
135
|
+
rdevMinor: bigint;
|
|
136
|
+
devMajor: bigint;
|
|
137
|
+
devMinor: bigint;
|
|
138
|
+
};*/
|
|
139
|
+
|
|
104
140
|
/*type TFuseRequest = {
|
|
105
141
|
unique: bigint;
|
|
106
142
|
requester: TRequesterInfo;
|
|
@@ -353,6 +389,54 @@ import {
|
|
|
353
389
|
readFlags: bigint;
|
|
354
390
|
lockOwner: bigint;
|
|
355
391
|
flags: bigint;
|
|
392
|
+
} | {
|
|
393
|
+
opcode: "LSEEK";
|
|
394
|
+
nodeId: bigint;
|
|
395
|
+
fh: bigint;
|
|
396
|
+
offset: bigint;
|
|
397
|
+
whence: bigint;
|
|
398
|
+
} | {
|
|
399
|
+
opcode: "COPY_FILE_RANGE";
|
|
400
|
+
nodeId: bigint;
|
|
401
|
+
fhIn: bigint;
|
|
402
|
+
offIn: bigint;
|
|
403
|
+
nodeIdOut: bigint;
|
|
404
|
+
fhOut: bigint;
|
|
405
|
+
offOut: bigint;
|
|
406
|
+
len: bigint;
|
|
407
|
+
flags: bigint;
|
|
408
|
+
} | {
|
|
409
|
+
opcode: "SETUPMAPPING";
|
|
410
|
+
nodeId: bigint;
|
|
411
|
+
fh: bigint;
|
|
412
|
+
foffset: bigint;
|
|
413
|
+
len: bigint;
|
|
414
|
+
flags: bigint;
|
|
415
|
+
moffset: bigint;
|
|
416
|
+
} | {
|
|
417
|
+
opcode: "REMOVEMAPPING";
|
|
418
|
+
nodeId: bigint;
|
|
419
|
+
mappings: Array<{
|
|
420
|
+
moffset: bigint;
|
|
421
|
+
len: bigint;
|
|
422
|
+
}>;
|
|
423
|
+
} | {
|
|
424
|
+
opcode: "SYNCFS";
|
|
425
|
+
nodeId: bigint;
|
|
426
|
+
} | {
|
|
427
|
+
opcode: "TMPFILE";
|
|
428
|
+
parentNodeId: bigint;
|
|
429
|
+
name: string;
|
|
430
|
+
flags: bigint;
|
|
431
|
+
mode: bigint;
|
|
432
|
+
umask: bigint;
|
|
433
|
+
} | {
|
|
434
|
+
opcode: "STATX";
|
|
435
|
+
nodeId: bigint;
|
|
436
|
+
getattrFlags: bigint;
|
|
437
|
+
fh: bigint;
|
|
438
|
+
sxFlags: bigint;
|
|
439
|
+
sxMask: bigint;
|
|
356
440
|
});*/
|
|
357
441
|
|
|
358
442
|
|
|
@@ -797,6 +881,87 @@ import {
|
|
|
797
881
|
result: {
|
|
798
882
|
data: Uint8Array;
|
|
799
883
|
};
|
|
884
|
+
} | {
|
|
885
|
+
forOpcode: "LSEEK";
|
|
886
|
+
unique: bigint;
|
|
887
|
+
errorCode: number;
|
|
888
|
+
result: undefined;
|
|
889
|
+
} | {
|
|
890
|
+
forOpcode: "LSEEK";
|
|
891
|
+
unique: bigint;
|
|
892
|
+
errorCode: undefined;
|
|
893
|
+
result: {
|
|
894
|
+
offset: bigint;
|
|
895
|
+
};
|
|
896
|
+
} | {
|
|
897
|
+
forOpcode: "COPY_FILE_RANGE";
|
|
898
|
+
unique: bigint;
|
|
899
|
+
errorCode: number;
|
|
900
|
+
result: undefined;
|
|
901
|
+
} | {
|
|
902
|
+
forOpcode: "COPY_FILE_RANGE";
|
|
903
|
+
unique: bigint;
|
|
904
|
+
errorCode: undefined;
|
|
905
|
+
result: {
|
|
906
|
+
bytesWritten: bigint;
|
|
907
|
+
};
|
|
908
|
+
} | {
|
|
909
|
+
forOpcode: "SETUPMAPPING";
|
|
910
|
+
unique: bigint;
|
|
911
|
+
errorCode: number;
|
|
912
|
+
result: undefined;
|
|
913
|
+
} | {
|
|
914
|
+
forOpcode: "SETUPMAPPING";
|
|
915
|
+
unique: bigint;
|
|
916
|
+
errorCode: undefined;
|
|
917
|
+
result: Record<string, never>;
|
|
918
|
+
} | {
|
|
919
|
+
forOpcode: "REMOVEMAPPING";
|
|
920
|
+
unique: bigint;
|
|
921
|
+
errorCode: number;
|
|
922
|
+
result: undefined;
|
|
923
|
+
} | {
|
|
924
|
+
forOpcode: "REMOVEMAPPING";
|
|
925
|
+
unique: bigint;
|
|
926
|
+
errorCode: undefined;
|
|
927
|
+
result: Record<string, never>;
|
|
928
|
+
} | {
|
|
929
|
+
forOpcode: "SYNCFS";
|
|
930
|
+
unique: bigint;
|
|
931
|
+
errorCode: number;
|
|
932
|
+
result: undefined;
|
|
933
|
+
} | {
|
|
934
|
+
forOpcode: "SYNCFS";
|
|
935
|
+
unique: bigint;
|
|
936
|
+
errorCode: undefined;
|
|
937
|
+
result: Record<string, never>;
|
|
938
|
+
} | {
|
|
939
|
+
forOpcode: "TMPFILE";
|
|
940
|
+
unique: bigint;
|
|
941
|
+
errorCode: number;
|
|
942
|
+
result: undefined;
|
|
943
|
+
} | {
|
|
944
|
+
forOpcode: "TMPFILE";
|
|
945
|
+
unique: bigint;
|
|
946
|
+
errorCode: undefined;
|
|
947
|
+
result: TFuseEntry & {
|
|
948
|
+
fh: bigint;
|
|
949
|
+
openFlagsToKernel: TOpenFlagsToKernel;
|
|
950
|
+
};
|
|
951
|
+
} | {
|
|
952
|
+
forOpcode: "STATX";
|
|
953
|
+
unique: bigint;
|
|
954
|
+
errorCode: number;
|
|
955
|
+
result: undefined;
|
|
956
|
+
} | {
|
|
957
|
+
forOpcode: "STATX";
|
|
958
|
+
unique: bigint;
|
|
959
|
+
errorCode: undefined;
|
|
960
|
+
result: {
|
|
961
|
+
attrValidNsec: bigint;
|
|
962
|
+
flags: bigint;
|
|
963
|
+
stat: TFuseStatx;
|
|
964
|
+
};
|
|
800
965
|
};*/
|
|
801
966
|
|
|
802
967
|
/*type TGenericInterpretResult<T> = {
|
|
@@ -2083,6 +2248,210 @@ const createMessageFromKernelInterpreter = () => {
|
|
|
2083
2248
|
};
|
|
2084
2249
|
};
|
|
2085
2250
|
|
|
2251
|
+
const interpretLseek/*: TInterpretFunc<"LSEEK">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2252
|
+
if (payload.length !== fuseLseekInParser.size) {
|
|
2253
|
+
return {
|
|
2254
|
+
error: Error(
|
|
2255
|
+
`Invalid payload size for LSEEK request. Expected ${fuseLseekInParser.size} bytes, got ${payload.length} bytes.`
|
|
2256
|
+
),
|
|
2257
|
+
interpreted: undefined,
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
const { fh, offset, whence } = fuseLseekInParser.parse({ data: payload });
|
|
2262
|
+
|
|
2263
|
+
return {
|
|
2264
|
+
error: undefined,
|
|
2265
|
+
interpreted: {
|
|
2266
|
+
unique,
|
|
2267
|
+
requester,
|
|
2268
|
+
opcode: "LSEEK",
|
|
2269
|
+
nodeId,
|
|
2270
|
+
fh,
|
|
2271
|
+
offset,
|
|
2272
|
+
whence,
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
};
|
|
2276
|
+
|
|
2277
|
+
const interpretCopyFileRange/*: TInterpretFunc<"COPY_FILE_RANGE">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2278
|
+
if (payload.length !== fuseCopyFileRangeInParser.size) {
|
|
2279
|
+
return {
|
|
2280
|
+
error: Error(
|
|
2281
|
+
`Invalid payload size for COPY_FILE_RANGE request. Expected ${fuseCopyFileRangeInParser.size} bytes, got ${payload.length} bytes.`
|
|
2282
|
+
),
|
|
2283
|
+
interpreted: undefined,
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
const { fh_in, off_in, nodeid_out, fh_out, off_out, len, flags } = fuseCopyFileRangeInParser.parse({ data: payload });
|
|
2288
|
+
|
|
2289
|
+
return {
|
|
2290
|
+
error: undefined,
|
|
2291
|
+
interpreted: {
|
|
2292
|
+
unique,
|
|
2293
|
+
requester,
|
|
2294
|
+
opcode: "COPY_FILE_RANGE",
|
|
2295
|
+
nodeId,
|
|
2296
|
+
fhIn: fh_in,
|
|
2297
|
+
offIn: off_in,
|
|
2298
|
+
nodeIdOut: nodeid_out,
|
|
2299
|
+
fhOut: fh_out,
|
|
2300
|
+
offOut: off_out,
|
|
2301
|
+
len,
|
|
2302
|
+
flags,
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
2305
|
+
};
|
|
2306
|
+
|
|
2307
|
+
const interpretSetupMapping/*: TInterpretFunc<"SETUPMAPPING">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2308
|
+
if (payload.length !== fuseSetupmappingInParser.size) {
|
|
2309
|
+
return {
|
|
2310
|
+
error: Error(
|
|
2311
|
+
`Invalid payload size for SETUPMAPPING request. Expected ${fuseSetupmappingInParser.size} bytes, got ${payload.length} bytes.`
|
|
2312
|
+
),
|
|
2313
|
+
interpreted: undefined,
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
const { fh, foffset, len, flags, moffset } = fuseSetupmappingInParser.parse({ data: payload });
|
|
2318
|
+
|
|
2319
|
+
return {
|
|
2320
|
+
error: undefined,
|
|
2321
|
+
interpreted: {
|
|
2322
|
+
unique,
|
|
2323
|
+
requester,
|
|
2324
|
+
opcode: "SETUPMAPPING",
|
|
2325
|
+
nodeId,
|
|
2326
|
+
fh,
|
|
2327
|
+
foffset,
|
|
2328
|
+
len,
|
|
2329
|
+
flags,
|
|
2330
|
+
moffset,
|
|
2331
|
+
}
|
|
2332
|
+
};
|
|
2333
|
+
};
|
|
2334
|
+
|
|
2335
|
+
const interpretRemoveMapping/*: TInterpretFunc<"REMOVEMAPPING">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2336
|
+
if (payload.length < fuseRemovemappingInParser.size) {
|
|
2337
|
+
return {
|
|
2338
|
+
error: Error(
|
|
2339
|
+
`Invalid payload size for REMOVEMAPPING request. ` +
|
|
2340
|
+
`Expected at least ${fuseRemovemappingInParser.size} bytes, got ${payload.length} bytes.`
|
|
2341
|
+
),
|
|
2342
|
+
interpreted: undefined,
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
const header = fuseRemovemappingInParser.parse({ data: payload.subarray(0, fuseRemovemappingInParser.size) });
|
|
2347
|
+
const count = Number(header.count);
|
|
2348
|
+
const expectedSize = fuseRemovemappingInParser.size + (count * fuseRemovemappingOneParser.size);
|
|
2349
|
+
if (payload.length !== expectedSize) {
|
|
2350
|
+
return {
|
|
2351
|
+
error: Error(
|
|
2352
|
+
`Invalid payload size for REMOVEMAPPING request. Expected ${expectedSize} bytes, got ${payload.length} bytes.`
|
|
2353
|
+
),
|
|
2354
|
+
interpreted: undefined,
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
let mappings/*: Array<{ moffset: bigint; len: bigint }>*/ = [];
|
|
2359
|
+
for (let index = 0; index < count; index += 1) {
|
|
2360
|
+
const start = fuseRemovemappingInParser.size + (index * fuseRemovemappingOneParser.size);
|
|
2361
|
+
const parsed = fuseRemovemappingOneParser.parse({ data: payload.subarray(start, start + fuseRemovemappingOneParser.size) });
|
|
2362
|
+
mappings = [...mappings, {
|
|
2363
|
+
moffset: parsed.moffset,
|
|
2364
|
+
len: parsed.len,
|
|
2365
|
+
}];
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
return {
|
|
2369
|
+
error: undefined,
|
|
2370
|
+
interpreted: {
|
|
2371
|
+
unique,
|
|
2372
|
+
requester,
|
|
2373
|
+
opcode: "REMOVEMAPPING",
|
|
2374
|
+
nodeId,
|
|
2375
|
+
mappings,
|
|
2376
|
+
}
|
|
2377
|
+
};
|
|
2378
|
+
};
|
|
2379
|
+
|
|
2380
|
+
const interpretSyncFs/*: TInterpretFunc<"SYNCFS">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2381
|
+
if (payload.length !== fuseSyncfsInParser.size) {
|
|
2382
|
+
return {
|
|
2383
|
+
error: Error(
|
|
2384
|
+
`Invalid payload size for SYNCFS request. Expected ${fuseSyncfsInParser.size} bytes, got ${payload.length} bytes.`
|
|
2385
|
+
),
|
|
2386
|
+
interpreted: undefined,
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
return {
|
|
2391
|
+
error: undefined,
|
|
2392
|
+
interpreted: {
|
|
2393
|
+
unique,
|
|
2394
|
+
requester,
|
|
2395
|
+
opcode: "SYNCFS",
|
|
2396
|
+
nodeId,
|
|
2397
|
+
}
|
|
2398
|
+
};
|
|
2399
|
+
};
|
|
2400
|
+
|
|
2401
|
+
const interpretTmpFile/*: TInterpretFunc<"TMPFILE">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2402
|
+
if (payload.length < fuseCreateInParser.size) {
|
|
2403
|
+
return {
|
|
2404
|
+
error: Error(
|
|
2405
|
+
`Invalid payload size for TMPFILE request. Expected at least ${fuseCreateInParser.size} bytes, got ${payload.length} bytes.`
|
|
2406
|
+
),
|
|
2407
|
+
interpreted: undefined,
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
const { flags, mode, umask } = fuseCreateInParser.parse({ data: payload.subarray(0, fuseCreateInParser.size) });
|
|
2412
|
+
|
|
2413
|
+
return {
|
|
2414
|
+
error: undefined,
|
|
2415
|
+
interpreted: {
|
|
2416
|
+
unique,
|
|
2417
|
+
requester,
|
|
2418
|
+
opcode: "TMPFILE",
|
|
2419
|
+
parentNodeId: nodeId,
|
|
2420
|
+
name: decodeCString(payload.subarray(fuseCreateInParser.size)),
|
|
2421
|
+
flags,
|
|
2422
|
+
mode,
|
|
2423
|
+
umask,
|
|
2424
|
+
}
|
|
2425
|
+
};
|
|
2426
|
+
};
|
|
2427
|
+
|
|
2428
|
+
const interpretStatx/*: TInterpretFunc<"STATX">*/ = ({ unique, nodeId, requester, payload }) => {
|
|
2429
|
+
if (payload.length !== fuseStatxInParser.size) {
|
|
2430
|
+
return {
|
|
2431
|
+
error: Error(
|
|
2432
|
+
`Invalid payload size for STATX request. Expected ${fuseStatxInParser.size} bytes, got ${payload.length} bytes.`
|
|
2433
|
+
),
|
|
2434
|
+
interpreted: undefined,
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
const { getattr_flags, fh, sx_flags, sx_mask } = fuseStatxInParser.parse({ data: payload });
|
|
2439
|
+
|
|
2440
|
+
return {
|
|
2441
|
+
error: undefined,
|
|
2442
|
+
interpreted: {
|
|
2443
|
+
unique,
|
|
2444
|
+
requester,
|
|
2445
|
+
opcode: "STATX",
|
|
2446
|
+
nodeId,
|
|
2447
|
+
getattrFlags: getattr_flags,
|
|
2448
|
+
fh,
|
|
2449
|
+
sxFlags: sx_flags,
|
|
2450
|
+
sxMask: sx_mask,
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2453
|
+
};
|
|
2454
|
+
|
|
2086
2455
|
const interpretMessageFromKernel = (
|
|
2087
2456
|
{ parsedMessageFromKernel }/*: { parsedMessageFromKernel: TParsedMessageFromKernel }*/
|
|
2088
2457
|
)/*: TGenericInterpretResult<TFuseRequest>*/ => {
|
|
@@ -2490,10 +2859,73 @@ const createMessageFromKernelInterpreter = () => {
|
|
|
2490
2859
|
});
|
|
2491
2860
|
}
|
|
2492
2861
|
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2862
|
+
case BigInt(opcode.LSEEK): {
|
|
2863
|
+
return interpretLseek({
|
|
2864
|
+
unique,
|
|
2865
|
+
nodeId,
|
|
2866
|
+
requester,
|
|
2867
|
+
payload: parsedMessageFromKernel.payload,
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
case BigInt(opcode.COPY_FILE_RANGE): {
|
|
2872
|
+
return interpretCopyFileRange({
|
|
2873
|
+
unique,
|
|
2874
|
+
nodeId,
|
|
2875
|
+
requester,
|
|
2876
|
+
payload: parsedMessageFromKernel.payload,
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
case BigInt(opcode.SETUPMAPPING): {
|
|
2881
|
+
return interpretSetupMapping({
|
|
2882
|
+
unique,
|
|
2883
|
+
nodeId,
|
|
2884
|
+
requester,
|
|
2885
|
+
payload: parsedMessageFromKernel.payload,
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
case BigInt(opcode.REMOVEMAPPING): {
|
|
2890
|
+
return interpretRemoveMapping({
|
|
2891
|
+
unique,
|
|
2892
|
+
nodeId,
|
|
2893
|
+
requester,
|
|
2894
|
+
payload: parsedMessageFromKernel.payload,
|
|
2895
|
+
});
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
case BigInt(opcode.SYNCFS): {
|
|
2899
|
+
return interpretSyncFs({
|
|
2900
|
+
unique,
|
|
2901
|
+
nodeId,
|
|
2902
|
+
requester,
|
|
2903
|
+
payload: parsedMessageFromKernel.payload,
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
case BigInt(opcode.TMPFILE): {
|
|
2908
|
+
return interpretTmpFile({
|
|
2909
|
+
unique,
|
|
2910
|
+
nodeId,
|
|
2911
|
+
requester,
|
|
2912
|
+
payload: parsedMessageFromKernel.payload,
|
|
2913
|
+
});
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
case BigInt(opcode.STATX): {
|
|
2917
|
+
return interpretStatx({
|
|
2918
|
+
unique,
|
|
2919
|
+
nodeId,
|
|
2920
|
+
requester,
|
|
2921
|
+
payload: parsedMessageFromKernel.payload,
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
default: {
|
|
2926
|
+
break;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2497
2929
|
|
|
2498
2930
|
return {
|
|
2499
2931
|
error: Error(`Unsupported opcode: ${parsedMessageFromKernel.header.opcode}`),
|
|
@@ -2921,6 +3353,144 @@ const createMessageToKernelInterpreter = () => {
|
|
|
2921
3353
|
};
|
|
2922
3354
|
};
|
|
2923
3355
|
|
|
3356
|
+
const encodeLseekResponse = (
|
|
3357
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "LSEEK", errorCode: undefined }> }*/
|
|
3358
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3359
|
+
const payload = fuseLseekOutParser.format({
|
|
3360
|
+
value: {
|
|
3361
|
+
offset: response.result.offset,
|
|
3362
|
+
}
|
|
3363
|
+
});
|
|
3364
|
+
|
|
3365
|
+
return {
|
|
3366
|
+
header: {
|
|
3367
|
+
unique: response.unique,
|
|
3368
|
+
error: 0n,
|
|
3369
|
+
},
|
|
3370
|
+
payload,
|
|
3371
|
+
};
|
|
3372
|
+
};
|
|
3373
|
+
|
|
3374
|
+
const encodeCopyFileRangeResponse = (
|
|
3375
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "COPY_FILE_RANGE", errorCode: undefined }> }*/
|
|
3376
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3377
|
+
const payload = fuseWriteOutParser.format({
|
|
3378
|
+
value: {
|
|
3379
|
+
size: response.result.bytesWritten,
|
|
3380
|
+
padding: 0n,
|
|
3381
|
+
}
|
|
3382
|
+
});
|
|
3383
|
+
|
|
3384
|
+
return {
|
|
3385
|
+
header: {
|
|
3386
|
+
unique: response.unique,
|
|
3387
|
+
error: 0n,
|
|
3388
|
+
},
|
|
3389
|
+
payload,
|
|
3390
|
+
};
|
|
3391
|
+
};
|
|
3392
|
+
|
|
3393
|
+
const encodeSetupMappingResponse = (
|
|
3394
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "SETUPMAPPING", errorCode: undefined }> }*/
|
|
3395
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3396
|
+
return encodeEmptyPayload({ unique: response.unique });
|
|
3397
|
+
};
|
|
3398
|
+
|
|
3399
|
+
const encodeRemoveMappingResponse = (
|
|
3400
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "REMOVEMAPPING", errorCode: undefined }> }*/
|
|
3401
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3402
|
+
return encodeEmptyPayload({ unique: response.unique });
|
|
3403
|
+
};
|
|
3404
|
+
|
|
3405
|
+
const encodeSyncFsResponse = (
|
|
3406
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "SYNCFS", errorCode: undefined }> }*/
|
|
3407
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3408
|
+
return encodeEmptyPayload({ unique: response.unique });
|
|
3409
|
+
};
|
|
3410
|
+
|
|
3411
|
+
const encodeTmpFileResponse = (
|
|
3412
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "TMPFILE", errorCode: undefined }> }*/
|
|
3413
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3414
|
+
const entryPayload = fuseEntryOutParser.format({
|
|
3415
|
+
value: {
|
|
3416
|
+
nodeid: response.result.nodeId,
|
|
3417
|
+
generation: response.result.generation,
|
|
3418
|
+
entry_valid: response.result.entryValidNsec / 1_000_000_000n,
|
|
3419
|
+
attr_valid: response.result.attrValidNsec / 1_000_000_000n,
|
|
3420
|
+
entry_valid_nsec: response.result.entryValidNsec % 1_000_000_000n,
|
|
3421
|
+
attr_valid_nsec: response.result.attrValidNsec % 1_000_000_000n,
|
|
3422
|
+
attr: fuseAttrToPayloadValue({ attr: response.result.attr }),
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
3425
|
+
const openPayload = fuseOpenOutParser.format({
|
|
3426
|
+
value: {
|
|
3427
|
+
fh: response.result.fh,
|
|
3428
|
+
open_flags: openFlagsToKernelToBitmask({ openFlagsToKernel: response.result.openFlagsToKernel }),
|
|
3429
|
+
backing_id: 0n,
|
|
3430
|
+
}
|
|
3431
|
+
});
|
|
3432
|
+
|
|
3433
|
+
const payload = new Uint8Array(entryPayload.length + openPayload.length);
|
|
3434
|
+
payload.set(entryPayload, 0);
|
|
3435
|
+
payload.set(openPayload, entryPayload.length);
|
|
3436
|
+
|
|
3437
|
+
return {
|
|
3438
|
+
header: {
|
|
3439
|
+
unique: response.unique,
|
|
3440
|
+
error: 0n,
|
|
3441
|
+
},
|
|
3442
|
+
payload,
|
|
3443
|
+
};
|
|
3444
|
+
};
|
|
3445
|
+
|
|
3446
|
+
const fuseStatxToPayloadValue = ({ stat }/*: { stat: TFuseStatx }*/) => {
|
|
3447
|
+
return {
|
|
3448
|
+
mask: stat.mask,
|
|
3449
|
+
blksize: stat.blksize,
|
|
3450
|
+
attributes: stat.attributes,
|
|
3451
|
+
nlink: stat.nlink,
|
|
3452
|
+
uid: stat.uid,
|
|
3453
|
+
gid: stat.gid,
|
|
3454
|
+
mode: stat.mode,
|
|
3455
|
+
__spare0: [0n],
|
|
3456
|
+
ino: stat.ino,
|
|
3457
|
+
size: stat.size,
|
|
3458
|
+
blocks: stat.blocks,
|
|
3459
|
+
attributes_mask: stat.attributesMask,
|
|
3460
|
+
atime: { tv_sec: stat.atime.sec, tv_nsec: stat.atime.nsec, __reserved: 0n },
|
|
3461
|
+
btime: { tv_sec: stat.btime.sec, tv_nsec: stat.btime.nsec, __reserved: 0n },
|
|
3462
|
+
ctime: { tv_sec: stat.ctime.sec, tv_nsec: stat.ctime.nsec, __reserved: 0n },
|
|
3463
|
+
mtime: { tv_sec: stat.mtime.sec, tv_nsec: stat.mtime.nsec, __reserved: 0n },
|
|
3464
|
+
rdev_major: stat.rdevMajor,
|
|
3465
|
+
rdev_minor: stat.rdevMinor,
|
|
3466
|
+
dev_major: stat.devMajor,
|
|
3467
|
+
dev_minor: stat.devMinor,
|
|
3468
|
+
__spare2: [0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n],
|
|
3469
|
+
};
|
|
3470
|
+
};
|
|
3471
|
+
|
|
3472
|
+
const encodeStatxResponse = (
|
|
3473
|
+
{ response }/*: { response: Extract<TFuseResponse, { forOpcode: "STATX", errorCode: undefined }> }*/
|
|
3474
|
+
)/*: TParsedMessageToKernel*/ => {
|
|
3475
|
+
const payload = fuseStatxOutParser.format({
|
|
3476
|
+
value: {
|
|
3477
|
+
attr_valid: response.result.attrValidNsec / 1_000_000_000n,
|
|
3478
|
+
attr_valid_nsec: response.result.attrValidNsec % 1_000_000_000n,
|
|
3479
|
+
flags: response.result.flags,
|
|
3480
|
+
spare: [0n, 0n],
|
|
3481
|
+
stat: fuseStatxToPayloadValue({ stat: response.result.stat }),
|
|
3482
|
+
}
|
|
3483
|
+
});
|
|
3484
|
+
|
|
3485
|
+
return {
|
|
3486
|
+
header: {
|
|
3487
|
+
unique: response.unique,
|
|
3488
|
+
error: 0n,
|
|
3489
|
+
},
|
|
3490
|
+
payload,
|
|
3491
|
+
};
|
|
3492
|
+
};
|
|
3493
|
+
|
|
2924
3494
|
const encodeMessageToKernel = ({ response }/*: { response: TFuseResponse }*/)/*: TParsedMessageToKernel*/ => {
|
|
2925
3495
|
|
|
2926
3496
|
if (response.errorCode !== undefined) {
|
|
@@ -3091,6 +3661,34 @@ const createMessageToKernelInterpreter = () => {
|
|
|
3091
3661
|
return encodeReadDirPlusResponse({ response });
|
|
3092
3662
|
}
|
|
3093
3663
|
|
|
3664
|
+
case "LSEEK": {
|
|
3665
|
+
return encodeLseekResponse({ response });
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
case "COPY_FILE_RANGE": {
|
|
3669
|
+
return encodeCopyFileRangeResponse({ response });
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
case "SETUPMAPPING": {
|
|
3673
|
+
return encodeSetupMappingResponse({ response });
|
|
3674
|
+
}
|
|
3675
|
+
|
|
3676
|
+
case "REMOVEMAPPING": {
|
|
3677
|
+
return encodeRemoveMappingResponse({ response });
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
case "SYNCFS": {
|
|
3681
|
+
return encodeSyncFsResponse({ response });
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
case "TMPFILE": {
|
|
3685
|
+
return encodeTmpFileResponse({ response });
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
case "STATX": {
|
|
3689
|
+
return encodeStatxResponse({ response });
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3094
3692
|
default: {
|
|
3095
3693
|
// @ts-expect-error exhaustiveness check
|
|
3096
3694
|
throw Error(`Unsupported opcode: ${response.forOpcode}`);
|
|
@@ -3454,6 +4052,150 @@ const createMessageToKernelInterpreter = () => {
|
|
|
3454
4052
|
};
|
|
3455
4053
|
};
|
|
3456
4054
|
|
|
4055
|
+
const interpretLseekResponse/*: TInterpretFunc<"LSEEK">*/ = ({ unique, payload }) => {
|
|
4056
|
+
if (payload.length !== fuseLseekOutParser.size) {
|
|
4057
|
+
return {
|
|
4058
|
+
error: Error(
|
|
4059
|
+
`Invalid payload size for LSEEK response. Expected ${fuseLseekOutParser.size} bytes, got ${payload.length} bytes.`
|
|
4060
|
+
),
|
|
4061
|
+
interpreted: undefined,
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
|
|
4065
|
+
const parsed = fuseLseekOutParser.parse({ data: payload });
|
|
4066
|
+
|
|
4067
|
+
return {
|
|
4068
|
+
error: undefined,
|
|
4069
|
+
interpreted: {
|
|
4070
|
+
forOpcode: "LSEEK",
|
|
4071
|
+
unique,
|
|
4072
|
+
errorCode: undefined,
|
|
4073
|
+
result: {
|
|
4074
|
+
offset: parsed.offset,
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
};
|
|
4078
|
+
};
|
|
4079
|
+
|
|
4080
|
+
const interpretCopyFileRangeResponse/*: TInterpretFunc<"COPY_FILE_RANGE">*/ = ({ unique, payload }) => {
|
|
4081
|
+
if (payload.length !== fuseWriteOutParser.size) {
|
|
4082
|
+
return {
|
|
4083
|
+
error: Error(
|
|
4084
|
+
`Invalid payload size for COPY_FILE_RANGE response. Expected ${fuseWriteOutParser.size} bytes, got ${payload.length} bytes.`
|
|
4085
|
+
),
|
|
4086
|
+
interpreted: undefined,
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
const parsed = fuseWriteOutParser.parse({ data: payload });
|
|
4091
|
+
|
|
4092
|
+
return {
|
|
4093
|
+
error: undefined,
|
|
4094
|
+
interpreted: {
|
|
4095
|
+
forOpcode: "COPY_FILE_RANGE",
|
|
4096
|
+
unique,
|
|
4097
|
+
errorCode: undefined,
|
|
4098
|
+
result: {
|
|
4099
|
+
bytesWritten: parsed.size,
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
};
|
|
4103
|
+
};
|
|
4104
|
+
|
|
4105
|
+
const interpretSetupMappingResponse/*: TInterpretFunc<"SETUPMAPPING">*/ = ({ unique }) => {
|
|
4106
|
+
return interpretEmptyPayload({ unique, forOpcode: "SETUPMAPPING" });
|
|
4107
|
+
};
|
|
4108
|
+
|
|
4109
|
+
const interpretRemoveMappingResponse/*: TInterpretFunc<"REMOVEMAPPING">*/ = ({ unique }) => {
|
|
4110
|
+
return interpretEmptyPayload({ unique, forOpcode: "REMOVEMAPPING" });
|
|
4111
|
+
};
|
|
4112
|
+
|
|
4113
|
+
const interpretSyncFsResponse/*: TInterpretFunc<"SYNCFS">*/ = ({ unique }) => {
|
|
4114
|
+
return interpretEmptyPayload({ unique, forOpcode: "SYNCFS" });
|
|
4115
|
+
};
|
|
4116
|
+
|
|
4117
|
+
const interpretTmpFileResponse/*: TInterpretFunc<"TMPFILE">*/ = ({ unique, payload }) => {
|
|
4118
|
+
const expectedSize = fuseEntryOutParser.size + fuseOpenOutParser.size;
|
|
4119
|
+
if (payload.length !== expectedSize) {
|
|
4120
|
+
return {
|
|
4121
|
+
error: Error(`Invalid payload size for TMPFILE response. Expected ${expectedSize} bytes, got ${payload.length} bytes.`),
|
|
4122
|
+
interpreted: undefined,
|
|
4123
|
+
};
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4126
|
+
const entry = fuseEntryOutParser.parse({ data: payload.subarray(0, fuseEntryOutParser.size) });
|
|
4127
|
+
const open = fuseOpenOutParser.parse({ data: payload.subarray(fuseEntryOutParser.size) });
|
|
4128
|
+
|
|
4129
|
+
return {
|
|
4130
|
+
error: undefined,
|
|
4131
|
+
interpreted: {
|
|
4132
|
+
forOpcode: "TMPFILE",
|
|
4133
|
+
unique,
|
|
4134
|
+
errorCode: undefined,
|
|
4135
|
+
result: {
|
|
4136
|
+
nodeId: entry.nodeid,
|
|
4137
|
+
generation: entry.generation,
|
|
4138
|
+
entryValidNsec: entry.entry_valid * 1_000_000_000n + entry.entry_valid_nsec,
|
|
4139
|
+
attrValidNsec: entry.attr_valid * 1_000_000_000n + entry.attr_valid_nsec,
|
|
4140
|
+
attr: payloadValueToFuseAttr({ attr: entry.attr }),
|
|
4141
|
+
fh: open.fh,
|
|
4142
|
+
openFlagsToKernel: openFlagsToKernelFromBitmask({ bitmask: open.open_flags }),
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
};
|
|
4146
|
+
};
|
|
4147
|
+
|
|
4148
|
+
const payloadValueToFuseStatx = ({ stat }/*: { stat: ReturnType<typeof fuseStatxOutParser.parse>["stat"] }*/)/*: TFuseStatx*/ => {
|
|
4149
|
+
return {
|
|
4150
|
+
mask: stat.mask,
|
|
4151
|
+
blksize: stat.blksize,
|
|
4152
|
+
attributes: stat.attributes,
|
|
4153
|
+
nlink: stat.nlink,
|
|
4154
|
+
uid: stat.uid,
|
|
4155
|
+
gid: stat.gid,
|
|
4156
|
+
mode: stat.mode,
|
|
4157
|
+
ino: stat.ino,
|
|
4158
|
+
size: stat.size,
|
|
4159
|
+
blocks: stat.blocks,
|
|
4160
|
+
attributesMask: stat.attributes_mask,
|
|
4161
|
+
atime: { sec: stat.atime.tv_sec, nsec: stat.atime.tv_nsec },
|
|
4162
|
+
btime: { sec: stat.btime.tv_sec, nsec: stat.btime.tv_nsec },
|
|
4163
|
+
ctime: { sec: stat.ctime.tv_sec, nsec: stat.ctime.tv_nsec },
|
|
4164
|
+
mtime: { sec: stat.mtime.tv_sec, nsec: stat.mtime.tv_nsec },
|
|
4165
|
+
rdevMajor: stat.rdev_major,
|
|
4166
|
+
rdevMinor: stat.rdev_minor,
|
|
4167
|
+
devMajor: stat.dev_major,
|
|
4168
|
+
devMinor: stat.dev_minor,
|
|
4169
|
+
};
|
|
4170
|
+
};
|
|
4171
|
+
|
|
4172
|
+
const interpretStatxResponse/*: TInterpretFunc<"STATX">*/ = ({ unique, payload }) => {
|
|
4173
|
+
if (payload.length !== fuseStatxOutParser.size) {
|
|
4174
|
+
return {
|
|
4175
|
+
error: Error(
|
|
4176
|
+
`Invalid payload size for STATX response. Expected ${fuseStatxOutParser.size} bytes, got ${payload.length} bytes.`
|
|
4177
|
+
),
|
|
4178
|
+
interpreted: undefined,
|
|
4179
|
+
};
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
const parsed = fuseStatxOutParser.parse({ data: payload });
|
|
4183
|
+
|
|
4184
|
+
return {
|
|
4185
|
+
error: undefined,
|
|
4186
|
+
interpreted: {
|
|
4187
|
+
forOpcode: "STATX",
|
|
4188
|
+
unique,
|
|
4189
|
+
errorCode: undefined,
|
|
4190
|
+
result: {
|
|
4191
|
+
attrValidNsec: parsed.attr_valid * 1_000_000_000n + parsed.attr_valid_nsec,
|
|
4192
|
+
flags: parsed.flags,
|
|
4193
|
+
stat: payloadValueToFuseStatx({ stat: parsed.stat }),
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
};
|
|
4197
|
+
};
|
|
4198
|
+
|
|
3457
4199
|
const interpretStatFsResponse/*: TInterpretFunc<"STATFS">*/ = ({ unique, payload }) => {
|
|
3458
4200
|
if (payload.length !== fuseStatfsOutParser.size) {
|
|
3459
4201
|
return {
|
|
@@ -3774,6 +4516,55 @@ const createMessageToKernelInterpreter = () => {
|
|
|
3774
4516
|
});
|
|
3775
4517
|
}
|
|
3776
4518
|
|
|
4519
|
+
case "LSEEK": {
|
|
4520
|
+
return interpretLseekResponse({
|
|
4521
|
+
unique,
|
|
4522
|
+
payload: parsedMessageToKernel.payload,
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
|
|
4526
|
+
case "COPY_FILE_RANGE": {
|
|
4527
|
+
return interpretCopyFileRangeResponse({
|
|
4528
|
+
unique,
|
|
4529
|
+
payload: parsedMessageToKernel.payload,
|
|
4530
|
+
});
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
case "SETUPMAPPING": {
|
|
4534
|
+
return interpretSetupMappingResponse({
|
|
4535
|
+
unique,
|
|
4536
|
+
payload: parsedMessageToKernel.payload,
|
|
4537
|
+
});
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
case "REMOVEMAPPING": {
|
|
4541
|
+
return interpretRemoveMappingResponse({
|
|
4542
|
+
unique,
|
|
4543
|
+
payload: parsedMessageToKernel.payload,
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
case "SYNCFS": {
|
|
4548
|
+
return interpretSyncFsResponse({
|
|
4549
|
+
unique,
|
|
4550
|
+
payload: parsedMessageToKernel.payload,
|
|
4551
|
+
});
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
case "TMPFILE": {
|
|
4555
|
+
return interpretTmpFileResponse({
|
|
4556
|
+
unique,
|
|
4557
|
+
payload: parsedMessageToKernel.payload,
|
|
4558
|
+
});
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4561
|
+
case "STATX": {
|
|
4562
|
+
return interpretStatxResponse({
|
|
4563
|
+
unique,
|
|
4564
|
+
payload: parsedMessageToKernel.payload,
|
|
4565
|
+
});
|
|
4566
|
+
}
|
|
4567
|
+
|
|
3777
4568
|
default: {
|
|
3778
4569
|
throw Error(`unsupported opcode for interpretation: ${forOpcode}`);
|
|
3779
4570
|
}
|
|
@@ -3794,4 +4585,6 @@ export {
|
|
|
3794
4585
|
/*export type {
|
|
3795
4586
|
TFuseRequest,
|
|
3796
4587
|
TFuseResponse,
|
|
4588
|
+
TFuseStatx,
|
|
4589
|
+
TFuseSxTime,
|
|
3797
4590
|
};*/
|