Fix uncaught errors when extracting zips

Fixes #966.
This commit is contained in:
Asher 2019-09-19 16:34:44 -05:00
parent 637e58f255
commit 7812f6b75a
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A

View File

@ -79,52 +79,55 @@ export const buffer = (targetPath: string, filePath: string): Promise<Buffer> =>
}; };
const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise<void> => { const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise<void> => {
const buffer = await util.promisify(fs.readFile)(tarPath); return new Promise<void>((resolve, reject): void => {
return new Promise<void>(async (resolve, reject): Promise<void> => {
const extractor = tarStream.extract(); 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) => { extractor.on("entry", async (header, stream, next) => {
const name = header.name; const name = header.name;
if (match.test(name)) { if (match.test(name)) {
extractData(stream).then((data) => { extractData(stream).then((data) => {
callback(name, data); callback(name, data);
next(); next();
}).catch(reject); }).catch(fail);
stream.resume();
} else { } else {
stream.on("end", () => next()); stream.on("end", () => next());
stream.resume(); stream.resume(); // Just drain it.
} }
}); });
extractor.on("finish", resolve); extractor.on("finish", resolve);
extractor.write(buffer); fs.createReadStream(tarPath).pipe(extractor);
extractor.end();
}); });
}; };
const extractData = (stream: NodeJS.ReadableStream): Promise<Buffer> => { const extractData = (stream: NodeJS.ReadableStream): Promise<Buffer> => {
return new Promise((resolve, reject): void => { return new Promise((resolve, reject): void => {
const fileData: Buffer[] = []; const fileData: Buffer[] = [];
stream.on("data", (data) => fileData.push(data));
stream.on("end", () => resolve(Buffer.concat(fileData)));
stream.on("error", reject); 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<void> => { const extractTar = async (tarPath: string, targetPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise<void> => {
const buffer = await util.promisify(fs.readFile)(tarPath); return new Promise<void>((resolve, reject): void => {
return new Promise<void>(async (resolve, reject): Promise<void> => {
const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : ""); const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : "");
const extractor = tarStream.extract(); 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) => { extractor.on("entry", async (header, stream, next) => {
const rawName = path.normalize(header.name);
const nextEntry = (): void => { const nextEntry = (): void => {
stream.on("end", () => next());
stream.resume(); stream.resume();
next();
}; };
const rawName = path.normalize(header.name);
if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) { if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) {
return nextEntry(); return nextEntry();
} }
@ -138,20 +141,18 @@ const extractTar = async (tarPath: string, targetPath: string, options: IExtract
const dirName = path.dirname(fileName); const dirName = path.dirname(fileName);
const targetDirName = path.join(targetPath, dirName); const targetDirName = path.join(targetPath, dirName);
if (targetDirName.indexOf(targetPath) !== 0) { 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(() => { await mkdirp(targetDirName, undefined, token);
const fstream = fs.createWriteStream(targetFileName, { mode: header.mode });
fstream.once("close", () => next()); const fstream = fs.createWriteStream(targetFileName, { mode: header.mode });
fstream.once("error", reject); fstream.once("close", () => next());
stream.pipe(fstream); fstream.once("error", fail);
stream.resume(); stream.pipe(fstream);
});
}); });
extractor.once("finish", resolve); extractor.once("finish", resolve);
extractor.write(buffer); fs.createReadStream(tarPath).pipe(extractor);
extractor.end();
}); });
}; };