@zenfs/core 0.5.4 → 0.5.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.
- package/dist/ApiError.d.ts +5 -12
- package/dist/ApiError.js +6 -27
- package/dist/FileIndex.js +10 -10
- package/dist/backends/AsyncStore.js +24 -24
- package/dist/backends/Overlay.js +17 -17
- package/dist/backends/SyncStore.js +23 -23
- package/dist/backends/backend.d.ts +3 -3
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +3 -3
- package/dist/emulation/promises.d.ts +2 -3
- package/dist/emulation/promises.js +15 -11
- package/dist/emulation/shared.d.ts +9 -1
- package/dist/emulation/shared.js +28 -40
- package/dist/emulation/sync.d.ts +3 -6
- package/dist/emulation/sync.js +17 -7
- package/dist/file.d.ts +4 -0
- package/dist/file.js +10 -14
- package/dist/stats.d.ts +2 -3
- package/dist/stats.js +6 -22
- package/dist/utils.js +6 -2
- package/package.json +1 -1
package/dist/ApiError.d.ts
CHANGED
|
@@ -80,9 +80,10 @@ export declare const ErrorStrings: {
|
|
|
80
80
|
interface ApiErrorJSON {
|
|
81
81
|
errno: ErrorCode;
|
|
82
82
|
message: string;
|
|
83
|
-
path
|
|
83
|
+
path?: string;
|
|
84
84
|
code: string;
|
|
85
85
|
stack: string;
|
|
86
|
+
syscall: string;
|
|
86
87
|
}
|
|
87
88
|
/**
|
|
88
89
|
* Represents a ZenFS error. Passed back to applications after a failed
|
|
@@ -91,18 +92,10 @@ interface ApiErrorJSON {
|
|
|
91
92
|
export declare class ApiError extends Error implements NodeJS.ErrnoException {
|
|
92
93
|
errno: ErrorCode;
|
|
93
94
|
path?: string;
|
|
95
|
+
syscall: string;
|
|
94
96
|
static fromJSON(json: ApiErrorJSON): ApiError;
|
|
95
|
-
static
|
|
96
|
-
static EACCES(path: string): ApiError;
|
|
97
|
-
static ENOENT(path: string): ApiError;
|
|
98
|
-
static EEXIST(path: string): ApiError;
|
|
99
|
-
static EISDIR(path: string): ApiError;
|
|
100
|
-
static ENOTDIR(path: string): ApiError;
|
|
101
|
-
static EPERM(path: string): ApiError;
|
|
102
|
-
static ENOTEMPTY(path: string): ApiError;
|
|
97
|
+
static With(code: string, path: string, syscall?: string): ApiError;
|
|
103
98
|
code: string;
|
|
104
|
-
syscall: string;
|
|
105
|
-
stack?: string;
|
|
106
99
|
/**
|
|
107
100
|
* Represents a ZenFS error. Passed back to applications after a failed
|
|
108
101
|
* call to the ZenFS API.
|
|
@@ -113,7 +106,7 @@ export declare class ApiError extends Error implements NodeJS.ErrnoException {
|
|
|
113
106
|
* @param type The type of the error.
|
|
114
107
|
* @param message A descriptive error message.
|
|
115
108
|
*/
|
|
116
|
-
constructor(errno: ErrorCode, message?: string, path?: string);
|
|
109
|
+
constructor(errno: ErrorCode, message?: string, path?: string, syscall?: string);
|
|
117
110
|
/**
|
|
118
111
|
* @return A friendly error message.
|
|
119
112
|
*/
|
package/dist/ApiError.js
CHANGED
|
@@ -98,34 +98,13 @@ export const ErrorStrings = {
|
|
|
98
98
|
*/
|
|
99
99
|
export class ApiError extends Error {
|
|
100
100
|
static fromJSON(json) {
|
|
101
|
-
const err = new ApiError(json.errno, json.message, json.path);
|
|
101
|
+
const err = new ApiError(json.errno, json.message, json.path, json.syscall);
|
|
102
102
|
err.code = json.code;
|
|
103
103
|
err.stack = json.stack;
|
|
104
104
|
return err;
|
|
105
105
|
}
|
|
106
|
-
static
|
|
107
|
-
return new ApiError(code, ErrorStrings[code], path);
|
|
108
|
-
}
|
|
109
|
-
static EACCES(path) {
|
|
110
|
-
return this.OnPath(ErrorCode.EACCES, path);
|
|
111
|
-
}
|
|
112
|
-
static ENOENT(path) {
|
|
113
|
-
return this.OnPath(ErrorCode.ENOENT, path);
|
|
114
|
-
}
|
|
115
|
-
static EEXIST(path) {
|
|
116
|
-
return this.OnPath(ErrorCode.EEXIST, path);
|
|
117
|
-
}
|
|
118
|
-
static EISDIR(path) {
|
|
119
|
-
return this.OnPath(ErrorCode.EISDIR, path);
|
|
120
|
-
}
|
|
121
|
-
static ENOTDIR(path) {
|
|
122
|
-
return this.OnPath(ErrorCode.ENOTDIR, path);
|
|
123
|
-
}
|
|
124
|
-
static EPERM(path) {
|
|
125
|
-
return this.OnPath(ErrorCode.EPERM, path);
|
|
126
|
-
}
|
|
127
|
-
static ENOTEMPTY(path) {
|
|
128
|
-
return this.OnPath(ErrorCode.ENOTEMPTY, path);
|
|
106
|
+
static With(code, path, syscall) {
|
|
107
|
+
return new ApiError(ErrorCode[code], ErrorStrings[ErrorCode[code]], path, syscall);
|
|
129
108
|
}
|
|
130
109
|
/**
|
|
131
110
|
* Represents a ZenFS error. Passed back to applications after a failed
|
|
@@ -137,12 +116,11 @@ export class ApiError extends Error {
|
|
|
137
116
|
* @param type The type of the error.
|
|
138
117
|
* @param message A descriptive error message.
|
|
139
118
|
*/
|
|
140
|
-
constructor(errno, message = ErrorStrings[errno], path) {
|
|
119
|
+
constructor(errno, message = ErrorStrings[errno], path, syscall = '') {
|
|
141
120
|
super(message);
|
|
142
121
|
this.errno = errno;
|
|
143
122
|
this.path = path;
|
|
144
|
-
|
|
145
|
-
this.syscall = '';
|
|
123
|
+
this.syscall = syscall;
|
|
146
124
|
this.code = ErrorCode[errno];
|
|
147
125
|
this.message = `${this.code}: ${message}${this.path ? `, '${this.path}'` : ''}`;
|
|
148
126
|
}
|
|
@@ -159,6 +137,7 @@ export class ApiError extends Error {
|
|
|
159
137
|
path: this.path,
|
|
160
138
|
stack: this.stack,
|
|
161
139
|
message: this.message,
|
|
140
|
+
syscall: this.syscall,
|
|
162
141
|
};
|
|
163
142
|
}
|
|
164
143
|
/**
|
package/dist/FileIndex.js
CHANGED
|
@@ -306,7 +306,7 @@ export class FileIndexFS extends Readonly(FileSystem) {
|
|
|
306
306
|
async stat(path) {
|
|
307
307
|
const inode = this._index.get(path);
|
|
308
308
|
if (!inode) {
|
|
309
|
-
throw ApiError.ENOENT
|
|
309
|
+
throw ApiError.With('ENOENT', path, 'stat');
|
|
310
310
|
}
|
|
311
311
|
if (inode.isDirectory()) {
|
|
312
312
|
return inode.stats;
|
|
@@ -319,7 +319,7 @@ export class FileIndexFS extends Readonly(FileSystem) {
|
|
|
319
319
|
statSync(path) {
|
|
320
320
|
const inode = this._index.get(path);
|
|
321
321
|
if (!inode) {
|
|
322
|
-
throw ApiError.ENOENT
|
|
322
|
+
throw ApiError.With('ENOENT', path, 'statSync');
|
|
323
323
|
}
|
|
324
324
|
if (inode.isDirectory()) {
|
|
325
325
|
return inode.stats;
|
|
@@ -337,10 +337,10 @@ export class FileIndexFS extends Readonly(FileSystem) {
|
|
|
337
337
|
// Check if the path exists, and is a file.
|
|
338
338
|
const inode = this._index.get(path);
|
|
339
339
|
if (!inode) {
|
|
340
|
-
throw ApiError.ENOENT
|
|
340
|
+
throw ApiError.With('ENOENT', path, 'openFile');
|
|
341
341
|
}
|
|
342
342
|
if (!inode.toStats().hasAccess(flagToMode(flag), cred)) {
|
|
343
|
-
throw ApiError.
|
|
343
|
+
throw ApiError.With('EACCESS', path, 'openFile');
|
|
344
344
|
}
|
|
345
345
|
if (inode.isDirectory()) {
|
|
346
346
|
const stats = inode.stats;
|
|
@@ -356,10 +356,10 @@ export class FileIndexFS extends Readonly(FileSystem) {
|
|
|
356
356
|
// Check if the path exists, and is a file.
|
|
357
357
|
const inode = this._index.get(path);
|
|
358
358
|
if (!inode) {
|
|
359
|
-
throw ApiError.ENOENT
|
|
359
|
+
throw ApiError.With('ENOENT', path, 'openFileSync');
|
|
360
360
|
}
|
|
361
361
|
if (!inode.toStats().hasAccess(flagToMode(flag), cred)) {
|
|
362
|
-
throw ApiError.EACCES
|
|
362
|
+
throw ApiError.With('EACCES', path, 'openFileSync');
|
|
363
363
|
}
|
|
364
364
|
if (inode.isDirectory()) {
|
|
365
365
|
const stats = inode.stats;
|
|
@@ -371,23 +371,23 @@ export class FileIndexFS extends Readonly(FileSystem) {
|
|
|
371
371
|
// Check if it exists.
|
|
372
372
|
const inode = this._index.get(path);
|
|
373
373
|
if (!inode) {
|
|
374
|
-
throw ApiError.ENOENT
|
|
374
|
+
throw ApiError.With('ENOENT', path, 'readdir');
|
|
375
375
|
}
|
|
376
376
|
if (inode.isDirectory()) {
|
|
377
377
|
return inode.listing;
|
|
378
378
|
}
|
|
379
|
-
throw ApiError.ENOTDIR
|
|
379
|
+
throw ApiError.With('ENOTDIR', path, 'readdir');
|
|
380
380
|
}
|
|
381
381
|
readdirSync(path) {
|
|
382
382
|
// Check if it exists.
|
|
383
383
|
const inode = this._index.get(path);
|
|
384
384
|
if (!inode) {
|
|
385
|
-
throw ApiError.ENOENT
|
|
385
|
+
throw ApiError.With('ENOENT', path, 'readdirSync');
|
|
386
386
|
}
|
|
387
387
|
if (inode.isDirectory()) {
|
|
388
388
|
return inode.listing;
|
|
389
389
|
}
|
|
390
|
-
throw ApiError.ENOTDIR
|
|
390
|
+
throw ApiError.With('ENOTDIR', path, 'readdirSync');
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
export class SyncFileIndexFS extends Sync((FileIndexFS)) {
|
|
@@ -127,10 +127,10 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
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)) {
|
|
130
|
-
throw ApiError.EACCES
|
|
130
|
+
throw ApiError.With('EACCES', oldPath, 'rename');
|
|
131
131
|
}
|
|
132
132
|
if (!oldDirList[oldName]) {
|
|
133
|
-
throw ApiError.ENOENT
|
|
133
|
+
throw ApiError.With('ENOENT', oldPath, 'rename');
|
|
134
134
|
}
|
|
135
135
|
const nodeId = oldDirList[oldName];
|
|
136
136
|
delete oldDirList[oldName];
|
|
@@ -168,7 +168,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
168
168
|
}
|
|
169
169
|
else {
|
|
170
170
|
// If it's a directory, throw a permissions error.
|
|
171
|
-
throw ApiError.EPERM
|
|
171
|
+
throw ApiError.With('EPERM', newPath, 'rename');
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
newDirList[newName] = nodeId;
|
|
@@ -193,11 +193,11 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
193
193
|
const tx = this.store.beginTransaction();
|
|
194
194
|
const inode = await this.findINode(tx, p);
|
|
195
195
|
if (!inode) {
|
|
196
|
-
throw ApiError.ENOENT
|
|
196
|
+
throw ApiError.With('ENOENT', p, 'stat');
|
|
197
197
|
}
|
|
198
198
|
const stats = inode.toStats();
|
|
199
199
|
if (!stats.hasAccess(R_OK, cred)) {
|
|
200
|
-
throw ApiError.EACCES
|
|
200
|
+
throw ApiError.With('EACCES', p, 'stat');
|
|
201
201
|
}
|
|
202
202
|
return stats;
|
|
203
203
|
}
|
|
@@ -209,10 +209,10 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
209
209
|
async openFile(p, flag, cred) {
|
|
210
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
|
-
throw ApiError.EACCES
|
|
212
|
+
throw ApiError.With('EACCES', p, 'openFile');
|
|
213
213
|
}
|
|
214
214
|
if (!data) {
|
|
215
|
-
throw ApiError.ENOENT
|
|
215
|
+
throw ApiError.With('ENOENT', p, 'openFile');
|
|
216
216
|
}
|
|
217
217
|
return new AsyncFile(this, p, flag, node.toStats(), data);
|
|
218
218
|
}
|
|
@@ -223,7 +223,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
223
223
|
// Check first if directory is empty.
|
|
224
224
|
const list = await this.readdir(p, cred);
|
|
225
225
|
if (list.length > 0) {
|
|
226
|
-
throw ApiError.ENOTEMPTY
|
|
226
|
+
throw ApiError.With('ENOTEMPTY', p, 'rmdir');
|
|
227
227
|
}
|
|
228
228
|
await this.removeEntry(p, true, cred);
|
|
229
229
|
}
|
|
@@ -235,7 +235,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
235
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
|
-
throw ApiError.EACCES
|
|
238
|
+
throw ApiError.With('EACCES', p, 'readdur');
|
|
239
239
|
}
|
|
240
240
|
return Object.keys(await this.getDirListing(tx, node, p));
|
|
241
241
|
}
|
|
@@ -264,16 +264,16 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
264
264
|
async link(existing, newpath, cred) {
|
|
265
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
|
-
throw ApiError.EACCES
|
|
267
|
+
throw ApiError.With('EACCES', existingDir, 'link');
|
|
268
268
|
}
|
|
269
269
|
const newDir = dirname(newpath), newDirNode = await this.findINode(tx, newDir), newListing = await this.getDirListing(tx, newDirNode, newDir);
|
|
270
270
|
if (!newDirNode.toStats().hasAccess(W_OK, cred)) {
|
|
271
|
-
throw ApiError.EACCES
|
|
271
|
+
throw ApiError.With('EACCES', newDir, 'link');
|
|
272
272
|
}
|
|
273
273
|
const ino = await this._findINode(tx, existingDir, basename(existing));
|
|
274
274
|
const node = await this.getINode(tx, ino, existing);
|
|
275
275
|
if (!node.toStats().hasAccess(W_OK, cred)) {
|
|
276
|
-
throw ApiError.EACCES
|
|
276
|
+
throw ApiError.With('EACCES', newpath, 'link');
|
|
277
277
|
}
|
|
278
278
|
node.nlink++;
|
|
279
279
|
newListing[basename(newpath)] = ino;
|
|
@@ -341,7 +341,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
341
341
|
return id;
|
|
342
342
|
}
|
|
343
343
|
else {
|
|
344
|
-
throw ApiError.ENOENT
|
|
344
|
+
throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
}
|
|
@@ -358,7 +358,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
358
358
|
return id;
|
|
359
359
|
}
|
|
360
360
|
else {
|
|
361
|
-
throw ApiError.ENOENT
|
|
361
|
+
throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
364
|
}
|
|
@@ -380,7 +380,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
380
380
|
async getINode(tx, id, p) {
|
|
381
381
|
const data = await tx.get(id);
|
|
382
382
|
if (!data) {
|
|
383
|
-
throw ApiError.ENOENT
|
|
383
|
+
throw ApiError.With('ENOENT', p, 'getINode');
|
|
384
384
|
}
|
|
385
385
|
return new Inode(data.buffer);
|
|
386
386
|
}
|
|
@@ -390,7 +390,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
390
390
|
*/
|
|
391
391
|
async getDirListing(tx, inode, p) {
|
|
392
392
|
if (!inode.toStats().isDirectory()) {
|
|
393
|
-
throw ApiError.ENOTDIR
|
|
393
|
+
throw ApiError.With('ENOTDIR', p, 'getDirListing');
|
|
394
394
|
}
|
|
395
395
|
const data = await tx.get(inode.ino);
|
|
396
396
|
if (!data) {
|
|
@@ -399,7 +399,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
399
399
|
than a directory listing. The latter should never occur unless
|
|
400
400
|
the file system is corrupted.
|
|
401
401
|
*/
|
|
402
|
-
throw ApiError.ENOENT
|
|
402
|
+
throw ApiError.With('ENOENT', p, 'getDirListing');
|
|
403
403
|
}
|
|
404
404
|
return decodeDirListing(data);
|
|
405
405
|
}
|
|
@@ -434,18 +434,18 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
434
434
|
const parentDir = dirname(p), fname = basename(p), parentNode = await this.findINode(tx, parentDir), dirListing = await this.getDirListing(tx, parentNode, parentDir);
|
|
435
435
|
//Check that the creater has correct access
|
|
436
436
|
if (!parentNode.toStats().hasAccess(W_OK, cred)) {
|
|
437
|
-
throw ApiError.EACCES
|
|
437
|
+
throw ApiError.With('EACCES', p, 'commitNewFile');
|
|
438
438
|
}
|
|
439
439
|
// Invariant: The root always exists.
|
|
440
440
|
// If we don't check this prior to taking steps below, we will create a
|
|
441
441
|
// file with name '' in root should p == '/'.
|
|
442
442
|
if (p === '/') {
|
|
443
|
-
throw ApiError.EEXIST
|
|
443
|
+
throw ApiError.With('EEXIST', p, 'commitNewFile');
|
|
444
444
|
}
|
|
445
445
|
// Check if file already exists.
|
|
446
446
|
if (dirListing[fname]) {
|
|
447
447
|
await tx.abort();
|
|
448
|
-
throw ApiError.EEXIST
|
|
448
|
+
throw ApiError.With('EEXIST', p, 'commitNewFile');
|
|
449
449
|
}
|
|
450
450
|
try {
|
|
451
451
|
// Commit data.
|
|
@@ -484,21 +484,21 @@ export class AsyncStoreFS extends Async(FileSystem) {
|
|
|
484
484
|
}
|
|
485
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);
|
|
486
486
|
if (!parentListing[fileName]) {
|
|
487
|
-
throw ApiError.ENOENT
|
|
487
|
+
throw ApiError.With('ENOENT', p, 'removeEntry');
|
|
488
488
|
}
|
|
489
489
|
const fileIno = parentListing[fileName];
|
|
490
490
|
// Get file inode.
|
|
491
491
|
const fileNode = await this.getINode(tx, fileIno, p);
|
|
492
492
|
if (!fileNode.toStats().hasAccess(W_OK, cred)) {
|
|
493
|
-
throw ApiError.EACCES
|
|
493
|
+
throw ApiError.With('EACCES', p, 'removeEntry');
|
|
494
494
|
}
|
|
495
495
|
// Remove from directory listing of parent.
|
|
496
496
|
delete parentListing[fileName];
|
|
497
497
|
if (!isDir && fileNode.toStats().isDirectory()) {
|
|
498
|
-
throw ApiError.EISDIR
|
|
498
|
+
throw ApiError.With('EISDIR', p, 'removeEntry');
|
|
499
499
|
}
|
|
500
500
|
if (isDir && !fileNode.toStats().isDirectory()) {
|
|
501
|
-
throw ApiError.ENOTDIR
|
|
501
|
+
throw ApiError.With('ENOTDIR', p, 'removeEntry');
|
|
502
502
|
}
|
|
503
503
|
try {
|
|
504
504
|
await tx.put(parentNode.ino, encodeDirListing(parentListing), true);
|
package/dist/backends/Overlay.js
CHANGED
|
@@ -134,7 +134,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
134
134
|
}
|
|
135
135
|
catch (e) {
|
|
136
136
|
if (this._deletedFiles.has(oldPath)) {
|
|
137
|
-
throw ApiError.ENOENT
|
|
137
|
+
throw ApiError.With('ENOENT', oldPath, 'rename');
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -147,7 +147,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
147
147
|
}
|
|
148
148
|
catch (e) {
|
|
149
149
|
if (this._deletedFiles.has(oldPath)) {
|
|
150
|
-
throw ApiError.ENOENT
|
|
150
|
+
throw ApiError.With('ENOENT', oldPath, 'renameSync');
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
}
|
|
@@ -158,7 +158,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
158
158
|
}
|
|
159
159
|
catch (e) {
|
|
160
160
|
if (this._deletedFiles.has(p)) {
|
|
161
|
-
throw ApiError.ENOENT
|
|
161
|
+
throw ApiError.With('ENOENT', p, 'stat');
|
|
162
162
|
}
|
|
163
163
|
const oldStat = new Stats(await this._readable.stat(p, cred));
|
|
164
164
|
// Make the oldStat's mode writable. Preserve the topmost part of the mode, which specifies the type
|
|
@@ -173,7 +173,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
173
173
|
}
|
|
174
174
|
catch (e) {
|
|
175
175
|
if (this._deletedFiles.has(p)) {
|
|
176
|
-
throw ApiError.ENOENT
|
|
176
|
+
throw ApiError.With('ENOENT', p, 'statSync');
|
|
177
177
|
}
|
|
178
178
|
const oldStat = new Stats(this._readable.statSync(p, cred));
|
|
179
179
|
// Make the oldStat's mode writable. Preserve the topmost part of the mode, which specifies the type.
|
|
@@ -224,7 +224,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
224
224
|
this.checkInitialized();
|
|
225
225
|
this.checkPath(p);
|
|
226
226
|
if (!(await this.exists(p, cred))) {
|
|
227
|
-
throw ApiError.ENOENT
|
|
227
|
+
throw ApiError.With('ENOENT', p, 'unlink');
|
|
228
228
|
}
|
|
229
229
|
if (await this._writable.exists(p, cred)) {
|
|
230
230
|
await this._writable.unlink(p, cred);
|
|
@@ -238,7 +238,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
238
238
|
this.checkInitialized();
|
|
239
239
|
this.checkPath(p);
|
|
240
240
|
if (!this.existsSync(p, cred)) {
|
|
241
|
-
throw ApiError.ENOENT
|
|
241
|
+
throw ApiError.With('ENOENT', p, 'unlinkSync');
|
|
242
242
|
}
|
|
243
243
|
if (this._writable.existsSync(p, cred)) {
|
|
244
244
|
this._writable.unlinkSync(p, cred);
|
|
@@ -251,7 +251,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
251
251
|
async rmdir(p, cred) {
|
|
252
252
|
this.checkInitialized();
|
|
253
253
|
if (!(await this.exists(p, cred))) {
|
|
254
|
-
throw ApiError.ENOENT
|
|
254
|
+
throw ApiError.With('ENOENT', p, 'rmdir');
|
|
255
255
|
}
|
|
256
256
|
if (await this._writable.exists(p, cred)) {
|
|
257
257
|
await this._writable.rmdir(p, cred);
|
|
@@ -259,7 +259,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
259
259
|
if (await this.exists(p, cred)) {
|
|
260
260
|
// Check if directory is empty.
|
|
261
261
|
if ((await this.readdir(p, cred)).length > 0) {
|
|
262
|
-
throw ApiError.ENOTEMPTY
|
|
262
|
+
throw ApiError.With('ENOTEMPTY', p, 'rmdir');
|
|
263
263
|
}
|
|
264
264
|
else {
|
|
265
265
|
this.deletePath(p, cred);
|
|
@@ -269,7 +269,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
269
269
|
rmdirSync(p, cred) {
|
|
270
270
|
this.checkInitialized();
|
|
271
271
|
if (!this.existsSync(p, cred)) {
|
|
272
|
-
throw ApiError.ENOENT
|
|
272
|
+
throw ApiError.With('ENOENT', p, 'rmdirSync');
|
|
273
273
|
}
|
|
274
274
|
if (this._writable.existsSync(p, cred)) {
|
|
275
275
|
this._writable.rmdirSync(p, cred);
|
|
@@ -277,7 +277,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
277
277
|
if (this.existsSync(p, cred)) {
|
|
278
278
|
// Check if directory is empty.
|
|
279
279
|
if (this.readdirSync(p, cred).length > 0) {
|
|
280
|
-
throw ApiError.ENOTEMPTY
|
|
280
|
+
throw ApiError.With('ENOTEMPTY', p, 'rmdirSync');
|
|
281
281
|
}
|
|
282
282
|
else {
|
|
283
283
|
this.deletePath(p, cred);
|
|
@@ -287,7 +287,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
287
287
|
async mkdir(p, mode, cred) {
|
|
288
288
|
this.checkInitialized();
|
|
289
289
|
if (await this.exists(p, cred)) {
|
|
290
|
-
throw ApiError.EEXIST
|
|
290
|
+
throw ApiError.With('EEXIST', p, 'mkdir');
|
|
291
291
|
}
|
|
292
292
|
// The below will throw should any of the parent directories fail to exist on _writable.
|
|
293
293
|
await this.createParentDirectories(p, cred);
|
|
@@ -296,7 +296,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
296
296
|
mkdirSync(p, mode, cred) {
|
|
297
297
|
this.checkInitialized();
|
|
298
298
|
if (this.existsSync(p, cred)) {
|
|
299
|
-
throw ApiError.EEXIST
|
|
299
|
+
throw ApiError.With('EEXIST', p, 'mkdirSync');
|
|
300
300
|
}
|
|
301
301
|
// The below will throw should any of the parent directories fail to exist on _writable.
|
|
302
302
|
this.createParentDirectoriesSync(p, cred);
|
|
@@ -306,7 +306,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
306
306
|
this.checkInitialized();
|
|
307
307
|
const dirStats = await this.stat(p, cred);
|
|
308
308
|
if (!dirStats.isDirectory()) {
|
|
309
|
-
throw ApiError.ENOTDIR
|
|
309
|
+
throw ApiError.With('ENOTDIR', p, 'readdir');
|
|
310
310
|
}
|
|
311
311
|
// Readdir in both, check delete log on RO file system's listing, merge, return.
|
|
312
312
|
const contents = [];
|
|
@@ -333,7 +333,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
333
333
|
this.checkInitialized();
|
|
334
334
|
const dirStats = this.statSync(p, cred);
|
|
335
335
|
if (!dirStats.isDirectory()) {
|
|
336
|
-
throw ApiError.ENOTDIR
|
|
336
|
+
throw ApiError.With('ENOTDIR', p, 'readdirSync');
|
|
337
337
|
}
|
|
338
338
|
// Readdir in both, check delete log on RO file system's listing, merge, return.
|
|
339
339
|
let contents = [];
|
|
@@ -405,7 +405,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
405
405
|
}
|
|
406
406
|
checkPath(path) {
|
|
407
407
|
if (path == deletionLogPath) {
|
|
408
|
-
throw ApiError.EPERM
|
|
408
|
+
throw ApiError.With('EPERM', path, 'checkPath');
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
/**
|
|
@@ -442,7 +442,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
442
442
|
*/
|
|
443
443
|
operateOnWritable(p, cred) {
|
|
444
444
|
if (!this.existsSync(p, cred)) {
|
|
445
|
-
throw ApiError.ENOENT
|
|
445
|
+
throw ApiError.With('ENOENT', p, 'operateOnWriteable');
|
|
446
446
|
}
|
|
447
447
|
if (!this._writable.existsSync(p, cred)) {
|
|
448
448
|
// File is on readable storage. Copy to writable storage before
|
|
@@ -452,7 +452,7 @@ export class UnlockedOverlayFS extends FileSystem {
|
|
|
452
452
|
}
|
|
453
453
|
async operateOnWritableAsync(p, cred) {
|
|
454
454
|
if (!(await this.exists(p, cred))) {
|
|
455
|
-
throw ApiError.ENOENT
|
|
455
|
+
throw ApiError.With('ENOENT', p, 'operateOnWritableAsync');
|
|
456
456
|
}
|
|
457
457
|
if (!(await this._writable.exists(p, cred))) {
|
|
458
458
|
return this.copyToWritable(p, cred);
|
|
@@ -134,10 +134,10 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
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)) {
|
|
137
|
-
throw ApiError.EACCES
|
|
137
|
+
throw ApiError.With('EACCES', oldPath, 'renameSync');
|
|
138
138
|
}
|
|
139
139
|
if (!oldDirList[oldName]) {
|
|
140
|
-
throw ApiError.ENOENT
|
|
140
|
+
throw ApiError.With('ENOENT', oldPath, 'renameSync');
|
|
141
141
|
}
|
|
142
142
|
const ino = oldDirList[oldName];
|
|
143
143
|
delete oldDirList[oldName];
|
|
@@ -175,7 +175,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
175
175
|
}
|
|
176
176
|
else {
|
|
177
177
|
// If it's a directory, throw a permissions error.
|
|
178
|
-
throw ApiError.EPERM
|
|
178
|
+
throw ApiError.With('EPERM', newPath, 'renameSync');
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
newDirList[newName] = ino;
|
|
@@ -194,7 +194,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
194
194
|
// Get the inode to the item, convert it into a Stats object.
|
|
195
195
|
const stats = this.findINode(this.store.beginTransaction(), p).toStats();
|
|
196
196
|
if (!stats.hasAccess(R_OK, cred)) {
|
|
197
|
-
throw ApiError.EACCES
|
|
197
|
+
throw ApiError.With('EACCES', p, 'statSync');
|
|
198
198
|
}
|
|
199
199
|
return stats;
|
|
200
200
|
}
|
|
@@ -205,10 +205,10 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
205
205
|
openFileSync(p, flag, cred) {
|
|
206
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
|
-
throw ApiError.EACCES
|
|
208
|
+
throw ApiError.With('EACCES', p, 'openFileSync');
|
|
209
209
|
}
|
|
210
210
|
if (data === null) {
|
|
211
|
-
throw ApiError.ENOENT
|
|
211
|
+
throw ApiError.With('ENOENT', p, 'openFileSync');
|
|
212
212
|
}
|
|
213
213
|
return new SyncStoreFile(this, p, flag, node.toStats(), data);
|
|
214
214
|
}
|
|
@@ -218,7 +218,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
218
218
|
rmdirSync(p, cred) {
|
|
219
219
|
// Check first if directory is empty.
|
|
220
220
|
if (this.readdirSync(p, cred).length > 0) {
|
|
221
|
-
throw ApiError.ENOTEMPTY
|
|
221
|
+
throw ApiError.With('ENOTEMPTY', p, 'rmdirSync');
|
|
222
222
|
}
|
|
223
223
|
else {
|
|
224
224
|
this.removeEntry(p, true, cred);
|
|
@@ -231,7 +231,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
231
231
|
const tx = this.store.beginTransaction();
|
|
232
232
|
const node = this.findINode(tx, p);
|
|
233
233
|
if (!node.toStats().hasAccess(R_OK, cred)) {
|
|
234
|
-
throw ApiError.EACCES
|
|
234
|
+
throw ApiError.With('EACCES', p, 'readdirSync');
|
|
235
235
|
}
|
|
236
236
|
return Object.keys(this.getDirListing(tx, node, p));
|
|
237
237
|
}
|
|
@@ -258,16 +258,16 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
258
258
|
linkSync(existing, newpath, cred) {
|
|
259
259
|
const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = this.findINode(tx, existingDir);
|
|
260
260
|
if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
|
|
261
|
-
throw ApiError.EACCES
|
|
261
|
+
throw ApiError.With('EACCES', existingDir, 'linkSync');
|
|
262
262
|
}
|
|
263
263
|
const newDir = dirname(newpath), newDirNode = this.findINode(tx, newDir), newListing = this.getDirListing(tx, newDirNode, newDir);
|
|
264
264
|
if (!newDirNode.toStats().hasAccess(W_OK, cred)) {
|
|
265
|
-
throw ApiError.EACCES
|
|
265
|
+
throw ApiError.With('EACCES', newDir, 'linkSync');
|
|
266
266
|
}
|
|
267
267
|
const ino = this._findINode(tx, existingDir, basename(existing));
|
|
268
268
|
const node = this.getINode(tx, ino, existing);
|
|
269
269
|
if (!node.toStats().hasAccess(W_OK, cred)) {
|
|
270
|
-
throw ApiError.EACCES
|
|
270
|
+
throw ApiError.With('EACCES', newpath, 'linkSync');
|
|
271
271
|
}
|
|
272
272
|
node.nlink++;
|
|
273
273
|
newListing[basename(newpath)] = ino;
|
|
@@ -314,7 +314,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
314
314
|
const ino = this._findINode(tx, dirname(parent), basename(parent), visited);
|
|
315
315
|
const dir = this.getDirListing(tx, this.getINode(tx, ino, parent + sep + filename), parent);
|
|
316
316
|
if (!(filename in dir)) {
|
|
317
|
-
throw ApiError.ENOENT
|
|
317
|
+
throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
|
|
318
318
|
}
|
|
319
319
|
return dir[filename];
|
|
320
320
|
}
|
|
@@ -322,7 +322,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
322
322
|
// Find the item in the root node.
|
|
323
323
|
const dir = this.getDirListing(tx, this.getINode(tx, rootIno, parent), parent);
|
|
324
324
|
if (!(filename in dir)) {
|
|
325
|
-
throw ApiError.ENOENT
|
|
325
|
+
throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
|
|
326
326
|
}
|
|
327
327
|
return dir[filename];
|
|
328
328
|
}
|
|
@@ -348,7 +348,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
348
348
|
getINode(tx, id, p) {
|
|
349
349
|
const data = tx.get(id);
|
|
350
350
|
if (!data) {
|
|
351
|
-
throw ApiError.ENOENT
|
|
351
|
+
throw ApiError.With('ENOENT', p, 'getINode');
|
|
352
352
|
}
|
|
353
353
|
const inode = new Inode(data.buffer);
|
|
354
354
|
return inode;
|
|
@@ -358,11 +358,11 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
358
358
|
*/
|
|
359
359
|
getDirListing(tx, inode, p) {
|
|
360
360
|
if (!inode.toStats().isDirectory()) {
|
|
361
|
-
throw ApiError.ENOTDIR
|
|
361
|
+
throw ApiError.With('ENOTDIR', p, 'getDirListing');
|
|
362
362
|
}
|
|
363
363
|
const data = tx.get(inode.ino);
|
|
364
364
|
if (!data) {
|
|
365
|
-
throw ApiError.ENOENT
|
|
365
|
+
throw ApiError.With('ENOENT', p, 'getDirListing');
|
|
366
366
|
}
|
|
367
367
|
return decodeDirListing(data);
|
|
368
368
|
}
|
|
@@ -394,18 +394,18 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
394
394
|
const tx = this.store.beginTransaction(), parentDir = dirname(p), fname = basename(p), parentNode = this.findINode(tx, parentDir), dirListing = this.getDirListing(tx, parentNode, parentDir);
|
|
395
395
|
//Check that the creater has correct access
|
|
396
396
|
if (!parentNode.toStats().hasAccess(W_OK, cred)) {
|
|
397
|
-
throw ApiError.EACCES
|
|
397
|
+
throw ApiError.With('EACCES', p, 'commitNewFile');
|
|
398
398
|
}
|
|
399
399
|
/* Invariant: The root always exists.
|
|
400
400
|
If we don't check this prior to taking steps below,
|
|
401
401
|
we will create a file with name '' in root should p == '/'.
|
|
402
402
|
*/
|
|
403
403
|
if (p === '/') {
|
|
404
|
-
throw ApiError.EEXIST
|
|
404
|
+
throw ApiError.With('EEXIST', p, 'commitNewFile');
|
|
405
405
|
}
|
|
406
406
|
// Check if file already exists.
|
|
407
407
|
if (dirListing[fname]) {
|
|
408
|
-
throw ApiError.EEXIST
|
|
408
|
+
throw ApiError.With('EEXIST', p, 'commitNewFile');
|
|
409
409
|
}
|
|
410
410
|
const fileNode = new Inode();
|
|
411
411
|
try {
|
|
@@ -435,20 +435,20 @@ export class SyncStoreFS extends Sync(FileSystem) {
|
|
|
435
435
|
removeEntry(p, isDir, cred) {
|
|
436
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];
|
|
437
437
|
if (!fileIno) {
|
|
438
|
-
throw ApiError.ENOENT
|
|
438
|
+
throw ApiError.With('ENOENT', p, 'removeEntry');
|
|
439
439
|
}
|
|
440
440
|
// Get file inode.
|
|
441
441
|
const fileNode = this.getINode(tx, fileIno, p);
|
|
442
442
|
if (!fileNode.toStats().hasAccess(W_OK, cred)) {
|
|
443
|
-
throw ApiError.EACCES
|
|
443
|
+
throw ApiError.With('EACCES', p, 'removeEntry');
|
|
444
444
|
}
|
|
445
445
|
// Remove from directory listing of parent.
|
|
446
446
|
delete parentListing[fileName];
|
|
447
447
|
if (!isDir && fileNode.toStats().isDirectory()) {
|
|
448
|
-
throw ApiError.EISDIR
|
|
448
|
+
throw ApiError.With('EISDIR', p, 'removeEntry');
|
|
449
449
|
}
|
|
450
450
|
if (isDir && !fileNode.toStats().isDirectory()) {
|
|
451
|
-
throw ApiError.ENOTDIR
|
|
451
|
+
throw ApiError.With('ENOTDIR', p, 'removeEntry');
|
|
452
452
|
}
|
|
453
453
|
try {
|
|
454
454
|
// Update directory listing.
|