Created
January 14, 2023 22:04
-
-
Save Azq2/0aadadcc05e373acd6c2b38455878b8e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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