Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
du
android_build
Commits
b2ee0fd5
Commit
b2ee0fd5
authored
15 years ago
by
Doug Zongker
Committed by
Android (Google) Code Review
15 years ago
Browse files
Options
Download
Plain Diff
Merge "relocate applypatch; check patch integrity"
parents
577c5ba9
5a482095
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
7 additions
and
3876 deletions
+7
-3876
tools/applypatch/Android.mk
tools/applypatch/Android.mk
+0
-59
tools/applypatch/applypatch.c
tools/applypatch/applypatch.c
+0
-895
tools/applypatch/applypatch.h
tools/applypatch/applypatch.h
+0
-65
tools/applypatch/applypatch.sh
tools/applypatch/applypatch.sh
+0
-345
tools/applypatch/bsdiff.c
tools/applypatch/bsdiff.c
+0
-410
tools/applypatch/bspatch.c
tools/applypatch/bspatch.c
+0
-252
tools/applypatch/freecache.c
tools/applypatch/freecache.c
+0
-172
tools/applypatch/imgdiff.c
tools/applypatch/imgdiff.c
+0
-1010
tools/applypatch/imgdiff.h
tools/applypatch/imgdiff.h
+0
-30
tools/applypatch/imgdiff_test.sh
tools/applypatch/imgdiff_test.sh
+0
-118
tools/applypatch/imgpatch.c
tools/applypatch/imgpatch.c
+0
-364
tools/applypatch/main.c
tools/applypatch/main.c
+0
-60
tools/applypatch/testdata/new.file
tools/applypatch/testdata/new.file
+0
-0
tools/applypatch/testdata/old.file
tools/applypatch/testdata/old.file
+0
-0
tools/applypatch/testdata/patch.bsdiff
tools/applypatch/testdata/patch.bsdiff
+0
-0
tools/applypatch/utils.c
tools/applypatch/utils.c
+0
-62
tools/applypatch/utils.h
tools/applypatch/utils.h
+0
-30
tools/releasetools/edify_generator.py
tools/releasetools/edify_generator.py
+1
-1
tools/releasetools/ota_from_target_files
tools/releasetools/ota_from_target_files
+6
-3
No files found.
tools/applypatch/Android.mk
deleted
100644 → 0
View file @
577c5ba9
# 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_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_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
This diff is collapsed.
Click to expand it.
tools/applypatch/applypatch.c
deleted
100644 → 0
View file @
577c5ba9
This diff is collapsed.
Click to expand it.
tools/applypatch/applypatch.h
deleted
100644 → 0
View file @
577c5ba9
/*
* 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"
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
;
size_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
size_t
(
*
SinkFn
)(
unsigned
char
*
,
size_t
,
void
*
);
// applypatch.c
size_t
FreeSpaceForFile
(
const
char
*
filename
);
int
applypatch
(
int
argc
,
char
**
argv
);
// bsdiff.c
void
ShowBSDiffLicense
();
int
ApplyBSDiffPatch
(
const
unsigned
char
*
old_data
,
ssize_t
old_size
,
const
char
*
patch_filename
,
ssize_t
offset
,
SinkFn
sink
,
void
*
token
,
SHA_CTX
*
ctx
);
int
ApplyBSDiffPatchMem
(
const
unsigned
char
*
old_data
,
ssize_t
old_size
,
const
char
*
patch_filename
,
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
char
*
patch_filename
,
SinkFn
sink
,
void
*
token
,
SHA_CTX
*
ctx
);
// freecache.c
int
MakeFreeSpaceOnCache
(
size_t
bytes_needed
);
#endif
This diff is collapsed.
Click to expand it.
tools/applypatch/applypatch.sh
deleted
100755 → 0
View file @
577c5ba9
#!/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
/build/tools/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
/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
rm
-rf
$tmpdir
}
cleanup
$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
# 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
This diff is collapsed.
Click to expand it.
tools/applypatch/bsdiff.c
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
;
}
This diff is collapsed.
Click to expand it.
tools/applypatch/bspatch.c
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
ApplyBSDiffPatch
(
const
unsigned
char
*
old_data
,
ssize_t
old_size
,
const
char
*
patch_filename
,
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_filename
,
patch_offset
,
&
new_data
,
&
new_size
)
!=
0
)
{
return
-
1
;
}
if
(
sink
(
new_data
,
new_size
,
token
)
<
new_size
)
{
fprintf
(
stderr
,
"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
char
*
patch_filename
,
ssize_t
patch_offset
,
unsigned
char
**
new_data
,
ssize_t
*
new_size
)
{
FILE
*
f
;
if
((
f
=
fopen
(
patch_filename
,
"rb"
))
==
NULL
)
{
fprintf
(
stderr
,
"failed to open patch file
\n
"
);
return
1
;
}
// File 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".
fseek
(
f
,
patch_offset
,
SEEK_SET
);
unsigned
char
header
[
32
];
if
(
fread
(
header
,
1
,
32
,
f
)
<
32
)
{
fprintf
(
stderr
,
"failed to read patch file header
\n
"
);
return
1
;
}
if
(
memcmp
(
header
,
"BSDIFF40"
,
8
)
!=
0
)
{
fprintf
(
stderr
,
"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
)
{
fprintf
(
stderr
,
"corrupt patch file header (data lengths)
\n
"
);
return
1
;
}
fclose
(
f
);
int
bzerr
;
#define OPEN_AT(f, bzf, offset) \
FILE* f; \
BZFILE* bzf; \
if ((f = fopen(patch_filename, "rb")) == NULL) { \
fprintf(stderr, "failed to open patch file\n"); \
return 1; \
} \
if (fseeko(f, offset+patch_offset, SEEK_SET)) { \
fprintf(stderr, "failed to seek in patch file\n"); \
return 1; \
} \
if ((bzf = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL) { \
fprintf(stderr, "failed to bzReadOpen in patch file (%d)\n", bzerr); \
return 1; \
}
OPEN_AT
(
cpf
,
cpfbz2
,
32
);
OPEN_AT
(
dpf
,
dpfbz2
,
32
+
ctrl_len
);
OPEN_AT
(
epf
,
epfbz2
,
32
+
ctrl_len
+
data_len
);
#undef OPEN_AT
*
new_data
=
malloc
(
*
new_size
);
if
(
*
new_data
==
NULL
)
{
fprintf
(
stderr
,
"failed to allocate %d bytes of memory for output file
\n
"
,
(
int
)
*
new_size
);
return
1
;
}
off_t
oldpos
=
0
,
newpos
=
0
;
off_t
ctrl
[
3
];
off_t
len_read
;
int
i
;
unsigned
char
buf
[
8
];
while
(
newpos
<
*
new_size
)
{
// Read control data
for
(
i
=
0
;
i
<
3
;
++
i
)
{
len_read
=
BZ2_bzRead
(
&
bzerr
,
cpfbz2
,
buf
,
8
);
if
(
len_read
<
8
||
!
(
bzerr
==
BZ_OK
||
bzerr
==
BZ_STREAM_END
))
{
fprintf
(
stderr
,
"corrupt patch (read control)
\n
"
);
return
1
;
}
ctrl
[
i
]
=
offtin
(
buf
);
}
// Sanity check
if
(
newpos
+
ctrl
[
0
]
>
*
new_size
)
{
fprintf
(
stderr
,
"corrupt patch (new file overrun)
\n
"
);
return
1
;
}
// Read diff string
len_read
=
BZ2_bzRead
(
&
bzerr
,
dpfbz2
,
*
new_data
+
newpos
,
ctrl
[
0
]);
if
(
len_read
<
ctrl
[
0
]
||
!
(
bzerr
==
BZ_OK
||
bzerr
==
BZ_STREAM_END
))
{
fprintf
(
stderr
,
"corrupt patch (read diff)
\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
)
{
fprintf
(
stderr
,
"corrupt patch (new file overrun)
\n
"
);
return
1
;
}
// Read extra string
len_read
=
BZ2_bzRead
(
&
bzerr
,
epfbz2
,
*
new_data
+
newpos
,
ctrl
[
1
]);
if
(
len_read
<
ctrl
[
1
]
||
!
(
bzerr
==
BZ_OK
||
bzerr
==
BZ_STREAM_END
))
{
fprintf
(
stderr
,
"corrupt patch (read extra)
\n
"
);
return
1
;
}
// Adjust pointers
newpos
+=
ctrl
[
1
];
oldpos
+=
ctrl
[
2
];
}
BZ2_bzReadClose
(
&
bzerr
,
cpfbz2
);
BZ2_bzReadClose
(
&
bzerr
,
dpfbz2
);
BZ2_bzReadClose
(
&
bzerr
,
epfbz2
);
fclose
(
cpf
);
fclose
(
dpf
);
fclose
(
epf
);
return
0
;
}
This diff is collapsed.
Click to expand it.
tools/applypatch/freecache.c
deleted
100644 → 0
View file @
577c5ba9
#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
;
}
This diff is collapsed.
Click to expand it.
tools/applypatch/imgdiff.c
deleted
100644 → 0
View file @
577c5ba9
This diff is collapsed.
Click to expand it.
tools/applypatch/imgdiff.h
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
This diff is collapsed.
Click to expand it.
tools/applypatch/imgdiff_test.sh
deleted
100755 → 0
View file @
577c5ba9
#!/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
This diff is collapsed.
Click to expand it.
tools/applypatch/imgpatch.c
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
char
*
patch_filename
,
SinkFn
sink
,
void
*
token
,
SHA_CTX
*
ctx
)
{
FILE
*
f
;
if
((
f
=
fopen
(
patch_filename
,
"rb"
))
==
NULL
)
{
printf
(
"failed to open patch file
\n
"
);
return
-
1
;
}
unsigned
char
header
[
12
];
if
(
fread
(
header
,
1
,
12
,
f
)
!=
12
)
{
printf
(
"failed to read patch file header
\n
"
);
return
-
1
;
}
// IMGDIFF1 uses CHUNK_NORMAL and CHUNK_GZIP.
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
if
(
memcmp
(
header
,
"IMGDIFF"
,
7
)
!=
0
||
(
header
[
7
]
!=
'1'
&&
header
[
7
]
!=
'2'
))
{
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.
unsigned
char
chunk
[
4
];
if
(
fread
(
chunk
,
1
,
4
,
f
)
!=
4
)
{
printf
(
"failed to read chunk %d record
\n
"
,
i
);
return
-
1
;
}
int
type
=
Read4
(
chunk
);
if
(
type
==
CHUNK_NORMAL
)
{
unsigned
char
normal_header
[
24
];
if
(
fread
(
normal_header
,
1
,
24
,
f
)
!=
24
)
{
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
);
printf
(
"CHUNK %d: normal patch offset %d
\n
"
,
i
,
patch_offset
);
ApplyBSDiffPatch
(
old_data
+
src_start
,
src_len
,
patch_filename
,
patch_offset
,
sink
,
token
,
ctx
);
}
else
if
(
type
==
CHUNK_GZIP
)
{
// This branch is basically a duplicate of the CHUNK_DEFLATE
// branch, with a bit of extra processing for the gzip header
// and footer. I've avoided factoring the common code out since
// this branch will just be deleted when we drop support for
// IMGDIFF1.
// gzip chunks have an additional 64 + gzip_header_len + 8 bytes
// in their chunk header.
unsigned
char
*
gzip
=
malloc
(
64
);
if
(
fread
(
gzip
,
1
,
64
,
f
)
!=
64
)
{
printf
(
"failed to read chunk %d initial gzip header data
\n
"
,
i
);
return
-
1
;
}
size_t
gzip_header_len
=
Read4
(
gzip
+
60
);
gzip
=
realloc
(
gzip
,
64
+
gzip_header_len
+
8
);
if
(
fread
(
gzip
+
64
,
1
,
gzip_header_len
+
8
,
f
)
!=
gzip_header_len
+
8
)
{
printf
(
"failed to read chunk %d remaining gzip header data
\n
"
,
i
);
return
-
1
;
}
size_t
src_start
=
Read8
(
gzip
);
size_t
src_len
=
Read8
(
gzip
+
8
);
size_t
patch_offset
=
Read8
(
gzip
+
16
);
size_t
expanded_len
=
Read8
(
gzip
+
24
);
size_t
target_len
=
Read8
(
gzip
+
32
);
int
gz_level
=
Read4
(
gzip
+
40
);
int
gz_method
=
Read4
(
gzip
+
44
);
int
gz_windowBits
=
Read4
(
gzip
+
48
);
int
gz_memLevel
=
Read4
(
gzip
+
52
);
int
gz_strategy
=
Read4
(
gzip
+
56
);
printf
(
"CHUNK %d: gzip patch offset %d
\n
"
,
i
,
patch_offset
);
// 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
-
(
gzip_header_len
+
8
);
strm
.
next_in
=
(
unsigned
char
*
)(
old_data
+
src_start
+
gzip_header_len
);
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_filename
,
patch_offset
,
&
uncompressed_target_data
,
&
uncompressed_target_size
)
!=
0
)
{
return
-
1
;
}
// Now compress the target data and append it to the output.
// start with the gzip header.
sink
(
gzip
+
64
,
gzip_header_len
,
token
);
SHA_update
(
ctx
,
gzip
+
64
,
gzip_header_len
);
// 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
,
gz_level
,
gz_method
,
gz_windowBits
,
gz_memLevel
,
gz_strategy
);
do
{
strm
.
avail_out
=
temp_size
;
strm
.
next_out
=
temp_data
;
ret
=
deflate
(
&
strm
,
Z_FINISH
);
size_t
have
=
temp_size
-
strm
.
avail_out
;
if
(
sink
(
temp_data
,
have
,
token
)
!=
have
)
{
printf
(
"failed to write %d compressed bytes to output
\n
"
,
have
);
return
-
1
;
}
SHA_update
(
ctx
,
temp_data
,
have
);
}
while
(
ret
!=
Z_STREAM_END
);
deflateEnd
(
&
strm
);
// lastly, the gzip footer.
sink
(
gzip
+
64
+
gzip_header_len
,
8
,
token
);
SHA_update
(
ctx
,
gzip
+
64
+
gzip_header_len
,
8
);
free
(
temp_data
);
free
(
uncompressed_target_data
);
free
(
gzip
);
}
else
if
(
type
==
CHUNK_RAW
)
{
unsigned
char
raw_header
[
4
];
if
(
fread
(
raw_header
,
1
,
4
,
f
)
!=
4
)
{
printf
(
"failed to read chunk %d raw header data
\n
"
,
i
);
return
-
1
;
}
size_t
data_len
=
Read4
(
raw_header
);
printf
(
"CHUNK %d: raw data %d
\n
"
,
i
,
data_len
);
unsigned
char
*
temp
=
malloc
(
data_len
);
if
(
fread
(
temp
,
1
,
data_len
,
f
)
!=
data_len
)
{
printf
(
"failed to read chunk %d raw data
\n
"
,
i
);
return
-
1
;
}
SHA_update
(
ctx
,
temp
,
data_len
);
if
(
sink
(
temp
,
data_len
,
token
)
!=
data_len
)
{
printf
(
"failed to write chunk %d raw data
\n
"
,
i
);
return
-
1
;
}
}
else
if
(
type
==
CHUNK_DEFLATE
)
{
// deflate chunks have an additional 60 bytes in their chunk header.
unsigned
char
deflate_header
[
60
];
if
(
fread
(
deflate_header
,
1
,
60
,
f
)
!=
60
)
{
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
);
printf
(
"CHUNK %d: deflate patch offset %d
\n
"
,
i
,
patch_offset
);
// 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_filename
,
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
);
size_t
have
=
temp_size
-
strm
.
avail_out
;
if
(
sink
(
temp_data
,
have
,
token
)
!=
have
)
{
printf
(
"failed to write %d compressed bytes to output
\n
"
,
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
;
}
This diff is collapsed.
Click to expand it.
tools/applypatch/main.c
deleted
100644 → 0
View file @
577c5ba9
/*
* 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>
extern
int
applypatch
(
int
argc
,
char
**
argv
);
// 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
)
{
int
result
=
applypatch
(
argc
,
argv
);
if
(
result
==
2
)
{
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
result
;
}
This diff is collapsed.
Click to expand it.
tools/applypatch/testdata/new.file
deleted
100644 → 0
View file @
577c5ba9
File deleted
This diff is collapsed.
Click to expand it.
tools/applypatch/testdata/old.file
deleted
100644 → 0
View file @
577c5ba9
File deleted
This diff is collapsed.
Click to expand it.
tools/applypatch/testdata/patch.bsdiff
deleted
100644 → 0
View file @
577c5ba9
File deleted
This diff is collapsed.
Click to expand it.
tools/applypatch/utils.c
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
(
unsigned
char
*
p
)
{
return
(
int
)(((
unsigned
int
)
p
[
1
]
<<
8
)
|
(
unsigned
int
)
p
[
0
]);
}
int
Read4
(
unsigned
char
*
p
)
{
return
(
int
)(((
unsigned
int
)
p
[
3
]
<<
24
)
|
((
unsigned
int
)
p
[
2
]
<<
16
)
|
((
unsigned
int
)
p
[
1
]
<<
8
)
|
(
unsigned
int
)
p
[
0
]);
}
long
long
Read8
(
unsigned
char
*
p
)
{
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
]);
}
This diff is collapsed.
Click to expand it.
tools/applypatch/utils.h
deleted
100644 → 0
View file @
577c5ba9
/*
* 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
(
unsigned
char
*
p
);
int
Read4
(
unsigned
char
*
p
);
long
long
Read8
(
unsigned
char
*
p
);
#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H
This diff is collapsed.
Click to expand it.
tools/releasetools/edify_generator.py
View file @
b2ee0fd5
...
...
@@ -113,7 +113,7 @@ class EdifyGenerator(object):
def
PatchCheck
(
self
,
filename
,
*
sha1
):
"""Check that the given file (or MTD reference) has one of the
given *sha1 hashes."""
self
.
script
.
append
(
'assert(
apply_patch_check
("%s"'
%
(
filename
,)
+
self
.
script
.
append
(
'assert(
sha1_check(read_file
("%s"
)
'
%
(
filename
,)
+
""
.
join
([
', "%s"'
%
(
i
,)
for
i
in
sha1
])
+
'));'
)
...
...
This diff is collapsed.
Click to expand it.
tools/releasetools/ota_from_target_files
View file @
b2ee0fd5
...
...
@@ -627,7 +627,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
verbatim_targets
.
append
((
tf
.
name
,
tf
.
size
))
else
:
common
.
ZipWriteStr
(
output_zip
,
"patch/"
+
tf
.
name
+
".p"
,
d
)
patch_list
.
append
((
tf
.
name
,
tf
,
sf
,
tf
.
size
))
patch_list
.
append
((
tf
.
name
,
tf
,
sf
,
tf
.
size
,
sha
.
sha
(
d
).
hexdigest
()
))
largest_source_size
=
max
(
largest_source_size
,
sf
.
size
)
source_fp
=
GetBuildProp
(
"ro.build.fingerprint"
,
source_zip
)
...
...
@@ -669,7 +669,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
total_verify_size
+=
source_boot
.
size
so_far
=
0
for
fn
,
tf
,
sf
,
size
in
patch_list
:
for
fn
,
tf
,
sf
,
size
,
patch_sha
in
patch_list
:
script
.
PatchCheck
(
"/"
+
fn
,
tf
.
sha1
,
sf
.
sha1
)
so_far
+=
sf
.
size
script
.
SetProgress
(
so_far
/
total_verify_size
)
...
...
@@ -693,6 +693,9 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
script
.
Print
(
"Unpacking patches..."
)
script
.
UnpackPackageDir
(
"patch"
,
"/tmp/patchtmp"
)
for
fn
,
tf
,
sf
,
size
,
patch_sha
in
patch_list
:
script
.
PatchCheck
(
"/tmp/patchtmp/"
+
tf
.
name
+
".p"
,
patch_sha
)
device_specific
.
IncrementalOTA_VerifyEnd
()
script
.
Comment
(
"---- start making changes here ----"
)
...
...
@@ -714,7 +717,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
so_far
=
0
script
.
Print
(
"Patching system files..."
)
for
fn
,
tf
,
sf
,
size
in
patch_list
:
for
fn
,
tf
,
sf
,
size
,
_
in
patch_list
:
script
.
ApplyPatch
(
"/"
+
fn
,
"-"
,
tf
.
size
,
tf
.
sha1
,
sf
.
sha1
,
"/tmp/patchtmp/"
+
fn
+
".p"
)
so_far
+=
tf
.
size
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment