bin: Android 15

bin
cfig 6 months ago
parent e5ae389b48
commit 7fdc790d85
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

3
.gitattributes vendored

@ -0,0 +1,3 @@
aosp/* linguist-vendored
external/* linguist-vendored
avb/* linguist-vendored

@ -0,0 +1,98 @@
name: CI
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ rc, master, bin ]
pull_request:
branches: [ ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
linux:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
with:
submodules: true
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: apt
run: sudo apt install device-tree-compiler p7zip-full android-sdk-libsparse-utils erofs-utils
# Runs a single command using the runners shell
- name: Unit Test
run: ./gradlew check && ./gradlew clean || true
# Runs a set of commands using the runners shell
- name: Integration Test
run: |
./integrationTest.py
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: brew
run: brew install dtc
- name: Unit Test
run: ./gradlew check && ./gradlew clean || true
# Runs a set of commands using the runners shell
- name: Integration Test
run: ./integrationTest.py
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: choco
run: choco install openssl dtc-msys2 zip vim
- name: Unit Test
run: ./gradlew.bat check && ./gradlew.bat clean || true
# Runs a set of commands using the runners shell
- name: Integration Test
run: python integrationTest.py

4
.gitignore vendored

@ -0,0 +1,4 @@
.idea
.gradle
build/
__pycache__

9
.gitmodules vendored

@ -0,0 +1,9 @@
[submodule "src/integrationTest/resources"]
path = src/integrationTest/resources
url = https://github.com/cfig/android_image_res
[submodule "src/integrationTest/resources_2"]
path = src/integrationTest/resources_2
url = https://github.com/cfig/android_image_res2.git
[submodule "src/integrationTest/resources_3"]
path = src/integrationTest/resources_3
url = https://github.com/cfig/android_image_res3.git

@ -0,0 +1,22 @@
language: java
os:
- linux
- osx
dist: focal
osx_image: xcode12.2
addons:
apt:
packages:
- xz-utils
- libblkid-dev
- liblz4-tool
- device-tree-compiler
- python3
- python-all
before_install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install lz4 dtc gradle; fi
script:
- ./gradlew check
- ./gradlew clean
- ./integrationTest.py

@ -0,0 +1,364 @@
# Android_boot_image_editor
[![CI](https://github.com/cfig/Android_boot_image_editor/actions/workflows/main.yml/badge.svg)](https://github.com/cfig/Android_boot_image_editor/actions/workflows/main.yml)
[![License](http://img.shields.io/:license-apache-blue.svg?style=flat-square)](http://www.apache.org/licenses/LICENSE-2.0.html)
A tool for reverse engineering Android ROM images.
## Requirements
Make sure you have [JDK11+](https://www.oracle.com/java/technologies/downloads/#java17) and [Python3](https://www.python.org/downloads/).
* Linux / WSL: `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-17-jdk gcc g++ python3 python-is-python3 p7zip-full android-sdk-libsparse-utils erofs-utils`
* Mac: `brew install lz4 xz dtc`
* Windows: Install openssl and device-tree compiler with [chocolate](https://chocolatey.org/install)
`choco install openssl dtc-msys2 zip vim`
## Getting Started
Put your boot.img to current directory, then start gradle 'unpack' task:
```bash
cp <original_boot_image> boot.img
./gradlew unpack
```
Your get the flattened kernel and /root filesystem under **./build/unzip\_boot**:
build/unzip_boot/
├── boot.json (boot image info)
├── boot.avb.json (AVB only)
├── kernel
├── second (2nd bootloader, if exists)
├── dtb (dtb, if exists)
├── dtbo (dtbo, if exists)
└── root (extracted initramfs)
Then you can edit the actual file contents, like rootfs or kernel.
Now, pack the boot.img again
./gradlew pack
You get the repacked boot.img at $(CURDIR):
boot.img.signed
Well done you did it! The last step is to star this repo :smile
### live demo
<!-- ![](doc/op.gif) -->
<p align="center">
<img src=doc/op.gif width="615" height="492">
</p>
## Supported ROM image types
| Image Type | file names | platforms | note |
| --------------- |----------------------------------------------------------------|-------------|-------------------------|
| boot | boot.img, init_boot.img, boot-debug.img, boot-test-harness.img | all | |
|vendor boot | vendor_boot.img, vendor_boot-debug.img, vendor_kernel_boot.img | all | |
| recovery | recovery.img, recovery-two-step.img | all | |
| vbmeta | vbmeta.img, vbmeta_system.img etc. | all | |
| dtbo | dtbo.img | linux & mac | |
| dtb | *.dtb | linux & mac | |
| sparse images | system.img, vendor.img, product.img etc. | linux | |
| OTA payload | payload.bin | all | Windows git-bash |
Please note that the boot.img MUST follows AOSP verified boot flow, either [Boot image signature](https://source.android.com/security/verifiedboot/verified-boot#signature_format) in VBoot 1.0 or [AVB HASH footer](https://android.googlesource.com/platform/external/avb/+/master/README.md#The-VBMeta-struct) (a.k.a. AVB) in VBoot 2.0.
## compatible devices
| Device Model | Manufacturer | Compatible | Android Version | Note |
|--------------------------------|--------------|----------------------|--------------------------|------|
| Pixel 7 (panther) | Google | Y | 13 (TQ2A.230505.002) <Br>2023)| |
| ADT-3 (adt3) | Askey/Google | Y | 12 (spp2.210219.010) | amlogic inside, <Br>Android TV |
| Pixel 3 (blueline) | Google | Y | 12 (spp2.210219.008, <Br>2021)| |
| Pixel 3 (blueline) | Google | Y | 11 (RP1A.200720.009, <Br>2020)| [more ...](doc/additional_tricks.md#pixel-3-blueline) |
| Pixel 3 (blueline) | Google | Y | Q preview (qpp2.190228.023, <Br>2019)| [more ...](doc/additional_tricks.md#pixel-3-blueline) |
| Redmi K30 4G (phoenix[n]) | XiaoMi | Y | 10 | [verified](https://github.com/cfig/Android_boot_image_editor/issues/17#issuecomment-817169307) by @eebssk1 |
| TS10 | Topway | Y | 10 | car headunit, @mariodantas |
| Pixel XL (marlin) | HTC | Y | 9.0.0 (PPR2.180905.006, <Br>Sep 2018)| [more ...](doc/additional_tricks.md#pixel-xl-marlin) |
| K3 (CPH1955) | OPPO | Y for recovery.img<Br> N for boot.img | Pie | [more](doc/additional_tricks.md#k3-cph1955) |
| Z18 (NX606J) | ZTE | Y | 8.1.0 | [more...](doc/additional_tricks.md#nx606j) |
| Nexus 9 (volantis/flounder) | HTC | Y(with some tricks) | 7.1.1 (N9F27M, Oct 2017) | [tricks](doc/additional_tricks.md#tricks-for-nexus-9volantis)|
| Nexus 5x (bullhead) | LG | Y | 6.0.0_r12 (MDA89E) | |
| Moto X (2013) T-Mobile | Motorola | N | | |
| X7 (PD1602_A_3.12.8) | VIVO | N | ? | [Issue 35](https://github.com/cfig/Android_boot_image_editor/issues/35) |
| Realme GT Neo 3 | Realme | N | 12 | [Issue 105](https://github.com/cfig/Android_boot_image_editor/issues/105) |
## more examples
<details>
<summary>working with recovery.img</summary>
Please remember to clean the work directory first.
```bash
rm *.img
cp <your_recovery_image> recovery.img
./gradlew unpack
./gradlew pack
```
</details>
<details>
<summary>working with vbmeta.img</summary>
```bash
rm *.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
./gradlew pack
```
</details>
<details>
<summary>clean workspace</summary>
When you finished current work and need to clean the workspace for next image, it's a good idea to call the `clear` command:
```bash
./gradlew clear
```
</details>
<details>
<summary>working with boot.img and vbmeta.img</summary>
If your vbmeta.img contains hash of boot.img, you MUST update vbmeta image together.
```bash
rm *.img
cp <your_boot_image> boot.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
./gradlew pack
```
Your boot.img.signed and vbmeta.img.signd will be updated together, then you can flash them to your device.
</details>
<details>
<summary>working with vendor_boot.img + vbmeta.img (Pixel 5 etc.)</summary>
Most devices include hash descriptor of vendor_boot.img in vbmeta.img, so if you need to modify vendor_boot.img, you need to update vbmeta.img together.
```bash
rm *.img
cp <your_vendor_boot_image> vendor_boot.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
./gradlew pack
./gradlew flash
```
Please note that to use 'gradle flash', your host machine must be connectted to your DUT with adb, and you already 'adb root'.
</details>
<details>
<summary>How to edit device tree blob(dtb) inside vendor_boot.img</summary>
If you want to edit the device-tree blob in place:
```bash
cp <your_vendor_boot_image> vendor_boot.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
==> now you can edit build/unzip_boot/dtb.dts directly
./gradlew pack
```
During unpack stage, dtb will be dumped to file `build/unzip_boot/dtb`, dts will be decompiled to `build/unzip_boot/dtb.dts`.
You can edit `dtb.dts` directly, and it will be compiled to dtb duing repack stage.
If you just want to replace the dtb with the one that is compiled outside this tool, please
```bash
cp <your_vendor_boot_image> vendor_boot.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
rm build/unzip_boot/dtb.dts
cp <your_dtb> build/unzip_boot/dtb
./gradlew pack
```
</details>
<details>
<summary>How to pull device tree blob(dtb) from a rooted device</summary>
If you have a rooted device and want to pull /proc/device-tree
```bash
touch fake.dtb
./gradlew pull
```
This tool will copy `dtc` to the target device via `adb`, and dump the dtb and dts file. Eventually you should get something like this
```
+--------+------------------------------+
| What | Where |
+--------+------------------------------+
| source | /proc/device-tree |
+--------+------------------------------+
| DTB | panther.dtb |
+--------+------------------------------+
| DTS | build/unzip_boot/panther.dts |
+--------+------------------------------+
```
</details>
<details>
<summary>How to work edit device tree blob(dtb) file</summary>
If you have a dtb file and want to edit its content
```bash
cp <your_dtb_file> .
./gradlew unpack
```
This tool will decompile it and put the decompiled source to build/unzip_boot.
```
Unpack Summary of panther.dtb
+------+------------------------------+
| What | Where |
+------+------------------------------+
| DTB | panther.dtb |
+------+------------------------------+
| DTS | build/unzip_boot/panther.dts |
+------+------------------------------+
```
</details>
<details>
<summary>working with system.img</summary>
```bash
cp <your_system_image> system.img
./gradlew unpack
```
You get `system.img.unsparse`, that's a plain ext4 filesystem data.
</details>
<details>
<summary>How to disable AVB verification</summary>
The idea is to set flag=2 in main vbmeta.
```bash
rm *.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
vim -u NONE -N build/unzip_boot/vbmeta.avb.json -c ":19s/0/2/g" -c ":wq"
./gradlew pack
```
Then flash vbmeta.img.signed to your device.
</details>
<details>
<summary>How to merge init_boot.img into boot.img</summary>
* unpack init_boot.img and copy out "build/unzip_boot/root".
* clear workspace by `gradle clear`, then unpack boot.img
* copy back the "build/unzip_boot/root"
* edit build/unzip_boot/boot.json
- change `ramdisk.size` to 1
- change `ramdisk.file` from "build/unzip_boot/ramdisk.img" to "build/unzip_boot/ramdisk.img.lz4"
</details>
<details>
<summary>work with payload.bin</summary>
- extract everything
Usage:
```
gradle unpack
```
- extract only 1 specified partition
Usage:
```
gradle unpack -Dpart=<part_name>
```
Example:
```
gradle unpack -Dpart=boot
gradle unpack -Dpart=system
```
Note:
"build/payload/" will be deleted before each "unpack" task
</details>
<details>
<summary>work with apex images</summary>
AOSP already has tools like apexer, deapexer, sign_apex.py, these should suffice the needs on .apex and .capex.
Refer to Issue https://github.com/cfig/Android_boot_image_editor/issues/120
- For those who may be interested in apex generation flow, there is a graph here
![image](doc/apexer_generate_flow.png)
</details>
<details>
<summary>How to work with vendor_dlkm.img</summary>
```bash
cp <your_vendor_dlkm.img> vendor_dlkm.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
# replace your .ko
./gradlew pack
```
Then flash `vbmeta.img.signed` and `vendor_dlkm.img.signed` to the device.
</details>
## boot.img layout
Read [boot layout](doc/layout.md) of Android boot.img and vendor\_boot.img.
Read [misc layout](doc/misc_image_layout.md) of misc\.img
## References and Acknowledgement
<details>
<summary>more ...</summary>
Android version list https://source.android.com/source/build-numbers.html<br/>
Android build-numbers https://source.android.com/setup/start/build-numbers
cpio & fs\_config<br>
https://android.googlesource.com/platform/system/core<br/>
https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt<br/>
AVB<br/>
https://android.googlesource.com/platform/external/avb/<br/>
boot\_signer<br/>
https://android.googlesource.com/platform/system/extras<br/>
mkbootimg<br/>
https://android.googlesource.com/platform/system/tools/mkbootimg/+/refs/heads/master/<br/>
boot header definition<br/>
https://android.googlesource.com/platform/system/tools/mkbootimg/+/refs/heads/master/include/bootimg/bootimg.h<br/>
kernel info extractor<br/>
https://android.googlesource.com/platform/build/+/refs/heads/master/tools/extract_kernel.py<br/>
mkdtboimg<br/>
https://android.googlesource.com/platform/system/libufdt/<br/>
libsparse<br/>
https://android.googlesource.com/platform/system/core/+/refs/heads/master/libsparse/<br/>
Android Nexus/Pixle factory images<br/>
https://developers.google.cn/android/images<br/>
</details>

@ -0,0 +1,20 @@
diff --git a/avb/avbtool b/avb/avbtool
index 8732024..5f62948 100755
--- a/avb/avbtool
+++ b/avb/avbtool
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2.7
# Copyright 2016, The Android Open Source Project
#
@@ -2159,7 +2159,8 @@ class Avb(object):
expected_chain_partitions_map[partition_name] = (rollback_index_location, pk_blob)
image_dir = os.path.dirname(image_filename)
- image_ext = os.path.splitext(image_filename)[1]
+ #image_ext = os.path.splitext(image_filename)[1]
+ image_ext = image_filename[image_filename.index('.'):]
key_blob = None
if key_path:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
WM8yjCL8U3+kfP4L6uIgmAuVcmbrX68=
-----END PRIVATE KEY-----

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
MSKHJYIcbmEACtr9tALUhZo5SkjMLrQ=
-----END PRIVATE KEY-----

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCy2mHwjC3ylCFF
dzNkZPKOiZzrUiPawe8OFcTJOySMv0/P4fILDiZuhC1VLwMHquR6kQhvyP9ffeHl
W3JHliiIFOcS71bxlO1aqVYFt3qF8A/qFVruLjpwh47+WEPfWnCEeX2i8RGpUFh/
oc2Ey1Dv+BuoHpNUFm2HsJgTe/R1EXadmGfTthvaVfWXb9nW/67YkMEWbH5MZ6BY
bPXVpA+AN0IoQm+emSj2Ipve0TTGxgX3VQDzA8aTYimAVB+HuOq6p/UxiJu5GCyI
AhqLsVVHd1qnxCn6eGKcaRACfy6n0mWLn/UXgi2h5hhI3TFGpFSU5ZXB6TfDfYNe
uzE8njYZloWVrbSy0IascNK9JnQy9/ySy8l5Fw67QByNz9DDCRJJLE78e1ss73Dr
pjOafwtE6P+koRZe6SbE8NS2v1qiSSoCiBt6lgjOIMR9+KMp7vk8oLEfBBTMc4JR
4hiZkxPW6j8PYTuiJDs8h7ItZ5awisabbE5URvDc5DscWSE8KbGMa8iXHMJK1Eam
uko4EIQ/fod5BQ1vpJeS4vPAMqeKMufBHJUcuBkUi0au5Ux8lSNkU0591RfFfmUL
AodIqtXX39yHMN7SQqQAfAibdcDWmujN9F/Js4OHCWuhj1q6VUhSEEEqtDeX01sH
xlghCFg8lNO5GeDG5SDyGsdxY+iObQIDAQABAoICAEQwEkr9hr8HTrAHRCawffFt
8c+d32GVsqhyEDaQP90RS0J8aCVi3bAg4I+rfsI7myRHiynjPcmQWsFw3d8BFq7b
GUYUzdcI6n04Nj2zuBi8b7TVM3e/VDR22kOKL0ZGWsOG9ilbM1qT8UmnzI0mXtM+
inzMO2tBqbyjzTcQeSDw6YIoCt2ifnf9ccastCbOEEEs3xDHiFdk4rMTx54OEILX
jnd+7MNQrVc51qdap35pHPkxBU2hUOH7+MqeR+8cxxEm28poxMYKu1+XPbuoflTi
4kM3/LErmJz9SUdKaeU9x801zOGLlg41hWiyPAksubqS1Ue6vLHhdmZ1g84Sm5j+
lABJXRBnc1YG/nyJZlFvMhp7gCXVDYQ4nUT4y2Ozd7ip9BweBzVoXQSMvjWfQvvb
fzqJS0dNKqMQQU78x+B1g8iNgL9PCCkEeFN1YZwkJQMfQLdv+fgP9GEHlE/zz1Sv
lZNpve0CARWZUg0Nbw1w9fsbeezJpCntZMs4wVMS0Vyn9TmFAEielILmmW/tkUyR
WpZI7l4AYX4Rzx+nnVVwrSO9UDqp+2aiOODXpL3RboFi8qbblZWvNy7/mSKSKxwv
E7Z7a8qMcaFsOy7LKSsbheZNWyyhQlfe3yNeYKMDj3rFmooNpJd0hU2kqt1fZKQK
SIyutcEHQFP/p1LP1X9ZAoIBAQDdNg0o3FdYySCYTc5N6T+SUai8FyOlUhXvh7wn
m28QmC8YBafjUAPXQYJYKiKtyb1/34FSgaBS9kv5nNL5HYxr15HW7aVrFUV3kSnT
2+yuRrzHiN4B0ZuHlaRHd/fSmuOADM8b/s+CaYeWSWq0qE54uDRSa541OSENxIAq
9f83rNcg8JF/eYaJQ4bAHzDdjCPS+nSJFtfVmswyoLFZBEeBdyR7zyXPBcLKPSvc
4BfBbnrrh+boUvw6hgijDopAQVvyzuDECuA7+0Nsx/7M4p0154kxqgmP/ixuamrF
0Wdx/VOOeXMZ7pEN8hInr4XJ3QEWcxHDl7Yj2Pk8jzduCBQfAoIBAQDO+v9Ax3RH
E2kw+ce6k1K/u37Foku4EgAMuAHPtlEX0HjbC7t67p8mdqFfOLe3Gka8EFvwpmbr
af1fWijErCLxv+JtVsQuv2cr4aFBjs+F/NRaNtY4fS5732O7kGML8y1qtLXGi6qS
bdsdTjhjA2s65tU/lE7g6vJEhAFUtTA9PPZxFQfIv6mFtW0yvdgZcdi3wH7s/NAX
SVkgxPnBwUpLnJ+NvK6dRt6dxr1d5cp2ghWhryt3FOUVl60e0dbJrykOedl/rWF6
C3fCQnyWQx8Yzq1Lk/CTfzHln9YIDkyYT0DD6ccNJ2OBECsP0+zMKMfPUBYu2vep
w3Yh826Hm+vzAoIBAEKBOI2bSOtZdGI1qhuET2d3A2qg7keKmSutPCUQNuDfT/FB
6gqOCMmTWVOWP1zONRmXoXKjpAatI4RE4KyidJALfD4Irl22RG9BBjk6ejqe66x1
eoFDeiXWGFCgQbJgfJsHvtBk2BAWF/xX0CvGGelzP8+zqRnJNiXEeN/xmywq23Z8
vNF9QLRNx9pExlUlB7QrNhPs+TCv3EowQ4FGpxTGNALA8VX/HmPc5i3+dUXjKDNd
ZU9de5VArKIRAgF1ZOZnye1Gc8m0rb2rlvAUBT2qgXWb8EoJGWSMu9MDNL1xcsh3
vOID9joiF9E0lN1ugyAzshiCqPC4D55kVD7RUPMCggEBAIzg/GHcIEHMbXm/WXmd
kuIbvTLJv53+6ne9usXlQxbhd5EoUChhSIQGlNnaIfmH8gNJYzrOGBk94A5JsJwE
yhgf0f834norHw8YGQklKgz5xJPO5Uo3si7wItLkePYGQ7BwZZVJNQVLrqsotWp3
RkImIZmP2YxvfgyyiLFeTgIwf1ECznSON9VhYnz6CJ9xBOA1Lm8huIVREFAkohaF
+Iq0hUkU1wkH1rgvMG872+2DpzOQphX8a9yhi10B2J8YEOrgdvDXUxSdv5rCZEhm
UUEyU3OwszvBhHXVr/l1uh6lOuDeOvSyDaEoHxc72N4xF6b8zMyBj7bF6p87MM0u
jI8CggEBAIzDR/EGdJEQJrm4ZFbBrWyxYzKQLCTQ3IpKVVzmaSEy6iXegsTfFbVz
TgHMWh0lUBnokoFSQrPZ5fVng1+AfZOPRToBYLwjVM7mprsmnrjGevJK9VzejOrc
O9NLOlnBL7lNUjDLl2vfzI3O9kwE0OKgfu/kjHNW4WtssQwexsu8kMLbd5sC1txI
G4uHedf6AMwty1m4jLC0MAu40N/CGbyQMfQmAG1ozinFuKTUMgN5f3TjdKMdWx6u
35hLzEgfvrNcu2/Awt6sdmfKPesbKrSBN/5I3NXfFbaI/4aUkjMKqTr2frDt6ZDJ
PqPOQDQM7f0JPuFGA9kFRaKUQygQckw=
-----END PRIVATE KEY-----

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxlVR3TIkouAOvH79vaJTgFhpfvVKQIeVkFRZPVXK/zY0Gvrh
4JAqGjJoW/PfrQv5sdD36qtHH3a+G5hLZ6Ni+t/mtfjucxZfuLGC3kmJ1T3XqEKZ
gXXI2IR7vVSoImREvDQGEDyJwtHzLANlkbGg0cghVhWZSCAndO8BenalC2v94/rt
DfkPekH6dgU3Sf40T0sBSeSY94mOzTaqOR2pfV1rWlLRdWmo33zeHBv52Rlbt0dM
uXAureXWiHztkm5GCBC1dgM+CaxNtizNEgC91KcD0xuRCCM2WxH+r1lpszyIJDct
YbrFmVEYl/kjQpafhy7Nsk1fqSTyRdriZSYmTQIDAQABAoIBAQC+kJgaCuX8wYAn
SXWQ0fmdZlXnMNRpcF0a0pD0SAzGb1RdYBXMaXiqtyhiwc53PPxsCDdNecjayIMd
jJVXPTwLhTruOgMS/bp3gcgWwV34UHV4LJXGOGAE+jbS0hbDBMiudOYmj6RmVshp
z9G1zZCSQNMXHaWsEYkX59XpzzoB384nRul2QgEtwzUNR9XlpzgtJBLk3SACkvsN
mQ/DW8IWHXLg8vLn1LzVJ2e3B16H4MoE2TCHxqfMgr03IDRRJogkenQuQsFhevYT
o/mJyHSWavVgzMHG9I5m+eepF4Wyhj1Y4WyKAuMI+9dHAX/h7Lt8XFCQCh5DbkVG
zGr34sWBAoGBAOs7n7YZqNaaguovfIdRRsxxZr1yJAyDsr6w3yGImDZYju4c4WY9
5esO2kP3FA4p0c7FhQF5oOb1rBuHEPp36cpL4aGeK87caqTfq63WZAujoTZpr9Lp
BRbkL7w/xG7jpQ/clpA8sHzHGQs/nelxoOtC7E118FiRgvD/jdhlMyL9AoGBANfX
vyoN1pplfT2xR8QOjSZ+Q35S/+SAtMuBnHx3l0qH2bbBjcvM1MNDWjnRDyaYhiRu
i+KA7tqfib09+XpB3g5D6Ov7ls/Ldx0S/VcmVWtia2HK8y8iLGtokoBZKQ5AaFX2
iQU8+tC4h69GnJYQKqNwgCUzh8+gHX5Y46oDiTmRAoGAYpOx8lX+czB8/Da6MNrW
mIZNT8atZLEsDs2ANEVRxDSIcTCZJId7+m1W+nRoaycLTWNowZ1+2ErLvR10+AGY
b7Ys79Wg9idYaY9yGn9lnZsMzAiuLeyIvXcSqgjvAKlVWrhOQFOughvNWvFl85Yy
oWSCMlPiTLtt7CCsCKsgKuECgYBgdIp6GZsIfkgclKe0hqgvRoeU4TR3gcjJlM9A
lBTo+pKhaBectplx9RxR8AnsPobbqwcaHnIfAuKDzjk5mEvKZjClnFXF4HAHbyAF
nRzZEy9XkWFhc80T5rRpZO7C7qdxmu2aiKixM3V3L3/0U58qULEDbubHMw9bEhAT
PudI8QKBgHEEiMm/hr9T41hbQi/LYanWnlFw1ue+osKuF8bXQuxnnHNuFT/c+9/A
vWhgqG6bOEHu+p/IPrYm4tBMYlwsyh4nXCyGgDJLbLIfzKwKAWCtH9LwnyDVhOow
GH9shdR+sW3Ew97xef02KAH4VlNANEmBV4sQNqWWvsYrcFm2rOdL
-----END RSA PRIVATE KEY-----

Binary file not shown.

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

Binary file not shown.

@ -0,0 +1,14 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ASv49OEbH4NiT3CjNMS
VeliyfEPXswWcqtEfCxlSpS1FisAuwbvEwdTTPlkuSh6G4SYiNhnpCP5p0vcSg/3
OhiuVKgV/rCtrDXaO60nvK/o0y83NNZRK2xaJ9eWBq9ruIDK+jC0sYWzTaqqwxY0
Grjnx/r5CXerl5PrRK7PILzwgBHbIwxHcblt1ntgR4cWVpO3wiqasEwBDDDYk4fw
7W6LvjBb9qav3YB8RV6PkZNeRP64ggfuecq/MXNiWOPNxLzCER2hSr/+J32h9jWj
XsrcVy8+8Mldhmr4r2an7c247aFfupuFGtUJrpROO8/LXMl5gPfMpkqoatjTMRH5
9gJjKhot0RpmGxZBvb33TcBK5SdJX39Y4yct5clmDlI4Fjj7FutTP+b96aJeJVnY
eUX/A0wmogBajsJRoRX5e/RcgZsYRzXYLQXprQ81dBWjjovMJ9p8XeT6BNMFC7o6
sklFL0fHDUE/l4BNP8G1u3BfpzevSCISRS71D4eS4oQB+RIPFBUkzomZ7rnEF3Bw
Feq+xmwfYrP0LRaH+1YeRauuMuReke1TZl697a3mEjkNg8noa2wtpe7EWmaujJfX
DWxJx/XEkjGLCe4z2qk3tkkY+A5gRcgzke8gVxC+eC2DJtbKYfkv4L8FMFJaEhwA
p13MfC7FlYujO/BDLl7dANsCAwEAAQ==
-----END PUBLIC KEY-----

@ -0,0 +1,99 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

Binary file not shown.

@ -0,0 +1,45 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
filegroup {
name: "q-gsi_avbpubkey",
srcs: [
"q-gsi.avbpubkey",
],
}
filegroup {
name: "r-gsi_avbpubkey",
srcs: [
"r-gsi.avbpubkey",
],
}
filegroup {
name: "s-gsi_avbpubkey",
srcs: [
"s-gsi.avbpubkey",
],
}
filegroup {
name: "t-gsi_avbpubkey",
srcs: [
"t-gsi.avbpubkey",
],
}
filegroup {
name: "qcar-gsi_avbpubkey",
srcs: [
"qcar-gsi.avbpubkey",
],
}
filegroup {
name: "kernel_version_matrix.textproto",
srcs: [
"kernel_version_matrix.textproto"
],
}

@ -0,0 +1,91 @@
# Copyright (C) 2023 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.
# https://source.android.com/docs/core/architecture/kernel/android-common#compatibility-matrix
release_requirements: [
{
# Android 13
# This is the minimum SDK level where we start enforcing the matrix.
key: 33
value {
upgrade: [
# -q, -stable are dropped from non-GKI kernel release formats because the kernel branch
# cannot be looked up anywhere.
"android-4.9",
"android-4.14",
"android-4.19",
"android11-5.4",
"android12-5.4",
"android12-5.10",
"android13-5.10",
"android13-5.15"
]
launch: [
"android11-5.4",
"android12-5.4",
"android12-5.10",
"android13-5.10",
"android13-5.15"
]
launch_grf: [
# -q, -stable are dropped from non-GKI kernel release formats because the kernel branch
# cannot be looked up anywhere.
"android-4.19",
"android11-5.4",
"android12-5.4",
"android12-5.10",
"android13-5.10",
"android13-5.15"
]
}
},
{
# Android 14
key: 34
value {
upgrade: [
# -q, -stable are dropped from non-GKI kernel release formats because the kernel branch
# cannot be looked up anywhere.
"android-4.14",
"android-4.19",
"android11-5.4",
"android12-5.4",
"android12-5.10",
"android13-5.10",
"android13-5.15",
"android14-5.15",
"android14-6.1"
]
launch: [
"android12-5.10",
"android13-5.10",
"android13-5.15",
"android14-5.15",
"android14-6.1"
]
launch_grf: [
# -q, -stable are dropped from non-GKI kernel release formats because the kernel branch
# cannot be looked up anywhere.
"android-4.19",
"android11-5.4",
"android12-5.4",
"android12-5.10",
"android13-5.10",
"android13-5.15",
"android14-5.15",
"android14-6.1"
]
}
}
]

@ -0,0 +1,24 @@
.PHONY: all checkpolicy libsepol prepare
nothing:
@echo "Nothing to do"
checkpolicy: export CFLAGS := -g -Wall -Werror -Wshadow -pipe -fno-strict-aliasing -I$(CURDIR)/libsepol-3.2/include
checkpolicy: export LIBSEPOLA := $(CURDIR)/libsepol-3.2/src/libsepol.a
checkpolicy: export LDLIBS_LIBSEPOLA := -l:libsepol.a -L$(CURDIR)/libsepol-3.2/src
checkpolicy: libsepol
make -C checkpolicy-3.2 -j
cp checkpolicy-3.2/test/dispol .
libsepol:
make -C libsepol-3.2 -j
prepare:
rm -fr libsepol-3.2 checkpolicy-3.2
wget https://github.com/SELinuxProject/selinux/releases/download/3.2/libsepol-3.2.tar.gz
wget https://github.com/SELinuxProject/selinux/releases/download/3.2/checkpolicy-3.2.tar.gz
tar xaf checkpolicy-3.2.tar.gz
tar xaf libsepol-3.2.tar.gz
all: checkpolicy libsepol prepare
# vim:ft=make
#

@ -0,0 +1,7 @@
# dispol
decompile binary selinux policy file
Android sepolicy file is `/sys/fs/selinux/policy`
```
make all
./dispol <policy_file>
```

@ -0,0 +1 @@
https://github.com/dracutdevs/dracut/tree/master/skipcpio

@ -0,0 +1,122 @@
/* dracut-install.c -- install files and executables
Copyright (C) 2012 Harald Hoyer
Copyright (C) 2012 Red Hat, Inc. All rights reserved.
This program is free software: you can redistribute it and/or modify
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#define PROGRAM_VERSION_STRING "1"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define CPIO_END "TRAILER!!!"
#define CPIO_ENDLEN (sizeof(CPIO_END)-1)
static char buf[CPIO_ENDLEN * 2 + 1];
int main(int argc, char **argv)
{
FILE *f;
size_t s;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(1);
}
f = fopen(argv[1], "r");
if (f == NULL) {
fprintf(stderr, "Cannot open file '%s'\n", argv[1]);
exit(1);
}
s = fread(buf, 6, 1, f);
if (s <= 0) {
fprintf(stderr, "Read error from file '%s'\n", argv[1]);
fclose(f);
exit(1);
}
fseek(f, 0, SEEK_SET);
/* check, if this is a cpio archive */
if (buf[0] == '0' && buf[1] == '7' && buf[2] == '0' && buf[3] == '7' && buf[4] == '0' && buf[5] == '1') {
long pos = 0;
/* Search for CPIO_END */
do {
char *h;
fseek(f, pos, SEEK_SET);
buf[sizeof(buf) - 1] = 0;
s = fread(buf, CPIO_ENDLEN, 2, f);
if (s <= 0)
break;
h = strstr(buf, CPIO_END);
if (h) {
pos = (h - buf) + pos + CPIO_ENDLEN;
fseek(f, pos, SEEK_SET);
break;
}
pos += CPIO_ENDLEN;
} while (!feof(f));
if (feof(f)) {
/* CPIO_END not found, just cat the whole file */
fseek(f, 0, SEEK_SET);
} else {
/* skip zeros */
while (!feof(f)) {
size_t i;
buf[sizeof(buf) - 1] = 0;
s = fread(buf, 1, sizeof(buf) - 1, f);
if (s <= 0)
break;
for (i = 0; (i < s) && (buf[i] == 0); i++) ;
if (buf[i] != 0) {
pos += i;
fseek(f, pos, SEEK_SET);
break;
}
pos += s;
}
}
}
/* cat out the rest */
while (!feof(f)) {
s = fread(buf, 1, sizeof(buf), f);
if (s <= 0)
break;
s = fwrite(buf, 1, s, stdout);
if (s <= 0)
break;
}
fclose(f);
return EXIT_SUCCESS;
}

