135 Commits

Author SHA1 Message Date
0b7bbf29d5 recovery: Remove condition around get_root_mtd_partition
Change-Id: I2e763000f65aba342f1851c7e94778a815bbaa6f
2010-12-14 03:43:35 -05:00
d352233ab6 Added options for an internal SD card to be handled by recovery.
Exable uses in BoardConfig.mk:
	BOARD_HAS_SDCARD_INTERNAL := true
	BOARD_SDCARD_DEVICE_INTERNAL := /dev/block/mmcblk3p1

Setting BOARD_SDCARD_DEVICE_SECONDARY to the same value as
	BOARD_SDCARD_DEVICE_INTERNAL will allow the device to
	"fall back" to the internal SD card for other actions.

Change-Id: I2cf8ab4b1d385ac714f5b7416b915d059033d94b
2010-12-13 23:57:20 -08:00
16c0ace22b Fix write_raw_image on mtd devices.
Change-Id: I0fa64d4f4deaf8f067be3bd0b0bb963cf5af3f3f
2010-12-13 19:26:03 -08:00
134ead7537 fix up bmlutils some more
Change-Id: Ia11e917a6c0dc8164d599e02154f9f7b2934ed65
2010-12-12 16:54:41 -08:00
03a4f5ba0d supprot backup and restore of samsung kernels
Change-Id: I6deb5918f97ca5c5466b1d78369454b3452b89c0
2010-12-12 12:24:02 -08:00
cd8af06d64 whoops
Change-Id: I9c46bb443c43186fda1ae71e49278bd1a7d6aa6f
2010-12-12 02:53:21 -08:00
02c360501b Fix graphics corruption on some devices. BML restore needs to unlock first.
Change-Id: Ib6ede1dee0a0a4494319cfdb1613be2e89260874
2010-12-12 02:52:44 -08:00
8df69c0660 minui: useless code is useless
Change-Id: I288c82a647c4145a2569d5dec206b8ca89693e7c
2010-11-27 23:02:01 -06:00
229a543bb3 minui: clean up some stuff, and avoid multiple key events on N1
Change-Id: I7d26a406eb200c866b2fbc841424ac698f6d3bf3
2010-11-27 22:52:39 -06:00
517a16b98f Merge "minui: Add haptic feedback to virtual keys" into froyo 2010-11-28 03:54:03 +00:00
9397e322c3 Merge "minui: add support for virtual keys" into froyo 2010-11-28 03:53:44 +00:00
ddc2e39dcf fix fstab generation
Change-Id: I223a07fd0ce3c0d48b7f18f5c42ae204affe087a
2010-11-27 17:53:50 -08:00
d90ad5dedf fix no select button
Change-Id: I142d48156e166f9e5e7f3ad7c89c1829dbe2009a
2010-11-27 14:41:07 -08:00
3847a2ddd9 add missing file
Change-Id: I11948c0b4aece99e5cbdc32b39ba5b76d1b0ffb2
2010-11-27 13:36:17 -08:00
44bd4947d2 minui: Add haptic feedback to virtual keys
Change-Id: Ibd9298513626092297bff83f4914b436c4ffbb3a
2010-11-27 13:36:23 -06:00
ac731c88e3 minui: add support for virtual keys
Change-Id: Ie0e75a2fbccd42993a2f7c3d42ba38afea2d7679
2010-11-26 23:32:26 -06:00
9acb022ab8 recovery: Support board-specified font sizes and font-files
This, for example, is for an LDPI device:
BOARD_RECOVERY_FONT_INCLUDE_HEADER := ../../device/geeksphone/one/font_7x16.h
BOARD_RECOVERY_FONT_WIDTH := 7
BOARD_RECOVERY_FONT_HEIGHT := 16

Change-Id: I71d2f420b9668b5767c9b0b5d90e3e523c56e873
2010-11-27 04:08:06 +00:00
37d96f7414 2.5.1.3
Change-Id: Iae5d458edaedb90dd2422175a185a9b5725dbc74
2010-11-26 18:45:06 -08:00
0b23331f23 Added larger DATA size values for SD partitioning.
Used for systems that use internal SD partitioning for DATA storage.

Change-Id: I3274c196a7143143fccb806cff1665a6f40c1ce7
2010-11-19 10:28:56 -05:00
4123b58299 recovery: Autodetection of device flash type
Detect flash type at runtime rather than requiring this to be set in the
device configuration. The detection is based on the existence of /proc/mtd,
/proc/emmc, or /dev/block/bml1.

Change-Id: I464962a567022c5862c249f06d36c2d1cddeacba
2010-11-14 22:40:30 -05:00
158d25cae4 Supress "warning: comparison between signed and unsigned integer expressions" in minui/resources.c and mtdutils/mtdutils.c 2010-11-13 05:23:33 +08:00
7c50645a6c always build
Change-Id: I007eb15230e948074a1aad420ef0c3c6a2ae102e
2010-11-11 01:20:29 -08:00
e5c7e0eaca implement bmlutils
Change-Id: I8ec38a3b5e20e39b02c393d13e89142038ae3e82
2010-11-11 01:19:10 -08:00
12154200a7 fix up implementation of int get_partition_device
Change-Id: I142b15228322790892dd07b10d6a3f31440badc7
2010-11-11 01:16:14 -08:00
d771acbed0 Modify apply_patch to fail if trying to patch mtd on non-mtd devices.
Change-Id: I09c5bb5d12d838fdc4c4c6eb380021c9b3f3e33e
2010-11-11 00:00:45 -08:00
1b86754eaa Fix up updater to use the new refactored block device support.
Change-Id: I597f3d83ef14d2640192e0026a0fe1a93023bfc6
2010-11-10 23:52:09 -08:00
19447c0550 Refactor recovery's block device handling to work across variant hardware in a cleaner fashion.
Re add firmware update

Change-Id: I699ad22390ed14e597d17a7bcb32ad1b1af00b4b

support mmc misc

Change-Id: Iff02f8d03db6835f501d052140cebeefee521305

fix compile errors

Change-Id: I032edbd157a8a15f561bb83330c715ebaa008d18

fix compile errors

Change-Id: Idff3449be3376f22fceefc2c35637527f8df8f3f

Initial work to clean up the block devices.

Change-Id: I4be20ac124864a281be9cd116e211a2618404a27

all done

Change-Id: I0338f62f6a045556ebe90b0200685be113178319

fix up nandroid

Change-Id: I886f00271183e6d2921c080b0939341f2cf12a4d
2010-11-10 23:31:34 -08:00
fef77c0253 Changes to support Vision recovery. Fixing up a lot of bugs related to the CodeAurora mmc commit.
Change-Id: I9b71070fe41559a5d93d3c35efc3a511b7088e8e
2010-11-09 20:03:42 -08:00
7a77aec362 fix mmcutils usage
Change-Id: I04db586599af21f64174b0e656201c724bf82050
2010-11-09 09:23:15 -08:00
487821abe5 Merge remote branch 'github/eclair' into froyo 2010-11-06 17:59:05 -07:00
9456641236 2.5.1.1 2010-11-05 12:47:48 -07:00
1805cfe02e missing file
Change-Id: Ie87219d798f62128906fc6050ced7be5b4801426
2010-10-12 18:46:41 -07:00
815ca5d230 [recovery]: Add support for OTA upgrade on mmc devices.
Change-Id: I8f230dfa5be4e9f142765797d949e10434e1fdeb
2010-10-12 18:46:30 -07:00
0209a62c7d merge from froyo
Change-Id: Ic80ad93cd3b05d55ba8b4e16edaa59ee58f08f05
2010-10-12 11:39:35 -07:00
cb71c2f334 merge from eclair 2010-09-17 14:19:52 -07:00
e17a78ddda allow the parted and fix permissions tools to be optional 2010-09-17 14:17:57 -07:00
4e10b135cc Lie and say it is version 2 for backwards compatibility.
Change-Id: I5b0627fd49d3ee9f562c67bcac48783b00198ab0
2010-09-13 15:14:07 -07:00
56c1b3b576 add support for bml dumping
Change-Id: I9dd7fd8552d4efce533c23541f3612c01e3bd90b
2010-09-13 15:08:49 -07:00
68df48c28f implement redbend flashing
Change-Id: Icad93103ed2321ad8b6aecbbf2e0f2f8fe139c0f
2010-09-13 15:04:54 -07:00
28a41b4df2 initial support for bml backup and restore
Change-Id: I7e6f1a76371c0d1c1f4cfac0413ba6fa7743f17a
2010-09-13 14:55:17 -07:00
5a9fe1c964 missing
Change-Id: I836d8c28c9efce034032fa3bd2e0e15cac1ad23f
2010-09-13 14:33:50 -07:00
b5a36a0e20 add bmlutils
Change-Id: Ia402c4fcd2881cfb7cf7318718933ed64a19ec6b
2010-09-13 14:33:15 -07:00
e5678e9249 initial support for flashing samsung kernels via redbend_ua
Change-Id: I9033146899d596c6d0a4ba8a5fad080d799d96ae
2010-09-13 13:25:11 -07:00
4233c7fb3c Use the primary device.
Change-Id: Id45fcedcb5b3cacd753346a117423a462a00efb2
2010-09-03 22:16:57 -07:00
91e9e830e2 new fix permissions 2010-08-26 10:41:08 -07:00
fad25ab75b merge with eclair recovery 2010-08-26 10:40:57 -07:00
ef83d3ea87 fix
Change-Id: I9bc8cfde27b89d9a548c47c5727530c604d36ee0
2010-07-19 08:54:23 -07:00
702294d5b8 merge
Change-Id: I25a675887320afd2984523efbc3b7506231ebe4b
2010-07-19 08:43:05 -07:00
f146bc1b74 removal of the recovery checkpoint needs to happen AFTER sdcard is mounted. 2010-07-19 08:41:40 -07:00
d61e56ab36 version 2.5.0.0 2010-07-19 08:41:40 -07:00
9565424508 add confirmations to anything that would change the system. 2010-07-19 08:41:40 -07:00
17bba907ac Make generic confirmation function. 2010-07-19 08:40:58 -07:00
4ca9b4c3a0 allow toggling of software back menu item. add recovery checkpoint file. mount auto now uses busybox mount. 2010-07-19 08:40:58 -07:00
efa6530dbd up the version 2010-07-19 08:40:58 -07:00
b41b4589c2 2.0.2.0 2010-07-19 08:40:58 -07:00
fdda0d66d3 fail 2010-07-19 08:40:57 -07:00
30e5b7f6dc change where the recovery version is spit 2010-07-19 08:40:57 -07:00
6e5851647a command line nandroid 2010-07-19 08:40:57 -07:00
82c2ca262e Backup of Froyo apps on external storage. 2010-07-03 13:57:28 -07:00
d3cc60b036 nandroid executable
Change-Id: I697530a804be443260059b24e231d77dfe5bc6c4
2010-07-03 13:56:45 -07:00
d823d5f327 fix build
Change-Id: I284e852856ffa7f6588b243a628c35e5f6d73fc7
2010-07-01 08:21:02 -07:00
789ab6bed2 alphabetical sort
Change-Id: I4b1bb6787a5cbe1e99e3d8b0cc5bf37d7167398d
2010-07-01 00:23:25 -07:00
916f5538f9 fail
Change-Id: I93fc7a7a717e5a7eceafd7175e22c32b2588742a
2010-06-30 23:31:35 -07:00
f2954b5b64 Always use the default recovery ui.
Change-Id: Ia73aeb932498d39e508bf232c0070910aa204ec5
2010-06-30 23:27:26 -07:00
107629b02d forward port excluded bootloader stuff from eclair
Change-Id: I03fb0d4dc982a3718a616c6204e70a3e11cff8f8
2010-06-30 23:17:53 -07:00
0eb14b30e0 Merge from Froyo. 2010-06-23 17:38:05 -07:00
2654f5aae1 DO NOT MERGE
Removing unused recovey options.
Please refer to Bug#2502219 for more info.

Change-Id: I2fe3cdb0c8b93ed7e1cc4093824fbe181f5f0aea
2010-03-26 16:03:44 -07:00
dcc38b3c15 Add an empty CleanSpec.mk
Change-Id: Icd177bd26120e0c8929faa8d1007f6c5bd446cb8
2010-03-08 18:04:03 -08:00
5b695f393e make StringValue wrapper okay to call on NULL
The docs say "don't do this", but it's trivial to make safe.  Make
StringValue(NULL) return NULL instead of crashing.

Change-Id: I2221bcb4c98d8adb4e25c764d7bdcfa787822bcf
2010-02-24 15:05:07 -08:00
c4351c7910 refactor applypatch and friends
Change the applypatch function to take meaningful arguments instead of
argc and argv.  Move all the parsing of arguments into main.c (for the
standalone binary) and into install.c (for the updater function).
applypatch() takes patches as Value objects, so we can pass in blobs
extracted from the package without ever writing them to temp files.

The patching code is changed to read the patch from memory instead of
a file.

A bunch of compiler warnings (mostly about signed vs unsigned types)
are fixed.

Support for the IMGDIFF1 format is dropped.  (We've been generating
IMGDIFF2 packages for some time now.)

Change-Id: I217563c500012750f27110db821928a06211323f
2010-02-22 15:30:33 -08:00
583fc12c3d add missing includes to fix mac build (maybe)
Change-Id: Id2712940c4929f3a8b3ba5d4e9e03bb8034747ee
2010-02-19 16:07:57 -08:00
512536a54a relocate applypatch; add type system and new functions to edify
- Move applypatch to this package (from build).

- Add a rudimentary type system to edify:  instead of just returning a
  char*, functions now return a Value*, which is a struct that can
  carry different types of value (currently just STRING and BLOB).
  Convert all functions to this new scheme.

- Change the one-argument form of package_extract_file to return a
  Value of the new BLOB type.

- Add read_file() to load a local file and return a blob, and
  sha1_check() to test a blob (or string) against a set of possible
  sha1s.  read_file() uses the file-loading code from applypatch so it
  can read MTD partitions as well.

This is the start of better integration between applypatch and the
rest of edify.

b/2361316 - VZW Issue PP628: Continuous reset to Droid logo:
            framework-res.apk update failed (CR LIBtt59130)

Change-Id: Ibd038074749a4d515de1f115c498c6c589ee91e5
2010-02-18 14:22:12 -08:00
21854ccdb2 Filename check and free allocated strings
Make sure file is valid before we try to read it. Also free all the
strings we allocate in various functions so we don't leak memory.

Change-Id: Ica3c8dae992e73718c79c12ff5d7e315c290caea
2010-02-17 18:33:44 -08:00
2e068dc330 am da846fcf: am 4c382b13: reconcile main tree with open-source eclair
Merge commit 'da846fcf1b6a7bbd2f9f30c965b25f084568ef75'

* commit 'da846fcf1b6a7bbd2f9f30c965b25f084568ef75':
  android-2.1_r1 snapshot
2010-02-05 14:09:04 -08:00
da846fcf1b am 4c382b13: reconcile main tree with open-source eclair
Merge commit '4c382b13657be5d949e7dfc9ef46a66f2eb496e0' into eclair-plus-aosp

* commit '4c382b13657be5d949e7dfc9ef46a66f2eb496e0':
  android-2.1_r1 snapshot
2010-02-05 08:22:49 -08:00
4c382b1365 reconcile main tree with open-source eclair 2010-02-05 08:09:31 -08:00
e08991e02a bump updater API version to 3; deprecate firmware update command
Remove support for the HTC-specific "firmware" update command and the
corresponding edify function write_firmware_update().  This
functionality is now done by an edify extension library that lives in
vendor/htc.

Change-Id: I80858951ff10ed8dfff98aefb796bef009e05efb
2010-02-03 09:20:07 -08:00
93dbe07ff6 Merge "change log recovery to generic device_recovery_start function" 2010-02-02 08:54:10 -08:00
efa1bab94c change log recovery to generic device_recovery_start function
Remove (or at least stop calling) the HTC-specific mechanism for
preserving the recovery log from before a radio or hboot update.
Replace it with a generic device_recovery_start() function which each
device's code can implement to do whatever it wants on recovery
startup.

Change-Id: If3cca4b498c0b1cf0565236404ecf56a1fc46123
2010-02-01 15:59:12 -08:00
6aece33b3f add a one-argument version of package_extract_file
Add a version of package_extract_file that returns the file data as
its return value (to be consumed by some other edify function that
expects to receive a bunch of binary data as an argument).  Lets us
avoid having two copies of a big file in memory (extracting it into
/tmp, which is a ramdisk, and then having something load it into
memory) when doing things like radio updates.

Change-Id: Ie26ece5fbae457eb0ddcd8a13d74d78a769fbc70
2010-02-01 14:40:12 -08:00
b551724ceb reconcile android-2.1_r1 snapshot 2010-01-29 14:07:31 -08:00
aa062531aa fix parsing of dumpkeys output
%i can't be used to read unsigned ints (though it happens to work with
bionic).  Change to %x and %u as appropriate.

Change-Id: I8ea9ca16a939501757cf70fc5953abee26c8231c
http://b/2402231 - Parser for /res/keys interprets n0inv as a signed int
2010-01-28 16:51:00 -08:00
687bc12ccf save the recovery log from before HTC firmware updates
When doing a firmware (radio or hboot) update on HTC devices, save the
recovery log in block 1 of the cache partition, before the firmware
image and the UI bitmaps.  When we boot back into recovery after the
firmware update to reformat the cache partition, copy that log out of
cache before reformatting it and dump it into the current invocation's
log.

The practical upshot of all this is that we can see the log output
from radio and hboot updates.

Change-Id: Ie0e89566754c88f4bed6a90d8a0aa04047b01a27
2010-01-21 12:50:04 -08:00
883b4c8be5 am 4e9332cb: am 22d79a5c: make offsets in firmware update header not point to bad blocks
Merge commit '4e9332cb0bb84df4c08bbb469e59a54eab2a9df0'

* commit '4e9332cb0bb84df4c08bbb469e59a54eab2a9df0':
  make offsets in firmware update header not point to bad blocks
2010-01-13 12:17:11 -08:00
4e9332cb0b am 22d79a5c: make offsets in firmware update header not point to bad blocks
Merge commit '22d79a5c5eab9c1e86ff2af210bb072689e2d630' into eclair-plus-aosp

* commit '22d79a5c5eab9c1e86ff2af210bb072689e2d630':
  make offsets in firmware update header not point to bad blocks
2010-01-13 11:24:42 -08:00
4c5f9f3416 make offsets in firmware update header not point to bad blocks
hboot will apparently fail to install if the first block of the image
(the one pointed to by the offset in the block 0 header) is a bad
block.  (Hopefully it handles subsequent bad blocks.)

This change makes the MTD write code keep track of the bad blocks it
has skipped over, so that the offset in the header can be adjusted to
be the address of the first successfully written block.

Change-Id: I45d58e32a36d0c1dbc0a7f871bd5985b6c8ff524
http://b/2358012 - passion: failure to flash hboot (bad blocks?)
2010-01-13 09:21:25 -08:00
b765729081 android-2.1_r1 snapshot 2010-01-12 15:18:06 -08:00
be47155f75 am 158657bc: merge from open-source master
Merge commit '158657bc5ce438d3cf1f601255896b854fd49103'

* commit '158657bc5ce438d3cf1f601255896b854fd49103':
  Security: Fix typo in recovery EOCD detection.
2009-12-21 15:47:17 -08:00
158657bc5c merge from open-source master 2009-12-21 15:31:49 -08:00
9b514530a6 am d36308c2: am 17a47098: use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
Merge commit 'd36308c26d3f2947f4ff49f2ecc22cbb659fdf37'

* commit 'd36308c26d3f2947f4ff49f2ecc22cbb659fdf37':
  use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
2009-12-15 15:04:32 -08:00
d36308c26d am 17a47098: use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
Merge commit '17a47098d2a4214397f8b30e2692c9487d7ab5ff' into eclair-plus-aosp

* commit '17a47098d2a4214397f8b30e2692c9487d7ab5ff':
  use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
2009-12-15 07:42:36 -08:00
8fae8279fa Merge commit 'goog/eclair-plus-aosp' 2009-12-15 00:44:04 -08:00
25215285c4 am 9b430e11: am 73ae31ce: add a simple unit test for the OTA package verifier
Merge commit '9b430e11d6c4fb907d0aa96667142e2c00585e09'

* commit '9b430e11d6c4fb907d0aa96667142e2c00585e09':
  add a simple unit test for the OTA package verifier
2009-12-10 15:52:09 -08:00
9b430e11d6 am 73ae31ce: add a simple unit test for the OTA package verifier
Merge commit '73ae31ce0ac09c0e45924d817644261c87ab1a60' into eclair-mr2-plus-aosp

* commit '73ae31ce0ac09c0e45924d817644261c87ab1a60':
  add a simple unit test for the OTA package verifier
2009-12-10 15:35:23 -08:00
bd6181ad58 Merge change I117fdea9
* changes:
  Recovery changes for Encrypted File Systems. This change enables/disables the Encrypted file systems feature. It reads some properties form the data partition, wipes the partition out, and then rewrites the proper properties again into the data partition to signal that encrypted FS are enabled.
2009-12-10 14:51:10 -08:00
0523156775 Recovery changes for Encrypted File Systems.
This change enables/disables the Encrypted file systems feature. It reads some properties form the data partition, wipes the partition out, and then rewrites the proper properties again into the data partition to signal that encrypted FS are enabled.
2009-12-10 14:49:04 -08:00
002c9dfb80 am 2278a04a: am 9acf28a3: am c652e41d: fix cut-and-paste error in verifier
Merge commit '2278a04a0921007d726e9e1ec4b668860f961f88'

* commit '2278a04a0921007d726e9e1ec4b668860f961f88':
  fix cut-and-paste error in verifier
2009-12-10 14:37:57 -08:00
73ae31ce0a add a simple unit test for the OTA package verifier 2009-12-09 17:01:45 -08:00
2278a04a09 am 9acf28a3: am c652e41d: fix cut-and-paste error in verifier
Merge commit '9acf28a390aab3e0f394c701bc3cda6cbc9393b3' into eclair-mr2-plus-aosp

* commit '9acf28a390aab3e0f394c701bc3cda6cbc9393b3':
  fix cut-and-paste error in verifier
2009-12-09 15:54:14 -08:00
3b0f484776 Security: Fix typo in recovery EOCD detection.
This issue results in the ability to modify the contents of a signed
OTA recovery image.
2009-12-09 01:31:06 -05:00
9acf28a390 am c652e41d: fix cut-and-paste error in verifier
Merge commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12' into eclair-mr2

* commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12':
  fix cut-and-paste error in verifier
2009-12-08 15:54:50 -08:00
6149073651 am c652e41d: fix cut-and-paste error in verifier
Merge commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12' into eclair-plus-aosp

* commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12':
  fix cut-and-paste error in verifier
2009-12-08 15:54:32 -08:00
b8f506fb37 am 6e5be9b2: merge from open-source master
Merge commit '6e5be9b24c232be4cfc22b7cbabb0fdf6d869f7c'

* commit '6e5be9b24c232be4cfc22b7cbabb0fdf6d869f7c':
  eclair snapshot
2009-11-15 15:00:59 -08:00
6e5be9b24c merge from open-source master 2009-11-15 14:55:00 -08:00
052acd61c8 merge from open-source master
Merge commit 'goog/stage-korg-master' into HEAD
2009-11-15 14:05:55 -08:00
b2ce982d43 merge from eclair 2009-11-15 12:05:33 -08:00
a43c44f31f eclair snapshot 2009-11-12 18:45:15 -08:00
f88cea6ded am 4011770f: merge from open-source master
Merge commit '4011770f2d06fcb743abc91a01a531c7ae2d9175'

* commit '4011770f2d06fcb743abc91a01a531c7ae2d9175':
2009-10-14 16:11:42 -07:00
4011770f2d merge from open-source master 2009-10-14 16:02:08 -07:00
31f0fc2235 am d93a2545: simplify construction of the recovery progress bar
Merge commit 'd93a25459cdefba940f254b4c5f54fd7d9cdaf11'

* commit 'd93a25459cdefba940f254b4c5f54fd7d9cdaf11':
  simplify construction of the recovery progress bar
2009-10-13 11:59:45 -07:00
2ec8a1929f am 54ec81fe: Merge change I1c8ca2e4 into eclair
Merge commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa'

* commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa':
  replace generic recovery icons
2009-10-12 12:40:12 -07:00
022229c47e am 988500b6: add terminator to recovery\'s getopt_long options array
Merge commit '988500b615de24455e1fee69e72055bb1dca9c86'

* commit '988500b615de24455e1fee69e72055bb1dca9c86':
  add terminator to recovery's getopt_long options array
2009-10-12 11:45:31 -07:00
d93a25459c simplify construction of the recovery progress bar
Instead of six separate images for the left end, right end, and tiled
center portion of the full and empty progress bars, just use two
images:  a full bar and an empty bar.  Draw the left side of the full
bar and the right side of the empty one, moving the boundary rightward
to "fill" the bar.  This makes recovery trivially smaller, and allows
fancier images to be used as progress bars.

Support paletted PNG images as resources.
2009-10-08 16:32:58 -07:00
d641a0e141 am 54ec81fe: Merge change I1c8ca2e4 into eclair
Merge commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa' into eclair-plus-aosp

* commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa':
  replace generic recovery icons
2009-10-07 17:17:41 -07:00
42ab176195 am 988500b6: add terminator to recovery\'s getopt_long options array
Merge commit '988500b615de24455e1fee69e72055bb1dca9c86' into eclair-plus-aosp

* commit '988500b615de24455e1fee69e72055bb1dca9c86':
  add terminator to recovery's getopt_long options array
2009-10-07 11:57:04 -07:00
4526d4fe62 am 8f8bc4cb: am f93d8166: confirm before wiping user data in recovery
Merge commit '8f8bc4cb487e0f853c97cb5ff1481d707ac6b66d'

