@zenfs/core 0.5.2 → 0.5.4
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/AsyncStore.d.ts +7 -17
- package/dist/backends/AsyncStore.js +22 -30
- package/dist/backends/InMemory.d.ts +2 -2
- package/dist/backends/InMemory.js +2 -2
- package/dist/backends/SyncStore.d.ts +10 -20
- package/dist/backends/SyncStore.js +16 -21
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +3 -3
- package/dist/emulation/promises.d.ts +7 -7
- package/dist/emulation/promises.js +43 -32
- package/package.json +1 -1
- package/readme.md +2 -2
|
@@ -4,41 +4,31 @@ import { FileSystem, type FileSystemMetadata } from '../filesystem.js';
|
|
|
4
4
|
import { type Ino } from '../inode.js';
|
|
5
5
|
import { type Stats } from '../stats.js';
|
|
6
6
|
/**
|
|
7
|
-
* Represents an
|
|
7
|
+
* Represents an asynchronous key-value store.
|
|
8
8
|
*/
|
|
9
9
|
export interface AsyncStore {
|
|
10
10
|
/**
|
|
11
|
-
* The name of the
|
|
11
|
+
* The name of the store.
|
|
12
12
|
*/
|
|
13
13
|
name: string;
|
|
14
14
|
/**
|
|
15
|
-
* Empties the
|
|
15
|
+
* Empties the store completely.
|
|
16
16
|
*/
|
|
17
17
|
clear(): Promise<void>;
|
|
18
18
|
/**
|
|
19
|
-
* Begins a
|
|
19
|
+
* Begins a transaction.
|
|
20
20
|
*/
|
|
21
|
-
beginTransaction(
|
|
22
|
-
/**
|
|
23
|
-
* Begins a read-only transaction.
|
|
24
|
-
*/
|
|
25
|
-
beginTransaction(type: 'readonly'): AsyncROTransaction;
|
|
26
|
-
beginTransaction(type: string): AsyncROTransaction;
|
|
21
|
+
beginTransaction(): AsyncTransaction;
|
|
27
22
|
}
|
|
28
23
|
/**
|
|
29
|
-
* Represents an asynchronous
|
|
24
|
+
* Represents an asynchronous transaction.
|
|
30
25
|
*/
|
|
31
|
-
export interface
|
|
26
|
+
export interface AsyncTransaction {
|
|
32
27
|
/**
|
|
33
28
|
* Retrieves the data at the given key.
|
|
34
29
|
* @param key The key to look under for data.
|
|
35
30
|
*/
|
|
36
31
|
get(key: Ino): Promise<Uint8Array>;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Represents an asynchronous read-write transaction.
|
|
40
|
-
*/
|
|
41
|
-
export interface AsyncRWTransaction extends AsyncROTransaction {
|
|
42
32
|
/**
|
|
43
33
|
* Adds the data to the store under the given key. Overwrites any existing
|
|
44
34
|
* data.
|
|
@@ -123,7 +123,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
123
123
|
c.reset();
|
|
124
124
|
}
|
|
125
125
|
try {
|
|
126
|
-
const tx = this.store.beginTransaction(
|
|
126
|
+
const tx = this.store.beginTransaction(), oldParent = dirname(oldPath), oldName = basename(oldPath), newParent = dirname(newPath), newName = basename(newPath),
|
|
127
127
|
// Remove oldPath from parent's directory listing.
|
|
128
128
|
oldDirNode = await this.findINode(tx, oldParent), oldDirList = await this.getDirListing(tx, oldDirNode, oldParent);
|
|
129
129
|
if (!oldDirNode.toStats().hasAccess(W_OK, cred)) {
|
|
@@ -190,7 +190,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
async stat(p, cred) {
|
|
193
|
-
const tx = this.store.beginTransaction(
|
|
193
|
+
const tx = this.store.beginTransaction();
|
|
194
194
|
const inode = await this.findINode(tx, p);
|
|
195
195
|
if (!inode) {
|
|
196
196
|
throw ApiError.ENOENT(p);
|
|
@@ -202,12 +202,12 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
202
202
|
return stats;
|
|
203
203
|
}
|
|
204
204
|
async createFile(p, flag, mode, cred) {
|
|
205
|
-
const tx = this.store.beginTransaction(
|
|
205
|
+
const tx = this.store.beginTransaction(), data = new Uint8Array(0), newFile = await this.commitNewFile(tx, p, FileType.FILE, mode, cred, data);
|
|
206
206
|
// Open the file.
|
|
207
207
|
return new AsyncFile(this, p, flag, newFile.toStats(), data);
|
|
208
208
|
}
|
|
209
209
|
async openFile(p, flag, cred) {
|
|
210
|
-
const tx = this.store.beginTransaction(
|
|
210
|
+
const tx = this.store.beginTransaction(), node = await this.findINode(tx, p), data = await tx.get(node.ino);
|
|
211
211
|
if (!node.toStats().hasAccess(flagToMode(flag), cred)) {
|
|
212
212
|
throw ApiError.EACCES(p);
|
|
213
213
|
}
|
|
@@ -228,11 +228,11 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
228
228
|
await this.removeEntry(p, true, cred);
|
|
229
229
|
}
|
|
230
230
|
async mkdir(p, mode, cred) {
|
|
231
|
-
const tx = this.store.beginTransaction(
|
|
231
|
+
const tx = this.store.beginTransaction(), data = encode('{}');
|
|
232
232
|
await this.commitNewFile(tx, p, FileType.DIRECTORY, mode, cred, data);
|
|
233
233
|
}
|
|
234
234
|
async readdir(p, cred) {
|
|
235
|
-
const tx = this.store.beginTransaction(
|
|
235
|
+
const tx = this.store.beginTransaction();
|
|
236
236
|
const node = await this.findINode(tx, p);
|
|
237
237
|
if (!node.toStats().hasAccess(R_OK, cred)) {
|
|
238
238
|
throw ApiError.EACCES(p);
|
|
@@ -244,7 +244,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
244
244
|
* @todo Ensure mtime updates properly, and use that to determine if a data update is required.
|
|
245
245
|
*/
|
|
246
246
|
async sync(p, data, stats) {
|
|
247
|
-
const tx = this.store.beginTransaction(
|
|
247
|
+
const tx = this.store.beginTransaction(),
|
|
248
248
|
// We use the _findInode helper because we actually need the INode id.
|
|
249
249
|
fileInodeId = await this._findINode(tx, dirname(p), basename(p)), fileInode = await this.getINode(tx, fileInodeId, p), inodeChanged = fileInode.update(stats);
|
|
250
250
|
try {
|
|
@@ -262,7 +262,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
262
262
|
await tx.commit();
|
|
263
263
|
}
|
|
264
264
|
async link(existing, newpath, cred) {
|
|
265
|
-
const tx = this.store.beginTransaction(
|
|
265
|
+
const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = await this.findINode(tx, existingDir);
|
|
266
266
|
if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
|
|
267
267
|
throw ApiError.EACCES(existingDir);
|
|
268
268
|
}
|
|
@@ -291,7 +291,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
291
291
|
* Checks if the root directory exists. Creates it if it doesn't.
|
|
292
292
|
*/
|
|
293
293
|
async makeRootDirectory() {
|
|
294
|
-
const tx = this.store.beginTransaction(
|
|
294
|
+
const tx = this.store.beginTransaction();
|
|
295
295
|
if ((await tx.get(rootIno)) === undefined) {
|
|
296
296
|
// Create new inode. o777, owned by root:root
|
|
297
297
|
const dirInode = new Inode();
|
|
@@ -407,26 +407,18 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
407
407
|
* Adds a new node under a random ID. Retries 5 times before giving up in
|
|
408
408
|
* the exceedingly unlikely chance that we try to reuse a random ino.
|
|
409
409
|
*/
|
|
410
|
-
async addNewNode(tx, data) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return reroll();
|
|
423
|
-
}
|
|
424
|
-
else {
|
|
425
|
-
return ino;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
return reroll();
|
|
410
|
+
async addNewNode(tx, data, _maxAttempts = 5) {
|
|
411
|
+
if (_maxAttempts <= 0) {
|
|
412
|
+
// Max retries hit. Return with an error.
|
|
413
|
+
throw new ApiError(ErrorCode.EIO, 'Unable to commit data to key-value store.');
|
|
414
|
+
}
|
|
415
|
+
// Make an attempt
|
|
416
|
+
const ino = randomIno();
|
|
417
|
+
const isCommited = await tx.put(ino, data, false);
|
|
418
|
+
if (!isCommited) {
|
|
419
|
+
return await this.addNewNode(tx, data, --_maxAttempts);
|
|
420
|
+
}
|
|
421
|
+
return ino;
|
|
430
422
|
}
|
|
431
423
|
/**
|
|
432
424
|
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with
|
|
@@ -490,7 +482,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
490
482
|
if (this._cache) {
|
|
491
483
|
this._cache.remove(p);
|
|
492
484
|
}
|
|
493
|
-
const tx = this.store.beginTransaction(
|
|
485
|
+
const tx = this.store.beginTransaction(), parent = dirname(p), parentNode = await this.findINode(tx, parent), parentListing = await this.getDirListing(tx, parentNode, parent), fileName = basename(p);
|
|
494
486
|
if (!parentListing[fileName]) {
|
|
495
487
|
throw ApiError.ENOENT(p);
|
|
496
488
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Ino } from '../inode.js';
|
|
2
2
|
import type { Backend } from './backend.js';
|
|
3
|
-
import { SyncStore, SimpleSyncStore,
|
|
3
|
+
import { SyncStore, SimpleSyncStore, SyncTransaction } from './SyncStore.js';
|
|
4
4
|
/**
|
|
5
5
|
* A simple in-memory store
|
|
6
6
|
*/
|
|
@@ -9,7 +9,7 @@ export declare class InMemoryStore implements SyncStore, SimpleSyncStore {
|
|
|
9
9
|
private store;
|
|
10
10
|
constructor(name?: string);
|
|
11
11
|
clear(): void;
|
|
12
|
-
beginTransaction():
|
|
12
|
+
beginTransaction(): SyncTransaction;
|
|
13
13
|
get(key: Ino): Uint8Array;
|
|
14
14
|
put(key: Ino, data: Uint8Array, overwrite: boolean): boolean;
|
|
15
15
|
remove(key: Ino): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SimpleSyncTransaction, SyncStoreFS } from './SyncStore.js';
|
|
2
2
|
/**
|
|
3
3
|
* A simple in-memory store
|
|
4
4
|
*/
|
|
@@ -11,7 +11,7 @@ export class InMemoryStore {
|
|
|
11
11
|
this.store.clear();
|
|
12
12
|
}
|
|
13
13
|
beginTransaction() {
|
|
14
|
-
return new
|
|
14
|
+
return new SimpleSyncTransaction(this);
|
|
15
15
|
}
|
|
16
16
|
get(key) {
|
|
17
17
|
return this.store.get(key);
|
|
@@ -16,19 +16,14 @@ export interface SyncStore {
|
|
|
16
16
|
*/
|
|
17
17
|
clear(): void;
|
|
18
18
|
/**
|
|
19
|
-
* Begins a new
|
|
19
|
+
* Begins a new transaction.
|
|
20
20
|
*/
|
|
21
|
-
beginTransaction(
|
|
22
|
-
/**
|
|
23
|
-
* Begins a new read-write transaction.
|
|
24
|
-
*/
|
|
25
|
-
beginTransaction(type: 'readwrite'): SyncRWTransaction;
|
|
26
|
-
beginTransaction(type: string): SyncROTransaction;
|
|
21
|
+
beginTransaction(): SyncTransaction;
|
|
27
22
|
}
|
|
28
23
|
/**
|
|
29
|
-
* A
|
|
24
|
+
* A transaction for a synchronous key value store.
|
|
30
25
|
*/
|
|
31
|
-
export interface
|
|
26
|
+
export interface SyncTransaction {
|
|
32
27
|
/**
|
|
33
28
|
* Retrieves the data at the given key. Throws an ApiError if an error occurs
|
|
34
29
|
* or if the key does not exist.
|
|
@@ -36,11 +31,6 @@ export interface SyncROTransaction {
|
|
|
36
31
|
* @return The data stored under the key, or undefined if not present.
|
|
37
32
|
*/
|
|
38
33
|
get(ino: Ino): Uint8Array | undefined;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* A read-write transaction for a synchronous key value store.
|
|
42
|
-
*/
|
|
43
|
-
export interface SyncRWTransaction extends SyncROTransaction {
|
|
44
34
|
/**
|
|
45
35
|
* Adds the data to the store under the given key.
|
|
46
36
|
* @param ino The key to add the data under.
|
|
@@ -76,7 +66,7 @@ export interface SimpleSyncStore {
|
|
|
76
66
|
/**
|
|
77
67
|
* A simple RW transaction for simple synchronous key-value stores.
|
|
78
68
|
*/
|
|
79
|
-
export declare class
|
|
69
|
+
export declare class SimpleSyncTransaction implements SyncTransaction {
|
|
80
70
|
protected store: SimpleSyncStore;
|
|
81
71
|
/**
|
|
82
72
|
* Stores data in the keys we modify prior to modifying them.
|
|
@@ -186,25 +176,25 @@ export declare class SyncStoreFS extends SyncStoreFS_base {
|
|
|
186
176
|
* the parent.
|
|
187
177
|
* @return string The ID of the file's inode in the file system.
|
|
188
178
|
*/
|
|
189
|
-
protected _findINode(tx:
|
|
179
|
+
protected _findINode(tx: SyncTransaction, parent: string, filename: string, visited?: Set<string>): Ino;
|
|
190
180
|
/**
|
|
191
181
|
* Finds the Inode of the given path.
|
|
192
182
|
* @param p The path to look up.
|
|
193
183
|
* @return The Inode of the path p.
|
|
194
184
|
* @todo memoize/cache
|
|
195
185
|
*/
|
|
196
|
-
protected findINode(tx:
|
|
186
|
+
protected findINode(tx: SyncTransaction, p: string): Inode;
|
|
197
187
|
/**
|
|
198
188
|
* Given the ID of a node, retrieves the corresponding Inode.
|
|
199
189
|
* @param tx The transaction to use.
|
|
200
190
|
* @param p The corresponding path to the file (used for error messages).
|
|
201
191
|
* @param id The ID to look up.
|
|
202
192
|
*/
|
|
203
|
-
protected getINode(tx:
|
|
193
|
+
protected getINode(tx: SyncTransaction, id: Ino, p?: string): Inode;
|
|
204
194
|
/**
|
|
205
195
|
* Given the Inode of a directory, retrieves the corresponding directory listing.
|
|
206
196
|
*/
|
|
207
|
-
protected getDirListing(tx:
|
|
197
|
+
protected getDirListing(tx: SyncTransaction, inode: Inode, p?: string): {
|
|
208
198
|
[fileName: string]: Ino;
|
|
209
199
|
};
|
|
210
200
|
/**
|
|
@@ -212,7 +202,7 @@ export declare class SyncStoreFS extends SyncStoreFS_base {
|
|
|
212
202
|
* the exceedingly unlikely chance that we try to reuse a random GUID.
|
|
213
203
|
* @return The GUID that the data was stored under.
|
|
214
204
|
*/
|
|
215
|
-
protected addNewNode(tx:
|
|
205
|
+
protected addNewNode(tx: SyncTransaction, data: Uint8Array, _maxAttempts?: number): Ino;
|
|
216
206
|
/**
|
|
217
207
|
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with the given mode.
|
|
218
208
|
* Note: This will commit the transaction.
|
|
@@ -10,7 +10,7 @@ import { rootIno } from '../inode.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* A simple RW transaction for simple synchronous key-value stores.
|
|
12
12
|
*/
|
|
13
|
-
export class
|
|
13
|
+
export class SimpleSyncTransaction {
|
|
14
14
|
constructor(store) {
|
|
15
15
|
this.store = store;
|
|
16
16
|
/**
|
|
@@ -130,7 +130,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
130
130
|
this.makeRootDirectory();
|
|
131
131
|
}
|
|
132
132
|
renameSync(oldPath, newPath, cred) {
|
|
133
|
-
const tx = this.store.beginTransaction(
|
|
133
|
+
const tx = this.store.beginTransaction(), oldParent = dirname(oldPath), oldName = basename(oldPath), newParent = dirname(newPath), newName = basename(newPath),
|
|
134
134
|
// Remove oldPath from parent's directory listing.
|
|
135
135
|
oldDirNode = this.findINode(tx, oldParent), oldDirList = this.getDirListing(tx, oldDirNode, oldParent);
|
|
136
136
|
if (!oldDirNode.toStats().hasAccess(W_OK, cred)) {
|
|
@@ -192,7 +192,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
192
192
|
}
|
|
193
193
|
statSync(p, cred) {
|
|
194
194
|
// Get the inode to the item, convert it into a Stats object.
|
|
195
|
-
const stats = this.findINode(this.store.beginTransaction(
|
|
195
|
+
const stats = this.findINode(this.store.beginTransaction(), p).toStats();
|
|
196
196
|
if (!stats.hasAccess(R_OK, cred)) {
|
|
197
197
|
throw ApiError.EACCES(p);
|
|
198
198
|
}
|
|
@@ -203,7 +203,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
203
203
|
return this.openFileSync(p, flag, cred);
|
|
204
204
|
}
|
|
205
205
|
openFileSync(p, flag, cred) {
|
|
206
|
-
const tx = this.store.beginTransaction(
|
|
206
|
+
const tx = this.store.beginTransaction(), node = this.findINode(tx, p), data = tx.get(node.ino);
|
|
207
207
|
if (!node.toStats().hasAccess(flagToMode(flag), cred)) {
|
|
208
208
|
throw ApiError.EACCES(p);
|
|
209
209
|
}
|
|
@@ -228,7 +228,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
228
228
|
this.commitNewFile(p, FileType.DIRECTORY, mode, cred, encode('{}'));
|
|
229
229
|
}
|
|
230
230
|
readdirSync(p, cred) {
|
|
231
|
-
const tx = this.store.beginTransaction(
|
|
231
|
+
const tx = this.store.beginTransaction();
|
|
232
232
|
const node = this.findINode(tx, p);
|
|
233
233
|
if (!node.toStats().hasAccess(R_OK, cred)) {
|
|
234
234
|
throw ApiError.EACCES(p);
|
|
@@ -238,7 +238,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
238
238
|
syncSync(p, data, stats) {
|
|
239
239
|
// @todo Ensure mtime updates properly, and use that to determine if a data
|
|
240
240
|
// update is required.
|
|
241
|
-
const tx = this.store.beginTransaction(
|
|
241
|
+
const tx = this.store.beginTransaction(),
|
|
242
242
|
// We use the _findInode helper because we actually need the INode id.
|
|
243
243
|
fileInodeId = this._findINode(tx, dirname(p), basename(p)), fileInode = this.getINode(tx, fileInodeId, p), inodeChanged = fileInode.update(stats);
|
|
244
244
|
try {
|
|
@@ -256,7 +256,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
256
256
|
tx.commit();
|
|
257
257
|
}
|
|
258
258
|
linkSync(existing, newpath, cred) {
|
|
259
|
-
const tx = this.store.beginTransaction(
|
|
259
|
+
const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = this.findINode(tx, existingDir);
|
|
260
260
|
if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
|
|
261
261
|
throw ApiError.EACCES(existingDir);
|
|
262
262
|
}
|
|
@@ -285,7 +285,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
285
285
|
* Checks if the root directory exists. Creates it if it doesn't.
|
|
286
286
|
*/
|
|
287
287
|
makeRootDirectory() {
|
|
288
|
-
const tx = this.store.beginTransaction(
|
|
288
|
+
const tx = this.store.beginTransaction();
|
|
289
289
|
if (tx.get(rootIno)) {
|
|
290
290
|
return;
|
|
291
291
|
}
|
|
@@ -371,18 +371,13 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
371
371
|
* the exceedingly unlikely chance that we try to reuse a random GUID.
|
|
372
372
|
* @return The GUID that the data was stored under.
|
|
373
373
|
*/
|
|
374
|
-
addNewNode(tx, data) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
ino = randomIno();
|
|
380
|
-
tx.put(ino, data, false);
|
|
381
|
-
return ino;
|
|
382
|
-
}
|
|
383
|
-
catch (e) {
|
|
384
|
-
// Ignore and reroll.
|
|
374
|
+
addNewNode(tx, data, _maxAttempts = 5) {
|
|
375
|
+
for (let i = 0; i < _maxAttempts; i++) {
|
|
376
|
+
const ino = randomIno();
|
|
377
|
+
if (!tx.put(ino, data, false)) {
|
|
378
|
+
continue;
|
|
385
379
|
}
|
|
380
|
+
return ino;
|
|
386
381
|
}
|
|
387
382
|
throw new ApiError(ErrorCode.EIO, 'Unable to commit data to key-value store.');
|
|
388
383
|
}
|
|
@@ -396,7 +391,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
396
391
|
* @return The Inode for the new file.
|
|
397
392
|
*/
|
|
398
393
|
commitNewFile(p, type, mode, cred, data = new Uint8Array()) {
|
|
399
|
-
const tx = this.store.beginTransaction(
|
|
394
|
+
const tx = this.store.beginTransaction(), parentDir = dirname(p), fname = basename(p), parentNode = this.findINode(tx, parentDir), dirListing = this.getDirListing(tx, parentNode, parentDir);
|
|
400
395
|
//Check that the creater has correct access
|
|
401
396
|
if (!parentNode.toStats().hasAccess(W_OK, cred)) {
|
|
402
397
|
throw ApiError.EACCES(p);
|
|
@@ -438,7 +433,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
438
433
|
* @todo Update mtime.
|
|
439
434
|
*/
|
|
440
435
|
removeEntry(p, isDir, cred) {
|
|
441
|
-
const tx = this.store.beginTransaction(
|
|
436
|
+
const tx = this.store.beginTransaction(), parent = dirname(p), parentNode = this.findINode(tx, parent), parentListing = this.getDirListing(tx, parentNode, parent), fileName = basename(p), fileIno = parentListing[fileName];
|
|
442
437
|
if (!fileIno) {
|
|
443
438
|
throw ApiError.ENOENT(p);
|
|
444
439
|
}
|