@ -0,0 +1,18 @@
plugins {
`cpp-application`
}
application {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
dependencies {
implementation(project(":aosp:libsparse:sparse"))
}
}
tasks.withType(LinkExecutable::class.java).configureEach {
linkerArgs.add("-lz")
}
tasks.withType(CppCompile::class.java).configureEach {
compilerArgs.add("-std=c++17")
}

@ -0,0 +1,137 @@
/*
* Copyright (C) 2013 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.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sparse/sparse.h>
#include "backed_block.h"
#include "sparse_file.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
#endif
void usage() {
fprintf(stderr, "Usage: append2simg <output> <input>\n");
}
int main(int argc, char* argv[]) {
int output;
int output_block;
char* output_path;
struct sparse_file* sparse_output;
int input;
char* input_path;
off64_t input_len;
int tmp_fd;
char* tmp_path;
int ret;
if (argc == 3) {
output_path = argv[1];
input_path = argv[2];
} else {
usage();
exit(-1);
}
ret = asprintf(&tmp_path, "%s.append2simg", output_path);
if (ret < 0) {
fprintf(stderr, "Couldn't allocate filename\n");
exit(-1);
}
output = open(output_path, O_RDWR | O_BINARY);
if (output < 0) {
fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
exit(-1);
}
sparse_output = sparse_file_import_auto(output, false, true);
if (!sparse_output) {
fprintf(stderr, "Couldn't import output file\n");
exit(-1);
}
input = open(input_path, O_RDONLY | O_BINARY);
if (input < 0) {
fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
exit(-1);
}
input_len = lseek64(input, 0, SEEK_END);
if (input_len < 0) {
fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
exit(-1);
} else if (input_len % sparse_output->block_size) {
fprintf(stderr, "Input file is not a multiple of the output file's block size");
exit(-1);
}
lseek64(input, 0, SEEK_SET);
output_block = sparse_output->len / sparse_output->block_size;
if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
fprintf(stderr, "Couldn't add input file\n");
exit(-1);
}
sparse_output->len += input_len;
tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
if (tmp_fd < 0) {
fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
exit(-1);
}
lseek64(output, 0, SEEK_SET);
if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
fprintf(stderr, "Failed to write sparse file\n");
exit(-1);
}
sparse_file_destroy(sparse_output);
close(tmp_fd);
close(output);
close(input);
ret = rename(tmp_path, output_path);
if (ret < 0) {
fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
exit(-1);
}
free(tmp_path);
exit(0);
}

@ -0,0 +1,18 @@
plugins {
`cpp-library`
}
library {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
linkage.set(listOf(Linkage.STATIC))
}
extensions.configure<CppLibrary> {
source.from(file("src/main/cpp"))
privateHeaders.from(file("src/main/headers"))
publicHeaders.from(file("src/main/public"))
}
tasks.withType(CppCompile::class.java).configureEach {
compilerArgs.add("-std=c++17")
}

@ -0,0 +1,128 @@
/*
* Copyright (C) 2018 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.
*/
#include "android-base/mapped_file.h"
#include <utility>
#include <errno.h>
namespace android {
namespace base {
static constexpr char kEmptyBuffer[] = {'0'};
static off64_t InitPageSize() {
#if defined(_WIN32)
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwAllocationGranularity;
#else
return sysconf(_SC_PAGE_SIZE);
#endif
}
std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
int prot) {
#if defined(_WIN32)
return FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
#else
return FromOsHandle(fd.get(), offset, length, prot);
#endif
}
std::unique_ptr<MappedFile> MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length,
int prot) {
static const off64_t page_size = InitPageSize();
size_t slop = offset % page_size;
off64_t file_offset = offset - slop;
off64_t file_length = length + slop;
#if defined(_WIN32)
HANDLE handle = CreateFileMappingW(
h, nullptr, (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
if (handle == nullptr) {
// http://b/119818070 "app crashes when reading asset of zero length".
// Return a MappedFile that's only valid for reading the size.
if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
return std::unique_ptr<MappedFile>(
new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0, nullptr));
}
return nullptr;
}
void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
file_offset, file_length);
if (base == nullptr) {
CloseHandle(handle);
return nullptr;
}
return std::unique_ptr<MappedFile>(
new MappedFile(static_cast<char*>(base), length, slop, handle));
#else
void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
if (base == MAP_FAILED) {
// http://b/119818070 "app crashes when reading asset of zero length".
// mmap fails with EINVAL for a zero length region.
if (errno == EINVAL && length == 0) {
return std::unique_ptr<MappedFile>(new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0));
}
return nullptr;
}
return std::unique_ptr<MappedFile>(new MappedFile(static_cast<char*>(base), length, slop));
#endif
}
MappedFile::MappedFile(MappedFile&& other)
: base_(std::exchange(other.base_, nullptr)),
size_(std::exchange(other.size_, 0)),
offset_(std::exchange(other.offset_, 0))
#ifdef _WIN32
,
handle_(std::exchange(other.handle_, nullptr))
#endif
{
}
MappedFile& MappedFile::operator=(MappedFile&& other) {
Close();
base_ = std::exchange(other.base_, nullptr);
size_ = std::exchange(other.size_, 0);
offset_ = std::exchange(other.offset_, 0);
#ifdef _WIN32
handle_ = std::exchange(other.handle_, nullptr);
#endif
return *this;
}
MappedFile::~MappedFile() {
Close();
}
void MappedFile::Close() {
#if defined(_WIN32)
if (base_ != nullptr && size_ != 0) UnmapViewOfFile(base_);
if (handle_ != nullptr) CloseHandle(handle_);
handle_ = nullptr;
#else
if (base_ != nullptr && size_ != 0) munmap(base_, size_ + offset_);
#endif
base_ = nullptr;
offset_ = size_ = 0;
}
} // namespace base
} // namespace android

@ -0,0 +1,85 @@
/*
* =====================================================================================
*
* Filename: stringprintf.cpp
*
* Description:
*
* Version: 1.0
* Created: 08/14/2019 11:09:23 AM
* Revision: none
* Compiler: gcc
*
* Author: YOUR NAME (),
* Organization:
*
* =====================================================================================
*/
#include <cstdarg>
#include <cstdio>
#include <string>
namespace android {
namespace base {
void StringAppendV(std::string* dst, const char* format, va_list ap) {
// First try with a small fixed size buffer
char space[1024];
// It's possible for methods that use a va_list to invalidate
// the data in it upon use. The fix is to make a copy
// of the structure before using it and use that copy instead.
va_list backup_ap;
va_copy(backup_ap, ap);
int result = vsnprintf(space, sizeof(space), format, backup_ap);
va_end(backup_ap);
if (result < static_cast<int>(sizeof(space))) {
if (result >= 0) {
// Normal case -- everything fit.
dst->append(space, result);
return;
}
if (result < 0) {
// Just an error.
return;
}
}
// Increase the buffer size to the size requested by vsnprintf,
// plus one for the closing \0.
int length = result + 1;
char* buf = new char[length];
// Restore the va_list before we use it again
va_copy(backup_ap, ap);
result = vsnprintf(buf, length, format, backup_ap);
va_end(backup_ap);
if (result >= 0 && result < length) {
// It fit
dst->append(buf, result);
}
delete[] buf;
}
std::string StringPrintf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::string result;
StringAppendV(&result, fmt, ap);
va_end(ap);
return result;
}
void StringAppendF(std::string* dst, const char* format, ...) {
va_list ap;
va_start(ap, format);
StringAppendV(dst, format, ap);
va_end(ap);
}
} // namespace base
} // namespace android

