Files

68 lines
2.1 KiB
JavaScript

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);