Merge pull request #23982 from Microsoft/reduceVfsCaughtExceptions

Reduce number of 'caught exceptions' raised by vfs
This commit is contained in:
Ron Buckton 2018-05-09 09:23:23 -07:00 committed by GitHub
commit b31968a598
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -332,35 +332,20 @@ namespace vfs {
}
}
private _depth: string[] = [];
/**
* Make a directory and all of its parent paths (if they don't exist).
*/
public mkdirpSync(path: string) {
try {
this._depth.push(path);
path = this._resolve(path);
this.mkdirSync(path);
}
catch (e) {
if (e.code === "ENOENT") {
if (this._depth.length > 10) {
console.log(`path: ${path}`);
console.log(`dirname: ${vpath.dirname(path)}`);
console.log(this._depth);
throw e;
}
this.mkdirpSync(vpath.dirname(path));
this.mkdirSync(path);
path = this._resolve(path);
const result = this._walk(path, /*noFollow*/ true, (error, result) => {
if (error.code === "ENOENT") {
this._mkdir(result);
return "retry";
}
else if (e.code !== "EEXIST") {
throw e;
}
}
finally {
this._depth.pop();
}
return "throw";
});
if (!result.node) this._mkdir(result);
}
/**
@ -464,9 +449,11 @@ namespace vfs {
public mkdirSync(path: string) {
if (this.isReadonly) throw createIOError("EROFS");
const { parent, links, node: existingNode, basename } = this._walk(this._resolve(path), /*noFollow*/ true);
if (existingNode) throw createIOError("EEXIST");
this._mkdir(this._walk(this._resolve(path), /*noFollow*/ true));
}
private _mkdir({ parent, links, node: existingNode, basename }: WalkResult) {
if (existingNode) throw createIOError("EEXIST");
const time = this.time();
const node = this._mknod(parent ? parent.dev : ++devCount, S_IFDIR, /*mode*/ 0o777, time);
this._addLink(parent, links, basename, node, time);
@ -810,17 +797,18 @@ namespace vfs {
* @param path The path to follow.
* @param noFollow A value indicating whether to *not* dereference a symbolic link at the
* end of a path.
* @param allowPartial A value indicating whether to return a partial result if the node
* at the end of the path cannot be found.
*
* @link http://man7.org/linux/man-pages/man7/path_resolution.7.html
*/
private _walk(path: string, noFollow?: boolean): WalkResult {
private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "retry" | "throw"): WalkResult;
private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined;
private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined {
let links = this._getRootLinks();
let parent: DirectoryInode | undefined;
let components = vpath.parse(path);
let step = 0;
let depth = 0;
let retry = false;
while (true) {
if (depth >= 40) throw createIOError("ELOOP");
const lastStep = step === components.length - 1;
@ -830,7 +818,8 @@ namespace vfs {
return { realpath: vpath.format(components), basename, parent, links, node };
}
if (node === undefined) {
throw createIOError("ENOENT");
if (trapError(createIOError("ENOENT"), node)) continue;
return undefined;
}
if (isSymlink(node)) {
const dirname = vpath.format(components.slice(0, step));
@ -840,15 +829,30 @@ namespace vfs {
components = vpath.parse(symlink).concat(components.slice(step + 1));
step = 0;
depth++;
retry = false;
continue;
}
if (isDirectory(node)) {
links = this._getLinks(node);
parent = node;
step++;
retry = false;
continue;
}
throw createIOError("ENOTDIR");
if (trapError(createIOError("ENOTDIR"), node)) continue;
return undefined;
}
function trapError(error: NodeJS.ErrnoException, node?: Inode) {
const realpath = vpath.format(components.slice(0, step + 1));
const basename = components[step];
const result = !retry && onError ? onError(error, { realpath, basename, parent, links, node }) : "throw";
if (result === "stop") return false;
if (result === "retry") {
retry = true;
return true;
}
throw error;
}
}
@ -1118,6 +1122,7 @@ namespace vfs {
export function createIOError(code: keyof typeof IOErrorMessages) {
const err: NodeJS.ErrnoException = new Error(`${code}: ${IOErrorMessages[code]}`);
err.code = code;
if (Error.captureStackTrace) Error.captureStackTrace(err, createIOError);
return err;
}