@ -0,0 +1,146 @@
/*
* Copyright (C) 2015 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.
*/
#pragma once
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
#include <utility>
// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) \
({ \
decltype(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; \
})
#endif
// A macro to disallow the copy constructor and operator= functions
// This must be placed in the private: declarations for a class.
//
// For disallowing only assign or copy, delete the relevant operator or
// constructor, for example:
// void operator=(const TypeName&) = delete;
// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
// semantically, one should either use disallow both or neither. Try to
// avoid these in new code.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function. In these rare
// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
// due to a limitation in C++'s template system. The limitation might
// eventually be removed, but it hasn't happened yet.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().f)
// Changing this definition will cause you a lot of pain. A majority of
// vendor code defines LIKELY and UNLIKELY this way, and includes
// this header through an indirect path.
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define WARN_UNUSED __attribute__((warn_unused_result))
// A deprecated function to call to create a false use of the parameter, for
// example:
// int foo(int x) { UNUSED(x); return 10; }
// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
template <typename... T>
void UNUSED(const T&...) {
}
// An attribute to place on a parameter to a function, for example:
// int foo(int x ATTRIBUTE_UNUSED) { return 10; }
// to avoid compiler warnings.
#define ATTRIBUTE_UNUSED __attribute__((__unused__))
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
// between switch labels:
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in
// // comments.
// } else {
// return x;
// }
// case 42:
// ...
//
// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
// followed by a semicolon. It is designed to mimic control-flow statements
// like 'break;', so it can be placed in most places where 'break;' can, but
// only if there are no statements on the execution path between it and the
// next switch label.
//
// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
// [[clang::fallthrough]] attribute, which is analysed when performing switch
// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
// documentation on language extensions for details:
// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
//
// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
// effect on diagnostics.
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
// Current ABI string
#if defined(__arm__)
#define ABI_STRING "arm"
#elif defined(__aarch64__)
#define ABI_STRING "arm64"
#elif defined(__i386__)
#define ABI_STRING "x86"
#elif defined(__x86_64__)
#define ABI_STRING "x86_64"
#endif

@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 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.
*/
#pragma once
#include <sys/types.h>
#include <memory>
#include "android-base/macros.h"
#include "android-base/off64_t.h"
#include "android-base/unique_fd.h"
#if defined(_WIN32)
#include <windows.h>
#define PROT_READ 1
#define PROT_WRITE 2
using os_handle = HANDLE;
#else
#include <sys/mman.h>
using os_handle = int;
#endif
namespace android {
namespace base {
/**
* A region of a file mapped into memory (for grepping: also known as MmapFile or file mapping).
*/
class MappedFile {
public:
/**
* Creates a new mapping of the file pointed to by `fd`. Unlike the underlying OS primitives,
* `offset` does not need to be page-aligned. If `PROT_WRITE` is set in `prot`, the mapping
* will be writable, otherwise it will be read-only. Mappings are always `MAP_SHARED`.
*/
static std::unique_ptr<MappedFile> FromFd(borrowed_fd fd, off64_t offset, size_t length,
int prot);
/**
* Same thing, but using the raw OS file handle instead of a CRT wrapper.
*/
static std::unique_ptr<MappedFile> FromOsHandle(os_handle h, off64_t offset, size_t length,
int prot);
/**
* Removes the mapping.
*/
~MappedFile();
/**
* Not copyable but movable.
*/
MappedFile(MappedFile&& other);
MappedFile& operator=(MappedFile&& other);
char* data() const { return base_ + offset_; }
size_t size() const { return size_; }
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);
void Close();
char* base_;
size_t size_;
size_t offset_;
#if defined(_WIN32)
MappedFile(char* base, size_t size, size_t offset, HANDLE handle)
: base_(base), size_(size), offset_(offset), handle_(handle) {}
HANDLE handle_;
#else
MappedFile(char* base, size_t size, size_t offset) : base_(base), size_(size), offset_(offset) {}
#endif
};
} // namespace base
} // namespace android

@ -0,0 +1,22 @@
/*
* Copyright (C) 2018 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.
*/
#pragma once
#if defined(__APPLE__)
/** Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
typedef off_t off64_t;
#endif

@ -0,0 +1,40 @@
/*
* Copyright (C) 2011 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.
*/
#pragma once
#include <stdarg.h>
#include <string>
namespace android {
namespace base {
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking.
// Returns a string corresponding to printf-like formatting of the arguments.
std::string StringPrintf(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendF(std::string* dst, const char* fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendV(std::string* dst, const char* format, va_list ap)
__attribute__((__format__(__printf__, 2, 0)));
} // namespace base
} // namespace android

@ -0,0 +1,293 @@
/*
* Copyright (C) 2015 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.
*/
#pragma once
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <sys/socket.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
// DO NOT INCLUDE OTHER LIBBASE HEADERS!
// This file gets used in libbinder, and libbinder is used everywhere.
// Including other headers from libbase frequently results in inclusion of
// android-base/macros.h, which causes macro collisions.
// Container for a file descriptor that automatically closes the descriptor as
// it goes out of scope.
//
// unique_fd ufd(open("/some/path", "r"));
// if (ufd.get() == -1) return error;
//
// // Do something useful, possibly including 'return'.
//
// return 0; // Descriptor is closed for you.
//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.
#if defined(__BIONIC__)
#include <android/fdsan.h>
#endif
namespace android {
namespace base {
struct DefaultCloser {
#if defined(__BIONIC__)
static void Tag(int fd, void* old_addr, void* new_addr) {
if (android_fdsan_exchange_owner_tag) {
uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
reinterpret_cast<uint64_t>(old_addr));
uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
reinterpret_cast<uint64_t>(new_addr));
android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
}
}
static void Close(int fd, void* addr) {
if (android_fdsan_close_with_tag) {
uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
reinterpret_cast<uint64_t>(addr));
android_fdsan_close_with_tag(fd, tag);
} else {
close(fd);
}
}
#else
static void Close(int fd) {
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
// else's fd.
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
::close(fd);
}
#endif
};
template <typename Closer>
class unique_fd_impl final {
public:
unique_fd_impl() {}
explicit unique_fd_impl(int fd) { reset(fd); }
~unique_fd_impl() { reset(); }
unique_fd_impl(const unique_fd_impl&) = delete;
void operator=(const unique_fd_impl&) = delete;
unique_fd_impl(unique_fd_impl&& other) noexcept { reset(other.release()); }
unique_fd_impl& operator=(unique_fd_impl&& s) noexcept {
int fd = s.fd_;
s.fd_ = -1;
reset(fd, &s);
return *this;
}
[[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); }
int get() const { return fd_; }
#if !defined(ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION)
// unique_fd's operator int is dangerous, but we have way too much code that
// depends on it, so make this opt-in at first.
operator int() const { return get(); } // NOLINT
#endif
bool operator>=(int rhs) const { return get() >= rhs; }
bool operator<(int rhs) const { return get() < rhs; }
bool operator==(int rhs) const { return get() == rhs; }
bool operator!=(int rhs) const { return get() != rhs; }
bool operator==(const unique_fd_impl& rhs) const { return get() == rhs.get(); }
bool operator!=(const unique_fd_impl& rhs) const { return get() != rhs.get(); }
// Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
bool operator!() const = delete;
bool ok() const { return get() >= 0; }
int release() __attribute__((warn_unused_result)) {
tag(fd_, this, nullptr);
int ret = fd_;
fd_ = -1;
return ret;
}
private:
void reset(int new_value, void* previous_tag) {
int previous_errno = errno;
if (fd_ != -1) {
close(fd_, this);
}
fd_ = new_value;
if (new_value != -1) {
tag(new_value, previous_tag, this);
}
errno = previous_errno;
}
int fd_ = -1;
// Template magic to use Closer::Tag if available, and do nothing if not.
// If Closer::Tag exists, this implementation is preferred, because int is a better match.
// If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
template <typename T = Closer>
static auto tag(int fd, void* old_tag, void* new_tag)
-> decltype(T::Tag(fd, old_tag, new_tag), void()) {
T::Tag(fd, old_tag, new_tag);
}
template <typename T = Closer>
static void tag(long, void*, void*) {
// No-op.
}
// Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
template <typename T = Closer>
static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
T::Close(fd, tag_value);
}
template <typename T = Closer>
static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
T::Close(fd);
}
};
using unique_fd = unique_fd_impl<DefaultCloser>;
#if !defined(_WIN32)
// Inline functions, so that they can be used header-only.
template <typename Closer>
inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write,
int flags = O_CLOEXEC) {
int pipefd[2];
#if defined(__linux__)
if (pipe2(pipefd, flags) != 0) {
return false;
}
#else // defined(__APPLE__)
if (flags & ~(O_CLOEXEC | O_NONBLOCK)) {
return false;
}
if (pipe(pipefd) != 0) {
return false;
}
if (flags & O_CLOEXEC) {
if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
close(pipefd[0]);
close(pipefd[1]);
return false;
}
}
if (flags & O_NONBLOCK) {
if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 || fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
close(pipefd[0]);
close(pipefd[1]);
return false;
}
}
#endif
read->reset(pipefd[0]);
write->reset(pipefd[1]);
return true;
}
template <typename Closer>
inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
unique_fd_impl<Closer>* right) {
int sockfd[2];
if (socketpair(domain, type, protocol, sockfd) != 0) {
return false;
}
left->reset(sockfd[0]);
right->reset(sockfd[1]);
return true;
}
template <typename Closer>
inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
return Socketpair(AF_UNIX, type, 0, left, right);
}
// Using fdopen with unique_fd correctly is more annoying than it should be,
// because fdopen doesn't close the file descriptor received upon failure.
inline FILE* Fdopen(unique_fd&& ufd, const char* mode) {
int fd = ufd.release();
FILE* file = fdopen(fd, mode);
if (!file) {
close(fd);
}
return file;
}
// Using fdopendir with unique_fd correctly is more annoying than it should be,
// because fdopen doesn't close the file descriptor received upon failure.
inline DIR* Fdopendir(unique_fd&& ufd) {
int fd = ufd.release();
DIR* dir = fdopendir(fd);
if (dir == nullptr) {
close(fd);
}
return dir;
}
#endif // !defined(_WIN32)
// A wrapper type that can be implicitly constructed from either int or unique_fd.
struct borrowed_fd {
/* implicit */ borrowed_fd(int fd) : fd_(fd) {} // NOLINT
template <typename T>
/* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {} // NOLINT
int get() const { return fd_; }
bool operator>=(int rhs) const { return get() >= rhs; }
bool operator<(int rhs) const { return get() < rhs; }
bool operator==(int rhs) const { return get() == rhs; }
bool operator!=(int rhs) const { return get() != rhs; }
private:
int fd_ = -1;
};
} // namespace base
} // namespace android
template <typename T>
int close(const android::base::unique_fd_impl<T>&)
__attribute__((__unavailable__("close called on unique_fd")));
template <typename T>
FILE* fdopen(const android::base::unique_fd_impl<T>&, const char* mode)
__attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the "
"unique_fd, or use android::base::Fdopen to pass ownership")));
template <typename T>
DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
__unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
"unique_fd, or use android::base::Fdopendir to pass ownership")));

@ -0,0 +1,9 @@
/*
* This C++ source file was generated by the Gradle 'init' task.
*/
#include <cassert>
int main() {
return 0;
}

@ -0,0 +1,18 @@
plugins {
`cpp-application`
}
application {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
dependencies {
implementation(project(":aosp:libsparse:sparse"))
}
}
tasks.withType(LinkExecutable::class.java).configureEach {
linkerArgs.add("-lz")
}
tasks.withType(CppCompile::class.java).configureEach {
compilerArgs.add("-std=c++17")
}

@ -0,0 +1,112 @@
/*
* Copyright (C) 2012 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.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sparse/sparse.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
#endif
void usage() {
fprintf(stderr, "Usage: img2simg <raw_image_file> <sparse_image_file> [<block_size>]\n");
}
int main(int argc, char* argv[]) {
int in;
int out;
int ret;
struct sparse_file* s;
unsigned int block_size = 4096;
off64_t len;
if (argc < 3 || argc > 4) {
usage();
exit(-1);
}
if (argc == 4) {
block_size = atoi(argv[3]);
}
if (block_size < 1024 || block_size % 4 != 0) {
usage();
exit(-1);
}
if (strcmp(argv[1], "-") == 0) {
in = STDIN_FILENO;
} else {
in = open(argv[1], O_RDONLY | O_BINARY);
if (in < 0) {
fprintf(stderr, "Cannot open input file %s\n", argv[1]);
exit(-1);
}
}
if (strcmp(argv[2], "-") == 0) {
out = STDOUT_FILENO;
} else {
out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
if (out < 0) {
fprintf(stderr, "Cannot open output file %s\n", argv[2]);
exit(-1);
}
}
len = lseek64(in, 0, SEEK_END);
lseek64(in, 0, SEEK_SET);
s = sparse_file_new(block_size, len);
if (!s) {
fprintf(stderr, "Failed to create sparse file\n");
exit(-1);
}
sparse_file_verbose(s);
ret = sparse_file_read(s, in, false, false);
if (ret) {
fprintf(stderr, "Failed to read file\n");
exit(-1);
}
ret = sparse_file_write(s, out, false, true, false);
if (ret) {
fprintf(stderr, "Failed to write sparse file\n");
exit(-1);
}
close(in);
close(out);
exit(0);
}

@ -0,0 +1,21 @@
plugins {
`cpp-application`
}
application {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
dependencies {
implementation(project(":aosp:libsparse:sparse"))
}
}
tasks.withType(LinkExecutable::class.java).configureEach {
linkerArgs.add("-lz")
}
tasks.register<CppCompile>("hello") {
}
tasks.withType(CppCompile::class.java).configureEach {
compilerArgs.add("-std=c++17")
}

@ -0,0 +1,86 @@
/*
* Copyright (C) 2010 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.
*/
#include <sparse/sparse.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
void usage() {
fprintf(stderr, "Usage: simg2img <sparse_image_files> <raw_image_file>\n");
}
int main(int argc, char* argv[]) {
int in;
int out;
int i;
struct sparse_file* s;
if (argc < 3) {
usage();
exit(-1);
}
out = open(argv[argc - 1], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
if (out < 0) {
fprintf(stderr, "Cannot open output file %s\n", argv[argc - 1]);
exit(-1);
}
for (i = 1; i < argc - 1; i++) {
if (strcmp(argv[i], "-") == 0) {
in = STDIN_FILENO;
} else {
in = open(argv[i], O_RDONLY | O_BINARY);
if (in < 0) {
fprintf(stderr, "Cannot open input file %s\n", argv[i]);
exit(-1);
}
}
s = sparse_file_import(in, true, false);
if (!s) {
fprintf(stderr, "Failed to read sparse file\n");
exit(-1);
}
if (lseek(out, 0, SEEK_SET) == -1) {
perror("lseek failed");
exit(EXIT_FAILURE);
}
if (sparse_file_write(s, out, false, false, false) < 0) {
fprintf(stderr, "Cannot write output file\n");
exit(-1);
}
sparse_file_destroy(s);
close(in);
}
close(out);
exit(0);
}

@ -0,0 +1,18 @@
plugins {
`cpp-application`
}
application {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
dependencies {
implementation(project(":aosp:libsparse:sparse"))
}
}
tasks.withType(LinkExecutable::class.java).configureEach {
linkerArgs.add("-lz")
}
tasks.withType(CppCompile::class.java).configureEach {
compilerArgs.add("-std=c++17")
}

@ -0,0 +1,111 @@
/*
* Copyright (C) 2012 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.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sparse/sparse.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
void usage() {
fprintf(stderr, "Usage: simg2simg <sparse image file> <sparse_image_file> <max_size>\n");
}
int main(int argc, char* argv[]) {
int in;
int out;
int i;
int ret;
struct sparse_file* s;
int64_t max_size;
struct sparse_file** out_s;
int files;
char filename[4096];
if (argc != 4) {
usage();
exit(-1);
}
max_size = atoll(argv[3]);
in = open(argv[1], O_RDONLY | O_BINARY);
if (in < 0) {
fprintf(stderr, "Cannot open input file %s\n", argv[1]);
exit(-1);
}
s = sparse_file_import(in, true, false);
if (!s) {
fprintf(stderr, "Failed to import sparse file\n");
exit(-1);
}
files = sparse_file_resparse(s, max_size, nullptr, 0);
if (files < 0) {
fprintf(stderr, "Failed to resparse\n");
exit(-1);
}
out_s = (sparse_file**) calloc(sizeof(struct sparse_file*), files);
if (!out_s) {
fprintf(stderr, "Failed to allocate sparse file array\n");
exit(-1);
}
files = sparse_file_resparse(s, max_size, out_s, files);
if (files < 0) {
fprintf(stderr, "Failed to resparse\n");
exit(-1);
}
for (i = 0; i < files; i++) {
ret = snprintf(filename, sizeof(filename), "%s.%d", argv[2], i);
if (ret >= (int)sizeof(filename)) {
fprintf(stderr, "Filename too long\n");
exit(-1);
}
out = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
if (out < 0) {
fprintf(stderr, "Cannot open output file %s\n", argv[2]);
exit(-1);
}
ret = sparse_file_write(out_s[i], out, false, true, false);
if (ret) {
fprintf(stderr, "Failed to write sparse file\n");
exit(-1);
}
close(out);
}
close(in);
exit(0);
}

@ -0,0 +1,24 @@
plugins {
`cpp-library`
}
library {
targetMachines.set(listOf(machines.linux.x86_64, machines.macOS.x86_64))
linkage.set(listOf(Linkage.STATIC))
dependencies {
implementation(project(":aosp:libsparse:base"))
}
}
tasks.withType(CppCompile::class.java).configureEach {
macros.put("NDEBUG", null)
compilerArgs.add("-Wall")
compilerArgs.add("-std=c++17")
}
tasks.withType(LinkSharedLibrary::class.java).configureEach {
linkerArgs.add("-lz")
}
tasks.withType(CreateStaticLibrary::class.java).configureEach {
}

@ -0,0 +1,84 @@
// Copyright 2010 The Android Open Source Project
cc_library {
name: "libsparse",
host_supported: true,
recovery_available: true,
unique_host_soname: true,
srcs: [
"backed_block.cpp",
"output_file.cpp",
"sparse.cpp",
"sparse_crc32.cpp",
"sparse_err.cpp",
"sparse_read.cpp",
],
cflags: ["-Werror"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
shared_libs: [
"libz",
"libbase",
],
target: {
windows: {
enabled: true,
},
},
}
cc_binary {
name: "simg2img",
host_supported: true,
srcs: [
"simg2img.cpp",
"sparse_crc32.cpp",
],
static_libs: [
"libsparse",
"libz",
"libbase",
],
cflags: ["-Werror"],
}
cc_binary {
name: "img2simg",
host_supported: true,
srcs: ["img2simg.cpp"],
static_libs: [
"libsparse",
"libz",
"libbase",
],
cflags: ["-Werror"],
}
cc_binary_host {
name: "append2simg",
srcs: ["append2simg.cpp"],
static_libs: [
"libsparse",
"libz",
"libbase",
],
cflags: ["-Werror"],
}
python_binary_host {
name: "simg_dump.py",
main: "simg_dump.py",
srcs: ["simg_dump.py"],
version: {
py2: {
embedded_launcher: true,
enabled: true,
},
py3: {
enabled: false,
},
},
}

@ -0,0 +1,380 @@
/*
* Copyright (C) 2010 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.
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "backed_block.h"
#include "sparse_defs.h"
struct backed_block {
unsigned int block;
unsigned int len;
enum backed_block_type type;
union {
struct {
void* data;
} data;
struct {
char* filename;
int64_t offset;
} file;
struct {
int fd;
int64_t offset;
} fd;
struct {
uint32_t val;
} fill;
};
struct backed_block* next;
};
struct backed_block_list {
struct backed_block* data_blocks;
struct backed_block* last_used;
unsigned int block_size;
};
struct backed_block* backed_block_iter_new(struct backed_block_list* bbl) {
return bbl->data_blocks;
}
struct backed_block* backed_block_iter_next(struct backed_block* bb) {
return bb->next;
}
unsigned int backed_block_len(struct backed_block* bb) {
return bb->len;
}
unsigned int backed_block_block(struct backed_block* bb) {
return bb->block;
}
void* backed_block_data(struct backed_block* bb) {
assert(bb->type == BACKED_BLOCK_DATA);
return bb->data.data;
}
const char* backed_block_filename(struct backed_block* bb) {
assert(bb->type == BACKED_BLOCK_FILE);
return bb->file.filename;
}
int backed_block_fd(struct backed_block* bb) {
assert(bb->type == BACKED_BLOCK_FD);
return bb->fd.fd;
}
int64_t backed_block_file_offset(struct backed_block* bb) {
assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
if (bb->type == BACKED_BLOCK_FILE) {
return bb->file.offset;
} else { /* bb->type == BACKED_BLOCK_FD */
return bb->fd.offset;
}
}
uint32_t backed_block_fill_val(struct backed_block* bb) {
assert(bb->type == BACKED_BLOCK_FILL);
return bb->fill.val;
}
enum backed_block_type backed_block_type(struct backed_block* bb) {
return bb->type;
}
void backed_block_destroy(struct backed_block* bb) {
if (bb->type == BACKED_BLOCK_FILE) {
free(bb->file.filename);
}
free(bb);
}
struct backed_block_list* backed_block_list_new(unsigned int block_size) {
struct backed_block_list* b =
reinterpret_cast<backed_block_list*>(calloc(sizeof(struct backed_block_list), 1));
b->block_size = block_size;
return b;
}
void backed_block_list_destroy(struct backed_block_list* bbl) {
if (bbl->data_blocks) {
struct backed_block* bb = bbl->data_blocks;
while (bb) {
struct backed_block* next = bb->next;
backed_block_destroy(bb);
bb = next;
}
}
free(bbl);
}
void backed_block_list_move(struct backed_block_list* from, struct backed_block_list* to,
struct backed_block* start, struct backed_block* end) {
struct backed_block* bb;
if (start == nullptr) {
start = from->data_blocks;
}
if (!end) {
for (end = start; end && end->next; end = end->next)
;
}
if (start == nullptr || end == nullptr) {
return;
}
from->last_used = nullptr;
to->last_used = nullptr;
if (from->data_blocks == start) {
from->data_blocks = end->next;
} else {
for (bb = from->data_blocks; bb; bb = bb->next) {
if (bb->next == start) {
bb->next = end->next;
break;
}
}
}
if (!to->data_blocks) {
to->data_blocks = start;
end->next = nullptr;
} else {
for (bb = to->data_blocks; bb; bb = bb->next) {
if (!bb->next || bb->next->block > start->block) {
end->next = bb->next;
bb->next = start;
break;
}
}
}
}
/* may free b */
static int merge_bb(struct backed_block_list* bbl, struct backed_block* a, struct backed_block* b) {
unsigned int block_len;
/* Block doesn't exist (possible if one block is the last block) */
if (!a || !b) {
return -EINVAL;
}
assert(a->block < b->block);
/* Blocks are of different types */
if (a->type != b->type) {
return -EINVAL;
}
/* Blocks are not adjacent */
block_len = a->len / bbl->block_size; /* rounds down */
if (a->block + block_len != b->block) {
return -EINVAL;
}
switch (a->type) {
case BACKED_BLOCK_DATA:
/* Don't support merging data for now */
return -EINVAL;
case BACKED_BLOCK_FILL:
if (a->fill.val != b->fill.val) {
return -EINVAL;
}
break;
case BACKED_BLOCK_FILE:
/* Already make sure b->type is BACKED_BLOCK_FILE */
if (strcmp(a->file.filename, b->file.filename) || a->file.offset + a->len != b->file.offset) {
return -EINVAL;
}
break;
case BACKED_BLOCK_FD:
if (a->fd.fd != b->fd.fd || a->fd.offset + a->len != b->fd.offset) {
return -EINVAL;
}
break;
}
/* Blocks are compatible and adjacent, with a before b. Merge b into a,
* and free b */
a->len += b->len;
a->next = b->next;
backed_block_destroy(b);
return 0;
}
static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
struct backed_block* bb;
if (bbl->data_blocks == nullptr) {
bbl->data_blocks = new_bb;
return 0;
}
if (bbl->data_blocks->block > new_bb->block) {
new_bb->next = bbl->data_blocks;
bbl->data_blocks = new_bb;
return 0;
}
/* Optimization: blocks are mostly queued in sequence, so save the
pointer to the last bb that was added, and start searching from
there if the next block number is higher */
if (bbl->last_used && new_bb->block > bbl->last_used->block)
bb = bbl->last_used;
else
bb = bbl->data_blocks;
bbl->last_used = new_bb;
for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
;
if (bb->next == nullptr) {
bb->next = new_bb;
} else {
new_bb->next = bb->next;
bb->next = new_bb;
}
merge_bb(bbl, new_bb, new_bb->next);
if (!merge_bb(bbl, bb, new_bb)) {
/* new_bb destroyed, point to retained as last_used */
bbl->last_used = bb;
}
return 0;
}
/* Queues a fill block of memory to be written to the specified data blocks */
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
}
bb->block = block;
bb->len = len;
bb->type = BACKED_BLOCK_FILL;
bb->fill.val = fill_val;
bb->next = nullptr;
return queue_bb(bbl, bb);
}
/* Queues a block of memory to be written to the specified data blocks */
int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
}
bb->block = block;
bb->len = len;
bb->type = BACKED_BLOCK_DATA;
bb->data.data = data;
bb->next = nullptr;
return queue_bb(bbl, bb);
}
/* Queues a chunk of a file on disk to be written to the specified data blocks */
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
unsigned int len, unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
}
bb->block = block;
bb->len = len;
bb->type = BACKED_BLOCK_FILE;
bb->file.filename = strdup(filename);
bb->file.offset = offset;
bb->next = nullptr;
return queue_bb(bbl, bb);
}
/* Queues a chunk of a fd to be written to the specified data blocks */
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
}
bb->block = block;
bb->len = len;
bb->type = BACKED_BLOCK_FD;
bb->fd.fd = fd;
bb->fd.offset = offset;
bb->next = nullptr;
return queue_bb(bbl, bb);
}
int backed_block_split(struct backed_block_list* bbl, struct backed_block* bb,
unsigned int max_len) {
struct backed_block* new_bb;
max_len = ALIGN_DOWN(max_len, bbl->block_size);
if (bb->len <= max_len) {
return 0;
}
new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
if (new_bb == nullptr) {
return -ENOMEM;
}
*new_bb = *bb;
new_bb->len = bb->len - max_len;
new_bb->block = bb->block + max_len / bbl->block_size;
new_bb->next = bb->next;
bb->next = new_bb;
bb->len = max_len;
switch (bb->type) {
case BACKED_BLOCK_DATA:
new_bb->data.data = (char*)bb->data.data + max_len;
break;
case BACKED_BLOCK_FILE:
new_bb->file.offset += max_len;
break;
case BACKED_BLOCK_FD:
new_bb->fd.offset += max_len;
break;
case BACKED_BLOCK_FILL:
break;
}
return 0;
}

