initial commit

Signed-off-by: ColdWindScholar <3590361911@qq.com>
pull/2/head
ColdWindScholar 2023-07-24 20:29:02 +08:00
commit 148683743d
90 changed files with 17930 additions and 0 deletions

BIN
bin/images/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
bin/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

BIN
bin/images/loading_dark.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
bin/images/none Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

BIN
bin/images/wechat.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,185 @@
{
"ok": "确定",
"cancel": "取消",
"pack": "打包",
"unpack": "解包",
"lang": "语言:",
"settings": "设置",
"warn1": "请选择一个项目",
"warn2": "请选择一个插件",
"warn3": "未发现 {}",
"warn4": "解包失败...{}",
"warn5": "您未解包" ,
"warn6": "未发现图像文件!",
"warn7": "{} 未完全安装或损坏",
"warn8": "此插件不可运行",
"warn9": "卸载失败!此插件是否正在运行或被占用",
"warn10": "很抱歉,打包失败!",
"warn11": "删除 {} 失败!",
"warn12": "请输入",
"warn13": "警告:您正在使用普通用户运行工具,这可能导致解(打)包异常",
"warn14": "不支持的控件:{}",
"text1": "正在写入:",
"text2": "写入 {} 时出现错误 {}",
"text3": "打包 {} 成功!",
"text4": "正在反编译 {0}",
"text5": "解包成功!",
"text6": "正在回编译:",
"text7": "正在创建镜像:",
"text8": "成功!",
"text9": "功能",
"text10": "日志",
"text11": "主页",
"text12": "项目",
"text13": "设置",
"text14": "关于",
"text15": "后台任务",
"text16": "捐赠支持",
"text17": "关闭",
"text18": "子页面",
"text19": "插件管理器",
"text20": "卸载",
"text21": "安装",
"text22": "运行",
"text23": "刷新",
"text24": "单击右键以显示菜单",
"text25": "选择插件",
"text26": "插件",
"text27": "未实现",
"text28": "浏览",
"text29": "正在卸载:{}",
"text30": "卸载完成!",
"text31": "插件安装",
"text32": "版本:{}",
"text33": "作者:{}",
"text34": "完成",
"text35": "依赖正常:{}",
"text36": "%s 依赖于 %s但 %s 没有安装",
"text37": "重试",
"text38": "正在抽取:{0}",
"text39": "安装完毕",
"text40": "准备就绪",
"text41": "安装",
"text42": "打包设置",
"text43": "EXT4设置",
"text44": "EROFS打包",
"text45": "其他设置",
"text46": "打包分区",
"text47": "BR等级{}",
"text48": "打包方式:",
"text49": "打包格式:",
"text50": "压缩算法",
"text51": "版本:",
"text52": "处理Vbmeta",
"text53": "Super打包设置",
"text54": "分区类型",
"text55": "打包分区",
"text56": "簇名",
"text57": "Super大小",
"text58": "Sparse压缩",
"text59": "打包成功!输出:%s",
"text60": "请输入下载链接",
"text61": "下载:",
"text62": "已添加到后台任务",
"text63": "自动解包",
"text64": "进度:{} %\n下载速度:{} KB/S\n已下载: {} B/ {} B",
"text65": "{} 下载完成!用时 {} seconds",
"text66": "下载出错",
"text67": "请手动删除",
"text68": "下载失败",
"text69": "清理文件夹异常",
"text70": "找到:%s",
"text71": "正在处理:%s",
"text72": "正在清理:%s",
"text73": "删除%s失败原因%s",
"text74": "将 %s 大小调整为 %s",
"text75": "打包%s失败",
"text76": "输入文本",
"text77": "选择文件:",
"text78": "正在解密OZIP:",
"text79": "正在解包:",
"text80": "%s 解包失败,原因:%s",
"text81": "解压完成",
"text82": "此文件非ZIP为%s",
"text83": "合并 %s 到 %s",
"text84": "不存在",
"text85": "正在处理:",
"text86": "把 %s 打包为 %s.new.dat",
"text87": "打包%s.new.dat完成",
"text88": "开始打包%s.new.dat.br",
"text89": "打包%s.new.dat.br完成",
"text90": "开始打包:%s [erofs] \n压缩格式:%s \n版本%s",
"text91": "开始打包:%s",
"text92": "状态:",
"text93": "上传失败",
"text94": "上传成功",
"text95": "日志已保存到:",
"text96": "已选择项目:",
"text97": "正在删除:",
"text98": "删除成功:",
"text99": "新建项目:%s",
"text100": "选择主题:",
"text101": "选择主题失败:%s 原因:%s",
"text102": "重命名:",
"text103": "存在同名文件夹或文件!",
"text104": "名称相同",
"text105": "清空",
"text106": "导出",
"text107": "上传",
"text108": "欢迎使用全新的 MIO-KITCHEN\n本工具永久免费",
"text109": "Mio-KitChen 将一直保持免费,向开发者捐赠以表示支持.",
"text110": "© 2023 米欧科技版权所有.",
"text111": "- 专注于安卓ROM修改 -",
"text112": "其他",
"text113": "解包ROM",
"text114": "下载ROM",
"text115": "新建",
"text116": "删除",
"text117": "重命名",
"text118": "打包项目",
"text119": "打包BOOT",
"text120": "打包DTBO",
"text121": "打包LOGO",
"text122": "打包ZIP",
"text123": "打包Super",
"text124": "主题:",
"text125": "路径",
"text126": "修改",
"text127": "CoolMi x Mio-KitChen\n荣誉出品",
"text128": "工具版本:{}\nPython库版本{}\n操作系统{}\n指令集{}",
"text129": "选择语言:",
"text130": "选择语言失败!",
"text131": "拖入文件",
"text132": "在此处拖入插件或ROM\n或使用鼠标单击此处选择文件",
"text133": "插件无法解析",
"text134": "初始化用时: %s Seconds",
"text135": "欢迎!",
"text136": "开始",
"text137": "欢迎使用全新的 MIO-KITCHEN!\n让我们开始吧",
"text138": "下一步",
"text139": "开源协议",
"t1": "点击(下一步)即代表您已全部阅读并认同协议,\n并保证严格遵守",
"t2": "隐私政策和用户协议",
"t3": "点击(下一步)即代表您已全部阅读并同意隐私政策和用户协议",
"t4": "设置完成",
"t5": "体验激动人心的M.K.C吧\n单击完成以关闭此窗口",
"t6": "卸载插件",
"t7": "要卸载%s吗",
"t8": "同时会卸载以下插件:",
"t9": "是否删除 {}",
"t10": "Super大小太小.\n请重新设置大小。\n已为您填入参考值",
"t11": "删除源文件",
"t12": "您的OFP是MTK还是QC\nMTK:按确定\nQC:按取消",
"t13": "格式转换",
"t14": "导出",
"t15": "导出成功:%s",
"t16": "导出失败:%s",
"t17": "编辑",
"t18": "您的插件项目没有脚本文件\n请选择要创建的脚本类型",
"t19": "新建插件",
"t20": "名称:",
"t21": "作者",
"t22": "版本",
"t23": "依赖库:",
"t24": "介绍:"
}

185
bin/languages/English.json Normal file
View File

@ -0,0 +1,185 @@
{
"ok": "OK",
"cancel": "Cancel",
"pack": "Pack",
"unpack": "Unpack",
"lang": "Language:",
"settings": "Settings",
"warn1": "Please select a project",
"warn2": "Please select a plugin",
"warn3": "{} not found",
"warn4": "Unpacking failed... {}",
"warn5": "You have not unpacked",
"warn6": "Image file not found!" ,
"warn7": "{} not fully installed or damaged",
"warn8": "This plugin is not operational",
"warn9": "Uninstall failed! whether this plugin is running or occupied",
"warn10": "Sorry, packaging failed!" ,
"warn11": "Failed to delete {}!" ,
"warn12": "Please enter",
"warn13": "Warning: You are using a normal user to run the tool, this may cause packet deciphering (hitting) abnormalities",
"warn14": "Unsupport control{}",
"text1": "Writing:",
"text2": "Error writing {} :{}",
"text3": "Packaging {} succeeded!" ,
"text4": "Decompiling {0}",
"text5": "Unpacked successfully!" ,
"text6": "Backcompiling:",
"text7": "Creating image:",
"text8": "Success!" ,
"text9": "Function",
"text10": "Logs",
"text11": "Home",
"text12": "Project",
"text13": "Settings",
"text14": "About",
"text15": "Background Task",
"text16": "Donation Support",
"text17": "Close",
"text18": "Subpage",
"text19": "Plugin Manager",
"text20": "Uninstall",
"text21": "Install",
"text22": "Run",
"text23": "Refresh",
"text24": "Right-click to display menu",
"text25": "Select plugin",
"text26": "Plugin",
"text27": "not implemented",
"text28": "Browse",
"text29": "Unloading: {}",
"text30": "Uninstallation complete!" ,
"text31": "Plugin Installation",
"text32": "Version:{}",
"text33": "Author:{}",
"text34": "Finish",
"text35": "dependent normal: {}",
"text36": "%s depends on %s, but %s is not installed",
"text37": "Retry",
"text38": "Extracting: {0}",
"text39": "Installation complete",
"text40": "Ready",
"text41": "Install",
"text42": "packaging settings",
"text43": "EXT4 PACKING",
"text44": "EROFS PACKING",
"text45": "Additional settings",
"text46": "Pack partition",
"text47": "BR Level:{}",
"text48": "Packing by:",
"text49": "Packaging format:",
"text50": "compression algorithm",
"text51": "Version:",
"text52": "Process Vbmeta",
"text53": "Super packaging settings",
"text54": "partition type",
"text55": "Packaging partition",
"text56": "Cluster name",
"text57": "Super size",
"text58": "Sparse compression",
"text59": "Packed successfully! Output: %s",
"text60": "Please enter download link",
"text61": "Download:",
"text62": "Added to background task",
"text63": "Automatic unpacking",
"text64": "Progress: {}%\nDownload speed: {}KB/S\nDownloaded: {}B/ {}B",
"text65": "{} Download complete! {} seconds",
"text66": "Download error",
"text67": "Please delete manually",
"text68": "Download failed",
"text69": "Clean folder exception",
"text70": "Found: %s",
"text71": "Processing: %s",
"text72": "Cleaning up: %s",
"text73": "Failed to delete %s! Reason: %s",
"text74": "Resize %s to %s",
"text75": "Failed to package %s!" ,
"text76": "Enter text",
"text77": "Select file:",
"text78": "Deciphering OZIP:",
"text79": "Unpacking:",
"text80": "%s unpack failed, reason: %s",
"text81": "Decompression completed",
"text82": "This file is not ZIP, %s",
"text83": "Merge %s to %s",
"text84": "does not exist",
"text85": "Processing:",
"text86": "Package %s as %s.new.dat",
"text87": "Packaging %s.new.dat complete",
"text88": "Start packing %s.new.dat.br",
"text89": "Packed %s.new.dat.br complete",
"text90": "Start packing: %s [erofs] \nCompression format: %s \nversion: %s",
"text91": "Start packing: %s",
"text92": "Status:",
"text93": "Upload failed",
"text94": "Upload successful",
"text95": "Logs saved to:",
"text96": "Selected items:",
"text97": "Deleting:",
"text98": "Delete successful:",
"text99": "New Project:%s",
"text100": "Select Theme:",
"text101": "Failed to select topic: %s Reason: %s",
"text102": "Rename:",
"text103": "A folder or file with the same name exists!" ,
"text104": "Same name",
"text105": "Clear",
"text106": "Export",
"text107": "Upload",
"text108": "Welcome to the new MIO-KITCHEN\nThis tool is free forever",
"text109": "Mio-KitChen will always remain free \n donate to developers as a token of support.",
"text110": "©2023 Miou Technology All Rights Reserved.",
"text111": "- Focus on Android ROM modification -",
"text112": "Other",
"text113": "Unpack ROM",
"text114": "Download ROM",
"text115": "New",
"text116": "Delete",
"text117": "Rename",
"text118": "Pack Project",
"text119": "Pack BOOT",
"text120": "Pack DTBO",
"text121": "Pack LOGO",
"text122": "Pack ZIP",
"text123": "Pack Super",
"text124": "Theme:",
"text125": "Path:",
"text126": "Modify",
"text127": "CoolMi x Mio-KitChen\nHonorary production",
"text128": "Tool version: {}\nPython library version: {}\nOperating system: {}\nInstruction set: {}",
"text129": "Select language:",
"text130": "Language selection failed!",
"text131": "Drag in file",
"text132": "Drag the plugin or ROM here \nor use the mouse to click here to select a file",
"text133": "The plugin cannot parse",
"text134": "Initialization time : %s Seconds",
"text135": "Welcome!",
"text136": "Start",
"text137": "Welcome to use New MIO-KITCHEN!\nLet's Start!",
"text138": "Next",
"text139": "Open source certificate",
"t1": "By clicking (Next), you have fully read and agree to the agreement,\nand ensure strict compliance with it",
"t2": "Privacy Policy and User Agreement",
"t3": "By clicking (Next), you have read and agreed to all privacy policies and user agreements",
"t4": "Setting completed",
"t5": "Experience the exciting M.K.C! \nClick Finish to close this Window",
"t6": "Uninstall Plug-in",
"t7": "Uninstall %s?",
"t8": "The following plugins will also be uninstalled:",
"t9": "Delete {}?",
"t10": "Super size {} too small.\nPlease reset the size.\nWe have filled in the reference value for you",
"t11": "Delete Source File",
"t12": "Is your OFP mtk or qc?\nMTK: enter ok\nQC: enter cancel",
"t13": "format conversion",
"t14": "Export",
"t15": "Export successful:%s",
"t16": "Export Fail:%s",
"t17": "Edit",
"t18": "Your plugin project does not have a script file \n Please select the type of script you want to create",
"t19": "Make New Plug-in",
"t20": "Name:",
"t21": "Author:",
"t22": "Version:",
"t23": "Dependent Libraries:",
"t24": "Introduce"
}

674
bin/licenses/Magisk.txt Normal file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

201
bin/licenses/android.txt Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

19
bin/licenses/brotli.txt Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,348 @@
--- A note on GPL versions
BusyBox is distributed under version 2 of the General Public License (included
in its entirety, below). Version 2 is the only version of this license which
this version of BusyBox (or modified versions derived from this one) may be
distributed under.
------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

676
bin/licenses/cpio.txt Normal file
View File

@ -0,0 +1,676 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

165
bin/licenses/cygwin.txt Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

1724
bin/licenses/dtc.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,546 @@
Valid-License-Identifier: Apache-2.0
SPDX-URL: https://spdx.org/licenses/Apache-2.0.html
Usage-Guide:
The Apache-2.0 may only be used for dual-licensed files where the other
license is GPL2 compatible. If you end up using this it MUST be used
together with a GPL2 compatible license using "OR".
To use the Apache License version 2.0 put the following SPDX tag/value
pair into a comment according to the placement guidelines in the
licensing rules documentation:
SPDX-License-Identifier: Apache-2.0
License-Text:
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the
copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other
entities that control, are controlled by, or are under common control with
that entity. For the purposes of this definition, "control" means (i) the
power, direct or indirect, to cause the direction or management of such
entity, whether by contract or otherwise, or (ii) ownership of fifty
percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source,
and configuration files.
"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled
object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the
Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial
revisions, annotations, elaborations, or other modifications represent, as
a whole, an original work of authorship. For the purposes of this License,
Derivative Works shall not include works that remain separable from, or
merely link (or bind by name) to the interfaces of, the Work and Derivative
Works thereof.
"Contribution" shall mean any work of authorship, including the original
version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the copyright owner or by an individual or Legal
Entity authorized to submit on behalf of the copyright owner. For the
purposes of this definition, "submitted" means any form of electronic,
verbal, or written communication sent to the Licensor or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that
are managed by, or on behalf of, the Licensor for the purpose of discussing
and improving the Work, but excluding communication that is conspicuously
marked or otherwise designated in writing by the copyright owner as "Not a
Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on
behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable copyright license to
reproduce, prepare Derivative Works of, publicly display, publicly
perform, sublicense, and distribute the Work and such Derivative Works
in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in
this section) patent license to make, have made, use, offer to sell,
sell, import, and otherwise transfer the Work, where such license
applies only to those patent claims licensable by such Contributor that
are necessarily infringed by their Contribution(s) alone or by
combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation
against any entity (including a cross-claim or counterclaim in a
lawsuit) alleging that the Work or a Contribution incorporated within
the Work constitutes direct or contributory patent infringement, then
any patent licenses granted to You under this License for that Work
shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or
Derivative Works thereof in any medium, with or without modifications,
and in Source or Object form, provided that You meet the following
conditions:
a. You must give any other recipients of the Work or Derivative Works a
copy of this License; and
b. You must cause any modified files to carry prominent notices stating
that You changed the files; and
c. You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices
from the Source form of the Work, excluding those notices that do not
pertain to any part of the Derivative Works; and
d. If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained within
such NOTICE file, excluding those notices that do not pertain to any
part of the Derivative Works, in at least one of the following
places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if
provided along with the Derivative Works; or, within a display
generated by the Derivative Works, if and wherever such third-party
notices normally appear. The contents of the NOTICE file are for
informational purposes only and do not modify the License. You may
add Your own attribution notices within Derivative Works that You
distribute, alongside or as an addendum to the NOTICE text from the
Work, provided that such additional attribution notices cannot be
construed as modifying the License.
You may add Your own copyright statement to Your modifications and may
provide additional or different license terms and conditions for use,
reproduction, or distribution of Your modifications, or for any such
Derivative Works as a whole, provided Your use, reproduction, and
distribution of the Work otherwise complies with the conditions stated
in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any
Contribution intentionally submitted for inclusion in the Work by You to
the Licensor shall be under the terms and conditions of this License,
without any additional terms or conditions. Notwithstanding the above,
nothing herein shall supersede or modify the terms of any separate
license agreement you may have executed with Licensor regarding such
Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
in writing, Licensor provides the Work (and each Contributor provides
its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied, including, without limitation,
any warranties or conditions of TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely
responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your
exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether
in tort (including negligence), contract, or otherwise, unless required
by applicable law (such as deliberate and grossly negligent acts) or
agreed to in writing, shall any Contributor be liable to You for
damages, including any direct, indirect, special, incidental, or
consequential damages of any character arising as a result of this
License or out of the use or inability to use the Work (including but
not limited to damages for loss of goodwill, work stoppage, computer
failure or malfunction, or any and all other commercial damages or
losses), even if such Contributor has been advised of the possibility of
such damages.
9. Accepting Warranty or Additional Liability. While redistributing the
Work or Derivative Works thereof, You may choose to offer, and charge a
fee for, acceptance of support, warranty, indemnity, or other liability
obligations and/or rights consistent with this License. However, in
accepting such obligations, You may act only on Your own behalf and on
Your sole responsibility, not on behalf of any other Contributor, and
only if You agree to indemnify, defend, and hold each Contributor
harmless for any liability incurred by, or claims asserted against, such
Contributor by reason of your accepting any such warranty or additional
liability.
END OF TERMS AND CONDITIONS
---------------------------------------------------------------------------------------------------------
Valid-License-Identifier: GPL-2.0
Valid-License-Identifier: GPL-2.0-only
Valid-License-Identifier: GPL-2.0+
Valid-License-Identifier: GPL-2.0-or-later
SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
Usage-Guide:
To use this license in source code, put one of the following SPDX
tag/value pairs into a comment according to the placement
guidelines in the licensing rules documentation.
For 'GNU General Public License (GPL) version 2 only' use:
SPDX-License-Identifier: GPL-2.0
or
SPDX-License-Identifier: GPL-2.0-only
For 'GNU General Public License (GPL) version 2 or any later version' use:
SPDX-License-Identifier: GPL-2.0+
or
SPDX-License-Identifier: GPL-2.0-or-later
License-Text:
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

201
bin/licenses/fspatch.txt Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

21
bin/licenses/img2sdat.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Andrei Conache
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
bin/licenses/other.txt Normal file
View File

@ -0,0 +1,3 @@
oppo_ozip_decrypt by bkerler
ext4-extractor by Ahmad723
payload_dumper by vm03

90
bin/licenses/private.txt Normal file
View File

@ -0,0 +1,90 @@
隐私政策
更新日期2023/7/2
生效日期2023/7/2
导言
MIO-KITCHHEN 是一款由 米欧科技 (以下简称“我们”)提供的产品。 您在使用我们的服务时,我们可能会收集和使用您的相关信息。我们希望通过本《隐私政策》向您说明,在使用我们的服务时,我们如何收集、使用、储存和分享这些信息,以及我们为您提供的访问、更新、控制和保护这些信息的方式。 本《隐私政策》与您所使用的 MIO-KITCHHEN 服务息息相关,希望您仔细阅读,在需要时,按照本《隐私政策》的指引,作出您认为适当的选择。本《隐私政策》中涉及的相关技术词汇,我们尽量以简明扼要的表述,并提供进一步说明的链接,以便您的理解。
您使用或继续使用我们的服务,即意味着同意我们按照本《隐私政策》收集、使用、储存和分享您的相关信息。
如对本《隐私政策》或相关事宜有任何问题,请通过 3590361911@qq.com 与我们联系。
1. 我们收集的信息
我们或我们的第三方合作伙伴提供服务时,可能会收集、储存和使用下列与您有关的信息。如果您不提供相关信息,可能无法注册成为我们的用户或无法享受我们提供的某些服务,或者无法达到相关服务拟达到的效果。
个人信息,您在注册账户或使用我们的服务时,向我们提供的相关个人信息,例如电话号码、电子邮件等。
日志信息指您使用我们的服务时系统可能通过cookies、标识符及相关技术收集的信息包括您的设备信息、浏览信息、点击信息并将该等信息储存为日志信息为您提供个性化的用户体验、保障服务安全。您可以通过浏览器设置拒绝或管理cookie、标识符或相关技术的使用。
2. 信息的存储
2.1 信息存储的方式和期限
我们会通过安全的方式存储您的信息包括本地存储例如利用APP进行数据缓存、数据库和服务器日志。
一般情况下,我们只会在为实现服务目的所必需的时间内或法律法规规定的条件下存储您的个人信息。
2.2 信息存储的地域
我们会按照法律法规规定,将境内收集的用户个人信息存储于中国境内。
目前我们不会跨境传输或存储您的个人信息。将来如需跨境传输或存储的,我们会向您告知信息出境的目的、接收方、安全保证措施和安全风险,并征得您的同意。
2.3 产品或服务停止运营时的通知
当我们的产品或服务发生停止运营的情况时,我们将以推送通知、公告等形式通知您,并在合理期限内删除您的个人信息或进行匿名化处理,法律法规另有规定的除外。
3. 信息安全
我们使用各种安全技术和程序以防信息的丢失、不当使用、未经授权阅览或披露。例如在某些服务中我们将利用加密技术例如SSL来保护您提供的个人信息。但请您理解由于技术的限制以及可能存在的各种恶意手段在互联网行业即便竭尽所能加强安全措施也不可能始终保证信息百分之百的安全。您需要了解您接入我们的服务所用的系统和通讯网络有可能因我们可控范围外的因素而出现问题。
4. 我们如何使用信息
我们可能将在向您提供服务的过程之中所收集的信息用作下列用途:
向您提供服务;
在我们提供服务时,用于身份验证、客户服务、安全防范、诈骗监测、存档和备份用途,确保我们向您提供的产品和服务的安全性;
帮助我们设计新服务,改善我们现有服务;
使我们更加了解您如何接入和使用我们的服务,从而针对性地回应您的个性化需求,例如语言设定、位置设定、个性化的帮助服务和指示,或对您和其他用户作出其他方面的回应;
向您提供与您更加相关的广告以替代普遍投放的广告;
评估我们服务中的广告和其他促销及推广活动的效果,并加以改善;
软件认证或管理软件升级;
让您参与有关我们产品和服务的调查。
5. 信息共享
目前,我们不会主动共享或转让您的个人信息至第三方,如存在其他共享或转让您的个人信息或您需要我们将您的个人信息共享或转让至第三方情形时,我们会直接或确认第三方征得您对上述行为的明示同意。
为了投放广告,评估、优化广告投放效果等目的,我们需要向广告主及其代理商等第三方合作伙伴共享您的部分数据,要求其严格遵守我们关于数据隐私保护的措施与要求,包括但不限于根据数据保护协议、承诺书及相关数据处理政策进行处理,避免识别出个人身份,保障隐私安全。
我们不会向合作伙伴分享可用于识别您个人身份的信息(例如您的姓名或电子邮件地址),除非您明确授权。
我们不会对外公开披露所收集的个人信息,如必须公开披露时,我们会向您告知此次公开披露的目的、披露信息的类型及可能涉及的敏感信息,并征得您的明示同意。
随着我们业务的持续发展,我们有可能进行合并、收购、资产转让等交易,我们将告知您相关情形,按照法律法规及不低于本《隐私政策》所要求的标准继续保护或要求新的控制者继续保护您的个人信息。
另外,根据相关法律法规及国家标准,以下情形中,我们可能会共享、转让、公开披露个人信息无需事先征得您的授权同意:
与国家安全、国防安全直接相关的;
与公共安全、公共卫生、重大公共利益直接相关的;
犯罪侦查、起诉、审判和判决执行等直接相关的;
出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
个人信息主体自行向社会公众公开个人信息的;
从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。
6. 您的权利
在您使用我们的服务期间,我们可能会视产品具体情况为您提供相应的操作设置,以便您可以查询、删除、更正或撤回您的相关个人信息,您可参考相应的具体指引进行操作。此外,我们还设置了投诉举报渠道,您的意见将会得到及时的处理。如果您无法通过上述途径和方式行使您的个人信息主体权利,您可以通过本《隐私政策》中提供的联系方式提出您的请求,我们会按照法律法规的规定予以反馈。
当您决定不再使用我们的产品或服务时,可以申请注销账户。注销账户后,除法律法规另有规定外,我们将删除或匿名化处理您的个人信息。
7. 变更
我们可能适时修订本《隐私政策》的条款。当变更发生时,我们会在版本更新时向您提示新的《隐私政策》,并向您说明生效日期。请您仔细阅读变更后的《隐私政策》内容,若您继续使用我们的服务,即表示您同意我们按照更新后的《隐私政策》处理您的个人信息。
8. 未成年人保护
我们鼓励父母或监护人指导未满十八岁的未成年人使用我们的服务。我们建议未成年人鼓励他们的父母或监护人阅读本《隐私政策》,并建议未成年人在提交的个人信息之前寻求父母或监护人的同意和指导。
=========================================================
用户协议
米欧科技以下简称“我们”依据本协议为用户以下简称“你”提供MIO-KITCHEN服务。本协议对你和我们均具有法律约束力。
一、本服务的功能
你可以使用本服务修改、制作ROM。
二、责任范围及限制
2.1 你使用本服务得到的结果仅供参考,实际情况以官方为准。
2.2 您不得破解、售卖、修改此程序,一经发现,立即追究
三、隐私保护
我们重视对你隐私的保护,你的个人隐私信息将根据《隐私政策》受到保护与规范,详情请参阅《隐私政策》。
四、其他条款
4.1 本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。
4.2 本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。
五、免责声明
5.1 您因使用不当造成的(包括但不限于)系统崩溃、硬件损坏等 需自行承担 我方概不负责
5.2 若因您自行(包括但不限于)破解、修改本软件造成的计算机(包括但不限于)损坏、计算机病毒传播而造成的(包括但不限于)经济损失等,由您自行承担,我方概不负责
5.3 若因使用他人的(包括但不限于)破解、修改的软件等,造成的任何后果,责任自行承担

21
bin/licenses/sdat2img.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Andrei Conache
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

BIN
bin/nt_AMD64/brotli.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/busybox.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/cpio.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/cygwin1.dll Normal file

Binary file not shown.

BIN
bin/nt_AMD64/dtc.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/e2fsdroid.exe Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/nt_AMD64/img2simg.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/lpmake.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/magiskboot.exe Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/nt_AMD64/mke2fs.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/mkfs.erofs.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/mv.exe Normal file

Binary file not shown.

BIN
bin/nt_AMD64/simg2img.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/brotli.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/busybox.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/cpio.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/cygwin1.dll Normal file

Binary file not shown.

BIN
bin/nt_x86/dtc.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/e2fsdroid.exe Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/nt_x86/img2simg.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/lpmake.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/magiskboot.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/make_ext4fs.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/mke2fs.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/mkfs.erofs.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/mv.exe Normal file

Binary file not shown.

BIN
bin/nt_x86/simg2img.exe Normal file

Binary file not shown.

BIN
bin/posix_AMD64/brotli Normal file

Binary file not shown.

BIN
bin/posix_AMD64/busybox Normal file

Binary file not shown.

BIN
bin/posix_AMD64/cpio Normal file

Binary file not shown.

BIN
bin/posix_AMD64/dtc Normal file

Binary file not shown.

BIN
bin/posix_AMD64/e2fsdroid Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/posix_AMD64/img2simg Normal file

Binary file not shown.

BIN
bin/posix_AMD64/lpmake Normal file

Binary file not shown.

BIN
bin/posix_AMD64/magiskboot Normal file

Binary file not shown.

BIN
bin/posix_AMD64/make_ext4fs Normal file

Binary file not shown.

BIN
bin/posix_AMD64/mke2fs Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/posix_AMD64/simg2img Normal file

Binary file not shown.

10
bin/setting.ini Normal file
View File

@ -0,0 +1,10 @@
[setting]
theme = dark
path =
update_url = https://raw.githubusercontent.com/zjadzhd/MIO-KITCHEN/main/
version = 2.2.4
barlevel = 0.98
key = MIO-PUBLIC-BETA-KEY
oobe = 4
language = Chinese-Simplified

1227
blockimgdiff.py Normal file

File diff suppressed because it is too large Load Diff

5
by.bat Normal file
View File

@ -0,0 +1,5 @@
@echo off
pyinstaller -Fw tool.py --exclude-module=numpy -i icon.ico --collect-data sv_ttk
::if not exist dist\bin\ md dist\bin\
::copy bin\* dist\bin\
pause

1720
common.py Normal file

File diff suppressed because it is too large Load Diff

110
editor.py Normal file
View File

@ -0,0 +1,110 @@
import tkinter as tk
from tkinter import ttk, messagebox
from os.path import basename
kwlist = ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del',
'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda',
'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', "msh", 'echo', 'sed',
'find', 'cd', 'done', 'rm', 'mkdir'
"mv", "cat"]
class PythonEditor(tk.Frame):
def __init__(self, parent, file_):
tk.Frame.__init__(self, parent)
self.file_ = file_
self.parent = parent
self.text = tk.Text(self, wrap="word", undo=True, font=("Calibri", 15))
self.scrollbar = ttk.Scrollbar(self, command=self.text.yview)
self.text.configure(yscrollcommand=self.scrollbar.set)
self.text.pack(side="left", fill="both", expand=True)
self.scrollbar.pack(side="right", fill="y")
self.text.bind("<KeyRelease>", self.highlight)
self.highlight()
f1 = ttk.Frame(self.parent)
ttk.Button(f1, text="保存", command=self.save).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5, expand=1)
ttk.Button(f1, text="关闭", command=self.parent.destroy).pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5, expand=1)
f1.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
if self.file_:
try:
with open(self.file_, 'r+', encoding='utf-8', newline='\n') as f:
self.text.delete(0.0, tk.END)
self.text.insert(tk.END, f.read())
self.highlight()
except:
pass
self.parent.title(f"{basename(self.file_)} - Editor")
def save(self):
with open(self.file_, 'w+', encoding='utf-8', newline='\n') as txt:
txt.write(self.text.get(1.0, tk.END))
messagebox.showinfo("已保存", f"{basename(self.file_)} 已保存")
def highlight(self, event=None):
self.text.tag_remove("keyword", "1.0", "end")
self.text.tag_remove("builtin", "1.0", "end")
self.text.tag_remove("string", "1.0", "end")
self.text.tag_remove("comment", "1.0", "end")
for word in kwlist:
start = "1.0"
while True:
start = self.text.search(word, start, stopindex="end")
if not start:
break
end = "{}+{}c".format(start, len(word))
self.text.tag_add("keyword", start, end)
start = end
for word in dir(__builtins__):
start = "1.0"
while True:
start = self.text.search(word, start, stopindex="end")
if not start:
break
end = "{}+{}c".format(start, len(word))
self.text.tag_add("builtin", start, end)
start = end
start = "1.0"
countVar = tk.StringVar()
while True:
start = self.text.search("@[^@]+@", start, stopindex="end", regexp=True, count=countVar)
if not start:
break
end = "{}+{}c".format(start, countVar.get())
self.text.tag_add("string", start, end)
start = end
start = "1.0"
countVar = tk.StringVar()
while True:
start = self.text.search('"[^"]+@"', start, stopindex="end", regexp=True, count=countVar)
if not start:
break
end = "{}+{}c".format(start, countVar.get())
self.text.tag_add("string", start, end)
start = end
start = "1.0"
while True:
start = self.text.search("#", start, stopindex="end")
if not start:
break
end = self.text.search("\n", start, stopindex="end")
if not end:
end = "end"
self.text.tag_add("comment", start, end)
start = end
self.text.tag_configure("keyword", foreground="#00BFFF")
self.text.tag_configure("builtin", foreground="purple")
self.text.tag_configure("string", foreground="orange")
self.text.tag_configure("comment", foreground="gray")
def main(file_=None):
root = tk.Toplevel()
root.title("Editor")
editor = PythonEditor(root, file_)
editor.pack(side="top", fill="both", expand=True)

