#!/bin/bash
#
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# This script imports new versions of Bouncy Castle
# (http://bouncycastle.org) into the Android source tree. To run, (1)
# fetch the appropriate tarballs (bcprov and bcpkix) from the Bouncy
# Castle repository, (2) check the checksum, and then (3) run:
# ./import_bouncycastle.sh import bcprov-jdk*-*.tar.gz
#
# IMPORTANT: See README.android for additional details.
# turn on exit on error as well as a warning when it happens
set -e
trap "echo WARNING: Exiting on non-zero subprocess exit code" ERR;
function die() {
declare -r message=$1
echo $message
exit 1
}
function usage() {
declare -r message=$1
if [ ! "$message" = "" ]; then
echo $message
fi
echo "Usage:"
echo " ./import_bouncycastle.sh import </path/to/bcprov-jdk*-*.tar.gz>"
echo " ./import_bouncycastle.sh regenerate <patch/*.patch>"
echo " ./import_bouncycastle.sh generate <patch/*.patch> </path/to/bcprov-jdk*-*.tar.gz>"
exit 1
}
function main() {
if [ ! -d patches ]; then
die "Bouncy Castle patch directory patches/ not found"
fi
if [ ! -f bouncycastle.version ]; then
die "bouncycastle.version not found"
fi
source bouncycastle.version
if [ "$BOUNCYCASTLE_JDK" == "" -o "$BOUNCYCASTLE_VERSION" == "" ]; then
die "Invalid bouncycastle.version; see README.android for more information"
fi
BOUNCYCASTLE_BCPROV_DIR=bcprov-jdk$BOUNCYCASTLE_JDK-$BOUNCYCASTLE_VERSION
BOUNCYCASTLE_BCPROV_DIR_ORIG=$BOUNCYCASTLE_BCPROV_DIR.orig
BOUNCYCASTLE_BCPKIX_DIR=bcpkix-jdk$BOUNCYCASTLE_JDK-$BOUNCYCASTLE_VERSION
BOUNCYCASTLE_BCPKIX_DIR_ORIG=$BOUNCYCASTLE_BCPKIX_DIR.orig
if [ ! -f bouncycastle.config ]; then
die "bouncycastle.config not found"
fi
source bouncycastle.config
if [ "$UNNEEDED_BCPROV_SOURCES" == "" -o "$NEEDED_BCPROV_SOURCES" == "" \
-o "$UNNEEDED_BCPKIX_SOURCES" == "" -o "$NEEDED_BCPKIX_SOURCES" == "" ]; then
die "Invalid bouncycastle.config; see README.android for more information"
fi
declare -r command=$1
shift || usage "No command specified. Try import, regenerate, or generate."
if [ "$command" = "import" ]; then
declare -r bcprov_tar=$1
shift || usage "No tar file specified."
declare -r bcpkix_tar=`echo $bcprov_tar | sed s/bcprov/bcpkix/`
import $bcprov_tar $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG bcprov "$BOUNCYCASTLE_BCPROV_PATCHES" "$NEEDED_BCPROV_SOURCES" "$UNNEEDED_BCPROV_SOURCES"
import $bcpkix_tar $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG bcpkix "$BOUNCYCASTLE_BCPKIX_PATCHES" "$NEEDED_BCPKIX_SOURCES" "$UNNEEDED_BCPKIX_SOURCES"
elif [ "$command" = "regenerate" ]; then
declare -r patch=$1
shift || usage "No patch file specified."
if [[ $BOUNCYCASTLE_BCPROV_PATCHES == *$patch* ]]; then
[ -d $BOUNCYCASTLE_BCPROV_DIR ] || usage "$BOUNCYCASTLE_BCPROV_DIR not found, did you mean to use generate?"
[ -d $BOUNCYCASTLE_BCPROV_DIR_ORIG ] || usage "$BOUNCYCASTLE_BCPROV_DIR_ORIG not found, did you mean to use generate?"
regenerate $patch $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG
elif [[ $BOUNCYCASTLE_BCPKIX_PATCHES == *$patch* ]]; then
[ -d $BOUNCYCASTLE_BCPKIX_DIR ] || usage "$BOUNCYCASTLE_BCPROV_DIR not found, did you mean to use generate?"
[ -d $BOUNCYCASTLE_BCPKIX_DIR_ORIG ] || usage "$BOUNCYCASTLE_BCPKIX_DIR_ORIG not found, did you mean to use generate?"
regenerate $patch $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG
else
usage "Unknown patch file $patch specified"
fi
elif [ "$command" = "generate" ]; then
declare -r patch=$1
shift || usage "No patch file specified."
declare -r bcprov_tar=$1
shift || usage "No tar file specified."
declare -r bcpkix_tar=`echo $bcprov_tar | sed s/bcprov/bcpkix/`
if [[ $BOUNCYCASTLE_BCPROV_PATCHES == *$patch* ]]; then
generate $patch $bcprov_tar $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG bcprov "$BOUNCYCASTLE_BCPROV_PATCHES" "$NEEDED_BCPROV_SOURCES" "$UNNEEDED_BCPROV_SOURCES"
elif [[ $BOUNCYCASTLE_BCPKIX_PATCHES == *$patch* ]]; then
generate $patch $bcpkix_tar $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG bcpkix "$BOUNCYCASTLE_BCPKIX_PATCHES" "$NEEDED_BCPKIX_SOURCES" "$UNNEEDED_BCPKIX_SOURCES"
else
usage "Unknown patch file $patch specified"
fi
else
usage "Unknown command specified $command. Try import, regenerate, or generate."
fi
}
function import() {
declare -r bouncycastle_source=$1
declare -r bouncycastle_dir=$2
declare -r bouncycastle_dir_orig=$3
declare -r bouncycastle_out_dir=$4
declare -r bouncycastle_patches=$5
declare -r needed_sources=$6
declare -r unneeded_sources=$7
untar $bouncycastle_source $bouncycastle_dir $bouncycastle_dir_orig "$unneeded_sources"
applypatches $bouncycastle_dir "$bouncycastle_patches" "$unneeded_sources"
cd $bouncycastle_dir
sed 's/<p>/& <BR>/g' LICENSE.html | html2text -width 102 -nobs -ascii > ../NOTICE
touch ../MODULE_LICENSE_BSD_LIKE
cd ..
rm -r $bouncycastle_out_dir/src
mkdir -p $bouncycastle_out_dir/src/main/java/
for i in $needed_sources; do
echo "Updating $i"
mv $bouncycastle_dir/$i $bouncycastle_out_dir/src/main/java/
done
cleantar $bouncycastle_dir $bouncycastle_dir_orig
}
function regenerate() {
declare -r patch=$1
declare -r bouncycastle_dir=$2
declare -r bouncycastle_dir_orig=$3
generatepatch $patch $bouncycastle_dir $bouncycastle_dir_orig
}
function update_timestamps() {
declare -r git_dir="$1"
declare -r target_dir="$2"
echo -n "Restoring timestamps for ${target_dir}... "
find "$git_dir" -type f -print0 | while IFS= read -r -d $'\0' file; do
file_rev="$(git rev-list -n 1 HEAD "$file")"
if [ "$file_rev" == "" ]; then
echo
echo -n "WARNING: No file revision for file $file..."
continue
fi
file_time="$(git show --pretty=format:%ai --abbrev-commit "$file_rev" | head -n 1)"
touch -d "$file_time" "${target_dir}${file#$git_dir}"
done
echo "done."
}
function generate() {
declare -r patch=$1
declare -r bouncycastle_source=$2
declare -r bouncycastle_dir=$3
declare -r bouncycastle_dir_orig=$4
declare -r bouncycastle_out_dir=$5
declare -r bouncycastle_patches=$6
declare -r needed_sources=$7
declare -r unneeded_sources=$8
untar $bouncycastle_source $bouncycastle_dir $bouncycastle_dir_orig "$unneeded_sources"
applypatches $bouncycastle_dir "$bouncycastle_patches" "$unneeded_sources"
for i in $needed_sources; do
echo "Restoring $i"
rm -r $bouncycastle_dir/$i
cp -rf $bouncycastle_out_dir/src/main/java/$i $bouncycastle_dir/$i
update_timestamps $bouncycastle_out_dir/src/main/java/$i $bouncycastle_dir/$i
done
generatepatch $patch $bouncycastle_dir $bouncycastle_dir_orig
cleantar $bouncycastle_dir $bouncycastle_dir_orig
}
function untar() {
declare -r bouncycastle_source=$1
declare -r bouncycastle_dir=$2
declare -r bouncycastle_dir_orig=$3
declare -r unneeded_sources=$4
# Remove old source
cleantar $bouncycastle_dir $bouncycastle_dir_orig
# Process new source
tar -zxf $bouncycastle_source
mv $bouncycastle_dir $bouncycastle_dir_orig
find $bouncycastle_dir_orig -type f -print0 | xargs -0 chmod a-w
(cd $bouncycastle_dir_orig && unzip -q src.zip)
tar -zxf $bouncycastle_source
(cd $bouncycastle_dir && unzip -q src.zip)
# Prune unnecessary sources
echo "Removing $unneeded_sources"
(cd $bouncycastle_dir_orig && rm -rf $unneeded_sources)
(cd $bouncycastle_dir && rm -r $unneeded_sources)
}
function cleantar() {
declare -r bouncycastle_dir=$1
declare -r bouncycastle_dir_orig=$2
rm -rf $bouncycastle_dir_orig
rm -rf $bouncycastle_dir
}
function applypatches () {
declare -r bouncycastle_dir=$1
declare -r bouncycastle_patches=$2
declare -r unneeded_sources=$3
cd $bouncycastle_dir
# Apply appropriate patches
for i in $bouncycastle_patches; do
echo "Applying patch $i"
patch -p1 --merge < ../$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate $i"
# make sure no unneeded sources got into the patch
problem=0
for s in $unneeded_sources; do
if [ -e $s ]; then
echo Unneeded source $s restored by patch $i
problem=1
fi
done
if [ $problem = 1 ]; then
exit 1
fi
done
# Cleanup patch output
find . -type f -name "*.orig" -print0 | xargs -0 rm -f
cd ..
}
function generatepatch() {
declare -r patch=$1
declare -r bouncycastle_dir=$2
declare -r bouncycastle_dir_orig=$3
# Cleanup stray files before generating patch
find $bouncycastle_dir -type f -name "*.orig" -print0 | xargs -0 rm -f
find $bouncycastle_dir -type f -name "*~" -print0 | xargs -0 rm -f
rm -f $patch
LC_ALL=C TZ=UTC0 diff -Naur $bouncycastle_dir_orig $bouncycastle_dir >> $patch && die "ERROR: No diff for patch $path in file $i"
echo "Generated patch $patch"
}
main $@