UNPKG

@sanity/migrate

Version:

Tooling for running data migrations on Sanity.io projects

215 lines (214 loc) • 6.44 kB
// Extracted from https://github.com/mafintosh/tar-stream/blob/master/headers.js // Converted to TypeScript and removed reliance on Node Buffers import { areUint8ArraysEqual } from '../uint8arrays/index.js'; var ZERO_OFFSET = '0'.codePointAt(0); var USTAR_MAGIC = new Uint8Array([ 0x75, 0x73, 0x74, 0x61, 0x72, 0x00 ]) // ustar\x00 ; var GNU_MAGIC = new Uint8Array([ 0x75, 0x73, 0x74, 0x61, 0x72, 0x20 ]) // ustar\x20 ; var GNU_VER = new Uint8Array([ 0x20, 0x00 ]); var MAGIC_OFFSET = 257; var VERSION_OFFSET = 263; export function decode(buf, filenameEncoding, allowUnknownFormat) { var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET; var name = decodeStr(buf, 0, 100, filenameEncoding); var mode = decodeOct(buf, 100, 8); var uid = decodeOct(buf, 108, 8); var gid = decodeOct(buf, 116, 8); var size = decodeOct(buf, 124, 12); var mtime = decodeOct(buf, 136, 12); var type = toType(typeflag); var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100, filenameEncoding); var uname = decodeStr(buf, 265, 32); var gname = decodeStr(buf, 297, 32); var devmajor = decodeOct(buf, 329, 8); var devminor = decodeOct(buf, 337, 8); var c = cksum(buf); // checksum is still initial value if header was null. if (c === 8 * 32) return null; // valid checksum if (c !== decodeOct(buf, 148, 8)) { throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?'); } if (isUSTAR(buf)) { // ustar (posix) format. // prepend prefix, if present. if (buf[345]) name = "".concat(decodeStr(buf, 345, 155, filenameEncoding), "/").concat(name); } else if (isGNU(buf)) { // 'gnu'/'oldgnu' format. Similar to ustar, but has support for incremental and // multi-volume tarballs. } else if (!allowUnknownFormat) { throw new Error('Invalid tar header: unknown format.'); } // to support old tar versions that use trailing / to indicate dirs if (typeflag === 0 && name && name.at(-1) === '/') typeflag = 5; return { devmajor: devmajor, devminor: devminor, gid: gid, gname: gname, linkname: linkname, mode: mode, mtime: mtime ? new Date(1000 * mtime) : null, name: name, size: size, type: type, uid: uid, uname: uname }; } function isUSTAR(buf) { return areUint8ArraysEqual(USTAR_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)); } function isGNU(buf) { return areUint8ArraysEqual(GNU_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)) && areUint8ArraysEqual(GNU_VER, buf.subarray(VERSION_OFFSET, VERSION_OFFSET + 2)); } function clamp(index, len, defaultValue) { if (typeof index !== 'number') return defaultValue; index = Math.trunc(index); // Coerce to integer. if (index >= len) return len; if (index >= 0) return index; index += len; if (index >= 0) return index; return 0; } function toType(flag) { switch(flag){ case 0: { return 'file'; } case 1: { return 'link'; } case 2: { return 'symlink'; } case 3: { return 'character-device'; } case 4: { return 'block-device'; } case 5: { return 'directory'; } case 6: { return 'fifo'; } case 7: { return 'contiguous-file'; } case 27: { return 'gnu-long-link-path'; } case 28: case 30: { return 'gnu-long-path'; } case 55: { return 'pax-global-header'; } case 72: { return 'pax-header'; } default: { return null; } } } function indexOf(block, num, offset, end) { for(; offset < end; offset++){ if (block[offset] === num) return offset; } return end; } function cksum(block) { var sum = 8 * 32; for(var i = 0; i < 148; i++)sum += block[i]; for(var j = 156; j < 512; j++)sum += block[j]; return sum; } /* Copied from the node-tar repo and modified to meet * tar-stream coding standard. * * Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349 */ function parse256(buf) { // first byte MUST be either 80 or FF // 80 for positive, FF for 2's comp var positive; if (buf[0] === 0x80) positive = true; else if (buf[0] === 0xff) positive = false; else return null; // build up a base-256 tuple from the least sig to the highest var tuple = []; var i; for(i = buf.length - 1; i > 0; i--){ var byte = buf[i]; if (positive) tuple.push(byte); else tuple.push(0xff - byte); } var sum = 0; var l = tuple.length; for(i = 0; i < l; i++){ sum += tuple[i] * Math.pow(256, i); } return positive ? sum : -1 * sum; } var decoders = {}; var getCachedDecoder = function(encoding) { if (!(encoding in decoders)) { decoders[encoding] = new TextDecoder(encoding); } return decoders[encoding]; }; function toString(uint8) { var encoding = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 'utf8'; return getCachedDecoder(encoding).decode(uint8); } function decodeOct(val, offset, length) { val = val.subarray(offset, offset + length); offset = 0; // If prefixed with 0x80 then parse as a base-256 integer if (val[offset] & 0x80) { return parse256(val); } // Older versions of tar can prefix with spaces while(offset < val.length && val[offset] === 32)offset++; var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length); while(offset < end && val[offset] === 0)offset++; if (end === offset) return 0; return Number.parseInt(toString(val.subarray(offset, end)), 8); } function decodeStr(val, offset, length, encoding) { return toString(val.subarray(offset, indexOf(val, 0, offset, offset + length)), encoding); }