"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('../_virtual/_rolldown/runtime.js');
const require_primordials_error = require('../primordials/error.js');
const require_paths_normalize = require('../paths/normalize.js');
const require_archives__internal = require('./_internal.js');
const require_fs_safe = require('../fs/safe.js');
let node_fs = require("node:fs");
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process);
let node_stream_promises = require("node:stream/promises");
let node_zlib = require("node:zlib");

//#region src/archives/tar.ts
/**
* @file Tar / tar.gz extraction with security limits and symlink rejection.
*   Both functions share a `map(header)` callback that enforces:
*
*   - max entry count (inode-exhaustion DoS guard)
*   - max single-file size
*   - max total extracted size
*   - rejection of null bytes in entry names
*   - rejection of symlink / hardlink entries The duplicate map() bodies are
*     intentional: the surrounding state (entryCount, totalExtractedSize,
*     destroyScheduled) is per-call, so a shared helper would require threading
*     state through closures and obscure the security-defense intent.
*/
/**
* Extract a tar archive to a directory.
*
* @example
*   ;```typescript
*   await extractTar('/tmp/archive.tar', '/tmp/output')
*   await extractTar('/tmp/archive.tar', '/tmp/output', { strip: 1 })
*   ```
*
* @param archivePath - Path to tar file.
* @param outputDir - Directory to extract to.
* @param options - Extraction options.
*/
async function extractTar(archivePath, outputDir, options = {}) {
	require_archives__internal.assertArchiveExists(archivePath);
	const { maxEntries = require_archives__internal.DEFAULT_MAX_ENTRIES, maxFileSize = require_archives__internal.DEFAULT_MAX_FILE_SIZE, maxTotalSize = require_archives__internal.DEFAULT_MAX_TOTAL_SIZE, strip = 0 } = options;
	const normalizedOutputDir = /* @__PURE__ */ require_paths_normalize.normalizePath(outputDir);
	await require_fs_safe.safeMkdir(normalizedOutputDir);
	let totalExtractedSize = 0;
	let entryCount = 0;
	let destroyScheduled = false;
	const extractStream = (/* @__PURE__ */ require_archives__internal.getTarFs()).extract(normalizedOutputDir, {
		map: (header) => {
			/* c8 ignore start - destroyScheduled is set by the same map() when a
			security limit trips; only fires after the schedule. */
			if (destroyScheduled) return header;
			/* c8 ignore stop */
			/* c8 ignore start - Security-defense branches inside tar-fs
			map() schedule extractStream.destroy via process.nextTick.
			tar-fs@3.1.2 has an async-cleanup race after destroy that
			crashes the vitest pool runner. Re-enable once tar-fs is
			upgraded or the SUT refactors destroy. */
			entryCount += 1;
			if (entryCount > maxEntries) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Archive has too many entries: exceeded limit of ${maxEntries}`));
				});
				return header;
			}
			if (header.name.includes("\0")) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Invalid null byte in archive entry name: ${header.name}`));
				});
				return header;
			}
			if (header.type === "symlink" || header.type === "link") {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Symlink detected in archive: ${header.name}. Symlinks are not supported for security reasons.`));
				});
				return header;
			}
			if (header.size && header.size > maxFileSize) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`File size exceeds limit: ${header.name} (${header.size} bytes > ${maxFileSize} bytes)`));
				});
				return header;
			}
			if (header.size) {
				totalExtractedSize += header.size;
				if (totalExtractedSize > maxTotalSize) {
					destroyScheduled = true;
					node_process.default.nextTick(() => {
						extractStream.destroy(new require_primordials_error.ErrorCtor(`Total extracted size exceeds limit: ${totalExtractedSize} bytes > ${maxTotalSize} bytes`));
					});
					return header;
				}
			}
			/* c8 ignore stop */
			return header;
		},
		strip
	});
	extractStream.on("error", () => {});
	const readStream = (0, node_fs.createReadStream)(archivePath);
	try {
		await (0, node_stream_promises.pipeline)(readStream, extractStream);
	} catch (e) {
		readStream.destroy();
		throw e;
	}
}
/**
* Extract a gzipped tar archive to a directory.
*
* @example
*   ;```typescript
*   await extractTarGz('/tmp/archive.tar.gz', '/tmp/output')
*   await extractTarGz('/tmp/archive.tgz', '/tmp/output', { strip: 1 })
*   ```
*
* @param archivePath - Path to tar.gz or tgz file.
* @param outputDir - Directory to extract to.
* @param options - Extraction options.
*/
async function extractTarGz(archivePath, outputDir, options = {}) {
	require_archives__internal.assertArchiveExists(archivePath);
	const { maxEntries = require_archives__internal.DEFAULT_MAX_ENTRIES, maxFileSize = require_archives__internal.DEFAULT_MAX_FILE_SIZE, maxTotalSize = require_archives__internal.DEFAULT_MAX_TOTAL_SIZE, strip = 0 } = options;
	const normalizedOutputDir = /* @__PURE__ */ require_paths_normalize.normalizePath(outputDir);
	await require_fs_safe.safeMkdir(normalizedOutputDir);
	let totalExtractedSize = 0;
	let entryCount = 0;
	let destroyScheduled = false;
	const extractStream = (/* @__PURE__ */ require_archives__internal.getTarFs()).extract(normalizedOutputDir, {
		map: (header) => {
			/* c8 ignore start - destroyScheduled is set by the same map() when a
			security limit trips; only fires after the schedule. */
			if (destroyScheduled) return header;
			/* c8 ignore stop */
			/* c8 ignore start - Security-defense branches inside tar-fs
			map() schedule extractStream.destroy via process.nextTick.
			tar-fs@3.1.2 has an async-cleanup race after destroy that
			crashes the vitest pool runner. Re-enable once tar-fs is
			upgraded or the SUT refactors destroy. */
			entryCount += 1;
			if (entryCount > maxEntries) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Archive has too many entries: exceeded limit of ${maxEntries}`));
				});
				return header;
			}
			if (header.name.includes("\0")) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Invalid null byte in archive entry name: ${header.name}`));
				});
				return header;
			}
			if (header.type === "symlink" || header.type === "link") {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`Symlink detected in archive: ${header.name}. Symlinks are not supported for security reasons.`));
				});
				return header;
			}
			if (header.size && header.size > maxFileSize) {
				destroyScheduled = true;
				node_process.default.nextTick(() => {
					extractStream.destroy(new require_primordials_error.ErrorCtor(`File size exceeds limit: ${header.name} (${header.size} bytes > ${maxFileSize} bytes)`));
				});
				return header;
			}
			if (header.size) {
				totalExtractedSize += header.size;
				if (totalExtractedSize > maxTotalSize) {
					destroyScheduled = true;
					node_process.default.nextTick(() => {
						extractStream.destroy(new require_primordials_error.ErrorCtor(`Total extracted size exceeds limit: ${totalExtractedSize} bytes > ${maxTotalSize} bytes`));
					});
					return header;
				}
			}
			/* c8 ignore stop */
			return header;
		},
		strip
	});
	extractStream.on("error", () => {});
	const readStream = (0, node_fs.createReadStream)(archivePath);
	try {
		await (0, node_stream_promises.pipeline)(readStream, (0, node_zlib.createGunzip)(), extractStream);
	} catch (e) {
		readStream.destroy();
		throw e;
	}
}

//#endregion
exports.extractTar = extractTar;
exports.extractTarGz = extractTarGz;