@ -0,0 +1,23 @@
/*
* 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.
*/
#ifndef _LIBSPARSE_DEFS_H_
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
#endif /* _LIBSPARSE_DEFS_H_ */

@ -0,0 +1,676 @@
/*
* Copyright (C) 2010 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.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#include <algorithm>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <zlib.h>
#include "defs.h"
#include "output_file.h"
#include "sparse_crc32.h"
#include "sparse_format.h"
#include <android-base/mapped_file.h>
#ifndef _WIN32
#define O_BINARY 0
#else
#define ftruncate64 ftruncate
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define ftruncate64 ftruncate
#define off64_t off_t
#endif
#define SPARSE_HEADER_MAJOR_VER 1
#define SPARSE_HEADER_MINOR_VER 0
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
#define container_of(inner, outer_t, elem) ((outer_t*)((char*)(inner)-offsetof(outer_t, elem)))
struct output_file_ops {
int (*open)(struct output_file*, int fd);
int (*skip)(struct output_file*, int64_t);
int (*pad)(struct output_file*, int64_t);
int (*write)(struct output_file*, void*, size_t);
void (*close)(struct output_file*);
};
struct sparse_file_ops {
int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
int (*write_skip_chunk)(struct output_file* out, int64_t len);
int (*write_end_chunk)(struct output_file* out);
};
struct output_file {
int64_t cur_out_ptr;
unsigned int chunk_cnt;
uint32_t crc32;
struct output_file_ops* ops;
struct sparse_file_ops* sparse_ops;
int use_crc;
unsigned int block_size;
int64_t len;
char* zero_buf;
uint32_t* fill_buf;
char* buf;
};
struct output_file_gz {
struct output_file out;
gzFile gz_fd;
};
#define to_output_file_gz(_o) container_of((_o), struct output_file_gz, out)
struct output_file_normal {
struct output_file out;
int fd;
};
#define to_output_file_normal(_o) container_of((_o), struct output_file_normal, out)
struct output_file_callback {
struct output_file out;
void* priv;
int (*write)(void* priv, const void* buf, size_t len);
};
#define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out)
static int file_open(struct output_file* out, int fd) {
struct output_file_normal* outn = to_output_file_normal(out);
outn->fd = fd;
return 0;
}
static int file_skip(struct output_file* out, int64_t cnt) {
off64_t ret;
struct output_file_normal* outn = to_output_file_normal(out);
ret = lseek64(outn->fd, cnt, SEEK_CUR);
if (ret < 0) {
error_errno("lseek64");
return -1;
}
return 0;
}
static int file_pad(struct output_file* out, int64_t len) {
int ret;
struct output_file_normal* outn = to_output_file_normal(out);
ret = ftruncate64(outn->fd, len);
if (ret < 0) {
return -errno;
}
return 0;
}
static int file_write(struct output_file* out, void* data, size_t len) {
ssize_t ret;
struct output_file_normal* outn = to_output_file_normal(out);
while (len > 0) {
ret = write(outn->fd, data, len);
if (ret < 0) {
if (errno == EINTR) {
continue;
}
error_errno("write");
return -1;
}
data = (char*)data + ret;
len -= ret;
}
return 0;
}
static void file_close(struct output_file* out) {
struct output_file_normal* outn = to_output_file_normal(out);
free(outn);
}
static struct output_file_ops file_ops = {
.open = file_open,
.skip = file_skip,
.pad = file_pad,
.write = file_write,
.close = file_close,
};
static int gz_file_open(struct output_file* out, int fd) {
struct output_file_gz* outgz = to_output_file_gz(out);
outgz->gz_fd = gzdopen(fd, "wb9");
if (!outgz->gz_fd) {
error_errno("gzopen");
return -errno;
}
return 0;
}
static int gz_file_skip(struct output_file* out, int64_t cnt) {
off64_t ret;
struct output_file_gz* outgz = to_output_file_gz(out);
ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
if (ret < 0) {
error_errno("gzseek");
return -1;
}
return 0;
}
static int gz_file_pad(struct output_file* out, int64_t len) {
off64_t ret;
struct output_file_gz* outgz = to_output_file_gz(out);
ret = gztell(outgz->gz_fd);
if (ret < 0) {
return -1;
}
if (ret >= len) {
return 0;
}
ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
if (ret < 0) {
return -1;
}
gzwrite(outgz->gz_fd, "", 1);
return 0;
}
static int gz_file_write(struct output_file* out, void* data, size_t len) {
int ret;
struct output_file_gz* outgz = to_output_file_gz(out);
while (len > 0) {
ret = gzwrite(outgz->gz_fd, data, std::min<unsigned int>(len, (unsigned int)INT_MAX));
if (ret == 0) {
error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
return -1;
}
len -= ret;
data = (char*)data + ret;
}
return 0;
}
static void gz_file_close(struct output_file* out) {
struct output_file_gz* outgz = to_output_file_gz(out);
gzclose(outgz->gz_fd);
free(outgz);
}
static struct output_file_ops gz_file_ops = {
.open = gz_file_open,
.skip = gz_file_skip,
.pad = gz_file_pad,
.write = gz_file_write,
.close = gz_file_close,
};
static int callback_file_open(struct output_file* out __unused, int fd __unused) {
return 0;
}
static int callback_file_skip(struct output_file* out, int64_t off) {
struct output_file_callback* outc = to_output_file_callback(out);
int to_write;
int ret;
while (off > 0) {
to_write = std::min(off, (int64_t)INT_MAX);
ret = outc->write(outc->priv, nullptr, to_write);
if (ret < 0) {
return ret;
}
off -= to_write;
}
return 0;
}
static int callback_file_pad(struct output_file* out __unused, int64_t len __unused) {
return -1;
}
static int callback_file_write(struct output_file* out, void* data, size_t len) {
struct output_file_callback* outc = to_output_file_callback(out);
return outc->write(outc->priv, data, len);
}
static void callback_file_close(struct output_file* out) {
struct output_file_callback* outc = to_output_file_callback(out);
free(outc);
}
static struct output_file_ops callback_file_ops = {
.open = callback_file_open,
.skip = callback_file_skip,
.pad = callback_file_pad,
.write = callback_file_write,
.close = callback_file_close,
};
int read_all(int fd, void* buf, size_t len) {
size_t total = 0;
int ret;
char* ptr = reinterpret_cast<char*>(buf);
while (total < len) {
ret = read(fd, ptr, len - total);
if (ret < 0) return -errno;
if (ret == 0) return -EINVAL;
ptr += ret;
total += ret;
}
return 0;
}
static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
chunk_header_t chunk_header;
int ret;
if (skip_len % out->block_size) {
error("don't care size %" PRIi64 " is not a multiple of the block size %u", skip_len,
out->block_size);
return -1;
}
/* We are skipping data, so emit a don't care chunk. */
chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
chunk_header.reserved1 = 0;
chunk_header.chunk_sz = skip_len / out->block_size;
chunk_header.total_sz = CHUNK_HEADER_LEN;
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
if (ret < 0) return -1;
out->cur_out_ptr += skip_len;
out->chunk_cnt++;
return 0;
}
static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
chunk_header_t chunk_header;
int rnd_up_len, count;
int ret;
/* Round up the fill length to a multiple of the block size */
rnd_up_len = ALIGN(len, out->block_size);
/* Finally we can safely emit a chunk of data */
chunk_header.chunk_type = CHUNK_TYPE_FILL;
chunk_header.reserved1 = 0;
chunk_header.chunk_sz = rnd_up_len / out->block_size;
chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
if (ret < 0) return -1;
ret = out->ops->write(out, &fill_val, sizeof(fill_val));
if (ret < 0) return -1;
if (out->use_crc) {
count = out->block_size / sizeof(uint32_t);
while (count--) out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t));
}
out->cur_out_ptr += rnd_up_len;
out->chunk_cnt++;
return 0;
}
static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
chunk_header_t chunk_header;
int rnd_up_len, zero_len;
int ret;
/* Round up the data length to a multiple of the block size */
rnd_up_len = ALIGN(len, out->block_size);
zero_len = rnd_up_len - len;
/* Finally we can safely emit a chunk of data */
chunk_header.chunk_type = CHUNK_TYPE_RAW;
chunk_header.reserved1 = 0;
chunk_header.chunk_sz = rnd_up_len / out->block_size;
chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
if (ret < 0) return -1;
ret = out->ops->write(out, data, len);
if (ret < 0) return -1;
if (zero_len) {
ret = out->ops->write(out, out->zero_buf, zero_len);
if (ret < 0) return -1;
}
if (out->use_crc) {
out->crc32 = sparse_crc32(out->crc32, data, len);
if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
}
out->cur_out_ptr += rnd_up_len;
out->chunk_cnt++;
return 0;
}
int write_sparse_end_chunk(struct output_file* out) {
chunk_header_t chunk_header;
int ret;
if (out->use_crc) {
chunk_header.chunk_type = CHUNK_TYPE_CRC32;
chunk_header.reserved1 = 0;
chunk_header.chunk_sz = 0;
chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
if (ret < 0) {
return ret;
}
out->ops->write(out, &out->crc32, 4);
if (ret < 0) {
return ret;
}
out->chunk_cnt++;
}
return 0;
}
static struct sparse_file_ops sparse_file_ops = {
.write_data_chunk = write_sparse_data_chunk,
.write_fill_chunk = write_sparse_fill_chunk,
.write_skip_chunk = write_sparse_skip_chunk,
.write_end_chunk = write_sparse_end_chunk,
};
static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
int ret;
unsigned int rnd_up_len = ALIGN(len, out->block_size);
ret = out->ops->write(out, data, len);
if (ret < 0) {
return ret;
}
if (rnd_up_len > len) {
ret = out->ops->skip(out, rnd_up_len - len);
}
return ret;
}
static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
int ret;
unsigned int i;
unsigned int write_len;
/* Initialize fill_buf with the fill_val */
for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
out->fill_buf[i] = fill_val;
}
while (len) {
write_len = std::min(len, out->block_size);
ret = out->ops->write(out, out->fill_buf, write_len);
if (ret < 0) {
return ret;
}
len -= write_len;
}
return 0;
}
static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
return out->ops->skip(out, len);
}
int write_normal_end_chunk(struct output_file* out) {
return out->ops->pad(out, out->len);
}
static struct sparse_file_ops normal_file_ops = {
.write_data_chunk = write_normal_data_chunk,
.write_fill_chunk = write_normal_fill_chunk,
.write_skip_chunk = write_normal_skip_chunk,
.write_end_chunk = write_normal_end_chunk,
};
void output_file_close(struct output_file* out) {
out->sparse_ops->write_end_chunk(out);
free(out->zero_buf);
free(out->fill_buf);
out->zero_buf = nullptr;
out->fill_buf = nullptr;
out->ops->close(out);
}
static int output_file_init(struct output_file* out, int block_size, int64_t len, bool sparse,
int chunks, bool crc) {
int ret;
out->len = len;
out->block_size = block_size;
out->cur_out_ptr = 0LL;
out->chunk_cnt = 0;
out->crc32 = 0;
out->use_crc = crc;
out->zero_buf = reinterpret_cast<char*>(calloc(block_size, 1));
if (!out->zero_buf) {
error_errno("malloc zero_buf");
return -ENOMEM;
}
out->fill_buf = reinterpret_cast<uint32_t*>(calloc(block_size, 1));
if (!out->fill_buf) {
error_errno("malloc fill_buf");
ret = -ENOMEM;
goto err_fill_buf;
}
if (sparse) {
out->sparse_ops = &sparse_file_ops;
} else {
out->sparse_ops = &normal_file_ops;
}
if (sparse) {
sparse_header_t sparse_header = {
.magic = SPARSE_HEADER_MAGIC,
.major_version = SPARSE_HEADER_MAJOR_VER,
.minor_version = SPARSE_HEADER_MINOR_VER,
.file_hdr_sz = SPARSE_HEADER_LEN,
.chunk_hdr_sz = CHUNK_HEADER_LEN,
.blk_sz = out->block_size,
.total_blks = static_cast<unsigned>(DIV_ROUND_UP(out->len, out->block_size)),
.total_chunks = static_cast<unsigned>(chunks),
.image_checksum = 0};
if (out->use_crc) {
sparse_header.total_chunks++;
}
ret = out->ops->write(out, &sparse_header, sizeof(sparse_header));
if (ret < 0) {
goto err_write;
}
}
return 0;
err_write:
free(out->fill_buf);
err_fill_buf:
free(out->zero_buf);
return ret;
}
static struct output_file* output_file_new_gz(void) {
struct output_file_gz* outgz =
reinterpret_cast<struct output_file_gz*>(calloc(1, sizeof(struct output_file_gz)));
if (!outgz) {
error_errno("malloc struct outgz");
return nullptr;
}
outgz->out.ops = &gz_file_ops;
return &outgz->out;
}
static struct output_file* output_file_new_normal(void) {
struct output_file_normal* outn =
reinterpret_cast<struct output_file_normal*>(calloc(1, sizeof(struct output_file_normal)));
if (!outn) {
error_errno("malloc struct outn");
return nullptr;
}
outn->out.ops = &file_ops;
return &outn->out;
}
struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
unsigned int block_size, int64_t len, int gz __unused,
int sparse, int chunks, int crc) {
int ret;
struct output_file_callback* outc;
outc =
reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
if (!outc) {
error_errno("malloc struct outc");
return nullptr;
}
outc->out.ops = &callback_file_ops;
outc->priv = priv;
outc->write = write;
ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
if (ret < 0) {
free(outc);
return nullptr;
}
return &outc->out;
}
struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc) {
int ret;
struct output_file* out;
if (gz) {
out = output_file_new_gz();
} else {
out = output_file_new_normal();
}
if (!out) {
return nullptr;
}
out->ops->open(out, fd);
ret = output_file_init(out, block_size, len, sparse, chunks, crc);
if (ret < 0) {
free(out);
return nullptr;
}
return out;
}
/* Write a contiguous region of data blocks from a memory buffer */
int write_data_chunk(struct output_file* out, unsigned int len, void* data) {
return out->sparse_ops->write_data_chunk(out, len, data);
}
/* Write a contiguous region of data blocks with a fill value */
int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
return out->sparse_ops->write_fill_chunk(out, len, fill_val);
}
int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
if (!m) return -errno;
return out->sparse_ops->write_data_chunk(out, m->size(), m->data());
}
/* Write a contiguous region of data blocks from a file */
int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset) {
int ret;
int file_fd = open(file, O_RDONLY | O_BINARY);
if (file_fd < 0) {
return -errno;
}
ret = write_fd_chunk(out, len, file_fd, offset);
close(file_fd);
return ret;
}
int write_skip_chunk(struct output_file* out, int64_t len) {
return out->sparse_ops->write_skip_chunk(out, len);
}

