mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-06 00:13:33 +00:00
initial rev of streaming tar encoder
This commit is contained in:
260
modules/tar-encoder.js
Normal file
260
modules/tar-encoder.js
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
Copyright 2019 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var readable = require('stream').Readable;
|
||||
|
||||
|
||||
function loadUstarHeader(path, offset)
|
||||
{
|
||||
var fd = require('fs').openSync(path, 'rb');
|
||||
var buffer = Buffer.alloc(512);
|
||||
var result = require('fs').readSync(fd, buffer, 0, 512, offset);
|
||||
require('fs').closeSync(fd);
|
||||
|
||||
var v = 0;
|
||||
for (var i = 0; i < 512; ++i)
|
||||
{
|
||||
if (i >= 148 && i < 155)
|
||||
{
|
||||
v += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
v += buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (parseInt(buffer.slice(148, 148 + 8).toString(), 8) != (new Uint32Array([v]))[0])
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
function generateUstarHeader(path, basePath, uidtable, gidtable)
|
||||
{
|
||||
var ret = Buffer.alloc(512);
|
||||
var stats = require('fs').statSync(path);
|
||||
var name = process.platform == 'win32' ? path.split('\\').join('/') : path;
|
||||
if (basePath) { name = name.substring(basePath.endsWith('/') ? basePath.length : (basePath.length + 1)); }
|
||||
|
||||
if (stats.isFile())
|
||||
{
|
||||
Buffer.from(stats.size.toString(8), 'binary').copy(ret, 124, 0, 12);
|
||||
Object.defineProperty(ret, 'isFile', { value: true });
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.from('0').copy(ret, 124, 0, 12);
|
||||
Object.defineProperty(ret, 'isFile', { value: false });
|
||||
name += '/';
|
||||
}
|
||||
|
||||
Buffer.from(name, 'binary').copy(ret, 0, 0, 100);
|
||||
ret[156] = stats.isFile() ? 48 : 53;
|
||||
Buffer.from((Date.parse(stats.mtime) / 1000).toString(8), 'binary').copy(ret, 136, 0, 12);
|
||||
Buffer.from('USTAR', 'binary').copy(ret, 257, 0, 5);
|
||||
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
// Windows Platforms, set UID/GID to 0
|
||||
Buffer.from('0', 'binary').copy(ret, 108, 0, 8); // uid
|
||||
Buffer.from('0', 'binary').copy(ret, 116, 0, 8); // gid
|
||||
|
||||
// Windows Platforms, set uname/gname to root/root
|
||||
Buffer.from('root', 'binary').copy(ret, 265, 0, 32);
|
||||
Buffer.from('root', 'binary').copy(ret, 297, 0, 32);
|
||||
|
||||
// Windows Platforms, set mode to (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
|
||||
var m = require('fs').CHMOD_MODES;
|
||||
Buffer.from((m.S_IRUSR | m.S_IWUSR | m.S_IRGRP | m.S_IWGRP | m.S_IROTH | m.S_IWOTH).toString(8), 'binary').copy(ret, 100, 0, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// POSIX platforms, set the UID/GID
|
||||
Buffer.from(stats.uid.toString(8), 'binary').copy(ret, 108, 0, 8); // uid
|
||||
Buffer.from(stats.gid.toString(8), 'binary').copy(ret, 116, 0, 8); // gid
|
||||
|
||||
if (!uidtable[stats.uid]) { uidtable[stats.uid] = require('user-sessions').getUsername(stats.uid); }
|
||||
if (!gidtable[stats.gid]) { gidtable[stats.gid] = require('user-sessions').getGroupname(stats.gid); }
|
||||
|
||||
Buffer.from(uidtable[stats.uid], 'binary').copy(ret, 265, 0, 32);
|
||||
Buffer.from(gidtable[stats.gid], 'binary').copy(ret, 297, 0, 32);
|
||||
|
||||
// Set Mode
|
||||
Buffer.from(stats.mode.toString(8), 'binary').copy(ret, 100, 0, 8);
|
||||
}
|
||||
|
||||
|
||||
var checksum = 0;
|
||||
for (var i = 0; i < 8; ++i)
|
||||
{
|
||||
ret[148 + i] = 32; // Blank out the checksum, so we can calculate the checksum, then write it back
|
||||
}
|
||||
for (var i = 0; i < 512; ++i)
|
||||
{
|
||||
checksum += ret[i];
|
||||
}
|
||||
Buffer.from(checksum.toString(8), 'binary').copy(ret, 148, 0, 8); // Write the checksum
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function encodeFiles(files, basePath)
|
||||
{
|
||||
var ret = new readable(
|
||||
{
|
||||
read: function read()
|
||||
{
|
||||
var bytesRead;
|
||||
var ok = true;
|
||||
if(this._fd == null)
|
||||
{
|
||||
if (this.files.length > 0)
|
||||
{
|
||||
var name = this.files.shift();
|
||||
var header = generateUstarHeader(name, this._basePath, this._uidTable, this._gidTable);
|
||||
if (header.isFile) { this._fd = require('fs').openSync(name, 'rb'); }
|
||||
ok = this.push(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.pause();
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
while(this._fd != null && ok)
|
||||
{
|
||||
bytesRead = require('fs').readSync(this._fd, this._buffer, 0, 512);
|
||||
this._buffer.fill(0, bytesRead, 512);
|
||||
if (bytesRead < 512)
|
||||
{
|
||||
require('fs').closeSync(this._fd);
|
||||
this._fd = null;
|
||||
}
|
||||
ok = this.push(this._buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
ret.files = files;
|
||||
ret._basePath = basePath;
|
||||
ret._fd = null;
|
||||
ret._buffer = Buffer.alloc(512);
|
||||
ret._uidTable = {};
|
||||
ret._gidTable = {};
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function expandFolderPaths(folderPath, recurse, arr)
|
||||
{
|
||||
var files = require('fs').readdirSync(folderPath);
|
||||
for(var f in files)
|
||||
{
|
||||
if(require('fs').statSync(folderPath + '/' + files[f]).isDirectory())
|
||||
{
|
||||
if (recurse)
|
||||
{
|
||||
arr.push(folderPath + '/' + files[f]);
|
||||
expandFolderPaths(folderPath + '/' + files[f], recurse, arr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arr.push(folderPath + '/' + files[f]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function encodeFolder(folderPath, recurse)
|
||||
{
|
||||
var files = [];
|
||||
expandFolderPaths(folderPath, recurse, files);
|
||||
return (encodeFiles(files, folderPath));
|
||||
}
|
||||
|
||||
function showHeader(path, offset)
|
||||
{
|
||||
do
|
||||
{
|
||||
var b = loadUstarHeader(path, offset);
|
||||
if (b == null) { break; }
|
||||
if (offset != null && isNaN(offset)) { process.exit();}
|
||||
console.log('-----------------------------');
|
||||
console.log('THIS Offset: ' + (offset == null ? 0 : offset));
|
||||
var mtime = parseInt(b.slice(136, 136 + 12).toString(), 8) * 1000;
|
||||
console.log('name: ' + b.slice(0, 100).toString());
|
||||
console.log('size: ' + parseInt(b.slice(124, 124 + 12).toString(), 8));
|
||||
console.log('mtime: ' + (new Date(mtime)).toString());
|
||||
console.log('type: ' + String.fromCharCode(b[156]));
|
||||
console.log('linkname: ' + b.slice(157, 257).toString());
|
||||
console.log('magic: ' + b.slice(257, 257 + 6).toString());
|
||||
console.log('version: ' + b.slice(263, 265).toString('hex'));
|
||||
console.log('uname: ' + b.slice(265, 265 + 32).toString());
|
||||
console.log('uid: ' + parseInt(b.slice(108, 108 + 8).toString(), 8));
|
||||
console.log('gname: ' + b.slice(297, 297 + 32).toString());
|
||||
console.log('gid: ' + parseInt(b.slice(116, 116 + 8).toString(), 8));
|
||||
console.log('prefix: ' + b.slice(345, 345 + 155).toString());
|
||||
console.log('mode: ' + b.slice(100, 100 + 8).toString());
|
||||
console.log('checksum: ' + parseInt(b.slice(148, 148 + 8).toString(), 8).toString());
|
||||
|
||||
// Calculate Checksum
|
||||
for (var i = 0; i < 8; ++i)
|
||||
{
|
||||
b[148 + i] = 32;
|
||||
}
|
||||
|
||||
var v = 0;
|
||||
for (var i = 0; i < 512; ++i)
|
||||
{
|
||||
v += b[i];
|
||||
}
|
||||
|
||||
v = (new Uint32Array([v]))[0]
|
||||
console.log('Computed Checksum: ' + v.toString());
|
||||
console.log('');
|
||||
if (String.fromCharCode(b[156]) == '5')
|
||||
{
|
||||
if(offset == null)
|
||||
{
|
||||
offset = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += 512;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var filesize = parseInt(b.slice(124, 124 + 12).toString(), 8);
|
||||
var recordskip = Math.floor(filesize / 512);
|
||||
if (filesize % 512 != 0) { ++recordskip; }
|
||||
if (offset == null)
|
||||
{
|
||||
offset = recordskip * 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += (recordskip * 512);
|
||||
}
|
||||
offset += 512;
|
||||
}
|
||||
} while (offset != null);
|
||||
}
|
||||
|
||||
module.exports = { encodeFolder: encodeFolder, encodeFiles: encodeFiles, showHeader: showHeader };
|
||||
Reference in New Issue
Block a user