977
ext4.py Normal file
View File

@ -0,0 +1,977 @@
import ctypes
import functools
import io
import math
import queue
def wcscmp(str_a, str_b):
for a, b in zip(str_a, str_b):
tmp = ord(a) - ord(b)
if tmp != 0:
return -1 if tmp < 0 else 1
tmp = len(str_a) - len(str_b)
return -1 if tmp < 0 else 1 if tmp > 0 else 0
class Ext4Error(Exception):
pass
class BlockMapError(Ext4Error):
pass
class EndOfStreamError(Ext4Error):
pass
class MagicError(Ext4Error):
pass
# ----------------------------- LOW LEVEL ------------------------------
class ext4_struct(ctypes.LittleEndianStructure):
def __getattr__(self, name):
try:
# Combining *_lo and *_hi fields
lo_field = ctypes.LittleEndianStructure.__getattribute__(type(self), name + "_lo")
size = lo_field.size
lo = lo_field.__get__(self)
hi = ctypes.LittleEndianStructure.__getattribute__(self, name + "_hi")
return (hi << (8 * size)) | lo
except AttributeError:
return ctypes.LittleEndianStructure.__getattribute__(self, name)
def __setattr__(self, name, value):
try:
# Combining *_lo and *_hi fields
lo_field = ctypes.LittleEndianStructure.__getattribute__(type(self), name + "_lo")
size = lo_field.size
lo_field.__set__(self, value & ((1 << (8 * size)) - 1))
ctypes.LittleEndianStructure.__setattr__(self, name + "_hi", value >> (8 * size))
except AttributeError:
ctypes.LittleEndianStructure.__setattr__(self, name, value)
class ext4_dir_entry_2(ext4_struct):
_fields_ = [
("inode", ctypes.c_uint), # 0x0
("rec_len", ctypes.c_ushort), # 0x4
("name_len", ctypes.c_ubyte), # 0x6
("file_type", ctypes.c_ubyte) # 0x7
# Variable length field "name" missing at 0x8
]
def _from_buffer_copy(raw, offset=0, platform64=True):
struct = ext4_dir_entry_2.from_buffer_copy(raw, offset)
struct.name = raw[offset + 0x8: offset + 0x8 + struct.name_len]
return struct
class ext4_extent(ext4_struct):
_fields_ = [
("ee_block", ctypes.c_uint), # 0x0000
("ee_len", ctypes.c_ushort), # 0x0004
("ee_start_hi", ctypes.c_ushort), # 0x0006
("ee_start_lo", ctypes.c_uint) # 0x0008
]
class ext4_extent_header(ext4_struct):
_fields_ = [
("eh_magic", ctypes.c_ushort), # 0x0000, Must be 0xF30A
("eh_entries", ctypes.c_ushort), # 0x0002
("eh_max", ctypes.c_ushort), # 0x0004
("eh_depth", ctypes.c_ushort), # 0x0006
("eh_generation", ctypes.c_uint) # 0x0008
]
class ext4_extent_idx(ext4_struct):
_fields_ = [
("ei_block", ctypes.c_uint), # 0x0000
("ei_leaf_lo", ctypes.c_uint), # 0x0004
("ei_leaf_hi", ctypes.c_ushort), # 0x0008
("ei_unused", ctypes.c_ushort) # 0x000A
]
class ext4_group_descriptor(ext4_struct):
_fields_ = [
("bg_block_bitmap_lo", ctypes.c_uint), # 0x0000
("bg_inode_bitmap_lo", ctypes.c_uint), # 0x0004
("bg_inode_table_lo", ctypes.c_uint), # 0x0008
("bg_free_blocks_count_lo", ctypes.c_ushort), # 0x000C
("bg_free_inodes_count_lo", ctypes.c_ushort), # 0x000E
("bg_used_dirs_count_lo", ctypes.c_ushort), # 0x0010
("bg_flags", ctypes.c_ushort), # 0x0012
("bg_exclude_bitmap_lo", ctypes.c_uint), # 0x0014
("bg_block_bitmap_csum_lo", ctypes.c_ushort), # 0x0018
("bg_inode_bitmap_csum_lo", ctypes.c_ushort), # 0x001A
("bg_itable_unused_lo", ctypes.c_ushort), # 0x001C
("bg_checksum", ctypes.c_ushort), # 0x001E
# 64-bit fields
("bg_block_bitmap_hi", ctypes.c_uint), # 0x0020
("bg_inode_bitmap_hi", ctypes.c_uint), # 0x0024
("bg_inode_table_hi", ctypes.c_uint), # 0x0028
("bg_free_blocks_count_hi", ctypes.c_ushort), # 0x002C
("bg_free_inodes_count_hi", ctypes.c_ushort), # 0x002E
("bg_used_dirs_count_hi", ctypes.c_ushort), # 0x0030
("bg_itable_unused_hi", ctypes.c_ushort), # 0x0032
("bg_exclude_bitmap_hi", ctypes.c_uint), # 0x0034
("bg_block_bitmap_csum_hi", ctypes.c_ushort), # 0x0038
("bg_inode_bitmap_csum_hi", ctypes.c_ushort), # 0x003A
("bg_reserved", ctypes.c_uint), # 0x003C
]
@staticmethod
def _from_buffer_copy(raw, platform64=True):
struct = ext4_group_descriptor.from_buffer_copy(raw)
if not platform64:
struct.bg_block_bitmap_hi = 0
struct.bg_inode_bitmap_hi = 0
struct.bg_inode_table_hi = 0
struct.bg_free_blocks_count_hi = 0
struct.bg_free_inodes_count_hi = 0
struct.bg_used_dirs_count_hi = 0
struct.bg_itable_unused_hi = 0
struct.bg_exclude_bitmap_hi = 0
struct.bg_block_bitmap_csum_hi = 0
struct.bg_inode_bitmap_csum_hi = 0
struct.bg_reserved = 0
return struct
class ext4_inode(ext4_struct):
EXT2_GOOD_OLD_INODE_SIZE = 128 # Every field passing 128 bytes is "additional data", whose size is specified by i_extra_isize.
# i_mode
S_IXOTH = 0x1 # Others can execute
S_IWOTH = 0x2 # Others can write
S_IROTH = 0x4 # Others can read
S_IXGRP = 0x8 # Group can execute
S_IWGRP = 0x10 # Group can write
S_IRGRP = 0x20 # Group can read
S_IXUSR = 0x40 # Owner can execute
S_IWUSR = 0x80 # Owner can write
S_IRUSR = 0x100 # Owner can read
S_ISVTX = 0x200 # Sticky bit (only owner can delete)
S_ISGID = 0x400 # Set GID (execute with privileges of group owner of the file's group)
S_ISUID = 0x800 # Set UID (execute with privileges of the file's owner)
S_IFIFO = 0x1000 # FIFO device (named pipe)
S_IFCHR = 0x2000 # Character device (raw, unbuffered, aligned, direct access to hardware storage)
S_IFDIR = 0x4000 # Directory
S_IFBLK = 0x6000 # Block device (buffered, arbitrary access to storage)
S_IFREG = 0x8000 # Regular file
S_IFLNK = 0xA000 # Symbolic link
S_IFSOCK = 0xC000 # Socket
# i_flags
EXT4_INDEX_FL = 0x1000 # Uses hash trees
EXT4_EXTENTS_FL = 0x80000 # Uses extents
EXT4_EA_INODE_FL = 0x200000 # Inode stores large xattr
EXT4_INLINE_DATA_FL = 0x10000000 # Has inline data
_fields_ = [
("i_mode", ctypes.c_ushort), # 0x0000
("i_uid_lo", ctypes.c_ushort), # 0x0002, Originally named i_uid
("i_size_lo", ctypes.c_uint), # 0x0004
("i_atime", ctypes.c_uint), # 0x0008
("i_ctime", ctypes.c_uint), # 0x000C
("i_mtime", ctypes.c_uint), # 0x0010
("i_dtime", ctypes.c_uint), # 0x0014
("i_gid_lo", ctypes.c_ushort), # 0x0018, Originally named i_gid
("i_links_count", ctypes.c_ushort), # 0x001A
("i_blocks_lo", ctypes.c_uint), # 0x001C
("i_flags", ctypes.c_uint), # 0x0020
("osd1", ctypes.c_uint), # 0x0024
("i_block", ctypes.c_uint * 15), # 0x0028
("i_generation", ctypes.c_uint), # 0x0064
("i_file_acl_lo", ctypes.c_uint), # 0x0068
("i_size_hi", ctypes.c_uint), # 0x006C, Originally named i_size_high
("i_obso_faddr", ctypes.c_uint), # 0x0070
("i_osd2_blocks_high", ctypes.c_ushort), # 0x0074, Originally named i_osd2.linux2.l_i_blocks_high
("i_file_acl_hi", ctypes.c_ushort), # 0x0076, Originally named i_osd2.linux2.l_i_file_acl_high
("i_uid_hi", ctypes.c_ushort), # 0x0078, Originally named i_osd2.linux2.l_i_uid_high
("i_gid_hi", ctypes.c_ushort), # 0x007A, Originally named i_osd2.linux2.l_i_gid_high
("i_osd2_checksum_lo", ctypes.c_ushort), # 0x007C, Originally named i_osd2.linux2.l_i_checksum_lo
("i_osd2_reserved", ctypes.c_ushort), # 0x007E, Originally named i_osd2.linux2.l_i_reserved
("i_extra_isize", ctypes.c_ushort), # 0x0080
("i_checksum_hi", ctypes.c_ushort), # 0x0082
("i_ctime_extra", ctypes.c_uint), # 0x0084
("i_mtime_extra", ctypes.c_uint), # 0x0088
("i_atime_extra", ctypes.c_uint), # 0x008C
("i_crtime", ctypes.c_uint), # 0x0090
("i_crtime_extra", ctypes.c_uint), # 0x0094
("i_version_hi", ctypes.c_uint), # 0x0098
("i_projid", ctypes.c_uint), # 0x009C
]
class ext4_superblock(ext4_struct):
EXT2_DESC_SIZE = 0x20 # Default value for s_desc_size, if INCOMPAT_64BIT is not set (NEEDS CONFIRMATION)
EXT2_MIN_DESC_SIZE = 0x20
EXT2_MIN_DESC_SIZE_64BIT = 0x40
# s_feature_incompat
INCOMPAT_64BIT = 0x80 # Uses 64-bit features (e.g. *_hi structure fields in ext4_group_descriptor)
INCOMPAT_32BIT = 0x66
INCOMPAT_FILETYPE = 0x2 # Directory entries record file type (instead of inode flags)
_fields_ = [
("s_inodes_count", ctypes.c_uint), # 0x0000
("s_blocks_count_lo", ctypes.c_uint), # 0x0004
("s_r_blocks_count_lo", ctypes.c_uint), # 0x0008
("s_free_blocks_count_lo", ctypes.c_uint), # 0x000C
("s_free_inodes_count", ctypes.c_uint), # 0x0010
("s_first_data_block", ctypes.c_uint), # 0x0014
("s_log_block_size", ctypes.c_uint), # 0x0018
("s_log_cluster_size", ctypes.c_uint), # 0x001C
("s_blocks_per_group", ctypes.c_uint), # 0x0020
("s_clusters_per_group", ctypes.c_uint), # 0x0024
("s_inodes_per_group", ctypes.c_uint), # 0x0028
("s_mtime", ctypes.c_uint), # 0x002C
("s_wtime", ctypes.c_uint), # 0x0030
("s_mnt_count", ctypes.c_ushort), # 0x0034
("s_max_mnt_count", ctypes.c_ushort), # 0x0036
("s_magic", ctypes.c_ushort), # 0x0038, Must be 0xEF53
("s_state", ctypes.c_ushort), # 0x003A
("s_errors", ctypes.c_ushort), # 0x003C
("s_minor_rev_level", ctypes.c_ushort), # 0x003E
("s_lastcheck", ctypes.c_uint), # 0x0040
("s_checkinterval", ctypes.c_uint), # 0x0044
("s_creator_os", ctypes.c_uint), # 0x0048
("s_rev_level", ctypes.c_uint), # 0x004C
("s_def_resuid", ctypes.c_ushort), # 0x0050
("s_def_resgid", ctypes.c_ushort), # 0x0052
("s_first_ino", ctypes.c_uint), # 0x0054
("s_inode_size", ctypes.c_ushort), # 0x0058
("s_block_group_nr", ctypes.c_ushort), # 0x005A
("s_feature_compat", ctypes.c_uint), # 0x005C
("s_feature_incompat", ctypes.c_uint), # 0x0060
("s_feature_ro_compat", ctypes.c_uint), # 0x0064
("s_uuid", ctypes.c_ubyte * 16), # 0x0068
("s_volume_name", ctypes.c_char * 16), # 0x0078
("s_last_mounted", ctypes.c_char * 64), # 0x0088
("s_algorithm_usage_bitmap", ctypes.c_uint), # 0x00C8
("s_prealloc_blocks", ctypes.c_ubyte), # 0x00CC
("s_prealloc_dir_blocks", ctypes.c_ubyte), # 0x00CD
("s_reserved_gdt_blocks", ctypes.c_ushort), # 0x00CE
("s_journal_uuid", ctypes.c_ubyte * 16), # 0x00D0
("s_journal_inum", ctypes.c_uint), # 0x00E0
("s_journal_dev", ctypes.c_uint), # 0x00E4
("s_last_orphan", ctypes.c_uint), # 0x00E8
("s_hash_seed", ctypes.c_uint * 4), # 0x00EC
("s_def_hash_version", ctypes.c_ubyte), # 0x00FC
("s_jnl_backup_type", ctypes.c_ubyte), # 0x00FD
("s_desc_size", ctypes.c_ushort), # 0x00FE
("s_default_mount_opts", ctypes.c_uint), # 0x0100
("s_first_meta_bg", ctypes.c_uint), # 0x0104
("s_mkfs_time", ctypes.c_uint), # 0x0108
("s_jnl_blocks", ctypes.c_uint * 17), # 0x010C
# 64-bit fields
("s_blocks_count_hi", ctypes.c_uint), # 0x0150
("s_r_blocks_count_hi", ctypes.c_uint), # 0x0154
("s_free_blocks_count_hi", ctypes.c_uint), # 0x0158
("s_min_extra_isize", ctypes.c_ushort), # 0x015C
("s_want_extra_isize", ctypes.c_ushort), # 0x015E
("s_flags", ctypes.c_uint), # 0x0160
("s_raid_stride", ctypes.c_ushort), # 0x0164
("s_mmp_interval", ctypes.c_ushort), # 0x0166
("s_mmp_block", ctypes.c_ulonglong), # 0x0168
("s_raid_stripe_width", ctypes.c_uint), # 0x0170
("s_log_groups_per_flex", ctypes.c_ubyte), # 0x0174
("s_checksum_type", ctypes.c_ubyte), # 0x0175
("s_reserved_pad", ctypes.c_ushort), # 0x0176
("s_kbytes_written", ctypes.c_ulonglong), # 0x0178
("s_snapshot_inum", ctypes.c_uint), # 0x0180
("s_snapshot_id", ctypes.c_uint), # 0x0184
("s_snapshot_r_blocks_count", ctypes.c_ulonglong), # 0x0188
("s_snapshot_list", ctypes.c_uint), # 0x0190
("s_error_count", ctypes.c_uint), # 0x0194
("s_first_error_time", ctypes.c_uint), # 0x0198
("s_first_error_ino", ctypes.c_uint), # 0x019C
("s_first_error_block", ctypes.c_ulonglong), # 0x01A0
("s_first_error_func", ctypes.c_ubyte * 32), # 0x01A8
("s_first_error_line", ctypes.c_uint), # 0x01C8
("s_last_error_time", ctypes.c_uint), # 0x01CC
("s_last_error_ino", ctypes.c_uint), # 0x01D0
("s_last_error_line", ctypes.c_uint), # 0x01D4
("s_last_error_block", ctypes.c_ulonglong), # 0x01D8
("s_last_error_func", ctypes.c_ubyte * 32), # 0x01E0
("s_mount_opts", ctypes.c_ubyte * 64), # 0x0200
("s_usr_quota_inum", ctypes.c_uint), # 0x0240
("s_grp_quota_inum", ctypes.c_uint), # 0x0244
("s_overhead_blocks", ctypes.c_uint), # 0x0248
("s_backup_bgs", ctypes.c_uint * 2), # 0x024C
("s_encrypt_algos", ctypes.c_ubyte * 4), # 0x0254
("s_encrypt_pw_salt", ctypes.c_ubyte * 16), # 0x0258
("s_lpf_ino", ctypes.c_uint), # 0x0268
("s_prj_quota_inum", ctypes.c_uint), # 0x026C
("s_checksum_seed", ctypes.c_uint), # 0x0270
("s_reserved", ctypes.c_uint * 98), # 0x0274
("s_checksum", ctypes.c_uint) # 0x03FC
]
@staticmethod
def _from_buffer_copy(raw, platform64=True):
struct = ext4_superblock.from_buffer_copy(raw)
if not platform64:
struct.s_blocks_count_hi = 0
struct.s_r_blocks_count_hi = 0
struct.s_free_blocks_count_hi = 0
struct.s_min_extra_isize = 0
struct.s_want_extra_isize = 0
struct.s_flags = 0
struct.s_raid_stride = 0
struct.s_mmp_interval = 0
struct.s_mmp_block = 0
struct.s_raid_stripe_width = 0
struct.s_log_groups_per_flex = 0
struct.s_checksum_type = 0
struct.s_reserved_pad = 0
struct.s_kbytes_written = 0
struct.s_snapshot_inum = 0
struct.s_snapshot_id = 0
struct.s_snapshot_r_blocks_count = 0
struct.s_snapshot_list = 0
struct.s_error_count = 0
struct.s_first_error_time = 0
struct.s_first_error_ino = 0
struct.s_first_error_block = 0
struct.s_first_error_func = 0
struct.s_first_error_line = 0
struct.s_last_error_time = 0
struct.s_last_error_ino = 0
struct.s_last_error_line = 0
struct.s_last_error_block = 0
struct.s_last_error_func = 0
struct.s_mount_opts = 0
struct.s_usr_quota_inum = 0
struct.s_grp_quota_inum = 0
struct.s_overhead_blocks = 0
struct.s_backup_bgs = 0
struct.s_encrypt_algos = 0
struct.s_encrypt_pw_salt = 0
struct.s_lpf_ino = 0
struct.s_prj_quota_inum = 0
struct.s_checksum_seed = 0
struct.s_reserved = 0
struct.s_checksum = 0
# if (struct.s_feature_incompat & ext4_superblock.INCOMPAT_64BIT) == 0:
# struct.s_desc_size = ext4_superblock.EXT2_DESC_SIZE
if struct.s_desc_size == 0:
if (struct.s_feature_incompat & ext4_superblock.INCOMPAT_64BIT) == 0:
struct.s_desc_size = ext4_superblock.EXT2_MIN_DESC_SIZE
else:
struct.s_desc_size = ext4_superblock.EXT2_MIN_DESC_SIZE_64BIT
return struct
class ext4_xattr_entry(ext4_struct):
_fields_ = [
("e_name_len", ctypes.c_ubyte), # 0x00
("e_name_index", ctypes.c_ubyte), # 0x01
("e_value_offs", ctypes.c_ushort), # 0x02
("e_value_inum", ctypes.c_uint), # 0x04
("e_value_size", ctypes.c_uint), # 0x08
("e_hash", ctypes.c_uint) # 0x0C
# Variable length field "e_name" missing at 0x10
]
def _from_buffer_copy(raw, offset=0, platform64=True):
struct = ext4_xattr_entry.from_buffer_copy(raw, offset)
struct.e_name = raw[offset + 0x10: offset + 0x10 + struct.e_name_len]
return struct
@property
def _size(self): return 4 * ((ctypes.sizeof(type(self)) + self.e_name_len + 3) // 4) # 4-byte alignment
class ext4_xattr_header(ext4_struct):
_fields_ = [
("h_magic", ctypes.c_uint), # 0x0, Must be 0xEA020000
("h_refcount", ctypes.c_uint), # 0x4
("h_blocks", ctypes.c_uint), # 0x8
("h_hash", ctypes.c_uint), # 0xC
("h_checksum", ctypes.c_uint), # 0x10
("h_reserved", ctypes.c_uint * 3), # 0x14
]
class ext4_xattr_ibody_header(ext4_struct):
_fields_ = [
("h_magic", ctypes.c_uint) # 0x0, Must be 0xEA020000
]
class InodeType:
UNKNOWN = 0x0 # Unknown file type
FILE = 0x1 # Regular file
DIRECTORY = 0x2 # Directory
CHARACTER_DEVICE = 0x3 # Character device
BLOCK_DEVICE = 0x4 # Block device
FIFO = 0x5 # FIFO
SOCKET = 0x6 # Socket
SYMBOLIC_LINK = 0x7 # Symbolic link
CHECKSUM = 0xDE # Checksum entry; not really a file type, but a type of directory entry
# ----------------------------- HIGH LEVEL ------------------------------
class MappingEntry:
def __init__(self, file_block_idx, disk_block_idx, block_count=1):
self.file_block_idx = file_block_idx
self.disk_block_idx = disk_block_idx
self.block_count = block_count
def __iter__(self):
yield self.file_block_idx
yield self.disk_block_idx
yield self.block_count
def __repr__(self):
return "{type:s}({file_block_idx!r:s}, {disk_block_idx!r:s}, {blocK_count!r:s})".format(
blocK_count=self.block_count,
disk_block_idx=self.disk_block_idx,
file_block_idx=self.file_block_idx,
type=type(self).__name__
)
def copy(self):
return MappingEntry(self.file_block_idx, self.disk_block_idx, self.block_count)
def create_mapping(*entries):
file_block_idx = 0
result = [None] * len(entries)
for i, entry in enumerate(entries):
disk_block_idx, block_count = entry
result[i] = MappingEntry(file_block_idx, disk_block_idx, block_count)
file_block_idx += block_count
return result
def optimize(entries):
entries.sort(key=lambda entry: entry.file_block_idx)
idx = 0
while idx < len(entries):
while idx + 1 < len(entries) \
and entries[idx].file_block_idx + entries[idx].block_count == entries[idx + 1].file_block_idx \
and entries[idx].disk_block_idx + entries[idx].block_count == entries[idx + 1].disk_block_idx:
tmp = entries.pop(idx + 1)
entries[idx].block_count += tmp.block_count
idx += 1
class Volume:
ROOT_INODE = 2
def __init__(self, stream, offset=0, ignore_flags=False, ignore_magic=False):
self.ignore_flags = ignore_flags
self.ignore_magic = ignore_magic
self.offset = offset
self.platform64 = True # Initial value needed for Volume.read_struct
self.stream = stream
# Superblock
self.superblock = self.read_struct(ext4_superblock, 0x400)
self.platform64 = (self.superblock.s_feature_incompat & ext4_superblock.INCOMPAT_64BIT) != 0
if not ignore_magic and self.superblock.s_magic != 0xEF53:
raise MagicError("Invalid magic value in superblock: 0x{magic:04X} (expected 0xEF53)".format(
magic=self.superblock.s_magic))
# Group descriptors
self.group_descriptors = [None] * (self.superblock.s_inodes_count // self.superblock.s_inodes_per_group)
group_desc_table_offset = (0x400 // self.block_size + 1) * self.block_size # First block after superblock
for group_desc_idx in range(len(self.group_descriptors)):
group_desc_offset = group_desc_table_offset + group_desc_idx * self.superblock.s_desc_size
self.group_descriptors[group_desc_idx] = self.read_struct(ext4_group_descriptor, group_desc_offset)
def __repr__(self):
return "{type_name:s}(volume_name = {volume_name!r:s}, uuid = {uuid!r:s}, last_mounted = {last_mounted!r:s})".format(
last_mounted=self.superblock.s_last_mounted,
type_name=type(self).__name__,
uuid=self.uuid,
volume_name=self.superblock.s_volume_name
)
@property
def block_size(self):
return 1 << (10 + self.superblock.s_log_block_size)
def get_inode(self, inode_idx, file_type=InodeType.UNKNOWN):
group_idx, inode_table_entry_idx = self.get_inode_group(inode_idx)
inode_table_offset = self.group_descriptors[group_idx].bg_inode_table * self.block_size
inode_offset = inode_table_offset + inode_table_entry_idx * self.superblock.s_inode_size
return Inode(self, inode_offset, inode_idx, file_type)
def get_inode_group(self, inode_idx):
group_idx = (inode_idx - 1) // self.superblock.s_inodes_per_group
inode_table_entry_idx = (inode_idx - 1) % self.superblock.s_inodes_per_group
return group_idx, inode_table_entry_idx
def read(self, offset, byte_len):
if self.offset + offset != self.stream.tell():
self.stream.seek(self.offset + offset, io.SEEK_SET)
return self.stream.read(byte_len)
def read_struct(self, structure, offset, platform64=None):
raw = self.read(offset, ctypes.sizeof(structure))
if hasattr(structure, "_from_buffer_copy"):
return structure._from_buffer_copy(raw, platform64=platform64 if platform64 else self.platform64)
else:
return structure.from_buffer_copy(raw)
@property
def root(self):
return self.get_inode(Volume.ROOT_INODE, InodeType.DIRECTORY)
@property
def uuid(self):
uuid = self.superblock.s_uuid
uuid = [uuid[:4], uuid[4: 6], uuid[6: 8], uuid[8: 10], uuid[10:]]
return "-".join("".join("{0:02X}".format(c) for c in part) for part in uuid)
class Inode:
def __init__(self, volume, offset, inode_idx, file_type=InodeType.UNKNOWN):
self.inode_idx = inode_idx
self.offset = offset
self.volume = volume
self.file_type = file_type
self.inode = volume.read_struct(ext4_inode, offset)
def __len__(self):
return self.inode.i_size
def __repr__(self):
if self.inode_idx is not None:
return "{type_name:s}(inode_idx = {inode!r:s}, offset = 0x{offset:X}, volume_uuid = {uuid!r:s})".format(
inode=self.inode_idx,
offset=self.offset,
type_name=type(self).__name__,
uuid=self.volume.uuid
)
else:
return "{type_name:s}(offset = 0x{offset:X}, volume_uuid = {uuid!r:s})".format(
offset=self.offset,
type_name=type(self).__name__,
uuid=self.volume.uuid
)
def _parse_xattrs(self, raw_data, offset, prefix_override={}):
prefixes = {
0: "",
1: "user.",
2: "system.posix_acl_access",
3: "system.posix_acl_default",
4: "trusted.",
6: "security.",
7: "system.",
8: "system.richacl"
}
prefixes.update(prefixes)
# Iterator over ext4_xattr_entry structures
i = 0
while i < len(raw_data):
xattr_entry = ext4_xattr_entry._from_buffer_copy(raw_data, i, platform64=self.volume.platform64)
if (
xattr_entry.e_name_len | xattr_entry.e_name_index | xattr_entry.e_value_offs | xattr_entry.e_value_inum) == 0:
# End of ext4_xattr_entry list
break
if not xattr_entry.e_name_index in prefixes:
raise Ext4Error("Unknown attribute prefix {prefix:d} in inode {inode:d}".format(
inode=self.inode_idx,
prefix=xattr_entry.e_name_index
))
xattr_name = prefixes[xattr_entry.e_name_index] + xattr_entry.e_name.decode("iso-8859-2")
if xattr_entry.e_value_inum != 0:
# external xattr
xattr_inode = self.volume.get_inode(xattr.e_value_inum, InodeType.FILE)
if not self.volume.ignore_flags and (xattr_inode.inode.i_flags & ext4_inode.EXT4_EA_INODE_FL) != 0:
raise Ext4Error(
"Inode {value_indoe:d} associated with the extended attribute {xattr_name!r:s} of inode {inode:d} is not marked as large extended attribute value.".format(
inode=self.inode_idx,
value_inode=xattr_inode.inode_idx,
xattr_name=xattr_name
))
# TODO Use xattr_entry.e_value_size or xattr_inode.inode.i_size?
xattr_value = xattr_inode.open_read().read()
else:
# internal xattr
xattr_value = raw_data[
xattr_entry.e_value_offs + offset: xattr_entry.e_value_offs + offset + xattr_entry.e_value_size]
yield (xattr_name, xattr_value)
i += xattr_entry._size
def directory_entry_comparator(dir_a, dir_b):
file_name_a, _, file_type_a = dir_a
file_name_b, _, file_type_b = dir_b
if file_type_a == InodeType.DIRECTORY == file_type_b or file_type_a != InodeType.DIRECTORY != file_type_b:
tmp = wcscmp(file_name_a.lower(), file_name_b.lower())
return tmp if tmp != 0 else wcscmp(file_name_a, file_name_b)
else:
return -1 if file_type_a == InodeType.DIRECTORY else 1
directory_entry_key = functools.cmp_to_key(directory_entry_comparator)
def get_inode(self, *relative_path, decode_name=None):
if not self.is_dir:
raise Ext4Error("Inode {inode:d} is not a directory.".format(inode=self.inode_idx))
current_inode = self
for i, part in enumerate(relative_path):
if not self.volume.ignore_flags and not current_inode.is_dir:
current_path = "/".join(relative_path[:i])
raise Ext4Error("{current_path!r:s} (Inode {inode:d}) is not a directory.".format(
current_path=current_path,
inode=inode_idx
))
file_name, inode_idx, file_type = next(
filter(lambda entry: entry[0] == part, current_inode.open_dir(decode_name)), (None, None, None))
if inode_idx == None:
current_path = "/".join(relative_path[:i])
raise FileNotFoundError("{part!r:s} not found in {current_path!r:s} (Inode {inode:d}).".format(
current_path=current_path,
inode=current_inode.inode_idx,
part=part
))
current_inode = current_inode.volume.get_inode(inode_idx, file_type)
return current_inode
@property
def is_dir(self):
if (self.volume.superblock.s_feature_incompat & ext4_superblock.INCOMPAT_FILETYPE) == 0:
return (self.inode.i_mode & ext4_inode.S_IFDIR) != 0
else:
return self.file_type == InodeType.DIRECTORY
@property
def is_file(self):
if (self.volume.superblock.s_feature_incompat & ext4_superblock.INCOMPAT_FILETYPE) == 0:
return (self.inode.i_mode & ext4_inode.S_IFREG) != 0
else:
return self.file_type == InodeType.FILE
@property
def is_symlink(self):
if (self.volume.superblock.s_feature_incompat & ext4_superblock.INCOMPAT_FILETYPE) == 0:
return (self.inode.i_mode & ext4_inode.S_IFLNK) != 0
else:
return self.file_type == InodeType.SYMBOLIC_LINK
@property
def is_in_use(self):
group_idx, bitmap_bit = self.volume.get_inode_group(self.inode_idx)
inode_usage_bitmap_offset = self.volume.group_descriptors[group_idx].bg_inode_bitmap * self.volume.block_size
inode_usage_byte = self.volume.read(inode_usage_bitmap_offset + bitmap_bit // 8, 1)[0]
return ((inode_usage_byte >> (7 - bitmap_bit % 8)) & 1) != 0
@property
def mode_str(self):
special_flag = lambda letter, execute, special: {
(False, False): "-",
(False, True): letter.upper(),
(True, False): "x",
(True, True): letter.lower()
}[(execute, special)]
try:
if (self.volume.superblock.s_feature_incompat & ext4_superblock.INCOMPAT_FILETYPE) == 0:
device_type = {
ext4_inode.S_IFIFO: "p",
ext4_inode.S_IFCHR: "c",
ext4_inode.S_IFDIR: "d",
ext4_inode.S_IFBLK: "b",
ext4_inode.S_IFREG: "-",
ext4_inode.S_IFLNK: "l",
ext4_inode.S_IFSOCK: "s",
}[self.inode.i_mode & 0xF000]
else:
device_type = {
InodeType.FILE: "-",
InodeType.DIRECTORY: "d",
InodeType.CHARACTER_DEVICE: "c",
InodeType.BLOCK_DEVICE: "b",
InodeType.FIFO: "p",
InodeType.SOCKET: "s",
InodeType.SYMBOLIC_LINK: "l"
}[self.file_type]
except KeyError:
device_type = "?"
return "".join([
device_type,
"r" if (self.inode.i_mode & ext4_inode.S_IRUSR) != 0 else "-",
"w" if (self.inode.i_mode & ext4_inode.S_IWUSR) != 0 else "-",
special_flag("s", (self.inode.i_mode & ext4_inode.S_IXUSR) != 0,
(self.inode.i_mode & ext4_inode.S_ISUID) != 0),
"r" if (self.inode.i_mode & ext4_inode.S_IRGRP) != 0 else "-",
"w" if (self.inode.i_mode & ext4_inode.S_IWGRP) != 0 else "-",
special_flag("s", (self.inode.i_mode & ext4_inode.S_IXGRP) != 0,
(self.inode.i_mode & ext4_inode.S_ISGID) != 0),
"r" if (self.inode.i_mode & ext4_inode.S_IROTH) != 0 else "-",
"w" if (self.inode.i_mode & ext4_inode.S_IWOTH) != 0 else "-",
special_flag("t", (self.inode.i_mode & ext4_inode.S_IXOTH) != 0,
(self.inode.i_mode & ext4_inode.S_ISVTX) != 0),
])
def open_dir(self, decode_name=None):
# Parse args
if decode_name == None:
decode_name = lambda raw: raw.decode("utf8")
if not self.volume.ignore_flags and not self.is_dir:
raise Ext4Error("Inode ({inode:d}) is not a directory.".format(inode=self.inode_idx))
# # Hash trees are compatible with linear arrays
if (self.inode.i_flags & ext4_inode.EXT4_INDEX_FL) != 0:
pass
# Read raw directory content
raw_data = self.open_read().read()
offset = 0
while offset < len(raw_data):
dirent = ext4_dir_entry_2._from_buffer_copy(raw_data, offset, platform64=self.volume.platform64)
if dirent.file_type != InodeType.CHECKSUM:
yield decode_name(dirent.name), dirent.inode, dirent.file_type
offset += dirent.rec_len
def open_read(self):
if (self.inode.i_flags & ext4_inode.EXT4_EXTENTS_FL) != 0:
# Obtain mapping from extents
mapping = [] # List of MappingEntry instances
nodes = queue.Queue()
nodes.put_nowait(self.offset + ext4_inode.i_block.offset)
while nodes.qsize() != 0:
header_offset = nodes.get_nowait()
header = self.volume.read_struct(ext4_extent_header, header_offset)
if not self.volume.ignore_magic and header.eh_magic != 0xF30A:
raise MagicError(
"Invalid magic value in extent header at offset 0x{header_offset:X} of inode {inode:d}: 0x{header_magic:04X} (expected 0xF30A)".format(
header_magic=header.eh_magic,
header_offset=self.inode_idx,
inode=self.inode_idx
))
if header.eh_depth != 0:
indices = self.volume.read_struct(ext4_extent_idx * header.eh_entries,
header_offset + ctypes.sizeof(ext4_extent_header))
for idx in indices: nodes.put_nowait(idx.ei_leaf * self.volume.block_size)
else:
extents = self.volume.read_struct(ext4_extent * header.eh_entries,
header_offset + ctypes.sizeof(ext4_extent_header))
for extent in extents:
mapping.append(MappingEntry(extent.ee_block, extent.ee_start, extent.ee_len))
MappingEntry.optimize(mapping)
return BlockReader(self.volume, len(self), mapping)
else:
# Inode uses inline data
i_block = self.volume.read(self.offset + ext4_inode.i_block.offset, ext4_inode.i_block.size)
return io.BytesIO(i_block[:self.inode.i_size])
@property
def size_readable(self):
if self.inode.i_size < 1024:
return "{0:d} bytes".format(self.inode.i_size) if self.inode.i_size != 1 else "1 byte"
else:
units = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
unit_idx = min(int(math.log(self.inode.i_size, 1024)), len(units))
return "{size:.2f} {unit:s}".format(
size=self.inode.i_size / (1024 ** unit_idx),
unit=units[unit_idx - 1]
)
def xattrs(self, check_inline=True, check_block=True, force_inline=False, prefix_override={}):
# Inline xattrs
inline_data_offset = self.offset + ext4_inode.EXT2_GOOD_OLD_INODE_SIZE + self.inode.i_extra_isize
inline_data_length = self.offset + self.volume.superblock.s_inode_size - inline_data_offset
if check_inline and inline_data_length > ctypes.sizeof(ext4_xattr_ibody_header):
inline_data = self.volume.read(inline_data_offset, inline_data_length)
xattrs_header = ext4_xattr_ibody_header.from_buffer_copy(inline_data)
# TODO Find way to detect inline xattrs without checking the h_magic field to enable error detection with the h_magic field.
if force_inline or xattrs_header.h_magic == 0xEA020000:
offset = 4 * ((ctypes.sizeof(
ext4_xattr_ibody_header) + 3) // 4) # The ext4_xattr_entry following the header is aligned on a 4-byte boundary
try:
for xattr_name, xattr_value in self._parse_xattrs(inline_data[offset:], 0,
prefix_override=prefix_override):
yield xattr_name, xattr_value
except:
pass
# xattr block(s)
if check_block and self.inode.i_file_acl != 0:
xattrs_block_start = self.inode.i_file_acl * self.volume.block_size
xattrs_block = self.volume.read(xattrs_block_start, self.volume.block_size)
xattrs_header = ext4_xattr_header.from_buffer_copy(xattrs_block)
if not self.volume.ignore_magic and xattrs_header.h_magic != 0xEA020000:
try:
raise MagicError(
"Invalid magic value in xattrs block header at offset 0x{xattrs_block_start:X} of inode {inode:d}: 0x{xattrs_header} (expected 0xEA020000)".format(
inode=self.inode_idx,
xattrs_block_start=xattrs_block_start,
xattrs_header=xattrs_header.h_magic
))
except:
pass
if xattrs_header.h_blocks != 1:
raise Ext4Error(
"Invalid number of xattr blocks at offset 0x{xattrs_block_start:X} of inode {inode:d}: {xattrs_header:d} (expected 1)".format(
inode=self.inode_idx,
xattrs_header=xattrs_header.h_blocks,
xattrs_block_start=xattrs_block_start
))
offset = 4 * ((ctypes.sizeof(
ext4_xattr_header) + 3) // 4) # The ext4_xattr_entry following the header is aligned on a 4-byte boundary
for xattr_name, xattr_value in self._parse_xattrs(xattrs_block[offset:], -offset,
prefix_override=prefix_override):
yield xattr_name, xattr_value
class BlockReader:
# OSError
EINVAL = 22
def __init__(self, volume, byte_size, block_map):
self.byte_size = byte_size
self.volume = volume
self.cursor = 0
block_map = list(map(MappingEntry.copy, block_map))
# Optimize mapping (stich together)
MappingEntry.optimize(block_map)
self.block_map = block_map
def __repr__(self):
return "{type_name:s}(byte_size = {size!r:s}, block_map = {block_map!r:s}, volume_uuid = {uuid!r:s})".format(
block_map=self.block_map,
size=self.byte_size,
type_name=type(self).__name__,
uuid=self.volume.uuid
)
def get_block_mapping(self, file_block_idx):
disk_block_idx = None
# Find disk block
for entry in self.block_map:
if entry.file_block_idx <= file_block_idx < entry.file_block_idx + entry.block_count:
block_diff = file_block_idx - entry.file_block_idx
disk_block_idx = entry.disk_block_idx + block_diff
break
return disk_block_idx
def read(self, byte_len=-1):
# Parse args
if byte_len < -1:
raise ValueError("byte_len must be non-negative or -1")
bytes_remaining = self.byte_size - self.cursor
byte_len = bytes_remaining if byte_len == -1 else max(0, min(byte_len, bytes_remaining))
if byte_len == 0:
return b""
# Reading blocks
start_block_idx = self.cursor // self.volume.block_size
end_block_idx = (self.cursor + byte_len - 1) // self.volume.block_size
end_of_stream_check = byte_len
blocks = [self.read_block(i) for i in range(start_block_idx, end_block_idx - start_block_idx + 1)]
start_offset = self.cursor % self.volume.block_size
if start_offset != 0:
blocks[0] = blocks[0][start_offset:]
byte_len = (byte_len + start_offset - self.volume.block_size - 1) % self.volume.block_size + 1
blocks[-1] = blocks[-1][:byte_len]
result = b"".join(blocks)
# Check read
if len(result) != end_of_stream_check:
raise EndOfStreamError(
"The volume's underlying stream ended {0:d} bytes before EOF.".format(byte_len - len(result)))
self.cursor += len(result)
return result
def read_block(self, file_block_idx):
disk_block_idx = self.get_block_mapping(file_block_idx)
if disk_block_idx is not None:
return self.volume.read(disk_block_idx * self.volume.block_size, self.volume.block_size)
else:
return bytes([0] * self.volume.block_size)
def seek(self, seek, seek_mode=io.SEEK_SET):
if seek_mode == io.SEEK_CUR:
seek += self.cursor
elif seek_mode == io.SEEK_END:
seek += self.byte_size
# elif seek_mode == io.SEEK_SET:
# seek += 0
if seek < 0:
raise OSError(BlockReader.EINVAL, "Invalid argument") # Exception behavior copied from IOBase.seek
self.cursor = seek
return seek
def tell(self):
return self.cursor

140
fspatch.py Normal file
View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright by affggh
# This program based on Apache 2.0 LICENES
import os
def scanfs(file): # 读取fs_config文件返回一个字典
fsfile = open(file, "r")
fsconfig = {}
for i in fsfile.readlines():
filepath = i.split(' ')[0]
uid = i.split(' ')[1]
gid = i.split(' ')[2]
mode = i.split(' ')[3]
if len(i.split(' ')) > 4:
link = i.split(' ')[4].replace('\n', '')
fsconfig[filepath] = [uid, gid, mode, link]
else:
fsconfig[filepath] = [uid, gid, mode.replace('\n', '')]
return fsconfig
def scanfsdir(folder): # 读取解包的目录,返回一个字典
allfile = []
allfile.append('/')
if os.name == 'nt':
allfile.append(os.path.basename(folder).replace('\\', ''))
elif os.name == 'posix':
allfile.append(os.path.basename(folder).replace('/', ''))
else:
return False
for root, dirs, files in os.walk(folder):
for dir in dirs:
if os.name == 'nt':
allfile.append(os.path.join(root, dir).replace(folder, os.path.basename(folder)).replace('\\', '/'))
elif os.name == 'posix':
allfile.append(os.path.join(root, dir).replace(folder, os.path.basename(folder)))
for file in files:
if os.name == 'nt':
allfile.append(os.path.join(root, file).replace(folder, os.path.basename(folder)).replace('\\', '/'))
elif os.name == 'posix':
allfile.append(os.path.join(root, file).replace(folder, os.path.basename(folder)))
return allfile
def islink(file):
if os.name == 'nt':
if not os.path.isdir(file):
with open(file, 'rb') as f:
magic = f.read(12)
if magic == b'!<symlink>\xff\xfe':
point = f.read()
return point.decode("utf-8").replace('\x00', '')
else:
return False
if os.name == 'posix':
if os.path.islink(file):
return os.readlink(file)
else:
return False
def fspatch(fsfile, filename, dirpath): # 接收两个字典对比
newfs = {}
for i in filename:
if fsfile.get(i):
newfs.update({i: fsfile[i]})
else:
if os.name == 'nt':
filepath = os.path.abspath(dirpath + os.sep + ".." + os.sep + i.replace('/', '\\'))
elif os.name == 'posix':
filepath = os.path.abspath(dirpath + os.sep + ".." + os.sep + i)
if os.path.isdir(filepath):
uid = '0'
if i.find("system/bin") != -1 or i.find("system/xbin") != -1:
gid = '2000'
elif i.find("vendor/bin") != -1:
gid = '2000'
else:
gid = '0'
mode = '0755' # dir path always 755
config = [uid, gid, mode]
elif islink(filepath):
uid = '0'
if (i.find("system/bin") != -1) or (i.find("system/xbin") != -1) or (i.find("vendor/bin") != -1):
gid = '2000'
else:
gid = '0'
if (i.find("/bin") != -1) or (i.find("/xbin") != -1):
mode = '0755'
elif i.find(".sh") != -1:
mode = "0750"
else:
mode = "0644"
link = islink(filepath)
config = [uid, gid, mode, link]
elif (i.find("/bin") != -1) or (i.find("/xbin") != -1):
uid = '0'
if (i.find("system/bin") != -1) or (i.find("system/xbin") != -1) or (i.find("vendor/bin") != -1):
gid = '2000'
else:
gid = '0'
mode = '0755'
if i.find(".sh") != -1:
mode = "0750"
else:
for s in ["/bin/su", "/xbin/su", "disable_selinux.sh", "daemonsu", "ext/.su", "install-recovery", 'installed_su_daemon']:
if i.find(s) != -1:
mode = "0755"
config = [uid, gid, mode]
else:
uid = '0'
gid = '0'
mode = '0644'
config = [uid, gid, mode]
newfs.update({i: config})
return newfs
def writetofile(file, newfsconfig):
with open(file, "w") as f:
for i in list(sorted(newfsconfig.keys())):
if len(newfsconfig[i]) < 4:
fs = i + ' ' + newfsconfig[i][0] + ' ' + newfsconfig[i][1] + ' ' + newfsconfig[i][2] + "\n"
else:
fs = i + ' ' + newfsconfig[i][0] + ' ' + newfsconfig[i][1] + ' ' + newfsconfig[i][2] + ' ' + \
newfsconfig[i][3] + "\n"
f.write(fs)
def main(dirpath, fsconfig):
origfs = scanfs(os.path.abspath(fsconfig))
allfile = scanfsdir(os.path.abspath(dirpath))
newfs = fspatch(origfs, allfile, dirpath)
writetofile(fsconfig, newfs)
print("Load origin %d" % (len(origfs.keys())) + " entrys")
print("Detect totsl %d" % (len(allfile)) + " entrys")
print("New fs_config %d" % (len(newfs.keys())) + " entrys")

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

92
img2sdat.py Normal file
View File

@ -0,0 +1,92 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ====================================================
# FILE: img2sdat.py
# AUTHORS: xpirt - luxi78 - howellzhu
# DATE: 2018-05-25 12:19:12 CEST
# ====================================================
from __future__ import print_function
import sys, os, errno, tempfile
import common, blockimgdiff, sparse_img
def main(INPUT_IMAGE, OUTDIR='.', VERSION=None, PREFIX='system'):
global input
__version__ = '1.7'
print('img2sdat binary - version: %s\n' % __version__)
if not os.path.isdir(OUTDIR):
os.makedirs(OUTDIR)
OUTDIR = OUTDIR + '/' + PREFIX
if not VERSION:
VERSION = 4
while True:
print(''' 1. Android Lollipop 5.0
2. Android Lollipop 5.1
3. Android Marshmallow 6.0
4. Android Nougat 7.0/7.1/8.0/8.1
''')
try:
input = input
except NameError:
pass
item = input('Choose system version: ')
if item == '1':
VERSION = 1
break
elif item == '2':
VERSION = 2
break
elif item == '3':
VERSION = 3
break
elif item == '4':
VERSION = 4
break
else:
return
# Get sparse image
image = sparse_img.SparseImage(INPUT_IMAGE, tempfile.mkstemp()[1], '0')
# Generate output files
b = blockimgdiff.BlockImageDiff(image, None, VERSION)
b.Compute(OUTDIR)
print('Done! Output files: %s' % os.path.dirname(OUTDIR))
return
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Visit xda thread for more information.')
parser.add_argument('image', help='input system image')
parser.add_argument('-o', '--outdir', help='output directory (current directory by default)')
parser.add_argument('-v', '--version',
help='transfer list version number, will be asked by default - more info on xda thread)')
parser.add_argument('-p', '--prefix', help='name of image (prefix.new.dat)')
args = parser.parse_args()
INPUT_IMAGE = args.image
if args.outdir:
OUTDIR = args.outdir
else:
OUTDIR = '.'
if args.version:
VERSION = int(args.version)
else:
VERSION = None
if args.prefix:
PREFIX = args.prefix
else:
PREFIX = 'system'
main(INPUT_IMAGE, OUTDIR, VERSION, PREFIX)

673
imgextractor.py Normal file
View File

@ -0,0 +1,673 @@
import mmap
import os
import re
import shutil
import struct
import subprocess
import traceback
from timeit import default_timer as dti
EXT4_HEADER_MAGIC = 0xED26FF3A
EXT4_SPARSE_HEADER_LEN = 28
EXT4_CHUNK_HEADER_SIZE = 12
class ext4_file_header(object):
def __init__(self, buf):
(self.magic,
self.major,
self.minor,
self.file_header_size,
self.chunk_header_size,
self.block_size,
self.total_blocks,
self.total_chunks,
self.crc32) = struct.unpack('<I4H4I', buf)
class ext4_chunk_header(object):
def __init__(self, buf):
(self.type,
self.reserved,
self.chunk_size,
self.total_size) = struct.unpack('<2H2I', buf)
class Extractor(object):
def __init__(self):
self.FileName = ""
self.BASE_DIR = ""
self.OUTPUT_IMAGE_FILE = ""
self.EXTRACT_DIR = ""
self.BLOCK_SIZE = 4096
self.TYPE_IMG = 'system'
self.context = []
self.fsconfig = []
def __remove(self, path):
if os.path.isfile(path):
os.remove(path) # remove the file
elif os.path.isdir(path):
shutil.rmtree(path) # remove dir and all contains
else:
raise ValueError("file {} is not a file or dir.".format(path))
def __logtb(self, ex, ex_traceback=None):
if ex_traceback is None:
ex_traceback = ex.__traceback__
tb_lines = [line.rstrip('\n') for line in
traceback.format_exception(ex.__class__, ex, ex_traceback)]
return '\n'.join(tb_lines)
def __file_name(self, file_path):
name = os.path.basename(file_path).split('.')[0]
name = name.split('-')[0]
# name = name.split('_')[0]
name = name.split(' ')[0]
name = name.split('+')[0]
name = name.split('{')[0]
name = name.split('(')[0]
return name
def __appendf(self, msg, log_file):
with open(log_file, 'a', newline='\n') as file:
print(msg, file=file)
def __getperm(self, arg):
if len(arg) < 9 or len(arg) > 10:
return
if len(arg) > 8:
arg = arg[1:]
oor, ow, ox, gr, gw, gx, wr, ww, wx = list(arg)
o, g, w, s = 0, 0, 0, 0
if oor == 'r': o += 4
if ow == 'w': o += 2
if ox == 'x': o += 1
if ox == 'S': s += 4
if ox == 's': s += 4; o += 1
if gr == 'r': g += 4
if gw == 'w': g += 2
if gx == 'x': g += 1
if gx == 'S': s += 2
if gx == 's': s += 2; g += 1
if wr == 'r': w += 4
if ww == 'w': w += 2
if wx == 'x': w += 1
if wx == 'T': s += 1
if wx == 't': s += 1; w += 1
return str(s) + str(o) + str(g) + str(w)
def __ext4extractor(self):
import ext4, string, struct
fs_config_file = self.FileName + '_fs_config'
fuking_symbols = '\\^$.|?*+(){}[]'
contexts = self.CONFING_DIR + os.sep + self.FileName + "_file_contexts" # 08.05.18
def scan_dir(root_inode, root_path=""):
for entry_name, entry_inode_idx, entry_type in root_inode.open_dir():
if entry_name in ['.', '..'] or entry_name.endswith(' (2)'):
continue
entry_inode = root_inode.volume.get_inode(entry_inode_idx, entry_type)
entry_inode_path = root_path + '/' + entry_name
mode = self.__getperm(entry_inode.mode_str)
uid = entry_inode.inode.i_uid
gid = entry_inode.inode.i_gid
con = ''
cap = ''
for i in list(entry_inode.xattrs()):
if i[0] == 'security.selinux':
con = i[1].decode('utf8')[:-1]
elif i[0] == 'security.capability':
raw_cap = struct.unpack("<5I", i[1])
if raw_cap[1] > 65535:
cap = '' + str(hex(int('%04x%04x' % (raw_cap[3], raw_cap[1]), 16)))
else:
cap = '' + str(hex(int('%04x%04x%04x' % (raw_cap[3], raw_cap[2], raw_cap[1]), 16)))
cap = ' capabilities={cap}'.format(cap=cap)
if entry_inode.is_dir:
dir_target = self.EXTRACT_DIR + entry_inode_path.replace(' ', '_').replace('"', '')
if not os.path.isdir(dir_target):
os.makedirs(dir_target)
if os.name == 'posix' and os.geteuid() == 0:
os.chmod(dir_target, int(mode, 8))
os.chown(dir_target, uid, gid)
scan_dir(entry_inode, entry_inode_path)
if cap == '' and con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode))
else:
self.fsconfig.append('%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode))
else:
if cap == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode))
else:
self.fsconfig.append('%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
else:
if con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode + cap))
else:
self.fsconfig.append(
'%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode + cap))
else:
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode + cap))
else:
self.fsconfig.append(
'%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode + cap))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
elif entry_inode.is_file:
raw = entry_inode.open_read().read()
wdone = None
if os.name == 'nt':
if entry_name.endswith('/'):
entry_name = entry_name[:-1]
file_target = self.EXTRACT_DIR + entry_inode_path.replace('/', os.sep).replace(' ',
'_').replace('"',
'')
if not os.path.isdir(os.path.dirname(file_target)):
os.makedirs(os.path.dirname(file_target))
try:
with open(file_target, 'wb') as out:
out.write(raw)
except:
print(f"ERROR:Cannot Write {file_target}")
if os.name == 'posix':
file_target = self.EXTRACT_DIR + entry_inode_path.replace(' ', '_').replace('"', '')
if not os.path.isdir(os.path.dirname(file_target)):
os.makedirs(os.path.dirname(file_target))
with open(file_target, 'wb') as out:
out.write(raw)
if os.geteuid() == 0:
os.chmod(file_target, int(mode, 8))
os.chown(file_target, uid, gid)
if cap == '' and con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode))
else:
self.fsconfig.append('%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode))
else:
if cap == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode))
else:
self.fsconfig.append('%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
else:
if con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode + cap))
else:
self.fsconfig.append(
'%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode + cap))
else:
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s' % (tmppath, uid, gid, mode + cap))
else:
self.fsconfig.append(
'%s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode + cap))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
elif entry_inode.is_symlink:
try:
link_target = entry_inode.open_read().read().decode("utf8")
target = self.EXTRACT_DIR + entry_inode_path.replace(' ', '_')
if cap == '' and con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s %s' % (tmppath, uid, gid, mode, link_target))
else:
self.fsconfig.append(
'%s %s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode, link_target))
else:
if cap == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s %s' % (tmppath, uid, gid, mode, link_target))
else:
self.fsconfig.append(
'%s %s %s %s %s' % (self.DIR + entry_inode_path, uid, gid, mode, link_target))
for fuk_symb in fuking_symbols:
tmppath = tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
else:
if con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append(
'%s %s %s %s %s' % (tmppath, uid, gid, mode + cap, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode + cap, link_target))
else:
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append(
'%s %s %s %s %s' % (tmppath, uid, gid, mode + cap, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode + cap, link_target))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
if os.path.islink(target):
try:
os.remove(target)
except:
pass
if os.path.isfile(target):
try:
os.remove(target)
except:
pass
if os.name == 'posix':
os.symlink(link_target, target)
if os.name == 'nt':
with open(target.replace('/', os.sep), 'wb') as out:
tmp = bytes.fromhex('213C73796D6C696E6B3EFFFE')
for index in list(link_target):
tmp = tmp + struct.pack('>sx', index.encode('utf-8'))
out.write(tmp + struct.pack('xx'))
subprocess.Popen('attrib +s "%s"' % target.replace('/', os.sep), shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# call('attrib +s "%s"' % target.replace('/', os.sep))
if not all(c in string.printable for c in link_target):
pass
if entry_inode_path[1:] == entry_name or link_target[1:] == entry_name:
self.symlinks.append('%s %s' % (link_target, entry_inode_path[1:]))
else:
self.symlinks.append('%s %s' % (link_target, self.DIR + entry_inode_path))
except:
try:
link_target_block = int.from_bytes(entry_inode.open_read().read(), "little")
link_target = root_inode.volume.read(link_target_block * root_inode.volume.block_size,
entry_inode.inode.i_size).decode("utf8")
target = self.EXTRACT_DIR + entry_inode_path.replace(' ', '_')
if link_target and all(c in string.printable for c in link_target):
if cap == '' and con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append('%s %s %s %s %s' % (tmppath, uid, gid, mode, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode, link_target))
else:
if cap == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append(
'%s %s %s %s %s' % (tmppath, uid, gid, mode, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode, link_target))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
else:
if con == '':
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append(
'%s %s %s %s %s' % (tmppath, uid, gid, mode + cap, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode + cap, link_target))
else:
tmppath = self.DIR + entry_inode_path
if (tmppath).find(' ', 1, len(tmppath)) > 0:
spaces_file = self.BASE_MYDIR + 'config' + os.sep + self.FileName + '_space.txt'
if not os.path.isfile(spaces_file):
f = open(spaces_file, 'tw', encoding='utf-8')
self.__appendf(tmppath, spaces_file)
f.close
else:
self.__appendf(tmppath, spaces_file)
tmppath = tmppath.replace(' ', '_')
self.fsconfig.append(
'%s %s %s %s %s' % (tmppath, uid, gid, mode + cap, link_target))
else:
self.fsconfig.append('%s %s %s %s %s' % (
self.DIR + entry_inode_path, uid, gid, mode + cap, link_target))
for fuk_symb in fuking_symbols:
tmppath = tmppath.replace(fuk_symb, '\\' + fuk_symb)
self.context.append('/%s %s' % (tmppath, con))
if os.name == 'posix':
os.symlink(link_target, target)
if os.name == 'nt':
with open(target.replace('/', os.sep), 'wb') as out:
tmp = bytes.fromhex('213C73796D6C696E6B3EFFFE')
for index in list(link_target):
tmp = tmp + struct.pack('>sx', index.encode('utf-8'))
out.write(tmp + struct.pack('xx'))
# call('attrib +s %s' % target.replace('/', os.sep))
# subprocess.Popen('attrib +s "%s"' % target.replace('/', os.sep), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
pass
except:
pass
dir_my = self.CONFING_DIR + os.sep
if not os.path.isdir(dir_my):
os.makedirs(dir_my)
f = open(dir_my + self.FileName + '_size.txt', 'tw', encoding='utf-8')
self.__appendf(os.path.getsize(self.OUTPUT_IMAGE_FILE), dir_my + self.FileName + '_size.txt')
f.close()
with open(self.OUTPUT_IMAGE_FILE, 'rb') as file:
root = ext4.Volume(file).root
dirlist = []
for file_name, inode_idx, file_type in root.open_dir():
dirlist.append(file_name)
dirr = self.__file_name(os.path.basename(self.OUTPUT_IMAGE_FILE).split('.')[0]) # 11.05.18
setattr(self, 'DIR', dirr)
scan_dir(root)
for c in self.fsconfig:
if dirr == 'vendor':
self.fsconfig.insert(0, '/' + ' 0 2000 0755')
self.fsconfig.insert(1, dirr + ' 0 2000 0755')
elif dirr == 'system':
self.fsconfig.insert(0, '/' + ' 0 0 0755')
self.fsconfig.insert(1, '/' + 'lost+found' + ' 0 0 0700')
self.fsconfig.insert(2, dirr + ' 0 0 0755')
else:
self.fsconfig.insert(0, '/' + ' 0 0 0755')
self.fsconfig.insert(1, dirr + ' 0 0 0755')
break
self.__appendf('\n'.join(self.fsconfig), self.CONFING_DIR + os.sep + fs_config_file)
if self.context: # 11.05.18
self.context.sort() # 11.05.18
for c in self.context:
if re.search('lost..found', c):
self.context.insert(0, '/' + ' ' + c.split(" ")[1])
self.context.insert(1, '/' + dirr + '(/.*)? ' + c.split(" ")[1])
self.context.insert(2, '/' + dirr + ' ' + c.split(" ")[1])
self.context.insert(3, '/' + dirr + '/lost+\\found' + ' ' + c.split(" ")[1])
break
for c in self.context:
if re.search('/system/system/build..prop ', c):
self.context.insert(3, '/lost+\\found' + ' u:object_r:rootfs:s0')
self.context.insert(4, '/' + dirr + '/' + dirr + '(/.*)? ' + c.split(" ")[1])
break
self.__appendf('\n'.join(self.context), contexts) # 11.05.18
def __converSimgToImg(self, target):
with open(target, "rb") as img_file:
if self.sign_offset > 0:
img_file.seek(self.sign_offset, 0)
header = ext4_file_header(img_file.read(28))
total_chunks = header.total_chunks
if header.file_header_size > EXT4_SPARSE_HEADER_LEN:
img_file.seek(header.file_header_size - EXT4_SPARSE_HEADER_LEN, 1)
with open(target.replace(".img", ".raw.img"), "wb") as raw_img_file:
sector_base = 82528
output_len = 0
while total_chunks > 0:
chunk_header = ext4_chunk_header(img_file.read(EXT4_CHUNK_HEADER_SIZE))
sector_size = (chunk_header.chunk_size * header.block_size) >> 9
chunk_data_size = chunk_header.total_size - header.chunk_header_size
if chunk_header.type == 0xCAC1: # CHUNK_TYPE_RAW
if header.chunk_header_size > EXT4_CHUNK_HEADER_SIZE:
img_file.seek(header.chunk_header_size - EXT4_CHUNK_HEADER_SIZE, 1)
data = img_file.read(chunk_data_size)
len_data = len(data)
if len_data == (sector_size << 9):
raw_img_file.write(data)
output_len += len_data
sector_base += sector_size
else:
if chunk_header.type == 0xCAC2: # CHUNK_TYPE_FILL
if header.chunk_header_size > EXT4_CHUNK_HEADER_SIZE:
img_file.seek(header.chunk_header_size - EXT4_CHUNK_HEADER_SIZE, 1)
data = img_file.read(chunk_data_size)
len_data = sector_size << 9
raw_img_file.write(struct.pack("B", 0) * len_data)
output_len += len(data)
sector_base += sector_size
else:
if chunk_header.type == 0xCAC3: # CHUNK_TYPE_DONT_CARE
if header.chunk_header_size > EXT4_CHUNK_HEADER_SIZE:
img_file.seek(header.chunk_header_size - EXT4_CHUNK_HEADER_SIZE, 1)
data = img_file.read(chunk_data_size)
len_data = sector_size << 9
raw_img_file.write(struct.pack("B", 0) * len_data)
output_len += len(data)
sector_base += sector_size
else:
len_data = sector_size << 9
raw_img_file.write(struct.pack("B", 0) * len_data)
sector_base += sector_size
total_chunks -= 1
self.OUTPUT_IMAGE_FILE = target.replace(".img", ".raw.img")
def fixmoto(self, input_file):
if os.path.exists(input_file) == False:
return
output_file = input_file + "_"
if os.path.exists(output_file) == True:
try:
os.remove(output_file)
except:
pass
with open(input_file, 'rb') as f:
data = f.read(500000)
moto = re.search(b'\x4d\x4f\x54\x4f', data)
if not moto:
return
result = []
for i in re.finditer(b'\x53\xEF', data):
result.append(i.start() - 1080)
offset = 0
for i in result:
if data[i] == 0:
offset = i
break
if offset > 0:
with open(output_file, 'wb') as o, open(input_file, 'rb') as f:
data = f.seek(offset)
data = f.read(15360)
if data:
devnull = o.write(data)
try:
os.remove(input_file)
os.rename(output_file, input_file)
except:
pass
def checkSignOffset(self, file):
size = os.stat(file.name).st_size
if size <= 52428800:
mm = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ)
else:
mm = mmap.mmap(file.fileno(), 52428800, access=mmap.ACCESS_READ) # 52428800=50Mb
offset = mm.find(struct.pack('<L', EXT4_HEADER_MAGIC))
return offset
def __getTypeTarget(self, target):
filename, file_extension = os.path.splitext(target)
if file_extension == '.img':
with open(target, "rb") as img_file:
setattr(self, 'sign_offset', self.checkSignOffset(img_file))
if self.sign_offset > 0:
img_file.seek(self.sign_offset, 0)
header = ext4_file_header(img_file.read(28))
if header.magic != EXT4_HEADER_MAGIC:
return 'img'
else:
return 'simg'
def main(self, target, output_dir, work):
self.BASE_DIR = (os.path.realpath(os.path.dirname(target)) + os.sep)
self.BASE_MYDIR = output_dir + os.sep
self.EXTRACT_DIR = os.path.realpath(os.path.dirname(output_dir)) + os.sep + self.__file_name(
os.path.basename(output_dir)) # output_dir
self.OUTPUT_IMAGE_FILE = self.BASE_DIR + os.path.basename(target)
self.OUTPUT_MYIMAGE_FILE = os.path.basename(target)
self.MYFileName = os.path.basename(self.OUTPUT_IMAGE_FILE).replace(".img", "")
self.FileName = self.__file_name(os.path.basename(target))
target_type = 'img'
self.CONFING_DIR = work + os.sep + 'config'
if target_type == 'simg':
print(".....Convert %s to %s" % (
os.path.basename(target), os.path.basename(target).replace(".img", ".raw.img")))
self.__converSimgToImg(target)
with open(os.path.abspath(self.OUTPUT_IMAGE_FILE), 'rb') as f:
data = f.read(500000)
moto = re.search(b'\x4d\x4f\x54\x4f', data)
if moto:
print(".....Finding MOTO structure! Fixing.....")
self.fixmoto(os.path.abspath(self.OUTPUT_IMAGE_FILE))
print("Extracting %s --> %s" % (os.path.basename(target), os.path.basename(self.EXTRACT_DIR)))
start = dti()
self.__ext4extractor()
print("Done! [%s]" % (dti() - start))
if target_type == 'img':
with open(os.path.abspath(self.OUTPUT_IMAGE_FILE), 'rb') as f:
data = f.read(500000)
moto = re.search(b'\x4d\x4f\x54\x4f', data)
if moto:
print(".....Finding MOTO structure! Fixing.....")
self.fixmoto(os.path.abspath(self.OUTPUT_IMAGE_FILE))
print("Extracting %s --> %s" % (os.path.basename(target), os.path.basename(self.EXTRACT_DIR)))
start = dti()
self.__ext4extractor()
print("Done! [%s]" % (dti() - start))

946
lpunpack.py Normal file
View File

@ -0,0 +1,946 @@
import argparse
import copy
import enum
import io
import json
import re
import struct
import sys
from dataclasses import dataclass, field
import os
from string import Template
from typing import IO, Dict, List, TypeVar, cast, BinaryIO, Tuple
from timeit import default_timer as dti
SPARSE_HEADER_MAGIC = 0xED26FF3A
SPARSE_HEADER_SIZE = 28
SPARSE_CHUNK_HEADER_SIZE = 12
LP_PARTITION_RESERVED_BYTES = 4096
LP_METADATA_GEOMETRY_MAGIC = 0x616c4467
LP_METADATA_GEOMETRY_SIZE = 4096
LP_METADATA_HEADER_MAGIC = 0x414C5030
LP_SECTOR_SIZE = 512
LP_TARGET_TYPE_LINEAR = 0
LP_TARGET_TYPE_ZERO = 1
LP_PARTITION_ATTR_READONLY = (1 << 0)
LP_PARTITION_ATTR_SLOT_SUFFIXED = (1 << 1)
LP_PARTITION_ATTR_UPDATED = (1 << 2)
LP_PARTITION_ATTR_DISABLED = (1 << 3)
LP_BLOCK_DEVICE_SLOT_SUFFIXED = (1 << 0)
LP_GROUP_SLOT_SUFFIXED = (1 << 0)
PLAIN_TEXT_TEMPLATE = """Slot 0:
Metadata version: $metadata_version
Metadata size: $metadata_size bytes
Metadata max size: $metadata_max_size bytes
Metadata slot count: $metadata_slot_count
Header flags: $header_flags
Partition table:
------------------------
$partitions
------------------------
Super partition layout:
------------------------
$layouts
------------------------
Block device table:
------------------------
$blocks
------------------------
Group table:
------------------------
$groups
"""
def build_attribute_string(attributes: int) -> str:
if attributes & LP_PARTITION_ATTR_READONLY:
result = "readonly"
elif attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED:
result = "slot-suffixed"
elif attributes & LP_PARTITION_ATTR_UPDATED:
result = "updated"
elif attributes & LP_PARTITION_ATTR_DISABLED:
result = "disabled"
else:
result = "none"
return result
def build_block_device_flag_string(flags: int) -> str:
return "slot-suffixed" if (flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) else "none"
def build_group_flag_string(flags: int) -> str:
return "slot-suffixed" if (flags & LP_GROUP_SLOT_SUFFIXED) else "none"
class FormatType(enum.Enum):
TEXT = "text"
JSON = "json"
class EnumAction(argparse.Action):
"""Argparse action for handling Enums"""
def __init__(self, **kwargs):
enum_type = kwargs.pop("type", None)
if enum_type is None:
raise ValueError("Type must be assigned an Enum when using EnumAction")
if not issubclass(enum_type, enum.Enum):
raise TypeError("Type must be an Enum when using EnumAction")
kwargs.setdefault("choices", tuple(e.value for e in enum_type))
super(EnumAction, self).__init__(**kwargs)
self._enum = enum_type
def __call__(self, parser, namespace, values, option_string=None):
value = self._enum(values)
setattr(namespace, self.dest, value)
class ShowJsonInfo(json.JSONEncoder):
def __init__(self, ignore_keys: List[str], **kwargs):
super().__init__(**kwargs)
self._ignore_keys = ignore_keys
def _remove_ignore_keys(self, data: Dict):
_data = copy.deepcopy(data)
for field_key, v in data.items():
if field_key in self._ignore_keys:
_data.pop(field_key)
continue
if v == 0:
_data.pop(field_key)
continue
if isinstance(v, int) and not isinstance(v, bool):
_data.update({field_key: str(v)})
return _data
def encode(self, data: Dict) -> str:
result = {
"partitions": list(map(self._remove_ignore_keys, data["partition_table"])),
"groups": list(map(self._remove_ignore_keys, data["group_table"])),
"block_devices": list(map(self._remove_ignore_keys, data["block_devices"]))
}
return super().encode(result)
class SparseHeader(object):
def __init__(self, buffer):
fmt = '<I4H4I'
(
self.magic, # 0xed26ff3a
self.major_version, # (0x1) - reject images with higher major versions
self.minor_version, # (0x0) - allow images with higer minor versions
self.file_hdr_sz, # 28 bytes for first revision of the file format
self.chunk_hdr_sz, # 12 bytes for first revision of the file format
self.blk_sz, # block size in bytes, must be a multiple of 4 (4096)
self.total_blks, # total blocks in the non-sparse output image
self.total_chunks, # total chunks in the sparse input image
self.image_checksum # CRC32 checksum of the original data, counting "don't care"
) = struct.unpack(fmt, buffer[0:struct.calcsize(fmt)])
class SparseChunkHeader(object):
"""
Following a Raw or Fill or CRC32 chunk is data.
For a Raw chunk, it's the data in chunk_sz * blk_sz.
For a Fill chunk, it's 4 bytes of the fill data.
For a CRC32 chunk, it's 4 bytes of CRC32
"""
def __init__(self, buffer):
fmt = '<2H2I'
(
self.chunk_type, # 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
self.reserved,
self.chunk_sz, # in blocks in output image * /
self.total_sz, # in bytes of chunk input file including chunk header and data * /
) = struct.unpack(fmt, buffer[0:struct.calcsize(fmt)])
class LpMetadataBase:
_fmt = None
@classmethod
@property
def size(cls) -> int:
return struct.calcsize(cls._fmt)
class LpMetadataGeometry(LpMetadataBase):
"""
Offset 0: Magic signature
Offset 4: Size of the `LpMetadataGeometry`
Offset 8: SHA256 checksum
Offset 40: Maximum amount of space a single copy of the metadata can use
Offset 44: Number of copies of the metadata to keep
Offset 48: Logical block size
"""
_fmt = '<2I32s3I'
def __init__(self, buffer):
(
self.magic,
self.struct_size,
self.checksum,
self.metadata_max_size,
self.metadata_slot_count,
self.logical_block_size
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
# self.size
class LpMetadataTableDescriptor(LpMetadataBase):
"""
Offset 0: Location of the table, relative to end of the metadata header.
Offset 4: Number of entries in the table.
Offset 8: Size of each entry in the table, in bytes.
"""
_fmt = '<3I'
def __init__(self, buffer):
(
self.offset,
self.num_entries,
self.entry_size
) = struct.unpack(self._fmt, buffer[:struct.calcsize(self._fmt)])
class LpMetadataPartition(LpMetadataBase):
"""
Offset 0: Name of this partition in ASCII characters. Any unused characters in
the buffer must be set to 0. Characters may only be alphanumeric or _.
The name must include at least one ASCII character, and it must be unique
across all partition names. The length (36) is the same as the maximum
length of a GPT partition name.
Offset 36: Attributes for the partition (see LP_PARTITION_ATTR_* flags above).
Offset 40: Index of the first extent owned by this partition. The extent will
start at logical sector 0. Gaps between extents are not allowed.
Offset 44: Number of extents in the partition. Every partition must have at least one extent.
Offset 48: Group this partition belongs to.
"""
_fmt = '<36s4I'
def __init__(self, buffer):
(
self.name,
self.attributes,
self.first_extent_index,
self.num_extents,
self.group_index
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
self.name = self.name.decode("utf-8").strip('\x00')
@property
def filename(self) -> str:
return f'{self.name}.img'
class LpMetadataExtent(LpMetadataBase):
"""
Offset 0: Length of this extent, in 512-byte sectors.
Offset 8: Target type for device-mapper (see LP_TARGET_TYPE_* values).
Offset 12: Contents depends on target_type. LINEAR: The sector on the physical partition that this extent maps onto.
ZERO: This field must be 0.
Offset 20: Contents depends on target_type. LINEAR: Must be an index into the block devices table.
"""
_fmt = '<QIQI'
def __init__(self, buffer):
(
self.num_sectors,
self.target_type,
self.target_data,
self.target_source
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
class LpMetadataHeader(LpMetadataBase):
"""
+-----------------------------------------+
| Header data - fixed size |
+-----------------------------------------+
| Partition table - variable size |
+-----------------------------------------+
| Partition table extents - variable size |
+-----------------------------------------+
Offset 0: Four bytes equal to `LP_METADATA_HEADER_MAGIC`
Offset 4: Version number required to read this metadata. If the version is not
equal to the library version, the metadata should be considered incompatible.
Offset 6: Minor version. A library supporting newer features should be able to
read metadata with an older minor version. However, an older library
should not support reading metadata if its minor version is higher.
Offset 8: The size of this header struct.
Offset 12: SHA256 checksum of the header, up to |header_size| bytes, computed as if this field were set to 0.
Offset 44: The total size of all tables. This size is contiguous; tables may not
have gaps in between, and they immediately follow the header.
Offset 48: SHA256 checksum of all table contents.
Offset 80: Partition table descriptor.
Offset 92: Extent table descriptor.
Offset 104: Updateable group descriptor.
Offset 116: Block device table.
Offset 128: Header flags are independent of the version number and intended to be informational only.
New flags can be added without bumping the version.
Offset 132: Reserved (zero), pad to 256 bytes.
"""
_fmt = '<I2hI32sI32s'
partitions: LpMetadataTableDescriptor = field(default=None)
extents: LpMetadataTableDescriptor = field(default=None)
groups: LpMetadataTableDescriptor = field(default=None)
block_devices: LpMetadataTableDescriptor = field(default=None)
def __init__(self, buffer):
(
self.magic,
self.major_version,
self.minor_version,
self.header_size,
self.header_checksum,
self.tables_size,
self.tables_checksum
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
self.flags = 0
# self.size
class LpMetadataPartitionGroup(LpMetadataBase):
"""
Offset 0: Name of this group. Any unused characters must be 0.
Offset 36: Flags (see LP_GROUP_*).
Offset 40: Maximum size in bytes. If 0, the group has no maximum size.
"""
_fmt = '<36sIQ'
def __init__(self, buffer):
(
self.name,
self.flags,
self.maximum_size
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
self.name = self.name.decode("utf-8").strip('\x00')
class LpMetadataBlockDevice(LpMetadataBase):
"""
Offset 0: First usable sector for allocating logical partitions. this will be
the first sector after the initial geometry blocks, followed by the
space consumed by metadata_max_size*metadata_slot_count*2.
Offset 8: Alignment for defining partitions or partition extents. For example,
an alignment of 1MiB will require that all partitions have a size evenly
divisible by 1MiB, and that the smallest unit the partition can grow by is 1MiB.
Alignment is normally determined at runtime when growing or adding
partitions. If for some reason the alignment cannot be determined, then
this predefined alignment in the geometry is used instead. By default it is set to 1MiB.
Offset 12: Alignment offset for "stacked" devices. For example, if the "super"
partition itself is not aligned within the parent block device's
partition table, then we adjust for this in deciding where to place
|first_logical_sector|.
Similar to |alignment|, this will be derived from the operating system.
If it cannot be determined, it is assumed to be 0.
Offset 16: Block device size, as specified when the metadata was created.
This can be used to verify the geometry against a target device.
Offset 24: Partition name in the GPT. Any unused characters must be 0.
Offset 60: Flags (see LP_BLOCK_DEVICE_* flags below).
"""
_fmt = '<Q2IQ36sI'
def __init__(self, buffer):
(
self.first_logical_sector,
self.alignment,
self.alignment_offset,
self.block_device_size,
self.partition_name,
self.flags
) = struct.unpack(self._fmt, buffer[0:struct.calcsize(self._fmt)])
self.partition_name = self.partition_name.decode("utf-8").strip('\x00')
@dataclass
class Metadata:
header: LpMetadataHeader = field(default=None)
geometry: LpMetadataGeometry = field(default=None)
partitions: List[LpMetadataPartition] = field(default_factory=list)
extents: List[LpMetadataExtent] = field(default_factory=list)
groups: List[LpMetadataPartitionGroup] = field(default_factory=list)
block_devices: List[LpMetadataBlockDevice] = field(default_factory=list)
@property
def info(self) -> Dict:
return self._get_info()
@property
def metadata_region(self) -> int:
if self.geometry is None:
return 0
return LP_PARTITION_RESERVED_BYTES + (
LP_METADATA_GEOMETRY_SIZE + self.geometry.metadata_max_size * self.geometry.metadata_slot_count
) * 2
def _get_extents_string(self, partition: LpMetadataPartition) -> List[str]:
result = []
first_sector = 0
for extent_number in range(partition.num_extents):
index = partition.first_extent_index + extent_number
extent = self.extents[index]
_base = f"{first_sector} .. {first_sector + extent.num_sectors - 1}"
first_sector += extent.num_sectors
if extent.target_type == LP_TARGET_TYPE_LINEAR:
result.append(
f"{_base} linear {self.block_devices[extent.target_source].partition_name} {extent.target_data}"
)
elif extent.target_type == LP_TARGET_TYPE_ZERO:
result.append(f"{_base} zero")
return result
def _get_partition_layout(self) -> List[str]:
result = []
for partition in self.partitions:
for extent_number in range(partition.num_extents):
index = partition.first_extent_index + extent_number
extent = self.extents[index]
block_device_name = ""
if extent.target_type == LP_TARGET_TYPE_LINEAR:
block_device_name = self.block_devices[extent.target_source].partition_name
result.append(
f"{block_device_name}: {extent.target_data} .. {extent.target_data + extent.num_sectors}: "
f"{partition.name} ({extent.num_sectors} sectors)"
)
return result
def get_offsets(self, slot_number: int = 0) -> List[int]:
base = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2)
_tmp_offset = self.geometry.metadata_max_size * slot_number
primary_offset = base + _tmp_offset
backup_offset = base + self.geometry.metadata_max_size * self.geometry.metadata_slot_count + _tmp_offset
return [primary_offset, backup_offset]
def _get_info(self) -> Dict:
# TODO 25.01.2023: Liblp version 1.2 build_header_flag_string check header version 1.2
result = {}
try:
result = {
"metadata_version": f"{self.header.major_version}.{self.header.minor_version}",
"metadata_size": self.header.header_size + self.header.tables_size,
"metadata_max_size": self.geometry.metadata_max_size,
"metadata_slot_count": self.geometry.metadata_slot_count,
"header_flags": "none",
"block_devices": [
{
"name": item.partition_name,
"first_sector": item.first_logical_sector,
"size": item.block_device_size,
"block_size": self.geometry.logical_block_size,
"flags": build_block_device_flag_string(item.flags),
"alignment": item.alignment,
"alignment_offset": item.alignment_offset
} for item in self.block_devices
],
"group_table": [
{
"name": self.groups[index].name,
"maximum_size": self.groups[index].maximum_size,
"flags": build_group_flag_string(self.groups[index].flags)
} for index in range(0, self.header.groups.num_entries)
],
"partition_table": [
{
"name": item.name,
"group_name": self.groups[item.group_index].name,
"is_dynamic": True,
"size": self.extents[item.first_extent_index].num_sectors * LP_SECTOR_SIZE,
"attributes": build_attribute_string(item.attributes),
"extents": self._get_extents_string(item)
} for item in self.partitions
],
"partition_layout": self._get_partition_layout()
}
except Exception:
pass
finally:
return result
def to_json(self) -> str:
data = self._get_info()
if not data:
return ""
return json.dumps(
data,
indent=1,
cls=ShowJsonInfo,
ignore_keys=[
'metadata_version', 'metadata_size', 'metadata_max_size', 'metadata_slot_count', 'header_flags',
'partition_layout',
'attributes', 'extents', 'flags', 'first_sector'
])
def __str__(self):
data = self._get_info()
if not data:
return ""
template = Template(PLAIN_TEXT_TEMPLATE)
layouts = "\n".join(data["partition_layout"])
partitions = "------------------------\n".join(
[
" Name: {}\n Group: {}\n Attributes: {}\n Extents:\n {}\n".format(
item["name"],
item["group_name"],
item["attributes"],
"\n".join(item["extents"])
) for item in data["partition_table"]
]
)[:-1]
blocks = "\n".join(
[
" Partition name: {}\n First sector: {}\n Size: {} bytes\n Flags: {}".format(
item["name"],
item["first_sector"],
item["size"],
item["flags"]
)
for item in data["block_devices"]
]
)
groups = "------------------------\n".join(
[
" Name: {}\n Maximum size: {} bytes\n Flags: {}\n".format(
item["name"],
item["maximum_size"],
item["flags"]
) for item in data["group_table"]
]
)[:-1]
return template.substitute(partitions=partitions, layouts=layouts, blocks=blocks, groups=groups, **data)
class LpUnpackError(Exception):
"""Raised any error unpacking"""
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
@dataclass
class UnpackJob:
name: str
geometry: LpMetadataGeometry
parts: List[Tuple[int, int]] = field(default_factory=list)
total_size: int = field(default=0)
class SparseImage:
def __init__(self, fd):
self._fd = fd
self.header = None
def check(self):
self._fd.seek(0)
self.header = SparseHeader(self._fd.read(SPARSE_HEADER_SIZE))
return False if self.header.magic != SPARSE_HEADER_MAGIC else True
def _read_data(self, chunk_data_size: int):
if self.header.chunk_hdr_sz > SPARSE_CHUNK_HEADER_SIZE:
self._fd.seek(self.header.chunk_hdr_sz - SPARSE_CHUNK_HEADER_SIZE, 1)
return self._fd.read(chunk_data_size)
def unsparse(self):
if not self.header:
self._fd.seek(0)
self.header = SparseHeader(self._fd.read(SPARSE_HEADER_SIZE))
chunks = self.header.total_chunks
self._fd.seek(self.header.file_hdr_sz - SPARSE_HEADER_SIZE, 1)
unsparse_file_dir = os.path.dirname(self._fd.name)
unsparse_file = os.path.join(unsparse_file_dir,
"{}.unsparse.img".format(os.path.splitext(os.path.basename(self._fd.name))[0]))
with open(str(unsparse_file), 'wb') as out:
sector_base = 82528
output_len = 0
while chunks > 0:
chunk_header = SparseChunkHeader(self._fd.read(SPARSE_CHUNK_HEADER_SIZE))
sector_size = (chunk_header.chunk_sz * self.header.blk_sz) >> 9
chunk_data_size = chunk_header.total_sz - self.header.chunk_hdr_sz
if chunk_header.chunk_type == 0xCAC1:
data = self._read_data(chunk_data_size)
len_data = len(data)
if len_data == (sector_size << 9):
out.write(data)
output_len += len_data
sector_base += sector_size
else:
if chunk_header.chunk_type == 0xCAC2:
data = self._read_data(chunk_data_size)
len_data = sector_size << 9
out.write(struct.pack("B", 0) * len_data)
output_len += len(data)
sector_base += sector_size
else:
if chunk_header.chunk_type == 0xCAC3:
data = self._read_data(chunk_data_size)
len_data = sector_size << 9
out.write(struct.pack("B", 0) * len_data)
output_len += len(data)
sector_base += sector_size
else:
len_data = sector_size << 9
out.write(struct.pack("B", 0) * len_data)
sector_base += sector_size
chunks -= 1
return unsparse_file
T = TypeVar('T')
class LpUnpack(object):
def __init__(self, **kwargs):
self._partition_name = kwargs.get('NAME')
self._show_info = kwargs.get('SHOW_INFO', True)
self._show_info_format = kwargs.get('SHOW_INFO_FORMAT', FormatType.TEXT)
self._config = kwargs.get('CONFIG', None)
self._slot_num = None
self._fd: BinaryIO = open(kwargs.get('SUPER_IMAGE'), 'rb')
self._out_dir = kwargs.get('OUTPUT_DIR', None)
def _check_out_dir_exists(self):
if self._out_dir is None:
return
if not os.path.exists(self._out_dir):
os.makedirs(self._out_dir, exist_ok=True)
def _extract_partition(self, unpack_job: UnpackJob):
self._check_out_dir_exists()
start = dti()
print(f'Extracting partition [{unpack_job.name}]')
out_file = os.path.join(self._out_dir, f'{unpack_job.name}.img')
with open(str(out_file), 'wb') as out:
for part in unpack_job.parts:
offset, size = part
self._write_extent_to_file(out, offset, size, unpack_job.geometry.logical_block_size)
print('Done:[%s]' % (dti() - start))
def _extract(self, partition, metadata):
unpack_job = UnpackJob(name=partition.name, geometry=metadata.geometry)
if partition.num_extents != 0:
for extent_number in range(partition.num_extents):
index = partition.first_extent_index + extent_number
extent = metadata.extents[index]
if extent.target_type != LP_TARGET_TYPE_LINEAR:
raise LpUnpackError(f'Unsupported target type in extent: {extent.target_type}')
offset = extent.target_data * LP_SECTOR_SIZE
size = extent.num_sectors * LP_SECTOR_SIZE
unpack_job.parts.append((offset, size))
unpack_job.total_size += size
self._extract_partition(unpack_job)
def _get_data(self, count: int, size: int, clazz: T) -> List[T]:
result = []
while count > 0:
result.append(clazz(self._fd.read(size)))
count -= 1
return result
def _read_chunk(self, block_size):
while True:
data = self._fd.read(block_size)
if not data:
break
yield data
def _read_metadata_header(self, metadata: Metadata):
offsets = metadata.get_offsets()
for index, offset in enumerate(offsets):
self._fd.seek(offset, io.SEEK_SET)
header = LpMetadataHeader(self._fd.read(80))
header.partitions = LpMetadataTableDescriptor(self._fd.read(12))
header.extents = LpMetadataTableDescriptor(self._fd.read(12))
header.groups = LpMetadataTableDescriptor(self._fd.read(12))
header.block_devices = LpMetadataTableDescriptor(self._fd.read(12))
if header.magic != LP_METADATA_HEADER_MAGIC:
check_index = index + 1
if check_index > len(offsets):
raise LpUnpackError('Logical partition metadata has invalid magic value.')
else:
print(f'Read Backup header by offset 0x{offsets[check_index]:x}')
continue
metadata.header = header
self._fd.seek(offset + header.header_size, io.SEEK_SET)
def _read_metadata(self):
self._fd.seek(LP_PARTITION_RESERVED_BYTES, io.SEEK_SET)
metadata = Metadata(geometry=self._read_primary_geometry())
if metadata.geometry.magic != LP_METADATA_GEOMETRY_MAGIC:
raise LpUnpackError('Logical partition metadata has invalid geometry magic signature.')
if metadata.geometry.metadata_slot_count == 0:
raise LpUnpackError('Logical partition metadata has invalid slot count.')
if metadata.geometry.metadata_max_size % LP_SECTOR_SIZE != 0:
raise LpUnpackError('Metadata max size is not sector-aligned.')
self._read_metadata_header(metadata)
metadata.partitions = self._get_data(
metadata.header.partitions.num_entries,
metadata.header.partitions.entry_size,
LpMetadataPartition
)
metadata.extents = self._get_data(
metadata.header.extents.num_entries,
metadata.header.extents.entry_size,
LpMetadataExtent
)
metadata.groups = self._get_data(
metadata.header.groups.num_entries,
metadata.header.groups.entry_size,
LpMetadataPartitionGroup
)
metadata.block_devices = self._get_data(
metadata.header.block_devices.num_entries,
metadata.header.block_devices.entry_size,
LpMetadataBlockDevice
)
try:
super_device: LpMetadataBlockDevice = cast(LpMetadataBlockDevice, iter(metadata.block_devices).__next__())
if metadata.metadata_region > super_device.first_logical_sector * LP_SECTOR_SIZE:
raise LpUnpackError('Logical partition metadata overlaps with logical partition contents.')
except StopIteration:
raise LpUnpackError('Metadata does not specify a super device.')
return metadata
def _read_primary_geometry(self) -> LpMetadataGeometry:
geometry = LpMetadataGeometry(self._fd.read(LP_METADATA_GEOMETRY_SIZE))
if geometry is not None:
return geometry
else:
return LpMetadataGeometry(self._fd.read(LP_METADATA_GEOMETRY_SIZE))
def _write_extent_to_file(self, fd: IO, offset: int, size: int, block_size: int):
self._fd.seek(offset)
for block in self._read_chunk(block_size):
if size == 0:
break
fd.write(block)
size -= block_size
def unpack(self):
try:
if SparseImage(self._fd).check():
print('Sparse image detected.')
print('Process conversion to non sparse image...')
unsparse_file = SparseImage(self._fd).unsparse()
self._fd.close()
self._fd = open(str(unsparse_file), 'rb')
print('Result:[ok]')
self._fd.seek(0)
metadata = self._read_metadata()
if self._partition_name:
filter_partition = []
for index, partition in enumerate(metadata.partitions):
if partition.name in self._partition_name:
filter_partition.append(partition)
if not filter_partition:
raise LpUnpackError(f'Could not find partition: {self._partition_name}')
metadata.partitions = filter_partition
if self._slot_num:
if self._slot_num > metadata.geometry.metadata_slot_count:
raise LpUnpackError(f'Invalid metadata slot number: {self._slot_num}')
if self._show_info:
if self._show_info_format == FormatType.TEXT:
print(metadata)
elif self._show_info_format == FormatType.JSON:
print(f"{metadata.to_json()}\n")
if not self._show_info and self._out_dir is None:
raise LpUnpackError(message=f'Not specified directory for extraction')
if self._out_dir:
for partition in metadata.partitions:
self._extract(partition, metadata)
except LpUnpackError as e:
print(e.message)
sys.exit(1)
finally:
self._fd.close()
def create_parser():
_parser = argparse.ArgumentParser(
description=f'{os.path.basename(sys.argv[0])} - command-line tool for extracting partition images from super'
)
_parser.add_argument(
'-p',
'--partition',
dest='NAME',
type=lambda x: re.split("\W+", x),
help='Extract the named partition. This can be specified multiple times or through the delimiter ["," ":"]'
)
_parser.add_argument(
'-S',
'--slot',
dest='NUM',
type=int,
help=' !!! No implementation yet !!! Slot number (default is 0).'
)
if sys.version_info >= (3, 9):
_parser.add_argument(
'--info',
dest='SHOW_INFO',
default=False,
action=argparse.BooleanOptionalAction,
help='Displays pretty-printed partition metadata'
)
else:
_parser.add_argument(
'--info',
dest='SHOW_INFO',
action='store_true',
help='Displays pretty-printed partition metadata'
)
_parser.add_argument(
'--no-info',
dest='SHOW_INFO',
action='store_false'
)
_parser.set_defaults(SHOW_INFO=False)
_parser.add_argument(
'-f',
'--format',
dest='SHOW_INFO_FORMAT',
type=FormatType,
action=EnumAction,
default=FormatType.TEXT,
help='Choice the format for printing info'
)
_parser.add_argument('SUPER_IMAGE')
_parser.add_argument(
'OUTPUT_DIR',
type=str,
nargs='?',
)
return _parser
def unpack(file: str, out: str):
_parser = argparse.ArgumentParser()
_parser.add_argument('--SUPER_IMAGE', default=file)
_parser.add_argument('--OUTPUT_DIR', default=out)
_parser.add_argument('--SHOW_INFO', default=False)
namespace = _parser.parse_args()
if not os.path.exists(namespace.SUPER_IMAGE):
raise FileNotFoundError("%s Cannot Find" % namespace.SUPER_IMAGE)
else:
LpUnpack(**vars(namespace)).unpack()
def main():
parser = create_parser()
namespace = parser.parse_args()
if len(sys.argv) >= 2:
if not os.path.exists(namespace.SUPER_IMAGE):
return 2
LpUnpack(**vars(namespace)).unpack()
else:
return 1

975
mkdtboimg.py Normal file
View File

@ -0,0 +1,975 @@
#! /usr/bin/env python
# Copyright 2017, The Android Open Source Project
#
# 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.
from __future__ import print_function
"""Tool for packing multiple DTB/DTBO files into a single image"""
import argparse
import fnmatch
import os
import struct
import zlib
from array import array
from collections import namedtuple
from sys import stdout
class CompressionFormat(object):
"""Enum representing DT compression format for a DT entry.
"""
NO_COMPRESSION = 0x00
ZLIB_COMPRESSION = 0x01
GZIP_COMPRESSION = 0x02
class DtEntry(object):
"""Provides individual DT image file arguments to be added to a DTBO.
Attributes:
REQUIRED_KEYS_V0: 'keys' needed to be present in the dictionary passed to instantiate
an object of this class when a DTBO header of version 0 is used.
REQUIRED_KEYS_V1: 'keys' needed to be present in the dictionary passed to instantiate
an object of this class when a DTBO header of version 1 is used.
COMPRESSION_FORMAT_MASK: Mask to retrieve compression info for DT entry from flags field
when a DTBO header of version 1 is used.
"""
COMPRESSION_FORMAT_MASK = 0x0f
REQUIRED_KEYS_V0 = ('dt_file', 'dt_size', 'dt_offset', 'id', 'rev',
'custom0', 'custom1', 'custom2', 'custom3')
REQUIRED_KEYS_V1 = ('dt_file', 'dt_size', 'dt_offset', 'id', 'rev',
'flags', 'custom0', 'custom1', 'custom2')
@staticmethod
def __get_number_or_prop(arg):
"""Converts string to integer or reads the property from DT image.
Args:
arg: String containing the argument provided on the command line.
Returns:
An integer property read from DT file or argument string
converted to integer
"""
if not arg or arg[0] == '+' or arg[0] == '-':
raise ValueError('Invalid argument passed to DTImage')
if arg[0] == '/':
# TODO(b/XXX): Use pylibfdt to get property value from DT
raise ValueError('Invalid argument passed to DTImage')
else:
base = 10
if arg.startswith('0x') or arg.startswith('0X'):
base = 16
elif arg.startswith('0'):
base = 8
return int(arg, base)
def __init__(self, **kwargs):
"""Constructor for DtEntry object.
Initializes attributes from dictionary object that contains
values keyed with names equivalent to the class's attributes.
Args:
kwargs: Dictionary object containing values to instantiate
class members with. Expected keys in dictionary are from
the tuple (_REQUIRED_KEYS)
"""
self.__version = kwargs['version']
required_keys = None
if self.__version == 0:
required_keys = self.REQUIRED_KEYS_V0
elif self.__version == 1:
required_keys = self.REQUIRED_KEYS_V1
missing_keys = set(required_keys) - set(kwargs)
if missing_keys:
raise ValueError('Missing keys in DtEntry constructor: %r' %
sorted(missing_keys))
self.__dt_file = kwargs['dt_file']
self.__dt_offset = kwargs['dt_offset']
self.__dt_size = kwargs['dt_size']
self.__id = self.__get_number_or_prop(kwargs['id'])
self.__rev = self.__get_number_or_prop(kwargs['rev'])
if self.__version == 1:
self.__flags = self.__get_number_or_prop(kwargs['flags'])
self.__custom0 = self.__get_number_or_prop(kwargs['custom0'])
self.__custom1 = self.__get_number_or_prop(kwargs['custom1'])
self.__custom2 = self.__get_number_or_prop(kwargs['custom2'])
if self.__version == 0:
self.__custom3 = self.__get_number_or_prop(kwargs['custom3'])
def __str__(self):
sb = []
sb.append('{key:>20} = {value:d}'.format(key='dt_size',
value=self.__dt_size))
sb.append('{key:>20} = {value:d}'.format(key='dt_offset',
value=self.__dt_offset))
sb.append('{key:>20} = {value:08x}'.format(key='id',
value=self.__id))
sb.append('{key:>20} = {value:08x}'.format(key='rev',
value=self.__rev))
if self.__version == 1:
sb.append('{key:>20} = {value:08x}'.format(key='flags',
value=self.__flags))
sb.append('{key:>20} = {value:08x}'.format(key='custom[0]',
value=self.__custom0))
sb.append('{key:>20} = {value:08x}'.format(key='custom[1]',
value=self.__custom1))
sb.append('{key:>20} = {value:08x}'.format(key='custom[2]',
value=self.__custom2))
if self.__version == 0:
sb.append('{key:>20} = {value:08x}'.format(key='custom[3]',
value=self.__custom3))
return '\n'.join(sb)
def compression_info(self):
"""CompressionFormat: compression format for DT image file.
Args:
version: Version of DTBO header, compression is only
supported from version 1.
"""
if self.__version == 0:
return CompressionFormat.NO_COMPRESSION
return self.flags & self.COMPRESSION_FORMAT_MASK
@property
def dt_file(self):
"""file: File handle to the DT image file."""
return self.__dt_file
@property
def size(self):
"""int: size in bytes of the DT image file."""
return self.__dt_size
@size.setter
def size(self, value):
self.__dt_size = value
@property
def dt_offset(self):
"""int: offset in DTBO file for this DT image."""
return self.__dt_offset
@dt_offset.setter
def dt_offset(self, value):
self.__dt_offset = value
@property
def image_id(self):
"""int: DT entry _id for this DT image."""
return self.__id
@property
def rev(self):
"""int: DT entry _rev for this DT image."""
return self.__rev
@property
def flags(self):
"""int: DT entry _flags for this DT image."""
return self.__flags
@property
def custom0(self):
"""int: DT entry _custom0 for this DT image."""
return self.__custom0
@property
def custom1(self):
"""int: DT entry _custom1 for this DT image."""
return self.__custom1
@property
def custom2(self):
"""int: DT entry custom2 for this DT image."""
return self.__custom2
@property
def custom3(self):
"""int: DT entry custom3 for this DT image."""
return self.__custom3
class Dtbo(object):
"""
Provides parser, reader, writer for dumping and creating Device Tree Blob
Overlay (DTBO) images.
Attributes:
_DTBO_MAGIC: Device tree table header magic.
_ACPIO_MAGIC: Advanced Configuration and Power Interface table header
magic.
_DT_TABLE_HEADER_SIZE: Size of Device tree table header.
_DT_TABLE_HEADER_INTS: Number of integers in DT table header.
_DT_ENTRY_HEADER_SIZE: Size of Device tree entry header within a DTBO.
_DT_ENTRY_HEADER_INTS: Number of integers in DT entry header.
_GZIP_COMPRESSION_WBITS: Argument 'wbits' for gzip compression
_ZLIB_DECOMPRESSION_WBITS: Argument 'wbits' for zlib/gzip compression
"""
_DTBO_MAGIC = 0xd7b7ab1e
_ACPIO_MAGIC = 0x41435049
_DT_TABLE_HEADER_SIZE = struct.calcsize('>8I')
_DT_TABLE_HEADER_INTS = 8
_DT_ENTRY_HEADER_SIZE = struct.calcsize('>8I')
_DT_ENTRY_HEADER_INTS = 8
_GZIP_COMPRESSION_WBITS = 31
_ZLIB_DECOMPRESSION_WBITS = 47
def _update_dt_table_header(self):
"""Converts header entries into binary data for DTBO header.
Packs the current Device tree table header attribute values in
metadata buffer.
"""
struct.pack_into('>8I', self.__metadata, 0, self.magic,
self.total_size, self.header_size,
self.dt_entry_size, self.dt_entry_count,
self.dt_entries_offset, self.page_size,
self.version)
def _update_dt_entry_header(self, dt_entry, metadata_offset):
"""Converts each DT entry header entry into binary data for DTBO file.
Packs the current device tree table entry attribute into
metadata buffer as device tree entry header.
Args:
dt_entry: DtEntry object for the header to be packed.
metadata_offset: Offset into metadata buffer to begin writing.
dtbo_offset: Offset where the DT image file for this dt_entry can
be found in the resulting DTBO image.
"""
if self.version == 0:
struct.pack_into('>8I', self.__metadata, metadata_offset, dt_entry.size,
dt_entry.dt_offset, dt_entry.image_id, dt_entry.rev,
dt_entry.custom0, dt_entry.custom1, dt_entry.custom2,
dt_entry.custom3)
elif self.version == 1:
struct.pack_into('>8I', self.__metadata, metadata_offset, dt_entry.size,
dt_entry.dt_offset, dt_entry.image_id, dt_entry.rev,
dt_entry.flags, dt_entry.custom0, dt_entry.custom1,
dt_entry.custom2)
def _update_metadata(self):
"""Updates the DTBO metadata.
Initialize the internal metadata buffer and fill it with all Device
Tree table entries and update the DTBO header.
"""
self.__metadata = array('b', b' ' * self.__metadata_size)
metadata_offset = self.header_size
for dt_entry in self.__dt_entries:
self._update_dt_entry_header(dt_entry, metadata_offset)
metadata_offset += self.dt_entry_size
self._update_dt_table_header()
def _read_dtbo_header(self, buf):
"""Reads DTBO file header into metadata buffer.
Unpack and read the DTBO table header from given buffer. The
buffer size must exactly be equal to _DT_TABLE_HEADER_SIZE.
Args:
buf: Bytebuffer read directly from the file of size
_DT_TABLE_HEADER_SIZE.
"""
(self.magic, self.total_size, self.header_size,
self.dt_entry_size, self.dt_entry_count, self.dt_entries_offset,
self.page_size, self.version) = struct.unpack_from('>8I', buf, 0)
# verify the header
if self.magic != self._DTBO_MAGIC and self.magic != self._ACPIO_MAGIC:
raise ValueError('Invalid magic number 0x%x in DTBO/ACPIO file' %
self.magic)
if self.header_size != self._DT_TABLE_HEADER_SIZE:
raise ValueError('Invalid header size (%d) in DTBO/ACPIO file' %
self.header_size)
if self.dt_entry_size != self._DT_ENTRY_HEADER_SIZE:
raise ValueError('Invalid DT entry header size (%d) in DTBO/ACPIO file' %
self.dt_entry_size)
def _read_dt_entries_from_metadata(self):
"""Reads individual DT entry headers from metadata buffer.
Unpack and read the DTBO DT entry headers from the internal buffer.
The buffer size must exactly be equal to _DT_TABLE_HEADER_SIZE +
(_DT_ENTRY_HEADER_SIZE * dt_entry_count). The method raises exception
if DT entries have already been set for this object.
"""
if self.__dt_entries:
raise ValueError('DTBO DT entries can be added only once')
offset = self.dt_entries_offset // 4
params = {}
params['version'] = self.version
params['dt_file'] = None
for i in range(0, self.dt_entry_count):
dt_table_entry = self.__metadata[offset:offset + self._DT_ENTRY_HEADER_INTS]
params['dt_size'] = dt_table_entry[0]
params['dt_offset'] = dt_table_entry[1]
for j in range(2, self._DT_ENTRY_HEADER_INTS):
required_keys = None
if self.version == 0:
required_keys = DtEntry.REQUIRED_KEYS_V0
elif self.version == 1:
required_keys = DtEntry.REQUIRED_KEYS_V1
params[required_keys[j + 1]] = str(dt_table_entry[j])
dt_entry = DtEntry(**params)
self.__dt_entries.append(dt_entry)
offset += self._DT_ENTRY_HEADER_INTS
def _read_dtbo_image(self):
"""Parse the input file and instantiate this object."""
# First check if we have enough to read the header
file_size = os.fstat(self.__file.fileno()).st_size
if file_size < self._DT_TABLE_HEADER_SIZE:
raise ValueError('Invalid DTBO file')
self.__file.seek(0)
buf = self.__file.read(self._DT_TABLE_HEADER_SIZE)
self._read_dtbo_header(buf)
self.__metadata_size = (self.header_size +
self.dt_entry_count * self.dt_entry_size)
if file_size < self.__metadata_size:
raise ValueError('Invalid or truncated DTBO file of size %d expected %d' %
file_size, self.__metadata_size)
num_ints = (self._DT_TABLE_HEADER_INTS +
self.dt_entry_count * self._DT_ENTRY_HEADER_INTS)
if self.dt_entries_offset > self._DT_TABLE_HEADER_SIZE:
num_ints += (self.dt_entries_offset - self._DT_TABLE_HEADER_SIZE) / 4
format_str = '>' + str(num_ints) + 'I'
self.__file.seek(0)
self.__metadata = struct.unpack(format_str,
self.__file.read(self.__metadata_size))
self._read_dt_entries_from_metadata()
def _find_dt_entry_with_same_file(self, dt_entry):
"""Finds DT Entry that has identical backing DT file.
Args:
dt_entry: DtEntry object whose 'dtfile' we find for existence in the
current 'dt_entries'.
Returns:
If a match by file path is found, the corresponding DtEntry object
from internal list is returned. If not, 'None' is returned.
"""
dt_entry_path = os.path.realpath(dt_entry.dt_file.name)
for entry in self.__dt_entries:
entry_path = os.path.realpath(entry.dt_file.name)
if entry_path == dt_entry_path:
return entry
return None
def __init__(self, file_handle, dt_type='dtb', page_size=None, version=0):
"""Constructor for Dtbo Object
Args:
file_handle: The Dtbo File handle corresponding to this object.
The file handle can be used to write to (in case of 'create')
or read from (in case of 'dump')
"""
self.__file = file_handle
self.__dt_entries = []
self.__metadata = None
self.__metadata_size = 0
# if page_size is given, assume the object is being instantiated to
# create a DTBO file
if page_size:
if dt_type == 'acpi':
self.magic = self._ACPIO_MAGIC
else:
self.magic = self._DTBO_MAGIC
self.total_size = self._DT_TABLE_HEADER_SIZE
self.header_size = self._DT_TABLE_HEADER_SIZE
self.dt_entry_size = self._DT_ENTRY_HEADER_SIZE
self.dt_entry_count = 0
self.dt_entries_offset = self._DT_TABLE_HEADER_SIZE
self.page_size = page_size
self.version = version
self.__metadata_size = self._DT_TABLE_HEADER_SIZE
else:
self._read_dtbo_image()
def __str__(self):
sb = []
sb.append('dt_table_header:')
_keys = ('magic', 'total_size', 'header_size', 'dt_entry_size',
'dt_entry_count', 'dt_entries_offset', 'page_size', 'version')
for key in _keys:
if key == 'magic':
sb.append('{key:>20} = {value:08x}'.format(key=key,
value=self.__dict__[key]))
else:
sb.append('{key:>20} = {value:d}'.format(key=key,
value=self.__dict__[key]))
count = 0
for dt_entry in self.__dt_entries:
sb.append('dt_table_entry[{0:d}]:'.format(count))
sb.append(str(dt_entry))
count = count + 1
return '\n'.join(sb)
@property
def dt_entries(self):
"""Returns a list of DtEntry objects found in DTBO file."""
return self.__dt_entries
def compress_dt_entry(self, compression_format, dt_entry_file):
"""Compresses a DT entry.
Args:
compression_format: Compression format for DT Entry
dt_entry_file: File handle to read DT entry from.
Returns:
Compressed DT entry and its length.
Raises:
ValueError if unrecognized compression format is found.
"""
compress_zlib = zlib.compressobj() # zlib
compress_gzip = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED, self._GZIP_COMPRESSION_WBITS) # gzip
compression_obj_dict = {
CompressionFormat.NO_COMPRESSION: None,
CompressionFormat.ZLIB_COMPRESSION: compress_zlib,
CompressionFormat.GZIP_COMPRESSION: compress_gzip,
}
if compression_format not in compression_obj_dict:
ValueError("Bad compression format %d" % compression_format)
if compression_format is CompressionFormat.NO_COMPRESSION:
dt_entry = dt_entry_file.read()
else:
compression_object = compression_obj_dict[compression_format]
dt_entry_file.seek(0)
dt_entry = compression_object.compress(dt_entry_file.read())
dt_entry += compression_object.flush()
return dt_entry, len(dt_entry)
def add_dt_entries(self, dt_entries):
"""Adds DT image files to the DTBO object.
Adds a list of Dtentry Objects to the DTBO image. The changes are not
committed to the output file until commit() is called.
Args:
dt_entries: List of DtEntry object to be added.
Returns:
A buffer containing all DT entries.
Raises:
ValueError: if the list of DT entries is empty or if a list of DT entries
has already been added to the DTBO.
"""
if not dt_entries:
raise ValueError('Attempted to add empty list of DT entries')
if self.__dt_entries:
raise ValueError('DTBO DT entries can be added only once')
dt_entry_count = len(dt_entries)
dt_offset = (self.header_size +
dt_entry_count * self.dt_entry_size)
dt_entry_buf = b""
for dt_entry in dt_entries:
if not isinstance(dt_entry, DtEntry):
raise ValueError('Adding invalid DT entry object to DTBO')
entry = self._find_dt_entry_with_same_file(dt_entry)
dt_entry_compression_info = dt_entry.compression_info()
if entry and (entry.compression_info() == dt_entry_compression_info):
dt_entry.dt_offset = entry.dt_offset
dt_entry.size = entry.size
else:
dt_entry.dt_offset = dt_offset
compressed_entry, dt_entry.size = self.compress_dt_entry(dt_entry_compression_info,
dt_entry.dt_file)
dt_entry_buf += compressed_entry
dt_offset += dt_entry.size
self.total_size += dt_entry.size
self.__dt_entries.append(dt_entry)
self.dt_entry_count += 1
self.__metadata_size += self.dt_entry_size
self.total_size += self.dt_entry_size
return dt_entry_buf
def extract_dt_file(self, idx, fout, decompress):
"""Extract DT Image files embedded in the DTBO file.
Extracts Device Tree blob image file at given index into a file handle.
Args:
idx: Index of the DT entry in the DTBO file.
fout: File handle where the DTB at index idx to be extracted into.
decompress: If a DT entry is compressed, decompress it before writing
it to the file handle.
Raises:
ValueError: if invalid DT entry index or compression format is detected.
"""
if idx > self.dt_entry_count:
raise ValueError('Invalid index %d of DtEntry' % idx)
size = self.dt_entries[idx].size
offset = self.dt_entries[idx].dt_offset
self.__file.seek(offset, 0)
fout.seek(0)
compression_format = self.dt_entries[idx].compression_info()
if decompress and compression_format:
if (compression_format == CompressionFormat.ZLIB_COMPRESSION or
compression_format == CompressionFormat.GZIP_COMPRESSION):
fout.write(zlib.decompress(self.__file.read(size), self._ZLIB_DECOMPRESSION_WBITS))
else:
raise ValueError("Unknown compression format detected")
else:
fout.write(self.__file.read(size))
def commit(self, dt_entry_buf):
"""Write out staged changes to the DTBO object to create a DTBO file.
Writes a fully instantiated Dtbo Object into the output file using the
file handle present in '_file'. No checks are performed on the object
except for existence of output file handle on the object before writing
out the file.
Args:
dt_entry_buf: Buffer containing all DT entries.
"""
if not self.__file:
raise ValueError('No file given to write to.')
if not self.__dt_entries:
raise ValueError('No DT image files to embed into DTBO image given.')
self._update_metadata()
self.__file.seek(0)
self.__file.write(self.__metadata)
self.__file.write(dt_entry_buf)
self.__file.flush()
def parse_dt_entry(global_args, arglist):
"""Parse arguments for single DT entry file.
Parses command line arguments for single DT image file while
creating a Device tree blob overlay (DTBO).
Args:
global_args: Dtbo object containing global default values
for DtEntry attributes.
arglist: Command line argument list for this DtEntry.
Returns:
A Namespace object containing all values to instantiate DtEntry object.
"""
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('dt_file', nargs='?',
type=argparse.FileType('rb'),
default=None)
parser.add_argument('--id', type=str, dest='id', action='store',
default=global_args.id)
parser.add_argument('--rev', type=str, dest='rev',
action='store', default=global_args.rev)
parser.add_argument('--flags', type=str, dest='flags',
action='store',
default=global_args.flags)
parser.add_argument('--custom0', type=str, dest='custom0',
action='store',
default=global_args.custom0)
parser.add_argument('--custom1', type=str, dest='custom1',
action='store',
default=global_args.custom1)
parser.add_argument('--custom2', type=str, dest='custom2',
action='store',
default=global_args.custom2)
parser.add_argument('--custom3', type=str, dest='custom3',
action='store',
default=global_args.custom3)
return parser.parse_args(arglist)
def parse_dt_entries(global_args, arg_list):
"""Parse all DT entries from command line.
Parse all DT image files and their corresponding attribute from
command line
Args:
global_args: Argument containing default global values for _id,
_rev and customX.
arg_list: The remainder of the command line after global options
DTBO creation have been parsed.
Returns:
A List of DtEntry objects created after parsing the command line
given in argument.
"""
dt_entries = []
img_file_idx = []
idx = 0
# find all positional arguments (i.e. DT image file paths)
for arg in arg_list:
if not arg.startswith("--"):
img_file_idx.append(idx)
idx = idx + 1
if not img_file_idx:
raise ValueError('Input DT images must be provided')
total_images = len(img_file_idx)
for idx in range(total_images):
start_idx = img_file_idx[idx]
if idx == total_images - 1:
argv = arg_list[start_idx:]
else:
end_idx = img_file_idx[idx + 1]
argv = arg_list[start_idx:end_idx]
args = parse_dt_entry(global_args, argv)
params = vars(args)
params['version'] = global_args.version
params['dt_offset'] = 0
params['dt_size'] = os.fstat(params['dt_file'].fileno()).st_size
dt_entries.append(DtEntry(**params))
return dt_entries
def parse_config_option(line, is_global, dt_keys, global_key_types):
"""Parses a single line from the configuration file.
Args:
line: String containing the key=value line from the file.
is_global: Boolean indicating if we should parse global or DT entry
specific option.
dt_keys: Tuple containing all valid DT entry and global option strings
in configuration file.
global_key_types: A dict of global options and their corresponding types. It
contains all exclusive valid global option strings in configuration
file that are not repeated in dt entry options.
Returns:
Returns a tuple for parsed key and value for the option. Also, checks
the key to make sure its valid.
"""
if line.find('=') == -1:
raise ValueError('Invalid line (%s) in configuration file' % line)
key, value = (x.strip() for x in line.split('='))
if is_global and key in global_key_types:
if global_key_types[key] is int:
value = int(value)
elif key not in dt_keys:
raise ValueError('Invalid option (%s) in configuration file' % key)
return key, value
def parse_config_file(fin, dt_keys, global_key_types):
"""Parses the configuration file for creating DTBO image.
Args:
fin: File handle for configuration file
is_global: Boolean indicating if we should parse global or DT entry
specific option.
dt_keys: Tuple containing all valid DT entry and global option strings
in configuration file.
global_key_types: A dict of global options and their corresponding types. It
contains all exclusive valid global option strings in configuration
file that are not repeated in dt entry options.
Returns:
global_args, dt_args: Tuple of a dictionary with global arguments
and a list of dictionaries for all DT entry specific arguments the
following format.
global_args:
{'id' : <value>, 'rev' : <value> ...}
dt_args:
[{'filename' : 'dt_file_name', 'id' : <value>,
'rev' : <value> ...},
{'filename' : 'dt_file_name2', 'id' : <value2>,
'rev' : <value2> ...}, ...
]
"""
# set all global defaults
global_args = dict((k, '0') for k in dt_keys)
global_args['dt_type'] = 'dtb'
global_args['page_size'] = 2048
global_args['version'] = 0
dt_args = []
found_dt_entry = False
count = -1
for line in fin:
line = line.rstrip()
if line.lstrip().startswith('#'):
continue
comment_idx = line.find('#')
line = line if comment_idx == -1 else line[0:comment_idx]
if not line or line.isspace():
continue
if line.startswith((' ', '\t')) and not found_dt_entry:
# This is a global argument
key, value = parse_config_option(line, True, dt_keys, global_key_types)
global_args[key] = value
elif line.find('=') != -1:
key, value = parse_config_option(line, False, dt_keys, global_key_types)
dt_args[-1][key] = value
else:
found_dt_entry = True
count += 1
dt_args.append({})
dt_args[-1]['filename'] = line.strip()
return global_args, dt_args
def parse_config_create_cmd_args(arglist):
"""Parse command line arguments for 'cfg_create subcommand.
Args:
arglist: A list of all command line arguments including the
mandatory input configuration file name.
Returns:
A Namespace object of parsed arguments.
"""
parser = argparse.ArgumentParser(prog='cfg_create')
parser.add_argument('conf_file', nargs='?',
type=argparse.FileType('r'),
default=None)
cwd = os.getcwd()
parser.add_argument('--dtb-dir', '-d', nargs='?', type=str,
dest='dtbdir', default=cwd)
return parser.parse_args(arglist)
def create_dtbo_image(fout, list, page_size=2048, version=0, dt_type='dtb', id="0", rev="0", flags='0', custom0='0',
custom1='0', custom2='0', custom3='0'):
"""Create Device Tree Blob Overlay image using provided arguments.
Args:
fout: Output file handle to write to.
argv: list of command line arguments.
"""
if not list:
raise ValueError('List of dtimages to add to DTBO not provided')
parser = argparse.ArgumentParser()
parser.add_argument('--id',type=str,default=id,action='store')
parser.add_argument('--rev',type=str,default=rev,action='store')
parser.add_argument('--flags',type=str,default=flags,action='store')
parser.add_argument('--custom0',type=str,default=custom0,action='store')
parser.add_argument('--custom1',type=str,default=custom1,action='store')
parser.add_argument('--custom2',type=str,default=custom2,action='store')
parser.add_argument('--custom3',type=str,default=custom3,action='store')
parser.add_argument('--version', type=int, default=version, action='store')
global_args = parser.parse_args()
dt_entries = parse_dt_entries(global_args, list)
dtbo = Dtbo(fout, dt_type, page_size, version)
dt_entry_buf = dtbo.add_dt_entries(dt_entries)
dtbo.commit(dt_entry_buf)
fout.close()
def dump_dtbo_image(fin, dtfilename, decompress=False, outfile=stdout):
"""Dump DTBO file.
Dump Device Tree Blob Overlay metadata as output and the device
tree image files embedded in the DTBO image into file(s) provided
as arguments
Args:
fin: Input DTBO image files.
argv: list of command line arguments.
"""
dtbo = Dtbo(fin)
if dtfilename:
num_entries = len(dtbo.dt_entries)
for idx in range(0, num_entries):
with open(dtfilename + '.{:d}'.format(idx), 'wb') as fout:
dtbo.extract_dt_file(idx, fout, decompress)
outfile.write(str(dtbo) + '\n')
outfile.close()
def create_dtbo_image_from_config(fout, argv):
"""Create DTBO file from a configuration file.
Args:
fout: Output file handle to write to.
argv: list of command line arguments.
"""
args = parse_config_create_cmd_args(argv)
if not args.conf_file:
raise ValueError('Configuration file must be provided')
_DT_KEYS = ('id', 'rev', 'flags', 'custom0', 'custom1', 'custom2', 'custom3')
_GLOBAL_KEY_TYPES = {'dt_type': str, 'page_size': int, 'version': int}
global_args, dt_args = parse_config_file(args.conf_file,
_DT_KEYS, _GLOBAL_KEY_TYPES)
version = global_args['version']
params = {}
params['version'] = version
dt_entries = []
for dt_arg in dt_args:
filepath = dt_arg['filename']
if not os.path.isabs(filepath):
for root, dirnames, filenames in os.walk(args.dtbdir):
for filename in fnmatch.filter(filenames, os.path.basename(filepath)):
filepath = os.path.join(root, filename)
params['dt_file'] = open(filepath, 'rb')
params['dt_offset'] = 0
params['dt_size'] = os.fstat(params['dt_file'].fileno()).st_size
for key in _DT_KEYS:
if key not in dt_arg:
params[key] = global_args[key]
else:
params[key] = dt_arg[key]
dt_entries.append(DtEntry(**params))
# Create and write DTBO file
dtbo = Dtbo(fout, global_args['dt_type'], global_args['page_size'], version)
dt_entry_buf = dtbo.add_dt_entries(dt_entries)
dtbo.commit(dt_entry_buf)
fout.close()
def print_default_usage(progname):
"""Prints program's default help string.
Args:
progname: This program's name.
"""
sb = []
sb.append(' ' + progname + ' help all')
sb.append(' ' + progname + ' help <command>\n')
sb.append(' commands:')
sb.append(' help, dump, create, cfg_create')
print('\n'.join(sb))
def print_dump_usage(progname):
"""Prints usage for 'dump' sub-command.
Args:
progname: This program's name.
"""
sb = []
sb.append(' ' + progname + ' dump <image_file> (<option>...)\n')
sb.append(' options:')
sb.append(' -o, --output <filename> Output file name.')
sb.append(' Default is output to stdout.')
sb.append(' -b, --dtb <filename> Dump dtb/dtbo files from image.')
sb.append(' Will output to <filename>.0, <filename>.1, etc.')
print('\n'.join(sb))
def print_cfg_create_usage(progname):
"""Prints usage for 'cfg_create' sub-command.
Args:
progname: This program's name.
"""
sb = []
sb.append(' ' + progname + ' cfg_create <image_file> <config_file> (<option>...)\n')
sb.append(' options:')
sb.append(' -d, --dtb-dir <dir> The path to load dtb files.')
sb.append(' Default is load from the current path.')
print('\n'.join(sb))
def print_usage(cmd, _):
"""Prints usage for this program.
Args:
cmd: The string sub-command for which help (usage) is requested.
"""
prog_name = os.path.basename(__file__)
if not cmd:
print_default_usage(prog_name)
return
HelpCommand = namedtuple('HelpCommand', 'help_cmd, help_func')
help_commands = (HelpCommand('dump'),
HelpCommand('create'),
HelpCommand('cfg_create'),
)
if cmd == 'all':
print_default_usage(prog_name)
for help_cmd, help_func in help_commands:
if cmd == 'all' or cmd == help_cmd:
help_func(prog_name)
if cmd != 'all':
return
print('Unsupported help command: %s' % cmd, end='\n\n')
print_default_usage(prog_name)
return
def main():
"""Main entry point for mkdtboimg."""
parser = argparse.ArgumentParser(prog='mkdtboimg.py')
subparser = parser.add_subparsers(title='subcommand',
description='Valid subcommands')
config_parser = subparser.add_parser('cfg_create', add_help=False)
config_parser.add_argument('argfile', nargs='?',
action='store',
type=argparse.FileType('wb'))
config_parser.set_defaults(func=create_dtbo_image_from_config)
(subcmd, subcmd_args) = parser.parse_known_args()
subcmd.func(subcmd.argfile, subcmd_args)
def dump_dtbo(file, out):
with open(file, 'rb') as f:
dump_dtbo_image(f, out)
def create_dtbo(out, list,page_size):
with open(out, 'wb') as f:
create_dtbo_image(f, list, page_size)

179
ofp_mtk_decrypt.py Normal file
View File

@ -0,0 +1,179 @@
#!/usr/bin/env python3
# Oppo OFP MTK Decrypter (c) B. Kerler 2022
# Licensed under MIT License
import os
import sys
import hashlib
from Crypto.Cipher import AES
from struct import unpack
from binascii import unhexlify, hexlify
def swap(ch):
return ((ch & 0xF) << 4) + ((ch & 0xF0) >> 4)
def keyshuffle(key, hkey):
for i in range(0, 0x10, 4):
key[i] = swap((hkey[i] ^ key[i]))
key[i + 1] = swap(hkey[i + 1] ^ key[i + 1])
key[i + 2] = swap(hkey[i + 2] ^ key[i + 2])
key[i + 3] = swap(hkey[i + 3] ^ key[i + 3])
return key
def mtk_shuffle(key, keylength, input, inputlength):
for i in range(0, inputlength):
k = key[(i % keylength)]
h = ((((input[i]) & 0xF0) >> 4) | (16 * ((input[i]) & 0xF)))
input[i] = k ^ h
return input
def mtk_shuffle2(key, keylength, input, inputlength):
for i in range(0, inputlength):
tmp = key[i % keylength] ^ input[i]
input[i] = ((tmp & 0xF0) >> 4) | (16 * (tmp & 0xF))
return input
def aes_cfb(key, iv, data, decrypt=True, segment_size=128):
cipher = AES.new(key, AES.MODE_CFB, IV=iv, segment_size=segment_size)
if decrypt:
plaintext = cipher.decrypt(data)
return plaintext
else:
ciphertext = cipher.encrypt(data)
return ciphertext
keytables = [
["67657963787565E837D226B69A495D21", # A77 CPH1715EX_11_A.04_170426, F1S A1601_MT6750_EX_11_A.15_160913 FW
"F6C50203515A2CE7D8C3E1F938B7E94C",
"42F2D5399137E2B2813CD8ECDF2F4D72"],
["9E4F32639D21357D37D226B69A495D21", # A77 CPH1715EX_11_A.04_170426, F1S A1601_MT6750_EX_11_A.15_160913 CDT
"A3D8D358E42F5A9E931DD3917D9A3218",
"386935399137416B67416BECF22F519A"],
["892D57E92A4D8A975E3C216B7C9DE189",
"D26DF2D9913785B145D18C7219B89F26",
"516989E4A1BFC78B365C6BC57D944391"],
["27827963787265EF89D126B69A495A21",
"82C50203285A2CE7D8C3E198383CE94C",
"422DD5399181E223813CD8ECDF2E4D72"],
["3C4A618D9BF2E4279DC758CD535147C3",
"87B13D29709AC1BF2382276C4E8DF232",
"59B7A8E967265E9BCABE2469FE4A915E"],
["1C3288822BF824259DC852C1733127D3", # A83_CPH1827_11_A.21_2G_180923 FW, Realme 3 RMX1827EX_11_C.13_200624_1264686e
"E7918D22799181CF2312176C9E2DF298",
"3247F889A7B6DECBCA3E28693E4AAAFE"],
["1E4F32239D65A57D37D2266D9A775D43",
"A332D3C3E42F5A3E931DD991729A321D",
"3F2A35399A373377674155ECF28FD19A"],
["122D57E92A518AFF5E3C786B7C34E189",
"DD6DF2D9543785674522717219989FB0",
"12698965A132C76136CC88C5DD94EE91"],
[
"ab3f76d7989207f2", # AES KEY
"2bf515b3a9737835" # AES IV
]
]
def getkey(index):
kt = keytables[index]
if len(kt) == 3:
obskey = bytearray(unhexlify(kt[0]))
encaeskey = bytearray(unhexlify(kt[1]))
encaesiv = bytearray(unhexlify(kt[2]))
aeskey = hexlify(hashlib.md5(mtk_shuffle2(obskey, 16, encaeskey, 16)).digest())[:16]
aesiv = hexlify(hashlib.md5(mtk_shuffle2(obskey, 16, encaesiv, 16)).digest())[:16]
else:
aeskey = bytes(kt[0], 'utf-8')
aesiv = bytes(kt[1], 'utf-8')
print(aeskey, aesiv)
return aeskey, aesiv
def brutekey(rf):
rf.seek(0)
encdata = rf.read(16)
for keyid in range(0, len(keytables)):
aeskey, aesiv = getkey(keyid)
data = aes_cfb(aeskey, aesiv, encdata, True)
if data[:3] == b"MMM":
return aeskey, aesiv
print("Unknown key. Please ask the author for support :)")
exit(0)
def cleancstring(input):
return input.replace(b"\x00", b"").decode('utf-8')
def main(filename, outdir):
if not os.path.exists(outdir):
os.mkdir(outdir)
hdrkey = bytearray(b"geyixue")
filesize = os.stat(filename).st_size
hdrlength = 0x6C
with open(filename, 'rb') as rf:
aeskey, aesiv = brutekey(rf)
rf.seek(filesize - hdrlength)
hdr = mtk_shuffle(hdrkey, len(hdrkey), bytearray(rf.read(hdrlength)), hdrlength)
prjname, unknownval, reserved, cpu, flashtype, hdr2entries, prjinfo, crc = unpack("46s Q 4s 7s 5s H 32s H", hdr)
hdr2length = hdr2entries * 0x60
prjname = cleancstring(prjname)
prjinfo = cleancstring(prjinfo)
cpu = cleancstring(cpu)
flashtype = cleancstring(flashtype)
if prjname != "": print(f"Detected prjname:{prjname}")
if prjinfo != "": print(f"Detected prjinfo:{prjinfo}")
if cpu != "": print(f"Detected cpu:{cpu}")
if flashtype != "": print(f"Detected flash:{flashtype}")
rf.seek(filesize - hdr2length - hdrlength)
hdr2 = mtk_shuffle(hdrkey, len(hdrkey), bytearray(rf.read(hdr2length)), hdr2length)
for i in range(0, len(hdr2) // 0x60):
name, start, length, enclength, filename, crc = unpack("<32s Q Q Q 32s Q", hdr2[i * 0x60:(i * 0x60) + 0x60])
name = name.replace(b"\x00", b"").decode('utf-8')
filename = filename.replace(b"\x00", b"").decode('utf-8')
print(f"Writing \"{name}\" as \"{outdir}/{filename}\"...")
with open(os.path.join(outdir, filename), 'wb') as wb:
if enclength > 0:
rf.seek(start)
encdata = rf.read(enclength)
if enclength % 16 != 0:
encdata += b"\x00" * (16 - (enclength % 16))
data = aes_cfb(aeskey, aesiv, encdata, True)
wb.write(data[:enclength])
length -= enclength
while length > 0:
size = 0x200000
if length < size:
size = length
data = rf.read(size)
length -= size
wb.write(data)
print(f"Files successfully decrypted to subdirectory {outdir}")
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Oppo MTK OFP decrypt tool 1.1 (c) B.Kerler 2020-2022\n")
print("Usage: %s <filename> <directory to extract>" % __file__)
sys.exit(1)
filename = sys.argv[1]
outdir = sys.argv[2]
main(filename, outdir)

365
ofp_qc_decrypt.py Normal file
View File

@ -0,0 +1,365 @@
#!/usr/bin/env python3
# (c) B.Kerler 2018-2021, MIT license
import os
import sys
import xml.etree.ElementTree as ET
import zipfile
from struct import unpack
from binascii import unhexlify, hexlify
from Crypto.Cipher import AES
import hashlib
import shutil
def swap(ch):
return ((ch & 0xF) << 4) + ((ch & 0xF0) >> 4)
def keyshuffle(key, hkey):
for i in range(0, 0x10, 4):
key[i] = swap((hkey[i] ^ key[i]))
key[i + 1] = swap(hkey[i + 1] ^ key[i + 1])
key[i + 2] = swap(hkey[i + 2] ^ key[i + 2])
key[i + 3] = swap(hkey[i + 3] ^ key[i + 3])
return key
def ROL(x, n, bits=32):
n = bits - n
mask = (2 ** n) - 1
mask_bits = x & mask
return (x >> n) | (mask_bits << (bits - n))
def generatekey1():
key1 = "42F2D5399137E2B2813CD8ECDF2F4D72"
key2 = "F6C50203515A2CE7D8C3E1F938B7E94C"
key3 = "67657963787565E837D226B69A495D21"
key1 = bytearray.fromhex(key1)
key2 = bytearray.fromhex(key2)
key3 = bytearray.fromhex(key3)
key2 = keyshuffle(key2, key3)
aeskey = bytes(hashlib.md5(key2).hexdigest()[0:16], 'utf-8')
key1 = keyshuffle(key1, key3)
iv = bytes(hashlib.md5(key1).hexdigest()[0:16], 'utf-8')
return aeskey, iv
def deobfuscate(data, mask):
ret = bytearray()
for i in range(0, len(data)):
v = ROL((data[i] ^ mask[i]), 4, 8)
ret.append(v)
return ret
def generatekey2(filename):
keys = [
# R9s/A57t
["V1.4.17/1.4.27",
"27827963787265EF89D126B69A495A21",
"82C50203285A2CE7D8C3E198383CE94C",
"422DD5399181E223813CD8ECDF2E4D72"],
# a3s
["V1.6.17",
"E11AA7BB558A436A8375FD15DDD4651F",
"77DDF6A0696841F6B74782C097835169",
"A739742384A44E8BA45207AD5C3700EA"],
["V1.5.13",
"67657963787565E837D226B69A495D21",
"F6C50203515A2CE7D8C3E1F938B7E94C",
"42F2D5399137E2B2813CD8ECDF2F4D72"],
# R15 Pro CPH1831 V1.6.6 / FindX CPH1871 V1.6.9 / R17 Pro CPH1877 V1.6.17 / R17 PBEM00 V1.6.17 / A5 2020 V1.7.6 / K3 CPH1955 V1.6.26 UFS
# Reno 5G CPH1921 V1.6.26 / Realme 3 Pro RMX1851 V1.6.17 / Reno 10X Zoom V1.6.26 / R17 CPH1879 V1.6.17 / R17 Neo CPH1893 / K1 PBCM30
["V1.6.6/1.6.9/1.6.17/1.6.24/1.6.26/1.7.6",
"3C2D518D9BF2E4279DC758CD535147C3",
"87C74A29709AC1BF2382276C4E8DF232",
"598D92E967265E9BCABE2469FE4A915E"],
# RM1921EX V1.7.2, Realme X RMX1901 V1.7.2, Realme 5 Pro RMX1971 V1.7.2, Realme 5 RMX1911 V1.7.2
["V1.7.2",
"8FB8FB261930260BE945B841AEFA9FD4",
"E529E82B28F5A2F8831D860AE39E425D",
"8A09DA60ED36F125D64709973372C1CF"],
# OW19W8AP_11_A.23_200715
["V2.0.3",
"E8AE288C0192C54BF10C5707E9C4705B",
"D64FC385DCD52A3C9B5FBA8650F92EDA",
"79051FD8D8B6297E2E4559E997F63B7F"]
]
for dkey in keys:
key = bytearray()
iv = bytearray()
# "Read metadata failed"
mc = bytearray.fromhex(dkey[1])
userkey = bytearray.fromhex(dkey[2])
ivec = bytearray.fromhex(dkey[3])
# userkey=bytearray(unhexlify("A3D8D358E42F5A9E931DD3917D9A3218"))
# ivec=bytearray(unhexlify("386935399137416B67416BECF22F519A"))
# mc=bytearray(unhexlify("9E4F32639D21357D37D226B69A495D21"))
key = (hashlib.md5(deobfuscate(userkey, mc)).hexdigest()[0:16]).encode()
iv = (hashlib.md5(deobfuscate(ivec, mc)).hexdigest()[0:16]).encode()
pagesize, data = extract_xml(filename, key, iv)
if pagesize != 0:
return pagesize, key, iv, data
return 0, None, None, None
def extract_xml(filename, key, iv):
filesize = os.stat(filename).st_size
with open(filename, 'rb') as rf:
pagesize = 0
for x in [0x200, 0x1000]:
rf.seek(filesize - x + 0x10)
if unpack("<I", rf.read(4))[0] == 0x7CEF:
pagesize = x
break
if pagesize == 0:
print("Unknown pagesize. Aborting")
exit(0)
xmloffset = filesize - pagesize
rf.seek(xmloffset + 0x14)
offset = unpack("<I", rf.read(4))[0] * pagesize
length = unpack("<I", rf.read(4))[0]
if length < 200: # A57 hack
length = xmloffset - offset - 0x57
rf.seek(offset)
data = rf.read(length)
dec = aes_cfb(data, key, iv)
# h=MD5.new()
# h.update(data)
# print(dec.decode('utf-8'))
# print(h.hexdigest())
# print("Done.")
if b"<?xml" in dec:
return pagesize, dec
else:
return 0, ""
def aes_cfb(data, key, iv):
ctx = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
decrypted = ctx.decrypt(data)
return decrypted
def copysub(rf, wf, start, length):
rf.seek(start)
rlen = 0
while length > 0:
if length < 0x100000:
size = length
else:
size = 0x100000
data = rf.read(size)
wf.write(data)
rlen += len(data)
length -= size
return rlen
def copy(filename, wfilename, path, start, length, checksums):
print(f"\nExtracting {wfilename}")
with open(filename, 'rb') as rf:
with open(os.path.join(path, wfilename), 'wb') as wf:
rf.seek(start)
data = rf.read(length)
wf.write(data)
checkhashfile(os.path.join(path, wfilename), checksums, True)
def decryptfile(key, iv, filename, path, wfilename, start, length, rlength, checksums, decryptsize=0x40000):
print(f"\nExtracting {wfilename}")
if rlength == length:
tlen = length
length = (length // 0x4 * 0x4)
if tlen % 0x4 != 0:
length += 0x4
with open(filename, 'rb') as rf:
with open(os.path.join(path, wfilename), 'wb') as wf:
rf.seek(start)
size = decryptsize
if rlength < decryptsize:
size = rlength
data = rf.read(size)
if size % 4:
data += (4 - (size % 4)) * b'\x00'
outp = aes_cfb(data, key, iv)
wf.write(outp[:size])
if rlength > decryptsize:
copysub(rf, wf, start + size, rlength - size)
if rlength % 0x1000 != 0:
fill = bytearray([0x00 for i in range(0x1000 - (rlength % 0x1000))])
# wf.write(fill)
checkhashfile(os.path.join(path, wfilename), checksums, False)
def checkhashfile(wfilename, checksums, iscopy):
sha256sum = checksums[0]
md5sum = checksums[1]
if iscopy:
prefix = "Copy: "
else:
prefix = "Decrypt: "
with open(wfilename, "rb") as rf:
size = os.stat(wfilename).st_size
md5 = hashlib.md5(rf.read(0x40000))
sha256bad = False
md5bad = False
md5status = "empty"
sha256status = "empty"
if sha256sum != "":
for x in [0x40000, size]:
rf.seek(0)
# sha256 = hashlib.sha256(rf.read(x))
sha256 = hashlib.sha256()
if x == 0x40000:
sha256.update(rf.read(x))
if x == size:
for chunk in iter(lambda: rf.read(128 * sha256.block_size), b''):
sha256.update(chunk)
if sha256sum != sha256.hexdigest():
sha256bad = True
sha256status = "bad"
else:
sha256status = "verified"
break
if md5sum != "":
if md5sum != md5.hexdigest():
md5bad = True
md5status = "bad"
else:
md5status = "verified"
if (sha256bad and md5bad) or (sha256bad and md5sum == "") or (md5bad and sha256sum == ""):
print(f"{prefix}error on hashes. File might be broken!")
else:
print(f"{prefix}success! (md5: {md5status} | sha256: {sha256status})")
def decryptitem(item, pagesize):
sha256sum = ""
md5sum = ""
wfilename = ""
start = -1
rlength = 0
decryptsize = 0x40000
if "Path" in item.attrib:
wfilename = item.attrib["Path"]
elif "filename" in item.attrib:
wfilename = item.attrib["filename"]
if "sha256" in item.attrib:
sha256sum = item.attrib["sha256"]
if "md5" in item.attrib:
md5sum = item.attrib["md5"]
if "FileOffsetInSrc" in item.attrib:
start = int(item.attrib["FileOffsetInSrc"]) * pagesize
elif "SizeInSectorInSrc" in item.attrib:
start = int(item.attrib["SizeInSectorInSrc"]) * pagesize
if "SizeInByteInSrc" in item.attrib:
rlength = int(item.attrib["SizeInByteInSrc"])
if "SizeInSectorInSrc" in item.attrib:
length = int(item.attrib["SizeInSectorInSrc"]) * pagesize
else:
length = rlength
return wfilename, start, length, rlength, [sha256sum, md5sum], decryptsize
def main(filename, outdir):
if not os.path.exists(outdir):
os.mkdir(outdir)
pk = False
with open(filename, "rb") as rf:
if rf.read(2) == b"PK":
pk = True
if pk == True:
print("Zip file detected, trying to decrypt files")
zippw = bytes("flash@realme$50E7F7D847732396F1582CD62DD385ED7ABB0897", 'utf-8')
with zipfile.ZipFile(filename) as file:
for zfile in file.namelist():
print("Extracting " + zfile + " to " + outdir)
file.extract(zfile, pwd=zippw, path=outdir)
print("Files extracted to " + outdir)
exit(0)
# key,iv=generatekey1()
pagesize, key, iv, data = generatekey2(filename)
if pagesize == 0:
print("Unknown key. Aborting")
exit(0)
else:
xml = data[:data.rfind(b">") + 1].decode('utf-8')
if "/" in filename:
path = filename[:filename.rfind("/")]
elif "\\" in filename:
path = filename[:filename.rfind("\\")]
else:
path = ""
path = os.path.join(path, outdir)
if os.path.exists(path):
shutil.rmtree(path)
os.mkdir(path)
else:
os.mkdir(path)
print("Saving ProFile.xml")
file_handle = open(path + os.sep + "ProFile.xml", mode="w")
file_handle.write(xml)
file_handle.close()
root = ET.fromstring(xml)
for child in root:
for item in child:
if "Path" not in item.attrib and "filename" not in item.attrib:
for subitem in item:
wfilename, start, length, rlength, checksums, decryptsize = decryptitem(subitem, pagesize)
if wfilename == "" or start == -1:
continue
decryptfile(key, iv, filename, path, wfilename, start, length, rlength, checksums, decryptsize)
wfilename, start, length, rlength, checksums, decryptsize = decryptitem(item, pagesize)
if wfilename == "" or start == -1:
continue
if child.tag in ["Sahara"]:
decryptsize = rlength
if child.tag in ["Config", "Provision", "ChainedTableOfDigests", "DigestsToSign", "Firmware"]:
length = rlength
if child.tag in ["DigestsToSign", "ChainedTableOfDigests", "Firmware"]:
copy(filename, wfilename, path, start, length, checksums)
else:
decryptfile(key, iv, filename, path, wfilename, start, length, rlength, checksums, decryptsize)
print("\nDone. Extracted files to " + path)
exit(0)
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Oppo MTK QC decrypt tool 1.1 (c) B.Kerler 2020-2022\n")
print("Usage: ./ofp_qc_extract.py [Filename.ofp] [Directory to extract files to]")
sys.exit(1)
filename_ = sys.argv[1]
outdir_ = sys.argv[2]
main(filename_, outdir_)

318
ozipdecrypt.py Normal file
View File

@ -0,0 +1,318 @@
#!/usr/bin/env python3
# (c) B. Kerler 2017-2020, licensed under MIT license
"""
Usage:
ozipdecrypt.py --help
ozipdecrypt.py <filename>
Options:
Mode 1 for regular ozip, Mode 2 for CPH1803/CPH1909 [default: 1]
"""
import os
import stat
import shutil
import binascii
from Crypto.Cipher import AES
import zipfile
from os.path import basename
def main(file_arg):
keys = [
"D6EECF0AE5ACD4E0E9FE522DE7CE381E", # mnkey
"D6ECCF0AE5ACD4E0E92E522DE7C1381E", # mkey
"D6DCCF0AD5ACD4E0292E522DB7C1381E",
# realkey, R9s CPH1607 MSM8953, Plus, R11, RMX1921 Realme XT, RMX1851EX Realme Android 10, RMX1992EX_11_OTA_1050
"D7DCCE1AD4AFDCE2393E5161CBDC4321", # testkey
"D7DBCE2AD4ADDCE1393E5521CBDC4321", # utilkey
"D7DBCE1AD4AFDCE1393E5121CBDC4321", # R11s CPH1719 MSM8976, Plus
"D4D2CD61D4AFDCE13B5E01221BD14D20", # FindX CPH1871 SDM845
"261CC7131D7C1481294E532DB752381E", # FindX
"1CA21E12271335AE33AB81B2A7B14622", # Realme 2 pro SDM660/MSM8976
"D4D2CE11D4AFDCE13B3E0121CBD14D20", # K1 SDM660/MSM8976
"1C4C1EA3A12531AE491B21BB31613C11", # Realme 3 Pro SDM710, X, 5 Pro, Q, RMX1921 Realme XT
"1C4C1EA3A12531AE4A1B21BB31C13C21", # Reno 10x zoom PCCM00 SDM855, CPH1921EX Reno 5G
"1C4A11A3A12513AE441B23BB31513121", # Reno 2 PCKM00 SDM730G
"1C4A11A3A12589AE441A23BB31517733", # Realme X2 SDM730G
"1C4A11A3A22513AE541B53BB31513121", # Realme 5 SDM665
"2442CE821A4F352E33AE81B22BC1462E", # R17 Pro SDM710
"14C2CD6214CFDC2733AE81B22BC1462C", # CPH1803 OppoA3s SDM450/MSM8953
"1E38C1B72D522E29E0D4ACD50ACFDCD6",
"12341EAAC4C123CE193556A1BBCC232D",
"2143DCCB21513E39E1DCAFD41ACEDBD7",
"2D23CCBBA1563519CE23C1C4AA1E3412", # A77 CPH1715 MT6750T
"172B3E14E46F3CE13E2B5121CBDC4321", # Realme 1 MTK P60
"ACAA1E12A71431CE4A1B21BBA1C1C6A2", # Realme U1 RMX1831 MTK P70
"ACAC1E13A72531AE4A1B22BB31C1CC22", # Realme 3 RMX1825EX P70
"1C4411A3A12533AE441B21BB31613C11", # A1k CPH1923 MTK P22
"1C4416A8A42717AE441523B336513121", # Reno 3 PCRM00 MTK 1000L, CPH2059 OPPO A92, CPH2067 OPPO A72
"55EEAA33112133AE441B23BB31513121", # RenoAce SDM855Plus
"ACAC1E13A12531AE4A1B21BB31C13C21", # Reno, K3
"ACAC1E13A72431AE4A1B22BBA1C1C6A2", # A9
"12CAC11211AAC3AEA2658690122C1E81", # A1,A83t
"1CA21E12271435AE331B81BBA7C14612", # CPH1909 OppoA5s MT6765
"D1DACF24351CE428A9CE32ED87323216", # Realme1(reserved)
"A1CC75115CAECB890E4A563CA1AC67C8", # A73(reserved)
"2132321EA2CA86621A11241ABA512722", # Realme3(reserved)
"22A21E821743E5EE33AE81B227B1462E"
# F3 Plus CPH1613 - MSM8976
]
def keytest(data):
for key in keys:
ctx = AES.new(binascii.unhexlify(key), AES.MODE_ECB)
dat = ctx.decrypt(data)
if dat[0:4] == b'\x50\x4B\x03\x04':
print("Found correct AES key: " + key)
return binascii.unhexlify(key)
elif dat[0:4] == b'\x41\x56\x42\x30':
print("Found correct AES key: " + key)
return binascii.unhexlify(key)
elif dat[0:4] == b'\x41\x4E\x44\x52':
print("Found correct AES key: " + key)
return binascii.unhexlify(key)
return -1
def del_rw(action, name, exc):
os.chmod(name, stat.S_IWRITE)
os.remove(name)
def rmrf(path):
if os.path.exists(path):
if os.path.isfile(path):
del_rw("", path, "")
else:
shutil.rmtree(path, onerror=del_rw)
def decryptfile(key, rfilename):
with open(rfilename, 'rb') as rr:
with open(rfilename + ".tmp", 'wb') as wf:
rr.seek(0x10)
dsize = int(rr.read(0x10).replace(b"\x00", b"").decode('utf-8'), 10)
rr.seek(0x1050)
flen = os.stat(rfilename).st_size - 0x1050
ctx = AES.new(key, AES.MODE_ECB)
while dsize > 0:
if flen > 0x4000:
size = 0x4000
else:
size = flen
data = rr.read(size)
if dsize < size:
size = dsize
if len(data) == 0:
break
dr = ctx.decrypt(data)
wf.write(dr[:size])
flen -= size
dsize -= size
os.remove(rfilename)
os.rename(rfilename + ".tmp", rfilename)
def decryptfile2(key, rfilename, wfilename):
with open(rfilename, 'rb') as rr:
with open(wfilename, 'wb') as wf:
ctx = AES.new(key, AES.MODE_ECB)
bstart = 0
goon = True
while goon:
rr.seek(bstart)
header = rr.read(12)
if len(header) == 0:
break
if header != b"OPPOENCRYPT!":
return 1
rr.seek(0x10 + bstart)
bdsize = int(rr.read(0x10).replace(b"\x00", b"").decode('utf-8'), 10)
if bdsize < 0x40000:
goon = False
rr.seek(0x50 + bstart)
while bdsize > 0:
data = rr.read(0x10)
if len(data) == 0:
break
size = 0x10
if bdsize < 0x10:
size = bdsize
dr = ctx.decrypt(data)
wf.write(dr[:size])
bdsize -= 0x10
data = rr.read(0x3FF0)
if len(data) == 0:
break
bdsize -= 0x3FF0
wf.write(data)
bstart = bstart + 0x40000 + 0x50
return 0
def mode2(filename):
temp = os.path.join(os.path.abspath(os.path.dirname(filename)), "temp")
out = os.path.join(os.path.abspath(os.path.dirname(filename)), "out")
with open(filename, 'rb') as fr:
magic = fr.read(12)
if magic[:2] == b"PK":
with zipfile.ZipFile(file_arg, 'r') as zipObj:
if os.path.exists(temp):
rmrf(temp)
os.mkdir(temp)
if os.path.exists(out):
rmrf(out)
os.mkdir(out)
print("Finding key... " + file_arg)
for zi in zipObj.infolist():
orgfilename = zi.filename
if "boot.img" in orgfilename:
zi.filename = "out"
zipObj.extract(zi, temp)
zi.filename = orgfilename
with open(os.path.join(temp, "out"), 'rb') as rr:
magic = rr.read(12)
if magic == b"OPPOENCRYPT!":
rr.seek(0x50)
data = rr.read(16)
key = keytest(data)
if key == -1:
print("Unknown AES key, reverse key from recovery first!")
return 1
else:
break
else:
print("Unknown mode2, boot.img wasn't encrypted")
break
print("Extracting... " + file_arg)
outzip = filename[:-4] + 'zip'
if os.path.exists(outzip):
os.remove(outzip)
with zipfile.ZipFile(outzip, 'w', zipfile.ZIP_DEFLATED) as WzipObj:
for zi in zipObj.infolist():
orgfilename = zi.filename
zi.filename = "out"
zipObj.extract(zi, temp)
zi.filename = orgfilename
with open(os.path.join(temp, "out"), 'rb') as rr:
magic = rr.read(12)
if magic == b"OPPOENCRYPT!":
print("Decrypting " + orgfilename)
if decryptfile2(key, os.path.join(temp, "out"),
os.path.join(temp, "out") + ".dec") == 1:
return 1
WzipObj.write(os.path.join(temp, "out") + ".dec", orgfilename)
os.remove(os.path.join(temp, "out"))
os.remove(os.path.join(temp, "out") + ".dec")
else:
WzipObj.write(os.path.join(temp, "out"), orgfilename)
os.remove(os.path.join(temp, "out"))
rmrf(temp)
print("DONE... file decrypted to: " + outzip)
return 0
print("ozipdecrypt 1.32 (c) B.Kerler 2017-2022")
filename = file_arg
with open(filename, 'rb') as fr:
magic = fr.read(12)
if magic == b"OPPOENCRYPT!":
pk = False
elif magic[:2] == b"PK":
pk = True
else:
print("ozip has unknown magic, OPPOENCRYPT! expected!")
return 1
if not pk:
fr.seek(0x1050)
data = fr.read(16)
key = keytest(data)
if key == -1:
print("Unknown AES key, reverse key from recovery first!")
return 1
ctx = AES.new(key, AES.MODE_ECB)
filename = file_arg[:-4] + "zip"
with open(filename, 'wb') as wf:
fr.seek(0x1050)
print("Decrypting...")
while True:
data = fr.read(16)
if len(data) == 0:
break
wf.write(ctx.decrypt(data))
data = fr.read(0x4000)
if len(data) == 0:
break
wf.write(data)
print("DONE!!")
else:
testkey = True
filename = os.path.abspath(file_arg)
path = os.path.abspath(os.path.dirname(filename))
outpath = os.path.join(path, "tmp")
if os.path.exists(outpath):
shutil.rmtree(outpath)
os.mkdir(outpath)
with zipfile.ZipFile(filename, 'r') as zo:
clist = []
try:
if zo.extract('oppo_metadata', outpath):
with open(os.path.join(outpath, 'oppo_metadata')) as rt:
for line in rt:
clist.append(line[:-1])
except Exception as e:
print(str(e))
print("Detected mode 2....")
return mode2(filename)
if testkey:
fname = ''
if "firmware-update/vbmeta.img" in clist:
fname = "firmware-update/vbmeta.img"
elif "vbmeta.img" in clist:
fname = 'vbmeta.img'
if fname != '':
if zo.extract(fname, outpath):
with open(os.path.join(outpath, fname.replace("/", os.sep)), "rb") as rt:
rt.seek(0x1050)
data = rt.read(16)
key = keytest(data)
if key == -1:
print("Unknown AES key, reverse key from recovery first!")
return 1
testkey = False
if testkey:
print("Unknown image, please report an issue with image name!")
return 1
outzip = filename[:-4] + 'zip'
with zipfile.ZipFile(outzip, 'w', zipfile.ZIP_DEFLATED) as WzipObj:
for info in zo.infolist():
print("Extracting " + info.filename)
orgfilename = info.filename
info.filename = "out"
zo.extract(info, outpath)
info.filename = orgfilename
if len(clist) > 0:
if info.filename in clist:
print("Decrypting " + info.filename)
decryptfile(key, os.path.join(outpath, "out"))
else:
with open(os.path.join(outpath, "out"), 'rb') as rr:
magic = rr.read(12)
if magic == b"OPPOENCRYPT!":
decryptfile(key, os.path.join(outpath, "out"))
WzipObj.write(os.path.join(outpath, "out"), orgfilename)
rmrf(os.path.join(outpath, "out"))
print("DONE... files decrypted to: " + outzip)
return 0
if __name__ == '__main__':
import sys, argparse
parser = argparse.ArgumentParser(description="ozipdecrypt 1.3 (c) B.Kerler 2017-2021", add_help=False)
required = parser.add_argument_group('Required')
required.add_argument("filename", help="Path to ozip file")
optional = parser.add_argument_group('Optional')
optional.add_argument("-h", "--help", action="help", help="Show this help message and exit")
args = parser.parse_args()
sys.exit(main(args.filename))

166
payload_dumper.py Normal file
View File

@ -0,0 +1,166 @@
#!/usr/bin/env python3
import struct
import hashlib
import bz2
import sys
import argparse
import bsdiff4
import io
import os
import lzma
import threading
import update_metadata_pb2 as um
import timeit
flatten = lambda l: [item for sublist in l for item in sublist]
def CallZ(func, *args): # 传入函数名和参数
# 创建线程
t = threading.Thread(target=func, args=args)
t.daemon = True
t.start()
def u32(x):
return struct.unpack('>I', x)[0]
def u64(x):
return struct.unpack('>Q', x)[0]
def verify_contiguous(exts):
blocks = 0
for ext in exts:
if ext.start_block != blocks:
return False
blocks += ext.num_blocks
return True
def data_for_op(op, out_file, old_file):
args.payloadfile.seek(data_offset + op.data_offset)
data = args.payloadfile.read(op.data_length)
# assert hashlib.sha256(data).digest() == op.data_sha256_hash, 'operation data hash mismatch'
if op.type == op.REPLACE_XZ:
dec = lzma.LZMADecompressor()
data = dec.decompress(data)
out_file.seek(op.dst_extents[0].start_block * block_size)
out_file.write(data)
elif op.type == op.REPLACE_BZ:
dec = bz2.BZ2Decompressor()
data = dec.decompress(data)
out_file.seek(op.dst_extents[0].start_block * block_size)
out_file.write(data)
elif op.type == op.REPLACE:
out_file.seek(op.dst_extents[0].start_block * block_size)
out_file.write(data)
elif op.type == op.SOURCE_COPY:
if not args.diff:
print("SOURCE_COPY supported only for differential OTA")
sys.exit(-2)
out_file.seek(op.dst_extents[0].start_block * block_size)
for ext in op.src_extents:
old_file.seek(ext.start_block * block_size)
data = old_file.read(ext.num_blocks * block_size)
out_file.write(data)
elif op.type == op.SOURCE_BSDIFF:
if not args.diff:
print("SOURCE_BSDIFF supported only for differential OTA")
sys.exit(-3)
out_file.seek(op.dst_extents[0].start_block * block_size)
tmp_buff = io.BytesIO()
for ext in op.src_extents:
old_file.seek(ext.start_block * block_size)
old_data = old_file.read(ext.num_blocks * block_size)
tmp_buff.write(old_data)
tmp_buff.seek(0)
old_data = tmp_buff.read()
tmp_buff.seek(0)
tmp_buff.write(bsdiff4.patch(old_data, data))
n = 0;
tmp_buff.seek(0)
for ext in op.dst_extents:
tmp_buff.seek(n * block_size)
n += ext.num_blocks
data = tmp_buff.read(ext.num_blocks * block_size)
out_file.seek(ext.start_block * block_size)
out_file.write(data)
elif op.type == op.ZERO:
for ext in op.dst_extents:
out_file.seek(ext.start_block * block_size)
out_file.write(b'\x00' * ext.num_blocks * block_size)
else:
print("Unsupported type = %d" % op.type)
sys.exit(-1)
return data
def dump_part(part):
start = timeit.default_timer()
if os.access(args.out + part.partition_name + ".img", os.F_OK):
print(part.partition_name + "已存在")
else:
print("%s:[EXTRACTING]" % part.partition_name)
out_file = open('%s/%s.img' % (args.out, part.partition_name), 'wb')
h = hashlib.sha256()
if args.diff:
old_file = open('%s/%s.img' % (args.old, part.partition_name), 'rb')
else:
old_file = None
for op in part.operations:
data = data_for_op(op, out_file, old_file)
print("%s:[%s]" % (part.partition_name, timeit.default_timer() - start))
def ota_payload_dumper(payloadfile, out='output', diff='store_true', old='old', images='', command: int = 1):
parser = argparse.ArgumentParser(description='OTA payload dumper')
parser.add_argument('payloadfile', type=argparse.FileType('rb'))
parser.add_argument('--out', default=out)
parser.add_argument('--diff', action=diff)
parser.add_argument('--old', default=old)
parser.add_argument('--images', default=images)
global args
args = parser.parse_args([payloadfile])
if not os.path.exists(args.out):
os.makedirs(args.out)
magic = args.payloadfile.read(4)
assert magic == b'CrAU'
file_format_version = u64(args.payloadfile.read(8))
assert file_format_version == 2
manifest_size = u64(args.payloadfile.read(8))
metadata_signature_size = 0
if file_format_version > 1:
metadata_signature_size = u32(args.payloadfile.read(4))
manifest = args.payloadfile.read(manifest_size)
metadata_signature = args.payloadfile.read(metadata_signature_size)
global data_offset
data_offset = args.payloadfile.tell()
dam = um.DeltaArchiveManifest()
dam.ParseFromString(manifest)
global block_size
block_size = dam.block_size
if command == 0:
return dam.partitions
if args.images == "":
for part in dam.partitions:
dump_part(part)
else:
if ',' in args.images:
images = args.images.split(",")
else:
images = args.images
for image in images:
partition = [part for part in dam.partitions if part.partition_name == image]
if partition:
dump_part(partition[0])
else:
sys.stderr.write("Partition %s not found in payload!\n" % image)
args.payloadfile.close()

29
qc.py Normal file
View File

@ -0,0 +1,29 @@
from sys import argv
from os.path import exists
class handle:
def __init__(self, file_) -> None:
if not exists(file_):
return
self.file_ = file_
self.data = self.read_()
self.write(sorted(set(self.data), key=self.data.index))
def read_(self) -> Ellipsis:
with open(self.file_, 'r', encoding='utf-8') as f:
return f.readlines()
def write(self, new_data):
if len(new_data) == len(self.data):
print("No need to handle")
return 1
with open(self.file_, 'w+', encoding='utf-8', newline='\n') as f:
f.writelines(new_data)
if __name__ == "__main__":
if len(argv) < 2:
print("Usage: {} file".format(argv[0]))
else:
handle(argv[1])

308
rangelib.py Normal file
View File

@ -0,0 +1,308 @@
# Copyright (C) 2014 The Android Open Source Project
#
# 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.
from __future__ import print_function
import heapq
import itertools
__all__ = ["RangeSet"]
class RangeSet(object):
"""A RangeSet represents a set of nonoverlapping ranges on the
integers (ie, a set of integers, but efficient when the set contains
lots of runs."""
def __init__(self, data=None):
self.monotonic = False
if isinstance(data, str):
self._parse_internal(data)
elif data:
assert len(data) % 2 == 0
self.data = tuple(self._remove_pairs(data))
self.monotonic = all(x < y for x, y in zip(self.data, self.data[1:]))
else:
self.data = ()
def __iter__(self):
for i in range(0, len(self.data), 2):
yield self.data[i:i + 2]
def __eq__(self, other):
return self.data == other.data
def __ne__(self, other):
return self.data != other.data
def __nonzero__(self):
return bool(self.data)
def __str__(self):
if not self.data:
return "empty"
else:
return self.to_string()
def __repr__(self):
return '<RangeSet("' + self.to_string() + '")>'
@classmethod
def parse(cls, text):
"""Parse a text string consisting of a space-separated list of
blocks and ranges, eg "10-20 30 35-40". Ranges are interpreted to
include both their ends (so the above example represents 18
individual blocks. Returns a RangeSet object.
If the input has all its blocks in increasing order, then returned
RangeSet will have an extra attribute 'monotonic' that is set to
True. For example the input "10-20 30" is monotonic, but the input
"15-20 30 10-14" is not, even though they represent the same set
of blocks (and the two RangeSets will compare equal with ==).
"""
return cls(text)
def _parse_internal(self, text):
data = []
last = -1
monotonic = True
for p in text.split():
if "-" in p:
s, e = (int(x) for x in p.split("-"))
data.append(s)
data.append(e + 1)
if last <= s <= e:
last = e
else:
monotonic = False
else:
s = int(p)
data.append(s)
data.append(s + 1)
if last <= s:
last = s + 1
else:
monotonic = False
data.sort()
self.data = tuple(self._remove_pairs(data))
self.monotonic = monotonic
@staticmethod
def _remove_pairs(source):
"""Remove consecutive duplicate items to simplify the result.
[1, 2, 2, 5, 5, 10] will become [1, 10]."""
last = None
for i in source:
if i == last:
last = None
else:
if last is not None:
yield last
last = i
if last is not None:
yield last
def to_string(self):
out = []
for i in range(0, len(self.data), 2):
s, e = self.data[i:i + 2]
if e == s + 1:
out.append(str(s))
else:
out.append(str(s) + "-" + str(e - 1))
return " ".join(out)
def to_string_raw(self):
assert self.data
return str(len(self.data)) + "," + ",".join(str(i) for i in self.data)
def union(self, other):
"""Return a new RangeSet representing the union of this RangeSet
with the argument.
>>> RangeSet("10-19 30-34").union(RangeSet("18-29"))
<RangeSet("10-34")>
>>> RangeSet("10-19 30-34").union(RangeSet("22 32"))
<RangeSet("10-19 22 30-34")>
"""
out = []
z = 0
for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
zip(other.data, itertools.cycle((+1, -1)))):
if (z == 0 and d == 1) or (z == 1 and d == -1):
out.append(p)
z += d
return RangeSet(data=out)
def intersect(self, other):
"""Return a new RangeSet representing the intersection of this
RangeSet with the argument.
>>> RangeSet("10-19 30-34").intersect(RangeSet("18-32"))
<RangeSet("18-19 30-32")>
>>> RangeSet("10-19 30-34").intersect(RangeSet("22-28"))
<RangeSet("")>
"""
out = []
z = 0
for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
zip(other.data, itertools.cycle((+1, -1)))):
if (z == 1 and d == 1) or (z == 2 and d == -1):
out.append(p)
z += d
return RangeSet(data=out)
def subtract(self, other):
"""Return a new RangeSet representing subtracting the argument
from this RangeSet.
>>> RangeSet("10-19 30-34").subtract(RangeSet("18-32"))
<RangeSet("10-17 33-34")>
>>> RangeSet("10-19 30-34").subtract(RangeSet("22-28"))
<RangeSet("10-19 30-34")>
"""
out = []
z = 0
for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
zip(other.data, itertools.cycle((-1, +1)))):
if (z == 0 and d == 1) or (z == 1 and d == -1):
out.append(p)
z += d
return RangeSet(data=out)
def overlaps(self, other):
"""Returns true if the argument has a nonempty overlap with this
RangeSet.
>>> RangeSet("10-19 30-34").overlaps(RangeSet("18-32"))
True
>>> RangeSet("10-19 30-34").overlaps(RangeSet("22-28"))
False
"""
# This is like intersect, but we can stop as soon as we discover the
# output is going to be nonempty.
z = 0
for _, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))),
zip(other.data, itertools.cycle((+1, -1)))):
if (z == 1 and d == 1) or (z == 2 and d == -1):
return True
z += d
return False
def size(self):
"""Returns the total size of the RangeSet (ie, how many integers
are in the set).
>>> RangeSet("10-19 30-34").size()
15
"""
total = 0
for i, p in enumerate(self.data):
if i % 2:
total += p
else:
total -= p
return total
def map_within(self, other):
"""'other' should be a subset of 'self'. Returns a RangeSet
representing what 'other' would get translated to if the integers
of 'self' were translated down to be contiguous starting at zero.
>>> RangeSet("0-9").map_within(RangeSet("3-4"))
<RangeSet("3-4")>
>>> RangeSet("10-19").map_within(RangeSet("13-14"))
<RangeSet("3-4")>
>>> RangeSet("10-19 30-39").map_within(RangeSet("17-19 30-32"))
<RangeSet("7-12")>
>>> RangeSet("10-19 30-39").map_within(RangeSet("12-13 17-19 30-32"))
<RangeSet("2-3 7-12")>
"""
out = []
offset = 0
start = None
for p, d in heapq.merge(zip(self.data, itertools.cycle((-5, +5))),
zip(other.data, itertools.cycle((-1, +1)))):
if d == -5:
start = p
elif d == +5:
offset += p - start
start = None
else:
out.append(offset + p - start)
return RangeSet(data=out)
def extend(self, n):
"""Extend the RangeSet by 'n' blocks.
The lower bound is guaranteed to be non-negative.
>>> RangeSet("0-9").extend(1)
<RangeSet("0-10")>
>>> RangeSet("10-19").extend(15)
<RangeSet("0-34")>
>>> RangeSet("10-19 30-39").extend(4)
<RangeSet("6-23 26-43")>
>>> RangeSet("10-19 30-39").extend(10)
<RangeSet("0-49")>
"""
out = self
for i in range(0, len(self.data), 2):
s, e = self.data[i:i + 2]
s1 = max(0, s - n)
e1 = e + n
out = out.union(RangeSet(str(s1) + "-" + str(e1 - 1)))
return out
def first(self, n):
"""Return the RangeSet that contains at most the first 'n' integers.
>>> RangeSet("0-9").first(1)
<RangeSet("0")>
>>> RangeSet("10-19").first(5)
<RangeSet("10-14")>
>>> RangeSet("10-19").first(15)
<RangeSet("10-19")>
>>> RangeSet("10-19 30-39").first(3)
<RangeSet("10-12")>
>>> RangeSet("10-19 30-39").first(15)
<RangeSet("10-19 30-34")>
>>> RangeSet("10-19 30-39").first(30)
<RangeSet("10-19 30-39")>
>>> RangeSet("0-9").first(0)
<RangeSet("")>
"""
if self.size() <= n:
return self
out = []
for s, e in self:
if e - s >= n:
out += (s, s + n)
break
else:
out += (s, e)
n -= e - s
return RangeSet(data=out)
if __name__ == "__main__":
import doctest
doctest.testmod()

151
sdat2img.py Normal file
View File

@ -0,0 +1,151 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ====================================================
# FILE: sdat2img.py
# AUTHORS: xpirt - luxi78 - howellzhu
# DATE: 2018-10-27 10:33:21 CEST
# ====================================================
from __future__ import print_function
from os.path import realpath
# import sys
from sys import hexversion, exit, stderr, argv
from errno import EEXIST
def main(TRANSFER_LIST_FILE, NEW_DATA_FILE, OUTPUT_IMAGE_FILE):
__version__ = '1.2'
if hexversion < 0x02070000:
print >> stderr, "Python 2.7 or newer is required."
try:
input = input
except NameError:
pass
input('Press ENTER to exit...')
exit(1)
else:
print('sdat2img binary - version: {}\n'.format(__version__))
def rangeset(src):
src_set = src.split(',')
num_set = [int(item) for item in src_set]
if len(num_set) != num_set[0] + 1:
print('Error on parsing following data to rangeset:\n{}'.format(src), file=stderr)
exit(1)
return tuple([(num_set[i], num_set[i + 1]) for i in range(1, len(num_set), 2)])
def parse_transfer_list_file(path):
trans_list = open(TRANSFER_LIST_FILE, 'r')
# First line in transfer list is the version number
version = int(trans_list.readline())
# Second line in transfer list is the total number of blocks we expect to write
new_blocks = int(trans_list.readline())
if version >= 2:
# Third line is how many stash entries are needed simultaneously
trans_list.readline()
# Fourth line is the maximum number of blocks that will be stashed simultaneously
trans_list.readline()
# Subsequent lines are all individual transfer commands
commands = []
for line in trans_list:
line = line.split(' ')
cmd = line[0]
if cmd in ['erase', 'new', 'zero']:
commands.append([cmd, rangeset(line[1])])
else:
# Skip lines starting with numbers, they are not commands anyway
if not cmd[0].isdigit():
print('Command "{}" is not valid.'.format(cmd), file=stderr)
trans_list.close()
exit(1)
trans_list.close()
return version, new_blocks, commands
BLOCK_SIZE = 4096
version, new_blocks, commands = parse_transfer_list_file(TRANSFER_LIST_FILE)
if version == 1:
print('Android Lollipop 5.0 detected!\n')
elif version == 2:
print('Android Lollipop 5.1 detected!\n')
elif version == 3:
print('Android Marshmallow 6.x detected!\n')
elif version == 4:
print('Android Nougat 7.x / Oreo 8.x detected!\n')
else:
print('Unknown Android version!\n')
# Don't clobber existing files to avoid accidental data loss
try:
output_img = open(OUTPUT_IMAGE_FILE, 'wb')
except IOError as e:
if e.errno == EEXIST:
print('Error: the output file "{}" already exists'.format(e.filename), file=stderr)
print('Remove it, rename it, or choose a different file name.', file=stderr)
exit(e.errno)
else:
raise
new_data_file = open(NEW_DATA_FILE, 'rb')
all_block_sets = [i for command in commands for i in command[1]]
max_file_size = max(pair[1] for pair in all_block_sets) * BLOCK_SIZE
for command in commands:
if command[0] == 'new':
for block in command[1]:
begin = block[0]
end = block[1]
block_count = end - begin
print('Copying {} blocks into position {}...'.format(block_count, begin))
# Position output file
output_img.seek(begin * BLOCK_SIZE)
# Copy one block at a time
while block_count > 0:
output_img.write(new_data_file.read(BLOCK_SIZE))
block_count -= 1
else:
print('Skipping command {}...'.format(command[0]))
# Make file larger if necessary
if output_img.tell() < max_file_size:
output_img.truncate(max_file_size)
output_img.close()
new_data_file.close()
print('Done! Output image: {}'.format(realpath(output_img.name)))
if __name__ == '__main__':
try:
TRANSFER_LIST_FILE = str(argv[1])
NEW_DATA_FILE = str(argv[2])
except IndexError:
print('\nUsage: sdat2img.py <transfer_list> <system_new_file> [system_img]\n')
print(' <transfer_list>: transfer list file')
print(' <system_new_file>: system new dat file')
print(' [system_img]: output system image\n\n')
print('Visit xda thread for more information.\n')
try:
input = input
except NameError:
pass
input('Press ENTER to exit...')
exit()
try:
OUTPUT_IMAGE_FILE = str(argv[3])
except IndexError:
OUTPUT_IMAGE_FILE = 'system.img'
main(TRANSFER_LIST_FILE, NEW_DATA_FILE, OUTPUT_IMAGE_FILE)

289
sparse_img.py Normal file
View File

@ -0,0 +1,289 @@
# Copyright (C) 2014 The Android Open Source Project
#
# 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.
import bisect
import os
import sys
import struct
from hashlib import sha1
import rangelib
class SparseImage(object):
"""Wraps a sparse image file into an image object.
Wraps a sparse image file (and optional file map and clobbered_blocks) into
an image object suitable for passing to BlockImageDiff. file_map contains
the mapping between files and their blocks. clobbered_blocks contains the set
of blocks that should be always written to the target regardless of the old
contents (i.e. copying instead of patching). clobbered_blocks should be in
the form of a string like "0" or "0 1-5 8".
"""
def __init__(self, simg_fn, file_map_fn=None, clobbered_blocks=None,
mode="rb", build_map=True):
self.simg_f = f = open(simg_fn, mode)
header_bin = f.read(28)
header = struct.unpack("<I4H4I", header_bin)
magic = header[0]
major_version = header[1]
minor_version = header[2]
file_hdr_sz = header[3]
chunk_hdr_sz = header[4]
self.blocksize = blk_sz = header[5]
self.total_blocks = total_blks = header[6]
self.total_chunks = total_chunks = header[7]
if magic != 0xED26FF3A:
raise ValueError("Magic should be 0xED26FF3A but is 0x%08X" % (magic,))
if major_version != 1 or minor_version != 0:
raise ValueError("I know about version 1.0, but this is version %u.%u" %
(major_version, minor_version))
if file_hdr_sz != 28:
raise ValueError("File header size was expected to be 28, but is %u." %
(file_hdr_sz,))
if chunk_hdr_sz != 12:
raise ValueError("Chunk header size was expected to be 12, but is %u." %
(chunk_hdr_sz,))
print("Total of %u %u-byte output blocks in %u input chunks."
% (total_blks, blk_sz, total_chunks))
if not build_map:
return
pos = 0 # in blocks
care_data = []
self.offset_map = offset_map = []
self.clobbered_blocks = rangelib.RangeSet(data=clobbered_blocks)
for i in range(total_chunks):
header_bin = f.read(12)
header = struct.unpack("<2H2I", header_bin)
chunk_type = header[0]
chunk_sz = header[2]
total_sz = header[3]
data_sz = total_sz - 12
if chunk_type == 0xCAC1:
if data_sz != (chunk_sz * blk_sz):
raise ValueError(
"Raw chunk input size (%u) does not match output size (%u)" %
(data_sz, chunk_sz * blk_sz))
else:
care_data.append(pos)
care_data.append(pos + chunk_sz)
offset_map.append((pos, chunk_sz, f.tell(), None))
pos += chunk_sz
f.seek(data_sz, os.SEEK_CUR)
elif chunk_type == 0xCAC2:
fill_data = f.read(4)
care_data.append(pos)
care_data.append(pos + chunk_sz)
offset_map.append((pos, chunk_sz, None, fill_data))
pos += chunk_sz
elif chunk_type == 0xCAC3:
if data_sz != 0:
raise ValueError("Don't care chunk input size is non-zero (%u)" %
(data_sz))
else:
pos += chunk_sz
elif chunk_type == 0xCAC4:
raise ValueError("CRC32 chunks are not supported")
else:
raise ValueError("Unknown chunk type 0x%04X not supported" %
(chunk_type,))
self.care_map = rangelib.RangeSet(care_data)
self.offset_index = [i[0] for i in offset_map]
# Bug: 20881595
# Introduce extended blocks as a workaround for the bug. dm-verity may
# touch blocks that are not in the care_map due to block device
# read-ahead. It will fail if such blocks contain non-zeroes. We zero out
# the extended blocks explicitly to avoid dm-verity failures. 512 blocks
# are the maximum read-ahead we configure for dm-verity block devices.
extended = self.care_map.extend(512)
all_blocks = rangelib.RangeSet(data=(0, self.total_blocks))
extended = extended.intersect(all_blocks).subtract(self.care_map)
self.extended = extended
if file_map_fn:
self.LoadFileBlockMap(file_map_fn, self.clobbered_blocks)
else:
self.file_map = {"__DATA": self.care_map}
def AppendFillChunk(self, data, blocks):
f = self.simg_f
# Append a fill chunk
f.seek(0, os.SEEK_END)
f.write(struct.pack("<2H3I", 0xCAC2, 0, blocks, 16, data))
# Update the sparse header
self.total_blocks += blocks
self.total_chunks += 1
f.seek(16, os.SEEK_SET)
f.write(struct.pack("<2I", self.total_blocks, self.total_chunks))
def ReadRangeSet(self, ranges):
return [d for d in self._GetRangeData(ranges)]
def TotalSha1(self, include_clobbered_blocks=False):
"""Return the SHA-1 hash of all data in the 'care' regions.
If include_clobbered_blocks is True, it returns the hash including the
clobbered_blocks."""
ranges = self.care_map
if not include_clobbered_blocks:
ranges = ranges.subtract(self.clobbered_blocks)
h = sha1()
for d in self._GetRangeData(ranges):
h.update(d)
return h.hexdigest()
def _GetRangeData(self, ranges):
"""Generator that produces all the image data in 'ranges'. The
number of individual pieces returned is arbitrary (and in
particular is not necessarily equal to the number of ranges in
'ranges'.
This generator is stateful -- it depends on the open file object
contained in this SparseImage, so you should not try to run two
instances of this generator on the same object simultaneously."""
f = self.simg_f
for s, e in ranges:
to_read = e - s
idx = bisect.bisect_right(self.offset_index, s) - 1
chunk_start, chunk_len, filepos, fill_data = self.offset_map[idx]
# for the first chunk we may be starting partway through it.
remain = chunk_len - (s - chunk_start)
this_read = min(remain, to_read)
if filepos is not None:
p = filepos + ((s - chunk_start) * self.blocksize)
f.seek(p, os.SEEK_SET)
yield f.read(this_read * self.blocksize)
else:
yield fill_data * (this_read * (self.blocksize >> 2))
to_read -= this_read
while to_read > 0:
# continue with following chunks if this range spans multiple chunks.
idx += 1
chunk_start, chunk_len, filepos, fill_data = self.offset_map[idx]
this_read = min(chunk_len, to_read)
if filepos is not None:
f.seek(filepos, os.SEEK_SET)
yield f.read(this_read * self.blocksize)
else:
yield fill_data * (this_read * (self.blocksize >> 2))
to_read -= this_read
def LoadFileBlockMap(self, fn, clobbered_blocks):
remaining = self.care_map
self.file_map = out = {}
with open(fn) as f:
for line in f:
fn, ranges = line.split(None, 1)
ranges = rangelib.RangeSet.parse(ranges)
out[fn] = ranges
assert ranges.size() == ranges.intersect(remaining).size()
# Currently we assume that blocks in clobbered_blocks are not part of
# any file.
assert not clobbered_blocks.overlaps(ranges)
remaining = remaining.subtract(ranges)
remaining = remaining.subtract(clobbered_blocks)
# For all the remaining blocks in the care_map (ie, those that
# aren't part of the data for any file nor part of the clobbered_blocks),
# divide them into blocks that are all zero and blocks that aren't.
# (Zero blocks are handled specially because (1) there are usually
# a lot of them and (2) bsdiff handles files with long sequences of
# repeated bytes especially poorly.)
zero_blocks = []
nonzero_blocks = []
if sys.version_info[:2] >= (3, 0):
reference = bytes('\0' * self.blocksize, encoding="UTF-8")
else:
reference = '\0' * self.blocksize
# Workaround for bug 23227672. For squashfs, we don't have a system.map. So
# the whole system image will be treated as a single file. But for some
# unknown bug, the updater will be killed due to OOM when writing back the
# patched image to flash (observed on lenok-userdebug MEA49). Prior to
# getting a real fix, we evenly divide the non-zero blocks into smaller
# groups (currently 1024 blocks or 4MB per group).
# Bug: 23227672
MAX_BLOCKS_PER_GROUP = 1024
nonzero_groups = []
f = self.simg_f
for s, e in remaining:
for b in range(s, e):
idx = bisect.bisect_right(self.offset_index, b) - 1
chunk_start, _, filepos, fill_data = self.offset_map[idx]
if filepos is not None:
filepos += (b - chunk_start) * self.blocksize
f.seek(filepos, os.SEEK_SET)
data = f.read(self.blocksize)
else:
if fill_data == reference[:4]: # fill with all zeros
data = reference
else:
data = None
if data == reference:
zero_blocks.append(b)
zero_blocks.append(b + 1)
else:
nonzero_blocks.append(b)
nonzero_blocks.append(b + 1)
if len(nonzero_blocks) >= MAX_BLOCKS_PER_GROUP:
nonzero_groups.append(nonzero_blocks)
# Clear the list.
nonzero_blocks = []
if nonzero_blocks:
nonzero_groups.append(nonzero_blocks)
nonzero_blocks = []
assert zero_blocks or nonzero_groups or clobbered_blocks
if zero_blocks:
out["__ZERO"] = rangelib.RangeSet(data=zero_blocks)
if nonzero_groups:
for i, blocks in enumerate(nonzero_groups):
out["__NONZERO-%d" % i] = rangelib.RangeSet(data=blocks)
if clobbered_blocks:
out["__COPY"] = clobbered_blocks
def ResetFileMap(self):
"""Throw away the file map and treat the entire image as
undifferentiated data."""
self.file_map = {"__DATA": self.care_map}

132
splituapp.py Normal file
View File

@ -0,0 +1,132 @@
#!/usr/bin/env python
# splituapp for Python2/3 by SuperR. @XDA
#
# For extracting img files from UPDATE.APP
# Based on the app_structure file in split_updata.pl by McSpoon
from __future__ import print_function
# import os
from os import makedirs, name, sep, path
import re
import sys
import string
import struct
from subprocess import check_output
class extract(object):
def __init__(self, source, flist):
def cmd(command):
try:
test1 = check_output(command)
test1 = test1.strip().decode()
except:
test1 = ''
return test1
bytenum = 4
outdir = 'output'
img_files = []
try:
makedirs(outdir)
except:
pass
py2 = None
if int(''.join(str(i) for i in sys.version_info[0:2])) < 30:
py2 = 1
with open(source, 'rb') as f:
while True:
i = f.read(bytenum)
if not i:
break
elif i != b'\x55\xAA\x5A\xA5':
continue
headersize = f.read(bytenum)
headersize = list(struct.unpack('<L', headersize))[0]
f.seek(16, 1)
filesize = f.read(bytenum)
filesize = list(struct.unpack('<L', filesize))[0]
f.seek(32, 1)
filename = f.read(16)
try:
filename = str(filename.decode())
filename = ''.join(f for f in filename if f in string.printable).lower()
except:
filename = ''
f.seek(22, 1)
crcdata = f.read(headersize - 98)
if not flist or filename in flist:
if filename in img_files:
filename = filename + '_2'
print('Extracting ' + filename + '.img ...')
chunk = 10240
try:
with open(outdir + sep + filename + '.img', 'wb') as o:
while filesize > 0:
if chunk > filesize:
chunk = filesize
o.write(f.read(chunk))
filesize -= chunk
except:
print('ERROR: Failed to create ' + filename + '.img\n')
return
img_files.append(filename)
if name != 'nt':
if path.isfile('crc'):
print('Calculating crc value for ' + filename + '.img ...\n')
crcval = []
if py2:
for i in crcdata:
crcval.append('%02X' % ord(i))
else:
for i in crcdata:
crcval.append('%02X' % i)
crcval = ''.join(crcval)
crcact = cmd('./crc output/' + filename + '.img')
if crcval != crcact:
print('ERROR: crc value for ' + filename + '.img does not match\n')
return
else:
f.seek(filesize, 1)
xbytes = bytenum - f.tell() % bytenum
if xbytes < bytenum:
f.seek(xbytes, 1)
print('\nExtraction complete')
return
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description="Split UPDATE.APP file into img files", add_help=False)
required = parser.add_argument_group('Required')
required.add_argument("-f", "--filename", required=True, help="Path to update.app file")
optional = parser.add_argument_group('Optional')
optional.add_argument("-h", "--help", action="help", help="show this help message and exit")
optional.add_argument("-l", "--list", nargs="*", metavar=('img1', 'img2'), help="List of img files to extract")
args = parser.parse_args()
extract(args.filename, args.list)