@ -0,0 +1,46 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _OUTPUT_FILE_H_
#define _OUTPUT_FILE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <sparse/sparse.h>
struct output_file;
struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc);
struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc);
int write_data_chunk(struct output_file* out, unsigned int len, void* data);
int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset);
int write_skip_chunk(struct output_file* out, int64_t len);
void output_file_close(struct output_file* out);
int read_all(int fd, void* buf, size_t len);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,221 @@
#! /usr/bin/env python
# Copyright (C) 2012 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 csv
import getopt
import hashlib
import posixpath
import signal
import struct
import sys
def usage(argv0):
print("""
Usage: %s [-v] [-s] [-c <filename>] sparse_image_file ...
-v verbose output
-s show sha1sum of data blocks
-c <filename> save .csv file of blocks
""" % (argv0))
sys.exit(2)
def main():
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
me = posixpath.basename(sys.argv[0])
# Parse the command line
verbose = 0 # -v
showhash = 0 # -s
csvfilename = None # -c
try:
opts, args = getopt.getopt(sys.argv[1:],
"vsc:",
["verbose", "showhash", "csvfile"])
except getopt.GetoptError, e:
print(e)
usage(me)
for o, a in opts:
if o in ("-v", "--verbose"):
verbose += 1
elif o in ("-s", "--showhash"):
showhash = True
elif o in ("-c", "--csvfile"):
csvfilename = a
else:
print("Unrecognized option \"%s\"" % (o))
usage(me)
if not args:
print("No sparse_image_file specified")
usage(me)
if csvfilename:
csvfile = open(csvfilename, "wb")
csvwriter = csv.writer(csvfile)
output = verbose or csvfilename or showhash
for path in args:
FH = open(path, "rb")
header_bin = FH.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]
blk_sz = header[5]
total_blks = header[6]
total_chunks = header[7]
image_checksum = header[8]
if magic != 0xED26FF3A:
print("%s: %s: Magic should be 0xED26FF3A but is 0x%08X"
% (me, path, magic))
continue
if major_version != 1 or minor_version != 0:
print("%s: %s: I only know about version 1.0, but this is version %u.%u"
% (me, path, major_version, minor_version))
continue
if file_hdr_sz != 28:
print("%s: %s: The file header size was expected to be 28, but is %u."
% (me, path, file_hdr_sz))
continue
if chunk_hdr_sz != 12:
print("%s: %s: The chunk header size was expected to be 12, but is %u."
% (me, path, chunk_hdr_sz))
continue
print("%s: Total of %u %u-byte output blocks in %u input chunks."
% (path, total_blks, blk_sz, total_chunks))
if image_checksum != 0:
print("checksum=0x%08X" % (image_checksum))
if not output:
continue
if verbose > 0:
print(" input_bytes output_blocks")
print("chunk offset number offset number")
if csvfilename:
csvwriter.writerow(["chunk", "input offset", "input bytes",
"output offset", "output blocks", "type", "hash"])
offset = 0
for i in xrange(1, total_chunks + 1):
header_bin = FH.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
curhash = ""
curtype = ""
curpos = FH.tell()
if verbose > 0:
print("%4u %10u %10u %7u %7u" % (i, curpos, data_sz, offset, chunk_sz),
end=" ")
if chunk_type == 0xCAC1:
if data_sz != (chunk_sz * blk_sz):
print("Raw chunk input size (%u) does not match output size (%u)"
% (data_sz, chunk_sz * blk_sz))
break
else:
curtype = "Raw data"
data = FH.read(data_sz)
if showhash:
h = hashlib.sha1()
h.update(data)
curhash = h.hexdigest()
elif chunk_type == 0xCAC2:
if data_sz != 4:
print("Fill chunk should have 4 bytes of fill, but this has %u"
% (data_sz))
break
else:
fill_bin = FH.read(4)
fill = struct.unpack("<I", fill_bin)
curtype = format("Fill with 0x%08X" % (fill))
if showhash:
h = hashlib.sha1()
data = fill_bin * (blk_sz / 4);
for block in xrange(chunk_sz):
h.update(data)
curhash = h.hexdigest()
elif chunk_type == 0xCAC3:
if data_sz != 0:
print("Don't care chunk input size is non-zero (%u)" % (data_sz))
break
else:
curtype = "Don't care"
elif chunk_type == 0xCAC4:
if data_sz != 4:
print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
% (data_sz))
break
else:
crc_bin = FH.read(4)
crc = struct.unpack("<I", crc_bin)
curtype = format("Unverified CRC32 0x%08X" % (crc))
else:
print("Unknown chunk type 0x%04X" % (chunk_type))
break
if verbose > 0:
print("%-18s" % (curtype), end=" ")
if verbose > 1:
header = struct.unpack("<12B", header_bin)
print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
% (header[0], header[1], header[2], header[3],
header[4], header[5], header[6], header[7],
header[8], header[9], header[10], header[11]), end=" ")
print(curhash)
if csvfilename:
csvwriter.writerow([i, curpos, data_sz, offset, chunk_sz, curtype,
curhash])
offset += chunk_sz
if verbose > 0:
print(" %10u %7u End" % (FH.tell(), offset))
if total_blks != offset:
print("The header said we should have %u output blocks, but we saw %u"
% (total_blks, offset))
junk_len = len(FH.read())
if junk_len:
print("There were %u bytes of extra data at the end of the file."
% (junk_len))
if csvfilename:
csvfile.close()
sys.exit(0)
if __name__ == "__main__":
main()

@ -0,0 +1,360 @@
/*
* Copyright (C) 2012 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.
*/
#include <assert.h>
#include <stdlib.h>
#include <sparse/sparse.h>
#include "defs.h"
#include "sparse_file.h"
#include "backed_block.h"
#include "output_file.h"
#include "sparse_defs.h"
#include "sparse_format.h"
struct sparse_file* sparse_file_new(unsigned int block_size, int64_t len) {
struct sparse_file* s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1));
if (!s) {
return nullptr;
}
s->backed_block_list = backed_block_list_new(block_size);
if (!s->backed_block_list) {
free(s);
return nullptr;
}
s->block_size = block_size;
s->len = len;
return s;
}
void sparse_file_destroy(struct sparse_file* s) {
backed_block_list_destroy(s->backed_block_list);
free(s);
}
int sparse_file_add_data(struct sparse_file* s, void* data, unsigned int len, unsigned int block) {
return backed_block_add_data(s->backed_block_list, data, len, block);
}
int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, unsigned int len,
unsigned int block) {
return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
}
int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
unsigned int len, unsigned int block) {
return backed_block_add_file(s->backed_block_list, filename, file_offset, len, block);
}
int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, unsigned int len,
unsigned int block) {
return backed_block_add_fd(s->backed_block_list, fd, file_offset, len, block);
}
unsigned int sparse_count_chunks(struct sparse_file* s) {
struct backed_block* bb;
unsigned int last_block = 0;
unsigned int chunks = 0;
for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
if (backed_block_block(bb) > last_block) {
/* If there is a gap between chunks, add a skip chunk */
chunks++;
}
chunks++;
last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), s->block_size);
}
if (last_block < DIV_ROUND_UP(s->len, s->block_size)) {
chunks++;
}
return chunks;
}
static int sparse_file_write_block(struct output_file* out, struct backed_block* bb) {
int ret = -EINVAL;
switch (backed_block_type(bb)) {
case BACKED_BLOCK_DATA:
ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
break;
case BACKED_BLOCK_FILE:
ret = write_file_chunk(out, backed_block_len(bb), backed_block_filename(bb),
backed_block_file_offset(bb));
break;
case BACKED_BLOCK_FD:
ret = write_fd_chunk(out, backed_block_len(bb), backed_block_fd(bb),
backed_block_file_offset(bb));
break;
case BACKED_BLOCK_FILL:
ret = write_fill_chunk(out, backed_block_len(bb), backed_block_fill_val(bb));
break;
}
return ret;
}
static int write_all_blocks(struct sparse_file* s, struct output_file* out) {
struct backed_block* bb;
unsigned int last_block = 0;
int64_t pad;
int ret = 0;
for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
if (backed_block_block(bb) > last_block) {
unsigned int blocks = backed_block_block(bb) - last_block;
write_skip_chunk(out, (int64_t)blocks * s->block_size);
}
ret = sparse_file_write_block(out, bb);
if (ret) return ret;
last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), s->block_size);
}
pad = s->len - (int64_t)last_block * s->block_size;
assert(pad >= 0);
if (pad > 0) {
write_skip_chunk(out, pad);
}
return 0;
}
/*
* This is a workaround for 32-bit Windows: Limit the block size to 64 MB before
* fastboot executable binary for windows 64-bit is released (b/156057250).
*/
#define MAX_BACKED_BLOCK_SIZE ((unsigned int) (64UL << 20))
int sparse_file_write(struct sparse_file* s, int fd, bool gz, bool sparse, bool crc) {
struct backed_block* bb;
int ret;
int chunks;
struct output_file* out;
for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
ret = backed_block_split(s->backed_block_list, bb, MAX_BACKED_BLOCK_SIZE);
if (ret) return ret;
}
chunks = sparse_count_chunks(s);
out = output_file_open_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
if (!out) return -ENOMEM;
ret = write_all_blocks(s, out);
output_file_close(out);
return ret;
}
int sparse_file_callback(struct sparse_file* s, bool sparse, bool crc,
int (*write)(void* priv, const void* data, size_t len), void* priv) {
int ret;
int chunks;
struct output_file* out;
chunks = sparse_count_chunks(s);
out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
if (!out) return -ENOMEM;
ret = write_all_blocks(s, out);
output_file_close(out);
return ret;
}
struct chunk_data {
void* priv;
unsigned int block;
unsigned int nr_blocks;
int (*write)(void* priv, const void* data, size_t len, unsigned int block, unsigned int nr_blocks);
};
static int foreach_chunk_write(void* priv, const void* data, size_t len) {
struct chunk_data* chk = reinterpret_cast<chunk_data*>(priv);
return chk->write(chk->priv, data, len, chk->block, chk->nr_blocks);
}
int sparse_file_foreach_chunk(struct sparse_file* s, bool sparse, bool crc,
int (*write)(void* priv, const void* data, size_t len,
unsigned int block, unsigned int nr_blocks),
void* priv) {
int ret = 0;
int chunks;
struct chunk_data chk;
struct output_file* out;
struct backed_block* bb;
chk.priv = priv;
chk.write = write;
chk.block = chk.nr_blocks = 0;
chunks = sparse_count_chunks(s);
out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
chunks, crc);
if (!out) return -ENOMEM;
for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
chk.block = backed_block_block(bb);
chk.nr_blocks = (backed_block_len(bb) - 1) / s->block_size + 1;
ret = sparse_file_write_block(out, bb);
if (ret) return ret;
}
output_file_close(out);
return ret;
}
static int out_counter_write(void* priv, const void* data __unused, size_t len) {
int64_t* count = reinterpret_cast<int64_t*>(priv);
*count += len;
return 0;
}
int64_t sparse_file_len(struct sparse_file* s, bool sparse, bool crc) {
int ret;
int chunks = sparse_count_chunks(s);
int64_t count = 0;
struct output_file* out;
out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
chunks, crc);
if (!out) {
return -1;
}
ret = write_all_blocks(s, out);
output_file_close(out);
if (ret < 0) {
return -1;
}
return count;
}
unsigned int sparse_file_block_size(struct sparse_file* s) {
return s->block_size;
}
static struct backed_block* move_chunks_up_to_len(struct sparse_file* from, struct sparse_file* to,
unsigned int len) {
int64_t count = 0;
struct output_file* out_counter;
struct backed_block* last_bb = nullptr;
struct backed_block* bb;
struct backed_block* start;
unsigned int last_block = 0;
int64_t file_len = 0;
int ret;
/*
* overhead is sparse file header, the potential end skip
* chunk and crc chunk.
*/
int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) + sizeof(uint32_t);
len -= overhead;
start = backed_block_iter_new(from->backed_block_list);
out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
true, 0, false);
if (!out_counter) {
return nullptr;
}
for (bb = start; bb; bb = backed_block_iter_next(bb)) {
count = 0;
if (backed_block_block(bb) > last_block) count += sizeof(chunk_header_t);
last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), to->block_size);
/* will call out_counter_write to update count */
ret = sparse_file_write_block(out_counter, bb);
if (ret) {
bb = nullptr;
goto out;
}
if (file_len + count > len) {
/*
* If the remaining available size is more than 1/8th of the
* requested size, split the chunk. Results in sparse files that
* are at least 7/8ths of the requested size
*/
file_len += sizeof(chunk_header_t);
if (!last_bb || (len - file_len > (len / 8))) {
backed_block_split(from->backed_block_list, bb, len - file_len);
last_bb = bb;
}
goto move;
}
file_len += count;
last_bb = bb;
}
move:
backed_block_list_move(from->backed_block_list, to->backed_block_list, start, last_bb);
out:
output_file_close(out_counter);
return bb;
}
int sparse_file_resparse(struct sparse_file* in_s, unsigned int max_len, struct sparse_file** out_s,
int out_s_count) {
struct backed_block* bb;
struct sparse_file* s;
struct sparse_file* tmp;
int c = 0;
tmp = sparse_file_new(in_s->block_size, in_s->len);
if (!tmp) {
return -ENOMEM;
}
do {
s = sparse_file_new(in_s->block_size, in_s->len);
bb = move_chunks_up_to_len(in_s, s, max_len);
if (c < out_s_count) {
out_s[c] = s;
} else {
backed_block_list_move(s->backed_block_list, tmp->backed_block_list, nullptr, nullptr);
sparse_file_destroy(s);
}
c++;
} while (bb);
backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, nullptr, nullptr);
sparse_file_destroy(tmp);
return c;
}
void sparse_file_verbose(struct sparse_file* s) {
s->verbose = true;
}

@ -0,0 +1,97 @@
/*-
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
/*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*
*
* CRC32 code derived from work by Gary S. Brown.
*/
/* Code taken from FreeBSD 8 */
#include <stdint.h>
#include <stdio.h>
static uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
/*
* A function that calculates the CRC-32 based on the table above is
* given below for documentation purposes. An equivalent implementation
* of this function that's actually used in the kernel can be found
* in sys/libkern.h, where it can be inlined.
*/
uint32_t sparse_crc32(uint32_t crc_in, const void* buf, size_t size) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(buf);
uint32_t crc;
crc = crc_in ^ ~0U;
while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}

@ -0,0 +1,24 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _LIBSPARSE_SPARSE_CRC32_H_
#define _LIBSPARSE_SPARSE_CRC32_H_
#include <stdint.h>
uint32_t sparse_crc32(uint32_t crc, const void* buf, size_t size);
#endif

