@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.
@@ -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
- default: {
2494
- break;
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
  };*/