* commit '8f8bc4cb487e0f853c97cb5ff1481d707ac6b66d':
  confirm before wiping user data in recovery
2009-09-25 08:45:47 -07:00
8f8bc4cb48 am f93d8166: confirm before wiping user data in recovery
Merge commit 'f93d8166ef4c06f6ad71293ffa8a4ce469df4fa5' into eclair-plus-aosp

* commit 'f93d8166ef4c06f6ad71293ffa8a4ce469df4fa5':
  confirm before wiping user data in recovery
2009-09-22 18:28:19 -07:00
83a25d7380 am 486aa290: am fd8fb0c4: reduce fraction of progress bar for verification
Merge commit '486aa290635dbf6f60b3435694951fed3470ffdf'

* commit '486aa290635dbf6f60b3435694951fed3470ffdf':
  reduce fraction of progress bar for verification
2009-09-20 14:40:27 -07:00
486aa29063 am fd8fb0c4: reduce fraction of progress bar for verification
Merge commit 'fd8fb0c49242af5147708f1a93ea3acba546555b' into eclair-plus-aosp

* commit 'fd8fb0c49242af5147708f1a93ea3acba546555b':
  reduce fraction of progress bar for verification
2009-09-20 14:30:37 -07:00
66c76bcfcf am d16fb221: am 60babf8b: delete files before symlinking; log error messages
Merge commit 'd16fb221cd27abea8a954bd5f6554fa116366519'

* commit 'd16fb221cd27abea8a954bd5f6554fa116366519':
  delete files before symlinking; log error messages
2009-09-18 18:15:46 -07:00
d16fb221cd am 60babf8b: delete files before symlinking; log error messages
Merge commit '60babf8ba766662cc0932e8271b67daa69cddd5f' into eclair-plus-aosp

* commit '60babf8ba766662cc0932e8271b67daa69cddd5f':
  delete files before symlinking; log error messages
2009-09-18 15:49:37 -07:00
b9ad6dfd81 am 2f4fc561: am 196c25c7: don\'t complain if recovery icon is short
Merge commit '2f4fc56183f3fe2edb5e3cd5e12329871e02518f'

* commit '2f4fc56183f3fe2edb5e3cd5e12329871e02518f':
  don't complain if recovery icon is short
2009-09-17 06:38:28 -07:00
2f4fc56183 am 196c25c7: don\'t complain if recovery icon is short
Merge commit '196c25c777daedbe2fe5a45171fb42e43ceed9af' into eclair-plus-aosp

* commit '196c25c777daedbe2fe5a45171fb42e43ceed9af':
  don't complain if recovery icon is short
2009-09-15 13:46:00 -07:00
49c82ce553 am b5d542cd: am a3f89eab: add a run_program() function to edify
Merge commit 'b5d542cd40360867bc00cdb9266c0abf26448c55'

* commit 'b5d542cd40360867bc00cdb9266c0abf26448c55':
  add a run_program() function to edify
2009-09-10 14:41:05 -07:00
b5d542cd40 am a3f89eab: add a run_program() function to edify
Merge commit 'a3f89eabb7ddcf44add8ce3b321ceab6d35289cb' into eclair-plus-aosp

* commit 'a3f89eabb7ddcf44add8ce3b321ceab6d35289cb':
  add a run_program() function to edify
2009-09-10 14:30:43 -07:00
af42fa0a7d am 9a77b613: merge from open-source master
Merge commit '9a77b613f3fdf6340b0f5f24d1c725fd0001e4a9'

* commit '9a77b613f3fdf6340b0f5f24d1c725fd0001e4a9':
2009-09-04 11:05:32 -07:00
9a77b613f3 merge from open-source master 2009-09-04 07:50:41 -07:00
65a56909a3 merge from donut 2009-09-03 14:12:45 -07:00
2f39bf9a9f am cbf90380: merge from open-source master
Merge commit 'cbf903803850deb4f70490d97a1603e7b8679cc2'

* commit 'cbf903803850deb4f70490d97a1603e7b8679cc2':
  Not all failures to fopen_root_path() are serious.
2009-09-01 12:14:02 -07:00
cbf9038038 merge from open-source master 2009-09-01 08:27:43 -07:00
619ec2f3aa Not all failures to fopen_root_path() are serious.
Example: E:Can't open /cache/recovery/command.
2009-08-25 12:53:40 -07:00
6785c2534a am 34c98df7: (-s ours) do not merge: cherry-pick of c2d666bd4f from master
Merge commit '34c98df78a80881698f63ce0815f3e16823d85e0'

* commit '34c98df78a80881698f63ce0815f3e16823d85e0':
  do not merge: cherry-pick of c2d666bd4f from master
2009-08-18 12:13:35 -07:00
c2d666bd4f Recovery: When updating from SD card, update can't resume automatically
after a power loss

Submitted on behalf of Hong-Bin Wang <hong-binwang@motorola.com>
Signed-off-by: Jared Suttles <jared.suttles@motorola.com>
2009-08-17 17:39:54 -07:00
50a8a71f0b am 54e2e86c: (-s ours) do not merge: cherry-picked 60151a295c from master branch
Merge commit '54e2e86c5740a2c7a02e95e94c4aff362a5502cf'

* commit '54e2e86c5740a2c7a02e95e94c4aff362a5502cf':
  do not merge: cherry-picked 60151a295c from master branch
2009-08-17 14:11:31 -07:00
60151a295c verify whole-file signature instead of jarsigner signatures
In recovery, verify a signature that covers the entire zip file,
instead of using the jarsigner format to verify individual files.

Bug: 1328985
2009-08-14 17:26:33 -07:00
92 changed files with 6740 additions and 760 deletions

View File