2771
tool.py Normal file

File diff suppressed because it is too large Load Diff

49
tool.spec Normal file
View File

@ -0,0 +1,49 @@
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files
datas = []
datas += collect_data_files('sv_ttk')
block_cipher = None
a = Analysis(
['tool.py'],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['numpy'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='tool',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icon.ico'],
)

977
update_metadata_pb2.py Normal file
View File

@ -0,0 +1,977 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: update_metadata.proto
import sys
_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode('latin1'))
import google.protobuf.descriptor as _descriptor
import google.protobuf.message as _message
import google.protobuf.reflection as _reflection
import google.protobuf.symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='update_metadata.proto',
package='chromeos_update_engine',
syntax='proto2',
serialized_options=_b('H\003'),
serialized_pb=_b(
'\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\xa6\x04\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xe5\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\x12\x0c\n\x08ZUCCHINI\x10\x0b\x12\x12\n\x0eLZ4DIFF_BSDIFF\x10\x0c\x12\x14\n\x10LZ4DIFF_PUFFDIFF\x10\r\"\x81\x02\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_offset\x18\x04 \x01(\r\"2\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\x12\x0b\n\x07\x43OW_XOR\x10\x01\x12\x0f\n\x0b\x43OW_REPLACE\x10\x02\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xbe\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\x12\x13\n\x0b\x63ow_version\x18\x05 \x01(\r\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\xc3\x03\n\x14\x44\x65ltaArchiveManifest\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\x12\x1c\n\x14security_patch_level\x18\x12 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07J\x04\x08\x07\x10\x08J\x04\x08\x08\x10\tJ\x04\x08\t\x10\nJ\x04\x08\n\x10\x0bJ\x04\x08\x0b\x10\x0c\x42\x02H\x03')
)
_INSTALLOPERATION_TYPE = _descriptor.EnumDescriptor(
name='Type',
full_name='chromeos_update_engine.InstallOperation.Type',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='REPLACE', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REPLACE_BZ', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='MOVE', index=2, number=2,
serialized_options=_b('\010\001'),
type=None),
_descriptor.EnumValueDescriptor(
name='BSDIFF', index=3, number=3,
serialized_options=_b('\010\001'),
type=None),
_descriptor.EnumValueDescriptor(
name='SOURCE_COPY', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SOURCE_BSDIFF', index=5, number=5,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REPLACE_XZ', index=6, number=8,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ZERO', index=7, number=6,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='DISCARD', index=8, number=7,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='BROTLI_BSDIFF', index=9, number=10,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='PUFFDIFF', index=10, number=9,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ZUCCHINI', index=11, number=11,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LZ4DIFF_BSDIFF', index=12, number=12,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LZ4DIFF_PUFFDIFF', index=13, number=13,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=629,
serialized_end=858,
)
_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE)
_COWMERGEOPERATION_TYPE = _descriptor.EnumDescriptor(
name='Type',
full_name='chromeos_update_engine.CowMergeOperation.Type',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='COW_COPY', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='COW_XOR', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='COW_REPLACE', index=2, number=2,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=1068,
serialized_end=1118,
)
_sym_db.RegisterEnumDescriptor(_COWMERGEOPERATION_TYPE)
_EXTENT = _descriptor.Descriptor(
name='Extent',
full_name='chromeos_update_engine.Extent',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='start_block', full_name='chromeos_update_engine.Extent.start_block', index=0,
number=1, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='num_blocks', full_name='chromeos_update_engine.Extent.num_blocks', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=49,
serialized_end=98,
)
_SIGNATURES_SIGNATURE = _descriptor.Descriptor(
name='Signature',
full_name='chromeos_update_engine.Signatures.Signature',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='version', full_name='chromeos_update_engine.Signatures.Signature.version', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=_b('\030\001'), file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data', full_name='chromeos_update_engine.Signatures.Signature.data', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='unpadded_signature_size',
full_name='chromeos_update_engine.Signatures.Signature.unpadded_signature_size', index=2,
number=3, type=7, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=181,
serialized_end=260,
)
_SIGNATURES = _descriptor.Descriptor(
name='Signatures',
full_name='chromeos_update_engine.Signatures',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='signatures', full_name='chromeos_update_engine.Signatures.signatures', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_SIGNATURES_SIGNATURE, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=101,
serialized_end=260,
)
_PARTITIONINFO = _descriptor.Descriptor(
name='PartitionInfo',
full_name='chromeos_update_engine.PartitionInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='size', full_name='chromeos_update_engine.PartitionInfo.size', index=0,
number=1, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash', full_name='chromeos_update_engine.PartitionInfo.hash', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=262,
serialized_end=305,
)
_INSTALLOPERATION = _descriptor.Descriptor(
name='InstallOperation',
full_name='chromeos_update_engine.InstallOperation',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='type', full_name='chromeos_update_engine.InstallOperation.type', index=0,
number=1, type=14, cpp_type=8, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_offset', full_name='chromeos_update_engine.InstallOperation.data_offset', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_length', full_name='chromeos_update_engine.InstallOperation.data_length', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_extents', full_name='chromeos_update_engine.InstallOperation.src_extents', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_length', full_name='chromeos_update_engine.InstallOperation.src_length', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dst_extents', full_name='chromeos_update_engine.InstallOperation.dst_extents', index=5,
number=6, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dst_length', full_name='chromeos_update_engine.InstallOperation.dst_length', index=6,
number=7, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data_sha256_hash', full_name='chromeos_update_engine.InstallOperation.data_sha256_hash', index=7,
number=8, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_sha256_hash', full_name='chromeos_update_engine.InstallOperation.src_sha256_hash', index=8,
number=9, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
_INSTALLOPERATION_TYPE,
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=308,
serialized_end=858,
)
_COWMERGEOPERATION = _descriptor.Descriptor(
name='CowMergeOperation',
full_name='chromeos_update_engine.CowMergeOperation',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='type', full_name='chromeos_update_engine.CowMergeOperation.type', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_extent', full_name='chromeos_update_engine.CowMergeOperation.src_extent', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dst_extent', full_name='chromeos_update_engine.CowMergeOperation.dst_extent', index=2,
number=3, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_offset', full_name='chromeos_update_engine.CowMergeOperation.src_offset', index=3,
number=4, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
_COWMERGEOPERATION_TYPE,
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=861,
serialized_end=1118,
)
_PARTITIONUPDATE = _descriptor.Descriptor(
name='PartitionUpdate',
full_name='chromeos_update_engine.PartitionUpdate',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='partition_name', full_name='chromeos_update_engine.PartitionUpdate.partition_name', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='run_postinstall', full_name='chromeos_update_engine.PartitionUpdate.run_postinstall', index=1,
number=2, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='postinstall_path', full_name='chromeos_update_engine.PartitionUpdate.postinstall_path', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='filesystem_type', full_name='chromeos_update_engine.PartitionUpdate.filesystem_type', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_partition_signature', full_name='chromeos_update_engine.PartitionUpdate.new_partition_signature',
index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='old_partition_info', full_name='chromeos_update_engine.PartitionUpdate.old_partition_info', index=5,
number=6, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='new_partition_info', full_name='chromeos_update_engine.PartitionUpdate.new_partition_info', index=6,
number=7, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='operations', full_name='chromeos_update_engine.PartitionUpdate.operations', index=7,
number=8, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='postinstall_optional', full_name='chromeos_update_engine.PartitionUpdate.postinstall_optional',
index=8,
number=9, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_data_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_data_extent',
index=9,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_extent', index=10,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_algorithm', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_algorithm',
index=11,
number=12, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='hash_tree_salt', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_salt', index=12,
number=13, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_data_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_data_extent', index=13,
number=14, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_extent', index=14,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='fec_roots', full_name='chromeos_update_engine.PartitionUpdate.fec_roots', index=15,
number=16, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=2,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='version', full_name='chromeos_update_engine.PartitionUpdate.version', index=16,
number=17, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='merge_operations', full_name='chromeos_update_engine.PartitionUpdate.merge_operations', index=17,
number=18, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='estimate_cow_size', full_name='chromeos_update_engine.PartitionUpdate.estimate_cow_size', index=18,
number=19, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=1121,
serialized_end=1961,
)
_DYNAMICPARTITIONGROUP = _descriptor.Descriptor(
name='DynamicPartitionGroup',
full_name='chromeos_update_engine.DynamicPartitionGroup',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='chromeos_update_engine.DynamicPartitionGroup.name', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='size', full_name='chromeos_update_engine.DynamicPartitionGroup.size', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='partition_names', full_name='chromeos_update_engine.DynamicPartitionGroup.partition_names', index=2,
number=3, type=9, cpp_type=9, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=1963,
serialized_end=2039,
)
_DYNAMICPARTITIONMETADATA = _descriptor.Descriptor(
name='DynamicPartitionMetadata',
full_name='chromeos_update_engine.DynamicPartitionMetadata',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='groups', full_name='chromeos_update_engine.DynamicPartitionMetadata.groups', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='snapshot_enabled', full_name='chromeos_update_engine.DynamicPartitionMetadata.snapshot_enabled',
index=1,
number=2, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='vabc_enabled', full_name='chromeos_update_engine.DynamicPartitionMetadata.vabc_enabled', index=2,
number=3, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='vabc_compression_param',
full_name='chromeos_update_engine.DynamicPartitionMetadata.vabc_compression_param', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cow_version', full_name='chromeos_update_engine.DynamicPartitionMetadata.cow_version', index=4,
number=5, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=2042,
serialized_end=2232,
)
_APEXINFO = _descriptor.Descriptor(
name='ApexInfo',
full_name='chromeos_update_engine.ApexInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='package_name', full_name='chromeos_update_engine.ApexInfo.package_name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='version', full_name='chromeos_update_engine.ApexInfo.version', index=1,
number=2, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='is_compressed', full_name='chromeos_update_engine.ApexInfo.is_compressed', index=2,
number=3, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='decompressed_size', full_name='chromeos_update_engine.ApexInfo.decompressed_size', index=3,
number=4, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=2234,
serialized_end=2333,
)
_APEXMETADATA = _descriptor.Descriptor(
name='ApexMetadata',
full_name='chromeos_update_engine.ApexMetadata',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='apex_info', full_name='chromeos_update_engine.ApexMetadata.apex_info', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=2335,
serialized_end=2402,
)
_DELTAARCHIVEMANIFEST = _descriptor.Descriptor(
name='DeltaArchiveManifest',
full_name='chromeos_update_engine.DeltaArchiveManifest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='block_size', full_name='chromeos_update_engine.DeltaArchiveManifest.block_size', index=0,
number=3, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=4096,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='signatures_offset', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_offset',
index=1,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='signatures_size', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_size', index=2,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='minor_version', full_name='chromeos_update_engine.DeltaArchiveManifest.minor_version', index=3,
number=12, type=13, cpp_type=3, label=1,
has_default_value=True, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='partitions', full_name='chromeos_update_engine.DeltaArchiveManifest.partitions', index=4,
number=13, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='max_timestamp', full_name='chromeos_update_engine.DeltaArchiveManifest.max_timestamp', index=5,
number=14, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='dynamic_partition_metadata',
full_name='chromeos_update_engine.DeltaArchiveManifest.dynamic_partition_metadata', index=6,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='partial_update', full_name='chromeos_update_engine.DeltaArchiveManifest.partial_update', index=7,
number=16, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='apex_info', full_name='chromeos_update_engine.DeltaArchiveManifest.apex_info', index=8,
number=17, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='security_patch_level', full_name='chromeos_update_engine.DeltaArchiveManifest.security_patch_level',
index=9,
number=18, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto2',
extension_ranges=[],
oneofs=[
],
serialized_start=2405,
serialized_end=2856,
)
_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
_SIGNATURES.fields_by_name['signatures'].message_type = _SIGNATURES_SIGNATURE
_INSTALLOPERATION.fields_by_name['type'].enum_type = _INSTALLOPERATION_TYPE
_INSTALLOPERATION.fields_by_name['src_extents'].message_type = _EXTENT
_INSTALLOPERATION.fields_by_name['dst_extents'].message_type = _EXTENT
_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION
_COWMERGEOPERATION.fields_by_name['type'].enum_type = _COWMERGEOPERATION_TYPE
_COWMERGEOPERATION.fields_by_name['src_extent'].message_type = _EXTENT
_COWMERGEOPERATION.fields_by_name['dst_extent'].message_type = _EXTENT
_COWMERGEOPERATION_TYPE.containing_type = _COWMERGEOPERATION
_PARTITIONUPDATE.fields_by_name['new_partition_signature'].message_type = _SIGNATURES_SIGNATURE
_PARTITIONUPDATE.fields_by_name['old_partition_info'].message_type = _PARTITIONINFO
_PARTITIONUPDATE.fields_by_name['new_partition_info'].message_type = _PARTITIONINFO
_PARTITIONUPDATE.fields_by_name['operations'].message_type = _INSTALLOPERATION
_PARTITIONUPDATE.fields_by_name['hash_tree_data_extent'].message_type = _EXTENT
_PARTITIONUPDATE.fields_by_name['hash_tree_extent'].message_type = _EXTENT
_PARTITIONUPDATE.fields_by_name['fec_data_extent'].message_type = _EXTENT
_PARTITIONUPDATE.fields_by_name['fec_extent'].message_type = _EXTENT
_PARTITIONUPDATE.fields_by_name['merge_operations'].message_type = _COWMERGEOPERATION
_DYNAMICPARTITIONMETADATA.fields_by_name['groups'].message_type = _DYNAMICPARTITIONGROUP
_APEXMETADATA.fields_by_name['apex_info'].message_type = _APEXINFO
_DELTAARCHIVEMANIFEST.fields_by_name['partitions'].message_type = _PARTITIONUPDATE
_DELTAARCHIVEMANIFEST.fields_by_name['dynamic_partition_metadata'].message_type = _DYNAMICPARTITIONMETADATA
_DELTAARCHIVEMANIFEST.fields_by_name['apex_info'].message_type = _APEXINFO
DESCRIPTOR.message_types_by_name['Extent'] = _EXTENT
DESCRIPTOR.message_types_by_name['Signatures'] = _SIGNATURES
DESCRIPTOR.message_types_by_name['PartitionInfo'] = _PARTITIONINFO
DESCRIPTOR.message_types_by_name['InstallOperation'] = _INSTALLOPERATION
DESCRIPTOR.message_types_by_name['CowMergeOperation'] = _COWMERGEOPERATION
DESCRIPTOR.message_types_by_name['PartitionUpdate'] = _PARTITIONUPDATE
DESCRIPTOR.message_types_by_name['DynamicPartitionGroup'] = _DYNAMICPARTITIONGROUP
DESCRIPTOR.message_types_by_name['DynamicPartitionMetadata'] = _DYNAMICPARTITIONMETADATA
DESCRIPTOR.message_types_by_name['ApexInfo'] = _APEXINFO
DESCRIPTOR.message_types_by_name['ApexMetadata'] = _APEXMETADATA
DESCRIPTOR.message_types_by_name['DeltaArchiveManifest'] = _DELTAARCHIVEMANIFEST
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Extent = _reflection.GeneratedProtocolMessageType('Extent', (_message.Message,), {
'DESCRIPTOR': _EXTENT,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Extent)
})
_sym_db.RegisterMessage(Extent)
Signatures = _reflection.GeneratedProtocolMessageType('Signatures', (_message.Message,), {
'Signature': _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), {
'DESCRIPTOR': _SIGNATURES_SIGNATURE,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures.Signature)
})
,
'DESCRIPTOR': _SIGNATURES,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures)
})
_sym_db.RegisterMessage(Signatures)
_sym_db.RegisterMessage(Signatures.Signature)
PartitionInfo = _reflection.GeneratedProtocolMessageType('PartitionInfo', (_message.Message,), {
'DESCRIPTOR': _PARTITIONINFO,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionInfo)
})
_sym_db.RegisterMessage(PartitionInfo)
InstallOperation = _reflection.GeneratedProtocolMessageType('InstallOperation', (_message.Message,), {
'DESCRIPTOR': _INSTALLOPERATION,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.InstallOperation)
})
_sym_db.RegisterMessage(InstallOperation)
CowMergeOperation = _reflection.GeneratedProtocolMessageType('CowMergeOperation', (_message.Message,), {
'DESCRIPTOR': _COWMERGEOPERATION,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.CowMergeOperation)
})
_sym_db.RegisterMessage(CowMergeOperation)
PartitionUpdate = _reflection.GeneratedProtocolMessageType('PartitionUpdate', (_message.Message,), {
'DESCRIPTOR': _PARTITIONUPDATE,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionUpdate)
})
_sym_db.RegisterMessage(PartitionUpdate)
DynamicPartitionGroup = _reflection.GeneratedProtocolMessageType('DynamicPartitionGroup', (_message.Message,), {
'DESCRIPTOR': _DYNAMICPARTITIONGROUP,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionGroup)
})
_sym_db.RegisterMessage(DynamicPartitionGroup)
DynamicPartitionMetadata = _reflection.GeneratedProtocolMessageType('DynamicPartitionMetadata', (_message.Message,), {
'DESCRIPTOR': _DYNAMICPARTITIONMETADATA,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionMetadata)
})
_sym_db.RegisterMessage(DynamicPartitionMetadata)
ApexInfo = _reflection.GeneratedProtocolMessageType('ApexInfo', (_message.Message,), {
'DESCRIPTOR': _APEXINFO,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.ApexInfo)
})
_sym_db.RegisterMessage(ApexInfo)
ApexMetadata = _reflection.GeneratedProtocolMessageType('ApexMetadata', (_message.Message,), {
'DESCRIPTOR': _APEXMETADATA,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.ApexMetadata)
})
_sym_db.RegisterMessage(ApexMetadata)
DeltaArchiveManifest = _reflection.GeneratedProtocolMessageType('DeltaArchiveManifest', (_message.Message,), {
'DESCRIPTOR': _DELTAARCHIVEMANIFEST,
'__module__': 'update_metadata_pb2'
# @@protoc_insertion_point(class_scope:chromeos_update_engine.DeltaArchiveManifest)
})
_sym_db.RegisterMessage(DeltaArchiveManifest)
DESCRIPTOR._options = None
_SIGNATURES_SIGNATURE.fields_by_name['version']._options = None
_INSTALLOPERATION_TYPE.values_by_name["MOVE"]._options = None
_INSTALLOPERATION_TYPE.values_by_name["BSDIFF"]._options = None
# @@protoc_insertion_point(module_scope)

60
vbpatch.py Normal file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
# Python script edit by
import os
def checkmagic(file):
if os.access(file, os.F_OK):
magic = b'AVB0'
with open(file, "rb") as f:
buf = f.read(4)
if magic == buf:
return True
else:
return False
else:
print("File dose not exist!")
def readflag(file):
if checkmagic(file):
pass
else:
return False
if os.access(file, os.F_OK):
with open(file, "rb") as f:
f.seek(123, 0)
flag = f.read(1)
if flag == b'\x00':
return 0 # Verify boot and dm-verity is on
elif flag == b'\x01':
return 1 # Verify boot but dm-verity is off
elif flag == b'\x02':
return 2 # All verity is off
else:
return flag
else:
print("File does not exist!")
def patchvb(flag, file):
if checkmagic(file):
pass
else:
return False
if os.access(file, os.F_OK):
with open(file, 'rb+') as f:
f.seek(123, 0)
f.write(flag)
print("Done!")
else:
print("File not Found")
def restore(file): patchvb(b'\x00', file)
def disdm(file): patchvb(b'\x01', file)
def disavb(file): patchvb(b'\x02', file)