Skip to content

Instantly share code, notes, and snippets.

@Azq2
Created January 14, 2023 22:04
Show Gist options
  • Select an option

  • Save Azq2/0aadadcc05e373acd6c2b38455878b8e to your computer and use it in GitHub Desktop.

Select an option

Save Azq2/0aadadcc05e373acd6c2b38455878b8e to your computer and use it in GitHub Desktop.
import fs from 'fs';
import path from 'path';
import child_process from 'child_process';
const OUTPUT_PATH = "/tmp/android";
let code = fs.readFileSync('./META-INF/com/google/android/updater-script').toString();
code = code.replace(/,\s*(0[\d]+)\s*,/gim, ', "$1", ');
code = code.replace(/delete\(/gim, 'deleteFile(');
//exec('rm', ['-rf', OUTPUT_PATH]);
exec('mkdir', ['-p', OUTPUT_PATH]);
eval(code);
function ui_print(str) {
// console.log(str);
}
function show_progress(v) {
// console.log('progress: ' + v + '%');
}
function set_progress(v) {
// console.log('progress: ' + (v * 100) + '%');
}
function unmount(path) {
// console.log(`unmount: ${path}`);
}
function format(type, label, dev, unk, path) {
// console.log(`format ${dev} to ${type} [${label}]`);
}
function mount(type, label, dev, path) {
// console.log(`mount ${dev} to ${path} as ${type} [${label}]`);
}
function package_extract_dir(from, to) {
console.log(`package_extract_dir: ${from} -> ${to}`);
exec('rsync', [
'-av', '--delete', `./${from}/`, `${OUTPUT_PATH}${to}/`
]);
}
function package_extract_file(from, to) {
// console.log(`package_extract_file: ${from} -> ${to}`);
}
function symlink(src, ...dsts) {
console.log(`symlink: ${src} -> ${dsts.join(', ')}`);
for (let dst of dsts) {
if (fs.existsSync(`${OUTPUT_PATH}${dst}`))
fs.unlinkSync(`${OUTPUT_PATH}${dst}`);
exec('mkdir', [
'-p', src, path.dirname(`${OUTPUT_PATH}${dst}`)
]);
exec('ln', [
'-s', src, `${OUTPUT_PATH}${dst}`
]);
}
}
function __read_files_and_dirs(dir, base, files, dirs) {
base = base || "";
files = files || [];
dirs = dirs || [];
fs.readdirSync(dir, {withFileTypes: true}).forEach((entry) => {
if (entry.isDirectory()) {
dirs.push(base + entry.name);
__read_files_and_dirs(dir + "/" + entry.name, base + entry.name + "/", files, dirs);
} else {
files.push(base + entry.name);
}
});
return [files, dirs];
}
function set_metadata_recursive(path, ...attrs_list) {
let attrs = {};
for (let i = 0; i < attrs_list.length; i += 2) {
let k = attrs_list[i];
let v = attrs_list[i + 1];
attrs[k] = v;
}
let file_attrs = Object.assign({}, attrs);
if ('fmode' in attrs)
file_attrs.mode = attrs.fmode;
let dir_attrs = Object.assign({}, attrs);
if ('dmode' in attrs)
dir_attrs.mode = attrs.dmode;
console.log(`set_metadata_recursive: ${path} [ ${JSON.stringify(attrs)} ]`);
let [files, dirs] = __read_files_and_dirs(OUTPUT_PATH + path);
for (let file of files)
__set_metadata(`${path}/${file}`, file_attrs);
for (let dir of dirs)
__set_metadata(`${path}/${dir}`, dir_attrs);
}
function __set_metadata(path, attrs) {
if (!fs.existsSync(OUTPUT_PATH + path))
return;
if ('uid' in attrs) {
exec('chown', [attrs.uid, `${OUTPUT_PATH}${path}`]);
}
if ('gid' in attrs) {
exec('chgrp', [attrs.gid, `${OUTPUT_PATH}${path}`]);
}
if ('mode' in attrs) {
exec('chmod', [attrs.mode, `${OUTPUT_PATH}${path}`]);
}
if ('selabel' in attrs) {
exec('chcon', [attrs.selabel, `${OUTPUT_PATH}${path}`]);
}
if ('capabilities' in attrs) {
if (attrs.capabilities == 0) {
exec('setfattr', ['-x', 'security.capability', `${OUTPUT_PATH}${path}`], [0, 1]);
} else {
let capabilities = BigInt(attrs.capabilities);
let permitted = [
Number(capabilities & BigInt('0xFFFFFFFF')),
Number((capabilities >> BigInt(32)) & BigInt('0xFFFFFFFF'))
];
let cap_data = Buffer.from([
0x01, 0x00, 0x00, 0x02, // magic_etc
(permitted[0] & 0xFF), ((permitted[0] >> 8) & 0xFF), ((permitted[0] >> 16) & 0xFF), ((permitted[0] >> 24) & 0xFF), // permitted[0]
0, 0, 0, 0, // inheritable[0]
(permitted[1] & 0xFF), ((permitted[1] >> 8) & 0xFF), ((permitted[1] >> 16) & 0xFF), ((permitted[1] >> 24) & 0xFF), // permitted[1]
0, 0, 0, 0, // inheritable[1]
]);
exec('setfattr', ['-n', 'security.capability', '-v', '0s' + cap_data.toString('base64'), `${OUTPUT_PATH}${path}`]);
}
}
}
function set_metadata(path, ...attrs_list) {
let attrs = {};
for (let i = 0; i < attrs_list.length; i += 2) {
let k = attrs_list[i];
let v = attrs_list[i + 1];
attrs[k] = v;
}
console.log(`set_metadata_recursive: ${path} [ ${JSON.stringify(attrs)} ]`);
__set_metadata(path, attrs);
}
function deleteFile(file) {
console.log(`delete: ${file}`);
if (fs.existsSync(OUTPUT_PATH + file))
fs.unlinkSync(OUTPUT_PATH + file);
}
function write_raw_image(from, to) {
// console.log(`write_raw_image: ${from} -> ${to}`);
}
function assert(v) {
}
function exec(cmd, args, allow_codes) {
console.log(`[cmd] ${cmd} ${args.join(' ')}`);
let result = child_process.spawnSync(cmd, args, {
stdio: ['ignore', process.stdout, process.stderr]
});
if (result.status != 0 && (!allow_codes || !allow_codes.includes(result.status)))
throw new Error(`Command failed!`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment