@vltpkg/tar
Advanced tools
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"unpack.d.ts","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,MAAM,YACR,MAAM,UACP,MAAM,KACb,OAAO,CAAC,IAAI,CAMd,CAAA"} | ||
| {"version":3,"file":"unpack.d.ts","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"AAwFA,eAAO,MAAM,MAAM,YACR,MAAM,UACP,MAAM,KACb,OAAO,CAAC,IAAI,CAMd,CAAA"} |
+12
-13
| import { error } from '@vltpkg/error-cause'; | ||
| import { randomBytes } from 'node:crypto'; | ||
| import { lstat, mkdir, rename, writeFile } from 'node:fs/promises'; | ||
| import { basename, dirname, parse, resolve } from 'node:path'; | ||
| import { basename, dirname, resolve, sep } from 'node:path'; | ||
| import { rimraf } from 'rimraf'; | ||
@@ -25,3 +25,3 @@ import { Header } from 'tar/header'; | ||
| const tmpSuffix = () => tmp + String(id++); | ||
| const checkFs = (h, tarDir) => { | ||
| const checkFs = (h, tarDir, target) => { | ||
| /* c8 ignore start - impossible */ | ||
@@ -34,12 +34,11 @@ if (!h.path) | ||
| h.path = h.path.replace(/[\\/]+/g, '/'); | ||
| const parsed = parse(h.path); | ||
| if (parsed.root) | ||
| // packages should always be in a 'package' tarDir in the archive | ||
| if (!h.path.startsWith(tarDir)) | ||
| return false; | ||
| const p = h.path.replace(/\\/, '/'); | ||
| // any .. at the beginning, end, or middle = no good | ||
| if (/(\/|)^\.\.(\/|$)/.test(p)) | ||
| // Package root | ||
| const absoluteBasePath = target; | ||
| const itemAbsolutePath = resolve(target, h.path.slice(tarDir.length)); | ||
| if (!itemAbsolutePath.startsWith(absoluteBasePath)) { | ||
| return false; | ||
| // packages should always be in a 'package' tarDir in the archive | ||
| if (!p.startsWith(tarDir)) | ||
| return false; | ||
| } | ||
| return true; | ||
@@ -96,3 +95,3 @@ }; | ||
| } | ||
| const tmp = dirname(target) + '/.' + basename(target) + '.' + tmpSuffix(); | ||
| const tmp = dirname(target) + sep + '.' + basename(target) + '.' + tmpSuffix(); | ||
| const og = tmp + '.ORIGINAL'; | ||
@@ -127,3 +126,3 @@ await Promise.all([rimraf(tmp), rimraf(og)]); | ||
| continue; | ||
| if (!checkFs(h, tarDir)) | ||
| if (!checkFs(h, tarDir, tmp)) | ||
| continue; | ||
@@ -141,3 +140,3 @@ await write(resolve(tmp, h.path.substring(tarDir.length)), body, | ||
| continue; | ||
| if (!checkFs(h, tarDir)) | ||
| if (!checkFs(h, tarDir, tmp)) | ||
| continue; | ||
@@ -144,0 +143,0 @@ await mkdirp(resolve(tmp, h.path.substring(tarDir.length))); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, rename, writeFile } from 'node:fs/promises'\nimport { basename, dirname, parse, resolve } from 'node:path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'node:zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n const parsed = parse(h.path)\n if (parsed.root) return false\n const p = h.path.replace(/\\\\/, '/')\n // any .. at the beginning, end, or middle = no good\n if (/(\\/|)^\\.\\.(\\/|$)/.test(p)) return false\n // packages should always be in a 'package' tarDir in the archive\n if (!p.startsWith(tarDir)) return false\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + '/.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n !(h = new Header(buffer, offset, ex, gex)).nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]} | ||
| {"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, rename, writeFile } from 'node:fs/promises'\nimport { basename, dirname, resolve, sep } from 'node:path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'node:zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n target: string,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n\n // packages should always be in a 'package' tarDir in the archive\n if (!h.path.startsWith(tarDir)) return false\n\n // Package root\n const absoluteBasePath = target\n const itemAbsolutePath = resolve(\n target,\n h.path.slice(tarDir.length),\n )\n\n if (!itemAbsolutePath.startsWith(absoluteBasePath)) {\n return false\n }\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + sep + '.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n !(h = new Header(buffer, offset, ex, gex)).nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir, tmp)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir, tmp)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]} |
+14
-14
| { | ||
| "name": "@vltpkg/tar", | ||
| "description": "An extremely limited and very fast tar extractor", | ||
| "version": "1.0.0-rc.9", | ||
| "version": "1.0.0-rc.10", | ||
| "repository": { | ||
@@ -26,19 +26,19 @@ "type": "git", | ||
| "dependencies": { | ||
| "rimraf": "^6.0.1", | ||
| "tar": "^7.4.3", | ||
| "@vltpkg/types": "1.0.0-rc.9", | ||
| "@vltpkg/error-cause": "1.0.0-rc.9" | ||
| "rimraf": "^6.1.2", | ||
| "tar": "^7.5.2", | ||
| "@vltpkg/error-cause": "1.0.0-rc.10", | ||
| "@vltpkg/types": "1.0.0-rc.10" | ||
| }, | ||
| "devDependencies": { | ||
| "@eslint/js": "^9.34.0", | ||
| "@types/node": "^22.17.2", | ||
| "@eslint/js": "^9.39.1", | ||
| "@types/node": "^22.19.2", | ||
| "@types/pacote": "^11.1.8", | ||
| "eslint": "^9.34.0", | ||
| "pacote": "^21.0.0", | ||
| "prettier": "^3.6.2", | ||
| "tap": "^21.1.0", | ||
| "tshy": "^3.0.2", | ||
| "eslint": "^9.39.1", | ||
| "pacote": "^21.0.4", | ||
| "prettier": "^3.7.4", | ||
| "tap": "^21.5.0", | ||
| "tshy": "^3.1.0", | ||
| "typedoc": "~0.27.9", | ||
| "typescript": "5.7.3", | ||
| "typescript-eslint": "^8.40.0", | ||
| "typescript-eslint": "^8.49.0", | ||
| "@vltpkg/benchmark": "0.0.0" | ||
@@ -48,3 +48,3 @@ }, | ||
| "engines": { | ||
| "node": ">=22" | ||
| "node": ">=22.9.0" | ||
| }, | ||
@@ -51,0 +51,0 @@ "tap": { |
46356
0.23%401
-0.25%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated