const zlib = require('zlib'); const fs = require('fs'); function createTar(files) { const chunks = []; for (const file of files) { const name = file.name; const content = Buffer.isBuffer(file.content) ? file.content : Buffer.from(file.content, 'utf8'); const size = content.length; const header = Buffer.alloc(512); // name (0..99) header.write(name, 0, 100, 'utf8'); // mode (100..107) header.write('0000644\0', 100, 8, 'utf8'); // uid (108..115) header.write('0000000\0', 108, 8, 'utf8'); // gid (116..123) header.write('0000000\0', 116, 8, 'utf8'); // size (124..135) header.write(size.toString(8).padStart(11, '0') + '\0', 124, 12, 'utf8'); // mtime (136..147) const mtime = Math.floor(Date.now() / 1000); header.write(mtime.toString(8).padStart(11, '0') + '\0', 136, 12, 'utf8'); // chksum placeholder (148..155) - 8 spaces header.write(' ', 148, 8, 'utf8'); // typeflag (156) - '0' regular file header.write('0', 156, 1, 'utf8'); // magic (257..262) - 'ustar\0' header.write('ustar\0', 257, 6, 'utf8'); // version (263..264) - '00' header.write('00', 263, 2, 'utf8'); // calculate checksum let sum = 0; for (let i = 0; i < 512; i++) { sum += header[i]; } header.write(sum.toString(8).padStart(6, '0') + '\0 ', 148, 8, 'utf8'); chunks.push(header); chunks.push(content); // pad content to 512 bytes const remainder = size % 512; if (remainder > 0) { chunks.push(Buffer.alloc(512 - remainder)); } } // 2 blocks of 512 zeros at end of tar chunks.push(Buffer.alloc(1024)); const tarBuffer = Buffer.concat(chunks); return zlib.gzipSync(tarBuffer); } const testTarGz = createTar([ { name: 'Dockerfile', content: 'FROM alpine:latest\nCMD ["echo", "hello"]\n' }, { name: 'test.txt', content: 'hello world\n' } ]); console.log('Tar.gz created successfully, size:', testTarGz.length); // verify decompression const uncompressed = zlib.gunzipSync(testTarGz); console.log('Uncompressed tar size:', uncompressed.length);