From 7812f6b75ad7dc53dceb9a5488e291b702d4a917 Mon Sep 17 00:00:00 2001 From: Asher Date: Thu, 19 Sep 2019 16:34:44 -0500 Subject: [PATCH] Fix uncaught errors when extracting zips Fixes #966. --- src/marketplace.ts | 53 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/marketplace.ts b/src/marketplace.ts index a12bb996..b125506e 100644 --- a/src/marketplace.ts +++ b/src/marketplace.ts @@ -79,52 +79,55 @@ export const buffer = (targetPath: string, filePath: string): Promise => }; const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise => { - const buffer = await util.promisify(fs.readFile)(tarPath); - return new Promise(async (resolve, reject): Promise => { + return new Promise((resolve, reject): void => { const extractor = tarStream.extract(); - extractor.once("error", reject); + const fail = (error: Error) => { + extractor.destroy(); + reject(error); + }; + extractor.once("error", fail); extractor.on("entry", async (header, stream, next) => { const name = header.name; if (match.test(name)) { extractData(stream).then((data) => { callback(name, data); next(); - }).catch(reject); - stream.resume(); + }).catch(fail); } else { stream.on("end", () => next()); - stream.resume(); + stream.resume(); // Just drain it. } }); extractor.on("finish", resolve); - extractor.write(buffer); - extractor.end(); + fs.createReadStream(tarPath).pipe(extractor); }); }; const extractData = (stream: NodeJS.ReadableStream): Promise => { return new Promise((resolve, reject): void => { const fileData: Buffer[] = []; - stream.on("data", (data) => fileData.push(data)); - stream.on("end", () => resolve(Buffer.concat(fileData))); stream.on("error", reject); + stream.on("end", () => resolve(Buffer.concat(fileData))); + stream.on("data", (data) => fileData.push(data)); }); }; const extractTar = async (tarPath: string, targetPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise => { - const buffer = await util.promisify(fs.readFile)(tarPath); - return new Promise(async (resolve, reject): Promise => { + return new Promise((resolve, reject): void => { const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : ""); const extractor = tarStream.extract(); - extractor.once("error", reject); + const fail = (error: Error) => { + extractor.destroy(); + reject(error); + }; + extractor.once("error", fail); extractor.on("entry", async (header, stream, next) => { - const rawName = path.normalize(header.name); - const nextEntry = (): void => { + stream.on("end", () => next()); stream.resume(); - next(); }; + const rawName = path.normalize(header.name); if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) { return nextEntry(); } @@ -138,20 +141,18 @@ const extractTar = async (tarPath: string, targetPath: string, options: IExtract const dirName = path.dirname(fileName); const targetDirName = path.join(targetPath, dirName); if (targetDirName.indexOf(targetPath) !== 0) { - return reject(nls.localize("invalid file", "Error extracting {0}. Invalid file.", fileName)); + return fail(new Error(nls.localize("invalid file", "Error extracting {0}. Invalid file.", fileName))); } - return mkdirp(targetDirName, undefined, token).then(() => { - const fstream = fs.createWriteStream(targetFileName, { mode: header.mode }); - fstream.once("close", () => next()); - fstream.once("error", reject); - stream.pipe(fstream); - stream.resume(); - }); + await mkdirp(targetDirName, undefined, token); + + const fstream = fs.createWriteStream(targetFileName, { mode: header.mode }); + fstream.once("close", () => next()); + fstream.once("error", fail); + stream.pipe(fstream); }); extractor.once("finish", resolve); - extractor.write(buffer); - extractor.end(); + fs.createReadStream(tarPath).pipe(extractor); }); };