@ -0,0 +1,52 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _LIBSPARSE_SPARSE_DEFS_
#define _LIBSPARSE_SPARSE_DEFS_
#include <errno.h>
#include <stdio.h>
#define __le64 u64
#define __le32 u32
#define __le16 u16
#define __be64 u64
#define __be32 u32
#define __be16 u16
#define __u64 u64
#define __u32 u32
#define __u16 u16
#define __u8 u8
typedef unsigned long long u64;
typedef signed long long s64;
typedef unsigned int u32;
typedef unsigned short int u16;
typedef unsigned char u8;
#define DIV_ROUND_UP(x, y) (((x) + (y)-1) / (y))
#define ALIGN(x, y) ((y)*DIV_ROUND_UP((x), (y)))
#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
#define error(fmt, args...) \
do { \
fprintf(stderr, "error: %s: " fmt "\n", __func__, ##args); \
} while (0)
#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
#endif

@ -0,0 +1,32 @@
/*
* Copyright (C) 2012 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.
*/
#include <sparse/sparse.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
void sparse_default_print(const char* fmt, ...) {
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
}
void (*sparse_print_error)(const char* fmt, ...) = sparse_default_print;
void (*sparse_print_verbose)(const char* fmt, ...) = sparse_default_print;

@ -0,0 +1,63 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _LIBSPARSE_SPARSE_FORMAT_H_
#define _LIBSPARSE_SPARSE_FORMAT_H_
#include "sparse_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sparse_header {
__le32 magic; /* 0xed26ff3a */
__le16 major_version; /* (0x1) - reject images with higher major versions */
__le16 minor_version; /* (0x0) - allow images with higer minor versions */
__le16 file_hdr_sz; /* 28 bytes for first revision of the file format */
__le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
__le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
__le32 total_blks; /* total blocks in the non-sparse output image */
__le32 total_chunks; /* total chunks in the sparse input image */
__le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
/* as 0. Standard 802.3 polynomial, use a Public Domain */
/* table implementation */
} sparse_header_t;
#define SPARSE_HEADER_MAGIC 0xed26ff3a
#define CHUNK_TYPE_RAW 0xCAC1
#define CHUNK_TYPE_FILL 0xCAC2
#define CHUNK_TYPE_DONT_CARE 0xCAC3
#define CHUNK_TYPE_CRC32 0xCAC4
typedef struct chunk_header {
__le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
__le16 reserved1;
__le32 chunk_sz; /* in blocks in output image */
__le32 total_sz; /* in bytes of chunk input file including chunk header and data */
} chunk_header_t;
/* 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
*/
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,577 @@
/*
* Copyright (C) 2012 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.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <string>
#include <sparse/sparse.h>
#include "android-base/stringprintf.h"
#include "defs.h"
#include "output_file.h"
#include "sparse_crc32.h"
#include "sparse_file.h"
#include "sparse_format.h"
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
#endif
#define SPARSE_HEADER_MAJOR_VER 1
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
static char* copybuf;
static std::string ErrorString(int err) {
if (err == -EOVERFLOW) return "EOF while reading file";
if (err == -EINVAL) return "Invalid sparse file format";
if (err == -ENOMEM) return "Failed allocation while reading file";
return android::base::StringPrintf("Unknown error %d", err);
}
class SparseFileSource {
public:
/* Seeks the source ahead by the given offset. */
virtual void Seek(int64_t offset) = 0;
/* Return the current offset. */
virtual int64_t GetOffset() = 0;
/* Set the current offset. Return 0 if successful. */
virtual int SetOffset(int64_t offset) = 0;
/* Adds the given length from the current offset of the source to the file at the given block.
* Return 0 if successful. */
virtual int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) = 0;
/* Get data of fixed size from the current offset and seek len bytes. Return 0 if successful. */
virtual int ReadValue(void* ptr, int len) = 0;
/* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */
virtual int GetCrc32(uint32_t* crc32, int64_t len) = 0;
virtual ~SparseFileSource(){};
};
class SparseFileFdSource : public SparseFileSource {
private:
int fd;
public:
SparseFileFdSource(int fd) : fd(fd) {}
~SparseFileFdSource() override {}
void Seek(int64_t off) override { lseek64(fd, off, SEEK_CUR); }
int64_t GetOffset() override { return lseek64(fd, 0, SEEK_CUR); }
int SetOffset(int64_t offset) override {
return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno;
}
int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
return sparse_file_add_fd(s, fd, GetOffset(), len, block);
}
int ReadValue(void* ptr, int len) override { return read_all(fd, ptr, len); }
int GetCrc32(uint32_t* crc32, int64_t len) override {
int chunk;
int ret;
while (len) {
chunk = std::min(len, COPY_BUF_SIZE);
ret = read_all(fd, copybuf, chunk);
if (ret < 0) {
return ret;
}
*crc32 = sparse_crc32(*crc32, copybuf, chunk);
len -= chunk;
}
return 0;
}
};
class SparseFileBufSource : public SparseFileSource {
private:
char* buf;
int64_t offset;
public:
SparseFileBufSource(char* buf) : buf(buf), offset(0) {}
~SparseFileBufSource() override {}
void Seek(int64_t off) override {
buf += off;
offset += off;
}
int64_t GetOffset() override { return offset; }
int SetOffset(int64_t off) override {
buf += off - offset;
offset = off;
return 0;
}
int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
return sparse_file_add_data(s, buf, len, block);
}
int ReadValue(void* ptr, int len) override {
memcpy(ptr, buf, len);
Seek(len);
return 0;
}
int GetCrc32(uint32_t* crc32, int64_t len) override {
*crc32 = sparse_crc32(*crc32, buf, len);
Seek(len);
return 0;
}
};
static void verbose_error(bool verbose, int err, const char* fmt, ...) {
if (!verbose) return;
std::string msg = ErrorString(err);
if (fmt) {
msg += " at ";
va_list argp;
va_start(argp, fmt);
android::base::StringAppendV(&msg, fmt, argp);
va_end(argp);
}
sparse_print_verbose("%s\n", msg.c_str());
}
static int process_raw_chunk(struct sparse_file* s, unsigned int chunk_size,
SparseFileSource* source, unsigned int blocks, unsigned int block,
uint32_t* crc32) {
int ret;
int64_t len = blocks * s->block_size;
if (chunk_size % s->block_size != 0) {
return -EINVAL;
}
if (chunk_size / s->block_size != blocks) {
return -EINVAL;
}
ret = source->AddToSparseFile(s, len, block);
if (ret < 0) {
return ret;
}
if (crc32) {
ret = source->GetCrc32(crc32, len);
if (ret < 0) {
return ret;
}
} else {
source->Seek(len);
}
return 0;
}
static int process_fill_chunk(struct sparse_file* s, unsigned int chunk_size,
SparseFileSource* source, unsigned int blocks, unsigned int block,
uint32_t* crc32) {
int ret;
int chunk;
int64_t len = (int64_t)blocks * s->block_size;
uint32_t fill_val;
uint32_t* fillbuf;
unsigned int i;
if (chunk_size != sizeof(fill_val)) {
return -EINVAL;
}
ret = source->ReadValue(&fill_val, sizeof(fill_val));
if (ret < 0) {
return ret;
}
ret = sparse_file_add_fill(s, fill_val, len, block);
if (ret < 0) {
return ret;
}
if (crc32) {
/* Fill copy_buf with the fill value */
fillbuf = (uint32_t*)copybuf;
for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
fillbuf[i] = fill_val;
}
while (len) {
chunk = std::min(len, COPY_BUF_SIZE);
*crc32 = sparse_crc32(*crc32, copybuf, chunk);
len -= chunk;
}
}
return 0;
}
static int process_skip_chunk(struct sparse_file* s, unsigned int chunk_size,
SparseFileSource* source __unused, unsigned int blocks,
unsigned int block __unused, uint32_t* crc32) {
if (chunk_size != 0) {
return -EINVAL;
}
if (crc32) {
int64_t len = (int64_t)blocks * s->block_size;
memset(copybuf, 0, COPY_BUF_SIZE);
while (len) {
int chunk = std::min(len, COPY_BUF_SIZE);
*crc32 = sparse_crc32(*crc32, copybuf, chunk);
len -= chunk;
}
}
return 0;
}
static int process_crc32_chunk(SparseFileSource* source, unsigned int chunk_size, uint32_t* crc32) {
uint32_t file_crc32;
if (chunk_size != sizeof(file_crc32)) {
return -EINVAL;
}
int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
if (ret < 0) {
return ret;
}
if (crc32 != nullptr && file_crc32 != *crc32) {
return -EINVAL;
}
return 0;
}
static int process_chunk(struct sparse_file* s, SparseFileSource* source, unsigned int chunk_hdr_sz,
chunk_header_t* chunk_header, unsigned int cur_block, uint32_t* crc_ptr) {
int ret;
unsigned int chunk_data_size;
int64_t offset = source->GetOffset();
chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
switch (chunk_header->chunk_type) {
case CHUNK_TYPE_RAW:
ret =
process_raw_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block, crc_ptr);
if (ret < 0) {
verbose_error(s->verbose, ret, "data block at %" PRId64, offset);
return ret;
}
return chunk_header->chunk_sz;
case CHUNK_TYPE_FILL:
ret = process_fill_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
crc_ptr);
if (ret < 0) {
verbose_error(s->verbose, ret, "fill block at %" PRId64, offset);
return ret;
}
return chunk_header->chunk_sz;
case CHUNK_TYPE_DONT_CARE:
ret = process_skip_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
crc_ptr);
if (chunk_data_size != 0) {
if (ret < 0) {
verbose_error(s->verbose, ret, "skip block at %" PRId64, offset);
return ret;
}
}
return chunk_header->chunk_sz;
case CHUNK_TYPE_CRC32:
ret = process_crc32_chunk(source, chunk_data_size, crc_ptr);
if (ret < 0) {
verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64, offset);
return ret;
}
return 0;
default:
verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64, chunk_header->chunk_type,
offset);
}
return 0;
}
static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* source, bool crc) {
int ret;
unsigned int i;
sparse_header_t sparse_header;
chunk_header_t chunk_header;
uint32_t crc32 = 0;
uint32_t* crc_ptr = nullptr;
unsigned int cur_block = 0;
if (!copybuf) {
copybuf = (char*)malloc(COPY_BUF_SIZE);
}
if (!copybuf) {
return -ENOMEM;
}
if (crc) {
crc_ptr = &crc32;
}
ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
if (ret < 0) {
return ret;
}
if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
return -EINVAL;
}
if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
return -EINVAL;
}
if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
return -EINVAL;
}
if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
return -EINVAL;
}
if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
}
for (i = 0; i < sparse_header.total_chunks; i++) {
ret = source->ReadValue(&chunk_header, sizeof(chunk_header));
if (ret < 0) {
return ret;
}
if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
}
ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header, cur_block, crc_ptr);
if (ret < 0) {
return ret;
}
cur_block += ret;
}
if (sparse_header.total_blks != cur_block) {
return -EINVAL;
}
return 0;
}
static int sparse_file_read_normal(struct sparse_file* s, int fd) {
int ret;
uint32_t* buf = (uint32_t*)malloc(s->block_size);
unsigned int block = 0;
int64_t remain = s->len;
int64_t offset = 0;
unsigned int to_read;
unsigned int i;
bool sparse_block;
if (!buf) {
return -ENOMEM;
}
while (remain > 0) {
to_read = std::min(remain, (int64_t)(s->block_size));
ret = read_all(fd, buf, to_read);
if (ret < 0) {
error("failed to read sparse file");
free(buf);
return ret;
}
if (to_read == s->block_size) {
sparse_block = true;
for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
if (buf[0] != buf[i]) {
sparse_block = false;
break;
}
}
} else {
sparse_block = false;
}
if (sparse_block) {
/* TODO: add flag to use skip instead of fill for buf[0] == 0 */
sparse_file_add_fill(s, buf[0], to_read, block);
} else {
sparse_file_add_fd(s, fd, offset, to_read, block);
}
remain -= to_read;
offset += to_read;
block++;
}
free(buf);
return 0;
}
int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
if (crc && !sparse) {
return -EINVAL;
}
if (sparse) {
SparseFileFdSource source(fd);
return sparse_file_read_sparse(s, &source, crc);
} else {
return sparse_file_read_normal(s, fd);
}
}
int sparse_file_read_buf(struct sparse_file* s, char* buf, bool crc) {
SparseFileBufSource source(buf);
return sparse_file_read_sparse(s, &source, crc);
}
static struct sparse_file* sparse_file_import_source(SparseFileSource* source, bool verbose,
bool crc) {
int ret;
sparse_header_t sparse_header;
int64_t len;
struct sparse_file* s;
ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
if (ret < 0) {
verbose_error(verbose, ret, "header");
return nullptr;
}
if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
verbose_error(verbose, -EINVAL, "header magic");
return nullptr;
}
if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
verbose_error(verbose, -EINVAL, "header major version");
return nullptr;
}
if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
return nullptr;
}
if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
return nullptr;
}
len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
s = sparse_file_new(sparse_header.blk_sz, len);
if (!s) {
verbose_error(verbose, -EINVAL, nullptr);
return nullptr;
}
ret = source->SetOffset(0);
if (ret < 0) {
verbose_error(verbose, ret, "seeking");
sparse_file_destroy(s);
return nullptr;
}
s->verbose = verbose;
ret = sparse_file_read_sparse(s, source, crc);
if (ret < 0) {
sparse_file_destroy(s);
return nullptr;
}
return s;
}
struct sparse_file* sparse_file_import(int fd, bool verbose, bool crc) {
SparseFileFdSource source(fd);
return sparse_file_import_source(&source, verbose, crc);
}
struct sparse_file* sparse_file_import_buf(char* buf, bool verbose, bool crc) {
SparseFileBufSource source(buf);
return sparse_file_import_source(&source, verbose, crc);
}
struct sparse_file* sparse_file_import_auto(int fd, bool crc, bool verbose) {
struct sparse_file* s;
int64_t len;
int ret;
s = sparse_file_import(fd, verbose, crc);
if (s) {
return s;
}
len = lseek64(fd, 0, SEEK_END);
if (len < 0) {
return nullptr;
}
lseek64(fd, 0, SEEK_SET);
s = sparse_file_new(4096, len);
if (!s) {
return nullptr;
}
ret = sparse_file_read_normal(s, fd);
if (ret < 0) {
sparse_file_destroy(s);
return nullptr;
}
return s;
}

@ -0,0 +1,62 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _BACKED_BLOCK_H_
#define _BACKED_BLOCK_H_
#include <stdint.h>
struct backed_block_list;
struct backed_block;
enum backed_block_type {
BACKED_BLOCK_DATA,
BACKED_BLOCK_FILE,
BACKED_BLOCK_FD,
BACKED_BLOCK_FILL,
};
int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
unsigned int block);
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
unsigned int block);
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
unsigned int len, unsigned int block);
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
unsigned int block);
struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
struct backed_block* backed_block_iter_next(struct backed_block* bb);
unsigned int backed_block_len(struct backed_block* bb);
unsigned int backed_block_block(struct backed_block* bb);
void* backed_block_data(struct backed_block* bb);
const char* backed_block_filename(struct backed_block* bb);
int backed_block_fd(struct backed_block* bb);
int64_t backed_block_file_offset(struct backed_block* bb);
uint32_t backed_block_fill_val(struct backed_block* bb);
enum backed_block_type backed_block_type(struct backed_block* bb);
int backed_block_split(struct backed_block_list* bbl, struct backed_block* bb, unsigned int max_len);
struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
struct backed_block* backed_block_iter_next(struct backed_block* bb);
struct backed_block_list* backed_block_list_new(unsigned int block_size);
void backed_block_list_destroy(struct backed_block_list* bbl);
void backed_block_list_move(struct backed_block_list* from, struct backed_block_list* to,
struct backed_block* start, struct backed_block* end);
#endif

@ -0,0 +1,346 @@
/*
* Copyright (C) 2012 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.
*/
#ifndef _LIBSPARSE_SPARSE_H_
#define _LIBSPARSE_SPARSE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct sparse_file;
// The callbacks in sparse_file_callback() and sparse_file_foreach_chunk() take
// size_t as the length type (was `int` in past). This allows clients to keep
// their codes compatibile with both versions as needed.
#define SPARSE_CALLBACK_USES_SIZE_T
/**
* sparse_file_new - create a new sparse file cookie
*
* @block_size - minimum size of a chunk
* @len - size of the expanded sparse file.
*
* Creates a new sparse_file cookie that can be used to associate data
* blocks. Can later be written to a file with a variety of options.
* block_size specifies the minimum size of a chunk in the file. The maximum
* size of the file is 2**32 * block_size (16TB for 4k block size).
*
* Returns the sparse file cookie, or NULL on error.
*/
struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len);
/**
* sparse_file_destroy - destroy a sparse file cookie
*
* @s - sparse file cookie
*
* Destroys a sparse file cookie. After destroy, all memory passed in to
* sparse_file_add_data can be freed by the caller
*/
void sparse_file_destroy(struct sparse_file *s);
/**
* sparse_file_add_data - associate a data chunk with a sparse file
*
* @s - sparse file cookie
* @data - pointer to data block
* @len - length of the data block
* @block - offset in blocks into the sparse file to place the data chunk
*
* Associates a data chunk with a sparse file cookie. The region
* [block * block_size : block * block_size + len) must not already be used in
* the sparse file. If len is not a multiple of the block size the data
* will be padded with zeros.
*
* The data pointer must remain valid until the sparse file is closed or the
* data block is removed from the sparse file.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_data(struct sparse_file *s,
void *data, unsigned int len, unsigned int block);
/**
* sparse_file_add_fill - associate a fill chunk with a sparse file
*
* @s - sparse file cookie
* @fill_val - 32 bit fill data
* @len - length of the fill block
* @block - offset in blocks into the sparse file to place the fill chunk
*
* Associates a chunk filled with fill_val with a sparse file cookie.
* The region [block * block_size : block * block_size + len) must not already
* be used in the sparse file. If len is not a multiple of the block size the
* data will be padded with zeros.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_fill(struct sparse_file *s,
uint32_t fill_val, unsigned int len, unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
*
* @s - sparse file cookie
* @filename - filename of the file to be copied
* @file_offset - offset into the copied file
* @len - length of the copied block
* @block - offset in blocks into the sparse file to place the file chunk
*
* Associates a chunk of an existing file with a sparse file cookie.
* The region [block * block_size : block * block_size + len) must not already
* be used in the sparse file. If len is not a multiple of the block size the
* data will be padded with zeros.
*
* Allows adding large amounts of data to a sparse file without needing to keep
* it all mapped. File size is limited by available virtual address space,
* exceptionally large files may need to be added in multiple chunks.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_file(struct sparse_file *s,
const char *filename, int64_t file_offset, unsigned int len,
unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
*
* @s - sparse file cookie
* @filename - filename of the file to be copied
* @file_offset - offset into the copied file
* @len - length of the copied block
* @block - offset in blocks into the sparse file to place the file chunk
*
* Associates a chunk of an existing fd with a sparse file cookie.
* The region [block * block_size : block * block_size + len) must not already
* be used in the sparse file. If len is not a multiple of the block size the
* data will be padded with zeros.
*
* Allows adding large amounts of data to a sparse file without needing to keep
* it all mapped. File size is limited by available virtual address space,
* exceptionally large files may need to be added in multiple chunks.
*
* The fd must remain open until the sparse file is closed or the fd block is
* removed from the sparse file.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_fd(struct sparse_file *s,
int fd, int64_t file_offset, unsigned int len, unsigned int block);
/**
* sparse_file_write - write a sparse file to a file
*
* @s - sparse file cookie
* @fd - file descriptor to write to
* @gz - write a gzipped file
* @sparse - write in the Android sparse file format
* @crc - append a crc chunk
*
* Writes a sparse file to a file. If gz is true, the data will be passed
* through zlib. If sparse is true, the file will be written in the Android
* sparse file format. If sparse is false, the file will be written by seeking
* over unused chunks, producing a smaller file if the filesystem supports
* sparse files. If crc is true, the crc of the expanded data will be
* calculated and appended in a crc chunk.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
bool crc);
/**
* sparse_file_len - return the length of a sparse file if written to disk
*
* @s - sparse file cookie
* @sparse - write in the Android sparse file format
* @crc - append a crc chunk
*
* Returns the size a sparse file would be on disk if it were written in the
* specified format. If sparse is true, this is the size of the data in the
* sparse format. If sparse is false, this is the size of the normal
* non-sparse file.
*/
int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc);
/**
* sparse_file_block_size
*
* @s - sparse file cookie
*/
unsigned int sparse_file_block_size(struct sparse_file *s);
/**
* sparse_file_callback - call a callback for blocks in sparse file
*
* @s - sparse file cookie
* @sparse - write in the Android sparse file format
* @crc - append a crc chunk
* @write - function to call for each block
* @priv - value that will be passed as the first argument to write
*
* Writes a sparse file by calling a callback function. If sparse is true, the
* file will be written in the Android sparse file format. If crc is true, the
* crc of the expanded data will be calculated and appended in a crc chunk.
* The callback 'write' will be called with data and length for each data,
* and with data==NULL to skip over a region (only used for non-sparse format).
* The callback should return negative on error, 0 on success.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
int (*write)(void *priv, const void *data, size_t len), void *priv);
/**
* sparse_file_foreach_chunk - call a callback for data blocks in sparse file
*
* @s - sparse file cookie
* @sparse - write in the Android sparse file format
* @crc - append a crc chunk
* @write - function to call for each block
* @priv - value that will be passed as the first argument to write
*
* The function has the same behavior as 'sparse_file_callback', except it only
* iterates on blocks that contain data.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc,
int (*write)(void *priv, const void *data, size_t len, unsigned int block,
unsigned int nr_blocks),
void *priv);
/**
* sparse_file_read - read a file into a sparse file cookie
*
* @s - sparse file cookie
* @fd - file descriptor to read from
* @sparse - read a file in the Android sparse file format
* @crc - verify the crc of a file in the Android sparse file format
*
* Reads a file into a sparse file cookie. If sparse is true, the file is
* assumed to be in the Android sparse file format. If sparse is false, the
* file will be sparsed by looking for block aligned chunks of all zeros or
* another 32 bit value. If crc is true, the crc of the sparse file will be
* verified.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
/**
* sparse_file_read_buf - read a buffer into a sparse file cookie
*
* @s - sparse file cookie
* @buf - buffer to read from
* @crc - verify the crc of a file in the Android sparse file format
*
* Reads a buffer into a sparse file cookie. The buffer must remain
* valid until the sparse file cookie is freed. If crc is true, the
* crc of the sparse file will be verified.
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_read_buf(struct sparse_file *s, char *buf, bool crc);
/**
* sparse_file_import - import an existing sparse file
*
* @fd - file descriptor to read from
* @verbose - print verbose errors while reading the sparse file
* @crc - verify the crc of a file in the Android sparse file format
*
* Reads an existing sparse file into a sparse file cookie, recreating the same
* sparse cookie that was used to write it. If verbose is true, prints verbose
* errors when the sparse file is formatted incorrectly.
*
* Returns a new sparse file cookie on success, NULL on error.
*/
struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc);
/**
* sparse_file_import_buf - import an existing sparse file from a buffer
*
* @buf - buffer to read from
* @verbose - print verbose errors while reading the sparse file
* @crc - verify the crc of a file in the Android sparse file format
*
* Reads existing sparse file data into a sparse file cookie, recreating the same
* sparse cookie that was used to write it. If verbose is true, prints verbose
* errors when the sparse file is formatted incorrectly.
*
* Returns a new sparse file cookie on success, NULL on error.
*/
struct sparse_file *sparse_file_import_buf(char* buf, bool verbose, bool crc);
/**
* sparse_file_import_auto - import an existing sparse or normal file
*
* @fd - file descriptor to read from
* @crc - verify the crc of a file in the Android sparse file format
* @verbose - whether to use verbose logging
*
* Reads an existing sparse or normal file into a sparse file cookie.
* Attempts to determine if the file is sparse or not by looking for the sparse
* file magic number in the first 4 bytes. If the file is not sparse, the file
* will be sparsed by looking for block aligned chunks of all zeros or another
* 32 bit value. If crc is true, the crc of the sparse file will be verified.
*
* Returns a new sparse file cookie on success, NULL on error.
*/
struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose);
/** sparse_file_resparse - rechunk an existing sparse file into smaller files
*
* @in_s - sparse file cookie of the existing sparse file
* @max_len - maximum file size
* @out_s - array of sparse file cookies
* @out_s_count - size of out_s array
*
* Splits chunks of an existing sparse file into smaller sparse files such that
* each sparse file is less than max_len. Returns the number of sparse_files
* that would have been written to out_s if out_s were big enough.
*/
int sparse_file_resparse(struct sparse_file *in_s, unsigned int max_len,
struct sparse_file **out_s, int out_s_count);
/**
* sparse_file_verbose - set a sparse file cookie to print verbose errors
*
* @s - sparse file cookie
*
* Print verbose sparse file errors whenever using the sparse file cookie.
*/
void sparse_file_verbose(struct sparse_file *s);
/**
* sparse_print_verbose - function called to print verbose errors
*
* By default, verbose errors will print to standard error.
* sparse_print_verbose may be overridden to log verbose errors somewhere else.
*
*/
extern void (*sparse_print_verbose)(const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,39 @@
/*
* Copyright (C) 2012 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.
*/
#ifndef _LIBSPARSE_SPARSE_FILE_H_
#define _LIBSPARSE_SPARSE_FILE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <sparse/sparse.h>
struct sparse_file {
unsigned int block_size;
int64_t len;
bool verbose;
struct backed_block_list* backed_block_list;
struct output_file* out;
};
#ifdef __cplusplus
}
#endif
#endif /* _LIBSPARSE_SPARSE_FILE_H_ */