@ -8,6 +8,7 @@ commands_recovery_local_path := $(LOCAL_PATH)
# LOCAL_CPP_EXTENSION := .c
LOCAL_SRC_FILES := \
mounts.c \
extendedcommands.c \
nandroid.c \
legacy.c \
@ -26,12 +27,6 @@ ifndef BOARD_HAS_NO_MISC_PARTITION
LOCAL_SRC_FILES += \
firmware.c \
bootloader.c
else
LOCAL_CFLAGS += -DBOARD_HAS_NO_MISC_PARTITION
endif
ifdef BOARD_RECOVERY_IGNORE_BOOTABLES
LOCAL_CFLAGS += -DBOARD_RECOVERY_IGNORE_BOOTABLES
endif
ifdef BOARD_HIJACK_RECOVERY_PATH
@ -44,90 +39,18 @@ LOCAL_MODULE := recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
RECOVERY_VERSION := ClockworkMod Recovery v2.5.1.0
RECOVERY_VERSION := ClockworkMod Recovery v2.5.1.8
LOCAL_CFLAGS += -DRECOVERY_VERSION="$(RECOVERY_VERSION)"
RECOVERY_API_VERSION := 2
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
ifeq ($(BOARD_HAS_NO_SELECT_BUTTON),true)
LOCAL_CFLAGS += -DKEY_POWER_IS_SELECT_ITEM
endif
BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_SDCARD_DEVICE_PRIMARY BOARD_SDCARD_DEVICE_SECONDARY BOARD_SDEXT_DEVICE BOARD_SDEXT_FILESYSTEM BOARD_DATA_DEVICE BOARD_DATA_FILESYSTEM BOARD_DATADATA_DEVICE BOARD_DATADATA_FILESYSTEM BOARD_CACHE_DEVICE BOARD_CACHE_FILESYSTEM BOARD_SYSTEM_DEVICE BOARD_SYSTEM_FILESYSTEM BOARD_HAS_DATADATA BOARD_DATA_FILESYSTEM_OPTIONS BOARD_DATADATA_FILESYSTEM_OPTIONS BOARD_CACHE_FILESYSTEM_OPTIONS BOARD_SYSTEM_FILESYSTEM_OPTIONS BOARD_HAS_MTD_CACHE BOARD_USES_BMLUTILS BOARD_USES_MMCUTILS BOARD_HAS_SMALL_RECOVERY BOARD_LDPI_RECOVERY BOARD_RECOVERY_IGNORE_BOOTABLES BOARD_HAS_NO_MISC_PARTITION BOARD_HAS_SDCARD_INTERNAL BOARD_SDCARD_DEVICE_INTERNAL
ifdef BOARD_SDCARD_DEVICE_PRIMARY
LOCAL_CFLAGS += -DSDCARD_DEVICE_PRIMARY=\"$(BOARD_SDCARD_DEVICE_PRIMARY)\"
endif
ifdef BOARD_SDCARD_DEVICE_SECONDARY
LOCAL_CFLAGS += -DSDCARD_DEVICE_SECONDARY=\"$(BOARD_SDCARD_DEVICE_SECONDARY)\"
endif
ifdef BOARD_SDEXT_DEVICE
LOCAL_CFLAGS += -DSDEXT_DEVICE=\"$(BOARD_SDEXT_DEVICE)\"
endif
ifdef BOARD_SDEXT_FILESYSTEM
LOCAL_CFLAGS += -DSDEXT_FILESYSTEM=\"$(BOARD_SDEXT_FILESYSTEM)\"
endif
ifdef BOARD_DATA_DEVICE
LOCAL_CFLAGS += -DDATA_DEVICE=\"$(BOARD_DATA_DEVICE)\"
endif
ifdef BOARD_DATA_FILESYSTEM
LOCAL_CFLAGS += -DDATA_FILESYSTEM=\"$(BOARD_DATA_FILESYSTEM)\"
endif
ifdef BOARD_DATADATA_DEVICE
LOCAL_CFLAGS += -DDATADATA_DEVICE=\"$(BOARD_DATADATA_DEVICE)\"
endif
ifdef BOARD_DATADATA_FILESYSTEM
LOCAL_CFLAGS += -DDATADATA_FILESYSTEM=\"$(BOARD_DATADATA_FILESYSTEM)\"
endif
ifdef BOARD_CACHE_DEVICE
LOCAL_CFLAGS += -DCACHE_DEVICE=\"$(BOARD_CACHE_DEVICE)\"
endif
ifdef BOARD_CACHE_FILESYSTEM
LOCAL_CFLAGS += -DCACHE_FILESYSTEM=\"$(BOARD_CACHE_FILESYSTEM)\"
endif
ifdef BOARD_SYSTEM_DEVICE
LOCAL_CFLAGS += -DSYSTEM_DEVICE=\"$(BOARD_SYSTEM_DEVICE)\"
endif
ifdef BOARD_SYSTEM_FILESYSTEM
LOCAL_CFLAGS += -DSYSTEM_FILESYSTEM=\"$(BOARD_SYSTEM_FILESYSTEM)\"
endif
ifdef BOARD_HAS_DATADATA
LOCAL_CFLAGS += -DHAS_DATADATA
endif
ifdef BOARD_DATA_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DDATA_FILESYSTEM_OPTIONS=\"$(BOARD_DATA_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_DATADATA_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DDATADATA_FILESYSTEM_OPTIONS=\"$(BOARD_DATADATA_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_CACHE_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DCACHE_FILESYSTEM_OPTIONS=\"$(BOARD_CACHE_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_SYSTEM_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DSYSTEM_FILESYSTEM_OPTIONS=\"$(BOARD_SYSTEM_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_HAS_MTD_CACHE
LOCAL_CFLAGS += -DBOARD_HAS_MTD_CACHE
endif
ifdef BOARD_HAS_SMALL_RECOVERY
LOCAL_CFLAGS += -DBOARD_HAS_SMALL_RECOVERY
endif
$(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
$(if $($(board_define)), \
$(eval LOCAL_CFLAGS += -D$(board_define)=\"$($(board_define))\") \
) \
)
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
@ -142,9 +65,12 @@ ifeq ($(BOARD_CUSTOM_RECOVERY_KEYMAPPING),)
else
LOCAL_SRC_FILES += $(BOARD_CUSTOM_RECOVERY_KEYMAPPING)
endif
LOCAL_STATIC_LIBRARIES += libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image libmtdutils
LOCAL_STATIC_LIBRARIES += libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_STATIC_LIBRARIES += libamend
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc
@ -191,16 +117,35 @@ LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_SRC_FILES := killrecovery.sh
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := verifier_test.c verifier.c
LOCAL_MODULE := verifier_test
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(commands_recovery_local_path)/amend/Android.mk
include $(commands_recovery_local_path)/bmlutils/Android.mk
include $(commands_recovery_local_path)/flashutils/Android.mk
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
include $(commands_recovery_local_path)/mmcutils/Android.mk
include $(commands_recovery_local_path)/tools/Android.mk
include $(commands_recovery_local_path)/edify/Android.mk
include $(commands_recovery_local_path)/updater/Android.mk
include $(commands_recovery_local_path)/applypatch/Android.mk
include $(commands_recovery_local_path)/utilities/Android.mk
commands_recovery_local_path :=
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR
endif # !TARGET_SIMULATOR

49
CleanSpec.mk Normal file
View File

@ -0,0 +1,49 @@
# Copyright (C) 2007 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.
#
# If you don't need to do a full clean build but would like to touch
# a file or delete some intermediate files, add a clean step to the end
# of the list. These steps will only be run once, if they haven't been
# run before.
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
#
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
# Use $(OUT_DIR) to refer to the "out" directory.
#
# If you need to re-do something that's already mentioned, just copy
# the command and add it to the bottom of the list. E.g., if a change
# that you made last week required touching a file and a change you
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

61
applypatch/Android.mk Normal file
View File

@ -0,0 +1,61 @@
# Copyright (C) 2008 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.
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := applypatch.c bspatch.c freecache.c imgpatch.c utils.c
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += external/bzip2 external/zlib bootable/recovery
LOCAL_STATIC_LIBRARIES += libmtdutils libmincrypt libbz libz
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch_static
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := imgdiff.c utils.c bsdiff.c
LOCAL_MODULE := imgdiff
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += external/zlib external/bzip2
LOCAL_STATIC_LIBRARIES += libz libbz
include $(BUILD_HOST_EXECUTABLE)
endif # !TARGET_SIMULATOR

826
applypatch/applypatch.c Normal file
View File

@ -0,0 +1,826 @@
/*
* Copyright (C) 2008 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 <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "mincrypt/sha.h"
#include "applypatch.h"
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
int SaveFileContents(const char* filename, FileContents file);
int LoadMTDContents(const char* filename, FileContents* file);
int ParseSha1(const char* str, uint8_t* digest);
ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
static int mtd_partitions_scanned = 0;
// Read a file into memory; store it and its associated metadata in
// *file. Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
file->data = NULL;
// A special 'filename' beginning with "MTD:" means to load the
// contents of an MTD partition.
if (strncmp(filename, "MTD:", 4) == 0) {
return LoadMTDContents(filename, file);
}
if (stat(filename, &file->st) != 0) {
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
return -1;
}
file->size = file->st.st_size;
file->data = malloc(file->size);
FILE* f = fopen(filename, "rb");
if (f == NULL) {
printf("failed to open \"%s\": %s\n", filename, strerror(errno));
free(file->data);
file->data = NULL;
return -1;
}
ssize_t bytes_read = fread(file->data, 1, file->size, f);
if (bytes_read != file->size) {
printf("short read of \"%s\" (%ld bytes of %ld)\n",
filename, (long)bytes_read, (long)file->size);
free(file->data);
file->data = NULL;
return -1;
}
fclose(f);
SHA(file->data, file->size, file->sha1);
return 0;
}
static size_t* size_array;
// comparison function for qsort()ing an int array of indexes into
// size_array[].
static int compare_size_indices(const void* a, const void* b) {
int aa = *(int*)a;
int bb = *(int*)b;
if (size_array[aa] < size_array[bb]) {
return -1;
} else if (size_array[aa] > size_array[bb]) {
return 1;
} else {
return 0;
}
}
void FreeFileContents(FileContents* file) {
if (file) free(file->data);
free(file);
}
// Load the contents of an MTD partition into the provided
// FileContents. filename should be a string of the form
// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:...".
// The smallest size_n bytes for which that prefix of the mtd contents
// has the corresponding sha1 hash will be loaded. It is acceptable
// for a size value to be repeated with different sha1s. Will return
// 0 on success.
//
// This complexity is needed because if an OTA installation is
// interrupted, the partition might contain either the source or the
// target data, which might be of different lengths. We need to know
// the length in order to read from MTD (there is no "end-of-file"
// marker), so the caller must specify the possible lengths and the
// hash of the data, and we'll do the load expecting to find one of
// those hashes.
int LoadMTDContents(const char* filename, FileContents* file) {
#ifdef BOARD_USES_MTDUTILS
char* copy = strdup(filename);
const char* magic = strtok(copy, ":");
if (strcmp(magic, "MTD") != 0) {
printf("LoadMTDContents called with bad filename (%s)\n",
filename);
return -1;
}
const char* partition = strtok(NULL, ":");
int i;
int colons = 0;
for (i = 0; filename[i] != '\0'; ++i) {
if (filename[i] == ':') {
++colons;
}
}
if (colons < 3 || colons%2 == 0) {
printf("LoadMTDContents called with bad filename (%s)\n",
filename);
}
int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename
int* index = malloc(pairs * sizeof(int));
size_t* size = malloc(pairs * sizeof(size_t));
char** sha1sum = malloc(pairs * sizeof(char*));
for (i = 0; i < pairs; ++i) {
const char* size_str = strtok(NULL, ":");
size[i] = strtol(size_str, NULL, 10);
if (size[i] == 0) {
printf("LoadMTDContents called with bad size (%s)\n", filename);
return -1;
}
sha1sum[i] = strtok(NULL, ":");
index[i] = i;
}
// sort the index[] array so it indexes the pairs in order of
// increasing size.
size_array = size;
qsort(index, pairs, sizeof(int), compare_size_indices);
if (!mtd_partitions_scanned) {
mtd_scan_partitions();
mtd_partitions_scanned = 1;
}
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
if (mtd == NULL) {
printf("mtd partition \"%s\" not found (loading %s)\n",
partition, filename);
return -1;
}
MtdReadContext* ctx = mtd_read_partition(mtd);
if (ctx == NULL) {
printf("failed to initialize read of mtd partition \"%s\"\n",
partition);
return -1;
}
SHA_CTX sha_ctx;
SHA_init(&sha_ctx);
uint8_t parsed_sha[SHA_DIGEST_SIZE];
// allocate enough memory to hold the largest size.
file->data = malloc(size[index[pairs-1]]);
char* p = (char*)file->data;
file->size = 0; // # bytes read so far
for (i = 0; i < pairs; ++i) {
// Read enough additional bytes to get us up to the next size
// (again, we're trying the possibilities in order of increasing
// size).
size_t next = size[index[i]] - file->size;
size_t read = 0;
if (next > 0) {
read = mtd_read_data(ctx, p, next);
if (next != read) {
printf("short read (%d bytes of %d) for partition \"%s\"\n",
read, next, partition);
free(file->data);
file->data = NULL;
return -1;
}
SHA_update(&sha_ctx, p, read);
file->size += read;
}
// Duplicate the SHA context and finalize the duplicate so we can
// check it against this pair's expected hash.
SHA_CTX temp_ctx;
memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
const uint8_t* sha_so_far = SHA_final(&temp_ctx);
if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) {
printf("failed to parse sha1 %s in %s\n",
sha1sum[index[i]], filename);
free(file->data);
file->data = NULL;
return -1;
}
if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
// we have a match. stop reading the partition; we'll return
// the data we've read so far.
printf("mtd read matched size %d sha %s\n",
size[index[i]], sha1sum[index[i]]);
break;
}
p += read;
}
mtd_read_close(ctx);
if (i == pairs) {
// Ran off the end of the list of (size,sha1) pairs without
// finding a match.
printf("contents of MTD partition \"%s\" didn't match %s\n",
partition, filename);
free(file->data);
file->data = NULL;
return -1;
}
const uint8_t* sha_final = SHA_final(&sha_ctx);
for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
file->sha1[i] = sha_final[i];
}
// Fake some stat() info.
file->st.st_mode = 0644;
file->st.st_uid = 0;
file->st.st_gid = 0;
free(copy);
free(index);
free(size);
free(sha1sum);
return 0;
#else
printf("mtd utils not supported.\n");
return -1;
#endif
}
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, FileContents file) {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
printf("failed to open \"%s\" for write: %s\n",
filename, strerror(errno));
return -1;
}
ssize_t bytes_written = FileSink(file.data, file.size, &fd);
if (bytes_written != file.size) {
printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n",
filename, (long)bytes_written, (long)file.size,
strerror(errno));
close(fd);
return -1;
}
fsync(fd);
close(fd);
if (chmod(filename, file.st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
return 0;
}
// Write a memory buffer to target_mtd partition, a string of the form
// "MTD:<partition>[:...]". Return 0 on success.
int WriteToMTDPartition(unsigned char* data, size_t len,
const char* target_mtd) {
#ifdef BOARD_USES_MTDUTILS
char* partition = strchr(target_mtd, ':');
if (partition == NULL) {
printf("bad MTD target name \"%s\"\n", target_mtd);
return -1;
}
++partition;
// Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...".
// We want just the partition name "boot".
partition = strdup(partition);
char* end = strchr(partition, ':');
if (end != NULL)
*end = '\0';
if (!mtd_partitions_scanned) {
mtd_scan_partitions();
mtd_partitions_scanned = 1;
}
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
if (mtd == NULL) {
printf("mtd partition \"%s\" not found for writing\n", partition);
return -1;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
printf("failed to init mtd partition \"%s\" for writing\n",
partition);
return -1;
}
size_t written = mtd_write_data(ctx, (char*)data, len);
if (written != len) {
printf("only wrote %d of %d bytes to MTD %s\n",
written, len, partition);
mtd_write_close(ctx);
return -1;
}
if (mtd_erase_blocks(ctx, -1) < 0) {
printf("error finishing mtd write of %s\n", partition);
mtd_write_close(ctx);
return -1;
}
if (mtd_write_close(ctx)) {
printf("error closing mtd write of %s\n", partition);
return -1;
}
free(partition);
return 0;
#else
printf("mtd utils not supported.\n");
return -1;
#endif
}
// Take a string 'str' of 40 hex digits and parse it into the 20
// byte array 'digest'. 'str' may contain only the digest or be of
// the form "<digest>:<anything>". Return 0 on success, -1 on any
// error.
int ParseSha1(const char* str, uint8_t* digest) {
int i;
const char* ps = str;
uint8_t* pd = digest;
for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
int digit;
if (*ps >= '0' && *ps <= '9') {
digit = *ps - '0';
} else if (*ps >= 'a' && *ps <= 'f') {
digit = *ps - 'a' + 10;
} else if (*ps >= 'A' && *ps <= 'F') {
digit = *ps - 'A' + 10;
} else {
return -1;
}
if (i % 2 == 0) {
*pd = digit << 4;
} else {
*pd |= digit;
++pd;
}
}
if (*ps != '\0') return -1;
return 0;
}
// Search an array of sha1 strings for one matching the given sha1.
// Return the index of the match on success, or -1 if no match is
// found.
int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
int num_patches) {
int i;
uint8_t patch_sha1[SHA_DIGEST_SIZE];
for (i = 0; i < num_patches; ++i) {
if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 &&
memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) {
return i;
}
}
return -1;
}
// Returns 0 if the contents of the file (argv[2]) or the cached file
// match any of the sha1's on the command line (argv[3:]). Returns
// nonzero otherwise.
int applypatch_check(const char* filename,
int num_patches, char** const patch_sha1_str) {
FileContents file;
file.data = NULL;
// It's okay to specify no sha1s; the check will pass if the
// LoadFileContents is successful. (Useful for reading MTD
// partitions, where the filename encodes the sha1s; no need to
// check them twice.)
if (LoadFileContents(filename, &file) != 0 ||
(num_patches > 0 &&
FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) {
printf("file \"%s\" doesn't have any of expected "
"sha1 sums; checking cache\n", filename);
free(file.data);
// If the source file is missing or corrupted, it might be because
// we were killed in the middle of patching it. A copy of it
// should have been made in CACHE_TEMP_SOURCE. If that file
// exists and matches the sha1 we're looking for, the check still
// passes.
if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
printf("failed to load cache file\n");
return 1;
}
if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
printf("cache bits don't match any sha1 for \"%s\"\n", filename);
free(file.data);
return 1;
}
}
free(file.data);
return 0;
}
int ShowLicenses() {
ShowBSDiffLicense();
return 0;
}
ssize_t FileSink(unsigned char* data, ssize_t len, void* token) {
int fd = *(int *)token;
ssize_t done = 0;
ssize_t wrote;
while (done < (ssize_t) len) {
wrote = write(fd, data+done, len-done);
if (wrote <= 0) {
printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno));
return done;
}
done += wrote;
}
return done;
}
typedef struct {
unsigned char* buffer;
ssize_t size;
ssize_t pos;
} MemorySinkInfo;
ssize_t MemorySink(unsigned char* data, ssize_t len, void* token) {
MemorySinkInfo* msi = (MemorySinkInfo*)token;
if (msi->size - msi->pos < len) {
return -1;
}
memcpy(msi->buffer + msi->pos, data, len);
msi->pos += len;
return len;
}
// Return the amount of free space (in bytes) on the filesystem
// containing filename. filename must exist. Return -1 on error.
size_t FreeSpaceForFile(const char* filename) {
struct statfs sf;
if (statfs(filename, &sf) != 0) {
printf("failed to statfs %s: %s\n", filename, strerror(errno));
return -1;
}
return sf.f_bsize * sf.f_bfree;
}
int CacheSizeCheck(size_t bytes) {
if (MakeFreeSpaceOnCache(bytes) < 0) {
printf("unable to make %ld bytes available on /cache\n", (long)bytes);
return 1;
} else {
return 0;
}
}
// This function applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// - if the sha1 hash of <target_filename> is <target_sha1_string>,
// does nothing and exits successfully.
//
// - otherwise, if the sha1 hash of <source_filename> is one of the
// entries in <patch_sha1_str>, the corresponding patch from
// <patch_data> (which must be a VAL_BLOB) is applied to produce a
// new file (the type of patch is automatically detected from the
// blob daat). If that new file has sha1 hash <target_sha1_str>,
// moves it to replace <target_filename>, and exits successfully.
// Note that if <source_filename> and <target_filename> are not the
// same, <source_filename> is NOT deleted on success.
// <target_filename> may be the string "-" to mean "the same as
// source_filename".
//
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
// <source_filename> may refer to an MTD partition to read the source
// data. See the comments for the LoadMTDContents() function above
// for the format of such a filename.
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
size_t target_size,
int num_patches,
char** const patch_sha1_str,
Value** patch_data) {
printf("\napplying patch to %s\n", source_filename);
if (target_filename[0] == '-' &&
target_filename[1] == '\0') {
target_filename = source_filename;
}
uint8_t target_sha1[SHA_DIGEST_SIZE];
if (ParseSha1(target_sha1_str, target_sha1) != 0) {
printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
return 1;
}
FileContents copy_file;
FileContents source_file;
const Value* source_patch_value = NULL;
const Value* copy_patch_value = NULL;
int made_copy = 0;
// We try to load the target file into the source_file object.
if (LoadFileContents(target_filename, &source_file) == 0) {
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
printf("\"%s\" is already target; no patch needed\n",
target_filename);
return 0;
}
}
if (source_file.data == NULL ||
(target_filename != source_filename &&
strcmp(target_filename, source_filename) != 0)) {
// Need to load the source file: either we failed to load the
// target file, or we did but it's different from the source file.
free(source_file.data);
LoadFileContents(source_filename, &source_file);
}
if (source_file.data != NULL) {
int to_use = FindMatchingPatch(source_file.sha1,
patch_sha1_str, num_patches);
if (to_use >= 0) {
source_patch_value = patch_data[to_use];
}
}
if (source_patch_value == NULL) {
free(source_file.data);
printf("source file is bad; trying copy\n");
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
// fail.
printf("failed to read copy file\n");
return 1;
}
int to_use = FindMatchingPatch(copy_file.sha1,
patch_sha1_str, num_patches);
if (to_use > 0) {
copy_patch_value = patch_data[to_use];
}
if (copy_patch_value == NULL) {
// fail.
printf("copy file doesn't match source SHA-1s either\n");
return 1;
}
}
int retry = 1;
SHA_CTX ctx;
int output;
MemorySinkInfo msi;
FileContents* source_to_use;
char* outname;
// assume that target_filename (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
// We need something that exists for calling statfs().
char target_fs[strlen(target_filename)+1];
char* slash = strchr(target_filename+1, '/');
if (slash != NULL) {
int count = slash - target_filename;
strncpy(target_fs, target_filename, count);
target_fs[count] = '\0';
} else {
strcpy(target_fs, target_filename);
}
do {
// Is there enough room in the target filesystem to hold the patched
// file?
if (strncmp(target_filename, "MTD:", 4) == 0) {
// If the target is an MTD partition, we're actually going to
// write the output to /tmp and then copy it to the partition.
// statfs() always returns 0 blocks free for /tmp, so instead
// we'll just assume that /tmp has enough space to hold the file.
// We still write the original source to cache, in case the MTD
// write is interrupted.
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
retry = 0;
} else {
int enough_space = 0;
if (retry > 0) {
size_t free_space = FreeSpaceForFile(target_fs);
int enough_space =
(free_space > (target_size * 3 / 2)); // 50% margin of error
printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
(long)target_size, (long)free_space, retry, enough_space);
}
if (!enough_space) {
retry = 0;
}
if (!enough_space && source_patch_value != NULL) {
// Using the original source, but not enough free space. First
// copy the source file to cache, then delete it from the original
// location.
if (strncmp(source_filename, "MTD:", 4) == 0) {
// It's impossible to free space on the target filesystem by
// deleting the source if the source is an MTD partition. If
// we're ever in a state where we need to do this, fail.
printf("not enough free space for target but source is MTD\n");
return 1;
}
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
unlink(source_filename);
size_t free_space = FreeSpaceForFile(target_fs);
printf("(now %ld bytes free for target)\n", (long)free_space);
}
}
const Value* patch;
if (source_patch_value != NULL) {
source_to_use = &source_file;
patch = source_patch_value;
} else {
source_to_use = &copy_file;
patch = copy_patch_value;
}
if (patch->type != VAL_BLOB) {
printf("patch is not a blob\n");
return 1;
}
SinkFn sink = NULL;
void* token = NULL;
output = -1;
outname = NULL;
if (strncmp(target_filename, "MTD:", 4) == 0) {
// We store the decoded output in memory.
msi.buffer = malloc(target_size);
if (msi.buffer == NULL) {
printf("failed to alloc %ld bytes for output\n",
(long)target_size);
return 1;
}
msi.pos = 0;
msi.size = target_size;
sink = MemorySink;
token = &msi;
} else {
// We write the decoded output to "<tgt-file>.patch".
outname = (char*)malloc(strlen(target_filename) + 10);
strcpy(outname, target_filename);
strcat(outname, ".patch");
output = open(outname, O_WRONLY | O_CREAT | O_TRUNC);
if (output < 0) {
printf("failed to open output file %s: %s\n",
outname, strerror(errno));
return 1;
}
sink = FileSink;
token = &output;
}
char* header = patch->data;
ssize_t header_bytes_read = patch->size;
SHA_init(&ctx);
int result;
if (header_bytes_read >= 8 &&
memcmp(header, "BSDIFF40", 8) == 0) {
result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
patch, 0, sink, token, &ctx);
} else if (header_bytes_read >= 8 &&
memcmp(header, "IMGDIFF2", 8) == 0) {
result = ApplyImagePatch(source_to_use->data, source_to_use->size,
patch, sink, token, &ctx);
} else {
printf("Unknown patch file format\n");
return 1;
}
if (output >= 0) {
fsync(output);
close(output);
}
if (result != 0) {
if (retry == 0) {
printf("applying patch failed\n");
return result != 0;
} else {
printf("applying patch failed; retrying\n");
}
if (outname != NULL) {
unlink(outname);
}
} else {
// succeeded; no need to retry
break;
}
} while (retry-- > 0);
const uint8_t* current_target_sha1 = SHA_final(&ctx);
if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
printf("patch did not produce expected sha1\n");
return 1;
}
if (output < 0) {
// Copy the temp file to the MTD partition.
if (WriteToMTDPartition(msi.buffer, msi.pos, target_filename) != 0) {
printf("write of patched data to %s failed\n", target_filename);
return 1;
}
free(msi.buffer);
} else {
// Give the .patch file the same owner, group, and mode of the
// original source file.
if (chmod(outname, source_to_use->st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
if (chown(outname, source_to_use->st.st_uid,
source_to_use->st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
// Finally, rename the .patch file to replace the target file.
if (rename(outname, target_filename) != 0) {
printf("rename of .patch to \"%s\" failed: %s\n",
target_filename, strerror(errno));
return 1;
}
}
// If this run of applypatch created the copy, and we're here, we
// can delete it.
if (made_copy) unlink(CACHE_TEMP_SOURCE);
// Success!
return 0;
}

84
applypatch/applypatch.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2008 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 _APPLYPATCH_H
#define _APPLYPATCH_H
#include <sys/stat.h>
#include "mincrypt/sha.h"
#include "edify/expr.h"
typedef struct _Patch {
uint8_t sha1[SHA_DIGEST_SIZE];
const char* patch_filename;
} Patch;
typedef struct _FileContents {
uint8_t sha1[SHA_DIGEST_SIZE];
unsigned char* data;
ssize_t size;
struct stat st;
} FileContents;
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
// it to free up space. If the expected source file doesn't exist, or
// is corrupted, we look to see if this file contains the bits we want
// and use it as the source instead.
#define CACHE_TEMP_SOURCE "/cache/saved.file"
typedef ssize_t (*SinkFn)(unsigned char*, ssize_t, void*);
// applypatch.c
int ShowLicenses();
size_t FreeSpaceForFile(const char* filename);
int CacheSizeCheck(size_t bytes);
int ParseSha1(const char* str, uint8_t* digest);
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
size_t target_size,
int num_patches,
char** const patch_sha1_str,
Value** patch_data);
int applypatch_check(const char* filename,
int num_patches,
char** const patch_sha1_str);
// Read a file into memory; store it and its associated metadata in
// *file. Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file);
void FreeFileContents(FileContents* file);
// bsdiff.c
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx);
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size);
// imgpatch.c
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx);
// freecache.c
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif

350
applypatch/applypatch.sh Executable file
View File

@ -0,0 +1,350 @@
#!/bin/bash
#
# A test suite for applypatch. Run in a client where you have done
# envsetup, choosecombo, etc.
#
# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
# system partition.
#
#
# TODO: find some way to get this run regularly along with the rest of
# the tests.
EMULATOR_PORT=5580
DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata
# This must be the filename that applypatch uses for its copies.
CACHE_TEMP_SOURCE=/cache/saved.file
# Put all binaries and files here. We use /cache because it's a
# temporary filesystem in the emulator; it's created fresh each time
# the emulator starts.
WORK_DIR=/system
# partition that WORK_DIR is located on, without the leading slash
WORK_FS=system
# set to 0 to use a device instead
USE_EMULATOR=1
# ------------------------
tmpdir=$(mktemp -d)
if [ "$USE_EMULATOR" == 1 ]; then
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
else
ADB="adb -d "
fi
echo "waiting to connect to device"
$ADB wait-for-device
echo "device is available"
$ADB remount
# free up enough space on the system partition for the test to run.
$ADB shell rm -r /system/media
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "$1"...
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
[ "$open_pid" == "" ] || kill $open_pid
[ "$pid_emulator" == "" ] || kill $pid_emulator
exit 1
}
sha1() {
sha1sum $1 | awk '{print $1}'
}
free_space() {
run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}"
}
cleanup() {
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
testname "removing test files"
run_command rm $WORK_DIR/bloat.dat
run_command rm $WORK_DIR/old.file
run_command rm $WORK_DIR/foo
run_command rm $WORK_DIR/patch.bsdiff
run_command rm $WORK_DIR/applypatch
run_command rm $CACHE_TEMP_SOURCE
run_command rm /cache/bloat*.dat
[ "$pid_emulator" == "" ] || kill $pid_emulator
if [ $# == 0 ]; then
rm -rf $tmpdir
fi
}
cleanup leave_tmp
$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
BAD1_SHA1=$(printf "%040x" $RANDOM)
BAD2_SHA1=$(printf "%040x" $RANDOM)
OLD_SHA1=$(sha1 $DATA_DIR/old.file)
NEW_SHA1=$(sha1 $DATA_DIR/new.file)
NEW_SIZE=$(stat -c %s $DATA_DIR/new.file)
# --------------- basic execution ----------------------
testname "usage message"
run_command $WORK_DIR/applypatch && fail
testname "display license"
run_command $WORK_DIR/applypatch -l | grep -q -i copyright || fail
# --------------- check mode ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
testname "check mode single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "check mode cache (corrupted) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (corrupted) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (corrupted) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "check mode cache (missing) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (missing) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (missing) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# --------------- apply patch ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
echo hello > $tmpdir/foo
$ADB push $tmpdir/foo $WORK_DIR
# Check that the partition has enough space to apply the patch without
# copying. If it doesn't, we'll be testing the low-space condition
# when we intend to test the not-low-space condition.
testname "apply patches (with enough space)"
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS."
if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then
echo "Not enough space on /$WORK_FS to patch test file."
echo
echo "This doesn't mean that applypatch is necessarily broken;"
echo "just that /$WORK_FS doesn't have enough free space to"
echo "properly run this test."
exit 1
fi
testname "apply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch in new location ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
# Check that the partition has enough space to apply the patch without
# copying. If it doesn't, we'll be testing the low-space condition
# when we intend to test the not-low-space condition.
testname "apply patch to new location (with enough space)"
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS."
if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then
echo "Not enough space on /$WORK_FS to patch test file."
echo
echo "This doesn't mean that applypatch is necessarily broken;"
echo "just that /$WORK_FS doesn't have enough free space to"
echo "properly run this test."
exit 1
fi
run_command rm $WORK_DIR/new.file
run_command rm $CACHE_TEMP_SOURCE
testname "apply bsdiff patch to new location"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch to new location"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "apply bsdiff patch to new location with corrupted source"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# put some junk in the cache copy, too
run_command dd if=/dev/urandom of=$CACHE_TEMP_SOURCE count=100 bs=1024 || fail
run_command rm $WORK_DIR/new.file
testname "apply bsdiff patch to new location with corrupted source and copy (no new file)"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail
# put some junk in the new file
run_command dd if=/dev/urandom of=$WORK_DIR/new.file count=100 bs=1024 || fail
testname "apply bsdiff patch to new location with corrupted source and copy (bad new file)"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail
# --------------- apply patch with low space on /system ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that."
echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS now."
testname "apply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch with low space on /system and /cache ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS"
run_command mkdir /cache/subdir
run_command 'echo > /cache/subdir/a.file'
run_command 'echo > /cache/a.file'
run_command mkdir /cache/recovery /cache/recovery/otatest
run_command 'echo > /cache/recovery/otatest/b.file'
run_command "echo > $CACHE_TEMP_SOURCE"
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache; we'll soon fix that."
run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail
run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache now."
testname "apply bsdiff patch with low space, full cache, can't delete enough"
$ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$!
echo "open_pid is $open_pid"
# size check should fail even though it deletes some stuff
run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail
run_command ls /cache/bloat_small.dat && fail # was deleted
run_command ls /cache/a.file && fail # was deleted
run_command ls /cache/recovery/otatest/b.file && fail # was deleted
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should fail; not enough files can be deleted
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff && fail
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
kill $open_pid # /cache/bloat_large.dat is no longer open
testname "apply bsdiff patch with low space, full cache, can delete enough"
# should succeed after deleting /cache/bloat_large.dat
run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail
run_command ls /cache/bloat_large.dat && fail # was deleted
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should succeed
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE && fail # was deleted because patching overwrote it, then deleted it
# --------------- apply patch from cache ----------------------
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "apply bsdiff patch from cache (corrupted source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "apply bsdiff patch from cache (missing source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- cleanup ----------------------
cleanup
echo
echo PASS
echo

410
applypatch/bsdiff.c Normal file
View File

@ -0,0 +1,410 @@
/*
* Copyright (C) 2009 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.
*/
/*
* Most of this code comes from bsdiff.c from the bsdiff-4.3
* distribution, which is:
*/
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <bzlib.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h)
{
off_t i,j,k,x,tmp,jj,kk;
if(len<16) {
for(k=start;k<start+len;k+=j) {
j=1;x=V[I[k]+h];
for(i=1;k+i<start+len;i++) {
if(V[I[k+i]+h]<x) {
x=V[I[k+i]+h];
j=0;
};
if(V[I[k+i]+h]==x) {
tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
j++;
};
};
for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
if(j==1) I[k]=-1;
};
return;
};
x=V[I[start+len/2]+h];
jj=0;kk=0;
for(i=start;i<start+len;i++) {
if(V[I[i]+h]<x) jj++;
if(V[I[i]+h]==x) kk++;
};
jj+=start;kk+=jj;
i=start;j=0;k=0;
while(i<jj) {
if(V[I[i]+h]<x) {
i++;
} else if(V[I[i]+h]==x) {
tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
j++;
} else {
tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
while(jj+j<kk) {
if(V[I[jj+j]+h]==x) {
j++;
} else {
tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
if(jj>start) split(I,V,start,jj-start,h);
for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
if(jj==kk-1) I[jj]=-1;
if(start+len>kk) split(I,V,kk,start+len-kk,h);
}
static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
{
off_t buckets[256];
off_t i,h,len;
for(i=0;i<256;i++) buckets[i]=0;
for(i=0;i<oldsize;i++) buckets[old[i]]++;
for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
for(i=255;i>0;i--) buckets[i]=buckets[i-1];
buckets[0]=0;
for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
I[0]=oldsize;
for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
V[oldsize]=0;
for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
I[0]=-1;
for(h=1;I[0]!=-(oldsize+1);h+=h) {
len=0;
for(i=0;i<oldsize+1;) {
if(I[i]<0) {
len-=I[i];
i-=I[i];
} else {
if(len) I[i-len]=-len;
len=V[I[i]]+1-i;
split(I,V,i,len,h);
i+=len;
len=0;
};
};
if(len) I[i-len]=-len;
};
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
static off_t matchlen(u_char *old,off_t oldsize,u_char *new,off_t newsize)
{
off_t i;
for(i=0;(i<oldsize)&&(i<newsize);i++)
if(old[i]!=new[i]) break;
return i;
}
static off_t search(off_t *I,u_char *old,off_t oldsize,
u_char *new,off_t newsize,off_t st,off_t en,off_t *pos)
{
off_t x,y;
if(en-st<2) {
x=matchlen(old+I[st],oldsize-I[st],new,newsize);
y=matchlen(old+I[en],oldsize-I[en],new,newsize);
if(x>y) {
*pos=I[st];
return x;
} else {
*pos=I[en];
return y;
}
};
x=st+(en-st)/2;
if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,new,newsize,x,en,pos);
} else {
return search(I,old,oldsize,new,newsize,st,x,pos);
};
}
static void offtout(off_t x,u_char *buf)
{
off_t y;
if(x<0) y=-x; else y=x;
buf[0]=y%256;y-=buf[0];
y=y/256;buf[1]=y%256;y-=buf[1];
y=y/256;buf[2]=y%256;y-=buf[2];
y=y/256;buf[3]=y%256;y-=buf[3];
y=y/256;buf[4]=y%256;y-=buf[4];
y=y/256;buf[5]=y%256;y-=buf[5];
y=y/256;buf[6]=y%256;y-=buf[6];
y=y/256;buf[7]=y%256;
if(x<0) buf[7]|=0x80;
}
// This is main() from bsdiff.c, with the following changes:
//
// - old, oldsize, new, newsize are arguments; we don't load this
// data from files. old and new are owned by the caller; we
// don't free them at the end.
//
// - the "I" block of memory is owned by the caller, who passes a
// pointer to *I, which can be NULL. This way if we call
// bsdiff() multiple times with the same 'old' data, we only do
// the qsufsort() step the first time.
//
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
const char* patch_filename)
{
int fd;
off_t *I;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t dblen,eblen;
u_char *db,*eb;
u_char buf[8];
u_char header[32];
FILE * pf;
BZFILE * pfbz2;
int bz2err;
if (*IP == NULL) {
off_t* V;
*IP = malloc((oldsize+1) * sizeof(off_t));
V = malloc((oldsize+1) * sizeof(off_t));
qsufsort(*IP, V, old, oldsize);
free(V);
}
I = *IP;
if(((db=malloc(newsize+1))==NULL) ||
((eb=malloc(newsize+1))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
/* Create the patch file */
if ((pf = fopen(patch_filename, "w")) == NULL)
err(1, "%s", patch_filename);
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
offtout(0, header + 8);
offtout(0, header + 16);
offtout(newsize, header + 24);
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
/* Compute the differences, writing ctrl as we go */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newsize) {
oldscore=0;
for(scsc=scan+=len;scan<newsize;scan++) {
len=search(I,old,oldsize,new+scan,newsize-scan,
0,oldsize,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldsize) &&
(old[scsc+lastoffset] == new[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldsize) &&
(old[scan+lastoffset] == new[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
if(old[lastpos+i]==new[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan<newsize) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==new[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(new[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(new[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=new[lastscan+i]-old[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=new[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((scan-lenb)-(lastscan+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((pos-lenb)-(lastpos+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed ctrl data */
if ((len = ftello(pf)) == -1)
err(1, "ftello");
offtout(len-32, header + 8);
/* Write compressed diff data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, db, dblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed diff data */
if ((newsize = ftello(pf)) == -1)
err(1, "ftello");
offtout(newsize - len, header + 16);
/* Write compressed extra data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, eb, eblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Seek to the beginning, write the header, and close the file */
if (fseeko(pf, 0, SEEK_SET))
err(1, "fseeko");
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
if (fclose(pf))
err(1, "fclose");
/* Free the memory we used */
free(db);
free(eb);
return 0;
}

252
applypatch/bspatch.c Normal file
View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2008 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.
*/
// This file is a nearly line-for-line copy of bspatch.c from the
// bsdiff-4.3 distribution; the primary differences being how the
// input and output data are read and the error handling. Running
// applypatch with the -l option will display the bsdiff license
// notice.
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
#include "mincrypt/sha.h"
#include "applypatch.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
"\n"
"Copyright 2003-2005 Colin Percival\n"
"All rights reserved\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted providing that the following conditions\n"
"are met:\n"
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in the\n"
" documentation and/or other materials provided with the distribution.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
"IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
"DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
"STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
"IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
"POSSIBILITY OF SUCH DAMAGE.\n"
"\n------------------\n\n"
"This program uses Julian R Seward's \"libbzip2\" library, available\n"
"from http://www.bzip.org/.\n"
);
}
static off_t offtin(u_char *buf)
{
off_t y;
y=buf[7]&0x7F;
y=y*256;y+=buf[6];
y=y*256;y+=buf[5];
y=y*256;y+=buf[4];
y=y*256;y+=buf[3];
y=y*256;y+=buf[2];
y=y*256;y+=buf[1];
y=y*256;y+=buf[0];
if(buf[7]&0x80) y=-y;
return y;
}
int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) {
stream->next_out = (char*)buffer;
stream->avail_out = size;
while (stream->avail_out > 0) {
int bzerr = BZ2_bzDecompress(stream);
if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
printf("bz error %d decompressing\n", bzerr);
return -1;
}
if (stream->avail_out > 0) {
printf("need %d more bytes\n", stream->avail_out);
}
}
return 0;
}
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx) {
unsigned char* new_data;
ssize_t new_size;
if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
&new_data, &new_size) != 0) {
return -1;
}
if (sink(new_data, new_size, token) < new_size) {
printf("short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
if (ctx) {
SHA_update(ctx, new_data, new_size);
}
free(new_data);
return 0;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size) {
// Patch data format:
// 0 8 "BSDIFF40"
// 8 8 X
// 16 8 Y
// 24 8 sizeof(newfile)
// 32 X bzip2(control block)
// 32+X Y bzip2(diff block)
// 32+X+Y ??? bzip2(extra block)
// with control block a set of triples (x,y,z) meaning "add x bytes
// from oldfile to x bytes from the diff block; copy y bytes from the
// extra block; seek forwards in oldfile by z bytes".
unsigned char* header = (unsigned char*) patch->data + patch_offset;
if (memcmp(header, "BSDIFF40", 8) != 0) {
printf("corrupt bsdiff patch file header (magic number)\n");
return 1;
}
ssize_t ctrl_len, data_len;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
*new_size = offtin(header+24);
if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
printf("corrupt patch file header (data lengths)\n");
return 1;
}
int bzerr;
bz_stream cstream;
cstream.next_in = patch->data + patch_offset + 32;
cstream.avail_in = ctrl_len;
cstream.bzalloc = NULL;
cstream.bzfree = NULL;
cstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit control stream (%d)\n", bzerr);
}
bz_stream dstream;
dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
dstream.avail_in = data_len;
dstream.bzalloc = NULL;
dstream.bzfree = NULL;
dstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit diff stream (%d)\n", bzerr);
}
bz_stream estream;
estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
estream.bzalloc = NULL;
estream.bzfree = NULL;
estream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
printf("failed to bzinit extra stream (%d)\n", bzerr);
}
*new_data = malloc(*new_size);
if (*new_data == NULL) {
printf("failed to allocate %ld bytes of memory for output file\n",
(long)*new_size);
return 1;
}
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
off_t len_read;
int i;
unsigned char buf[24];
while (newpos < *new_size) {
// Read control data
if (FillBuffer(buf, 24, &cstream) != 0) {
printf("error while reading control stream\n");
return 1;
}
ctrl[0] = offtin(buf);
ctrl[1] = offtin(buf+8);
ctrl[2] = offtin(buf+16);
// Sanity check
if (newpos + ctrl[0] > *new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
printf("error while reading diff stream\n");
return 1;
}
// Add old data to diff string
for (i = 0; i < ctrl[0]; ++i) {
if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
(*new_data)[newpos+i] += old_data[oldpos+i];
}
}
// Adjust pointers
newpos += ctrl[0];
oldpos += ctrl[0];
// Sanity check
if (newpos + ctrl[1] > *new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
printf("error while reading extra stream\n");
return 1;
}
// Adjust pointers
newpos += ctrl[1];
oldpos += ctrl[2];
}
BZ2_bzDecompressEnd(&cstream);
BZ2_bzDecompressEnd(&dstream);
BZ2_bzDecompressEnd(&estream);
return 0;
}

172
applypatch/freecache.c Normal file
View File

@ -0,0 +1,172 @@
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include "applypatch.h"
static int EliminateOpenFiles(char** files, int file_count) {
DIR* d;
struct dirent* de;
d = opendir("/proc");
if (d == NULL) {
printf("error opening /proc: %s\n", strerror(errno));
return -1;
}
while ((de = readdir(d)) != 0) {
int i;
for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
if (de->d_name[i]) continue;
// de->d_name[i] is numeric
char path[FILENAME_MAX];
strcpy(path, "/proc/");
strcat(path, de->d_name);
strcat(path, "/fd/");
DIR* fdd;
struct dirent* fdde;
fdd = opendir(path);
if (fdd == NULL) {
printf("error opening %s: %s\n", path, strerror(errno));
continue;
}
while ((fdde = readdir(fdd)) != 0) {
char fd_path[FILENAME_MAX];
char link[FILENAME_MAX];
strcpy(fd_path, path);
strcat(fd_path, fdde->d_name);
int count;
count = readlink(fd_path, link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
// This is inefficient, but it should only matter if there are
// lots of files in /cache, and lots of them are open (neither
// of which should be true, especially in recovery).
if (strncmp(link, "/cache/", 7) == 0) {
int j;
for (j = 0; j < file_count; ++j) {
if (files[j] && strcmp(files[j], link) == 0) {
printf("%s is open by %s\n", link, de->d_name);
free(files[j]);
files[j] = NULL;
}
}
}
}
}
closedir(fdd);
}
closedir(d);
return 0;
}
int FindExpendableFiles(char*** names, int* entries) {
DIR* d;
struct dirent* de;
int size = 32;
*entries = 0;
*names = malloc(size * sizeof(char*));
char path[FILENAME_MAX];
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
unsigned int i;
for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
d = opendir(dirs[i]);
if (d == NULL) {
printf("error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
while ((de = readdir(d)) != 0) {
strcpy(path, dirs[i]);
strcat(path, "/");
strcat(path, de->d_name);
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
struct stat st;
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
if (*entries >= size) {
size *= 2;
*names = realloc(*names, size * sizeof(char*));
}
(*names)[(*entries)++] = strdup(path);
}
}
closedir(d);
}
printf("%d regular files in deletable directories\n", *entries);
if (EliminateOpenFiles(*names, *entries) < 0) {
return -1;
}
return 0;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
size_t free_now = FreeSpaceForFile("/cache");
printf("%ld bytes free on /cache (%ld needed)\n",
(long)free_now, (long)bytes_needed);
if (free_now >= bytes_needed) {
return 0;
}
char** names;
int entries;
if (FindExpendableFiles(&names, &entries) < 0) {
return -1;
}
if (entries == 0) {
// nothing we can delete to free up space!
printf("no files can be deleted to free space on /cache\n");
return -1;
}
// We could try to be smarter about which files to delete: the
// biggest ones? the smallest ones that will free up enough space?
// the oldest? the newest?
//
// Instead, we'll be dumb.
int i;
for (i = 0; i < entries && free_now < bytes_needed; ++i) {
if (names[i]) {
unlink(names[i]);
free_now = FreeSpaceForFile("/cache");
printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now);
free(names[i]);
}
}
for (; i < entries; ++i) {
free(names[i]);
}
free(names);
return (free_now >= bytes_needed) ? 0 : -1;
}

1010
applypatch/imgdiff.c Normal file

File diff suppressed because it is too large Load Diff

30
applypatch/imgdiff.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2009 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.
*/
// Image patch chunk types
#define CHUNK_NORMAL 0
#define CHUNK_GZIP 1 // version 1 only
#define CHUNK_DEFLATE 2 // version 2 only
#define CHUNK_RAW 3 // version 2 only
// The gzip header size is actually variable, but we currently don't
// support gzipped data with any of the optional fields, so for now it
// will always be ten bytes. See RFC 1952 for the definition of the
// gzip format.
#define GZIP_HEADER_LEN 10
// The gzip footer size really is fixed.
#define GZIP_FOOTER_LEN 8

118
applypatch/imgdiff_test.sh Executable file
View File

@ -0,0 +1,118 @@
#!/bin/bash
#
# A script for testing imgdiff/applypatch. It takes two full OTA
# packages as arguments. It generates (on the host) patches for all
# the zip/jar/apk files they have in common, as well as boot and
# recovery images. It then applies the patches on the device (or
# emulator) and checks that the resulting file is correct.
EMULATOR_PORT=5580
# set to 0 to use a device instead
USE_EMULATOR=0
# where on the device to do all the patching.
WORK_DIR=/data/local/tmp
START_OTA_PACKAGE=$1
END_OTA_PACKAGE=$2
# ------------------------
tmpdir=$(mktemp -d)
if [ "$USE_EMULATOR" == 1 ]; then
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
else
ADB="adb -d "
fi
echo "waiting to connect to device"
$ADB wait-for-device
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "$1"...
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
[ "$open_pid" == "" ] || kill $open_pid
[ "$pid_emulator" == "" ] || kill $pid_emulator
exit 1
}
sha1() {
sha1sum $1 | awk '{print $1}'
}
size() {
stat -c %s $1 | tr -d '\n'
}
cleanup() {
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
testname "removing test files"
run_command rm $WORK_DIR/applypatch
run_command rm $WORK_DIR/source
run_command rm $WORK_DIR/target
run_command rm $WORK_DIR/patch
[ "$pid_emulator" == "" ] || kill $pid_emulator
rm -rf $tmpdir
}
$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
patch_and_apply() {
local fn=$1
shift
unzip -p $START_OTA_PACKAGE $fn > $tmpdir/source
unzip -p $END_OTA_PACKAGE $fn > $tmpdir/target
imgdiff "$@" $tmpdir/source $tmpdir/target $tmpdir/patch
bsdiff $tmpdir/source $tmpdir/target $tmpdir/patch.bs
echo "patch for $fn is $(size $tmpdir/patch) [of $(size $tmpdir/target)] ($(size $tmpdir/patch.bs) with bsdiff)"
echo "$fn $(size $tmpdir/patch) of $(size $tmpdir/target) bsdiff $(size $tmpdir/patch.bs)" >> /tmp/stats.txt
$ADB push $tmpdir/source $WORK_DIR/source || fail "source push failed"
run_command rm /data/local/tmp/target
$ADB push $tmpdir/patch $WORK_DIR/patch || fail "patch push failed"
run_command /data/local/tmp/applypatch /data/local/tmp/source \
/data/local/tmp/target $(sha1 $tmpdir/target) $(size $tmpdir/target) \
$(sha1 $tmpdir/source):/data/local/tmp/patch \
|| fail "applypatch of $fn failed"
$ADB pull /data/local/tmp/target $tmpdir/result
diff -q $tmpdir/target $tmpdir/result || fail "patch output not correct!"
}
# --------------- basic execution ----------------------
for i in $((zipinfo -1 $START_OTA_PACKAGE; zipinfo -1 $END_OTA_PACKAGE) | \
sort | uniq -d | egrep -e '[.](apk|jar|zip)$'); do
patch_and_apply $i -z
done
patch_and_apply boot.img
patch_and_apply system/recovery.img
# --------------- cleanup ----------------------
cleanup
echo
echo PASS
echo

219
applypatch/imgpatch.c Normal file
View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2009 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.
*/
// See imgdiff.c in this directory for a description of the patch file
// format.
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "zlib.h"
#include "mincrypt/sha.h"
#include "applypatch.h"
#include "imgdiff.h"
#include "utils.h"
/*
* Apply the patch given in 'patch_filename' to the source data given
* by (old_data, old_size). Write the patched output to the 'output'
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx) {
ssize_t pos = 12;
char* header = patch->data;
if (patch->size < 12) {
printf("patch too short to contain header\n");
return -1;
}
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
// (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
// CHUNK_GZIP.)
if (memcmp(header, "IMGDIFF2", 8) != 0) {
printf("corrupt patch file header (magic number)\n");
return -1;
}
int num_chunks = Read4(header+8);
int i;
for (i = 0; i < num_chunks; ++i) {
// each chunk's header record starts with 4 bytes.
if (pos + 4 > patch->size) {
printf("failed to read chunk %d record\n", i);
return -1;
}
int type = Read4(patch->data + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
char* normal_header = patch->data + pos;
pos += 24;
if (pos > patch->size) {
printf("failed to read chunk %d normal header data\n", i);
return -1;
}
size_t src_start = Read8(normal_header);
size_t src_len = Read8(normal_header+8);
size_t patch_offset = Read8(normal_header+16);
ApplyBSDiffPatch(old_data + src_start, src_len,
patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
char* raw_header = patch->data + pos;
pos += 4;
if (pos > patch->size) {
printf("failed to read chunk %d raw header data\n", i);
return -1;
}
ssize_t data_len = Read4(raw_header);
if (pos + data_len > patch->size) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
SHA_update(ctx, patch->data + pos, data_len);
if (sink((unsigned char*)patch->data + pos,
data_len, token) != data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
pos += data_len;
} else if (type == CHUNK_DEFLATE) {
// deflate chunks have an additional 60 bytes in their chunk header.
char* deflate_header = patch->data + pos;
pos += 60;
if (pos > patch->size) {
printf("failed to read chunk %d deflate header data\n", i);
return -1;
}
size_t src_start = Read8(deflate_header);
size_t src_len = Read8(deflate_header+8);
size_t patch_offset = Read8(deflate_header+16);
size_t expanded_len = Read8(deflate_header+24);
size_t target_len = Read8(deflate_header+32);
int level = Read4(deflate_header+40);
int method = Read4(deflate_header+44);
int windowBits = Read4(deflate_header+48);
int memLevel = Read4(deflate_header+52);
int strategy = Read4(deflate_header+56);
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
unsigned char* expanded_source = malloc(expanded_len);
if (expanded_source == NULL) {
printf("failed to allocate %d bytes for expanded_source\n",
expanded_len);
return -1;
}
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
strm.next_out = expanded_source;
int ret;
ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
// We should have filled the output buffer exactly.
if (strm.avail_out != 0) {
printf("source inflation short by %d bytes\n", strm.avail_out);
return -1;
}
inflateEnd(&strm);
// Next, apply the bsdiff patch (in memory) to the uncompressed
// data.
unsigned char* uncompressed_target_data;
ssize_t uncompressed_target_size;
if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
patch, patch_offset,
&uncompressed_target_data,
&uncompressed_target_size) != 0) {
return -1;
}
// Now compress the target data and append it to the output.
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
unsigned char* temp_data = expanded_source;
ssize_t temp_size = expanded_len;
if (temp_size < 32768) {
// ... unless the buffer is too small, in which case we'll
// allocate a fresh one.
free(temp_data);
temp_data = malloc(32768);
temp_size = 32768;
}
// now the deflate stream
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_size;
strm.next_in = uncompressed_target_data;
ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
do {
strm.avail_out = temp_size;
strm.next_out = temp_data;
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_size - strm.avail_out;
if (sink(temp_data, have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
return -1;
}
SHA_update(ctx, temp_data, have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
free(temp_data);
free(uncompressed_target_data);
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
}
}
return 0;
}

195
applypatch/main.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (C) 2009 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "applypatch.h"
#include "edify/expr.h"
#include "mincrypt/sha.h"
int CheckMode(int argc, char** argv) {
if (argc < 3) {
return 2;
}
return applypatch_check(argv[2], argc-3, argv+3);
}
int SpaceMode(int argc, char** argv) {
if (argc != 3) {
return 2;
}
char* endptr;
size_t bytes = strtol(argv[2], &endptr, 10);
if (bytes == 0 && endptr == argv[2]) {
printf("can't parse \"%s\" as byte count\n\n", argv[2]);
return 1;
}
return CacheSizeCheck(bytes);
}
// Parse arguments (which should be of the form "<sha1>" or
// "<sha1>:<filename>" into the new parallel arrays *sha1s and
// *patches (loading file contents into the patches). Returns 0 on
// success.
static int ParsePatchArgs(int argc, char** argv,
char*** sha1s, Value*** patches, int* num_patches) {
*num_patches = argc;
*sha1s = malloc(*num_patches * sizeof(char*));
*patches = malloc(*num_patches * sizeof(Value*));
memset(*patches, 0, *num_patches * sizeof(Value*));
uint8_t digest[SHA_DIGEST_SIZE];
int i;
for (i = 0; i < *num_patches; ++i) {
char* colon = strchr(argv[i], ':');
if (colon != NULL) {
*colon = '\0';
++colon;
}
if (ParseSha1(argv[i], digest) != 0) {
printf("failed to parse sha1 \"%s\"\n", argv[i]);
return -1;
}
(*sha1s)[i] = argv[i];
if (colon == NULL) {
(*patches)[i] = NULL;
} else {
FileContents fc;
if (LoadFileContents(colon, &fc) != 0) {
goto abort;
}
(*patches)[i] = malloc(sizeof(Value));
(*patches)[i]->type = VAL_BLOB;
(*patches)[i]->size = fc.size;
(*patches)[i]->data = (char*)fc.data;
}
}
return 0;
abort:
for (i = 0; i < *num_patches; ++i) {
Value* p = (*patches)[i];
if (p != NULL) {
free(p->data);
free(p);
}
}
free(*sha1s);
free(*patches);
return -1;
}
int PatchMode(int argc, char** argv) {
if (argc < 6) {
return 2;
}
char* endptr;
size_t target_size = strtol(argv[4], &endptr, 10);
if (target_size == 0 && endptr == argv[4]) {
printf("can't parse \"%s\" as byte count\n\n", argv[4]);
return 1;
}
char** sha1s;
Value** patches;
int num_patches;
if (ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches) != 0) {
printf("failed to parse patch args\n");
return 1;
}
int result = applypatch(argv[1], argv[2], argv[3], target_size,
num_patches, sha1s, patches);
int i;
for (i = 0; i < num_patches; ++i) {
Value* p = patches[i];
if (p != NULL) {
free(p->data);
free(p);
}
}
free(sha1s);
free(patches);
return result;
}
// This program applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// - if the sha1 hash of <tgt-file> is <tgt-sha1>, does nothing and exits
// successfully.
//
// - otherwise, if the sha1 hash of <src-file> is <src-sha1>, applies the
// bsdiff <patch> to <src-file> to produce a new file (the type of patch
// is automatically detected from the file header). If that new
// file has sha1 hash <tgt-sha1>, moves it to replace <tgt-file>, and
// exits successfully. Note that if <src-file> and <tgt-file> are
// not the same, <src-file> is NOT deleted on success. <tgt-file>
// may be the string "-" to mean "the same as src-file".
//
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
// <src-file> (or <file> in check mode) may refer to an MTD partition
// to read the source data. See the comments for the
// LoadMTDContents() function above for the format of such a filename.
int main(int argc, char** argv) {
if (argc < 2) {
usage:
printf(
"usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
"[<src-sha1>:<patch> ...]\n"
" or %s -c <file> [<sha1> ...]\n"
" or %s -s <bytes>\n"
" or %s -l\n"
"\n"
"Filenames may be of the form\n"
" MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
"to specify reading from or writing to an MTD partition.\n\n",
argv[0], argv[0], argv[0], argv[0]);
return 2;
}
int result;
if (strncmp(argv[1], "-l", 3) == 0) {
result = ShowLicenses();
} else if (strncmp(argv[1], "-c", 3) == 0) {
result = CheckMode(argc, argv);
} else if (strncmp(argv[1], "-s", 3) == 0) {
result = SpaceMode(argc, argv);
} else {
result = PatchMode(argc, argv);
}
if (result == 2) {
goto usage;
}
return result;
}

BIN
applypatch/testdata/new.file vendored Normal file

Binary file not shown.

BIN
applypatch/testdata/old.file vendored Normal file

Binary file not shown.

BIN
applypatch/testdata/patch.bsdiff vendored Normal file

Binary file not shown.

65
applypatch/utils.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2009 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 <stdio.h>
#include "utils.h"
/** Write a 4-byte value to f in little-endian order. */
void Write4(int value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
}
/** Write an 8-byte value to f in little-endian order. */
void Write8(long long value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
fputc((value >> 32) & 0xff, f);
fputc((value >> 40) & 0xff, f);
fputc((value >> 48) & 0xff, f);
fputc((value >> 56) & 0xff, f);
}
int Read2(void* pv) {
unsigned char* p = pv;
return (int)(((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
int Read4(void* pv) {
unsigned char* p = pv;
return (int)(((unsigned int)p[3] << 24) |
((unsigned int)p[2] << 16) |
((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
long long Read8(void* pv) {
unsigned char* p = pv;
return (long long)(((unsigned long long)p[7] << 56) |
((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) |
((unsigned long long)p[4] << 32) |
((unsigned long long)p[3] << 24) |
((unsigned long long)p[2] << 16) |
((unsigned long long)p[1] << 8) |
(unsigned long long)p[0]);
}

30
applypatch/utils.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2009 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 _BUILD_TOOLS_APPLYPATCH_UTILS_H
#define _BUILD_TOOLS_APPLYPATCH_UTILS_H
#include <stdio.h>
// Read and write little-endian values of various sizes.
void Write4(int value, FILE* f);
void Write8(long long value, FILE* f);
int Read2(void* p);
int Read4(void* p);
long long Read8(void* p);
#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H

7
bmlutils/Android.mk Normal file
View File

@ -0,0 +1,7 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DBOARD_BOOT_DEVICE=\"$(BOARD_BOOT_DEVICE)\"
LOCAL_SRC_FILES := bmlutils.c
LOCAL_MODULE := libbmlutils
include $(BUILD_STATIC_LIBRARY)

100
bmlutils/bmlutils.c Normal file
View File

@ -0,0 +1,100 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/reboot.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>
extern int __system(const char *command);
#define BML_UNLOCK_ALL 0x8A29 ///< unlock all partition RO -> RW
static int restore_internal(const char* bml, const char* filename)
{
char buf[4096];
int dstfd, srcfd, bytes_read, bytes_written, total_read = 0;
if (filename == NULL)
srcfd = 0;
else {
srcfd = open(filename, O_RDONLY | O_LARGEFILE);
if (srcfd < 0)
return 2;
}
dstfd = open(bml, O_RDWR | O_LARGEFILE);
if (dstfd < 0)
return 3;
if (ioctl(dstfd, BML_UNLOCK_ALL, 0))
return 4;
do {
total_read += bytes_read = read(srcfd, buf, 4096);
if (!bytes_read)
break;
if (bytes_read < 4096)
memset(&buf[bytes_read], 0, 4096 - bytes_read);
if (write(dstfd, buf, 4096) < 4096)
return 5;
} while(bytes_read == 4096);
close(dstfd);
close(srcfd);
return 0;
}
int cmd_bml_restore_raw_partition(const char *partition, const char *filename)
{
char *bml;
if (strcmp(partition, "boot") == 0 || strcmp(partition, "recovery") == 0)
bml = "/dev/block/bml7";
else
return 6;
int ret = restore_internal("/dev/block/bml7", filename);
if (ret != 0)
return ret;
ret = restore_internal("/dev/block/bml8", filename);
return ret;
}
int cmd_bml_backup_raw_partition(const char *partition, const char *filename)
{
char tmp[PATH_MAX];
sprintf(tmp, "dd of=%s if=/dev/block/bml7 bs=4096", filename);
return __system(tmp);
}
int cmd_bml_erase_raw_partition(const char *partition)
{
// TODO: implement raw wipe
return 0;
}
int cmd_bml_erase_partition(const char *partition, const char *filesystem)
{
return -1;
}
int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
{
return -1;
}
int cmd_bml_get_partition_device(const char *partition, char *device)
{
return -1;
}

View File

@ -40,6 +40,7 @@
#include "roots.h"
#include "extendedcommands.h"
#include "flashutils/flashutils.h"
static int gDidShowProgress = 0;
@ -145,7 +146,7 @@ cmd_format(const char *name, void *cookie, int argc, const char *argv[],
LOGE("Can't format %s\n", root);
return 1;
}
#ifdef HAS_DATADATA
#ifdef BOARD_HAS_DATADATA
if (0 == strcmp(root, "DATA:")) {
ret = format_root_device("DATADATA:");
if (ret != 0) {
@ -653,6 +654,11 @@ static int
cmd_write_raw_image(const char *name, void *cookie,
int argc, const char *argv[], PermissionRequestList *permissions)
{
if (device_flash_type() != MTD) {
LOGE("Board does not support mtd utils.");
return -1;
}
UNUSED(cookie);
CHECK_WORDS();
//xxx permissions

View File

@ -32,6 +32,10 @@ char* MENU_ITEMS[] = { "reboot system now",
"advanced",
NULL };
int device_recovery_start() {
return 0;
}
int device_toggle_display(volatile char* key_pressed, int key_code) {
int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
if (alt && key_code == KEY_L)

View File

@ -33,12 +33,40 @@ int BooleanString(const char* s) {
}
char* Evaluate(State* state, Expr* expr) {
Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
if (v == NULL) return NULL;
if (v->type != VAL_STRING) {
ErrorAbort(state, "expecting string, got value type %d", v->type);
FreeValue(v);
return NULL;
}
char* result = v->data;
free(v);
return result;
}
Value* EvaluateValue(State* state, Expr* expr) {
return expr->fn(expr->name, state, expr->argc, expr->argv);
}
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* StringValue(char* str) {
if (str == NULL) return NULL;
Value* v = malloc(sizeof(Value));
v->type = VAL_STRING;
v->size = strlen(str);
v->data = str;
return v;
}
void FreeValue(Value* v) {
if (v == NULL) return;
free(v->data);
free(v);
}
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
return strdup("");
return StringValue(strdup(""));
}
char** strings = malloc(argc * sizeof(char*));
int i;
@ -67,10 +95,11 @@ char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
for (i = 0; i < argc; ++i) {
free(strings[i]);
}
return result;
free(strings);
return StringValue(result);
}
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2 && argc != 3) {
free(state->errmsg);
state->errmsg = strdup("ifelse expects 2 or 3 arguments");
@ -83,18 +112,18 @@ char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (BooleanString(cond) == true) {
free(cond);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
if (argc == 3) {
free(cond);
return Evaluate(state, argv[2]);
return EvaluateValue(state, argv[2]);
} else {
return cond;
return StringValue(cond);
}
}
}
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
char* msg = NULL;
if (argc > 0) {
msg = Evaluate(state, argv[0]);
@ -108,7 +137,7 @@ char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@ -130,20 +159,20 @@ char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
}
return strdup("");
return StringValue(strdup(""));
}
char* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) {
return NULL;
}
int v = strtol(val, NULL, 10);
sleep(v);
return val;
return StringValue(val);
}
char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@ -153,48 +182,44 @@ char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
fputs(v, stdout);
free(v);
}
return strdup("");
return StringValue(strdup(""));
}
char* LogicalAndFn(const char* name, State* state,
Value* LogicalAndFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == true) {
free(left);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
return left;
return StringValue(left);
}
}
char* LogicalOrFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* LogicalOrFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == false) {
free(left);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
return left;
return StringValue(left);
}
}
char* LogicalNotFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* LogicalNotFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) return NULL;
bool bv = BooleanString(val);
free(val);
if (bv) {
return strdup("");
} else {
return strdup("t");
}
return StringValue(strdup(bv ? "" : "t"));
}
char* SubstringFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* SubstringFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* needle = Evaluate(state, argv[0]);
if (needle == NULL) return NULL;
char* haystack = Evaluate(state, argv[1]);
@ -206,10 +231,10 @@ char* SubstringFn(const char* name, State* state,
char* result = strdup(strstr(haystack, needle) ? "t" : "");
free(needle);
free(haystack);
return result;
return StringValue(result);
}
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@ -221,10 +246,10 @@ char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
free(left);
free(right);
return result;
return StringValue(result);
}
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@ -236,17 +261,17 @@ char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
free(left);
free(right);
return result;
return StringValue(result);
}
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* left = EvaluateValue(state, argv[0]);
if (left == NULL) return NULL;
free(left);
return Evaluate(state, argv[1]);
FreeValue(left);
return EvaluateValue(state, argv[1]);
}
char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("less_than_int expects 2 arguments");
@ -277,10 +302,11 @@ char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
done:
free(left);
free(right);
return strdup(result ? "t" : "");
return StringValue(strdup(result ? "t" : ""));
}
char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* GreaterThanIntFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("greater_than_int expects 2 arguments");
@ -294,8 +320,8 @@ char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
return LessThanIntFn(name, state, 2, temp);
}
char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return strdup(name);
Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(name));
}
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
@ -389,11 +415,39 @@ int ReadArgs(State* state, Expr* argv[], int count, ...) {
for (j = 0; j < i; ++j) {
free(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, char**)) = args[i];
}
va_end(v);
free(args);
return 0;
}
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
Value** args = malloc(count * sizeof(Value*));
va_list v;
va_start(v, count);
int i;
for (i = 0; i < count; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
va_end(v);
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, Value**)) = args[i];
}
va_end(v);
free(args);
return 0;
}
@ -418,9 +472,30 @@ char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
return args;
}
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
Value** args = (Value**)malloc(argc * sizeof(Value*));
int i = 0;
for (i = 0; i < argc; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return NULL;
}
}
return args;
}
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
char* ErrorAbort(State* state, char* format, ...) {
Value* ErrorAbort(State* state, char* format, ...) {
char* buffer = malloc(4096);
va_list v;
va_start(v, format);

View File

@ -17,6 +17,8 @@
#ifndef _EXPRESSION_H
#define _EXPRESSION_H
#include <unistd.h>
#include "yydefs.h"
#define MAX_STRING_LEN 1024
@ -39,8 +41,17 @@ typedef struct {
char* errmsg;
} State;
typedef char* (*Function)(const char* name, State* state,
int argc, Expr* argv[]);
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
#define VAL_BLOB 2
typedef struct {
int type;
ssize_t size;
char* data;
} Value;
typedef Value* (*Function)(const char* name, State* state,
int argc, Expr* argv[]);
struct Expr {
Function fn;
@ -50,31 +61,41 @@ struct Expr {
int start, end;
};
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, return the resulting Value. The caller takes
// ownership of the returned Value.
Value* EvaluateValue(State* state, Expr* expr);
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, assert that it is a string, and return the resulting
// char*. The caller takes ownership of the returned char*. This is
// a convenience function for older functions that want to deal only
// with strings.
char* Evaluate(State* state, Expr* expr);
// Glue to make an Expr out of a literal.
char* Literal(const char* name, State* state, int argc, Expr* argv[]);
Value* Literal(const char* name, State* state, int argc, Expr* argv[]);
// Functions corresponding to various syntactic sugar operators.
// ("concat" is also available as a builtin function, to concatenate
// more than two strings.)
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
// Convenience function for building expressions with a fixed number
// of arguments.
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
// Global builtins, registered by RegisterBuiltins().
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
// For setting and getting the global error string (when returning
@ -112,15 +133,31 @@ Function FindFunction(const char* name);
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
char* ErrorAbort(State* state, char* format, ...);
Value* ErrorAbort(State* state, char* format, ...);
// Wrap a string into a Value, taking ownership of the string.
Value* StringValue(char* str);
// Free a Value object.
void FreeValue(Value* v);
#endif // _EXPRESSION_H

View File

@ -15,6 +15,8 @@
* limitations under the License.
*/
#include <string.h>
#include "expr.h"
#include "yydefs.h"
#include "parser.h"

View File

@ -42,11 +42,12 @@ int expect(const char* expr_str, const char* expected, int* errors) {
State state;
state.cookie = NULL;
state.script = expr_str;
state.script = strdup(expr_str);
state.errmsg = NULL;
result = Evaluate(&state, e);
free(state.errmsg);
free(state.script);
if (result == NULL && expected != NULL) {
fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
++*errors;
@ -181,6 +182,10 @@ int main(int argc, char** argv) {
}
FILE* f = fopen(argv[1], "r");
if (f == NULL) {
printf("%s: %s: No such file or directory\n", argv[0], argv[1]);
return 1;
}
char buffer[8192];
int size = fread(buffer, 1, 8191, f);
fclose(f);

View File

@ -33,4 +33,6 @@ typedef struct {
} \
} while (0)
int yylex();
#endif

View File

@ -8,6 +8,7 @@ on init
symlink /system/etc /etc
mkdir /sdcard
mkdir /emmc
mkdir /system
mkdir /data
mkdir /cache

View File

@ -33,8 +33,6 @@
#include "commands.h"
#include "amend/amend.h"
#include "mtdutils/mtdutils.h"
#include "mtdutils/dump_image.h"
#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
@ -70,7 +68,7 @@ int install_zip(const char* packagefilepath)
ui_set_background(BACKGROUND_ICON_ERROR);
ui_print("Installation aborted.\n");
return 1;
}
}
#ifndef BOARD_HAS_NO_MISC_PARTITION
if (firmware_update_pending()) {
ui_print("\nReboot via menu to complete\ninstallation.\n");
@ -95,7 +93,7 @@ void show_install_update_menu()
{
static char* headers[] = { "Apply update from .zip file on SD card",
"",
NULL
NULL
};
for (;;)
{
@ -120,7 +118,7 @@ void show_install_update_menu()
default:
return;
}
}
}
@ -155,11 +153,11 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory,
ui_print("Couldn't open directory.\n");
return NULL;
}
int extension_length = 0;
if (fileExtensionOrDirectory != NULL)
extension_length = strlen(fileExtensionOrDirectory);
int isCounting = 1;
i = 0;
for (pass = 0; pass < 2; pass++) {
@ -167,7 +165,7 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory,
// skip hidden files
if (de->d_name[0] == '.')
continue;
// NULL means that we are gathering directories, so skip this
if (fileExtensionOrDirectory != NULL)
{
@ -189,13 +187,13 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory,
if (!(S_ISDIR(info.st_mode)))
continue;
}
if (pass == 0)
{
total++;
continue;
}
files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
strcpy(files[i], directory);
strcat(files[i], de->d_name);
@ -292,7 +290,7 @@ char* choose_file_menu(const char* directory, const char* fileExtensionOrDirecto
break;
}
continue;
}
}
strcpy(ret, files[chosen_item - numDirs]);
return_value = ret;
break;
@ -314,9 +312,9 @@ void show_choose_zip_menu()
static char* headers[] = { "Choose a zip to apply",
"",
NULL
NULL
};
char* file = choose_file_menu("/sdcard/", ".zip", headers);
if (file == NULL)
return;
@ -330,57 +328,16 @@ void show_choose_zip_menu()
install_zip(sdcard_package_file);
}
// This was pulled from bionic: The default system command always looks
// for shell in /system/bin/sh. This is bad.
#define _PATH_BSHELL "/sbin/sh"
extern char **environ;
int
__system(const char *command)
{
pid_t pid;
sig_t intsave, quitsave;
sigset_t mask, omask;
int pstat;
char *argp[] = {"sh", "-c", NULL, NULL};
if (!command) /* just checking... */
return(1);
argp[2] = (char *)command;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &omask);
switch (pid = vfork()) {
case -1: /* error */
sigprocmask(SIG_SETMASK, &omask, NULL);
return(-1);
case 0: /* child */
sigprocmask(SIG_SETMASK, &omask, NULL);
execve(_PATH_BSHELL, argp, environ);
_exit(127);
}
intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
pid = waitpid(pid, (int *)&pstat, 0);
sigprocmask(SIG_SETMASK, &omask, NULL);
(void)bsd_signal(SIGINT, intsave);
(void)bsd_signal(SIGQUIT, quitsave);
return (pid == -1 ? -1 : pstat);
}
void show_nandroid_restore_menu()
{
if (ensure_root_path_mounted("SDCARD:") != 0) {
LOGE ("Can't mount /sdcard\n");
return;
}
static char* headers[] = { "Choose an image to restore",
"",
NULL
NULL
};
char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
@ -394,24 +351,24 @@ void show_nandroid_restore_menu()
void show_mount_usb_storage_menu()
{
char command[PATH_MAX];
sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", SDCARD_DEVICE_PRIMARY);
sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", BOARD_SDCARD_DEVICE_PRIMARY);
__system(command);
static char* headers[] = { "USB Mass Storage device",
"Leaving this menu unmount",
"your SD card from your PC.",
"",
NULL
NULL
};
static char* list[] = { "Unmount", NULL };
for (;;)
{
int chosen_item = get_menu_selection(headers, list, 0);
if (chosen_item == GO_BACK || chosen_item == 0)
break;
}
__system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
__system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
}
@ -440,13 +397,13 @@ int confirm_selection(const char* title, const char* confirm)
return chosen_item == 7;
}
int format_non_mtd_device(const char* root)
int format_unknown_device(const char* root)
{
// if this is SDEXT:, don't worry about it.
if (0 == strcmp(root, "SDEXT:"))
{
struct stat st;
if (0 != stat(SDEXT_DEVICE, &st))
if (0 != stat(BOARD_SDEXT_DEVICE, &st))
{
ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
return 0;
@ -467,7 +424,7 @@ int format_non_mtd_device(const char* root)
__system(tmp);
sprintf(tmp, "rm -rf %s/.*", path);
__system(tmp);
ensure_root_path_unmounted(root);
return 0;
}
@ -480,33 +437,39 @@ void show_partition_menu()
{
static char* headers[] = { "Mounts and Storage Menu",
"",
NULL
NULL
};
typedef char* string;
string mounts[MOUNTABLE_COUNT][3] = {
string mounts[MOUNTABLE_COUNT][3] = {
{ "mount /system", "unmount /system", "SYSTEM:" },
{ "mount /data", "unmount /data", "DATA:" },
{ "mount /cache", "unmount /cache", "CACHE:" },
{ "mount /sdcard", "unmount /sdcard", "SDCARD:" },
#ifdef BOARD_HAS_SDCARD_INTERNAL
{ "mount /emmc", "unmount /emmc", "SDINTERNAL:" },
#endif
{ "mount /sd-ext", "unmount /sd-ext", "SDEXT:" }
};
string mtds[MTD_COUNT][2] = {
{ "format boot", "BOOT:" },
{ "format system", "SYSTEM:" },
{ "format data", "DATA:" },
{ "format cache", "CACHE:" },
};
string mmcs[MMC_COUNT][3] = {
{ "format sdcard", "SDCARD:" },
{ "format sd-ext", "SDEXT:" }
#ifdef BOARD_HAS_SDCARD_INTERNAL
{ "format internal sdcard", "SDINTERNAL:" },
#endif
{ "format sd-ext", "SDEXT:" }
};
static char* confirm_format = "Confirm format?";
static char* confirm = "Yes - Format";
for (;;)
{
int ismounted[MOUNTABLE_COUNT];
@ -517,20 +480,20 @@ void show_partition_menu()
ismounted[i] = is_root_path_mounted(mounts[i][2]);
options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
}
for (i = 0; i < MTD_COUNT; i++)
{
options[MOUNTABLE_COUNT + i] = mtds[i][0];
}
for (i = 0; i < MMC_COUNT; i++)
{
options[MOUNTABLE_COUNT + MTD_COUNT + i] = mmcs[i][0];
}
options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT] = "mount USB storage";
options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1] = NULL;
int chosen_item = get_menu_selection(headers, options, 0);
if (chosen_item == GO_BACK)
break;
@ -568,7 +531,7 @@ void show_partition_menu()
if (!confirm_selection(confirm_format, confirm))
continue;
ui_print("Formatting %s...\n", mmcs[chosen_item][1]);
if (0 != format_non_mtd_device(mmcs[chosen_item][1]))
if (0 != format_unknown_device(mmcs[chosen_item][1]))
ui_print("Error formatting %s!\n", mmcs[chosen_item][1]);
else
ui_print("Done.\n");
@ -609,8 +572,8 @@ int run_script_from_buffer(char* script_data, int script_len, char* filename)
}
printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
return 1;
}
}
return 0;
}
@ -621,7 +584,7 @@ int run_script(char* filename)
printf("Error executing stat on file: %s\n", filename);
return 1;
}
int script_len = file_info.st_size;
char* script_data = (char*)malloc(script_len + 1);
FILE *file = fopen(filename, "rb");
@ -656,14 +619,14 @@ int run_and_remove_extendedcommand()
if (i == 0) {
ui_print("Timed out waiting for SD card... continuing anyways.");
}
sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
return run_script(tmp);
}
int amend_main(int argc, char** argv)
{
if (argc != 2)
if (argc != 2)
{
printf("Usage: amend <script>\n");
return 0;
@ -742,10 +705,10 @@ void show_nandroid_menu()
{
static char* headers[] = { "Nandroid",
"",
NULL
NULL
};
static char* list[] = { "Backup",
static char* list[] = { "Backup",
"Restore",
"Advanced Restore",
NULL
@ -803,6 +766,9 @@ void show_advanced_menu()
#ifndef BOARD_HAS_SMALL_RECOVERY
"Partition SD Card",
"Fix Permissions",
#ifdef BOARD_HAS_SDCARD_INTERNAL
"Partition Internal SD Card",
#endif
#endif
NULL
};
@ -862,6 +828,8 @@ void show_advanced_menu()
"256M",
"512M",
"1024M",
"2048M",
"4096M",
NULL };
static char* swap_sizes[] = { "0M",
@ -877,7 +845,7 @@ void show_advanced_menu()
int ext_size = get_menu_selection(ext_headers, ext_sizes, 0);
if (ext_size == GO_BACK)
continue;
int swap_size = get_menu_selection(swap_headers, swap_sizes, 0);
if (swap_size == GO_BACK)
continue;
@ -906,6 +874,49 @@ void show_advanced_menu()
ui_print("Done!\n");
break;
}
case 7:
{
static char* ext_sizes[] = { "128M",
"256M",
"512M",
"1024M",
"2048M",
"4096M",
NULL };
static char* swap_sizes[] = { "0M",
"32M",
"64M",
"128M",
"256M",
NULL };
static char* ext_headers[] = { "Data Size", "", NULL };
static char* swap_headers[] = { "Swap Size", "", NULL };
int ext_size = get_menu_selection(ext_headers, ext_sizes, 0);
if (ext_size == GO_BACK)
continue;
int swap_size = 0;
if (swap_size == GO_BACK)
continue;
char sddevice[256];
const RootInfo *ri = get_root_info_for_path("SDINTERNAL:");
strcpy(sddevice, ri->device);
// we only want the mmcblk, not the partition
sddevice[strlen("/dev/block/mmcblkX")] = NULL;
char cmd[PATH_MAX];
setenv("SDPATH", sddevice, 1);
sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
ui_print("Partitioning Internal SD Card... please wait...\n");
if (0 == __system(cmd))
ui_print("Done!\n");
else
ui_print("An error occured while partitioning your Internal SD Card. Please see /tmp/recovery.log for more details.\n");
break;
}
}
}
}
@ -917,18 +928,19 @@ void write_fstab_root(char *root_path, FILE *file)
LOGW("Unable to get root info for %s during fstab generation!", root_path);
return;
}
MtdPartition *mtd = get_root_mtd_partition(root_path);
if (mtd != NULL)
char device[PATH_MAX];
int ret = get_root_partition_device(root_path, device);
if (ret == 0)
{
fprintf(file, "/dev/block/mtdblock%d ", mtd->device_index);
fprintf(file, "%s ", device);
}
else
{
fprintf(file, "%s ", info->device);
fprintf(file, "%s ", info->device);
}
fprintf(file, "%s ", info->mount_point);
fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
}
void create_fstab()
@ -941,7 +953,7 @@ void create_fstab()
}
write_fstab_root("CACHE:", file);
write_fstab_root("DATA:", file);
#ifdef HAS_DATADATA
#ifdef BOARD_HAS_DATADATA
write_fstab_root("DATADATA:", file);
#endif
write_fstab_root("SYSTEM:", file);
@ -959,4 +971,4 @@ void handle_failure(int ret)
mkdir("/sdcard/clockworkmod", S_IRWXU);
__system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
ui_print("/tmp/recovery.log was copied to /sdcard/clockworkmod/recovery.log. Please open ROM Manager to report the issue.\n");
}
}

View File

@ -38,7 +38,7 @@ void
show_advanced_menu();
int
format_non_mtd_device(const char* root);
format_unknown_device(const char* root);
void
wipe_battery_stats();

91
flashutils/Android.mk Normal file
View File

@ -0,0 +1,91 @@
LOCAL_PATH := $(call my-dir)
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flashutils.c
LOCAL_MODULE := libflashutils
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES := libmmcutils libmtdutils libbmlutils
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := flash_image
LOCAL_MODULE_TAGS := eng
#LOCAL_STATIC_LIBRARIES += $(BOARD_FLASH_LIBRARY)
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := dump_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := erase_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := libflash_image
LOCAL_CFLAGS += -Dmain=flash_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := libdump_image
LOCAL_CFLAGS += -Dmain=dump_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := liberase_image
LOCAL_CFLAGS += -Dmain=erase_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := utility_dump_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := dump_image
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := utility_flash_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := flash_image
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := utility_erase_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := erase_image
LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

View File

@ -23,13 +23,14 @@
#include <sys/ioctl.h>
#include "cutils/log.h"
#include "mtdutils.h"
#include "dump_image.h"
#include "flashutils.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#if 0
#define LOG_TAG "dump_image"
#define BLOCK_SIZE 2048
@ -135,3 +136,15 @@ int main(int argc, char **argv)
return dump_image(argv[1], argv[2], NULL);
}
#endif
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
return 2;
}
return backup_raw_partition(argv[1], argv[2]);
}

View File

@ -23,15 +23,17 @@
#include <unistd.h>
#include <fcntl.h>
#include <mtd/mtd-user.h>
#include "cutils/log.h"
#include "mtdutils.h"
#include "flashutils.h"
#if 0
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "erase_image"
static int die(const char *msg, ...) {
@ -86,3 +88,16 @@ int main(int argc, char **argv) {
return erase_image(argv[1]);
}
#endif
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s partition\n", argv[0]);
return 2;
}
return erase_raw_partition(argv[1]);
}

View File

@ -22,8 +22,8 @@
#include <unistd.h>
#include "cutils/log.h"
#include "mtdutils.h"
#if 0
#define LOG_TAG "flash_image"
#define HEADER_SIZE 2048 // size of header to compare for equality
@ -138,3 +138,17 @@ int main(int argc, char **argv) {
if (mtd_write_close(out)) die("error closing %s", argv[1]);
return 0;
}
#endif
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
return 2;
}
int ret = restore_raw_partition(argv[1], argv[2]);
if (ret != 0)
fprintf(stderr, "failed with error: %d\n", ret);
return ret;
}

160
flashutils/flashutils.c Normal file
View File

@ -0,0 +1,160 @@
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "flashutils/flashutils.h"
int the_flash_type = UNKNOWN;
int device_flash_type()
{
if (the_flash_type == UNKNOWN) {
if (access("/dev/block/bml1", F_OK) == 0) {
the_flash_type = BML;
} else if (access("/proc/emmc", F_OK) == 0) {
the_flash_type = MMC;
} else if (access("/proc/mtd", F_OK) == 0) {
the_flash_type = MTD;
} else {
the_flash_type = UNSUPPORTED;
}
}
return the_flash_type;
}
char* get_default_filesystem()
{
return device_flash_type() == MMC ? "ext3" : "yaffs2";
}
// This was pulled from bionic: The default system command always looks
// for shell in /system/bin/sh. This is bad.
#define _PATH_BSHELL "/sbin/sh"
extern char **environ;
int
__system(const char *command)
{
pid_t pid;
sig_t intsave, quitsave;
sigset_t mask, omask;
int pstat;
char *argp[] = {"sh", "-c", NULL, NULL};
if (!command) /* just checking... */
return(1);
argp[2] = (char *)command;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &omask);
switch (pid = vfork()) {
case -1: /* error */
sigprocmask(SIG_SETMASK, &omask, NULL);
return(-1);
case 0: /* child */
sigprocmask(SIG_SETMASK, &omask, NULL);
execve(_PATH_BSHELL, argp, environ);
_exit(127);
}
intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
pid = waitpid(pid, (int *)&pstat, 0);
sigprocmask(SIG_SETMASK, &omask, NULL);
(void)bsd_signal(SIGINT, intsave);
(void)bsd_signal(SIGQUIT, quitsave);
return (pid == -1 ? -1 : pstat);
}
int restore_raw_partition(const char *partition, const char *filename)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_restore_raw_partition(partition, filename);
case MMC:
return cmd_mmc_restore_raw_partition(partition, filename);
case BML:
return cmd_bml_restore_raw_partition(partition, filename);
default:
return -1;
}
}
int backup_raw_partition(const char *partition, const char *filename)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_backup_raw_partition(partition, filename);
case MMC:
return cmd_mmc_backup_raw_partition(partition, filename);
case BML:
return cmd_bml_backup_raw_partition(partition, filename);
default:
return -1;
}
}
int erase_raw_partition(const char *partition)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_erase_raw_partition(partition);
case MMC:
return cmd_mmc_erase_raw_partition(partition);
case BML:
return cmd_bml_erase_raw_partition(partition);
default:
return -1;
}
}
int erase_partition(const char *partition, const char *filesystem)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_erase_partition(partition, filesystem);
case MMC:
return cmd_mmc_erase_partition(partition, filesystem);
case BML:
return cmd_bml_erase_partition(partition, filesystem);
default:
return -1;
}
}
int mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_mount_partition(partition, mount_point, filesystem, read_only);
case MMC:
return cmd_mmc_mount_partition(partition, mount_point, filesystem, read_only);
case BML:
return cmd_bml_mount_partition(partition, mount_point, filesystem, read_only);
default:
return -1;
}
}
int get_partition_device(const char *partition, char *device)
{
int type = device_flash_type();
switch (type) {
case MTD:
return cmd_mtd_get_partition_device(partition, device);
case MMC:
return cmd_mmc_get_partition_device(partition, device);
case BML:
return cmd_bml_get_partition_device(partition, device);
default:
return -1;
}
}

51
flashutils/flashutils.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef FLASHUTILS_H
#define FLASHUTILS_H
int restore_raw_partition(const char *partition, const char *filename);
int backup_raw_partition(const char *partition, const char *filename);
int erase_raw_partition(const char *partition);
int erase_partition(const char *partition, const char *filesystem);
int mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
int get_partition_device(const char *partition, char *device);
#define FLASH_MTD 0
#define FLASH_MMC 1
#define FLASH_BML 2
int is_mtd_device();
char* get_default_filesystem();
int __system(const char *command);
extern int cmd_mtd_restore_raw_partition(const char *partition, const char *filename);
extern int cmd_mtd_backup_raw_partition(const char *partition, const char *filename);
extern int cmd_mtd_erase_raw_partition(const char *partition);
extern int cmd_mtd_erase_partition(const char *partition, const char *filesystem);
extern int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
extern int cmd_mtd_get_partition_device(const char *partition, char *device);
extern int cmd_mmc_restore_raw_partition(const char *partition, const char *filename);
extern int cmd_mmc_backup_raw_partition(const char *partition, const char *filename);
extern int cmd_mmc_erase_raw_partition(const char *partition);
extern int cmd_mmc_erase_partition(const char *partition, const char *filesystem);
extern int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
extern int cmd_mmc_get_partition_device(const char *partition, char *device);
extern int cmd_bml_restore_raw_partition(const char *partition, const char *filename);
extern int cmd_bml_backup_raw_partition(const char *partition, const char *filename);
extern int cmd_bml_erase_raw_partition(const char *partition);
extern int cmd_bml_erase_partition(const char *partition, const char *filesystem);
extern int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
extern int cmd_bml_get_partition_device(const char *partition, char *device);
extern int device_flash_type();
enum flash_type {
UNSUPPORTED = -1,
UNKNOWN = 0,
MTD = 1,
MMC = 2,
BML = 3
};
#endif

View File

@ -28,15 +28,17 @@
#include "minui/minui.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
#include "mtdutils/mounts.h"
#include "mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
#include "firmware.h"
#include "legacy.h"
#include "extendedcommands.h"
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"
@ -150,9 +152,12 @@ try_update_binary(const char *path, ZipArchive *zip) {
//
// firmware <"hboot"|"radio"> <filename>
// arrange to install the contents of <filename> in the
// given partition on reboot. (API v2: <filename> may
// start with "PACKAGE:" to indicate taking a file from
// the OTA package.)
// given partition on reboot.
//
// (API v2: <filename> may start with "PACKAGE:" to
// indicate taking a file from the OTA package.)
//
// (API v3: this command no longer exists.)
//
// ui_print <string>
// display <string> on the screen.
@ -236,6 +241,7 @@ try_update_binary(const char *path, ZipArchive *zip) {
} else {
return INSTALL_SUCCESS;
}
return INSTALL_SUCCESS;
}
static int
@ -297,7 +303,7 @@ load_keys(const char* filename, int* numKeys) {
++*numKeys;
out = realloc(out, *numKeys * sizeof(RSAPublicKey));
RSAPublicKey* key = out + (*numKeys - 1);
if (fscanf(f, " { %i , %i , { %i",
if (fscanf(f, " { %i , 0x%x , { %u",
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
goto exit;
}
@ -306,11 +312,11 @@ load_keys(const char* filename, int* numKeys) {
goto exit;
}
for (i = 1; i < key->len; ++i) {
if (fscanf(f, " , %i", &(key->n[i])) != 1) goto exit;
if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
}
if (fscanf(f, " } , { %i", &(key->rr[0])) != 1) goto exit;
if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
for (i = 1; i < key->len; ++i) {
if (fscanf(f, " , %i", &(key->rr[i])) != 1) goto exit;
if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
}
fscanf(f, " } } ");

View File

@ -28,7 +28,6 @@
#include "minui/minui.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
@ -41,7 +40,7 @@
#include "minui/minui.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
#include "mtdutils/mounts.h"
#include "mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"

View File

@ -7,6 +7,10 @@ LOCAL_C_INCLUDES +=\
external/libpng\
external/zlib
ifneq ($(BOARD_LDPI_RECOVERY),)
LOCAL_CFLAGS += -DBOARD_LDPI_RECOVERY='"$(BOARD_LDPI_RECOVERY)"'
endif
LOCAL_MODULE := libminui
include $(BUILD_STATIC_LIBRARY)

View File

@ -19,16 +19,161 @@
#include <fcntl.h>
#include <dirent.h>
#include <sys/poll.h>
#include <limits.h>
#include <linux/input.h>
#include "../common.h"
#include "minui.h"
#define MAX_DEVICES 16
#define VIBRATOR_TIMEOUT_FILE "/sys/class/timed_output/vibrator/enable"
#define VIBRATOR_TIME_MS 50
#define PRESS_THRESHHOLD 10
struct virtualkey {
int scancode;
int centerx, centery;
int width, height;
};
struct position {
int x, y;
int pressed;
struct input_absinfo xi, yi;
};
struct ev {
struct pollfd *fd;
struct virtualkey *vks;
int vk_count;
struct position p, mt_p;
int sent, mt_idx;
};
static struct pollfd ev_fds[MAX_DEVICES];
static struct ev evs[MAX_DEVICES];
static unsigned ev_count = 0;
static inline int ABS(int x) {
return x<0?-x:x;
}
int vibrate(int timeout_ms)
{
char str[20];
int fd;
int ret;
fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
if (fd < 0)
return -1;
ret = snprintf(str, sizeof(str), "%d", timeout_ms);
ret = write(fd, str, ret);
close(fd);
if (ret < 0)
return -1;
return 0;
}
/* Returns empty tokens */
static char *vk_strtok_r(char *str, const char *delim, char **save_str)
{
if(!str) {
if(!*save_str) return NULL;
str = (*save_str) + 1;
}
*save_str = strpbrk(str, delim);
if(*save_str) **save_str = '\0';
return str;
}
static int vk_init(struct ev *e)
{
char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
char vks[2048], *ts;
ssize_t len;
int vk_fd;
int i;
e->vk_count = 0;
len = strlen(vk_path);
len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
if (len <= 0)
return -1;
vk_fd = open(vk_path, O_RDONLY);
if (vk_fd < 0)
return -1;
len = read(vk_fd, vks, sizeof(vks)-1);
close(vk_fd);
if (len <= 0)
return -1;
vks[len] = '\0';
/* Parse a line like:
keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
*/
for (ts = vks, e->vk_count = 1; *ts; ++ts) {
if (*ts == ':')
++e->vk_count;
}
if (e->vk_count % 6) {
LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
}
e->vk_count /= 6;
if (e->vk_count <= 0)
return -1;
e->sent = 0;
e->mt_idx = 0;
ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
e->p.pressed = 0;
ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
e->mt_p.pressed = 0;
e->vks = malloc(sizeof(*e->vks) * e->vk_count);
for (i = 0; i < e->vk_count; ++i) {
char *token[6];
int j;
for (j = 0; j < 6; ++j) {
token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
}
if (strcmp(token[0], "0x01") != 0) {
/* Java does string compare, so we do too. */
LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
continue;
}
e->vks[i].scancode = strtol(token[1], NULL, 0);
e->vks[i].centerx = strtol(token[2], NULL, 0);
e->vks[i].centery = strtol(token[3], NULL, 0);
e->vks[i].width = strtol(token[4], NULL, 0);
e->vks[i].height = strtol(token[5], NULL, 0);
}
return 0;
}
int ev_init(void)
{
DIR *dir;
@ -45,6 +190,11 @@ int ev_init(void)
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
evs[ev_count].fd = &ev_fds[ev_count];
/* Load virtualkeys if there are any */
vk_init(&evs[ev_count]);
ev_count++;
if(ev_count == MAX_DEVICES) break;
}
@ -55,11 +205,135 @@ int ev_init(void)
void ev_exit(void)
{
while (ev_count > 0) {
close(ev_fds[--ev_count].fd);
while (ev_count-- > 0) {
if (evs[ev_count].vk_count) {
free(evs[ev_count].vks);
evs[ev_count].vk_count = 0;
}
close(ev_fds[ev_count].fd);
}
}
static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
{
int screen_pos;
if (info->minimum == info->maximum)
return 0;
screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
return (screen_pos >= 0 && screen_pos < screen_size);
}
static int vk_tp_to_screen(struct position *p, int *x, int *y)
{
if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
return 0;
*x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
*y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
if (*x >= 0 && *x < gr_fb_width() &&
*y >= 0 && *y < gr_fb_height()) {
return 0;
}
return 1;
}
/* Translate a virtual key in to a real key event, if needed */
/* Returns non-zero when the event should be consumed */
static int vk_modify(struct ev *e, struct input_event *ev)
{
int i;
int x, y;
if (ev->type == EV_KEY) {
if (ev->code == BTN_TOUCH)
e->p.pressed = ev->value;
return 0;
}
if (ev->type == EV_ABS) {
switch (ev->code) {
case ABS_X:
e->p.x = ev->value;
return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
case ABS_Y:
e->p.y = ev->value;
return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
case ABS_MT_POSITION_X:
if (e->mt_idx) return 1;
e->mt_p.x = ev->value;
return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
case ABS_MT_POSITION_Y:
if (e->mt_idx) return 1;
e->mt_p.y = ev->value;
return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
case ABS_MT_TOUCH_MAJOR:
if (e->mt_idx) return 1;
if (e->sent)
e->mt_p.pressed = (ev->value > 0);
else
e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
return 0;
}
return 0;
}
if (ev->type != EV_SYN)
return 0;
if (ev->code == SYN_MT_REPORT) {
/* Ignore the rest of the points */
++e->mt_idx;
return 1;
}
if (ev->code != SYN_REPORT)
return 0;
/* Report complete */
e->mt_idx = 0;
if (!e->p.pressed && !e->mt_p.pressed) {
/* No touch */
e->sent = 0;
return 0;
}
if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
!(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
/* No touch inside vk area */
return 0;
}
if (e->sent) {
/* We've already sent a fake key for this touch */
return 1;
}
/* The screen is being touched on the vk area */
e->sent = 1;
for (i = 0; i < e->vk_count; ++i) {
int xd = ABS(e->vks[i].centerx - x);
int yd = ABS(e->vks[i].centery - y);
if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
/* Fake a key event */
ev->type = EV_KEY;
ev->code = e->vks[i].scancode;
ev->value = 1;
vibrate(VIBRATOR_TIME_MS);
return 0;
}
}
return 1;
}
int ev_get(struct input_event *ev, unsigned dont_wait)
{
int r;
@ -72,7 +346,10 @@ int ev_get(struct input_event *ev, unsigned dont_wait)
for(n = 0; n < ev_count; n++) {
if(ev_fds[n].revents & POLLIN) {
r = read(ev_fds[n].fd, ev, sizeof(*ev));
if(r == sizeof(*ev)) return 0;
if(r == sizeof(*ev)) {
if (!vk_modify(&evs[n], ev))
return 0;
}
}
}
}

15
minui/font_7x16.h Normal file

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,12 @@
#include <pixelflinger/pixelflinger.h>
#include "font_10x18.h"
#ifndef BOARD_LDPI_RECOVERY
#include "font_10x18.h"
#else
#include "font_7x16.h"
#endif
#include "minui.h"
typedef struct {
@ -85,7 +90,7 @@ static int get_framebuffer(GGLSurface *fb)
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
fb->stride = vi.xres;
fb->stride = fi.line_length/2; /* stride is the number of pixels until the data of next row, >= xres */;
fb->data = bits;
fb->format = GGL_PIXEL_FORMAT_RGB_565;
@ -94,8 +99,8 @@ static int get_framebuffer(GGLSurface *fb)
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
fb->stride = vi.xres;
fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
fb->stride = fi.line_length/2;
fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length);
fb->format = GGL_PIXEL_FORMAT_RGB_565;
return fd;

View File

@ -97,9 +97,10 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->bit_depth;
int channels = info_ptr->channels;
if (bit_depth != 8 || (channels != 3 && channels != 4) ||
(color_type != PNG_COLOR_TYPE_RGB &&
color_type != PNG_COLOR_TYPE_RGBA)) {
if (!(bit_depth == 8 &&
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
(channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
(channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
return -7;
goto exit;
}
@ -118,9 +119,13 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
surface->format = (channels == 3) ?
GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
}
int y;
if (channels == 3) {
for (y = 0; y < height; ++y) {
for (y = 0; y < (int)height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
@ -139,7 +144,7 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
}
}
} else {
for (y = 0; y < height; ++y) {
for (y = 0; y < (int)height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
}

View File

@ -810,6 +810,43 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
return true;
}
typedef struct {
unsigned char* buffer;
long len;
} BufferExtractCookie;
static bool bufferProcessFunction(const unsigned char *data, int dataLen,
void *cookie) {
BufferExtractCookie *bec = (BufferExtractCookie*)cookie;
memmove(bec->buffer, data, dataLen);
bec->buffer += dataLen;
bec->len -= dataLen;
return true;
}
/*
* Uncompress "pEntry" in "pArchive" to buffer, which must be large
* enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
*/
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
const ZipEntry *pEntry, unsigned char *buffer)
{
BufferExtractCookie bec;
bec.buffer = buffer;
bec.len = mzGetZipEntryUncompLen(pEntry);
bool ret = mzProcessZipEntryContents(pArchive, pEntry,
bufferProcessFunction, (void*)&bec);
if (!ret || bec.len != 0) {
LOGE("Can't extract entry to memory buffer.\n");
return false;
}
return true;
}
/* Helper state to make path translation easier and less malloc-happy.
*/
typedef struct {

View File

@ -168,6 +168,13 @@ bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry);
bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
const ZipEntry *pEntry, int fd);
/*
* Inflate and write an entry to a memory buffer, which must be long
* enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
*/
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
const ZipEntry *pEntry, unsigned char* buffer);
/*
* Inflate all entries under zipDir to the directory specified by
* targetDir, which must exist and be a writable directory.

15
mmcutils/Android.mk Normal file
View File

@ -0,0 +1,15 @@
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
mmcutils.c
LOCAL_MODULE := libmmcutils
include $(BUILD_STATIC_LIBRARY)
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

591
mmcutils/mmcutils.c Normal file
View File

@ -0,0 +1,591 @@
/*
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h> // for _IOW, _IOR, mount()
#include "mmcutils.h"
unsigned ext3_count = 0;
char *ext3_partitions[] = {"system", "userdata", "cache", "NONE"};
unsigned vfat_count = 0;
char *vfat_partitions[] = {"modem", "NONE"};
struct MmcPartition {
char *device_index;
char *filesystem;
char *name;
unsigned dstatus;
unsigned dtype ;
unsigned dfirstsec;
unsigned dsize;
};
typedef struct {
MmcPartition *partitions;
int partitions_allocd;
int partition_count;
} MmcState;
static MmcState g_mmc_state = {
NULL, // partitions
0, // partitions_allocd
-1 // partition_count
};
#define MMC_DEVICENAME "/dev/block/mmcblk0"
static void
mmc_partition_name (MmcPartition *mbr, unsigned int type) {
switch(type)
{
char name[64];
case MMC_BOOT_TYPE:
sprintf(name,"boot");
mbr->name = strdup(name);
break;
case MMC_RECOVERY_TYPE:
sprintf(name,"recovery");
mbr->name = strdup(name);
break;
case MMC_EXT3_TYPE:
if (strcmp("NONE", ext3_partitions[ext3_count])) {
strcpy((char *)name,(const char *)ext3_partitions[ext3_count]);
mbr->name = strdup(name);
ext3_count++;
}
mbr->filesystem = strdup("ext3");
break;
case MMC_VFAT_TYPE:
if (strcmp("NONE", vfat_partitions[vfat_count])) {
strcpy((char *)name,(const char *)vfat_partitions[vfat_count]);
mbr->name = strdup(name);
vfat_count++;
}
mbr->filesystem = strdup("vfat");
break;
};
}
static int
mmc_read_mbr (const char *device, MmcPartition *mbr) {
FILE *fd;
unsigned char buffer[512];
int idx, i;
unsigned mmc_partition_count = 0;
unsigned int dtype;
unsigned int dfirstsec;
unsigned int EBR_first_sec;
unsigned int EBR_current_sec;
int ret = -1;
fd = fopen(device, "r");
if(fd == NULL)
{
printf("Can't open device: \"%s\"\n", device);
goto ERROR2;
}
if ((fread(buffer, 512, 1, fd)) != 1)
{
printf("Can't read device: \"%s\"\n", device);
goto ERROR1;
}
/* Check to see if signature exists */
if ((buffer[TABLE_SIGNATURE] != 0x55) || \
(buffer[TABLE_SIGNATURE + 1] != 0xAA))
{
printf("Incorrect mbr signatures!\n");
goto ERROR1;
}
idx = TABLE_ENTRY_0;
for (i = 0; i < 4; i++)
{
char device_index[128];
mbr[mmc_partition_count].dstatus = \
buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
mbr[mmc_partition_count].dtype = \
buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
mbr[mmc_partition_count].dfirstsec = \
GET_LWORD_FROM_BYTE(&buffer[idx + \
i * TABLE_ENTRY_SIZE + \
OFFSET_FIRST_SEC]);
mbr[mmc_partition_count].dsize = \
GET_LWORD_FROM_BYTE(&buffer[idx + \
i * TABLE_ENTRY_SIZE + \
OFFSET_SIZE]);
dtype = mbr[mmc_partition_count].dtype;
dfirstsec = mbr[mmc_partition_count].dfirstsec;
mmc_partition_name(&mbr[mmc_partition_count], \
mbr[mmc_partition_count].dtype);
sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
mbr[mmc_partition_count].device_index = strdup(device_index);
mmc_partition_count++;
if (mmc_partition_count == MAX_PARTITIONS)
goto SUCCESS;
}
/* See if the last partition is EBR, if not, parsing is done */
if (dtype != 0x05)
{
goto SUCCESS;
}
EBR_first_sec = dfirstsec;
EBR_current_sec = dfirstsec;
fseek (fd, (EBR_first_sec * 512), SEEK_SET);
if ((fread(buffer, 512, 1, fd)) != 1)
goto ERROR1;
/* Loop to parse the EBR */
for (i = 0;; i++)
{
char device_index[128];
if ((buffer[TABLE_SIGNATURE] != 0x55) || (buffer[TABLE_SIGNATURE + 1] != 0xAA))
{
break;
}
mbr[mmc_partition_count].dstatus = \
buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
mbr[mmc_partition_count].dtype = \
buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
mbr[mmc_partition_count].dfirstsec = \
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
OFFSET_FIRST_SEC]) + \
EBR_current_sec;
mbr[mmc_partition_count].dsize = \
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
OFFSET_SIZE]);
mmc_partition_name(&mbr[mmc_partition_count], \
mbr[mmc_partition_count].dtype);
sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
mbr[mmc_partition_count].device_index = strdup(device_index);
mmc_partition_count++;
if (mmc_partition_count == MAX_PARTITIONS)
goto SUCCESS;
dfirstsec = GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
if(dfirstsec == 0)
{
/* Getting to the end of the EBR tables */
break;
}
/* More EBR to follow - read in the next EBR sector */
fseek (fd, ((EBR_first_sec + dfirstsec) * 512), SEEK_SET);
if ((fread(buffer, 512, 1, fd)) != 1)
goto ERROR1;
EBR_current_sec = EBR_first_sec + dfirstsec;
}
SUCCESS:
ret = mmc_partition_count;
ERROR1:
fclose(fd);
ERROR2:
return ret;
}
int
mmc_scan_partitions() {
int i;
ssize_t nbytes;
if (g_mmc_state.partitions == NULL) {
const int nump = MAX_PARTITIONS;
MmcPartition *partitions = malloc(nump * sizeof(*partitions));
if (partitions == NULL) {
errno = ENOMEM;
return -1;
}
g_mmc_state.partitions = partitions;
g_mmc_state.partitions_allocd = nump;
memset(partitions, 0, nump * sizeof(*partitions));
}
g_mmc_state.partition_count = 0;
ext3_count = 0;
vfat_count = 0;
/* Initialize all of the entries to make things easier later.
* (Lets us handle sparsely-numbered partitions, which
* may not even be possible.)
*/
for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
MmcPartition *p = &g_mmc_state.partitions[i];
if (p->device_index != NULL) {
free(p->device_index);
p->device_index = NULL;
}
if (p->name != NULL) {
free(p->name);
p->name = NULL;
}
if (p->filesystem != NULL) {
free(p->filesystem);
p->filesystem = NULL;
}
}
g_mmc_state.partition_count = mmc_read_mbr(MMC_DEVICENAME, g_mmc_state.partitions);
if(g_mmc_state.partition_count == -1)
{
printf("Error in reading mbr!\n");
// keep "partitions" around so we can free the names on a rescan.
g_mmc_state.partition_count = -1;
}
return g_mmc_state.partition_count;
}
const MmcPartition *
mmc_find_partition_by_name(const char *name)
{
if (g_mmc_state.partitions != NULL) {
int i;
for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
MmcPartition *p = &g_mmc_state.partitions[i];
if (p->device_index !=NULL && p->name != NULL) {
if (strcmp(p->name, name) == 0) {
return p;
}
}
}
}
return NULL;
}
#define MKE2FS_BIN "/sbin/mke2fs"
#define TUNE2FS_BIN "/sbin/tune2fs"
#define E2FSCK_BIN "/sbin/e2fsck"
static int
run_exec_process ( char **argv) {
pid_t pid;
int status;
pid = fork();
if (pid == 0) {
execv(argv[0], argv);
fprintf(stderr, "E:Can't run (%s)\n",strerror(errno));
_exit(-1);
}
waitpid(pid, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
return 1;
}
return 0;
}
int
mmc_format_ext3 (MmcPartition *partition) {
char device[128];
strcpy(device, partition->device_index);
// Run mke2fs
char *const mke2fs[] = {MKE2FS_BIN, "-j", device, NULL};
if(run_exec_process(mke2fs))
return -1;
// Run tune2fs
char *const tune2fs[] = {TUNE2FS_BIN, "-j", "-C", "1", device, NULL};
if(run_exec_process(tune2fs))
return -1;
// Run e2fsck
char *const e2fsck[] = {E2FSCK_BIN, "-fy", device, NULL};
if(run_exec_process(e2fsck))
return -1;
return 0;
}
int
mmc_mount_partition(const MmcPartition *partition, const char *mount_point,
int read_only)
{
const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
char devname[128];
int rv = -1;
strcpy(devname, partition->device_index);
if (partition->filesystem == NULL) {
printf("Null filesystem!\n");
return rv;
}
if (!read_only) {
rv = mount(devname, mount_point, partition->filesystem, flags, NULL);
}
if (read_only || rv < 0) {
rv = mount(devname, mount_point, partition->filesystem, flags | MS_RDONLY, 0);
if (rv < 0) {
printf("Failed to mount %s on %s: %s\n",
devname, mount_point, strerror(errno));
} else {
printf("Mount %s on %s read-only\n", devname, mount_point);
}
}
return rv;
}
int
mmc_raw_copy (const MmcPartition *partition, char *in_file) {
int ch;
FILE *in;
FILE *out;
int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
char *out_file = partition->device_index;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR2;
fseek(in, 0L, SEEK_END);
sz = ftell(in);
fseek(in, 0L, SEEK_SET);
if (sz % 512)
{
while ( ( ch = fgetc ( in ) ) != EOF )
fputc ( ch, out );
}
else
{
for (i=0; i< (sz/512); i++)
{
if ((fread(buf, 512, 1, in)) != 1)
goto ERROR1;
if ((fwrite(buf, 512, 1, out)) != 1)
goto ERROR1;
}
}
fsync(out);
ret = 0;
ERROR1:
fclose ( out );
ERROR2:
fclose ( in );
ERROR3:
return ret;
}
// TODO: refactor this to not be a giant copy paste mess
int
mmc_raw_dump (const MmcPartition *partition, char *out_file) {
int ch;
FILE *in;
FILE *out;
int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
char *in_file = partition->device_index;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR2;
fseek(in, 0L, SEEK_END);
sz = ftell(in);
fseek(in, 0L, SEEK_SET);
if (sz % 512)
{
while ( ( ch = fgetc ( in ) ) != EOF )
fputc ( ch, out );
}
else
{
for (i=0; i< (sz/512); i++)
{
if ((fread(buf, 512, 1, in)) != 1)
goto ERROR1;
if ((fwrite(buf, 512, 1, out)) != 1)
goto ERROR1;
}
}
fsync(out);
ret = 0;
ERROR1:
fclose ( out );
ERROR2:
fclose ( in );
ERROR3:
return ret;
}
int
mmc_raw_read (const MmcPartition *partition, char *data, int data_size) {
int ch;
FILE *in;
int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
char *in_file = partition->device_index;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
fseek(in, 0L, SEEK_END);
sz = ftell(in);
fseek(in, 0L, SEEK_SET);
fread(data, data_size, 1, in);
ret = 0;
ERROR1:
ERROR2:
fclose ( in );
ERROR3:
return ret;
}
int
mmc_raw_write (const MmcPartition *partition, char *data, int data_size) {
int ch;
FILE *out;
int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
char *out_file = partition->device_index;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR3;
fwrite(data, data_size, 1, out);
ret = 0;
ERROR1:
ERROR2:
fclose ( out );
ERROR3:
return ret;
}
int cmd_mmc_restore_raw_partition(const char *partition, const char *filename)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
return mmc_raw_copy(p, filename);
}
int cmd_mmc_backup_raw_partition(const char *partition, const char *filename)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
return mmc_raw_dump(p, filename);
}
int cmd_mmc_erase_raw_partition(const char *partition)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
// TODO: implement raw wipe
return 0;
}
int cmd_mmc_erase_partition(const char *partition, const char *filesystem)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
return mmc_format_ext3 (p);
}
int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
return mmc_mount_partition(p, mount_point, read_only);
}
int cmd_mmc_get_partition_device(const char *partition, char *device)
{
mmc_scan_partitions();
const MmcPartition *p;
p = mmc_find_partition_by_name(partition);
if (p == NULL)
return -1;
strcpy(device, p->device_index);
return 0;
}

88
mmcutils/mmcutils.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MMCUTILS_H_
#define MMCUTILS_H_
/* Some useful define used to access the MBR/EBR table */
#define BLOCK_SIZE 0x200
#define TABLE_ENTRY_0 0x1BE
#define TABLE_ENTRY_1 0x1CE
#define TABLE_ENTRY_2 0x1DE
#define TABLE_ENTRY_3 0x1EE
#define TABLE_SIGNATURE 0x1FE
#define TABLE_ENTRY_SIZE 0x010
#define OFFSET_STATUS 0x00
#define OFFSET_TYPE 0x04
#define OFFSET_FIRST_SEC 0x08
#define OFFSET_SIZE 0x0C
#define COPYBUFF_SIZE (1024 * 16)
#define BINARY_IN_TABLE_SIZE (16 * 512)
#define MAX_FILE_ENTRIES 20
#define MMC_BOOT_TYPE 0x48
#define MMC_SYSTEM_TYPE 0x82
#define MMC_USERDATA_TYPE 0x83
#define MMC_RECOVERY_TYPE 0x71
#define MMC_RCA 2
#define MAX_PARTITIONS 64
#define GET_LWORD_FROM_BYTE(x) ((unsigned)*(x) | \
((unsigned)*((x)+1) << 8) | \
((unsigned)*((x)+2) << 16) | \
((unsigned)*((x)+3) << 24))
#define PUT_LWORD_TO_BYTE(x, y) do{*(x) = (y) & 0xff; \
*((x)+1) = ((y) >> 8) & 0xff; \
*((x)+2) = ((y) >> 16) & 0xff; \
*((x)+3) = ((y) >> 24) & 0xff; }while(0)
#define GET_PAR_NUM_FROM_POS(x) ((((x) & 0x0000FF00) >> 8) + ((x) & 0x000000FF))
#define MMC_BOOT_TYPE 0x48
#define MMC_EXT3_TYPE 0x83
#define MMC_VFAT_TYPE 0xC
typedef struct MmcPartition MmcPartition;
/* Functions */
int mmc_scan_partitions();
const MmcPartition *mmc_find_partition_by_name(const char *name);
int mmc_format_ext3 (MmcPartition *partition);
int mmc_mount_partition(const MmcPartition *partition, const char *mount_point, \
int read_only);
int mmc_raw_copy (const MmcPartition *partition, char *in_file);
int mmc_raw_read (const MmcPartition *partition, char *data, int data_size);
int mmc_raw_write (const MmcPartition *partition, char *data, int data_size);
#endif // MMCUTILS_H_

View File

@ -5,88 +5,12 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
mtdutils.c \
mounts.c
mtdutils.c
LOCAL_MODULE := libmtdutils
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := flash_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmtdutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := dump_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmtdutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := erase_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmtdutils
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := libflash_image
LOCAL_CFLAGS += -Dmain=flash_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := libdump_image
LOCAL_CFLAGS += -Dmain=dump_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := liberase_image
LOCAL_CFLAGS += -Dmain=erase_image_main
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := dump_image.c
LOCAL_MODULE := utility_dump_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := dump_image
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := utility_flash_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := flash_image
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := erase_image.c
LOCAL_MODULE := utility_erase_image
LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
LOCAL_MODULE_STEM := erase_image
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

View File

@ -1,17 +0,0 @@
#undef main
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if (strstr(argv[0], "flash_image") != NULL)
return flash_image_main(argc, argv);
if (strstr(argv[0], "dump_image") != NULL)
return dump_image_main(argc, argv);
if (strstr(argv[0], "mkyaffs2image") != NULL)
return mkyaffs2image_main(argc, argv);
if (strstr(argv[0], "unyaffs") != NULL)
return unyaffs_main(argc, argv);
return 0;
}

View File

@ -1,8 +0,0 @@
#ifndef DUMP_IMAGE_H
#define DUMP_IMAGE_H
typedef void (*dump_image_callback) (int partition_dumped, int partition_size);
int dump_image(char* partition_name, char* filename, dump_image_callback callback);
#endif

View File

@ -337,7 +337,7 @@ ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
read += ctx->partition->erase_size;
}
if (read >= len) {
if (read >= (int)len) {
return read;
}
@ -557,3 +557,295 @@ off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos) {
}
return pos;
}
#define BLOCK_SIZE 2048
#define SPARE_SIZE (BLOCK_SIZE >> 5)
#define HEADER_SIZE 2048
int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename)
{
const MtdPartition *ptn;
MtdWriteContext *write;
void *data;
unsigned sz;
if (mtd_scan_partitions() <= 0)
{
printf("error scanning partitions");
return -1;
}
const MtdPartition *partition = mtd_find_partition_by_name(partition_name);
if (partition == NULL)
{
printf("can't find %s partition", partition_name);
return -1;
}
// If the first part of the file matches the partition, skip writing
int fd = open(filename, O_RDONLY);
if (fd < 0)
{
printf("error opening %s", filename);
return -1;
}
char header[HEADER_SIZE];
int headerlen = read(fd, header, sizeof(header));
if (headerlen <= 0)
{
printf("error reading %s header", filename);
return -1;
}
MtdReadContext *in = mtd_read_partition(partition);
if (in == NULL) {
printf("error opening %s: %s\n", partition, strerror(errno));
// just assume it needs re-writing
} else {
char check[HEADER_SIZE];
int checklen = mtd_read_data(in, check, sizeof(check));
if (checklen <= 0) {
printf("error reading %s: %s\n", partition_name, strerror(errno));
// just assume it needs re-writing
} else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
printf("header is the same, not flashing %s\n", partition_name);
return 0;
}
mtd_read_close(in);
}
// Skip the header (we'll come back to it), write everything else
printf("flashing %s from %s\n", partition_name, filename);
MtdWriteContext *out = mtd_write_partition(partition);
if (out == NULL)
{
printf("error writing %s", partition_name);
return -1;
}
char buf[HEADER_SIZE];
memset(buf, 0, headerlen);
int wrote = mtd_write_data(out, buf, headerlen);
if (wrote != headerlen)
{
printf("error writing %s", partition_name);
return -1;
}
int len;
while ((len = read(fd, buf, sizeof(buf))) > 0) {
wrote = mtd_write_data(out, buf, len);
if (wrote != len)
{
printf("error writing %s", partition_name);
return -1;
}
}
if (len < 0)
{
printf("error reading %s", filename);
return -1;
}
if (mtd_write_close(out))
{
printf("error closing %s", partition_name);
return -1;
}
// Now come back and write the header last
out = mtd_write_partition(partition);
if (out == NULL)
{
printf("error re-opening %s", partition_name);
return -1;
}
wrote = mtd_write_data(out, header, headerlen);
if (wrote != headerlen)
{
printf("error re-writing %s", partition_name);
return -1;
}
// Need to write a complete block, so write the rest of the first block
size_t block_size;
if (mtd_partition_info(partition, NULL, &block_size, NULL))
{
printf("error getting %s block size", partition_name);
return -1;
}
if (lseek(fd, headerlen, SEEK_SET) != headerlen)
{
printf("error rewinding %s", filename);
return -1;
}
int left = block_size - headerlen;
while (left < 0) left += block_size;
while (left > 0) {
len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left);
if (len <= 0){
printf("error reading %s", filename);
return -1;
}
if (mtd_write_data(out, buf, len) != len)
{
printf("error writing %s", partition_name);
return -1;
}
left -= len;
}
if (mtd_write_close(out))
{
printf("error closing %s", partition_name);
return -1;
}
return 0;
}
int cmd_mtd_backup_raw_partition(const char *partition_name, const char *filename)
{
MtdReadContext *in;
const MtdPartition *partition;
char buf[BLOCK_SIZE + SPARE_SIZE];
size_t partition_size;
size_t read_size;
size_t total;
int fd;
int wrote;
int len;
if (mtd_scan_partitions() <= 0)
{
printf("error scanning partitions");
return -1;
}
partition = mtd_find_partition_by_name(partition_name);
if (partition == NULL)
{
printf("can't find %s partition", partition_name);
return -1;
}
if (mtd_partition_info(partition, &partition_size, NULL, NULL)) {
printf("can't get info of partition %s", partition_name);
return -1;
}
if (!strcmp(filename, "-")) {
fd = fileno(stdout);
}
else {
fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
}
if (fd < 0)
{
printf("error opening %s", filename);
return -1;
}
in = mtd_read_partition(partition);
if (in == NULL) {
close(fd);
unlink(filename);
printf("error opening %s: %s\n", partition_name, strerror(errno));
return -1;
}
total = 0;
while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) {
wrote = write(fd, buf, len);
if (wrote != len) {
close(fd);
unlink(filename);
printf("error writing %s", filename);
return -1;
}
total += BLOCK_SIZE;
}
mtd_read_close(in);
if (close(fd)) {
unlink(filename);
printf("error closing %s", filename);
return -1;
}
return 0;
}
int cmd_mtd_erase_raw_partition(const char *partition_name)
{
MtdWriteContext *out;
size_t erased;
size_t total_size;
size_t erase_size;
if (mtd_scan_partitions() <= 0)
{
printf("error scanning partitions");
return -1;
}
const MtdPartition *p = mtd_find_partition_by_name(partition_name);
if (p == NULL)
{
printf("can't find %s partition", partition_name);
return -1;
}
out = mtd_write_partition(p);
if (out == NULL)
{
printf("could not estabilish write context for %s", partition_name);
return -1;
}
// do the actual erase, -1 = full partition erase
erased = mtd_erase_blocks(out, -1);
// erased = bytes erased, if zero, something borked
if (!erased)
{
printf("error erasing %s", partition_name);
return -1;
}
return 0;
}
int cmd_mtd_erase_partition(const char *partition, const char *filesystem)
{
return cmd_mtd_erase_raw_partition(partition);
}
int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
{
mtd_scan_partitions();
const MtdPartition *p;
p = mtd_find_partition_by_name(partition);
if (p == NULL) {
return -1;
}
return mtd_mount_partition(p, mount_point, filesystem, read_only);
}
int cmd_mtd_get_partition_device(const char *partition, char *device)
{
mtd_scan_partitions();
MtdPartition *p = mtd_find_partition_by_name(partition);
if (p == NULL)
return -1;
sprintf(device, "/dev/block/mtdblock%d", p->device_index);
return 0;
}

View File

@ -33,7 +33,6 @@
#include "commands.h"
#include "amend/amend.h"
#include "mtdutils/dump_image.h"
#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
@ -136,13 +135,13 @@ int nandroid_backup(const char* backup_path)
#ifndef BOARD_RECOVERY_IGNORE_BOOTABLES
ui_print("Backing up boot...\n");
sprintf(tmp, "%s/%s", backup_path, "boot.img");
ret = dump_image("boot", tmp, NULL);
ret = backup_raw_partition("boot", tmp);
if (0 != ret)
return print_and_error("Error while dumping boot image!\n");
ui_print("Backing up recovery...\n");
sprintf(tmp, "%s/%s", backup_path, "recovery.img");
ret = dump_image("recovery", tmp, NULL);
ret = backup_raw_partition("recovery", tmp);
if (0 != ret)
return print_and_error("Error while dumping recovery image!\n");
#endif
@ -153,7 +152,7 @@ int nandroid_backup(const char* backup_path)
if (0 != (ret = nandroid_backup_partition(backup_path, "DATA:")))
return ret;
#ifdef HAS_DATADATA
#ifdef BOARD_HAS_DATADATA
if (0 != (ret = nandroid_backup_partition(backup_path, "DATADATA:")))
return ret;
#endif
@ -172,7 +171,7 @@ int nandroid_backup(const char* backup_path)
if (0 != (ret = nandroid_backup_partition_extended(backup_path, "CACHE:", 0)))
return ret;
if (0 != stat(SDEXT_DEVICE, &st))
if (0 != stat(BOARD_SDEXT_DEVICE, &st))
{
ui_print("No sd-ext found. Skipping backup of sd-ext.\n");
}
@ -283,9 +282,9 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst
ui_print("Erasing boot before restore...\n");
if (0 != (ret = format_root_device("BOOT:")))
return print_and_error("Error while formatting BOOT:!\n");
sprintf(tmp, "flash_image boot %s/boot.img", backup_path);
sprintf(tmp, "%s/boot.img", backup_path);
ui_print("Restoring boot image...\n");
if (0 != (ret = __system(tmp))) {
if (0 != (ret = restore_raw_partition("boot", tmp))) {
ui_print("Error while flashing boot image!");
return ret;
}
@ -298,7 +297,7 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst
if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "DATA:")))
return ret;
#ifdef HAS_DATADATA
#ifdef BOARD_HAS_DATADATA
if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "DATADATA:")))
return ret;
#endif

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -32,7 +33,6 @@
#include "bootloader.h"
#include "common.h"
#include "cutils/properties.h"
#include "firmware.h"
#include "install.h"
#include "minui/minui.h"
#include "minzip/DirUtil.h"
@ -69,6 +69,7 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
* --update_package=root:path - verify install an OTA package file
* --wipe_data - erase user data (and cache), then reboot
* --wipe_cache - wipe cache (but not user data), then reboot
* --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
*
* After completing, we remove /cache/recovery/command and reboot.
* Arguments may also be supplied in the bootloader control block (BCB).
@ -113,6 +114,26 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
* 8g. finish_recovery() erases BCB
* -- after this, rebooting will (try to) restart the main system --
* 9. main() calls reboot() to boot main system
*
* ENCRYPTED FILE SYSTEMS ENABLE/DISABLE
* 1. user selects "enable encrypted file systems"
* 2. main system writes "--set_encrypted_filesystem=on|off" to
* /cache/recovery/command
* 3. main system reboots into recovery
* 4. get_args() writes BCB with "boot-recovery" and
* "--set_encrypted_filesystems=on|off"
* -- after this, rebooting will restart the transition --
* 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /data
* Settings include: property to specify the Encrypted FS istatus and
* FS encryption key if enabled (not yet implemented)
* 6. erase_root() reformats /data
* 7. erase_root() reformats /cache
* 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /data
* Settings include: property to specify the Encrypted FS status and
* FS encryption key if enabled (not yet implemented)
* 9. finish_recovery() erases BCB
* -- after this, rebooting will restart the main system --
* 10. main() calls reboot() to boot main system
*/
static const int MAX_ARG_LENGTH = 4096;
@ -223,8 +244,7 @@ get_args(int *argc, char ***argv) {
#ifndef BOARD_HAS_NO_MISC_PARTITION
void
set_sdcard_update_bootloader_message()
{
set_sdcard_update_bootloader_message() {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
@ -238,12 +258,13 @@ set_sdcard_update_bootloader_message()
// record any intent we were asked to communicate back to the system.
// this function is idempotent: call it as many times as you like.
static void
finish_recovery(const char *send_intent)
{
finish_recovery(const char *send_intent) {
// By this point, we're ready to return to the main system...
if (send_intent != NULL) {
FILE *fp = fopen_root_path(INTENT_FILE, "w");
if (fp != NULL) {
if (fp == NULL) {
LOGE("Can't open %s\n", INTENT_FILE);
} else {
fputs(send_intent, fp);
check_and_fclose(fp, INTENT_FILE);
}
@ -251,7 +272,9 @@ finish_recovery(const char *send_intent)
// Copy logs to cache so the system can find out what happened.
FILE *log = fopen_root_path(LOG_FILE, "a");
if (log != NULL) {
if (log == NULL) {
LOGE("Can't open %s\n", LOG_FILE);
} else {
FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r");
if (tmplog == NULL) {
LOGE("Can't open %s\n", TEMPORARY_LOG_FILE);
@ -267,7 +290,7 @@ finish_recovery(const char *send_intent)
}
#ifndef BOARD_HAS_NO_MISC_PARTITION
// Reset the bootloader message to revert to a normal main system boot.
// Reset to mormal system boot so recovery won't cycle indefinitely.
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
set_bootloader_message(&boot);
@ -285,8 +308,7 @@ finish_recovery(const char *send_intent)
}
static int
erase_root(const char *root)
{
erase_root(const char *root) {
ui_set_background(BACKGROUND_ICON_INSTALLING);
ui_show_indeterminate_progress();
ui_print("Formatting %s...\n", root);
@ -422,7 +444,7 @@ wipe_data(int confirm) {
ui_print("\n-- Wiping data...\n");
device_wipe_data();
erase_root("DATA:");
#ifdef HAS_DATADATA
#ifdef BOARD_HAS_DATADATA
erase_root("DATADATA:");
#endif
erase_root("CACHE:");
@ -432,8 +454,7 @@ wipe_data(int confirm) {
}
static void
prompt_and_wait()
{
prompt_and_wait() {
char** headers = prepend_title(MENU_HEADERS);
for (;;) {
@ -512,14 +533,12 @@ prompt_and_wait()
}
static void
print_property(const char *key, const char *name, void *cookie)
{
print_property(const char *key, const char *name, void *cookie) {
fprintf(stderr, "%s=%s\n", key, name);
}
int
main(int argc, char **argv)
{
main(int argc, char **argv) {
if (strstr(argv[0], "recovery") == NULL)
{
if (strstr(argv[0], "flash_image") != NULL)
@ -576,6 +595,8 @@ main(int argc, char **argv)
}
}
device_recovery_start();
fprintf(stderr, "Command:");
for (arg = 0; arg < argc; arg++) {
fprintf(stderr, " \"%s\"", argv[arg]);

View File

@ -17,6 +17,9 @@
#ifndef _RECOVERY_UI_H
#define _RECOVERY_UI_H
// Called when recovery starts up. Returns 0.
extern int device_recovery_start();
// Called in the input thread when a new key (key_code) is pressed.
// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
// keys are already pressed. Return true if the text display should

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

111
roots.c
View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,35 +24,38 @@
#include <limits.h>
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
#include "flashutils/flashutils.h"
#include "minzip/Zip.h"
#include "roots.h"
#include "common.h"
#include "mounts.h"
#include "extendedcommands.h"
/* Canonical pointers.
xxx may just want to use enums
*/
static const char g_mtd_device[] = "@\0g_mtd_device";
static const char g_default_device[] = "@\0g_default_device";
static const char g_raw[] = "@\0g_raw";
static const char g_package_file[] = "@\0g_package_file";
static RootInfo g_roots[] = {
{ "BOOT:", g_mtd_device, NULL, "boot", NULL, g_raw, NULL },
{ "CACHE:", CACHE_DEVICE, NULL, "cache", "/cache", CACHE_FILESYSTEM, CACHE_FILESYSTEM_OPTIONS },
{ "DATA:", DATA_DEVICE, NULL, "userdata", "/data", DATA_FILESYSTEM, DATA_FILESYSTEM_OPTIONS },
#ifdef HAS_DATADATA
{ "DATADATA:", DATADATA_DEVICE, NULL, "datadata", "/datadata", DATADATA_FILESYSTEM, DATADATA_FILESYSTEM_OPTIONS },
{ "BOOT:", g_default_device, NULL, "boot", NULL, g_raw, NULL },
{ "CACHE:", BOARD_CACHE_DEVICE, NULL, "cache", "/cache", BOARD_CACHE_FILESYSTEM, BOARD_CACHE_FILESYSTEM_OPTIONS },
{ "DATA:", BOARD_DATA_DEVICE, NULL, "userdata", "/data", BOARD_DATA_FILESYSTEM, BOARD_DATA_FILESYSTEM_OPTIONS },
#ifdef BOARD_HAS_DATADATA
{ "DATADATA:", BOARD_DATADATA_DEVICE, NULL, "datadata", "/datadata", BOARD_DATADATA_FILESYSTEM, BOARD_DATADATA_FILESYSTEM_OPTIONS },
#endif
{ "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw, NULL },
{ "MISC:", g_default_device, NULL, "misc", NULL, g_raw, NULL },
{ "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file, NULL },
{ "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw, NULL },
{ "SDCARD:", SDCARD_DEVICE_PRIMARY, SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat", NULL },
{ "SDEXT:", SDEXT_DEVICE, NULL, NULL, "/sd-ext", SDEXT_FILESYSTEM, NULL },
{ "SYSTEM:", SYSTEM_DEVICE, NULL, "system", "/system", SYSTEM_FILESYSTEM, SYSTEM_FILESYSTEM_OPTIONS },
{ "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw, NULL },
{ "RECOVERY:", g_default_device, NULL, "recovery", "/", g_raw, NULL },
{ "SDCARD:", BOARD_SDCARD_DEVICE_PRIMARY, BOARD_SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat", NULL },
#ifdef BOARD_HAS_SDCARD_INTERNAL
{ "SDINTERNAL:", BOARD_SDCARD_DEVICE_INTERNAL, NULL, NULL, "/emmc", "vfat", NULL },
#endif
{ "SDEXT:", BOARD_SDEXT_DEVICE, NULL, NULL, "/sd-ext", BOARD_SDEXT_FILESYSTEM, NULL },
{ "SYSTEM:", BOARD_SYSTEM_DEVICE, NULL, "system", "/system", BOARD_SYSTEM_FILESYSTEM, BOARD_SYSTEM_FILESYSTEM_OPTIONS },
{ "MBM:", g_default_device, NULL, "mbm", NULL, g_raw, NULL },
{ "TMP:", NULL, NULL, NULL, "/tmp", NULL, NULL },
};
#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
@ -237,21 +241,6 @@ ensure_root_path_mounted(const char *root_path)
/* It's not mounted.
*/
if (info->device == g_mtd_device) {
if (info->partition_name == NULL) {
return -1;
}
//TODO: make the mtd stuff scan once when it needs to
mtd_scan_partitions();
const MtdPartition *partition;
partition = mtd_find_partition_by_name(info->partition_name);
if (partition == NULL) {
return -1;
}
return mtd_mount_partition(partition, info->mount_point,
info->filesystem, 0);
}
if (info->device == NULL || info->mount_point == NULL ||
info->filesystem == NULL ||
info->filesystem == g_raw ||
@ -259,6 +248,13 @@ ensure_root_path_mounted(const char *root_path)
return -1;
}
if (info->device == g_default_device) {
if (info->partition_name == NULL) {
return -1;
}
return mount_partition(info->partition_name, info->mount_point, info->filesystem, 0);
}
mkdir(info->mount_point, 0755); // in case it doesn't already exist
if (mount_internal(info->device, info->mount_point, info->filesystem, info->filesystem_options)) {
if (info->device2 == NULL) {
@ -305,11 +301,24 @@ ensure_root_path_unmounted(const char *root_path)
return unmount_mounted_volume(volume);
}
int
get_root_partition_device(const char *root_path, char *device)
{
const RootInfo *info = get_root_info_for_path(root_path);
if (info == NULL)
{
return NULL;
}
if (info->device == g_default_device)
return get_partition_device(info->partition_name, device);
return info->device;
}
const MtdPartition *
get_root_mtd_partition(const char *root_path)
{
const RootInfo *info = get_root_info_for_path(root_path);
if (info == NULL || info->device != g_mtd_device ||
if (info == NULL || info->device != g_default_device ||
info->partition_name == NULL)
{
#ifdef BOARD_HAS_MTD_CACHE
@ -345,7 +354,8 @@ format_root_device(const char *root)
LOGW("format_root_device: can't resolve \"%s\"\n", root);
return -1;
}
if (info->mount_point != NULL && info->device == g_mtd_device) {
if (info->mount_point != NULL && info->device == g_default_device) {
/* Don't try to format a mounted device.
*/
int ret = ensure_root_path_unmounted(root);
@ -357,32 +367,17 @@ format_root_device(const char *root)
/* Format the device.
*/
if (info->device == g_mtd_device) {
mtd_scan_partitions();
const MtdPartition *partition;
partition = mtd_find_partition_by_name(info->partition_name);
if (partition == NULL) {
LOGW("format_root_device: can't find mtd partition \"%s\"\n",
info->partition_name);
return -1;
}
if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
MtdWriteContext *write = mtd_write_partition(partition);
if (write == NULL) {
LOGW("format_root_device: can't open \"%s\"\n", root);
return -1;
} else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
LOGW("format_root_device: can't erase \"%s\"\n", root);
mtd_write_close(write);
return -1;
} else if (mtd_write_close(write)) {
LOGW("format_root_device: can't close \"%s\"\n", root);
return -1;
} else {
return 0;
}
}
if (info->device == g_default_device) {
int ret = 0;
if (info->filesystem == g_raw)
ret = erase_raw_partition(info->partition_name);
else
ret = erase_partition(info->partition_name, info->filesystem);
if (ret != 0)
LOGE("Error erasing device %s\n", info->device);
return ret;
}
return format_non_mtd_device(root);
return format_unknown_device(root);
}

78
roots.h
View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,70 +19,82 @@
#define RECOVERY_ROOTS_H_
#include "minzip/Zip.h"
#include "flashutils/flashutils.h"
#include "mtdutils/mtdutils.h"
#include "mmcutils/mmcutils.h"
#ifndef SDCARD_DEVICE_PRIMARY
#define SDCARD_DEVICE_PRIMARY "/dev/block/mmcblk0p1"
#ifndef BOARD_USES_MMCUTILS
#define DEFAULT_FILESYSTEM "yaffs2"
#else
#define DEFAULT_FILESYSTEM "ext3"
#endif
#ifndef SDCARD_DEVICE_SECONDARY
#define SDCARD_DEVICE_SECONDARY "/dev/block/mmcblk0"
#ifndef BOARD_SDCARD_DEVICE_PRIMARY
#define BOARD_SDCARD_DEVICE_PRIMARY "/dev/block/mmcblk0p1"
#endif
#ifndef SDEXT_DEVICE
#define SDEXT_DEVICE "/dev/block/mmcblk0p2"
#ifndef BOARD_SDCARD_DEVICE_SECONDARY
#define BOARD_SDCARD_DEVICE_SECONDARY "/dev/block/mmcblk0"
#endif
#ifndef SDEXT_FILESYSTEM
#define SDEXT_FILESYSTEM "auto"
#ifndef BOARD_SDCARD_DEVICE_INTERNAL
#define BOARD_SDCARD_DEVICE_INTERNAL g_default_device
#endif
#ifndef DATA_DEVICE
#define DATA_DEVICE g_mtd_device
#ifndef BOARD_SDEXT_DEVICE
#define BOARD_SDEXT_DEVICE "/dev/block/mmcblk0p2"
#endif
#ifndef DATA_FILESYSTEM
#define DATA_FILESYSTEM "yaffs2"
#ifndef BOARD_SDEXT_FILESYSTEM
#define BOARD_SDEXT_FILESYSTEM "auto"
#endif
#ifndef DATADATA_DEVICE
#define DATADATA_DEVICE g_mtd_device
#ifndef BOARD_DATA_DEVICE
#define BOARD_DATA_DEVICE g_default_device
#endif
#ifndef DATADATA_FILESYSTEM
#define DATADATA_FILESYSTEM "yaffs2"
#ifndef BOARD_DATA_FILESYSTEM
#define BOARD_DATA_FILESYSTEM DEFAULT_FILESYSTEM
#endif
#ifndef CACHE_DEVICE
#define CACHE_DEVICE g_mtd_device
#ifndef BOARD_DATADATA_DEVICE
#define BOARD_DATADATA_DEVICE g_default_device
#endif
#ifndef CACHE_FILESYSTEM
#define CACHE_FILESYSTEM "yaffs2"
#ifndef BOARD_DATADATA_FILESYSTEM
#define BOARD_DATADATA_FILESYSTEM DEFAULT_FILESYSTEM
#endif
#ifndef SYSTEM_DEVICE
#define SYSTEM_DEVICE g_mtd_device
#ifndef BOARD_CACHE_DEVICE
#define BOARD_CACHE_DEVICE g_default_device
#endif
#ifndef SYSTEM_FILESYSTEM
#define SYSTEM_FILESYSTEM "yaffs2"
#ifndef BOARD_CACHE_FILESYSTEM
#define BOARD_CACHE_FILESYSTEM DEFAULT_FILESYSTEM
#endif
#ifndef DATA_FILESYSTEM_OPTIONS
#define DATA_FILESYSTEM_OPTIONS NULL
#ifndef BOARD_SYSTEM_DEVICE
#define BOARD_SYSTEM_DEVICE g_default_device
#endif
#ifndef CACHE_FILESYSTEM_OPTIONS
#define CACHE_FILESYSTEM_OPTIONS NULL
#ifndef BOARD_SYSTEM_FILESYSTEM
#define BOARD_SYSTEM_FILESYSTEM DEFAULT_FILESYSTEM
#endif
#ifndef DATADATA_FILESYSTEM_OPTIONS
#define DATADATA_FILESYSTEM_OPTIONS NULL
#ifndef BOARD_DATA_FILESYSTEM_OPTIONS
#define BOARD_DATA_FILESYSTEM_OPTIONS NULL
#endif
#ifndef SYSTEM_FILESYSTEM_OPTIONS
#define SYSTEM_FILESYSTEM_OPTIONS NULL
#ifndef BOARD_CACHE_FILESYSTEM_OPTIONS
#define BOARD_CACHE_FILESYSTEM_OPTIONS NULL
#endif
#ifndef BOARD_DATADATA_FILESYSTEM_OPTIONS
#define BOARD_DATADATA_FILESYSTEM_OPTIONS NULL
#endif
#ifndef BOARD_SYSTEM_FILESYSTEM_OPTIONS
#define BOARD_SYSTEM_FILESYSTEM_OPTIONS NULL
#endif
@ -119,6 +132,7 @@ int ensure_root_path_mounted(const char *root_path);
int ensure_root_path_unmounted(const char *root_path);
const MtdPartition *get_root_mtd_partition(const char *root_path);
int get_root_partition_device(const char *root_path, char *device);
/* "root" must be the exact name of the root; no relative path is permitted.
* If the named root is mounted, this will attempt to unmount it first.

BIN
testdata/alter-footer.zip vendored Normal file

Binary file not shown.

BIN
testdata/alter-metadata.zip vendored Normal file

Binary file not shown.

BIN
testdata/fake-eocd.zip vendored Normal file

Binary file not shown.

BIN
testdata/jarsigned.zip vendored Normal file

Binary file not shown.

BIN
testdata/otasigned.zip vendored Normal file

Binary file not shown.

BIN
testdata/random.zip vendored Normal file

Binary file not shown.

BIN
testdata/unsigned.zip vendored Normal file

Binary file not shown.

51
ui.c
View File

@ -29,7 +29,7 @@
#include "minui/minui.h"
#include "recovery_ui.h"
#ifdef KEY_POWER_IS_SELECT_ITEM
#ifdef BOARD_HAS_NO_SELECT_BUTTON
static int gShowBackButton = 1;
#else
static int gShowBackButton = 0;
@ -41,40 +41,35 @@ static int gShowBackButton = 0;
#define MENU_MAX_COLS 64
#define MENU_MAX_ROWS 250
#define CHAR_WIDTH 10
#define CHAR_HEIGHT 18
#ifndef BOARD_LDPI_RECOVERY
#define CHAR_WIDTH 10
#define CHAR_HEIGHT 18
#else
#define CHAR_WIDTH 7
#define CHAR_HEIGHT 16
#endif
#define PROGRESSBAR_INDETERMINATE_STATES 6
#define PROGRESSBAR_INDETERMINATE_FPS 15
enum { LEFT_SIDE, CENTER_TILE, RIGHT_SIDE, NUM_SIDES };
static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER;
static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS];
static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES];
static gr_surface gProgressBarEmpty[NUM_SIDES];
static gr_surface gProgressBarFill[NUM_SIDES];
static gr_surface gProgressBarEmpty;
static gr_surface gProgressBarFill;
static int ui_has_initialized = 0;
static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
{ &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" },
{ &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" },
{ &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_INSTALLING],
"icon_firmware_install" },
{ &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_ERROR],
"icon_firmware_error" },
{ &gProgressBarIndeterminate[0], "indeterminate1" },
{ &gProgressBarIndeterminate[1], "indeterminate2" },
{ &gProgressBarIndeterminate[2], "indeterminate3" },
{ &gProgressBarIndeterminate[3], "indeterminate4" },
{ &gProgressBarIndeterminate[4], "indeterminate5" },
{ &gProgressBarIndeterminate[5], "indeterminate6" },
{ &gProgressBarEmpty[LEFT_SIDE], "progress_bar_empty_left_round" },
{ &gProgressBarEmpty[CENTER_TILE], "progress_bar_empty" },
{ &gProgressBarEmpty[RIGHT_SIDE], "progress_bar_empty_right_round" },
{ &gProgressBarFill[LEFT_SIDE], "progress_bar_left_round" },
{ &gProgressBarFill[CENTER_TILE], "progress_bar_fill" },
{ &gProgressBarFill[RIGHT_SIDE], "progress_bar_right_round" },
{ &gProgressBarEmpty, "progress_empty" },
{ &gProgressBarFill, "progress_fill" },
{ NULL, NULL },
};
@ -134,8 +129,8 @@ static void draw_progress_locked()
if (gProgressBarType == PROGRESSBAR_TYPE_NONE) return;
int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]);
int width = gr_get_width(gProgressBarIndeterminate[0]);
int height = gr_get_height(gProgressBarIndeterminate[0]);
int width = gr_get_width(gProgressBarEmpty);
int height = gr_get_height(gProgressBarEmpty);
int dx = (gr_fb_width() - width)/2;
int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
@ -148,18 +143,12 @@ static void draw_progress_locked()
float progress = gProgressScopeStart + gProgress * gProgressScopeSize;
int pos = (int) (progress * width);
gr_surface s = (pos ? gProgressBarFill : gProgressBarEmpty)[LEFT_SIDE];
gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx, dy);
int x = gr_get_width(s);
while (x + (int) gr_get_width(gProgressBarEmpty[RIGHT_SIDE]) < width) {
s = (pos > x ? gProgressBarFill : gProgressBarEmpty)[CENTER_TILE];
gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx + x, dy);
x += gr_get_width(s);
if (pos > 0) {
gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy);
}
if (pos < width-1) {
gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
}
s = (pos > x ? gProgressBarFill : gProgressBarEmpty)[RIGHT_SIDE];
gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx + x, dy);
}
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
@ -615,4 +604,4 @@ void ui_set_showing_back_button(int showBackButton) {
int ui_get_showing_back_button() {
return gShowBackButton;
}
}

View File

@ -4,6 +4,7 @@ LOCAL_PATH := $(call my-dir)
updater_src_files := \
install.c \
../mounts.c \
updater.c
#
@ -18,8 +19,10 @@ LOCAL_MODULE_TAGS := eng
LOCAL_SRC_FILES := $(updater_src_files)
LOCAL_STATIC_LIBRARIES := $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libminzip libz
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,17 +30,20 @@
#include "cutils/misc.h"
#include "cutils/properties.h"
#include "edify/expr.h"
#include "mincrypt/sha.h"
#include "minzip/DirUtil.h"
#include "mtdutils/mounts.h"
#include "mounts.h"
#include "flashutils/flashutils.h"
#include "mtdutils/mtdutils.h"
#include "mmcutils/mmcutils.h"
#include "updater.h"
#include "applypatch/applypatch.h"
// mount(type, location, mount_point)
//
// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
// type="vfat" location="/dev/block/<whatever>" to mount a device
char* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 3) {
return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
@ -66,23 +70,11 @@ char* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
mkdir(mount_point, 0755);
if (strcmp(type, "MTD") == 0) {
mtd_scan_partitions();
const MtdPartition* mtd;
mtd = mtd_find_partition_by_name(location);
if (mtd == NULL) {
fprintf(stderr, "%s: no mtd partition named \"%s\"",
name, location);
if (strcmp(type, "MTD") == 0 || strcmp(type, "MMC") == 0) {
if (0 == mount_partition(location, mount_point, get_default_filesystem(), 0))
result = mount_point;
else
result = strdup("");
goto done;
}
if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
fprintf(stderr, "mtd mount of %s failed: %s\n",
location, strerror(errno));
result = strdup("");
goto done;
}
result = mount_point;
} else {
if (mount(location, mount_point, type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
@ -98,12 +90,12 @@ done:
free(type);
free(location);
if (result != mount_point) free(mount_point);
return result;
return StringValue(result);
}
// is_mounted(mount_point)
char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
@ -127,11 +119,11 @@ char* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
done:
if (result != mount_point) free(mount_point);
return result;
return StringValue(result);
}
char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
@ -157,14 +149,14 @@ char* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
done:
if (result != mount_point) free(mount_point);
return result;
return StringValue(result);
}
// format(type, location)
//
// type="MTD" location=partition
char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
@ -184,45 +176,23 @@ char* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
if (strcmp(type, "MTD") == 0) {
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(location);
if (mtd == NULL) {
fprintf(stderr, "%s: no mtd partition named \"%s\"",
name, location);
if (strcmp(type, "MTD") == 0 || strcmp(type, "MMC") == 0) {
if (0 != erase_partition(location, NULL)) {
result = strdup("");
goto done;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
fprintf(stderr, "%s: can't write \"%s\"", name, location);
result = strdup("");
goto done;
}
if (mtd_erase_blocks(ctx, -1) == -1) {
mtd_write_close(ctx);
fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
result = strdup("");
goto done;
}
if (mtd_write_close(ctx) != 0) {
fprintf(stderr, "%s: failed to close \"%s\"", name, location);
result = strdup("");
goto done;
}
result = location;
} else {
fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
}
result = location;
done:
free(type);
if (result != location) free(location);
return result;
return StringValue(result);
}
char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
char** paths = malloc(argc * sizeof(char*));
int i;
for (i = 0; i < argc; ++i) {
@ -249,11 +219,11 @@ char* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
char buffer[10];
sprintf(buffer, "%d", success);
return strdup(buffer);
return StringValue(strdup(buffer));
}
char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
}
@ -270,10 +240,10 @@ char* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
free(sec_str);
return frac_str;
return StringValue(frac_str);
}
char* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
@ -287,11 +257,11 @@ char* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
return frac_str;
return StringValue(frac_str);
}
// package_extract_dir(package_path, destination_path)
char* PackageExtractDirFn(const char* name, State* state,
Value* PackageExtractDirFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
@ -310,48 +280,94 @@ char* PackageExtractDirFn(const char* name, State* state,
NULL, NULL);
free(zip_path);
free(dest_path);
return strdup(success ? "t" : "");
return StringValue(strdup(success ? "t" : ""));
}
// package_extract_file(package_path, destination_path)
char* PackageExtractFileFn(const char* name, State* state,
// or
// package_extract_file(package_path)
// to return the entire contents of the file as the result of this
// function (the char* returned is actually a FileContents*).
Value* PackageExtractFileFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
if (argc != 1 && argc != 2) {
return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
name, argc);
}
char* zip_path;
char* dest_path;
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
bool success = false;
if (argc == 2) {
// The two-argument version extracts to a file.
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
fprintf(stderr, "%s: no %s in package\n", name, zip_path);
goto done;
char* zip_path;
char* dest_path;
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
fprintf(stderr, "%s: no %s in package\n", name, zip_path);
goto done2;
}
FILE* f = fopen(dest_path, "wb");
if (f == NULL) {
fprintf(stderr, "%s: can't open %s for write: %s\n",
name, dest_path, strerror(errno));
goto done2;
}
success = mzExtractZipEntryToFile(za, entry, fileno(f));
fclose(f);
done2:
free(zip_path);
free(dest_path);
return StringValue(strdup(success ? "t" : ""));
} else {
// The one-argument version returns the contents of the file
// as the result.
char* zip_path;
Value* v = malloc(sizeof(Value));
v->type = VAL_BLOB;
v->size = -1;
v->data = NULL;
if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
const ZipEntry* entry = mzFindZipEntry(za, zip_path);
if (entry == NULL) {
fprintf(stderr, "%s: no %s in package\n", name, zip_path);
goto done1;
}
v->size = mzGetZipEntryUncompLen(entry);
v->data = malloc(v->size);
if (v->data == NULL) {
fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
name, (long)v->size, zip_path);
goto done1;
}
success = mzExtractZipEntryToBuffer(za, entry,
(unsigned char *)v->data);
done1:
free(zip_path);
if (!success) {
free(v->data);
v->data = NULL;
v->size = -1;
}
return v;
}
FILE* f = fopen(dest_path, "wb");
if (f == NULL) {
fprintf(stderr, "%s: can't open %s for write: %s\n",
name, dest_path, strerror(errno));
goto done;
}
success = mzExtractZipEntryToFile(za, entry, fileno(f));
fclose(f);
done:
free(zip_path);
free(dest_path);
return strdup(success ? "t" : "");
}
// symlink target src1 src2 ...
// unlinks any previously existing src1, src2, etc before creating symlinks.
char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
}
@ -380,11 +396,11 @@ char* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
free(srcs[i]);
}
free(srcs);
return strdup("");
return StringValue(strdup(""));
}
char* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
bool recursive = (strcmp(name, "set_perm_recursive") == 0);
@ -454,11 +470,11 @@ done:
}
free(args);
return result;
return StringValue(result);
}
char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
@ -470,7 +486,7 @@ char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
property_get(key, value, "");
free(key);
return strdup(value);
return StringValue(strdup(value));
}
@ -479,7 +495,7 @@ char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
// interprets 'file' as a getprop-style file (key=value pairs, one
// per line, # comment lines and blank lines okay), and returns the value
// for 'key' (or "" if it isn't defined).
char* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
char* buffer = NULL;
char* filename;
@ -569,7 +585,7 @@ char* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
free(filename);
free(key);
free(buffer);
return result;
return StringValue(result);
}
@ -582,7 +598,7 @@ static bool write_raw_image_cb(const unsigned char* data,
}
// write_raw_image(file, partition)
char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
char* partition;
@ -600,153 +616,138 @@ char* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
if (mtd == NULL) {
fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
if (0 == restore_raw_partition(partition, filename))
result = strdup(partition);
else
result = strdup("");
goto done;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
name, partition);
result = strdup("");
goto done;
}
bool success;
FILE* f = fopen(filename, "rb");
if (f == NULL) {
fprintf(stderr, "%s: can't open %s: %s\n",
name, filename, strerror(errno));
result = strdup("");
goto done;
}
success = true;
char* buffer = malloc(BUFSIZ);
int read;
while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
int wrote = mtd_write_data(ctx, buffer, read);
success = success && (wrote == read);
if (!success) {
fprintf(stderr, "mtd_write_data to %s failed: %s\n",
partition, strerror(errno));
}
}
free(buffer);
fclose(f);
if (mtd_erase_blocks(ctx, -1) == -1) {
fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
}
if (mtd_write_close(ctx) != 0) {
fprintf(stderr, "%s: error closing write of %s\n", name, partition);
}
printf("%s %s partition from %s\n",
success ? "wrote" : "failed to write", partition, filename);
result = success ? partition : strdup("");
done:
if (result != partition) free(partition);
free(filename);
return result;
return StringValue(result);
}
// write_firmware_image(file, partition)
//
// partition is "radio" or "hboot"
// file is not used until after updater exits
//
// TODO: this should live in some HTC-specific library
char* WriteFirmwareImageFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* result = NULL;
char* partition;
char* filename;
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
return NULL;
}
if (strlen(partition) == 0) {
ErrorAbort(state, "partition argument to %s can't be empty", name);
goto done;
}
if (strlen(filename) == 0) {
ErrorAbort(state, "file argument to %s can't be empty", name);
goto done;
}
FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
fprintf(cmd, "firmware %s %s\n", partition, filename);
printf("will write %s firmware from %s\n", partition, filename);
result = partition;
done:
if (result != partition) free(partition);
free(filename);
return result;
}
extern int applypatch(int argc, char** argv);
// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
// apply_patch_check(file, sha1, ...)
// apply_patch_space(bytes)
char* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
printf("in applypatchfn (%s)\n", name);
char* prepend = NULL;
if (strstr(name, "check") != NULL) {
prepend = "-c";
} else if (strstr(name, "space") != NULL) {
prepend = "-s";
Value* ApplyPatchSpaceFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* bytes_str;
if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
return NULL;
}
char** args = ReadVarArgs(state, argc, argv);
if (args == NULL) return NULL;
// insert the "program name" argv[0] and a copy of the "prepend"
// string (if any) at the start of the args.
int extra = 1 + (prepend != NULL ? 1 : 0);
char** temp = malloc((argc+extra) * sizeof(char*));
memcpy(temp+extra, args, argc * sizeof(char*));
temp[0] = strdup("updater");
if (prepend) {
temp[1] = strdup(prepend);
char* endptr;
size_t bytes = strtol(bytes_str, &endptr, 10);
if (bytes == 0 && endptr == bytes_str) {
ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
name, bytes_str);
free(bytes_str);
return NULL;
}
free(args);
args = temp;
argc += extra;
printf("calling applypatch\n");
fflush(stdout);
int result = applypatch(argc, args);
printf("applypatch returned %d\n", result);
return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
}
// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc < 6 || (argc % 2) == 1) {
return ErrorAbort(state, "%s(): expected at least 6 args and an "
"even number, got %d",
name, argc);
}
char* source_filename;
char* target_filename;
char* target_sha1;
char* target_size_str;
if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
&target_sha1, &target_size_str) < 0) {
return NULL;
}
char* endptr;
size_t target_size = strtol(target_size_str, &endptr, 10);
if (target_size == 0 && endptr == target_size_str) {
ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
name, target_size_str);
free(source_filename);
free(target_filename);
free(target_sha1);
free(target_size_str);
return NULL;
}
int patchcount = (argc-4) / 2;
Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
int i;
for (i = 0; i < argc; ++i) {
free(args[i]);
for (i = 0; i < patchcount; ++i) {
if (patches[i*2]->type != VAL_STRING) {
ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
break;
}
if (patches[i*2+1]->type != VAL_BLOB) {
ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
break;
}
}
if (i != patchcount) {
for (i = 0; i < patchcount*2; ++i) {
FreeValue(patches[i]);
}
free(patches);
return NULL;
}
free(args);
switch (result) {
case 0: return strdup("t");
case 1: return strdup("");
default: return ErrorAbort(state, "applypatch couldn't parse args");
char** patch_sha_str = malloc(patchcount * sizeof(char*));
for (i = 0; i < patchcount; ++i) {
patch_sha_str[i] = patches[i*2]->data;
patches[i*2]->data = NULL;
FreeValue(patches[i*2]);
patches[i] = patches[i*2+1];
}
int result = applypatch(source_filename, target_filename,
target_sha1, target_size,
patchcount, patch_sha_str, patches);
for (i = 0; i < patchcount; ++i) {
FreeValue(patches[i]);
}
free(patch_sha_str);
free(patches);
return StringValue(strdup(result == 0 ? "t" : ""));
}
char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
// apply_patch_check(file, [sha1_1, ...])
Value* ApplyPatchCheckFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc < 1) {
return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
name, argc);
}
char* filename;
if (ReadArgs(state, argv, 1, &filename) < 0) {
return NULL;
}
int patchcount = argc-1;
char** sha1s = ReadVarArgs(state, argc-1, argv+1);
int result = applypatch_check(filename, patchcount, sha1s);
int i;
for (i = 0; i < patchcount; ++i) {
free(sha1s[i]);
}
free(sha1s);
return StringValue(strdup(result == 0 ? "t" : ""));
}
Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
char** args = ReadVarArgs(state, argc, argv);
if (args == NULL) {
return NULL;
@ -775,10 +776,10 @@ char* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
}
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
return buffer;
return StringValue(buffer);
}
char* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc < 1) {
return ErrorAbort(state, "%s() expects at least 1 arg", name);
}
@ -821,9 +822,108 @@ char* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
char buffer[20];
sprintf(buffer, "%d", status);
return strdup(buffer);
return StringValue(strdup(buffer));
}
// Take a sha-1 digest and return it as a newly-allocated hex string.
static char* PrintSha1(uint8_t* digest) {
char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
int i;
const char* alphabet = "0123456789abcdef";
for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
buffer[i*2+1] = alphabet[digest[i] & 0xf];
}
buffer[i*2] = '\0';
return buffer;
}
// sha1_check(data)
// to return the sha1 of the data (given in the format returned by
// read_file).
//
// sha1_check(data, sha1_hex, [sha1_hex, ...])
// returns the sha1 of the file if it matches any of the hex
// strings passed, or "" if it does not equal any of them.
//
Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc < 1) {
return ErrorAbort(state, "%s() expects at least 1 arg", name);
}
Value** args = ReadValueVarArgs(state, argc, argv);
if (args == NULL) {
return NULL;
}
if (args[0]->size < 0) {
fprintf(stderr, "%s(): no file contents received", name);
return StringValue(strdup(""));
}
uint8_t digest[SHA_DIGEST_SIZE];
SHA(args[0]->data, args[0]->size, digest);
FreeValue(args[0]);
if (argc == 1) {
return StringValue(PrintSha1(digest));
}
int i;
uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
for (i = 1; i < argc; ++i) {
if (args[i]->type != VAL_STRING) {
fprintf(stderr, "%s(): arg %d is not a string; skipping",
name, i);
} else if (ParseSha1(args[i]->data, arg_digest) != 0) {
// Warn about bad args and skip them.
fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
name, args[i]->data);
} else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
break;
}
FreeValue(args[i]);
}
if (i >= argc) {
// Didn't match any of the hex strings; return false.
return StringValue(strdup(""));
}
// Found a match; free all the remaining arguments and return the
// matched one.
int j;
for (j = i+1; j < argc; ++j) {
FreeValue(args[j]);
}
return args[i];
}
// Read a local file and return its contents (the char* returned
// is actually a FileContents*).
Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 1) {
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
}
char* filename;
if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
Value* v = malloc(sizeof(Value));
v->type = VAL_BLOB;
FileContents fc;
if (LoadFileContents(filename, &fc) != 0) {
ErrorAbort(state, "%s() loading \"%s\" failed: %s",
name, filename, strerror(errno));
free(filename);
free(v);
free(fc.data);
return NULL;
}
v->size = fc.size;
v->data = (char*)fc.data;
free(filename);
return v;
}
void RegisterInstallFunctions() {
RegisterFunction("mount", MountFn);
@ -843,11 +943,13 @@ void RegisterInstallFunctions() {
RegisterFunction("getprop", GetPropFn);
RegisterFunction("file_getprop", FileGetPropFn);
RegisterFunction("write_raw_image", WriteRawImageFn);
RegisterFunction("write_firmware_image", WriteFirmwareImageFn);
RegisterFunction("apply_patch", ApplyPatchFn);
RegisterFunction("apply_patch_check", ApplyPatchFn);
RegisterFunction("apply_patch_space", ApplyPatchFn);
RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
RegisterFunction("read_file", ReadFileFn);
RegisterFunction("sha1_check", Sha1CheckFn);
RegisterFunction("ui_print", UIPrintFn);

View File

@ -33,15 +33,23 @@
#define SCRIPT_NAME "META-INF/com/google/android/updater-script"
int main(int argc, char** argv) {
// Various things log information to stdout or stderr more or less
// at random. The log file makes more sense if buffering is
// turned off so things appear in the right order.
setbuf(stdout, NULL);
setbuf(stderr, NULL);
if (argc != 4) {
fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
return 1;
}
char* version = argv[1];
if ((version[0] != '1' && version[0] != '2') || version[1] != '\0') {
// We support version "1" or "2".
fprintf(stderr, "wrong updater binary API; expected 1 or 2, got %s\n",
if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
version[1] != '\0') {
// We support version 1, 2, or 3.
fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
"got %s\n",
argv[1]);
return 2;
}
@ -100,6 +108,7 @@ int main(int argc, char** argv) {
UpdaterInfo updater_info;
updater_info.cmd_pipe = cmd_pipe;
updater_info.package_zip = &za;
updater_info.version = atoi(version);
State state;
state.cookie = &updater_info;

View File

@ -23,6 +23,7 @@
typedef struct {
FILE* cmd_pipe;
ZipArchive* package_zip;
int version;
} UpdaterInfo;
#endif

View File

@ -25,8 +25,8 @@
# v2.02 - ignore com.htc.resources.apk if it exists and minor code cleanups,
# fix help text, implement simulated run (-s) [farmatito]
# v2.03 - fixed chown group ownership output [Kastro]
VERSION="2.03"
# v2.04 - replaced /system/sd with $SD_EXT_DIRECTORY [Firerat]
VERSION="2.04"
# Defaults
DEBUG=0 # Debug off by default
@ -74,7 +74,15 @@ DATAMOUNT=0
SYSSDMOUNT=0
FP_STARTTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
FP_STARTEPOCH=$( $DATE +%s )
if $TEST "$SD_EXT_DIRECTORY" = ""; then
#check for mount point, /system/sd included in tests for backward compatibility
for MP in /sd-ext /system/sd;do
if $TEST -d $MP; then
SD_EXT_DIRECTORY=$MP
break
fi
done
fi
fp_usage()
{
$ECHO "Usage $0 [OPTIONS] [APK_PATH]"
@ -186,8 +194,8 @@ fp_start()
DATAMOUNT=1
fi
if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " /system/sd " "/proc/mounts" ) -eq 0; then
$MOUNT /system/sd > /dev/null 2>&1
if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " $SD_EXT_DIRECTORY " "/proc/mounts" ) -eq 0; then
$MOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1
SYSSDMOUNT=1
fi
fi
@ -445,7 +453,7 @@ fp_end()
fi
if $TEST $SYSSDMOUNT -eq 1; then
$UMOUNT /system/sd > /dev/null 2>&1
$UMOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1
fi
if $TEST $SYSMOUNT -eq 1; then

View File

@ -42,7 +42,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
// An archive with a whole-file signature will end in six bytes:
//
// $ff $ff (2-byte comment size) (2-byte signature start)
// (2-byte signature start) $ff $ff (2-byte comment size)
//
// (As far as the ZIP format is concerned, these are part of the
// archive comment.) We start by reading this footer, this tells
@ -169,7 +169,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
const uint8_t* sha1 = SHA_final(&ctx);
for (i = 0; i < numKeys; ++i) {
// The 6 bytes is the "$ff $ff (signature_start) (comment_size)" that
// The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
// the signing tool appends after the signature itself.
if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
RSANUMBYTES, sha1)) {

91
verifier_test.c Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2009 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "verifier.h"
// This is build/target/product/security/testkey.x509.pem after being
// dumped out by dumpkey.jar.
RSAPublicKey test_key =
{ 64, 0xc926ad21,
{ 1795090719, 2141396315, 950055447, -1713398866,
-26044131, 1920809988, 546586521, -795969498,
1776797858, -554906482, 1805317999, 1429410244,
129622599, 1422441418, 1783893377, 1222374759,
-1731647369, 323993566, 28517732, 609753416,
1826472888, 215237850, -33324596, -245884705,
-1066504894, 774857746, 154822455, -1797768399,
-1536767878, -1275951968, -1500189652, 87251430,
-1760039318, 120774784, 571297800, -599067824,
-1815042109, -483341846, -893134306, -1900097649,
-1027721089, 950095497, 555058928, 414729973,
1136544882, -1250377212, 465547824, -236820568,
-1563171242, 1689838846, -404210357, 1048029507,
895090649, 247140249, 178744550, -747082073,
-1129788053, 109881576, -350362881, 1044303212,
-522594267, -1309816990, -557446364, -695002876},
{ -857949815, -510492167, -1494742324, -1208744608,
251333580, 2131931323, 512774938, 325948880,
-1637480859, 2102694287, -474399070, 792812816,
1026422502, 2053275343, -1494078096, -1181380486,
165549746, -21447327, -229719404, 1902789247,
772932719, -353118870, -642223187, 216871947,
-1130566647, 1942378755, -298201445, 1055777370,
964047799, 629391717, -2062222979, -384408304,
191868569, -1536083459, -612150544, -1297252564,
-1592438046, -724266841, -518093464, -370899750,
-739277751, -1536141862, 1323144535, 61311905,
1997411085, 376844204, 213777604, -217643712,
9135381, 1625809335, -1490225159, -1342673351,
1117190829, -57654514, 1825108855, -1281819325,
1111251351, -1726129724, 1684324211, -1773988491,
367251975, 810756730, -1941182952, 1175080310 }
};
void ui_print(const char* fmt, ...) {
char buf[256];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, 256, fmt, ap);
va_end(ap);
fputs(buf, stderr);
}
void ui_set_progress(float fraction) {
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <package>\n", argv[0]);
return 2;
}
int result = verify_file(argv[1], &test_key, 1);
if (result == VERIFY_SUCCESS) {
printf("SUCCESS\n");
return 0;
} else if (result == VERIFY_FAILURE) {
printf("FAILURE\n");
return 1;
} else {
printf("bad return value\n");
return 3;
}
}

94
verifier_test.sh Executable file
View File

@ -0,0 +1,94 @@
#!/bin/bash
#
# A test suite for applypatch. Run in a client where you have done
# envsetup, choosecombo, etc.
#
# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
# system partition.
#
#
# TODO: find some way to get this run regularly along with the rest of
# the tests.
EMULATOR_PORT=5580
DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/testdata
WORK_DIR=/data/local/tmp
# set to 0 to use a device instead
USE_EMULATOR=0
# ------------------------
if [ "$USE_EMULATOR" == 1 ]; then
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
else
ADB="adb -d "
fi
echo "waiting to connect to device"
$ADB wait-for-device
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "::: testing $1 :::"
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
[ "$open_pid" == "" ] || kill $open_pid
[ "$pid_emulator" == "" ] || kill $pid_emulator
exit 1
}
cleanup() {
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
run_command rm $WORK_DIR/verifier_test
run_command rm $WORK_DIR/package.zip
[ "$pid_emulator" == "" ] || kill $pid_emulator
}
$ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \
$WORK_DIR/verifier_test
expect_succeed() {
testname "$1 (should succeed)"
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip || fail
}
expect_fail() {
testname "$1 (should fail)"
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail
}
expect_fail unsigned.zip
expect_fail jarsigned.zip
expect_succeed otasigned.zip
expect_fail random.zip
expect_fail fake-eocd.zip
expect_fail alter-metadata.zip
expect_fail alter-footer.zip
# --------------- cleanup ----------------------
cleanup
echo
echo PASS
echo