@zenfs/core 2.6.5 → 2.7.0
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/backends/cow.js +4 -3
- package/dist/backends/fetch.d.ts +4 -0
- package/dist/backends/fetch.js +30 -1
- package/dist/backends/memory.d.ts +1 -1
- package/dist/backends/store/fs.js +18 -5
- package/dist/config.js +7 -7
- package/dist/internal/contexts.d.ts +4 -0
- package/dist/internal/contexts.js +10 -6
- package/dist/internal/file_index.js +2 -1
- package/dist/internal/filesystem.d.ts +5 -0
- package/dist/internal/filesystem.js +18 -0
- package/dist/internal/inode.d.ts +6 -1
- package/dist/internal/inode.js +12 -3
- package/dist/internal/ioctl.d.ts +148 -0
- package/dist/internal/ioctl.js +368 -0
- package/dist/mixins/async.js +6 -1
- package/dist/mixins/mutexed.d.ts +3 -0
- package/dist/mixins/mutexed.js +29 -1
- package/dist/mixins/shared.d.ts +1 -1
- package/dist/mixins/shared.js +1 -0
- package/dist/mixins/sync.js +3 -0
- package/dist/node/sync.js +8 -8
- package/dist/vfs/async.js +2 -2
- package/dist/vfs/file.js +2 -1
- package/dist/vfs/ioctl.d.ts +8 -85
- package/dist/vfs/ioctl.js +67 -369
- package/dist/vfs/shared.d.ts +2 -0
- package/dist/vfs/shared.js +12 -8
- package/dist/vfs/sync.d.ts +1 -1
- package/dist/vfs/sync.js +11 -11
- package/dist/vfs/vcache.js +3 -0
- package/package.json +10 -1
- package/scripts/make-index.js +22 -7
- package/tests/backend/cow.test.ts +33 -0
- package/tests/backend/fetch.test.ts +8 -0
- package/tests/fs/truncate.test.ts +22 -0
package/dist/backends/cow.js
CHANGED
|
@@ -11,7 +11,8 @@ const journalOperations = new Set(['delete']);
|
|
|
11
11
|
function isJournalOp(op) {
|
|
12
12
|
return journalOperations.has(op);
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
// @todo use `Iterator` helper #296
|
|
15
|
+
const maxOpLength = [...journalOperations].reduce((max, op) => Math.max(max, op.length), 0);
|
|
15
16
|
const journalMagicString = '#journal@v0\n';
|
|
16
17
|
/**
|
|
17
18
|
* Tracks various operations for the CoW backend
|
|
@@ -450,7 +451,7 @@ export class CopyOnWriteFS extends FileSystem {
|
|
|
450
451
|
if (size)
|
|
451
452
|
this.readable.readSync(path, data, 0, size);
|
|
452
453
|
this.writable.createFileSync(path, stats);
|
|
453
|
-
this.writable.touchSync(path, stats);
|
|
454
|
+
this.writable.touchSync(path, { ...pick(stats, _inode_fields), attributes: stats.attributes, size });
|
|
454
455
|
if (size)
|
|
455
456
|
this.writable.writeSync(path, data, 0);
|
|
456
457
|
}
|
|
@@ -468,7 +469,7 @@ export class CopyOnWriteFS extends FileSystem {
|
|
|
468
469
|
if (size)
|
|
469
470
|
await this.readable.read(path, data, 0, size);
|
|
470
471
|
await this.writable.createFile(path, stats);
|
|
471
|
-
await this.writable.touch(path, stats);
|
|
472
|
+
await this.writable.touch(path, { ...pick(stats, _inode_fields), attributes: stats.attributes, size });
|
|
472
473
|
if (size)
|
|
473
474
|
await this.writable.write(path, data, 0);
|
|
474
475
|
}
|
package/dist/backends/fetch.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IndexData } from '../internal/file_index.js';
|
|
2
2
|
import { Index } from '../internal/file_index.js';
|
|
3
3
|
import { IndexFS } from '../internal/index_fs.js';
|
|
4
|
+
import type { Inode, InodeLike } from '../internal/inode.js';
|
|
4
5
|
import type { SharedConfig } from './backend.js';
|
|
5
6
|
/**
|
|
6
7
|
* Configuration options for FetchFS.
|
|
@@ -45,6 +46,9 @@ export declare class FetchFS extends IndexFS {
|
|
|
45
46
|
*/
|
|
46
47
|
protected _async(p: Promise<unknown>): void;
|
|
47
48
|
constructor(index: Index, baseUrl: string, requestInit?: RequestInit, remoteWrite?: boolean | undefined);
|
|
49
|
+
protected resize(path: string, inode: Inode, oldSize: number): Promise<void> | void;
|
|
50
|
+
touch(path: string, metadata: InodeLike): Promise<void>;
|
|
51
|
+
touchSync(path: string, metadata: InodeLike): void;
|
|
48
52
|
protected remove(path: string): Promise<void>;
|
|
49
53
|
protected removeSync(path: string): void;
|
|
50
54
|
read(path: string, buffer: Uint8Array, offset: number | undefined, end: number): Promise<void>;
|
package/dist/backends/fetch.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { withErrno } from 'kerium';
|
|
3
3
|
import { debug, err, warn } from 'kerium/log';
|
|
4
|
-
import { decodeUTF8 } from 'utilium';
|
|
4
|
+
import { _throw, decodeUTF8 } from 'utilium';
|
|
5
|
+
import { Resource } from 'utilium/cache';
|
|
5
6
|
import * as requests from 'utilium/requests';
|
|
6
7
|
import { Index } from '../internal/file_index.js';
|
|
7
8
|
import { IndexFS } from '../internal/index_fs.js';
|
|
9
|
+
import { isDirectory } from '../internal/inode.js';
|
|
8
10
|
import { normalizePath } from '../utils.js';
|
|
9
11
|
import { S_IFREG } from '../constants.js';
|
|
10
12
|
/** Parse and throw */
|
|
@@ -48,6 +50,33 @@ export class FetchFS extends IndexFS {
|
|
|
48
50
|
this.requestInit = requestInit;
|
|
49
51
|
this.remoteWrite = remoteWrite;
|
|
50
52
|
}
|
|
53
|
+
resize(path, inode, oldSize) {
|
|
54
|
+
if (isDirectory(inode) || inode.size == oldSize)
|
|
55
|
+
return;
|
|
56
|
+
const url = this.baseUrl + path;
|
|
57
|
+
const resource = requests.resourcesCache.get(url) ?? new Resource(url, oldSize, {}, requests.resourcesCache);
|
|
58
|
+
resource.size = inode.size;
|
|
59
|
+
if (inode.size < oldSize)
|
|
60
|
+
return;
|
|
61
|
+
const zeroes = new Uint8Array(inode.size - oldSize);
|
|
62
|
+
resource.add(zeroes, oldSize);
|
|
63
|
+
if (this.remoteWrite)
|
|
64
|
+
return requests.set(url, zeroes, { offset: oldSize, warn }, this.requestInit).catch(parseError);
|
|
65
|
+
}
|
|
66
|
+
async touch(path, metadata) {
|
|
67
|
+
const inode = this.index.get(path) ?? _throw(withErrno('ENOENT'));
|
|
68
|
+
const oldSize = inode.size;
|
|
69
|
+
inode.update(metadata);
|
|
70
|
+
await this.resize(path, inode, oldSize);
|
|
71
|
+
}
|
|
72
|
+
touchSync(path, metadata) {
|
|
73
|
+
const inode = this.index.get(path) ?? _throw(withErrno('ENOENT'));
|
|
74
|
+
const oldSize = inode.size;
|
|
75
|
+
inode.update(metadata);
|
|
76
|
+
const pending = this.resize(path, inode, oldSize);
|
|
77
|
+
if (pending)
|
|
78
|
+
this._async(pending);
|
|
79
|
+
}
|
|
51
80
|
async remove(path) {
|
|
52
81
|
await requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
|
|
53
82
|
}
|
|
@@ -9,7 +9,7 @@ export declare class InMemoryStore extends Map<number, Uint8Array> implements Sy
|
|
|
9
9
|
readonly maxSize: number;
|
|
10
10
|
readonly label?: string | undefined;
|
|
11
11
|
readonly flags: readonly [];
|
|
12
|
-
readonly name
|
|
12
|
+
readonly name: string;
|
|
13
13
|
constructor(maxSize?: number, label?: string | undefined);
|
|
14
14
|
sync(): Promise<void>;
|
|
15
15
|
transaction(): SyncMapTransaction;
|
|
@@ -234,7 +234,7 @@ export class StoreFS extends FileSystem {
|
|
|
234
234
|
const [path, ino] = queue.shift();
|
|
235
235
|
const inode = new Inode(await tx.get(ino));
|
|
236
236
|
index.set(path, inode);
|
|
237
|
-
if (inode
|
|
237
|
+
if (isDirectory(inode)) {
|
|
238
238
|
const dir = decodeDirListing((await tx.get(inode.data)) ?? _throw(withErrno('ENODATA')));
|
|
239
239
|
for (const [name, id] of Object.entries(dir)) {
|
|
240
240
|
queue.push([join(path, name), id]);
|
|
@@ -265,7 +265,7 @@ export class StoreFS extends FileSystem {
|
|
|
265
265
|
const [path, ino] = queue.shift();
|
|
266
266
|
const inode = new Inode(tx.getSync(ino));
|
|
267
267
|
index.set(path, inode);
|
|
268
|
-
if (inode
|
|
268
|
+
if (isDirectory(inode)) {
|
|
269
269
|
const dir = decodeDirListing(tx.getSync(inode.data) ?? _throw(withErrno('ENODATA')));
|
|
270
270
|
for (const [name, id] of Object.entries(dir)) {
|
|
271
271
|
queue.push([join(path, name), id]);
|
|
@@ -418,6 +418,12 @@ export class StoreFS extends FileSystem {
|
|
|
418
418
|
try {
|
|
419
419
|
const tx = __addDisposableResource(env_9, this.transaction(), true);
|
|
420
420
|
const inode = await this.findInode(tx, path);
|
|
421
|
+
if (!isDirectory(inode) && metadata.size !== undefined && metadata.size !== inode.size) {
|
|
422
|
+
const data = (await tx.get(inode.data)) ?? new Uint8Array();
|
|
423
|
+
if (metadata.size < data.byteLength)
|
|
424
|
+
data.fill(0, metadata.size);
|
|
425
|
+
await tx.set(inode.data, metadata.size < data.byteLength ? data.subarray(0, metadata.size) : extendBuffer(data, metadata.size));
|
|
426
|
+
}
|
|
421
427
|
if (inode.update(metadata)) {
|
|
422
428
|
this._add(inode.ino, path);
|
|
423
429
|
tx.setSync(inode.ino, inode);
|
|
@@ -439,6 +445,12 @@ export class StoreFS extends FileSystem {
|
|
|
439
445
|
try {
|
|
440
446
|
const tx = __addDisposableResource(env_10, this.transaction(), false);
|
|
441
447
|
const inode = this.findInodeSync(tx, path);
|
|
448
|
+
if (!isDirectory(inode) && metadata.size !== undefined && metadata.size !== inode.size) {
|
|
449
|
+
const data = tx.getSync(inode.data) ?? new Uint8Array();
|
|
450
|
+
if (metadata.size < data.byteLength)
|
|
451
|
+
data.fill(0, metadata.size);
|
|
452
|
+
tx.setSync(inode.data, metadata.size < data.byteLength ? data.subarray(0, metadata.size) : extendBuffer(data, metadata.size));
|
|
453
|
+
}
|
|
442
454
|
if (inode.update(metadata)) {
|
|
443
455
|
this._add(inode.ino, path);
|
|
444
456
|
tx.setSync(inode.ino, inode);
|
|
@@ -768,7 +780,7 @@ export class StoreFS extends FileSystem {
|
|
|
768
780
|
// Parse the raw data into our Inode object
|
|
769
781
|
const inode = new Inode(inodeData);
|
|
770
782
|
// If it is a directory and not yet visited, read its directory listing
|
|
771
|
-
if ((inode
|
|
783
|
+
if (!isDirectory(inode) || visitedDirectories.has(ino)) {
|
|
772
784
|
continue;
|
|
773
785
|
}
|
|
774
786
|
visitedDirectories.add(ino);
|
|
@@ -835,7 +847,7 @@ export class StoreFS extends FileSystem {
|
|
|
835
847
|
continue;
|
|
836
848
|
}
|
|
837
849
|
const inode = new Inode(inodeData);
|
|
838
|
-
if ((inode
|
|
850
|
+
if (!isDirectory(inode) || visitedDirectories.has(ino)) {
|
|
839
851
|
continue;
|
|
840
852
|
}
|
|
841
853
|
visitedDirectories.add(ino);
|
|
@@ -921,7 +933,8 @@ export class StoreFS extends FileSystem {
|
|
|
921
933
|
_lastID;
|
|
922
934
|
/** Allocates a new ID and adds the ID/path */
|
|
923
935
|
allocNew(path) {
|
|
924
|
-
|
|
936
|
+
// @todo use `Iterator` helper #296
|
|
937
|
+
this._lastID ||= Array.from(this._paths.keys()).reduce((max, ino) => Math.max(max, ino), 0);
|
|
925
938
|
this._lastID += 2;
|
|
926
939
|
const id = this._lastID;
|
|
927
940
|
if (id > size_max)
|
package/dist/config.js
CHANGED
|
@@ -7,7 +7,7 @@ import { FileSystem } from './internal/filesystem.js';
|
|
|
7
7
|
import { exists, mkdir, stat } from './node/promises.js';
|
|
8
8
|
import { existsSync, mkdirSync, statSync } from './node/sync.js';
|
|
9
9
|
import { _setAccessChecks } from './vfs/config.js';
|
|
10
|
-
import { mount,
|
|
10
|
+
import { mount, umount } from './vfs/shared.js';
|
|
11
11
|
/**
|
|
12
12
|
* Update the configuration of a file system.
|
|
13
13
|
* @category Backends and Configuration
|
|
@@ -191,7 +191,7 @@ function mountWithMkdirSync(path, fs) {
|
|
|
191
191
|
* @category Backends and Configuration
|
|
192
192
|
*/
|
|
193
193
|
export function addDevice(driver, options) {
|
|
194
|
-
const devfs = mounts.get('/dev');
|
|
194
|
+
const devfs = defaultContext.mounts.get('/dev');
|
|
195
195
|
if (!(devfs instanceof DeviceFS))
|
|
196
196
|
throw log.crit(withErrno('ENOTSUP', '/dev does not exist or is not a device file system'));
|
|
197
197
|
return devfs._createDevice(driver, options);
|
|
@@ -223,10 +223,10 @@ export async function configure(configuration) {
|
|
|
223
223
|
await mountWithMkdir(point, await resolveMountConfig(mountConfig));
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
-
for (const fs of mounts.values()) {
|
|
226
|
+
for (const fs of defaultContext.mounts.values()) {
|
|
227
227
|
configureFileSystem(fs, configuration);
|
|
228
228
|
}
|
|
229
|
-
if (configuration.addDevices && !mounts.has('/dev')) {
|
|
229
|
+
if (configuration.addDevices && !defaultContext.mounts.has('/dev')) {
|
|
230
230
|
const devfs = new DeviceFS();
|
|
231
231
|
devfs.addDefaults();
|
|
232
232
|
await devfs.ready();
|
|
@@ -270,10 +270,10 @@ export function configureSync(configuration) {
|
|
|
270
270
|
mountWithMkdirSync(point, resolveMountConfigSync(mountConfig));
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
|
-
for (const fs of mounts.values()) {
|
|
273
|
+
for (const fs of defaultContext.mounts.values()) {
|
|
274
274
|
configureFileSystem(fs, configuration);
|
|
275
275
|
}
|
|
276
|
-
if (configuration.addDevices && !mounts.has('/dev')) {
|
|
276
|
+
if (configuration.addDevices && !defaultContext.mounts.has('/dev')) {
|
|
277
277
|
const devfs = new DeviceFS();
|
|
278
278
|
devfs.addDefaults();
|
|
279
279
|
devfs.readySync();
|
|
@@ -292,6 +292,6 @@ export function configureSync(configuration) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
export async function sync() {
|
|
295
|
-
for (const fs of mounts.values())
|
|
295
|
+
for (const fs of defaultContext.mounts.values())
|
|
296
296
|
await fs.sync();
|
|
297
297
|
}
|
|
@@ -4,6 +4,7 @@ import type * as path from '../path.js';
|
|
|
4
4
|
import type { Handle } from '../vfs/file.js';
|
|
5
5
|
import type * as xattr from '../vfs/xattr.js';
|
|
6
6
|
import type { Credentials, CredentialsInit } from './credentials.js';
|
|
7
|
+
import type { FileSystem } from './filesystem.js';
|
|
7
8
|
/**
|
|
8
9
|
* Symbol used for context branding
|
|
9
10
|
* @internal @hidden
|
|
@@ -34,6 +35,8 @@ export interface FSContext {
|
|
|
34
35
|
readonly parent: FSContext | null;
|
|
35
36
|
/** The child contexts */
|
|
36
37
|
readonly children: FSContext[];
|
|
38
|
+
/** The mount table for this context */
|
|
39
|
+
readonly mounts: Map<string, FileSystem>;
|
|
37
40
|
}
|
|
38
41
|
export declare function isContext(obj: unknown): obj is FSContext;
|
|
39
42
|
export declare function assertContext(ctx: unknown): asserts ctx is FSContext;
|
|
@@ -64,6 +67,7 @@ export interface ContextInit {
|
|
|
64
67
|
root?: string;
|
|
65
68
|
pwd?: string;
|
|
66
69
|
credentials?: CredentialsInit;
|
|
70
|
+
mounts?: Record<string, FileSystem>;
|
|
67
71
|
}
|
|
68
72
|
/**
|
|
69
73
|
* The default/global context.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
+
// This needs to be in a separate file to avoid circular dependencies
|
|
3
3
|
import { withErrno } from 'kerium';
|
|
4
|
+
import { warn } from 'kerium/log';
|
|
5
|
+
import { createCredentials } from './credentials.js';
|
|
4
6
|
/**
|
|
5
7
|
* Symbol used for context branding
|
|
6
8
|
* @internal @hidden
|
|
@@ -20,19 +22,20 @@ export function assertContext(ctx) {
|
|
|
20
22
|
*/
|
|
21
23
|
export const defaultContext = {
|
|
22
24
|
[kIsContext]: true,
|
|
23
|
-
id:
|
|
25
|
+
id: 1,
|
|
24
26
|
root: '/',
|
|
25
27
|
pwd: '/',
|
|
26
28
|
credentials: createCredentials({ uid: 0, gid: 0 }),
|
|
27
29
|
descriptors: new Map(),
|
|
28
30
|
parent: null,
|
|
29
31
|
children: [],
|
|
32
|
+
mounts: new Map(),
|
|
30
33
|
};
|
|
31
34
|
export function contextOf($) {
|
|
32
35
|
return isContext($) ? $ : defaultContext;
|
|
33
36
|
}
|
|
34
|
-
//
|
|
35
|
-
let _nextId =
|
|
37
|
+
// 1 is reserved for the global/default context
|
|
38
|
+
let _nextId = 2;
|
|
36
39
|
/**
|
|
37
40
|
* Create a blank FS Context
|
|
38
41
|
* @internal
|
|
@@ -43,7 +46,7 @@ let _nextId = 1;
|
|
|
43
46
|
*/
|
|
44
47
|
export function createChildContext(parent, init = {}) {
|
|
45
48
|
assertContext(parent);
|
|
46
|
-
const { root = parent.root, pwd = parent.pwd, credentials = structuredClone(parent.credentials) } = init;
|
|
49
|
+
const { root = parent.root, pwd = parent.pwd, credentials = structuredClone(parent.credentials), mounts = Object.fromEntries(parent.mounts), } = init;
|
|
47
50
|
const ctx = {
|
|
48
51
|
[kIsContext]: true,
|
|
49
52
|
id: _nextId++,
|
|
@@ -53,6 +56,7 @@ export function createChildContext(parent, init = {}) {
|
|
|
53
56
|
descriptors: new Map(),
|
|
54
57
|
parent: parent,
|
|
55
58
|
children: [],
|
|
59
|
+
mounts: new Map(Object.entries(mounts)),
|
|
56
60
|
};
|
|
57
61
|
Object.defineProperties(ctx, {
|
|
58
62
|
id: { configurable: false, writable: false },
|
|
@@ -87,7 +87,8 @@ export class Index extends Map {
|
|
|
87
87
|
_alloc() {
|
|
88
88
|
// @todo use `Iterator.flatMap` #296
|
|
89
89
|
this.#lastAlloc ||= Array.from(this.values()).reduce((max, inode) => Math.max(max, inode.ino, inode.data), 0);
|
|
90
|
-
|
|
90
|
+
this.#lastAlloc++;
|
|
91
|
+
return this.#lastAlloc++;
|
|
91
92
|
}
|
|
92
93
|
/**
|
|
93
94
|
* Gets a list of entries for each directory in the index.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { UUID } from 'node:crypto';
|
|
2
2
|
import type { ConstMap } from 'utilium';
|
|
3
3
|
import type { InodeLike } from './inode.js';
|
|
4
|
+
import type { IoctlContext } from './ioctl.js';
|
|
4
5
|
/**
|
|
5
6
|
* Usage information about a file system
|
|
6
7
|
* @category Internals
|
|
@@ -244,4 +245,8 @@ export declare abstract class FileSystem {
|
|
|
244
245
|
* @privateRemarks The default implementation of `streamWrite` uses "chunked" `write`s
|
|
245
246
|
*/
|
|
246
247
|
streamWrite(path: string, options: StreamOptions): WritableStream;
|
|
248
|
+
/** @internal */
|
|
249
|
+
ioctl(context: IoctlContext, command: number, ...args: any[]): Promise<any>;
|
|
250
|
+
/** @internal */
|
|
251
|
+
ioctlSync(context: IoctlContext, command: number, ...args: any[]): any;
|
|
247
252
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
1
2
|
import { withErrno } from 'kerium';
|
|
3
|
+
import { ioctl_default_ops_async, ioctl_default_ops_sync } from './ioctl.js';
|
|
2
4
|
const _chunkSize = 0x1000;
|
|
3
5
|
/**
|
|
4
6
|
* Provides a consistent and easy to use internal API.
|
|
@@ -132,4 +134,20 @@ export class FileSystem {
|
|
|
132
134
|
},
|
|
133
135
|
});
|
|
134
136
|
}
|
|
137
|
+
/** @internal */
|
|
138
|
+
async ioctl(context, command, ...args) {
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unnecessary-type-assertion
|
|
140
|
+
const cmd = ioctl_default_ops_async[command];
|
|
141
|
+
if (!cmd)
|
|
142
|
+
throw withErrno('ENOTTY');
|
|
143
|
+
return await cmd(this, context, ...args);
|
|
144
|
+
}
|
|
145
|
+
/** @internal */
|
|
146
|
+
ioctlSync(context, command, ...args) {
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unnecessary-type-assertion
|
|
148
|
+
const cmd = ioctl_default_ops_sync[command];
|
|
149
|
+
if (!cmd)
|
|
150
|
+
throw withErrno('ENOTTY');
|
|
151
|
+
return cmd(this, context, ...args);
|
|
152
|
+
}
|
|
135
153
|
}
|
package/dist/internal/inode.d.ts
CHANGED
|
@@ -79,6 +79,10 @@ export interface InodeLike<T extends number | bigint = number> extends InodeFiel
|
|
|
79
79
|
* Number of hard links
|
|
80
80
|
*/
|
|
81
81
|
nlink: T;
|
|
82
|
+
/**
|
|
83
|
+
* Device ID for special files
|
|
84
|
+
*/
|
|
85
|
+
rdev: T;
|
|
82
86
|
/**
|
|
83
87
|
* Extended attributes
|
|
84
88
|
*/
|
|
@@ -87,7 +91,7 @@ export interface InodeLike<T extends number | bigint = number> extends InodeFiel
|
|
|
87
91
|
/**
|
|
88
92
|
* @internal @hidden
|
|
89
93
|
*/
|
|
90
|
-
export declare const _inode_fields: readonly ["ino", "data", "size", "mode", "flags", "nlink", "uid", "gid", "atimeMs", "birthtimeMs", "mtimeMs", "ctimeMs", "version"];
|
|
94
|
+
export declare const _inode_fields: readonly ["ino", "data", "size", "mode", "flags", "nlink", "uid", "gid", "atimeMs", "birthtimeMs", "mtimeMs", "ctimeMs", "version", "rdev"];
|
|
91
95
|
/**
|
|
92
96
|
* Represents which version of the `Inode` format we are on.
|
|
93
97
|
* 1. 58 bytes. The first member was called `ino` but used as the ID for data.
|
|
@@ -182,6 +186,7 @@ export declare class Inode extends Inode_base implements InodeLike {
|
|
|
182
186
|
* Unrelated to the inode format!
|
|
183
187
|
*/
|
|
184
188
|
accessor version: number;
|
|
189
|
+
accessor rdev: number;
|
|
185
190
|
/**
|
|
186
191
|
* Padding up to 128 bytes.
|
|
187
192
|
* This ensures there is enough room for expansion without breaking the ABI.
|
package/dist/internal/inode.js
CHANGED
|
@@ -270,6 +270,7 @@ export const _inode_fields = [
|
|
|
270
270
|
'mtimeMs',
|
|
271
271
|
'ctimeMs',
|
|
272
272
|
'version',
|
|
273
|
+
'rdev',
|
|
273
274
|
];
|
|
274
275
|
/**
|
|
275
276
|
* Represents which version of the `Inode` format we are on.
|
|
@@ -335,7 +336,7 @@ export const userModifiableFlags = 0x000380ff;
|
|
|
335
336
|
* @internal
|
|
336
337
|
*/
|
|
337
338
|
let Inode = (() => {
|
|
338
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
339
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
339
340
|
let _classDecorators = [struct.packed()];
|
|
340
341
|
let _classDescriptor;
|
|
341
342
|
let _classExtraInitializers = [];
|
|
@@ -389,6 +390,9 @@ let Inode = (() => {
|
|
|
389
390
|
let _version_decorators;
|
|
390
391
|
let _version_initializers = [];
|
|
391
392
|
let _version_extraInitializers = [];
|
|
393
|
+
let _rdev_decorators;
|
|
394
|
+
let _rdev_initializers = [];
|
|
395
|
+
let _rdev_extraInitializers = [];
|
|
392
396
|
let ___padding_decorators;
|
|
393
397
|
let ___padding_initializers = [];
|
|
394
398
|
let ___padding_extraInitializers = [];
|
|
@@ -418,7 +422,8 @@ let Inode = (() => {
|
|
|
418
422
|
_flags_decorators = [(_p = t).uint32.bind(_p)];
|
|
419
423
|
___after_flags_decorators = [(_q = t).uint16.bind(_q)];
|
|
420
424
|
_version_decorators = [(_r = t).uint32.bind(_r)];
|
|
421
|
-
|
|
425
|
+
_rdev_decorators = [(_s = t).uint32.bind(_s)];
|
|
426
|
+
___padding_decorators = [t.uint8(44)];
|
|
422
427
|
_attributes_decorators = [field(Attributes)];
|
|
423
428
|
___data_decorators = [t.uint8(maxDynamicData)];
|
|
424
429
|
__esDecorate(this, null, _data_decorators, { kind: "accessor", name: "data", static: false, private: false, access: { has: obj => "data" in obj, get: obj => obj.data, set: (obj, value) => { obj.data = value; } }, metadata: _metadata }, _data_initializers, _data_extraInitializers);
|
|
@@ -437,6 +442,7 @@ let Inode = (() => {
|
|
|
437
442
|
__esDecorate(this, null, _flags_decorators, { kind: "accessor", name: "flags", static: false, private: false, access: { has: obj => "flags" in obj, get: obj => obj.flags, set: (obj, value) => { obj.flags = value; } }, metadata: _metadata }, _flags_initializers, _flags_extraInitializers);
|
|
438
443
|
__esDecorate(this, null, ___after_flags_decorators, { kind: "accessor", name: "__after_flags", static: false, private: false, access: { has: obj => "__after_flags" in obj, get: obj => obj.__after_flags, set: (obj, value) => { obj.__after_flags = value; } }, metadata: _metadata }, ___after_flags_initializers, ___after_flags_extraInitializers);
|
|
439
444
|
__esDecorate(this, null, _version_decorators, { kind: "accessor", name: "version", static: false, private: false, access: { has: obj => "version" in obj, get: obj => obj.version, set: (obj, value) => { obj.version = value; } }, metadata: _metadata }, _version_initializers, _version_extraInitializers);
|
|
445
|
+
__esDecorate(this, null, _rdev_decorators, { kind: "accessor", name: "rdev", static: false, private: false, access: { has: obj => "rdev" in obj, get: obj => obj.rdev, set: (obj, value) => { obj.rdev = value; } }, metadata: _metadata }, _rdev_initializers, _rdev_extraInitializers);
|
|
440
446
|
__esDecorate(this, null, ___padding_decorators, { kind: "accessor", name: "__padding", static: false, private: false, access: { has: obj => "__padding" in obj, get: obj => obj.__padding, set: (obj, value) => { obj.__padding = value; } }, metadata: _metadata }, ___padding_initializers, ___padding_extraInitializers);
|
|
441
447
|
__esDecorate(this, null, _attributes_decorators, { kind: "accessor", name: "attributes", static: false, private: false, access: { has: obj => "attributes" in obj, get: obj => obj.attributes, set: (obj, value) => { obj.attributes = value; } }, metadata: _metadata }, _attributes_initializers, _attributes_extraInitializers);
|
|
442
448
|
__esDecorate(this, null, ___data_decorators, { kind: "accessor", name: "__data", static: false, private: false, access: { has: obj => "__data" in obj, get: obj => obj.__data, set: (obj, value) => { obj.__data = value; } }, metadata: _metadata }, ___data_initializers, ___data_extraInitializers);
|
|
@@ -528,7 +534,10 @@ let Inode = (() => {
|
|
|
528
534
|
*/
|
|
529
535
|
get version() { return this.#version_accessor_storage; }
|
|
530
536
|
set version(value) { this.#version_accessor_storage = value; }
|
|
531
|
-
#
|
|
537
|
+
#rdev_accessor_storage = (__runInitializers(this, _version_extraInitializers), __runInitializers(this, _rdev_initializers, void 0));
|
|
538
|
+
get rdev() { return this.#rdev_accessor_storage; }
|
|
539
|
+
set rdev(value) { this.#rdev_accessor_storage = value; }
|
|
540
|
+
#__padding_accessor_storage = (__runInitializers(this, _rdev_extraInitializers), __runInitializers(this, ___padding_initializers, void 0));
|
|
532
541
|
/**
|
|
533
542
|
* Padding up to 128 bytes.
|
|
534
543
|
* This ensures there is enough room for expansion without breaking the ABI.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { BufferView } from 'utilium/buffer';
|
|
2
|
+
import type { FileSystem } from './filesystem.js';
|
|
3
|
+
import type { InodeLike } from './inode.js';
|
|
4
|
+
declare const fsxattr_base: import("memium").StructConstructor<BufferView<any>>;
|
|
5
|
+
declare class fsxattr extends fsxattr_base {
|
|
6
|
+
static name: string;
|
|
7
|
+
/** xflags field value */
|
|
8
|
+
accessor xflags: number;
|
|
9
|
+
/** extsize field value */
|
|
10
|
+
accessor extsize: number;
|
|
11
|
+
/** nextents field value */
|
|
12
|
+
accessor nextents: number;
|
|
13
|
+
/** project identifier */
|
|
14
|
+
accessor projid: number;
|
|
15
|
+
/** CoW extsize field value */
|
|
16
|
+
accessor cowextsize: number;
|
|
17
|
+
protected accessor pad: number[];
|
|
18
|
+
constructor(inode?: Readonly<InodeLike>);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `FS_IOC_*` commands for {@link ioctl | `ioctl`}
|
|
22
|
+
* @remarks
|
|
23
|
+
* These are computed from a script since constant values are needed for enum member types
|
|
24
|
+
*/
|
|
25
|
+
export declare enum IOC {
|
|
26
|
+
GetFlags = 2148034049,
|
|
27
|
+
SetFlags = 1074292226,
|
|
28
|
+
GetVersion = 2148038145,
|
|
29
|
+
SetVersion = 1074296322,
|
|
30
|
+
Fiemap = 3223348747,
|
|
31
|
+
GetXattr = 2149341215,
|
|
32
|
+
SetXattr = 1075599392,
|
|
33
|
+
GetLabel = 2164298801,
|
|
34
|
+
SetLabel = 1090556978,
|
|
35
|
+
GetUUID = 2148603136,
|
|
36
|
+
GetSysfsPath = 2155943169
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `FS_IOC32_*` commands for {@link ioctl | `ioctl`}
|
|
40
|
+
* @remarks
|
|
41
|
+
* These are computed from a script since constant values are needed for enum member types
|
|
42
|
+
*/
|
|
43
|
+
export declare enum IOC32 {
|
|
44
|
+
GetFlags = 2147771905,
|
|
45
|
+
SetFlags = 1074030082,
|
|
46
|
+
GetVersion = 2147776001,
|
|
47
|
+
SetVersion = 1074034178
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @category ioctl
|
|
51
|
+
*/
|
|
52
|
+
export interface IoctlContext {
|
|
53
|
+
fs: FileSystem;
|
|
54
|
+
inode: InodeLike;
|
|
55
|
+
path: string;
|
|
56
|
+
file?: {
|
|
57
|
+
position: number;
|
|
58
|
+
flag: number;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* @category ioctl
|
|
63
|
+
*/
|
|
64
|
+
export type Ioctl = (context: IoctlContext, ...args: any[]) => any;
|
|
65
|
+
/**
|
|
66
|
+
* What an ioctl takes from whoever is calling it, which is everything but the context it is given.
|
|
67
|
+
* @category ioctl
|
|
68
|
+
*/
|
|
69
|
+
export type IoctlArgs<T extends Ioctl> = T extends (context: IoctlContext, ...args: infer A) => any ? A : never;
|
|
70
|
+
/**
|
|
71
|
+
* @category ioctl
|
|
72
|
+
*/
|
|
73
|
+
export interface IoctlOps extends Record<number, Ioctl> {
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
* @category ioctl
|
|
78
|
+
*/
|
|
79
|
+
export declare const ioctl_default_ops: {
|
|
80
|
+
2148034049($: IoctlContext): number;
|
|
81
|
+
2147771905($: IoctlContext): number;
|
|
82
|
+
2148038145($: IoctlContext): number;
|
|
83
|
+
2147776001($: IoctlContext): number;
|
|
84
|
+
3223348747(): never;
|
|
85
|
+
2149341215($: IoctlContext, _name: string): fsxattr;
|
|
86
|
+
1075599392($: IoctlContext, _name: string, _value: fsxattr): never;
|
|
87
|
+
2164298801($: IoctlContext): string | undefined;
|
|
88
|
+
1090556978($: IoctlContext, label: string): void;
|
|
89
|
+
2148603136($: IoctlContext): string;
|
|
90
|
+
2155943169($: IoctlContext): string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
* @category ioctl
|
|
95
|
+
*/
|
|
96
|
+
export declare const ioctl_default_ops_async: {
|
|
97
|
+
1074292226($: IoctlContext, flags: number): Promise<void>;
|
|
98
|
+
1074030082($: IoctlContext, flags: number): Promise<void>;
|
|
99
|
+
1074296322($: IoctlContext, version: number): Promise<void>;
|
|
100
|
+
1074034178($: IoctlContext, version: number): Promise<void>;
|
|
101
|
+
2148034049($: IoctlContext): number;
|
|
102
|
+
2147771905($: IoctlContext): number;
|
|
103
|
+
2148038145($: IoctlContext): number;
|
|
104
|
+
2147776001($: IoctlContext): number;
|
|
105
|
+
3223348747(): never;
|
|
106
|
+
2149341215($: IoctlContext, _name: string): fsxattr;
|
|
107
|
+
1075599392($: IoctlContext, _name: string, _value: fsxattr): never;
|
|
108
|
+
2164298801($: IoctlContext): string | undefined;
|
|
109
|
+
1090556978($: IoctlContext, label: string): void;
|
|
110
|
+
2148603136($: IoctlContext): string;
|
|
111
|
+
2155943169($: IoctlContext): string;
|
|
112
|
+
};
|
|
113
|
+
type _IoctlOpsAsync = typeof ioctl_default_ops_async;
|
|
114
|
+
/**
|
|
115
|
+
* @internal
|
|
116
|
+
* @category ioctl
|
|
117
|
+
*/
|
|
118
|
+
export interface IoctlDefaultAsyncOps extends _IoctlOpsAsync {
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* @internal
|
|
122
|
+
* @category ioctl
|
|
123
|
+
*/
|
|
124
|
+
export declare const ioctl_default_ops_sync: {
|
|
125
|
+
1074292226($: IoctlContext, flags: number): void;
|
|
126
|
+
1074030082($: IoctlContext, flags: number): void;
|
|
127
|
+
1074296322($: IoctlContext, version: number): void;
|
|
128
|
+
1074034178($: IoctlContext, version: number): void;
|
|
129
|
+
2148034049($: IoctlContext): number;
|
|
130
|
+
2147771905($: IoctlContext): number;
|
|
131
|
+
2148038145($: IoctlContext): number;
|
|
132
|
+
2147776001($: IoctlContext): number;
|
|
133
|
+
3223348747(): never;
|
|
134
|
+
2149341215($: IoctlContext, _name: string): fsxattr;
|
|
135
|
+
1075599392($: IoctlContext, _name: string, _value: fsxattr): never;
|
|
136
|
+
2164298801($: IoctlContext): string | undefined;
|
|
137
|
+
1090556978($: IoctlContext, label: string): void;
|
|
138
|
+
2148603136($: IoctlContext): string;
|
|
139
|
+
2155943169($: IoctlContext): string;
|
|
140
|
+
};
|
|
141
|
+
type _IoctlOpsSync = typeof ioctl_default_ops_sync;
|
|
142
|
+
/**
|
|
143
|
+
* @internal
|
|
144
|
+
* @category ioctl
|
|
145
|
+
*/
|
|
146
|
+
export interface IoctlDefaultSyncOps extends _IoctlOpsSync {
|
|
147
|
+
}
|
|
148
|
+
export {};
|