@ -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.

@ -0,0 +1,118 @@
/*
* Copyright (C) 2021 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.
*/
#include "libxbc.h"
#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
#define BOOTCONFIG_MAGIC_SIZE 12
#define BOOTCONFIG_SIZE_SIZE 4
#define BOOTCONFIG_CHECKSUM_SIZE 4
#define BOOTCONFIG_TRAILER_SIZE BOOTCONFIG_MAGIC_SIZE + \
BOOTCONFIG_SIZE_SIZE + \
BOOTCONFIG_CHECKSUM_SIZE
/*
* Simple checksum for a buffer.
*
* @param addr pointer to the start of the buffer.
* @param size size of the buffer in bytes.
* @return check sum result.
*/
static uint32_t checksum(const unsigned char* const buffer, uint32_t size) {
uint32_t sum = 0;
for (uint32_t i = 0; i < size; i++) {
sum += buffer[i];
}
return sum;
}
/*
* Check if the bootconfig trailer is present within the bootconfig section.
*
* @param bootconfig_end_addr address of the end of the bootconfig section. If
* the trailer is present, it will be directly preceding this address.
* @return true if the trailer is present, false if not.
*/
static bool isTrailerPresent(uint64_t bootconfig_end_addr) {
return !strncmp((char*)(bootconfig_end_addr - BOOTCONFIG_MAGIC_SIZE),
BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
}
/*
* Add a string of boot config parameters to memory appended by the trailer.
*/
int32_t addBootConfigParameters(const char* params, uint32_t params_size,
uint64_t bootconfig_start_addr, uint32_t bootconfig_size) {
if (!params || !bootconfig_start_addr) {
return -1;
}
if (params_size == 0) {
return 0;
}
int32_t applied_bytes = 0;
int32_t new_size = 0;
uint64_t end = bootconfig_start_addr + bootconfig_size;
if (isTrailerPresent(end)) {
end -= BOOTCONFIG_TRAILER_SIZE;
applied_bytes -= BOOTCONFIG_TRAILER_SIZE;
memcpy(&new_size, (void *)end, BOOTCONFIG_SIZE_SIZE);
} else {
new_size = bootconfig_size;
}
// params
memcpy((void*)end, params, params_size);
applied_bytes += params_size;
applied_bytes += addBootConfigTrailer(bootconfig_start_addr,
bootconfig_size + applied_bytes);
return applied_bytes;
}
/*
* Add boot config trailer.
*/
int32_t addBootConfigTrailer(uint64_t bootconfig_start_addr,
uint32_t bootconfig_size) {
if (!bootconfig_start_addr) {
return -1;
}
if (bootconfig_size == 0) {
return 0;
}
uint64_t end = bootconfig_start_addr + bootconfig_size;
if (isTrailerPresent(end)) {
// no need to overwrite the current trailers
return 0;
}
// size
memcpy((void *)(end), &bootconfig_size, BOOTCONFIG_SIZE_SIZE);
// checksum
uint32_t sum =
checksum((unsigned char*)bootconfig_start_addr, bootconfig_size);
memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE), &sum,
BOOTCONFIG_CHECKSUM_SIZE);
// magic
memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE + BOOTCONFIG_CHECKSUM_SIZE),
BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
return BOOTCONFIG_TRAILER_SIZE;
}

@ -0,0 +1,70 @@
/*
* Copyright (C) 2021 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.
*/
#ifndef LIBXBC_H_
#define LIBXBC_H_
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// memcpy and strncmp
//#include <common.h>
/*
* Add a string of boot config parameters to memory appended by the trailer.
* This memory needs to be immediately following the end of the ramdisks.
* The new boot config trailer will be written to the end of the entire
* parameter section(previous + new). The trailer contains a 4 byte size of the
* parameters, followed by a 4 byte checksum of the parameters, followed by a 12
* byte magic string.
*
* @param params pointer to string of boot config parameters
* @param params_size size of params string in bytes
* @param bootconfig_start_addr address that the boot config section is starting
* at in memory.
* @param bootconfig_size size of the current bootconfig section in bytes.
* @return number of bytes added to the boot config section. -1 for error.
*/
int addBootConfigParameters(const char *params, uint32_t params_size,
uint64_t bootconfig_start_addr,
uint32_t bootconfig_size);
/*
* Add the boot config trailer to the end of the boot config parameter section.
* This can be used after the vendor bootconfig section has been placed into
* memory if there are no additional parameters that need to be added.
* The new boot config trailer will be written to the end of the entire
* parameter section at (bootconfig_start_addr + bootconfig_size).
* The trailer contains a 4 byte size of the parameters, followed by a 4 byte
* checksum of the parameters, followed by a 12 byte magic string.
*
* @param bootconfig_start_addr address that the boot config section is starting
* at in memory.
* @param bootconfig_size size of the current bootconfig section in bytes.
* @return number of bytes added to the boot config section. -1 for error.
*/
int addBootConfigTrailer(uint64_t bootconfig_start_addr,
uint32_t bootconfig_size);
#ifdef __cplusplus
}
#endif
#endif /* LIBXBC_H_ */

@ -0,0 +1,84 @@
#include <fcntl.h>
#include <libxbc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
static_assert(sizeof(uint64_t) == 8, "uint64_t 8 bytes");
static_assert(sizeof(void*) == 8, "void* 8 bytes");
void dumpBuf(void* buf, size_t bufSize, const char* outFile) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
printf("dumping buffer to %s...\n", outFile);
auto fd = open(outFile, flags, 0644);
if (fd == -1) {
printf("fail to open file %s(%s)\n", outFile, strerror(errno));
exit(1);
}
size_t bytesWrite = write(fd, (char*)buf, bufSize);
if (bytesWrite != bufSize) {
printf("write failed. exp=%zu, act=%ld\n", bufSize, bytesWrite);
exit(2);
}
close(fd);
}
int main(int, char**) {
size_t bufSize = 256;
uint64_t buf = reinterpret_cast<uint64_t>(malloc(bufSize));
uint32_t bootConfigSize = 0;
if (!buf) {
printf("malloc failed\n");
exit(1);
}
{ // param1
char* ANDROID_BOOT_PARAM = (char*)"androidboot.xx=yy\n";
auto ret = addBootConfigParameters(ANDROID_BOOT_PARAM, strlen(ANDROID_BOOT_PARAM), buf,
bootConfigSize);
if (ret <= 0) {
printf("fail to apply boot config params\n");
exit(1);
} else {
printf("addBootConfigParameters() ret = %d\n", ret);
bootConfigSize += ret;
}
dumpBuf((void*)buf, bufSize, "tmp.1");
}
{ // param2
char* param2 = (char*)"k1=v1\nk2=v2\nk3=v3\n";
auto ret = addBootConfigParameters(param2, strlen(param2), buf, bootConfigSize);
if (ret <= 0) {
printf("fail to apply boot config param2\n");
exit(1);
} else {
printf("addBootConfigParameters() ret = %d\n", ret);
bootConfigSize += ret;
}
dumpBuf((void*)buf, bufSize, "tmp.2");
}
{ // param3
char* param3 =
(char*)"vendorboot_k1=vendorboot_v1\nvendorboot_k2=vendorboot_v2\nvendorboot_k3="
"vendorboot_v3\n";
auto ret = addBootConfigParameters(param3, strlen(param3), buf, bootConfigSize);
if (ret <= 0) {
printf("fail to apply boot config param3\n");
exit(1);
} else {
printf("addBootConfigParameters() ret = %d\n", ret);
bootConfigSize += ret;
}
dumpBuf((void*)buf, bufSize, "tmp.3");
dumpBuf((void*)buf, bootConfigSize, "tmp.final");
}
free((void*)buf);
return 0;
}

@ -0,0 +1,8 @@
project('libxbc', 'c', 'cpp',
version : '0.1',
default_options : ['warning_level=3'])
executable('xbc',
'libxbc.c',
'main.cpp',
install : true)

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA3fDgwU4JKVRHhAfofi/g8daTNplB2mTJCX9fIMy9FnZDXNij
1zijRQ8HKbt3bAGImQvb3GxSV4M5eIdiLDUF7RsUpE7K+s939i/AaTtcuyqimQbJ
QjP9emTsgngHzuKWMg1mwlRZYDfdv62zIQmZcbM9a0CZE36hAYvEBiDB8qT4ob++
godGAx3rpF2Wi7mhIYDINvkCw8/16Qi9CZgvOUrEolt3mz8Sps41z9j7YAsPbAa8
fg7dUu61s6NkZEykl4G67loOaf7h+SyP//LpFZ0gV+STZ+EMGofL0SXb8A+hdIYE
QxsnKUYo8e+GaQg92FLxVZqcfyG3AZuMB04R1QIDAQABAoIBAQDGj3/1UaSepjlJ
ZW3an2lH1Cpm2ZxyEGNQLPVluead1vaTdXq3zYM9AKHu8zp3lbOpAVQVk4/jnZJo
Q+9QD6waonTIP3oYBE+WIMirHSHsjctkzw52PV9VBkAWxd5ueIfZheXejGpdy/2H
RJcTQqxWbf7QGr4ZE9xmLq4UsW/zbXwy8qGEp9eMQIIaWBua43FkqmWYLSnVFVJI
Gl8mfVJctLNSZHhS3tKiV8up6NxZlDjO8o7kYVFCkv0xJ9yzQNBc3P2MEmvfZ06D
QnimHBqSxr0M9X6hqP43CnqtCbpsHS8A12Dm4l6fkXfkrAY0UNrEaCSDb8aN7TEc
7bc1MB4NAoGBAPK7xSuvQE9CH05Iy+G6mEQTtNmpfcQosqhi6dF60h4bqlkeGzUu
gF/PKHwwffHAxQSv4V831P3A/IoJFa9IFkg218mYPNfzpj4vJA4aNCDp+SYZAIYm
h6hMOmuByI97wds2yCBGt4mP0eow5B3A1b3UQeqW6LVSuobZ22QVlSk/AoGBAOoS
L82yda9hUa7vuXtqTraf9EGjSXhyjoPqWxa+a1ooI9l24f7mokS5Iof+a/SLfPUj
pwj8eOeOZksjAaWJIdrRb3TaYLaqhDkWQeV5N5XxYbn3+TvVJQyR+OSBfGoEpVP/
IS6fusvpT3eULJDax10By+gDcoLT5M1FNs4rBIvrAoGBAM8yJP5DHDwLjzl9vjsy
0iLaR3e8zBQTQV2nATvFAXKd3u0vW74rsX0XEdHgesFP8V0s3M4wlGj+wRL66j2y
5QJDfjMg9l7IJlHSX46CI5ks33X7xYy9evLYDs4R/Kct1q5OtsmGU8jisSadETus
jUb61kFvC7krovjVIgbuvWJ1AoGAVikzp4gVgeVU6AwePqu3JcpjYvX0SX4Br9VI
imq1oY49BAOa1PWYratoZp7kpjPiX2osRkaJStNEHExagtCjwaRuXpk0GIlT+p+S
yiGAsJUV4BrDh57B8IqbD6IKZgwnv2+ei0cIv562PdIxRXEDCd1rbZA3SqktA9KC
hgmXttkCgYBPU1lqRpwoHP9lpOBTDa6/Xi6WaDEWrG/tUF/wMlvrZ4hEVMDJRs1d
9JCXBxL/O4TMvpmyVKBZW15iZOcLM3EpiZ00UD+ChcAaFstup+oYKrs8gL9hgyTd
cvWMxGQm13KwSj2CLzEQpPAN5xG14njXaee5ksshxkzBz9z3MVWiiw==
-----END RSA PRIVATE KEY-----

@ -0,0 +1,265 @@
#!/usr/bin/env python
#
# Copyright (C) 2018 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.
"""
A tool to extract kernel information from a kernel image.
"""
import argparse
import subprocess
import sys
import re
CONFIG_PREFIX = b'IKCFG_ST'
GZIP_HEADER = b'\037\213\010'
COMPRESSION_ALGO = (
(["gzip", "-d"], GZIP_HEADER),
(["xz", "-d"], b'\3757zXZ\000'),
(["bzip2", "-d"], b'BZh'),
(["lz4", "-d", "-l"], b'\002\041\114\030'),
# These are not supported in the build system yet.
# (["unlzma"], b'\135\0\0\0'),
# (["lzop", "-d"], b'\211\114\132'),
)
# "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
# LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
LINUX_BANNER_PREFIX = b'Linux version '
LINUX_BANNER_REGEX = LINUX_BANNER_PREFIX.decode() + \
r'(?P<release>(?P<version>[0-9]+[.][0-9]+[.][0-9]+).*) \(.*@.*\) \((?P<compiler>.*)\) .*\n'
def get_from_release(input_bytes, start_idx, key):
null_idx = input_bytes.find(b'\x00', start_idx)
if null_idx < 0:
return None
try:
linux_banner = input_bytes[start_idx:null_idx].decode()
except UnicodeDecodeError:
return None
mo = re.match(LINUX_BANNER_REGEX, linux_banner)
if mo:
return mo.group(key)
return None
def dump_from_release(input_bytes, key):
"""
Helper of dump_version and dump_release
"""
idx = 0
while True:
idx = input_bytes.find(LINUX_BANNER_PREFIX, idx)
if idx < 0:
return None
value = get_from_release(input_bytes, idx, key)
if value:
return value.encode()
idx += len(LINUX_BANNER_PREFIX)
def dump_version(input_bytes):
"""
Dump kernel version, w.x.y, from input_bytes. Search for the string
"Linux version " and do pattern matching after it. See LINUX_BANNER_REGEX.
"""
return dump_from_release(input_bytes, "version")
def dump_compiler(input_bytes):
"""
Dump kernel version, w.x.y, from input_bytes. Search for the string
"Linux version " and do pattern matching after it. See LINUX_BANNER_REGEX.
"""
return dump_from_release(input_bytes, "compiler")
def dump_release(input_bytes):
"""
Dump kernel release, w.x.y-..., from input_bytes. Search for the string
"Linux version " and do pattern matching after it. See LINUX_BANNER_REGEX.
"""
return dump_from_release(input_bytes, "release")
def dump_configs(input_bytes):
"""
Dump kernel configuration from input_bytes. This can be done when
CONFIG_IKCONFIG is enabled, which is a requirement on Treble devices.
The kernel configuration is archived in GZip format right after the magic
string 'IKCFG_ST' in the built kernel.
"""
# Search for magic string + GZip header
idx = input_bytes.find(CONFIG_PREFIX + GZIP_HEADER)
if idx < 0:
return None
# Seek to the start of the archive
idx += len(CONFIG_PREFIX)
sp = subprocess.Popen(["gzip", "-d", "-c"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
o, _ = sp.communicate(input=input_bytes[idx:])
if sp.returncode == 1: # error
return None
# success or trailing garbage warning
assert sp.returncode in (0, 2), sp.returncode
return o
def try_decompress_bytes(cmd, input_bytes):
sp = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
o, _ = sp.communicate(input=input_bytes)
# ignore errors
return o
def try_decompress(cmd, search_bytes, input_bytes):
idx = 0
while True:
idx = input_bytes.find(search_bytes, idx)
if idx < 0:
return
yield try_decompress_bytes(cmd, input_bytes[idx:])
idx += 1
def decompress_dump(func, input_bytes):
"""
Run func(input_bytes) first; and if that fails (returns value evaluates to
False), then try different decompression algorithm before running func.
"""
o = func(input_bytes)
if o:
return o
for cmd, search_bytes in COMPRESSION_ALGO:
for decompressed in try_decompress(cmd, search_bytes, input_bytes):
if decompressed:
o = decompress_dump(func, decompressed)
if o:
return o
# Force decompress the whole file even if header doesn't match
decompressed = try_decompress_bytes(cmd, input_bytes)
if decompressed:
o = decompress_dump(func, decompressed)
if o:
return o
def dump_to_file(f, dump_fn, input_bytes, desc):
"""
Call decompress_dump(dump_fn, input_bytes) and write to f. If it fails, return
False; otherwise return True.
"""
if f is not None:
o = decompress_dump(dump_fn, input_bytes)
if o:
f.write(o)
else:
sys.stderr.write(
"Cannot extract kernel {}".format(desc))
return False
return True
def to_bytes_io(b):
"""
Make b, which is either sys.stdout or sys.stdin, receive bytes as arguments.
"""
return b.buffer if sys.version_info.major == 3 else b
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
description=__doc__ +
"\nThese algorithms are tried when decompressing the image:\n " +
" ".join(tup[0][0] for tup in COMPRESSION_ALGO))
parser.add_argument('--input',
help='Input kernel image. If not specified, use stdin',
metavar='FILE',
type=argparse.FileType('rb'),
default=to_bytes_io(sys.stdin))
parser.add_argument('--output-configs',
help='If specified, write configs. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
const=to_bytes_io(sys.stdout))
parser.add_argument('--output-version',
help='If specified, write version. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
const=to_bytes_io(sys.stdout))
parser.add_argument('--output-release',
help='If specified, write kernel release. Use stdout if '
'no file is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
const=to_bytes_io(sys.stdout))
parser.add_argument('--output-compiler',
help='If specified, write the compiler information. Use stdout if no file '
'is specified.',
metavar='FILE',
nargs='?',
type=argparse.FileType('wb'),
const=to_bytes_io(sys.stdout))
parser.add_argument('--tools',
help='Decompression tools to use. If not specified, PATH '
'is searched.',
metavar='ALGORITHM:EXECUTABLE',
nargs='*')
args = parser.parse_args()
tools = {pair[0]: pair[1]
for pair in (token.split(':') for token in args.tools or [])}
for cmd, _ in COMPRESSION_ALGO:
if cmd[0] in tools:
cmd[0] = tools[cmd[0]]
input_bytes = args.input.read()
ret = 0
if not dump_to_file(args.output_configs, dump_configs, input_bytes,
"configs in {}".format(args.input.name)):
ret = 1
if not dump_to_file(args.output_version, dump_version, input_bytes,
"version in {}".format(args.input.name)):
ret = 1
if not dump_to_file(args.output_release, dump_release, input_bytes,
"kernel release in {}".format(args.input.name)):
ret = 1
if not dump_to_file(args.output_compiler, dump_compiler, input_bytes,
"kernel compiler in {}".format(args.input.name)):
ret = 1
return ret
if __name__ == '__main__':
sys.exit(main())

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
For detailed information on key types and image signing, please see:
https://source.android.com/devices/tech/ota/sign_builds.html
The test keys in this directory are used in development only and should
NEVER be used to sign packages in publicly released images (as that would
open a major security hole).
key generation
--------------
The following commands were used to generate the test key pairs:
development/tools/make_key testkey '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
development/tools/make_key shared '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
development/tools/make_key media '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
signing using the openssl commandline (for boot/system images)
--------------------------------------------------------------
1. convert pk8 format key to pem format
% openssl pkcs8 -inform DER -nocrypt -in testkey.pk8 -out testkey.pem
2. create a signature using the pem format key
% openssl dgst -binary -sha1 -sign testkey.pem FILE > FILE.sig
extracting public keys for embedding
------------------------------------
dumpkey.jar is a Java tool that takes an x.509 certificate in PEM format as
input and prints a C structure to standard output:
$ java -jar out/host/linux-x86/framework/dumpkey.jar build/target/product/security/testkey.x509.pem
{64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}}
This is called by build/core/Makefile to incorporate the OTA signing keys
into the recovery image.

