UNPKG

tar-iterator

Version:

Extract contents from tar archive type using an iterator API using streams or paths. Use stream interface and pipe transforms to add decompression algorithms

136 lines 5.04 kB
/** * Extensions - GNU/PAX extension handling for TAR * * Manages state and decoding for: * - GNU LongPath (type 'L') - paths > 100 chars * - GNU LongLink (type 'K') - symlink targets > 100 chars * - PAX Headers (type 'x') - extended attributes per-entry * - PAX Global Headers (type 'g') - extended attributes for all entries */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get applyExtensions () { return applyExtensions; }, get applyPaxToHeader () { return applyPaxToHeader; }, get concatBuffers () { return concatBuffers; }, get createExtensionState () { return createExtensionState; }, get finalizeExtension () { return finalizeExtension; } }); var _extractbaseiterator = require("extract-base-iterator"); var _headersts = require("./headers.js"); function createExtensionState() { return { gnuLongPath: null, gnuLongLink: null, paxHeader: null, paxGlobal: {}, extensionData: [], extensionRemaining: 0 }; } function finalizeExtension(state, currentState, header, encoding) { // Import state constants var STATE_GNU_LONG_PATH = 4; var STATE_GNU_LONG_LINK = 5; var STATE_PAX_HEADER = 6; // Concatenate all collected data var combined = concatBuffers(state.extensionData); state.extensionData = []; switch(currentState){ case STATE_GNU_LONG_PATH: state.gnuLongPath = (0, _headersts.decodeLongPath)(combined, encoding); break; case STATE_GNU_LONG_LINK: state.gnuLongLink = (0, _headersts.decodeLongPath)(combined, encoding); break; case STATE_PAX_HEADER: // Check if this was a global header if (header && header.type === 'pax-global-header') { var global = (0, _headersts.decodePax)(combined); // Merge into global (don't replace, merge) for(var key in global){ // biome-ignore lint/suspicious/noPrototypeBuiltins: ES2021 compatibility if (global.hasOwnProperty(key)) { state.paxGlobal[key] = global[key]; } } } else { state.paxHeader = (0, _headersts.decodePax)(combined); } break; } } function applyExtensions(header, state) { // Apply PAX global header first if (state.paxGlobal) { applyPaxToHeader(header, state.paxGlobal); } // Apply PAX header (per-entry, overrides global) if (state.paxHeader) { applyPaxToHeader(header, state.paxHeader); header.pax = state.paxHeader; state.paxHeader = null; } // Apply GNU long path (overrides PAX path) if (state.gnuLongPath !== null) { header.name = state.gnuLongPath; state.gnuLongPath = null; } // Apply GNU long link (overrides PAX linkpath) if (state.gnuLongLink !== null) { header.linkname = state.gnuLongLink; state.gnuLongLink = null; } // Handle old tar versions that use trailing / to indicate directories // This check is done AFTER extensions are applied so we use the final // resolved name (GNU long path or PAX path), not the truncated name field. if (header.type === 'file' && header.name && header.name[header.name.length - 1] === '/') { header.type = 'directory'; } } function applyPaxToHeader(header, pax) { if (pax.path) header.name = pax.path; if (pax.linkpath) header.linkname = pax.linkpath; if (pax.size) header.size = parseInt(pax.size, 10); if (pax.uid) header.uid = parseInt(pax.uid, 10); if (pax.gid) header.gid = parseInt(pax.gid, 10); if (pax.uname) header.uname = pax.uname; if (pax.gname) header.gname = pax.gname; if (pax.mtime) header.mtime = new Date(parseFloat(pax.mtime) * 1000); } function concatBuffers(buffers) { if (buffers.length === 0) return Buffer.alloc ? Buffer.alloc(0) : new Buffer(0); if (buffers.length === 1) return buffers[0]; var totalLength = buffers.reduce(function(sum, buf) { return sum + buf.length; }, 0); if (Buffer.concat) { return Buffer.concat(buffers, totalLength); } // Node 0.8 fallback var result = (0, _extractbaseiterator.allocBufferUnsafe)(totalLength); var offset = 0; for(var i = 0; i < buffers.length; i++){ buffers[i].copy(result, offset); offset += buffers[i].length; } return result; } /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }