@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,177 @@
|
|
|
1
|
+
import { fuseInHeaderParser, fuseOutHeaderParser } from "./abi.js";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/*type TParsedMessageFromKernel = {
|
|
5
|
+
header: {
|
|
6
|
+
opcode: bigint;
|
|
7
|
+
unique: bigint;
|
|
8
|
+
nodeid: bigint;
|
|
9
|
+
uid: bigint;
|
|
10
|
+
gid: bigint;
|
|
11
|
+
pid: bigint;
|
|
12
|
+
},
|
|
13
|
+
payload: Uint8Array
|
|
14
|
+
};*/
|
|
15
|
+
|
|
16
|
+
/*type TParsedMessageToKernel = {
|
|
17
|
+
header: {
|
|
18
|
+
error: bigint;
|
|
19
|
+
unique: bigint;
|
|
20
|
+
},
|
|
21
|
+
payload: Uint8Array
|
|
22
|
+
};*/
|
|
23
|
+
|
|
24
|
+
/*type TParseMessageFromKernelResult = {
|
|
25
|
+
error: Error;
|
|
26
|
+
parsedMessageFromKernel: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
error: undefined;
|
|
29
|
+
parsedMessageFromKernel: TParsedMessageFromKernel;
|
|
30
|
+
};*/
|
|
31
|
+
|
|
32
|
+
/*type TParseMessageToKernelResult = {
|
|
33
|
+
error: Error;
|
|
34
|
+
parsedMessageToKernel: undefined;
|
|
35
|
+
} | {
|
|
36
|
+
error: undefined;
|
|
37
|
+
parsedMessageToKernel: TParsedMessageToKernel;
|
|
38
|
+
};*/
|
|
39
|
+
|
|
40
|
+
const createMessageFromKernelParser = () => {
|
|
41
|
+
|
|
42
|
+
const parseMessageFromKernel = ({ data }/*: { data: Uint8Array }*/)/*: TParseMessageFromKernelResult*/ => {
|
|
43
|
+
|
|
44
|
+
const inHeader = data.subarray(0, fuseInHeaderParser.size);
|
|
45
|
+
if (inHeader.length < fuseInHeaderParser.size) {
|
|
46
|
+
return {
|
|
47
|
+
error: Error(`invalid message: expected at least ${fuseInHeaderParser.size} bytes for header, got ${inHeader.length} bytes`),
|
|
48
|
+
parsedMessageFromKernel: undefined,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const parsedInHeader = fuseInHeaderParser.parse({
|
|
53
|
+
data: inHeader
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const length = Number(parsedInHeader.len);
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if (data.length !== length) {
|
|
60
|
+
return {
|
|
61
|
+
error: Error(`invalid message length: expected ${length} bytes, got ${data.length} bytes`),
|
|
62
|
+
parsedMessageFromKernel: undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const payload = data.slice(fuseInHeaderParser.size, length);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
error: undefined,
|
|
70
|
+
parsedMessageFromKernel: {
|
|
71
|
+
header: {
|
|
72
|
+
opcode: parsedInHeader.opcode,
|
|
73
|
+
unique: parsedInHeader.unique,
|
|
74
|
+
nodeid: parsedInHeader.nodeid,
|
|
75
|
+
uid: parsedInHeader.uid,
|
|
76
|
+
gid: parsedInHeader.gid,
|
|
77
|
+
pid: parsedInHeader.pid,
|
|
78
|
+
},
|
|
79
|
+
payload
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const formatMessageFromKernel = ({ parsedMessageFromKernel }/*: { parsedMessageFromKernel: TParsedMessageFromKernel }*/)/*: Uint8Array*/ => {
|
|
85
|
+
const messageBuffer = new Uint8Array(fuseInHeaderParser.size + parsedMessageFromKernel.payload.length);
|
|
86
|
+
|
|
87
|
+
const formattedHeader = fuseInHeaderParser.format({
|
|
88
|
+
value: {
|
|
89
|
+
opcode: parsedMessageFromKernel.header.opcode,
|
|
90
|
+
unique: parsedMessageFromKernel.header.unique,
|
|
91
|
+
nodeid: parsedMessageFromKernel.header.nodeid,
|
|
92
|
+
uid: parsedMessageFromKernel.header.uid,
|
|
93
|
+
gid: parsedMessageFromKernel.header.gid,
|
|
94
|
+
pid: parsedMessageFromKernel.header.pid,
|
|
95
|
+
len: BigInt(messageBuffer.length),
|
|
96
|
+
// TODO: what is this
|
|
97
|
+
total_extlen: 0n,
|
|
98
|
+
padding: 0n,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
messageBuffer.set(formattedHeader, 0);
|
|
103
|
+
messageBuffer.set(parsedMessageFromKernel.payload, formattedHeader.length);
|
|
104
|
+
|
|
105
|
+
return messageBuffer;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
parseMessageFromKernel,
|
|
110
|
+
formatMessageFromKernel
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const createMessageToKernelParser = () => {
|
|
115
|
+
|
|
116
|
+
const formatMessageToKernel = ({ parsedMessageToKernel }/*: { parsedMessageToKernel: TParsedMessageToKernel }*/)/*: Uint8Array*/ => {
|
|
117
|
+
const messageBuffer = new Uint8Array(fuseOutHeaderParser.size + parsedMessageToKernel.payload.length);
|
|
118
|
+
|
|
119
|
+
const formattedHeader = fuseOutHeaderParser.format({
|
|
120
|
+
value: {
|
|
121
|
+
error: parsedMessageToKernel.header.error,
|
|
122
|
+
unique: parsedMessageToKernel.header.unique,
|
|
123
|
+
len: BigInt(messageBuffer.length),
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
messageBuffer.set(formattedHeader, 0);
|
|
128
|
+
messageBuffer.set(parsedMessageToKernel.payload, formattedHeader.length);
|
|
129
|
+
|
|
130
|
+
return messageBuffer;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const parseMessageToKernel = ({ data }/*: { data: Uint8Array }*/)/*: TParseMessageToKernelResult*/ => {
|
|
134
|
+
const outHeader = data.subarray(0, fuseOutHeaderParser.size);
|
|
135
|
+
|
|
136
|
+
const parsedOutHeader = fuseOutHeaderParser.parse({
|
|
137
|
+
data: outHeader
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const length = Number(parsedOutHeader.len);
|
|
141
|
+
|
|
142
|
+
if (data.length !== length) {
|
|
143
|
+
return {
|
|
144
|
+
error: Error(`invalid message length: expected ${length} bytes, got ${data.length} bytes`),
|
|
145
|
+
parsedMessageToKernel: undefined,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const payload = data.slice(fuseOutHeaderParser.size, length);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
error: undefined,
|
|
153
|
+
parsedMessageToKernel: {
|
|
154
|
+
header: {
|
|
155
|
+
error: parsedOutHeader.error,
|
|
156
|
+
unique: parsedOutHeader.unique,
|
|
157
|
+
},
|
|
158
|
+
payload
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
formatMessageToKernel,
|
|
165
|
+
parseMessageToKernel
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
createMessageFromKernelParser,
|
|
171
|
+
createMessageToKernelParser
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/*export type {
|
|
175
|
+
TParsedMessageFromKernel,
|
|
176
|
+
TParsedMessageToKernel
|
|
177
|
+
};*/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type TRequiredFuseMountOptions = {
|
|
2
|
+
rootmode: number;
|
|
3
|
+
user_id: number;
|
|
4
|
+
group_id: number;
|
|
5
|
+
};
|
|
6
|
+
type TMountAttributes = {
|
|
7
|
+
MOUNT_ATTR_RDONLY?: boolean;
|
|
8
|
+
MOUNT_ATTR_NOSUID?: boolean;
|
|
9
|
+
MOUNT_ATTR_NODEV?: boolean;
|
|
10
|
+
MOUNT_ATTR_NOEXEC?: boolean;
|
|
11
|
+
MOUNT_ATTR_NOSYMFOLLOW?: boolean;
|
|
12
|
+
MOUNT_ATTR_NODIRATIME?: boolean;
|
|
13
|
+
customFlags?: bigint;
|
|
14
|
+
};
|
|
15
|
+
declare const mountAttributesToBitmask: ({ mountAttributes }: {
|
|
16
|
+
mountAttributes: TMountAttributes;
|
|
17
|
+
}) => bigint;
|
|
18
|
+
type TUnmountResult = {
|
|
19
|
+
error: Error | undefined;
|
|
20
|
+
};
|
|
21
|
+
declare const moveMount: ({ mountFd, newMountPoint, }: {
|
|
22
|
+
mountFd: number;
|
|
23
|
+
newMountPoint: string;
|
|
24
|
+
}) => {
|
|
25
|
+
error: any;
|
|
26
|
+
};
|
|
27
|
+
declare const unmount: ({ mountPoint, force, detach }: {
|
|
28
|
+
mountPoint: string;
|
|
29
|
+
force: boolean;
|
|
30
|
+
detach: boolean;
|
|
31
|
+
}) => TUnmountResult;
|
|
32
|
+
export { mountAttributesToBitmask, moveMount, unmount, };
|
|
33
|
+
export type { TRequiredFuseMountOptions, TMountAttributes, };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AT_FCWD,
|
|
3
|
+
MOUNT_ATTR_NODEV,
|
|
4
|
+
MOUNT_ATTR_NODIRATIME,
|
|
5
|
+
MOUNT_ATTR_NOEXEC,
|
|
6
|
+
MOUNT_ATTR_NOSUID,
|
|
7
|
+
MOUNT_ATTR_NOSYMFOLLOW,
|
|
8
|
+
MOUNT_ATTR_RDONLY,
|
|
9
|
+
MOVE_MOUNT_F_EMPTY_PATH
|
|
10
|
+
} from "./constants.js";
|
|
11
|
+
import { move_mount, umount } from "./syscalls.js";
|
|
12
|
+
|
|
13
|
+
/*type TRequiredFuseMountOptions = {
|
|
14
|
+
rootmode: number;
|
|
15
|
+
user_id: number;
|
|
16
|
+
group_id: number;
|
|
17
|
+
};*/
|
|
18
|
+
|
|
19
|
+
/*type TMountAttributes = {
|
|
20
|
+
MOUNT_ATTR_RDONLY?: boolean;
|
|
21
|
+
MOUNT_ATTR_NOSUID?: boolean;
|
|
22
|
+
MOUNT_ATTR_NODEV?: boolean;
|
|
23
|
+
MOUNT_ATTR_NOEXEC?: boolean;
|
|
24
|
+
MOUNT_ATTR_NOSYMFOLLOW?: boolean;
|
|
25
|
+
MOUNT_ATTR_NODIRATIME?: boolean;
|
|
26
|
+
|
|
27
|
+
customFlags?: bigint;
|
|
28
|
+
};*/
|
|
29
|
+
|
|
30
|
+
const knownMountAttributesBitmask = MOUNT_ATTR_RDONLY
|
|
31
|
+
| MOUNT_ATTR_NOSUID
|
|
32
|
+
| MOUNT_ATTR_NODEV
|
|
33
|
+
| MOUNT_ATTR_NOEXEC
|
|
34
|
+
| MOUNT_ATTR_NOSYMFOLLOW
|
|
35
|
+
| MOUNT_ATTR_NODIRATIME;
|
|
36
|
+
|
|
37
|
+
// eslint-disable-next-line max-statements, complexity
|
|
38
|
+
const mountAttributesToBitmask = ({ mountAttributes }/*: { mountAttributes: TMountAttributes }*/) => {
|
|
39
|
+
let bitmask = 0n;
|
|
40
|
+
|
|
41
|
+
if (mountAttributes.MOUNT_ATTR_RDONLY) {
|
|
42
|
+
bitmask |= MOUNT_ATTR_RDONLY;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (mountAttributes.MOUNT_ATTR_NOSUID) {
|
|
46
|
+
bitmask |= MOUNT_ATTR_NOSUID;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (mountAttributes.MOUNT_ATTR_NODEV) {
|
|
50
|
+
bitmask |= MOUNT_ATTR_NODEV;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (mountAttributes.MOUNT_ATTR_NOEXEC) {
|
|
54
|
+
bitmask |= MOUNT_ATTR_NOEXEC;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (mountAttributes.MOUNT_ATTR_NOSYMFOLLOW) {
|
|
58
|
+
bitmask |= MOUNT_ATTR_NOSYMFOLLOW;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (mountAttributes.MOUNT_ATTR_NODIRATIME) {
|
|
62
|
+
bitmask |= MOUNT_ATTR_NODIRATIME;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (mountAttributes.customFlags !== undefined) {
|
|
66
|
+
|
|
67
|
+
if ((mountAttributes.customFlags & knownMountAttributesBitmask) !== 0n) {
|
|
68
|
+
throw Error(`customFlags contains known mount attribute flags`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
bitmask |= mountAttributes.customFlags;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return bitmask;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/*type TUnmountResult = {
|
|
79
|
+
error: Error | undefined;
|
|
80
|
+
};*/
|
|
81
|
+
|
|
82
|
+
const MNT_FORCE = 1n;
|
|
83
|
+
const MNT_DETACH = 2n;
|
|
84
|
+
|
|
85
|
+
// for now, only export this simple variant for use with fuse
|
|
86
|
+
const moveMount = ({
|
|
87
|
+
mountFd,
|
|
88
|
+
newMountPoint,
|
|
89
|
+
}/*: {
|
|
90
|
+
mountFd: number;
|
|
91
|
+
newMountPoint: string;
|
|
92
|
+
}*/) => {
|
|
93
|
+
const { errno: moveMountErrno } = move_mount({
|
|
94
|
+
fromFd: mountFd,
|
|
95
|
+
fromPath: "",
|
|
96
|
+
toFd: Number(AT_FCWD),
|
|
97
|
+
toPath: newMountPoint,
|
|
98
|
+
flags: MOVE_MOUNT_F_EMPTY_PATH,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (moveMountErrno !== undefined) {
|
|
102
|
+
return {
|
|
103
|
+
error: Error(`move_mount syscall failed with errno ${moveMountErrno}`)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
error: undefined
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const unmount = ({ mountPoint, force, detach }/*: { mountPoint: string, force: boolean, detach: boolean }*/)/*: TUnmountResult*/ => {
|
|
113
|
+
|
|
114
|
+
let flags = 0n;
|
|
115
|
+
|
|
116
|
+
if (force) {
|
|
117
|
+
flags |= MNT_FORCE;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (detach) {
|
|
121
|
+
flags |= MNT_DETACH;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const { errno } = umount({
|
|
125
|
+
target: mountPoint,
|
|
126
|
+
flags,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (errno !== undefined) {
|
|
130
|
+
return {
|
|
131
|
+
error: Error(`umount syscall failed with errno ${errno}`)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
error: undefined
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
mountAttributesToBitmask,
|
|
142
|
+
moveMount,
|
|
143
|
+
unmount,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/*export type {
|
|
147
|
+
TRequiredFuseMountOptions,
|
|
148
|
+
TMountAttributes,
|
|
149
|
+
};*/
|