@zenfs/dom 1.1.5 → 1.1.7
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/IndexedDB.d.ts +13 -5
- package/dist/IndexedDB.js +35 -11
- package/dist/access.d.ts +4 -4
- package/dist/access.js +21 -20
- package/dist/devices/dsp.js +2 -2
- package/dist/devices/framebuffer.js +4 -4
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +9 -7
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +5 -4
- package/dist/xml.d.ts +8 -8
- package/dist/xml.js +38 -41
- package/package.json +4 -3
package/dist/IndexedDB.d.ts
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
import type { SharedConfig, Store } from '@zenfs/core';
|
|
2
|
-
import {
|
|
3
|
-
import type * as cache from 'utilium/cache.js';
|
|
2
|
+
import { StoreFS, Transaction } from '@zenfs/core';
|
|
4
3
|
/**
|
|
5
4
|
* @internal @hidden
|
|
6
5
|
*/
|
|
7
|
-
export declare class IndexedDBTransaction extends
|
|
6
|
+
export declare class IndexedDBTransaction extends Transaction<IndexedDBStore> {
|
|
8
7
|
tx: IDBTransaction;
|
|
9
8
|
store: IndexedDBStore;
|
|
10
9
|
private _idb;
|
|
10
|
+
protected asyncDone: Promise<unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Run a asynchronous operation from a sync context. Not magic and subject to (race) conditions.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
protected async(promise: Promise<unknown>): void;
|
|
11
16
|
constructor(tx: IDBTransaction, store: IndexedDBStore);
|
|
12
17
|
keys(): Promise<Iterable<number>>;
|
|
13
18
|
get(id: number): Promise<Uint8Array | undefined>;
|
|
19
|
+
getSync(id: number, offset: number, end?: number): Uint8Array | undefined;
|
|
14
20
|
set(id: number, data: Uint8Array): Promise<void>;
|
|
21
|
+
setSync(id: number, data: Uint8Array): void;
|
|
15
22
|
remove(id: number): Promise<void>;
|
|
23
|
+
removeSync(id: number): void;
|
|
16
24
|
commit(): Promise<void>;
|
|
17
25
|
abort(): Promise<void>;
|
|
18
26
|
}
|
|
19
27
|
export declare class IndexedDBStore implements Store {
|
|
20
28
|
protected db: IDBDatabase;
|
|
21
|
-
cache: Map<number,
|
|
29
|
+
cache: Map<number, Uint8Array<ArrayBufferLike>>;
|
|
22
30
|
constructor(db: IDBDatabase);
|
|
23
31
|
sync(): Promise<void>;
|
|
24
32
|
get name(): string;
|
|
@@ -52,7 +60,7 @@ declare const _IndexedDB: {
|
|
|
52
60
|
readonly required: false;
|
|
53
61
|
};
|
|
54
62
|
};
|
|
55
|
-
readonly isAvailable: (idbFactory
|
|
63
|
+
readonly isAvailable: ({ idbFactory }: IndexedDBOptions) => Promise<boolean>;
|
|
56
64
|
readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<StoreFS<IndexedDBStore>>;
|
|
57
65
|
};
|
|
58
66
|
type _IndexedDB = typeof _IndexedDB;
|
package/dist/IndexedDB.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StoreFS, Transaction } from '@zenfs/core';
|
|
2
|
+
import { log } from 'kerium';
|
|
2
3
|
import { convertException } from './utils.js';
|
|
3
4
|
function wrap(request) {
|
|
4
5
|
return new Promise((resolve, reject) => {
|
|
@@ -12,31 +13,54 @@ function wrap(request) {
|
|
|
12
13
|
/**
|
|
13
14
|
* @internal @hidden
|
|
14
15
|
*/
|
|
15
|
-
export class IndexedDBTransaction extends
|
|
16
|
+
export class IndexedDBTransaction extends Transaction {
|
|
17
|
+
/**
|
|
18
|
+
* Run a asynchronous operation from a sync context. Not magic and subject to (race) conditions.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
async(promise) {
|
|
22
|
+
this.asyncDone = this.asyncDone.then(() => promise);
|
|
23
|
+
}
|
|
16
24
|
constructor(tx, store) {
|
|
17
25
|
super(store);
|
|
18
26
|
this.tx = tx;
|
|
19
27
|
this.store = store;
|
|
28
|
+
this.asyncDone = Promise.resolve();
|
|
20
29
|
this._idb = tx.objectStore(store.name);
|
|
21
30
|
}
|
|
22
31
|
async keys() {
|
|
23
32
|
return (await wrap(this._idb.getAllKeys())).filter(k => typeof k == 'string').map(k => Number(k));
|
|
24
33
|
}
|
|
25
34
|
async get(id) {
|
|
26
|
-
const data = await wrap(this._idb.get(id
|
|
35
|
+
const data = await wrap(this._idb.get(id));
|
|
27
36
|
if (data)
|
|
28
|
-
this.
|
|
37
|
+
this.store.cache.set(id, new Uint8Array(data));
|
|
29
38
|
return data;
|
|
30
39
|
}
|
|
40
|
+
getSync(id, offset, end) {
|
|
41
|
+
if (!this.store.cache.has(id))
|
|
42
|
+
return;
|
|
43
|
+
const data = new Uint8Array(this.store.cache.get(id));
|
|
44
|
+
end ?? (end = data.byteLength);
|
|
45
|
+
return data.subarray(offset, end);
|
|
46
|
+
}
|
|
31
47
|
async set(id, data) {
|
|
32
|
-
this.
|
|
33
|
-
await wrap(this._idb.put(data, id
|
|
48
|
+
this.store.cache.set(id, new Uint8Array(data));
|
|
49
|
+
await wrap(this._idb.put(data, id));
|
|
50
|
+
}
|
|
51
|
+
setSync(id, data) {
|
|
52
|
+
this.async(this.set(id, data));
|
|
34
53
|
}
|
|
35
54
|
remove(id) {
|
|
36
55
|
this.store.cache.delete(id);
|
|
37
|
-
return wrap(this._idb.delete(id
|
|
56
|
+
return wrap(this._idb.delete(id));
|
|
57
|
+
}
|
|
58
|
+
removeSync(id) {
|
|
59
|
+
this.store.cache.delete(id);
|
|
60
|
+
this.async(this.remove(id));
|
|
38
61
|
}
|
|
39
62
|
async commit() {
|
|
63
|
+
await this.asyncDone;
|
|
40
64
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
41
65
|
this.tx.oncomplete = () => resolve();
|
|
42
66
|
this.tx.onerror = () => reject(convertException(this.tx.error));
|
|
@@ -44,6 +68,7 @@ export class IndexedDBTransaction extends AsyncTransaction {
|
|
|
44
68
|
return promise;
|
|
45
69
|
}
|
|
46
70
|
async abort() {
|
|
71
|
+
await this.asyncDone;
|
|
47
72
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
48
73
|
this.tx.onabort = () => resolve();
|
|
49
74
|
this.tx.onerror = () => reject(convertException(this.tx.error));
|
|
@@ -89,11 +114,10 @@ const _IndexedDB = {
|
|
|
89
114
|
storeName: { type: 'string', required: false },
|
|
90
115
|
idbFactory: { type: 'object', required: false },
|
|
91
116
|
},
|
|
92
|
-
async isAvailable(idbFactory = globalThis.indexedDB) {
|
|
117
|
+
async isAvailable({ idbFactory = globalThis.indexedDB }) {
|
|
93
118
|
try {
|
|
94
|
-
if (!(idbFactory instanceof IDBFactory))
|
|
119
|
+
if (!(idbFactory instanceof IDBFactory))
|
|
95
120
|
return false;
|
|
96
|
-
}
|
|
97
121
|
const req = idbFactory.open('__zenfs_test');
|
|
98
122
|
await wrap(req);
|
|
99
123
|
return true;
|
|
@@ -102,7 +126,7 @@ const _IndexedDB = {
|
|
|
102
126
|
return false;
|
|
103
127
|
}
|
|
104
128
|
finally {
|
|
105
|
-
idbFactory
|
|
129
|
+
idbFactory?.deleteDatabase('__zenfs_test');
|
|
106
130
|
}
|
|
107
131
|
},
|
|
108
132
|
async create(options) {
|
package/dist/access.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreationOptions, FileSystem } from '@zenfs/core';
|
|
1
|
+
import type { CreationOptions, FileSystem, InodeLike } from '@zenfs/core';
|
|
2
2
|
import { IndexFS } from '@zenfs/core';
|
|
3
3
|
export interface WebAccessOptions {
|
|
4
4
|
handle: FileSystemDirectoryHandle;
|
|
@@ -24,7 +24,7 @@ export declare class WebAccessFS extends WebAccessFS_base {
|
|
|
24
24
|
_sync: FileSystem;
|
|
25
25
|
constructor(handle: FileSystemDirectoryHandle);
|
|
26
26
|
remove(path: string): Promise<void>;
|
|
27
|
-
protected removeSync(
|
|
27
|
+
protected removeSync(): void;
|
|
28
28
|
read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
|
|
29
29
|
write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
|
|
30
30
|
/**
|
|
@@ -32,8 +32,8 @@ export declare class WebAccessFS extends WebAccessFS_base {
|
|
|
32
32
|
* @deprecated @internal @hidden
|
|
33
33
|
*/
|
|
34
34
|
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
35
|
-
mkdir(path: string,
|
|
36
|
-
protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string
|
|
35
|
+
mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
|
|
36
|
+
protected get<const T extends FileSystemHandleKind | null>(kind: T | undefined, path: string): T extends FileSystemHandleKind ? HKindToType<T> : FileSystemHandle;
|
|
37
37
|
}
|
|
38
38
|
declare const _WebAccess: {
|
|
39
39
|
readonly name: "WebAccess";
|
package/dist/access.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Async, constants,
|
|
1
|
+
import { Async, constants, IndexFS, InMemory, Inode } from '@zenfs/core';
|
|
2
|
+
import { basename, dirname, join } from '@zenfs/core/path.js';
|
|
2
3
|
import { S_IFDIR, S_IFMT } from '@zenfs/core/vfs/constants.js';
|
|
3
|
-
import {
|
|
4
|
+
import { log, withErrno } from 'kerium';
|
|
4
5
|
import { _throw } from 'utilium';
|
|
5
6
|
import { convertException } from './utils.js';
|
|
6
7
|
function isResizable(buffer) {
|
|
@@ -49,7 +50,7 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
49
50
|
continue;
|
|
50
51
|
}
|
|
51
52
|
if (!isKind(handle, 'directory'))
|
|
52
|
-
throw
|
|
53
|
+
throw withErrno('EIO', 'Invalid handle');
|
|
53
54
|
this.index.set(path, new Inode({ mode: 0o777 | constants.S_IFDIR, size: 0 }));
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -59,26 +60,25 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
59
60
|
/**
|
|
60
61
|
* @hidden
|
|
61
62
|
*/
|
|
62
|
-
this._sync = InMemory.create({
|
|
63
|
-
this.attributes.set('no_buffer_resize');
|
|
64
|
-
this.attributes.set('setid');
|
|
63
|
+
this._sync = InMemory.create({ label: 'accessfs-cache' });
|
|
64
|
+
this.attributes.set('no_buffer_resize', true);
|
|
65
65
|
this._handles.set('/', handle);
|
|
66
66
|
}
|
|
67
67
|
async remove(path) {
|
|
68
68
|
const handle = this.get('directory', dirname(path));
|
|
69
69
|
await handle.removeEntry(basename(path), { recursive: true }).catch(ex => _throw(convertException(ex, path)));
|
|
70
70
|
}
|
|
71
|
-
removeSync(
|
|
72
|
-
throw log.crit(
|
|
71
|
+
removeSync() {
|
|
72
|
+
throw log.crit(withErrno('ENOSYS'));
|
|
73
73
|
}
|
|
74
74
|
async read(path, buffer, offset, end) {
|
|
75
75
|
if (end <= offset)
|
|
76
76
|
return;
|
|
77
|
-
const handle = this.get('file', path
|
|
77
|
+
const handle = this.get('file', path);
|
|
78
78
|
const file = await handle.getFile();
|
|
79
79
|
const data = await file.arrayBuffer();
|
|
80
80
|
if (data.byteLength < end - offset)
|
|
81
|
-
throw
|
|
81
|
+
throw withErrno('ENODATA');
|
|
82
82
|
buffer.set(new Uint8Array(data, offset, end - offset));
|
|
83
83
|
}
|
|
84
84
|
async write(path, buffer, offset) {
|
|
@@ -89,21 +89,21 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
89
89
|
}
|
|
90
90
|
const inode = this.index.get(path);
|
|
91
91
|
if (!inode)
|
|
92
|
-
throw
|
|
92
|
+
throw withErrno('ENOENT');
|
|
93
93
|
const isDir = (inode.mode & S_IFMT) == S_IFDIR;
|
|
94
94
|
let handle;
|
|
95
95
|
try {
|
|
96
|
-
handle = this.get(isDir ? 'directory' : 'file', path
|
|
96
|
+
handle = this.get(isDir ? 'directory' : 'file', path);
|
|
97
97
|
}
|
|
98
98
|
catch {
|
|
99
|
-
const parent = this.get('directory', dirname(path)
|
|
99
|
+
const parent = this.get('directory', dirname(path));
|
|
100
100
|
handle = await parent[isDir ? 'getDirectoryHandle' : 'getFileHandle'](basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
101
101
|
this._handles.set(path, handle);
|
|
102
102
|
}
|
|
103
103
|
if (isDir)
|
|
104
104
|
return;
|
|
105
105
|
if (isKind(handle, 'directory')) {
|
|
106
|
-
log.crit(
|
|
106
|
+
log.crit(withErrno('EIO', 'Mismatch in entry kind on write'));
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
109
|
const writable = await handle.createWritable();
|
|
@@ -126,18 +126,19 @@ export class WebAccessFS extends Async(IndexFS) {
|
|
|
126
126
|
async writeFile(path, data) {
|
|
127
127
|
return this.write(path, data, 0);
|
|
128
128
|
}
|
|
129
|
-
async mkdir(path,
|
|
130
|
-
await super.mkdir(path,
|
|
131
|
-
const handle = this.get('directory', dirname(path)
|
|
129
|
+
async mkdir(path, options) {
|
|
130
|
+
const inode = await super.mkdir(path, options);
|
|
131
|
+
const handle = this.get('directory', dirname(path));
|
|
132
132
|
const dir = await handle.getDirectoryHandle(basename(path), { create: true }).catch((ex) => _throw(convertException(ex, path)));
|
|
133
133
|
this._handles.set(path, dir);
|
|
134
|
+
return inode;
|
|
134
135
|
}
|
|
135
|
-
get(kind = null, path
|
|
136
|
+
get(kind = null, path) {
|
|
136
137
|
const handle = this._handles.get(path);
|
|
137
138
|
if (!handle)
|
|
138
|
-
throw
|
|
139
|
+
throw withErrno('ENODATA');
|
|
139
140
|
if (kind && !isKind(handle, kind))
|
|
140
|
-
throw
|
|
141
|
+
throw withErrno(kind == 'directory' ? 'ENOTDIR' : 'EISDIR');
|
|
141
142
|
return handle;
|
|
142
143
|
}
|
|
143
144
|
}
|
package/dist/devices/dsp.js
CHANGED
|
@@ -44,10 +44,10 @@ export async function dsp(options = {}) {
|
|
|
44
44
|
init(ino, options) {
|
|
45
45
|
return { data: dsp, major: 14, minor: 3 };
|
|
46
46
|
},
|
|
47
|
-
|
|
47
|
+
read() {
|
|
48
48
|
return;
|
|
49
49
|
},
|
|
50
|
-
|
|
50
|
+
write(device, buffer, offset) {
|
|
51
51
|
device.data.port.postMessage(buffer.buffer);
|
|
52
52
|
},
|
|
53
53
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { withErrno } from 'kerium';
|
|
2
2
|
let framebufferN = 0;
|
|
3
3
|
/**
|
|
4
4
|
* A frame buffer
|
|
@@ -17,7 +17,7 @@ export const framebuffer = {
|
|
|
17
17
|
}
|
|
18
18
|
const context = canvas.getContext('2d');
|
|
19
19
|
if (!context) {
|
|
20
|
-
throw
|
|
20
|
+
throw withErrno('EIO', 'Could not get context from canvas whilst initializing frame buffer.');
|
|
21
21
|
}
|
|
22
22
|
const image = new ImageData(canvas.width, canvas.height);
|
|
23
23
|
return {
|
|
@@ -27,8 +27,8 @@ export const framebuffer = {
|
|
|
27
27
|
name: 'fb',
|
|
28
28
|
};
|
|
29
29
|
},
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
read() { },
|
|
31
|
+
write({ data: { image, context } }, buffer, offset) {
|
|
32
32
|
image.data.set(buffer, offset);
|
|
33
33
|
context.putImageData(image, 0, 0);
|
|
34
34
|
return buffer.byteLength;
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Store, SyncMapStore } from '@zenfs/core';
|
|
2
2
|
import { StoreFS, SyncMapTransaction } from '@zenfs/core';
|
|
3
3
|
/**
|
|
4
4
|
* A synchronous key-value store backed by Storage.
|
|
@@ -39,7 +39,7 @@ declare const _WebStorage: {
|
|
|
39
39
|
/**
|
|
40
40
|
* @todo Consider replacing `instanceof` with a duck-typing check?
|
|
41
41
|
*/
|
|
42
|
-
readonly isAvailable: (
|
|
42
|
+
readonly isAvailable: (config?: WebStorageOptions) => boolean;
|
|
43
43
|
readonly create: ({ storage }: WebStorageOptions) => StoreFS<WebStorageStore>;
|
|
44
44
|
};
|
|
45
45
|
type _WebStorage = typeof _WebStorage;
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { withErrno } from 'kerium';
|
|
2
|
+
import { StoreFS, SyncMapTransaction } from '@zenfs/core';
|
|
3
|
+
import { decodeASCII, encodeASCII } from 'utilium';
|
|
2
4
|
/**
|
|
3
5
|
* A synchronous key-value store backed by Storage.
|
|
4
6
|
*/
|
|
@@ -28,14 +30,14 @@ export class WebStorageStore {
|
|
|
28
30
|
if (typeof data != 'string') {
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
|
-
return
|
|
33
|
+
return encodeASCII(data);
|
|
32
34
|
}
|
|
33
35
|
set(key, data) {
|
|
34
36
|
try {
|
|
35
|
-
this.storage.setItem(key.toString(),
|
|
37
|
+
this.storage.setItem(key.toString(), decodeASCII(data));
|
|
36
38
|
}
|
|
37
39
|
catch {
|
|
38
|
-
throw
|
|
40
|
+
throw withErrno('ENOSPC');
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
delete(key) {
|
|
@@ -43,7 +45,7 @@ export class WebStorageStore {
|
|
|
43
45
|
this.storage.removeItem(key.toString());
|
|
44
46
|
}
|
|
45
47
|
catch (e) {
|
|
46
|
-
throw
|
|
48
|
+
throw withErrno('EIO', `Unable to delete '${key}': ${e}`);
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -58,8 +60,8 @@ const _WebStorage = {
|
|
|
58
60
|
/**
|
|
59
61
|
* @todo Consider replacing `instanceof` with a duck-typing check?
|
|
60
62
|
*/
|
|
61
|
-
isAvailable(
|
|
62
|
-
return storage instanceof globalThis.Storage;
|
|
63
|
+
isAvailable(config) {
|
|
64
|
+
return (config?.storage ?? globalThis.localStorage) instanceof globalThis.Storage;
|
|
63
65
|
},
|
|
64
66
|
create({ storage = globalThis.localStorage }) {
|
|
65
67
|
return new StoreFS(new WebStorageStore(storage));
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Exception } from 'kerium';
|
|
2
2
|
/** @internal */
|
|
3
|
-
export type ConvertException =
|
|
3
|
+
export type ConvertException = Exception | DOMException | Error;
|
|
4
4
|
/**
|
|
5
5
|
* Handles converting errors, then rethrowing them
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
|
-
export declare function convertException(ex: ConvertException, path?: string
|
|
8
|
+
export declare function convertException(ex: ConvertException, path?: string): Exception;
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Exception, Errno } from 'kerium';
|
|
2
2
|
/**
|
|
3
3
|
* Converts a DOMException into an Errno
|
|
4
4
|
* @see https://developer.mozilla.org/Web/API/DOMException
|
|
@@ -57,12 +57,13 @@ function errnoForDOMException(ex) {
|
|
|
57
57
|
* Handles converting errors, then rethrowing them
|
|
58
58
|
* @internal
|
|
59
59
|
*/
|
|
60
|
-
export function convertException(ex, path
|
|
61
|
-
if (ex instanceof
|
|
60
|
+
export function convertException(ex, path) {
|
|
61
|
+
if (ex instanceof Exception)
|
|
62
62
|
return ex;
|
|
63
63
|
const code = ex instanceof DOMException ? Errno[errnoForDOMException(ex)] : Errno.EIO;
|
|
64
|
-
const error = new
|
|
64
|
+
const error = new Exception(code, ex.message);
|
|
65
65
|
error.stack = ex.stack;
|
|
66
|
+
Error.captureStackTrace?.(error, convertException);
|
|
66
67
|
error.cause = ex.cause;
|
|
67
68
|
return error;
|
|
68
69
|
}
|
package/dist/xml.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { CreationOptions,
|
|
2
|
-
import { FileSystem,
|
|
1
|
+
import type { CreationOptions, InodeLike, StatsLike } from '@zenfs/core';
|
|
2
|
+
import { FileSystem, Inode } from '@zenfs/core';
|
|
3
3
|
export interface XMLOptions {
|
|
4
4
|
/**
|
|
5
5
|
* The root `fs` element
|
|
@@ -18,15 +18,15 @@ export declare class XMLFS extends XMLFS_base {
|
|
|
18
18
|
*/
|
|
19
19
|
root?: Element);
|
|
20
20
|
renameSync(oldPath: string, newPath: string): void;
|
|
21
|
-
statSync(path: string):
|
|
22
|
-
|
|
23
|
-
createFileSync(path: string, flag: string, mode: number, { uid, gid }: CreationOptions): File;
|
|
21
|
+
statSync(path: string): Inode;
|
|
22
|
+
createFileSync(path: string, options: CreationOptions): Inode;
|
|
24
23
|
unlinkSync(path: string): void;
|
|
25
24
|
rmdirSync(path: string): void;
|
|
26
|
-
mkdirSync(path: string,
|
|
25
|
+
mkdirSync(path: string, options: CreationOptions): InodeLike;
|
|
27
26
|
readdirSync(path: string): string[];
|
|
28
27
|
linkSync(target: string, link: string): void;
|
|
29
|
-
|
|
28
|
+
touchSync(path: string, metadata: Partial<InodeLike>): void;
|
|
29
|
+
syncSync(): void;
|
|
30
30
|
readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
|
|
31
31
|
writeSync(path: string, buffer: Uint8Array, offset: number): void;
|
|
32
32
|
toString(): string;
|
|
@@ -39,7 +39,7 @@ declare const _XML: {
|
|
|
39
39
|
name: string;
|
|
40
40
|
options: {
|
|
41
41
|
root: {
|
|
42
|
-
type:
|
|
42
|
+
type: string;
|
|
43
43
|
required: false;
|
|
44
44
|
};
|
|
45
45
|
};
|
package/dist/xml.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { withErrno } from 'kerium';
|
|
2
|
+
import { _inode_fields, constants, FileSystem, Inode, Sync } from '@zenfs/core';
|
|
3
|
+
import { basename, dirname } from '@zenfs/core/path.js';
|
|
4
|
+
import { decodeASCII, encodeASCII } from 'utilium';
|
|
3
5
|
function get_stats(node) {
|
|
4
6
|
const stats = {};
|
|
5
7
|
for (const key of _inode_fields) {
|
|
@@ -7,7 +9,7 @@ function get_stats(node) {
|
|
|
7
9
|
if (value !== null && value !== undefined)
|
|
8
10
|
stats[key] = parseInt(value, 16);
|
|
9
11
|
}
|
|
10
|
-
return new
|
|
12
|
+
return new Inode(stats);
|
|
11
13
|
}
|
|
12
14
|
function set_stats(node, stats) {
|
|
13
15
|
for (const key of Object.keys(stats)) {
|
|
@@ -35,9 +37,8 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
35
37
|
root = new DOMParser().parseFromString('<fs></fs>', 'application/xml').documentElement) {
|
|
36
38
|
super(0x20786d6c, 'xmltmpfs');
|
|
37
39
|
this.root = root;
|
|
38
|
-
this.attributes.set('setid');
|
|
39
40
|
try {
|
|
40
|
-
this.mkdirSync('/',
|
|
41
|
+
this.mkdirSync('/', { uid: 0, gid: 0, mode: 0o777 });
|
|
41
42
|
}
|
|
42
43
|
catch (e) {
|
|
43
44
|
const error = e;
|
|
@@ -53,72 +54,68 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
53
54
|
statSync(path) {
|
|
54
55
|
return get_stats(this.get('stat', path));
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
const node = this.get('openFile', path);
|
|
58
|
-
return new LazyFile(this, path, flag, get_stats(node));
|
|
59
|
-
}
|
|
60
|
-
createFileSync(path, flag, mode, { uid, gid }) {
|
|
57
|
+
createFileSync(path, options) {
|
|
61
58
|
const parent = this.statSync(dirname(path));
|
|
62
|
-
const
|
|
63
|
-
mode: mode | constants.S_IFREG,
|
|
64
|
-
uid: parent.mode & constants.S_ISUID ? parent.uid : uid,
|
|
65
|
-
gid: parent.mode & constants.S_ISGID ? parent.gid : gid,
|
|
59
|
+
const inode = new Inode({
|
|
60
|
+
mode: options.mode | constants.S_IFREG,
|
|
61
|
+
uid: parent.mode & constants.S_ISUID ? parent.uid : options.uid,
|
|
62
|
+
gid: parent.mode & constants.S_ISGID ? parent.gid : options.gid,
|
|
66
63
|
});
|
|
67
|
-
this.create('createFile', path,
|
|
68
|
-
return
|
|
64
|
+
this.create('createFile', path, inode);
|
|
65
|
+
return inode;
|
|
69
66
|
}
|
|
70
67
|
unlinkSync(path) {
|
|
71
68
|
const node = this.get('unlink', path);
|
|
72
|
-
if (get_stats(node).
|
|
73
|
-
throw
|
|
69
|
+
if (get_stats(node).mode & constants.S_IFDIR)
|
|
70
|
+
throw withErrno('EISDIR');
|
|
74
71
|
this.remove('unlink', node, path);
|
|
75
72
|
}
|
|
76
73
|
rmdirSync(path) {
|
|
77
74
|
const node = this.get('rmdir', path);
|
|
78
75
|
if (node.textContent?.length)
|
|
79
|
-
throw
|
|
80
|
-
if (!get_stats(node).
|
|
81
|
-
throw
|
|
76
|
+
throw withErrno('ENOTEMPTY');
|
|
77
|
+
if (!(get_stats(node).mode & constants.S_IFDIR))
|
|
78
|
+
throw withErrno('ENOTDIR');
|
|
82
79
|
this.remove('rmdir', node, path);
|
|
83
80
|
}
|
|
84
|
-
mkdirSync(path,
|
|
81
|
+
mkdirSync(path, options) {
|
|
85
82
|
const parent = this.statSync(dirname(path));
|
|
86
|
-
const
|
|
87
|
-
mode: mode | constants.S_IFDIR,
|
|
88
|
-
uid: parent.mode & constants.S_ISUID ? parent.uid : uid,
|
|
89
|
-
gid: parent.mode & constants.S_ISGID ? parent.gid : gid,
|
|
83
|
+
const inode = new Inode({
|
|
84
|
+
mode: options.mode | constants.S_IFDIR,
|
|
85
|
+
uid: parent.mode & constants.S_ISUID ? parent.uid : options.uid,
|
|
86
|
+
gid: parent.mode & constants.S_ISGID ? parent.gid : options.gid,
|
|
90
87
|
});
|
|
91
|
-
|
|
88
|
+
this.create('mkdir', path, inode).textContent = '[]';
|
|
89
|
+
return inode;
|
|
92
90
|
}
|
|
93
91
|
readdirSync(path) {
|
|
94
92
|
const node = this.get('readdir', path);
|
|
95
|
-
if (!get_stats(node).
|
|
96
|
-
throw
|
|
93
|
+
if (!(get_stats(node).mode & constants.S_IFDIR))
|
|
94
|
+
throw withErrno('ENOTDIR');
|
|
97
95
|
try {
|
|
98
96
|
return JSON.parse(node.textContent);
|
|
99
97
|
}
|
|
100
98
|
catch (e) {
|
|
101
|
-
throw
|
|
99
|
+
throw withErrno('EIO', 'Invalid directory listing: ' + e);
|
|
102
100
|
}
|
|
103
101
|
}
|
|
104
102
|
linkSync(target, link) {
|
|
105
103
|
const node = this.get('link', target);
|
|
106
104
|
this.add('link', node, link);
|
|
107
105
|
}
|
|
108
|
-
|
|
109
|
-
const node = this.get('
|
|
110
|
-
|
|
111
|
-
node.textContent = decodeRaw(data);
|
|
112
|
-
set_stats(node, stats);
|
|
106
|
+
touchSync(path, metadata) {
|
|
107
|
+
const node = this.get('touch', path);
|
|
108
|
+
set_stats(node, metadata);
|
|
113
109
|
}
|
|
110
|
+
syncSync() { }
|
|
114
111
|
readSync(path, buffer, offset, end) {
|
|
115
112
|
const node = this.get('read', path);
|
|
116
|
-
const raw =
|
|
113
|
+
const raw = encodeASCII(node.textContent.slice(offset, end));
|
|
117
114
|
buffer.set(raw);
|
|
118
115
|
}
|
|
119
116
|
writeSync(path, buffer, offset) {
|
|
120
117
|
const node = this.get('write', path);
|
|
121
|
-
const data =
|
|
118
|
+
const data = decodeASCII(buffer);
|
|
122
119
|
const after = node.textContent.slice(offset + data.length);
|
|
123
120
|
node.textContent = node.textContent.slice(0, offset) + data + after;
|
|
124
121
|
}
|
|
@@ -128,19 +125,19 @@ export class XMLFS extends Sync(FileSystem) {
|
|
|
128
125
|
get(syscall, path) {
|
|
129
126
|
const nodes = this.root.children;
|
|
130
127
|
if (!nodes)
|
|
131
|
-
throw
|
|
128
|
+
throw withErrno('EIO');
|
|
132
129
|
for (let i = 0; i < nodes.length; i++) {
|
|
133
130
|
if (get_paths(nodes[i]).includes(path))
|
|
134
131
|
return nodes[i];
|
|
135
132
|
}
|
|
136
|
-
throw
|
|
133
|
+
throw withErrno('ENOENT');
|
|
137
134
|
}
|
|
138
135
|
create(syscall, path, stats) {
|
|
139
136
|
if (this.existsSync(path))
|
|
140
|
-
throw
|
|
137
|
+
throw withErrno('EEXIST');
|
|
141
138
|
const node = document.createElement('file');
|
|
142
139
|
this.add(syscall, node, path);
|
|
143
|
-
set_stats(node, new
|
|
140
|
+
set_stats(node, new Inode({
|
|
144
141
|
...stats,
|
|
145
142
|
uid: stats.mode,
|
|
146
143
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/dom",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "DOM backends for ZenFS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -61,8 +61,9 @@
|
|
|
61
61
|
"typescript-eslint": "^8.8.1"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@zenfs/core": "^1.
|
|
65
|
-
"
|
|
64
|
+
"@zenfs/core": "^2.1.0",
|
|
65
|
+
"kerium": "^1.3.4",
|
|
66
|
+
"utilium": "^2.0.0"
|
|
66
67
|
},
|
|
67
68
|
"keywords": [
|
|
68
69
|
"filesystem",
|