From ca345d9b06c3f7c380c91e06ebed89fcdcdc5266 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Thu, 12 Dec 2024 11:44:27 +0100 Subject: [PATCH] simplify more --- packages/playwright-core/src/utils/tar.ts | 97 ++++++++++++----------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/packages/playwright-core/src/utils/tar.ts b/packages/playwright-core/src/utils/tar.ts index 4d6d9ecb8e..81ae94e433 100644 --- a/packages/playwright-core/src/utils/tar.ts +++ b/packages/playwright-core/src/utils/tar.ts @@ -14,8 +14,20 @@ * limitations under the License. */ import fs from 'fs'; -import { Writable } from 'stream'; +import { Writable, once } from 'stream'; import path from 'path'; +import assert from 'assert'; + +enum TarType { + REGTYPE, + LNKTYPE, + SYMTYPE, + CHRTYPE, + BLKTYPE, + DIRTYPE, + FIFOTYPE, + CONTTYPE +} function parseHeader(buffer: Buffer) { if (buffer.length < 512) @@ -25,29 +37,21 @@ function parseHeader(buffer: Buffer) { const prefixField = buffer.toString('utf8', 345, 500).replace(/\0/g, ''); if (prefixField) name = path.join(prefixField, name); + name = name.replace(/^\/+/, ''); const size = parseInt(buffer.toString('utf8', 124, 136).trim(), 8); - const typeFlag = buffer[156]; - const mode = parseInt(buffer.toString('utf8', 100, 108).trim(), 8); + const type = parseInt(buffer.toString('ascii', 156, 157), 10) as TarType; + const mode = parseInt(buffer.toString('utf8', 100, 108).trim(), 8) || 0o644; const linkname = buffer.toString('utf8', 157, 257).replace(/\0/g, ''); - // Parse user and group IDs const uid = parseInt(buffer.toString('utf8', 108, 116).trim(), 8); const gid = parseInt(buffer.toString('utf8', 116, 124).trim(), 8); - let type = 'file'; - if (typeFlag === 53) // ASCII '5' - type = 'directory'; - else if (typeFlag === 50) // ASCII '2' - type = 'symlink'; - else if (typeFlag === 0 || typeFlag === 48) // ASCII '0' - type = 'file'; - return { - name: name.replace(/^\/+/, ''), + name, size, type, - mode: mode || 0o644, + mode, linkname, uid, gid @@ -81,48 +85,49 @@ export class TarExtractor extends Writable { continue; } - this.currentHeader = parseHeader(this.buffer); + const header = parseHeader(this.buffer); this.buffer = this.buffer.subarray(512); - await this.processHeader(); - if (!this.currentFileStream) - this.currentHeader = null; + const fullPath = this.outputPath(header.name); + switch (header.type) { + case TarType.DIRTYPE: + await fs.promises.mkdir(fullPath, { recursive: true, mode: 0o755 }); + break; + case TarType.SYMTYPE: + await fs.promises.symlink(header.linkname, fullPath); + break; + case TarType.REGTYPE: + this.currentFileStream = fs.createWriteStream(fullPath, { mode: header.mode }); + await once(this.currentFileStream, 'ready'); + this.currentHeader = header; + this.remainingBytes = header.size; + break; + default: + throw new Error(`Unsupported type ${header.type} for '${header.name}'`); + } continue; } - if (this.remainingBytes > 0) { - const dataChunk = this.buffer.subarray(0, this.remainingBytes); - this.buffer = this.buffer.subarray(this.remainingBytes); - this.remainingBytes -= dataChunk.length; + assert(this.currentFileStream); + assert(this.remainingBytes > 0); - this.currentFileStream!.write(dataChunk); + const dataChunk = this.buffer.subarray(0, this.remainingBytes); + this.buffer = this.buffer.subarray(this.remainingBytes); + this.remainingBytes -= dataChunk.length; - if (this.remainingBytes === 0) { - const padding = 512 - (this.currentHeader!.size % 512); - if (padding < 512) - this.buffer = this.buffer.subarray(padding); + this.currentFileStream.write(dataChunk); - this.currentFileStream!.end(); - this.currentHeader = null; - this.currentFileStream = null; - } + if (this.remainingBytes === 0) { + this.currentFileStream.end(); + this.currentFileStream = null; + + const padding = 512 - (this.currentHeader.size % 512); + if (padding < 512) + this.buffer = this.buffer.subarray(padding); + + this.currentHeader = null; } } } - - private async processHeader() { - if (!this.currentHeader) - throw new Error('No header'); - const fullPath = this.outputPath(this.currentHeader.name); - - if (this.currentHeader.type === 'directory') { - await fs.promises.mkdir(fullPath, { recursive: true, mode: 0o755 }); - } else if (this.currentHeader.type === 'symlink') { - await fs.promises.symlink(this.currentHeader.linkname, fullPath); - } else { - this.currentFileStream = fs.createWriteStream(fullPath, { mode: this.currentHeader.mode }); - this.remainingBytes = this.currentHeader.size; - } - } }