Binary file not shown.

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJAPK5jmEjVyxOMA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODA0MTUyMzQwNTdaFw0zNTA5MDEyMzQwNTdaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBAK4lDFoW75f8KGmsZRsyF8w2ug6GlkFo1YoE
n0DOhYZxI6P/tPbZScM88to6BcI+rKpX2AOImxdZvPWefG8hiQriUIW37VaqYmwJ
ie+czTY2LKDo0blgP9TYModnkmzMCQxot3Wuf/MJNMw2nvKFWiZn3wxmf9DHz12O
umVYBnNzA7tiRybquu37cvB+16dqs8uaOBxLfc2AmxQNiR8AITvkAfWNagamHq3D
qcLxxlZyhbCa4JNCpm+kIer5Ot91c6AowzHXBgGrOvfMhAM+znx3KjpbhrDb6dd3
w6SKqYAe3O4ngVifRNnkETl5YAV2qZQQuoEJElna2YxsaP94S48CAQOjgfwwgfkw
HQYDVR0OBBYEFMopPKqLwO0+VC7vQgWiv/K1fk11MIHJBgNVHSMEgcEwgb6AFMop
PKqLwO0+VC7vQgWiv/K1fk11oYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAPK5jmEjVyxOMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAITelRbV5KhyF6c9qEhwSPUzc6X3
M/OQ1hvfPMnlJRYlv8qnwxWcriddFyqa4eh21UWBJ6xUL2gpDdUQwAKdj1Hg7hVr
e3tazbOUJBuOx4t05cQsXK+uFWyvW9GZojonUk2gct6743hGSlM2MLDk0P+34I7L
cB+ttjecdEZ/bgDG7YiFlTgHkgOHVgB4csjjAHr0I6V6LKs6KChptkxLe9X8GH0K
fiQVll1ark4Hpt91G0p16Xk8kYphK4HNC2KK7gFo3ETkexDTWTJghJ1q321yfcJE
RMIh0/nsw2jK0HmZ8rgQW8HyDTjUEGbMFBHCV6lupDSfV0ZWVQfk6AIKGoE=
-----END CERTIFICATE-----

Binary file not shown.

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJALOZgIbQVs/6MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODA0MTUyMjQwNTBaFw0zNTA5MDEyMjQwNTBaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBAJx4BZKsDV04HN6qZezIpgBuNkgMbXIHsSAR
vlCGOqvitV0Amt9xRtbyICKAx81Ne9smJDuKgGwms0sTdSOkkmgiSQTcAUk+fArP
GgXIdPabA3tgMJ2QdNJCgOFrrSqHNDYZUer3KkgtCbIEsYdeEqyYwap3PWgAuer9
5W1Yvtjo2hb5o2AJnDeoNKbf7be2tEoEngeiafzPLFSW8s821k35CjuNjzSjuqtM
9TNxqydxmzulh1StDFP8FOHbRdUeI0+76TybpO35zlQmE1DsU1YHv2mi/0qgfbX3
6iANCabBtJ4hQC+J7RGQiTqrWpGA8VLoL4WkV1PPX8GQccXuyCcCAQOjgfwwgfkw
HQYDVR0OBBYEFE/koLPdnLop9x1yh8Tnw48ghsKZMIHJBgNVHSMEgcEwgb6AFE/k
oLPdnLop9x1yh8Tnw48ghsKZoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJALOZgIbQVs/6MAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFclUbjZOh9z3g9tRp+G2tZwFAAp
PIigzXzXeLc9r8wZf6t25iEuVsHHYc/EL9cz3lLFCuCIFM78CjtaGkNGBU2Cnx2C
tCsgSL+ItdFJKe+F9g7dEtctVWV+IuPoXQTIMdYT0Zk4u4mCJH+jISVroS0dao+S
6h2xw3Mxe6DAN/DRr/ZFrvIkl5+6bnoUvAJccbmBOM7z3fwFlhfPJIRc97QNY4L3
J17XOElatuWTG5QhdlxJG3L7aOCA29tYwgKdNHyLMozkPvaosVUz7fvpib1qSN1L
IC7alMarjdW4OZID2q4u1EYjLk/pvZYTlMYwDlE448/Shebk5INTjLixs1c=
-----END CERTIFICATE-----

Binary file not shown.

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJAPKnM5a9OHZ6MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODA3MjMyMTU3NTlaFw0zNTEyMDkyMTU3NTlaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBAMjC2/0JSi30XD/xoy7SGAXscvxY0BeXG9D2
tSwmLXCBnRkZZ+FY39Oix/Gz4OgM5UXXnShIIgIR64bw/YMS03tCDBE3UMyUYYro
cvSIZGO9xGJ8qgwEg8hkk+NRVXEXAzi/3MTNat3RwKLzX1zyTtPkBDo+WOKwXmZM
zeEry2dzX9bfEknDaeYlQrwKRynlORf1w4/6UtF7c8nHN5jdsY7UgVkIdVR+Zr/F
2spMJabrlg7ZaSNwnaMCumRstJazJehsXIsuejN3srvkx88zJUKRFj9okVKsCIVQ
yDxQj0v1rfCu1aLcoFg/mrCtF2UNt+6ksj/bRYhVR9D+q3IYOIkCAQOjgfwwgfkw
HQYDVR0OBBYEFMtMfizbs/CtqY2reZaNFy6dux7RMIHJBgNVHSMEgcEwgb6AFMtM
fizbs/CtqY2reZaNFy6dux7RoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAPKnM5a9OHZ6MAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAECo0JaZeVnpF6NsRCRra6wrrgVD
fs2JeUEY94NHIDUtHG+KObCGmUL02mWYH6opUdM5cRKewZIdeVZxxSfW4knyUoKf
r1tZExAxHi3gllANVorUEUplbcNKjG9hBFOvwep5ktukqns/hUOm41wHKN53/pfu
rIN3H9DskPjkRJQ07gtgRXg+cMei5GAkkmDgA892CNw1Kkye9wbe9LJgUOl4ri//
16MyN4cBSRXrPMh0/MeprpMId8XIx9HC4qjuhjyJGA0YVc7bpADnukPMyqckPTl+
fA6Ojk19T5K2u+rUnAzwGAae3coufi+0Zo2J2715UNDNJUGA+h6q/CpVb4Q=
-----END CERTIFICATE-----

Binary file not shown.

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
-----END CERTIFICATE-----

Binary file not shown.

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID/TCCAuWgAwIBAgIJAJcPmDkJqolJMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g
VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE
AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0xNDExMDYxOTA3NDBaFw00MjAzMjQxOTA3NDBaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAOjreE0vTVSRenuzO9vnaWfk0eQzYab0gqpi
6xAzi6dmD+ugoEKJmbPiuE5Dwf21isZ9uhUUu0dQM46dK4ocKxMRrcnmGxydFn6o
fs3ODJMXOkv2gKXL/FdbEPdDbxzdu8z3yk+W67udM/fW7WbaQ3DO0knu+izKak/3
T41c5uoXmQ81UNtAzRGzGchNVXMmWuTGOkg6U+0I2Td7K8yvUMWhAWPPpKLtVH9r
AL5TzjYNR92izdKcz3AjRsI3CTjtpiVABGeX0TcjRSuZB7K9EK56HV+OFNS6I1NP
jdD7FIShyGlqqZdUOkAUZYanbpgeT5N7QL6uuqcGpoTOkalu6kkCAwEAAaNQME4w
HQYDVR0OBBYEFH5DM/m7oArf4O3peeKO0ZIEkrQPMB8GA1UdIwQYMBaAFH5DM/m7
oArf4O3peeKO0ZIEkrQPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
AHO3NSvDE5jFvMehGGtS8BnFYdFKRIglDMc4niWSzhzOVYRH4WajxdtBWc5fx0ix
NF/+hVKVhP6AIOQa+++sk+HIi7RvioPPbhjcsVlZe7cUEGrLSSveGouQyc+j0+m6
JF84kszIl5GGNMTnx0XRPO+g8t6h5LWfnVydgZfpGRRg+WHewk1U2HlvTjIceb0N
dcoJ8WKJAFWdcuE7VIm4w+vF/DYX/A2Oyzr2+QRhmYSv1cusgAeC1tvH4ap+J1Lg
UnOu5Kh/FqPLLSwNVQp4Bu7b9QFfqK8Moj84bj88NqRGZgDyqzuTrFxn6FW7dmyA
yttuAJAEAymk1mipd9+zp38=
-----END CERTIFICATE-----

Binary file not shown.

@ -0,0 +1 @@
../../build/soong/scripts/system-clang-format-2

@ -0,0 +1 @@
../../build/soong/scripts/system-clang-format

@ -0,0 +1,7 @@
# This clang-format configuration may be included in subdirectories to disable
# any warning.
DisableFormat: true
# This extra settings is required because of https://reviews.llvm.org/D67843.
SortIncludes: false

@ -0,0 +1,53 @@
[defaults]
base_features = sparse_super,large_file,filetype,dir_index,ext_attr
default_mntopts = acl,user_xattr
enable_periodic_fsck = 0
blocksize = 4096
inode_size = 256
inode_ratio = 16384
reserved_ratio = 1.0
[fs_types]
ext3 = {
features = has_journal
}
ext4 = {
features = has_journal,extent,huge_file,dir_nlink,extra_isize,uninit_bg
inode_size = 256
}
ext4dev = {
features = has_journal,extent,huge_file,flex_bg,inline_data,64bit,dir_nlink,extra_isize
inode_size = 256
options = test_fs=1
}
small = {
blocksize = 1024
inode_size = 128
inode_ratio = 4096
}
floppy = {
blocksize = 1024
inode_size = 128
inode_ratio = 8192
}
big = {
inode_ratio = 32768
}
huge = {
inode_ratio = 65536
}
news = {
inode_ratio = 4096
}
largefile = {
inode_ratio = 1048576
blocksize = -1
}
largefile4 = {
inode_ratio = 4194304
blocksize = -1
}
hurd = {
blocksize = 4096
inode_size = 128
}

@ -0,0 +1,265 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018 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 argparse
import logging
import os
import pkgutil
import subprocess
import sys
import tempfile
def RunCommand(cmd, env):
"""Runs the given command.
Args:
cmd: the command represented as a list of strings.
env: a dictionary of additional environment variables.
Returns:
A tuple of the output and the exit code.
"""
env_copy = os.environ.copy()
env_copy.update(env)
cmd[0] = FindProgram(cmd[0])
logging.info("Env: %s", env)
logging.info("Running: " + " ".join(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
env=env_copy, text=True)
output, _ = p.communicate()
return output, p.returncode
def FindProgram(prog_name):
"""Finds the path to prog_name.
Args:
prog_name: the program name to find.
Returns:
path to the progName if found. The program is searched in the same directory
where this script is located at. If not found, progName is returned.
"""
exec_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
prog_path = os.path.join(exec_dir, prog_name)
if os.path.exists(prog_path):
return prog_path
else:
return prog_name
def ParseArguments(argv):
"""Parses the input arguments to the program."""
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("src_dir", help="The source directory for user image.")
parser.add_argument("output_file", help="The path of the output image file.")
parser.add_argument("ext_variant", choices=["ext2", "ext4"],
help="Variant of the extended filesystem.")
parser.add_argument("mount_point", help="The mount point for user image.")
parser.add_argument("fs_size", help="Size of the file system.")
parser.add_argument("file_contexts", nargs='?',
help="The selinux file context.")
parser.add_argument("--android_sparse", "-s", action="store_true",
help="Outputs an android sparse image (mke2fs).")
parser.add_argument("--journal_size", "-j",
help="Journal size (mke2fs).")
parser.add_argument("--timestamp", "-T",
help="Fake timetamp for the output image.")
parser.add_argument("--fs_config", "-C",
help="Path to the fs config file (e2fsdroid).")
parser.add_argument("--product_out", "-D",
help="Path to the directory with device specific fs"
" config files (e2fsdroid).")
parser.add_argument("--block_list_file", "-B",
help="Path to the block list file (e2fsdroid).")
parser.add_argument("--base_alloc_file_in", "-d",
help="Path to the input base fs file (e2fsdroid).")
parser.add_argument("--base_alloc_file_out", "-A",
help="Path to the output base fs file (e2fsdroid).")
parser.add_argument("--label", "-L",
help="The mount point (mke2fs).")
parser.add_argument("--inodes", "-i",
help="The extfs inodes count (mke2fs).")
parser.add_argument("--inode_size", "-I",
help="The extfs inode size (mke2fs).")
parser.add_argument("--reserved_percent", "-M",
help="The reserved blocks percentage (mke2fs).")
parser.add_argument("--flash_erase_block_size", "-e",
help="The flash erase block size (mke2fs).")
parser.add_argument("--flash_logical_block_size", "-o",
help="The flash logical block size (mke2fs).")
parser.add_argument("--mke2fs_uuid", "-U",
help="The mke2fs uuid (mke2fs) .")
parser.add_argument("--mke2fs_hash_seed", "-S",
help="The mke2fs hash seed (mke2fs).")
parser.add_argument("--share_dup_blocks", "-c", action="store_true",
help="ext4 share dup blocks (e2fsdroid).")
args, remainder = parser.parse_known_args(argv)
# The current argparse doesn't handle intermixed arguments well. Checks
# manually whether the file_contexts exists as the last argument.
# TODO(xunchang) use parse_intermixed_args() when we switch to python 3.7.
if len(remainder) == 1 and remainder[0] == argv[-1]:
args.file_contexts = remainder[0]
elif remainder:
parser.print_usage()
sys.exit(1)
return args
def ConstructE2fsCommands(args):
"""Builds the mke2fs & e2fsdroid command based on the input arguments.
Args:
args: The result of ArgumentParser after parsing the command line arguments.
Returns:
A tuple of two lists that serve as the command for mke2fs and e2fsdroid.
"""
BLOCKSIZE = 4096
e2fsdroid_opts = []
mke2fs_extended_opts = []
mke2fs_opts = []
if args.android_sparse:
mke2fs_extended_opts.append("android_sparse")
else:
e2fsdroid_opts.append("-e")
if args.timestamp:
e2fsdroid_opts += ["-T", args.timestamp]
if args.fs_config:
e2fsdroid_opts += ["-C", args.fs_config]
if args.product_out:
e2fsdroid_opts += ["-p", args.product_out]
if args.block_list_file:
e2fsdroid_opts += ["-B", args.block_list_file]
if args.base_alloc_file_in:
e2fsdroid_opts += ["-d", args.base_alloc_file_in]
if args.base_alloc_file_out:
e2fsdroid_opts += ["-D", args.base_alloc_file_out]
if args.share_dup_blocks:
e2fsdroid_opts.append("-s")
if args.file_contexts:
e2fsdroid_opts += ["-S", args.file_contexts]
if args.flash_erase_block_size:
mke2fs_extended_opts.append("stripe_width={}".format(
int(args.flash_erase_block_size) // BLOCKSIZE))
if args.flash_logical_block_size:
# stride should be the max of 8kb and the logical block size
stride = max(int(args.flash_logical_block_size), 8192)
mke2fs_extended_opts.append("stride={}".format(stride // BLOCKSIZE))
if args.mke2fs_hash_seed:
mke2fs_extended_opts.append("hash_seed=" + args.mke2fs_hash_seed)
if args.journal_size:
if args.journal_size == "0":
mke2fs_opts += ["-O", "^has_journal"]
else:
mke2fs_opts += ["-J", "size=" + args.journal_size]
if args.label:
mke2fs_opts += ["-L", args.label]
if args.inodes:
mke2fs_opts += ["-N", args.inodes]
if args.inode_size:
mke2fs_opts += ["-I", args.inode_size]
if args.mount_point:
mke2fs_opts += ["-M", args.mount_point]
if args.reserved_percent:
mke2fs_opts += ["-m", args.reserved_percent]
if args.mke2fs_uuid:
mke2fs_opts += ["-U", args.mke2fs_uuid]
if mke2fs_extended_opts:
mke2fs_opts += ["-E", ','.join(mke2fs_extended_opts)]
# Round down the filesystem length to be a multiple of the block size
blocks = int(args.fs_size) // BLOCKSIZE
mke2fs_cmd = (["mke2fs"] + mke2fs_opts +
["-t", args.ext_variant, "-b", str(BLOCKSIZE), args.output_file,
str(blocks)])
e2fsdroid_cmd = (["e2fsdroid"] + e2fsdroid_opts +
["-f", args.src_dir, "-a", args.mount_point,
args.output_file])
return mke2fs_cmd, e2fsdroid_cmd
def main(argv):
logging_format = '%(asctime)s %(filename)s %(levelname)s: %(message)s'
logging.basicConfig(level=logging.INFO, format=logging_format,
datefmt='%H:%M:%S')
args = ParseArguments(argv)
if not os.path.isdir(args.src_dir):
logging.error("Can not find directory %s", args.src_dir)
sys.exit(2)
if not args.mount_point:
logging.error("Mount point is required")
sys.exit(2)
if args.mount_point[0] != '/':
args.mount_point = '/' + args.mount_point
if not args.fs_size:
logging.error("Size of the filesystem is required")
sys.exit(2)
mke2fs_cmd, e2fsdroid_cmd = ConstructE2fsCommands(args)
# truncate output file since mke2fs will keep verity section in existing file
with open(args.output_file, 'w') as output:
output.truncate()
# run mke2fs
with tempfile.NamedTemporaryFile() as conf_file:
conf_data = pkgutil.get_data('mkuserimg_mke2fs', 'mke2fs.conf')
conf_file.write(conf_data)
conf_file.flush()
mke2fs_env = {"MKE2FS_CONFIG" : conf_file.name}
if args.timestamp:
mke2fs_env["E2FSPROGS_FAKE_TIME"] = args.timestamp
output, ret = RunCommand(mke2fs_cmd, mke2fs_env)
print(output)
if ret != 0:
logging.error("Failed to run mke2fs: " + output)
sys.exit(4)
# run e2fsdroid
e2fsdroid_env = {}
if args.timestamp:
e2fsdroid_env["E2FSPROGS_FAKE_TIME"] = args.timestamp
output, ret = RunCommand(e2fsdroid_cmd, e2fsdroid_env)
# The build script is parsing the raw output of e2fsdroid; keep the pattern
# unchanged for now.
print(output)
if ret != 0:
logging.error("Failed to run e2fsdroid_cmd: " + output)
os.remove(args.output_file)
sys.exit(4)
if __name__ == '__main__':
main(sys.argv[1:])

@ -0,0 +1,63 @@
// Copyright 2017 The Android Open Source Project
package {
default_applicable_licenses: ["system_extras_f2fs_utils_license"],
}
// Added automatically by a large-scale-change
// See: http://go/android-license-faq
license {
name: "system_extras_f2fs_utils_license",
visibility: [":__subpackages__"],
license_kinds: [
"SPDX-license-identifier-Apache-2.0",
],
license_text: [
"NOTICE",
],
}
cc_library_shared {
name: "libf2fs_sparseblock",
cflags: ["-Werror"],
srcs: ["f2fs_sparseblock.c"],
shared_libs: [
"liblog",
"libcutils",
],
include_dirs: [
"external/f2fs-tools/include",
"bionic/libc",
],
export_include_dirs: ["."],
}
cc_binary {
name: "f2fs_sparseblock",
cflags: ["-Werror"],
srcs: ["f2fs_sparseblock.c"],
shared_libs: [
"liblog",
"libcutils",
],
include_dirs: [
"external/f2fs-tools/include",
"bionic/libc",
],
}
sh_binary_host {
name: "mkf2fsuserimg",
src: "mkf2fsuserimg.sh",
required: [
"make_f2fs",
"sload_f2fs",
],
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save