diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-02-06 03:54:12 +0100 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-02-06 03:54:42 +0100 |
commit | c1a2a42dab3edf1a01de8d2aedfebfbbc4d03cd9 (patch) | |
tree | 2e90913f33431e75c3853e215534ab313925418b | |
parent | 95234b55312b0f5dd6236b02e2472b4fc5a1a51e (diff) | |
download | msitools-c1a2a42dab3edf1a01de8d2aedfebfbbc4d03cd9.tar.gz msitools-c1a2a42dab3edf1a01de8d2aedfebfbbc4d03cd9.tar.xz msitools-c1a2a42dab3edf1a01de8d2aedfebfbbc4d03cd9.zip |
tools: add msidiff and msidump
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rwxr-xr-x | tools/msidiff.in | 219 | ||||
-rwxr-xr-x | tools/msidump.in | 131 |
5 files changed, 359 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 33279fb..c2137da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,5 @@ NULL = +CLEANFILES = EXTRA_DIST = ACLOCAL_AMFLAGS = -I m4 SUBDIRS = include data libmsi tests po . @@ -21,6 +22,8 @@ AM_CPPFLAGS = -Iinclude -I$(srcdir)/include \ AM_LDFLAGS = -Llibmsi # Low-level tools +bin_SCRIPTS = tools/msidump tools/msidiff +CLEANFILES += $(bin_SCRIPTS) bin_PROGRAMS = msibuild msiinfo @@ -151,7 +154,7 @@ EXTRA_DIST += $(completion_DATA) dist_noinst_DATA = tests/testsuite.at tests/wixl.at tests/package.m4 tests/testsuite DISTCLEANFILES = atconfig atlocal -CLEANFILES = testsuite.log +CLEANFILES += testsuite.log check-local: $(srcdir)/tests/testsuite atconfig atlocal $(SHELL) $(srcdir)/tests/testsuite AUTOTEST_PATH=. $(TESTSUITEFLAGS) @@ -1,4 +1,3 @@ -- write a msidiff tool - document an easy way to hack on wixl, using WiX and msi diff - verify gsf conversion, some tests fail on Windows but not POSIX? - make a SummaryInformation API that does not suck (including converting diff --git a/configure.ac b/configure.ac index 9b42f1d..51a9214 100644 --- a/configure.ac +++ b/configure.ac @@ -59,7 +59,12 @@ AC_CONFIG_FILES([ po/Makefile.in libmsi/Makefile libmsi/libmsi-1.0.pc + tools/msidump + tools/msidiff tests/Makefile +],[ + chmod +x tools/msidump + chmod +x tools/msidiff ]) AC_OUTPUT diff --git a/tools/msidiff.in b/tools/msidiff.in new file mode 100755 index 0000000..b3ef35e --- /dev/null +++ b/tools/msidiff.in @@ -0,0 +1,219 @@ +#!/bin/bash +# -*- coding: utf-8 -*- + +# msidiff - compare two MSI files table content with diff +# (originally based on rpmdev-diff) +# +# Copyright (c) 2004-2010 Ville Skyttä <ville.skytta@iki.fi> +# Copyright (c) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +set -e + +unset CDPATH +tmpdir= +diffopts= +list= +long= +tables= +diffcopts=-Nup +diffoopts=-U0 + +trap cleanup EXIT +cleanup() +{ + set +e + [ -z "$tmpdir" -o ! -d "$tmpdir" ] || rm -rf "$tmpdir" +} + +version() +{ + cat <<EOF +@PACKAGE_VERSION@ +EOF +} + +help() +{ + cat <<EOF +msidiff diffs contents of two MSI files. +EOF + usage + echo "" + echo "Report bugs to <@PACKAGE_BUGREPORT@>." +} + +usage() +{ + cat <<EOF +Usage: msidiff [OPTION]... [DIFF-OPTIONS] FROM-MSI TO-MSI + +Options: + -t, --tables Diff MSI tables as text. This is the default. + -l, --list Diff lists of files. + -L, --long-list Diff long lists (akin to 'find -ls') of files. + -h, --help Print help message and exit. + -v, --version Print version information and exit. + diff-options Options passed to diff(1). The first repeated argument of + the above or the first argument starting with a '-' but not + one of the above starts diff-options, the first one not + starting with it ends them. Default: $diffcopts for contents + (in addition to -r which will always be passed), -U0 for + others. + +More than one of -t, -l or -L may be specified. +EOF +} + +while true ; do + case $1 in + -t|--tables) + if [[ $tables$diffopts ]] ; then + diffopts+=" $1" + else + tables=true + fi + ;; + -l|--list) + if [[ $list$diffopts ]] ; then + diffopts+=" $1" + else + list=true + fi + ;; + -L|--long-list) + if [[ $long$diffopts ]] ; then + diffopts+=" $1" + else + long=true + fi + ;; + -h|--help) + if [[ $diffopts ]] ; then + diffopts+=" $1" + else + help + exit 0 + fi + ;; + -v|--version) + if [[ $diffopts ]] ; then + diffopts+=" $1" + else + version + exit 0 + fi + ;; + -*) + diffopts+=" $1" + ;; + *) + break + ;; + esac + shift +done +if [[ $# -lt 2 ]] ; then + usage + exit 1 +fi +for file in "$1" "$2" ; do + if [[ ! -f $file ]] ; then + [[ -e $file ]] && \ + echo "Error: not a regular file: '$file'" >&2 || + echo "Error: file does not exist: '$file'" >&2 + exit 1 + fi +done + +tmpdir=`mktemp -d ${TMPDIR:-/tmp}/msidiff.XXXXXX` + +mkdir "$tmpdir/old" "$tmpdir/new" +msidump --tables --directory "$tmpdir/old" $1 >/dev/null +msidump --tables --directory "$tmpdir/new" $2 >/dev/null +if ${list:-false} || ${long:-false} ; then + msiextract --directory "$tmpdir/old/files" $1 >/dev/null + msiextract --directory "$tmpdir/new/files" $2 >/dev/null +fi + +cd "$tmpdir" + +# Did the archives uncompress into base dirs? +if [[ $(ls -1d old/* | wc -l) -eq 1 ]] ; then + old=$(ls -1d old/*) +else + old=old +fi +if [[ $(ls -1d new/* | wc -l) -eq 1 ]] ; then + new=$(ls -1d new/*) +else + new=new +fi + +# Fixup base dirs to the same level. +if [[ $(basename "$old") != $(basename "$new") ]] ; then + if [[ $old != old ]] ; then + mv "$old" . + old=`basename "$old"` + fi + if [[ $new != new ]] ; then + mv "$new" . + new=`basename "$new"` + fi +fi + +# Tables mode is the default. +if [[ -z $list$tables$long ]] ; then + tables=true +else + tables=${tables:-false} +fi +list=${list:-false} +long=${long:-false} + +# Here we go. + +if $tables ; then + set +e + diff -r ${diffopts:-$diffcopts} "$old" "$new" + [[ $? -eq 0 || $? -eq 1 ]] || exit $? + set -e +fi + + +if $list ; then + find "$old/files" | sort | cut -d/ -f 3- -s > "$old.files" + find "$new/files" | sort | cut -d/ -f 3- -s > "$new.files" + set +e + diff ${diffopts:-$diffoopts} "$old.files" "$new.files" + [[ $? -eq 0 || $? -eq 1 ]] || exit $? + set -e +fi + +if $long ; then + find "$old/files" -ls | \ + perl -pe "s|^(?:[\d\s]*)(\S+)(?:\s+\d+)(.+)$|\1\2| ; + s|.*\s\Q$old/files\E$|| ; s|(\s)\Q$old/files/\E|\1|" | \ + sort > "$old.files" + find "$new/files" -ls | \ + perl -pe "s|^(?:[\d\s]*)(\S+)(?:\s+\d+)(.+)$|\1\2| ; + s|.*\s\Q$new/files\E$|| ; s|(\s)\Q$new/files/\E|\1|" | \ + sort > "$new.files" + set +e + diff ${diffopts:-$diffoopts} "$old.files" "$new.files" + [[ $? -eq 0 || $? -eq 1 ]] || exit $? + set -e +fi diff --git a/tools/msidump.in b/tools/msidump.in new file mode 100755 index 0000000..c675f02 --- /dev/null +++ b/tools/msidump.in @@ -0,0 +1,131 @@ +#!/bin/bash +# -*- coding: utf-8 -*- + +# msidump - dump raw MSI tables and stream content +# +# Copyright (c) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +set -e + +tables= +streams= +destdir=. + +version() +{ + cat <<EOF +@PACKAGE_VERSION@ +EOF +} + +help() +{ + cat <<EOF +msidump dumps MSI tables as idt text and streams +EOF + usage + echo "" + echo "Report bugs to <@PACKAGE_BUGREPORT@>." +} + +usage() +{ + cat <<EOF +Usage: msidump [OPTION]... MSI-FILE + +Options: + -t, --tables Dump tables. This is the default. + -s, --streams Dump streams + -d, --directory DIR Dump to given directory DIR + -h, --help Print help message and exit. + -v, --version Print version information and exit. + +More than one of -t or -s may be specified. +EOF +} + +while true ; do + case $1 in + -t|--tables) + tables=true + ;; + -s|--streams) + streams=true + ;; + -d|--directory) + destdir=$2 + shift + ;; + -h|--help) + help + exit 0 + ;; + -v|--version) + version + exit 0 + ;; + *) + break + ;; + esac + shift +done +if [[ $# -lt 1 ]] ; then + usage + exit 1 +fi +for file in "$1" ; do + if [[ ! -f $file ]] ; then + [[ -e $file ]] && \ + echo "Error: not a regular file: '$file'" >&2 || + echo "Error: file does not exist: '$file'" >&2 + exit 1 + fi +done + +if [[ ! -d $destdir ]] ; then + echo "Error: directory does not exist: '$destdir'" >&2 + exit 1 +fi + +# Tables mode is the default. +if [[ -z $tables$streams ]] ; then + tables=true +else + tables=${tables:-false} +fi +streams=${streams:-false} + + +# Here we go + +if $tables ; then + TABLES=$(msiinfo tables "$1") + for i in $TABLES; do + echo "Exporting table $i..." + msiinfo export "$1" "$i" > "$destdir/$i.idt" + done +fi + +if $streams ; then + mkdir -p "$destdir/_Streams" + STREAMS=$(msiinfo streams "$1") + for i in $STREAMS; do + echo "Exporting stream $i..." + msiinfo extract "$1" "$i" > "$destdir/_Streams/$i" + done +fi |