68 lines
2.1 KiB
JavaScript
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);
|