Imported Upstream version 3.6.2
Christophe Monniez
13 years ago
10 | 10 | Nicolas (kwizart) |
11 | 11 | Joachim Metz |
12 | 12 | David Collett (PyFlag), for the PyAFF integration |
13 | Phillip Hellewell (AccessData) for port to VC2008 and catching a few bugs. | |
13 | 14 | |
14 | 15 | The AFF Project has received substantial financial support from |
15 | 16 | Basis Technology Corporation. |
21 | 22 | I.D.E.A.L. Technology Corporation |
22 | 23 | Naval Postgraduate School |
23 | 24 | US Department of Defense |
25 | AccessData | |
24 | 26 | |
27 |
1 | 1 | |
2 | 2 | |
3 | 3 | PERFORMANCE IMPROVEMENTS: |
4 | * Cache the results of vstat | |
4 | * afconvert should calculate MD5, SHA256 and SHA1 | |
5 | 5 | * Store TOC sorted and find entries with binary search. |
6 | 6 | (A 1TB TOC has 62,500 pages or 100K segments; with fixed size records that would be 8,000,000, which is not much.) |
7 | 7 | * aff_write_seg() shouldn't be calling af_rewind_seg after every call |
0 | 2010-08-01 Simson Garfinkel <simsong@Silver-Surfer.local> | |
1 | ||
2 | * configure.ac: increased version to 3.6.2 | |
3 | ||
4 | * lib/vnode_afd.cpp (afd_identify_file): added file:// logic to | |
5 | afd_identify_file from aff_identify_file | |
6 | ||
7 | * lib/vnode_split_raw.cpp (split_raw_write_internal2): when | |
8 | storing data in AFM-files the mode set by af_open is only used for | |
9 | the AFM-file, but not for the .000 which contains the raw data. In | |
10 | case of mode 0600 for af_open, the mode for the .000 raw-data | |
11 | file is set to 0644, which enables read-access for everyone. This | |
12 | is a possible security risk on multi-user systems. To correct | |
13 | this, mode in open() is now taken from af->openmode, and not | |
14 | hard-coded to be 0644. | |
15 | ||
16 | ||
17 | 2010-07-29 Simson Garfinkel <simsong@imac2.home> | |
18 | ||
19 | * win32/afflib.mak (LINK_OPTS): updated for AFFLIB3.6 naming scheme | |
20 | ||
21 | * lib/afflib.h: added #ifdef for stdint.h | |
22 | ||
23 | * BUGLIST.txt: removed note about afd encryption not working. | |
24 | ||
25 | 2010-07-20 Simson Garfinkel <simsong@45.sub-75-206-247.myvzw.com> | |
26 | ||
27 | 2010-07-15 Simson Garfinkel <simsong@shorty.local> | |
28 | ||
29 | * lib/vnode_afd.cpp (vnode_afd): removed AF_VNODE_NO_SEALING from vnode_afd->flags. | |
30 | (afd_add_file): ap->num_afs>0 changed to ap->num_afs>1 for copying | |
31 | over the metadata for the second file. | |
32 | ||
33 | 2010-07-10 Simson L. Garfinkel <simsong@imac2.home> | |
34 | ||
35 | * lib/afflib.h (struct af_vnode_info): changed imagesize in | |
36 | af_vnode_info structure from int64_t to uint64_t. | |
37 | ||
38 | 2010-07-10 Simson L. Garfinkel <simsong@imac2.local> | |
39 | ||
40 | * tools/Makefile.am: all commands now begin aff rather than af. | |
41 | ||
42 | * lib/vnode_ewf.cpp (ewf_vstat): removed EWF support from AFF | |
43 | ||
44 | 2010-07-06 Simson L. Garfinkel <simsong@imac2.home> | |
45 | ||
46 | * lib/vnode_aff.cpp (aff_get_seg): fixed assertion in ret. | |
47 | ||
48 | 2010-06-28 Simson Garfinkel <simsong@silver-surfer.home> | |
49 | ||
50 | * configure.ac: increased version number to 3.5.13. | |
51 | ||
52 | * tools/Makefile.am (bin_PROGRAMS): renamed afconvert to | |
53 | affconvert because of name collission with MacOS | |
54 | ||
55 | 2010-06-27 Simson Garfinkel <simsong@silver-surfer.home> | |
56 | ||
57 | * lib/Makefile.am (EXTRA_PROGRAMS): I read on a debian complaint | |
58 | list that "aftest" and "s3" shouldn't be installed, but nobody | |
59 | thought to drop me a note explaining this or telling me how to do | |
60 | it. So after about 15 minutes with the automake manual I moved | |
61 | aftest and s3 from bin_PROGRAMS to EXTRA_PROGRAMS and now they | |
62 | shouldn't get installed. It would be really nice if those Debian | |
63 | folks to send their comments back to package authors. | |
64 | ||
0 | 65 | 2010-04-25 Simson L. Garfinkel <simsong@imac2.local> |
1 | 66 | |
2 | 67 | * configure.ac: version increased to 3.5.12 |
30 | 30 | make distribute_release |
31 | 31 | |
32 | 32 | prerelease: |
33 | @echo Making sure SVN is up to date | |
34 | svn update | |
35 | @echo update PACKAGE_VERSION in win32 directory | |
36 | sed s/PACKAGE_VERSION.\*/PACKAGE_VERSION\ \"$(PACKAGE_VERSION)\"/ win32/affconfig.h > win32/affconfig.h.$$ | |
37 | mv -f win32/affconfig.h.$$ win32/affconfig.h | |
38 | @echo Commit back changes | |
39 | svn commit -m 'make prerelease' | |
33 | 40 | @echo Building and uploading the release... |
34 | 41 | @echo Making release $(RELEASE) |
35 | 42 | @echo |
72 | 79 | tests/encrypted.iso \ |
73 | 80 | tests/encrypted.aff \ |
74 | 81 | win32/Changes.txt \ |
75 | win32/Makefile.am.old \ | |
76 | 82 | win32/README_MSVC++.txt \ |
77 | 83 | win32/affconfig.h \ |
78 | 84 | win32/afflib.mak \ |
262 | 262 | tests/encrypted.iso \ |
263 | 263 | tests/encrypted.aff \ |
264 | 264 | win32/Changes.txt \ |
265 | win32/Makefile.am.old \ | |
266 | 265 | win32/README_MSVC++.txt \ |
267 | 266 | win32/affconfig.h \ |
268 | 267 | win32/afflib.mak \ |
782 | 781 | make distribute_release |
783 | 782 | |
784 | 783 | prerelease: |
784 | @echo Making sure SVN is up to date | |
785 | svn update | |
786 | @echo update PACKAGE_VERSION in win32 directory | |
787 | sed s/PACKAGE_VERSION.\*/PACKAGE_VERSION\ \"$(PACKAGE_VERSION)\"/ win32/affconfig.h > win32/affconfig.h.$$ | |
788 | mv -f win32/affconfig.h.$$ win32/affconfig.h | |
789 | @echo Commit back changes | |
790 | svn commit -m 'make prerelease' | |
785 | 791 | @echo Building and uploading the release... |
786 | 792 | @echo Making release $(RELEASE) |
787 | 793 | @echo |
38 | 38 | |
39 | 39 | % afinfo.exe filename.aff |
40 | 40 | |
41 | ||
42 | 41 | To convert an AFF file into a RAW file, use: |
43 | 42 | |
44 | % afconvert.exe -e raw filename.aff | |
43 | % affconvert.exe -e raw filename.aff | |
45 | 44 | |
46 | 45 | |
47 | 46 | To reliably copy an AFF file from one location to another: |
65 | 64 | |
66 | 65 | |
67 | 66 | |
68 | ||
69 | 67 | Diskprint |
70 | 68 | ================= |
71 | 69 | An exciting feature in AFF 3.5 is the ability to rapidly calculate and |
81 | 79 | |
82 | 80 | % afdiskprint -x myfile.xml myfile.iso |
83 | 81 | |
84 | ||
85 | ||
86 | Bulk Extractor | |
87 | ============== | |
88 | In the ZIP file you will also find bulk_extractor.jar, a port of the | |
89 | bulk_extractor to Java which actually runs 2x faster than the original | |
90 | C version. (Unlike the C version, bulk_extractor.jar can only process | |
91 | raw disk images, not EnCase or AFF files.) | |
92 | ||
93 | To run bulk_extractor, you must have java on your system. Then type: | |
94 | ||
95 | % java -jar bulk_extractor.jar diskimage.raw | |
96 | ||
97 | You will probably want to extract the output to a file: | |
98 | ||
99 | % java -jar bulk_extractor.jar ubnist1.casper-rw.gen3.raw > output.txt | |
100 | ||
101 | The bulk extractor will report all of the email addresses, URLs, | |
102 | domain names, and timestamps on the disk images. The current version | |
103 | can handle a variety of Unicode encodings but it cannot handle | |
104 | compressed regions. | |
105 | 82 | |
106 | 83 | |
107 | 84 | Verifying the AFFLIB Digital Signature |
123 | 123 | /* Define to 1 if you have the `curl' library (-lcurl). */ |
124 | 124 | #undef HAVE_LIBCURL |
125 | 125 | |
126 | /* Define to 1 if you have the `ewf' library (-lewf). */ | |
127 | #undef HAVE_LIBEWF | |
128 | ||
129 | /* Define to 1 if you have the libewf_get_bytes_per_sector function. */ | |
130 | #undef HAVE_LIBEWF_GET_BYTES_PER_SECTOR | |
131 | ||
132 | /* Define to 1 if libewf_get_bytes_per_sector takes value as an argument. */ | |
133 | #undef HAVE_LIBEWF_GET_BYTES_PER_SECTOR_ARGUMENT_VALUE | |
134 | ||
135 | /* Define to 1 if you have the libewf_get_chunk_size function. */ | |
136 | #undef HAVE_LIBEWF_GET_CHUNK_SIZE | |
137 | ||
138 | /* Define to 1 if libewf_get_chunk_size takes value as an argument. */ | |
139 | #undef HAVE_LIBEWF_GET_CHUNK_SIZE_ARGUMENT_VALUE | |
140 | ||
141 | /* Define to 1 if you have the libewf_get_media_size function. */ | |
142 | #undef HAVE_LIBEWF_GET_MEDIA_SIZE | |
143 | ||
144 | /* Define to 1 if libewf_get_media_size takes value as an argument. */ | |
145 | #undef HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE | |
146 | ||
147 | /* Define to 1 if you have the <libewf.h> header file. */ | |
148 | #undef HAVE_LIBEWF_H | |
149 | ||
150 | 126 | /* Define to 1 if you have the `expat' library (-lexpat). */ |
151 | 127 | #undef HAVE_LIBEXPAT |
152 | 128 | |
159 | 135 | /* Define to 1 if you have the `readline' library (-lreadline). */ |
160 | 136 | #undef HAVE_LIBREADLINE |
161 | 137 | |
138 | /* Define to 1 if you have the `regex' library (-lregex). */ | |
139 | #undef HAVE_LIBREGEX | |
140 | ||
162 | 141 | /* Define to 1 if you have the `rt' library (-lrt). */ |
163 | 142 | #undef HAVE_LIBRT |
164 | 143 | |
165 | 144 | /* Define to 1 if you have the `ssl' library (-lssl). */ |
166 | 145 | #undef HAVE_LIBSSL |
167 | ||
168 | /* Define to 1 if you have the `uuid' library (-luuid). */ | |
169 | #undef HAVE_LIBUUID | |
170 | 146 | |
171 | 147 | /* Define to 1 if you have the `z' library (-lz). */ |
172 | 148 | #undef HAVE_LIBZ |
467 | 443 | /* Use FUSE to mount AFF images */ |
468 | 444 | #undef USE_FUSE |
469 | 445 | |
470 | /* Use libewf to read EnCase files */ | |
471 | #undef USE_LIBEWF | |
472 | ||
473 | 446 | /* Use QEMU image drivers */ |
474 | 447 | #undef USE_QEMU |
475 | 448 |
0 | 0 | Name: afflib |
1 | Version: 3.5.12 | |
1 | Version: 3.6.2 | |
2 | 2 | Release: 1 |
3 | 3 | Summary: Library to support the Advanced Forensic Format |
4 | 4 | Group: System Environment/Libraries |
5 | 5 | export PATH=/usr/bin:/usr/sbin:/bin:$PATH |
6 | 6 | touch NEWS README AUTHORS ChangeLog stamp-h |
7 | 7 | aclocal |
8 | libtoolize -f || glibtoolize -f | |
8 | LIBTOOLIZE=glibtoolize | |
9 | if test `which libtoolize`x != "x" ; | |
10 | then LIBTOOLIZE=libtoolize | |
11 | fi | |
12 | $LIBTOOLIZE -f | |
9 | 13 | autoheader -f |
10 | 14 | autoconf -f |
11 | 15 | automake --add-missing -c |
0 | 0 | #!/bin/sh |
1 | # From http://wagner.pp.ru/~vitus/articles/openssl-mingw.html | |
2 | # With modifications | |
3 | # Download openssl and unpack. | |
4 | # Open Configure script with a text editor, find this line: | |
5 | # $IsMK1MF=1 if ($target eq "mingw" && $^O ne "cygwin" && !is_msys()); | |
6 | # and comment it out. | |
7 | # | |
8 | # $ perl Configure mingw | |
9 | # $ make CC=i386-mingw32-gcc RANLIB=i386-mingw32-ranlib | |
10 | 1 | |
11 | export CC=/opt/local/bin/i386-mingw32-gcc | |
12 | export CXX=/opt/local/bin/i386-mingw32-g++ | |
13 | export RANLIB=/opt/local/bin/i386-mingw32-ranlib | |
14 | export MINGWFLAGS="-mwin32 -mconsole -march=pentium4 " | |
15 | export CFLAGS="$MINGWFLAGS" | |
16 | export CXXFLAGS="$MINGWFLAGS" | |
17 | autoreconf -f | |
18 | ./configure CC=$CC CXX=$CXX RANLIB=$RANLIB --target=i586-mingw32msvc --host=i586 | |
19 | make CC=$CC CXX=$CXX RANLIB=$RANLIB CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" | |
2 | # The easiest way to build AFFLIB for Win32 is to ues MinGW as either a cross-compiler | |
3 | # or as a native compiler. In either case you will need to install OpenSSL and optionally | |
4 | # libregex. | |
5 | ||
6 | # This script will compile AFFLIB for Win32 on either Mac or Linux. | |
7 | ||
8 | # To install OpenSSL on On Linux, first download OpenSSL 1.0.0 and then: | |
9 | # ./Configure mingw --prefix=/usr/i586-mingw32msvc/ | |
10 | # sudo make install | |
11 | ||
12 | ||
13 | if test -r /opt/local/bin/i386-mingw32-gcc ; then | |
14 | echo Compiling for mingw on a Mac installed with MacPorts | |
15 | export CC=/opt/local/bin/i386-mingw32-gcc | |
16 | export CXX=/opt/local/bin/i386-mingw32-g++ | |
17 | export RANLIB=/opt/local/bin/i386-mingw32-ranlib | |
18 | export AR=/opt/local/bin/i386-mingw32-ar | |
19 | export PREFIX=/opt/local/i386-mingw32/ | |
20 | export MINGWFLAGS="-mwin32 -mconsole -march=pentium4 " | |
21 | export CFLAGS="$MINGWFLAGS" | |
22 | export CXXFLAGS="$MINGWFLAGS" | |
23 | autoreconf -f | |
24 | ./configure CC=$CC CXX=$CXX RANLIB=$RANLIB --target=i586-mingw32msvc --host=i586 \ | |
25 | --prefix=$PREFIX | |
26 | make CC=$CC CXX=$CXX RANLIB=$RANLIB CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" | |
27 | fi | |
28 | if test -r /usr/i586-mingw32msvc ; then | |
29 | echo Compiling for mingw on Linux | |
30 | export PREFIX=/usr/i586-mingw32msvc | |
31 | export MINGW32PATH=/usr/i586-mingw32msvc | |
32 | export CC=/usr/bin/i586-mingw32msvc-gcc | |
33 | export CXX=/usr/bin/i586-mingw32msvc-g++ | |
34 | export AR=${MINGW32PATH}/bin/ar | |
35 | export RANLIB=${MINGW32PATH}/bin/ranlib | |
36 | export STRIP=${MINGW32PATH}/bin/strip | |
37 | export MINGWFLAGS="-mwin32 -mconsole -march=i586 " | |
38 | export CFLAGS="$MINGWFLAGS" | |
39 | export CXXFLAGS="$MINGWFLAGS" | |
40 | autoreconf -f | |
41 | ./configure CC=$CC CXX=$CXX RANLIB=$RANLIB --target=i586-mingw32msvc --host=i586 \ | |
42 | --enable-winapi=yes --prefix=$PREFIX | |
43 | make CC=$CC CXX=$CXX RANLIB=$RANLIB CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" | |
44 | fi | |
45 | ||
46 | # Make a release of the executables | |
47 | ||
20 | 48 | zip afflib_windows.zip tools/*.exe |
21 | 49 |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.61 for AFFLIB 3.5.12. | |
2 | # Generated by GNU Autoconf 2.61 for AFFLIB 3.6.2. | |
3 | 3 | # |
4 | 4 | # Report bugs to <bugs@afflib.org>. |
5 | 5 | # |
722 | 722 | # Identity of this package. |
723 | 723 | PACKAGE_NAME='AFFLIB' |
724 | 724 | PACKAGE_TARNAME='afflib' |
725 | PACKAGE_VERSION='3.5.12' | |
726 | PACKAGE_STRING='AFFLIB 3.5.12' | |
725 | PACKAGE_VERSION='3.6.2' | |
726 | PACKAGE_STRING='AFFLIB 3.6.2' | |
727 | 727 | PACKAGE_BUGREPORT='bugs@afflib.org' |
728 | 728 | |
729 | 729 | # Factoring default headers for most tests. |
1426 | 1426 | # Omit some internal or obsolete options to make the list less imposing. |
1427 | 1427 | # This message is too long to be a string in the A/UX 3.1 sh. |
1428 | 1428 | cat <<_ACEOF |
1429 | \`configure' configures AFFLIB 3.5.12 to adapt to many kinds of systems. | |
1429 | \`configure' configures AFFLIB 3.6.2 to adapt to many kinds of systems. | |
1430 | 1430 | |
1431 | 1431 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1432 | 1432 | |
1496 | 1496 | |
1497 | 1497 | if test -n "$ac_init_help"; then |
1498 | 1498 | case $ac_init_help in |
1499 | short | recursive ) echo "Configuration of AFFLIB 3.5.12:";; | |
1499 | short | recursive ) echo "Configuration of AFFLIB 3.6.2:";; | |
1500 | 1500 | esac |
1501 | 1501 | cat <<\_ACEOF |
1502 | 1502 | |
1513 | 1513 | optimize for fast installation [default=yes] |
1514 | 1514 | --disable-libtool-lock avoid locking (might break parallel builds) |
1515 | 1515 | --disable-largefile omit support for large files |
1516 | --enable-libewf=yes Use libewf for reading EnCase files(default yes) | |
1517 | 1516 | --enable-s3=yes Support for Amazon's S3 service. Requires CURL and |
1518 | 1517 | Expat. |
1519 | 1518 | |
1615 | 1614 | test -n "$ac_init_help" && exit $ac_status |
1616 | 1615 | if $ac_init_version; then |
1617 | 1616 | cat <<\_ACEOF |
1618 | AFFLIB configure 3.5.12 | |
1617 | AFFLIB configure 3.6.2 | |
1619 | 1618 | generated by GNU Autoconf 2.61 |
1620 | 1619 | |
1621 | 1620 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
1629 | 1628 | This file contains any messages produced by compilers while |
1630 | 1629 | running configure, to aid debugging if configure makes a mistake. |
1631 | 1630 | |
1632 | It was created by AFFLIB $as_me 3.5.12, which was | |
1631 | It was created by AFFLIB $as_me 3.6.2, which was | |
1633 | 1632 | generated by GNU Autoconf 2.61. Invocation command line was |
1634 | 1633 | |
1635 | 1634 | $ $0 $@ |
2319 | 2318 | |
2320 | 2319 | # Define the identity of the package. |
2321 | 2320 | PACKAGE='afflib' |
2322 | VERSION='3.5.12' | |
2321 | VERSION='3.6.2' | |
2323 | 2322 | |
2324 | 2323 | |
2325 | 2324 | cat >>confdefs.h <<_ACEOF |
4517 | 4516 | else |
4518 | 4517 | lt_cv_nm_interface="BSD nm" |
4519 | 4518 | echo "int some_variable = 0;" > conftest.$ac_ext |
4520 | (eval echo "\"\$as_me:4521: $ac_compile\"" >&5) | |
4519 | (eval echo "\"\$as_me:4520: $ac_compile\"" >&5) | |
4521 | 4520 | (eval "$ac_compile" 2>conftest.err) |
4522 | 4521 | cat conftest.err >&5 |
4523 | (eval echo "\"\$as_me:4524: $NM \\\"conftest.$ac_objext\\\"\"" >&5) | |
4522 | (eval echo "\"\$as_me:4523: $NM \\\"conftest.$ac_objext\\\"\"" >&5) | |
4524 | 4523 | (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) |
4525 | 4524 | cat conftest.err >&5 |
4526 | (eval echo "\"\$as_me:4527: output\"" >&5) | |
4525 | (eval echo "\"\$as_me:4526: output\"" >&5) | |
4527 | 4526 | cat conftest.out >&5 |
4528 | 4527 | if $GREP 'External.*some_variable' conftest.out > /dev/null; then |
4529 | 4528 | lt_cv_nm_interface="MS dumpbin" |
5634 | 5633 | ;; |
5635 | 5634 | *-*-irix6*) |
5636 | 5635 | # Find out which ABI we are using. |
5637 | echo '#line 5638 "configure"' > conftest.$ac_ext | |
5636 | echo '#line 5637 "configure"' > conftest.$ac_ext | |
5638 | 5637 | if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 |
5639 | 5638 | (eval $ac_compile) 2>&5 |
5640 | 5639 | ac_status=$? |
7481 | 7480 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
7482 | 7481 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
7483 | 7482 | -e 's:$: $lt_compiler_flag:'` |
7484 | (eval echo "\"\$as_me:7485: $lt_compile\"" >&5) | |
7483 | (eval echo "\"\$as_me:7484: $lt_compile\"" >&5) | |
7485 | 7484 | (eval "$lt_compile" 2>conftest.err) |
7486 | 7485 | ac_status=$? |
7487 | 7486 | cat conftest.err >&5 |
7488 | echo "$as_me:7489: \$? = $ac_status" >&5 | |
7487 | echo "$as_me:7488: \$? = $ac_status" >&5 | |
7489 | 7488 | if (exit $ac_status) && test -s "$ac_outfile"; then |
7490 | 7489 | # The compiler can only warn and ignore the option if not recognized |
7491 | 7490 | # So say no if there are warnings other than the usual output. |
7805 | 7804 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
7806 | 7805 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
7807 | 7806 | -e 's:$: $lt_compiler_flag:'` |
7808 | (eval echo "\"\$as_me:7809: $lt_compile\"" >&5) | |
7807 | (eval echo "\"\$as_me:7808: $lt_compile\"" >&5) | |
7809 | 7808 | (eval "$lt_compile" 2>conftest.err) |
7810 | 7809 | ac_status=$? |
7811 | 7810 | cat conftest.err >&5 |
7812 | echo "$as_me:7813: \$? = $ac_status" >&5 | |
7811 | echo "$as_me:7812: \$? = $ac_status" >&5 | |
7813 | 7812 | if (exit $ac_status) && test -s "$ac_outfile"; then |
7814 | 7813 | # The compiler can only warn and ignore the option if not recognized |
7815 | 7814 | # So say no if there are warnings other than the usual output. |
7910 | 7909 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
7911 | 7910 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
7912 | 7911 | -e 's:$: $lt_compiler_flag:'` |
7913 | (eval echo "\"\$as_me:7914: $lt_compile\"" >&5) | |
7912 | (eval echo "\"\$as_me:7913: $lt_compile\"" >&5) | |
7914 | 7913 | (eval "$lt_compile" 2>out/conftest.err) |
7915 | 7914 | ac_status=$? |
7916 | 7915 | cat out/conftest.err >&5 |
7917 | echo "$as_me:7918: \$? = $ac_status" >&5 | |
7916 | echo "$as_me:7917: \$? = $ac_status" >&5 | |
7918 | 7917 | if (exit $ac_status) && test -s out/conftest2.$ac_objext |
7919 | 7918 | then |
7920 | 7919 | # The compiler can only warn and ignore the option if not recognized |
7965 | 7964 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
7966 | 7965 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
7967 | 7966 | -e 's:$: $lt_compiler_flag:'` |
7968 | (eval echo "\"\$as_me:7969: $lt_compile\"" >&5) | |
7967 | (eval echo "\"\$as_me:7968: $lt_compile\"" >&5) | |
7969 | 7968 | (eval "$lt_compile" 2>out/conftest.err) |
7970 | 7969 | ac_status=$? |
7971 | 7970 | cat out/conftest.err >&5 |
7972 | echo "$as_me:7973: \$? = $ac_status" >&5 | |
7971 | echo "$as_me:7972: \$? = $ac_status" >&5 | |
7973 | 7972 | if (exit $ac_status) && test -s out/conftest2.$ac_objext |
7974 | 7973 | then |
7975 | 7974 | # The compiler can only warn and ignore the option if not recognized |
10713 | 10712 | lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 |
10714 | 10713 | lt_status=$lt_dlunknown |
10715 | 10714 | cat > conftest.$ac_ext <<_LT_EOF |
10716 | #line 10717 "configure" | |
10715 | #line 10716 "configure" | |
10717 | 10716 | #include "confdefs.h" |
10718 | 10717 | |
10719 | 10718 | #if HAVE_DLFCN_H |
10813 | 10812 | lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 |
10814 | 10813 | lt_status=$lt_dlunknown |
10815 | 10814 | cat > conftest.$ac_ext <<_LT_EOF |
10816 | #line 10817 "configure" | |
10815 | #line 10816 "configure" | |
10817 | 10816 | #include "confdefs.h" |
10818 | 10817 | |
10819 | 10818 | #if HAVE_DLFCN_H |
13978 | 13977 | |
13979 | 13978 | |
13980 | 13979 | |
13981 | for ac_header in arpa/inet.h assert.h ctype.h dmalloc.h err.h errno.h fcntl.h getopt.h inttypes.h linux/fs.h malloc.h ncurses/term.h netinet/in.h regex.h signal.h stdio.h stdlib.h string.h sys/cdefs.h sys/disk.h sys/file.h sys/ioctl.h sys/ioctl.h sys/param.h sys/param.h sys/socket.h sys/signal.h sys/stat.h sys/time.h sys/types.h sys/vfs.h sysexits.h term.h time.h unistd.h zlib.h | |
13980 | ||
13981 | for ac_header in arpa/inet.h assert.h ctype.h dmalloc.h err.h errno.h fcntl.h getopt.h inttypes.h linux/fs.h malloc.h ncurses/term.h netinet/in.h regex.h signal.h stdint.h stdio.h stdlib.h string.h sys/cdefs.h sys/disk.h sys/file.h sys/ioctl.h sys/ioctl.h sys/param.h sys/param.h sys/socket.h sys/signal.h sys/stat.h sys/time.h sys/types.h sys/vfs.h sysexits.h term.h time.h unistd.h zlib.h | |
13982 | 13982 | do |
13983 | 13983 | as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` |
13984 | 13984 | if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then |
14122 | 14122 | |
14123 | 14123 | done |
14124 | 14124 | |
14125 | ||
14126 | ||
14127 | { echo "$as_me:$LINENO: checking for regcomp in -lregex" >&5 | |
14128 | echo $ECHO_N "checking for regcomp in -lregex... $ECHO_C" >&6; } | |
14129 | if test "${ac_cv_lib_regex_regcomp+set}" = set; then | |
14130 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
14131 | else | |
14132 | ac_check_lib_save_LIBS=$LIBS | |
14133 | LIBS="-lregex $LIBS" | |
14134 | cat >conftest.$ac_ext <<_ACEOF | |
14135 | /* confdefs.h. */ | |
14136 | _ACEOF | |
14137 | cat confdefs.h >>conftest.$ac_ext | |
14138 | cat >>conftest.$ac_ext <<_ACEOF | |
14139 | /* end confdefs.h. */ | |
14140 | ||
14141 | /* Override any GCC internal prototype to avoid an error. | |
14142 | Use char because int might match the return type of a GCC | |
14143 | builtin and then its argument prototype would still apply. */ | |
14144 | #ifdef __cplusplus | |
14145 | extern "C" | |
14146 | #endif | |
14147 | char regcomp (); | |
14148 | int | |
14149 | main () | |
14150 | { | |
14151 | return regcomp (); | |
14152 | ; | |
14153 | return 0; | |
14154 | } | |
14155 | _ACEOF | |
14156 | rm -f conftest.$ac_objext conftest$ac_exeext | |
14157 | if { (ac_try="$ac_link" | |
14158 | case "(($ac_try" in | |
14159 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
14160 | *) ac_try_echo=$ac_try;; | |
14161 | esac | |
14162 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
14163 | (eval "$ac_link") 2>conftest.er1 | |
14164 | ac_status=$? | |
14165 | grep -v '^ *+' conftest.er1 >conftest.err | |
14166 | rm -f conftest.er1 | |
14167 | cat conftest.err >&5 | |
14168 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
14169 | (exit $ac_status); } && { | |
14170 | test -z "$ac_c_werror_flag" || | |
14171 | test ! -s conftest.err | |
14172 | } && test -s conftest$ac_exeext && | |
14173 | $as_test_x conftest$ac_exeext; then | |
14174 | ac_cv_lib_regex_regcomp=yes | |
14175 | else | |
14176 | echo "$as_me: failed program was:" >&5 | |
14177 | sed 's/^/| /' conftest.$ac_ext >&5 | |
14178 | ||
14179 | ac_cv_lib_regex_regcomp=no | |
14180 | fi | |
14181 | ||
14182 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
14183 | conftest$ac_exeext conftest.$ac_ext | |
14184 | LIBS=$ac_check_lib_save_LIBS | |
14185 | fi | |
14186 | { echo "$as_me:$LINENO: result: $ac_cv_lib_regex_regcomp" >&5 | |
14187 | echo "${ECHO_T}$ac_cv_lib_regex_regcomp" >&6; } | |
14188 | if test $ac_cv_lib_regex_regcomp = yes; then | |
14189 | cat >>confdefs.h <<_ACEOF | |
14190 | #define HAVE_LIBREGEX 1 | |
14191 | _ACEOF | |
14192 | ||
14193 | LIBS="-lregex $LIBS" | |
14194 | ||
14195 | fi | |
14196 | # see if we need -lregex | |
14125 | 14197 | |
14126 | 14198 | { echo "$as_me:$LINENO: checking for struct sockaddr_in.sin_len" >&5 |
14127 | 14199 | echo $ECHO_N "checking for struct sockaddr_in.sin_len... $ECHO_C" >&6; } |
17339 | 17411 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
17340 | 17412 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
17341 | 17413 | -e 's:$: $lt_compiler_flag:'` |
17342 | (eval echo "\"\$as_me:17343: $lt_compile\"" >&5) | |
17414 | (eval echo "\"\$as_me:17415: $lt_compile\"" >&5) | |
17343 | 17415 | (eval "$lt_compile" 2>conftest.err) |
17344 | 17416 | ac_status=$? |
17345 | 17417 | cat conftest.err >&5 |
17346 | echo "$as_me:17347: \$? = $ac_status" >&5 | |
17418 | echo "$as_me:17419: \$? = $ac_status" >&5 | |
17347 | 17419 | if (exit $ac_status) && test -s "$ac_outfile"; then |
17348 | 17420 | # The compiler can only warn and ignore the option if not recognized |
17349 | 17421 | # So say no if there are warnings other than the usual output. |
17438 | 17510 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
17439 | 17511 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
17440 | 17512 | -e 's:$: $lt_compiler_flag:'` |
17441 | (eval echo "\"\$as_me:17442: $lt_compile\"" >&5) | |
17513 | (eval echo "\"\$as_me:17514: $lt_compile\"" >&5) | |
17442 | 17514 | (eval "$lt_compile" 2>out/conftest.err) |
17443 | 17515 | ac_status=$? |
17444 | 17516 | cat out/conftest.err >&5 |
17445 | echo "$as_me:17446: \$? = $ac_status" >&5 | |
17517 | echo "$as_me:17518: \$? = $ac_status" >&5 | |
17446 | 17518 | if (exit $ac_status) && test -s out/conftest2.$ac_objext |
17447 | 17519 | then |
17448 | 17520 | # The compiler can only warn and ignore the option if not recognized |
17490 | 17562 | -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ |
17491 | 17563 | -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ |
17492 | 17564 | -e 's:$: $lt_compiler_flag:'` |
17493 | (eval echo "\"\$as_me:17494: $lt_compile\"" >&5) | |
17565 | (eval echo "\"\$as_me:17566: $lt_compile\"" >&5) | |
17494 | 17566 | (eval "$lt_compile" 2>out/conftest.err) |
17495 | 17567 | ac_status=$? |
17496 | 17568 | cat out/conftest.err >&5 |
17497 | echo "$as_me:17498: \$? = $ac_status" >&5 | |
17569 | echo "$as_me:17570: \$? = $ac_status" >&5 | |
17498 | 17570 | if (exit $ac_status) && test -s out/conftest2.$ac_objext |
17499 | 17571 | then |
17500 | 17572 | # The compiler can only warn and ignore the option if not recognized |
18608 | 18680 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' |
18609 | 18681 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' |
18610 | 18682 | ac_compiler_gnu=$ac_cv_c_compiler_gnu |
18611 | ||
18612 | ||
18613 | ||
18614 | ||
18615 | ################################################################ | |
18616 | ## LIBEWF support | |
18617 | ||
18618 | ||
18619 | ||
18620 | ||
18621 | ||
18622 | ||
18623 | ||
18624 | # Check whether --enable-libewf was given. | |
18625 | if test "${enable_libewf+set}" = set; then | |
18626 | enableval=$enable_libewf; enable_libewf=$enableval | |
18627 | else | |
18628 | enable_libewf=yes | |
18629 | fi | |
18630 | ||
18631 | ||
18632 | if test "${enable_libewf}" = "yes" ; then | |
18633 | ||
18634 | for ac_header in libewf.h | |
18635 | do | |
18636 | as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` | |
18637 | if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then | |
18638 | { echo "$as_me:$LINENO: checking for $ac_header" >&5 | |
18639 | echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } | |
18640 | if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then | |
18641 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
18642 | fi | |
18643 | ac_res=`eval echo '${'$as_ac_Header'}'` | |
18644 | { echo "$as_me:$LINENO: result: $ac_res" >&5 | |
18645 | echo "${ECHO_T}$ac_res" >&6; } | |
18646 | else | |
18647 | # Is the header compilable? | |
18648 | { echo "$as_me:$LINENO: checking $ac_header usability" >&5 | |
18649 | echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } | |
18650 | cat >conftest.$ac_ext <<_ACEOF | |
18651 | /* confdefs.h. */ | |
18652 | _ACEOF | |
18653 | cat confdefs.h >>conftest.$ac_ext | |
18654 | cat >>conftest.$ac_ext <<_ACEOF | |
18655 | /* end confdefs.h. */ | |
18656 | $ac_includes_default | |
18657 | #include <$ac_header> | |
18658 | _ACEOF | |
18659 | rm -f conftest.$ac_objext | |
18660 | if { (ac_try="$ac_compile" | |
18661 | case "(($ac_try" in | |
18662 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
18663 | *) ac_try_echo=$ac_try;; | |
18664 | esac | |
18665 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
18666 | (eval "$ac_compile") 2>conftest.er1 | |
18667 | ac_status=$? | |
18668 | grep -v '^ *+' conftest.er1 >conftest.err | |
18669 | rm -f conftest.er1 | |
18670 | cat conftest.err >&5 | |
18671 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
18672 | (exit $ac_status); } && { | |
18673 | test -z "$ac_c_werror_flag" || | |
18674 | test ! -s conftest.err | |
18675 | } && test -s conftest.$ac_objext; then | |
18676 | ac_header_compiler=yes | |
18677 | else | |
18678 | echo "$as_me: failed program was:" >&5 | |
18679 | sed 's/^/| /' conftest.$ac_ext >&5 | |
18680 | ||
18681 | ac_header_compiler=no | |
18682 | fi | |
18683 | ||
18684 | rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | |
18685 | { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 | |
18686 | echo "${ECHO_T}$ac_header_compiler" >&6; } | |
18687 | ||
18688 | # Is the header present? | |
18689 | { echo "$as_me:$LINENO: checking $ac_header presence" >&5 | |
18690 | echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } | |
18691 | cat >conftest.$ac_ext <<_ACEOF | |
18692 | /* confdefs.h. */ | |
18693 | _ACEOF | |
18694 | cat confdefs.h >>conftest.$ac_ext | |
18695 | cat >>conftest.$ac_ext <<_ACEOF | |
18696 | /* end confdefs.h. */ | |
18697 | #include <$ac_header> | |
18698 | _ACEOF | |
18699 | if { (ac_try="$ac_cpp conftest.$ac_ext" | |
18700 | case "(($ac_try" in | |
18701 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
18702 | *) ac_try_echo=$ac_try;; | |
18703 | esac | |
18704 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
18705 | (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 | |
18706 | ac_status=$? | |
18707 | grep -v '^ *+' conftest.er1 >conftest.err | |
18708 | rm -f conftest.er1 | |
18709 | cat conftest.err >&5 | |
18710 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
18711 | (exit $ac_status); } >/dev/null && { | |
18712 | test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || | |
18713 | test ! -s conftest.err | |
18714 | }; then | |
18715 | ac_header_preproc=yes | |
18716 | else | |
18717 | echo "$as_me: failed program was:" >&5 | |
18718 | sed 's/^/| /' conftest.$ac_ext >&5 | |
18719 | ||
18720 | ac_header_preproc=no | |
18721 | fi | |
18722 | ||
18723 | rm -f conftest.err conftest.$ac_ext | |
18724 | { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 | |
18725 | echo "${ECHO_T}$ac_header_preproc" >&6; } | |
18726 | ||
18727 | # So? What about this header? | |
18728 | case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in | |
18729 | yes:no: ) | |
18730 | { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 | |
18731 | echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} | |
18732 | { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 | |
18733 | echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} | |
18734 | ac_header_preproc=yes | |
18735 | ;; | |
18736 | no:yes:* ) | |
18737 | { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 | |
18738 | echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} | |
18739 | { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 | |
18740 | echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} | |
18741 | { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 | |
18742 | echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} | |
18743 | { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 | |
18744 | echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} | |
18745 | { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 | |
18746 | echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} | |
18747 | { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 | |
18748 | echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} | |
18749 | ( cat <<\_ASBOX | |
18750 | ## ------------------------------ ## | |
18751 | ## Report this to bugs@afflib.org ## | |
18752 | ## ------------------------------ ## | |
18753 | _ASBOX | |
18754 | ) | sed "s/^/$as_me: WARNING: /" >&2 | |
18755 | ;; | |
18756 | esac | |
18757 | { echo "$as_me:$LINENO: checking for $ac_header" >&5 | |
18758 | echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } | |
18759 | if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then | |
18760 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
18761 | else | |
18762 | eval "$as_ac_Header=\$ac_header_preproc" | |
18763 | fi | |
18764 | ac_res=`eval echo '${'$as_ac_Header'}'` | |
18765 | { echo "$as_me:$LINENO: result: $ac_res" >&5 | |
18766 | echo "${ECHO_T}$ac_res" >&6; } | |
18767 | ||
18768 | fi | |
18769 | if test `eval echo '${'$as_ac_Header'}'` = yes; then | |
18770 | cat >>confdefs.h <<_ACEOF | |
18771 | #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 | |
18772 | _ACEOF | |
18773 | ||
18774 | else | |
18775 | enable_libewf=no | |
18776 | fi | |
18777 | ||
18778 | done | |
18779 | ||
18780 | fi | |
18781 | ||
18782 | if test "${enable_libewf}" = "yes" ; then | |
18783 | { echo "$as_me:$LINENO: On linux, libewf has a dependency which forces linking with -luuid" >&5 | |
18784 | echo "$as_me: On linux, libewf has a dependency which forces linking with -luuid" >&6;} | |
18785 | { echo "$as_me:$LINENO: so if we are running on linux and that version of libewf is installed," >&5 | |
18786 | echo "$as_me: so if we are running on linux and that version of libewf is installed," >&6;} | |
18787 | { echo "$as_me:$LINENO: make sure the libuuid is installed" >&5 | |
18788 | echo "$as_me: make sure the libuuid is installed" >&6;} | |
18789 | ||
18790 | if test -r /usr/lib/libewf.la ; then | |
18791 | if grep luuid /usr/lib/libewf.la ; then | |
18792 | { echo "$as_me:$LINENO: Installed libewf requires libuuid." >&5 | |
18793 | echo "$as_me: Installed libewf requires libuuid." >&6;} | |
18794 | ||
18795 | { echo "$as_me:$LINENO: checking for uuid_generate_random in -luuid" >&5 | |
18796 | echo $ECHO_N "checking for uuid_generate_random in -luuid... $ECHO_C" >&6; } | |
18797 | if test "${ac_cv_lib_uuid_uuid_generate_random+set}" = set; then | |
18798 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
18799 | else | |
18800 | ac_check_lib_save_LIBS=$LIBS | |
18801 | LIBS="-luuid $LIBS" | |
18802 | cat >conftest.$ac_ext <<_ACEOF | |
18803 | /* confdefs.h. */ | |
18804 | _ACEOF | |
18805 | cat confdefs.h >>conftest.$ac_ext | |
18806 | cat >>conftest.$ac_ext <<_ACEOF | |
18807 | /* end confdefs.h. */ | |
18808 | ||
18809 | /* Override any GCC internal prototype to avoid an error. | |
18810 | Use char because int might match the return type of a GCC | |
18811 | builtin and then its argument prototype would still apply. */ | |
18812 | #ifdef __cplusplus | |
18813 | extern "C" | |
18814 | #endif | |
18815 | char uuid_generate_random (); | |
18816 | int | |
18817 | main () | |
18818 | { | |
18819 | return uuid_generate_random (); | |
18820 | ; | |
18821 | return 0; | |
18822 | } | |
18823 | _ACEOF | |
18824 | rm -f conftest.$ac_objext conftest$ac_exeext | |
18825 | if { (ac_try="$ac_link" | |
18826 | case "(($ac_try" in | |
18827 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
18828 | *) ac_try_echo=$ac_try;; | |
18829 | esac | |
18830 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
18831 | (eval "$ac_link") 2>conftest.er1 | |
18832 | ac_status=$? | |
18833 | grep -v '^ *+' conftest.er1 >conftest.err | |
18834 | rm -f conftest.er1 | |
18835 | cat conftest.err >&5 | |
18836 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
18837 | (exit $ac_status); } && { | |
18838 | test -z "$ac_c_werror_flag" || | |
18839 | test ! -s conftest.err | |
18840 | } && test -s conftest$ac_exeext && | |
18841 | $as_test_x conftest$ac_exeext; then | |
18842 | ac_cv_lib_uuid_uuid_generate_random=yes | |
18843 | else | |
18844 | echo "$as_me: failed program was:" >&5 | |
18845 | sed 's/^/| /' conftest.$ac_ext >&5 | |
18846 | ||
18847 | ac_cv_lib_uuid_uuid_generate_random=no | |
18848 | fi | |
18849 | ||
18850 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
18851 | conftest$ac_exeext conftest.$ac_ext | |
18852 | LIBS=$ac_check_lib_save_LIBS | |
18853 | fi | |
18854 | { echo "$as_me:$LINENO: result: $ac_cv_lib_uuid_uuid_generate_random" >&5 | |
18855 | echo "${ECHO_T}$ac_cv_lib_uuid_uuid_generate_random" >&6; } | |
18856 | if test $ac_cv_lib_uuid_uuid_generate_random = yes; then | |
18857 | cat >>confdefs.h <<_ACEOF | |
18858 | #define HAVE_LIBUUID 1 | |
18859 | _ACEOF | |
18860 | ||
18861 | LIBS="-luuid $LIBS" | |
18862 | ||
18863 | else | |
18864 | enable_libewf=no | |
18865 | fi | |
18866 | ||
18867 | fi | |
18868 | fi | |
18869 | fi | |
18870 | ||
18871 | if test "${enable_libewf}" = "yes" ; then | |
18872 | ||
18873 | { echo "$as_me:$LINENO: checking for libewf_get_version in -lewf" >&5 | |
18874 | echo $ECHO_N "checking for libewf_get_version in -lewf... $ECHO_C" >&6; } | |
18875 | if test "${ac_cv_lib_ewf_libewf_get_version+set}" = set; then | |
18876 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
18877 | else | |
18878 | ac_check_lib_save_LIBS=$LIBS | |
18879 | LIBS="-lewf $LIBS" | |
18880 | cat >conftest.$ac_ext <<_ACEOF | |
18881 | /* confdefs.h. */ | |
18882 | _ACEOF | |
18883 | cat confdefs.h >>conftest.$ac_ext | |
18884 | cat >>conftest.$ac_ext <<_ACEOF | |
18885 | /* end confdefs.h. */ | |
18886 | ||
18887 | /* Override any GCC internal prototype to avoid an error. | |
18888 | Use char because int might match the return type of a GCC | |
18889 | builtin and then its argument prototype would still apply. */ | |
18890 | #ifdef __cplusplus | |
18891 | extern "C" | |
18892 | #endif | |
18893 | char libewf_get_version (); | |
18894 | int | |
18895 | main () | |
18896 | { | |
18897 | return libewf_get_version (); | |
18898 | ; | |
18899 | return 0; | |
18900 | } | |
18901 | _ACEOF | |
18902 | rm -f conftest.$ac_objext conftest$ac_exeext | |
18903 | if { (ac_try="$ac_link" | |
18904 | case "(($ac_try" in | |
18905 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
18906 | *) ac_try_echo=$ac_try;; | |
18907 | esac | |
18908 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
18909 | (eval "$ac_link") 2>conftest.er1 | |
18910 | ac_status=$? | |
18911 | grep -v '^ *+' conftest.er1 >conftest.err | |
18912 | rm -f conftest.er1 | |
18913 | cat conftest.err >&5 | |
18914 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
18915 | (exit $ac_status); } && { | |
18916 | test -z "$ac_c_werror_flag" || | |
18917 | test ! -s conftest.err | |
18918 | } && test -s conftest$ac_exeext && | |
18919 | $as_test_x conftest$ac_exeext; then | |
18920 | ac_cv_lib_ewf_libewf_get_version=yes | |
18921 | else | |
18922 | echo "$as_me: failed program was:" >&5 | |
18923 | sed 's/^/| /' conftest.$ac_ext >&5 | |
18924 | ||
18925 | ac_cv_lib_ewf_libewf_get_version=no | |
18926 | fi | |
18927 | ||
18928 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
18929 | conftest$ac_exeext conftest.$ac_ext | |
18930 | LIBS=$ac_check_lib_save_LIBS | |
18931 | fi | |
18932 | { echo "$as_me:$LINENO: result: $ac_cv_lib_ewf_libewf_get_version" >&5 | |
18933 | echo "${ECHO_T}$ac_cv_lib_ewf_libewf_get_version" >&6; } | |
18934 | if test $ac_cv_lib_ewf_libewf_get_version = yes; then | |
18935 | cat >>confdefs.h <<_ACEOF | |
18936 | #define HAVE_LIBEWF 1 | |
18937 | _ACEOF | |
18938 | ||
18939 | LIBS="-lewf $LIBS" | |
18940 | ||
18941 | else | |
18942 | enable_libewf=no | |
18943 | fi | |
18944 | ||
18945 | fi | |
18946 | ||
18947 | if test "${enable_libewf}" = "yes" ; then | |
18948 | { echo "$as_me:$LINENO: checking for libewf_get_media_size" >&5 | |
18949 | echo $ECHO_N "checking for libewf_get_media_size... $ECHO_C" >&6; } | |
18950 | if test "${ac_cv_func_libewf_get_media_size+set}" = set; then | |
18951 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
18952 | else | |
18953 | cat >conftest.$ac_ext <<_ACEOF | |
18954 | /* confdefs.h. */ | |
18955 | _ACEOF | |
18956 | cat confdefs.h >>conftest.$ac_ext | |
18957 | cat >>conftest.$ac_ext <<_ACEOF | |
18958 | /* end confdefs.h. */ | |
18959 | /* Define libewf_get_media_size to an innocuous variant, in case <limits.h> declares libewf_get_media_size. | |
18960 | For example, HP-UX 11i <limits.h> declares gettimeofday. */ | |
18961 | #define libewf_get_media_size innocuous_libewf_get_media_size | |
18962 | ||
18963 | /* System header to define __stub macros and hopefully few prototypes, | |
18964 | which can conflict with char libewf_get_media_size (); below. | |
18965 | Prefer <limits.h> to <assert.h> if __STDC__ is defined, since | |
18966 | <limits.h> exists even on freestanding compilers. */ | |
18967 | ||
18968 | #ifdef __STDC__ | |
18969 | # include <limits.h> | |
18970 | #else | |
18971 | # include <assert.h> | |
18972 | #endif | |
18973 | ||
18974 | #undef libewf_get_media_size | |
18975 | ||
18976 | /* Override any GCC internal prototype to avoid an error. | |
18977 | Use char because int might match the return type of a GCC | |
18978 | builtin and then its argument prototype would still apply. */ | |
18979 | #ifdef __cplusplus | |
18980 | extern "C" | |
18981 | #endif | |
18982 | char libewf_get_media_size (); | |
18983 | /* The GNU C library defines this for functions which it implements | |
18984 | to always fail with ENOSYS. Some functions are actually named | |
18985 | something starting with __ and the normal name is an alias. */ | |
18986 | #if defined __stub_libewf_get_media_size || defined __stub___libewf_get_media_size | |
18987 | choke me | |
18988 | #endif | |
18989 | ||
18990 | int | |
18991 | main () | |
18992 | { | |
18993 | return libewf_get_media_size (); | |
18994 | ; | |
18995 | return 0; | |
18996 | } | |
18997 | _ACEOF | |
18998 | rm -f conftest.$ac_objext conftest$ac_exeext | |
18999 | if { (ac_try="$ac_link" | |
19000 | case "(($ac_try" in | |
19001 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19002 | *) ac_try_echo=$ac_try;; | |
19003 | esac | |
19004 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19005 | (eval "$ac_link") 2>conftest.er1 | |
19006 | ac_status=$? | |
19007 | grep -v '^ *+' conftest.er1 >conftest.err | |
19008 | rm -f conftest.er1 | |
19009 | cat conftest.err >&5 | |
19010 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19011 | (exit $ac_status); } && { | |
19012 | test -z "$ac_c_werror_flag" || | |
19013 | test ! -s conftest.err | |
19014 | } && test -s conftest$ac_exeext && | |
19015 | $as_test_x conftest$ac_exeext; then | |
19016 | ac_cv_func_libewf_get_media_size=yes | |
19017 | else | |
19018 | echo "$as_me: failed program was:" >&5 | |
19019 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19020 | ||
19021 | ac_cv_func_libewf_get_media_size=no | |
19022 | fi | |
19023 | ||
19024 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19025 | conftest$ac_exeext conftest.$ac_ext | |
19026 | fi | |
19027 | { echo "$as_me:$LINENO: result: $ac_cv_func_libewf_get_media_size" >&5 | |
19028 | echo "${ECHO_T}$ac_cv_func_libewf_get_media_size" >&6; } | |
19029 | if test $ac_cv_func_libewf_get_media_size = yes; then | |
19030 | ||
19031 | cat >>confdefs.h <<\_ACEOF | |
19032 | #define HAVE_LIBEWF_GET_MEDIA_SIZE 1 | |
19033 | _ACEOF | |
19034 | ||
19035 | ac_ext=c | |
19036 | ac_cpp='$CPP $CPPFLAGS' | |
19037 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19038 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19039 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19040 | ||
19041 | { echo "$as_me:$LINENO: checking if libewf_get_media_size takes size as an argument." >&5 | |
19042 | echo $ECHO_N "checking if libewf_get_media_size takes size as an argument.... $ECHO_C" >&6; } | |
19043 | cat >conftest.$ac_ext <<_ACEOF | |
19044 | /* confdefs.h. */ | |
19045 | _ACEOF | |
19046 | cat confdefs.h >>conftest.$ac_ext | |
19047 | cat >>conftest.$ac_ext <<_ACEOF | |
19048 | /* end confdefs.h. */ | |
19049 | #include <libewf.h> | |
19050 | int | |
19051 | main () | |
19052 | { | |
19053 | libewf_get_media_size(NULL,NULL); | |
19054 | ; | |
19055 | return 0; | |
19056 | } | |
19057 | _ACEOF | |
19058 | rm -f conftest.$ac_objext conftest$ac_exeext | |
19059 | if { (ac_try="$ac_link" | |
19060 | case "(($ac_try" in | |
19061 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19062 | *) ac_try_echo=$ac_try;; | |
19063 | esac | |
19064 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19065 | (eval "$ac_link") 2>conftest.er1 | |
19066 | ac_status=$? | |
19067 | grep -v '^ *+' conftest.er1 >conftest.err | |
19068 | rm -f conftest.er1 | |
19069 | cat conftest.err >&5 | |
19070 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19071 | (exit $ac_status); } && { | |
19072 | test -z "$ac_c_werror_flag" || | |
19073 | test ! -s conftest.err | |
19074 | } && test -s conftest$ac_exeext && | |
19075 | $as_test_x conftest$ac_exeext; then | |
19076 | { echo "$as_me:$LINENO: result: yes" >&5 | |
19077 | echo "${ECHO_T}yes" >&6; } | |
19078 | ||
19079 | cat >>confdefs.h <<\_ACEOF | |
19080 | #define HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE 1 | |
19081 | _ACEOF | |
19082 | ||
19083 | else | |
19084 | echo "$as_me: failed program was:" >&5 | |
19085 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19086 | ||
19087 | { echo "$as_me:$LINENO: result: no" >&5 | |
19088 | echo "${ECHO_T}no" >&6; } | |
19089 | fi | |
19090 | ||
19091 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19092 | conftest$ac_exeext conftest.$ac_ext | |
19093 | ac_ext=c | |
19094 | ac_cpp='$CPP $CPPFLAGS' | |
19095 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19096 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19097 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19098 | ||
19099 | fi | |
19100 | ||
19101 | ||
19102 | { echo "$as_me:$LINENO: checking for libewf_get_chunk_size" >&5 | |
19103 | echo $ECHO_N "checking for libewf_get_chunk_size... $ECHO_C" >&6; } | |
19104 | if test "${ac_cv_func_libewf_get_chunk_size+set}" = set; then | |
19105 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
19106 | else | |
19107 | cat >conftest.$ac_ext <<_ACEOF | |
19108 | /* confdefs.h. */ | |
19109 | _ACEOF | |
19110 | cat confdefs.h >>conftest.$ac_ext | |
19111 | cat >>conftest.$ac_ext <<_ACEOF | |
19112 | /* end confdefs.h. */ | |
19113 | /* Define libewf_get_chunk_size to an innocuous variant, in case <limits.h> declares libewf_get_chunk_size. | |
19114 | For example, HP-UX 11i <limits.h> declares gettimeofday. */ | |
19115 | #define libewf_get_chunk_size innocuous_libewf_get_chunk_size | |
19116 | ||
19117 | /* System header to define __stub macros and hopefully few prototypes, | |
19118 | which can conflict with char libewf_get_chunk_size (); below. | |
19119 | Prefer <limits.h> to <assert.h> if __STDC__ is defined, since | |
19120 | <limits.h> exists even on freestanding compilers. */ | |
19121 | ||
19122 | #ifdef __STDC__ | |
19123 | # include <limits.h> | |
19124 | #else | |
19125 | # include <assert.h> | |
19126 | #endif | |
19127 | ||
19128 | #undef libewf_get_chunk_size | |
19129 | ||
19130 | /* Override any GCC internal prototype to avoid an error. | |
19131 | Use char because int might match the return type of a GCC | |
19132 | builtin and then its argument prototype would still apply. */ | |
19133 | #ifdef __cplusplus | |
19134 | extern "C" | |
19135 | #endif | |
19136 | char libewf_get_chunk_size (); | |
19137 | /* The GNU C library defines this for functions which it implements | |
19138 | to always fail with ENOSYS. Some functions are actually named | |
19139 | something starting with __ and the normal name is an alias. */ | |
19140 | #if defined __stub_libewf_get_chunk_size || defined __stub___libewf_get_chunk_size | |
19141 | choke me | |
19142 | #endif | |
19143 | ||
19144 | int | |
19145 | main () | |
19146 | { | |
19147 | return libewf_get_chunk_size (); | |
19148 | ; | |
19149 | return 0; | |
19150 | } | |
19151 | _ACEOF | |
19152 | rm -f conftest.$ac_objext conftest$ac_exeext | |
19153 | if { (ac_try="$ac_link" | |
19154 | case "(($ac_try" in | |
19155 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19156 | *) ac_try_echo=$ac_try;; | |
19157 | esac | |
19158 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19159 | (eval "$ac_link") 2>conftest.er1 | |
19160 | ac_status=$? | |
19161 | grep -v '^ *+' conftest.er1 >conftest.err | |
19162 | rm -f conftest.er1 | |
19163 | cat conftest.err >&5 | |
19164 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19165 | (exit $ac_status); } && { | |
19166 | test -z "$ac_c_werror_flag" || | |
19167 | test ! -s conftest.err | |
19168 | } && test -s conftest$ac_exeext && | |
19169 | $as_test_x conftest$ac_exeext; then | |
19170 | ac_cv_func_libewf_get_chunk_size=yes | |
19171 | else | |
19172 | echo "$as_me: failed program was:" >&5 | |
19173 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19174 | ||
19175 | ac_cv_func_libewf_get_chunk_size=no | |
19176 | fi | |
19177 | ||
19178 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19179 | conftest$ac_exeext conftest.$ac_ext | |
19180 | fi | |
19181 | { echo "$as_me:$LINENO: result: $ac_cv_func_libewf_get_chunk_size" >&5 | |
19182 | echo "${ECHO_T}$ac_cv_func_libewf_get_chunk_size" >&6; } | |
19183 | if test $ac_cv_func_libewf_get_chunk_size = yes; then | |
19184 | ||
19185 | cat >>confdefs.h <<\_ACEOF | |
19186 | #define HAVE_LIBEWF_GET_CHUNK_SIZE 1 | |
19187 | _ACEOF | |
19188 | ||
19189 | ac_ext=c | |
19190 | ac_cpp='$CPP $CPPFLAGS' | |
19191 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19192 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19193 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19194 | ||
19195 | { echo "$as_me:$LINENO: checking if libewf_get_chunk_size takes size as an argument." >&5 | |
19196 | echo $ECHO_N "checking if libewf_get_chunk_size takes size as an argument.... $ECHO_C" >&6; } | |
19197 | cat >conftest.$ac_ext <<_ACEOF | |
19198 | /* confdefs.h. */ | |
19199 | _ACEOF | |
19200 | cat confdefs.h >>conftest.$ac_ext | |
19201 | cat >>conftest.$ac_ext <<_ACEOF | |
19202 | /* end confdefs.h. */ | |
19203 | #include <libewf.h> | |
19204 | int | |
19205 | main () | |
19206 | { | |
19207 | libewf_get_chunk_size(NULL,NULL); | |
19208 | ; | |
19209 | return 0; | |
19210 | } | |
19211 | _ACEOF | |
19212 | rm -f conftest.$ac_objext conftest$ac_exeext | |
19213 | if { (ac_try="$ac_link" | |
19214 | case "(($ac_try" in | |
19215 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19216 | *) ac_try_echo=$ac_try;; | |
19217 | esac | |
19218 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19219 | (eval "$ac_link") 2>conftest.er1 | |
19220 | ac_status=$? | |
19221 | grep -v '^ *+' conftest.er1 >conftest.err | |
19222 | rm -f conftest.er1 | |
19223 | cat conftest.err >&5 | |
19224 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19225 | (exit $ac_status); } && { | |
19226 | test -z "$ac_c_werror_flag" || | |
19227 | test ! -s conftest.err | |
19228 | } && test -s conftest$ac_exeext && | |
19229 | $as_test_x conftest$ac_exeext; then | |
19230 | { echo "$as_me:$LINENO: result: yes" >&5 | |
19231 | echo "${ECHO_T}yes" >&6; } | |
19232 | ||
19233 | cat >>confdefs.h <<\_ACEOF | |
19234 | #define HAVE_LIBEWF_GET_CHUNK_SIZE_ARGUMENT_VALUE 1 | |
19235 | _ACEOF | |
19236 | ||
19237 | else | |
19238 | echo "$as_me: failed program was:" >&5 | |
19239 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19240 | ||
19241 | { echo "$as_me:$LINENO: result: no" >&5 | |
19242 | echo "${ECHO_T}no" >&6; } | |
19243 | fi | |
19244 | ||
19245 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19246 | conftest$ac_exeext conftest.$ac_ext | |
19247 | ac_ext=c | |
19248 | ac_cpp='$CPP $CPPFLAGS' | |
19249 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19250 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19251 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19252 | ||
19253 | fi | |
19254 | ||
19255 | ||
19256 | { echo "$as_me:$LINENO: checking for libewf_get_bytes_per_sector" >&5 | |
19257 | echo $ECHO_N "checking for libewf_get_bytes_per_sector... $ECHO_C" >&6; } | |
19258 | if test "${ac_cv_func_libewf_get_bytes_per_sector+set}" = set; then | |
19259 | echo $ECHO_N "(cached) $ECHO_C" >&6 | |
19260 | else | |
19261 | cat >conftest.$ac_ext <<_ACEOF | |
19262 | /* confdefs.h. */ | |
19263 | _ACEOF | |
19264 | cat confdefs.h >>conftest.$ac_ext | |
19265 | cat >>conftest.$ac_ext <<_ACEOF | |
19266 | /* end confdefs.h. */ | |
19267 | /* Define libewf_get_bytes_per_sector to an innocuous variant, in case <limits.h> declares libewf_get_bytes_per_sector. | |
19268 | For example, HP-UX 11i <limits.h> declares gettimeofday. */ | |
19269 | #define libewf_get_bytes_per_sector innocuous_libewf_get_bytes_per_sector | |
19270 | ||
19271 | /* System header to define __stub macros and hopefully few prototypes, | |
19272 | which can conflict with char libewf_get_bytes_per_sector (); below. | |
19273 | Prefer <limits.h> to <assert.h> if __STDC__ is defined, since | |
19274 | <limits.h> exists even on freestanding compilers. */ | |
19275 | ||
19276 | #ifdef __STDC__ | |
19277 | # include <limits.h> | |
19278 | #else | |
19279 | # include <assert.h> | |
19280 | #endif | |
19281 | ||
19282 | #undef libewf_get_bytes_per_sector | |
19283 | ||
19284 | /* Override any GCC internal prototype to avoid an error. | |
19285 | Use char because int might match the return type of a GCC | |
19286 | builtin and then its argument prototype would still apply. */ | |
19287 | #ifdef __cplusplus | |
19288 | extern "C" | |
19289 | #endif | |
19290 | char libewf_get_bytes_per_sector (); | |
19291 | /* The GNU C library defines this for functions which it implements | |
19292 | to always fail with ENOSYS. Some functions are actually named | |
19293 | something starting with __ and the normal name is an alias. */ | |
19294 | #if defined __stub_libewf_get_bytes_per_sector || defined __stub___libewf_get_bytes_per_sector | |
19295 | choke me | |
19296 | #endif | |
19297 | ||
19298 | int | |
19299 | main () | |
19300 | { | |
19301 | return libewf_get_bytes_per_sector (); | |
19302 | ; | |
19303 | return 0; | |
19304 | } | |
19305 | _ACEOF | |
19306 | rm -f conftest.$ac_objext conftest$ac_exeext | |
19307 | if { (ac_try="$ac_link" | |
19308 | case "(($ac_try" in | |
19309 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19310 | *) ac_try_echo=$ac_try;; | |
19311 | esac | |
19312 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19313 | (eval "$ac_link") 2>conftest.er1 | |
19314 | ac_status=$? | |
19315 | grep -v '^ *+' conftest.er1 >conftest.err | |
19316 | rm -f conftest.er1 | |
19317 | cat conftest.err >&5 | |
19318 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19319 | (exit $ac_status); } && { | |
19320 | test -z "$ac_c_werror_flag" || | |
19321 | test ! -s conftest.err | |
19322 | } && test -s conftest$ac_exeext && | |
19323 | $as_test_x conftest$ac_exeext; then | |
19324 | ac_cv_func_libewf_get_bytes_per_sector=yes | |
19325 | else | |
19326 | echo "$as_me: failed program was:" >&5 | |
19327 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19328 | ||
19329 | ac_cv_func_libewf_get_bytes_per_sector=no | |
19330 | fi | |
19331 | ||
19332 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19333 | conftest$ac_exeext conftest.$ac_ext | |
19334 | fi | |
19335 | { echo "$as_me:$LINENO: result: $ac_cv_func_libewf_get_bytes_per_sector" >&5 | |
19336 | echo "${ECHO_T}$ac_cv_func_libewf_get_bytes_per_sector" >&6; } | |
19337 | if test $ac_cv_func_libewf_get_bytes_per_sector = yes; then | |
19338 | ||
19339 | cat >>confdefs.h <<\_ACEOF | |
19340 | #define HAVE_LIBEWF_GET_BYTES_PER_SECTOR 1 | |
19341 | _ACEOF | |
19342 | ||
19343 | ac_ext=c | |
19344 | ac_cpp='$CPP $CPPFLAGS' | |
19345 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19346 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19347 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19348 | ||
19349 | { echo "$as_me:$LINENO: checking if libewf_get_bytes_per_sector takes size as an argument." >&5 | |
19350 | echo $ECHO_N "checking if libewf_get_bytes_per_sector takes size as an argument.... $ECHO_C" >&6; } | |
19351 | cat >conftest.$ac_ext <<_ACEOF | |
19352 | /* confdefs.h. */ | |
19353 | _ACEOF | |
19354 | cat confdefs.h >>conftest.$ac_ext | |
19355 | cat >>conftest.$ac_ext <<_ACEOF | |
19356 | /* end confdefs.h. */ | |
19357 | #include <libewf.h> | |
19358 | int | |
19359 | main () | |
19360 | { | |
19361 | libewf_get_bytes_per_sector(NULL,NULL); | |
19362 | ; | |
19363 | return 0; | |
19364 | } | |
19365 | _ACEOF | |
19366 | rm -f conftest.$ac_objext conftest$ac_exeext | |
19367 | if { (ac_try="$ac_link" | |
19368 | case "(($ac_try" in | |
19369 | *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; | |
19370 | *) ac_try_echo=$ac_try;; | |
19371 | esac | |
19372 | eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 | |
19373 | (eval "$ac_link") 2>conftest.er1 | |
19374 | ac_status=$? | |
19375 | grep -v '^ *+' conftest.er1 >conftest.err | |
19376 | rm -f conftest.er1 | |
19377 | cat conftest.err >&5 | |
19378 | echo "$as_me:$LINENO: \$? = $ac_status" >&5 | |
19379 | (exit $ac_status); } && { | |
19380 | test -z "$ac_c_werror_flag" || | |
19381 | test ! -s conftest.err | |
19382 | } && test -s conftest$ac_exeext && | |
19383 | $as_test_x conftest$ac_exeext; then | |
19384 | { echo "$as_me:$LINENO: result: yes" >&5 | |
19385 | echo "${ECHO_T}yes" >&6; } | |
19386 | ||
19387 | cat >>confdefs.h <<\_ACEOF | |
19388 | #define HAVE_LIBEWF_GET_BYTES_PER_SECTOR_ARGUMENT_VALUE 1 | |
19389 | _ACEOF | |
19390 | ||
19391 | else | |
19392 | echo "$as_me: failed program was:" >&5 | |
19393 | sed 's/^/| /' conftest.$ac_ext >&5 | |
19394 | ||
19395 | { echo "$as_me:$LINENO: result: no" >&5 | |
19396 | echo "${ECHO_T}no" >&6; } | |
19397 | fi | |
19398 | ||
19399 | rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ | |
19400 | conftest$ac_exeext conftest.$ac_ext | |
19401 | ac_ext=c | |
19402 | ac_cpp='$CPP $CPPFLAGS' | |
19403 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' | |
19404 | ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' | |
19405 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | |
19406 | ||
19407 | fi | |
19408 | ||
19409 | ||
19410 | ||
19411 | cat >>confdefs.h <<\_ACEOF | |
19412 | #define USE_LIBEWF 1 | |
19413 | _ACEOF | |
19414 | ||
19415 | fi | |
19416 | 18683 | |
19417 | 18684 | |
19418 | 18685 | ################################################################ |
22263 | 21530 | |
22264 | 21531 | ac_config_files="$ac_config_files afflib.spec" |
22265 | 21532 | |
21533 | ||
22266 | 21534 | ac_config_headers="$ac_config_headers affconfig.h" |
22267 | 21535 | |
22268 | 21536 | |
22727 | 21995 | # report actual input values of CONFIG_FILES etc. instead of their |
22728 | 21996 | # values after options handling. |
22729 | 21997 | ac_log=" |
22730 | This file was extended by AFFLIB $as_me 3.5.12, which was | |
21998 | This file was extended by AFFLIB $as_me 3.6.2, which was | |
22731 | 21999 | generated by GNU Autoconf 2.61. Invocation command line was |
22732 | 22000 | |
22733 | 22001 | CONFIG_FILES = $CONFIG_FILES |
22780 | 22048 | _ACEOF |
22781 | 22049 | cat >>$CONFIG_STATUS <<_ACEOF |
22782 | 22050 | ac_cs_version="\\ |
22783 | AFFLIB config.status 3.5.12 | |
22051 | AFFLIB config.status 3.6.2 | |
22784 | 22052 | configured by $0, generated by GNU Autoconf 2.61, |
22785 | 22053 | with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" |
22786 | 22054 |
4 | 4 | # and http://www.openismus.com/documents/linux/automake/automake.shtml |
5 | 5 | |
6 | 6 | |
7 | AC_INIT([AFFLIB],[3.5.12],[bugs@afflib.org]) | |
7 | AC_INIT([AFFLIB],[3.6.2],[bugs@afflib.org]) | |
8 | 8 | AM_INIT_AUTOMAKE |
9 | 9 | AM_MAINTAINER_MODE |
10 | 10 | |
69 | 69 | |
70 | 70 | |
71 | 71 | # Specific headers that I plan to use |
72 | AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h dmalloc.h err.h errno.h fcntl.h getopt.h inttypes.h linux/fs.h malloc.h ncurses/term.h netinet/in.h regex.h signal.h stdio.h stdlib.h string.h sys/cdefs.h sys/disk.h sys/file.h sys/ioctl.h sys/ioctl.h sys/param.h sys/param.h sys/socket.h sys/signal.h sys/stat.h sys/time.h sys/types.h sys/vfs.h sysexits.h term.h time.h unistd.h zlib.h]) | |
72 | AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h dmalloc.h err.h errno.h fcntl.h getopt.h inttypes.h linux/fs.h malloc.h ncurses/term.h netinet/in.h regex.h signal.h stdint.h stdio.h stdlib.h string.h sys/cdefs.h sys/disk.h sys/file.h sys/ioctl.h sys/ioctl.h sys/param.h sys/param.h sys/socket.h sys/signal.h sys/stat.h sys/time.h sys/types.h sys/vfs.h sysexits.h term.h time.h unistd.h zlib.h]) | |
73 | ||
74 | AC_CHECK_LIB([regex],[regcomp]) # see if we need -lregex | |
73 | 75 | |
74 | 76 | AC_CHECK_MEMBER([struct sockaddr_in.sin_len], |
75 | 77 | [ AC_DEFINE(HAVE_SOCKADDR_SIN_LEN, 1, [Do we have sockaddr.sin_len?]) ], |
92 | 94 | AC_LANG_PUSH([C++]) |
93 | 95 | AC_CHECK_HEADERS([cstring]) |
94 | 96 | AC_LANG_POP([C++]) |
95 | ||
96 | ||
97 | ||
98 | ################################################################ | |
99 | ## LIBEWF support | |
100 | dnl Function to test if a libewf_get_media_size takes value as an argument | |
101 | AC_DEFUN([AFF_CHECK_LIBEWF_GET_MEDIA_SIZE], | |
102 | [AC_CHECK_FUNC( | |
103 | [libewf_get_media_size], | |
104 | [AC_DEFINE( | |
105 | [HAVE_LIBEWF_GET_MEDIA_SIZE], | |
106 | [1], | |
107 | [Define to 1 if you have the libewf_get_media_size function.]) | |
108 | AC_LANG_PUSH(C) | |
109 | AC_MSG_CHECKING( | |
110 | [if libewf_get_media_size takes size as an argument.]) | |
111 | AC_LINK_IFELSE( | |
112 | [AC_LANG_PROGRAM( | |
113 | [[#include <libewf.h>]], | |
114 | [[libewf_get_media_size(NULL,NULL); ]] )], | |
115 | [AC_MSG_RESULT( | |
116 | [yes]) | |
117 | AC_DEFINE( | |
118 | [HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE], | |
119 | [1], | |
120 | [Define to 1 if libewf_get_media_size takes value as an argument.])], | |
121 | [AC_MSG_RESULT( | |
122 | [no])] ) | |
123 | AC_LANG_POP(C) ]) | |
124 | ]) | |
125 | ||
126 | dnl Function to test if a libewf_get_chunk_size takes value as an argument | |
127 | AC_DEFUN([AFF_CHECK_LIBEWF_GET_CHUNK_SIZE], | |
128 | [AC_CHECK_FUNC( | |
129 | [libewf_get_chunk_size], | |
130 | [AC_DEFINE( | |
131 | [HAVE_LIBEWF_GET_CHUNK_SIZE], | |
132 | [1], | |
133 | [Define to 1 if you have the libewf_get_chunk_size function.]) | |
134 | AC_LANG_PUSH(C) | |
135 | AC_MSG_CHECKING( | |
136 | [if libewf_get_chunk_size takes size as an argument.]) | |
137 | AC_LINK_IFELSE( | |
138 | [AC_LANG_PROGRAM( | |
139 | [[#include <libewf.h>]], | |
140 | [[libewf_get_chunk_size(NULL,NULL); ]] )], | |
141 | [AC_MSG_RESULT( | |
142 | [yes]) | |
143 | AC_DEFINE( | |
144 | [HAVE_LIBEWF_GET_CHUNK_SIZE_ARGUMENT_VALUE], | |
145 | [1], | |
146 | [Define to 1 if libewf_get_chunk_size takes value as an argument.])], | |
147 | [AC_MSG_RESULT( | |
148 | [no])] ) | |
149 | AC_LANG_POP(C) ]) | |
150 | ]) | |
151 | ||
152 | dnl Function to test if a libewf_get_bytes_per_sector takes value as an argument | |
153 | AC_DEFUN([AFF_CHECK_LIBEWF_GET_BYTES_PER_SECTOR], | |
154 | [AC_CHECK_FUNC( | |
155 | [libewf_get_bytes_per_sector], | |
156 | [AC_DEFINE( | |
157 | [HAVE_LIBEWF_GET_BYTES_PER_SECTOR], | |
158 | [1], | |
159 | [Define to 1 if you have the libewf_get_bytes_per_sector function.]) | |
160 | AC_LANG_PUSH(C) | |
161 | AC_MSG_CHECKING( | |
162 | [if libewf_get_bytes_per_sector takes size as an argument.]) | |
163 | AC_LINK_IFELSE( | |
164 | [AC_LANG_PROGRAM( | |
165 | [[#include <libewf.h>]], | |
166 | [[libewf_get_bytes_per_sector(NULL,NULL); ]] )], | |
167 | [AC_MSG_RESULT( | |
168 | [yes]) | |
169 | AC_DEFINE( | |
170 | [HAVE_LIBEWF_GET_BYTES_PER_SECTOR_ARGUMENT_VALUE], | |
171 | [1], | |
172 | [Define to 1 if libewf_get_bytes_per_sector takes value as an argument.])], | |
173 | [AC_MSG_RESULT( | |
174 | [no])] ) | |
175 | AC_LANG_POP(C) ]) | |
176 | ]) | |
177 | ||
178 | ||
179 | AC_ARG_ENABLE([libewf], | |
180 | AC_HELP_STRING([--enable-libewf=yes], [Use libewf for reading EnCase files(default yes)]), | |
181 | [enable_libewf=$enableval], [enable_libewf=yes]) | |
182 | ||
183 | if test "${enable_libewf}" = "yes" ; then | |
184 | AC_CHECK_HEADERS([libewf.h],,[enable_libewf=no]) | |
185 | fi | |
186 | ||
187 | if test "${enable_libewf}" = "yes" ; then | |
188 | AC_MSG_NOTICE([On linux, libewf has a dependency which forces linking with -luuid]) | |
189 | AC_MSG_NOTICE([so if we are running on linux and that version of libewf is installed,]) | |
190 | AC_MSG_NOTICE([make sure the libuuid is installed]) | |
191 | ||
192 | if test -r /usr/lib/libewf.la ; then | |
193 | if grep luuid /usr/lib/libewf.la ; then | |
194 | AC_MSG_NOTICE([Installed libewf requires libuuid.]) | |
195 | AC_CHECK_LIB([uuid],[uuid_generate_random],,[enable_libewf=no]) | |
196 | fi | |
197 | fi | |
198 | fi | |
199 | ||
200 | if test "${enable_libewf}" = "yes" ; then | |
201 | AC_CHECK_LIB([ewf],[libewf_get_version],,[enable_libewf=no]) | |
202 | fi | |
203 | ||
204 | if test "${enable_libewf}" = "yes" ; then | |
205 | AFF_CHECK_LIBEWF_GET_MEDIA_SIZE | |
206 | AFF_CHECK_LIBEWF_GET_CHUNK_SIZE | |
207 | AFF_CHECK_LIBEWF_GET_BYTES_PER_SECTOR | |
208 | AC_DEFINE([USE_LIBEWF],1,[Use libewf to read EnCase files]) | |
209 | fi | |
210 | ||
211 | 97 | |
212 | 98 | ################################################################ |
213 | 99 | # For AFF tools |
416 | 302 | tests/Makefile doc/Makefile pyaff/Makefile man/Makefile lib/version.h]) |
417 | 303 | dnl Have configure make distribution specific files |
418 | 304 | AC_CONFIG_FILES([afflib.spec]) |
305 | ||
419 | 306 | dnl Have configure write its configuration |
420 | 307 | AM_CONFIG_HEADER([affconfig.h]) |
421 | 308 |
38 | 38 | af_open() and af_read() instead of fopen() and fread(). You can |
39 | 39 | then read the AFF files directly. If you don't have source code, |
40 | 40 | but have a scanner that can read from standard input, you can |
41 | use the "afcat" program to copy the contents of an AFF file to | |
41 | use the "affcat" program to copy the contents of an AFF file to | |
42 | 42 | standard output. |
43 | 43 | |
44 | 44 | Eventually, we plan to have a version of samba that is modified to |
0 | bin_PROGRAMS = aftest | |
0 | EXTRA_PROGRAMS = aftest | |
1 | TESTS = aftest | |
2 | ||
3 | CLEANFILES = aftest | |
4 | ||
1 | 5 | aftest_SOURCES = aftest.cpp |
2 | 6 | aftest_LDADD = libafflib.la |
3 | ||
4 | TESTS = aftest | |
5 | ||
6 | 7 | aftest_LDFLAGS = $(PTHREAD_CFLAGS) -static # easier debugging |
7 | 8 | |
8 | 9 | AFFLIB_SOURCES = aff_db.cpp aff_db.h aff_toc.cpp \ |
13 | 14 | vnode_aff.cpp vnode_aff.h \ |
14 | 15 | vnode_afd.cpp vnode_afd.h \ |
15 | 16 | vnode_afm.cpp vnode_afm.h \ |
16 | vnode_ewf.cpp vnode_ewf.h \ | |
17 | 17 | vnode_raw.cpp vnode_raw.h \ |
18 | 18 | vnode_split_raw.cpp vnode_split_raw.h \ |
19 | 19 | aftimer.h \ |
56 | 56 | endif |
57 | 57 | |
58 | 58 | if MAYBE_S3 |
59 | bin_PROGRAMS += s3 | |
59 | EXTRA_PROGRAMS += s3 | |
60 | 60 | libafflib_la_SOURCES += vnode_s3.cpp vnode_s3.h s3_glue.cpp |
61 | 61 | s3_SOURCES = s3.cpp |
62 | 62 | s3_LDADD = libafflib.la |
12 | 12 | # PARTICULAR PURPOSE. |
13 | 13 | |
14 | 14 | @SET_MAKE@ |
15 | ||
16 | 15 | |
17 | 16 | VPATH = @srcdir@ |
18 | 17 | pkgdatadir = $(datadir)/@PACKAGE@ |
32 | 31 | POST_UNINSTALL = : |
33 | 32 | build_triplet = @build@ |
34 | 33 | host_triplet = @host@ |
35 | bin_PROGRAMS = aftest$(EXEEXT) $(am__EXEEXT_1) | |
34 | EXTRA_PROGRAMS = aftest$(EXEEXT) $(am__EXEEXT_1) | |
36 | 35 | TESTS = aftest$(EXEEXT) |
37 | 36 | @MAYBE_QEMU_TRUE@am__append_1 = $(QEMU_SOURCES) |
38 | 37 | @MAYBE_S3_TRUE@am__append_2 = s3 |
54 | 53 | *) f=$$p;; \ |
55 | 54 | esac; |
56 | 55 | am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; |
57 | am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" | |
56 | am__installdirs = "$(DESTDIR)$(libdir)" | |
58 | 57 | libLTLIBRARIES_INSTALL = $(INSTALL) |
59 | 58 | LTLIBRARIES = $(lib_LTLIBRARIES) |
60 | 59 | libafflib_la_LIBADD = |
63 | 62 | afflib_pages.cpp afflib_stream.cpp afflib_util.cpp crypto.cpp \ |
64 | 63 | base64.cpp base64.h lzma_glue.cpp s3_glue.h vnode_aff.cpp \ |
65 | 64 | vnode_aff.h vnode_afd.cpp vnode_afd.h vnode_afm.cpp \ |
66 | vnode_afm.h vnode_ewf.cpp vnode_ewf.h vnode_raw.cpp \ | |
67 | vnode_raw.h vnode_split_raw.cpp vnode_split_raw.h aftimer.h \ | |
68 | utils.cpp utils.h display.cpp vnode_qemu.cpp vnode_qemu.h \ | |
69 | qemu/aes.h qemu/aff-block-vmdk.h qemu/block-bochs.c \ | |
70 | qemu/block-cloop.c qemu/block-cow.c qemu/block-dmg.c \ | |
71 | qemu/block-parallels.c qemu/block-qcow.c qemu/block-qcow2.c \ | |
72 | qemu/block-raw-posix.c qemu/block-vmdk.c qemu/block-vpc.c \ | |
73 | qemu/block-vvfat.c qemu/block.c qemu/block.h qemu/block_int.h \ | |
74 | qemu/bswap.h qemu/config-host.h qemu/console.h qemu/exec-all.h \ | |
75 | qemu/osdep.h qemu/qemu-common.h qemu/qemu-timer.h \ | |
76 | qemu/qemu_glue.c vnode_s3.cpp vnode_s3.h s3_glue.cpp \ | |
65 | vnode_afm.h vnode_raw.cpp vnode_raw.h vnode_split_raw.cpp \ | |
66 | vnode_split_raw.h aftimer.h utils.cpp utils.h display.cpp \ | |
67 | vnode_qemu.cpp vnode_qemu.h qemu/aes.h qemu/aff-block-vmdk.h \ | |
68 | qemu/block-bochs.c qemu/block-cloop.c qemu/block-cow.c \ | |
69 | qemu/block-dmg.c qemu/block-parallels.c qemu/block-qcow.c \ | |
70 | qemu/block-qcow2.c qemu/block-raw-posix.c qemu/block-vmdk.c \ | |
71 | qemu/block-vpc.c qemu/block-vvfat.c qemu/block.c qemu/block.h \ | |
72 | qemu/block_int.h qemu/bswap.h qemu/config-host.h \ | |
73 | qemu/console.h qemu/exec-all.h qemu/osdep.h qemu/qemu-common.h \ | |
74 | qemu/qemu-timer.h qemu/qemu_glue.c vnode_s3.cpp vnode_s3.h \ | |
75 | s3_glue.cpp \ | |
77 | 76 | @top_srcdir@/lzma443/C/7zip/Compress/LZMA_Alone/LzmaBench.cpp \ |
78 | 77 | @top_srcdir@/lzma443/C/7zip/Compress/LZMA_Alone/LzmaRam.cpp \ |
79 | 78 | @top_srcdir@/lzma443/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.c \ |
97 | 96 | am__objects_1 = aff_db.lo aff_toc.lo afflib.lo afflib_os.lo \ |
98 | 97 | afflib_pages.lo afflib_stream.lo afflib_util.lo crypto.lo \ |
99 | 98 | base64.lo lzma_glue.lo vnode_aff.lo vnode_afd.lo vnode_afm.lo \ |
100 | vnode_ewf.lo vnode_raw.lo vnode_split_raw.lo utils.lo \ | |
101 | display.lo | |
99 | vnode_raw.lo vnode_split_raw.lo utils.lo display.lo | |
102 | 100 | am__objects_2 = vnode_qemu.lo libafflib_la-block-bochs.lo \ |
103 | 101 | libafflib_la-block-cloop.lo libafflib_la-block-cow.lo \ |
104 | 102 | libafflib_la-block-dmg.lo libafflib_la-block-parallels.lo \ |
118 | 116 | $(am__objects_4) $(am__objects_5) |
119 | 117 | libafflib_la_OBJECTS = $(am_libafflib_la_OBJECTS) |
120 | 118 | @MAYBE_S3_TRUE@am__EXEEXT_1 = s3$(EXEEXT) |
121 | binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) | |
122 | PROGRAMS = $(bin_PROGRAMS) | |
123 | 119 | am_aftest_OBJECTS = aftest.$(OBJEXT) |
124 | 120 | aftest_OBJECTS = $(am_aftest_OBJECTS) |
125 | 121 | aftest_DEPENDENCIES = libafflib.la |
299 | 295 | target_alias = @target_alias@ |
300 | 296 | top_builddir = @top_builddir@ |
301 | 297 | top_srcdir = @top_srcdir@ |
298 | CLEANFILES = aftest | |
302 | 299 | aftest_SOURCES = aftest.cpp |
303 | 300 | aftest_LDADD = libafflib.la |
304 | 301 | aftest_LDFLAGS = $(PTHREAD_CFLAGS) -static # easier debugging |
310 | 307 | vnode_aff.cpp vnode_aff.h \ |
311 | 308 | vnode_afd.cpp vnode_afd.h \ |
312 | 309 | vnode_afm.cpp vnode_afm.h \ |
313 | vnode_ewf.cpp vnode_ewf.h \ | |
314 | 310 | vnode_raw.cpp vnode_raw.h \ |
315 | 311 | vnode_split_raw.cpp vnode_split_raw.h \ |
316 | 312 | aftimer.h \ |
447 | 443 | done |
448 | 444 | libafflib.la: $(libafflib_la_OBJECTS) $(libafflib_la_DEPENDENCIES) |
449 | 445 | $(CXXLINK) -rpath $(libdir) $(libafflib_la_OBJECTS) $(libafflib_la_LIBADD) $(LIBS) |
450 | install-binPROGRAMS: $(bin_PROGRAMS) | |
451 | @$(NORMAL_INSTALL) | |
452 | test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" | |
453 | @list='$(bin_PROGRAMS)'; for p in $$list; do \ | |
454 | p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ | |
455 | if test -f $$p \ | |
456 | || test -f $$p1 \ | |
457 | ; then \ | |
458 | f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ | |
459 | echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ | |
460 | $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ | |
461 | else :; fi; \ | |
462 | done | |
463 | ||
464 | uninstall-binPROGRAMS: | |
465 | @$(NORMAL_UNINSTALL) | |
466 | @list='$(bin_PROGRAMS)'; for p in $$list; do \ | |
467 | f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ | |
468 | echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ | |
469 | rm -f "$(DESTDIR)$(bindir)/$$f"; \ | |
470 | done | |
471 | ||
472 | clean-binPROGRAMS: | |
473 | @list='$(bin_PROGRAMS)'; for p in $$list; do \ | |
474 | f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ | |
475 | echo " rm -f $$p $$f"; \ | |
476 | rm -f $$p $$f ; \ | |
477 | done | |
478 | 446 | aftest$(EXEEXT): $(aftest_OBJECTS) $(aftest_DEPENDENCIES) |
479 | 447 | @rm -f aftest$(EXEEXT) |
480 | 448 | $(aftest_LINK) $(aftest_OBJECTS) $(aftest_LDADD) $(LIBS) |
539 | 507 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_afd.Plo@am__quote@ |
540 | 508 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_aff.Plo@am__quote@ |
541 | 509 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_afm.Plo@am__quote@ |
542 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_ewf.Plo@am__quote@ | |
543 | 510 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_qemu.Plo@am__quote@ |
544 | 511 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_raw.Plo@am__quote@ |
545 | 512 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_s3.Plo@am__quote@ |
974 | 941 | check-am: all-am |
975 | 942 | $(MAKE) $(AM_MAKEFLAGS) check-TESTS |
976 | 943 | check: check-am |
977 | all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) | |
978 | install-binPROGRAMS: install-libLTLIBRARIES | |
979 | ||
944 | all-am: Makefile $(LTLIBRARIES) | |
980 | 945 | installdirs: |
981 | for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)"; do \ | |
946 | for dir in "$(DESTDIR)$(libdir)"; do \ | |
982 | 947 | test -z "$$dir" || $(MKDIR_P) "$$dir"; \ |
983 | 948 | done |
984 | 949 | install: install-am |
998 | 963 | mostlyclean-generic: |
999 | 964 | |
1000 | 965 | clean-generic: |
966 | -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) | |
1001 | 967 | |
1002 | 968 | distclean-generic: |
1003 | 969 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) |
1007 | 973 | @echo "it deletes files that may require special tools to rebuild." |
1008 | 974 | clean: clean-am |
1009 | 975 | |
1010 | clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ | |
1011 | clean-libtool mostlyclean-am | |
976 | clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ | |
977 | mostlyclean-am | |
1012 | 978 | |
1013 | 979 | distclean: distclean-am |
1014 | 980 | -rm -rf ./$(DEPDIR) |
1030 | 996 | |
1031 | 997 | install-dvi: install-dvi-am |
1032 | 998 | |
1033 | install-exec-am: install-binPROGRAMS install-libLTLIBRARIES | |
999 | install-exec-am: install-libLTLIBRARIES | |
1034 | 1000 | @$(NORMAL_INSTALL) |
1035 | 1001 | $(MAKE) $(AM_MAKEFLAGS) install-exec-hook |
1036 | 1002 | |
1064 | 1030 | |
1065 | 1031 | ps-am: |
1066 | 1032 | |
1067 | uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES | |
1033 | uninstall-am: uninstall-libLTLIBRARIES | |
1068 | 1034 | |
1069 | 1035 | .MAKE: install-am install-exec-am install-strip |
1070 | 1036 | |
1071 | 1037 | .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ |
1072 | clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ | |
1073 | clean-libtool ctags distclean distclean-compile \ | |
1074 | distclean-generic distclean-libtool distclean-tags distdir dvi \ | |
1075 | dvi-am html html-am info info-am install install-am \ | |
1076 | install-binPROGRAMS install-data install-data-am install-dvi \ | |
1077 | install-dvi-am install-exec install-exec-am install-exec-hook \ | |
1078 | install-html install-html-am install-info install-info-am \ | |
1079 | install-libLTLIBRARIES install-man install-pdf install-pdf-am \ | |
1080 | install-ps install-ps-am install-strip installcheck \ | |
1081 | installcheck-am installdirs maintainer-clean \ | |
1082 | maintainer-clean-generic mostlyclean mostlyclean-compile \ | |
1083 | mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ | |
1084 | tags uninstall uninstall-am uninstall-binPROGRAMS \ | |
1085 | uninstall-libLTLIBRARIES | |
1038 | clean-generic clean-libLTLIBRARIES clean-libtool ctags \ | |
1039 | distclean distclean-compile distclean-generic \ | |
1040 | distclean-libtool distclean-tags distdir dvi dvi-am html \ | |
1041 | html-am info info-am install install-am install-data \ | |
1042 | install-data-am install-dvi install-dvi-am install-exec \ | |
1043 | install-exec-am install-exec-hook install-html install-html-am \ | |
1044 | install-info install-info-am install-libLTLIBRARIES \ | |
1045 | install-man install-pdf install-pdf-am install-ps \ | |
1046 | install-ps-am install-strip installcheck installcheck-am \ | |
1047 | installdirs maintainer-clean maintainer-clean-generic \ | |
1048 | mostlyclean mostlyclean-compile mostlyclean-generic \ | |
1049 | mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ | |
1050 | uninstall-am uninstall-libLTLIBRARIES | |
1086 | 1051 | |
1087 | 1052 | |
1088 | 1053 | install-exec-hook: |
89 | 89 | while(1){ |
90 | 90 | char segname[AF_MAX_NAME_LEN]; |
91 | 91 | size_t segname_len=sizeof(segname); |
92 | off_t pos = ftello(af->aseg); | |
92 | uint64_t pos = ftello(af->aseg); | |
93 | 93 | size_t datalen=0; |
94 | 94 | |
95 | 95 | int r = af_get_next_seg(af,segname,segname_len,0,0,&datalen); |
51 | 51 | #include "vnode_afm.h" |
52 | 52 | #include "vnode_aff.h" |
53 | 53 | #include "vnode_afd.h" |
54 | #include "vnode_ewf.h" | |
55 | 54 | |
56 | 55 | #ifdef USE_QEMU |
57 | 56 | #include "vnode_qemu.h" |
78 | 77 | &vnode_afd, |
79 | 78 | &vnode_afm, // must be before aff |
80 | 79 | &vnode_aff, |
81 | #ifdef USE_LIBEWF | |
82 | &vnode_ewf, // libewf | |
83 | #endif | |
84 | 80 | #ifdef USE_QEMU |
85 | 81 | &vnode_vmdk, |
86 | 82 | &vnode_dmg, |
354 | 350 | } |
355 | 351 | |
356 | 352 | /* Set up the encryption if requested and if this support metadata */ |
357 | if(AF_SEALING_VNODE(af)){ | |
353 | if(AF_SEALING_VNODE(af) && ((flags & AF_NO_CRYPTO)==0)){ | |
358 | 354 | bool can_decrypt = false; |
359 | 355 | if(af->password){ |
360 | 356 | struct af_vnode_info vni; |
555 | 551 | errno = EINVAL; |
556 | 552 | return -1; // this is bad |
557 | 553 | } |
558 | int ret = ((int64_t)af->pos >= vni.imagesize); | |
554 | int ret = (int64_t)af->pos >= (int64_t)vni.imagesize; | |
559 | 555 | AF_UNLOCK(af); |
560 | 556 | return ret; |
561 | 557 | } |
676 | 672 | } |
677 | 673 | |
678 | 674 | |
679 | ||
680 | /*TK: Here for locking */ | |
681 | 675 | |
682 | 676 | /* Decrypt data and perform unblocking if necessary. |
683 | 677 | * This could eliminate a memory copy by doing the decryption for everything |
4 | 4 | * afflib.h: |
5 | 5 | * |
6 | 6 | * This file describes the public AFFLIB interface. |
7 | * The interface to reading AFF files, Raw files, and EnCase file (if libewf is compiled in). | |
7 | * The interface to reading AFF files and Raw files. | |
8 | 8 | */ |
9 | 9 | |
10 | 10 | /* Figure out what kind of OS we are running on */ |
11 | 11 | |
12 | 12 | /* These are both needed; no need to bother with affconfig.h #defines */ |
13 | 13 | #include <stdio.h> |
14 | #ifdef HAVE_STDINT_H | |
15 | #include <stdint.h> | |
16 | #endif | |
14 | 17 | #include <sys/types.h> |
15 | 18 | |
16 | 19 | #ifdef HAVE_SYS_CDEFS_H |
32 | 35 | |
33 | 36 | /** WIN32 is defined by the NMAKE makefile for Visual C++ under Windows and by mingw **/ |
34 | 37 | #ifdef WIN32 |
38 | #include <basetsd.h> | |
35 | 39 | #include <io.h> // gets isatty |
36 | 40 | typedef unsigned int uint; |
37 | 41 | typedef unsigned int u_int; |
63 | 67 | #define PRIu64 "I64u" |
64 | 68 | #endif |
65 | 69 | |
66 | //int64 ftello(FILE *stream); /* Functions that Microsoft forgot */ | |
67 | //int fseeko(FILE *stream,int64 offset,int whence); | |
70 | ||
71 | #if defined(__MINGW_H) | |
68 | 72 | #define ftello ftello64 |
69 | 73 | #define fseeko fseeko64 |
70 | #endif | |
74 | #else | |
75 | #define ftello _ftelli64 /* replaces ftello64 in VC2008 */ | |
76 | #define fseeko _fseeki64 | |
77 | #endif | |
78 | ||
79 | #endif | |
71 | 80 | /** END OF WIN32 DEFINES **/ |
72 | 81 | |
73 | 82 | |
89 | 98 | }; |
90 | 99 | |
91 | 100 | struct af_vnode_info { |
92 | int64_t imagesize; // size of this image | |
101 | uint64_t imagesize; // size of this image | |
93 | 102 | int pagesize; // what is the natural page size? |
94 | 103 | u_int supports_compression:1; // supports writing compressed segments |
95 | 104 | u_int has_pages:1; // does system support page segments? |
174 | 183 | #define AF_OPEN_PRIMITIVE (1<<31) // only open primtive, not compound files |
175 | 184 | #define AF_BADBLOCK_FILL (1<<30) // fill unallocated (sparse) with BADBLOCK flag |
176 | 185 | #define AF_HALF_OPEN (1<<29) // return af before calling af->v->open; |
186 | #define AF_NO_CRYPTO (1<<28) // disable encryption layer | |
177 | 187 | |
178 | 188 | /* navigating within the data segments as if they were a single file */ |
179 | ssize_t af_read(AFFILE *af,unsigned char *buf,ssize_t count); | |
189 | #ifdef _WIN32 | |
190 | SSIZE_T af_read(AFFILE *af,unsigned char *buf,SSIZE_T count); | |
191 | #else | |
192 | ssize_t af_read(AFFILE *af,unsigned char *buf,ssize_t count); | |
193 | #endif | |
180 | 194 | uint64_t af_seek(AFFILE *af,int64_t pos,int whence); // returns new position |
181 | 195 | uint64_t af_tell(AFFILE *af); |
182 | int af_eof(AFFILE *af); // is the virtual file at the end? | |
196 | int af_eof(AFFILE *af); // is the virtual file at the end? | |
183 | 197 | |
184 | 198 | /* Additional routines for writing */ |
185 | 199 | void af_set_callback(AFFILE *af, void (*cb)(struct affcallback_info *acbi)); |
114 | 114 | #endif |
115 | 115 | |
116 | 116 | #ifdef WIN32 |
117 | #if !defined(__MINGW_H) | |
117 | 118 | #pragma warning(disable: 4996) /* Don't warn on Windows about using POSIX open() instead of _open() */ |
119 | #endif | |
118 | 120 | #include <malloc.h> |
119 | 121 | #include <windows.h> |
120 | 122 | #include <winsock.h> // htonl() |
318 | 320 | struct aff_pagebuf *pbcache; // array of pagebufs |
319 | 321 | int num_pbufs; // number of pagebufs; default is 1 |
320 | 322 | int afftime; // for updating last |
321 | int64_t cur_page; // used by vnode_raw and vnode_ewf to fake pages | |
322 | // must be able to go negative | |
323 | int64_t cur_page; // used by vnode_raw to fake pages must be able to go negative. | |
323 | 324 | |
324 | 325 | int debug; // for debugging, of course |
325 | 326 | unsigned int badflag_set:1; // is badflag set? |
515 | 516 | #define AF_IDENTIFY_EVD 4 // file is a .E01 file when there are more files following |
516 | 517 | #define AF_IDENTIFY_SPLIT_RAW 5 // file is a split raw file |
517 | 518 | #define AF_IDENTIFY_AFM 6 // file is raw file with metadata |
518 | #define AF_IDENTIFY_EWF 7 // libewf | |
519 | #define AF_IDENTIFY_EWF 7 // libewf; deprecated | |
519 | 520 | #define AF_IDENTIFY_S3 8 // is an s3:/// file |
520 | 521 | #define AF_IDENTIFY_VMDK 9 // QEMU support for VMDK format |
521 | 522 | #define AF_IDENTIFY_DMG 10 // QEMU support for Apple DMG format |
593 | 594 | * Note: pagename to string translation happens inside afflib.cpp, not inside |
594 | 595 | * the vnode driver. |
595 | 596 | */ |
597 | #define af_page_size(af) (af_get_pagesize(af)) /* backwards compatability */ | |
596 | 598 | void af_read_sizes(AFFILE *af); // sets up values if we can get them. |
597 | 599 | int af_set_pagesize(AFFILE *af,u_long pagesize); // sets the pagesize; fails with -1 if imagesize >=0 |
598 | 600 | int af_set_sectorsize(AFFILE *AF,int sectorsize); // fails with -1 if imagesize>=0 |
599 | 601 | int af_get_sectorsize(AFFILE *AF); // returns sector size |
600 | 602 | int af_has_pages(AFFILE *af); // does the underlying system support pages? |
601 | int af_page_size(AFFILE *af); // returns page size, or -1 | |
603 | int af_get_pagesize(AFFILE *af); // returns page size, or -1 | |
602 | 604 | int af_get_page_raw(AFFILE *af,int64_t pagenum,unsigned long *arg,u_char *data,size_t *bytes); |
603 | 605 | int af_get_page(AFFILE *af,int64_t pagenum,u_char *data,size_t *bytes); |
604 | 606 | #define AF_SIGFLAG_NOSIG 0x0001 // do not write signatures with af_update_segf() |
31 | 31 | *** Extra code for Windows... |
32 | 32 | ****************************************************************/ |
33 | 33 | |
34 | /* No longer needed with VC2008 */ | |
35 | #if 0 | |
34 | 36 | #if defined(WIN32) and !defined(__MINGW_H) |
35 | 37 | #pragma warning(disable: 4996) |
36 | 38 | int64 ftello(FILE *stream) |
59 | 61 | } |
60 | 62 | return fsetpos(stream,&offset); |
61 | 63 | } |
64 | #endif | |
62 | 65 | #endif |
63 | 66 | |
64 | 67 |
3 | 3 | |
4 | 4 | #ifdef __cplusplus |
5 | 5 | #ifndef WIN32 |
6 | #ifndef __STDC_FORMAT_MACROS | |
7 | #define __STDC_FORMAT_MACROS | |
8 | #endif | |
6 | 9 | #include <inttypes.h> |
7 | 10 | #include <sys/time.h> |
8 | 11 | #endif |
13 | 13 | #include <signal.h> |
14 | 14 | #include <assert.h> |
15 | 15 | #include <sys/types.h> |
16 | #ifdef HAVE_STDINT_H | |
16 | 17 | #include <stdint.h> |
18 | #endif | |
17 | 19 | |
18 | 20 | #ifndef MIN |
19 | 21 | #define MIN(x,y) ((x)<(y)?(x):(y)) |
203 | 203 | static int afd_identify_file(const char *filename,int exists) |
204 | 204 | { |
205 | 205 | if(filename==0 || strlen(filename)==0) return 0; // zero-length filenames aren't welcome |
206 | if(strncmp(filename,"file://",7)==0){ | |
207 | /* Move file pointer past file:// then find a '/' and take the next character */ | |
208 | filename += 7; | |
209 | while(*filename && *filename!='/'){ | |
210 | filename++; | |
211 | } | |
212 | /* At this point if *filename==0 then we never found the end of the URL. | |
213 | * return 0, since it's not an AFF file. | |
214 | */ | |
215 | if(*filename==0) return 0; | |
216 | ||
217 | /* So *filename must == '/' */ | |
218 | assert(*filename == '/'); | |
219 | filename++; | |
220 | } | |
206 | 221 | if(exists && access(filename,R_OK)!=0) return 0; // needs to exist and it doesn't |
207 | 222 | |
208 | 223 | /* If it ends with a '/', remove it */ |
268 | 283 | |
269 | 284 | int new_file = access(fname,F_OK)!=0; // Is this a new file? |
270 | 285 | |
271 | AFFILE *af2 = af_open(fname,af->openflags,af->openmode); | |
286 | AFFILE *af2 = af_open(fname,af->openflags|AF_NO_CRYPTO,af->openmode); | |
272 | 287 | if(af2==0){ |
273 | 288 | (*af->error_reporter)("open(%s,%d,%d) failed: %s\n", |
274 | 289 | fname,af->openflags,af->openmode,strerror(errno)); |
287 | 302 | af_update_seg(af,AF_AFF_FILE_TYPE,0,(const u_char *)"AFD",3); |
288 | 303 | |
289 | 304 | /* If this is the second file, copy over additional metadata from first... */ |
290 | if(ap->num_afs>0){ | |
305 | if(ap->num_afs>1){ | |
291 | 306 | AFFILE *af0 = ap->afs[0]; |
292 | 307 | memcpy(af2->badflag,af0->badflag,af->image_sectorsize); |
293 | 308 | af2->bytes_memcpy += af->image_sectorsize; |
517 | 532 | |
518 | 533 | struct af_vnode vnode_afd = { |
519 | 534 | AF_IDENTIFY_AFD, // |
520 | AF_VNODE_TYPE_COMPOUND|AF_VNODE_TYPE_RELIABLE|AF_VNODE_NO_SEALING, // | |
535 | AF_VNODE_TYPE_COMPOUND|AF_VNODE_TYPE_RELIABLE, // | |
521 | 536 | "AFF Directory", |
522 | 537 | afd_identify_file, |
523 | 538 | afd_open, // open |
167 | 167 | |
168 | 168 | fseeko(af->aseg,adm->offset,SEEK_SET); |
169 | 169 | int ret = aff_get_next_seg(af,next,sizeof(next),arg,data,datalen); |
170 | assert(strcmp(next,name)==0); // hopefully this is what they asked for | |
170 | assert(ret!=0 || strcmp(next,name)==0); // hopefully this is what they asked for | |
171 | 171 | return ret; |
172 | 172 | } |
173 | 173 | |
197 | 197 | return AF_ERROR_INVALID_ARG; |
198 | 198 | } |
199 | 199 | |
200 | off_t start = ftello(af->aseg); | |
200 | uint64_t start = ftello(af->aseg); | |
201 | 201 | size_t data_len; |
202 | 202 | |
203 | 203 | int r = af_probe_next_seg(af,segname,segname_len,arg,&data_len,0,0); |
0 | /** | |
1 | ** AFF/libewf glue | |
2 | ** | |
3 | ** (C) 2006 by Simson L. Garfinkel | |
4 | ** | |
5 | ** | |
6 | **/ | |
7 | ||
8 | ||
9 | ||
10 | #include "affconfig.h" | |
11 | #include "afflib.h" | |
12 | #include "afflib_i.h" | |
13 | ||
14 | #ifdef USE_LIBEWF | |
15 | ||
16 | #include <ctype.h> | |
17 | #include <stdio.h> | |
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
20 | #include "vnode_ewf.h" | |
21 | ||
22 | #ifdef HAVE_CSTRING | |
23 | #include <cstring> | |
24 | #endif | |
25 | ||
26 | /* We're gonna include libewf.h now, which causes problems, because libewf.h currently | |
27 | * includes an autoconf-generated affconfig.h file | |
28 | */ | |
29 | ||
30 | #undef PACKAGE | |
31 | #undef PACKAGE_BUGREPORT | |
32 | #undef PACKAGE_NAME | |
33 | #undef PACKAGE_STRING | |
34 | #undef PACKAGE_TARNAME | |
35 | #undef PACKAGE_VERSION | |
36 | #undef VERSION | |
37 | ||
38 | #ifdef HAVE_LIBEWF_H | |
39 | #include "libewf.h" | |
40 | #else | |
41 | #error EWF support requires libewf, but HAVE_LIBEWF_H is not defined | |
42 | #endif | |
43 | ||
44 | ||
45 | ||
46 | /**************************************************************** | |
47 | *** Service routines | |
48 | ****************************************************************/ | |
49 | ||
50 | #define EWF_HANDLE(af) ((libewf_handle_t *)af->vnodeprivate) | |
51 | ||
52 | /**************************************************************** | |
53 | *** AFFLIB Glue Follows | |
54 | ****************************************************************/ | |
55 | ||
56 | ||
57 | /* Return 1 if a file is a ewf file... */ | |
58 | static int ewf_identify_file(const char *filename,int exists) | |
59 | { | |
60 | return libewf_check_file_signature(filename)==1 ? 1 : 0; | |
61 | } | |
62 | ||
63 | static int ewf_open(AFFILE *af) | |
64 | { | |
65 | ||
66 | if(strchr(af->fname,'.')==0) return -1; // need a '.' in the filename | |
67 | ||
68 | /* Find all of the EWF files to open*/ | |
69 | char **files = (char **)malloc(sizeof(char *)); | |
70 | int nfiles = 1; | |
71 | files[0] = strdup(af->fname); | |
72 | ||
73 | char fname[MAXPATHLEN+1]; | |
74 | strlcpy(fname,af->fname,sizeof(fname)); | |
75 | char *ext = strrchr(fname,'.')+1; | |
76 | if(ext-fname > MAXPATHLEN-4){ | |
77 | warn("ewf_open: %s: filename too long",af->fname); | |
78 | return -1; | |
79 | } | |
80 | ||
81 | /* Now open .E02 through .E99 and then .AAA through .ZZZ if they exist... */ | |
82 | for(int i=2;i<=99;i++){ | |
83 | sprintf(ext+1,"%02d",i); | |
84 | if(access(fname,R_OK)!=0) break; | |
85 | files = (char **)realloc(files,(nfiles+1) * sizeof(char *)); | |
86 | files[nfiles] = strdup(fname); | |
87 | nfiles++; | |
88 | } | |
89 | for(int i=4*26*26;i<=26*26*26;i++){ | |
90 | sprintf(ext, "%c%c%c", i/26/26%26+'A', i/26%26+'A', i%26+'A'); | |
91 | if(access(fname,R_OK)!=0) break; // file can't be read | |
92 | files = (char **)realloc(files,(nfiles+1) * sizeof(char *)); | |
93 | files[nfiles] = strdup(fname); | |
94 | nfiles++; | |
95 | } | |
96 | ||
97 | ||
98 | LIBEWF_HANDLE *handle = libewf_open( files, nfiles, LIBEWF_OPEN_READ ); | |
99 | ||
100 | if(!handle){ | |
101 | warn("Unable to open EWF image file"); | |
102 | for(int i=0;i<nfiles;i++) free(files[i]); | |
103 | free(files); | |
104 | return -1; | |
105 | } | |
106 | #if defined( HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE ) || (LIBEWF_VERSION>=20080501) | |
107 | int r = libewf_get_media_size(handle,&af->image_size); | |
108 | if(r < 0){ | |
109 | warn("EFW error: image size==0?"); | |
110 | for(int i=0;i<nfiles;i++) free(files[i]); | |
111 | free(files); | |
112 | return -1; | |
113 | } | |
114 | #else | |
115 | af->image_size = libewf_get_media_size(handle); | |
116 | ||
117 | if( af->image_size == 0 ){ | |
118 | warn("EFW error: image size==0?"); | |
119 | for(int i=0;i<nfiles;i++) free(files[i]); | |
120 | free(files); | |
121 | return -1; | |
122 | } | |
123 | #endif | |
124 | ||
125 | af->vnodeprivate = (void *)handle; | |
126 | #if defined( HAVE_LIBEWF_GET_CHUNK_SIZE_ARGUMENT_VALUE ) || LIBEWF_VERSION>=20080501 | |
127 | libewf_get_chunk_size(handle,(size32_t *)&af->image_pagesize); | |
128 | #else | |
129 | af->image_pagesize = libewf_get_chunk_size(handle); | |
130 | #endif | |
131 | for(int i=0;i<nfiles;i++) free(files[i]); | |
132 | free(files); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | ||
137 | static int ewf_vstat(AFFILE *af,struct af_vnode_info *vni) | |
138 | { | |
139 | LIBEWF_HANDLE *handle = EWF_HANDLE(af); | |
140 | #if defined( HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE ) || LIBEWF_VERSION>=20080501 | |
141 | libewf_get_media_size(handle,(size64_t *)&vni->imagesize); | |
142 | #else | |
143 | vni->imagesize = (int64_t) libewf_get_media_size(handle); | |
144 | #endif | |
145 | ||
146 | vni->pagesize = 0; | |
147 | #if defined( HAVE_LIBEWF_GET_CHUNK_SIZE_ARGUMENT_VALUE ) || LIBEWF_VERSION>=20080501 | |
148 | libewf_get_chunk_size(handle,(size32_t *)&vni->pagesize); | |
149 | #else | |
150 | vni->pagesize = libewf_get_chunk_size(handle); | |
151 | #endif | |
152 | vni->supports_metadata = 1; | |
153 | vni->changable_pagesize = 0; | |
154 | vni->changable_sectorsize = 0; | |
155 | vni->supports_compression = 1; | |
156 | vni->has_pages = 1; // debatable | |
157 | return 0; | |
158 | } | |
159 | ||
160 | static int ewf_read(AFFILE *af, unsigned char *buf, uint64_t pos,size_t count) | |
161 | { | |
162 | LIBEWF_HANDLE *handle = EWF_HANDLE(af); | |
163 | return libewf_read_random(handle,buf,(uint64_t)count,pos); | |
164 | } | |
165 | ||
166 | static int ewf_write(AFFILE *af, unsigned char *buf, uint64_t pos,size_t count) | |
167 | { | |
168 | LIBEWF_HANDLE *handle = EWF_HANDLE(af); | |
169 | return libewf_write_random(handle,buf,(uint64_t)count,pos); | |
170 | } | |
171 | ||
172 | static int ewf_close(AFFILE *af) | |
173 | { | |
174 | LIBEWF_HANDLE *handle = EWF_HANDLE(af); | |
175 | if(libewf_close(handle)<0) return -1; | |
176 | return 0; | |
177 | } | |
178 | ||
179 | ||
180 | static int ewf_rewind_seg(AFFILE *af) | |
181 | { | |
182 | af->cur_page = -1; // starts at the metadata | |
183 | return 0; | |
184 | } | |
185 | ||
186 | ||
187 | /* return the length of a string up to a max */ | |
188 | static int strlenp(const unsigned char *data,int max) | |
189 | { | |
190 | for(int i=0;i<max;i++){ | |
191 | if(data[i]==0) return i; | |
192 | } | |
193 | return max; | |
194 | } | |
195 | ||
196 | static uint32_t ewf_bytes_per_sector(LIBEWF_HANDLE *handle) | |
197 | { | |
198 | uint32_t bps = 0; | |
199 | #if defined( HAVE_LIBEWF_GET_BYTES_PER_SECTOR_ARGUMENT_VALUE ) || LIBEWF_VERSION>=20080501 | |
200 | libewf_get_bytes_per_sector(handle,&bps); | |
201 | #else | |
202 | bps=libewf_get_bytes_per_sector(handle); | |
203 | #endif | |
204 | return bps; | |
205 | } | |
206 | ||
207 | static int ewf_get_seg(AFFILE *af,const char *name, unsigned long *arg, | |
208 | unsigned char *data,size_t *datalen) | |
209 | { | |
210 | LIBEWF_HANDLE *handle = EWF_HANDLE(af); | |
211 | ||
212 | /* Is the user asking for a page? */ | |
213 | int64_t segnum = af_segname_page_number(name); | |
214 | if(segnum>=0){ | |
215 | /* Get the segment number */ | |
216 | if(data==0){ | |
217 | /* Need to make sure that the segment exists */ | |
218 | if(segnum*af->image_pagesize+af->image_pagesize > af->image_size ) return -1; // this segment does not exist | |
219 | if(datalen) *datalen = af->image_pagesize; // just return the chunk size | |
220 | return 0; | |
221 | } | |
222 | size_t r = libewf_read_random(handle,data,*datalen,segnum * af->image_pagesize); | |
223 | return r>0 ? 0 : -1; // should probably put in some error checking | |
224 | } | |
225 | ||
226 | /* See if it is a page name we understand */ | |
227 | if(strcmp(name,AF_PAGESIZE)==0){ | |
228 | if(arg) *arg = af->image_pagesize; | |
229 | return 0; | |
230 | } | |
231 | if(strcmp(name,AF_IMAGESIZE)==0){ | |
232 | if(arg) *arg = 0; | |
233 | if(datalen==0) return 0; | |
234 | if(*datalen==0){ | |
235 | *datalen = 8; // the structure is 8 bytes long | |
236 | return 0; | |
237 | } | |
238 | if(*datalen<8) return -2; | |
239 | ||
240 | struct aff_quad q; | |
241 | q.low = htonl((unsigned long)(af->image_size & 0xffffffff)); | |
242 | q.high = htonl((unsigned long)(af->image_size >> 32)); | |
243 | memcpy(data,&q,8); | |
244 | return 0; | |
245 | } | |
246 | if(strcmp(name,AF_SECTORSIZE)==0){ | |
247 | if(arg) *arg=(unsigned long)ewf_bytes_per_sector(handle); | |
248 | if(datalen) *datalen = 0; | |
249 | return 0; | |
250 | } | |
251 | if(strcmp(name,AF_DEVICE_SECTORS)==0){ | |
252 | /* Is this in flag or a quad word? */ | |
253 | uint32_t bps = ewf_bytes_per_sector(handle); | |
254 | if(arg && bps>0) *arg = af->image_size / bps; | |
255 | if(datalen) *datalen = 0; | |
256 | return 0; | |
257 | } | |
258 | ||
259 | ||
260 | /* They are asking for a metdata segment. If we have wide character type | |
261 | * compiled in for libewf, just ignore it, because afflib doesn't do wide characters | |
262 | * at the moment... | |
263 | */ | |
264 | ||
265 | #if !defined(LIBEWF_WIDE_CHARACTER_TYPE) && defined(LIBEWF_VERSION) && (LIBEWF_VERSION >= 20080322) | |
266 | /* Can't guarentee character type in older versions of libewf */ | |
267 | if(strcmp(name,AF_CASE_NUM)==0){ | |
268 | if(data && datalen){ | |
269 | libewf_get_header_value_case_number(handle,(char *)data,*datalen); | |
270 | *datalen = strlenp(data,*datalen); | |
271 | if(arg) *arg = 0; | |
272 | } | |
273 | return 0; | |
274 | } | |
275 | if(strcmp(name,AF_IMAGE_GID)==0){ | |
276 | if(data && datalen){ | |
277 | libewf_get_guid(handle,data,*datalen); | |
278 | if(arg) *arg = 0; | |
279 | } | |
280 | return 0; | |
281 | } | |
282 | if(strcmp(name,AF_ACQUISITION_NOTES)==0){ | |
283 | if(data && datalen){ | |
284 | libewf_get_header_value_notes(handle,(char *)data,*datalen); | |
285 | *datalen = strlenp(data,*datalen); | |
286 | } | |
287 | if(data==0 && datalen){ | |
288 | /* Caller wants to learn size of the notes */ | |
289 | unsigned char tmp[128]; | |
290 | memset(tmp,0,sizeof(tmp)); | |
291 | *datalen = sizeof(tmp); | |
292 | libewf_get_header_value_notes(handle,(char *)tmp,*datalen); | |
293 | *datalen = strlenp(tmp,*datalen); | |
294 | } | |
295 | if(arg) *arg = 0; | |
296 | return 0; | |
297 | } | |
298 | #endif | |
299 | return -1; // don't know this header | |
300 | } | |
301 | ||
302 | static const char *emap[] = { | |
303 | AF_PAGESIZE, | |
304 | AF_IMAGESIZE, | |
305 | AF_SECTORSIZE, | |
306 | AF_DEVICE_SECTORS, | |
307 | AF_CASE_NUM, | |
308 | AF_IMAGE_GID, | |
309 | AF_ACQUISITION_NOTES, | |
310 | 0 | |
311 | }; | |
312 | ||
313 | ||
314 | static int ewf_get_next_seg(AFFILE *af,char *segname,size_t segname_len,unsigned long *arg, | |
315 | unsigned char *data,size_t *datalen) | |
316 | { | |
317 | /* Figure out what the next segment would be, then get it */ | |
318 | /* Metadata first */ | |
319 | if(af->cur_page<0){ | |
320 | /* Find out how many mapped segments there are */ | |
321 | int mapped=0; | |
322 | for(mapped=0;emap[mapped];mapped++){ | |
323 | } | |
324 | if(-af->cur_page >= mapped ){ | |
325 | af->cur_page = 0; | |
326 | goto get_next_data_seg; | |
327 | } | |
328 | int which = 0 - af->cur_page; // which one to get | |
329 | af->cur_page--; // go to the next one | |
330 | if(segname_len < strlen(emap[which])) return -2; // not enough room for segname | |
331 | strlcpy(segname,emap[which],segname_len); // give caller the name of the mapped segment. | |
332 | return ewf_get_seg(af,segname,arg,data,datalen); | |
333 | } | |
334 | ||
335 | get_next_data_seg: | |
336 | if(af->cur_page * af->image_pagesize >= af->image_size) return -1; // end of list | |
337 | /* Make the segment name */ | |
338 | char pagename[AF_MAX_NAME_LEN]; // | |
339 | memset(pagename,0,sizeof(pagename)); | |
340 | snprintf(pagename,sizeof(pagename),AF_PAGE,af->cur_page++); | |
341 | ||
342 | int r = 0; | |
343 | /* Get the segment, if it is wanted */ | |
344 | if(data) r = ewf_get_seg(af,pagename,arg,data,datalen); | |
345 | ||
346 | /* If r==0 and there is room for copying in the segment name, return it */ | |
347 | if(r==0){ | |
348 | if(strlen(pagename)+1 < segname_len){ | |
349 | strlcpy(segname,pagename,segname_len); | |
350 | return 0; | |
351 | } | |
352 | /* segname wasn't big enough */ | |
353 | return -2; | |
354 | } | |
355 | return r; // some other error | |
356 | } | |
357 | ||
358 | struct af_vnode vnode_ewf = { | |
359 | AF_IDENTIFY_EWF, | |
360 | AF_VNODE_TYPE_PRIMITIVE|AF_VNODE_NO_SIGNING|AF_VNODE_NO_SEALING, | |
361 | "LIBEWF", | |
362 | ewf_identify_file, | |
363 | ewf_open, | |
364 | ewf_close, | |
365 | ewf_vstat, | |
366 | ewf_get_seg, // get seg | |
367 | ewf_get_next_seg, // get_next_seg | |
368 | ewf_rewind_seg, // rewind_seg | |
369 | 0, // update_seg | |
370 | 0, // del_seg | |
371 | ewf_read, // read | |
372 | ewf_write // write | |
373 | }; | |
374 | ||
375 | #endif |
182 | 182 | int fd; |
183 | 183 | struct stat sb; |
184 | 184 | |
185 | fd = open(srp->first_raw_fname, af->openflags|O_BINARY, 0666); | |
185 | fd = open(srp->first_raw_fname, af->openflags|O_BINARY, af->openmode); | |
186 | 186 | if (fd < 0) { |
187 | 187 | (*af->error_reporter)("split_raw_open_internal: open(%s): ",af->fname); |
188 | 188 | return -1; |
374 | 374 | if (af->maxsize) { // do we need to possibly split into multiple file writes? |
375 | 375 | /* Figure out which file number we will need to write to... */ |
376 | 376 | if (pos >= (af->maxsize * srp->num_raw_files)) { |
377 | int fd = open(srp->next_raw_fname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0666); | |
377 | int fd = open(srp->next_raw_fname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, af->openmode); | |
378 | 378 | if (fd < 0) { |
379 | 379 | (*af->error_reporter)("split_raw_write: open(%s): ",af->fname); |
380 | 380 | if (ret) return ret; |
187 | 187 | target_alias = @target_alias@ |
188 | 188 | top_builddir = @top_builddir@ |
189 | 189 | top_srcdir = @top_srcdir@ |
190 | dist_man_MANS = afcat.1 | |
190 | dist_man_MANS = affcat.1 | |
191 | 191 | all: all-am |
192 | 192 | |
193 | 193 | .SUFFIXES: |
0 | .\" Process this file with | |
1 | .\" groff -man -Tascii foo.1 | |
2 | .\" | |
3 | .TH AFCAT 1 "OCT 2008" "User Manuals" | |
4 | .SH NAME | |
5 | afcat \- Output contents of an image file to stdout. | |
6 | .SH SYNOPSIS | |
7 | .B afcat [options] | |
8 | .I image [images] | |
9 | .SH DESCRIPTION | |
10 | .B affcat | |
11 | outputs the contents of an image file to stdout. Image files that are not raw but are recognized | |
12 | by AFF will be output in raw format. Missing pages will not be padded, but the fact that they are missing | |
13 | will be noted on STDERR. | |
14 | ||
15 | The options are as follows: | |
16 | .IP "-s name" | |
17 | Output the named segment, instead of the image data. This is a way to output metadata. | |
18 | .IP "-p nnn" | |
19 | Just output page number | |
20 | .B nnn | |
21 | .IP "-S nnn" | |
22 | Just output data sector number | |
23 | .B nnn. | |
24 | Sector #0 is the first sector. | |
25 | .IP "-q" | |
26 | Quiet mode. Don't print to STDERR if a page is skipped because it is not present. | |
27 | .IP "-n" | |
28 | Noisy mode. Tell when pages are skipped. | |
29 | .IP "-l" | |
30 | List all the segment names, rather than outputing data. | |
31 | .IP "-L" | |
32 | List Long. Prints segment names, lengths, and args. | |
33 | .IP "-d" | |
34 | Debug mode. Print the page numbers to stderr as data goes to stdout. | |
35 | .IP "-b" | |
36 | Output BADFALG for bad blocks (default is to output NULLs). | |
37 | .IP "-v" | |
38 | Just print the version number and exit. | |
39 | .IP "-r offset:count" | |
40 | Seek to the given byte offset and output count characters in each file; may be repeated. | |
41 | .SH HISTORY | |
42 | .BR "afcat" " first appeared in " "AFFLIB" " v1.00." | |
43 | .SH AUTHOR | |
44 | Simson Garfinkel <simsong@acm.org> | |
45 |
0 | .\" Process this file with | |
1 | .\" groff -man -Tascii foo.1 | |
2 | .\" | |
3 | .TH AFCAT 1 "OCT 2008" "User Manuals" | |
4 | .SH NAME | |
5 | afcat \- Output contents of an image file to stdout. | |
6 | .SH SYNOPSIS | |
7 | .B afcat [options] | |
8 | .I image [images] | |
9 | .SH DESCRIPTION | |
10 | .B affcat | |
11 | outputs the contents of an image file to stdout. Image files that are not raw but are recognized | |
12 | by AFF will be output in raw format. Missing pages will not be padded, but the fact that they are missing | |
13 | will be noted on STDERR. | |
14 | ||
15 | The options are as follows: | |
16 | .IP "-s name" | |
17 | Output the named segment, instead of the image data. This is a way to output metadata. | |
18 | .IP "-p nnn" | |
19 | Just output page number | |
20 | .B nnn | |
21 | .IP "-S nnn" | |
22 | Just output data sector number | |
23 | .B nnn. | |
24 | Sector #0 is the first sector. | |
25 | .IP "-q" | |
26 | Quiet mode. Don't print to STDERR if a page is skipped because it is not present. | |
27 | .IP "-n" | |
28 | Noisy mode. Tell when pages are skipped. | |
29 | .IP "-l" | |
30 | List all the segment names, rather than outputing data. | |
31 | .IP "-L" | |
32 | List Long. Prints segment names, lengths, and args. | |
33 | .IP "-d" | |
34 | Debug mode. Print the page numbers to stderr as data goes to stdout. | |
35 | .IP "-b" | |
36 | Output BADFALG for bad blocks (default is to output NULLs). | |
37 | .IP "-v" | |
38 | Just print the version number and exit. | |
39 | .IP "-r offset:count" | |
40 | Seek to the given byte offset and output count characters in each file; may be repeated. | |
41 | .SH HISTORY | |
42 | .BR "afcat" " first appeared in " "AFFLIB" " v1.00." | |
43 | .SH AUTHOR | |
44 | Simson Garfinkel <simsong@acm.org> | |
45 |
5 | 5 | srcdir=. |
6 | 6 | fi |
7 | 7 | |
8 | if ( ../tools/afcompare file://:password@/$srcdir/encrypted.aff $srcdir/encrypted.iso ) ; then | |
8 | if ( ../tools/affcompare file://:password@/$srcdir/encrypted.aff $srcdir/encrypted.iso ) ; then | |
9 | 9 | echo Verifies with correct decryption passphrase. |
10 | 10 | else |
11 | 11 | echo Does not verify with correct decryption passphrase. |
13 | 13 | fi |
14 | 14 | |
15 | 15 | |
16 | echo This next afcompare should generate an error: | |
17 | if ( ../tools/afcompare file://:wrongphrase@/$srcdir/encrypted.aff $srcdir/encrypted.iso ) ; then | |
16 | echo This next affcompare should generate an error: | |
17 | if ( ../tools/affcompare file://:wrongphrase@/$srcdir/encrypted.aff $srcdir/encrypted.iso ) ; then | |
18 | 18 | echo Does not verify with correct decryption passphrase. |
19 | 19 | exit 1 |
20 | 20 | else |
16 | 16 | cmd("rm -rf %s %s %s %s" % (iso,iso2,i1,i2)) |
17 | 17 | cmd("./makeimage %s 100000",(iso)) |
18 | 18 | cmd("../aimage/aimage %s -q -E %s %s" % (maxsize,iso,i1)) |
19 | cmd("../tools/afconvert %s -o %s %s" % (maxsize,i2,iso)) | |
20 | cmd("../tools/afinfo -mS %s" % (i1)) | |
21 | cmd("../tools/afinfo -mS %s" % (i2)) | |
22 | cmd("../tools/afcompare %s %s" % (iso,i1)) | |
23 | cmd("../tools/afcompare %s %s" % (iso,i2)) | |
24 | cmd("../tools/afconvert -r -o %s %s" % (iso,i1)) | |
25 | cmd("../tools/afcat %s > %s" % (i2,iso2)) | |
19 | cmd("../tools/affconvert %s -o %s %s" % (maxsize,i2,iso)) | |
20 | cmd("../tools/affinfo -mS %s" % (i1)) | |
21 | cmd("../tools/affinfo -mS %s" % (i2)) | |
22 | cmd("../tools/affcompare %s %s" % (iso,i1)) | |
23 | cmd("../tools/affcompare %s %s" % (iso,i2)) | |
24 | cmd("../tools/affconvert -r -o %s %s" % (iso,i1)) | |
25 | cmd("../tools/affcat %s > %s" % (i2,iso2)) | |
26 | 26 | cmd("cmp %s %s" % (iso,iso2)) |
27 | 27 | cmd("rm -rf %s %s %s %s" % (iso,iso2,i1,i2)) |
28 | 28 |
0 | bin_PROGRAMS = afcat afcompare afconvert afcopy afcrypto affix afinfo afsegment \ | |
1 | afstats afverify afxml affuse afrecover afsign afdiskprint | |
0 | bin_PROGRAMS = affcat affcompare affconvert affcopy affcrypto affix affinfo affsegment \ | |
1 | affstats affverify affxml affuse affrecover affsign affdiskprint | |
2 | 2 | |
3 | 3 | EXTRA_DIST = test_make_random_iso.sh test_crypto.sh test_signing.sh test_recovery.sh \ |
4 | 4 | test_passphrase.sh test_afsegment.sh |
9 | 9 | |
10 | 10 | AM_LDFLAGS = -static # staticly link our tools (easier debugging) |
11 | 11 | |
12 | afcat_SOURCES = afcat.cpp | |
12 | affcat_SOURCES = affcat.cpp | |
13 | 13 | |
14 | afcrypto_SOURCES = afcrypto.cpp | |
15 | afcompare_SOURCES = afcompare.cpp unix4win32.h | |
16 | afconvert_SOURCES = afconvert.cpp unix4win32.h | |
17 | afcopy_SOURCES = afcopy.cpp unix4win32.h aff_bom.h aff_bom.cpp | |
18 | afdiskprint_SOURCES = afdiskprint.cpp unix4win32.h hashextent.h | |
14 | affcrypto_SOURCES = affcrypto.cpp | |
15 | affcompare_SOURCES = affcompare.cpp unix4win32.h | |
16 | affconvert_SOURCES = affconvert.cpp unix4win32.h | |
17 | affcopy_SOURCES = affcopy.cpp unix4win32.h aff_bom.h aff_bom.cpp | |
18 | affdiskprint_SOURCES = affdiskprint.cpp unix4win32.h hashextent.h | |
19 | 19 | affix_SOURCES = affix.cpp unix4win32.h |
20 | 20 | affuse_SOURCES = affuse.c |
21 | afinfo_SOURCES = afinfo.cpp unix4win32.h | |
22 | afrecover_SOURCES = afrecover.cpp unix4win32.h | |
23 | afsegment_SOURCES = afsegment.cpp | |
24 | afsign_SOURCES = afsign.cpp aff_bom.h aff_bom.cpp | |
25 | afstats_SOURCES = afstats.cpp | |
26 | afverify_SOURCES = afverify.cpp aff_bom.h aff_bom.cpp | |
27 | afxml_SOURCES = afxml.cpp unix4win32.h | |
21 | affinfo_SOURCES = affinfo.cpp unix4win32.h | |
22 | affrecover_SOURCES = affrecover.cpp unix4win32.h | |
23 | affsegment_SOURCES = affsegment.cpp | |
24 | affsign_SOURCES = affsign.cpp aff_bom.h aff_bom.cpp | |
25 | affstats_SOURCES = affstats.cpp | |
26 | affverify_SOURCES = affverify.cpp aff_bom.h aff_bom.cpp | |
27 | affxml_SOURCES = affxml.cpp unix4win32.h | |
28 | 28 | |
29 | 29 | INCLUDES = -I@top_srcdir@/lib/ |
30 | 30 | LDADD = @top_builddir@/lib/libafflib.la |
31 | 31 | POST_UNINSTALL = : |
32 | 32 | build_triplet = @build@ |
33 | 33 | host_triplet = @host@ |
34 | bin_PROGRAMS = afcat$(EXEEXT) afcompare$(EXEEXT) afconvert$(EXEEXT) \ | |
35 | afcopy$(EXEEXT) afcrypto$(EXEEXT) affix$(EXEEXT) \ | |
36 | afinfo$(EXEEXT) afsegment$(EXEEXT) afstats$(EXEEXT) \ | |
37 | afverify$(EXEEXT) afxml$(EXEEXT) affuse$(EXEEXT) \ | |
38 | afrecover$(EXEEXT) afsign$(EXEEXT) afdiskprint$(EXEEXT) | |
34 | bin_PROGRAMS = affcat$(EXEEXT) affcompare$(EXEEXT) affconvert$(EXEEXT) \ | |
35 | affcopy$(EXEEXT) affcrypto$(EXEEXT) affix$(EXEEXT) \ | |
36 | affinfo$(EXEEXT) affsegment$(EXEEXT) affstats$(EXEEXT) \ | |
37 | affverify$(EXEEXT) affxml$(EXEEXT) affuse$(EXEEXT) \ | |
38 | affrecover$(EXEEXT) affsign$(EXEEXT) affdiskprint$(EXEEXT) | |
39 | 39 | subdir = tools |
40 | 40 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in |
41 | 41 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 |
49 | 49 | am__installdirs = "$(DESTDIR)$(bindir)" |
50 | 50 | binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) |
51 | 51 | PROGRAMS = $(bin_PROGRAMS) |
52 | am_afcat_OBJECTS = afcat.$(OBJEXT) | |
53 | afcat_OBJECTS = $(am_afcat_OBJECTS) | |
54 | afcat_LDADD = $(LDADD) | |
55 | afcat_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
56 | am_afcompare_OBJECTS = afcompare.$(OBJEXT) | |
57 | afcompare_OBJECTS = $(am_afcompare_OBJECTS) | |
58 | afcompare_LDADD = $(LDADD) | |
59 | afcompare_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
60 | am_afconvert_OBJECTS = afconvert.$(OBJEXT) | |
61 | afconvert_OBJECTS = $(am_afconvert_OBJECTS) | |
62 | afconvert_LDADD = $(LDADD) | |
63 | afconvert_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
64 | am_afcopy_OBJECTS = afcopy.$(OBJEXT) aff_bom.$(OBJEXT) | |
65 | afcopy_OBJECTS = $(am_afcopy_OBJECTS) | |
66 | afcopy_LDADD = $(LDADD) | |
67 | afcopy_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
68 | am_afcrypto_OBJECTS = afcrypto.$(OBJEXT) | |
69 | afcrypto_OBJECTS = $(am_afcrypto_OBJECTS) | |
70 | afcrypto_LDADD = $(LDADD) | |
71 | afcrypto_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
72 | am_afdiskprint_OBJECTS = afdiskprint.$(OBJEXT) | |
73 | afdiskprint_OBJECTS = $(am_afdiskprint_OBJECTS) | |
74 | afdiskprint_LDADD = $(LDADD) | |
75 | afdiskprint_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
52 | am_affcat_OBJECTS = affcat.$(OBJEXT) | |
53 | affcat_OBJECTS = $(am_affcat_OBJECTS) | |
54 | affcat_LDADD = $(LDADD) | |
55 | affcat_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
56 | am_affcompare_OBJECTS = affcompare.$(OBJEXT) | |
57 | affcompare_OBJECTS = $(am_affcompare_OBJECTS) | |
58 | affcompare_LDADD = $(LDADD) | |
59 | affcompare_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
60 | am_affconvert_OBJECTS = affconvert.$(OBJEXT) | |
61 | affconvert_OBJECTS = $(am_affconvert_OBJECTS) | |
62 | affconvert_LDADD = $(LDADD) | |
63 | affconvert_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
64 | am_affcopy_OBJECTS = affcopy.$(OBJEXT) aff_bom.$(OBJEXT) | |
65 | affcopy_OBJECTS = $(am_affcopy_OBJECTS) | |
66 | affcopy_LDADD = $(LDADD) | |
67 | affcopy_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
68 | am_affcrypto_OBJECTS = affcrypto.$(OBJEXT) | |
69 | affcrypto_OBJECTS = $(am_affcrypto_OBJECTS) | |
70 | affcrypto_LDADD = $(LDADD) | |
71 | affcrypto_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
72 | am_affdiskprint_OBJECTS = affdiskprint.$(OBJEXT) | |
73 | affdiskprint_OBJECTS = $(am_affdiskprint_OBJECTS) | |
74 | affdiskprint_LDADD = $(LDADD) | |
75 | affdiskprint_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
76 | am_affinfo_OBJECTS = affinfo.$(OBJEXT) | |
77 | affinfo_OBJECTS = $(am_affinfo_OBJECTS) | |
78 | affinfo_LDADD = $(LDADD) | |
79 | affinfo_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
76 | 80 | am_affix_OBJECTS = affix.$(OBJEXT) |
77 | 81 | affix_OBJECTS = $(am_affix_OBJECTS) |
78 | 82 | affix_LDADD = $(LDADD) |
79 | 83 | affix_DEPENDENCIES = @top_builddir@/lib/libafflib.la |
84 | am_affrecover_OBJECTS = affrecover.$(OBJEXT) | |
85 | affrecover_OBJECTS = $(am_affrecover_OBJECTS) | |
86 | affrecover_LDADD = $(LDADD) | |
87 | affrecover_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
88 | am_affsegment_OBJECTS = affsegment.$(OBJEXT) | |
89 | affsegment_OBJECTS = $(am_affsegment_OBJECTS) | |
90 | affsegment_LDADD = $(LDADD) | |
91 | affsegment_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
92 | am_affsign_OBJECTS = affsign.$(OBJEXT) aff_bom.$(OBJEXT) | |
93 | affsign_OBJECTS = $(am_affsign_OBJECTS) | |
94 | affsign_LDADD = $(LDADD) | |
95 | affsign_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
96 | am_affstats_OBJECTS = affstats.$(OBJEXT) | |
97 | affstats_OBJECTS = $(am_affstats_OBJECTS) | |
98 | affstats_LDADD = $(LDADD) | |
99 | affstats_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
80 | 100 | am_affuse_OBJECTS = affuse-affuse.$(OBJEXT) |
81 | 101 | affuse_OBJECTS = $(am_affuse_OBJECTS) |
82 | 102 | affuse_DEPENDENCIES = @top_builddir@/lib/libafflib.la |
83 | am_afinfo_OBJECTS = afinfo.$(OBJEXT) | |
84 | afinfo_OBJECTS = $(am_afinfo_OBJECTS) | |
85 | afinfo_LDADD = $(LDADD) | |
86 | afinfo_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
87 | am_afrecover_OBJECTS = afrecover.$(OBJEXT) | |
88 | afrecover_OBJECTS = $(am_afrecover_OBJECTS) | |
89 | afrecover_LDADD = $(LDADD) | |
90 | afrecover_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
91 | am_afsegment_OBJECTS = afsegment.$(OBJEXT) | |
92 | afsegment_OBJECTS = $(am_afsegment_OBJECTS) | |
93 | afsegment_LDADD = $(LDADD) | |
94 | afsegment_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
95 | am_afsign_OBJECTS = afsign.$(OBJEXT) aff_bom.$(OBJEXT) | |
96 | afsign_OBJECTS = $(am_afsign_OBJECTS) | |
97 | afsign_LDADD = $(LDADD) | |
98 | afsign_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
99 | am_afstats_OBJECTS = afstats.$(OBJEXT) | |
100 | afstats_OBJECTS = $(am_afstats_OBJECTS) | |
101 | afstats_LDADD = $(LDADD) | |
102 | afstats_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
103 | am_afverify_OBJECTS = afverify.$(OBJEXT) aff_bom.$(OBJEXT) | |
104 | afverify_OBJECTS = $(am_afverify_OBJECTS) | |
105 | afverify_LDADD = $(LDADD) | |
106 | afverify_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
107 | am_afxml_OBJECTS = afxml.$(OBJEXT) | |
108 | afxml_OBJECTS = $(am_afxml_OBJECTS) | |
109 | afxml_LDADD = $(LDADD) | |
110 | afxml_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
103 | am_affverify_OBJECTS = affverify.$(OBJEXT) aff_bom.$(OBJEXT) | |
104 | affverify_OBJECTS = $(am_affverify_OBJECTS) | |
105 | affverify_LDADD = $(LDADD) | |
106 | affverify_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
107 | am_affxml_OBJECTS = affxml.$(OBJEXT) | |
108 | affxml_OBJECTS = $(am_affxml_OBJECTS) | |
109 | affxml_LDADD = $(LDADD) | |
110 | affxml_DEPENDENCIES = @top_builddir@/lib/libafflib.la | |
111 | 111 | DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ |
112 | 112 | depcomp = $(SHELL) $(top_srcdir)/depcomp |
113 | 113 | am__depfiles_maybe = depfiles |
129 | 129 | CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ |
130 | 130 | --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ |
131 | 131 | $(LDFLAGS) -o $@ |
132 | SOURCES = $(afcat_SOURCES) $(afcompare_SOURCES) $(afconvert_SOURCES) \ | |
133 | $(afcopy_SOURCES) $(afcrypto_SOURCES) $(afdiskprint_SOURCES) \ | |
134 | $(affix_SOURCES) $(affuse_SOURCES) $(afinfo_SOURCES) \ | |
135 | $(afrecover_SOURCES) $(afsegment_SOURCES) $(afsign_SOURCES) \ | |
136 | $(afstats_SOURCES) $(afverify_SOURCES) $(afxml_SOURCES) | |
137 | DIST_SOURCES = $(afcat_SOURCES) $(afcompare_SOURCES) \ | |
138 | $(afconvert_SOURCES) $(afcopy_SOURCES) $(afcrypto_SOURCES) \ | |
139 | $(afdiskprint_SOURCES) $(affix_SOURCES) $(affuse_SOURCES) \ | |
140 | $(afinfo_SOURCES) $(afrecover_SOURCES) $(afsegment_SOURCES) \ | |
141 | $(afsign_SOURCES) $(afstats_SOURCES) $(afverify_SOURCES) \ | |
142 | $(afxml_SOURCES) | |
132 | SOURCES = $(affcat_SOURCES) $(affcompare_SOURCES) \ | |
133 | $(affconvert_SOURCES) $(affcopy_SOURCES) $(affcrypto_SOURCES) \ | |
134 | $(affdiskprint_SOURCES) $(affinfo_SOURCES) $(affix_SOURCES) \ | |
135 | $(affrecover_SOURCES) $(affsegment_SOURCES) $(affsign_SOURCES) \ | |
136 | $(affstats_SOURCES) $(affuse_SOURCES) $(affverify_SOURCES) \ | |
137 | $(affxml_SOURCES) | |
138 | DIST_SOURCES = $(affcat_SOURCES) $(affcompare_SOURCES) \ | |
139 | $(affconvert_SOURCES) $(affcopy_SOURCES) $(affcrypto_SOURCES) \ | |
140 | $(affdiskprint_SOURCES) $(affinfo_SOURCES) $(affix_SOURCES) \ | |
141 | $(affrecover_SOURCES) $(affsegment_SOURCES) $(affsign_SOURCES) \ | |
142 | $(affstats_SOURCES) $(affuse_SOURCES) $(affverify_SOURCES) \ | |
143 | $(affxml_SOURCES) | |
143 | 144 | ETAGS = etags |
144 | 145 | CTAGS = ctags |
145 | 146 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) |
289 | 290 | |
290 | 291 | # See http://www.gnu.org/software/libtool/manual.html # Using-Automake |
291 | 292 | AM_LDFLAGS = -static # staticly link our tools (easier debugging) |
292 | afcat_SOURCES = afcat.cpp | |
293 | afcrypto_SOURCES = afcrypto.cpp | |
294 | afcompare_SOURCES = afcompare.cpp unix4win32.h | |
295 | afconvert_SOURCES = afconvert.cpp unix4win32.h | |
296 | afcopy_SOURCES = afcopy.cpp unix4win32.h aff_bom.h aff_bom.cpp | |
297 | afdiskprint_SOURCES = afdiskprint.cpp unix4win32.h hashextent.h | |
293 | affcat_SOURCES = affcat.cpp | |
294 | affcrypto_SOURCES = affcrypto.cpp | |
295 | affcompare_SOURCES = affcompare.cpp unix4win32.h | |
296 | affconvert_SOURCES = affconvert.cpp unix4win32.h | |
297 | affcopy_SOURCES = affcopy.cpp unix4win32.h aff_bom.h aff_bom.cpp | |
298 | affdiskprint_SOURCES = affdiskprint.cpp unix4win32.h hashextent.h | |
298 | 299 | affix_SOURCES = affix.cpp unix4win32.h |
299 | 300 | affuse_SOURCES = affuse.c |
300 | afinfo_SOURCES = afinfo.cpp unix4win32.h | |
301 | afrecover_SOURCES = afrecover.cpp unix4win32.h | |
302 | afsegment_SOURCES = afsegment.cpp | |
303 | afsign_SOURCES = afsign.cpp aff_bom.h aff_bom.cpp | |
304 | afstats_SOURCES = afstats.cpp | |
305 | afverify_SOURCES = afverify.cpp aff_bom.h aff_bom.cpp | |
306 | afxml_SOURCES = afxml.cpp unix4win32.h | |
301 | affinfo_SOURCES = affinfo.cpp unix4win32.h | |
302 | affrecover_SOURCES = affrecover.cpp unix4win32.h | |
303 | affsegment_SOURCES = affsegment.cpp | |
304 | affsign_SOURCES = affsign.cpp aff_bom.h aff_bom.cpp | |
305 | affstats_SOURCES = affstats.cpp | |
306 | affverify_SOURCES = affverify.cpp aff_bom.h aff_bom.cpp | |
307 | affxml_SOURCES = affxml.cpp unix4win32.h | |
307 | 308 | INCLUDES = -I@top_srcdir@/lib/ |
308 | 309 | LDADD = @top_builddir@/lib/libafflib.la |
309 | 310 | affuse_CFLAGS = @FUSE_CFLAGS@ |
373 | 374 | echo " rm -f $$p $$f"; \ |
374 | 375 | rm -f $$p $$f ; \ |
375 | 376 | done |
376 | afcat$(EXEEXT): $(afcat_OBJECTS) $(afcat_DEPENDENCIES) | |
377 | @rm -f afcat$(EXEEXT) | |
378 | $(CXXLINK) $(afcat_OBJECTS) $(afcat_LDADD) $(LIBS) | |
379 | afcompare$(EXEEXT): $(afcompare_OBJECTS) $(afcompare_DEPENDENCIES) | |
380 | @rm -f afcompare$(EXEEXT) | |
381 | $(CXXLINK) $(afcompare_OBJECTS) $(afcompare_LDADD) $(LIBS) | |
382 | afconvert$(EXEEXT): $(afconvert_OBJECTS) $(afconvert_DEPENDENCIES) | |
383 | @rm -f afconvert$(EXEEXT) | |
384 | $(CXXLINK) $(afconvert_OBJECTS) $(afconvert_LDADD) $(LIBS) | |
385 | afcopy$(EXEEXT): $(afcopy_OBJECTS) $(afcopy_DEPENDENCIES) | |
386 | @rm -f afcopy$(EXEEXT) | |
387 | $(CXXLINK) $(afcopy_OBJECTS) $(afcopy_LDADD) $(LIBS) | |
388 | afcrypto$(EXEEXT): $(afcrypto_OBJECTS) $(afcrypto_DEPENDENCIES) | |
389 | @rm -f afcrypto$(EXEEXT) | |
390 | $(CXXLINK) $(afcrypto_OBJECTS) $(afcrypto_LDADD) $(LIBS) | |
391 | afdiskprint$(EXEEXT): $(afdiskprint_OBJECTS) $(afdiskprint_DEPENDENCIES) | |
392 | @rm -f afdiskprint$(EXEEXT) | |
393 | $(CXXLINK) $(afdiskprint_OBJECTS) $(afdiskprint_LDADD) $(LIBS) | |
377 | affcat$(EXEEXT): $(affcat_OBJECTS) $(affcat_DEPENDENCIES) | |
378 | @rm -f affcat$(EXEEXT) | |
379 | $(CXXLINK) $(affcat_OBJECTS) $(affcat_LDADD) $(LIBS) | |
380 | affcompare$(EXEEXT): $(affcompare_OBJECTS) $(affcompare_DEPENDENCIES) | |
381 | @rm -f affcompare$(EXEEXT) | |
382 | $(CXXLINK) $(affcompare_OBJECTS) $(affcompare_LDADD) $(LIBS) | |
383 | affconvert$(EXEEXT): $(affconvert_OBJECTS) $(affconvert_DEPENDENCIES) | |
384 | @rm -f affconvert$(EXEEXT) | |
385 | $(CXXLINK) $(affconvert_OBJECTS) $(affconvert_LDADD) $(LIBS) | |
386 | affcopy$(EXEEXT): $(affcopy_OBJECTS) $(affcopy_DEPENDENCIES) | |
387 | @rm -f affcopy$(EXEEXT) | |
388 | $(CXXLINK) $(affcopy_OBJECTS) $(affcopy_LDADD) $(LIBS) | |
389 | affcrypto$(EXEEXT): $(affcrypto_OBJECTS) $(affcrypto_DEPENDENCIES) | |
390 | @rm -f affcrypto$(EXEEXT) | |
391 | $(CXXLINK) $(affcrypto_OBJECTS) $(affcrypto_LDADD) $(LIBS) | |
392 | affdiskprint$(EXEEXT): $(affdiskprint_OBJECTS) $(affdiskprint_DEPENDENCIES) | |
393 | @rm -f affdiskprint$(EXEEXT) | |
394 | $(CXXLINK) $(affdiskprint_OBJECTS) $(affdiskprint_LDADD) $(LIBS) | |
395 | affinfo$(EXEEXT): $(affinfo_OBJECTS) $(affinfo_DEPENDENCIES) | |
396 | @rm -f affinfo$(EXEEXT) | |
397 | $(CXXLINK) $(affinfo_OBJECTS) $(affinfo_LDADD) $(LIBS) | |
394 | 398 | affix$(EXEEXT): $(affix_OBJECTS) $(affix_DEPENDENCIES) |
395 | 399 | @rm -f affix$(EXEEXT) |
396 | 400 | $(CXXLINK) $(affix_OBJECTS) $(affix_LDADD) $(LIBS) |
401 | affrecover$(EXEEXT): $(affrecover_OBJECTS) $(affrecover_DEPENDENCIES) | |
402 | @rm -f affrecover$(EXEEXT) | |
403 | $(CXXLINK) $(affrecover_OBJECTS) $(affrecover_LDADD) $(LIBS) | |
404 | affsegment$(EXEEXT): $(affsegment_OBJECTS) $(affsegment_DEPENDENCIES) | |
405 | @rm -f affsegment$(EXEEXT) | |
406 | $(CXXLINK) $(affsegment_OBJECTS) $(affsegment_LDADD) $(LIBS) | |
407 | affsign$(EXEEXT): $(affsign_OBJECTS) $(affsign_DEPENDENCIES) | |
408 | @rm -f affsign$(EXEEXT) | |
409 | $(CXXLINK) $(affsign_OBJECTS) $(affsign_LDADD) $(LIBS) | |
410 | affstats$(EXEEXT): $(affstats_OBJECTS) $(affstats_DEPENDENCIES) | |
411 | @rm -f affstats$(EXEEXT) | |
412 | $(CXXLINK) $(affstats_OBJECTS) $(affstats_LDADD) $(LIBS) | |
397 | 413 | affuse$(EXEEXT): $(affuse_OBJECTS) $(affuse_DEPENDENCIES) |
398 | 414 | @rm -f affuse$(EXEEXT) |
399 | 415 | $(affuse_LINK) $(affuse_OBJECTS) $(affuse_LDADD) $(LIBS) |
400 | afinfo$(EXEEXT): $(afinfo_OBJECTS) $(afinfo_DEPENDENCIES) | |
401 | @rm -f afinfo$(EXEEXT) | |
402 | $(CXXLINK) $(afinfo_OBJECTS) $(afinfo_LDADD) $(LIBS) | |
403 | afrecover$(EXEEXT): $(afrecover_OBJECTS) $(afrecover_DEPENDENCIES) | |
404 | @rm -f afrecover$(EXEEXT) | |
405 | $(CXXLINK) $(afrecover_OBJECTS) $(afrecover_LDADD) $(LIBS) | |
406 | afsegment$(EXEEXT): $(afsegment_OBJECTS) $(afsegment_DEPENDENCIES) | |
407 | @rm -f afsegment$(EXEEXT) | |
408 | $(CXXLINK) $(afsegment_OBJECTS) $(afsegment_LDADD) $(LIBS) | |
409 | afsign$(EXEEXT): $(afsign_OBJECTS) $(afsign_DEPENDENCIES) | |
410 | @rm -f afsign$(EXEEXT) | |
411 | $(CXXLINK) $(afsign_OBJECTS) $(afsign_LDADD) $(LIBS) | |
412 | afstats$(EXEEXT): $(afstats_OBJECTS) $(afstats_DEPENDENCIES) | |
413 | @rm -f afstats$(EXEEXT) | |
414 | $(CXXLINK) $(afstats_OBJECTS) $(afstats_LDADD) $(LIBS) | |
415 | afverify$(EXEEXT): $(afverify_OBJECTS) $(afverify_DEPENDENCIES) | |
416 | @rm -f afverify$(EXEEXT) | |
417 | $(CXXLINK) $(afverify_OBJECTS) $(afverify_LDADD) $(LIBS) | |
418 | afxml$(EXEEXT): $(afxml_OBJECTS) $(afxml_DEPENDENCIES) | |
419 | @rm -f afxml$(EXEEXT) | |
420 | $(CXXLINK) $(afxml_OBJECTS) $(afxml_LDADD) $(LIBS) | |
416 | affverify$(EXEEXT): $(affverify_OBJECTS) $(affverify_DEPENDENCIES) | |
417 | @rm -f affverify$(EXEEXT) | |
418 | $(CXXLINK) $(affverify_OBJECTS) $(affverify_LDADD) $(LIBS) | |
419 | affxml$(EXEEXT): $(affxml_OBJECTS) $(affxml_DEPENDENCIES) | |
420 | @rm -f affxml$(EXEEXT) | |
421 | $(CXXLINK) $(affxml_OBJECTS) $(affxml_LDADD) $(LIBS) | |
421 | 422 | |
422 | 423 | mostlyclean-compile: |
423 | 424 | -rm -f *.$(OBJEXT) |
425 | 426 | distclean-compile: |
426 | 427 | -rm -f *.tab.c |
427 | 428 | |
428 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afcat.Po@am__quote@ | |
429 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afcompare.Po@am__quote@ | |
430 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afconvert.Po@am__quote@ | |
431 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afcopy.Po@am__quote@ | |
432 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afcrypto.Po@am__quote@ | |
433 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afdiskprint.Po@am__quote@ | |
434 | 429 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aff_bom.Po@am__quote@ |
430 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affcat.Po@am__quote@ | |
431 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affcompare.Po@am__quote@ | |
432 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affconvert.Po@am__quote@ | |
433 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affcopy.Po@am__quote@ | |
434 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affcrypto.Po@am__quote@ | |
435 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affdiskprint.Po@am__quote@ | |
436 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinfo.Po@am__quote@ | |
435 | 437 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affix.Po@am__quote@ |
438 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affrecover.Po@am__quote@ | |
439 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affsegment.Po@am__quote@ | |
440 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affsign.Po@am__quote@ | |
441 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affstats.Po@am__quote@ | |
436 | 442 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affuse-affuse.Po@am__quote@ |
437 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afinfo.Po@am__quote@ | |
438 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afrecover.Po@am__quote@ | |
439 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afsegment.Po@am__quote@ | |
440 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afsign.Po@am__quote@ | |
441 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afstats.Po@am__quote@ | |
442 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afverify.Po@am__quote@ | |
443 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/afxml.Po@am__quote@ | |
443 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affverify.Po@am__quote@ | |
444 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affxml.Po@am__quote@ | |
444 | 445 | |
445 | 446 | .c.o: |
446 | 447 | @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
0 | /* | |
1 | * afcat.cpp: | |
2 | * | |
3 | * cat the contents of an AFF file... | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005, 2006 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | #include "affconfig.h" | |
47 | #include "afflib.h" | |
48 | #include "afflib_i.h" | |
49 | ||
50 | #include <stdio.h> | |
51 | #include <algorithm> | |
52 | #include <vector> | |
53 | #include <string> | |
54 | #ifdef HAVE_CSTRING | |
55 | #include <cstring> | |
56 | #endif | |
57 | ||
58 | ||
59 | using namespace std; | |
60 | ||
61 | vector <int64_t> pages; | |
62 | ||
63 | const char *progname = "afcat"; | |
64 | int opt_info = 0; | |
65 | char *opt_segname=0; | |
66 | int64_t opt_pagenum = -1; | |
67 | int opt_quiet = 1; | |
68 | int opt_list= 0 ; | |
69 | int opt_list_long = 0; | |
70 | int opt_debug = 0; | |
71 | int64_t opt_sector = -1; | |
72 | int opt_badflag = 0; | |
73 | vector<string> opt_r; | |
74 | ||
75 | ||
76 | void usage() | |
77 | { | |
78 | printf("afcat version %s\n",PACKAGE_VERSION); | |
79 | printf("usage: afcat [options] infile [... more infiles]\n"); | |
80 | printf("options:\n"); | |
81 | printf(" -s name --- Just output segment name\n"); | |
82 | printf(" -p ### --- just output data page number ###\n"); | |
83 | printf(" -S ### --- Just output data sector ### (assumes 512-byte sectors). Sector #0 is first\n"); | |
84 | printf(" -q --- quiet; don't print to STDERR if a page is skipped\n"); | |
85 | printf(" -n --- noisy; tell when pages are skipped.\n"); | |
86 | printf(" -l --- List all of the segment names\n"); | |
87 | printf(" -L --- List segment names, lengths, and args\n"); | |
88 | printf(" -d --- debug. Print the page numbers to stderr as data goes to stdout\n"); | |
89 | printf(" -b --- Output BADFALG for bad blocks (default is NULLs)\n"); | |
90 | printf(" -v --- Just print the version number and exit.\n"); | |
91 | printf(" -r offset:count --- seek to offset and output count characters in each file; may be repeated\n"); | |
92 | exit(0); | |
93 | } | |
94 | ||
95 | ||
96 | const char *current_fname = 0; | |
97 | int64_t current_page = -1; | |
98 | void sig_info(int arg) | |
99 | { | |
100 | fprintf(stderr,"afcat "); | |
101 | if(current_fname) fprintf(stderr,"%s: ",current_fname); | |
102 | if(current_page>=0) fprintf(stderr,"[%"PRId64"] ",current_page); | |
103 | fflush(stderr); | |
104 | } | |
105 | ||
106 | ||
107 | ||
108 | int compar(const void *a_,const void *b_) | |
109 | { | |
110 | int64_t a = *(int *)a_; | |
111 | int64_t b = *(int *)b_; | |
112 | if(a<b) return -1; | |
113 | if(a>b) return 1; | |
114 | return 0; | |
115 | } | |
116 | ||
117 | struct afm_private { | |
118 | AFFILE *aff; // the AFFILE we use for the actual metadata | |
119 | AFFILE *sr; // the AFFILE we use for the splitraw | |
120 | int sr_initialized; // has the split-raw been setup from AFM? | |
121 | }; | |
122 | ||
123 | int output_page(AFFILE *af,FILE *outfile,int64_t pagenum) | |
124 | { | |
125 | current_fname = af_filename(af); | |
126 | current_page = pagenum; | |
127 | unsigned char *buf = (unsigned char *)malloc(af->image_pagesize); | |
128 | if(buf==0){ | |
129 | err(1,"malloc(%d) failed",(int)af->image_pagesize); | |
130 | } | |
131 | uint64_t offset = (uint64_t)pagenum * af->image_pagesize; // go to that location | |
132 | ||
133 | ||
134 | af_seek(af,offset,SEEK_SET); | |
135 | ||
136 | ||
137 | int bytes = af_read(af,buf,af->image_pagesize); // read what we can | |
138 | ||
139 | if(bytes<0){ | |
140 | if(opt_debug) fprintf(stderr,"afcat: cannot read page %"I64d"\n",pagenum); | |
141 | return -1; | |
142 | } | |
143 | ||
144 | if(opt_debug){ | |
145 | fprintf(stderr,"afcat: page:%"I64d" bytes: %d offset:%"I64d"\n", | |
146 | pagenum, bytes,offset); | |
147 | } | |
148 | ||
149 | /* Check each sector to see if it is badflag or not. | |
150 | * If it is and if opt_badflag is not set, make it all NULs. | |
151 | */ | |
152 | for(unsigned char *cc=buf;cc<buf+bytes;cc+=af->image_sectorsize){ | |
153 | if(af_is_badsector(af,cc) && opt_badflag==0){ | |
154 | memset(cc,0,af->image_sectorsize); | |
155 | } | |
156 | } | |
157 | ||
158 | if(opt_debug) fprintf(stderr," outputing %d bytes\n",bytes); | |
159 | int count = fwrite(buf,1,bytes,outfile); // send to the output | |
160 | if(count!=bytes) fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",bytes,count); | |
161 | free(buf); | |
162 | return bytes; | |
163 | } | |
164 | ||
165 | ||
166 | int afcat(AFFILE *af) | |
167 | { | |
168 | int64_t total_bytes_written = 0; | |
169 | ||
170 | /* Read all of the pages from beginning to end and capture | |
171 | * all the segment numbers... | |
172 | */ | |
173 | ||
174 | #ifdef WIN32 | |
175 | _setmode(fileno(stdout),_O_BINARY); | |
176 | #endif | |
177 | if(opt_debug) fprintf(stderr,"afcat(%s)\n",af_filename(af)); | |
178 | ||
179 | if(opt_segname){ | |
180 | /* First figure out how big the segment is */ | |
181 | size_t datalen = 0; | |
182 | if(af_get_seg(af,opt_segname,0,0,&datalen)){ | |
183 | fprintf(stderr,"%s: segment '%s' does not exist\n", | |
184 | af_filename(af),opt_segname); | |
185 | return -1; | |
186 | } | |
187 | unsigned char *data = (unsigned char *)malloc(datalen); | |
188 | if(data==0) err(1,"malloc"); | |
189 | if(af_get_seg(af,opt_segname,0,data,&datalen)){ | |
190 | free(data); | |
191 | fprintf(stderr,"%s: could not read segment '%s'\n", | |
192 | af_filename(af),opt_segname); | |
193 | return -1; | |
194 | } | |
195 | int count = fwrite(data,1,datalen,stdout); | |
196 | if(count!=(ssize_t)datalen){ | |
197 | fprintf(stderr,"fwrite(buf,1,%zd,outfile) only wrote %d bytes\n",datalen,count); | |
198 | } | |
199 | free(data); | |
200 | return 0; | |
201 | } | |
202 | ||
203 | if(opt_pagenum != -1){ // just write a particular page? | |
204 | int r = output_page(af,stdout,opt_pagenum); | |
205 | return r>=0 ? 0 : -1; | |
206 | } | |
207 | ||
208 | if(opt_sector>=0){ | |
209 | unsigned char *buf = (unsigned char *)malloc(af->image_sectorsize); | |
210 | af_seek(af,(uint64_t)opt_sector*af->image_sectorsize,SEEK_SET); | |
211 | int bytes_read = af_read(af,buf,af->image_sectorsize); | |
212 | if(bytes_read>0){ | |
213 | int bytes_written = fwrite(buf,1,bytes_read,stdout); | |
214 | if(bytes_read!=bytes_written){ | |
215 | fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n", | |
216 | bytes_read,bytes_written); | |
217 | } | |
218 | } | |
219 | free(buf); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | /* Get a list of all the segments. If we are doing a list, just print them. | |
224 | * If we are not doing a list, capture the data pages and put their numbers | |
225 | * into an array. | |
226 | */ | |
227 | ||
228 | if(opt_debug) fprintf(stderr,"af_rewind_seg()\n"); | |
229 | ||
230 | if(opt_r.size()>0){ | |
231 | unsigned char *buf = (unsigned char *)malloc(af->image_pagesize); | |
232 | for(vector<string>::const_iterator offset_count=opt_r.begin(); offset_count != opt_r.end(); offset_count++){ | |
233 | string opts = *offset_count; | |
234 | const char *opt = opts.c_str(); | |
235 | uint64_t offset=0; | |
236 | int count=0; | |
237 | if(sscanf(opt,"%"I64u":%d",&offset,&count)!=2){ | |
238 | err(1,"Cannot decode '%s'\n",opt); | |
239 | } | |
240 | af_seek(af,offset,SEEK_SET); | |
241 | int r= af_read(af,buf,count); | |
242 | if(r>0){ | |
243 | int bytes_written = fwrite(buf,1,r,stdout); | |
244 | if(bytes_written!=r) { | |
245 | fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",r,bytes_written); | |
246 | } | |
247 | ||
248 | } | |
249 | } | |
250 | free(buf); | |
251 | return 0; | |
252 | } | |
253 | ||
254 | ||
255 | af_rewind_seg(af); // start at the beginning | |
256 | char segname[AF_MAX_NAME_LEN]; | |
257 | unsigned long arg; | |
258 | size_t datalen = 0; | |
259 | memset(segname,0,sizeof(segname)); | |
260 | ||
261 | int encrypted_segments = 0; | |
262 | while(af_get_next_seg(af,segname,sizeof(segname),&arg,0,&datalen)==0){ | |
263 | if(opt_debug) fprintf(stderr,"af_get_next_seg found segment %s\n",segname); | |
264 | if(segname[0]==0) continue; // ignore sector | |
265 | if(opt_list){ | |
266 | printf("%s",segname); | |
267 | if(opt_list_long){ | |
268 | printf("\targ:%lu\tlen:%d",arg,(int)datalen); | |
269 | } | |
270 | putchar('\n'); | |
271 | } | |
272 | else { | |
273 | int64_t pagenum = af_segname_page_number(segname); | |
274 | if(pagenum>=0) pages.push_back(pagenum); | |
275 | if(af_is_encrypted_segment(segname)) encrypted_segments++; | |
276 | } | |
277 | datalen = 0; // allow to get the next one | |
278 | } | |
279 | if(opt_list) return 0; // that's all that was wanted. | |
280 | ||
281 | ||
282 | sort(pages.begin(),pages.end()); | |
283 | ||
284 | if(pages.size()==0 && encrypted_segments){ | |
285 | fprintf(stderr,"afcat: This file has %d encrypted segments.\n",encrypted_segments); | |
286 | fprintf(stderr,"afcat: No unencrypted pages could be found.\n"); | |
287 | } | |
288 | ||
289 | /* Now I have a list of pages; cat each one */ | |
290 | int next_page = 0; // starting page number | |
291 | int64_t imagesize = af_get_imagesize(af); | |
292 | for(vector<int64_t>::iterator i = pages.begin(); i != pages.end(); i++){ | |
293 | ||
294 | int page = *i; | |
295 | if(page != next_page && opt_quiet==0){ | |
296 | if(page == next_page+1 ){ | |
297 | fprintf(stderr,"afcat: page %d not in file\n",next_page); | |
298 | } | |
299 | else{ | |
300 | fprintf(stderr,"afcat: pages %d through %d not in file\n", | |
301 | next_page,page-1); | |
302 | } | |
303 | } | |
304 | int r = output_page(af,stdout,page); | |
305 | if(r<0) return -1; | |
306 | total_bytes_written += r; | |
307 | next_page = page + 1; // note what should be next | |
308 | ||
309 | //fprintf(stderr,"bytes written=%qd imagesize=%qd\n",total_bytes_written,imagesize); | |
310 | if((total_bytes_written > imagesize) && (imagesize>0)){ | |
311 | err(1,"afcat internal error. bytes written=%"I64d" imagesize=%" I64d, | |
312 | (int64_t)total_bytes_written, | |
313 | (int64_t)imagesize); | |
314 | return -1; | |
315 | } | |
316 | } | |
317 | return 0; | |
318 | } | |
319 | ||
320 | ||
321 | int64_t atoi64(const char *buf) | |
322 | { | |
323 | int64_t r=0; | |
324 | char ch; | |
325 | if(sscanf(buf,"%"I64d"%c",&r,&ch)==1) return r; | |
326 | fprintf(stderr,"Cannot parse '%s'\n",buf); | |
327 | exit(0); | |
328 | } | |
329 | ||
330 | ||
331 | int main(int argc,char **argv) | |
332 | { | |
333 | int bflag, ch; | |
334 | ||
335 | #ifdef SIGINFO | |
336 | signal(SIGINFO,sig_info); | |
337 | #endif | |
338 | ||
339 | bflag = 0; | |
340 | while ((ch = getopt(argc, argv, "s:S:p:lLh?dqnvr:")) != -1) { | |
341 | switch (ch) { | |
342 | case 's': | |
343 | opt_segname = optarg; | |
344 | break; | |
345 | case 'S': | |
346 | opt_sector = atoi64(optarg); | |
347 | break; | |
348 | case 'p': | |
349 | opt_pagenum = atoi64(optarg); | |
350 | break; | |
351 | case 'q': | |
352 | opt_quiet = 1; | |
353 | break; | |
354 | case 'n': | |
355 | opt_quiet = 0; | |
356 | break; | |
357 | case 'l': | |
358 | opt_list = 1; | |
359 | break; | |
360 | case 'r': | |
361 | opt_r.push_back(optarg); | |
362 | break; | |
363 | case 'L': | |
364 | opt_list = 1; | |
365 | opt_list_long = 1; | |
366 | break; | |
367 | case 'b': | |
368 | opt_badflag = 1; | |
369 | break; | |
370 | case 'd': | |
371 | opt_debug++; | |
372 | break; | |
373 | case 'h': | |
374 | case '?': | |
375 | default: | |
376 | usage(); | |
377 | break; | |
378 | case 'v': | |
379 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
380 | exit(0); | |
381 | } | |
382 | } | |
383 | argc -= optind; | |
384 | argv += optind; | |
385 | ||
386 | if(argc<1){ | |
387 | usage(); | |
388 | } | |
389 | ||
390 | while(*argv){ | |
391 | AFFILE *af = af_open(*argv,O_RDONLY,0); | |
392 | if(!af) af_err(1,"afcat(%s)",*argv); | |
393 | if(afcat(af)) err(1,"afcat"); | |
394 | af_close(af); | |
395 | argv++; | |
396 | argc--; | |
397 | } | |
398 | } |
0 | /* | |
1 | * acompare.cpp: | |
2 | * | |
3 | * Compare the contents of an ISO file to an AFF file. | |
4 | * Optionally, if they are equal, delete the ISO file | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2005--2008 | |
9 | * Simson L. Garfinkel and Basis Technology, Inc. | |
10 | * All rights reserved. | |
11 | * | |
12 | * This code is derrived from software contributed by | |
13 | * Simson L. Garfinkel | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | |
23 | * 3. All advertising materials mentioning features or use of this software | |
24 | * must display the following acknowledgement: | |
25 | * This product includes software developed by Simson L. Garfinkel | |
26 | * and Basis Technology Corp. | |
27 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
28 | * contributors to this program may be used to endorse or promote | |
29 | * products derived from this software without specific prior written | |
30 | * permission. | |
31 | * | |
32 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
33 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
34 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
35 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
36 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
37 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
38 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
40 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
41 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
42 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
43 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
44 | * SUCH DAMAGE. | |
45 | */ | |
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "utils.h" | |
51 | ||
52 | using namespace std; | |
53 | using namespace aff; | |
54 | ||
55 | ||
56 | #ifdef WIN32 | |
57 | #include "unix4win32.h" | |
58 | #endif | |
59 | ||
60 | ||
61 | #ifdef UNIX | |
62 | #include <sys/signal.h> | |
63 | #include <unistd.h> | |
64 | #endif | |
65 | ||
66 | #include <ctype.h> | |
67 | #include <stdio.h> | |
68 | #include <stdlib.h> | |
69 | #include <sys/types.h> | |
70 | #include <sys/stat.h> | |
71 | #include <fcntl.h> | |
72 | #include <limits.h> | |
73 | #include <string.h> | |
74 | #include <zlib.h> | |
75 | #include <openssl/md5.h> | |
76 | #include <openssl/sha.h> | |
77 | #include <assert.h> | |
78 | ||
79 | #ifdef HAVE_CSTRING | |
80 | #include <cstring> | |
81 | #endif | |
82 | ||
83 | #ifdef linux | |
84 | #include <sys/time.h> | |
85 | #endif | |
86 | ||
87 | ||
88 | ||
89 | const char *progname = "afcompare"; | |
90 | ||
91 | int opt_quiet = 0; | |
92 | int opt_all = 0; | |
93 | int opt_print_sectors = 0; | |
94 | int opt_print_sector_contents = 0; | |
95 | int opt_page = -1; | |
96 | int opt_preen = 0; | |
97 | int opt_exist = 0; | |
98 | int opt_ignore_metadata = 0; | |
99 | int opt_s3 = 0; | |
100 | int opt_verbose = 0; | |
101 | const char *batch_ext = ""; | |
102 | ||
103 | vector<string> errors; | |
104 | ||
105 | const char *current_source = 0; | |
106 | ||
107 | void sig_info(int arg) | |
108 | { | |
109 | if(current_source){ | |
110 | printf("%s... ",current_source); | |
111 | } | |
112 | printf("\n"); | |
113 | fflush(stdout); | |
114 | } | |
115 | ||
116 | void print_title(char *title) | |
117 | { | |
118 | if(title[0]){ | |
119 | puts(title); | |
120 | title[0] = 0; | |
121 | } | |
122 | } | |
123 | ||
124 | void usage() | |
125 | { | |
126 | printf("afcompare version %s\n",PACKAGE_VERSION); | |
127 | printf("\n"); | |
128 | printf("usage: afcompare [options] file1 file2\n"); | |
129 | printf(" compares file1 with file2\n"); | |
130 | printf("\n"); | |
131 | printf("or afcompare [options] -r dir1 dir2\n"); | |
132 | printf(" comparses similarly-named files in dir1 and dir2\n"); | |
133 | printf("\n"); | |
134 | printf("or afcompare [options] -s file1 file2...\n"); | |
135 | printf(" Reports if file was successfully copied to Amazon S3\n"); | |
136 | printf(" checking only for existence, not reading back the bytes.\n"); | |
137 | printf(" (Because all writes to S3 are validated by the MD5 of the object\n"); | |
138 | #ifndef USE_S3 | |
139 | printf(" NOTE: S3 support is not provided in this version\n"); | |
140 | #endif | |
141 | ||
142 | printf("fast options:\n"); | |
143 | printf("(These compare segments but not their contents.)\n"); | |
144 | printf(" -p --- report about the results of preening\n"); | |
145 | printf(" -e --- Just report about existence (use with -r)\n"); | |
146 | printf(" -s --- Just see if all of the segments are present, but don't\n"); | |
147 | printf(" validate the contents. (Primarily for use with Amazon S3)\n"); | |
148 | ||
149 | printf("other options:\n"); | |
150 | printf(" -V --- just print the version number and exit\n"); | |
151 | printf(" -v --- Verbose; each file as it is compared.\n"); | |
152 | printf(" -q --- Quiet. No output except for errors\n"); | |
153 | printf(" -a --- print what's the same (all)\n"); | |
154 | printf(" -b --- print the numbers of differing sectors\n"); | |
155 | printf(" -c --- print the contents of differing sectors\n"); | |
156 | printf(" -m --- Just report about the data (ignore metadata)\n"); | |
157 | printf(" -P ### --- Just examine the differences on page ###\n"); | |
158 | printf(" -q --- Quiet; no output except for errors.\n"); | |
159 | printf("\n"); | |
160 | printf("Options documented above:\n"); | |
161 | printf(" -r dir1 dir2 --- recursively compare what's in dir1 with dir2, and\n"); | |
162 | printf(" report what's in dir1 that's not in dir2\n"); | |
163 | printf(" -s --- Check to see if named files are on Amazon S3\n"); | |
164 | printf("\n"); | |
165 | printf(" afcompare file1.aff file2.aff --- compare file1.aff and file2.aff\n"); | |
166 | printf(" afcompare f1.aff f2.aff dir1/ --- compare f1.aff with dir1/f1.aff and f2.aff with dir2/f2.aff\n"); | |
167 | printf(" note: dir1/ must end with a slash.\n"); | |
168 | printf(" afcompare -b img file.aff --- compare file.aff and file.img\n"); | |
169 | printf(" afcompare -b img file1.aff file2.aff... --- compare file1.aff, file1.img, etc.\n"); | |
170 | printf(" afcompare -re dir1 dir2 --- report AFF files in dir1 but not in dir2\n"); | |
171 | printf(" afcompare -rse dir1 s3:/// --- report AFF files in dir1 but not on S3 (low bandwidth)\n"); | |
172 | printf(" afcompare -rs dir1 s3:/// --- report AFF files in dir1 but incomplete on on S3 (more bandwidth)\n"); | |
173 | printf("\n"); | |
174 | exit(0); | |
175 | } | |
176 | ||
177 | void print_sector(AFFILE *af,unsigned char *buf) | |
178 | { | |
179 | for(unsigned int i=0;i<af->image_sectorsize;i++){ | |
180 | if(isprint(buf[i])){ | |
181 | putchar(buf[i]); | |
182 | } | |
183 | else { | |
184 | putchar('.'); | |
185 | } | |
186 | if(i%64==63) putchar('\n'); | |
187 | } | |
188 | } | |
189 | ||
190 | ||
191 | void print_info(char dir,const char *segname,unsigned long arg,size_t len, | |
192 | unsigned char *data,int mcr) | |
193 | { | |
194 | printf(" %c %s arg=%lu len=%d\n",dir,segname,arg,(int)len); | |
195 | printf(" "); | |
196 | if((arg == AF_SEG_QUADWORD) && (len==8)){ | |
197 | printf("data=%"I64d" as a 64-bit value\n",af_decode_q(data)); | |
198 | return; | |
199 | } | |
200 | /* Otherwise, just print some stuff... */ | |
201 | for(unsigned int i=0;i<len && i<60;i++){ | |
202 | if(data[i]==' '){ | |
203 | putchar(' '); | |
204 | continue; | |
205 | } | |
206 | if(!isprint(data[i])){ | |
207 | putchar('.'); | |
208 | continue; | |
209 | } | |
210 | putchar(data[i]); | |
211 | } | |
212 | putchar('\n'); | |
213 | } | |
214 | ||
215 | int compare_aff_metadata_segments(char *title,AFFILE *af1,AFFILE *af2,const char *segname,int mode) | |
216 | { | |
217 | int ret = 0; | |
218 | ||
219 | unsigned long arg1 = 0; | |
220 | size_t data1_len = 0; | |
221 | int r1 = af_get_seg(af1,segname,&arg1,0,&data1_len); | |
222 | ||
223 | unsigned long arg2 = 0; | |
224 | size_t data2_len = 0; | |
225 | int r2 = af_get_seg(af2,segname,&arg2,0,&data2_len); | |
226 | ||
227 | if(r1==0 && r2!=0){ | |
228 | if(mode==1){ | |
229 | print_title(title); | |
230 | printf(" %s \n",segname); | |
231 | } | |
232 | return 1; | |
233 | } | |
234 | ||
235 | if(r1!=0 && r2==0){ | |
236 | if(mode==2){ | |
237 | print_title(title); | |
238 | printf(" %s \n",segname); | |
239 | } | |
240 | return 1; | |
241 | } | |
242 | if(mode!=3) return 0; // only report differences in mode 3 | |
243 | /* Get the actual data... */ | |
244 | ||
245 | unsigned char *data1 = (unsigned char *)malloc(data1_len); | |
246 | unsigned char *data2 = (unsigned char *)malloc(data2_len); | |
247 | ||
248 | int s1 = af_get_seg(af1,segname,&arg1,data1,&data1_len); | |
249 | if(s1!=0) err(1,"Couldn't read data segment %s in %s",segname,af_filename(af1)); | |
250 | ||
251 | int s2 = af_get_seg(af2,segname,&arg2,data2,&data2_len); | |
252 | if(s2!=0) err(1,"Couldn't read data segment %s in %s",segname,af_filename(af2)); | |
253 | ||
254 | int mcr = 0; | |
255 | ||
256 | if(data1_len != data2_len) mcr = 1; | |
257 | else mcr = memcmp(data1,data2,data1_len); | |
258 | if(arg1!=arg2 || data1_len!=data2_len || mcr!=0){ | |
259 | print_title(title); | |
260 | print_info('<',segname,arg1,data1_len,data1,mcr); | |
261 | print_info('>',segname,arg2,data2_len,data2,mcr); | |
262 | if(mcr){ | |
263 | printf(" *** Metadata segment are different "); | |
264 | if(strcmp(segname,AF_BADFLAG)==0){ | |
265 | printf("(bad flags should be different!)"); | |
266 | } | |
267 | putchar('\n'); | |
268 | } | |
269 | putchar('\n'); | |
270 | ret = 1; | |
271 | } | |
272 | else { | |
273 | if(opt_all){ | |
274 | print_title(title); | |
275 | printf(" %s (same in both) \n",segname); | |
276 | } | |
277 | } | |
278 | free(data1); | |
279 | free(data2); | |
280 | return ret; | |
281 | } | |
282 | ||
283 | int compare_aff_data_segments(char *title,AFFILE *af1,AFFILE *af2,int64_t pagenum,int mode) | |
284 | { | |
285 | int ret = 0; | |
286 | char pagename[65]; | |
287 | snprintf(pagename,sizeof(pagename),AF_PAGE,pagenum); | |
288 | ||
289 | char segname[65]; | |
290 | snprintf(segname,sizeof(segname),AF_SEG_D,pagenum); | |
291 | ||
292 | unsigned long arg1=0; | |
293 | size_t data1_len=0; | |
294 | int r1 = af_get_seg(af1,pagename,&arg1,0,&data1_len); | |
295 | if(r1==-1) r1=af_get_seg(af1,segname,&arg1,0,&data1_len); | |
296 | ||
297 | unsigned long arg2=0; | |
298 | size_t data2_len=0; | |
299 | int r2 = af_get_seg(af2,pagename,&arg2,0,&data2_len); | |
300 | if(r2 == -1) r2=af_get_seg(af2,segname,&arg2,0,&data2_len); | |
301 | ||
302 | if(r1<0 && r2<0) return 0; // no data segment in either file | |
303 | if(r1==0 && r2!=0){ | |
304 | if(mode==1){ | |
305 | print_title(title); | |
306 | printf(" %s \n",pagename); | |
307 | } | |
308 | return 1; | |
309 | } | |
310 | ||
311 | if(r2==0 && r1!=0){ | |
312 | if(mode==2){ | |
313 | print_title(title); | |
314 | printf(" %s \n",pagename); | |
315 | } | |
316 | return 1; | |
317 | } | |
318 | if(mode!=3) return 0; // only report differences in mode 3 | |
319 | ||
320 | /* Get the actual data... */ | |
321 | unsigned char *data1 = (unsigned char *)malloc(af_page_size(af1)); | |
322 | unsigned char *data2 = (unsigned char *)malloc(af_page_size(af2)); | |
323 | ||
324 | data1_len = af_page_size(af1); | |
325 | data2_len = af_page_size(af2); | |
326 | ||
327 | uint64_t start_sector_number = (pagenum * data1_len) / af1->image_sectorsize; | |
328 | ||
329 | /* Find the size of each page, then get the page */ | |
330 | if(af_get_page(af1,pagenum,0,&data1_len)<0) | |
331 | err(1,"Cannot read page %"I64d" size from %s\n",pagenum,af_filename(af1)); | |
332 | if(af_get_page(af1,pagenum,data1,&data1_len)<0) | |
333 | err(1,"Cannot read page %"I64d" from %s",pagenum,af_filename(af1)); | |
334 | ||
335 | if(af_get_page(af2,pagenum,0,&data2_len)<0) | |
336 | err(1,"Cannot read page %"I64d" size from %s\n",pagenum,af_filename(af2)); | |
337 | if(af_get_page(af2,pagenum,data2,&data2_len)<0) | |
338 | err(1,"Cannot read page %"I64d" from %s",pagenum,af_filename(af2)); | |
339 | ||
340 | if(data1_len != data2_len){ | |
341 | printf("page %"I64d" size %zd != size %zd\n",pagenum,data1_len,data2_len); | |
342 | return 1; | |
343 | } | |
344 | ||
345 | /* Now look at the pages sector-by-sector. */ | |
346 | int af1_bad=0; | |
347 | int af2_bad=0; | |
348 | int matching_bad_sectors = 0; | |
349 | int matching_sectors = 0; | |
350 | int total_sectors = 0; | |
351 | int no_match = 0; | |
352 | vector<uint64_t> different_sectors; | |
353 | ||
354 | for(unsigned int offset=0;offset<data1_len;offset+=af1->image_sectorsize){ | |
355 | uint64_t this_sector = start_sector_number + offset/af1->image_sectorsize; | |
356 | total_sectors++; | |
357 | if(af_is_badsector(af1,data1+offset) && | |
358 | af_is_badsector(af2,data2+offset)){ | |
359 | matching_bad_sectors++; | |
360 | continue; | |
361 | } | |
362 | if(af_is_badsector(af1,data1+offset)){ | |
363 | af1_bad++; | |
364 | continue; | |
365 | } | |
366 | if(af_is_badsector(af2,data2+offset)){ | |
367 | af2_bad++; | |
368 | continue; | |
369 | } | |
370 | if(memcmp(data1+offset,data2+offset,af1->image_sectorsize)==0){ | |
371 | matching_sectors++; | |
372 | continue; | |
373 | } | |
374 | no_match++; | |
375 | different_sectors.push_back(this_sector); | |
376 | } | |
377 | ||
378 | char outline[256]; | |
379 | outline[0] = 0; | |
380 | if(opt_all || (no_match>0) || af1_bad || af2_bad){ | |
381 | snprintf(outline,sizeof(outline), | |
382 | " page%"I64d" sectors:%4d matching: %3d different:%3d", | |
383 | pagenum,total_sectors,matching_sectors,no_match); | |
384 | } | |
385 | if(af1_bad){ | |
386 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
387 | " file 1 bad: %3d ",af1_bad); | |
388 | } | |
389 | if(af2_bad){ | |
390 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
391 | " file 2 bad: %3d ",af2_bad); | |
392 | } | |
393 | if(matching_bad_sectors){ | |
394 | if(opt_all){ | |
395 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
396 | " bad both:%3d ",matching_bad_sectors); | |
397 | } | |
398 | } | |
399 | ||
400 | if(outline[0]){ | |
401 | print_title(title); | |
402 | puts(outline); | |
403 | } | |
404 | if(opt_print_sectors && different_sectors.size()>0){ | |
405 | print_title(title); | |
406 | printf(" Sectors with differences:"); | |
407 | int i=0; | |
408 | for(vector<uint64_t>::iterator j = different_sectors.begin(); | |
409 | j != different_sectors.end(); | |
410 | j++){ | |
411 | if(i==0){ | |
412 | printf("\n "); | |
413 | } | |
414 | printf(" %"I64d,*j); | |
415 | i = (i+1) % 10; | |
416 | } | |
417 | putchar('\n'); | |
418 | ret = 1; | |
419 | } | |
420 | if(opt_print_sector_contents && different_sectors.size()>0){ | |
421 | print_title(title); | |
422 | printf(" Sectors with differences:"); | |
423 | for(vector<uint64_t>::iterator j = different_sectors.begin(); | |
424 | j != different_sectors.end(); j++){ | |
425 | int offset = (*j - start_sector_number)*af1->image_sectorsize; | |
426 | char b2[16]; | |
427 | printf("offset=%d\n",offset); | |
428 | ||
429 | memcpy(b2,data1+offset,16); | |
430 | b2[15]=0; | |
431 | ||
432 | printf("=== sector %"I64d" (offset=%d) ===\n",*j,offset); | |
433 | printf(" %s:\n",af_filename(af1)); | |
434 | print_sector(af1,data1+offset); | |
435 | printf("-------------------------------------\n"); | |
436 | printf(" %s:\n",af_filename(af2)); | |
437 | print_sector(af2,data2+offset); | |
438 | printf("=====================================\n\n"); | |
439 | } | |
440 | ret = 1; | |
441 | } | |
442 | free(data1); | |
443 | free(data2); | |
444 | return ret; | |
445 | } | |
446 | ||
447 | /* Compare the results of two files that were preened */ | |
448 | int compare_preen(AFFILE *af1,AFFILE *af2) | |
449 | { | |
450 | vector<int64_t> pages; | |
451 | int comp_zero=0; | |
452 | int comp_lzma=0; | |
453 | int comp_unchanged=0; | |
454 | uint64_t bytes_old = 0; | |
455 | uint64_t bytes_new = 0; | |
456 | ||
457 | af_rewind_seg(af1); | |
458 | /* Build a list of all the pages */ | |
459 | char segname[AF_MAX_NAME_LEN]; | |
460 | while(af_get_next_seg(af1,segname,sizeof(segname),0,0,0)==0){ | |
461 | int64_t pagenumber = af_segname_page_number(segname); | |
462 | if(pagenumber>=0) pages.push_back(pagenumber); | |
463 | } | |
464 | /* Now, compare each one */ | |
465 | for(vector<int64_t>::const_iterator i = pages.begin(); i != pages.end(); i++){ | |
466 | unsigned long arg1,arg2; | |
467 | size_t len1,len2; | |
468 | ||
469 | if(af_get_page_raw(af1,*i,&arg1,0,&len1)){ | |
470 | err(1,"Could not read page %"I64d" in file %s\n",*i,af_filename(af1)); | |
471 | } | |
472 | if(af_get_page_raw(af2,*i,&arg2,0,&len2)){ | |
473 | err(1,"Page %"I64d" is in file %s but not in %s\n",*i,af_filename(af1), | |
474 | af_filename(af2)); | |
475 | } | |
476 | if(arg1==arg2 && len1==len2){ | |
477 | comp_unchanged++; | |
478 | continue; | |
479 | } | |
480 | if((arg2 & AF_PAGE_COMP_ALG_MASK)==AF_PAGE_COMP_ALG_ZERO){ | |
481 | comp_zero++; | |
482 | continue; | |
483 | } | |
484 | if((arg2 & AF_PAGE_COMP_ALG_MASK)==AF_PAGE_COMP_ALG_LZMA){ | |
485 | comp_lzma++; | |
486 | bytes_old += len1; | |
487 | bytes_new += len2; | |
488 | continue; | |
489 | } | |
490 | } | |
491 | printf("%s -> %s Nochg: %d NUL: %d LZMA: %d old: %"I64d" new: %"I64d" LZred: %6.2f%%\n", | |
492 | af_filename(af1), | |
493 | af_filename(af2), | |
494 | comp_unchanged,comp_zero,comp_lzma,bytes_old,bytes_new,(bytes_old-bytes_new)*100.0/bytes_old); | |
495 | return 0; | |
496 | } | |
497 | ||
498 | ||
499 | /* Compare two AFF files. | |
500 | * Return 0 if they are equal. | |
501 | */ | |
502 | int compare_aff_aff(const char *file1,const char *file2) | |
503 | { | |
504 | bool no_data_segments = false; | |
505 | int ret = 0; | |
506 | ||
507 | current_source = file1; | |
508 | ||
509 | if(opt_all) printf("compare %s and %s:\n",file1,file2); | |
510 | ||
511 | AFFILE *af1 = af_open(file1,O_RDONLY,0); | |
512 | if(!af1) af_err(1,"af_open(%s)",file1); | |
513 | ||
514 | AFFILE *af2 = af_open(file2,O_RDONLY,0); | |
515 | if(!af2) af_err(1,"af_open(%s)",file2); | |
516 | ||
517 | af_vnode_info vni1,vni2; | |
518 | ||
519 | if(af_vstat(af1,&vni1) || af_vstat(af2,&vni2)){ | |
520 | err(1,"af_vstat failed?"); | |
521 | } | |
522 | ||
523 | if(af_cannot_decrypt(af1) != af_cannot_decrypt(af2)){ | |
524 | printf("%s: %s decrypt\n",file1,af_cannot_decrypt(af1) ? "cannot" : "can"); | |
525 | printf("%s: %s decrypt\n",file2,af_cannot_decrypt(af2) ? "cannot" : "can"); | |
526 | fprintf(stderr,"afcompare must be able to decrypt both files or neither of the files.\n"); | |
527 | exit(1); | |
528 | } | |
529 | ||
530 | if(af1->image_pagesize != af2->image_pagesize){ | |
531 | fprintf(stderr,"Currently, %s requires that both images have the " | |
532 | "same image datsegsize.\n" | |
533 | "pagesize(%s)=%ld\n" | |
534 | "pagesize(%s)=%ld\n", | |
535 | progname,file1,af1->image_pagesize, | |
536 | file2,af2->image_pagesize); | |
537 | fprintf(stderr,"Data segments will be ignored.\n"); | |
538 | no_data_segments = true; | |
539 | } | |
540 | ||
541 | if(af1->image_sectorsize != af2->image_sectorsize){ | |
542 | fprintf(stderr,"Currently, %s requires that both images have the " | |
543 | "same image sectorsize.\n" | |
544 | "sectorsize(%s)=%ld\n" | |
545 | "sectorsize(%s)=%ld\n", | |
546 | progname,file1,af1->image_sectorsize, file2,af2->image_sectorsize); | |
547 | fprintf(stderr,"Data segments will be ignored.\n"); | |
548 | no_data_segments = true; | |
549 | } | |
550 | ||
551 | if(opt_preen){ | |
552 | compare_preen(af1,af2); | |
553 | af_close(af1); | |
554 | af_close(af2); | |
555 | return 0; | |
556 | } | |
557 | ||
558 | if(opt_s3){ | |
559 | printf("bypass\n"); | |
560 | seglist list1(af1); | |
561 | seglist list2(af2); | |
562 | ||
563 | /* Just compare the presence/absence of each segment */ | |
564 | char title[1024]; | |
565 | snprintf(title,sizeof(title),"\nPresent in %s but not %s:",af_filename(af1),af_filename(af2)); | |
566 | for(seglist::const_iterator i=list1.begin(); i!=list1.end(); i++){ | |
567 | if(find(list2.begin(),list2.end(),*i)==list2.end()){ | |
568 | print_title(title); | |
569 | printf(" %s\n",(*i).name.c_str()); | |
570 | } | |
571 | } | |
572 | snprintf(title,sizeof(title),"\nPresent in %s but not %s:",af_filename(af2),af_filename(af1)); | |
573 | for(seglist::const_iterator i=list2.begin(); i!=list2.end(); i++){ | |
574 | if(find(list1.begin(),list1.end(),*i)==list1.end()){ | |
575 | print_title(title); | |
576 | printf(" %s\n",(*i).name.c_str()); | |
577 | } | |
578 | } | |
579 | return 0; | |
580 | } | |
581 | ||
582 | /* Compare all of the metadata segments in af1 with a2. | |
583 | * Report those that are missing or different. Then report | |
584 | * all of the segments in a2 but not in af1 | |
585 | */ | |
586 | ||
587 | /* First build a list of the segments in each */ | |
588 | ||
589 | vector <string> segs_with_dups; | |
590 | ||
591 | AFFILE *af[2] = {af1,af2}; | |
592 | for(int i=0;i<2;i++){ | |
593 | if(opt_verbose) printf("\n%s:\n",af_filename(af[i])); | |
594 | af_rewind_seg(af[i]); | |
595 | char segname[AF_MAX_NAME_LEN]; | |
596 | while(af_get_next_seg(af[i],segname,sizeof(segname),0,0,0)==0){ | |
597 | if(segname[0]){ | |
598 | string s; | |
599 | s = segname; | |
600 | segs_with_dups.push_back(s); // may give duplicates | |
601 | if(opt_verbose) printf(" %s\n",segname); | |
602 | } | |
603 | } | |
604 | } | |
605 | sort(segs_with_dups.begin(),segs_with_dups.end()); | |
606 | vector<string>segs; | |
607 | ||
608 | /* Make a list of segs without duplicates */ | |
609 | string last; | |
610 | for(vector<string>::iterator i = segs_with_dups.begin(); | |
611 | i != segs_with_dups.end(); i++){ | |
612 | if(last != *i){ | |
613 | segs.push_back(*i); | |
614 | } | |
615 | last = *i; | |
616 | } | |
617 | ||
618 | int lowest_page = -1; | |
619 | int highest_page = -1; | |
620 | /* Scan for the lowest and highest numbers */ | |
621 | for(vector<string>::iterator i = segs.begin();i != segs.end(); i++){ | |
622 | int64_t num = af_segname_page_number(i->c_str()); | |
623 | if(num!=-1){ | |
624 | if(num<lowest_page ||lowest_page==-1) lowest_page = num; | |
625 | if(num>highest_page||highest_page==-1) highest_page = num; | |
626 | } | |
627 | } | |
628 | ||
629 | ||
630 | if(opt_page != -1){ | |
631 | lowest_page = opt_page; | |
632 | highest_page = opt_page; | |
633 | } | |
634 | ||
635 | ||
636 | if(opt_page == -1 | |
637 | && vni1.supports_metadata | |
638 | && vni2.supports_metadata | |
639 | && opt_ignore_metadata==0 ){ | |
640 | if(opt_all) puts("Inspecting metadata..."); | |
641 | for(int mode=1;mode<=3;mode++){ | |
642 | const char *title = "Metadata segments "; | |
643 | char mode_title[1024]; | |
644 | switch(mode){ | |
645 | case 1: | |
646 | snprintf(mode_title,sizeof(mode_title)," %s only in %s:\n", | |
647 | title,af_filename(af1)); | |
648 | break; | |
649 | case 2: | |
650 | snprintf(mode_title,sizeof(mode_title)," %s only in %s:\n", | |
651 | title,af_filename(af2)); | |
652 | break; | |
653 | case 3: | |
654 | snprintf(mode_title,sizeof(mode_title)," %s in both files:\n",title); | |
655 | break; | |
656 | } | |
657 | ||
658 | for(vector<string>::iterator i = segs.begin();i != segs.end();i++){ | |
659 | int64_t num = af_segname_page_number(i->c_str()); | |
660 | if(num==-1){ | |
661 | int r = compare_aff_metadata_segments(mode_title, af1,af2, | |
662 | i->c_str(),mode); | |
663 | if(r!=0) ret = r; | |
664 | } | |
665 | } | |
666 | } | |
667 | } | |
668 | ||
669 | if(no_data_segments==false){ | |
670 | if(opt_all) puts("Inspecting data..."); | |
671 | for(int mode=1;mode<=3;mode++){ | |
672 | char mode_title[1024]; | |
673 | switch(mode){ | |
674 | case 1: snprintf(mode_title,sizeof(mode_title), | |
675 | " Pages only in %s:\n", af_filename(af1));break; | |
676 | case 2: snprintf(mode_title,sizeof(mode_title), | |
677 | " Pages only in %s:\n", af_filename(af2));break; | |
678 | case 3: snprintf(mode_title,sizeof(mode_title)," Pages in both files:\n");break; | |
679 | } | |
680 | ||
681 | for(int i=lowest_page;i<=highest_page;i++){ | |
682 | int r = compare_aff_data_segments(mode_title,af1,af2,i,mode); | |
683 | if(r!=0) ret = r; | |
684 | } | |
685 | } | |
686 | } | |
687 | current_source = 0; | |
688 | #ifdef HAVE_ISATTY | |
689 | if(ret==0 && isatty(fileno(stdout))) printf("%s and %s: files compare okay\n",file1,file2); | |
690 | #endif | |
691 | return ret; | |
692 | } | |
693 | ||
694 | int recurse(const char *dir1,const char *dir2) | |
695 | { | |
696 | vector<string> only_in_dir1; | |
697 | ||
698 | DIR *dirp = opendir(dir1); | |
699 | struct dirent *dp; | |
700 | if(!dirp) err(1,"opendir: %s",dir1); | |
701 | while ((dp = readdir(dirp)) != NULL){ | |
702 | ||
703 | char fn1[MAXPATHLEN+1]; memset(fn1,0,sizeof(fn1)); | |
704 | char fn2[MAXPATHLEN+1]; memset(fn2,0,sizeof(fn2)); | |
705 | ||
706 | strlcpy(fn1,dir1,sizeof(fn1)); | |
707 | if(fn1[strlen(fn1)-1]!='/') strlcat(fn1,"/",sizeof(fn1)); | |
708 | strlcat(fn1,dp->d_name,sizeof(fn1)); | |
709 | ||
710 | current_source = fn1; | |
711 | if(opt_verbose) printf("%s...\n",fn1); | |
712 | ||
713 | switch(af_identify_file_type(fn1,1)){ | |
714 | case AF_IDENTIFY_ERR: | |
715 | case AF_IDENTIFY_NOEXIST: | |
716 | only_in_dir1.push_back(fn1); | |
717 | break; | |
718 | case AF_IDENTIFY_AFF: | |
719 | case AF_IDENTIFY_AFD: | |
720 | case AF_IDENTIFY_AFM: | |
721 | strlcpy(fn2,dir2,sizeof(fn2)); | |
722 | if(fn2[strlen(fn2)-1]!='/') strlcat(fn2,"/",sizeof(fn2)); | |
723 | strlcat(fn2,dp->d_name,sizeof(fn2)); | |
724 | if(af_identify_file_type(fn2,1)<0){ | |
725 | char buf[1024]; | |
726 | snprintf(buf,sizeof(buf),"%s not in %s\n",dp->d_name,dir2); | |
727 | errors.push_back(buf); | |
728 | break; | |
729 | } | |
730 | if(opt_exist==0){ | |
731 | compare_aff_aff(fn1,fn2); | |
732 | } | |
733 | break; | |
734 | default: | |
735 | break; | |
736 | } | |
737 | } | |
738 | closedir(dirp); | |
739 | printf("========================\n"); | |
740 | printf("Only in %s\n",dir1); | |
741 | for(vector<string>::const_iterator i = only_in_dir1.begin(); | |
742 | i != only_in_dir1.end(); | |
743 | i++){ | |
744 | printf("%s\n",i->c_str()); | |
745 | } | |
746 | return 0; | |
747 | } | |
748 | ||
749 | int main(int argc,char **argv) | |
750 | { | |
751 | int bflag, ch; | |
752 | int opt_recurse=0; | |
753 | ||
754 | #ifdef SIGINFO | |
755 | signal(SIGINFO,sig_info); | |
756 | #endif | |
757 | ||
758 | bflag = 0; | |
759 | while ((ch = getopt(argc, argv, "P:Vabcempqrsh?v")) != -1) { | |
760 | switch (ch) { | |
761 | case 'P': opt_page = atoi(optarg); break; | |
762 | case 'V': printf("%s version %s\n",progname,PACKAGE_VERSION); exit(0); | |
763 | case 'a': opt_all++; break; | |
764 | case 'b': opt_print_sectors=1; break; | |
765 | case 'c': opt_print_sector_contents=1; break; | |
766 | case 'e': opt_exist++; break; | |
767 | case 'm': opt_ignore_metadata++; break; | |
768 | case 'p': opt_preen++; break; | |
769 | case 'q': opt_quiet++; break; | |
770 | case 'r': opt_recurse++; break; | |
771 | case 's': opt_s3++;break; | |
772 | case 'v': opt_verbose++;break; | |
773 | case 'h': | |
774 | case '?': | |
775 | default: | |
776 | usage(); | |
777 | } | |
778 | } | |
779 | argc -= optind; | |
780 | argv += optind; | |
781 | ||
782 | if(opt_recurse){ | |
783 | if(argc!=2) usage(); | |
784 | char *dir1 = *argv++; | |
785 | char *dir2 = *argv++; | |
786 | recurse(dir1,dir2); | |
787 | if(errors.size()>0){ | |
788 | fprintf(stderr,"================================\n"); | |
789 | fprintf(stderr,"%zd afcompare errors:\n",errors.size()); | |
790 | for(vector<string>::const_iterator i=errors.begin(); | |
791 | i!=errors.end(); | |
792 | i++){ | |
793 | fputs(i->c_str(),stderr); | |
794 | } | |
795 | exit(1); | |
796 | } | |
797 | exit(0); | |
798 | } | |
799 | ||
800 | if(argc>1){ | |
801 | char *last = argv[argc-1]; | |
802 | if(last[strlen(last)-1]=='/'){ | |
803 | while(argc>1){ | |
804 | char *file1 = *argv; | |
805 | char *name1 = file1; | |
806 | char *cc; | |
807 | ||
808 | cc = strrchr(file1,'/'); | |
809 | if(cc) name1 = cc+1; | |
810 | ||
811 | char file2[MAXPATHLEN+1]; | |
812 | strlcpy(file2,last,sizeof(file2)); | |
813 | strlcat(file2,name1,sizeof(file2)); | |
814 | int e_code = compare_aff_aff(file1,file2); | |
815 | if(e_code) exit(e_code); | |
816 | argv++; | |
817 | argc--; | |
818 | } | |
819 | } | |
820 | } | |
821 | ||
822 | if(argc!=2) usage(); // if just 2, compare them | |
823 | ||
824 | char *file1 = *argv++; | |
825 | char *file2 = *argv++; | |
826 | ||
827 | if(opt_verbose) printf("%s...\n",file1); | |
828 | int e_code = compare_aff_aff(file1,file2); | |
829 | exit(e_code); | |
830 | } |
0 | /* | |
1 | * afconvert.cpp: | |
2 | * | |
3 | * Convert raw -> aff | |
4 | * aff -> raw | |
5 | * aff -> aff (recompressing/uncompressing) | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (c) 2005--2008 | |
10 | * Simson L. Garfinkel and Basis Technology, Inc. | |
11 | * All rights reserved. | |
12 | * | |
13 | * This code is derrived from software contributed by | |
14 | * Simson L. Garfinkel | |
15 | * | |
16 | * Redistribution and use in source and binary forms, with or without | |
17 | * modification, are permitted provided that the following conditions | |
18 | * are met: | |
19 | * 1. Redistributions of source code must retain the above copyright | |
20 | * notice, this list of conditions and the following disclaimer. | |
21 | * 2. Redistributions in binary form must reproduce the above copyright | |
22 | * notice, this list of conditions and the following disclaimer in the | |
23 | * documentation and/or other materials provided with the distribution. | |
24 | * 3. All advertising materials mentioning features or use of this software | |
25 | * must display the following acknowledgement: | |
26 | * This product includes software developed by Simson L. Garfinkel, | |
27 | * Basis Technology, and its contributors. | |
28 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
29 | * contributors to this program may be used to endorse or promote | |
30 | * products derived from this software without specific prior written | |
31 | * permission. | |
32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
34 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
35 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
36 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
37 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
38 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
45 | * SUCH DAMAGE. | |
46 | */ | |
47 | ||
48 | ||
49 | ||
50 | #include "affconfig.h" | |
51 | #include "afflib.h" | |
52 | #include "afflib_i.h" // we do enough mucking, we need the internal version | |
53 | #include "utils.h" | |
54 | ||
55 | #include <openssl/md5.h> | |
56 | #include <openssl/sha.h> | |
57 | ||
58 | #ifdef WIN32 | |
59 | #include "unix4win32.h" | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_CURSES_H | |
63 | #include <curses.h> | |
64 | #endif | |
65 | ||
66 | #ifdef HAVE_TERM_H | |
67 | #include <term.h> | |
68 | #endif | |
69 | ||
70 | ||
71 | #ifdef HAVE_SYS_TIME_H | |
72 | #include <sys/time.h> | |
73 | #endif | |
74 | ||
75 | #include <sys/stat.h> | |
76 | #include <string> | |
77 | ||
78 | #ifdef HAVE_UNISTD_H | |
79 | #include <unistd.h> | |
80 | #endif | |
81 | ||
82 | #ifdef HAVE_GETOPT_H | |
83 | #include <getopt.h> | |
84 | #endif | |
85 | ||
86 | ||
87 | ||
88 | const char *progname = "afconvert"; | |
89 | ||
90 | int image_pagesize = 16*1024*1024; // default seg size --- 16MB | |
91 | int opt_compression_alg = AF_COMPRESSION_ALG_ZLIB; | |
92 | int opt_compress_level = AF_COMPRESSION_DEFAULT; | |
93 | int64_t bytes_to_convert = 0; | |
94 | int opt_batch = 1; | |
95 | int opt_zap = 0; | |
96 | int opt_quiet = 0; | |
97 | int opt_write_raw = 0; // output | |
98 | int opt_probe_compressed = 1; // probe for compressed files | |
99 | const char *opt_write_raw_ext = "raw"; | |
100 | const char *opt_outdir = 0; | |
101 | const char *opt_aff_ext = "aff"; | |
102 | int64_t opt_maxsize = 0; | |
103 | int opt_yes = 0; | |
104 | int opt_debug = 0; | |
105 | std::string command_line; | |
106 | ||
107 | ||
108 | char *append(char *base,const char *str) | |
109 | { | |
110 | base = (char *)realloc(base,strlen(base)+strlen(str)+1); | |
111 | strcat(base,str); // can't fail | |
112 | return base; | |
113 | } | |
114 | ||
115 | ||
116 | ||
117 | void usage() | |
118 | { | |
119 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
120 | printf("\n"); | |
121 | printf("usage: %s [options] file1 [... files] \n",progname); | |
122 | printf("\n"); | |
123 | printf("examples:\n"); | |
124 | printf(" %s file1.iso --- convert file1.iso to file1.aff\n",progname); | |
125 | printf(" %s file1.iso file2.iso file3.iso... --- batch convert files\n",progname); | |
126 | printf(" %s -r -e iso image.aff --- convert image.aff to image.iso\n",progname); | |
127 | printf(" %s -M4g -o/media/dvd.afd bigfile.aff --- split an AFF file into 4GB chunks for archiving to DVD\n", | |
128 | progname); | |
129 | //printf(" %s -p image.aff --- recompress image.aff to maximum compression\n",progname); | |
130 | printf("\n"); | |
131 | printf("\nGeneral options:\n"); | |
132 | printf(" -q -- Quiet mode. Don't ask questions, don't print status.\n"); | |
133 | ||
134 | printf("\nAFF output options:\n"); | |
135 | printf(" -a ext -- use 'ext' for aff files (default is %s)\n",opt_aff_ext); | |
136 | printf(" (use .afd for AFD files)\n"); | |
137 | printf(" -Mn[kgm] -- set maximum size of output file. Suffix with g, m or k.\n"); | |
138 | printf(" -sn -- set the image_pagesize (default %d)\n",image_pagesize); | |
139 | printf(" -x -- don't compress AFF file.\n"); | |
140 | printf(" -O dir -- use 'dir' as the output directory\n"); | |
141 | printf(" -o file -- output to 'file' (can only convert one at a time)\n"); | |
142 | printf(" File is AFF is file ends .aff; otherwise assumes raw.\n"); | |
143 | printf(" -Xn -- Set compression to n; default is 7\n"); | |
144 | printf(" -L -- Use the LZMA compression algorithm (better but slower)\n"); | |
145 | ||
146 | printf("\nRaw output options:\n"); | |
147 | printf(" -r -- force raw output. \n"); | |
148 | printf(" -e ext -- use 'ext' for the raw files (default %s)\n",opt_write_raw_ext); | |
149 | printf(" (implies -r)\n"); | |
150 | ||
151 | printf("\nDangerous input options:\n"); | |
152 | printf(" -z -- zap; delete the output file if it already exists.\n"); | |
153 | printf(" -Z -- Do not automatically probe for gzip/bzip2 compression.\n"); | |
154 | printf(" -y -- Always answer yes/no questions 'yes.'\n"); | |
155 | printf(" -V = Just print the version number and exit.\n"); | |
156 | printf("\n"); | |
157 | exit(0); | |
158 | } | |
159 | ||
160 | ||
161 | /* probe_gzip(): | |
162 | * Is this a gzip file? | |
163 | * Right now it just looks at the file extension. | |
164 | */ | |
165 | ||
166 | int probe_gzip(const char *infile) | |
167 | { | |
168 | int len = strlen(infile); | |
169 | ||
170 | if(len>3 && strcmp(infile+len-3,".gz")==0){ | |
171 | return 1; | |
172 | } | |
173 | return 0; | |
174 | } | |
175 | ||
176 | int probe_bzip2(const char *infile) | |
177 | { | |
178 | int len = strlen(infile); | |
179 | ||
180 | if(len>4 && strcmp(infile+len-4,".bz2")==0){ | |
181 | return 1; | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | ||
186 | /* yesno(): | |
187 | * As a yes/no question. Return 1 if yes, 0 if no. | |
188 | */ | |
189 | ||
190 | int yesno(const char *statement,const char *question,const char *affirmative) | |
191 | { | |
192 | if(opt_yes){ | |
193 | if(!opt_quiet) printf("%s. %s.\n",statement,affirmative); | |
194 | return 1; | |
195 | } | |
196 | ||
197 | printf("%s. ",statement); | |
198 | char buf[256]; | |
199 | do { | |
200 | printf("%s [y/n]: ",question); | |
201 | memset(buf,0,sizeof(buf)); | |
202 | if(fgets(buf,sizeof(buf)-1,stdin)==0) return 0; | |
203 | if(buf[0]=='y' || buf[0]=='Y'){ | |
204 | printf("%s.\n",affirmative); | |
205 | return 1; | |
206 | } | |
207 | } while(buf[0]!='n' && buf[0]!='N'); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | ||
212 | /* | |
213 | * Basic conversion: | |
214 | * We have an input, which may be raw or aff, | |
215 | * and we have an output, which may be raw or aff. | |
216 | * We are going to want to read a segment at a time. | |
217 | */ | |
218 | ||
219 | ||
220 | #include <algorithm> | |
221 | #include <cstdlib> | |
222 | #include <vector> | |
223 | #include <string> | |
224 | ||
225 | #ifdef HAVE_CSTRING | |
226 | #include <cstring> | |
227 | #endif | |
228 | ||
229 | ||
230 | using namespace std; | |
231 | ||
232 | /** Do the conversion. | |
233 | * return 0 if success, code if fail. | |
234 | */ | |
235 | int convert(const char *infile,char *outfile) | |
236 | { | |
237 | ||
238 | if(opt_debug) fprintf(stderr,"convert(%s,%s)\n",infile,outfile); | |
239 | ||
240 | if(infile && outfile && strcmp(infile,outfile)==0){ | |
241 | errx(1,"Can't convert a file to itself\n"); | |
242 | } | |
243 | ||
244 | /**************************************************************** | |
245 | *** Open Input | |
246 | ****************************************************************/ | |
247 | ||
248 | AFFILE *a_in = 0; // input file, if aff | |
249 | ||
250 | #ifdef UNIX | |
251 | /* Check to see if it is a gzip file... */ | |
252 | if(opt_probe_compressed | |
253 | && probe_gzip(infile) | |
254 | && yesno("infile looks like a gzip file","Uncompress it","Uncompressing")){ | |
255 | /* Open with a subprocess. We will need to use zlib when we move to Windows. */ | |
256 | if(af_hasmeta(infile)) return -1; // don't covert with shell metacharacters | |
257 | char buf[256]; | |
258 | snprintf(buf,sizeof(buf),"gzcat %s",infile); | |
259 | a_in = af_popen(buf,"r"); | |
260 | } | |
261 | ||
262 | /* Check to see if it is a bzip2 file... */ | |
263 | if(!a_in | |
264 | && opt_probe_compressed | |
265 | && probe_bzip2(infile) | |
266 | && yesno("infile looks like a bzip2 file","Uncompress it","Uncompressing")){ | |
267 | /* Open with a subprocess. We will need to use bzip2zlib when we move to Windows. */ | |
268 | if(af_hasmeta(infile)) return -1; // don't covert with shell metacharacters | |
269 | char buf[256]; | |
270 | snprintf(buf,sizeof(buf),"bzcat %s",infile); | |
271 | a_in = af_popen(buf,"r"); | |
272 | } | |
273 | #endif | |
274 | ||
275 | /* If the file isn't open, try to open it... */ | |
276 | if(!a_in){ | |
277 | a_in = af_open(infile,O_RDONLY,0); | |
278 | if(!a_in) af_err(1,"%s",infile); // give up | |
279 | if(af_identify(a_in)==AF_IDENTIFY_RAW){ | |
280 | af_set_pagesize(a_in,image_pagesize); // match the page size we want to use | |
281 | } | |
282 | else { | |
283 | image_pagesize = a_in->image_pagesize; // that's what we are using | |
284 | } | |
285 | } | |
286 | ||
287 | const char *ain_fn = af_filename(a_in); | |
288 | struct stat si; | |
289 | memset((char *)&si,0,sizeof(si)); | |
290 | if(ain_fn && stat(ain_fn,&si)){ | |
291 | warn("Cannot stat %s",ain_fn); | |
292 | } | |
293 | ||
294 | ||
295 | /**************************************************************** | |
296 | *** Open Ouptut | |
297 | ****************************************************************/ | |
298 | ||
299 | ||
300 | if(opt_zap) unlink(outfile); // we were told to zap it | |
301 | ||
302 | AFFILE *a_out = 0; // output file, if aff or raw... | |
303 | if(access(outfile,F_OK)==0){ | |
304 | /* If outfile is a device, ask user... */ | |
305 | struct stat so; | |
306 | if(stat(outfile,&so)){ | |
307 | err(1,"%s exists but can't be stat?",outfile); | |
308 | } | |
309 | if((so.st_mode & S_IFMT)==S_IFCHR || | |
310 | (so.st_mode & S_IFMT)==S_IFBLK){ | |
311 | char buf[1024]; | |
312 | snprintf(buf,sizeof(buf),"%s is a raw device.\n",outfile); | |
313 | if(yesno(buf,"Overwrite raw device?","yes")){ | |
314 | goto doit; | |
315 | } | |
316 | } | |
317 | fprintf(stderr,"%s: file exists. Delete it before converting.\n",outfile); | |
318 | exit(-1); | |
319 | } | |
320 | /* Check for splitraw names */ | |
321 | if(af_ext_is(outfile,"afm")){ | |
322 | char file000[MAXPATHLEN+1]; | |
323 | strlcpy(file000,outfile,sizeof(file000)); | |
324 | char *cc = strrchr(file000,'.'); | |
325 | if(!cc) err(1,"Cannot file '.' in %s\n",file000); | |
326 | for(int i=0;i<2;i++){ | |
327 | sprintf(cc,".%03d",i); | |
328 | if(access(file000,F_OK)==0){ | |
329 | fprintf(stderr,"%s: file exists. Delete it before converting.\n",file000); | |
330 | fprintf(stderr,"NOTE: -z option will not delete %s\n",file000); | |
331 | return -1; | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | doit:; | |
337 | ||
338 | if(opt_write_raw){ | |
339 | /* Easy way to make a raw output is to reopen an existing output file... */ | |
340 | FILE *f = fopen(outfile,"w+b"); | |
341 | if(!f){ | |
342 | err(1,"%s",outfile); | |
343 | } | |
344 | a_out = af_freopen(f); | |
345 | } | |
346 | else { | |
347 | a_out = af_open(outfile,O_RDWR|O_CREAT|O_BINARY,0777); | |
348 | if(!a_out) af_err(1,"%s",outfile); | |
349 | if(opt_maxsize){ | |
350 | af_set_maxsize(a_out,opt_maxsize); | |
351 | } | |
352 | ||
353 | } | |
354 | if(a_out == 0) af_err(1,"af_open: %s",outfile); | |
355 | ||
356 | if(!opt_quiet) printf("convert %s --> %s\n",infile,outfile); | |
357 | ||
358 | af_update_seg(a_out,AF_ACQUISITION_COMMAND_LINE,0, | |
359 | (const u_char *)command_line.c_str(), | |
360 | command_line.size()); | |
361 | ||
362 | /**************************************************************** | |
363 | *** Set up the AFF file (assuming it's an aff file) | |
364 | *** stuff that we keep at the beginning of the file... | |
365 | ****************************************************************/ | |
366 | ||
367 | MD5_CTX md5; | |
368 | MD5_Init(&md5); | |
369 | ||
370 | SHA_CTX sha; | |
371 | SHA1_Init(&sha); | |
372 | ||
373 | /* Setup writing */ | |
374 | if(a_in->image_pagesize){ | |
375 | image_pagesize = a_in->image_pagesize; | |
376 | } | |
377 | af_set_pagesize(a_out,image_pagesize); | |
378 | af_set_sectorsize(a_out,a_in->image_sectorsize); | |
379 | ||
380 | struct af_vnode_info vni; | |
381 | af_vstat(a_out,&vni); | |
382 | if(vni.supports_compression){ | |
383 | if(opt_compression_alg){ | |
384 | af_enable_compression(a_out,opt_compression_alg,opt_compress_level); | |
385 | } | |
386 | else{ | |
387 | af_enable_compression(a_out,0,0); | |
388 | } | |
389 | } | |
390 | ||
391 | /* Get a list of all the metadata segments and the pages | |
392 | * (if this is a raw file, then the vnode raw driver will give us those segments) | |
393 | */ | |
394 | ||
395 | char segname[AF_MAX_NAME_LEN]; | |
396 | vector <string> metadata_segments; | |
397 | vector <int64_t> pages; | |
398 | af_rewind_seg(a_in); // start at the beginning | |
399 | int64_t highest_pagenum = 0; | |
400 | while(af_get_next_seg(a_in,segname,sizeof(segname),0,0,0)==0){ | |
401 | int64_t page_num = af_segname_page_number(segname); | |
402 | if(page_num>=0){ | |
403 | pages.push_back(page_num); | |
404 | if(page_num>highest_pagenum) highest_pagenum = page_num; | |
405 | } | |
406 | else { | |
407 | metadata_segments.push_back(segname); | |
408 | } | |
409 | } | |
410 | ||
411 | /* Copy over all of the metadata segments. | |
412 | * But don't bother if we are creating raw output | |
413 | */ | |
414 | if(opt_write_raw==0){ | |
415 | for(vector<string>::iterator i = metadata_segments.begin(); | |
416 | i != metadata_segments.end(); | |
417 | i++){ | |
418 | strlcpy(segname,i->c_str(),sizeof(segname)); | |
419 | size_t data_len = 0; | |
420 | unsigned long arg; | |
421 | ||
422 | /* First find out how big the segment is */ | |
423 | if(af_get_seg(a_in,segname,&arg,0,&data_len)){ | |
424 | warn("af_get_seg_1"); | |
425 | continue; | |
426 | } | |
427 | /* Now get the data */ | |
428 | unsigned char *data = (unsigned char *)malloc(data_len); | |
429 | if(af_get_seg(a_in,segname,0,data,&data_len)){ | |
430 | warn("af_get_seg_2"); | |
431 | free(data); | |
432 | continue; | |
433 | } | |
434 | /* Now put the data */ | |
435 | if(af_update_seg(a_out,segname,arg,data,data_len)){ | |
436 | err(1,"af_update_seg"); | |
437 | } | |
438 | free(data); | |
439 | } | |
440 | } | |
441 | ||
442 | /* Now sort the pages and copy them over. If there is no break, | |
443 | * we can compute the hashes... | |
444 | */ | |
445 | sort(pages.begin(),pages.end()); | |
446 | ||
447 | int64_t prev_pagenum = -1; | |
448 | bool hash_valid = true; | |
449 | uint64_t last_byte_in_image = 0; | |
450 | uint64_t total_bytes_converted = 0; | |
451 | ||
452 | bool copy_by_pages = af_has_pages(a_in); | |
453 | ||
454 | unsigned char *data = (unsigned char *)malloc(image_pagesize); | |
455 | if(copy_by_pages){ | |
456 | /* Copy over data one page at a time */ | |
457 | for(vector<int64_t>::iterator i = pages.begin(); i != pages.end(); i++){ | |
458 | ||
459 | int64_t pagenum = *i; | |
460 | ||
461 | if(!opt_quiet) printf("Converting page %"I64d" of %"I64d"\r",pagenum,highest_pagenum);fflush(stdout); | |
462 | ||
463 | size_t data_len = image_pagesize; | |
464 | if(af_get_page(a_in,pagenum,data,&data_len)){ | |
465 | err(1,"af_get_page(file=%s,page=%"I64d")", | |
466 | af_filename(a_in),pagenum); | |
467 | } | |
468 | if(af_update_page(a_out,pagenum,data,data_len)){ | |
469 | err(1,"af_update_page(file=%s,page=%"I64d")", | |
470 | af_filename(a_out),pagenum); | |
471 | } | |
472 | ||
473 | if(pagenum != prev_pagenum + 1) hash_valid = false; | |
474 | ||
475 | if(hash_valid && vni.supports_metadata){ | |
476 | MD5_Update(&md5,data,data_len); | |
477 | SHA1_Update(&sha,data,data_len); | |
478 | prev_pagenum = pagenum; | |
479 | } | |
480 | last_byte_in_image = (int64_t)image_pagesize * pagenum + (int64_t)data_len; | |
481 | total_bytes_converted += data_len; | |
482 | } | |
483 | /* Go back and update the image size (necessary since I have been writing page-by-page) */ | |
484 | if(af_update_segq(a_out,AF_IMAGESIZE,last_byte_in_image) | |
485 | && errno!=ENOTSUP){ | |
486 | err(1,"Could not upate AF_IMAGESIZE"); | |
487 | } | |
488 | } else { | |
489 | /* No page support; Copy from beginning to end */ | |
490 | while(!af_eof(a_in)){ | |
491 | int data_len = af_read(a_in,data,image_pagesize); | |
492 | if(data_len>0){ | |
493 | if(!opt_quiet){ | |
494 | printf("Writing to page %" I64d " with %d bytes read from input... \r", | |
495 | total_bytes_converted / image_pagesize,data_len); | |
496 | fflush(stdout); | |
497 | } | |
498 | if(af_write(a_out,data,data_len)!=data_len){ | |
499 | err(1,"af_write"); | |
500 | } | |
501 | if(vni.supports_metadata){ | |
502 | MD5_Update(&md5,data,data_len); | |
503 | SHA1_Update(&sha,data,data_len); | |
504 | } | |
505 | } | |
506 | if(data_len<0) err(1,"af_read"); | |
507 | if(data_len==0){ | |
508 | if(!opt_quiet) printf("af_read returned 0. Reached a sparse region or end of pipe.\n"); | |
509 | break; | |
510 | } | |
511 | last_byte_in_image += data_len; | |
512 | total_bytes_converted += data_len; | |
513 | } | |
514 | } | |
515 | free(data); | |
516 | if(!opt_quiet) printf("\n"); | |
517 | ||
518 | /* Write out the new hash if it is valid */ | |
519 | if(hash_valid && vni.supports_metadata){ | |
520 | u_char md5_buf[32],sha1_buf[40]; | |
521 | char buf[256]; | |
522 | MD5_Final(md5_buf,&md5); | |
523 | if(af_update_seg(a_out,AF_MD5,0,md5_buf,16) && errno!=ENOTSUP){ | |
524 | err(1,"Could not update AF_MD5"); | |
525 | } | |
526 | if(!opt_quiet) printf("md5: %s\n",af_hexbuf(buf,sizeof(buf),md5_buf,16,1)); | |
527 | ||
528 | SHA1_Final(sha1_buf,&sha); | |
529 | if(af_update_seg(a_out,AF_SHA1,0,sha1_buf,20) && errno!=ENOTSUP){ | |
530 | err(1,"Could not update AF_SHA1"); | |
531 | } | |
532 | if(!opt_quiet) printf("sha1: %s\n",af_hexbuf(buf,sizeof(buf),sha1_buf,20,1)); | |
533 | } | |
534 | ||
535 | /* Finish the hash calculations and write to the db */ | |
536 | if(!opt_quiet){ | |
537 | printf("bytes converted: %"I64d" \n",total_bytes_converted); | |
538 | /* If the vnode implementation tracked segments written, report it. */ | |
539 | if(a_out->pages_written || a_out->pages_compressed){ | |
540 | printf("Total pages: %"I64u" (%"I64u" compressed)\n", | |
541 | a_out->pages_written,a_out->pages_compressed); | |
542 | } | |
543 | } | |
544 | ||
545 | if(vni.supports_metadata){ | |
546 | /* make an AF_IMAGE_GID if it doesn't exist */ | |
547 | af_make_gid(a_out); | |
548 | af_set_acquisition_date(a_out,si.st_mtime); | |
549 | } | |
550 | ||
551 | /* Make a copy of the a_out filename if we can get it */ | |
552 | char *a_out_fn=0; // output filename, to remember for utimes | |
553 | const char *a_ = af_filename(a_out); // remember the output filename | |
554 | if(a_){ | |
555 | a_out_fn = strdup(a_); // make a copy of it | |
556 | } | |
557 | if(af_close(a_out)) err(1,"af_close(a_out)"); | |
558 | ||
559 | if(!opt_quiet){ | |
560 | printf("Conversion finished.\n"); | |
561 | if(af_cannot_decrypt(a_in)){ | |
562 | printf("*** encrypted pages are present which could not be decrypted ***\n"); | |
563 | } | |
564 | printf("\n\n"); | |
565 | } | |
566 | if(af_close(a_in)) err(1,"af_close(a_in)"); | |
567 | ||
568 | /* Set the utime on the resulting file if we can stat it */ | |
569 | struct timeval times[2]; | |
570 | ||
571 | memset(times,0,sizeof(times)); | |
572 | times[0].tv_sec = si.st_atime; | |
573 | times[1].tv_sec = si.st_mtime; | |
574 | #ifdef HAVE_UTIMES | |
575 | if(a_out_fn){ | |
576 | if(utimes(a_out_fn,times)) warn("utimes(%s):",outfile); | |
577 | free(a_out_fn); | |
578 | a_out_fn = 0; | |
579 | } | |
580 | #endif | |
581 | return(0); | |
582 | } | |
583 | ||
584 | ||
585 | int64_t atoi64(const char *buf) | |
586 | { | |
587 | int64_t r=0; | |
588 | sscanf(buf,"%"I64d,&r); | |
589 | return r; | |
590 | } | |
591 | ||
592 | int64_t atoi64m(const char *optarg) | |
593 | { | |
594 | int multiplier; | |
595 | switch(optarg[strlen(optarg)-1]){ | |
596 | case 'g': | |
597 | case 'G': | |
598 | multiplier=1024*1024*1024;break; | |
599 | case 'm': | |
600 | case 'M': | |
601 | multiplier=1024*1024; break; | |
602 | case 'k': | |
603 | case 'K': | |
604 | multiplier=1024; break; | |
605 | case 'b': | |
606 | case 'B': | |
607 | multiplier=1;break; | |
608 | default: | |
609 | err(1,"Specify multiplier units of g, m, k or b in '%s'\n",optarg); | |
610 | } | |
611 | return atoi64(optarg) * multiplier; | |
612 | } | |
613 | ||
614 | ||
615 | int main(int argc,char **argv) | |
616 | { | |
617 | char *outfile = 0; | |
618 | int ch; | |
619 | ||
620 | command_line = aff::command_line(argc,argv); | |
621 | while ((ch = getopt(argc, argv, "a:e:Lo:zqrs:xX:Zh?M:O::ydV")) != -1) { | |
622 | switch (ch) { | |
623 | case 'a': | |
624 | opt_aff_ext = optarg; | |
625 | break; | |
626 | case 'e': | |
627 | opt_write_raw++; | |
628 | opt_write_raw_ext = optarg; | |
629 | break; | |
630 | case 'o': | |
631 | outfile = optarg; | |
632 | break; | |
633 | case 'z': | |
634 | opt_zap ++; | |
635 | break; | |
636 | case 'q': | |
637 | opt_quiet++; | |
638 | break; | |
639 | case 'L': | |
640 | opt_compression_alg = AF_COMPRESSION_ALG_LZMA; | |
641 | break; | |
642 | case 'r': | |
643 | opt_write_raw++; | |
644 | break; | |
645 | case 's': | |
646 | image_pagesize = atoi64m(optarg); | |
647 | break; | |
648 | case 'x': | |
649 | opt_compression_alg=AF_COMPRESSION_ALG_NONE; | |
650 | break; | |
651 | case 'X': | |
652 | opt_compress_level = atoi(optarg); | |
653 | break; | |
654 | case 'Z': | |
655 | opt_probe_compressed = 0; | |
656 | break; | |
657 | case 'y': | |
658 | opt_yes = 1; | |
659 | break; | |
660 | case 'M': | |
661 | opt_maxsize = atoi64m(optarg); | |
662 | break; | |
663 | case 'O': | |
664 | if(!optarg) err(1,"-O flag requires a directory"); | |
665 | opt_outdir = optarg; | |
666 | break; | |
667 | case 'd': | |
668 | opt_debug++; | |
669 | break; | |
670 | case 'h': | |
671 | case '?': | |
672 | default: | |
673 | usage(); | |
674 | exit(0); | |
675 | case 'V': | |
676 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
677 | exit(0); | |
678 | ||
679 | } | |
680 | } | |
681 | argc -= optind; | |
682 | argv += optind; | |
683 | ||
684 | if(argc<1){ | |
685 | usage(); | |
686 | } | |
687 | ||
688 | if(outfile){ | |
689 | return convert(*argv,outfile); | |
690 | } | |
691 | ||
692 | /* Check for "-o filename" at the end of the command line... */ | |
693 | if(argc==3 && !strcmp(argv[1],"-o")){ | |
694 | return convert(argv[0],argv[2]); | |
695 | } | |
696 | ||
697 | /* Convert each file*/ | |
698 | ||
699 | while(*argv){ | |
700 | char outfile[MAXPATHLEN+1]; | |
701 | memset(outfile,0,sizeof(outfile)); | |
702 | ||
703 | const char *ext = opt_write_raw ? opt_write_raw_ext : opt_aff_ext; | |
704 | char *infile = *argv; | |
705 | argv++; | |
706 | argc--; | |
707 | ||
708 | /* Copy over the filename and change the extension */ | |
709 | strlcpy(outfile,infile,sizeof(outfile)); | |
710 | char *cc = strrchr(outfile,'.'); // to strip off extension | |
711 | if(cc){ | |
712 | /* Found an extension; copy over mine. */ | |
713 | strlcpy(cc+1,ext,sizeof(outfile)-(cc-outfile)); | |
714 | } | |
715 | else { | |
716 | /* No extension; make one */ | |
717 | strlcat(outfile,".",sizeof(outfile)); | |
718 | strlcat(outfile,ext,sizeof(outfile)); | |
719 | } | |
720 | ||
721 | /* The user might want us to put things | |
722 | * in a different directory. Pull off the filename... | |
723 | */ | |
724 | if(opt_outdir){ | |
725 | cc = strrchr(outfile,'/'); | |
726 | char filename[PATH_MAX]; | |
727 | if(cc){ | |
728 | strlcpy(filename,cc+1,sizeof(filename)); // just the filename | |
729 | } | |
730 | else{ | |
731 | strlcpy(filename,outfile,sizeof(filename)); // the outfile is the filename | |
732 | } | |
733 | strlcpy(outfile,opt_outdir,sizeof(outfile)); | |
734 | strlcat(outfile,"/",sizeof(outfile)); | |
735 | strlcat(outfile,filename,sizeof(outfile)); | |
736 | } | |
737 | if(convert(infile,outfile)){ | |
738 | exit(1); | |
739 | } | |
740 | } | |
741 | exit(0); | |
742 | } |
0 | /* | |
1 | * afcopy.cpp: | |
2 | * | |
3 | * Copy one AFF file to another. | |
4 | * Resulting file is re-ordered and possibly re-compressed. | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2006 | |
9 | * Simson L. Garfinkel | |
10 | * All rights reserved. | |
11 | * | |
12 | * This code is derrived from software contributed by | |
13 | * Simson L. Garfinkel | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | |
23 | * 3. [Omitted] | |
24 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
25 | * contributors to this program may be used to endorse or promote | |
26 | * products derived from this software without specific prior written | |
27 | * permission. | |
28 | * | |
29 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL AND CONTRIBUTORS ``AS | |
30 | * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SIMSON | |
33 | * GARFINKEL, BAIS TECHNOLOGy, OR CONTRIBUTORS BE LIABLE FOR ANY | |
34 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
35 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
36 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
38 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
39 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
40 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
41 | */ | |
42 | ||
43 | ||
44 | #include "affconfig.h" | |
45 | #include "afflib.h" | |
46 | #include "afflib_i.h" | |
47 | #include "utils.h" | |
48 | #include "base64.h" | |
49 | #include "aff_bom.h" | |
50 | ||
51 | using namespace std; | |
52 | using namespace aff; | |
53 | ||
54 | #ifdef HAVE_SYS_SIGNAL_H | |
55 | #include <sys/signal.h> | |
56 | #endif | |
57 | ||
58 | #ifdef HAVE_TIME_H | |
59 | #include <time.h> | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_SYS_TIME_H | |
63 | #include <sys/time.h> | |
64 | #endif | |
65 | ||
66 | #include <ctype.h> | |
67 | #include <zlib.h> | |
68 | #include <openssl/md5.h> | |
69 | #include <openssl/sha.h> | |
70 | #include <assert.h> | |
71 | ||
72 | #ifdef HAVE_UNISTD_H | |
73 | #include <unistd.h> | |
74 | #endif | |
75 | ||
76 | #ifdef HAVE_TERM_H | |
77 | #include <term.h> | |
78 | #endif | |
79 | ||
80 | #ifdef HAVE_NCURSES_TERM_H | |
81 | #include <ncurses/term.h> | |
82 | #endif | |
83 | ||
84 | #ifdef WIN32 | |
85 | #include "unix4win32.h" | |
86 | #endif | |
87 | ||
88 | const char *progname = "afcopy"; | |
89 | ||
90 | int opt_verbose = 0; | |
91 | int opt_debug = 0; | |
92 | int opt_x = 0; | |
93 | int opt_X = AF_COMPRESSION_DEFAULT; | |
94 | int opt_noverify = 0; | |
95 | int opt_preen = 0; | |
96 | int opt_zap =0; | |
97 | int opt_missing = 0; | |
98 | int opt_preen_alg_arg = 0; // algorithm for recompressing | |
99 | int opt_preen_alg_flag = 0; | |
100 | int opt_sign = 0; | |
101 | ||
102 | int opt_note = 0; | |
103 | const char *opt_sign_key_file = 0; | |
104 | const char *opt_sign_cert_file = 0; | |
105 | ||
106 | void usage() | |
107 | { | |
108 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
109 | printf("usage: %s [options] file1 file\n",progname); | |
110 | printf(" Copies file1 to file2\n"); | |
111 | printf(" %s [options] file1 file2 file3 ... dir\n",progname); | |
112 | printf(" Copies file1.. into dir\n"); | |
113 | printf(" %s [options] file1 file2 file3 ... dir1 dir2...\n",progname); | |
114 | printf(" Copies file1.. into dirs1, dir2, ...\n"); | |
115 | printf("\n"); | |
116 | printf("By default, all page MACs are verified on read and all segments\n"); | |
117 | printf("are verified after write.\n"); | |
118 | ||
119 | printf("Options:\n"); | |
120 | printf(" -v = verbose: print each file as it is copied\n"); | |
121 | printf(" -vv = very verbose: print each segment as it is copied\n"); | |
122 | printf(" -d = print debugging information as well\n"); | |
123 | printf(" -x = don't verify hashes on reads\n"); | |
124 | printf(" -y = don't verify writes\n"); | |
125 | printf(" -Xn = recompress pages (preen) with zlib level n\n"); | |
126 | printf(" -L = recompress pages (preen) with LZMA (smaller but slower)\n"); | |
127 | printf("\n"); | |
128 | printf(" -h = help; print this message.\n"); | |
129 | printf(" -V = print the program version and exit.\n"); | |
130 | printf(" -z = zap; copy even if the destination exists.\n"); | |
131 | printf(" -m = just copy the missing segments\n"); | |
132 | printf("\nSignature Options:\n"); | |
133 | printf(" -k filename.key = specify private key for signing\n"); | |
134 | printf(" -c filename.cer = specify a X.509 certificate that matches the private key\n"); | |
135 | printf(" (by default, the file is assumed to be the same one\n"); | |
136 | printf(" provided with the -k option.)"); | |
137 | printf(" -n = read notes to accompany the copy from standard in.\n"); | |
138 | printf("\n"); | |
139 | printf("\nEncryption Options:"); | |
140 | printf(" Specify passphrase encryption for filename.aff with:\n"); | |
141 | printf(" file://:passphrase@/filename.aff\n"); | |
142 | printf("\n"); | |
143 | printf("Examples:\n"); | |
144 | printf(" %s file.aff file://:mypassword@/file-encrypted.aff - encrypt file.aff\n",progname); | |
145 | #ifdef USE_S3 | |
146 | printf(" %s -vy -X9 *.aff s3:/// Copy all files in current\n",progname); | |
147 | printf(" directory to S3 default bucket with X9 compression\n"); | |
148 | #endif | |
149 | exit(1); | |
150 | } | |
151 | ||
152 | ||
153 | const char *current_source = 0; | |
154 | const char *current_dest = 0; | |
155 | const char *current_seg = 0; | |
156 | void sig_info(int arg) | |
157 | { | |
158 | if(current_source){ | |
159 | printf("Copying %s ",current_source); | |
160 | if(current_dest){ | |
161 | printf("--> %s",current_dest); | |
162 | if(current_seg) printf(" (%s) ",current_seg); | |
163 | } | |
164 | } | |
165 | printf("\n"); | |
166 | } | |
167 | ||
168 | ||
169 | void unlink_outfiles(vector<string> outfiles) | |
170 | { | |
171 | int failure=0; | |
172 | for(vector<string>::const_iterator o = outfiles.begin(); | |
173 | o != outfiles.end(); | |
174 | o++){ | |
175 | char *protocol=0; | |
176 | char *path = 0; | |
177 | af_parse_url(o->c_str(),&protocol,0,0,0,0,&path); | |
178 | if(strcmp(protocol,"file")==0){ | |
179 | unlink(path); | |
180 | } | |
181 | else{ | |
182 | fprintf(stderr,"Cannot unlink %s\n",o->c_str()); | |
183 | failure=1; | |
184 | } | |
185 | if(protocol) free(protocol); | |
186 | if(path) free(path); | |
187 | } | |
188 | if(failure) exit(1); | |
189 | } | |
190 | ||
191 | #if !defined( __BSD_VISIBLE) && !defined(isnumber) | |
192 | #define isnumber(x) isdigit(x) | |
193 | #endif | |
194 | ||
195 | #ifdef WIN32 | |
196 | #include <windows.h> | |
197 | #include <windowsx.h> | |
198 | int gettimeofday (struct timeval *tv, void* tz) | |
199 | { | |
200 | union { | |
201 | int64_t ns100; /*time since 1 Jan 1601 in 100ns units */ | |
202 | FILETIME ft; | |
203 | } now; | |
204 | ||
205 | GetSystemTimeAsFileTime (&now.ft); | |
206 | tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); | |
207 | tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); | |
208 | return (0); | |
209 | } | |
210 | #endif | |
211 | ||
212 | void open_outfiles(AFFILE *ain,outlist &afouts,const vector<string> &outfiles) | |
213 | { | |
214 | /* Open every output file */ | |
215 | for(vector<string>::const_iterator o = outfiles.begin(); | |
216 | o != outfiles.end(); o++){ | |
217 | ||
218 | const char *outfilename = o->c_str(); | |
219 | outelement out; | |
220 | ||
221 | /* First see if the output file exists */ | |
222 | out.af = 0; | |
223 | int ident = af_identify_file_type(outfilename,1); | |
224 | if(ident!=AF_IDENTIFY_NOEXIST){ | |
225 | fprintf(stderr,"%s: file exists... ",outfilename); | |
226 | if(opt_zap==0 && opt_missing==0){ | |
227 | fprintf(stderr,"\n Will not overwrite; use -m or -z\n"); | |
228 | continue; | |
229 | } | |
230 | if(opt_missing){ | |
231 | fprintf(stderr,"Will fill in missing segments...\n"); | |
232 | out.af = af_open(outfilename,O_RDWR|O_EXCL,0666); | |
233 | if(!out.af) af_err(1,outfilename); | |
234 | if(af_page_size(ain) != af_page_size(out.af)){ | |
235 | fprintf(stderr,"%s and %s have different page sizes (%d != %d)\n", | |
236 | af_filename(ain), | |
237 | af_filename(out.af), | |
238 | af_page_size(ain), | |
239 | af_page_size(out.af)); | |
240 | af_close(out.af); | |
241 | out.af=0; | |
242 | continue; | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | ||
248 | ||
249 | if(out.af==0){ | |
250 | out.af = af_open(outfilename,O_RDWR|O_EXCL|O_CREAT,0666); | |
251 | if(!out.af){ | |
252 | warn("%s",outfilename); | |
253 | continue; | |
254 | } | |
255 | if(af_set_pagesize(out.af,af_page_size(ain))){ | |
256 | errx(1,"%s: cannot set page size to %d\n", af_filename(out.af),af_page_size(ain)); | |
257 | } | |
258 | } | |
259 | if(o != outfiles.begin()) printf("\t "); | |
260 | if(opt_verbose){ | |
261 | printf(" => %s ",outfilename); | |
262 | if(opt_preen) printf(" (preening) "); | |
263 | printf("\n"); | |
264 | } | |
265 | if(opt_missing) out.segs.get_seglist(out.af); | |
266 | afouts.push_back(out); | |
267 | } | |
268 | } | |
269 | ||
270 | /* Copy pagenumber from ain to aout. | |
271 | * Return 0 if success, -1 if can't do it. | |
272 | * Properly handles signing and preening if requested. | |
273 | */ | |
274 | int copy_page(AFFILE *ain,AFFILE *aout,int64_t pagenum,unsigned long arg,u_char *seghash,u_int *seghash_len) | |
275 | { | |
276 | /* If we are preening but not signing, see if we can get out fast */ | |
277 | if(opt_sign==0 && opt_preen==0) return -1; // not preening and not signing | |
278 | ||
279 | /* If we are not signing, don't bother decompressing and recompressing*/ | |
280 | if(opt_sign==0 && opt_preen){ | |
281 | int alg = (arg & AF_PAGE_COMP_ALG_MASK); | |
282 | if(alg==AF_PAGE_COMP_ALG_ZERO) return -1; // don't preen ZERO | |
283 | if(alg==opt_preen_alg_arg) return -1; // don't decompress then re-compress with old alg | |
284 | } | |
285 | ||
286 | /* If we get here, page must be read into memory and decompressed */ | |
287 | size_t pagesize = af_page_size(ain); | |
288 | if(pagesize<=0) return -1; // couldn't get pagesize | |
289 | ||
290 | u_char *pagebuf = (unsigned char *)malloc(pagesize); | |
291 | if(!pagebuf) return -1; // couldn't allocate memory for page? | |
292 | ||
293 | if(af_get_page(ain,pagenum,pagebuf,&pagesize)){ // note --- this may make pagesize smaller | |
294 | free(pagebuf); | |
295 | return -1; | |
296 | } | |
297 | ||
298 | if(opt_preen){ // set compression if we are preening | |
299 | af_enable_compression(aout,opt_preen_alg_flag,opt_X); | |
300 | } | |
301 | ||
302 | #ifdef USE_AFFSIGS | |
303 | /* If calculating a bom, calculate the bom! */ | |
304 | if(opt_sign){ | |
305 | char segname[AF_MAX_NAME_LEN]; | |
306 | sprintf(segname,AF_PAGE,pagenum); | |
307 | aff_bom::make_hash(seghash,arg,segname,pagebuf,pagesize); | |
308 | } | |
309 | #endif | |
310 | ||
311 | /* Write out the page */ | |
312 | int ret = af_update_page(aout,pagenum,pagebuf,pagesize); | |
313 | free(pagebuf); | |
314 | return ret; | |
315 | } | |
316 | ||
317 | string base64(const u_char *buf,size_t buflen) | |
318 | { | |
319 | size_t len = buflen*2+1; | |
320 | char *str = (char *)malloc(len); | |
321 | b64_ntop(buf,buflen,str,len); | |
322 | string ret = string(str); | |
323 | free(str); | |
324 | return ret; | |
325 | } | |
326 | ||
327 | #ifndef HAVE_ISATTY | |
328 | int isatty(int fd) | |
329 | { | |
330 | return 1; // have to assume it's a tty | |
331 | } | |
332 | #endif | |
333 | ||
334 | int afcopy(char *infile,vector<string> &outfiles) | |
335 | { | |
336 | #ifdef SIGINFO | |
337 | signal(SIGINFO,sig_info); | |
338 | #endif | |
339 | hashMapT hashMap; | |
340 | ||
341 | /* Open the input file */ | |
342 | AFFILE *ain = af_open(infile,O_RDONLY,0); | |
343 | if(opt_debug) printf("af_open(%s,O_RDONLY)=%p\n",infile,ain); | |
344 | if(!ain) af_err(1,"%s",infile); | |
345 | seglist segments(ain); | |
346 | ||
347 | if(opt_zap) unlink_outfiles(outfiles); | |
348 | ||
349 | outlist afouts; // vector of output AFFs | |
350 | vector<int64_t>preened_pages; | |
351 | open_outfiles(ain,afouts,outfiles); | |
352 | ||
353 | /* Now, try to open the output files, to see if they exist */ | |
354 | current_source = infile; | |
355 | if(opt_verbose) printf("%s: ",infile); | |
356 | if(opt_verbose>1) putchar('\n'); | |
357 | ||
358 | /* If we couldn't open any output files, return */ | |
359 | if(afouts.size()==0){ | |
360 | af_close(ain); // close the input file | |
361 | return -1; | |
362 | } | |
363 | ||
364 | #ifdef USE_AFFSIGS | |
365 | /* If we are signing, initialize the signing machinery */ | |
366 | aff_bom bom(opt_note); | |
367 | if(opt_sign){ | |
368 | if(bom.read_files(opt_sign_cert_file,opt_sign_key_file)){ | |
369 | opt_sign = 0; // can't sign | |
370 | } | |
371 | } | |
372 | #endif | |
373 | ||
374 | /* Now the files are open. For each output file: | |
375 | * 1. Initialize signing if options were set and the segments aren't already signed. | |
376 | * 2. Sign all of the segments that are unsigned | |
377 | */ | |
378 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
379 | if(opt_sign_key_file && segments.has_signed_segments()==false){ | |
380 | if(af_set_sign_files(aout->af,opt_sign_key_file,opt_sign_cert_file)){ | |
381 | err(1,"%s",opt_sign_key_file); | |
382 | } | |
383 | af_sign_all_unsigned_segments(aout->af); | |
384 | opt_sign = true; | |
385 | } | |
386 | } | |
387 | ||
388 | /* Start the copying */ | |
389 | struct timeval t0,t1; | |
390 | gettimeofday(&t0,0); | |
391 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
392 | /* For each segment, get the size of the segment */ | |
393 | const char *segname = seg->name.c_str(); | |
394 | current_seg = segname; // for printing | |
395 | size_t seglen=0; | |
396 | ||
397 | if(af_get_seg(ain,segname,0,0,&seglen)){ | |
398 | unlink_outfiles(outfiles); | |
399 | err(1,"Cannot read length of segment '%s' on input file %s", segname,af_filename(ain)); | |
400 | } | |
401 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
402 | if(!segbuf){ | |
403 | unlink_outfiles(outfiles); | |
404 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
405 | (int)seglen,segname,af_filename(ain)); | |
406 | } | |
407 | ||
408 | /* Now get the raw source segment */ | |
409 | unsigned long arg=0; | |
410 | if(af_get_seg(ain,segname,&arg,segbuf,&seglen)){ | |
411 | unlink_outfiles(outfiles); // failure; unlink the output files | |
412 | err(1,"Cannot read segment '%s' in %s. Deleteing output file", segname,af_filename(ain)); | |
413 | } | |
414 | ||
415 | /* Calculate the MD5 of this segment and remember it in the map */ | |
416 | md5blob md5; | |
417 | MD5(segbuf,seglen,md5.buf); | |
418 | hashMap[segname] = md5; | |
419 | ||
420 | /* See if this is a page; if so, it is handled specially */ | |
421 | int64_t pagenumber = af_segname_page_number(segname); | |
422 | ||
423 | /* Write the segment to each file */ | |
424 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
425 | current_dest = af_filename(aout->af); | |
426 | if(opt_verbose>1 || opt_debug){ | |
427 | if(aout != afouts.begin()) printf("\n "); | |
428 | printf(" %s -> %s:%s ...", segname,af_filename(aout->af),segname); | |
429 | } | |
430 | ||
431 | /** COPY THE DATA **/ | |
432 | ||
433 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
434 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
435 | int sigmode = AF_SIGNATURE_MODE0; | |
436 | ||
437 | memset(seghash,0,sizeof(seghash)); | |
438 | ||
439 | bool copied = false; | |
440 | ||
441 | /* If we are preening, signing, or building a ToC, we need to copy the raw page */ | |
442 | if(pagenumber>=0 && (opt_preen || opt_sign_key_file)){ | |
443 | if(copy_page(ain,aout->af,pagenumber,arg,seghash,&seghash_len)==0){ | |
444 | preened_pages.push_back(pagenumber); // preened pages won't be verified by md5 | |
445 | if(opt_debug && opt_preen) printf(" (PREENED) "); | |
446 | sigmode = AF_SIGNATURE_MODE1; | |
447 | copied = true; | |
448 | } | |
449 | } | |
450 | ||
451 | /* Copy the page if it is not in the destination */ | |
452 | if(copied==false){ | |
453 | if(!aout->segs.contains(segname)){ | |
454 | if(af_update_seg(aout->af,segname,arg,segbuf,seglen)){ | |
455 | unlink_outfiles(outfiles); | |
456 | err(1,"Cannot write segment '%s' to %s.", segname,af_filename(aout->af)); | |
457 | } | |
458 | ||
459 | #ifdef USE_AFFSIGS | |
460 | if(opt_sign){ | |
461 | aff_bom::make_hash(seghash,arg,segname,segbuf,seglen); | |
462 | } | |
463 | #endif | |
464 | } | |
465 | else{ | |
466 | if(opt_verbose>1 || opt_debug) printf(" [already in %s] ",af_filename(aout->af)); | |
467 | } | |
468 | } | |
469 | #ifdef USE_AFFSIGS | |
470 | if(opt_sign) bom.add(segname,sigmode,seghash,seghash_len); | |
471 | #endif | |
472 | } | |
473 | free(segbuf); | |
474 | current_dest = 0; | |
475 | if(opt_verbose>1 || opt_debug) putchar('\n'); | |
476 | } | |
477 | current_seg = 0; | |
478 | ||
479 | #ifdef USE_AFFSIGS | |
480 | /* For each open file, make an AF_IMAGE_GID if one doesn't exist */ | |
481 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
482 | if(af_make_gid(aout->af)>0){ | |
483 | if(opt_sign){ | |
484 | af_sign_seg(aout->af,AF_IMAGE_GID); // make sure the GID is signed | |
485 | bom.add(aout->af,AF_IMAGE_GID); | |
486 | bom.add(aout->af,AF_IMAGE_GID AF_SIG256_SUFFIX); | |
487 | ||
488 | } | |
489 | } | |
490 | } | |
491 | ||
492 | if(opt_sign){ | |
493 | bom.close(); | |
494 | /* Now write to each of the output files */ | |
495 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
496 | bom.write(aout->af,segments); | |
497 | } | |
498 | } | |
499 | #endif | |
500 | ||
501 | gettimeofday(&t1,0); | |
502 | if(afouts.size()==1){ | |
503 | AFFILE *af = afouts.begin()->af; | |
504 | uint64_t w = af->bytes_written; | |
505 | double sec = ((t1.tv_sec-t0.tv_sec)+(t1.tv_usec-t0.tv_usec)/1000000.0); | |
506 | printf("%s: %"I64d" bytes transfered in %.2f seconds. xfer rate: %.2f MBytes/sec\n", | |
507 | af_filename(af),w,sec,(w/1000000.0) / sec); | |
508 | } | |
509 | ||
510 | if(opt_noverify==0){ | |
511 | current_seg = "VERIFYING"; | |
512 | /* Now verify all of the hashes */ | |
513 | if(opt_verbose || opt_debug) printf("\n\nFiles copied. Verifying...\n"); | |
514 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
515 | ||
516 | const char *segname = seg->name.c_str(); | |
517 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
518 | size_t seglen=0; | |
519 | char b2[1024]; | |
520 | ||
521 | if((aout->af)->v->flag & AF_VNODE_TYPE_RELIABLE){ | |
522 | continue; // no need to verify a reliable write | |
523 | } | |
524 | if(opt_verbose>1 || opt_debug) printf(" verifying %s...\n",segname); | |
525 | ||
526 | again: | |
527 | if(af_get_seg(aout->af,segname,0,0,&seglen)){ | |
528 | if(segname != b2 && | |
529 | segname[0]=='s' && segname[1]=='e' && segname[2]=='g' && | |
530 | isnumber(segname[3])){ | |
531 | /* Looks like a legacy segname name was renamed. | |
532 | * Try the new name | |
533 | */ | |
534 | snprintf(b2,sizeof(b2),"page%s",segname+3); | |
535 | if(opt_verbose) printf(" Couldn't read %s; looking for %s\n", | |
536 | segname,b2); | |
537 | segname = b2; | |
538 | goto again; | |
539 | } | |
540 | unlink_outfiles(outfiles); | |
541 | errx(1,"Cannot read length of segment '%s' in output file %s", | |
542 | segname,af_filename(aout->af)); | |
543 | } | |
544 | int64_t pagenumber = af_segname_page_number(segname); | |
545 | if(find(preened_pages.begin(),preened_pages.end(),pagenumber) !=preened_pages.end()){ | |
546 | /* TK: page pagenumber was preened. | |
547 | * It should probably be checked against the original hash... | |
548 | */ | |
549 | continue; | |
550 | } | |
551 | ||
552 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
553 | if(!segbuf){ | |
554 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
555 | (int)seglen,segname,af_filename(ain)); | |
556 | } | |
557 | unsigned long arg; | |
558 | if(af_get_seg(aout->af,segname,&arg,segbuf,&seglen)){ | |
559 | err(1,"Cannot read segment '%s' in %s", | |
560 | segname,af_filename(aout->af)); | |
561 | } | |
562 | ||
563 | /* Calculate the MD5 of this segment and see if it matches the map. | |
564 | * (But don't do this for preened segments. | |
565 | */ | |
566 | unsigned char md5_read[16]; | |
567 | MD5(segbuf,seglen,md5_read); | |
568 | if(memcmp(hashMap[segname].buf,md5_read,16)!=0){ | |
569 | unlink_outfiles(outfiles); | |
570 | errx(1,"Hash read from %s for segment %s doesn't validate.", | |
571 | af_filename(aout->af),segname); | |
572 | } | |
573 | free(segbuf); // free the buffer | |
574 | } | |
575 | } | |
576 | } | |
577 | ||
578 | /* Finally, close the output files*/ | |
579 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
580 | af_close(aout->af); | |
581 | } | |
582 | af_close(ain); | |
583 | if(opt_verbose>1 || opt_debug) printf("==============================\n"); | |
584 | current_source = 0; | |
585 | return 0; | |
586 | } | |
587 | ||
588 | int main(int argc,char **argv) | |
589 | { | |
590 | int ch; | |
591 | ||
592 | setvbuf(stdout,0,_IONBF,0); // turn off buffering on stdout | |
593 | while ((ch = getopt(argc, argv, "vdVxyh?zmX:Lp:P:k:c:n")) != -1) { | |
594 | switch (ch) { | |
595 | case 'v': opt_verbose++; break; | |
596 | case 'd': opt_debug++; break; | |
597 | case 'X': | |
598 | opt_preen =1; | |
599 | opt_X = optarg[0] - '0'; | |
600 | opt_preen_alg_arg = AF_PAGE_COMP_ALG_ZLIB; | |
601 | opt_preen_alg_flag = AF_COMPRESSION_ALG_ZLIB; | |
602 | if(opt_X<0 || opt_X>9) opt_X = AF_COMPRESSION_DEFAULT; | |
603 | break; | |
604 | case 'L': | |
605 | opt_preen=1; | |
606 | opt_preen_alg_arg = AF_PAGE_COMP_ALG_LZMA; | |
607 | opt_preen_alg_flag = AF_COMPRESSION_ALG_LZMA; | |
608 | break; | |
609 | case 'x': opt_x++;break; | |
610 | case 'y': opt_noverify++;break; | |
611 | case 'z': opt_zap++;break; | |
612 | case 'm': opt_missing++;break; | |
613 | case 'n': opt_note++;break; | |
614 | case 'k': | |
615 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
616 | opt_sign_key_file = optarg; | |
617 | if(opt_sign_cert_file==0) opt_sign_cert_file=optarg; | |
618 | opt_sign = true; | |
619 | break; | |
620 | case 'c': | |
621 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
622 | opt_sign_cert_file = optarg; | |
623 | break; | |
624 | case 'V': | |
625 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
626 | exit(0); | |
627 | case 'h': | |
628 | case '?': | |
629 | default: | |
630 | usage(); | |
631 | break; | |
632 | } | |
633 | } | |
634 | argc -= optind; | |
635 | argv += optind; | |
636 | ||
637 | if(argc<2){ // at this point, we need at least two args | |
638 | usage(); | |
639 | } | |
640 | ||
641 | /* We either need both a key file and a cert file, or neither */ | |
642 | if((opt_sign_key_file==0) != (opt_sign_cert_file==0)){ | |
643 | errx(1,"Both a private key and a certificate must be specified."); | |
644 | } | |
645 | ||
646 | /* Find any directories */ | |
647 | vector<string> dirlist; | |
648 | for(int i=argc-1;i>0;i--){ | |
649 | struct stat st; | |
650 | ||
651 | // s3 names that do not end with ".aff" are directories | |
652 | const char *last4 = strlen(argv[i])>4 ? argv[i]+strlen(argv[i])-4 : ""; | |
653 | if(strncmp(argv[i],"s3://",5)==0 && | |
654 | strcmp(last4,".aff")!=0){ | |
655 | dirlist.push_back(argv[i]); | |
656 | argc--; | |
657 | continue; | |
658 | } | |
659 | ||
660 | if(stat(argv[i],&st)!=0) break; // out of directories | |
661 | if((st.st_mode & S_IFMT)!=S_IFDIR) break; // found a non-dir | |
662 | dirlist.push_back(argv[i]); | |
663 | argc--; // ignore the last | |
664 | } | |
665 | ||
666 | /* If I found no directories, then there better just be two values */ | |
667 | if(dirlist.size()==0){ | |
668 | if(argc!=2){ | |
669 | fprintf(stderr,"Please specify a directory or just two AFF files.\n\n"); | |
670 | usage(); | |
671 | } | |
672 | /* Must be copying from file1 to file2. Make sure file2 does not exist */ | |
673 | if(access(argv[1],R_OK)==0){ | |
674 | fprintf(stderr,"File exists: %s\n",argv[1]); | |
675 | if(!opt_zap) exit(1); | |
676 | } | |
677 | ||
678 | vector<string> outfiles; | |
679 | outfiles.push_back(argv[1]); | |
680 | return afcopy(argv[0],outfiles); | |
681 | } | |
682 | ||
683 | /* Loop for each file and each directory */ | |
684 | ||
685 | while(argc--){ | |
686 | /* Open the output files */ | |
687 | vector<string> outfiles; | |
688 | for(u_int i=0;i<dirlist.size();i++){ | |
689 | string outfilename; | |
690 | const char *name = strrchr(*argv,'/'); | |
691 | if(name) name++; | |
692 | else name = *argv; | |
693 | ||
694 | outfilename.append(dirlist[i]); | |
695 | if(outfilename[outfilename.size()-1]!='/') { | |
696 | outfilename.append("/"); | |
697 | } | |
698 | outfilename.append(name); | |
699 | outfiles.push_back(outfilename); | |
700 | } | |
701 | afcopy(argv[0],outfiles); // old outfiles will get GCed | |
702 | argv++; | |
703 | } | |
704 | exit(0); | |
705 | } | |
706 | ||
707 |
0 | /* | |
1 | * afcrypto.cpp: | |
2 | * | |
3 | * command for dealing with encryption issues | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2007, 2008 | |
8 | * Simson L. Garfinkel | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. [omitted] | |
23 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
24 | * contributors to this program may be used to endorse or promote | |
25 | * products derived from this software without specific prior written | |
26 | * permission. | |
27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL | |
29 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
30 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
31 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
32 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
33 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
34 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
35 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
36 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
37 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
38 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
39 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
40 | * SUCH DAMAGE. | |
41 | */ | |
42 | ||
43 | #include "affconfig.h" | |
44 | #include "afflib.h" | |
45 | #include "afflib_i.h" | |
46 | #include "utils.h" | |
47 | ||
48 | #include <stdio.h> | |
49 | #include <algorithm> | |
50 | #include <vector> | |
51 | ||
52 | const char *progname = "afcrypto"; | |
53 | #define DEFAULT_PASSPHRASE_FILE ".affpassphrase" | |
54 | int opt_debug = 0; | |
55 | int opt_verbose = 0; | |
56 | int opt_just_print_encrypted_count = 0; | |
57 | int opt_just_print_unencrypted_count = 0; | |
58 | char *opt_unsealing_private_key_file= 0; | |
59 | int opt_xml = 0; | |
60 | ||
61 | void change_passphrase(const char *fn,const char *old_passphrase,const char *new_passphrase) | |
62 | { | |
63 | int fail = 0; | |
64 | ||
65 | AFFILE *af = af_open(fn,O_RDWR,0666); | |
66 | if(!af) af_err(1,fn); | |
67 | if(af_change_aes_passphrase(af,old_passphrase,new_passphrase)){ | |
68 | warnx("%s: af_change_aes_passphrase failed",fn); | |
69 | fail = 1; | |
70 | } | |
71 | af_close(af); | |
72 | if(!fail) printf("%s: passphrase changed.\n",fn); | |
73 | } | |
74 | ||
75 | void get_and_change_passphrase(const char *fn) | |
76 | { | |
77 | char old_passphrase[1024]; | |
78 | char new_passphrase[1024]; | |
79 | ||
80 | memset(old_passphrase,0,sizeof(old_passphrase)); | |
81 | memset(new_passphrase,0,sizeof(new_passphrase)); | |
82 | ||
83 | printf("Enter old passphrase: "); | |
84 | if(fgets(old_passphrase,sizeof(old_passphrase),stdin)==0) return; | |
85 | char *cc = strchr(old_passphrase,'\n');if(cc) *cc='\000'; | |
86 | ||
87 | /* See if this passphrase works*/ | |
88 | ||
89 | AFFILE *af = af_open(fn,O_RDONLY,0666); | |
90 | if(!af) af_err(1,fn); | |
91 | if(af_use_aes_passphrase(af,old_passphrase)){ | |
92 | errx(1,"passphrase incorrect"); | |
93 | } | |
94 | af_close(af); | |
95 | ||
96 | printf("Enter new passphrase: "); | |
97 | if(fgets(new_passphrase,sizeof(new_passphrase),stdin)==0) return; | |
98 | cc = strchr(new_passphrase,'\n');if(cc) *cc='\000'; | |
99 | change_passphrase(fn,old_passphrase,new_passphrase); | |
100 | } | |
101 | ||
102 | void usage() | |
103 | { | |
104 | printf("afcrypto version %s\n",PACKAGE_VERSION); | |
105 | printf("usage: afcrypto [options] filename.aff [filename2.aff ... ]\n"); | |
106 | printf(" prints if each file is encrypted or not.\n"); | |
107 | printf("options:\n"); | |
108 | printf(" -x --- output in XML\n"); | |
109 | printf(" -j --- Just print the number of encrypted segments\n"); | |
110 | printf(" -J --- Just print the number of unencrypted segments\n"); | |
111 | ||
112 | printf("\nData conversion options:\n"); | |
113 | printf(" -e --- encrypt the unencrypted non-signature segments\n"); | |
114 | printf(" -d --- decrypt the encrypted non-signature segments\n"); | |
115 | printf(" -r --- change passphrase (take old and new from stdin)\n"); | |
116 | printf(" -O old --- specify old passphrase\n"); | |
117 | printf(" -N new --- specify new passphrase\n"); | |
118 | printf(" -K mykey.key -- specifies a private keyfile for unsealing (may not be repeated)\n"); | |
119 | printf(" -C mycert.crt -- specifies a certificate file for sealing (may be repeated)\n"); | |
120 | printf(" -S --- add symmetric encryptiong (passphrase) to AFFILE encrypted with public key\n"); | |
121 | printf(" (requires a private key and a specified passphrase).\n"); | |
122 | printf(" -A --- add asymmetric encryption to a AFFILE encrypted with a passphrase\n"); | |
123 | printf(" (requires a certificate file spcified with the -C option\n"); | |
124 | ||
125 | ||
126 | printf("\nPassword Cracking Options:\n"); | |
127 | printf(" -p passphrase --- checks to see if passphrase is the passphrase of the file\n"); | |
128 | printf(" exit code is 0 if it is, -1 if it is not\n"); | |
129 | printf(" -k --- attempt to crack passwords by reading a list of passwords from ~/.affpassphrase\n"); | |
130 | printf(" -f file --- Crack passwords but read them from file.\n"); | |
131 | ||
132 | printf("\nDebugging:\n"); | |
133 | printf(" -V --- Just print the version number and exit.\n"); | |
134 | printf(" -D --- debug; print out each key as it is tried\n"); | |
135 | printf(" -l --- List the installed hash and encryption algorithms \n"); | |
136 | printf("Note: This program ignores the environment variables:\n"); | |
137 | puts(AFFLIB_PASSPHRASE); | |
138 | puts(AFFLIB_PASSPHRASE_FILE); | |
139 | puts(AFFLIB_PASSPHRASE_FD); | |
140 | puts(AFFLIB_DECRYPTING_PRIVATE_KEYFILE); | |
141 | exit(0); | |
142 | } | |
143 | ||
144 | /* Try each of the passphrases in the file against the passphrase. If it is found, return it. */ | |
145 | char *check_file(AFFILE *af,const char *passphrase_file) | |
146 | { | |
147 | char *ret = 0; | |
148 | FILE *f = fopen(passphrase_file,"r"); | |
149 | if(!f) return 0; | |
150 | ||
151 | char buf[1024]; | |
152 | memset(buf,0,sizeof(buf)); | |
153 | while(fgets(buf,sizeof(buf)-1,f)){ | |
154 | char *cc = strchr(buf,'\n'); | |
155 | if(cc) *cc = 0; | |
156 | if(opt_debug){ | |
157 | if(opt_debug) printf("checking with '%s' ... ",buf); | |
158 | fflush(stdout); | |
159 | } | |
160 | int r= af_use_aes_passphrase(af,buf); | |
161 | if(r==0){ | |
162 | if(opt_debug) printf("YES!\n"); | |
163 | ret = strdup(buf); | |
164 | break; | |
165 | } | |
166 | } | |
167 | fclose(f); | |
168 | return ret; | |
169 | } | |
170 | ||
171 | /** | |
172 | * This will eventually decrypt non-signature segments that are | |
173 | * encrypted | |
174 | * | |
175 | * @param af - the AFFILE to open | |
176 | * @param count - The number of pages actually encrypted | |
177 | */ | |
178 | int af_decrypt_encrypted_segments(AFFILE *af, int *count, int mode) | |
179 | { | |
180 | af_set_option(af,AF_OPTION_AUTO_ENCRYPT,0); | |
181 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); // turn off auto decryption | |
182 | aff::seglist sl(af); // get the list of the segments | |
183 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,1); // turn auto decryption back on | |
184 | for(aff::seglist::const_iterator si = sl.begin();si!=sl.end();si++){ | |
185 | if(opt_debug) printf(" checking segment %s",si->name.c_str()); | |
186 | if(af_is_encrypted_segment(si->name.c_str())){ | |
187 | ||
188 | if(mode == O_RDONLY){ // if readonly, just tally | |
189 | (*count) ++; | |
190 | if(opt_debug) printf(" would decrypt segment\n"); | |
191 | continue; | |
192 | } | |
193 | ||
194 | /* Generate the name of the unencrypted segment */ | |
195 | char segname[AF_MAX_NAME_LEN]; | |
196 | strcpy(segname,si->name.c_str()); | |
197 | char *cc = strstr(segname,AF_AES256_SUFFIX); | |
198 | if(!cc){ | |
199 | if(opt_debug) printf(" will not decrypt AFFKEY segments; will be deleted later.\n"); | |
200 | continue; // something is wrong; can't find the /aes256 | |
201 | } | |
202 | *cc = '\000'; // truncate off the /aes256 | |
203 | ||
204 | /* Get the segment and put it, which will force the decryption to take place */ | |
205 | if(opt_debug) printf(" decrypting segment\n"); | |
206 | u_char *buf = (u_char *)malloc(si->len); | |
207 | if(!buf) warn("malloc(%zd) failed", si->len); | |
208 | else { | |
209 | unsigned long arg; | |
210 | size_t datalen = si->len; | |
211 | if(af_get_seg(af,segname,&arg,buf,&datalen)){ | |
212 | warn("Could not read segment '%s'",segname); | |
213 | } | |
214 | else{ | |
215 | /* si->datalen >= datalen. | |
216 | * si->datalen is the length of the encrypted segment. | |
217 | * datalen is the length of the decrypted segment. | |
218 | */ | |
219 | assert(si->len >= datalen); | |
220 | assert(si->arg==arg); | |
221 | if(af_update_seg(af,segname,arg,buf,datalen)){ | |
222 | warn("Could not decrypt segment '%s'",si->name.c_str()); | |
223 | } else { | |
224 | (*count) ++; | |
225 | } | |
226 | } | |
227 | free(buf); | |
228 | } | |
229 | } else { | |
230 | if(opt_debug) printf(" not encrypted\n"); | |
231 | } | |
232 | } | |
233 | /* Delete the AF_AFFKEY segment */ | |
234 | if(af_get_seg(af,AF_AFFKEY,0,0,0)==0) af_del_seg(af,AF_AFFKEY); | |
235 | /* Delete all of the EVP segments */ | |
236 | for(int i=0;;i++){ | |
237 | char segname[1024]; | |
238 | snprintf(segname,sizeof(segname),AF_AFFKEY_EVP,i); | |
239 | if(af_get_seg(af,segname,0,0,0)!=0) break; // found the last segment | |
240 | if(af_del_seg(af,segname)) warn("Cannot delete segment %s",segname); | |
241 | } | |
242 | return 0; | |
243 | } | |
244 | ||
245 | ||
246 | /** | |
247 | * Encrypts the non-signature segments that are not encrypted. | |
248 | * There is no reason to encrypt the signature segments. | |
249 | * | |
250 | * @param af - the AFFILE to open | |
251 | * @param count - The number of pages actually encrypted | |
252 | */ | |
253 | ||
254 | int af_encrypt_unencrypted_nonsignature_segments(AFFILE *af,int *count,int mode) | |
255 | { | |
256 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); // do not automatically decrypt | |
257 | aff::seglist sl(af); | |
258 | for(aff::seglist::const_iterator si = sl.begin();si!=sl.end();si++){ | |
259 | if(si->name == AF_AFFKEY) continue; // don't encrypt the affkey! | |
260 | if(strstr(si->name.c_str(),"affkey_evp")) continue; | |
261 | if(!af_is_encrypted_segment(si->name.c_str()) && | |
262 | !af_is_signature_segment(si->name.c_str())){ | |
263 | ||
264 | if(mode == O_RDONLY){ // if readonly, just tally | |
265 | (*count) ++; | |
266 | continue; | |
267 | } | |
268 | ||
269 | /* Get the segment and put it, which will force the encryption to take place */ | |
270 | if(opt_debug) printf(" encrypting segment %s\n",si->name.c_str()); | |
271 | u_char *buf = (u_char *)malloc(si->len); | |
272 | if(!buf) warn("Cannot encrypt segment '%s' --- too large (%zd bytes) --- malloc failed", | |
273 | si->name.c_str(),si->len); | |
274 | else { | |
275 | unsigned long arg; | |
276 | size_t datalen = si->len; | |
277 | if(af_get_seg(af,si->name.c_str(),&arg,buf,&datalen)){ | |
278 | warn("Could not read segment '%s'",si->name.c_str()); | |
279 | } | |
280 | else{ | |
281 | /* make sure that what we read is what we thought we were going to read */ | |
282 | assert(si->len==datalen); | |
283 | assert(si->arg==arg); | |
284 | if(af_update_seg(af,si->name.c_str(),arg,buf,datalen)){ | |
285 | warn("Could not encrypt segment '%s'",si->name.c_str()); | |
286 | } else { | |
287 | (*count) ++; | |
288 | } | |
289 | } | |
290 | free(buf); | |
291 | } | |
292 | } else { | |
293 | if(opt_debug) printf(" already encrypted or signed: %s\n",si->name.c_str()); | |
294 | } | |
295 | } | |
296 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,1); // go back to automatically decrypting | |
297 | return 0; | |
298 | } | |
299 | ||
300 | void list_openssl_hashes() | |
301 | { | |
302 | const char *digests[] = {"md5","sha1","sha256",0}; | |
303 | OpenSSL_add_all_algorithms(); | |
304 | for(int i=0;digests[i];i++){ | |
305 | printf("OpenSSL has %s: %s\n",digests[i],EVP_get_digestbyname(digests[i]) ? "YES" : "NO"); | |
306 | } | |
307 | exit(0); | |
308 | } | |
309 | ||
310 | int main(int argc,char **argv) | |
311 | { | |
312 | int bflag, ch; | |
313 | const char *old_passphrase=0; | |
314 | const char *new_passphrase=0; | |
315 | const char *check_passphrase = 0; | |
316 | char *passphrase_file = 0; | |
317 | const char *progname = argv[0]; | |
318 | int opt_encrypt = 0; | |
319 | int opt_decrypt = 0; | |
320 | int opt_add_passphrase_to_public_key = 0; | |
321 | int opt_add_public_key_to_passphrase = 0; | |
322 | ||
323 | int mode = O_RDONLY; // mode for opening AFF file | |
324 | const char **certificates = (const char **)malloc(0); | |
325 | int num_certificates = 0; | |
326 | const char *envvars[] = {AFFLIB_PASSPHRASE,AFFLIB_PASSPHRASE_FILE,AFFLIB_PASSPHRASE_FD, | |
327 | AFFLIB_DECRYPTING_PRIVATE_KEYFILE,0}; | |
328 | for(int i=0;envvars[i];i++){ | |
329 | /* Don't use auto-supplied passphrases */ | |
330 | #ifdef HAVE_UNSETENV | |
331 | unsetenv(envvars[i]); | |
332 | #else | |
333 | if(getenv(envvars[i])){ | |
334 | fprintf(stderr,"Please unset %s and restart\n",envvars[i]); | |
335 | exit(1); | |
336 | } | |
337 | #endif | |
338 | } | |
339 | ||
340 | bflag = 0; | |
341 | int opt_change = 0; | |
342 | const char *home = getenv("HOME"); | |
343 | ||
344 | while ((ch = getopt(argc, argv, "zreC:SAO:N:p:f:kdDh?VK:vljJx:")) != -1) { | |
345 | switch (ch) { | |
346 | case 'x': opt_xml = 1; break; | |
347 | case 'j': opt_just_print_encrypted_count =1;break; | |
348 | case 'J': opt_just_print_unencrypted_count =1;break; | |
349 | ||
350 | /* These options make the mode read-write */ | |
351 | case 'r': opt_change = 1; mode = O_RDWR; break; | |
352 | case 'e': opt_encrypt = 1; mode = O_RDWR; break; | |
353 | case 'd': opt_decrypt = 1; mode = O_RDWR; break; | |
354 | case 'S': opt_add_passphrase_to_public_key = 1; mode = O_RDWR; break; | |
355 | case 'A': opt_add_public_key_to_passphrase = 1; mode = O_RDWR; break; | |
356 | /* These just set up variables */ | |
357 | case 'C': | |
358 | certificates = (const char **)realloc(certificates,sizeof(int *)*(num_certificates+1)); | |
359 | certificates[num_certificates] = optarg; | |
360 | num_certificates++; | |
361 | break; | |
362 | case 'K': opt_unsealing_private_key_file = optarg;break; | |
363 | case 'O': old_passphrase = optarg;break; | |
364 | case 'N': new_passphrase = optarg;break; | |
365 | case 'p': check_passphrase = optarg;break; | |
366 | case 'f': passphrase_file = optarg;break; | |
367 | case 'k': | |
368 | if(!home) home = "/"; | |
369 | passphrase_file = (char *)malloc(strlen(home)+strlen(DEFAULT_PASSPHRASE_FILE)+2); | |
370 | strcpy(passphrase_file,home); | |
371 | strcat(passphrase_file,"/"); | |
372 | strcat(passphrase_file,DEFAULT_PASSPHRASE_FILE); | |
373 | break; | |
374 | case 'D': opt_debug = 1;break; | |
375 | case 'v': opt_verbose = 1;break; | |
376 | case 'l': list_openssl_hashes(); exit(0); | |
377 | case 'h': | |
378 | case '?': | |
379 | default: | |
380 | usage(); | |
381 | break; | |
382 | case 'V': | |
383 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
384 | exit(0); | |
385 | } | |
386 | } | |
387 | argc -= optind; | |
388 | argv += optind; | |
389 | if(argc<1){ | |
390 | fprintf(stderr,"No image file specified\n"); | |
391 | usage(); | |
392 | } | |
393 | ||
394 | if(opt_just_print_encrypted_count && opt_just_print_unencrypted_count){ | |
395 | errx(1,"Options -j and -J conflict\n"); | |
396 | } | |
397 | ||
398 | if(num_certificates>0 && (opt_encrypt==0 && opt_decrypt==0 && opt_add_public_key_to_passphrase==0)){ | |
399 | errx(1,"Encryption certificates specified but neither -e nor -d option not set. " | |
400 | "What do you want me to do with these certificates? "); | |
401 | } | |
402 | ||
403 | if((check_passphrase || passphrase_file) && opt_encrypt){ | |
404 | err(1,"Sorry, can't both encrypt and password crack. Pick one.\n"); | |
405 | } | |
406 | ||
407 | if(opt_encrypt && (new_passphrase==0 && num_certificates==0) && mode!=O_RDONLY){ | |
408 | err(1,"Currently -e requires that the passphrase be specified on the command line\n" | |
409 | "or that one or more encryption certificates be provided\n"); | |
410 | } | |
411 | ||
412 | while(argc--){ | |
413 | const char *fname = *argv++; | |
414 | ||
415 | if(opt_change){ | |
416 | if(old_passphrase && new_passphrase) change_passphrase(fname,old_passphrase,new_passphrase); | |
417 | else get_and_change_passphrase(fname); | |
418 | } | |
419 | ||
420 | /* Get the information */ | |
421 | AFFILE *af = af_open(fname,mode,0); | |
422 | if(!af) af_err(1,"af_open(%s)",fname); | |
423 | if(af_identify(af)!=AF_IDENTIFY_AFF && af_identify(af)!=AF_IDENTIFY_AFD){ | |
424 | errx(1,"Cannot encrypt %s: %s only supports AFF and AFD files.",af_filename(af),progname); | |
425 | } | |
426 | ||
427 | if(opt_encrypt && new_passphrase){ | |
428 | int r = af_establish_aes_passphrase(af,new_passphrase); | |
429 | switch(r){ | |
430 | case AF_ERROR_NO_AES: errx(1,"AFFLIB: AES256 not available; cannot continue"); | |
431 | case AF_ERROR_NO_SHA256: errx(1,"AFFLIB: SHA256 not available; cannot continue"); | |
432 | default: err(1,"%s: cannot establish passphrase (error %d)",fname,r); | |
433 | case 0: | |
434 | case AF_ERROR_AFFKEY_EXISTS: | |
435 | /* no matter if we established it or if a phrase already exists, try to use it now */ | |
436 | /* File already has a passphrase; see if this is it. */ | |
437 | break; | |
438 | } | |
439 | r = af_use_aes_passphrase(af,new_passphrase); | |
440 | switch(r){ | |
441 | case 0: break; // everything okay | |
442 | case AF_ERROR_WRONG_PASSPHRASE: errx(1,"%s: wrong passphrase",fname); | |
443 | default: errx(1,"%s: passphrase already established (error %d)",fname,r); | |
444 | } | |
445 | } | |
446 | ||
447 | if(opt_decrypt && old_passphrase){ | |
448 | int r = af_use_aes_passphrase(af, old_passphrase); | |
449 | switch(r){ | |
450 | case 0: printf("Passphrase is good!\n"); break; | |
451 | case AF_ERROR_WRONG_PASSPHRASE: errx(1,"%s: wrong passphrase",fname); | |
452 | } | |
453 | } | |
454 | ||
455 | if (opt_add_public_key_to_passphrase){ | |
456 | if(!num_certificates) errx(1,"You must specify a certificate with the -C option"); | |
457 | if(!check_passphrase) errx(1,"You must specify a passphrase with the -p option"); | |
458 | printf("Attepmting to add public key to AFFILE...\n"); | |
459 | if(af->crypto->sealing_key_set) return AF_ERROR_KEY_SET; // already enabled | |
460 | unsigned char affkey[32]; | |
461 | int r = af_get_aes_key_from_passphrase(af,check_passphrase,affkey); | |
462 | if(r) errx(1, "%s: cannot get aes key. Failed to add Public Key", fname); | |
463 | af_seal_affkey_using_certificates(af, certificates, num_certificates, affkey); | |
464 | printf("...Public key added successfully.\n"); | |
465 | } | |
466 | ||
467 | if(opt_encrypt && num_certificates){ | |
468 | if(af_set_seal_certificates(af,certificates,num_certificates)){ | |
469 | errx(1,"%s: can't set encryption certificate%s",fname,num_certificates==1 ? "" : "s"); | |
470 | } | |
471 | } | |
472 | if(opt_encrypt){ | |
473 | int count = 0; | |
474 | if(af_encrypt_unencrypted_nonsignature_segments(af,&count,mode)){ | |
475 | errx(1,"%s: can't encrypt unsigned, unencrypted segments",fname); | |
476 | } | |
477 | if(mode==O_RDONLY){ // if it is readonly just print the number of segments that would be changed. | |
478 | printf("%d\n",count); | |
479 | af_close(af); | |
480 | continue; | |
481 | } | |
482 | } | |
483 | if(opt_decrypt){ | |
484 | int count = 0; | |
485 | if(af_decrypt_encrypted_segments(af, &count, mode)){ | |
486 | } | |
487 | if(mode==O_RDONLY){ | |
488 | printf("%d\n",count); | |
489 | af_close(af); | |
490 | continue; | |
491 | } | |
492 | } | |
493 | ||
494 | if(opt_add_passphrase_to_public_key) { | |
495 | if(!new_passphrase) errx(1,"You must specify a new passphrase with the -N option"); | |
496 | printf("Attempting to add passphrase...\n"); | |
497 | u_char affkey[32]; | |
498 | if(af_get_affkey_using_keyfile(af, opt_unsealing_private_key_file,affkey)){ | |
499 | errx(1,"%s: cannot unseal AFFKEY",fname); | |
500 | } | |
501 | if(af_save_aes_key_with_passphrase(af,new_passphrase,affkey)){ | |
502 | af_err(1,"%s: could not set the passphrase",fname); | |
503 | } | |
504 | printf("... new passphrase established.\n"); | |
505 | } | |
506 | ||
507 | ||
508 | af_vnode_info vni; | |
509 | memset(&vni,0,sizeof(vni)); | |
510 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed: ",fname); | |
511 | const char *the_passphrase = 0; // the correct passphrase | |
512 | ||
513 | if(opt_just_print_encrypted_count){ | |
514 | printf("%d\n",vni.segment_count_encrypted); | |
515 | af_close(af); | |
516 | continue; | |
517 | } | |
518 | ||
519 | if(opt_just_print_unencrypted_count){ | |
520 | printf("%d\n",vni.segment_count_total-vni.segment_count_encrypted); | |
521 | af_close(af); | |
522 | continue; | |
523 | } | |
524 | ||
525 | ||
526 | /* were we supposed to try a check_passphrase? */ | |
527 | if(check_passphrase){ | |
528 | if(af_use_aes_passphrase(af,check_passphrase)==0){ | |
529 | the_passphrase = check_passphrase; | |
530 | } | |
531 | af_use_aes_passphrase(af,0); // clear the passphrase | |
532 | } | |
533 | ||
534 | /* Is a passphrase file provided? */ | |
535 | if(!the_passphrase && passphrase_file){ | |
536 | the_passphrase = check_file(af,passphrase_file); | |
537 | if(the_passphrase){ | |
538 | af_use_aes_passphrase(af,0); // clear the passphrase | |
539 | } | |
540 | } | |
541 | ||
542 | if(opt_xml){ | |
543 | /* This should be replaced with our xml.cpp object */ | |
544 | printf("<afcrypto>\n"); | |
545 | printf(" <image_filename>%s</image_filename>\n",fname); | |
546 | printf(" <segment_count_total>%d</segment_count_total>\n",vni.segment_count_total); | |
547 | printf(" <segment_count_signed>%d</segment_count_signed>\n",vni.segment_count_signed); | |
548 | printf(" <segment_count_encrypted>%d</segment_count_encrypted>\n",vni.segment_count_encrypted); | |
549 | printf(" <page_count_total>%d</page_count_total>\n",vni.page_count_total); | |
550 | printf(" <page_count_encrypted>%d</page_count_encrypted>\n",vni.page_count_encrypted); | |
551 | if(the_passphrase){ | |
552 | printf(" <passphrase correct='1'>%s</passphrase>\n",the_passphrase); | |
553 | } | |
554 | printf("</afcrypto>\n"); | |
555 | } | |
556 | else{ | |
557 | /* re-run vstat because counts may have changed */ | |
558 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed: ",fname); | |
559 | printf("%s: %5d segments; %5d signed; %5d encrypted; %5d pages; %5d encrypted pages", | |
560 | fname,vni.segment_count_total,vni.segment_count_signed,vni.segment_count_encrypted, | |
561 | vni.page_count_total,vni.page_count_encrypted ); | |
562 | if(the_passphrase) printf("passphrase correct (\"%s\")",the_passphrase); | |
563 | putchar('\n'); | |
564 | } | |
565 | af_close(af); | |
566 | } | |
567 | return(0); | |
568 | } |
0 | /* | |
1 | * afdiskprint.cpp: | |
2 | * | |
3 | * Creates a diskprint AFF structure | |
4 | */ | |
5 | ||
6 | /* | |
7 | * PUBLIC DOMAIN | |
8 | * By Simson L. Garfinkel | |
9 | * | |
10 | * The software provided here is released by the Naval Postgraduate | |
11 | * School (NPS), an agency of the U.S. Department of Navy.The software | |
12 | * bears no warranty, either expressed or implied. NPS does not assume | |
13 | * legal liability nor responsibility for a User's use of the software | |
14 | * or the results of such use. | |
15 | * | |
16 | * Please note that within the United States, copyright protection, | |
17 | * under Section 105 of the United States Code, Title 17, is not | |
18 | * available for any work of the United States Government and/or for | |
19 | * any works created by United States Government employees. User | |
20 | * acknowledges that this software contains work which was created by | |
21 | * NPS employees and is therefore in the public domain and not | |
22 | * subject to copyright. | |
23 | */ | |
24 | ||
25 | ||
26 | #include "affconfig.h" | |
27 | #include "afflib.h" | |
28 | #include "afflib_i.h" | |
29 | #include "base64.h" | |
30 | #include "hashextent.h" | |
31 | ||
32 | #ifdef HAVE_EXPAT | |
33 | ||
34 | #include <openssl/evp.h> | |
35 | ||
36 | #ifdef WIN32 | |
37 | #include "unix4win32.h" | |
38 | #endif | |
39 | ||
40 | #include <vector> | |
41 | #include <string> | |
42 | #include <iostream> | |
43 | #include <sstream> | |
44 | #include <map> | |
45 | #include <set> | |
46 | ||
47 | #ifdef HAVE_CSTRING | |
48 | #include <cstring> | |
49 | #endif | |
50 | ||
51 | const char *hashes[] = {"SHA256","SHA1",0}; // what should we hash? | |
52 | ||
53 | using namespace std; | |
54 | ||
55 | #if HAVE_CTYPE_H | |
56 | #include <ctype.h> | |
57 | #endif | |
58 | ||
59 | #if !defined(HAVE_ISALPHANUM) && defined(HAVE_ISALNUM) | |
60 | #define isalphanum(c) isalnum(c) | |
61 | #endif | |
62 | ||
63 | #if !defined(HAVE_ISALPHANUM) && !defined(HAVE_ISALNUM) | |
64 | #define isalphanum(c) (isalpha(c)||isdigit(c)) | |
65 | #endif | |
66 | ||
67 | #if !defined(O_BINARY) | |
68 | #define O_BINARY 0 | |
69 | #endif | |
70 | ||
71 | const char *progname = "afdiskprint"; | |
72 | const char *xml_special_chars = "<>\r\n&'\""; | |
73 | ||
74 | void usage() | |
75 | { | |
76 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
77 | printf("usage: %s [options] infile \n",progname); | |
78 | printf(" -x XML = Verify the diskprint\n"); | |
79 | printf(" -V = Just print the version number and exit.\n"); | |
80 | printf(" -h = Print this help.\n"); | |
81 | exit(0); | |
82 | } | |
83 | ||
84 | /**************************************************************** | |
85 | ** Support routines... | |
86 | */ | |
87 | ||
88 | /** | |
89 | * Return a random 64-bit number | |
90 | */ | |
91 | uint64_t random64() | |
92 | { | |
93 | return (((uint64_t)random())<<32) | random(); | |
94 | } | |
95 | ||
96 | uint64_t atoi64(const char *buf) | |
97 | { | |
98 | uint64_t ret=0; | |
99 | sscanf(buf,"%"PRIu64,&ret); | |
100 | return ret; | |
101 | } | |
102 | ||
103 | ||
104 | static int *hexcharvals = 0; | |
105 | static void nsrl_bloom_init() | |
106 | { | |
107 | if(hexcharvals==0){ | |
108 | /* Need to initialize this */ | |
109 | int i; | |
110 | hexcharvals = (int *)calloc(sizeof(int),256); | |
111 | for(i=0;i<10;i++){ | |
112 | hexcharvals['0'+i] = i; | |
113 | } | |
114 | for(i=10;i<16;i++){ | |
115 | hexcharvals['A'+i-10] = i; | |
116 | hexcharvals['a'+i-10] = i; | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | ||
122 | /** | |
123 | * Convert a hex representation to binary, and return | |
124 | * the number of bits converted. | |
125 | * @param binbuf output buffer | |
126 | * @param binbuf_size size of output buffer in bytes. | |
127 | * @param hex input buffer (in hex) | |
128 | */ | |
129 | int nsrl_hex2bin(unsigned char *binbuf,size_t hexbuf_size,const char *hex) | |
130 | { | |
131 | int bits = 0; | |
132 | if(hexcharvals==0) nsrl_bloom_init(); | |
133 | while(hex[0] && hex[1] && hexbuf_size>0){ | |
134 | *binbuf++ = ((hexcharvals[(unsigned char)hex[0]]<<4) | | |
135 | hexcharvals[(unsigned char)hex[1]]); | |
136 | hex += 2; | |
137 | bits += 8; | |
138 | hexbuf_size -= 1; | |
139 | } | |
140 | if(hexbuf_size>0) binbuf[0] = 0; // might as well null-terminate if there is room | |
141 | return bits; | |
142 | } | |
143 | ||
144 | ||
145 | ||
146 | /** | |
147 | * Strip an XML string as necessary for a tag name. | |
148 | */ | |
149 | ||
150 | void out_xmlstr(ostream &ostr,int indent,const char *tag,const char *value) | |
151 | { | |
152 | for(int i=0;i<indent;i++) ostr << " "; | |
153 | ostr << "<" << tag << ">"; | |
154 | for(const char *ch=value;*ch;ch++){ | |
155 | if(isprint(*ch) && !strchr(xml_special_chars,*ch)){ | |
156 | ostr << *ch; | |
157 | } | |
158 | } | |
159 | ostr << "</" << tag << ">"; | |
160 | } | |
161 | ||
162 | void out_xmlhex(ostream &ostr,int indent,const char *tag,const char **attribs, | |
163 | unsigned char *md,int len) | |
164 | { | |
165 | for(int i=0;i<indent;i++) ostr << ' '; | |
166 | ostr << "<" << tag << " coding='base16'"; | |
167 | for(int i=0;attribs && attribs[i];i++){ | |
168 | ostr << " "; | |
169 | ostr << attribs[i]; | |
170 | } | |
171 | ostr << ">" << hashextent::bin2hex(md,len) << "</" << tag << ">\n"; | |
172 | } | |
173 | ||
174 | /** | |
175 | * Calculate the disk fingerprint for a spcific file and output it to stdout. | |
176 | * Includes other named segments. | |
177 | * | |
178 | * @param infile the file to process. | |
179 | */ | |
180 | ||
181 | int diskprint(const char *infile) | |
182 | { | |
183 | /** segments to include in output. | |
184 | */ | |
185 | const char *segments[] = {AF_MD5,AF_SHA1,AF_SHA256,AF_CREATOR,AF_CASE_NUM,AF_IMAGE_GID, | |
186 | AF_ACQUISITION_ISO_COUNTRY, | |
187 | AF_ACQUISITION_COMMAND_LINE,AF_ACQUISITION_DATE, | |
188 | AF_ACQUISITION_NOTES,AF_ACQUISITION_TECHNICIAN, | |
189 | AF_BATCH_NAME,AF_BATCH_ITEM_NAME,0}; | |
190 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
191 | if(!af){ | |
192 | warn("%s",infile); | |
193 | return -1; | |
194 | } | |
195 | ||
196 | cout << "<!-- XML generated by " << progname << " version " << PACKAGE_VERSION << " -->\n"; | |
197 | cout << "<diskprint image_filename='" << infile << "'>\n"; | |
198 | ||
199 | /* First handle the imagesize */ | |
200 | int64_t imagesize = af_get_imagesize(af); | |
201 | if(imagesize>0){ | |
202 | char buf[32]; | |
203 | snprintf(buf,sizeof(buf),"%"PRIu64,imagesize); | |
204 | out_xmlstr(cout,2,AF_IMAGESIZE,buf); | |
205 | cout << "\n"; | |
206 | } | |
207 | /* Get sector size and number of sectors */ | |
208 | unsigned long sectorsize=512; // default sectorsize | |
209 | af_get_seg(af,AF_SECTORSIZE,§orsize,0,0); | |
210 | if(sectorsize==0) sectorsize=512; // default sectorsize | |
211 | int64_t sectors = imagesize/sectorsize; | |
212 | if(sectors>0){ | |
213 | char buf[32]; | |
214 | snprintf(buf,sizeof(buf),"%lu",sectorsize); | |
215 | out_xmlstr(cout,2,AF_SECTORSIZE,buf); | |
216 | cout << "\n"; | |
217 | } | |
218 | ||
219 | /* Output specific named segments */ | |
220 | for(int i=0;segments[i];i++){ | |
221 | char buf[65536]; | |
222 | size_t buflen = sizeof(buf); | |
223 | if(af_get_seg(af,segments[i],0,(u_char *)buf,&buflen)==0){ | |
224 | buf[buflen] = 0; // null terminate it | |
225 | if(af_display_as_hex(segments[i])){ | |
226 | out_xmlhex(cout,2,segments[i],0,(u_char *)buf,buflen); | |
227 | } else { | |
228 | out_xmlstr(cout,2,segments[i],buf); | |
229 | } | |
230 | } | |
231 | } | |
232 | ||
233 | /** | |
234 | * The list of segments to hash is defined by: | |
235 | * 1. The first 128K sectors. | |
236 | * 2. The last 128K sectors. | |
237 | * 3. A random set of 64K sectors. | |
238 | */ | |
239 | hashvector hashextents; | |
240 | ||
241 | for(int i=0;i<8;i++){ | |
242 | hashextents.push_back(hashextent(131072*i,131072)); | |
243 | } | |
244 | for(int i=0;i<8;i++){ | |
245 | hashextents.push_back(hashextent(imagesize-131072*(8-i),131072)); | |
246 | } | |
247 | ||
248 | /* Pick some random hashextents as well */ | |
249 | for(int i=0;i<100;i++){ | |
250 | uint64_t sector = random64() % (sectors-128); | |
251 | hashextents.push_back(hashextent(sector*sectorsize,65536)); | |
252 | } | |
253 | ||
254 | /** Sort the segments for maximal seek efficiency. | |
255 | */ | |
256 | sort(hashextents.begin(),hashextents.end(),hashextent::compare); | |
257 | ||
258 | /** Send the hashes to stdout using print_hash. | |
259 | */ | |
260 | cout << " <hashes>\n"; | |
261 | for(hashvector::iterator it=hashextents.begin(); it!=hashextents.end(); it++){ | |
262 | for(int i=0;hashes[i];i++){ | |
263 | if((*it).compute_digest(af,hashes[i])==0){ | |
264 | cout << " " << (*it).toXML() << "\n"; | |
265 | } | |
266 | } | |
267 | } | |
268 | cout << " </hashes>\n"; | |
269 | cout << "</diskprint>\n"; | |
270 | af_close(af); | |
271 | return 0; | |
272 | } | |
273 | ||
274 | ||
275 | /** | |
276 | * Code for reading the hashvector XML structure. | |
277 | */ | |
278 | #include <expat.h> | |
279 | ||
280 | class diskprintReader { | |
281 | public: | |
282 | /* General EXPAT stuff */ | |
283 | XML_Parser parser; | |
284 | bool get_cdata; // this is cdata worth getting | |
285 | string cdata; // the cdata that has been gotten | |
286 | diskprintReader():get_cdata(false),hash(0){ | |
287 | parser = XML_ParserCreate(NULL); | |
288 | XML_SetUserData(parser,this); | |
289 | XML_SetElementHandler(parser,startElement,endElement); | |
290 | XML_SetCharacterDataHandler(parser,cHandler); | |
291 | } | |
292 | int parse(const char *buf,int len) { return XML_Parse(parser, buf, len, 1);} | |
293 | void clear(){ | |
294 | cdata = ""; | |
295 | get_cdata = false; | |
296 | } | |
297 | ||
298 | /* Specific stuff for XML diskprint */ | |
299 | hashextent *hash; // current hash | |
300 | hashvector hashextents; // all discovered hashes | |
301 | /* Turn the static functions into method calls */ | |
302 | static void startElement(void *userData,const char *name,const char **attrs){ | |
303 | ((diskprintReader *)userData)->startElement(name,attrs); | |
304 | } | |
305 | static void endElement(void *userData,const char *name){ | |
306 | ((diskprintReader *)userData)->endElement(name); | |
307 | } | |
308 | static void cHandler(void *userData,const XML_Char *s,int len){ | |
309 | diskprintReader *dh = (diskprintReader *)userData; | |
310 | if(dh->get_cdata) dh->cdata.append(s,len); | |
311 | } | |
312 | void startElement(string name,const char **attrs){ | |
313 | clear(); | |
314 | /* If this is an element that we want, indicate such */ | |
315 | if(name=="hash"){ | |
316 | hash = new hashextent(); | |
317 | for(int i=0;attrs[i];i+=2){ | |
318 | if(strcmp(attrs[i],"coding")==0){ hash->coding = attrs[i+1]; continue;} | |
319 | if(strcmp(attrs[i],"start")==0){ hash->start = atoi64(attrs[i+1]); continue;} | |
320 | if(strcmp(attrs[i],"bytes")==0){ hash->bytes = atoi64(attrs[i+1]); continue;} | |
321 | if(strcmp(attrs[i],"alg")==0){ hash->digest_name = attrs[i+1]; continue;} | |
322 | } | |
323 | get_cdata = true; | |
324 | } | |
325 | } | |
326 | void endElement(const char *name){ | |
327 | if(get_cdata==false) return; // don't care about it. | |
328 | if(!strcmp(name,"hash")){ | |
329 | if(hash->coding=="base16"){ | |
330 | hash->hexdigest = cdata; | |
331 | } | |
332 | hashextents.push_back(*hash); | |
333 | } | |
334 | if(!strcmp(name,"diskprint")){ | |
335 | XML_StopParser(parser,0); // stop the parser | |
336 | return; | |
337 | } | |
338 | get_cdata = false; | |
339 | } | |
340 | }; | |
341 | ||
342 | void diskprint_verify(const char *filename,const char *xmlfile) | |
343 | { | |
344 | AFFILE *af = af_open(filename,O_RDONLY,0); | |
345 | if(!af) err(1,"af_open(%s): ",filename); | |
346 | ||
347 | /* Let's read the XML file */ | |
348 | int fd = open(xmlfile,O_RDONLY|O_BINARY); | |
349 | if(!fd) err(1,"open: %s",xmlfile); | |
350 | struct stat st; | |
351 | if(fstat(fd,&st)) err(1,"stat: %s",xmlfile); | |
352 | char *buf = (char *)malloc(st.st_size+1); | |
353 | if(!buf) err(1,"malloc"); | |
354 | ||
355 | if(read(fd,buf,st.st_size)!=st.st_size) err(1,"cannot read XML file"); | |
356 | buf[st.st_size]=0; // terminate the buffer (not strictly needed) | |
357 | ||
358 | diskprintReader dp; | |
359 | dp.parse(buf,st.st_size); | |
360 | cout << "Number of digests read: "<< dp.hashextents.size() << "\n"; | |
361 | const EVP_MD *strongest = dp.hashextents.strongest_available(); | |
362 | cout << "Strongest hash available: " << EVP_MD_name(strongest) << "\n"; | |
363 | /* Now verify each hash */ | |
364 | int matched=0; | |
365 | int notmatched=0; | |
366 | for(hashvector::iterator it = dp.hashextents.begin(); it!=dp.hashextents.end() && notmatched==0;it++){ | |
367 | if(EVP_MD_name(strongest) == (*it).digest_name){ | |
368 | hashextent &hp = (*it); // hash print | |
369 | hashextent hs(af,hp.digest_name,hp.start,hp.bytes); | |
370 | //cout << "hp: " << hp << "\n"; | |
371 | //cout << "hs: " << hs << "\n"; | |
372 | if(hp==hs){ | |
373 | matched++; | |
374 | } else { | |
375 | notmatched++; | |
376 | } | |
377 | } | |
378 | } | |
379 | if(notmatched){ | |
380 | cout << "Diskprint does not match.\n"; | |
381 | } | |
382 | if(notmatched==0 && matched){ | |
383 | cout << "Diskprint matches.\n"; | |
384 | } | |
385 | if(notmatched==0 && matched==0){ | |
386 | cout << "Cannot verify Diskprint; no available hash functions.\n"; | |
387 | } | |
388 | exit(0); | |
389 | } | |
390 | ||
391 | int main(int argc,char **argv) | |
392 | { | |
393 | int ch; | |
394 | const char *opt_x=0; | |
395 | ||
396 | /* Initialize */ | |
397 | #ifdef HAVE_SRANDOMEDEV | |
398 | srandomdev(); | |
399 | #endif | |
400 | OpenSSL_add_all_digests();/* Dynamically loads the digests */ | |
401 | ||
402 | ||
403 | /* Parse arguments */ | |
404 | while ((ch = getopt(argc, argv, "x:h?V")) != -1) { | |
405 | switch (ch) { | |
406 | case 'h': | |
407 | case '?': | |
408 | default: | |
409 | usage(); | |
410 | break; | |
411 | case 'x': opt_x = optarg; break; | |
412 | case 'V': | |
413 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
414 | exit(0); | |
415 | } | |
416 | } | |
417 | argc -= optind; | |
418 | argv += optind; | |
419 | ||
420 | if(argc!=1){ // currently only generates for one file | |
421 | usage(); | |
422 | } | |
423 | ||
424 | if(opt_x){ | |
425 | diskprint_verify(argv[0],opt_x); | |
426 | return(0); | |
427 | } | |
428 | ||
429 | /* Loop through all of the files */ | |
430 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
431 | printf("<diskprints>\n"); | |
432 | while(*argv){ | |
433 | if(opt_x){ | |
434 | diskprint_verify(*argv,opt_x); | |
435 | } | |
436 | else { | |
437 | diskprint(*argv); | |
438 | } | |
439 | argv++; | |
440 | argc--; | |
441 | } | |
442 | printf("</diskprints>\n"); | |
443 | exit(0); | |
444 | } | |
445 | #else | |
446 | int main(int argc,char **argv) | |
447 | { | |
448 | fprintf(stderr,"afdiskprint requires EXPAT. Cannot continue.\n"); | |
449 | exit(-1); | |
450 | } | |
451 | #endif | |
452 |
0 | /* | |
1 | * afcat.cpp: | |
2 | * | |
3 | * cat the contents of an AFF file... | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005, 2006 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | #include "affconfig.h" | |
47 | #include "afflib.h" | |
48 | #include "afflib_i.h" | |
49 | ||
50 | #include <stdio.h> | |
51 | #include <algorithm> | |
52 | #include <vector> | |
53 | #include <string> | |
54 | #ifdef HAVE_CSTRING | |
55 | #include <cstring> | |
56 | #endif | |
57 | ||
58 | ||
59 | using namespace std; | |
60 | ||
61 | vector <int64_t> pages; | |
62 | ||
63 | const char *progname = "afcat"; | |
64 | int opt_info = 0; | |
65 | char *opt_segname=0; | |
66 | int64_t opt_pagenum = -1; | |
67 | int opt_quiet = 1; | |
68 | int opt_list= 0 ; | |
69 | int opt_list_long = 0; | |
70 | int opt_debug = 0; | |
71 | int64_t opt_sector = -1; | |
72 | int opt_badflag = 0; | |
73 | vector<string> opt_r; | |
74 | ||
75 | ||
76 | void usage() | |
77 | { | |
78 | printf("afcat version %s\n",PACKAGE_VERSION); | |
79 | printf("usage: afcat [options] infile [... more infiles]\n"); | |
80 | printf("options:\n"); | |
81 | printf(" -s name --- Just output segment name\n"); | |
82 | printf(" -p ### --- just output data page number ###\n"); | |
83 | printf(" -S ### --- Just output data sector ### (assumes 512-byte sectors). Sector #0 is first\n"); | |
84 | printf(" -q --- quiet; don't print to STDERR if a page is skipped\n"); | |
85 | printf(" -n --- noisy; tell when pages are skipped.\n"); | |
86 | printf(" -l --- List all of the segment names\n"); | |
87 | printf(" -L --- List segment names, lengths, and args\n"); | |
88 | printf(" -d --- debug. Print the page numbers to stderr as data goes to stdout\n"); | |
89 | printf(" -b --- Output BADFALG for bad blocks (default is NULLs)\n"); | |
90 | printf(" -v --- Just print the version number and exit.\n"); | |
91 | printf(" -r offset:count --- seek to offset and output count characters in each file; may be repeated\n"); | |
92 | exit(0); | |
93 | } | |
94 | ||
95 | ||
96 | const char *current_fname = 0; | |
97 | int64_t current_page = -1; | |
98 | void sig_info(int arg) | |
99 | { | |
100 | fprintf(stderr,"afcat "); | |
101 | if(current_fname) fprintf(stderr,"%s: ",current_fname); | |
102 | if(current_page>=0) fprintf(stderr,"[%"PRId64"] ",current_page); | |
103 | fflush(stderr); | |
104 | } | |
105 | ||
106 | ||
107 | ||
108 | int compar(const void *a_,const void *b_) | |
109 | { | |
110 | int64_t a = *(int *)a_; | |
111 | int64_t b = *(int *)b_; | |
112 | if(a<b) return -1; | |
113 | if(a>b) return 1; | |
114 | return 0; | |
115 | } | |
116 | ||
117 | struct afm_private { | |
118 | AFFILE *aff; // the AFFILE we use for the actual metadata | |
119 | AFFILE *sr; // the AFFILE we use for the splitraw | |
120 | int sr_initialized; // has the split-raw been setup from AFM? | |
121 | }; | |
122 | ||
123 | int output_page(AFFILE *af,FILE *outfile,int64_t pagenum) | |
124 | { | |
125 | current_fname = af_filename(af); | |
126 | current_page = pagenum; | |
127 | unsigned char *buf = (unsigned char *)malloc(af->image_pagesize); | |
128 | if(buf==0){ | |
129 | err(1,"malloc(%d) failed",(int)af->image_pagesize); | |
130 | } | |
131 | uint64_t offset = (uint64_t)pagenum * af->image_pagesize; // go to that location | |
132 | ||
133 | ||
134 | af_seek(af,offset,SEEK_SET); | |
135 | ||
136 | ||
137 | int bytes = af_read(af,buf,af->image_pagesize); // read what we can | |
138 | ||
139 | if(bytes<0){ | |
140 | if(opt_debug) fprintf(stderr,"afcat: cannot read page %"I64d"\n",pagenum); | |
141 | return -1; | |
142 | } | |
143 | ||
144 | if(opt_debug){ | |
145 | fprintf(stderr,"afcat: page:%"I64d" bytes: %d offset:%"I64d"\n", | |
146 | pagenum, bytes,offset); | |
147 | } | |
148 | ||
149 | /* Check each sector to see if it is badflag or not. | |
150 | * If it is and if opt_badflag is not set, make it all NULs. | |
151 | */ | |
152 | for(unsigned char *cc=buf;cc<buf+bytes;cc+=af->image_sectorsize){ | |
153 | if(af_is_badsector(af,cc) && opt_badflag==0){ | |
154 | memset(cc,0,af->image_sectorsize); | |
155 | } | |
156 | } | |
157 | ||
158 | if(opt_debug) fprintf(stderr," outputing %d bytes\n",bytes); | |
159 | int count = fwrite(buf,1,bytes,outfile); // send to the output | |
160 | if(count!=bytes) fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",bytes,count); | |
161 | free(buf); | |
162 | return bytes; | |
163 | } | |
164 | ||
165 | ||
166 | int afcat(AFFILE *af) | |
167 | { | |
168 | int64_t total_bytes_written = 0; | |
169 | ||
170 | /* Read all of the pages from beginning to end and capture | |
171 | * all the segment numbers... | |
172 | */ | |
173 | ||
174 | #ifdef WIN32 | |
175 | _setmode(fileno(stdout),_O_BINARY); | |
176 | #endif | |
177 | if(opt_debug) fprintf(stderr,"afcat(%s)\n",af_filename(af)); | |
178 | ||
179 | if(opt_segname){ | |
180 | /* First figure out how big the segment is */ | |
181 | size_t datalen = 0; | |
182 | if(af_get_seg(af,opt_segname,0,0,&datalen)){ | |
183 | fprintf(stderr,"%s: segment '%s' does not exist\n", | |
184 | af_filename(af),opt_segname); | |
185 | return -1; | |
186 | } | |
187 | unsigned char *data = (unsigned char *)malloc(datalen); | |
188 | if(data==0) err(1,"malloc"); | |
189 | if(af_get_seg(af,opt_segname,0,data,&datalen)){ | |
190 | free(data); | |
191 | fprintf(stderr,"%s: could not read segment '%s'\n", | |
192 | af_filename(af),opt_segname); | |
193 | return -1; | |
194 | } | |
195 | int count = fwrite(data,1,datalen,stdout); | |
196 | if(count!=(ssize_t)datalen){ | |
197 | fprintf(stderr,"fwrite(buf,1,%zd,outfile) only wrote %d bytes\n",datalen,count); | |
198 | } | |
199 | free(data); | |
200 | return 0; | |
201 | } | |
202 | ||
203 | if(opt_pagenum != -1){ // just write a particular page? | |
204 | int r = output_page(af,stdout,opt_pagenum); | |
205 | return r>=0 ? 0 : -1; | |
206 | } | |
207 | ||
208 | if(opt_sector>=0){ | |
209 | unsigned char *buf = (unsigned char *)malloc(af->image_sectorsize); | |
210 | af_seek(af,(uint64_t)opt_sector*af->image_sectorsize,SEEK_SET); | |
211 | int bytes_read = af_read(af,buf,af->image_sectorsize); | |
212 | if(bytes_read>0){ | |
213 | int bytes_written = fwrite(buf,1,bytes_read,stdout); | |
214 | if(bytes_read!=bytes_written){ | |
215 | fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n", | |
216 | bytes_read,bytes_written); | |
217 | } | |
218 | } | |
219 | free(buf); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | /* Get a list of all the segments. If we are doing a list, just print them. | |
224 | * If we are not doing a list, capture the data pages and put their numbers | |
225 | * into an array. | |
226 | */ | |
227 | ||
228 | if(opt_debug) fprintf(stderr,"af_rewind_seg()\n"); | |
229 | ||
230 | if(opt_r.size()>0){ | |
231 | unsigned char *buf = (unsigned char *)malloc(af->image_pagesize); | |
232 | for(vector<string>::const_iterator offset_count=opt_r.begin(); offset_count != opt_r.end(); offset_count++){ | |
233 | string opts = *offset_count; | |
234 | const char *opt = opts.c_str(); | |
235 | uint64_t offset=0; | |
236 | int count=0; | |
237 | if(sscanf(opt,"%"I64u":%d",&offset,&count)!=2){ | |
238 | err(1,"Cannot decode '%s'\n",opt); | |
239 | } | |
240 | af_seek(af,offset,SEEK_SET); | |
241 | int r= af_read(af,buf,count); | |
242 | if(r>0){ | |
243 | int bytes_written = fwrite(buf,1,r,stdout); | |
244 | if(bytes_written!=r) { | |
245 | fprintf(stderr,"fwrite(buf,1,%d,outfile) only wrote %d bytes\n",r,bytes_written); | |
246 | } | |
247 | ||
248 | } | |
249 | } | |
250 | free(buf); | |
251 | return 0; | |
252 | } | |
253 | ||
254 | ||
255 | af_rewind_seg(af); // start at the beginning | |
256 | char segname[AF_MAX_NAME_LEN]; | |
257 | unsigned long arg; | |
258 | size_t datalen = 0; | |
259 | memset(segname,0,sizeof(segname)); | |
260 | ||
261 | int encrypted_segments = 0; | |
262 | while(af_get_next_seg(af,segname,sizeof(segname),&arg,0,&datalen)==0){ | |
263 | if(opt_debug) fprintf(stderr,"af_get_next_seg found segment %s\n",segname); | |
264 | if(segname[0]==0) continue; // ignore sector | |
265 | if(opt_list){ | |
266 | printf("%s",segname); | |
267 | if(opt_list_long){ | |
268 | printf("\targ:%lu\tlen:%d",arg,(int)datalen); | |
269 | } | |
270 | putchar('\n'); | |
271 | } | |
272 | else { | |
273 | int64_t pagenum = af_segname_page_number(segname); | |
274 | if(pagenum>=0) pages.push_back(pagenum); | |
275 | if(af_is_encrypted_segment(segname)) encrypted_segments++; | |
276 | } | |
277 | datalen = 0; // allow to get the next one | |
278 | } | |
279 | if(opt_list) return 0; // that's all that was wanted. | |
280 | ||
281 | ||
282 | sort(pages.begin(),pages.end()); | |
283 | ||
284 | if(pages.size()==0 && encrypted_segments){ | |
285 | fprintf(stderr,"afcat: This file has %d encrypted segments.\n",encrypted_segments); | |
286 | fprintf(stderr,"afcat: No unencrypted pages could be found.\n"); | |
287 | } | |
288 | ||
289 | /* Now I have a list of pages; cat each one */ | |
290 | int next_page = 0; // starting page number | |
291 | int64_t imagesize = af_get_imagesize(af); | |
292 | for(vector<int64_t>::iterator i = pages.begin(); i != pages.end(); i++){ | |
293 | ||
294 | int page = *i; | |
295 | if(page != next_page && opt_quiet==0){ | |
296 | if(page == next_page+1 ){ | |
297 | fprintf(stderr,"afcat: page %d not in file\n",next_page); | |
298 | } | |
299 | else{ | |
300 | fprintf(stderr,"afcat: pages %d through %d not in file\n", | |
301 | next_page,page-1); | |
302 | } | |
303 | } | |
304 | int r = output_page(af,stdout,page); | |
305 | if(r<0) return -1; | |
306 | total_bytes_written += r; | |
307 | next_page = page + 1; // note what should be next | |
308 | ||
309 | //fprintf(stderr,"bytes written=%qd imagesize=%qd\n",total_bytes_written,imagesize); | |
310 | if((total_bytes_written > imagesize) && (imagesize>0)){ | |
311 | err(1,"afcat internal error. bytes written=%"I64d" imagesize=%" I64d, | |
312 | (int64_t)total_bytes_written, | |
313 | (int64_t)imagesize); | |
314 | return -1; | |
315 | } | |
316 | } | |
317 | return 0; | |
318 | } | |
319 | ||
320 | ||
321 | int64_t atoi64(const char *buf) | |
322 | { | |
323 | int64_t r=0; | |
324 | char ch; | |
325 | if(sscanf(buf,"%"I64d"%c",&r,&ch)==1) return r; | |
326 | fprintf(stderr,"Cannot parse '%s'\n",buf); | |
327 | exit(0); | |
328 | } | |
329 | ||
330 | ||
331 | int main(int argc,char **argv) | |
332 | { | |
333 | int bflag, ch; | |
334 | ||
335 | #ifdef SIGINFO | |
336 | signal(SIGINFO,sig_info); | |
337 | #endif | |
338 | ||
339 | bflag = 0; | |
340 | while ((ch = getopt(argc, argv, "s:S:p:lLh?dqnvr:")) != -1) { | |
341 | switch (ch) { | |
342 | case 's': | |
343 | opt_segname = optarg; | |
344 | break; | |
345 | case 'S': | |
346 | opt_sector = atoi64(optarg); | |
347 | break; | |
348 | case 'p': | |
349 | opt_pagenum = atoi64(optarg); | |
350 | break; | |
351 | case 'q': | |
352 | opt_quiet = 1; | |
353 | break; | |
354 | case 'n': | |
355 | opt_quiet = 0; | |
356 | break; | |
357 | case 'l': | |
358 | opt_list = 1; | |
359 | break; | |
360 | case 'r': | |
361 | opt_r.push_back(optarg); | |
362 | break; | |
363 | case 'L': | |
364 | opt_list = 1; | |
365 | opt_list_long = 1; | |
366 | break; | |
367 | case 'b': | |
368 | opt_badflag = 1; | |
369 | break; | |
370 | case 'd': | |
371 | opt_debug++; | |
372 | break; | |
373 | case 'h': | |
374 | case '?': | |
375 | default: | |
376 | usage(); | |
377 | break; | |
378 | case 'v': | |
379 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
380 | exit(0); | |
381 | } | |
382 | } | |
383 | argc -= optind; | |
384 | argv += optind; | |
385 | ||
386 | if(argc<1){ | |
387 | usage(); | |
388 | } | |
389 | ||
390 | while(*argv){ | |
391 | AFFILE *af = af_open(*argv,O_RDONLY,0); | |
392 | if(!af) af_err(1,"afcat(%s)",*argv); | |
393 | if(afcat(af)) err(1,"afcat"); | |
394 | af_close(af); | |
395 | argv++; | |
396 | argc--; | |
397 | } | |
398 | } |
0 | /* | |
1 | * acompare.cpp: | |
2 | * | |
3 | * Compare the contents of an ISO file to an AFF file. | |
4 | * Optionally, if they are equal, delete the ISO file | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2005--2008 | |
9 | * Simson L. Garfinkel and Basis Technology, Inc. | |
10 | * All rights reserved. | |
11 | * | |
12 | * This code is derrived from software contributed by | |
13 | * Simson L. Garfinkel | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | |
23 | * 3. All advertising materials mentioning features or use of this software | |
24 | * must display the following acknowledgement: | |
25 | * This product includes software developed by Simson L. Garfinkel | |
26 | * and Basis Technology Corp. | |
27 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
28 | * contributors to this program may be used to endorse or promote | |
29 | * products derived from this software without specific prior written | |
30 | * permission. | |
31 | * | |
32 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
33 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
34 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
35 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
36 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
37 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
38 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
40 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
41 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
42 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
43 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
44 | * SUCH DAMAGE. | |
45 | */ | |
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "utils.h" | |
51 | ||
52 | using namespace std; | |
53 | using namespace aff; | |
54 | ||
55 | ||
56 | #ifdef WIN32 | |
57 | #include "unix4win32.h" | |
58 | #endif | |
59 | ||
60 | ||
61 | #ifdef UNIX | |
62 | #include <sys/signal.h> | |
63 | #include <unistd.h> | |
64 | #endif | |
65 | ||
66 | #include <ctype.h> | |
67 | #include <stdio.h> | |
68 | #include <stdlib.h> | |
69 | #include <sys/types.h> | |
70 | #include <sys/stat.h> | |
71 | #include <fcntl.h> | |
72 | #include <limits.h> | |
73 | #include <string.h> | |
74 | #include <zlib.h> | |
75 | #include <openssl/md5.h> | |
76 | #include <openssl/sha.h> | |
77 | #include <assert.h> | |
78 | ||
79 | #ifdef HAVE_CSTRING | |
80 | #include <cstring> | |
81 | #endif | |
82 | ||
83 | #ifdef linux | |
84 | #include <sys/time.h> | |
85 | #endif | |
86 | ||
87 | ||
88 | ||
89 | const char *progname = "affcompare"; | |
90 | ||
91 | int opt_quiet = 0; | |
92 | int opt_all = 0; | |
93 | int opt_print_sectors = 0; | |
94 | int opt_print_sector_contents = 0; | |
95 | int opt_page = -1; | |
96 | int opt_preen = 0; | |
97 | int opt_exist = 0; | |
98 | int opt_ignore_metadata = 0; | |
99 | int opt_s3 = 0; | |
100 | int opt_verbose = 0; | |
101 | const char *batch_ext = ""; | |
102 | ||
103 | vector<string> errors; | |
104 | ||
105 | const char *current_source = 0; | |
106 | ||
107 | void sig_info(int arg) | |
108 | { | |
109 | if(current_source){ | |
110 | printf("%s... ",current_source); | |
111 | } | |
112 | printf("\n"); | |
113 | fflush(stdout); | |
114 | } | |
115 | ||
116 | void print_title(char *title) | |
117 | { | |
118 | if(title[0]){ | |
119 | puts(title); | |
120 | title[0] = 0; | |
121 | } | |
122 | } | |
123 | ||
124 | void usage() | |
125 | { | |
126 | printf("affcompare version %s\n",PACKAGE_VERSION); | |
127 | printf("\n"); | |
128 | printf("usage: affcompare [options] file1 file2\n"); | |
129 | printf(" compares file1 with file2\n"); | |
130 | printf("\n"); | |
131 | printf("or affcompare [options] -r dir1 dir2\n"); | |
132 | printf(" comparses similarly-named files in dir1 and dir2\n"); | |
133 | printf("\n"); | |
134 | printf("or affcompare [options] -s file1 file2...\n"); | |
135 | printf(" Reports if file was successfully copied to Amazon S3\n"); | |
136 | printf(" checking only for existence, not reading back the bytes.\n"); | |
137 | printf(" (Because all writes to S3 are validated by the MD5 of the object\n"); | |
138 | #ifndef USE_S3 | |
139 | printf(" NOTE: S3 support is not provided in this version\n"); | |
140 | #endif | |
141 | ||
142 | printf("fast options:\n"); | |
143 | printf("(These compare segments but not their contents.)\n"); | |
144 | printf(" -p --- report about the results of preening\n"); | |
145 | printf(" -e --- Just report about existence (use with -r)\n"); | |
146 | printf(" -s --- Just see if all of the segments are present, but don't\n"); | |
147 | printf(" validate the contents. (Primarily for use with Amazon S3)\n"); | |
148 | ||
149 | printf("other options:\n"); | |
150 | printf(" -V --- just print the version number and exit\n"); | |
151 | printf(" -v --- Verbose; each file as it is compared.\n"); | |
152 | printf(" -q --- Quiet. No output except for errors\n"); | |
153 | printf(" -a --- print what's the same (all)\n"); | |
154 | printf(" -b --- print the numbers of differing sectors\n"); | |
155 | printf(" -c --- print the contents of differing sectors\n"); | |
156 | printf(" -m --- Just report about the data (ignore metadata)\n"); | |
157 | printf(" -P ### --- Just examine the differences on page ###\n"); | |
158 | printf(" -q --- Quiet; no output except for errors.\n"); | |
159 | printf("\n"); | |
160 | printf("Options documented above:\n"); | |
161 | printf(" -r dir1 dir2 --- recursively compare what's in dir1 with dir2, and\n"); | |
162 | printf(" report what's in dir1 that's not in dir2\n"); | |
163 | printf(" -s --- Check to see if named files are on Amazon S3\n"); | |
164 | printf("\n"); | |
165 | printf(" affcompare file1.aff file2.aff --- compare file1.aff and file2.aff\n"); | |
166 | printf(" affcompare f1.aff f2.aff dir1/ --- compare f1.aff with dir1/f1.aff and f2.aff with dir2/f2.aff\n"); | |
167 | printf(" note: dir1/ must end with a slash.\n"); | |
168 | printf(" affcompare -b img file.aff --- compare file.aff and file.img\n"); | |
169 | printf(" affcompare -b img file1.aff file2.aff... --- compare file1.aff, file1.img, etc.\n"); | |
170 | printf(" affcompare -re dir1 dir2 --- report AFF files in dir1 but not in dir2\n"); | |
171 | printf(" affcompare -rse dir1 s3:/// --- report AFF files in dir1 but not on S3 (low bandwidth)\n"); | |
172 | printf(" affcompare -rs dir1 s3:/// --- report AFF files in dir1 but incomplete on on S3 (more bandwidth)\n"); | |
173 | printf("\n"); | |
174 | exit(0); | |
175 | } | |
176 | ||
177 | void print_sector(AFFILE *af,unsigned char *buf) | |
178 | { | |
179 | for(unsigned int i=0;i<af->image_sectorsize;i++){ | |
180 | if(isprint(buf[i])){ | |
181 | putchar(buf[i]); | |
182 | } | |
183 | else { | |
184 | putchar('.'); | |
185 | } | |
186 | if(i%64==63) putchar('\n'); | |
187 | } | |
188 | } | |
189 | ||
190 | ||
191 | void print_info(char dir,const char *segname,unsigned long arg,size_t len, | |
192 | unsigned char *data,int mcr) | |
193 | { | |
194 | printf(" %c %s arg=%lu len=%d\n",dir,segname,arg,(int)len); | |
195 | printf(" "); | |
196 | if((arg == AF_SEG_QUADWORD) && (len==8)){ | |
197 | printf("data=%"I64d" as a 64-bit value\n",af_decode_q(data)); | |
198 | return; | |
199 | } | |
200 | /* Otherwise, just print some stuff... */ | |
201 | for(unsigned int i=0;i<len && i<60;i++){ | |
202 | if(data[i]==' '){ | |
203 | putchar(' '); | |
204 | continue; | |
205 | } | |
206 | if(!isprint(data[i])){ | |
207 | putchar('.'); | |
208 | continue; | |
209 | } | |
210 | putchar(data[i]); | |
211 | } | |
212 | putchar('\n'); | |
213 | } | |
214 | ||
215 | int compare_aff_metadata_segments(char *title,AFFILE *af1,AFFILE *af2,const char *segname,int mode) | |
216 | { | |
217 | int ret = 0; | |
218 | ||
219 | unsigned long arg1 = 0; | |
220 | size_t data1_len = 0; | |
221 | int r1 = af_get_seg(af1,segname,&arg1,0,&data1_len); | |
222 | ||
223 | unsigned long arg2 = 0; | |
224 | size_t data2_len = 0; | |
225 | int r2 = af_get_seg(af2,segname,&arg2,0,&data2_len); | |
226 | ||
227 | if(r1==0 && r2!=0){ | |
228 | if(mode==1){ | |
229 | print_title(title); | |
230 | printf(" %s \n",segname); | |
231 | } | |
232 | return 1; | |
233 | } | |
234 | ||
235 | if(r1!=0 && r2==0){ | |
236 | if(mode==2){ | |
237 | print_title(title); | |
238 | printf(" %s \n",segname); | |
239 | } | |
240 | return 1; | |
241 | } | |
242 | if(mode!=3) return 0; // only report differences in mode 3 | |
243 | /* Get the actual data... */ | |
244 | ||
245 | unsigned char *data1 = (unsigned char *)malloc(data1_len); | |
246 | unsigned char *data2 = (unsigned char *)malloc(data2_len); | |
247 | ||
248 | int s1 = af_get_seg(af1,segname,&arg1,data1,&data1_len); | |
249 | if(s1!=0) err(1,"Couldn't read data segment %s in %s",segname,af_filename(af1)); | |
250 | ||
251 | int s2 = af_get_seg(af2,segname,&arg2,data2,&data2_len); | |
252 | if(s2!=0) err(1,"Couldn't read data segment %s in %s",segname,af_filename(af2)); | |
253 | ||
254 | int mcr = 0; | |
255 | ||
256 | if(data1_len != data2_len) mcr = 1; | |
257 | else mcr = memcmp(data1,data2,data1_len); | |
258 | if(arg1!=arg2 || data1_len!=data2_len || mcr!=0){ | |
259 | print_title(title); | |
260 | print_info('<',segname,arg1,data1_len,data1,mcr); | |
261 | print_info('>',segname,arg2,data2_len,data2,mcr); | |
262 | if(mcr){ | |
263 | printf(" *** Metadata segment are different "); | |
264 | if(strcmp(segname,AF_BADFLAG)==0){ | |
265 | printf("(bad flags should be different!)"); | |
266 | } | |
267 | putchar('\n'); | |
268 | } | |
269 | putchar('\n'); | |
270 | ret = 1; | |
271 | } | |
272 | else { | |
273 | if(opt_all){ | |
274 | print_title(title); | |
275 | printf(" %s (same in both) \n",segname); | |
276 | } | |
277 | } | |
278 | free(data1); | |
279 | free(data2); | |
280 | return ret; | |
281 | } | |
282 | ||
283 | int compare_aff_data_segments(char *title,AFFILE *af1,AFFILE *af2,int64_t pagenum,int mode) | |
284 | { | |
285 | int ret = 0; | |
286 | char pagename[65]; | |
287 | snprintf(pagename,sizeof(pagename),AF_PAGE,pagenum); | |
288 | ||
289 | char segname[65]; | |
290 | snprintf(segname,sizeof(segname),AF_SEG_D,pagenum); | |
291 | ||
292 | unsigned long arg1=0; | |
293 | size_t data1_len=0; | |
294 | int r1 = af_get_seg(af1,pagename,&arg1,0,&data1_len); | |
295 | if(r1==-1) r1=af_get_seg(af1,segname,&arg1,0,&data1_len); | |
296 | ||
297 | unsigned long arg2=0; | |
298 | size_t data2_len=0; | |
299 | int r2 = af_get_seg(af2,pagename,&arg2,0,&data2_len); | |
300 | if(r2 == -1) r2=af_get_seg(af2,segname,&arg2,0,&data2_len); | |
301 | ||
302 | if(r1<0 && r2<0) return 0; // no data segment in either file | |
303 | if(r1==0 && r2!=0){ | |
304 | if(mode==1){ | |
305 | print_title(title); | |
306 | printf(" %s \n",pagename); | |
307 | } | |
308 | return 1; | |
309 | } | |
310 | ||
311 | if(r2==0 && r1!=0){ | |
312 | if(mode==2){ | |
313 | print_title(title); | |
314 | printf(" %s \n",pagename); | |
315 | } | |
316 | return 1; | |
317 | } | |
318 | if(mode!=3) return 0; // only report differences in mode 3 | |
319 | ||
320 | /* Get the actual data... */ | |
321 | unsigned char *data1 = (unsigned char *)malloc(af_page_size(af1)); | |
322 | unsigned char *data2 = (unsigned char *)malloc(af_page_size(af2)); | |
323 | ||
324 | data1_len = af_page_size(af1); | |
325 | data2_len = af_page_size(af2); | |
326 | ||
327 | uint64_t start_sector_number = (pagenum * data1_len) / af1->image_sectorsize; | |
328 | ||
329 | /* Find the size of each page, then get the page */ | |
330 | if(af_get_page(af1,pagenum,0,&data1_len)<0) | |
331 | err(1,"Cannot read page %"I64d" size from %s\n",pagenum,af_filename(af1)); | |
332 | if(af_get_page(af1,pagenum,data1,&data1_len)<0) | |
333 | err(1,"Cannot read page %"I64d" from %s",pagenum,af_filename(af1)); | |
334 | ||
335 | if(af_get_page(af2,pagenum,0,&data2_len)<0) | |
336 | err(1,"Cannot read page %"I64d" size from %s\n",pagenum,af_filename(af2)); | |
337 | if(af_get_page(af2,pagenum,data2,&data2_len)<0) | |
338 | err(1,"Cannot read page %"I64d" from %s",pagenum,af_filename(af2)); | |
339 | ||
340 | if(data1_len != data2_len){ | |
341 | printf("page %"I64d" size %zd != size %zd\n",pagenum,data1_len,data2_len); | |
342 | return 1; | |
343 | } | |
344 | ||
345 | /* Now look at the pages sector-by-sector. */ | |
346 | int af1_bad=0; | |
347 | int af2_bad=0; | |
348 | int matching_bad_sectors = 0; | |
349 | int matching_sectors = 0; | |
350 | int total_sectors = 0; | |
351 | int no_match = 0; | |
352 | vector<uint64_t> different_sectors; | |
353 | ||
354 | for(unsigned int offset=0;offset<data1_len;offset+=af1->image_sectorsize){ | |
355 | uint64_t this_sector = start_sector_number + offset/af1->image_sectorsize; | |
356 | total_sectors++; | |
357 | if(af_is_badsector(af1,data1+offset) && | |
358 | af_is_badsector(af2,data2+offset)){ | |
359 | matching_bad_sectors++; | |
360 | continue; | |
361 | } | |
362 | if(af_is_badsector(af1,data1+offset)){ | |
363 | af1_bad++; | |
364 | continue; | |
365 | } | |
366 | if(af_is_badsector(af2,data2+offset)){ | |
367 | af2_bad++; | |
368 | continue; | |
369 | } | |
370 | if(memcmp(data1+offset,data2+offset,af1->image_sectorsize)==0){ | |
371 | matching_sectors++; | |
372 | continue; | |
373 | } | |
374 | no_match++; | |
375 | different_sectors.push_back(this_sector); | |
376 | } | |
377 | ||
378 | char outline[256]; | |
379 | outline[0] = 0; | |
380 | if(opt_all || (no_match>0) || af1_bad || af2_bad){ | |
381 | snprintf(outline,sizeof(outline), | |
382 | " page%"I64d" sectors:%4d matching: %3d different:%3d", | |
383 | pagenum,total_sectors,matching_sectors,no_match); | |
384 | } | |
385 | if(af1_bad){ | |
386 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
387 | " file 1 bad: %3d ",af1_bad); | |
388 | } | |
389 | if(af2_bad){ | |
390 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
391 | " file 2 bad: %3d ",af2_bad); | |
392 | } | |
393 | if(matching_bad_sectors){ | |
394 | if(opt_all){ | |
395 | snprintf(outline+strlen(outline),sizeof(outline)-strlen(outline), | |
396 | " bad both:%3d ",matching_bad_sectors); | |
397 | } | |
398 | } | |
399 | ||
400 | if(outline[0]){ | |
401 | print_title(title); | |
402 | puts(outline); | |
403 | } | |
404 | if(opt_print_sectors && different_sectors.size()>0){ | |
405 | print_title(title); | |
406 | printf(" Sectors with differences:"); | |
407 | int i=0; | |
408 | for(vector<uint64_t>::iterator j = different_sectors.begin(); | |
409 | j != different_sectors.end(); | |
410 | j++){ | |
411 | if(i==0){ | |
412 | printf("\n "); | |
413 | } | |
414 | printf(" %"I64d,*j); | |
415 | i = (i+1) % 10; | |
416 | } | |
417 | putchar('\n'); | |
418 | ret = 1; | |
419 | } | |
420 | if(opt_print_sector_contents && different_sectors.size()>0){ | |
421 | print_title(title); | |
422 | printf(" Sectors with differences:"); | |
423 | for(vector<uint64_t>::iterator j = different_sectors.begin(); | |
424 | j != different_sectors.end(); j++){ | |
425 | int offset = (*j - start_sector_number)*af1->image_sectorsize; | |
426 | char b2[16]; | |
427 | printf("offset=%d\n",offset); | |
428 | ||
429 | memcpy(b2,data1+offset,16); | |
430 | b2[15]=0; | |
431 | ||
432 | printf("=== sector %"I64d" (offset=%d) ===\n",*j,offset); | |
433 | printf(" %s:\n",af_filename(af1)); | |
434 | print_sector(af1,data1+offset); | |
435 | printf("-------------------------------------\n"); | |
436 | printf(" %s:\n",af_filename(af2)); | |
437 | print_sector(af2,data2+offset); | |
438 | printf("=====================================\n\n"); | |
439 | } | |
440 | ret = 1; | |
441 | } | |
442 | free(data1); | |
443 | free(data2); | |
444 | return ret; | |
445 | } | |
446 | ||
447 | /* Compare the results of two files that were preened */ | |
448 | int compare_preen(AFFILE *af1,AFFILE *af2) | |
449 | { | |
450 | vector<int64_t> pages; | |
451 | int comp_zero=0; | |
452 | int comp_lzma=0; | |
453 | int comp_unchanged=0; | |
454 | uint64_t bytes_old = 0; | |
455 | uint64_t bytes_new = 0; | |
456 | ||
457 | af_rewind_seg(af1); | |
458 | /* Build a list of all the pages */ | |
459 | char segname[AF_MAX_NAME_LEN]; | |
460 | while(af_get_next_seg(af1,segname,sizeof(segname),0,0,0)==0){ | |
461 | int64_t pagenumber = af_segname_page_number(segname); | |
462 | if(pagenumber>=0) pages.push_back(pagenumber); | |
463 | } | |
464 | /* Now, compare each one */ | |
465 | for(vector<int64_t>::const_iterator i = pages.begin(); i != pages.end(); i++){ | |
466 | unsigned long arg1,arg2; | |
467 | size_t len1,len2; | |
468 | ||
469 | if(af_get_page_raw(af1,*i,&arg1,0,&len1)){ | |
470 | err(1,"Could not read page %"I64d" in file %s\n",*i,af_filename(af1)); | |
471 | } | |
472 | if(af_get_page_raw(af2,*i,&arg2,0,&len2)){ | |
473 | err(1,"Page %"I64d" is in file %s but not in %s\n",*i,af_filename(af1), | |
474 | af_filename(af2)); | |
475 | } | |
476 | if(arg1==arg2 && len1==len2){ | |
477 | comp_unchanged++; | |
478 | continue; | |
479 | } | |
480 | if((arg2 & AF_PAGE_COMP_ALG_MASK)==AF_PAGE_COMP_ALG_ZERO){ | |
481 | comp_zero++; | |
482 | continue; | |
483 | } | |
484 | if((arg2 & AF_PAGE_COMP_ALG_MASK)==AF_PAGE_COMP_ALG_LZMA){ | |
485 | comp_lzma++; | |
486 | bytes_old += len1; | |
487 | bytes_new += len2; | |
488 | continue; | |
489 | } | |
490 | } | |
491 | printf("%s -> %s Nochg: %d NUL: %d LZMA: %d old: %"I64d" new: %"I64d" LZred: %6.2f%%\n", | |
492 | af_filename(af1), | |
493 | af_filename(af2), | |
494 | comp_unchanged,comp_zero,comp_lzma,bytes_old,bytes_new,(bytes_old-bytes_new)*100.0/bytes_old); | |
495 | return 0; | |
496 | } | |
497 | ||
498 | ||
499 | /* Compare two AFF files. | |
500 | * Return 0 if they are equal. | |
501 | */ | |
502 | int compare_aff_aff(const char *file1,const char *file2) | |
503 | { | |
504 | bool no_data_segments = false; | |
505 | int ret = 0; | |
506 | ||
507 | current_source = file1; | |
508 | ||
509 | if(opt_all) printf("compare %s and %s:\n",file1,file2); | |
510 | ||
511 | AFFILE *af1 = af_open(file1,O_RDONLY,0); | |
512 | if(!af1) af_err(1,"af_open(%s)",file1); | |
513 | ||
514 | AFFILE *af2 = af_open(file2,O_RDONLY,0); | |
515 | if(!af2) af_err(1,"af_open(%s)",file2); | |
516 | ||
517 | af_vnode_info vni1,vni2; | |
518 | ||
519 | if(af_vstat(af1,&vni1) || af_vstat(af2,&vni2)){ | |
520 | err(1,"af_vstat failed?"); | |
521 | } | |
522 | ||
523 | if(af_cannot_decrypt(af1) != af_cannot_decrypt(af2)){ | |
524 | printf("%s: %s decrypt\n",file1,af_cannot_decrypt(af1) ? "cannot" : "can"); | |
525 | printf("%s: %s decrypt\n",file2,af_cannot_decrypt(af2) ? "cannot" : "can"); | |
526 | fprintf(stderr,"affcompare must be able to decrypt both files or neither of the files.\n"); | |
527 | exit(1); | |
528 | } | |
529 | ||
530 | if(af1->image_pagesize != af2->image_pagesize){ | |
531 | fprintf(stderr,"Currently, %s requires that both images have the " | |
532 | "same image datsegsize.\n" | |
533 | "pagesize(%s)=%ld\n" | |
534 | "pagesize(%s)=%ld\n", | |
535 | progname,file1,af1->image_pagesize, | |
536 | file2,af2->image_pagesize); | |
537 | fprintf(stderr,"Data segments will be ignored.\n"); | |
538 | no_data_segments = true; | |
539 | } | |
540 | ||
541 | if(af1->image_sectorsize != af2->image_sectorsize){ | |
542 | fprintf(stderr,"Currently, %s requires that both images have the " | |
543 | "same image sectorsize.\n" | |
544 | "sectorsize(%s)=%ld\n" | |
545 | "sectorsize(%s)=%ld\n", | |
546 | progname,file1,af1->image_sectorsize, file2,af2->image_sectorsize); | |
547 | fprintf(stderr,"Data segments will be ignored.\n"); | |
548 | no_data_segments = true; | |
549 | } | |
550 | ||
551 | if(opt_preen){ | |
552 | compare_preen(af1,af2); | |
553 | af_close(af1); | |
554 | af_close(af2); | |
555 | return 0; | |
556 | } | |
557 | ||
558 | if(opt_s3){ | |
559 | printf("bypass\n"); | |
560 | seglist list1(af1); | |
561 | seglist list2(af2); | |
562 | ||
563 | /* Just compare the presence/absence of each segment */ | |
564 | char title[1024]; | |
565 | snprintf(title,sizeof(title),"\nPresent in %s but not %s:",af_filename(af1),af_filename(af2)); | |
566 | for(seglist::const_iterator i=list1.begin(); i!=list1.end(); i++){ | |
567 | if(find(list2.begin(),list2.end(),*i)==list2.end()){ | |
568 | print_title(title); | |
569 | printf(" %s\n",(*i).name.c_str()); | |
570 | } | |
571 | } | |
572 | snprintf(title,sizeof(title),"\nPresent in %s but not %s:",af_filename(af2),af_filename(af1)); | |
573 | for(seglist::const_iterator i=list2.begin(); i!=list2.end(); i++){ | |
574 | if(find(list1.begin(),list1.end(),*i)==list1.end()){ | |
575 | print_title(title); | |
576 | printf(" %s\n",(*i).name.c_str()); | |
577 | } | |
578 | } | |
579 | return 0; | |
580 | } | |
581 | ||
582 | /* Compare all of the metadata segments in af1 with a2. | |
583 | * Report those that are missing or different. Then report | |
584 | * all of the segments in a2 but not in af1 | |
585 | */ | |
586 | ||
587 | /* First build a list of the segments in each */ | |
588 | ||
589 | vector <string> segs_with_dups; | |
590 | ||
591 | AFFILE *af[2] = {af1,af2}; | |
592 | for(int i=0;i<2;i++){ | |
593 | if(opt_verbose) printf("\n%s:\n",af_filename(af[i])); | |
594 | af_rewind_seg(af[i]); | |
595 | char segname[AF_MAX_NAME_LEN]; | |
596 | while(af_get_next_seg(af[i],segname,sizeof(segname),0,0,0)==0){ | |
597 | if(segname[0]){ | |
598 | string s; | |
599 | s = segname; | |
600 | segs_with_dups.push_back(s); // may give duplicates | |
601 | if(opt_verbose) printf(" %s\n",segname); | |
602 | } | |
603 | } | |
604 | } | |
605 | sort(segs_with_dups.begin(),segs_with_dups.end()); | |
606 | vector<string>segs; | |
607 | ||
608 | /* Make a list of segs without duplicates */ | |
609 | string last; | |
610 | for(vector<string>::iterator i = segs_with_dups.begin(); | |
611 | i != segs_with_dups.end(); i++){ | |
612 | if(last != *i){ | |
613 | segs.push_back(*i); | |
614 | } | |
615 | last = *i; | |
616 | } | |
617 | ||
618 | int lowest_page = -1; | |
619 | int highest_page = -1; | |
620 | /* Scan for the lowest and highest numbers */ | |
621 | for(vector<string>::iterator i = segs.begin();i != segs.end(); i++){ | |
622 | int64_t num = af_segname_page_number(i->c_str()); | |
623 | if(num!=-1){ | |
624 | if(num<lowest_page ||lowest_page==-1) lowest_page = num; | |
625 | if(num>highest_page||highest_page==-1) highest_page = num; | |
626 | } | |
627 | } | |
628 | ||
629 | ||
630 | if(opt_page != -1){ | |
631 | lowest_page = opt_page; | |
632 | highest_page = opt_page; | |
633 | } | |
634 | ||
635 | ||
636 | if(opt_page == -1 | |
637 | && vni1.supports_metadata | |
638 | && vni2.supports_metadata | |
639 | && opt_ignore_metadata==0 ){ | |
640 | if(opt_all) puts("Inspecting metadata..."); | |
641 | for(int mode=1;mode<=3;mode++){ | |
642 | const char *title = "Metadata segments "; | |
643 | char mode_title[1024]; | |
644 | switch(mode){ | |
645 | case 1: | |
646 | snprintf(mode_title,sizeof(mode_title)," %s only in %s:\n", | |
647 | title,af_filename(af1)); | |
648 | break; | |
649 | case 2: | |
650 | snprintf(mode_title,sizeof(mode_title)," %s only in %s:\n", | |
651 | title,af_filename(af2)); | |
652 | break; | |
653 | case 3: | |
654 | snprintf(mode_title,sizeof(mode_title)," %s in both files:\n",title); | |
655 | break; | |
656 | } | |
657 | ||
658 | for(vector<string>::iterator i = segs.begin();i != segs.end();i++){ | |
659 | int64_t num = af_segname_page_number(i->c_str()); | |
660 | if(num==-1){ | |
661 | int r = compare_aff_metadata_segments(mode_title, af1,af2, | |
662 | i->c_str(),mode); | |
663 | if(r!=0) ret = r; | |
664 | } | |
665 | } | |
666 | } | |
667 | } | |
668 | ||
669 | if(no_data_segments==false){ | |
670 | if(opt_all) puts("Inspecting data..."); | |
671 | for(int mode=1;mode<=3;mode++){ | |
672 | char mode_title[1024]; | |
673 | switch(mode){ | |
674 | case 1: snprintf(mode_title,sizeof(mode_title), | |
675 | " Pages only in %s:\n", af_filename(af1));break; | |
676 | case 2: snprintf(mode_title,sizeof(mode_title), | |
677 | " Pages only in %s:\n", af_filename(af2));break; | |
678 | case 3: snprintf(mode_title,sizeof(mode_title)," Pages in both files:\n");break; | |
679 | } | |
680 | ||
681 | for(int i=lowest_page;i<=highest_page;i++){ | |
682 | int r = compare_aff_data_segments(mode_title,af1,af2,i,mode); | |
683 | if(r!=0) ret = r; | |
684 | } | |
685 | } | |
686 | } | |
687 | current_source = 0; | |
688 | #ifdef HAVE_ISATTY | |
689 | if(ret==0 && isatty(fileno(stdout))) printf("%s and %s: files compare okay\n",file1,file2); | |
690 | #endif | |
691 | return ret; | |
692 | } | |
693 | ||
694 | int recurse(const char *dir1,const char *dir2) | |
695 | { | |
696 | vector<string> only_in_dir1; | |
697 | ||
698 | DIR *dirp = opendir(dir1); | |
699 | struct dirent *dp; | |
700 | if(!dirp) err(1,"opendir: %s",dir1); | |
701 | while ((dp = readdir(dirp)) != NULL){ | |
702 | ||
703 | char fn1[MAXPATHLEN+1]; memset(fn1,0,sizeof(fn1)); | |
704 | char fn2[MAXPATHLEN+1]; memset(fn2,0,sizeof(fn2)); | |
705 | ||
706 | strlcpy(fn1,dir1,sizeof(fn1)); | |
707 | if(fn1[strlen(fn1)-1]!='/') strlcat(fn1,"/",sizeof(fn1)); | |
708 | strlcat(fn1,dp->d_name,sizeof(fn1)); | |
709 | ||
710 | current_source = fn1; | |
711 | if(opt_verbose) printf("%s...\n",fn1); | |
712 | ||
713 | switch(af_identify_file_type(fn1,1)){ | |
714 | case AF_IDENTIFY_ERR: | |
715 | case AF_IDENTIFY_NOEXIST: | |
716 | only_in_dir1.push_back(fn1); | |
717 | break; | |
718 | case AF_IDENTIFY_AFF: | |
719 | case AF_IDENTIFY_AFD: | |
720 | case AF_IDENTIFY_AFM: | |
721 | strlcpy(fn2,dir2,sizeof(fn2)); | |
722 | if(fn2[strlen(fn2)-1]!='/') strlcat(fn2,"/",sizeof(fn2)); | |
723 | strlcat(fn2,dp->d_name,sizeof(fn2)); | |
724 | if(af_identify_file_type(fn2,1)<0){ | |
725 | char buf[1024]; | |
726 | snprintf(buf,sizeof(buf),"%s not in %s\n",dp->d_name,dir2); | |
727 | errors.push_back(buf); | |
728 | break; | |
729 | } | |
730 | if(opt_exist==0){ | |
731 | compare_aff_aff(fn1,fn2); | |
732 | } | |
733 | break; | |
734 | default: | |
735 | break; | |
736 | } | |
737 | } | |
738 | closedir(dirp); | |
739 | printf("========================\n"); | |
740 | printf("Only in %s\n",dir1); | |
741 | for(vector<string>::const_iterator i = only_in_dir1.begin(); | |
742 | i != only_in_dir1.end(); | |
743 | i++){ | |
744 | printf("%s\n",i->c_str()); | |
745 | } | |
746 | return 0; | |
747 | } | |
748 | ||
749 | int main(int argc,char **argv) | |
750 | { | |
751 | int bflag, ch; | |
752 | int opt_recurse=0; | |
753 | ||
754 | #ifdef SIGINFO | |
755 | signal(SIGINFO,sig_info); | |
756 | #endif | |
757 | ||
758 | bflag = 0; | |
759 | while ((ch = getopt(argc, argv, "P:Vabcempqrsh?v")) != -1) { | |
760 | switch (ch) { | |
761 | case 'P': opt_page = atoi(optarg); break; | |
762 | case 'V': printf("%s version %s\n",progname,PACKAGE_VERSION); exit(0); | |
763 | case 'a': opt_all++; break; | |
764 | case 'b': opt_print_sectors=1; break; | |
765 | case 'c': opt_print_sector_contents=1; break; | |
766 | case 'e': opt_exist++; break; | |
767 | case 'm': opt_ignore_metadata++; break; | |
768 | case 'p': opt_preen++; break; | |
769 | case 'q': opt_quiet++; break; | |
770 | case 'r': opt_recurse++; break; | |
771 | case 's': opt_s3++;break; | |
772 | case 'v': opt_verbose++;break; | |
773 | case 'h': | |
774 | case '?': | |
775 | default: | |
776 | usage(); | |
777 | } | |
778 | } | |
779 | argc -= optind; | |
780 | argv += optind; | |
781 | ||
782 | if(opt_recurse){ | |
783 | if(argc!=2) usage(); | |
784 | char *dir1 = *argv++; | |
785 | char *dir2 = *argv++; | |
786 | recurse(dir1,dir2); | |
787 | if(errors.size()>0){ | |
788 | fprintf(stderr,"================================\n"); | |
789 | fprintf(stderr,"%zd affcompare errors:\n",errors.size()); | |
790 | for(vector<string>::const_iterator i=errors.begin(); | |
791 | i!=errors.end(); | |
792 | i++){ | |
793 | fputs(i->c_str(),stderr); | |
794 | } | |
795 | exit(1); | |
796 | } | |
797 | exit(0); | |
798 | } | |
799 | ||
800 | if(argc>1){ | |
801 | char *last = argv[argc-1]; | |
802 | if(last[strlen(last)-1]=='/'){ | |
803 | while(argc>1){ | |
804 | char *file1 = *argv; | |
805 | char *name1 = file1; | |
806 | char *cc; | |
807 | ||
808 | cc = strrchr(file1,'/'); | |
809 | if(cc) name1 = cc+1; | |
810 | ||
811 | char file2[MAXPATHLEN+1]; | |
812 | strlcpy(file2,last,sizeof(file2)); | |
813 | strlcat(file2,name1,sizeof(file2)); | |
814 | int e_code = compare_aff_aff(file1,file2); | |
815 | if(e_code) exit(e_code); | |
816 | argv++; | |
817 | argc--; | |
818 | } | |
819 | } | |
820 | } | |
821 | ||
822 | if(argc!=2) usage(); // if just 2, compare them | |
823 | ||
824 | char *file1 = *argv++; | |
825 | char *file2 = *argv++; | |
826 | ||
827 | if(opt_verbose) printf("%s...\n",file1); | |
828 | int e_code = compare_aff_aff(file1,file2); | |
829 | exit(e_code); | |
830 | } |
0 | /* | |
1 | * affconvert.cpp: | |
2 | * | |
3 | * Convert raw -> aff | |
4 | * aff -> raw | |
5 | * aff -> aff (recompressing/uncompressing) | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (c) 2005--2008 | |
10 | * Simson L. Garfinkel and Basis Technology, Inc. | |
11 | * All rights reserved. | |
12 | * | |
13 | * This code is derrived from software contributed by | |
14 | * Simson L. Garfinkel | |
15 | * | |
16 | * Redistribution and use in source and binary forms, with or without | |
17 | * modification, are permitted provided that the following conditions | |
18 | * are met: | |
19 | * 1. Redistributions of source code must retain the above copyright | |
20 | * notice, this list of conditions and the following disclaimer. | |
21 | * 2. Redistributions in binary form must reproduce the above copyright | |
22 | * notice, this list of conditions and the following disclaimer in the | |
23 | * documentation and/or other materials provided with the distribution. | |
24 | * 3. All advertising materials mentioning features or use of this software | |
25 | * must display the following acknowledgement: | |
26 | * This product includes software developed by Simson L. Garfinkel, | |
27 | * Basis Technology, and its contributors. | |
28 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
29 | * contributors to this program may be used to endorse or promote | |
30 | * products derived from this software without specific prior written | |
31 | * permission. | |
32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
34 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
35 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
36 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
37 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
38 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
45 | * SUCH DAMAGE. | |
46 | */ | |
47 | ||
48 | ||
49 | ||
50 | #include "affconfig.h" | |
51 | #include "afflib.h" | |
52 | #include "afflib_i.h" // we do enough mucking, we need the internal version | |
53 | #include "utils.h" | |
54 | ||
55 | #include <openssl/md5.h> | |
56 | #include <openssl/sha.h> | |
57 | ||
58 | #ifdef WIN32 | |
59 | #include "unix4win32.h" | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_CURSES_H | |
63 | #include <curses.h> | |
64 | #endif | |
65 | ||
66 | #ifdef HAVE_TERM_H | |
67 | #include <term.h> | |
68 | #endif | |
69 | ||
70 | ||
71 | #ifdef HAVE_SYS_TIME_H | |
72 | #include <sys/time.h> | |
73 | #endif | |
74 | ||
75 | #include <sys/stat.h> | |
76 | #include <string> | |
77 | ||
78 | #ifdef HAVE_UNISTD_H | |
79 | #include <unistd.h> | |
80 | #endif | |
81 | ||
82 | #ifdef HAVE_GETOPT_H | |
83 | #include <getopt.h> | |
84 | #endif | |
85 | ||
86 | ||
87 | ||
88 | const char *progname = "affconvert"; | |
89 | ||
90 | int image_pagesize = 16*1024*1024; // default seg size --- 16MB | |
91 | int opt_compression_alg = AF_COMPRESSION_ALG_ZLIB; | |
92 | int opt_compress_level = AF_COMPRESSION_DEFAULT; | |
93 | int64_t bytes_to_convert = 0; | |
94 | int opt_batch = 1; | |
95 | int opt_zap = 0; | |
96 | int opt_quiet = 0; | |
97 | int opt_write_raw = 0; // output | |
98 | int opt_probe_compressed = 1; // probe for compressed files | |
99 | const char *opt_write_raw_ext = "raw"; | |
100 | const char *opt_outdir = 0; | |
101 | const char *opt_aff_ext = "aff"; | |
102 | int64_t opt_maxsize = 0; | |
103 | int opt_yes = 0; | |
104 | int opt_debug = 0; | |
105 | std::string command_line; | |
106 | ||
107 | ||
108 | char *append(char *base,const char *str) | |
109 | { | |
110 | base = (char *)realloc(base,strlen(base)+strlen(str)+1); | |
111 | strcat(base,str); // can't fail | |
112 | return base; | |
113 | } | |
114 | ||
115 | ||
116 | ||
117 | void usage() | |
118 | { | |
119 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
120 | printf("\n"); | |
121 | printf("usage: %s [options] file1 [... files] \n",progname); | |
122 | printf("\n"); | |
123 | printf("examples:\n"); | |
124 | printf(" %s file1.iso --- convert file1.iso to file1.aff\n",progname); | |
125 | printf(" %s file1.iso file2.iso file3.iso... --- batch convert files\n",progname); | |
126 | printf(" %s -r -e iso image.aff --- convert image.aff to image.iso\n",progname); | |
127 | printf(" %s -M4g -o/media/dvd.afd bigfile.aff --- split an AFF file into 4GB chunks for archiving to DVD\n", | |
128 | progname); | |
129 | //printf(" %s -p image.aff --- recompress image.aff to maximum compression\n",progname); | |
130 | printf("\n"); | |
131 | printf("\nGeneral options:\n"); | |
132 | printf(" -q -- Quiet mode. Don't ask questions, don't print status.\n"); | |
133 | ||
134 | printf("\nAFF output options:\n"); | |
135 | printf(" -a ext -- use 'ext' for aff files (default is %s)\n",opt_aff_ext); | |
136 | printf(" (use .afd for AFD files)\n"); | |
137 | printf(" -Mn[kgm] -- set maximum size of output file. Suffix with g, m or k.\n"); | |
138 | printf(" -sn -- set the image_pagesize (default %d)\n",image_pagesize); | |
139 | printf(" -x -- don't compress AFF file.\n"); | |
140 | printf(" -O dir -- use 'dir' as the output directory\n"); | |
141 | printf(" -o file -- output to 'file' (can only convert one at a time)\n"); | |
142 | printf(" File is AFF is file ends .aff; otherwise assumes raw.\n"); | |
143 | printf(" -Xn -- Set compression to n; default is 7\n"); | |
144 | printf(" -L -- Use the LZMA compression algorithm (better but slower)\n"); | |
145 | ||
146 | printf("\nRaw output options:\n"); | |
147 | printf(" -r -- force raw output. \n"); | |
148 | printf(" -e ext -- use 'ext' for the raw files (default %s)\n",opt_write_raw_ext); | |
149 | printf(" (implies -r)\n"); | |
150 | ||
151 | printf("\nDangerous input options:\n"); | |
152 | printf(" -z -- zap; delete the output file if it already exists.\n"); | |
153 | printf(" -Z -- Do not automatically probe for gzip/bzip2 compression.\n"); | |
154 | printf(" -y -- Always answer yes/no questions 'yes.'\n"); | |
155 | printf(" -V = Just print the version number and exit.\n"); | |
156 | printf("\n"); | |
157 | exit(0); | |
158 | } | |
159 | ||
160 | ||
161 | /* probe_gzip(): | |
162 | * Is this a gzip file? | |
163 | * Right now it just looks at the file extension. | |
164 | */ | |
165 | ||
166 | int probe_gzip(const char *infile) | |
167 | { | |
168 | int len = strlen(infile); | |
169 | ||
170 | if(len>3 && strcmp(infile+len-3,".gz")==0){ | |
171 | return 1; | |
172 | } | |
173 | return 0; | |
174 | } | |
175 | ||
176 | int probe_bzip2(const char *infile) | |
177 | { | |
178 | int len = strlen(infile); | |
179 | ||
180 | if(len>4 && strcmp(infile+len-4,".bz2")==0){ | |
181 | return 1; | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | ||
186 | /* yesno(): | |
187 | * As a yes/no question. Return 1 if yes, 0 if no. | |
188 | */ | |
189 | ||
190 | int yesno(const char *statement,const char *question,const char *affirmative) | |
191 | { | |
192 | if(opt_yes){ | |
193 | if(!opt_quiet) printf("%s. %s.\n",statement,affirmative); | |
194 | return 1; | |
195 | } | |
196 | ||
197 | printf("%s. ",statement); | |
198 | char buf[256]; | |
199 | do { | |
200 | printf("%s [y/n]: ",question); | |
201 | memset(buf,0,sizeof(buf)); | |
202 | if(fgets(buf,sizeof(buf)-1,stdin)==0) return 0; | |
203 | if(buf[0]=='y' || buf[0]=='Y'){ | |
204 | printf("%s.\n",affirmative); | |
205 | return 1; | |
206 | } | |
207 | } while(buf[0]!='n' && buf[0]!='N'); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | ||
212 | /* | |
213 | * Basic conversion: | |
214 | * We have an input, which may be raw or aff, | |
215 | * and we have an output, which may be raw or aff. | |
216 | * We are going to want to read a segment at a time. | |
217 | */ | |
218 | ||
219 | ||
220 | #include <algorithm> | |
221 | #include <cstdlib> | |
222 | #include <vector> | |
223 | #include <string> | |
224 | ||
225 | #ifdef HAVE_CSTRING | |
226 | #include <cstring> | |
227 | #endif | |
228 | ||
229 | ||
230 | using namespace std; | |
231 | ||
232 | /** Do the conversion. | |
233 | * return 0 if success, code if fail. | |
234 | */ | |
235 | int convert(const char *infile,char *outfile) | |
236 | { | |
237 | ||
238 | if(opt_debug) fprintf(stderr,"convert(%s,%s)\n",infile,outfile); | |
239 | ||
240 | if(infile && outfile && strcmp(infile,outfile)==0){ | |
241 | errx(1,"Can't convert a file to itself\n"); | |
242 | } | |
243 | ||
244 | /**************************************************************** | |
245 | *** Open Input | |
246 | ****************************************************************/ | |
247 | ||
248 | AFFILE *a_in = 0; // input file, if aff | |
249 | ||
250 | #ifdef UNIX | |
251 | /* Check to see if it is a gzip file... */ | |
252 | if(opt_probe_compressed | |
253 | && probe_gzip(infile) | |
254 | && yesno("infile looks like a gzip file","Uncompress it","Uncompressing")){ | |
255 | /* Open with a subprocess. We will need to use zlib when we move to Windows. */ | |
256 | if(af_hasmeta(infile)) return -1; // don't covert with shell metacharacters | |
257 | char buf[256]; | |
258 | snprintf(buf,sizeof(buf),"gzcat %s",infile); | |
259 | a_in = af_popen(buf,"r"); | |
260 | } | |
261 | ||
262 | /* Check to see if it is a bzip2 file... */ | |
263 | if(!a_in | |
264 | && opt_probe_compressed | |
265 | && probe_bzip2(infile) | |
266 | && yesno("infile looks like a bzip2 file","Uncompress it","Uncompressing")){ | |
267 | /* Open with a subprocess. We will need to use bzip2zlib when we move to Windows. */ | |
268 | if(af_hasmeta(infile)) return -1; // don't covert with shell metacharacters | |
269 | char buf[256]; | |
270 | snprintf(buf,sizeof(buf),"bzcat %s",infile); | |
271 | a_in = af_popen(buf,"r"); | |
272 | } | |
273 | #endif | |
274 | ||
275 | /* If the file isn't open, try to open it... */ | |
276 | if(!a_in){ | |
277 | a_in = af_open(infile,O_RDONLY,0); | |
278 | if(!a_in) af_err(1,"%s",infile); // give up | |
279 | if(af_identify(a_in)==AF_IDENTIFY_RAW){ | |
280 | af_set_pagesize(a_in,image_pagesize); // match the page size we want to use | |
281 | } | |
282 | else { | |
283 | image_pagesize = a_in->image_pagesize; // that's what we are using | |
284 | } | |
285 | } | |
286 | ||
287 | const char *ain_fn = af_filename(a_in); | |
288 | struct stat si; | |
289 | memset((char *)&si,0,sizeof(si)); | |
290 | if(ain_fn && stat(ain_fn,&si)){ | |
291 | warn("Cannot stat %s",ain_fn); | |
292 | } | |
293 | ||
294 | ||
295 | /**************************************************************** | |
296 | *** Open Ouptut | |
297 | ****************************************************************/ | |
298 | ||
299 | ||
300 | if(opt_zap) unlink(outfile); // we were told to zap it | |
301 | ||
302 | AFFILE *a_out = 0; // output file, if aff or raw... | |
303 | if(access(outfile,F_OK)==0){ | |
304 | /* If outfile is a device, ask user... */ | |
305 | struct stat so; | |
306 | if(stat(outfile,&so)){ | |
307 | err(1,"%s exists but can't be stat?",outfile); | |
308 | } | |
309 | if((so.st_mode & S_IFMT)==S_IFCHR || | |
310 | (so.st_mode & S_IFMT)==S_IFBLK){ | |
311 | char buf[1024]; | |
312 | snprintf(buf,sizeof(buf),"%s is a raw device.\n",outfile); | |
313 | if(yesno(buf,"Overwrite raw device?","yes")){ | |
314 | goto doit; | |
315 | } | |
316 | } | |
317 | fprintf(stderr,"%s: file exists. Delete it before converting.\n",outfile); | |
318 | exit(-1); | |
319 | } | |
320 | /* Check for splitraw names */ | |
321 | if(af_ext_is(outfile,"afm")){ | |
322 | char file000[MAXPATHLEN+1]; | |
323 | strlcpy(file000,outfile,sizeof(file000)); | |
324 | char *cc = strrchr(file000,'.'); | |
325 | if(!cc) err(1,"Cannot file '.' in %s\n",file000); | |
326 | for(int i=0;i<2;i++){ | |
327 | sprintf(cc,".%03d",i); | |
328 | if(access(file000,F_OK)==0){ | |
329 | fprintf(stderr,"%s: file exists. Delete it before converting.\n",file000); | |
330 | fprintf(stderr,"NOTE: -z option will not delete %s\n",file000); | |
331 | return -1; | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | doit:; | |
337 | ||
338 | if(opt_write_raw){ | |
339 | /* Easy way to make a raw output is to reopen an existing output file... */ | |
340 | FILE *f = fopen(outfile,"w+b"); | |
341 | if(!f){ | |
342 | err(1,"%s",outfile); | |
343 | } | |
344 | a_out = af_freopen(f); | |
345 | } | |
346 | else { | |
347 | a_out = af_open(outfile,O_RDWR|O_CREAT|O_BINARY,0777); | |
348 | if(!a_out) af_err(1,"%s",outfile); | |
349 | if(opt_maxsize){ | |
350 | af_set_maxsize(a_out,opt_maxsize); | |
351 | } | |
352 | ||
353 | } | |
354 | if(a_out == 0) af_err(1,"af_open: %s",outfile); | |
355 | ||
356 | if(!opt_quiet) printf("convert %s --> %s\n",infile,outfile); | |
357 | ||
358 | af_update_seg(a_out,AF_ACQUISITION_COMMAND_LINE,0, | |
359 | (const u_char *)command_line.c_str(), | |
360 | command_line.size()); | |
361 | ||
362 | /**************************************************************** | |
363 | *** Set up the AFF file (assuming it's an aff file) | |
364 | *** stuff that we keep at the beginning of the file... | |
365 | ****************************************************************/ | |
366 | ||
367 | MD5_CTX md5; | |
368 | MD5_Init(&md5); | |
369 | ||
370 | SHA_CTX sha; | |
371 | SHA1_Init(&sha); | |
372 | ||
373 | /* Setup writing */ | |
374 | if(a_in->image_pagesize){ | |
375 | image_pagesize = a_in->image_pagesize; | |
376 | } | |
377 | af_set_pagesize(a_out,image_pagesize); | |
378 | af_set_sectorsize(a_out,a_in->image_sectorsize); | |
379 | ||
380 | struct af_vnode_info vni; | |
381 | af_vstat(a_out,&vni); | |
382 | if(vni.supports_compression){ | |
383 | if(opt_compression_alg){ | |
384 | af_enable_compression(a_out,opt_compression_alg,opt_compress_level); | |
385 | } | |
386 | else{ | |
387 | af_enable_compression(a_out,0,0); | |
388 | } | |
389 | } | |
390 | ||
391 | /* Get a list of all the metadata segments and the pages | |
392 | * (if this is a raw file, then the vnode raw driver will give us those segments) | |
393 | */ | |
394 | ||
395 | char segname[AF_MAX_NAME_LEN]; | |
396 | vector <string> metadata_segments; | |
397 | vector <int64_t> pages; | |
398 | af_rewind_seg(a_in); // start at the beginning | |
399 | int64_t highest_pagenum = 0; | |
400 | while(af_get_next_seg(a_in,segname,sizeof(segname),0,0,0)==0){ | |
401 | int64_t page_num = af_segname_page_number(segname); | |
402 | if(page_num>=0){ | |
403 | pages.push_back(page_num); | |
404 | if(page_num>highest_pagenum) highest_pagenum = page_num; | |
405 | } | |
406 | else { | |
407 | metadata_segments.push_back(segname); | |
408 | } | |
409 | } | |
410 | ||
411 | /* Copy over all of the metadata segments. | |
412 | * But don't bother if we are creating raw output | |
413 | */ | |
414 | if(opt_write_raw==0){ | |
415 | for(vector<string>::iterator i = metadata_segments.begin(); | |
416 | i != metadata_segments.end(); | |
417 | i++){ | |
418 | strlcpy(segname,i->c_str(),sizeof(segname)); | |
419 | size_t data_len = 0; | |
420 | unsigned long arg; | |
421 | ||
422 | /* First find out how big the segment is */ | |
423 | if(af_get_seg(a_in,segname,&arg,0,&data_len)){ | |
424 | warn("af_get_seg_1"); | |
425 | continue; | |
426 | } | |
427 | /* Now get the data */ | |
428 | unsigned char *data = (unsigned char *)malloc(data_len); | |
429 | if(af_get_seg(a_in,segname,0,data,&data_len)){ | |
430 | warn("af_get_seg_2"); | |
431 | free(data); | |
432 | continue; | |
433 | } | |
434 | /* Now put the data */ | |
435 | if(af_update_seg(a_out,segname,arg,data,data_len)){ | |
436 | err(1,"af_update_seg"); | |
437 | } | |
438 | free(data); | |
439 | } | |
440 | } | |
441 | ||
442 | /* Now sort the pages and copy them over. If there is no break, | |
443 | * we can compute the hashes... | |
444 | */ | |
445 | sort(pages.begin(),pages.end()); | |
446 | ||
447 | int64_t prev_pagenum = -1; | |
448 | bool hash_valid = true; | |
449 | uint64_t last_byte_in_image = 0; | |
450 | uint64_t total_bytes_converted = 0; | |
451 | ||
452 | bool copy_by_pages = af_has_pages(a_in); | |
453 | ||
454 | unsigned char *data = (unsigned char *)malloc(image_pagesize); | |
455 | if(copy_by_pages){ | |
456 | /* Copy over data one page at a time */ | |
457 | for(vector<int64_t>::iterator i = pages.begin(); i != pages.end(); i++){ | |
458 | ||
459 | int64_t pagenum = *i; | |
460 | ||
461 | if(!opt_quiet) printf("Converting page %"I64d" of %"I64d"\r",pagenum,highest_pagenum);fflush(stdout); | |
462 | ||
463 | size_t data_len = image_pagesize; | |
464 | if(af_get_page(a_in,pagenum,data,&data_len)){ | |
465 | err(1,"af_get_page(file=%s,page=%"I64d")", | |
466 | af_filename(a_in),pagenum); | |
467 | } | |
468 | if(af_update_page(a_out,pagenum,data,data_len)){ | |
469 | err(1,"af_update_page(file=%s,page=%"I64d")", | |
470 | af_filename(a_out),pagenum); | |
471 | } | |
472 | ||
473 | if(pagenum != prev_pagenum + 1) hash_valid = false; | |
474 | ||
475 | if(hash_valid && vni.supports_metadata){ | |
476 | MD5_Update(&md5,data,data_len); | |
477 | SHA1_Update(&sha,data,data_len); | |
478 | prev_pagenum = pagenum; | |
479 | } | |
480 | last_byte_in_image = (int64_t)image_pagesize * pagenum + (int64_t)data_len; | |
481 | total_bytes_converted += data_len; | |
482 | } | |
483 | /* Go back and update the image size (necessary since I have been writing page-by-page) */ | |
484 | if(af_update_segq(a_out,AF_IMAGESIZE,last_byte_in_image) | |
485 | && errno!=ENOTSUP){ | |
486 | err(1,"Could not upate AF_IMAGESIZE"); | |
487 | } | |
488 | } else { | |
489 | /* No page support; Copy from beginning to end */ | |
490 | while(!af_eof(a_in)){ | |
491 | int data_len = af_read(a_in,data,image_pagesize); | |
492 | if(data_len>0){ | |
493 | if(!opt_quiet){ | |
494 | printf("Writing to page %" I64d " with %d bytes read from input... \r", | |
495 | total_bytes_converted / image_pagesize,data_len); | |
496 | fflush(stdout); | |
497 | } | |
498 | if(af_write(a_out,data,data_len)!=data_len){ | |
499 | err(1,"af_write"); | |
500 | } | |
501 | if(vni.supports_metadata){ | |
502 | MD5_Update(&md5,data,data_len); | |
503 | SHA1_Update(&sha,data,data_len); | |
504 | } | |
505 | } | |
506 | if(data_len<0) err(1,"af_read"); | |
507 | if(data_len==0){ | |
508 | if(!opt_quiet) printf("af_read returned 0. Reached a sparse region or end of pipe.\n"); | |
509 | break; | |
510 | } | |
511 | last_byte_in_image += data_len; | |
512 | total_bytes_converted += data_len; | |
513 | } | |
514 | } | |
515 | free(data); | |
516 | if(!opt_quiet) printf("\n"); | |
517 | ||
518 | /* Write out the new hash if it is valid */ | |
519 | if(hash_valid && vni.supports_metadata){ | |
520 | u_char md5_buf[32],sha1_buf[40]; | |
521 | char buf[256]; | |
522 | MD5_Final(md5_buf,&md5); | |
523 | if(af_update_seg(a_out,AF_MD5,0,md5_buf,16) && errno!=ENOTSUP){ | |
524 | err(1,"Could not update AF_MD5"); | |
525 | } | |
526 | if(!opt_quiet) printf("md5: %s\n",af_hexbuf(buf,sizeof(buf),md5_buf,16,1)); | |
527 | ||
528 | SHA1_Final(sha1_buf,&sha); | |
529 | if(af_update_seg(a_out,AF_SHA1,0,sha1_buf,20) && errno!=ENOTSUP){ | |
530 | err(1,"Could not update AF_SHA1"); | |
531 | } | |
532 | if(!opt_quiet) printf("sha1: %s\n",af_hexbuf(buf,sizeof(buf),sha1_buf,20,1)); | |
533 | } | |
534 | ||
535 | /* Finish the hash calculations and write to the db */ | |
536 | if(!opt_quiet){ | |
537 | printf("bytes converted: %"I64d" \n",total_bytes_converted); | |
538 | /* If the vnode implementation tracked segments written, report it. */ | |
539 | if(a_out->pages_written || a_out->pages_compressed){ | |
540 | printf("Total pages: %"I64u" (%"I64u" compressed)\n", | |
541 | a_out->pages_written,a_out->pages_compressed); | |
542 | } | |
543 | } | |
544 | ||
545 | if(vni.supports_metadata){ | |
546 | /* make an AF_IMAGE_GID if it doesn't exist */ | |
547 | af_make_gid(a_out); | |
548 | af_set_acquisition_date(a_out,si.st_mtime); | |
549 | } | |
550 | ||
551 | /* Make a copy of the a_out filename if we can get it */ | |
552 | char *a_out_fn=0; // output filename, to remember for utimes | |
553 | const char *a_ = af_filename(a_out); // remember the output filename | |
554 | if(a_){ | |
555 | a_out_fn = strdup(a_); // make a copy of it | |
556 | } | |
557 | if(af_close(a_out)) err(1,"af_close(a_out)"); | |
558 | ||
559 | if(!opt_quiet){ | |
560 | printf("Conversion finished.\n"); | |
561 | if(af_cannot_decrypt(a_in)){ | |
562 | printf("*** encrypted pages are present which could not be decrypted ***\n"); | |
563 | } | |
564 | printf("\n\n"); | |
565 | } | |
566 | if(af_close(a_in)) err(1,"af_close(a_in)"); | |
567 | ||
568 | /* Set the utime on the resulting file if we can stat it */ | |
569 | struct timeval times[2]; | |
570 | ||
571 | memset(times,0,sizeof(times)); | |
572 | times[0].tv_sec = si.st_atime; | |
573 | times[1].tv_sec = si.st_mtime; | |
574 | #ifdef HAVE_UTIMES | |
575 | if(a_out_fn){ | |
576 | if(utimes(a_out_fn,times)) warn("utimes(%s):",outfile); | |
577 | free(a_out_fn); | |
578 | a_out_fn = 0; | |
579 | } | |
580 | #endif | |
581 | return(0); | |
582 | } | |
583 | ||
584 | ||
585 | int64_t atoi64(const char *buf) | |
586 | { | |
587 | int64_t r=0; | |
588 | sscanf(buf,"%"I64d,&r); | |
589 | return r; | |
590 | } | |
591 | ||
592 | int64_t atoi64m(const char *optarg) | |
593 | { | |
594 | int multiplier; | |
595 | switch(optarg[strlen(optarg)-1]){ | |
596 | case 'g': | |
597 | case 'G': | |
598 | multiplier=1024*1024*1024;break; | |
599 | case 'm': | |
600 | case 'M': | |
601 | multiplier=1024*1024; break; | |
602 | case 'k': | |
603 | case 'K': | |
604 | multiplier=1024; break; | |
605 | case 'b': | |
606 | case 'B': | |
607 | multiplier=1;break; | |
608 | default: | |
609 | err(1,"Specify multiplier units of g, m, k or b in '%s'\n",optarg); | |
610 | } | |
611 | return atoi64(optarg) * multiplier; | |
612 | } | |
613 | ||
614 | ||
615 | int main(int argc,char **argv) | |
616 | { | |
617 | char *outfile = 0; | |
618 | int ch; | |
619 | ||
620 | command_line = aff::command_line(argc,argv); | |
621 | while ((ch = getopt(argc, argv, "a:e:Lo:zqrs:xX:Zh?M:O::ydV")) != -1) { | |
622 | switch (ch) { | |
623 | case 'a': | |
624 | opt_aff_ext = optarg; | |
625 | break; | |
626 | case 'e': | |
627 | opt_write_raw++; | |
628 | opt_write_raw_ext = optarg; | |
629 | break; | |
630 | case 'o': | |
631 | outfile = optarg; | |
632 | break; | |
633 | case 'z': | |
634 | opt_zap ++; | |
635 | break; | |
636 | case 'q': | |
637 | opt_quiet++; | |
638 | break; | |
639 | case 'L': | |
640 | opt_compression_alg = AF_COMPRESSION_ALG_LZMA; | |
641 | break; | |
642 | case 'r': | |
643 | opt_write_raw++; | |
644 | break; | |
645 | case 's': | |
646 | image_pagesize = atoi64m(optarg); | |
647 | break; | |
648 | case 'x': | |
649 | opt_compression_alg=AF_COMPRESSION_ALG_NONE; | |
650 | break; | |
651 | case 'X': | |
652 | opt_compress_level = atoi(optarg); | |
653 | break; | |
654 | case 'Z': | |
655 | opt_probe_compressed = 0; | |
656 | break; | |
657 | case 'y': | |
658 | opt_yes = 1; | |
659 | break; | |
660 | case 'M': | |
661 | opt_maxsize = atoi64m(optarg); | |
662 | break; | |
663 | case 'O': | |
664 | if(!optarg) err(1,"-O flag requires a directory"); | |
665 | opt_outdir = optarg; | |
666 | break; | |
667 | case 'd': | |
668 | opt_debug++; | |
669 | break; | |
670 | case 'h': | |
671 | case '?': | |
672 | default: | |
673 | usage(); | |
674 | exit(0); | |
675 | case 'V': | |
676 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
677 | exit(0); | |
678 | ||
679 | } | |
680 | } | |
681 | argc -= optind; | |
682 | argv += optind; | |
683 | ||
684 | if(argc<1){ | |
685 | usage(); | |
686 | } | |
687 | ||
688 | if(outfile){ | |
689 | return convert(*argv,outfile); | |
690 | } | |
691 | ||
692 | /* Check for "-o filename" at the end of the command line... */ | |
693 | if(argc==3 && !strcmp(argv[1],"-o")){ | |
694 | return convert(argv[0],argv[2]); | |
695 | } | |
696 | ||
697 | /* Convert each file*/ | |
698 | ||
699 | while(*argv){ | |
700 | char outfile[MAXPATHLEN+1]; | |
701 | memset(outfile,0,sizeof(outfile)); | |
702 | ||
703 | const char *ext = opt_write_raw ? opt_write_raw_ext : opt_aff_ext; | |
704 | char *infile = *argv; | |
705 | argv++; | |
706 | argc--; | |
707 | ||
708 | /* Copy over the filename and change the extension */ | |
709 | strlcpy(outfile,infile,sizeof(outfile)); | |
710 | char *cc = strrchr(outfile,'.'); // to strip off extension | |
711 | if(cc){ | |
712 | /* Found an extension; copy over mine. */ | |
713 | strlcpy(cc+1,ext,sizeof(outfile)-(cc-outfile)); | |
714 | } | |
715 | else { | |
716 | /* No extension; make one */ | |
717 | strlcat(outfile,".",sizeof(outfile)); | |
718 | strlcat(outfile,ext,sizeof(outfile)); | |
719 | } | |
720 | ||
721 | /* The user might want us to put things | |
722 | * in a different directory. Pull off the filename... | |
723 | */ | |
724 | if(opt_outdir){ | |
725 | cc = strrchr(outfile,'/'); | |
726 | char filename[PATH_MAX]; | |
727 | if(cc){ | |
728 | strlcpy(filename,cc+1,sizeof(filename)); // just the filename | |
729 | } | |
730 | else{ | |
731 | strlcpy(filename,outfile,sizeof(filename)); // the outfile is the filename | |
732 | } | |
733 | strlcpy(outfile,opt_outdir,sizeof(outfile)); | |
734 | strlcat(outfile,"/",sizeof(outfile)); | |
735 | strlcat(outfile,filename,sizeof(outfile)); | |
736 | } | |
737 | if(convert(infile,outfile)){ | |
738 | exit(1); | |
739 | } | |
740 | } | |
741 | exit(0); | |
742 | } |
0 | /* | |
1 | * afcopy.cpp: | |
2 | * | |
3 | * Copy one AFF file to another. | |
4 | * Resulting file is re-ordered and possibly re-compressed. | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2006 | |
9 | * Simson L. Garfinkel | |
10 | * All rights reserved. | |
11 | * | |
12 | * This code is derrived from software contributed by | |
13 | * Simson L. Garfinkel | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | |
23 | * 3. [Omitted] | |
24 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
25 | * contributors to this program may be used to endorse or promote | |
26 | * products derived from this software without specific prior written | |
27 | * permission. | |
28 | * | |
29 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL AND CONTRIBUTORS ``AS | |
30 | * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SIMSON | |
33 | * GARFINKEL, BAIS TECHNOLOGy, OR CONTRIBUTORS BE LIABLE FOR ANY | |
34 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
35 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
36 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
38 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
39 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
40 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
41 | */ | |
42 | ||
43 | ||
44 | #include "affconfig.h" | |
45 | #include "afflib.h" | |
46 | #include "afflib_i.h" | |
47 | #include "utils.h" | |
48 | #include "base64.h" | |
49 | #include "aff_bom.h" | |
50 | ||
51 | using namespace std; | |
52 | using namespace aff; | |
53 | ||
54 | #ifdef HAVE_SYS_SIGNAL_H | |
55 | #include <sys/signal.h> | |
56 | #endif | |
57 | ||
58 | #ifdef HAVE_TIME_H | |
59 | #include <time.h> | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_SYS_TIME_H | |
63 | #include <sys/time.h> | |
64 | #endif | |
65 | ||
66 | #include <ctype.h> | |
67 | #include <zlib.h> | |
68 | #include <openssl/md5.h> | |
69 | #include <openssl/sha.h> | |
70 | #include <assert.h> | |
71 | ||
72 | #ifdef HAVE_UNISTD_H | |
73 | #include <unistd.h> | |
74 | #endif | |
75 | ||
76 | #ifdef HAVE_TERM_H | |
77 | #include <term.h> | |
78 | #endif | |
79 | ||
80 | #ifdef HAVE_NCURSES_TERM_H | |
81 | #include <ncurses/term.h> | |
82 | #endif | |
83 | ||
84 | #ifdef WIN32 | |
85 | #include "unix4win32.h" | |
86 | #endif | |
87 | ||
88 | const char *progname = "afcopy"; | |
89 | ||
90 | int opt_verbose = 0; | |
91 | int opt_debug = 0; | |
92 | int opt_x = 0; | |
93 | int opt_X = AF_COMPRESSION_DEFAULT; | |
94 | int opt_noverify = 0; | |
95 | int opt_preen = 0; | |
96 | int opt_zap =0; | |
97 | int opt_missing = 0; | |
98 | int opt_preen_alg_arg = 0; // algorithm for recompressing | |
99 | int opt_preen_alg_flag = 0; | |
100 | int opt_sign = 0; | |
101 | ||
102 | int opt_note = 0; | |
103 | const char *opt_sign_key_file = 0; | |
104 | const char *opt_sign_cert_file = 0; | |
105 | ||
106 | void usage() | |
107 | { | |
108 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
109 | printf("usage: %s [options] file1 file\n",progname); | |
110 | printf(" Copies file1 to file2\n"); | |
111 | printf(" %s [options] file1 file2 file3 ... dir\n",progname); | |
112 | printf(" Copies file1.. into dir\n"); | |
113 | printf(" %s [options] file1 file2 file3 ... dir1 dir2...\n",progname); | |
114 | printf(" Copies file1.. into dirs1, dir2, ...\n"); | |
115 | printf("\n"); | |
116 | printf("By default, all page MACs are verified on read and all segments\n"); | |
117 | printf("are verified after write.\n"); | |
118 | ||
119 | printf("Options:\n"); | |
120 | printf(" -v = verbose: print each file as it is copied\n"); | |
121 | printf(" -vv = very verbose: print each segment as it is copied\n"); | |
122 | printf(" -d = print debugging information as well\n"); | |
123 | printf(" -x = don't verify hashes on reads\n"); | |
124 | printf(" -y = don't verify writes\n"); | |
125 | printf(" -Xn = recompress pages (preen) with zlib level n\n"); | |
126 | printf(" -L = recompress pages (preen) with LZMA (smaller but slower)\n"); | |
127 | printf("\n"); | |
128 | printf(" -h = help; print this message.\n"); | |
129 | printf(" -V = print the program version and exit.\n"); | |
130 | printf(" -z = zap; copy even if the destination exists.\n"); | |
131 | printf(" -m = just copy the missing segments\n"); | |
132 | printf("\nSignature Options:\n"); | |
133 | printf(" -k filename.key = specify private key for signing\n"); | |
134 | printf(" -c filename.cer = specify a X.509 certificate that matches the private key\n"); | |
135 | printf(" (by default, the file is assumed to be the same one\n"); | |
136 | printf(" provided with the -k option.)"); | |
137 | printf(" -n = read notes to accompany the copy from standard in.\n"); | |
138 | printf("\n"); | |
139 | printf("\nEncryption Options:"); | |
140 | printf(" Specify passphrase encryption for filename.aff with:\n"); | |
141 | printf(" file://:passphrase@/filename.aff\n"); | |
142 | printf("\n"); | |
143 | printf("Examples:\n"); | |
144 | printf(" %s file.aff file://:mypassword@/file-encrypted.aff - encrypt file.aff\n",progname); | |
145 | #ifdef USE_S3 | |
146 | printf(" %s -vy -X9 *.aff s3:/// Copy all files in current\n",progname); | |
147 | printf(" directory to S3 default bucket with X9 compression\n"); | |
148 | #endif | |
149 | exit(1); | |
150 | } | |
151 | ||
152 | ||
153 | const char *current_source = 0; | |
154 | const char *current_dest = 0; | |
155 | const char *current_seg = 0; | |
156 | void sig_info(int arg) | |
157 | { | |
158 | if(current_source){ | |
159 | printf("Copying %s ",current_source); | |
160 | if(current_dest){ | |
161 | printf("--> %s",current_dest); | |
162 | if(current_seg) printf(" (%s) ",current_seg); | |
163 | } | |
164 | } | |
165 | printf("\n"); | |
166 | } | |
167 | ||
168 | ||
169 | void unlink_outfiles(vector<string> outfiles) | |
170 | { | |
171 | int failure=0; | |
172 | for(vector<string>::const_iterator o = outfiles.begin(); | |
173 | o != outfiles.end(); | |
174 | o++){ | |
175 | char *protocol=0; | |
176 | char *path = 0; | |
177 | af_parse_url(o->c_str(),&protocol,0,0,0,0,&path); | |
178 | if(strcmp(protocol,"file")==0){ | |
179 | unlink(path); | |
180 | } | |
181 | else{ | |
182 | fprintf(stderr,"Cannot unlink %s\n",o->c_str()); | |
183 | failure=1; | |
184 | } | |
185 | if(protocol) free(protocol); | |
186 | if(path) free(path); | |
187 | } | |
188 | if(failure) exit(1); | |
189 | } | |
190 | ||
191 | #if !defined( __BSD_VISIBLE) && !defined(isnumber) | |
192 | #define isnumber(x) isdigit(x) | |
193 | #endif | |
194 | ||
195 | #ifdef WIN32 | |
196 | #include <windows.h> | |
197 | #include <windowsx.h> | |
198 | int gettimeofday (struct timeval *tv, void* tz) | |
199 | { | |
200 | union { | |
201 | int64_t ns100; /*time since 1 Jan 1601 in 100ns units */ | |
202 | FILETIME ft; | |
203 | } now; | |
204 | ||
205 | GetSystemTimeAsFileTime (&now.ft); | |
206 | tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); | |
207 | tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); | |
208 | return (0); | |
209 | } | |
210 | #endif | |
211 | ||
212 | void open_outfiles(AFFILE *ain,outlist &afouts,const vector<string> &outfiles) | |
213 | { | |
214 | /* Open every output file */ | |
215 | for(vector<string>::const_iterator o = outfiles.begin(); | |
216 | o != outfiles.end(); o++){ | |
217 | ||
218 | const char *outfilename = o->c_str(); | |
219 | outelement out; | |
220 | ||
221 | /* First see if the output file exists */ | |
222 | out.af = 0; | |
223 | int ident = af_identify_file_type(outfilename,1); | |
224 | if(ident!=AF_IDENTIFY_NOEXIST){ | |
225 | fprintf(stderr,"%s: file exists... ",outfilename); | |
226 | if(opt_zap==0 && opt_missing==0){ | |
227 | fprintf(stderr,"\n Will not overwrite; use -m or -z\n"); | |
228 | continue; | |
229 | } | |
230 | if(opt_missing){ | |
231 | fprintf(stderr,"Will fill in missing segments...\n"); | |
232 | out.af = af_open(outfilename,O_RDWR|O_EXCL,0666); | |
233 | if(!out.af) af_err(1,outfilename); | |
234 | if(af_page_size(ain) != af_page_size(out.af)){ | |
235 | fprintf(stderr,"%s and %s have different page sizes (%d != %d)\n", | |
236 | af_filename(ain), | |
237 | af_filename(out.af), | |
238 | af_page_size(ain), | |
239 | af_page_size(out.af)); | |
240 | af_close(out.af); | |
241 | out.af=0; | |
242 | continue; | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | ||
248 | ||
249 | if(out.af==0){ | |
250 | out.af = af_open(outfilename,O_RDWR|O_EXCL|O_CREAT,0666); | |
251 | if(!out.af){ | |
252 | warn("%s",outfilename); | |
253 | continue; | |
254 | } | |
255 | if(af_set_pagesize(out.af,af_page_size(ain))){ | |
256 | errx(1,"%s: cannot set page size to %d\n", af_filename(out.af),af_page_size(ain)); | |
257 | } | |
258 | } | |
259 | if(o != outfiles.begin()) printf("\t "); | |
260 | if(opt_verbose){ | |
261 | printf(" => %s ",outfilename); | |
262 | if(opt_preen) printf(" (preening) "); | |
263 | printf("\n"); | |
264 | } | |
265 | if(opt_missing) out.segs.get_seglist(out.af); | |
266 | afouts.push_back(out); | |
267 | } | |
268 | } | |
269 | ||
270 | /* Copy pagenumber from ain to aout. | |
271 | * Return 0 if success, -1 if can't do it. | |
272 | * Properly handles signing and preening if requested. | |
273 | */ | |
274 | int copy_page(AFFILE *ain,AFFILE *aout,int64_t pagenum,unsigned long arg,u_char *seghash,u_int *seghash_len) | |
275 | { | |
276 | /* If we are preening but not signing, see if we can get out fast */ | |
277 | if(opt_sign==0 && opt_preen==0) return -1; // not preening and not signing | |
278 | ||
279 | /* If we are not signing, don't bother decompressing and recompressing*/ | |
280 | if(opt_sign==0 && opt_preen){ | |
281 | int alg = (arg & AF_PAGE_COMP_ALG_MASK); | |
282 | if(alg==AF_PAGE_COMP_ALG_ZERO) return -1; // don't preen ZERO | |
283 | if(alg==opt_preen_alg_arg) return -1; // don't decompress then re-compress with old alg | |
284 | } | |
285 | ||
286 | /* If we get here, page must be read into memory and decompressed */ | |
287 | size_t pagesize = af_page_size(ain); | |
288 | if(pagesize<=0) return -1; // couldn't get pagesize | |
289 | ||
290 | u_char *pagebuf = (unsigned char *)malloc(pagesize); | |
291 | if(!pagebuf) return -1; // couldn't allocate memory for page? | |
292 | ||
293 | if(af_get_page(ain,pagenum,pagebuf,&pagesize)){ // note --- this may make pagesize smaller | |
294 | free(pagebuf); | |
295 | return -1; | |
296 | } | |
297 | ||
298 | if(opt_preen){ // set compression if we are preening | |
299 | af_enable_compression(aout,opt_preen_alg_flag,opt_X); | |
300 | } | |
301 | ||
302 | #ifdef USE_AFFSIGS | |
303 | /* If calculating a bom, calculate the bom! */ | |
304 | if(opt_sign){ | |
305 | char segname[AF_MAX_NAME_LEN]; | |
306 | sprintf(segname,AF_PAGE,pagenum); | |
307 | aff_bom::make_hash(seghash,arg,segname,pagebuf,pagesize); | |
308 | } | |
309 | #endif | |
310 | ||
311 | /* Write out the page */ | |
312 | int ret = af_update_page(aout,pagenum,pagebuf,pagesize); | |
313 | free(pagebuf); | |
314 | return ret; | |
315 | } | |
316 | ||
317 | string base64(const u_char *buf,size_t buflen) | |
318 | { | |
319 | size_t len = buflen*2+1; | |
320 | char *str = (char *)malloc(len); | |
321 | b64_ntop(buf,buflen,str,len); | |
322 | string ret = string(str); | |
323 | free(str); | |
324 | return ret; | |
325 | } | |
326 | ||
327 | #ifndef HAVE_ISATTY | |
328 | int isatty(int fd) | |
329 | { | |
330 | return 1; // have to assume it's a tty | |
331 | } | |
332 | #endif | |
333 | ||
334 | int afcopy(char *infile,vector<string> &outfiles) | |
335 | { | |
336 | #ifdef SIGINFO | |
337 | signal(SIGINFO,sig_info); | |
338 | #endif | |
339 | hashMapT hashMap; | |
340 | ||
341 | /* Open the input file */ | |
342 | AFFILE *ain = af_open(infile,O_RDONLY,0); | |
343 | if(opt_debug) printf("af_open(%s,O_RDONLY)=%p\n",infile,ain); | |
344 | if(!ain) af_err(1,"%s",infile); | |
345 | seglist segments(ain); | |
346 | ||
347 | if(opt_zap) unlink_outfiles(outfiles); | |
348 | ||
349 | outlist afouts; // vector of output AFFs | |
350 | vector<int64_t>preened_pages; | |
351 | open_outfiles(ain,afouts,outfiles); | |
352 | ||
353 | /* Now, try to open the output files, to see if they exist */ | |
354 | current_source = infile; | |
355 | if(opt_verbose) printf("%s: ",infile); | |
356 | if(opt_verbose>1) putchar('\n'); | |
357 | ||
358 | /* If we couldn't open any output files, return */ | |
359 | if(afouts.size()==0){ | |
360 | af_close(ain); // close the input file | |
361 | return -1; | |
362 | } | |
363 | ||
364 | #ifdef USE_AFFSIGS | |
365 | /* If we are signing, initialize the signing machinery */ | |
366 | aff_bom bom(opt_note); | |
367 | if(opt_sign){ | |
368 | if(bom.read_files(opt_sign_cert_file,opt_sign_key_file)){ | |
369 | opt_sign = 0; // can't sign | |
370 | } | |
371 | } | |
372 | #endif | |
373 | ||
374 | /* Now the files are open. For each output file: | |
375 | * 1. Initialize signing if options were set and the segments aren't already signed. | |
376 | * 2. Sign all of the segments that are unsigned | |
377 | */ | |
378 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
379 | if(opt_sign_key_file && segments.has_signed_segments()==false){ | |
380 | if(af_set_sign_files(aout->af,opt_sign_key_file,opt_sign_cert_file)){ | |
381 | err(1,"%s",opt_sign_key_file); | |
382 | } | |
383 | af_sign_all_unsigned_segments(aout->af); | |
384 | opt_sign = true; | |
385 | } | |
386 | } | |
387 | ||
388 | /* Start the copying */ | |
389 | struct timeval t0,t1; | |
390 | gettimeofday(&t0,0); | |
391 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
392 | /* For each segment, get the size of the segment */ | |
393 | const char *segname = seg->name.c_str(); | |
394 | current_seg = segname; // for printing | |
395 | size_t seglen=0; | |
396 | ||
397 | if(af_get_seg(ain,segname,0,0,&seglen)){ | |
398 | unlink_outfiles(outfiles); | |
399 | err(1,"Cannot read length of segment '%s' on input file %s", segname,af_filename(ain)); | |
400 | } | |
401 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
402 | if(!segbuf){ | |
403 | unlink_outfiles(outfiles); | |
404 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
405 | (int)seglen,segname,af_filename(ain)); | |
406 | } | |
407 | ||
408 | /* Now get the raw source segment */ | |
409 | unsigned long arg=0; | |
410 | if(af_get_seg(ain,segname,&arg,segbuf,&seglen)){ | |
411 | unlink_outfiles(outfiles); // failure; unlink the output files | |
412 | err(1,"Cannot read segment '%s' in %s. Deleteing output file", segname,af_filename(ain)); | |
413 | } | |
414 | ||
415 | /* Calculate the MD5 of this segment and remember it in the map */ | |
416 | md5blob md5; | |
417 | MD5(segbuf,seglen,md5.buf); | |
418 | hashMap[segname] = md5; | |
419 | ||
420 | /* See if this is a page; if so, it is handled specially */ | |
421 | int64_t pagenumber = af_segname_page_number(segname); | |
422 | ||
423 | /* Write the segment to each file */ | |
424 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
425 | current_dest = af_filename(aout->af); | |
426 | if(opt_verbose>1 || opt_debug){ | |
427 | if(aout != afouts.begin()) printf("\n "); | |
428 | printf(" %s -> %s:%s ...", segname,af_filename(aout->af),segname); | |
429 | } | |
430 | ||
431 | /** COPY THE DATA **/ | |
432 | ||
433 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
434 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
435 | int sigmode = AF_SIGNATURE_MODE0; | |
436 | ||
437 | memset(seghash,0,sizeof(seghash)); | |
438 | ||
439 | bool copied = false; | |
440 | ||
441 | /* If we are preening, signing, or building a ToC, we need to copy the raw page */ | |
442 | if(pagenumber>=0 && (opt_preen || opt_sign_key_file)){ | |
443 | if(copy_page(ain,aout->af,pagenumber,arg,seghash,&seghash_len)==0){ | |
444 | preened_pages.push_back(pagenumber); // preened pages won't be verified by md5 | |
445 | if(opt_debug && opt_preen) printf(" (PREENED) "); | |
446 | sigmode = AF_SIGNATURE_MODE1; | |
447 | copied = true; | |
448 | } | |
449 | } | |
450 | ||
451 | /* Copy the page if it is not in the destination */ | |
452 | if(copied==false){ | |
453 | if(!aout->segs.contains(segname)){ | |
454 | if(af_update_seg(aout->af,segname,arg,segbuf,seglen)){ | |
455 | unlink_outfiles(outfiles); | |
456 | err(1,"Cannot write segment '%s' to %s.", segname,af_filename(aout->af)); | |
457 | } | |
458 | ||
459 | #ifdef USE_AFFSIGS | |
460 | if(opt_sign){ | |
461 | aff_bom::make_hash(seghash,arg,segname,segbuf,seglen); | |
462 | } | |
463 | #endif | |
464 | } | |
465 | else{ | |
466 | if(opt_verbose>1 || opt_debug) printf(" [already in %s] ",af_filename(aout->af)); | |
467 | } | |
468 | } | |
469 | #ifdef USE_AFFSIGS | |
470 | if(opt_sign) bom.add(segname,sigmode,seghash,seghash_len); | |
471 | #endif | |
472 | } | |
473 | free(segbuf); | |
474 | current_dest = 0; | |
475 | if(opt_verbose>1 || opt_debug) putchar('\n'); | |
476 | } | |
477 | current_seg = 0; | |
478 | ||
479 | #ifdef USE_AFFSIGS | |
480 | /* For each open file, make an AF_IMAGE_GID if one doesn't exist */ | |
481 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
482 | if(af_make_gid(aout->af)>0){ | |
483 | if(opt_sign){ | |
484 | af_sign_seg(aout->af,AF_IMAGE_GID); // make sure the GID is signed | |
485 | bom.add(aout->af,AF_IMAGE_GID); | |
486 | bom.add(aout->af,AF_IMAGE_GID AF_SIG256_SUFFIX); | |
487 | ||
488 | } | |
489 | } | |
490 | } | |
491 | ||
492 | if(opt_sign){ | |
493 | bom.close(); | |
494 | /* Now write to each of the output files */ | |
495 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
496 | bom.write(aout->af,segments); | |
497 | } | |
498 | } | |
499 | #endif | |
500 | ||
501 | gettimeofday(&t1,0); | |
502 | if(afouts.size()==1){ | |
503 | AFFILE *af = afouts.begin()->af; | |
504 | uint64_t w = af->bytes_written; | |
505 | double sec = ((t1.tv_sec-t0.tv_sec)+(t1.tv_usec-t0.tv_usec)/1000000.0); | |
506 | printf("%s: %"I64d" bytes transfered in %.2f seconds. xfer rate: %.2f MBytes/sec\n", | |
507 | af_filename(af),w,sec,(w/1000000.0) / sec); | |
508 | } | |
509 | ||
510 | if(opt_noverify==0){ | |
511 | current_seg = "VERIFYING"; | |
512 | /* Now verify all of the hashes */ | |
513 | if(opt_verbose || opt_debug) printf("\n\nFiles copied. Verifying...\n"); | |
514 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
515 | ||
516 | const char *segname = seg->name.c_str(); | |
517 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
518 | size_t seglen=0; | |
519 | char b2[1024]; | |
520 | ||
521 | if((aout->af)->v->flag & AF_VNODE_TYPE_RELIABLE){ | |
522 | continue; // no need to verify a reliable write | |
523 | } | |
524 | if(opt_verbose>1 || opt_debug) printf(" verifying %s...\n",segname); | |
525 | ||
526 | again: | |
527 | if(af_get_seg(aout->af,segname,0,0,&seglen)){ | |
528 | if(segname != b2 && | |
529 | segname[0]=='s' && segname[1]=='e' && segname[2]=='g' && | |
530 | isnumber(segname[3])){ | |
531 | /* Looks like a legacy segname name was renamed. | |
532 | * Try the new name | |
533 | */ | |
534 | snprintf(b2,sizeof(b2),"page%s",segname+3); | |
535 | if(opt_verbose) printf(" Couldn't read %s; looking for %s\n", | |
536 | segname,b2); | |
537 | segname = b2; | |
538 | goto again; | |
539 | } | |
540 | unlink_outfiles(outfiles); | |
541 | errx(1,"Cannot read length of segment '%s' in output file %s", | |
542 | segname,af_filename(aout->af)); | |
543 | } | |
544 | int64_t pagenumber = af_segname_page_number(segname); | |
545 | if(find(preened_pages.begin(),preened_pages.end(),pagenumber) !=preened_pages.end()){ | |
546 | /* TK: page pagenumber was preened. | |
547 | * It should probably be checked against the original hash... | |
548 | */ | |
549 | continue; | |
550 | } | |
551 | ||
552 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
553 | if(!segbuf){ | |
554 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
555 | (int)seglen,segname,af_filename(ain)); | |
556 | } | |
557 | unsigned long arg; | |
558 | if(af_get_seg(aout->af,segname,&arg,segbuf,&seglen)){ | |
559 | err(1,"Cannot read segment '%s' in %s", | |
560 | segname,af_filename(aout->af)); | |
561 | } | |
562 | ||
563 | /* Calculate the MD5 of this segment and see if it matches the map. | |
564 | * (But don't do this for preened segments. | |
565 | */ | |
566 | unsigned char md5_read[16]; | |
567 | MD5(segbuf,seglen,md5_read); | |
568 | if(memcmp(hashMap[segname].buf,md5_read,16)!=0){ | |
569 | unlink_outfiles(outfiles); | |
570 | errx(1,"Hash read from %s for segment %s doesn't validate.", | |
571 | af_filename(aout->af),segname); | |
572 | } | |
573 | free(segbuf); // free the buffer | |
574 | } | |
575 | } | |
576 | } | |
577 | ||
578 | /* Finally, close the output files*/ | |
579 | for(outlist::iterator aout = afouts.begin(); aout != afouts.end(); aout++){ | |
580 | af_close(aout->af); | |
581 | } | |
582 | af_close(ain); | |
583 | if(opt_verbose>1 || opt_debug) printf("==============================\n"); | |
584 | current_source = 0; | |
585 | return 0; | |
586 | } | |
587 | ||
588 | int main(int argc,char **argv) | |
589 | { | |
590 | int ch; | |
591 | ||
592 | setvbuf(stdout,0,_IONBF,0); // turn off buffering on stdout | |
593 | while ((ch = getopt(argc, argv, "vdVxyh?zmX:Lp:P:k:c:n")) != -1) { | |
594 | switch (ch) { | |
595 | case 'v': opt_verbose++; break; | |
596 | case 'd': opt_debug++; break; | |
597 | case 'X': | |
598 | opt_preen =1; | |
599 | opt_X = optarg[0] - '0'; | |
600 | opt_preen_alg_arg = AF_PAGE_COMP_ALG_ZLIB; | |
601 | opt_preen_alg_flag = AF_COMPRESSION_ALG_ZLIB; | |
602 | if(opt_X<0 || opt_X>9) opt_X = AF_COMPRESSION_DEFAULT; | |
603 | break; | |
604 | case 'L': | |
605 | opt_preen=1; | |
606 | opt_preen_alg_arg = AF_PAGE_COMP_ALG_LZMA; | |
607 | opt_preen_alg_flag = AF_COMPRESSION_ALG_LZMA; | |
608 | break; | |
609 | case 'x': opt_x++;break; | |
610 | case 'y': opt_noverify++;break; | |
611 | case 'z': opt_zap++;break; | |
612 | case 'm': opt_missing++;break; | |
613 | case 'n': opt_note++;break; | |
614 | case 'k': | |
615 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
616 | opt_sign_key_file = optarg; | |
617 | if(opt_sign_cert_file==0) opt_sign_cert_file=optarg; | |
618 | opt_sign = true; | |
619 | break; | |
620 | case 'c': | |
621 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
622 | opt_sign_cert_file = optarg; | |
623 | break; | |
624 | case 'V': | |
625 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
626 | exit(0); | |
627 | case 'h': | |
628 | case '?': | |
629 | default: | |
630 | usage(); | |
631 | break; | |
632 | } | |
633 | } | |
634 | argc -= optind; | |
635 | argv += optind; | |
636 | ||
637 | if(argc<2){ // at this point, we need at least two args | |
638 | usage(); | |
639 | } | |
640 | ||
641 | /* We either need both a key file and a cert file, or neither */ | |
642 | if((opt_sign_key_file==0) != (opt_sign_cert_file==0)){ | |
643 | errx(1,"Both a private key and a certificate must be specified."); | |
644 | } | |
645 | ||
646 | /* Find any directories */ | |
647 | vector<string> dirlist; | |
648 | for(int i=argc-1;i>0;i--){ | |
649 | struct stat st; | |
650 | ||
651 | // s3 names that do not end with ".aff" are directories | |
652 | const char *last4 = strlen(argv[i])>4 ? argv[i]+strlen(argv[i])-4 : ""; | |
653 | if(strncmp(argv[i],"s3://",5)==0 && | |
654 | strcmp(last4,".aff")!=0){ | |
655 | dirlist.push_back(argv[i]); | |
656 | argc--; | |
657 | continue; | |
658 | } | |
659 | ||
660 | if(stat(argv[i],&st)!=0) break; // out of directories | |
661 | if((st.st_mode & S_IFMT)!=S_IFDIR) break; // found a non-dir | |
662 | dirlist.push_back(argv[i]); | |
663 | argc--; // ignore the last | |
664 | } | |
665 | ||
666 | /* If I found no directories, then there better just be two values */ | |
667 | if(dirlist.size()==0){ | |
668 | if(argc!=2){ | |
669 | fprintf(stderr,"Please specify a directory or just two AFF files.\n\n"); | |
670 | usage(); | |
671 | } | |
672 | /* Must be copying from file1 to file2. Make sure file2 does not exist */ | |
673 | if(access(argv[1],R_OK)==0){ | |
674 | fprintf(stderr,"File exists: %s\n",argv[1]); | |
675 | if(!opt_zap) exit(1); | |
676 | } | |
677 | ||
678 | vector<string> outfiles; | |
679 | outfiles.push_back(argv[1]); | |
680 | return afcopy(argv[0],outfiles); | |
681 | } | |
682 | ||
683 | /* Loop for each file and each directory */ | |
684 | ||
685 | while(argc--){ | |
686 | /* Open the output files */ | |
687 | vector<string> outfiles; | |
688 | for(u_int i=0;i<dirlist.size();i++){ | |
689 | string outfilename; | |
690 | const char *name = strrchr(*argv,'/'); | |
691 | if(name) name++; | |
692 | else name = *argv; | |
693 | ||
694 | outfilename.append(dirlist[i]); | |
695 | if(outfilename[outfilename.size()-1]!='/') { | |
696 | outfilename.append("/"); | |
697 | } | |
698 | outfilename.append(name); | |
699 | outfiles.push_back(outfilename); | |
700 | } | |
701 | afcopy(argv[0],outfiles); // old outfiles will get GCed | |
702 | argv++; | |
703 | } | |
704 | exit(0); | |
705 | } | |
706 | ||
707 |
0 | /* | |
1 | * afcrypto.cpp: | |
2 | * | |
3 | * command for dealing with encryption issues | |
4 | */ | |
5 | ||
6 | /* Public Domain Software | |
7 | * Simson L. Garfinkel | |
8 | * Naval Postgraduate School | |
9 | * | |
10 | * The software provided here is released by the Naval Postgraduate | |
11 | * School, an agency of the U.S. Department of Navy. The software bears | |
12 | * no warranty, either expressed or implied. NPS does not assume legal | |
13 | * liability nor responsibility for a User's use of the software or the | |
14 | * results of such use. | |
15 | * | |
16 | * Please note that within the United States, copyright protection, under | |
17 | * Section 105 of the United States Code, Title 17, is not available for | |
18 | * any work of the United States Government and/or for any works created | |
19 | * by United States Government employees. | |
20 | */ | |
21 | ||
22 | ||
23 | ||
24 | #include "affconfig.h" | |
25 | #include "afflib.h" | |
26 | #include "afflib_i.h" | |
27 | #include "utils.h" | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <algorithm> | |
31 | #include <vector> | |
32 | ||
33 | const char *progname = "afcrypto"; | |
34 | #define DEFAULT_PASSPHRASE_FILE ".affpassphrase" | |
35 | int opt_debug = 0; | |
36 | int opt_verbose = 0; | |
37 | int opt_just_print_encrypted_count = 0; | |
38 | int opt_just_print_unencrypted_count = 0; | |
39 | char *opt_unsealing_private_key_file= 0; | |
40 | int opt_xml = 0; | |
41 | ||
42 | void change_passphrase(const char *fn,const char *old_passphrase,const char *new_passphrase) | |
43 | { | |
44 | int fail = 0; | |
45 | ||
46 | AFFILE *af = af_open(fn,O_RDWR,0666); | |
47 | if(!af) af_err(1,fn); | |
48 | if(af_change_aes_passphrase(af,old_passphrase,new_passphrase)){ | |
49 | warnx("%s: af_change_aes_passphrase failed",fn); | |
50 | fail = 1; | |
51 | } | |
52 | af_close(af); | |
53 | if(!fail) printf("%s: passphrase changed.\n",fn); | |
54 | } | |
55 | ||
56 | void get_and_change_passphrase(const char *fn) | |
57 | { | |
58 | char old_passphrase[1024]; | |
59 | char new_passphrase[1024]; | |
60 | ||
61 | memset(old_passphrase,0,sizeof(old_passphrase)); | |
62 | memset(new_passphrase,0,sizeof(new_passphrase)); | |
63 | ||
64 | printf("Enter old passphrase: "); | |
65 | if(fgets(old_passphrase,sizeof(old_passphrase),stdin)==0) return; | |
66 | char *cc = strchr(old_passphrase,'\n');if(cc) *cc='\000'; | |
67 | ||
68 | /* See if this passphrase works*/ | |
69 | ||
70 | AFFILE *af = af_open(fn,O_RDONLY,0666); | |
71 | if(!af) af_err(1,fn); | |
72 | if(af_use_aes_passphrase(af,old_passphrase)){ | |
73 | errx(1,"passphrase incorrect"); | |
74 | } | |
75 | af_close(af); | |
76 | ||
77 | printf("Enter new passphrase: "); | |
78 | if(fgets(new_passphrase,sizeof(new_passphrase),stdin)==0) return; | |
79 | cc = strchr(new_passphrase,'\n');if(cc) *cc='\000'; | |
80 | change_passphrase(fn,old_passphrase,new_passphrase); | |
81 | } | |
82 | ||
83 | void usage() | |
84 | { | |
85 | printf("afcrypto version %s\n",PACKAGE_VERSION); | |
86 | printf("usage: afcrypto [options] filename.aff [filename2.aff ... ]\n"); | |
87 | printf(" prints if each file is encrypted or not.\n"); | |
88 | printf("options:\n"); | |
89 | printf(" -x --- output in XML\n"); | |
90 | printf(" -j --- Just print the number of encrypted segments\n"); | |
91 | printf(" -J --- Just print the number of unencrypted segments\n"); | |
92 | ||
93 | printf("\nData conversion options:\n"); | |
94 | printf(" -e --- encrypt the unencrypted non-signature segments\n"); | |
95 | printf(" -d --- decrypt the encrypted non-signature segments\n"); | |
96 | printf(" -r --- change passphrase (take old and new from stdin)\n"); | |
97 | printf(" -O old --- specify old passphrase\n"); | |
98 | printf(" -N new --- specify new passphrase\n"); | |
99 | printf(" -K mykey.key -- specifies a private keyfile for unsealing (may not be repeated)\n"); | |
100 | printf(" -C mycert.crt -- specifies a certificate file for sealing (may be repeated)\n"); | |
101 | printf(" -S --- add symmetric encryptiong (passphrase) to AFFILE encrypted with public key\n"); | |
102 | printf(" (requires a private key and a specified passphrase).\n"); | |
103 | printf(" -A --- add asymmetric encryption to a AFFILE encrypted with a passphrase\n"); | |
104 | printf(" (requires a certificate file spcified with the -C option\n"); | |
105 | ||
106 | ||
107 | printf("\nPassword Cracking Options:\n"); | |
108 | printf(" -p passphrase --- checks to see if passphrase is the passphrase of the file\n"); | |
109 | printf(" exit code is 0 if it is, -1 if it is not\n"); | |
110 | printf(" -k --- attempt to crack passwords by reading a list of passwords from ~/.affpassphrase\n"); | |
111 | printf(" -f file --- Crack passwords but read them from file.\n"); | |
112 | ||
113 | printf("\nDebugging:\n"); | |
114 | printf(" -V --- Just print the version number and exit.\n"); | |
115 | printf(" -D --- debug; print out each key as it is tried\n"); | |
116 | printf(" -l --- List the installed hash and encryption algorithms \n"); | |
117 | printf("Note: This program ignores the environment variables:\n"); | |
118 | puts(AFFLIB_PASSPHRASE); | |
119 | puts(AFFLIB_PASSPHRASE_FILE); | |
120 | puts(AFFLIB_PASSPHRASE_FD); | |
121 | puts(AFFLIB_DECRYPTING_PRIVATE_KEYFILE); | |
122 | exit(0); | |
123 | } | |
124 | ||
125 | /* Try each of the passphrases in the file against the passphrase. If it is found, return it. */ | |
126 | char *check_file(AFFILE *af,const char *passphrase_file) | |
127 | { | |
128 | char *ret = 0; | |
129 | FILE *f = fopen(passphrase_file,"r"); | |
130 | if(!f) return 0; | |
131 | ||
132 | char buf[1024]; | |
133 | memset(buf,0,sizeof(buf)); | |
134 | while(fgets(buf,sizeof(buf)-1,f)){ | |
135 | char *cc = strchr(buf,'\n'); | |
136 | if(cc) *cc = 0; | |
137 | if(opt_debug){ | |
138 | if(opt_debug) printf("checking with '%s' ... ",buf); | |
139 | fflush(stdout); | |
140 | } | |
141 | int r= af_use_aes_passphrase(af,buf); | |
142 | if(r==0){ | |
143 | if(opt_debug) printf("YES!\n"); | |
144 | ret = strdup(buf); | |
145 | break; | |
146 | } | |
147 | } | |
148 | fclose(f); | |
149 | return ret; | |
150 | } | |
151 | ||
152 | /** | |
153 | * This will eventually decrypt non-signature segments that are | |
154 | * encrypted | |
155 | * | |
156 | * @param af - the AFFILE to open | |
157 | * @param count - The number of pages actually encrypted | |
158 | */ | |
159 | int af_decrypt_encrypted_segments(AFFILE *af, int *count, int mode) | |
160 | { | |
161 | af_set_option(af,AF_OPTION_AUTO_ENCRYPT,0); | |
162 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); // turn off auto decryption | |
163 | aff::seglist sl(af); // get the list of the segments | |
164 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,1); // turn auto decryption back on | |
165 | for(aff::seglist::const_iterator si = sl.begin();si!=sl.end();si++){ | |
166 | if(opt_debug) printf(" checking segment %s",si->name.c_str()); | |
167 | if(af_is_encrypted_segment(si->name.c_str())){ | |
168 | ||
169 | if(mode == O_RDONLY){ // if readonly, just tally | |
170 | (*count) ++; | |
171 | if(opt_debug) printf(" would decrypt segment\n"); | |
172 | continue; | |
173 | } | |
174 | ||
175 | /* Generate the name of the unencrypted segment */ | |
176 | char segname[AF_MAX_NAME_LEN]; | |
177 | strcpy(segname,si->name.c_str()); | |
178 | char *cc = strstr(segname,AF_AES256_SUFFIX); | |
179 | if(!cc){ | |
180 | if(opt_debug) printf(" will not decrypt AFFKEY segments; will be deleted later.\n"); | |
181 | continue; // something is wrong; can't find the /aes256 | |
182 | } | |
183 | *cc = '\000'; // truncate off the /aes256 | |
184 | ||
185 | /* Get the segment and put it, which will force the decryption to take place */ | |
186 | if(opt_debug) printf(" decrypting segment\n"); | |
187 | u_char *buf = (u_char *)malloc(si->len); | |
188 | if(!buf) warn("malloc(%zd) failed", si->len); | |
189 | else { | |
190 | unsigned long arg; | |
191 | size_t datalen = si->len; | |
192 | if(af_get_seg(af,segname,&arg,buf,&datalen)){ | |
193 | warn("Could not read segment '%s'",segname); | |
194 | } | |
195 | else{ | |
196 | /* si->datalen >= datalen. | |
197 | * si->datalen is the length of the encrypted segment. | |
198 | * datalen is the length of the decrypted segment. | |
199 | */ | |
200 | assert(si->len >= datalen); | |
201 | assert(si->arg==arg); | |
202 | if(af_update_seg(af,segname,arg,buf,datalen)){ | |
203 | warn("Could not decrypt segment '%s'",si->name.c_str()); | |
204 | } else { | |
205 | (*count) ++; | |
206 | } | |
207 | } | |
208 | free(buf); | |
209 | } | |
210 | } else { | |
211 | if(opt_debug) printf(" not encrypted\n"); | |
212 | } | |
213 | } | |
214 | /* Delete the AF_AFFKEY segment */ | |
215 | if(af_get_seg(af,AF_AFFKEY,0,0,0)==0) af_del_seg(af,AF_AFFKEY); | |
216 | /* Delete all of the EVP segments */ | |
217 | for(int i=0;;i++){ | |
218 | char segname[1024]; | |
219 | snprintf(segname,sizeof(segname),AF_AFFKEY_EVP,i); | |
220 | if(af_get_seg(af,segname,0,0,0)!=0) break; // found the last segment | |
221 | if(af_del_seg(af,segname)) warn("Cannot delete segment %s",segname); | |
222 | } | |
223 | return 0; | |
224 | } | |
225 | ||
226 | ||
227 | /** | |
228 | * Encrypts the non-signature segments that are not encrypted. | |
229 | * There is no reason to encrypt the signature segments. | |
230 | * | |
231 | * @param af - the AFFILE to open | |
232 | * @param count - The number of pages actually encrypted | |
233 | */ | |
234 | ||
235 | int af_encrypt_unencrypted_nonsignature_segments(AFFILE *af,int *count,int mode) | |
236 | { | |
237 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); // do not automatically decrypt | |
238 | aff::seglist sl(af); | |
239 | for(aff::seglist::const_iterator si = sl.begin();si!=sl.end();si++){ | |
240 | if(si->name == AF_AFFKEY) continue; // don't encrypt the affkey! | |
241 | if(strstr(si->name.c_str(),"affkey_evp")) continue; | |
242 | if(!af_is_encrypted_segment(si->name.c_str()) && | |
243 | !af_is_signature_segment(si->name.c_str())){ | |
244 | ||
245 | if(mode == O_RDONLY){ // if readonly, just tally | |
246 | (*count) ++; | |
247 | continue; | |
248 | } | |
249 | ||
250 | /* Get the segment and put it, which will force the encryption to take place */ | |
251 | if(opt_debug) printf(" encrypting segment %s\n",si->name.c_str()); | |
252 | u_char *buf = (u_char *)malloc(si->len); | |
253 | if(!buf) warn("Cannot encrypt segment '%s' --- too large (%zd bytes) --- malloc failed", | |
254 | si->name.c_str(),si->len); | |
255 | else { | |
256 | unsigned long arg; | |
257 | size_t datalen = si->len; | |
258 | if(af_get_seg(af,si->name.c_str(),&arg,buf,&datalen)){ | |
259 | warn("Could not read segment '%s'",si->name.c_str()); | |
260 | } | |
261 | else{ | |
262 | /* make sure that what we read is what we thought we were going to read */ | |
263 | assert(si->len==datalen); | |
264 | assert(si->arg==arg); | |
265 | if(af_update_seg(af,si->name.c_str(),arg,buf,datalen)){ | |
266 | warn("Could not encrypt segment '%s'",si->name.c_str()); | |
267 | } else { | |
268 | (*count) ++; | |
269 | } | |
270 | } | |
271 | free(buf); | |
272 | } | |
273 | } else { | |
274 | if(opt_debug) printf(" already encrypted or signed: %s\n",si->name.c_str()); | |
275 | } | |
276 | } | |
277 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,1); // go back to automatically decrypting | |
278 | return 0; | |
279 | } | |
280 | ||
281 | void list_openssl_hashes() | |
282 | { | |
283 | const char *digests[] = {"md5","sha1","sha256",0}; | |
284 | OpenSSL_add_all_algorithms(); | |
285 | for(int i=0;digests[i];i++){ | |
286 | printf("OpenSSL has %s: %s\n",digests[i],EVP_get_digestbyname(digests[i]) ? "YES" : "NO"); | |
287 | } | |
288 | exit(0); | |
289 | } | |
290 | ||
291 | int main(int argc,char **argv) | |
292 | { | |
293 | int bflag, ch; | |
294 | const char *old_passphrase=0; | |
295 | const char *new_passphrase=0; | |
296 | const char *check_passphrase = 0; | |
297 | char *passphrase_file = 0; | |
298 | const char *progname = argv[0]; | |
299 | int opt_encrypt = 0; | |
300 | int opt_decrypt = 0; | |
301 | int opt_add_passphrase_to_public_key = 0; | |
302 | int opt_add_public_key_to_passphrase = 0; | |
303 | ||
304 | int mode = O_RDONLY; // mode for opening AFF file | |
305 | const char **certificates = (const char **)malloc(0); | |
306 | int num_certificates = 0; | |
307 | const char *envvars[] = {AFFLIB_PASSPHRASE,AFFLIB_PASSPHRASE_FILE,AFFLIB_PASSPHRASE_FD, | |
308 | AFFLIB_DECRYPTING_PRIVATE_KEYFILE,0}; | |
309 | for(int i=0;envvars[i];i++){ | |
310 | /* Don't use auto-supplied passphrases */ | |
311 | #ifdef HAVE_UNSETENV | |
312 | unsetenv(envvars[i]); | |
313 | #else | |
314 | if(getenv(envvars[i])){ | |
315 | fprintf(stderr,"Please unset %s and restart\n",envvars[i]); | |
316 | exit(1); | |
317 | } | |
318 | #endif | |
319 | } | |
320 | ||
321 | bflag = 0; | |
322 | int opt_change = 0; | |
323 | const char *home = getenv("HOME"); | |
324 | ||
325 | while ((ch = getopt(argc, argv, "zreC:SAO:N:p:f:kdDh?VK:vljJx:")) != -1) { | |
326 | switch (ch) { | |
327 | case 'x': opt_xml = 1; break; | |
328 | case 'j': opt_just_print_encrypted_count =1;break; | |
329 | case 'J': opt_just_print_unencrypted_count =1;break; | |
330 | ||
331 | /* These options make the mode read-write */ | |
332 | case 'r': opt_change = 1; mode = O_RDWR; break; | |
333 | case 'e': opt_encrypt = 1; mode = O_RDWR; break; | |
334 | case 'd': opt_decrypt = 1; mode = O_RDWR; break; | |
335 | case 'S': opt_add_passphrase_to_public_key = 1; mode = O_RDWR; break; | |
336 | case 'A': opt_add_public_key_to_passphrase = 1; mode = O_RDWR; break; | |
337 | /* These just set up variables */ | |
338 | case 'C': | |
339 | certificates = (const char **)realloc(certificates,sizeof(int *)*(num_certificates+1)); | |
340 | certificates[num_certificates] = optarg; | |
341 | num_certificates++; | |
342 | break; | |
343 | case 'K': opt_unsealing_private_key_file = optarg;break; | |
344 | case 'O': old_passphrase = optarg;break; | |
345 | case 'N': new_passphrase = optarg;break; | |
346 | case 'p': check_passphrase = optarg;break; | |
347 | case 'f': passphrase_file = optarg;break; | |
348 | case 'k': | |
349 | if(!home) home = "/"; | |
350 | passphrase_file = (char *)malloc(strlen(home)+strlen(DEFAULT_PASSPHRASE_FILE)+2); | |
351 | strcpy(passphrase_file,home); | |
352 | strcat(passphrase_file,"/"); | |
353 | strcat(passphrase_file,DEFAULT_PASSPHRASE_FILE); | |
354 | break; | |
355 | case 'D': opt_debug = 1;break; | |
356 | case 'v': opt_verbose = 1;break; | |
357 | case 'l': list_openssl_hashes(); exit(0); | |
358 | case 'h': | |
359 | case '?': | |
360 | default: | |
361 | usage(); | |
362 | break; | |
363 | case 'V': | |
364 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
365 | exit(0); | |
366 | } | |
367 | } | |
368 | argc -= optind; | |
369 | argv += optind; | |
370 | if(argc<1){ | |
371 | fprintf(stderr,"No image file specified\n"); | |
372 | usage(); | |
373 | } | |
374 | ||
375 | if(opt_just_print_encrypted_count && opt_just_print_unencrypted_count){ | |
376 | errx(1,"Options -j and -J conflict\n"); | |
377 | } | |
378 | ||
379 | if(num_certificates>0 && (opt_encrypt==0 && opt_decrypt==0 && opt_add_public_key_to_passphrase==0)){ | |
380 | errx(1,"Encryption certificates specified but neither -e nor -d option not set. " | |
381 | "What do you want me to do with these certificates? "); | |
382 | } | |
383 | ||
384 | if((check_passphrase || passphrase_file) && opt_encrypt){ | |
385 | err(1,"Sorry, can't both encrypt and password crack. Pick one.\n"); | |
386 | } | |
387 | ||
388 | if(opt_encrypt && (new_passphrase==0 && num_certificates==0) && mode!=O_RDONLY){ | |
389 | err(1,"Currently -e requires that the passphrase be specified on the command line\n" | |
390 | "or that one or more encryption certificates be provided\n"); | |
391 | } | |
392 | ||
393 | while(argc--){ | |
394 | const char *fname = *argv++; | |
395 | ||
396 | if(opt_change){ | |
397 | if(old_passphrase && new_passphrase) change_passphrase(fname,old_passphrase,new_passphrase); | |
398 | else get_and_change_passphrase(fname); | |
399 | } | |
400 | ||
401 | /* Get the information */ | |
402 | AFFILE *af = af_open(fname,mode,0); | |
403 | if(!af) af_err(1,"af_open(%s)",fname); | |
404 | if(af_identify(af)!=AF_IDENTIFY_AFF && af_identify(af)!=AF_IDENTIFY_AFD){ | |
405 | errx(1,"Cannot encrypt %s: %s only supports AFF and AFD files.",af_filename(af),progname); | |
406 | } | |
407 | ||
408 | if(opt_encrypt && new_passphrase){ | |
409 | int r = af_establish_aes_passphrase(af,new_passphrase); | |
410 | switch(r){ | |
411 | case AF_ERROR_NO_AES: errx(1,"AFFLIB: AES256 not available; cannot continue"); | |
412 | case AF_ERROR_NO_SHA256: errx(1,"AFFLIB: SHA256 not available; cannot continue"); | |
413 | default: err(1,"%s: cannot establish passphrase (error %d)",fname,r); | |
414 | case 0: | |
415 | case AF_ERROR_AFFKEY_EXISTS: | |
416 | /* no matter if we established it or if a phrase already exists, try to use it now */ | |
417 | /* File already has a passphrase; see if this is it. */ | |
418 | break; | |
419 | } | |
420 | r = af_use_aes_passphrase(af,new_passphrase); | |
421 | switch(r){ | |
422 | case 0: break; // everything okay | |
423 | case AF_ERROR_WRONG_PASSPHRASE: errx(1,"%s: wrong passphrase",fname); | |
424 | default: errx(1,"%s: passphrase already established (error %d)",fname,r); | |
425 | } | |
426 | } | |
427 | ||
428 | if(opt_decrypt && old_passphrase){ | |
429 | int r = af_use_aes_passphrase(af, old_passphrase); | |
430 | switch(r){ | |
431 | case 0: printf("Passphrase is good!\n"); break; | |
432 | case AF_ERROR_WRONG_PASSPHRASE: errx(1,"%s: wrong passphrase",fname); | |
433 | } | |
434 | } | |
435 | ||
436 | if (opt_add_public_key_to_passphrase){ | |
437 | if(!num_certificates) errx(1,"You must specify a certificate with the -C option"); | |
438 | if(!check_passphrase) errx(1,"You must specify a passphrase with the -p option"); | |
439 | printf("Attepmting to add public key to AFFILE...\n"); | |
440 | if(af->crypto->sealing_key_set) return AF_ERROR_KEY_SET; // already enabled | |
441 | unsigned char affkey[32]; | |
442 | int r = af_get_aes_key_from_passphrase(af,check_passphrase,affkey); | |
443 | if(r) errx(1, "%s: cannot get aes key. Failed to add Public Key", fname); | |
444 | af_seal_affkey_using_certificates(af, certificates, num_certificates, affkey); | |
445 | printf("...Public key added successfully.\n"); | |
446 | } | |
447 | ||
448 | if(opt_encrypt && num_certificates){ | |
449 | if(af_set_seal_certificates(af,certificates,num_certificates)){ | |
450 | errx(1,"%s: can't set encryption certificate%s",fname,num_certificates==1 ? "" : "s"); | |
451 | } | |
452 | } | |
453 | if(opt_encrypt){ | |
454 | int count = 0; | |
455 | if(af_encrypt_unencrypted_nonsignature_segments(af,&count,mode)){ | |
456 | errx(1,"%s: can't encrypt unsigned, unencrypted segments",fname); | |
457 | } | |
458 | if(mode==O_RDONLY){ // if it is readonly just print the number of segments that would be changed. | |
459 | printf("%d\n",count); | |
460 | af_close(af); | |
461 | continue; | |
462 | } | |
463 | } | |
464 | if(opt_decrypt){ | |
465 | int count = 0; | |
466 | if(af_decrypt_encrypted_segments(af, &count, mode)){ | |
467 | } | |
468 | if(mode==O_RDONLY){ | |
469 | printf("%d\n",count); | |
470 | af_close(af); | |
471 | continue; | |
472 | } | |
473 | } | |
474 | ||
475 | if(opt_add_passphrase_to_public_key) { | |
476 | if(!new_passphrase) errx(1,"You must specify a new passphrase with the -N option"); | |
477 | printf("Attempting to add passphrase...\n"); | |
478 | u_char affkey[32]; | |
479 | if(af_get_affkey_using_keyfile(af, opt_unsealing_private_key_file,affkey)){ | |
480 | errx(1,"%s: cannot unseal AFFKEY",fname); | |
481 | } | |
482 | if(af_save_aes_key_with_passphrase(af,new_passphrase,affkey)){ | |
483 | af_err(1,"%s: could not set the passphrase",fname); | |
484 | } | |
485 | printf("... new passphrase established.\n"); | |
486 | } | |
487 | ||
488 | ||
489 | af_vnode_info vni; | |
490 | memset(&vni,0,sizeof(vni)); | |
491 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed: ",fname); | |
492 | const char *the_passphrase = 0; // the correct passphrase | |
493 | ||
494 | if(opt_just_print_encrypted_count){ | |
495 | printf("%d\n",vni.segment_count_encrypted); | |
496 | af_close(af); | |
497 | continue; | |
498 | } | |
499 | ||
500 | if(opt_just_print_unencrypted_count){ | |
501 | printf("%d\n",vni.segment_count_total-vni.segment_count_encrypted); | |
502 | af_close(af); | |
503 | continue; | |
504 | } | |
505 | ||
506 | ||
507 | /* were we supposed to try a check_passphrase? */ | |
508 | if(check_passphrase){ | |
509 | if(af_use_aes_passphrase(af,check_passphrase)==0){ | |
510 | the_passphrase = check_passphrase; | |
511 | } | |
512 | af_use_aes_passphrase(af,0); // clear the passphrase | |
513 | } | |
514 | ||
515 | /* Is a passphrase file provided? */ | |
516 | if(!the_passphrase && passphrase_file){ | |
517 | the_passphrase = check_file(af,passphrase_file); | |
518 | if(the_passphrase){ | |
519 | af_use_aes_passphrase(af,0); // clear the passphrase | |
520 | } | |
521 | } | |
522 | ||
523 | if(opt_xml){ | |
524 | /* This should be replaced with our xml.cpp object */ | |
525 | printf("<afcrypto>\n"); | |
526 | printf(" <image_filename>%s</image_filename>\n",fname); | |
527 | printf(" <segment_count_total>%d</segment_count_total>\n",vni.segment_count_total); | |
528 | printf(" <segment_count_signed>%d</segment_count_signed>\n",vni.segment_count_signed); | |
529 | printf(" <segment_count_encrypted>%d</segment_count_encrypted>\n",vni.segment_count_encrypted); | |
530 | printf(" <page_count_total>%d</page_count_total>\n",vni.page_count_total); | |
531 | printf(" <page_count_encrypted>%d</page_count_encrypted>\n",vni.page_count_encrypted); | |
532 | if(the_passphrase){ | |
533 | printf(" <passphrase correct='1'>%s</passphrase>\n",the_passphrase); | |
534 | } | |
535 | printf("</afcrypto>\n"); | |
536 | } | |
537 | else{ | |
538 | /* re-run vstat because counts may have changed */ | |
539 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed: ",fname); | |
540 | printf("%s: %5d segments; %5d signed; %5d encrypted; %5d pages; %5d encrypted pages", | |
541 | fname,vni.segment_count_total,vni.segment_count_signed,vni.segment_count_encrypted, | |
542 | vni.page_count_total,vni.page_count_encrypted ); | |
543 | if(the_passphrase) printf("passphrase correct (\"%s\")",the_passphrase); | |
544 | putchar('\n'); | |
545 | } | |
546 | af_close(af); | |
547 | } | |
548 | return(0); | |
549 | } |
0 | /* | |
1 | * afdiskprint.cpp: | |
2 | * | |
3 | * Creates a diskprint AFF structure | |
4 | */ | |
5 | ||
6 | /* | |
7 | * PUBLIC DOMAIN | |
8 | * By Simson L. Garfinkel | |
9 | * | |
10 | * The software provided here is released by the Naval Postgraduate | |
11 | * School (NPS), an agency of the U.S. Department of Navy.The software | |
12 | * bears no warranty, either expressed or implied. NPS does not assume | |
13 | * legal liability nor responsibility for a User's use of the software | |
14 | * or the results of such use. | |
15 | * | |
16 | * Please note that within the United States, copyright protection, | |
17 | * under Section 105 of the United States Code, Title 17, is not | |
18 | * available for any work of the United States Government and/or for | |
19 | * any works created by United States Government employees. User | |
20 | * acknowledges that this software contains work which was created by | |
21 | * NPS employees and is therefore in the public domain and not | |
22 | * subject to copyright. | |
23 | */ | |
24 | ||
25 | ||
26 | #include "affconfig.h" | |
27 | #include "afflib.h" | |
28 | #include "afflib_i.h" | |
29 | #include "base64.h" | |
30 | #include "hashextent.h" | |
31 | ||
32 | #ifdef HAVE_EXPAT | |
33 | ||
34 | #include <openssl/evp.h> | |
35 | ||
36 | #ifdef WIN32 | |
37 | #include "unix4win32.h" | |
38 | #endif | |
39 | ||
40 | #include <vector> | |
41 | #include <string> | |
42 | #include <iostream> | |
43 | #include <sstream> | |
44 | #include <map> | |
45 | #include <set> | |
46 | ||
47 | #ifdef HAVE_CSTRING | |
48 | #include <cstring> | |
49 | #endif | |
50 | ||
51 | const char *hashes[] = {"SHA256","SHA1",0}; // what should we hash? | |
52 | ||
53 | using namespace std; | |
54 | ||
55 | #if HAVE_CTYPE_H | |
56 | #include <ctype.h> | |
57 | #endif | |
58 | ||
59 | #if !defined(HAVE_ISALPHANUM) && defined(HAVE_ISALNUM) | |
60 | #define isalphanum(c) isalnum(c) | |
61 | #endif | |
62 | ||
63 | #if !defined(HAVE_ISALPHANUM) && !defined(HAVE_ISALNUM) | |
64 | #define isalphanum(c) (isalpha(c)||isdigit(c)) | |
65 | #endif | |
66 | ||
67 | #if !defined(O_BINARY) | |
68 | #define O_BINARY 0 | |
69 | #endif | |
70 | ||
71 | const char *progname = "afdiskprint"; | |
72 | const char *xml_special_chars = "<>\r\n&'\""; | |
73 | ||
74 | void usage() | |
75 | { | |
76 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
77 | printf("usage: %s [options] infile \n",progname); | |
78 | printf(" -x XML = Verify the diskprint\n"); | |
79 | printf(" -V = Just print the version number and exit.\n"); | |
80 | printf(" -h = Print this help.\n"); | |
81 | exit(0); | |
82 | } | |
83 | ||
84 | /**************************************************************** | |
85 | ** Support routines... | |
86 | */ | |
87 | ||
88 | /** | |
89 | * Return a random 64-bit number | |
90 | */ | |
91 | uint64_t random64() | |
92 | { | |
93 | return (((uint64_t)random())<<32) | random(); | |
94 | } | |
95 | ||
96 | uint64_t atoi64(const char *buf) | |
97 | { | |
98 | uint64_t ret=0; | |
99 | sscanf(buf,"%"PRIu64,&ret); | |
100 | return ret; | |
101 | } | |
102 | ||
103 | ||
104 | static int *hexcharvals = 0; | |
105 | static void nsrl_bloom_init() | |
106 | { | |
107 | if(hexcharvals==0){ | |
108 | /* Need to initialize this */ | |
109 | int i; | |
110 | hexcharvals = (int *)calloc(sizeof(int),256); | |
111 | for(i=0;i<10;i++){ | |
112 | hexcharvals['0'+i] = i; | |
113 | } | |
114 | for(i=10;i<16;i++){ | |
115 | hexcharvals['A'+i-10] = i; | |
116 | hexcharvals['a'+i-10] = i; | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | ||
122 | /** | |
123 | * Convert a hex representation to binary, and return | |
124 | * the number of bits converted. | |
125 | * @param binbuf output buffer | |
126 | * @param binbuf_size size of output buffer in bytes. | |
127 | * @param hex input buffer (in hex) | |
128 | */ | |
129 | int nsrl_hex2bin(unsigned char *binbuf,size_t hexbuf_size,const char *hex) | |
130 | { | |
131 | int bits = 0; | |
132 | if(hexcharvals==0) nsrl_bloom_init(); | |
133 | while(hex[0] && hex[1] && hexbuf_size>0){ | |
134 | *binbuf++ = ((hexcharvals[(unsigned char)hex[0]]<<4) | | |
135 | hexcharvals[(unsigned char)hex[1]]); | |
136 | hex += 2; | |
137 | bits += 8; | |
138 | hexbuf_size -= 1; | |
139 | } | |
140 | if(hexbuf_size>0) binbuf[0] = 0; // might as well null-terminate if there is room | |
141 | return bits; | |
142 | } | |
143 | ||
144 | ||
145 | ||
146 | /** | |
147 | * Strip an XML string as necessary for a tag name. | |
148 | */ | |
149 | ||
150 | void out_xmlstr(ostream &ostr,int indent,const char *tag,const char *value) | |
151 | { | |
152 | for(int i=0;i<indent;i++) ostr << " "; | |
153 | ostr << "<" << tag << ">"; | |
154 | for(const char *ch=value;*ch;ch++){ | |
155 | if(isprint(*ch) && !strchr(xml_special_chars,*ch)){ | |
156 | ostr << *ch; | |
157 | } | |
158 | } | |
159 | ostr << "</" << tag << ">"; | |
160 | } | |
161 | ||
162 | void out_xmlhex(ostream &ostr,int indent,const char *tag,const char **attribs, | |
163 | unsigned char *md,int len) | |
164 | { | |
165 | for(int i=0;i<indent;i++) ostr << ' '; | |
166 | ostr << "<" << tag << " coding='base16'"; | |
167 | for(int i=0;attribs && attribs[i];i++){ | |
168 | ostr << " "; | |
169 | ostr << attribs[i]; | |
170 | } | |
171 | ostr << ">" << hashextent::bin2hex(md,len) << "</" << tag << ">\n"; | |
172 | } | |
173 | ||
174 | /** | |
175 | * Calculate the disk fingerprint for a spcific file and output it to stdout. | |
176 | * Includes other named segments. | |
177 | * | |
178 | * @param infile the file to process. | |
179 | */ | |
180 | ||
181 | int diskprint(const char *infile) | |
182 | { | |
183 | /** segments to include in output. | |
184 | */ | |
185 | const char *segments[] = {AF_MD5,AF_SHA1,AF_SHA256,AF_CREATOR,AF_CASE_NUM,AF_IMAGE_GID, | |
186 | AF_ACQUISITION_ISO_COUNTRY, | |
187 | AF_ACQUISITION_COMMAND_LINE,AF_ACQUISITION_DATE, | |
188 | AF_ACQUISITION_NOTES,AF_ACQUISITION_TECHNICIAN, | |
189 | AF_BATCH_NAME,AF_BATCH_ITEM_NAME,0}; | |
190 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
191 | if(!af){ | |
192 | warn("%s",infile); | |
193 | return -1; | |
194 | } | |
195 | ||
196 | cout << "<!-- XML generated by " << progname << " version " << PACKAGE_VERSION << " -->\n"; | |
197 | cout << "<diskprint image_filename='" << infile << "'>\n"; | |
198 | ||
199 | /* First handle the imagesize */ | |
200 | int64_t imagesize = af_get_imagesize(af); | |
201 | if(imagesize>0){ | |
202 | char buf[32]; | |
203 | snprintf(buf,sizeof(buf),"%"PRIu64,imagesize); | |
204 | out_xmlstr(cout,2,AF_IMAGESIZE,buf); | |
205 | cout << "\n"; | |
206 | } | |
207 | /* Get sector size and number of sectors */ | |
208 | unsigned long sectorsize=512; // default sectorsize | |
209 | af_get_seg(af,AF_SECTORSIZE,§orsize,0,0); | |
210 | if(sectorsize==0) sectorsize=512; // default sectorsize | |
211 | int64_t sectors = imagesize/sectorsize; | |
212 | if(sectors>0){ | |
213 | char buf[32]; | |
214 | snprintf(buf,sizeof(buf),"%lu",sectorsize); | |
215 | out_xmlstr(cout,2,AF_SECTORSIZE,buf); | |
216 | cout << "\n"; | |
217 | } | |
218 | ||
219 | /* Output specific named segments */ | |
220 | for(int i=0;segments[i];i++){ | |
221 | char buf[65536]; | |
222 | size_t buflen = sizeof(buf); | |
223 | if(af_get_seg(af,segments[i],0,(u_char *)buf,&buflen)==0){ | |
224 | buf[buflen] = 0; // null terminate it | |
225 | if(af_display_as_hex(segments[i])){ | |
226 | out_xmlhex(cout,2,segments[i],0,(u_char *)buf,buflen); | |
227 | } else { | |
228 | out_xmlstr(cout,2,segments[i],buf); | |
229 | } | |
230 | } | |
231 | } | |
232 | ||
233 | /** | |
234 | * The list of segments to hash is defined by: | |
235 | * 1. The first 128K sectors. | |
236 | * 2. The last 128K sectors. | |
237 | * 3. A random set of 64K sectors. | |
238 | */ | |
239 | hashvector hashextents; | |
240 | ||
241 | for(int i=0;i<8;i++){ | |
242 | hashextents.push_back(hashextent(131072*i,131072)); | |
243 | } | |
244 | for(int i=0;i<8;i++){ | |
245 | hashextents.push_back(hashextent(imagesize-131072*(8-i),131072)); | |
246 | } | |
247 | ||
248 | /* Pick some random hashextents as well */ | |
249 | for(int i=0;i<100;i++){ | |
250 | uint64_t sector = random64() % (sectors-128); | |
251 | hashextents.push_back(hashextent(sector*sectorsize,65536)); | |
252 | } | |
253 | ||
254 | /** Sort the segments for maximal seek efficiency. | |
255 | */ | |
256 | sort(hashextents.begin(),hashextents.end(),hashextent::compare); | |
257 | ||
258 | /** Send the hashes to stdout using print_hash. | |
259 | */ | |
260 | cout << " <hashes>\n"; | |
261 | for(hashvector::iterator it=hashextents.begin(); it!=hashextents.end(); it++){ | |
262 | for(int i=0;hashes[i];i++){ | |
263 | if((*it).compute_digest(af,hashes[i])==0){ | |
264 | cout << " " << (*it).toXML() << "\n"; | |
265 | } | |
266 | } | |
267 | } | |
268 | cout << " </hashes>\n"; | |
269 | cout << "</diskprint>\n"; | |
270 | af_close(af); | |
271 | return 0; | |
272 | } | |
273 | ||
274 | ||
275 | /** | |
276 | * Code for reading the hashvector XML structure. | |
277 | */ | |
278 | #include <expat.h> | |
279 | ||
280 | class diskprintReader { | |
281 | public: | |
282 | /* General EXPAT stuff */ | |
283 | XML_Parser parser; | |
284 | bool get_cdata; // this is cdata worth getting | |
285 | string cdata; // the cdata that has been gotten | |
286 | diskprintReader():get_cdata(false),hash(0){ | |
287 | parser = XML_ParserCreate(NULL); | |
288 | XML_SetUserData(parser,this); | |
289 | XML_SetElementHandler(parser,startElement,endElement); | |
290 | XML_SetCharacterDataHandler(parser,cHandler); | |
291 | } | |
292 | int parse(const char *buf,int len) { return XML_Parse(parser, buf, len, 1);} | |
293 | void clear(){ | |
294 | cdata = ""; | |
295 | get_cdata = false; | |
296 | } | |
297 | ||
298 | /* Specific stuff for XML diskprint */ | |
299 | hashextent *hash; // current hash | |
300 | hashvector hashextents; // all discovered hashes | |
301 | /* Turn the static functions into method calls */ | |
302 | static void startElement(void *userData,const char *name,const char **attrs){ | |
303 | ((diskprintReader *)userData)->startElement(name,attrs); | |
304 | } | |
305 | static void endElement(void *userData,const char *name){ | |
306 | ((diskprintReader *)userData)->endElement(name); | |
307 | } | |
308 | static void cHandler(void *userData,const XML_Char *s,int len){ | |
309 | diskprintReader *dh = (diskprintReader *)userData; | |
310 | if(dh->get_cdata) dh->cdata.append(s,len); | |
311 | } | |
312 | void startElement(string name,const char **attrs){ | |
313 | clear(); | |
314 | /* If this is an element that we want, indicate such */ | |
315 | if(name=="hash"){ | |
316 | hash = new hashextent(); | |
317 | for(int i=0;attrs[i];i+=2){ | |
318 | if(strcmp(attrs[i],"coding")==0){ hash->coding = attrs[i+1]; continue;} | |
319 | if(strcmp(attrs[i],"start")==0){ hash->start = atoi64(attrs[i+1]); continue;} | |
320 | if(strcmp(attrs[i],"bytes")==0){ hash->bytes = atoi64(attrs[i+1]); continue;} | |
321 | if(strcmp(attrs[i],"alg")==0){ hash->digest_name = attrs[i+1]; continue;} | |
322 | } | |
323 | get_cdata = true; | |
324 | } | |
325 | } | |
326 | void endElement(const char *name){ | |
327 | if(get_cdata==false) return; // don't care about it. | |
328 | if(!strcmp(name,"hash")){ | |
329 | if(hash->coding=="base16"){ | |
330 | hash->hexdigest = cdata; | |
331 | } | |
332 | hashextents.push_back(*hash); | |
333 | } | |
334 | if(!strcmp(name,"diskprint")){ | |
335 | XML_StopParser(parser,0); // stop the parser | |
336 | return; | |
337 | } | |
338 | get_cdata = false; | |
339 | } | |
340 | }; | |
341 | ||
342 | void diskprint_verify(const char *filename,const char *xmlfile) | |
343 | { | |
344 | AFFILE *af = af_open(filename,O_RDONLY,0); | |
345 | if(!af) err(1,"af_open(%s): ",filename); | |
346 | ||
347 | /* Let's read the XML file */ | |
348 | int fd = open(xmlfile,O_RDONLY|O_BINARY); | |
349 | if(!fd) err(1,"open: %s",xmlfile); | |
350 | struct stat st; | |
351 | if(fstat(fd,&st)) err(1,"stat: %s",xmlfile); | |
352 | char *buf = (char *)malloc(st.st_size+1); | |
353 | if(!buf) err(1,"malloc"); | |
354 | ||
355 | if(read(fd,buf,st.st_size)!=st.st_size) err(1,"cannot read XML file"); | |
356 | buf[st.st_size]=0; // terminate the buffer (not strictly needed) | |
357 | ||
358 | diskprintReader dp; | |
359 | dp.parse(buf,st.st_size); | |
360 | cout << "Number of digests read: "<< dp.hashextents.size() << "\n"; | |
361 | const EVP_MD *strongest = dp.hashextents.strongest_available(); | |
362 | cout << "Strongest hash available: " << EVP_MD_name(strongest) << "\n"; | |
363 | /* Now verify each hash */ | |
364 | int matched=0; | |
365 | int notmatched=0; | |
366 | for(hashvector::iterator it = dp.hashextents.begin(); it!=dp.hashextents.end() && notmatched==0;it++){ | |
367 | if(EVP_MD_name(strongest) == (*it).digest_name){ | |
368 | hashextent &hp = (*it); // hash print | |
369 | hashextent hs(af,hp.digest_name,hp.start,hp.bytes); | |
370 | //cout << "hp: " << hp << "\n"; | |
371 | //cout << "hs: " << hs << "\n"; | |
372 | if(hp==hs){ | |
373 | matched++; | |
374 | } else { | |
375 | notmatched++; | |
376 | } | |
377 | } | |
378 | } | |
379 | if(notmatched){ | |
380 | cout << "Diskprint does not match.\n"; | |
381 | } | |
382 | if(notmatched==0 && matched){ | |
383 | cout << "Diskprint matches.\n"; | |
384 | } | |
385 | if(notmatched==0 && matched==0){ | |
386 | cout << "Cannot verify Diskprint; no available hash functions.\n"; | |
387 | } | |
388 | exit(0); | |
389 | } | |
390 | ||
391 | int main(int argc,char **argv) | |
392 | { | |
393 | int ch; | |
394 | const char *opt_x=0; | |
395 | ||
396 | /* Initialize */ | |
397 | #ifdef HAVE_SRANDOMEDEV | |
398 | srandomdev(); | |
399 | #endif | |
400 | OpenSSL_add_all_digests();/* Dynamically loads the digests */ | |
401 | ||
402 | ||
403 | /* Parse arguments */ | |
404 | while ((ch = getopt(argc, argv, "x:h?V")) != -1) { | |
405 | switch (ch) { | |
406 | case 'h': | |
407 | case '?': | |
408 | default: | |
409 | usage(); | |
410 | break; | |
411 | case 'x': opt_x = optarg; break; | |
412 | case 'V': | |
413 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
414 | exit(0); | |
415 | } | |
416 | } | |
417 | argc -= optind; | |
418 | argv += optind; | |
419 | ||
420 | if(argc!=1){ // currently only generates for one file | |
421 | usage(); | |
422 | } | |
423 | ||
424 | if(opt_x){ | |
425 | diskprint_verify(argv[0],opt_x); | |
426 | return(0); | |
427 | } | |
428 | ||
429 | /* Loop through all of the files */ | |
430 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
431 | printf("<diskprints>\n"); | |
432 | while(*argv){ | |
433 | if(opt_x){ | |
434 | diskprint_verify(*argv,opt_x); | |
435 | } | |
436 | else { | |
437 | diskprint(*argv); | |
438 | } | |
439 | argv++; | |
440 | argc--; | |
441 | } | |
442 | printf("</diskprints>\n"); | |
443 | exit(0); | |
444 | } | |
445 | #else | |
446 | int main(int argc,char **argv) | |
447 | { | |
448 | fprintf(stderr,"afdiskprint requires EXPAT. Cannot continue.\n"); | |
449 | exit(-1); | |
450 | } | |
451 | #endif | |
452 |
0 | /* | |
1 | * afinfo.cpp: | |
2 | * | |
3 | * print information about an aff file | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005--2008 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "utils.h" | |
50 | #include "afflib_i.h" | |
51 | ||
52 | #ifdef USE_S3 | |
53 | #include "s3_glue.h" | |
54 | #endif | |
55 | ||
56 | #include <ctype.h> | |
57 | #include <zlib.h> | |
58 | #include <openssl/md5.h> | |
59 | #include <openssl/sha.h> | |
60 | #include <assert.h> | |
61 | ||
62 | #include <algorithm> | |
63 | #include <cstdlib> | |
64 | #include <vector> | |
65 | #include <string> | |
66 | ||
67 | #ifdef HAVE_CSTRING | |
68 | #include <cstring> | |
69 | #endif | |
70 | ||
71 | using namespace std; | |
72 | ||
73 | #ifdef HAVE_CURSES_H | |
74 | #include <curses.h> | |
75 | #endif | |
76 | ||
77 | #ifdef HAVE_TERM_H | |
78 | #include <term.h> | |
79 | #endif | |
80 | ||
81 | #ifdef HAVE_NCURSES_TERM_H | |
82 | #include <ncurses/term.h> | |
83 | #endif | |
84 | ||
85 | #ifdef WIN32 | |
86 | #include "unix4win32.h" | |
87 | #endif | |
88 | ||
89 | const char *progname = "afinfo"; | |
90 | ||
91 | #define VALIDATE_MD5 0x01 | |
92 | #define VALIDATE_SHA1 0x02 | |
93 | ||
94 | int opt_validate = 0; | |
95 | int opt_info = 1; | |
96 | int opt_all = 0; | |
97 | int opt_wide = 0; | |
98 | int opt_l = 0; | |
99 | unsigned int cols = 80; // default | |
100 | int opt_x = 0; | |
101 | int opt_b = 0; | |
102 | int opt_identify = 1; | |
103 | int opt_verbose = 0; | |
104 | int opt_y = 0; | |
105 | int opt_hexbuf = AF_HEXBUF_SPACE4 | AF_HEXBUF_UPPERCASE; | |
106 | int opt_page_validate = 0; | |
107 | int opt_no_preview = 0; | |
108 | int opt_preview_md5 = 0; | |
109 | int opt_debug = 0; | |
110 | int opt_figure_media = 0; | |
111 | const char *opt_passphrase = 0; | |
112 | ||
113 | vector<string> opt_seglist; // just info these segments | |
114 | bool something_was_decrypted = false; | |
115 | const char *term = 0; | |
116 | ||
117 | ||
118 | /** | |
119 | * select bold on or off | |
120 | */ | |
121 | void bold(int on) | |
122 | { | |
123 | if(!term) return; | |
124 | #if defined(HAVE_LIBNCURSES) | |
125 | #ifdef HAVE_ISATTY | |
126 | if(!isatty(fileno(stdout))) return; | |
127 | #endif | |
128 | if(on) tputs(enter_bold_mode,1,putchar); | |
129 | else tputs(exit_attribute_mode,0,putchar); | |
130 | #endif | |
131 | } | |
132 | ||
133 | /** | |
134 | * select a color. | |
135 | * @param num - 0 is black; 1 red; 2 green; 3 yellow; 4 blue; 5 magenta; 6 cyan; 7 white; | |
136 | */ | |
137 | ||
138 | #define RED 1 | |
139 | #define WHITE 7 | |
140 | ||
141 | void color(int num) | |
142 | { | |
143 | #ifdef HAVE_ISATTY | |
144 | if(!isatty(fileno(stdout))) return; | |
145 | #endif | |
146 | #ifdef HAVE_CURSES_H | |
147 | char *setf = tigetstr((char *)"setf"); | |
148 | if(!setf) setf = tigetstr((char *)"setaf"); | |
149 | if(setf){ | |
150 | putp(tparm(setf,num)); | |
151 | } | |
152 | #endif | |
153 | } | |
154 | ||
155 | ||
156 | void usage() | |
157 | { | |
158 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
159 | printf("usage: %s [options] infile\n",progname); | |
160 | printf(" -a = print ALL segments (normally data segments are suppressed)\n"); | |
161 | printf(" -b = print how many bad blocks in each segment (implies -a)\n"); | |
162 | printf(" -i = identify the files, don't do info on them.\n"); | |
163 | printf(" -w = wide output; print more than 1 line if necessary.\n"); | |
164 | printf(" -s segment = Just print information about 'segment'.\n"); | |
165 | printf(" (may be repeated)\n"); | |
166 | printf(" -m = validate MD5 hash of entire image\n"); | |
167 | printf(" -S = validate SHA1 hash of entire image\n"); | |
168 | printf(" -v = validate the hash of each page (if present)\n"); | |
169 | printf(" -y = don't print segments of lengths 16 and 20 as hex)\n"); | |
170 | printf(" -p<passphrase> = Specify <passphrase> to decrypt file\n"); | |
171 | printf(" -l = Just print the segment names and exit\n"); | |
172 | printf(" -V = Just print the version number and exit.\n"); | |
173 | ||
174 | printf("\nPreview Options:\n"); | |
175 | printf(" -X = no data preview; just print the segment names\n"); | |
176 | printf(" -x = print binary values in hex (default is ASCII)\n"); | |
177 | printf("\nMisc:\n"); | |
178 | printf(" -d = debug\n"); | |
179 | printf(" -A = if infile is a device, print the number of sectors\n"); | |
180 | printf(" and sector size to stdout in XML. Otherwise error\n"); | |
181 | printf("\nCompilation:\n"); | |
182 | printf(" LZMA compression: Enabled\n"); | |
183 | #ifdef USE_LIBEWF | |
184 | printf(" LIBEWF enabled\n"); | |
185 | #endif | |
186 | #ifdef USE_QEMU | |
187 | printf(" QEMU enabled\n"); | |
188 | #endif | |
189 | #ifdef USE_FUSE | |
190 | printf(" FUSE enabled\n"); | |
191 | #endif | |
192 | #ifdef USE_S3 | |
193 | printf(" Amazon S3 enabled\n"); | |
194 | #endif | |
195 | #ifdef HAVE_LIBEXPAT | |
196 | printf(" HAVE_LIBEXPAT "); | |
197 | #endif | |
198 | printf("\n"); | |
199 | ||
200 | if(opt_debug){ | |
201 | for(int i=0;i<9;i++){ | |
202 | color(i);printf("Color %d\n",i);color(7); | |
203 | } | |
204 | } | |
205 | ||
206 | exit(0); | |
207 | } | |
208 | ||
209 | ||
210 | AFFILE *af=0; | |
211 | ||
212 | void sig_info(int arg) | |
213 | { | |
214 | if(af==0) return; | |
215 | printf("Validating %"I64d" of %"I64d"\n", af->pos,af->image_size); | |
216 | } | |
217 | ||
218 | ||
219 | ||
220 | ||
221 | void validate(const char *infile) | |
222 | { | |
223 | af = af_open(infile,O_RDONLY,0); | |
224 | if(!af) af_err(1,infile); | |
225 | switch(af_identify(af)){ | |
226 | case AF_IDENTIFY_AFF: | |
227 | case AF_IDENTIFY_AFM: | |
228 | case AF_IDENTIFY_AFD: | |
229 | break; | |
230 | default: | |
231 | printf("%s is not an AFF file\n",infile); | |
232 | af_close(af); | |
233 | return; | |
234 | } | |
235 | ||
236 | printf("\nValidating "); | |
237 | if(opt_validate & VALIDATE_MD5) printf("MD5 "); | |
238 | if(opt_validate == (VALIDATE_MD5|VALIDATE_SHA1)) printf("and "); | |
239 | if(opt_validate & VALIDATE_SHA1) printf("SHA1 "); | |
240 | printf("hash codes.\n"); | |
241 | ||
242 | ||
243 | #ifdef SIGINFO | |
244 | signal(SIGINFO,sig_info); | |
245 | #endif | |
246 | ||
247 | /* Get a list of all the segments to see if there is a space */ | |
248 | af_rewind_seg(af); | |
249 | char segname[AF_MAX_NAME_LEN]; | |
250 | vector <int> pages; | |
251 | memset(segname,0,sizeof(segname)); | |
252 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,0)==0){ | |
253 | int64_t page_num = af_segname_page_number(segname); | |
254 | if(page_num>=0) pages.push_back(page_num); | |
255 | } | |
256 | ||
257 | if(pages.size()==0){ | |
258 | printf("No pages to validate.\n"); | |
259 | af_close(af); | |
260 | } | |
261 | ||
262 | sort(pages.begin(),pages.end()); | |
263 | vector<int>::iterator i = pages.begin(); | |
264 | int last = *i; | |
265 | i++; | |
266 | for(; i!= pages.end();i++){ | |
267 | if(last+1 != *i){ | |
268 | printf("gap in pages (%d!=%d); %s can't be validated.\n",last+1,*i,infile); | |
269 | af_close(af); | |
270 | return; | |
271 | } | |
272 | last = *i; | |
273 | } | |
274 | ||
275 | /* Set up the hash machinery */ | |
276 | MD5_CTX md5; | |
277 | MD5_Init(&md5); | |
278 | ||
279 | SHA_CTX sha; | |
280 | SHA1_Init(&sha); | |
281 | ||
282 | uint64_t total_bytes = 0; | |
283 | while(!af_eof(af)){ | |
284 | unsigned char buf[65536]; // a decent size | |
285 | size_t bytes = af_read(af,buf,sizeof(buf)); | |
286 | if(bytes==0) break; // reached sparse region of file | |
287 | total_bytes += bytes; | |
288 | if(opt_validate & VALIDATE_MD5) MD5_Update(&md5,buf,bytes); | |
289 | if(opt_validate & VALIDATE_SHA1) SHA1_Update(&sha,buf,bytes); | |
290 | } | |
291 | ||
292 | /* Finish the hash calculations and write to the db */ | |
293 | ||
294 | if(opt_validate & VALIDATE_MD5){ | |
295 | unsigned char md5_stored[16]; | |
296 | size_t md5len = sizeof(md5_stored); | |
297 | unsigned char md5_computed[16]; | |
298 | char buf[256]; | |
299 | ||
300 | MD5_Final(md5_computed,&md5); | |
301 | printf("computed md5: %s\n", | |
302 | af_hexbuf(buf,sizeof(buf),md5_computed,16,opt_hexbuf)); | |
303 | if(af_get_seg(af,AF_MD5,0,md5_stored,&md5len)==0){ | |
304 | printf(" stored md5: %s ", | |
305 | af_hexbuf(buf,sizeof(buf),md5_stored,16,opt_hexbuf)); | |
306 | if(md5len==16 && !memcmp((const char *)md5_stored, | |
307 | (const char *)md5_computed,16)){ | |
308 | printf(" MATCH\n"); | |
309 | } | |
310 | else { | |
311 | printf(" NO MATCH!\n"); | |
312 | } | |
313 | } | |
314 | else { | |
315 | printf("(no MD5 in AFF file)\n"); | |
316 | } | |
317 | } | |
318 | ||
319 | ||
320 | if(opt_validate & VALIDATE_SHA1){ | |
321 | unsigned char sha1_stored[20]; | |
322 | size_t sha1len = sizeof(sha1_stored); | |
323 | unsigned char sha1_computed[20]; | |
324 | char buf[256]; | |
325 | ||
326 | SHA1_Final(sha1_computed,&sha); | |
327 | printf("computed sha1: %s \n",af_hexbuf(buf,sizeof(buf),sha1_computed,20,opt_hexbuf)); | |
328 | if(af_get_seg(af,AF_SHA1,0,sha1_stored,&sha1len)==0){ | |
329 | printf(" stored sha1: %s ",af_hexbuf(buf,sizeof(buf),sha1_stored,20,opt_hexbuf)); | |
330 | if(sha1len==20 && !memcmp((const char *)sha1_stored, | |
331 | (const char *)sha1_computed,20)){ | |
332 | printf(" MATCH\n"); | |
333 | } | |
334 | else { | |
335 | printf(" NO MATCH!\n"); | |
336 | } | |
337 | } | |
338 | else { | |
339 | printf("(no SHA1 in AFF file)\n"); | |
340 | } | |
341 | } | |
342 | ||
343 | af_close(af); | |
344 | } | |
345 | ||
346 | #define OUTLINE_LEN 65536 | |
347 | ||
348 | ||
349 | bool display_as_time(const char *segname) | |
350 | { | |
351 | if(strcmp(segname,AF_ACQUISITION_SECONDS)==0) return true; | |
352 | return false; | |
353 | } | |
354 | ||
355 | bool display_as_hex(const char *segname,int data_len) | |
356 | { | |
357 | if(af_display_as_hex(segname)) return true; | |
358 | if(data_len==16 && strstr(segname,"md5")) return true; | |
359 | if(data_len==20 && strstr(segname,"sha1")) return true; | |
360 | if(opt_x) return true; | |
361 | if(opt_preview_md5) return true; | |
362 | return false; | |
363 | } | |
364 | ||
365 | void badscan(AFFILE *af,int page_number,size_t data_len) | |
366 | { | |
367 | size_t page_size = af->image_pagesize; | |
368 | unsigned char *buf = (unsigned char *)malloc(page_size); | |
369 | if(af_get_page(af,page_number,buf,&page_size)){ | |
370 | err(1,"Could not read page %d",page_number); | |
371 | } | |
372 | printf("page_size = %d\n",(int)page_size); | |
373 | int sectors = 0; | |
374 | int bad_sectors = 0; | |
375 | int funny_sectors = 0; | |
376 | for(unsigned int offset=0;offset<page_size;offset+=af->image_sectorsize){ | |
377 | sectors++; | |
378 | if(af_is_badsector(af,buf+offset)){ | |
379 | bad_sectors ++; | |
380 | continue; | |
381 | } | |
382 | #ifdef __FreeBSD__ | |
383 | /* Look for the part of the bad flag that we know and love */ | |
384 | if(strnstr((char *)buf+offset,"BAD SECTOR",af->image_sectorsize)){ | |
385 | funny_sectors++; | |
386 | continue; | |
387 | } | |
388 | #endif | |
389 | } | |
390 | printf(" sectors scanned: %d bad: %d ", sectors,bad_sectors); | |
391 | if(funny_sectors){ | |
392 | printf("suspicious: %d ",funny_sectors); | |
393 | } | |
394 | printf("\n"); | |
395 | free(buf); | |
396 | } | |
397 | ||
398 | ||
399 | /* print_info: | |
400 | * Print the info on a given segment name | |
401 | */ | |
402 | void print_info(AFFILE *af,const char *segname) | |
403 | { | |
404 | unsigned long arg; | |
405 | unsigned char *data = 0; | |
406 | int dots = 0; | |
407 | u_int display_len = 0; | |
408 | char *cc = 0; | |
409 | ||
410 | /* Check to see if this is a null page. */ | |
411 | if(segname[0]==0 && opt_all==0){ | |
412 | return; | |
413 | } | |
414 | if(segname[0]=='[' && opt_all){ | |
415 | puts(segname); | |
416 | return; | |
417 | } | |
418 | ||
419 | /* Check to see if this is a data page */ | |
420 | int64_t page_num = af_segname_page_number(segname); | |
421 | ||
422 | size_t data_len = 0; | |
423 | /* First find out how big the segment is, then get the data */ | |
424 | if(af_get_seg(af,segname,&arg,0,&data_len)){ | |
425 | printf("%-25s SEGMENT NOT FOUND\n",segname); | |
426 | return; | |
427 | } | |
428 | ||
429 | /* is this an encrypted segment that I have decrypted? | |
430 | * Turn off automatic decryption and see if I can get it again... | |
431 | * If we can get it again, then it wasn't decrypted. | |
432 | */ | |
433 | int prev = af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); | |
434 | bool was_decrypted = ( af_get_seg(af,segname,0,0,0)!=0) ; | |
435 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,prev); | |
436 | ||
437 | if(was_decrypted){ | |
438 | bold(1); | |
439 | something_was_decrypted = true; // print key at bottom | |
440 | } | |
441 | ||
442 | /* Start the output line */ | |
443 | char output_line[OUTLINE_LEN]; | |
444 | memset(output_line,0,sizeof(output_line)); | |
445 | ||
446 | /* Now append the arg and the data len */ | |
447 | sprintf(output_line,"%-24s %8ld %8zd ",segname,arg,data_len); | |
448 | ||
449 | if(opt_no_preview){ | |
450 | printf("%s\n",output_line); | |
451 | goto done; | |
452 | } | |
453 | ||
454 | data = (unsigned char *)malloc(data_len); | |
455 | if(af_get_seg(af,segname,0,data,&data_len)){ | |
456 | warn("af_get_seg_2 failed: segname=%s data_len=%zd",segname,data_len); | |
457 | goto done; | |
458 | } | |
459 | ||
460 | /* Special handling of values that should be displayed as time */ | |
461 | if(display_as_time(segname)){ | |
462 | int hours = arg / 3600; | |
463 | int minutes = (arg / 60) % 60; | |
464 | int seconds = arg % 60; | |
465 | printf("%s= %02d:%02d:%02d (hh:mm:ss)\n",output_line,hours,minutes,seconds); | |
466 | goto done; | |
467 | } | |
468 | ||
469 | /* Special handling of quadwords that should be printed as such? */ | |
470 | if(((arg == AF_SEG_QUADWORD) && (data_len==8)) || af_display_as_quad(segname)){ | |
471 | /* Print it as a 64-bit value. | |
472 | * The strcmp is there because early AF_IMAGESIZE segs didn't set | |
473 | * AF_SEG_QUADWORD... | |
474 | */ | |
475 | switch(data_len){ | |
476 | case 8: | |
477 | printf("%s= %"I64d" (64-bit value)\n", | |
478 | output_line,af_decode_q(data)); | |
479 | break; | |
480 | case 0: | |
481 | printf("%s= 0 (0-length segment)\n",output_line); | |
482 | break; | |
483 | default: | |
484 | printf("%s= CANNOT DECODE %d byte segment\n",output_line,(int)data_len); | |
485 | } | |
486 | goto done; | |
487 | } | |
488 | ||
489 | ||
490 | /* See if I need to truncate */ | |
491 | display_len = data_len; | |
492 | if(opt_wide==0 && data_len>32){ // don't bother showing more than first 32 bytes | |
493 | dots = 1; | |
494 | display_len = 32; | |
495 | } | |
496 | ||
497 | cc = output_line + strlen(output_line); | |
498 | ||
499 | if(opt_preview_md5){ | |
500 | u_char md5[32]; | |
501 | MD5(data,data_len,md5); | |
502 | memcpy(data,md5,32); | |
503 | data_len = 32; | |
504 | } | |
505 | if(display_as_hex(segname,display_len)){ | |
506 | char buf[80]; | |
507 | snprintf(cc,sizeof(output_line)-strlen(output_line), | |
508 | "%s%s",af_hexbuf(buf,sizeof(buf),data,display_len,opt_hexbuf), | |
509 | dots ? "..." : ""); | |
510 | /* Special code for SHA1 */ | |
511 | if(!opt_wide && strcmp(segname,AF_SHA1)==0){ | |
512 | int r = fwrite(output_line,1,82,stdout); | |
513 | if(r!=82) fprintf(stderr,"fwrite(output_line,1,82,stdout) returned %d\n",r); | |
514 | printf("\n%62s\n",output_line+82); | |
515 | goto done; | |
516 | } | |
517 | } | |
518 | else { | |
519 | /* Fill it out with some printable data */ | |
520 | unsigned int i; | |
521 | if(display_len > sizeof(output_line)-strlen(output_line)){ | |
522 | display_len = sizeof(output_line)-strlen(output_line); | |
523 | } | |
524 | for(i=0;i<display_len;i++){ | |
525 | *cc = data[i]; | |
526 | if(isprint(*cc)==0) *cc='.'; | |
527 | if(*cc=='\n' || *cc=='\r') *cc=' '; | |
528 | cc++; | |
529 | } | |
530 | *cc = 0; | |
531 | } | |
532 | ||
533 | /* Now print the results... */ | |
534 | if(!opt_wide){ | |
535 | if(strlen(output_line)>cols){ | |
536 | output_line[cols-4] = '.'; | |
537 | output_line[cols-3] = '.'; | |
538 | output_line[cols-2] = '.'; | |
539 | output_line[cols-1] = '\000'; | |
540 | } | |
541 | } | |
542 | fputs(output_line,stdout); | |
543 | if(page_num>=0 && opt_b){ | |
544 | badscan(af,page_num,data_len); | |
545 | } | |
546 | if(opt_page_validate && page_num>=0){ | |
547 | /* Get the page again; this may involve decompression */ | |
548 | unsigned char *page_data = (unsigned char *)malloc(af->image_pagesize); | |
549 | size_t page_data_len = af->image_pagesize; | |
550 | if(af_get_page(af,page_num,page_data,&page_data_len)){ | |
551 | printf("** COULD NOT READ UNCOMPRESSED PAGE "); | |
552 | goto skip1; | |
553 | } | |
554 | ||
555 | char hash_segname[32]; | |
556 | unsigned char hash_buf[16]; | |
557 | unsigned char hash_calc[16]; | |
558 | size_t hash_len = sizeof(hash_buf); | |
559 | snprintf(hash_segname,sizeof(hash_segname),AF_PAGE_MD5,page_num); | |
560 | printf(" "); | |
561 | if(af_get_seg(af,hash_segname,0,hash_buf,&hash_len)){ | |
562 | printf("** NO SEGMENT %s ** ",hash_segname); | |
563 | goto skip1; | |
564 | } | |
565 | ||
566 | MD5(page_data,page_data_len,hash_calc); | |
567 | if(memcmp(hash_buf,hash_calc,sizeof(hash_buf))!=0){ | |
568 | char hb[32]; | |
569 | printf("** HASH INVALID **\n%30s Calculated %s\n","", | |
570 | af_hexbuf(hb,sizeof(hb),hash_calc,16,opt_hexbuf)); | |
571 | printf("%30s Wanted %s ","",af_hexbuf(hb,sizeof(hb),hash_buf,16,opt_hexbuf)); | |
572 | printf("data_len=%d\n",(int)data_len); | |
573 | } else{ | |
574 | printf("HASH OK "); | |
575 | } | |
576 | free(page_data); | |
577 | } | |
578 | skip1:; | |
579 | putchar('\n'); | |
580 | done: | |
581 | if(data) free(data); | |
582 | bold(0); // make sure bold is off | |
583 | ||
584 | //color(WHITE); // make sure we are back to normal color | |
585 | } | |
586 | ||
587 | ||
588 | /* Print the information on a specific file. */ | |
589 | int info_file(const char *infile) | |
590 | { | |
591 | unsigned long total_segs = 0; | |
592 | unsigned long total_pages = 0; | |
593 | unsigned long total_hashes = 0; | |
594 | unsigned long total_signatures =0; | |
595 | unsigned long total_nulls = 0; | |
596 | struct af_vnode_info vni; | |
597 | ||
598 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
599 | if(!af) af_err(1,"Cannot open %s",infile); | |
600 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed",infile); | |
601 | ||
602 | if(opt_l){ | |
603 | /* Just list the segments and exit */ | |
604 | aff::seglist sl; | |
605 | sl.get_seglist(af); | |
606 | for(aff::seglist::const_iterator i = sl.begin(); i!=sl.end(); i++){ | |
607 | printf("%s\n",(*i).name.c_str()); | |
608 | } | |
609 | af_close(af); | |
610 | return 0; | |
611 | } | |
612 | ||
613 | if(vni.segment_count_encrypted>0 || vni.segment_count_signed>0){ | |
614 | printf("%s: has %s%s%ssegments\n",infile, | |
615 | (vni.segment_count_encrypted ? "encrypted " : ""), | |
616 | ((vni.segment_count_encrypted && vni.segment_count_signed) ? "and ": ""), | |
617 | (vni.segment_count_signed ? "signed " : "")); | |
618 | } | |
619 | ||
620 | ||
621 | if(opt_passphrase){ | |
622 | if(af_use_aes_passphrase(af,opt_passphrase)){ | |
623 | errx(1,"%s: cannot use passphrase",opt_passphrase); | |
624 | } | |
625 | } | |
626 | ||
627 | printf("\n%s\n",af_filename(af)); | |
628 | const char *v1 = "data"; | |
629 | const char *v2 = "===="; | |
630 | ||
631 | if(opt_all==0) printf("[skipping data segments]\n"); | |
632 | if(opt_all==0 && vni.segment_count_encrypted) printf("[skipping encrypted segments]\n"); | |
633 | if(opt_no_preview){ | |
634 | v1 = ""; | |
635 | v2 = ""; | |
636 | } | |
637 | if(opt_preview_md5){ | |
638 | v1 = "md5"; | |
639 | } | |
640 | ||
641 | printf(" data \n"); | |
642 | printf("Segment arg length %s\n",v1); | |
643 | printf("======= ========= ======== %s\n",v2); | |
644 | ||
645 | /* If a list of segments was specified by the user, just use that list */ | |
646 | if(opt_seglist.size()>0){ | |
647 | for(vector<string>::iterator i = opt_seglist.begin(); | |
648 | i != opt_seglist.end(); | |
649 | i++){ | |
650 | const char *segname = i->c_str(); | |
651 | print_info(af,segname); | |
652 | } | |
653 | af_close(af); | |
654 | return 0; | |
655 | } | |
656 | ||
657 | /* Go through the whole file, get all of the segments, put them in a list */ | |
658 | vector <string> segments; | |
659 | char segname[AF_MAX_NAME_LEN]; | |
660 | af_rewind_seg(af); // start at the beginning | |
661 | int64_t total_datalen = 0; | |
662 | size_t total_segname_len = 0; | |
663 | size_t datalen = 0; | |
664 | int aes_segs=0; | |
665 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){ | |
666 | total_segs ++; | |
667 | total_datalen += datalen; | |
668 | total_segname_len += strlen(segname); | |
669 | if(segname[0]==0) total_nulls++; | |
670 | ||
671 | /* Check to see if this is a regular page or a hash page */ | |
672 | char hash[64]; | |
673 | int64_t page_num = af_segname_page_number(segname); | |
674 | int64_t hash_num = af_segname_hash_page_number(segname,hash,sizeof(hash)); | |
675 | if(page_num>=0) total_pages++; | |
676 | if(hash_num>=0) total_hashes++; | |
677 | if(strstr(segname,AF_SIG256_SUFFIX)) total_signatures++; | |
678 | if(strstr(segname,AF_AES256_SUFFIX)) aes_segs++; | |
679 | if(opt_all==0 && (page_num>=0||hash_num>=0)) continue; // skip | |
680 | if(opt_all==0 && af_is_encrypted_segment(segname)) continue; // skip | |
681 | ||
682 | if(segname[0]==0 && datalen>0 && opt_all){ | |
683 | snprintf(segname,sizeof(segname),"[null %zd bytes]",datalen); | |
684 | } | |
685 | segments.push_back(segname); | |
686 | } | |
687 | ||
688 | /* Now process the segments */ | |
689 | for(vector<string>::const_iterator i = segments.begin(); | |
690 | i != segments.end(); i++){ | |
691 | print_info(af,i->c_str()); | |
692 | } | |
693 | ||
694 | /* Print the key */ | |
695 | if(something_was_decrypted){ | |
696 | bold(1); | |
697 | printf("Bold indicates segments that were decrypted.\n"); | |
698 | bold(0); | |
699 | } | |
700 | ||
701 | ||
702 | printf("\n"); | |
703 | printf("Total segments: %8lu (%lu real)\n", total_segs,total_segs-total_nulls); | |
704 | if(aes_segs){ | |
705 | printf(" Encrypted segments: %8u\n",aes_segs); | |
706 | } | |
707 | printf(" Page segments: %8lu\n",total_pages); | |
708 | printf(" Hash segments: %8lu\n",total_hashes); | |
709 | printf(" Signature segments: %8lu\n",total_signatures); | |
710 | printf(" Null segments: %8lu\n",total_nulls); | |
711 | if(opt_all){ | |
712 | printf(" Empty segments: %8lu\n",total_nulls); | |
713 | printf("\n"); | |
714 | printf("Total data bytes in segments: %"I64d"\n",total_datalen); | |
715 | ||
716 | printf("Total space in file dedicated to segment names: %zd\n", | |
717 | total_segname_len); | |
718 | printf("Total overhead for %lu segments: %zd bytes (%lu*(%zd+%zd))\n", | |
719 | total_segs, | |
720 | (size_t) total_segs*(sizeof(struct af_segment_head) +sizeof(struct af_segment_tail)), | |
721 | total_segs, | |
722 | sizeof(struct af_segment_head), | |
723 | sizeof(struct af_segment_tail)); | |
724 | printf("Overhead for AFF file header: %zd bytes\n",sizeof(struct af_head)); | |
725 | } | |
726 | ||
727 | int64_t device_sectors = 0; | |
728 | af_get_segq(af,AF_DEVICE_SECTORS,&device_sectors); | |
729 | if(device_sectors==0){ | |
730 | /* See if we can fake it */ | |
731 | unsigned long cylinders=0; | |
732 | unsigned long heads=0; | |
733 | unsigned long sectors_per_track=0; | |
734 | af_get_seg(af,AF_CYLINDERS,&cylinders,0,0); | |
735 | af_get_seg(af,AF_HEADS,&heads,0,0); | |
736 | af_get_seg(af,AF_SECTORS_PER_TRACK,§ors_per_track,0,0); | |
737 | device_sectors = cylinders * heads * sectors_per_track; | |
738 | } | |
739 | //printf("device_sectors=%"I64d"\n",device_sectors); | |
740 | ||
741 | ||
742 | int some_missing_pages = 1; | |
743 | if(af->image_pagesize && af->image_sectorsize && device_sectors){ | |
744 | int64_t device_bytes = (int64_t)device_sectors * af->image_sectorsize; | |
745 | int64_t device_pages = (device_bytes+af->image_pagesize-1) / af->image_pagesize; | |
746 | int64_t missing_pages = device_pages - total_pages; | |
747 | //printf("device_bytes=%"I64d"\n",device_bytes); | |
748 | //printf("device_pages=%"I64d"\n",device_pages); | |
749 | if(missing_pages!=0){ | |
750 | printf("Missing page segments: %8"I64u"\n",missing_pages); | |
751 | } | |
752 | else { | |
753 | some_missing_pages=0; | |
754 | } | |
755 | } | |
756 | if (some_missing_pages){ | |
757 | if(((total_pages-1) * af->image_pagesize <= af->image_size) && | |
758 | ((total_pages) * af->image_pagesize >= af->image_size)){ | |
759 | some_missing_pages = 0; | |
760 | } | |
761 | } | |
762 | ||
763 | if(some_missing_pages && opt_debug){ | |
764 | printf("Cannot calculate missing pages\n"); | |
765 | printf(" device_sectors=%"I64d" image_pagesize=%lu sectorsize=%lu\n", | |
766 | device_sectors,af->image_pagesize,af->image_sectorsize); | |
767 | } | |
768 | af_close(af); | |
769 | return 0; | |
770 | ||
771 | } | |
772 | ||
773 | ||
774 | void figure_media(const char *fn) | |
775 | { | |
776 | int fd = open(fn,O_RDONLY,0); | |
777 | if(fd<0) err(1,"open(%s)",fn); | |
778 | struct af_figure_media_buf afb; | |
779 | if(af_figure_media(fd,&afb)){ | |
780 | err(1,"af_figure_media(%s)",fn); | |
781 | } | |
782 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
783 | printf("<!DOCTYPE Server >\n"); | |
784 | printf("<device name='%s'>\n",fn); | |
785 | printf(" <sector_size>%d</sector_size>\n",afb.sector_size); | |
786 | printf(" <total_sectors>%"PRId64"</total_sectors>\n",afb.total_sectors); | |
787 | printf(" <max_read_blocks>%"PRIu64"</max_read_blocks>\n",afb.max_read_blocks); | |
788 | printf("</device>\n"); | |
789 | close(fd); | |
790 | } | |
791 | ||
792 | int main(int argc,char **argv) | |
793 | { | |
794 | int ch; | |
795 | const char *infile; | |
796 | ||
797 | /* Figure out how many cols the screen has... */ | |
798 | #ifdef HAVE_LIBNCURSES | |
799 | term = getenv("TERM"); | |
800 | if(term){ | |
801 | setupterm((char *)0,1,(int *)0); | |
802 | start_color(); | |
803 | cols = tgetnum((char *)"co"); | |
804 | } | |
805 | #endif | |
806 | ||
807 | while ((ch = getopt(argc, argv, "abh?s:SmiIwj:p:xvVX5dAl")) != -1) { | |
808 | switch (ch) { | |
809 | case 'a': opt_all++; break; | |
810 | case 'b': opt_all ++; opt_b ++; break; | |
811 | case 'i': opt_info=0; opt_identify = 1; break; | |
812 | case 'w': opt_wide++; break; | |
813 | case 'X': opt_no_preview++;break; | |
814 | case 'x': opt_x++; break; | |
815 | case 'y': opt_y++; break; | |
816 | case 'l': opt_l++;break; | |
817 | case 'm': opt_validate |= VALIDATE_MD5; break; | |
818 | case 'S': opt_validate |= VALIDATE_SHA1; break; | |
819 | case 'v': opt_page_validate = 1;break; | |
820 | case 'p': opt_passphrase = optarg; break; | |
821 | case '5': opt_preview_md5 = 1;break; | |
822 | case 'd': opt_debug = 1;break; | |
823 | case 'A': opt_figure_media = 1 ; break; | |
824 | ||
825 | case 'h': | |
826 | case '?': | |
827 | default: | |
828 | usage(); | |
829 | break; | |
830 | case 's': | |
831 | opt_seglist.push_back(optarg); // add to the list of segments to info | |
832 | break; | |
833 | case 'V': | |
834 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
835 | exit(0); | |
836 | } | |
837 | } | |
838 | argc -= optind; | |
839 | argv += optind; | |
840 | ||
841 | if(argc<1){ | |
842 | usage(); | |
843 | } | |
844 | ||
845 | ||
846 | /* Loop through all of the files */ | |
847 | while(*argv){ | |
848 | infile = *argv++; // get the file | |
849 | argc--; // decrement argument counter | |
850 | ||
851 | const char *name = af_identify_file_name(infile,1); | |
852 | if(!name) err(1,"%s",infile); | |
853 | ||
854 | if(opt_figure_media){ figure_media(infile);continue;} | |
855 | if(opt_identify) printf("%s is a %s file\n",infile,name); | |
856 | if(opt_info) info_file(infile); | |
857 | if(opt_validate) validate(infile); | |
858 | } | |
859 | #ifdef USE_S3 | |
860 | s3_audit(0); | |
861 | #endif | |
862 | return(0); | |
863 | } | |
864 | ||
865 |
136 | 136 | /* See if we can build a TOC */ |
137 | 137 | if(r<0){ |
138 | 138 | printf("AFF file corrupt at %"I64d" out of %"I64d" (%"I64d" bytes from end)\n", |
139 | ftello(af->aseg),len,len-ftello(af->aseg)); | |
139 | ftello(af->aseg),(int64_t)len,len-ftello(af->aseg)); | |
140 | 140 | if(opt_fix){ |
141 | 141 | printf("Truncating... %d \n",fileno(af->aseg)); |
142 | 142 | if(ftruncate(fileno(af->aseg),ftello(af->aseg))){ |
0 | /* | |
1 | * afrecover.cpp | |
2 | * | |
3 | * Recover broken pages of an AFF file using the party bits | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "utils.h" | |
51 | ||
52 | #include <ctype.h> | |
53 | ||
54 | #include <zlib.h> | |
55 | #include <openssl/md5.h> | |
56 | #include <openssl/sha.h> | |
57 | #include <assert.h> | |
58 | ||
59 | #ifdef HAVE_UNISTD_H | |
60 | #include <unistd.h> | |
61 | #endif | |
62 | ||
63 | #ifdef HAVE_TERM_H | |
64 | #include <term.h> | |
65 | #endif | |
66 | ||
67 | #ifdef HAVE_NCURSES_TERM_H | |
68 | #include <ncurses/term.h> | |
69 | #endif | |
70 | ||
71 | #ifdef WIN32 | |
72 | #include "unix4win32.h" | |
73 | #include <malloc.h> | |
74 | #endif | |
75 | ||
76 | using namespace std; | |
77 | using namespace aff; | |
78 | ||
79 | const char *progname = "affix"; | |
80 | ||
81 | ||
82 | int opt_b = 0; | |
83 | ||
84 | ||
85 | void usage() | |
86 | { | |
87 | printf("usage: %s filename\n",progname); | |
88 | exit(0); | |
89 | } | |
90 | ||
91 | ||
92 | ||
93 | int recover(const char *fname) | |
94 | { | |
95 | AFFILE *af = af_open(fname,O_RDWR,0); | |
96 | if(!af) af_err(1,fname); | |
97 | ||
98 | /* Get the parity page */ | |
99 | size_t pagesize = af_page_size(af); | |
100 | u_char *pagebuf = (unsigned char *)calloc(pagesize,1); | |
101 | u_char *parity_buf = (unsigned char *)calloc(pagesize,1); | |
102 | u_char *my_parity_buf = (unsigned char *)calloc(pagesize,1); | |
103 | ||
104 | ||
105 | if(af_get_seg(af,AF_PARITY0,0,parity_buf,&pagesize)){ | |
106 | err(1,"Cannot read %s segment; cannot continue",AF_PARITY0); | |
107 | } | |
108 | ||
109 | /* Now, for every page: | |
110 | * 1. Read the page & the signature | |
111 | * 2. If the signature is good, add it into the parity buffer. | |
112 | * - If not, put it on the list of bad segments. | |
113 | */ | |
114 | seglist segments(af); | |
115 | seglist bad_sigs; | |
116 | seglist good_sigs; | |
117 | for(seglist::const_iterator seg = segments.begin(); | |
118 | seg != segments.end(); | |
119 | seg++){ | |
120 | ||
121 | if (seg->pagenumber()<0) continue; // only look for pages | |
122 | switch(af_sig_verify_seg(af,seg->name.c_str())){ | |
123 | case AF_ERROR_SIG_NO_CERT: | |
124 | errx(1,"%s: no public key in AFF file\n",af_filename(af)); | |
125 | case AF_ERROR_SIG_READ_ERROR: | |
126 | errx(1,"no signature for segment '%s' --- recovery cannot continue",seg->name.c_str()); | |
127 | case AF_ERROR_SIG_BAD: | |
128 | printf("%s has a bad signature\n",af_filename(af)); | |
129 | bad_sigs.push_back(*seg); | |
130 | break; | |
131 | case AF_SIG_GOOD: | |
132 | good_sigs.push_back(*seg); | |
133 | /* While the page is in the cache, make our parity buf */ | |
134 | pagesize = af_page_size(af); | |
135 | if(af_get_page(af,seg->pagenumber(),pagebuf,&pagesize)){ | |
136 | err(1,"cannot read %s\n",seg->name.c_str()); | |
137 | } | |
138 | for(u_int i=0;i<pagesize;i++){ | |
139 | my_parity_buf[i] ^= pagebuf[i]; | |
140 | } | |
141 | break; | |
142 | default: | |
143 | break; | |
144 | } | |
145 | } | |
146 | u_char *new_pagebuf = (unsigned char *)calloc(pagesize,1); | |
147 | ||
148 | if(bad_sigs.size()>1) errx(1,"This program can only repair 1 bad page at the moment."); | |
149 | if(bad_sigs.size()==0) errx(1,"There are no bad pages for this program to repair."); | |
150 | printf("Attempting to repair %s\n",bad_sigs[0].name.c_str()); | |
151 | ||
152 | /* Calculate the page buf */ | |
153 | for(u_int i=0;i<pagesize;i++){ | |
154 | new_pagebuf[i] = parity_buf[i] ^ my_parity_buf[i]; | |
155 | } | |
156 | ||
157 | /* Write the page back */ | |
158 | if(af_update_page(af,bad_sigs[0].pagenumber(),new_pagebuf,pagesize)){ | |
159 | err(1,"Cannot put page back"); | |
160 | } | |
161 | ||
162 | /* Now verify the signature */ | |
163 | int r = af_sig_verify_seg(af,bad_sigs[0].name.c_str()); | |
164 | if(r==AF_SIG_GOOD){ | |
165 | printf("Page %s successfully repaired\n",bad_sigs[0].name.c_str()); | |
166 | } | |
167 | else{ | |
168 | printf("Page %s could not be repaired; signature error code=%d\n",bad_sigs[0].name.c_str(),r); | |
169 | exit(1); | |
170 | } | |
171 | af_close(af); | |
172 | return 0; | |
173 | } | |
174 | ||
175 | ||
176 | ||
177 | int main(int argc,char **argv) | |
178 | { | |
179 | setvbuf(stdout,0,_IONBF,0); // turn off buffering | |
180 | int ch; | |
181 | while ((ch = getopt(argc, argv, "bh?v")) != -1) { | |
182 | switch (ch) { | |
183 | case 'h': | |
184 | case '?': | |
185 | default: | |
186 | usage(); | |
187 | break; | |
188 | case 'v': | |
189 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
190 | exit(0); | |
191 | ||
192 | } | |
193 | } | |
194 | argc -= optind; | |
195 | argv += optind; | |
196 | ||
197 | if(argc<1){ | |
198 | usage(); | |
199 | } | |
200 | ||
201 | recover(argv[0]); | |
202 | exit(0); | |
203 | } | |
204 | ||
205 |
0 | /* | |
1 | * afsegment.cpp | |
2 | * | |
3 | * segment manipulation tool | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2006 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | ||
51 | #include <limits.h> | |
52 | ||
53 | #ifdef HAVE_REGEX_H | |
54 | #include <regex.h> | |
55 | #endif | |
56 | ||
57 | #include <algorithm> | |
58 | #include <cstdlib> | |
59 | #include <vector> | |
60 | #include <string> | |
61 | ||
62 | #ifdef HAVE_CSTRING | |
63 | #include <cstring> | |
64 | #endif | |
65 | ||
66 | using namespace std; | |
67 | ||
68 | ||
69 | const char *progname = "afsegment"; | |
70 | ||
71 | int opt_create = 0; | |
72 | int opt_quad = 0; | |
73 | int opt_arg = 0; | |
74 | int opt_verbose = 0; | |
75 | int filecount = 0; | |
76 | int opt_debug = 0; | |
77 | int opt_x = 0; | |
78 | ||
79 | void usage() | |
80 | { | |
81 | printf("afsegment version %s\n",PACKAGE_VERSION); | |
82 | #ifdef REG_EXTENDED | |
83 | printf("usage: afsegment [options] file1.aff [file2.aff ...]\n"); | |
84 | printf("options:\n"); | |
85 | printf(" -c Create AFF files if they do not exist\n"); | |
86 | printf(" -ssegval Sets the value of a segment; may be repeated\n"); | |
87 | printf(" -psegname Prints the contents of the segment name for each file\n"); | |
88 | printf(" -V Just print the version number and exit.\n"); | |
89 | printf(" -dname Delete segment 'name'\n"); | |
90 | printf(" -h, -? Print this message\n"); | |
91 | printf(" -Q interpert 8-byte segments as a 64-bit value\n"); | |
92 | printf(" -A Print the 32-bit arg, not the segment value\n"); | |
93 | printf(" -x Print the segment as a hex string\n"); | |
94 | printf("\n"); | |
95 | printf("Values for segval:\n"); | |
96 | printf("\n"); | |
97 | printf("Setting the segment values:\n"); | |
98 | printf(" -sname=- Take the new value of segment 'name' from stdin\n"); | |
99 | printf(" -sname=val Sets segment 'name' to be 'val' \n"); | |
100 | printf(" -sname=<val Sets segment 'name' to be contents of file 'val'\n"); | |
101 | printf("\n"); | |
102 | printf("Setting the segment args:\n"); | |
103 | printf(" -sname/arg Sets segment 'name' arg to be 'arg' (may be repeated)\n"); | |
104 | printf("\n"); | |
105 | printf("Setting both the segment value and the arg:\n"); | |
106 | printf(" -sname/arg=val Sets both arg and val for segment 'name'\n"); | |
107 | printf(" -sname/arg=<file Sets the arg and take contents from file 'file'\n"); | |
108 | printf(" -sname/arg=- Sets the arg of segment 'name' and take the contents from stdin\n"); | |
109 | printf("\n"); | |
110 | printf("Note: All deletions are done first, then all updates. Don't specify the\n"); | |
111 | printf("same segment twice on one command line.\n"); | |
112 | #else | |
113 | printf("afsegment requires a functioning regex package to be installed\n"); | |
114 | #endif | |
115 | exit(0); | |
116 | } | |
117 | ||
118 | #ifdef REG_EXTENDED | |
119 | int get_segment_from_file(AFFILE *af,const char *segname,unsigned long arg,FILE *in) | |
120 | { | |
121 | u_char *value = (u_char *)malloc(0); | |
122 | int value_len = 0; | |
123 | ||
124 | while(!feof(in)){ | |
125 | char buf[4096]; | |
126 | int count; | |
127 | count = fread(buf,1,sizeof(buf),in); | |
128 | if(count>0){ | |
129 | value = (u_char *)realloc(value,value_len+count); | |
130 | memcpy(value+value_len,buf,count); | |
131 | value_len += count; | |
132 | } | |
133 | } | |
134 | int r = af_update_seg(af,segname,arg,value,value_len); | |
135 | free(value); | |
136 | return r; | |
137 | } | |
138 | ||
139 | ||
140 | void update_segment(AFFILE *af,const char *segname, | |
141 | const char *argstr,const char *segval) | |
142 | { | |
143 | unsigned long arg = 0; | |
144 | ||
145 | if(strlen(argstr)>1) arg = atoi(argstr+1); | |
146 | ||
147 | if(!strcmp(segval,"=-")){ | |
148 | get_segment_from_file(af,segname,arg,stdin); | |
149 | return; | |
150 | } | |
151 | if(!strncmp(segval,"=<",2)){ | |
152 | FILE *f = fopen(segval+2,"rb"); | |
153 | if(!f) err(1,"fopen(%s)",segval+2); | |
154 | get_segment_from_file(af,segname,arg,f); | |
155 | fclose(f); | |
156 | return; | |
157 | } | |
158 | segval++; // skip past the "=" | |
159 | int r = af_update_seg(af,segname,arg,(const u_char *)segval,strlen(segval)); | |
160 | if(r) warn("af_update(%s,%s) ",af_filename(af),segname); | |
161 | } | |
162 | ||
163 | ||
164 | char *make_re_string(const char *buf,regmatch_t *match,int num) | |
165 | { | |
166 | int len = match[num].rm_eo - match[num].rm_so; | |
167 | char *ret = (char *)malloc(len+1); | |
168 | memcpy(ret,buf+match[num].rm_so,len); | |
169 | ret[len] = '\000'; | |
170 | return ret; | |
171 | } | |
172 | ||
173 | ||
174 | vector<string>del_segs; | |
175 | vector<string>new_segs; | |
176 | vector<string>print_segs; | |
177 | int flags=O_RDONLY; | |
178 | int openmode = 0666; | |
179 | regex_t re; | |
180 | ||
181 | void process(const char *fn) | |
182 | { | |
183 | AFFILE *af = af_open(fn,flags,openmode); | |
184 | if(af){ | |
185 | vector<string>::iterator i; | |
186 | ||
187 | for(i=del_segs.begin();i!=del_segs.end();i++){ | |
188 | if(af_del_seg(af,i->c_str())){ | |
189 | warnx("af_del_seg(%s): cannot delete segment '%s' ",fn,i->c_str()); | |
190 | } | |
191 | else { | |
192 | printf("%s: '%s' deleted\n",fn,i->c_str()); | |
193 | } | |
194 | } | |
195 | for(i=new_segs.begin();i!=new_segs.end();i++){ | |
196 | regmatch_t match[10]; | |
197 | memset(match,0,sizeof(match)); | |
198 | if(regexec(&re,i->c_str(),10,match,0)==0){ | |
199 | char *segname = make_re_string(i->c_str(),match,1); | |
200 | char *argstr = make_re_string(i->c_str(),match,2); | |
201 | char *segval = make_re_string(i->c_str(),match,3); | |
202 | update_segment(af,segname,argstr,segval); | |
203 | free(segname); | |
204 | free(argstr); | |
205 | free(segval); | |
206 | } | |
207 | } | |
208 | for(i=print_segs.begin();i!=print_segs.end();i++){ | |
209 | size_t len = 0; | |
210 | const char *segname = i->c_str(); | |
211 | if(opt_debug) fprintf(stderr," %s: \n",segname); | |
212 | unsigned char *buf=0; | |
213 | if(af_get_seg(af,segname,0,0,&len)){ | |
214 | #if HAVE_ISATTY | |
215 | if(isatty(fileno(stdout))){ | |
216 | fprintf(stderr,"%s: segment %s not found\n",fn,segname); | |
217 | continue; | |
218 | } | |
219 | #endif | |
220 | if(opt_debug) fprintf(stderr," <<not found>>\n"); | |
221 | continue; | |
222 | } | |
223 | ||
224 | buf = (u_char *)malloc(len+1); | |
225 | if(!buf) err(1,"malloc"); | |
226 | unsigned long arg = 0; | |
227 | buf[len] = 0; | |
228 | if(af_get_seg(af,segname,&arg,buf,&len)){ | |
229 | af_err(1,"af_get_seg"); // this shoudln't fail here | |
230 | free(buf); | |
231 | continue; | |
232 | } | |
233 | if(opt_debug) fprintf(stderr," arg=%lu len=%zd\n",arg,len); | |
234 | int p = 1; | |
235 | ||
236 | if(filecount>1) printf("%s:",fn); | |
237 | if(print_segs.size()>1) printf("%s=",segname); | |
238 | if(opt_quad && len==8){ | |
239 | uint64_t quad = af_decode_q(buf); | |
240 | printf("%"I64u"\n",quad); | |
241 | p = 0; | |
242 | } | |
243 | ||
244 | if(opt_arg){ | |
245 | printf("%lu\n",arg); | |
246 | p = 0; | |
247 | } | |
248 | ||
249 | if(p){ | |
250 | for(u_int i=0;i<len;i++){ | |
251 | putchar(buf[i]); | |
252 | } | |
253 | } | |
254 | if(filecount>1) printf("\n"); | |
255 | fflush(stdout); | |
256 | if(buf) free(buf); | |
257 | } | |
258 | af_close(af); | |
259 | if(opt_x) printf("\n"); | |
260 | } | |
261 | else { | |
262 | af_err(1,"af_open(%s) failed:",fn); | |
263 | } | |
264 | } | |
265 | ||
266 | int main(int argc,char **argv) | |
267 | { | |
268 | ||
269 | int ch; | |
270 | while ((ch = getopt(argc, argv, "cd:Vp:s::h?QADx")) != -1) { | |
271 | switch (ch) { | |
272 | case 'c': | |
273 | flags |= O_CREAT; | |
274 | openmode = 0666; | |
275 | break; | |
276 | case 'Q': opt_quad=1;break; | |
277 | case 'A': opt_arg=1;break; | |
278 | case 'd': | |
279 | if(optarg==0) usage(); | |
280 | del_segs.push_back(optarg); flags |= O_RDWR;break; | |
281 | case 'D': | |
282 | opt_debug=1; | |
283 | break; | |
284 | case 'p': | |
285 | if(optarg==0) usage(); | |
286 | print_segs.push_back(optarg); break; | |
287 | case 's': | |
288 | if(optarg==0) usage(); | |
289 | if(strlen(optarg)==0) usage(); | |
290 | new_segs.push_back(optarg); flags |= O_RDWR;break; | |
291 | case 'x': | |
292 | opt_x++; | |
293 | break; | |
294 | case 'h': | |
295 | case '?': | |
296 | default: | |
297 | usage(); | |
298 | exit(0); | |
299 | case 'V': | |
300 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
301 | exit(0); | |
302 | } | |
303 | } | |
304 | argc -= optind; | |
305 | argv += optind; | |
306 | ||
307 | if(argc<1){ | |
308 | usage(); | |
309 | } | |
310 | ||
311 | if(regcomp(&re,"([^/=]*)(/[0-9]+)?(=.*)?",REG_EXTENDED|REG_ICASE)){ | |
312 | err(1,"regcomp"); | |
313 | } | |
314 | ||
315 | filecount = argc; | |
316 | while(*argv){ | |
317 | fflush(stdout); | |
318 | if(opt_debug) fprintf(stderr,"%s:\n",*argv); | |
319 | process(*argv); | |
320 | argv++; | |
321 | argc--; | |
322 | } | |
323 | exit(0); | |
324 | } | |
325 | #else | |
326 | int main(int argc,char **argv) | |
327 | { | |
328 | usage(); | |
329 | exit(1); | |
330 | } | |
331 | #endif |
0 | /* | |
1 | * afsign.cpp: | |
2 | * | |
3 | * Sign an existing AFF file. | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2007 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | #include "affconfig.h" | |
47 | #include "afflib.h" | |
48 | #include "afflib_i.h" | |
49 | ||
50 | #ifdef USE_AFFSIGS | |
51 | ||
52 | #include "utils.h" | |
53 | #include "base64.h" | |
54 | ||
55 | #include <stdio.h> | |
56 | #include <algorithm> | |
57 | #include <vector> | |
58 | #include <iostream> | |
59 | #include <openssl/pem.h> | |
60 | #include <openssl/x509.h> | |
61 | ||
62 | ||
63 | #include "aff_bom.h" | |
64 | ||
65 | int opt_note = 0; | |
66 | const char *opt_sign_key_file = 0; | |
67 | const char *opt_sign_cert_file = 0; | |
68 | ||
69 | using namespace std; | |
70 | using namespace aff; | |
71 | ||
72 | const char *progname = "afsign"; | |
73 | ||
74 | void usage() | |
75 | { | |
76 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
77 | printf("usage: %s [options] filename.aff\n",progname); | |
78 | printf("This program will:\n"); | |
79 | printf(" * Sign each segment if there are no segment signatures.\n"); | |
80 | printf(" * Write signed chain-of-custody Bill of Materials segment.\n"); | |
81 | printf("\nSignature Options:\n"); | |
82 | printf(" -k filename.key = specify private key for signing\n"); | |
83 | printf(" -c filename.cer = specify a X.509 certificate that matches the private key\n"); | |
84 | printf(" (by default, the file is assumed to be the same one\n"); | |
85 | printf(" provided with the -k option.)\n"); | |
86 | printf(" -Z = ZAP (remove) all signature segments.\n"); | |
87 | printf("options:\n"); | |
88 | printf(" -n --- ask for a chain-of-custody note.\n"); | |
89 | printf(" -v --- Just print the version number and exit.\n"); | |
90 | exit(0); | |
91 | } | |
92 | ||
93 | ||
94 | int afsign(const char *fn) | |
95 | { | |
96 | AFFILE *af = af_open(fn,O_RDWR,0); | |
97 | if(!af) af_err(1,"%s",fn); | |
98 | ||
99 | struct af_vnode_info vni; | |
100 | if(af_vstat(af,&vni)) err(1,"af_vstat"); | |
101 | ||
102 | if(vni.supports_metadata==0){ | |
103 | /* If it is a raw file, we can create an AFM file to sign */ | |
104 | if(vni.is_raw==0) errx(1,"%s: file does not support metadata. Cannot sign\n",fn); | |
105 | af_close(af); // afm will open it | |
106 | char afmfile[MAXPATHLEN+1]; | |
107 | char file000[MAXPATHLEN+1]; | |
108 | char extension[MAXPATHLEN+1]; | |
109 | strcpy(afmfile,fn); | |
110 | char *period = strrchr(afmfile,'.'); | |
111 | if(!period) errx(1,"%s: file does not support metadata and lacks a file extension,\n" | |
112 | "which is needed to create an AFM file '%s\n",afmfile,fn); | |
113 | strcpy(extension,period+1); // get the extension | |
114 | ||
115 | /* If the file being opened is not a .000 file, and a .000 file exists, do not proceed */ | |
116 | strcpy(period,".000"); | |
117 | strcpy(file000,afmfile); // make the 000 file | |
118 | strcpy(period,".afm"); | |
119 | ||
120 | if(strcmp(extension,"000")!=0){ | |
121 | if(access(file000,F_OK)==0){ | |
122 | errx(1,"Can't create .afm file because %s exists.\n",file000); | |
123 | } | |
124 | } | |
125 | ||
126 | strcpy(period,".afm"); // we are now going to make an afm file | |
127 | af = af_open(afmfile,O_RDWR|O_CREAT,0600); | |
128 | if(!af) af_err(1,"%s: file does not support metadata and cannot create AFM file '%s\n",fn,afmfile); | |
129 | if(strcmp(extension,"000")!=0){ | |
130 | af_update_seg(af,AF_RAW_IMAGE_FILE_EXTENSION,0,(const u_char *)extension,strlen(extension)); | |
131 | af_close(af); | |
132 | unlink(file000); // get rid of that .000 file | |
133 | af = af_open(afmfile,O_RDWR,0600); | |
134 | if(!af) af_err(1,"%s: Created AFM file but cannot re-open it\n",fn); | |
135 | /* Read the first byte to force a call to afm_split_raw_setup(). | |
136 | * The results of the read don't matter, but we better be able to read. | |
137 | */ | |
138 | u_char buf[1]; | |
139 | if(af_read(af,buf,1)!=1){ | |
140 | err(1,"Cannot read first byte of %s",fn); | |
141 | } | |
142 | af_seek(af,0L,0); | |
143 | } | |
144 | } | |
145 | ||
146 | seglist segments(af); | |
147 | ||
148 | if(isatty(fileno(stdout))){ | |
149 | printf("Signing segments...\n"); | |
150 | fflush(stdout); | |
151 | } | |
152 | ||
153 | bool signed_unsigned_segments = false; | |
154 | if(segments.has_signed_segments()==false){ | |
155 | if(af_set_sign_files(af,opt_sign_key_file,opt_sign_cert_file)){ | |
156 | errx(1,"key file '%s' or certificate file '%s' is invalid", | |
157 | opt_sign_key_file,opt_sign_cert_file); | |
158 | } | |
159 | int r = af_sign_all_unsigned_segments(af); | |
160 | if(r<0) af_err(1,"%s: all unsigned segments cannot be signed.",fn); | |
161 | if(r>0) signed_unsigned_segments = true; | |
162 | } | |
163 | ||
164 | aff_bom bom(opt_note); | |
165 | if(bom.read_files(opt_sign_cert_file,opt_sign_key_file)) err(1,"Can't read signature files???"); | |
166 | ||
167 | u_char *pagebuf = (unsigned char *)calloc(af_page_size(af),1); | |
168 | u_char *parity_buf = (unsigned char *)calloc(af_page_size(af),1); | |
169 | bool compute_parity = true; // do we need to compute the parity? | |
170 | ||
171 | /* Create the parity buffer if it doesn't exist. If the parity buffer exists, we'll just trust it. | |
172 | * We could do a two-pass here, one for creating the parity buffer, another for creating the BOM. | |
173 | * But that would require reading the data twice; hence this extra layer of complexity. | |
174 | */ | |
175 | size_t parity_buf_len = af_page_size(af); | |
176 | if(af_get_seg(af,AF_PARITY0,0,parity_buf,&parity_buf_len)==0){ | |
177 | compute_parity = false; // no need to compute it; we read it | |
178 | } | |
179 | ||
180 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
181 | const char *segname = seg->name.c_str(); | |
182 | ||
183 | if(isatty(fileno(stdout))){ | |
184 | printf("\rCalculating BOM for segment %s... ",segname); | |
185 | printf("\n"); | |
186 | fflush(stdout); | |
187 | } | |
188 | ||
189 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
190 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
191 | int sigmode = 0; | |
192 | int64_t pagenumber = af_segname_page_number(segname); | |
193 | if(pagenumber>=0){ | |
194 | /* Page segments must run in SIGNATURE_MODE1 - the actual data in the page */ | |
195 | size_t this_pagesize = af_page_size(af); | |
196 | if(af_get_page(af,pagenumber,pagebuf,&this_pagesize)){ | |
197 | free(pagebuf); | |
198 | return -1; | |
199 | } | |
200 | /* Add to parity buf if we are making a parity page*/ | |
201 | if(compute_parity){ | |
202 | for(u_int i=0;i<this_pagesize;i++){ | |
203 | parity_buf[i] ^= pagebuf[i]; | |
204 | } | |
205 | } | |
206 | aff_bom::make_hash(seghash,0,segname,pagebuf,this_pagesize); | |
207 | sigmode = AF_SIGNATURE_MODE1; | |
208 | } | |
209 | else{ | |
210 | /* Non-Page segments can be run in SIGNATURE_MODE0 - the actual data in the file */ | |
211 | size_t seglen=0; | |
212 | if(af_get_seg(af,segname,0,0,&seglen)){ | |
213 | err(1,"Cannot read length of segment '%s' on input file %s", segname,af_filename(af)); | |
214 | } | |
215 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
216 | if(!segbuf){ | |
217 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
218 | (int)seglen,segname,af_filename(af)); | |
219 | } | |
220 | /* Now get the raw source segment */ | |
221 | unsigned long arg=0; | |
222 | if(af_get_seg(af,segname,&arg,segbuf,&seglen)){ | |
223 | err(1,"Cannot read segment '%s' in %s. Deleteing output file", segname,af_filename(af)); | |
224 | } | |
225 | aff_bom::make_hash(seghash,arg,segname,segbuf,seglen); | |
226 | sigmode = AF_SIGNATURE_MODE0; | |
227 | free(segbuf); | |
228 | } | |
229 | bom.add(segname,sigmode,seghash,seghash_len); // add to the BOM | |
230 | } | |
231 | ||
232 | /* If we have been making the parity buf: | |
233 | * 1 - Write it out; add it to the BOM | |
234 | * 2 - Write out the signature segment for the parity buf; add it to the bom | |
235 | */ | |
236 | if(compute_parity){ | |
237 | if(af_update_seg(af,AF_PARITY0,0,parity_buf,af_page_size(af))) err(1,"Can't write %s",AF_PARITY0); | |
238 | ||
239 | /* Add the parity page that we made to the BOM */ | |
240 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
241 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
242 | ||
243 | aff_bom::make_hash(seghash,0,AF_PARITY0,parity_buf,af_page_size(af)); | |
244 | bom.add(AF_PARITY0,AF_SIGNATURE_MODE0,seghash,seghash_len); | |
245 | ||
246 | ||
247 | /* If we are signing segments for the first time, we need to sign the parity page | |
248 | * and then add the parity page's signature segment to the BOM as well. | |
249 | */ | |
250 | if(signed_unsigned_segments){ | |
251 | af_sign_seg(af,AF_PARITY0); // sign the parity segment if we signed the other segments | |
252 | bom.add(af,AF_PARITY0_SIG); | |
253 | ||
254 | u_char buf[1024]; | |
255 | size_t buflen = sizeof(buf); | |
256 | ||
257 | const char *segname = AF_PARITY0_SIG; | |
258 | if(af_get_seg(af,segname,0,buf,&buflen)==0){ // Get the signature | |
259 | aff_bom::make_hash(seghash,0,segname,buf,buflen); // and add it to the BOM | |
260 | bom.add(segname,AF_SIGNATURE_MODE0,seghash,seghash_len); | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | if(isatty(fileno(stdout))){ | |
266 | printf(" \r\n"); | |
267 | fflush(stdout); | |
268 | } | |
269 | ||
270 | bom.close(); | |
271 | bom.write(af,segments); | |
272 | af_close(af); | |
273 | return 0; | |
274 | } | |
275 | ||
276 | int remove_signatures(const char *fn) | |
277 | { | |
278 | AFFILE *af = af_open(fn,O_RDWR,0); | |
279 | if(!af) af_err(1,"%s",fn); | |
280 | ||
281 | aff::seglist sl(af); | |
282 | for(aff::seglist::const_iterator i = sl.begin(); | |
283 | i!= sl.end(); | |
284 | i++){ | |
285 | if(af_is_signature_segment(i->name.c_str()) || i->name==AF_SIGN256_CERT){ | |
286 | cout << "Deleting " << i->name << "\n"; | |
287 | af_del_seg(af,i->name.c_str()); | |
288 | } | |
289 | } | |
290 | af_close(af); | |
291 | return 0; | |
292 | } | |
293 | ||
294 | int main(int argc,char **argv) | |
295 | { | |
296 | int bflag, ch; | |
297 | int opt_zap = 0; | |
298 | ||
299 | bflag = 0; | |
300 | while ((ch = getopt(argc, argv, "nk:c:h?vZ")) != -1) { | |
301 | switch (ch) { | |
302 | case 'n': opt_note = 1;break; | |
303 | case 'k': | |
304 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
305 | opt_sign_key_file = optarg; | |
306 | break; | |
307 | case 'c': | |
308 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
309 | opt_sign_cert_file = optarg; | |
310 | break; | |
311 | case 'v': | |
312 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
313 | exit(0); | |
314 | case 'Z': | |
315 | opt_zap = 1; | |
316 | break; | |
317 | case 'h': | |
318 | case '?': | |
319 | default: | |
320 | usage(); | |
321 | break; | |
322 | } | |
323 | } | |
324 | argc -= optind; | |
325 | argv += optind; | |
326 | ||
327 | if(opt_sign_cert_file==0) opt_sign_cert_file=opt_sign_key_file; // if not set, make same as key file | |
328 | ||
329 | ||
330 | if(argc!=1){ | |
331 | usage(); | |
332 | } | |
333 | ||
334 | if(opt_zap) return remove_signatures(argv[0]); | |
335 | ||
336 | /* We either need both a key file and a cert file, or neither */ | |
337 | if((opt_sign_key_file==0) || (opt_sign_cert_file==0)){ | |
338 | errx(1,"Both a private key and a certificate must be specified."); | |
339 | } | |
340 | ||
341 | ||
342 | return afsign(argv[0]); | |
343 | } | |
344 | #else | |
345 | int main(int argc,char **argv) | |
346 | { | |
347 | fprintf(stderr,"afflib compiled without USE_AFFSIGS. afsign cannot run.\n"); | |
348 | exit(-1); | |
349 | } | |
350 | ||
351 | #endif | |
352 |
0 | /* | |
1 | * afstats.cpp: | |
2 | * | |
3 | * print specific statistics about one or more AFF files. | |
4 | * Ideally, we can get the stats from the metadata, but this program will | |
5 | * calculate it if necessary. | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (c) 2005 | |
10 | * Simson L. Garfinkel and Basis Technology, Inc. | |
11 | * All rights reserved. | |
12 | * | |
13 | * This code is derrived from software contributed by | |
14 | * Simson L. Garfinkel | |
15 | * | |
16 | * Redistribution and use in source and binary forms, with or without | |
17 | * modification, are permitted provided that the following conditions | |
18 | * are met: | |
19 | * 1. Redistributions of source code must retain the above copyright | |
20 | * notice, this list of conditions and the following disclaimer. | |
21 | * 2. Redistributions in binary form must reproduce the above copyright | |
22 | * notice, this list of conditions and the following disclaimer in the | |
23 | * documentation and/or other materials provided with the distribution. | |
24 | * 3. All advertising materials mentioning features or use of this software | |
25 | * must display the following acknowledgement: | |
26 | * This product includes software developed by Simson L. Garfinkel | |
27 | * and Basis Technology Corp. | |
28 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
29 | * contributors to this program may be used to endorse or promote | |
30 | * products derived from this software without specific prior written | |
31 | * permission. | |
32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
34 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
35 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
36 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
37 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
38 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
45 | * SUCH DAMAGE. | |
46 | */ | |
47 | ||
48 | ||
49 | #include "affconfig.h" | |
50 | #include "afflib.h" | |
51 | #include "afflib_i.h" | |
52 | ||
53 | #include <openssl/md5.h> | |
54 | #include <openssl/sha.h> | |
55 | #include <zlib.h> | |
56 | #include <assert.h> | |
57 | ||
58 | #ifdef HAVE_ERR_H | |
59 | #include <err.h> | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_UNISTD_H | |
63 | #include <unistd.h> | |
64 | #endif | |
65 | ||
66 | #ifdef HAVE_UNISTD_H | |
67 | #include <unistd.h> | |
68 | #endif | |
69 | ||
70 | #ifdef HAVE_TERM_H | |
71 | #include <term.h> | |
72 | #endif | |
73 | ||
74 | #ifdef HAVE_NCURSES_TERM_H | |
75 | #include <ncurses/term.h> | |
76 | #endif | |
77 | ||
78 | #ifdef HAVE_NCURSES_H | |
79 | #include <ncurses.h> | |
80 | #endif | |
81 | ||
82 | #ifdef WIN32 | |
83 | #include "unix4win32.h" | |
84 | #include <malloc.h> | |
85 | #endif | |
86 | ||
87 | const char *progname = "afstats"; | |
88 | int opt_m = 0; | |
89 | ||
90 | void usage() | |
91 | { | |
92 | printf("%s version %s\n\n",progname,PACKAGE_VERSION); | |
93 | printf("usage: %s [options] infile(s)\n",progname); | |
94 | printf(" -m = print all output in megabytes\n"); | |
95 | printf(" -v = Just print the version number and exit.\n"); | |
96 | exit(0); | |
97 | } | |
98 | ||
99 | ||
100 | void title() | |
101 | { | |
102 | printf("fname\tbytes\tcompressed\n"); | |
103 | } | |
104 | ||
105 | void print_size(uint64_t s) | |
106 | { | |
107 | if(opt_m){ | |
108 | printf("%u",(unsigned int)(s/(1024*1024))); | |
109 | return; | |
110 | } | |
111 | printf("%"I64u,s); | |
112 | } | |
113 | ||
114 | void afstats_title() | |
115 | { | |
116 | printf("Name\tAF_IMAGESIZE\tCompressed\tUncompressed\tBlank\tBad\n"); | |
117 | } | |
118 | ||
119 | void afstats(const char *fname) | |
120 | { | |
121 | AFFILE *af = af_open(fname,O_RDONLY,0); | |
122 | if(!af) af_err(1,"af_open(%s)",fname); | |
123 | ||
124 | printf("%s\t",fname); | |
125 | ||
126 | long unsigned int segsize=0; | |
127 | ||
128 | int64_t imagesize=0; | |
129 | int64_t blanksectors=0; | |
130 | int64_t badsectors=0; | |
131 | af_get_segq(af,AF_IMAGESIZE,&imagesize); | |
132 | if(af_get_seg(af,AF_PAGESIZE,&segsize,0,0)){ | |
133 | af_get_seg(af,AF_SEGSIZE_D,&segsize,0,0); // check for oldstype | |
134 | } | |
135 | af_get_segq(af,AF_BADSECTORS,&badsectors); | |
136 | af_get_segq(af,AF_BLANKSECTORS,&blanksectors); | |
137 | ||
138 | print_size(imagesize); | |
139 | printf("\t"); | |
140 | fflush(stdout); | |
141 | ||
142 | int64_t compressed_bytes = 0; | |
143 | int64_t uncompressed_bytes = 0; | |
144 | ||
145 | /* Now read through all of the segments and count the number of | |
146 | * data segments. We know the uncompressed size... | |
147 | */ | |
148 | af_rewind_seg(af); | |
149 | char segname[AF_MAX_NAME_LEN+1]; | |
150 | size_t datalen; | |
151 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){ | |
152 | int64_t page_num = af_segname_page_number(segname); | |
153 | if(page_num>=0){ | |
154 | compressed_bytes += datalen; | |
155 | uncompressed_bytes += segsize; | |
156 | } | |
157 | } | |
158 | if(uncompressed_bytes > imagesize) uncompressed_bytes = imagesize; | |
159 | ||
160 | print_size(compressed_bytes); | |
161 | printf("\t"); | |
162 | print_size(uncompressed_bytes); | |
163 | printf(" %"I64d" %"I64d,blanksectors,badsectors); | |
164 | putchar('\n'); | |
165 | ||
166 | ||
167 | } | |
168 | ||
169 | ||
170 | ||
171 | ||
172 | int main(int argc,char **argv) | |
173 | { | |
174 | int ch; | |
175 | while ((ch = getopt(argc, argv, "mh?V")) != -1) { | |
176 | switch (ch) { | |
177 | case 'm': | |
178 | opt_m = 1; | |
179 | break; | |
180 | case 'h': | |
181 | case '?': | |
182 | default: | |
183 | usage(); | |
184 | break; | |
185 | case 'V': | |
186 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
187 | exit(0); | |
188 | } | |
189 | } | |
190 | argc -= optind; | |
191 | argv += optind; | |
192 | ||
193 | if(argc<1){ | |
194 | usage(); | |
195 | } | |
196 | ||
197 | /* Each argument is now a file. Process each one */ | |
198 | afstats_title(); | |
199 | while(*argv){ | |
200 | afstats(*argv++); | |
201 | argc--; | |
202 | } | |
203 | exit(0); | |
204 | } | |
205 | ||
206 |
0 | /* | |
1 | * afverify.cpp: | |
2 | * | |
3 | * Verify the digital signature on a signed file | |
4 | */ | |
5 | ||
6 | #include "affconfig.h" | |
7 | #include "afflib.h" | |
8 | #include "afflib_i.h" | |
9 | ||
10 | #include "utils.h" | |
11 | #include "base64.h" | |
12 | #include "aff_bom.h" | |
13 | #include "aftimer.h" | |
14 | ||
15 | #include <stdio.h> | |
16 | #include <algorithm> | |
17 | #include <vector> | |
18 | #include <iostream> | |
19 | #include <openssl/pem.h> | |
20 | #include <openssl/x509.h> | |
21 | ||
22 | using namespace std; | |
23 | using namespace aff; | |
24 | ||
25 | const char *progname = "afcrypto"; | |
26 | int opt_change = 0; | |
27 | int opt_verbose = 0; | |
28 | int opt_all = 0; | |
29 | ||
30 | void usage() | |
31 | { | |
32 | printf("afverify version %s\n",PACKAGE_VERSION); | |
33 | printf("usage: afverify [options] filename.aff\n"); | |
34 | printf("Verifies the digital signatures on a file\n"); | |
35 | printf("options:\n"); | |
36 | printf(" -a --- print all segments\n"); | |
37 | printf(" -V --- Just print the version number and exit.\n"); | |
38 | printf(" -v --- verbose\n"); | |
39 | ||
40 | OpenSSL_add_all_digests(); | |
41 | const EVP_MD *sha256 = EVP_get_digestbyname("sha256"); | |
42 | if(sha256){ | |
43 | printf(" SHA256 is operational\n"); | |
44 | } else { | |
45 | printf("Warning: EVP_get_digestbyname(\"sha256\") fails\n"); | |
46 | } | |
47 | exit(0); | |
48 | } | |
49 | ||
50 | void print_x509_info(X509 *cert) | |
51 | { | |
52 | printf("SIGNING CERTIFICATE :\n"); | |
53 | printf(" Subject: "); X509_NAME_print_ex_fp(stdout,X509_get_subject_name(cert),0,XN_FLAG_SEP_CPLUS_SPC); | |
54 | printf("\n"); | |
55 | printf(" Issuer: "); X509_NAME_print_ex_fp(stdout,X509_get_issuer_name(cert),0,XN_FLAG_SEP_CPLUS_SPC); | |
56 | printf("\n"); | |
57 | ASN1_INTEGER *sn = X509_get_serialNumber(cert); | |
58 | if(sn){ | |
59 | long num = ASN1_INTEGER_get(sn); | |
60 | if(num>0) printf(" Certificate serial number: %ld\n",num); | |
61 | } | |
62 | printf("\n"); | |
63 | } | |
64 | ||
65 | #ifdef USE_AFFSIGS | |
66 | #include "expat.h" | |
67 | void startElement(void *userData, const char *name, const char **atts); | |
68 | void endElement(void *userData, const char *name); | |
69 | void cHandler(void *userData,const XML_Char *s,int len); | |
70 | ||
71 | class segmenthash { | |
72 | public: | |
73 | segmenthash():total_validated(0),total_invalid(0),sigmode(0),in_cert(false), | |
74 | in_seghash(false),get_cdata(false),arg(0),seglen(0), | |
75 | get_cdata_segment(0),af(0),cert(0),pubkey(0) { | |
76 | ||
77 | parser = XML_ParserCreate(NULL); | |
78 | XML_SetUserData(parser, this); | |
79 | XML_SetElementHandler(parser, ::startElement, ::endElement); | |
80 | XML_SetCharacterDataHandler(parser,cHandler); | |
81 | }; | |
82 | int parse(const char *buf,int len) { return XML_Parse(parser, buf, len, 1);} | |
83 | XML_Parser parser; | |
84 | int total_validated; | |
85 | int total_invalid; | |
86 | int sigmode; | |
87 | bool in_cert; | |
88 | bool in_seghash; | |
89 | bool get_cdata; | |
90 | string segname; | |
91 | string alg; | |
92 | string cdata; | |
93 | int arg; | |
94 | int seglen; | |
95 | const char *get_cdata_segment; // just get this segment | |
96 | AFFILE *af; // if set, we are parsing crypto | |
97 | X509 *cert; // public key used to sign | |
98 | EVP_PKEY *pubkey; | |
99 | void clear(){ | |
100 | segname=""; | |
101 | cdata=""; | |
102 | sigmode=0; | |
103 | alg=""; | |
104 | seglen=0; | |
105 | } | |
106 | ~segmenthash(){ | |
107 | if(cert) X509_free(cert); | |
108 | if(parser) XML_ParserFree(parser); | |
109 | } | |
110 | void startElement(const char *name,const char **atts); | |
111 | void endElement(const char *name); | |
112 | }; | |
113 | ||
114 | int count=0; | |
115 | void startElement(void *userData, const char *name, const char **atts) | |
116 | { | |
117 | segmenthash *sh = (segmenthash *)userData; | |
118 | sh->startElement(name,atts); | |
119 | } | |
120 | ||
121 | void segmenthash::startElement(const char *name,const char **atts) | |
122 | { | |
123 | clear(); | |
124 | if(strcmp(name,AF_XML_SEGMENT_HASH)==0){ | |
125 | for(int i=0;atts[i];i+=2){ | |
126 | const char *name = atts[i]; | |
127 | const char *value = atts[i+1]; | |
128 | if(!strcmp(name,"segname")) segname = value; | |
129 | if(!strcmp(name,"sigmode")) sigmode = atoi(value); | |
130 | if(!strcmp(name,"alg")) alg = value; | |
131 | if(!strcmp(name,"seglen")) seglen = atoi(value); | |
132 | } | |
133 | in_seghash = true; | |
134 | get_cdata = true; | |
135 | return; | |
136 | } | |
137 | if(strcmp(name,"signingcertificate")==0){ | |
138 | in_cert = true; | |
139 | get_cdata = true; | |
140 | return; | |
141 | } | |
142 | if(get_cdata_segment && strcmp(name,get_cdata_segment)==0){ | |
143 | get_cdata = true; | |
144 | return; | |
145 | } | |
146 | } | |
147 | ||
148 | void cHandler(void *userData,const XML_Char *s,int len) | |
149 | { | |
150 | segmenthash *sh = (segmenthash *)userData; | |
151 | if(sh->get_cdata==false) return; // don't want cdata | |
152 | sh->cdata.append(s,len); | |
153 | } | |
154 | ||
155 | void endElement(void *userData, const char *name) | |
156 | { | |
157 | segmenthash *sh = (segmenthash *)userData; | |
158 | sh->endElement(name); | |
159 | } | |
160 | ||
161 | ||
162 | void segmenthash::endElement(const char *name) | |
163 | { | |
164 | if(get_cdata_segment && strcmp(name,get_cdata_segment)==0){ | |
165 | get_cdata = false; | |
166 | XML_StopParser(parser,0); | |
167 | return; | |
168 | } | |
169 | if(in_seghash && af){ | |
170 | if(segname.size()==0) return; // don't have a segment name | |
171 | /* Try to validate this one */ | |
172 | size_t hashbuf_len = cdata.size() + 2; | |
173 | u_char *hashbuf = (u_char *)malloc(hashbuf_len); | |
174 | hashbuf_len = b64_pton_slg((char *)cdata.c_str(),cdata.size(),hashbuf,hashbuf_len); | |
175 | if(alg=="sha256"){ | |
176 | /* TODO: Don't re-validate something that's already validated */ | |
177 | int r = af_hash_verify_seg2(af,segname.c_str(),hashbuf,hashbuf_len,sigmode); | |
178 | if(r==AF_HASH_VERIFIES){ | |
179 | total_validated++; | |
180 | } | |
181 | else total_invalid++; | |
182 | } | |
183 | free(hashbuf); | |
184 | in_seghash = false; | |
185 | } | |
186 | if(in_cert && af){ | |
187 | BIO *cert_bio = BIO_new_mem_buf((char *)cdata.c_str(),cdata.size()); | |
188 | PEM_read_bio_X509(cert_bio,&cert,0,0); | |
189 | BIO_free(cert_bio); | |
190 | pubkey = X509_get_pubkey(cert); | |
191 | in_cert = false; | |
192 | } | |
193 | cdata = ""; // erase it | |
194 | } | |
195 | ||
196 | string get_xml_field(const char *buf,const char *field) | |
197 | { | |
198 | segmenthash sh; | |
199 | sh.get_cdata_segment = field; | |
200 | sh.parse(buf,strlen(buf)); | |
201 | return sh.cdata; | |
202 | } | |
203 | ||
204 | /* verify the chain signature; return 0 if successful, -1 if failed. | |
205 | * The signature is a block of XML with a base64 encoded at the end. | |
206 | */ | |
207 | int verify_bom_signature(AFFILE *af,const char *buf) | |
208 | { | |
209 | OpenSSL_add_all_digests(); | |
210 | const EVP_MD *sha256 = EVP_get_digestbyname("sha256"); | |
211 | ||
212 | if(!sha256){ | |
213 | fprintf(stderr,"OpenSSL does not have SHA256; signatures cannot be verified.\n"); | |
214 | return -1; | |
215 | } | |
216 | ||
217 | const char *cce = "</" AF_XML_AFFBOM ">\n"; | |
218 | const char *chain_end = strstr(buf,cce); | |
219 | if(!chain_end){ | |
220 | warn("end of chain XML can't be found\n"); | |
221 | return -1; // can't find it | |
222 | } | |
223 | const char *sig_start = chain_end + strlen(cce); | |
224 | ||
225 | BIO *seg = BIO_new_mem_buf((void *)buf,strlen(buf)); | |
226 | if(BIO_seek(seg,0)!=0){ | |
227 | printf("Cannot seek to beginning of BIO mem?"); | |
228 | return -1; | |
229 | } | |
230 | X509 *cert = 0; | |
231 | PEM_read_bio_X509(seg,&cert,0,0); // get the contained x509 cert | |
232 | BIO_free(seg); | |
233 | ||
234 | /* Now get the binary signature */ | |
235 | u_char sigbuf[1024]; | |
236 | int sigbuf_len = b64_pton_slg(sig_start,strlen(sig_start),sigbuf,sizeof(sigbuf)); | |
237 | if(sigbuf_len<80){ | |
238 | warn("BOM is not signed"); | |
239 | return -1; | |
240 | } | |
241 | ||
242 | /* Try to verify it */ | |
243 | EVP_MD_CTX md; | |
244 | EVP_VerifyInit(&md,sha256); | |
245 | EVP_VerifyUpdate(&md,buf,sig_start-buf); | |
246 | int r = EVP_VerifyFinal(&md,sigbuf,sigbuf_len,X509_get_pubkey(cert)); | |
247 | if(r!=1){ | |
248 | printf("BAD SIGNATURE ON BOM\n"); | |
249 | return -1; | |
250 | } | |
251 | ||
252 | print_x509_info(cert); | |
253 | printf("Date: %s\n",get_xml_field(buf,"date").c_str()); | |
254 | printf("Notes: \n%s\n",get_xml_field(buf,"notes").c_str()); | |
255 | ||
256 | /* Now extract the XML block, terminating at the beginning of the XML signature */ | |
257 | char *buffer_without_signature = strdup(buf); | |
258 | char *sigend = strstr(buffer_without_signature,cce); | |
259 | if(sigend){ | |
260 | sigend[strlen(cce)] = 0;/* terminate the XML to remove the signature */ | |
261 | } | |
262 | ||
263 | segmenthash sh; | |
264 | sh.af = af; | |
265 | if (!sh.parse(buffer_without_signature, strlen(buffer_without_signature))){ | |
266 | fprintf(stderr, "expat error: %s at line %d\n", | |
267 | XML_ErrorString(XML_GetErrorCode(sh.parser)), | |
268 | (int)XML_GetCurrentLineNumber(sh.parser)); | |
269 | fprintf(stderr,"buffer without signature:\n%s\n",buffer_without_signature); | |
270 | return 1; | |
271 | } | |
272 | free(buffer_without_signature); | |
273 | return 0; | |
274 | } | |
275 | #endif | |
276 | ||
277 | int crypto_verify(AFFILE *af,u_char *certbuf,size_t certbuf_len) | |
278 | { | |
279 | ||
280 | seglist segments(af); | |
281 | seglist no_sigs; | |
282 | seglist bad_sigs; | |
283 | seglist good_sigs; | |
284 | seglist unknown_errors; | |
285 | ||
286 | for(seglist::const_iterator seg = segments.begin(); | |
287 | seg != segments.end(); | |
288 | seg++){ | |
289 | ||
290 | if(parse_chain(seg->name)>=0) continue; // chain of custody segments don't need signatures | |
291 | ||
292 | const char *segname = seg->name.c_str(); | |
293 | int i =af_sig_verify_seg(af,segname); | |
294 | if(opt_verbose){ | |
295 | printf("af_sig_verify_seg(af,%s)=%d\n",segname,i); | |
296 | } | |
297 | switch(i){ | |
298 | case AF_ERROR_SIG_NO_CERT: | |
299 | err(1,"%s: no public key in AFF file\n",af_filename(af)); | |
300 | case AF_ERROR_SIG_BAD: | |
301 | bad_sigs.push_back(*seg); | |
302 | break; | |
303 | case AF_ERROR_SIG_READ_ERROR: | |
304 | no_sigs.push_back(*seg); | |
305 | break; | |
306 | case AF_SIG_GOOD: | |
307 | good_sigs.push_back(*seg); | |
308 | break; | |
309 | case AF_ERROR_SIG_SIG_SEG: | |
310 | break; // can't verify the sig on a sig seg | |
311 | case AF_ERROR_SIG_NOT_COMPILED: | |
312 | errx(1,"AFFLIB was compiled without signature support. Cannot continue.\n"); | |
313 | default: | |
314 | unknown_errors.push_back(*seg); | |
315 | break; | |
316 | } | |
317 | } | |
318 | const char *prn = ""; | |
319 | /* Tell us something about the certificate */ | |
320 | BIO *cert_bio = BIO_new_mem_buf(certbuf,certbuf_len); | |
321 | X509 *cert = 0; | |
322 | PEM_read_bio_X509(cert_bio,&cert,0,0); | |
323 | if(!cert) errx(1,"Cannot decode certificate"); | |
324 | printf("\n"); | |
325 | printf("Filename: %s\n",af_filename(af)); | |
326 | printf("# Segments signed and Verified: %d\n",(int)good_sigs.size()); | |
327 | printf("# Segments unsigned: %d\n",(int)no_sigs.size()); | |
328 | printf("# Segments with corrupted signatures: %d\n",(int)bad_sigs.size()); | |
329 | printf("\n"); | |
330 | print_x509_info(cert); | |
331 | ||
332 | int compromised = 0; | |
333 | for(seglist::const_iterator seg = good_sigs.begin(); seg != good_sigs.end() && opt_all; | |
334 | seg++){ | |
335 | if(*seg==good_sigs.front()) printf("%sSegments with valid signatures:\n",prn); | |
336 | printf("\t%s\n",seg->name.c_str()); | |
337 | prn = "\n"; | |
338 | } | |
339 | for(seglist::const_iterator seg = no_sigs.begin(); | |
340 | seg != no_sigs.end(); | |
341 | seg++){ | |
342 | if(*seg==no_sigs.front()) printf("%sUnsigned segments:\n",prn); | |
343 | printf("\t%s\n",seg->name.c_str()); | |
344 | prn = "\n"; | |
345 | ||
346 | /* Only unsigned data segments are a problem */ | |
347 | if(af_segname_page_number(seg->name.c_str())>=0){ | |
348 | compromised++; | |
349 | } | |
350 | } | |
351 | for(seglist::const_iterator seg = bad_sigs.begin(); | |
352 | seg != bad_sigs.end(); | |
353 | seg++){ | |
354 | if(*seg==bad_sigs.front()) printf("%sBad signature segments:\n",prn); | |
355 | printf("\t%s\n",seg->name.c_str()); | |
356 | prn = "\n"; | |
357 | compromised++; | |
358 | } | |
359 | for(seglist::const_iterator seg = unknown_errors.begin(); | |
360 | seg != unknown_errors.end(); | |
361 | seg++){ | |
362 | if(*seg==unknown_errors.front()) printf("%sUnknown error segments:\n",prn); | |
363 | printf("\t%s\n",seg->name.c_str()); | |
364 | prn = "\n"; | |
365 | compromised++; | |
366 | } | |
367 | ||
368 | int highest = highest_chain(segments); | |
369 | printf("\nNumber of custody chains: %d\n",highest+1); | |
370 | for(int i=0;i<=highest;i++){ | |
371 | /* Now print each one */ | |
372 | printf("---------------------\n"); | |
373 | printf("Signed Bill of Material #%d:\n\n",i+1); | |
374 | ||
375 | /* Get the segment and verify */ | |
376 | size_t chainbuf_len = 0; | |
377 | char segname[AF_MAX_NAME_LEN]; | |
378 | snprintf(segname,sizeof(segname),AF_BOM_SEG,i); | |
379 | if(af_get_seg(af,segname,0,0,&chainbuf_len)){ | |
380 | printf("*** BOM MISSING ***\n"); | |
381 | compromised++; | |
382 | } | |
383 | char *chainbuf = (char *)malloc(chainbuf_len+1); | |
384 | if(af_get_seg(af,segname,0,(u_char *)chainbuf,&chainbuf_len)){ | |
385 | printf("*** CANNOT READ BOM ***\n"); | |
386 | compromised++; | |
387 | } | |
388 | ||
389 | chainbuf[chainbuf_len]=0; // terminate | |
390 | #ifdef USE_AFFSIGS | |
391 | if(verify_bom_signature(af,chainbuf)){ | |
392 | printf("*** BOM SIGNATURE INVALID ***\n"); | |
393 | compromised++; | |
394 | } | |
395 | #else | |
396 | printf("BOM signature cannot be verified beause libxpat is not available.\n"); | |
397 | #endif | |
398 | } | |
399 | printf("---------------------\n"); | |
400 | af_close(af); | |
401 | #ifdef USE_AFFSIGS | |
402 | if(compromised){ | |
403 | printf("\nEVIDENCE FILE DOES NOT VERIFY.\n"); | |
404 | printf("ERRORS DETECTED: %d\n",compromised); | |
405 | printf("EVIDENTUARY VALUE MAY BE COMPROMISED.\n"); | |
406 | return -1; | |
407 | } | |
408 | printf("\nEVIDENCE FILE VERIFIES.\n"); | |
409 | return 0; | |
410 | #endif | |
411 | printf("\n"); | |
412 | return -1; | |
413 | } | |
414 | ||
415 | int hash_verify(AFFILE *af) | |
416 | { | |
417 | /* See if there is a SHA1 segment */ | |
418 | unsigned char sha1_buf[20]; | |
419 | unsigned char md5_buf[16]; | |
420 | char hexbuf[256]; | |
421 | size_t sha1_len = sizeof(sha1_buf); | |
422 | size_t md5_len =sizeof(md5_buf); | |
423 | const EVP_MD *md5_evp = 0; | |
424 | const EVP_MD *sha1_evp = 0; | |
425 | EVP_MD_CTX md5,sha1; | |
426 | if(af_get_seg(af,AF_SHA1,0,sha1_buf,&sha1_len)==0){ | |
427 | printf("SHA1 stored in file: %s\n",af_hexbuf(hexbuf,sizeof(hexbuf),sha1_buf,sha1_len,0)); | |
428 | sha1_evp = EVP_get_digestbyname("sha1"); | |
429 | EVP_DigestInit(&sha1,sha1_evp); | |
430 | } | |
431 | if(af_get_seg(af,AF_MD5,0,md5_buf,&md5_len)==0){ | |
432 | printf("MD5 stored in file: %s\n",af_hexbuf(hexbuf,sizeof(hexbuf),md5_buf,md5_len,0)); | |
433 | md5_evp = EVP_get_digestbyname("md5"); | |
434 | EVP_DigestInit(&md5,md5_evp); | |
435 | } | |
436 | /* Might as well read this puppy */ | |
437 | u_char *buf = (u_char *)malloc(af_get_pagesize(af)); | |
438 | ssize_t readsize = 0; | |
439 | ssize_t total_read = 0; | |
440 | af_seek(af,0L,0); | |
441 | aftimer t; | |
442 | t.start(); | |
443 | printf("\n"); | |
444 | do { | |
445 | char tbuf[64]; | |
446 | double frac = (double)total_read / af_get_imagesize(af); | |
447 | printf(" Read %14zd/%14"PRId64" bytes; done in %s\n", | |
448 | total_read,af_get_imagesize(af),t.eta_text(tbuf,frac)); | |
449 | readsize = af_read(af,buf,af_get_pagesize(af)); | |
450 | if(readsize<1) break; | |
451 | if(md5_evp) EVP_DigestUpdate(&md5,buf,readsize); | |
452 | if(sha1_evp) EVP_DigestUpdate(&sha1,buf,readsize); | |
453 | total_read += readsize; | |
454 | } while(total_read < af_get_imagesize(af)); | |
455 | ||
456 | printf("\n"); | |
457 | ||
458 | if(sha1_evp){ | |
459 | unsigned char sha1_calc[32]; | |
460 | unsigned int sha1_calc_len = sizeof(sha1_calc); | |
461 | ||
462 | EVP_DigestFinal(&sha1,sha1_calc,(unsigned int *)&sha1_calc_len); | |
463 | printf("Calculated SHA1: %s ",af_hexbuf(hexbuf,sizeof(hexbuf),sha1_calc,sha1_calc_len,0)); | |
464 | if(memcmp(sha1_buf,sha1_calc,sha1_len)==0){ | |
465 | printf("VERIFIES\n"); | |
466 | } else { | |
467 | printf("INVALID\n"); | |
468 | } | |
469 | } | |
470 | ||
471 | if(md5_evp){ | |
472 | unsigned char md5_calc[32]; | |
473 | unsigned int md5_calc_len = sizeof(md5_calc); | |
474 | ||
475 | EVP_DigestFinal(&md5,md5_calc,(unsigned int *)&md5_calc_len); | |
476 | printf("Calculated MD5: %s ",af_hexbuf(hexbuf,sizeof(hexbuf),md5_calc,md5_calc_len,0)); | |
477 | if(memcmp(md5_buf,md5_calc,md5_len)==0){ | |
478 | printf("VERIFIES\n"); | |
479 | } else { | |
480 | printf("INVALID\n"); | |
481 | } | |
482 | } | |
483 | ||
484 | af_close(af); | |
485 | return 0; | |
486 | } | |
487 | ||
488 | int process(const char *fn) | |
489 | { | |
490 | AFFILE *af = af_open(fn,O_RDONLY,0666); | |
491 | if(!af) af_err(1,fn); | |
492 | ||
493 | /* Get the public key */ | |
494 | unsigned char certbuf[65536]; | |
495 | size_t certbuf_len = sizeof(certbuf); | |
496 | if(af_get_seg(af,AF_SIGN256_CERT,0,certbuf,&certbuf_len)){ | |
497 | /* See if it is present, but encrypted */ | |
498 | if(af_get_seg(af,AF_SIGN256_CERT AF_AES256_SUFFIX,0,0,0)==0){ | |
499 | errx(1,"%s: signed file is encrypted; present decryption key to verify signature",fn); | |
500 | } | |
501 | printf("%s: no signing certificate present. \n\n",fn); | |
502 | return hash_verify(af); | |
503 | } | |
504 | return crypto_verify(af,certbuf,certbuf_len); | |
505 | } | |
506 | ||
507 | ||
508 | int main(int argc,char **argv) | |
509 | { | |
510 | int bflag, ch; | |
511 | ||
512 | bflag = 0; | |
513 | while ((ch = getopt(argc, argv, "ach?vV")) != -1) { | |
514 | switch (ch) { | |
515 | case 'a': opt_all = 1; break; | |
516 | case 'c': opt_change = 1; break; | |
517 | case 'v': opt_verbose++; break; | |
518 | case 'h': | |
519 | case '?': | |
520 | default: | |
521 | usage(); | |
522 | break; | |
523 | case 'V': | |
524 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
525 | exit(0); | |
526 | } | |
527 | } | |
528 | argc -= optind; | |
529 | argv += optind; | |
530 | ||
531 | if(argc!=1){ | |
532 | usage(); | |
533 | } | |
534 | ||
535 | OpenSSL_add_all_digests(); | |
536 | return process(argv[0]); | |
537 | } |
0 | /* | |
1 | * afxml.cpp: | |
2 | * | |
3 | * print AFF information as an XML | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "base64.h" | |
51 | ||
52 | #ifdef WIN32 | |
53 | #include "unix4win32.h" | |
54 | #endif | |
55 | ||
56 | #include <vector> | |
57 | #include <string> | |
58 | ||
59 | #ifdef HAVE_CSTRING | |
60 | #include <cstring> | |
61 | #endif | |
62 | ||
63 | using namespace std; | |
64 | ||
65 | #if HAVE_CTYPE_H | |
66 | #include <ctype.h> | |
67 | #endif | |
68 | ||
69 | #if !defined(HAVE_ISALPHANUM) && defined(HAVE_ISALNUM) | |
70 | #define isalphanum(c) isalnum(c) | |
71 | #endif | |
72 | ||
73 | #if !defined(HAVE_ISALPHANUM) && !defined(HAVE_ISALNUM) | |
74 | #define isalphanum(c) (isalpha(c)||isdigit(c)) | |
75 | #endif | |
76 | ||
77 | const char *progname = "afxml"; | |
78 | ||
79 | int opt_x = 0; | |
80 | char **opt_j = 0; | |
81 | int opt_j_count = 0; | |
82 | int opt_stats = 0; | |
83 | ||
84 | struct page_stat_block { | |
85 | unsigned long long zsectors; // number of sectors that are all blank | |
86 | unsigned long long badsectors; // number of bad sectors | |
87 | unsigned long long zpages; // number of pages that are all blank | |
88 | unsigned long long pages; // total number of pages | |
89 | unsigned long long sectors; // total number of sectors | |
90 | }; | |
91 | ||
92 | ||
93 | void usage() | |
94 | { | |
95 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
96 | printf("usage: %s [options] infile... \n",progname); | |
97 | printf(" -V = Just print the version number and exit\n"); | |
98 | printf(" -x = Don't include the infile filename in output.\n"); | |
99 | printf(" -j segname = Just print information about segname \n"); | |
100 | printf(" (may be repeated)\n"); | |
101 | printf(" -s = output 'stats' for the file data (may a long time)\n"); | |
102 | exit(0); | |
103 | } | |
104 | ||
105 | ||
106 | ||
107 | /* Return true if segname is in the optj list */ | |
108 | bool in_opt_j_list(char *segname) | |
109 | { | |
110 | for(int i=0;i<opt_j_count;i++){ | |
111 | if(strcmp(segname,opt_j[i])==0) return true; | |
112 | } | |
113 | return false; | |
114 | } | |
115 | ||
116 | /* It's okay to print if there are no funky characters in it... | |
117 | * (avoids problems with invalid UTF-8 | |
118 | */ | |
119 | bool okay_to_print(const char *data,int datalen) | |
120 | { | |
121 | for(const char *cc=data;cc<data+datalen;cc++){ | |
122 | if (*cc <= 0) return false; | |
123 | if (*cc == 10 || *cc==13) continue; | |
124 | if (*cc<32) return false; | |
125 | if (*cc>=127) return false; | |
126 | } | |
127 | return true; | |
128 | } | |
129 | ||
130 | bool is_blank(const u_char *buf,size_t len) | |
131 | { | |
132 | for(size_t i=0;i<len;i++){ | |
133 | if(buf[i]) return false; | |
134 | } | |
135 | return true; | |
136 | } | |
137 | ||
138 | void print_xml64(const char *name,int64_t val) | |
139 | { | |
140 | printf(" <%s coding='base10'>%"I64d"</%s>\n\n",name,val,name); | |
141 | } | |
142 | ||
143 | int xml_info(const char *infile) | |
144 | { | |
145 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
146 | if(!af){ | |
147 | warn("%s",infile); | |
148 | return -1; | |
149 | } | |
150 | ||
151 | struct page_stat_block psb; | |
152 | memset(&psb,0,sizeof(psb)); | |
153 | ||
154 | printf("<!-- XML generated by afxml version %s -->\n",PACKAGE_VERSION); | |
155 | printf("<affinfo"); | |
156 | if(!opt_x) printf(" image_filename='%s'",infile); | |
157 | printf(">\n"); | |
158 | ||
159 | af_rewind_seg(af); // start at the beginning | |
160 | ||
161 | char segname[AF_MAX_NAME_LEN]; | |
162 | int pages = 0; | |
163 | vector<string> seglist; // list of segments we will get | |
164 | vector<int64_t> pagelist; // list of segments we will get | |
165 | ||
166 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,0)==0){ | |
167 | if(segname[0]==0) continue; // segment to ignore | |
168 | if(strcmp(segname,AF_DIRECTORY)==0) continue; // don't output the directories | |
169 | if(strstr(segname,AF_AES256_SUFFIX)) continue; // don't output encrypted segments that won't decrypt | |
170 | ||
171 | /* check optj */ | |
172 | if(opt_j_count > 0 && in_opt_j_list(segname)==false){ | |
173 | continue; | |
174 | } | |
175 | ||
176 | int64_t page_num = af_segname_page_number(segname); | |
177 | if(page_num>=0){ | |
178 | pages += 1; | |
179 | pagelist.push_back(page_num); | |
180 | } | |
181 | else { | |
182 | seglist.push_back(segname); | |
183 | } | |
184 | } | |
185 | ||
186 | printf(" <pages coding='base10'>%d</pages>\n",pages); // tell how many pages we have | |
187 | ||
188 | /* If we have been asked to create stats, create the states */ | |
189 | if(opt_stats){ | |
190 | unsigned char *data= (unsigned char *)malloc(af_page_size(af)); | |
191 | if(!data) err(1,"Can't allocate page with %d bytes.",af_page_size(af)); | |
192 | for(vector<int64_t>::const_iterator it = pagelist.begin(); it != pagelist.end(); it++){ | |
193 | size_t pagesize = af_page_size(af); | |
194 | size_t sectorsize = af_get_sectorsize(af); | |
195 | if(af_get_page(af,*it,data,&pagesize)){ | |
196 | err(1,"Can't read page %"PRId64,*it); | |
197 | } | |
198 | psb.pages++; | |
199 | bool allblank = true; | |
200 | for(const unsigned char *s = data; s < data+pagesize; s+=sectorsize){ | |
201 | psb.sectors ++; | |
202 | if(is_blank(s,sectorsize)){ | |
203 | psb.zsectors++; | |
204 | continue; | |
205 | } | |
206 | allblank = false; | |
207 | if(af_is_badsector(af,s)){ | |
208 | psb.badsectors++; | |
209 | continue; | |
210 | } | |
211 | } | |
212 | if(allblank) psb.zpages++; | |
213 | } | |
214 | free(data); | |
215 | printf(" <calculated>\n"); | |
216 | print_xml64("pages",psb.pages); | |
217 | print_xml64("zpages",psb.zpages); | |
218 | print_xml64("sectors",psb.sectors); | |
219 | print_xml64("zsectors",psb.zsectors); | |
220 | print_xml64("badsectors",psb.badsectors); | |
221 | printf(" </calculated>\n"); | |
222 | } | |
223 | ||
224 | /* Now that we have a list of segments, print them */ | |
225 | for(vector<string>::const_iterator it = seglist.begin(); | |
226 | it != seglist.end(); | |
227 | it++){ | |
228 | ||
229 | /* See how long the data is */ | |
230 | size_t datalen = 0; | |
231 | unsigned long arg=0; | |
232 | ||
233 | strcpy(segname,it->c_str()); | |
234 | ||
235 | if(af_get_seg(af,segname,&arg,0,&datalen)){ | |
236 | err(1,"Can't read info for segment '%s'",segname); | |
237 | } | |
238 | ||
239 | unsigned char *data= (unsigned char *)malloc(datalen); | |
240 | if(data==0) err(1,"Can't allocate %zd bytes for data",datalen); | |
241 | if(af_get_seg(af,segname,&arg,data,&datalen)!=0){ | |
242 | err(1,"Can't read data for segment '%s'",segname); | |
243 | } | |
244 | ||
245 | /* Change non-XML characters in segname to _ */ | |
246 | for(char *cc=segname;*cc;cc++){ | |
247 | if(!isalphanum(*cc)) *cc = '_'; | |
248 | } | |
249 | ||
250 | if(datalen==8 && (arg & AF_SEG_QUADWORD || af_display_as_quad(segname))){ | |
251 | /* Print it as a 64-bit value. | |
252 | * The strcmp is there because early AF_IMAGESIZE segs didn't set | |
253 | * AF_SEG_QUADWORD... | |
254 | */ | |
255 | printf(" <%s coding='base10'>%"I64d"</%s>\n",segname,af_decode_q(data),segname); | |
256 | free(data); | |
257 | continue; | |
258 | } | |
259 | ||
260 | /* If datalen==0, just print the arg as an unsigned number */ | |
261 | if(datalen==0){ | |
262 | printf(" <%s coding='base10'>%ld</%s>\n",segname,arg,segname); | |
263 | free(data); | |
264 | continue; | |
265 | } | |
266 | ||
267 | /* Just handle it as binhex ... */ | |
268 | printf(" <%s",segname); | |
269 | if(datalen==0){ | |
270 | printf(" arg='%lu' />\n",arg); | |
271 | free(data); | |
272 | continue; | |
273 | } | |
274 | ||
275 | /* If segname ends 'md5', code in hex */ | |
276 | if(strlen(segname)>=3 && strcmp(segname+strlen(segname)-3,"md5")==0){ | |
277 | char hex_buf[40]; | |
278 | printf(" coding='base16'>%s</%s>\n", | |
279 | af_hexbuf(hex_buf,sizeof(hex_buf),data,datalen,0), | |
280 | segname); | |
281 | free(data); | |
282 | continue; | |
283 | } | |
284 | ||
285 | /* If all segment contents are printable ascii with no CRs, LFs, or brackets, | |
286 | * just print as-is... | |
287 | */ | |
288 | if(okay_to_print((const char *)data,datalen)){ | |
289 | putchar('>'); | |
290 | for(const char *cc=(const char *)data;cc<(const char *)data+datalen;cc++){ | |
291 | switch(*cc){ | |
292 | case '>': fputs("<",stdout);break; | |
293 | case '<': fputs(">",stdout);break; | |
294 | case '&': fputs("&",stdout);break; | |
295 | case '\'': fputs("'",stdout);break; | |
296 | case '"': fputs(""",stdout);break; | |
297 | default: putchar(*cc); | |
298 | } | |
299 | } | |
300 | printf("</%s>\n",segname); | |
301 | free(data); | |
302 | continue; | |
303 | } | |
304 | ||
305 | /* Default coding: base64 */ | |
306 | int b64size = datalen*2+2; | |
307 | char *b64buf = (char *)calloc(b64size,1); | |
308 | int b64size_real = b64_ntop(data,datalen,b64buf,b64size); | |
309 | data[b64size_real] = 0; // be sure it is null terminated | |
310 | ||
311 | printf(" coding='base64'>"); | |
312 | fputs(b64buf,stdout); | |
313 | printf("</%s>\n",segname); | |
314 | free(b64buf); | |
315 | free(data); | |
316 | } | |
317 | af_close(af); | |
318 | ||
319 | printf("</affinfo>\n"); | |
320 | return 0; | |
321 | } | |
322 | ||
323 | ||
324 | int main(int argc,char **argv) | |
325 | { | |
326 | int bflag, ch; | |
327 | const char *infile; | |
328 | ||
329 | /* Figure out how many cols the screen has... */ | |
330 | ||
331 | bflag = 0; | |
332 | while ((ch = getopt(argc, argv, "xj:h?Vs")) != -1) { | |
333 | switch (ch) { | |
334 | case 'j': | |
335 | if(opt_j==0) opt_j = (char **)malloc(0); | |
336 | opt_j_count++; | |
337 | opt_j = (char **)realloc(opt_j,sizeof(char *)*opt_j_count); | |
338 | opt_j[opt_j_count-1] = strdup(optarg); // make a copy | |
339 | case 'x': opt_x++; break; | |
340 | case 's': opt_stats++; break; | |
341 | case 'h': | |
342 | case '?': | |
343 | default: | |
344 | usage(); | |
345 | break; | |
346 | case 'V': | |
347 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
348 | exit(0); | |
349 | } | |
350 | } | |
351 | argc -= optind; | |
352 | argv += optind; | |
353 | ||
354 | if(argc<1){ | |
355 | usage(); | |
356 | } | |
357 | ||
358 | ||
359 | /* Loop through all of the files */ | |
360 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
361 | printf("<affobjects>\n"); | |
362 | while(*argv){ | |
363 | infile = *argv++; // get the file | |
364 | argc--; // decrement argument counter | |
365 | xml_info(infile); | |
366 | } | |
367 | printf("</affobjects>\n"); | |
368 | exit(0); | |
369 | } | |
370 | ||
371 |
0 | /* | |
1 | * afinfo.cpp: | |
2 | * | |
3 | * print information about an aff file | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005--2008 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "utils.h" | |
50 | #include "afflib_i.h" | |
51 | ||
52 | #ifdef USE_S3 | |
53 | #include "s3_glue.h" | |
54 | #endif | |
55 | ||
56 | #include <ctype.h> | |
57 | #include <zlib.h> | |
58 | #include <openssl/md5.h> | |
59 | #include <openssl/sha.h> | |
60 | #include <assert.h> | |
61 | ||
62 | #include <algorithm> | |
63 | #include <cstdlib> | |
64 | #include <vector> | |
65 | #include <string> | |
66 | ||
67 | #ifdef HAVE_CSTRING | |
68 | #include <cstring> | |
69 | #endif | |
70 | ||
71 | using namespace std; | |
72 | ||
73 | #ifdef HAVE_CURSES_H | |
74 | #include <curses.h> | |
75 | #endif | |
76 | ||
77 | #ifdef HAVE_TERM_H | |
78 | #include <term.h> | |
79 | #endif | |
80 | ||
81 | #ifdef HAVE_NCURSES_TERM_H | |
82 | #include <ncurses/term.h> | |
83 | #endif | |
84 | ||
85 | #ifdef WIN32 | |
86 | #include "unix4win32.h" | |
87 | #endif | |
88 | ||
89 | const char *progname = "afinfo"; | |
90 | ||
91 | #define VALIDATE_MD5 0x01 | |
92 | #define VALIDATE_SHA1 0x02 | |
93 | ||
94 | int opt_validate = 0; | |
95 | int opt_info = 1; | |
96 | int opt_all = 0; | |
97 | int opt_wide = 0; | |
98 | int opt_l = 0; | |
99 | unsigned int cols = 80; // default | |
100 | int opt_x = 0; | |
101 | int opt_b = 0; | |
102 | int opt_identify = 1; | |
103 | int opt_verbose = 0; | |
104 | int opt_y = 0; | |
105 | int opt_hexbuf = AF_HEXBUF_SPACE4 | AF_HEXBUF_UPPERCASE; | |
106 | int opt_page_validate = 0; | |
107 | int opt_no_preview = 0; | |
108 | int opt_preview_md5 = 0; | |
109 | int opt_debug = 0; | |
110 | int opt_figure_media = 0; | |
111 | const char *opt_passphrase = 0; | |
112 | ||
113 | vector<string> opt_seglist; // just info these segments | |
114 | bool something_was_decrypted = false; | |
115 | const char *term = 0; | |
116 | ||
117 | ||
118 | /** | |
119 | * select bold on or off | |
120 | */ | |
121 | void bold(int on) | |
122 | { | |
123 | if(!term) return; | |
124 | #if defined(HAVE_LIBNCURSES) | |
125 | #ifdef HAVE_ISATTY | |
126 | if(!isatty(fileno(stdout))) return; | |
127 | #endif | |
128 | if(on) tputs(enter_bold_mode,1,putchar); | |
129 | else tputs(exit_attribute_mode,0,putchar); | |
130 | #endif | |
131 | } | |
132 | ||
133 | /** | |
134 | * select a color. | |
135 | * @param num - 0 is black; 1 red; 2 green; 3 yellow; 4 blue; 5 magenta; 6 cyan; 7 white; | |
136 | */ | |
137 | ||
138 | #define RED 1 | |
139 | #define WHITE 7 | |
140 | ||
141 | void color(int num) | |
142 | { | |
143 | #ifdef HAVE_ISATTY | |
144 | if(!isatty(fileno(stdout))) return; | |
145 | #endif | |
146 | #ifdef HAVE_CURSES_H | |
147 | char *setf = tigetstr((char *)"setf"); | |
148 | if(!setf) setf = tigetstr((char *)"setaf"); | |
149 | if(setf){ | |
150 | putp(tparm(setf,num)); | |
151 | } | |
152 | #endif | |
153 | } | |
154 | ||
155 | ||
156 | void usage() | |
157 | { | |
158 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
159 | printf("usage: %s [options] infile\n",progname); | |
160 | printf(" -a = print ALL segments (normally data segments are suppressed)\n"); | |
161 | printf(" -b = print how many bad blocks in each segment (implies -a)\n"); | |
162 | printf(" -i = identify the files, don't do info on them.\n"); | |
163 | printf(" -w = wide output; print more than 1 line if necessary.\n"); | |
164 | printf(" -s segment = Just print information about 'segment'.\n"); | |
165 | printf(" (may be repeated)\n"); | |
166 | printf(" -m = validate MD5 hash of entire image\n"); | |
167 | printf(" -S = validate SHA1 hash of entire image\n"); | |
168 | printf(" -v = validate the hash of each page (if present)\n"); | |
169 | printf(" -y = don't print segments of lengths 16 and 20 as hex)\n"); | |
170 | printf(" -p<passphrase> = Specify <passphrase> to decrypt file\n"); | |
171 | printf(" -l = Just print the segment names and exit\n"); | |
172 | printf(" -V = Just print the version number and exit.\n"); | |
173 | ||
174 | printf("\nPreview Options:\n"); | |
175 | printf(" -X = no data preview; just print the segment names\n"); | |
176 | printf(" -x = print binary values in hex (default is ASCII)\n"); | |
177 | printf("\nMisc:\n"); | |
178 | printf(" -d = debug\n"); | |
179 | printf(" -A = if infile is a device, print the number of sectors\n"); | |
180 | printf(" and sector size to stdout in XML. Otherwise error\n"); | |
181 | printf("\nCompilation:\n"); | |
182 | printf(" LZMA compression: Enabled\n"); | |
183 | #ifdef USE_LIBEWF | |
184 | printf(" LIBEWF enabled\n"); | |
185 | #endif | |
186 | #ifdef USE_QEMU | |
187 | printf(" QEMU enabled\n"); | |
188 | #endif | |
189 | #ifdef USE_FUSE | |
190 | printf(" FUSE enabled\n"); | |
191 | #endif | |
192 | #ifdef USE_S3 | |
193 | printf(" Amazon S3 enabled\n"); | |
194 | #endif | |
195 | #ifdef HAVE_LIBEXPAT | |
196 | printf(" HAVE_LIBEXPAT "); | |
197 | #endif | |
198 | printf("\n"); | |
199 | ||
200 | if(opt_debug){ | |
201 | for(int i=0;i<9;i++){ | |
202 | color(i);printf("Color %d\n",i);color(7); | |
203 | } | |
204 | } | |
205 | ||
206 | exit(0); | |
207 | } | |
208 | ||
209 | ||
210 | AFFILE *af=0; | |
211 | ||
212 | void sig_info(int arg) | |
213 | { | |
214 | if(af==0) return; | |
215 | printf("Validating %"I64d" of %"I64d"\n", af->pos,af->image_size); | |
216 | } | |
217 | ||
218 | ||
219 | ||
220 | ||
221 | void validate(const char *infile) | |
222 | { | |
223 | af = af_open(infile,O_RDONLY,0); | |
224 | if(!af) af_err(1,infile); | |
225 | switch(af_identify(af)){ | |
226 | case AF_IDENTIFY_AFF: | |
227 | case AF_IDENTIFY_AFM: | |
228 | case AF_IDENTIFY_AFD: | |
229 | break; | |
230 | default: | |
231 | printf("%s is not an AFF file\n",infile); | |
232 | af_close(af); | |
233 | return; | |
234 | } | |
235 | ||
236 | printf("\nValidating "); | |
237 | if(opt_validate & VALIDATE_MD5) printf("MD5 "); | |
238 | if(opt_validate == (VALIDATE_MD5|VALIDATE_SHA1)) printf("and "); | |
239 | if(opt_validate & VALIDATE_SHA1) printf("SHA1 "); | |
240 | printf("hash codes.\n"); | |
241 | ||
242 | ||
243 | #ifdef SIGINFO | |
244 | signal(SIGINFO,sig_info); | |
245 | #endif | |
246 | ||
247 | /* Get a list of all the segments to see if there is a space */ | |
248 | af_rewind_seg(af); | |
249 | char segname[AF_MAX_NAME_LEN]; | |
250 | vector <int> pages; | |
251 | memset(segname,0,sizeof(segname)); | |
252 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,0)==0){ | |
253 | int64_t page_num = af_segname_page_number(segname); | |
254 | if(page_num>=0) pages.push_back(page_num); | |
255 | } | |
256 | ||
257 | if(pages.size()==0){ | |
258 | printf("No pages to validate.\n"); | |
259 | af_close(af); | |
260 | } | |
261 | ||
262 | sort(pages.begin(),pages.end()); | |
263 | vector<int>::iterator i = pages.begin(); | |
264 | int last = *i; | |
265 | i++; | |
266 | for(; i!= pages.end();i++){ | |
267 | if(last+1 != *i){ | |
268 | printf("gap in pages (%d!=%d); %s can't be validated.\n",last+1,*i,infile); | |
269 | af_close(af); | |
270 | return; | |
271 | } | |
272 | last = *i; | |
273 | } | |
274 | ||
275 | /* Set up the hash machinery */ | |
276 | MD5_CTX md5; | |
277 | MD5_Init(&md5); | |
278 | ||
279 | SHA_CTX sha; | |
280 | SHA1_Init(&sha); | |
281 | ||
282 | uint64_t total_bytes = 0; | |
283 | while(!af_eof(af)){ | |
284 | unsigned char buf[65536]; // a decent size | |
285 | size_t bytes = af_read(af,buf,sizeof(buf)); | |
286 | if(bytes==0) break; // reached sparse region of file | |
287 | total_bytes += bytes; | |
288 | if(opt_validate & VALIDATE_MD5) MD5_Update(&md5,buf,bytes); | |
289 | if(opt_validate & VALIDATE_SHA1) SHA1_Update(&sha,buf,bytes); | |
290 | } | |
291 | ||
292 | /* Finish the hash calculations and write to the db */ | |
293 | ||
294 | if(opt_validate & VALIDATE_MD5){ | |
295 | unsigned char md5_stored[16]; | |
296 | size_t md5len = sizeof(md5_stored); | |
297 | unsigned char md5_computed[16]; | |
298 | char buf[256]; | |
299 | ||
300 | MD5_Final(md5_computed,&md5); | |
301 | printf("computed md5: %s\n", | |
302 | af_hexbuf(buf,sizeof(buf),md5_computed,16,opt_hexbuf)); | |
303 | if(af_get_seg(af,AF_MD5,0,md5_stored,&md5len)==0){ | |
304 | printf(" stored md5: %s ", | |
305 | af_hexbuf(buf,sizeof(buf),md5_stored,16,opt_hexbuf)); | |
306 | if(md5len==16 && !memcmp((const char *)md5_stored, | |
307 | (const char *)md5_computed,16)){ | |
308 | printf(" MATCH\n"); | |
309 | } | |
310 | else { | |
311 | printf(" NO MATCH!\n"); | |
312 | } | |
313 | } | |
314 | else { | |
315 | printf("(no MD5 in AFF file)\n"); | |
316 | } | |
317 | } | |
318 | ||
319 | ||
320 | if(opt_validate & VALIDATE_SHA1){ | |
321 | unsigned char sha1_stored[20]; | |
322 | size_t sha1len = sizeof(sha1_stored); | |
323 | unsigned char sha1_computed[20]; | |
324 | char buf[256]; | |
325 | ||
326 | SHA1_Final(sha1_computed,&sha); | |
327 | printf("computed sha1: %s \n",af_hexbuf(buf,sizeof(buf),sha1_computed,20,opt_hexbuf)); | |
328 | if(af_get_seg(af,AF_SHA1,0,sha1_stored,&sha1len)==0){ | |
329 | printf(" stored sha1: %s ",af_hexbuf(buf,sizeof(buf),sha1_stored,20,opt_hexbuf)); | |
330 | if(sha1len==20 && !memcmp((const char *)sha1_stored, | |
331 | (const char *)sha1_computed,20)){ | |
332 | printf(" MATCH\n"); | |
333 | } | |
334 | else { | |
335 | printf(" NO MATCH!\n"); | |
336 | } | |
337 | } | |
338 | else { | |
339 | printf("(no SHA1 in AFF file)\n"); | |
340 | } | |
341 | } | |
342 | ||
343 | af_close(af); | |
344 | } | |
345 | ||
346 | #define OUTLINE_LEN 65536 | |
347 | ||
348 | ||
349 | bool display_as_time(const char *segname) | |
350 | { | |
351 | if(strcmp(segname,AF_ACQUISITION_SECONDS)==0) return true; | |
352 | return false; | |
353 | } | |
354 | ||
355 | bool display_as_hex(const char *segname,int data_len) | |
356 | { | |
357 | if(af_display_as_hex(segname)) return true; | |
358 | if(data_len==16 && strstr(segname,"md5")) return true; | |
359 | if(data_len==20 && strstr(segname,"sha1")) return true; | |
360 | if(opt_x) return true; | |
361 | if(opt_preview_md5) return true; | |
362 | return false; | |
363 | } | |
364 | ||
365 | void badscan(AFFILE *af,int page_number,size_t data_len) | |
366 | { | |
367 | size_t page_size = af->image_pagesize; | |
368 | unsigned char *buf = (unsigned char *)malloc(page_size); | |
369 | if(af_get_page(af,page_number,buf,&page_size)){ | |
370 | err(1,"Could not read page %d",page_number); | |
371 | } | |
372 | printf("page_size = %d\n",(int)page_size); | |
373 | int sectors = 0; | |
374 | int bad_sectors = 0; | |
375 | int funny_sectors = 0; | |
376 | for(unsigned int offset=0;offset<page_size;offset+=af->image_sectorsize){ | |
377 | sectors++; | |
378 | if(af_is_badsector(af,buf+offset)){ | |
379 | bad_sectors ++; | |
380 | continue; | |
381 | } | |
382 | #ifdef __FreeBSD__ | |
383 | /* Look for the part of the bad flag that we know and love */ | |
384 | if(strnstr((char *)buf+offset,"BAD SECTOR",af->image_sectorsize)){ | |
385 | funny_sectors++; | |
386 | continue; | |
387 | } | |
388 | #endif | |
389 | } | |
390 | printf(" sectors scanned: %d bad: %d ", sectors,bad_sectors); | |
391 | if(funny_sectors){ | |
392 | printf("suspicious: %d ",funny_sectors); | |
393 | } | |
394 | printf("\n"); | |
395 | free(buf); | |
396 | } | |
397 | ||
398 | ||
399 | /* print_info: | |
400 | * Print the info on a given segment name | |
401 | */ | |
402 | void print_info(AFFILE *af,const char *segname) | |
403 | { | |
404 | unsigned long arg; | |
405 | unsigned char *data = 0; | |
406 | int dots = 0; | |
407 | u_int display_len = 0; | |
408 | char *cc = 0; | |
409 | ||
410 | /* Check to see if this is a null page. */ | |
411 | if(segname[0]==0 && opt_all==0){ | |
412 | return; | |
413 | } | |
414 | if(segname[0]=='[' && opt_all){ | |
415 | puts(segname); | |
416 | return; | |
417 | } | |
418 | ||
419 | /* Check to see if this is a data page */ | |
420 | int64_t page_num = af_segname_page_number(segname); | |
421 | ||
422 | size_t data_len = 0; | |
423 | /* First find out how big the segment is, then get the data */ | |
424 | if(af_get_seg(af,segname,&arg,0,&data_len)){ | |
425 | printf("%-25s SEGMENT NOT FOUND\n",segname); | |
426 | return; | |
427 | } | |
428 | ||
429 | /* is this an encrypted segment that I have decrypted? | |
430 | * Turn off automatic decryption and see if I can get it again... | |
431 | * If we can get it again, then it wasn't decrypted. | |
432 | */ | |
433 | int prev = af_set_option(af,AF_OPTION_AUTO_DECRYPT,0); | |
434 | bool was_decrypted = ( af_get_seg(af,segname,0,0,0)!=0) ; | |
435 | af_set_option(af,AF_OPTION_AUTO_DECRYPT,prev); | |
436 | ||
437 | if(was_decrypted){ | |
438 | bold(1); | |
439 | something_was_decrypted = true; // print key at bottom | |
440 | } | |
441 | ||
442 | /* Start the output line */ | |
443 | char output_line[OUTLINE_LEN]; | |
444 | memset(output_line,0,sizeof(output_line)); | |
445 | ||
446 | /* Now append the arg and the data len */ | |
447 | sprintf(output_line,"%-24s %8ld %8zd ",segname,arg,data_len); | |
448 | ||
449 | if(opt_no_preview){ | |
450 | printf("%s\n",output_line); | |
451 | goto done; | |
452 | } | |
453 | ||
454 | data = (unsigned char *)malloc(data_len); | |
455 | if(af_get_seg(af,segname,0,data,&data_len)){ | |
456 | warn("af_get_seg_2 failed: segname=%s data_len=%zd",segname,data_len); | |
457 | goto done; | |
458 | } | |
459 | ||
460 | /* Special handling of values that should be displayed as time */ | |
461 | if(display_as_time(segname)){ | |
462 | int hours = arg / 3600; | |
463 | int minutes = (arg / 60) % 60; | |
464 | int seconds = arg % 60; | |
465 | printf("%s= %02d:%02d:%02d (hh:mm:ss)\n",output_line,hours,minutes,seconds); | |
466 | goto done; | |
467 | } | |
468 | ||
469 | /* Special handling of quadwords that should be printed as such? */ | |
470 | if(((arg == AF_SEG_QUADWORD) && (data_len==8)) || af_display_as_quad(segname)){ | |
471 | /* Print it as a 64-bit value. | |
472 | * The strcmp is there because early AF_IMAGESIZE segs didn't set | |
473 | * AF_SEG_QUADWORD... | |
474 | */ | |
475 | switch(data_len){ | |
476 | case 8: | |
477 | printf("%s= %"I64d" (64-bit value)\n", | |
478 | output_line,af_decode_q(data)); | |
479 | break; | |
480 | case 0: | |
481 | printf("%s= 0 (0-length segment)\n",output_line); | |
482 | break; | |
483 | default: | |
484 | printf("%s= CANNOT DECODE %d byte segment\n",output_line,(int)data_len); | |
485 | } | |
486 | goto done; | |
487 | } | |
488 | ||
489 | ||
490 | /* See if I need to truncate */ | |
491 | display_len = data_len; | |
492 | if(opt_wide==0 && data_len>32){ // don't bother showing more than first 32 bytes | |
493 | dots = 1; | |
494 | display_len = 32; | |
495 | } | |
496 | ||
497 | cc = output_line + strlen(output_line); | |
498 | ||
499 | if(opt_preview_md5){ | |
500 | u_char md5[32]; | |
501 | MD5(data,data_len,md5); | |
502 | memcpy(data,md5,32); | |
503 | data_len = 32; | |
504 | } | |
505 | if(display_as_hex(segname,display_len)){ | |
506 | char buf[80]; | |
507 | snprintf(cc,sizeof(output_line)-strlen(output_line), | |
508 | "%s%s",af_hexbuf(buf,sizeof(buf),data,display_len,opt_hexbuf), | |
509 | dots ? "..." : ""); | |
510 | /* Special code for SHA1 */ | |
511 | if(!opt_wide && strcmp(segname,AF_SHA1)==0){ | |
512 | int r = fwrite(output_line,1,82,stdout); | |
513 | if(r!=82) fprintf(stderr,"fwrite(output_line,1,82,stdout) returned %d\n",r); | |
514 | printf("\n%62s\n",output_line+82); | |
515 | goto done; | |
516 | } | |
517 | } | |
518 | else { | |
519 | /* Fill it out with some printable data */ | |
520 | unsigned int i; | |
521 | if(display_len > sizeof(output_line)-strlen(output_line)){ | |
522 | display_len = sizeof(output_line)-strlen(output_line); | |
523 | } | |
524 | for(i=0;i<display_len;i++){ | |
525 | *cc = data[i]; | |
526 | if(isprint(*cc)==0) *cc='.'; | |
527 | if(*cc=='\n' || *cc=='\r') *cc=' '; | |
528 | cc++; | |
529 | } | |
530 | *cc = 0; | |
531 | } | |
532 | ||
533 | /* Now print the results... */ | |
534 | if(!opt_wide){ | |
535 | if(strlen(output_line)>cols){ | |
536 | output_line[cols-4] = '.'; | |
537 | output_line[cols-3] = '.'; | |
538 | output_line[cols-2] = '.'; | |
539 | output_line[cols-1] = '\000'; | |
540 | } | |
541 | } | |
542 | fputs(output_line,stdout); | |
543 | if(page_num>=0 && opt_b){ | |
544 | badscan(af,page_num,data_len); | |
545 | } | |
546 | if(opt_page_validate && page_num>=0){ | |
547 | /* Get the page again; this may involve decompression */ | |
548 | unsigned char *page_data = (unsigned char *)malloc(af->image_pagesize); | |
549 | size_t page_data_len = af->image_pagesize; | |
550 | if(af_get_page(af,page_num,page_data,&page_data_len)){ | |
551 | printf("** COULD NOT READ UNCOMPRESSED PAGE "); | |
552 | goto skip1; | |
553 | } | |
554 | ||
555 | char hash_segname[32]; | |
556 | unsigned char hash_buf[16]; | |
557 | unsigned char hash_calc[16]; | |
558 | size_t hash_len = sizeof(hash_buf); | |
559 | snprintf(hash_segname,sizeof(hash_segname),AF_PAGE_MD5,page_num); | |
560 | printf(" "); | |
561 | if(af_get_seg(af,hash_segname,0,hash_buf,&hash_len)){ | |
562 | printf("** NO SEGMENT %s ** ",hash_segname); | |
563 | goto skip1; | |
564 | } | |
565 | ||
566 | MD5(page_data,page_data_len,hash_calc); | |
567 | if(memcmp(hash_buf,hash_calc,sizeof(hash_buf))!=0){ | |
568 | char hb[32]; | |
569 | printf("** HASH INVALID **\n%30s Calculated %s\n","", | |
570 | af_hexbuf(hb,sizeof(hb),hash_calc,16,opt_hexbuf)); | |
571 | printf("%30s Wanted %s ","",af_hexbuf(hb,sizeof(hb),hash_buf,16,opt_hexbuf)); | |
572 | printf("data_len=%d\n",(int)data_len); | |
573 | } else{ | |
574 | printf("HASH OK "); | |
575 | } | |
576 | free(page_data); | |
577 | } | |
578 | skip1:; | |
579 | putchar('\n'); | |
580 | done: | |
581 | if(data) free(data); | |
582 | bold(0); // make sure bold is off | |
583 | ||
584 | //color(WHITE); // make sure we are back to normal color | |
585 | } | |
586 | ||
587 | ||
588 | /* Print the information on a specific file. */ | |
589 | int info_file(const char *infile) | |
590 | { | |
591 | unsigned long total_segs = 0; | |
592 | unsigned long total_pages = 0; | |
593 | unsigned long total_hashes = 0; | |
594 | unsigned long total_signatures =0; | |
595 | unsigned long total_nulls = 0; | |
596 | struct af_vnode_info vni; | |
597 | ||
598 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
599 | if(!af) af_err(1,"Cannot open %s",infile); | |
600 | if(af_vstat(af,&vni)) err(1,"%s: af_vstat failed",infile); | |
601 | ||
602 | if(opt_l){ | |
603 | /* Just list the segments and exit */ | |
604 | aff::seglist sl; | |
605 | sl.get_seglist(af); | |
606 | for(aff::seglist::const_iterator i = sl.begin(); i!=sl.end(); i++){ | |
607 | printf("%s\n",(*i).name.c_str()); | |
608 | } | |
609 | af_close(af); | |
610 | return 0; | |
611 | } | |
612 | ||
613 | if(vni.segment_count_encrypted>0 || vni.segment_count_signed>0){ | |
614 | printf("%s: has %s%s%ssegments\n",infile, | |
615 | (vni.segment_count_encrypted ? "encrypted " : ""), | |
616 | ((vni.segment_count_encrypted && vni.segment_count_signed) ? "and ": ""), | |
617 | (vni.segment_count_signed ? "signed " : "")); | |
618 | } | |
619 | ||
620 | ||
621 | if(opt_passphrase){ | |
622 | if(af_use_aes_passphrase(af,opt_passphrase)){ | |
623 | errx(1,"%s: cannot use passphrase",opt_passphrase); | |
624 | } | |
625 | } | |
626 | ||
627 | printf("\n%s\n",af_filename(af)); | |
628 | const char *v1 = "data"; | |
629 | const char *v2 = "===="; | |
630 | ||
631 | if(opt_all==0) printf("[skipping data segments]\n"); | |
632 | if(opt_all==0 && vni.segment_count_encrypted) printf("[skipping encrypted segments]\n"); | |
633 | if(opt_no_preview){ | |
634 | v1 = ""; | |
635 | v2 = ""; | |
636 | } | |
637 | if(opt_preview_md5){ | |
638 | v1 = "md5"; | |
639 | } | |
640 | ||
641 | printf(" data \n"); | |
642 | printf("Segment arg length %s\n",v1); | |
643 | printf("======= ========= ======== %s\n",v2); | |
644 | ||
645 | /* If a list of segments was specified by the user, just use that list */ | |
646 | if(opt_seglist.size()>0){ | |
647 | for(vector<string>::iterator i = opt_seglist.begin(); | |
648 | i != opt_seglist.end(); | |
649 | i++){ | |
650 | const char *segname = i->c_str(); | |
651 | print_info(af,segname); | |
652 | } | |
653 | af_close(af); | |
654 | return 0; | |
655 | } | |
656 | ||
657 | /* Go through the whole file, get all of the segments, put them in a list */ | |
658 | vector <string> segments; | |
659 | char segname[AF_MAX_NAME_LEN]; | |
660 | af_rewind_seg(af); // start at the beginning | |
661 | int64_t total_datalen = 0; | |
662 | size_t total_segname_len = 0; | |
663 | size_t datalen = 0; | |
664 | int aes_segs=0; | |
665 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){ | |
666 | total_segs ++; | |
667 | total_datalen += datalen; | |
668 | total_segname_len += strlen(segname); | |
669 | if(segname[0]==0) total_nulls++; | |
670 | ||
671 | /* Check to see if this is a regular page or a hash page */ | |
672 | char hash[64]; | |
673 | int64_t page_num = af_segname_page_number(segname); | |
674 | int64_t hash_num = af_segname_hash_page_number(segname,hash,sizeof(hash)); | |
675 | if(page_num>=0) total_pages++; | |
676 | if(hash_num>=0) total_hashes++; | |
677 | if(strstr(segname,AF_SIG256_SUFFIX)) total_signatures++; | |
678 | if(strstr(segname,AF_AES256_SUFFIX)) aes_segs++; | |
679 | if(opt_all==0 && (page_num>=0||hash_num>=0)) continue; // skip | |
680 | if(opt_all==0 && af_is_encrypted_segment(segname)) continue; // skip | |
681 | ||
682 | if(segname[0]==0 && datalen>0 && opt_all){ | |
683 | snprintf(segname,sizeof(segname),"[null %zd bytes]",datalen); | |
684 | } | |
685 | segments.push_back(segname); | |
686 | } | |
687 | ||
688 | /* Now process the segments */ | |
689 | for(vector<string>::const_iterator i = segments.begin(); | |
690 | i != segments.end(); i++){ | |
691 | print_info(af,i->c_str()); | |
692 | } | |
693 | ||
694 | /* Print the key */ | |
695 | if(something_was_decrypted){ | |
696 | bold(1); | |
697 | printf("Bold indicates segments that were decrypted.\n"); | |
698 | bold(0); | |
699 | } | |
700 | ||
701 | ||
702 | printf("\n"); | |
703 | printf("Total segments: %8lu (%lu real)\n", total_segs,total_segs-total_nulls); | |
704 | if(aes_segs){ | |
705 | printf(" Encrypted segments: %8u\n",aes_segs); | |
706 | } | |
707 | printf(" Page segments: %8lu\n",total_pages); | |
708 | printf(" Hash segments: %8lu\n",total_hashes); | |
709 | printf(" Signature segments: %8lu\n",total_signatures); | |
710 | printf(" Null segments: %8lu\n",total_nulls); | |
711 | if(opt_all){ | |
712 | printf(" Empty segments: %8lu\n",total_nulls); | |
713 | printf("\n"); | |
714 | printf("Total data bytes in segments: %"I64d"\n",total_datalen); | |
715 | ||
716 | printf("Total space in file dedicated to segment names: %zd\n", | |
717 | total_segname_len); | |
718 | printf("Total overhead for %lu segments: %zd bytes (%lu*(%zd+%zd))\n", | |
719 | total_segs, | |
720 | (size_t) total_segs*(sizeof(struct af_segment_head) +sizeof(struct af_segment_tail)), | |
721 | total_segs, | |
722 | sizeof(struct af_segment_head), | |
723 | sizeof(struct af_segment_tail)); | |
724 | printf("Overhead for AFF file header: %zd bytes\n",sizeof(struct af_head)); | |
725 | } | |
726 | ||
727 | int64_t device_sectors = 0; | |
728 | af_get_segq(af,AF_DEVICE_SECTORS,&device_sectors); | |
729 | if(device_sectors==0){ | |
730 | /* See if we can fake it */ | |
731 | unsigned long cylinders=0; | |
732 | unsigned long heads=0; | |
733 | unsigned long sectors_per_track=0; | |
734 | af_get_seg(af,AF_CYLINDERS,&cylinders,0,0); | |
735 | af_get_seg(af,AF_HEADS,&heads,0,0); | |
736 | af_get_seg(af,AF_SECTORS_PER_TRACK,§ors_per_track,0,0); | |
737 | device_sectors = cylinders * heads * sectors_per_track; | |
738 | } | |
739 | //printf("device_sectors=%"I64d"\n",device_sectors); | |
740 | ||
741 | ||
742 | int some_missing_pages = 1; | |
743 | if(af->image_pagesize && af->image_sectorsize && device_sectors){ | |
744 | int64_t device_bytes = (int64_t)device_sectors * af->image_sectorsize; | |
745 | int64_t device_pages = (device_bytes+af->image_pagesize-1) / af->image_pagesize; | |
746 | int64_t missing_pages = device_pages - total_pages; | |
747 | //printf("device_bytes=%"I64d"\n",device_bytes); | |
748 | //printf("device_pages=%"I64d"\n",device_pages); | |
749 | if(missing_pages!=0){ | |
750 | printf("Missing page segments: %8"I64u"\n",missing_pages); | |
751 | } | |
752 | else { | |
753 | some_missing_pages=0; | |
754 | } | |
755 | } | |
756 | if (some_missing_pages){ | |
757 | if(((total_pages-1) * af->image_pagesize <= af->image_size) && | |
758 | ((total_pages) * af->image_pagesize >= af->image_size)){ | |
759 | some_missing_pages = 0; | |
760 | } | |
761 | } | |
762 | ||
763 | if(some_missing_pages && opt_debug){ | |
764 | printf("Cannot calculate missing pages\n"); | |
765 | printf(" device_sectors=%"I64d" image_pagesize=%lu sectorsize=%lu\n", | |
766 | device_sectors,af->image_pagesize,af->image_sectorsize); | |
767 | } | |
768 | af_close(af); | |
769 | return 0; | |
770 | ||
771 | } | |
772 | ||
773 | ||
774 | void figure_media(const char *fn) | |
775 | { | |
776 | int fd = open(fn,O_RDONLY,0); | |
777 | if(fd<0) err(1,"open(%s)",fn); | |
778 | struct af_figure_media_buf afb; | |
779 | if(af_figure_media(fd,&afb)){ | |
780 | err(1,"af_figure_media(%s)",fn); | |
781 | } | |
782 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
783 | printf("<!DOCTYPE Server >\n"); | |
784 | printf("<device name='%s'>\n",fn); | |
785 | printf(" <sector_size>%d</sector_size>\n",afb.sector_size); | |
786 | printf(" <total_sectors>%"PRId64"</total_sectors>\n",afb.total_sectors); | |
787 | printf(" <max_read_blocks>%"PRIu64"</max_read_blocks>\n",afb.max_read_blocks); | |
788 | printf("</device>\n"); | |
789 | close(fd); | |
790 | } | |
791 | ||
792 | int main(int argc,char **argv) | |
793 | { | |
794 | int ch; | |
795 | const char *infile; | |
796 | ||
797 | /* Figure out how many cols the screen has... */ | |
798 | #ifdef HAVE_LIBNCURSES | |
799 | term = getenv("TERM"); | |
800 | if(term){ | |
801 | setupterm((char *)0,1,(int *)0); | |
802 | start_color(); | |
803 | cols = tgetnum((char *)"co"); | |
804 | } | |
805 | #endif | |
806 | ||
807 | while ((ch = getopt(argc, argv, "abh?s:SmiIwj:p:xvVX5dAl")) != -1) { | |
808 | switch (ch) { | |
809 | case 'a': opt_all++; break; | |
810 | case 'b': opt_all ++; opt_b ++; break; | |
811 | case 'i': opt_info=0; opt_identify = 1; break; | |
812 | case 'w': opt_wide++; break; | |
813 | case 'X': opt_no_preview++;break; | |
814 | case 'x': opt_x++; break; | |
815 | case 'y': opt_y++; break; | |
816 | case 'l': opt_l++;break; | |
817 | case 'm': opt_validate |= VALIDATE_MD5; break; | |
818 | case 'S': opt_validate |= VALIDATE_SHA1; break; | |
819 | case 'v': opt_page_validate = 1;break; | |
820 | case 'p': opt_passphrase = optarg; break; | |
821 | case '5': opt_preview_md5 = 1;break; | |
822 | case 'd': opt_debug = 1;break; | |
823 | case 'A': opt_figure_media = 1 ; break; | |
824 | ||
825 | case 'h': | |
826 | case '?': | |
827 | default: | |
828 | usage(); | |
829 | break; | |
830 | case 's': | |
831 | opt_seglist.push_back(optarg); // add to the list of segments to info | |
832 | break; | |
833 | case 'V': | |
834 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
835 | exit(0); | |
836 | } | |
837 | } | |
838 | argc -= optind; | |
839 | argv += optind; | |
840 | ||
841 | if(argc<1){ | |
842 | usage(); | |
843 | } | |
844 | ||
845 | ||
846 | /* Loop through all of the files */ | |
847 | while(*argv){ | |
848 | infile = *argv++; // get the file | |
849 | argc--; // decrement argument counter | |
850 | ||
851 | const char *name = af_identify_file_name(infile,1); | |
852 | if(!name) err(1,"%s",infile); | |
853 | ||
854 | if(opt_figure_media){ figure_media(infile);continue;} | |
855 | if(opt_identify) printf("%s is a %s file\n",infile,name); | |
856 | if(opt_info) info_file(infile); | |
857 | if(opt_validate) validate(infile); | |
858 | } | |
859 | #ifdef USE_S3 | |
860 | s3_audit(0); | |
861 | #endif | |
862 | return(0); | |
863 | } | |
864 | ||
865 |
0 | /* | |
1 | * afrecover.cpp | |
2 | * | |
3 | * Recover broken pages of an AFF file using the party bits | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "utils.h" | |
51 | ||
52 | #include <ctype.h> | |
53 | ||
54 | #include <zlib.h> | |
55 | #include <openssl/md5.h> | |
56 | #include <openssl/sha.h> | |
57 | #include <assert.h> | |
58 | ||
59 | #ifdef HAVE_UNISTD_H | |
60 | #include <unistd.h> | |
61 | #endif | |
62 | ||
63 | #ifdef HAVE_TERM_H | |
64 | #include <term.h> | |
65 | #endif | |
66 | ||
67 | #ifdef HAVE_NCURSES_TERM_H | |
68 | #include <ncurses/term.h> | |
69 | #endif | |
70 | ||
71 | #ifdef WIN32 | |
72 | #include "unix4win32.h" | |
73 | #include <malloc.h> | |
74 | #endif | |
75 | ||
76 | using namespace std; | |
77 | using namespace aff; | |
78 | ||
79 | const char *progname = "affix"; | |
80 | ||
81 | ||
82 | int opt_b = 0; | |
83 | ||
84 | ||
85 | void usage() | |
86 | { | |
87 | printf("usage: %s filename\n",progname); | |
88 | exit(0); | |
89 | } | |
90 | ||
91 | ||
92 | ||
93 | int recover(const char *fname) | |
94 | { | |
95 | AFFILE *af = af_open(fname,O_RDWR,0); | |
96 | if(!af) af_err(1,fname); | |
97 | ||
98 | /* Get the parity page */ | |
99 | size_t pagesize = af_page_size(af); | |
100 | u_char *pagebuf = (unsigned char *)calloc(pagesize,1); | |
101 | u_char *parity_buf = (unsigned char *)calloc(pagesize,1); | |
102 | u_char *my_parity_buf = (unsigned char *)calloc(pagesize,1); | |
103 | ||
104 | ||
105 | if(af_get_seg(af,AF_PARITY0,0,parity_buf,&pagesize)){ | |
106 | err(1,"Cannot read %s segment; cannot continue",AF_PARITY0); | |
107 | } | |
108 | ||
109 | /* Now, for every page: | |
110 | * 1. Read the page & the signature | |
111 | * 2. If the signature is good, add it into the parity buffer. | |
112 | * - If not, put it on the list of bad segments. | |
113 | */ | |
114 | seglist segments(af); | |
115 | seglist bad_sigs; | |
116 | seglist good_sigs; | |
117 | for(seglist::const_iterator seg = segments.begin(); | |
118 | seg != segments.end(); | |
119 | seg++){ | |
120 | ||
121 | if (seg->pagenumber()<0) continue; // only look for pages | |
122 | switch(af_sig_verify_seg(af,seg->name.c_str())){ | |
123 | case AF_ERROR_SIG_NO_CERT: | |
124 | errx(1,"%s: no public key in AFF file\n",af_filename(af)); | |
125 | case AF_ERROR_SIG_READ_ERROR: | |
126 | errx(1,"no signature for segment '%s' --- recovery cannot continue",seg->name.c_str()); | |
127 | case AF_ERROR_SIG_BAD: | |
128 | printf("%s has a bad signature\n",af_filename(af)); | |
129 | bad_sigs.push_back(*seg); | |
130 | break; | |
131 | case AF_SIG_GOOD: | |
132 | good_sigs.push_back(*seg); | |
133 | /* While the page is in the cache, make our parity buf */ | |
134 | pagesize = af_page_size(af); | |
135 | if(af_get_page(af,seg->pagenumber(),pagebuf,&pagesize)){ | |
136 | err(1,"cannot read %s\n",seg->name.c_str()); | |
137 | } | |
138 | for(u_int i=0;i<pagesize;i++){ | |
139 | my_parity_buf[i] ^= pagebuf[i]; | |
140 | } | |
141 | break; | |
142 | default: | |
143 | break; | |
144 | } | |
145 | } | |
146 | u_char *new_pagebuf = (unsigned char *)calloc(pagesize,1); | |
147 | ||
148 | if(bad_sigs.size()>1) errx(1,"This program can only repair 1 bad page at the moment."); | |
149 | if(bad_sigs.size()==0) errx(1,"There are no bad pages for this program to repair."); | |
150 | printf("Attempting to repair %s\n",bad_sigs[0].name.c_str()); | |
151 | ||
152 | /* Calculate the page buf */ | |
153 | for(u_int i=0;i<pagesize;i++){ | |
154 | new_pagebuf[i] = parity_buf[i] ^ my_parity_buf[i]; | |
155 | } | |
156 | ||
157 | /* Write the page back */ | |
158 | if(af_update_page(af,bad_sigs[0].pagenumber(),new_pagebuf,pagesize)){ | |
159 | err(1,"Cannot put page back"); | |
160 | } | |
161 | ||
162 | /* Now verify the signature */ | |
163 | int r = af_sig_verify_seg(af,bad_sigs[0].name.c_str()); | |
164 | if(r==AF_SIG_GOOD){ | |
165 | printf("Page %s successfully repaired\n",bad_sigs[0].name.c_str()); | |
166 | } | |
167 | else{ | |
168 | printf("Page %s could not be repaired; signature error code=%d\n",bad_sigs[0].name.c_str(),r); | |
169 | exit(1); | |
170 | } | |
171 | af_close(af); | |
172 | return 0; | |
173 | } | |
174 | ||
175 | ||
176 | ||
177 | int main(int argc,char **argv) | |
178 | { | |
179 | setvbuf(stdout,0,_IONBF,0); // turn off buffering | |
180 | int ch; | |
181 | while ((ch = getopt(argc, argv, "bh?v")) != -1) { | |
182 | switch (ch) { | |
183 | case 'h': | |
184 | case '?': | |
185 | default: | |
186 | usage(); | |
187 | break; | |
188 | case 'v': | |
189 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
190 | exit(0); | |
191 | ||
192 | } | |
193 | } | |
194 | argc -= optind; | |
195 | argv += optind; | |
196 | ||
197 | if(argc<1){ | |
198 | usage(); | |
199 | } | |
200 | ||
201 | recover(argv[0]); | |
202 | exit(0); | |
203 | } | |
204 | ||
205 |
0 | /* | |
1 | * afsegment.cpp | |
2 | * | |
3 | * segment manipulation tool | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2006 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | ||
51 | #include <limits.h> | |
52 | ||
53 | #ifdef HAVE_REGEX_H | |
54 | #include <regex.h> | |
55 | #endif | |
56 | ||
57 | #include <algorithm> | |
58 | #include <cstdlib> | |
59 | #include <vector> | |
60 | #include <string> | |
61 | ||
62 | #ifdef HAVE_CSTRING | |
63 | #include <cstring> | |
64 | #endif | |
65 | ||
66 | using namespace std; | |
67 | ||
68 | ||
69 | const char *progname = "afsegment"; | |
70 | ||
71 | int opt_create = 0; | |
72 | int opt_quad = 0; | |
73 | int opt_arg = 0; | |
74 | int opt_verbose = 0; | |
75 | int filecount = 0; | |
76 | int opt_debug = 0; | |
77 | int opt_x = 0; | |
78 | ||
79 | void usage() | |
80 | { | |
81 | printf("afsegment version %s\n",PACKAGE_VERSION); | |
82 | #ifdef REG_EXTENDED | |
83 | printf("usage: afsegment [options] file1.aff [file2.aff ...]\n"); | |
84 | printf("options:\n"); | |
85 | printf(" -c Create AFF files if they do not exist\n"); | |
86 | printf(" -ssegval Sets the value of a segment; may be repeated\n"); | |
87 | printf(" -psegname Prints the contents of the segment name for each file\n"); | |
88 | printf(" -V Just print the version number and exit.\n"); | |
89 | printf(" -dname Delete segment 'name'\n"); | |
90 | printf(" -h, -? Print this message\n"); | |
91 | printf(" -Q interpert 8-byte segments as a 64-bit value\n"); | |
92 | printf(" -A Print the 32-bit arg, not the segment value\n"); | |
93 | printf(" -x Print the segment as a hex string\n"); | |
94 | printf("\n"); | |
95 | printf("Values for segval:\n"); | |
96 | printf("\n"); | |
97 | printf("Setting the segment values:\n"); | |
98 | printf(" -sname=- Take the new value of segment 'name' from stdin\n"); | |
99 | printf(" -sname=val Sets segment 'name' to be 'val' \n"); | |
100 | printf(" -sname=<val Sets segment 'name' to be contents of file 'val'\n"); | |
101 | printf("\n"); | |
102 | printf("Setting the segment args:\n"); | |
103 | printf(" -sname/arg Sets segment 'name' arg to be 'arg' (may be repeated)\n"); | |
104 | printf("\n"); | |
105 | printf("Setting both the segment value and the arg:\n"); | |
106 | printf(" -sname/arg=val Sets both arg and val for segment 'name'\n"); | |
107 | printf(" -sname/arg=<file Sets the arg and take contents from file 'file'\n"); | |
108 | printf(" -sname/arg=- Sets the arg of segment 'name' and take the contents from stdin\n"); | |
109 | printf("\n"); | |
110 | printf("Note: All deletions are done first, then all updates. Don't specify the\n"); | |
111 | printf("same segment twice on one command line.\n"); | |
112 | #else | |
113 | printf("afsegment requires a functioning regex package to be installed\n"); | |
114 | #endif | |
115 | exit(0); | |
116 | } | |
117 | ||
118 | #ifdef REG_EXTENDED | |
119 | int get_segment_from_file(AFFILE *af,const char *segname,unsigned long arg,FILE *in) | |
120 | { | |
121 | u_char *value = (u_char *)malloc(0); | |
122 | int value_len = 0; | |
123 | ||
124 | while(!feof(in)){ | |
125 | char buf[4096]; | |
126 | int count; | |
127 | count = fread(buf,1,sizeof(buf),in); | |
128 | if(count>0){ | |
129 | value = (u_char *)realloc(value,value_len+count); | |
130 | memcpy(value+value_len,buf,count); | |
131 | value_len += count; | |
132 | } | |
133 | } | |
134 | int r = af_update_seg(af,segname,arg,value,value_len); | |
135 | free(value); | |
136 | return r; | |
137 | } | |
138 | ||
139 | ||
140 | void update_segment(AFFILE *af,const char *segname, | |
141 | const char *argstr,const char *segval) | |
142 | { | |
143 | unsigned long arg = 0; | |
144 | ||
145 | if(strlen(argstr)>1) arg = atoi(argstr+1); | |
146 | ||
147 | if(!strcmp(segval,"=-")){ | |
148 | get_segment_from_file(af,segname,arg,stdin); | |
149 | return; | |
150 | } | |
151 | if(!strncmp(segval,"=<",2)){ | |
152 | FILE *f = fopen(segval+2,"rb"); | |
153 | if(!f) err(1,"fopen(%s)",segval+2); | |
154 | get_segment_from_file(af,segname,arg,f); | |
155 | fclose(f); | |
156 | return; | |
157 | } | |
158 | segval++; // skip past the "=" | |
159 | int r = af_update_seg(af,segname,arg,(const u_char *)segval,strlen(segval)); | |
160 | if(r) warn("af_update(%s,%s) ",af_filename(af),segname); | |
161 | } | |
162 | ||
163 | ||
164 | char *make_re_string(const char *buf,regmatch_t *match,int num) | |
165 | { | |
166 | int len = match[num].rm_eo - match[num].rm_so; | |
167 | char *ret = (char *)malloc(len+1); | |
168 | memcpy(ret,buf+match[num].rm_so,len); | |
169 | ret[len] = '\000'; | |
170 | return ret; | |
171 | } | |
172 | ||
173 | ||
174 | vector<string>del_segs; | |
175 | vector<string>new_segs; | |
176 | vector<string>print_segs; | |
177 | int flags=O_RDONLY; | |
178 | int openmode = 0666; | |
179 | regex_t re; | |
180 | ||
181 | void process(const char *fn) | |
182 | { | |
183 | AFFILE *af = af_open(fn,flags,openmode); | |
184 | if(af){ | |
185 | vector<string>::iterator i; | |
186 | ||
187 | for(i=del_segs.begin();i!=del_segs.end();i++){ | |
188 | if(af_del_seg(af,i->c_str())){ | |
189 | warnx("af_del_seg(%s): cannot delete segment '%s' ",fn,i->c_str()); | |
190 | } | |
191 | else { | |
192 | printf("%s: '%s' deleted\n",fn,i->c_str()); | |
193 | } | |
194 | } | |
195 | for(i=new_segs.begin();i!=new_segs.end();i++){ | |
196 | regmatch_t match[10]; | |
197 | memset(match,0,sizeof(match)); | |
198 | if(regexec(&re,i->c_str(),10,match,0)==0){ | |
199 | char *segname = make_re_string(i->c_str(),match,1); | |
200 | char *argstr = make_re_string(i->c_str(),match,2); | |
201 | char *segval = make_re_string(i->c_str(),match,3); | |
202 | update_segment(af,segname,argstr,segval); | |
203 | free(segname); | |
204 | free(argstr); | |
205 | free(segval); | |
206 | } | |
207 | } | |
208 | for(i=print_segs.begin();i!=print_segs.end();i++){ | |
209 | size_t len = 0; | |
210 | const char *segname = i->c_str(); | |
211 | if(opt_debug) fprintf(stderr," %s: \n",segname); | |
212 | unsigned char *buf=0; | |
213 | if(af_get_seg(af,segname,0,0,&len)){ | |
214 | #if HAVE_ISATTY | |
215 | if(isatty(fileno(stdout))){ | |
216 | fprintf(stderr,"%s: segment %s not found\n",fn,segname); | |
217 | continue; | |
218 | } | |
219 | #endif | |
220 | if(opt_debug) fprintf(stderr," <<not found>>\n"); | |
221 | continue; | |
222 | } | |
223 | ||
224 | buf = (u_char *)malloc(len+1); | |
225 | if(!buf) err(1,"malloc"); | |
226 | unsigned long arg = 0; | |
227 | buf[len] = 0; | |
228 | if(af_get_seg(af,segname,&arg,buf,&len)){ | |
229 | af_err(1,"af_get_seg"); // this shoudln't fail here | |
230 | free(buf); | |
231 | continue; | |
232 | } | |
233 | if(opt_debug) fprintf(stderr," arg=%lu len=%zd\n",arg,len); | |
234 | int p = 1; | |
235 | ||
236 | if(filecount>1) printf("%s:",fn); | |
237 | if(print_segs.size()>1) printf("%s=",segname); | |
238 | if(opt_quad && len==8){ | |
239 | uint64_t quad = af_decode_q(buf); | |
240 | printf("%"I64u"\n",quad); | |
241 | p = 0; | |
242 | } | |
243 | ||
244 | if(opt_arg){ | |
245 | printf("%lu\n",arg); | |
246 | p = 0; | |
247 | } | |
248 | ||
249 | if(p){ | |
250 | for(u_int i=0;i<len;i++){ | |
251 | putchar(buf[i]); | |
252 | } | |
253 | } | |
254 | if(filecount>1) printf("\n"); | |
255 | fflush(stdout); | |
256 | if(buf) free(buf); | |
257 | } | |
258 | af_close(af); | |
259 | if(opt_x) printf("\n"); | |
260 | } | |
261 | else { | |
262 | af_err(1,"af_open(%s) failed:",fn); | |
263 | } | |
264 | } | |
265 | ||
266 | int main(int argc,char **argv) | |
267 | { | |
268 | ||
269 | int ch; | |
270 | while ((ch = getopt(argc, argv, "cd:Vp:s::h?QADx")) != -1) { | |
271 | switch (ch) { | |
272 | case 'c': | |
273 | flags |= O_CREAT; | |
274 | openmode = 0666; | |
275 | break; | |
276 | case 'Q': opt_quad=1;break; | |
277 | case 'A': opt_arg=1;break; | |
278 | case 'd': | |
279 | if(optarg==0) usage(); | |
280 | del_segs.push_back(optarg); flags |= O_RDWR;break; | |
281 | case 'D': | |
282 | opt_debug=1; | |
283 | break; | |
284 | case 'p': | |
285 | if(optarg==0) usage(); | |
286 | print_segs.push_back(optarg); break; | |
287 | case 's': | |
288 | if(optarg==0) usage(); | |
289 | if(strlen(optarg)==0) usage(); | |
290 | new_segs.push_back(optarg); flags |= O_RDWR;break; | |
291 | case 'x': | |
292 | opt_x++; | |
293 | break; | |
294 | case 'h': | |
295 | case '?': | |
296 | default: | |
297 | usage(); | |
298 | exit(0); | |
299 | case 'V': | |
300 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
301 | exit(0); | |
302 | } | |
303 | } | |
304 | argc -= optind; | |
305 | argv += optind; | |
306 | ||
307 | if(argc<1){ | |
308 | usage(); | |
309 | } | |
310 | ||
311 | if(regcomp(&re,"([^/=]*)(/[0-9]+)?(=.*)?",REG_EXTENDED|REG_ICASE)){ | |
312 | err(1,"regcomp"); | |
313 | } | |
314 | ||
315 | filecount = argc; | |
316 | while(*argv){ | |
317 | fflush(stdout); | |
318 | if(opt_debug) fprintf(stderr,"%s:\n",*argv); | |
319 | process(*argv); | |
320 | argv++; | |
321 | argc--; | |
322 | } | |
323 | exit(0); | |
324 | } | |
325 | #else | |
326 | int main(int argc,char **argv) | |
327 | { | |
328 | usage(); | |
329 | exit(1); | |
330 | } | |
331 | #endif |
0 | /* | |
1 | * afsign.cpp: | |
2 | * | |
3 | * Sign an existing AFF file. | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2007 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | #include "affconfig.h" | |
47 | #include "afflib.h" | |
48 | #include "afflib_i.h" | |
49 | ||
50 | #ifdef USE_AFFSIGS | |
51 | ||
52 | #include "utils.h" | |
53 | #include "base64.h" | |
54 | ||
55 | #include <stdio.h> | |
56 | #include <algorithm> | |
57 | #include <vector> | |
58 | #include <iostream> | |
59 | #include <openssl/pem.h> | |
60 | #include <openssl/x509.h> | |
61 | ||
62 | ||
63 | #include "aff_bom.h" | |
64 | ||
65 | int opt_note = 0; | |
66 | const char *opt_sign_key_file = 0; | |
67 | const char *opt_sign_cert_file = 0; | |
68 | ||
69 | using namespace std; | |
70 | using namespace aff; | |
71 | ||
72 | const char *progname = "afsign"; | |
73 | ||
74 | void usage() | |
75 | { | |
76 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
77 | printf("usage: %s [options] filename.aff\n",progname); | |
78 | printf("This program will:\n"); | |
79 | printf(" * Sign each segment if there are no segment signatures.\n"); | |
80 | printf(" * Write signed chain-of-custody Bill of Materials segment.\n"); | |
81 | printf("\nSignature Options:\n"); | |
82 | printf(" -k filename.key = specify private key for signing\n"); | |
83 | printf(" -c filename.cer = specify a X.509 certificate that matches the private key\n"); | |
84 | printf(" (by default, the file is assumed to be the same one\n"); | |
85 | printf(" provided with the -k option.)\n"); | |
86 | printf(" -Z = ZAP (remove) all signature segments.\n"); | |
87 | printf("options:\n"); | |
88 | printf(" -n --- ask for a chain-of-custody note.\n"); | |
89 | printf(" -v --- Just print the version number and exit.\n"); | |
90 | exit(0); | |
91 | } | |
92 | ||
93 | ||
94 | int afsign(const char *fn) | |
95 | { | |
96 | AFFILE *af = af_open(fn,O_RDWR,0); | |
97 | if(!af) af_err(1,"%s",fn); | |
98 | ||
99 | struct af_vnode_info vni; | |
100 | if(af_vstat(af,&vni)) err(1,"af_vstat"); | |
101 | ||
102 | if(vni.supports_metadata==0){ | |
103 | /* If it is a raw file, we can create an AFM file to sign */ | |
104 | if(vni.is_raw==0) errx(1,"%s: file does not support metadata. Cannot sign\n",fn); | |
105 | af_close(af); // afm will open it | |
106 | char afmfile[MAXPATHLEN+1]; | |
107 | char file000[MAXPATHLEN+1]; | |
108 | char extension[MAXPATHLEN+1]; | |
109 | strcpy(afmfile,fn); | |
110 | char *period = strrchr(afmfile,'.'); | |
111 | if(!period) errx(1,"%s: file does not support metadata and lacks a file extension,\n" | |
112 | "which is needed to create an AFM file '%s\n",afmfile,fn); | |
113 | strcpy(extension,period+1); // get the extension | |
114 | ||
115 | /* If the file being opened is not a .000 file, and a .000 file exists, do not proceed */ | |
116 | strcpy(period,".000"); | |
117 | strcpy(file000,afmfile); // make the 000 file | |
118 | strcpy(period,".afm"); | |
119 | ||
120 | if(strcmp(extension,"000")!=0){ | |
121 | if(access(file000,F_OK)==0){ | |
122 | errx(1,"Can't create .afm file because %s exists.\n",file000); | |
123 | } | |
124 | } | |
125 | ||
126 | strcpy(period,".afm"); // we are now going to make an afm file | |
127 | af = af_open(afmfile,O_RDWR|O_CREAT,0600); | |
128 | if(!af) af_err(1,"%s: file does not support metadata and cannot create AFM file '%s\n",fn,afmfile); | |
129 | if(strcmp(extension,"000")!=0){ | |
130 | af_update_seg(af,AF_RAW_IMAGE_FILE_EXTENSION,0,(const u_char *)extension,strlen(extension)); | |
131 | af_close(af); | |
132 | unlink(file000); // get rid of that .000 file | |
133 | af = af_open(afmfile,O_RDWR,0600); | |
134 | if(!af) af_err(1,"%s: Created AFM file but cannot re-open it\n",fn); | |
135 | /* Read the first byte to force a call to afm_split_raw_setup(). | |
136 | * The results of the read don't matter, but we better be able to read. | |
137 | */ | |
138 | u_char buf[1]; | |
139 | if(af_read(af,buf,1)!=1){ | |
140 | err(1,"Cannot read first byte of %s",fn); | |
141 | } | |
142 | af_seek(af,0L,0); | |
143 | } | |
144 | } | |
145 | ||
146 | seglist segments(af); | |
147 | ||
148 | if(isatty(fileno(stdout))){ | |
149 | printf("Signing segments...\n"); | |
150 | fflush(stdout); | |
151 | } | |
152 | ||
153 | bool signed_unsigned_segments = false; | |
154 | if(segments.has_signed_segments()==false){ | |
155 | if(af_set_sign_files(af,opt_sign_key_file,opt_sign_cert_file)){ | |
156 | errx(1,"key file '%s' or certificate file '%s' is invalid", | |
157 | opt_sign_key_file,opt_sign_cert_file); | |
158 | } | |
159 | int r = af_sign_all_unsigned_segments(af); | |
160 | if(r<0) af_err(1,"%s: all unsigned segments cannot be signed.",fn); | |
161 | if(r>0) signed_unsigned_segments = true; | |
162 | } | |
163 | ||
164 | aff_bom bom(opt_note); | |
165 | if(bom.read_files(opt_sign_cert_file,opt_sign_key_file)) err(1,"Can't read signature files???"); | |
166 | ||
167 | u_char *pagebuf = (unsigned char *)calloc(af_page_size(af),1); | |
168 | u_char *parity_buf = (unsigned char *)calloc(af_page_size(af),1); | |
169 | bool compute_parity = true; // do we need to compute the parity? | |
170 | ||
171 | /* Create the parity buffer if it doesn't exist. If the parity buffer exists, we'll just trust it. | |
172 | * We could do a two-pass here, one for creating the parity buffer, another for creating the BOM. | |
173 | * But that would require reading the data twice; hence this extra layer of complexity. | |
174 | */ | |
175 | size_t parity_buf_len = af_page_size(af); | |
176 | if(af_get_seg(af,AF_PARITY0,0,parity_buf,&parity_buf_len)==0){ | |
177 | compute_parity = false; // no need to compute it; we read it | |
178 | } | |
179 | ||
180 | for(seglist::const_iterator seg = segments.begin(); seg!= segments.end();seg++){ | |
181 | const char *segname = seg->name.c_str(); | |
182 | ||
183 | if(isatty(fileno(stdout))){ | |
184 | printf("\rCalculating BOM for segment %s... ",segname); | |
185 | printf("\n"); | |
186 | fflush(stdout); | |
187 | } | |
188 | ||
189 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
190 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
191 | int sigmode = 0; | |
192 | int64_t pagenumber = af_segname_page_number(segname); | |
193 | if(pagenumber>=0){ | |
194 | /* Page segments must run in SIGNATURE_MODE1 - the actual data in the page */ | |
195 | size_t this_pagesize = af_page_size(af); | |
196 | if(af_get_page(af,pagenumber,pagebuf,&this_pagesize)){ | |
197 | free(pagebuf); | |
198 | return -1; | |
199 | } | |
200 | /* Add to parity buf if we are making a parity page*/ | |
201 | if(compute_parity){ | |
202 | for(u_int i=0;i<this_pagesize;i++){ | |
203 | parity_buf[i] ^= pagebuf[i]; | |
204 | } | |
205 | } | |
206 | aff_bom::make_hash(seghash,0,segname,pagebuf,this_pagesize); | |
207 | sigmode = AF_SIGNATURE_MODE1; | |
208 | } | |
209 | else{ | |
210 | /* Non-Page segments can be run in SIGNATURE_MODE0 - the actual data in the file */ | |
211 | size_t seglen=0; | |
212 | if(af_get_seg(af,segname,0,0,&seglen)){ | |
213 | err(1,"Cannot read length of segment '%s' on input file %s", segname,af_filename(af)); | |
214 | } | |
215 | unsigned char *segbuf = (unsigned char *)malloc(seglen); | |
216 | if(!segbuf){ | |
217 | err(1,"Cannot allocated %d bytes for segment '%s' in %s", | |
218 | (int)seglen,segname,af_filename(af)); | |
219 | } | |
220 | /* Now get the raw source segment */ | |
221 | unsigned long arg=0; | |
222 | if(af_get_seg(af,segname,&arg,segbuf,&seglen)){ | |
223 | err(1,"Cannot read segment '%s' in %s. Deleteing output file", segname,af_filename(af)); | |
224 | } | |
225 | aff_bom::make_hash(seghash,arg,segname,segbuf,seglen); | |
226 | sigmode = AF_SIGNATURE_MODE0; | |
227 | free(segbuf); | |
228 | } | |
229 | bom.add(segname,sigmode,seghash,seghash_len); // add to the BOM | |
230 | } | |
231 | ||
232 | /* If we have been making the parity buf: | |
233 | * 1 - Write it out; add it to the BOM | |
234 | * 2 - Write out the signature segment for the parity buf; add it to the bom | |
235 | */ | |
236 | if(compute_parity){ | |
237 | if(af_update_seg(af,AF_PARITY0,0,parity_buf,af_page_size(af))) err(1,"Can't write %s",AF_PARITY0); | |
238 | ||
239 | /* Add the parity page that we made to the BOM */ | |
240 | u_char seghash[32]; /* resultant message digest; could be any size */ | |
241 | unsigned int seghash_len = sizeof(seghash); /* big enough to hold SHA256 */ | |
242 | ||
243 | aff_bom::make_hash(seghash,0,AF_PARITY0,parity_buf,af_page_size(af)); | |
244 | bom.add(AF_PARITY0,AF_SIGNATURE_MODE0,seghash,seghash_len); | |
245 | ||
246 | ||
247 | /* If we are signing segments for the first time, we need to sign the parity page | |
248 | * and then add the parity page's signature segment to the BOM as well. | |
249 | */ | |
250 | if(signed_unsigned_segments){ | |
251 | af_sign_seg(af,AF_PARITY0); // sign the parity segment if we signed the other segments | |
252 | bom.add(af,AF_PARITY0_SIG); | |
253 | ||
254 | u_char buf[1024]; | |
255 | size_t buflen = sizeof(buf); | |
256 | ||
257 | const char *segname = AF_PARITY0_SIG; | |
258 | if(af_get_seg(af,segname,0,buf,&buflen)==0){ // Get the signature | |
259 | aff_bom::make_hash(seghash,0,segname,buf,buflen); // and add it to the BOM | |
260 | bom.add(segname,AF_SIGNATURE_MODE0,seghash,seghash_len); | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | if(isatty(fileno(stdout))){ | |
266 | printf(" \r\n"); | |
267 | fflush(stdout); | |
268 | } | |
269 | ||
270 | bom.close(); | |
271 | bom.write(af,segments); | |
272 | af_close(af); | |
273 | return 0; | |
274 | } | |
275 | ||
276 | int remove_signatures(const char *fn) | |
277 | { | |
278 | AFFILE *af = af_open(fn,O_RDWR,0); | |
279 | if(!af) af_err(1,"%s",fn); | |
280 | ||
281 | aff::seglist sl(af); | |
282 | for(aff::seglist::const_iterator i = sl.begin(); | |
283 | i!= sl.end(); | |
284 | i++){ | |
285 | if(af_is_signature_segment(i->name.c_str()) || i->name==AF_SIGN256_CERT){ | |
286 | cout << "Deleting " << i->name << "\n"; | |
287 | af_del_seg(af,i->name.c_str()); | |
288 | } | |
289 | } | |
290 | af_close(af); | |
291 | return 0; | |
292 | } | |
293 | ||
294 | int main(int argc,char **argv) | |
295 | { | |
296 | int bflag, ch; | |
297 | int opt_zap = 0; | |
298 | ||
299 | bflag = 0; | |
300 | while ((ch = getopt(argc, argv, "nk:c:h?vZ")) != -1) { | |
301 | switch (ch) { | |
302 | case 'n': opt_note = 1;break; | |
303 | case 'k': | |
304 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
305 | opt_sign_key_file = optarg; | |
306 | break; | |
307 | case 'c': | |
308 | if(access(optarg,R_OK)) err(1,"%s",optarg); | |
309 | opt_sign_cert_file = optarg; | |
310 | break; | |
311 | case 'v': | |
312 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
313 | exit(0); | |
314 | case 'Z': | |
315 | opt_zap = 1; | |
316 | break; | |
317 | case 'h': | |
318 | case '?': | |
319 | default: | |
320 | usage(); | |
321 | break; | |
322 | } | |
323 | } | |
324 | argc -= optind; | |
325 | argv += optind; | |
326 | ||
327 | if(opt_sign_cert_file==0) opt_sign_cert_file=opt_sign_key_file; // if not set, make same as key file | |
328 | ||
329 | ||
330 | if(argc!=1){ | |
331 | usage(); | |
332 | } | |
333 | ||
334 | if(opt_zap) return remove_signatures(argv[0]); | |
335 | ||
336 | /* We either need both a key file and a cert file, or neither */ | |
337 | if((opt_sign_key_file==0) || (opt_sign_cert_file==0)){ | |
338 | errx(1,"Both a private key and a certificate must be specified."); | |
339 | } | |
340 | ||
341 | ||
342 | return afsign(argv[0]); | |
343 | } | |
344 | #else | |
345 | int main(int argc,char **argv) | |
346 | { | |
347 | fprintf(stderr,"afflib compiled without USE_AFFSIGS. afsign cannot run.\n"); | |
348 | exit(-1); | |
349 | } | |
350 | ||
351 | #endif | |
352 |
0 | /* | |
1 | * afstats.cpp: | |
2 | * | |
3 | * print specific statistics about one or more AFF files. | |
4 | * Ideally, we can get the stats from the metadata, but this program will | |
5 | * calculate it if necessary. | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (c) 2005 | |
10 | * Simson L. Garfinkel and Basis Technology, Inc. | |
11 | * All rights reserved. | |
12 | * | |
13 | * This code is derrived from software contributed by | |
14 | * Simson L. Garfinkel | |
15 | * | |
16 | * Redistribution and use in source and binary forms, with or without | |
17 | * modification, are permitted provided that the following conditions | |
18 | * are met: | |
19 | * 1. Redistributions of source code must retain the above copyright | |
20 | * notice, this list of conditions and the following disclaimer. | |
21 | * 2. Redistributions in binary form must reproduce the above copyright | |
22 | * notice, this list of conditions and the following disclaimer in the | |
23 | * documentation and/or other materials provided with the distribution. | |
24 | * 3. All advertising materials mentioning features or use of this software | |
25 | * must display the following acknowledgement: | |
26 | * This product includes software developed by Simson L. Garfinkel | |
27 | * and Basis Technology Corp. | |
28 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
29 | * contributors to this program may be used to endorse or promote | |
30 | * products derived from this software without specific prior written | |
31 | * permission. | |
32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
34 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
35 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
36 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
37 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
38 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
45 | * SUCH DAMAGE. | |
46 | */ | |
47 | ||
48 | ||
49 | #include "affconfig.h" | |
50 | #include "afflib.h" | |
51 | #include "afflib_i.h" | |
52 | ||
53 | #include <openssl/md5.h> | |
54 | #include <openssl/sha.h> | |
55 | #include <zlib.h> | |
56 | #include <assert.h> | |
57 | ||
58 | #ifdef HAVE_ERR_H | |
59 | #include <err.h> | |
60 | #endif | |
61 | ||
62 | #ifdef HAVE_UNISTD_H | |
63 | #include <unistd.h> | |
64 | #endif | |
65 | ||
66 | #ifdef HAVE_UNISTD_H | |
67 | #include <unistd.h> | |
68 | #endif | |
69 | ||
70 | #ifdef HAVE_TERM_H | |
71 | #include <term.h> | |
72 | #endif | |
73 | ||
74 | #ifdef HAVE_NCURSES_TERM_H | |
75 | #include <ncurses/term.h> | |
76 | #endif | |
77 | ||
78 | #ifdef HAVE_NCURSES_H | |
79 | #include <ncurses.h> | |
80 | #endif | |
81 | ||
82 | #ifdef WIN32 | |
83 | #include "unix4win32.h" | |
84 | #include <malloc.h> | |
85 | #endif | |
86 | ||
87 | const char *progname = "afstats"; | |
88 | int opt_m = 0; | |
89 | ||
90 | void usage() | |
91 | { | |
92 | printf("%s version %s\n\n",progname,PACKAGE_VERSION); | |
93 | printf("usage: %s [options] infile(s)\n",progname); | |
94 | printf(" -m = print all output in megabytes\n"); | |
95 | printf(" -v = Just print the version number and exit.\n"); | |
96 | exit(0); | |
97 | } | |
98 | ||
99 | ||
100 | void title() | |
101 | { | |
102 | printf("fname\tbytes\tcompressed\n"); | |
103 | } | |
104 | ||
105 | void print_size(uint64_t s) | |
106 | { | |
107 | if(opt_m){ | |
108 | printf("%u",(unsigned int)(s/(1024*1024))); | |
109 | return; | |
110 | } | |
111 | printf("%"I64u,s); | |
112 | } | |
113 | ||
114 | void afstats_title() | |
115 | { | |
116 | printf("Name\tAF_IMAGESIZE\tCompressed\tUncompressed\tBlank\tBad\n"); | |
117 | } | |
118 | ||
119 | void afstats(const char *fname) | |
120 | { | |
121 | AFFILE *af = af_open(fname,O_RDONLY,0); | |
122 | if(!af) af_err(1,"af_open(%s)",fname); | |
123 | ||
124 | printf("%s\t",fname); | |
125 | ||
126 | long unsigned int segsize=0; | |
127 | ||
128 | int64_t imagesize=0; | |
129 | int64_t blanksectors=0; | |
130 | int64_t badsectors=0; | |
131 | af_get_segq(af,AF_IMAGESIZE,&imagesize); | |
132 | if(af_get_seg(af,AF_PAGESIZE,&segsize,0,0)){ | |
133 | af_get_seg(af,AF_SEGSIZE_D,&segsize,0,0); // check for oldstype | |
134 | } | |
135 | af_get_segq(af,AF_BADSECTORS,&badsectors); | |
136 | af_get_segq(af,AF_BLANKSECTORS,&blanksectors); | |
137 | ||
138 | print_size(imagesize); | |
139 | printf("\t"); | |
140 | fflush(stdout); | |
141 | ||
142 | int64_t compressed_bytes = 0; | |
143 | int64_t uncompressed_bytes = 0; | |
144 | ||
145 | /* Now read through all of the segments and count the number of | |
146 | * data segments. We know the uncompressed size... | |
147 | */ | |
148 | af_rewind_seg(af); | |
149 | char segname[AF_MAX_NAME_LEN+1]; | |
150 | size_t datalen; | |
151 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,&datalen)==0){ | |
152 | int64_t page_num = af_segname_page_number(segname); | |
153 | if(page_num>=0){ | |
154 | compressed_bytes += datalen; | |
155 | uncompressed_bytes += segsize; | |
156 | } | |
157 | } | |
158 | if(uncompressed_bytes > imagesize) uncompressed_bytes = imagesize; | |
159 | ||
160 | print_size(compressed_bytes); | |
161 | printf("\t"); | |
162 | print_size(uncompressed_bytes); | |
163 | printf(" %"I64d" %"I64d,blanksectors,badsectors); | |
164 | putchar('\n'); | |
165 | ||
166 | ||
167 | } | |
168 | ||
169 | ||
170 | ||
171 | ||
172 | int main(int argc,char **argv) | |
173 | { | |
174 | int ch; | |
175 | while ((ch = getopt(argc, argv, "mh?V")) != -1) { | |
176 | switch (ch) { | |
177 | case 'm': | |
178 | opt_m = 1; | |
179 | break; | |
180 | case 'h': | |
181 | case '?': | |
182 | default: | |
183 | usage(); | |
184 | break; | |
185 | case 'V': | |
186 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
187 | exit(0); | |
188 | } | |
189 | } | |
190 | argc -= optind; | |
191 | argv += optind; | |
192 | ||
193 | if(argc<1){ | |
194 | usage(); | |
195 | } | |
196 | ||
197 | /* Each argument is now a file. Process each one */ | |
198 | afstats_title(); | |
199 | while(*argv){ | |
200 | afstats(*argv++); | |
201 | argc--; | |
202 | } | |
203 | exit(0); | |
204 | } | |
205 | ||
206 |
0 | /* | |
1 | * afverify.cpp: | |
2 | * | |
3 | * Verify the digital signature on a signed file | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2007 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | #include "affconfig.h" | |
47 | #include "afflib.h" | |
48 | #include "afflib_i.h" | |
49 | ||
50 | #include "utils.h" | |
51 | #include "base64.h" | |
52 | ||
53 | #include "aff_bom.h" | |
54 | ||
55 | #include <stdio.h> | |
56 | #include <algorithm> | |
57 | #include <vector> | |
58 | #include <iostream> | |
59 | #include <openssl/pem.h> | |
60 | #include <openssl/x509.h> | |
61 | ||
62 | using namespace std; | |
63 | using namespace aff; | |
64 | ||
65 | const char *progname = "afcrypto"; | |
66 | int opt_change = 0; | |
67 | int opt_verbose = 0; | |
68 | int opt_all = 0; | |
69 | ||
70 | void usage() | |
71 | { | |
72 | printf("afverify version %s\n",PACKAGE_VERSION); | |
73 | printf("usage: afverify [options] filename.aff\n"); | |
74 | printf("Verifies the digital signatures on a file\n"); | |
75 | printf("options:\n"); | |
76 | printf(" -a --- print all segments\n"); | |
77 | printf(" -V --- Just print the version number and exit.\n"); | |
78 | printf(" -v --- verbose\n"); | |
79 | ||
80 | OpenSSL_add_all_digests(); | |
81 | const EVP_MD *sha256 = EVP_get_digestbyname("sha256"); | |
82 | if(sha256){ | |
83 | printf(" SHA256 is operational\n"); | |
84 | } else { | |
85 | printf("Warning: EVP_get_digestbyname(\"sha256\") fails\n"); | |
86 | } | |
87 | exit(0); | |
88 | } | |
89 | ||
90 | void print_x509_info(X509 *cert) | |
91 | { | |
92 | printf("SIGNING CERTIFICATE :\n"); | |
93 | printf(" Subject: "); X509_NAME_print_ex_fp(stdout,X509_get_subject_name(cert),0,XN_FLAG_SEP_CPLUS_SPC); | |
94 | printf("\n"); | |
95 | printf(" Issuer: "); X509_NAME_print_ex_fp(stdout,X509_get_issuer_name(cert),0,XN_FLAG_SEP_CPLUS_SPC); | |
96 | printf("\n"); | |
97 | ASN1_INTEGER *sn = X509_get_serialNumber(cert); | |
98 | if(sn){ | |
99 | long num = ASN1_INTEGER_get(sn); | |
100 | if(num>0) printf(" Certificate serial number: %ld\n",num); | |
101 | } | |
102 | printf("\n"); | |
103 | } | |
104 | ||
105 | #ifdef USE_AFFSIGS | |
106 | #include "expat.h" | |
107 | void startElement(void *userData, const char *name, const char **atts); | |
108 | void endElement(void *userData, const char *name); | |
109 | void cHandler(void *userData,const XML_Char *s,int len); | |
110 | ||
111 | class segmenthash { | |
112 | public: | |
113 | segmenthash():total_validated(0),total_invalid(0),sigmode(0),in_cert(false), | |
114 | in_seghash(false),get_cdata(false),arg(0),seglen(0), | |
115 | get_cdata_segment(0),af(0),cert(0),pubkey(0) { | |
116 | ||
117 | parser = XML_ParserCreate(NULL); | |
118 | XML_SetUserData(parser, this); | |
119 | XML_SetElementHandler(parser, ::startElement, ::endElement); | |
120 | XML_SetCharacterDataHandler(parser,cHandler); | |
121 | }; | |
122 | int parse(const char *buf,int len) { return XML_Parse(parser, buf, len, 1);} | |
123 | XML_Parser parser; | |
124 | int total_validated; | |
125 | int total_invalid; | |
126 | int sigmode; | |
127 | bool in_cert; | |
128 | bool in_seghash; | |
129 | bool get_cdata; | |
130 | string segname; | |
131 | string alg; | |
132 | string cdata; | |
133 | int arg; | |
134 | int seglen; | |
135 | const char *get_cdata_segment; // just get this segment | |
136 | AFFILE *af; // if set, we are parsing crypto | |
137 | X509 *cert; // public key used to sign | |
138 | EVP_PKEY *pubkey; | |
139 | void clear(){ | |
140 | segname=""; | |
141 | cdata=""; | |
142 | sigmode=0; | |
143 | alg=""; | |
144 | seglen=0; | |
145 | } | |
146 | ~segmenthash(){ | |
147 | if(cert) X509_free(cert); | |
148 | if(parser) XML_ParserFree(parser); | |
149 | } | |
150 | void startElement(const char *name,const char **atts); | |
151 | void endElement(const char *name); | |
152 | }; | |
153 | ||
154 | int count=0; | |
155 | void startElement(void *userData, const char *name, const char **atts) | |
156 | { | |
157 | segmenthash *sh = (segmenthash *)userData; | |
158 | sh->startElement(name,atts); | |
159 | } | |
160 | ||
161 | void segmenthash::startElement(const char *name,const char **atts) | |
162 | { | |
163 | clear(); | |
164 | if(strcmp(name,AF_XML_SEGMENT_HASH)==0){ | |
165 | for(int i=0;atts[i];i+=2){ | |
166 | const char *name = atts[i]; | |
167 | const char *value = atts[i+1]; | |
168 | if(!strcmp(name,"segname")) segname = value; | |
169 | if(!strcmp(name,"sigmode")) sigmode = atoi(value); | |
170 | if(!strcmp(name,"alg")) alg = value; | |
171 | if(!strcmp(name,"seglen")) seglen = atoi(value); | |
172 | } | |
173 | in_seghash = true; | |
174 | get_cdata = true; | |
175 | return; | |
176 | } | |
177 | if(strcmp(name,"signingcertificate")==0){ | |
178 | in_cert = true; | |
179 | get_cdata = true; | |
180 | return; | |
181 | } | |
182 | if(get_cdata_segment && strcmp(name,get_cdata_segment)==0){ | |
183 | get_cdata = true; | |
184 | return; | |
185 | } | |
186 | } | |
187 | ||
188 | void cHandler(void *userData,const XML_Char *s,int len) | |
189 | { | |
190 | segmenthash *sh = (segmenthash *)userData; | |
191 | if(sh->get_cdata==false) return; // don't want cdata | |
192 | sh->cdata.append(s,len); | |
193 | } | |
194 | ||
195 | void endElement(void *userData, const char *name) | |
196 | { | |
197 | segmenthash *sh = (segmenthash *)userData; | |
198 | sh->endElement(name); | |
199 | } | |
200 | ||
201 | ||
202 | void segmenthash::endElement(const char *name) | |
203 | { | |
204 | if(get_cdata_segment && strcmp(name,get_cdata_segment)==0){ | |
205 | get_cdata = false; | |
206 | XML_StopParser(parser,0); | |
207 | return; | |
208 | } | |
209 | if(in_seghash && af){ | |
210 | if(segname.size()==0) return; // don't have a segment name | |
211 | /* Try to validate this one */ | |
212 | size_t hashbuf_len = cdata.size() + 2; | |
213 | u_char *hashbuf = (u_char *)malloc(hashbuf_len); | |
214 | hashbuf_len = b64_pton_slg((char *)cdata.c_str(),cdata.size(),hashbuf,hashbuf_len); | |
215 | if(alg=="sha256"){ | |
216 | /* TODO: Don't re-validate something that's already validated */ | |
217 | int r = af_hash_verify_seg2(af,segname.c_str(),hashbuf,hashbuf_len,sigmode); | |
218 | if(r==AF_HASH_VERIFIES){ | |
219 | total_validated++; | |
220 | } | |
221 | else total_invalid++; | |
222 | } | |
223 | free(hashbuf); | |
224 | in_seghash = false; | |
225 | } | |
226 | if(in_cert && af){ | |
227 | BIO *cert_bio = BIO_new_mem_buf((char *)cdata.c_str(),cdata.size()); | |
228 | PEM_read_bio_X509(cert_bio,&cert,0,0); | |
229 | BIO_free(cert_bio); | |
230 | pubkey = X509_get_pubkey(cert); | |
231 | in_cert = false; | |
232 | } | |
233 | cdata = ""; // erase it | |
234 | } | |
235 | ||
236 | string get_xml_field(const char *buf,const char *field) | |
237 | { | |
238 | segmenthash sh; | |
239 | sh.get_cdata_segment = field; | |
240 | sh.parse(buf,strlen(buf)); | |
241 | return sh.cdata; | |
242 | } | |
243 | ||
244 | /* verify the chain signature; return 0 if successful, -1 if failed. | |
245 | * The signature is a block of XML with a base64 encoded at the end. | |
246 | */ | |
247 | int verify_bom_signature(AFFILE *af,const char *buf) | |
248 | { | |
249 | OpenSSL_add_all_digests(); | |
250 | const EVP_MD *sha256 = EVP_get_digestbyname("sha256"); | |
251 | ||
252 | if(!sha256){ | |
253 | fprintf(stderr,"OpenSSL does not have SHA256; signatures cannot be verified.\n"); | |
254 | return -1; | |
255 | } | |
256 | ||
257 | const char *cce = "</" AF_XML_AFFBOM ">\n"; | |
258 | const char *chain_end = strstr(buf,cce); | |
259 | if(!chain_end){ | |
260 | warn("end of chain XML can't be found\n"); | |
261 | return -1; // can't find it | |
262 | } | |
263 | const char *sig_start = chain_end + strlen(cce); | |
264 | ||
265 | BIO *seg = BIO_new_mem_buf((void *)buf,strlen(buf)); | |
266 | if(BIO_seek(seg,0)!=0){ | |
267 | printf("Cannot seek to beginning of BIO mem?"); | |
268 | return -1; | |
269 | } | |
270 | X509 *cert = 0; | |
271 | PEM_read_bio_X509(seg,&cert,0,0); // get the contained x509 cert | |
272 | BIO_free(seg); | |
273 | ||
274 | /* Now get the binary signature */ | |
275 | u_char sigbuf[1024]; | |
276 | int sigbuf_len = b64_pton_slg(sig_start,strlen(sig_start),sigbuf,sizeof(sigbuf)); | |
277 | if(sigbuf_len<80){ | |
278 | warn("BOM is not signed"); | |
279 | return -1; | |
280 | } | |
281 | ||
282 | /* Try to verify it */ | |
283 | EVP_MD_CTX md; | |
284 | EVP_VerifyInit(&md,sha256); | |
285 | EVP_VerifyUpdate(&md,buf,sig_start-buf); | |
286 | int r = EVP_VerifyFinal(&md,sigbuf,sigbuf_len,X509_get_pubkey(cert)); | |
287 | if(r!=1){ | |
288 | printf("BAD SIGNATURE ON BOM\n"); | |
289 | return -1; | |
290 | } | |
291 | ||
292 | print_x509_info(cert); | |
293 | printf("Date: %s\n",get_xml_field(buf,"date").c_str()); | |
294 | printf("Notes: \n%s\n",get_xml_field(buf,"notes").c_str()); | |
295 | ||
296 | /* Now extract the XML block, terminating at the beginning of the XML signature */ | |
297 | char *buffer_without_signature = strdup(buf); | |
298 | char *sigend = strstr(buffer_without_signature,cce); | |
299 | if(sigend){ | |
300 | sigend[strlen(cce)] = 0;/* terminate the XML to remove the signature */ | |
301 | } | |
302 | ||
303 | segmenthash sh; | |
304 | sh.af = af; | |
305 | if (!sh.parse(buffer_without_signature, strlen(buffer_without_signature))){ | |
306 | fprintf(stderr, "expat error: %s at line %d\n", | |
307 | XML_ErrorString(XML_GetErrorCode(sh.parser)), | |
308 | (int)XML_GetCurrentLineNumber(sh.parser)); | |
309 | fprintf(stderr,"buffer without signature:\n%s\n",buffer_without_signature); | |
310 | return 1; | |
311 | } | |
312 | free(buffer_without_signature); | |
313 | return 0; | |
314 | } | |
315 | #endif | |
316 | ||
317 | int process(const char *fn) | |
318 | { | |
319 | AFFILE *af = af_open(fn,O_RDONLY,0666); | |
320 | if(!af) af_err(1,fn); | |
321 | ||
322 | /* Get the public key */ | |
323 | unsigned char certbuf[65536]; | |
324 | size_t certbuf_len = sizeof(certbuf); | |
325 | if(af_get_seg(af,AF_SIGN256_CERT,0,certbuf,&certbuf_len)){ | |
326 | /* See if it is present, but encrypted */ | |
327 | if(af_get_seg(af,AF_SIGN256_CERT AF_AES256_SUFFIX,0,0,0)==0){ | |
328 | errx(1,"%s: signed file is encrypted; present decryption key to verify signature",fn); | |
329 | } | |
330 | errx(1,"%s: no signing certificate present. Cannot continue.",fn); | |
331 | } | |
332 | ||
333 | seglist segments(af); | |
334 | seglist no_sigs; | |
335 | seglist bad_sigs; | |
336 | seglist good_sigs; | |
337 | seglist unknown_errors; | |
338 | ||
339 | for(seglist::const_iterator seg = segments.begin(); | |
340 | seg != segments.end(); | |
341 | seg++){ | |
342 | ||
343 | if(parse_chain(seg->name)>=0) continue; // chain of custody segments don't need signatures | |
344 | ||
345 | const char *segname = seg->name.c_str(); | |
346 | int i =af_sig_verify_seg(af,segname); | |
347 | if(opt_verbose){ | |
348 | printf("af_sig_verify_seg(af,%s)=%d\n",segname,i); | |
349 | } | |
350 | switch(i){ | |
351 | case AF_ERROR_SIG_NO_CERT: | |
352 | err(1,"%s: no public key in AFF file\n",af_filename(af)); | |
353 | case AF_ERROR_SIG_BAD: | |
354 | bad_sigs.push_back(*seg); | |
355 | break; | |
356 | case AF_ERROR_SIG_READ_ERROR: | |
357 | no_sigs.push_back(*seg); | |
358 | break; | |
359 | case AF_SIG_GOOD: | |
360 | good_sigs.push_back(*seg); | |
361 | break; | |
362 | case AF_ERROR_SIG_SIG_SEG: | |
363 | break; // can't verify the sig on a sig seg | |
364 | case AF_ERROR_SIG_NOT_COMPILED: | |
365 | errx(1,"AFFLIB was compiled without signature support. Cannot continue.\n"); | |
366 | default: | |
367 | unknown_errors.push_back(*seg); | |
368 | break; | |
369 | } | |
370 | } | |
371 | const char *prn = ""; | |
372 | /* Tell us something about the certificate */ | |
373 | BIO *cert_bio = BIO_new_mem_buf(certbuf,certbuf_len); | |
374 | X509 *cert = 0; | |
375 | PEM_read_bio_X509(cert_bio,&cert,0,0); | |
376 | if(!cert) errx(1,"Cannot decode certificate"); | |
377 | printf("\n"); | |
378 | printf("Filename: %s\n",fn); | |
379 | printf("# Segments signed and Verified: %d\n",(int)good_sigs.size()); | |
380 | printf("# Segments unsigned: %d\n",(int)no_sigs.size()); | |
381 | printf("# Segments with corrupted signatures: %d\n",(int)bad_sigs.size()); | |
382 | printf("\n"); | |
383 | print_x509_info(cert); | |
384 | ||
385 | int compromised = 0; | |
386 | for(seglist::const_iterator seg = good_sigs.begin(); seg != good_sigs.end() && opt_all; | |
387 | seg++){ | |
388 | if(*seg==good_sigs.front()) printf("%sSegments with valid signatures:\n",prn); | |
389 | printf("\t%s\n",seg->name.c_str()); | |
390 | prn = "\n"; | |
391 | } | |
392 | for(seglist::const_iterator seg = no_sigs.begin(); | |
393 | seg != no_sigs.end(); | |
394 | seg++){ | |
395 | if(*seg==no_sigs.front()) printf("%sUnsigned segments:\n",prn); | |
396 | printf("\t%s\n",seg->name.c_str()); | |
397 | prn = "\n"; | |
398 | ||
399 | /* Only unsigned data segments are a problem */ | |
400 | if(af_segname_page_number(seg->name.c_str())>=0){ | |
401 | compromised++; | |
402 | } | |
403 | } | |
404 | for(seglist::const_iterator seg = bad_sigs.begin(); | |
405 | seg != bad_sigs.end(); | |
406 | seg++){ | |
407 | if(*seg==bad_sigs.front()) printf("%sBad signature segments:\n",prn); | |
408 | printf("\t%s\n",seg->name.c_str()); | |
409 | prn = "\n"; | |
410 | compromised++; | |
411 | } | |
412 | for(seglist::const_iterator seg = unknown_errors.begin(); | |
413 | seg != unknown_errors.end(); | |
414 | seg++){ | |
415 | if(*seg==unknown_errors.front()) printf("%sUnknown error segments:\n",prn); | |
416 | printf("\t%s\n",seg->name.c_str()); | |
417 | prn = "\n"; | |
418 | compromised++; | |
419 | } | |
420 | ||
421 | int highest = highest_chain(segments); | |
422 | printf("\nNumber of custody chains: %d\n",highest+1); | |
423 | for(int i=0;i<=highest;i++){ | |
424 | /* Now print each one */ | |
425 | printf("---------------------\n"); | |
426 | printf("Signed Bill of Material #%d:\n\n",i+1); | |
427 | ||
428 | /* Get the segment and verify */ | |
429 | size_t chainbuf_len = 0; | |
430 | char segname[AF_MAX_NAME_LEN]; | |
431 | snprintf(segname,sizeof(segname),AF_BOM_SEG,i); | |
432 | if(af_get_seg(af,segname,0,0,&chainbuf_len)){ | |
433 | printf("*** BOM MISSING ***\n"); | |
434 | compromised++; | |
435 | } | |
436 | char *chainbuf = (char *)malloc(chainbuf_len+1); | |
437 | if(af_get_seg(af,segname,0,(u_char *)chainbuf,&chainbuf_len)){ | |
438 | printf("*** CANNOT READ BOM ***\n"); | |
439 | compromised++; | |
440 | } | |
441 | ||
442 | chainbuf[chainbuf_len]=0; // terminate | |
443 | #ifdef USE_AFFSIGS | |
444 | if(verify_bom_signature(af,chainbuf)){ | |
445 | printf("*** BOM SIGNATURE INVALID ***\n"); | |
446 | compromised++; | |
447 | } | |
448 | #else | |
449 | printf("BOM signature cannot be verified beause libxpat is not available.\n"); | |
450 | #endif | |
451 | } | |
452 | printf("---------------------\n"); | |
453 | af_close(af); | |
454 | #ifdef USE_AFFSIGS | |
455 | if(compromised){ | |
456 | printf("\nEVIDENCE FILE DOES NOT VERIFY.\n"); | |
457 | printf("ERRORS DETECTED: %d\n",compromised); | |
458 | printf("EVIDENTUARY VALUE MAY BE COMPROMISED.\n"); | |
459 | return -1; | |
460 | } | |
461 | printf("\nEVIDENCE FILE VERIFIES.\n"); | |
462 | return 0; | |
463 | #endif | |
464 | printf("\n"); | |
465 | return -1; | |
466 | } | |
467 | ||
468 | ||
469 | int main(int argc,char **argv) | |
470 | { | |
471 | int bflag, ch; | |
472 | ||
473 | bflag = 0; | |
474 | while ((ch = getopt(argc, argv, "ach?vV")) != -1) { | |
475 | switch (ch) { | |
476 | case 'a': opt_all = 1; break; | |
477 | case 'c': opt_change = 1; break; | |
478 | case 'v': opt_verbose++; break; | |
479 | case 'h': | |
480 | case '?': | |
481 | default: | |
482 | usage(); | |
483 | break; | |
484 | case 'V': | |
485 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
486 | exit(0); | |
487 | } | |
488 | } | |
489 | argc -= optind; | |
490 | argv += optind; | |
491 | ||
492 | if(argc!=1){ | |
493 | usage(); | |
494 | } | |
495 | ||
496 | OpenSSL_add_all_digests(); | |
497 | return process(argv[0]); | |
498 | } |
0 | /* | |
1 | * afxml.cpp: | |
2 | * | |
3 | * print AFF information as an XML | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Copyright (c) 2005 | |
8 | * Simson L. Garfinkel and Basis Technology, Inc. | |
9 | * All rights reserved. | |
10 | * | |
11 | * This code is derrived from software contributed by | |
12 | * Simson L. Garfinkel | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. All advertising materials mentioning features or use of this software | |
23 | * must display the following acknowledgement: | |
24 | * This product includes software developed by Simson L. Garfinkel | |
25 | * and Basis Technology Corp. | |
26 | * 4. Neither the name of Simson Garfinkel, Basis Technology, or other | |
27 | * contributors to this program may be used to endorse or promote | |
28 | * products derived from this software without specific prior written | |
29 | * permission. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, | |
32 | * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
33 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
34 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
35 | * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, | |
36 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
37 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
39 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
40 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
41 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
42 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | |
44 | */ | |
45 | ||
46 | ||
47 | #include "affconfig.h" | |
48 | #include "afflib.h" | |
49 | #include "afflib_i.h" | |
50 | #include "base64.h" | |
51 | ||
52 | #ifdef WIN32 | |
53 | #include "unix4win32.h" | |
54 | #endif | |
55 | ||
56 | #include <vector> | |
57 | #include <string> | |
58 | ||
59 | #ifdef HAVE_CSTRING | |
60 | #include <cstring> | |
61 | #endif | |
62 | ||
63 | using namespace std; | |
64 | ||
65 | #if HAVE_CTYPE_H | |
66 | #include <ctype.h> | |
67 | #endif | |
68 | ||
69 | #if !defined(HAVE_ISALPHANUM) && defined(HAVE_ISALNUM) | |
70 | #define isalphanum(c) isalnum(c) | |
71 | #endif | |
72 | ||
73 | #if !defined(HAVE_ISALPHANUM) && !defined(HAVE_ISALNUM) | |
74 | #define isalphanum(c) (isalpha(c)||isdigit(c)) | |
75 | #endif | |
76 | ||
77 | const char *progname = "afxml"; | |
78 | ||
79 | int opt_x = 0; | |
80 | char **opt_j = 0; | |
81 | int opt_j_count = 0; | |
82 | int opt_stats = 0; | |
83 | ||
84 | struct page_stat_block { | |
85 | unsigned long long zsectors; // number of sectors that are all blank | |
86 | unsigned long long badsectors; // number of bad sectors | |
87 | unsigned long long zpages; // number of pages that are all blank | |
88 | unsigned long long pages; // total number of pages | |
89 | unsigned long long sectors; // total number of sectors | |
90 | }; | |
91 | ||
92 | ||
93 | void usage() | |
94 | { | |
95 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
96 | printf("usage: %s [options] infile... \n",progname); | |
97 | printf(" -V = Just print the version number and exit\n"); | |
98 | printf(" -x = Don't include the infile filename in output.\n"); | |
99 | printf(" -j segname = Just print information about segname \n"); | |
100 | printf(" (may be repeated)\n"); | |
101 | printf(" -s = output 'stats' for the file data (may a long time)\n"); | |
102 | exit(0); | |
103 | } | |
104 | ||
105 | ||
106 | ||
107 | /* Return true if segname is in the optj list */ | |
108 | bool in_opt_j_list(char *segname) | |
109 | { | |
110 | for(int i=0;i<opt_j_count;i++){ | |
111 | if(strcmp(segname,opt_j[i])==0) return true; | |
112 | } | |
113 | return false; | |
114 | } | |
115 | ||
116 | /* It's okay to print if there are no funky characters in it... | |
117 | * (avoids problems with invalid UTF-8 | |
118 | */ | |
119 | bool okay_to_print(const char *data,int datalen) | |
120 | { | |
121 | for(const char *cc=data;cc<data+datalen;cc++){ | |
122 | if (*cc <= 0) return false; | |
123 | if (*cc == 10 || *cc==13) continue; | |
124 | if (*cc<32) return false; | |
125 | if (*cc>=127) return false; | |
126 | } | |
127 | return true; | |
128 | } | |
129 | ||
130 | bool is_blank(const u_char *buf,size_t len) | |
131 | { | |
132 | for(size_t i=0;i<len;i++){ | |
133 | if(buf[i]) return false; | |
134 | } | |
135 | return true; | |
136 | } | |
137 | ||
138 | void print_xml64(const char *name,int64_t val) | |
139 | { | |
140 | printf(" <%s coding='base10'>%"I64d"</%s>\n\n",name,val,name); | |
141 | } | |
142 | ||
143 | int xml_info(const char *infile) | |
144 | { | |
145 | AFFILE *af = af_open(infile,O_RDONLY,0); | |
146 | if(!af){ | |
147 | warn("%s",infile); | |
148 | return -1; | |
149 | } | |
150 | ||
151 | struct page_stat_block psb; | |
152 | memset(&psb,0,sizeof(psb)); | |
153 | ||
154 | printf("<!-- XML generated by afxml version %s -->\n",PACKAGE_VERSION); | |
155 | printf("<affinfo"); | |
156 | if(!opt_x) printf(" image_filename='%s'",infile); | |
157 | printf(">\n"); | |
158 | ||
159 | af_rewind_seg(af); // start at the beginning | |
160 | ||
161 | char segname[AF_MAX_NAME_LEN]; | |
162 | int pages = 0; | |
163 | vector<string> seglist; // list of segments we will get | |
164 | vector<int64_t> pagelist; // list of segments we will get | |
165 | ||
166 | while(af_get_next_seg(af,segname,sizeof(segname),0,0,0)==0){ | |
167 | if(segname[0]==0) continue; // segment to ignore | |
168 | if(strcmp(segname,AF_DIRECTORY)==0) continue; // don't output the directories | |
169 | if(strstr(segname,AF_AES256_SUFFIX)) continue; // don't output encrypted segments that won't decrypt | |
170 | ||
171 | /* check optj */ | |
172 | if(opt_j_count > 0 && in_opt_j_list(segname)==false){ | |
173 | continue; | |
174 | } | |
175 | ||
176 | int64_t page_num = af_segname_page_number(segname); | |
177 | if(page_num>=0){ | |
178 | pages += 1; | |
179 | pagelist.push_back(page_num); | |
180 | } | |
181 | else { | |
182 | seglist.push_back(segname); | |
183 | } | |
184 | } | |
185 | ||
186 | printf(" <pages coding='base10'>%d</pages>\n",pages); // tell how many pages we have | |
187 | ||
188 | /* If we have been asked to create stats, create the states */ | |
189 | if(opt_stats){ | |
190 | unsigned char *data= (unsigned char *)malloc(af_page_size(af)); | |
191 | if(!data) err(1,"Can't allocate page with %d bytes.",af_page_size(af)); | |
192 | for(vector<int64_t>::const_iterator it = pagelist.begin(); it != pagelist.end(); it++){ | |
193 | size_t pagesize = af_page_size(af); | |
194 | size_t sectorsize = af_get_sectorsize(af); | |
195 | if(af_get_page(af,*it,data,&pagesize)){ | |
196 | err(1,"Can't read page %"PRId64,*it); | |
197 | } | |
198 | psb.pages++; | |
199 | bool allblank = true; | |
200 | for(const unsigned char *s = data; s < data+pagesize; s+=sectorsize){ | |
201 | psb.sectors ++; | |
202 | if(is_blank(s,sectorsize)){ | |
203 | psb.zsectors++; | |
204 | continue; | |
205 | } | |
206 | allblank = false; | |
207 | if(af_is_badsector(af,s)){ | |
208 | psb.badsectors++; | |
209 | continue; | |
210 | } | |
211 | } | |
212 | if(allblank) psb.zpages++; | |
213 | } | |
214 | free(data); | |
215 | printf(" <calculated>\n"); | |
216 | print_xml64("pages",psb.pages); | |
217 | print_xml64("zpages",psb.zpages); | |
218 | print_xml64("sectors",psb.sectors); | |
219 | print_xml64("zsectors",psb.zsectors); | |
220 | print_xml64("badsectors",psb.badsectors); | |
221 | printf(" </calculated>\n"); | |
222 | } | |
223 | ||
224 | /* Now that we have a list of segments, print them */ | |
225 | for(vector<string>::const_iterator it = seglist.begin(); | |
226 | it != seglist.end(); | |
227 | it++){ | |
228 | ||
229 | /* See how long the data is */ | |
230 | size_t datalen = 0; | |
231 | unsigned long arg=0; | |
232 | ||
233 | strcpy(segname,it->c_str()); | |
234 | ||
235 | if(af_get_seg(af,segname,&arg,0,&datalen)){ | |
236 | err(1,"Can't read info for segment '%s'",segname); | |
237 | } | |
238 | ||
239 | unsigned char *data= (unsigned char *)malloc(datalen); | |
240 | if(data==0) err(1,"Can't allocate %zd bytes for data",datalen); | |
241 | if(af_get_seg(af,segname,&arg,data,&datalen)!=0){ | |
242 | err(1,"Can't read data for segment '%s'",segname); | |
243 | } | |
244 | ||
245 | /* Change non-XML characters in segname to _ */ | |
246 | for(char *cc=segname;*cc;cc++){ | |
247 | if(!isalphanum(*cc)) *cc = '_'; | |
248 | } | |
249 | ||
250 | if(datalen==8 && (arg & AF_SEG_QUADWORD || af_display_as_quad(segname))){ | |
251 | /* Print it as a 64-bit value. | |
252 | * The strcmp is there because early AF_IMAGESIZE segs didn't set | |
253 | * AF_SEG_QUADWORD... | |
254 | */ | |
255 | printf(" <%s coding='base10'>%"I64d"</%s>\n",segname,af_decode_q(data),segname); | |
256 | free(data); | |
257 | continue; | |
258 | } | |
259 | ||
260 | /* If datalen==0, just print the arg as an unsigned number */ | |
261 | if(datalen==0){ | |
262 | printf(" <%s coding='base10'>%ld</%s>\n",segname,arg,segname); | |
263 | free(data); | |
264 | continue; | |
265 | } | |
266 | ||
267 | /* Just handle it as binhex ... */ | |
268 | printf(" <%s",segname); | |
269 | if(datalen==0){ | |
270 | printf(" arg='%lu' />\n",arg); | |
271 | free(data); | |
272 | continue; | |
273 | } | |
274 | ||
275 | /* If segname ends 'md5', code in hex */ | |
276 | if(strlen(segname)>=3 && strcmp(segname+strlen(segname)-3,"md5")==0){ | |
277 | char hex_buf[40]; | |
278 | printf(" coding='base16'>%s</%s>\n", | |
279 | af_hexbuf(hex_buf,sizeof(hex_buf),data,datalen,0), | |
280 | segname); | |
281 | free(data); | |
282 | continue; | |
283 | } | |
284 | ||
285 | /* If all segment contents are printable ascii with no CRs, LFs, or brackets, | |
286 | * just print as-is... | |
287 | */ | |
288 | if(okay_to_print((const char *)data,datalen)){ | |
289 | putchar('>'); | |
290 | for(const char *cc=(const char *)data;cc<(const char *)data+datalen;cc++){ | |
291 | switch(*cc){ | |
292 | case '>': fputs("<",stdout);break; | |
293 | case '<': fputs(">",stdout);break; | |
294 | case '&': fputs("&",stdout);break; | |
295 | case '\'': fputs("'",stdout);break; | |
296 | case '"': fputs(""",stdout);break; | |
297 | default: putchar(*cc); | |
298 | } | |
299 | } | |
300 | printf("</%s>\n",segname); | |
301 | free(data); | |
302 | continue; | |
303 | } | |
304 | ||
305 | /* Default coding: base64 */ | |
306 | int b64size = datalen*2+2; | |
307 | char *b64buf = (char *)calloc(b64size,1); | |
308 | int b64size_real = b64_ntop(data,datalen,b64buf,b64size); | |
309 | data[b64size_real] = 0; // be sure it is null terminated | |
310 | ||
311 | printf(" coding='base64'>"); | |
312 | fputs(b64buf,stdout); | |
313 | printf("</%s>\n",segname); | |
314 | free(b64buf); | |
315 | free(data); | |
316 | } | |
317 | af_close(af); | |
318 | ||
319 | printf("</affinfo>\n"); | |
320 | return 0; | |
321 | } | |
322 | ||
323 | ||
324 | int main(int argc,char **argv) | |
325 | { | |
326 | int bflag, ch; | |
327 | const char *infile; | |
328 | ||
329 | /* Figure out how many cols the screen has... */ | |
330 | ||
331 | bflag = 0; | |
332 | while ((ch = getopt(argc, argv, "xj:h?Vs")) != -1) { | |
333 | switch (ch) { | |
334 | case 'j': | |
335 | if(opt_j==0) opt_j = (char **)malloc(0); | |
336 | opt_j_count++; | |
337 | opt_j = (char **)realloc(opt_j,sizeof(char *)*opt_j_count); | |
338 | opt_j[opt_j_count-1] = strdup(optarg); // make a copy | |
339 | case 'x': opt_x++; break; | |
340 | case 's': opt_stats++; break; | |
341 | case 'h': | |
342 | case '?': | |
343 | default: | |
344 | usage(); | |
345 | break; | |
346 | case 'V': | |
347 | printf("%s version %s\n",progname,PACKAGE_VERSION); | |
348 | exit(0); | |
349 | } | |
350 | } | |
351 | argc -= optind; | |
352 | argv += optind; | |
353 | ||
354 | if(argc<1){ | |
355 | usage(); | |
356 | } | |
357 | ||
358 | ||
359 | /* Loop through all of the files */ | |
360 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); | |
361 | printf("<affobjects>\n"); | |
362 | while(*argv){ | |
363 | infile = *argv++; // get the file | |
364 | argc--; // decrement argument counter | |
365 | xml_info(infile); | |
366 | } | |
367 | printf("</affobjects>\n"); | |
368 | exit(0); | |
369 | } | |
370 | ||
371 |
8 | 8 | echo === Putting a new metadata segment into blank.aff === |
9 | 9 | |
10 | 10 | /bin/rm -f $BLANK_AFF |
11 | afcopy /dev/null $BLANK_AFF | |
12 | afsegment -ssegname=testseg1 $BLANK_AFF | |
13 | if [ x"testseg1" = x`afsegment -p segname $BLANK_AFF` ] ; then | |
14 | echo afsegment worked! | |
11 | affcopy /dev/null $BLANK_AFF | |
12 | affsegment -ssegname=testseg1 $BLANK_AFF | |
13 | if [ x"testseg1" = x`affsegment -p segname $BLANK_AFF` ] ; then | |
14 | echo affsegment worked! | |
15 | 15 | else |
16 | echo afsegment does not work properly | |
16 | echo affsegment does not work properly | |
17 | 17 | exit 1 |
18 | 18 | fi |
19 | 19 | /bin/rm -f $BLANK_AFF |
8 | 8 | |
9 | 9 | BASE=`mktemp -t encryptedXXXXXX` |
10 | 10 | ENCRYPTED_AFF=$BASE.aff |
11 | ENCRYPTED_ISO=$BASE.iso | |
11 | ENCRYPTED_AFD=$BASE.afd | |
12 | PLAINTEXT_ISO=$BASE.iso | |
13 | ||
14 | echo Making encrypted AFF from stored value | |
12 | 15 | |
13 | 16 | openssl base64 -d > $ENCRYPTED_AFF <<EOF |
14 | 17 | QUZGMTANCgBBRkYAAAAABwAAAgAAAAAAYmFkZmxhZ0JBRCBTRUNUT1IAQwRKkA4whVoweN599xo5 |
29 | 32 | uydwNotCzenReTJdzn7fdMlBVFQAAAAARA== |
30 | 33 | EOF |
31 | 34 | |
32 | openssl base64 -d > $ENCRYPTED_ISO <<EOF | |
35 | echo Making encrypted AFD | |
36 | mkdir $ENCRYPTED_AFD | |
37 | cp $ENCRYPTED_AFF $ENCRYPTED_AFD/file_000.aff | |
38 | ||
39 | echo Making plaintext ISO | |
40 | openssl base64 -d > $PLAINTEXT_ISO <<EOF | |
33 | 41 | QUZGIGRlY3J5cHRpb24gYXBwZWFycyB0byB3b3JrLgo= |
34 | 42 | EOF |
35 | 43 | |
44 | echo TESTING WITH PASSPHRASE IN ENVIRONMENT VARIABLE | |
45 | export AFFLIB_PASSPHRASE=password | |
46 | if ! affcompare $ENCRYPTED_AFF $PLAINTEXT_ISO ; | |
47 | then | |
48 | echo $ENCRYPTED_AFF does not decrypt properly. | |
49 | exit 1 | |
50 | fi | |
51 | ||
52 | if ! affcompare $ENCRYPTED_AFD $PLAINTEXT_ISO ; | |
53 | then | |
54 | echo $ENCRYPTED_AFD does not decrypt properly. | |
55 | exit 1 | |
56 | fi | |
57 | ||
58 | echo TESTING DECRYPTION WITH URL | |
59 | unset AFFLIB_PASSPHRASE | |
60 | ||
61 | if ! affcompare file://:password@/$ENCRYPTED_AFF $PLAINTEXT_ISO ; | |
62 | then | |
63 | echo $ENCRYPTED_AFF does not decrypt properly. | |
64 | exit 1 | |
65 | fi | |
66 | ||
67 | if ! affcompare file://:password@/$ENCRYPTED_AFD $PLAINTEXT_ISO ; | |
68 | then | |
69 | echo $ENCRYPTED_AFF does not decrypt properly. | |
70 | exit 1 | |
71 | fi | |
72 | ||
73 | ||
36 | 74 | # file://:password@/$ENCRYPTED_AFF |
37 | echo afcompare $ENCRYPTED_ISO $ENCRYPTED_ISO | |
38 | if ! afcompare $ENCRYPTED_ISO $ENCRYPTED_ISO ; then | |
39 | echo $ENCRYPTED_ISO does not decrypt properly. | |
40 | exit 1 | |
41 | fi | |
42 | /bin/rm -f $ENCRYPTED_ISO $ENCRYPTED_AFF | |
75 | ||
76 | # /bin/rm -f $PLAINTEXT_ISO $ENCRYPTED_AFF | |
43 | 77 | exit 0 |
3 | 3 | |
4 | 4 | export PATH=$srcdir:../tools:../../tools:.:$PATH |
5 | 5 | |
6 | echo === testing `afcrypto -V` === | |
6 | echo === testing `affcrypto -V` === | |
7 | 7 | echo === MAKING THE TEST FILES == |
8 | 8 | unset AFFLIB_PASSPHRASE |
9 | 9 | |
22 | 22 | exit 0 |
23 | 23 | fi |
24 | 24 | |
25 | afconvert -o $BLANK_AFF $BLANK_ISO || exit 1 | |
26 | afconvert -o file://:passphrase@/$BLANK_ENCRYPTED_AFF $BLANK_ISO || exit 1 | |
25 | affconvert -o $BLANK_AFF $BLANK_ISO || exit 1 | |
26 | affconvert -o file://:passphrase@/$BLANK_ENCRYPTED_AFF $BLANK_ISO || exit 1 | |
27 | 27 | |
28 | 28 | if [ ! -r $BLANK_ENCRYPTED_AFF ]; then |
29 | 29 | echo CANNOT CREATE $BLANK_ENCRYPTED_AFF |
32 | 32 | fi |
33 | 33 | |
34 | 34 | |
35 | # Make sure afcrypto reports properly for with and with no encrypted segments | |
36 | if (afcrypto $BLANK_AFF | grep " 0 encrypted" > /dev/null ) ; then | |
35 | # Make sure affcrypto reports properly for with and with no encrypted segments | |
36 | if (affcrypto $BLANK_AFF | grep " 0 encrypted" > /dev/null ) ; then | |
37 | 37 | echo $BLANK_ENCRYPTED_AFF properly created |
38 | 38 | else |
39 | 39 | echo ENCRYPTED SEGMENTS IN $BLANK_ENCRYPTED_AFF --- STOP |
40 | 40 | exit 1 |
41 | 41 | fi |
42 | 42 | |
43 | # Now test afcrypto | |
44 | echo Encrypted segment count: `afcrypto -j $BLANK_ENCRYPTED_AFF` | |
45 | if [ `afcrypto -j $BLANK_ENCRYPTED_AFF` = "0" ]; then | |
43 | # Now test affcrypto | |
44 | echo Encrypted segment count: `affcrypto -j $BLANK_ENCRYPTED_AFF` | |
45 | if [ `affcrypto -j $BLANK_ENCRYPTED_AFF` = "0" ]; then | |
46 | 46 | echo NO ENCRYPTED SEGMENTS IN $BLANK_ENCRYPTED_AFF --- STOP |
47 | 47 | exit 1 |
48 | 48 | else |
54 | 54 | echo "doc" >> $WORDS |
55 | 55 | echo "passphrase" >> $WORDS |
56 | 56 | echo "foobar" >> $WORDS |
57 | if [ "`afcrypto -k -f $WORDS $BLANK_ENCRYPTED_AFF|grep correct|grep passphrase`"x = x ] ; then | |
58 | echo afcrypto did not find the right passphrase | |
57 | if [ "`affcrypto -k -f $WORDS $BLANK_ENCRYPTED_AFF|grep correct|grep passphrase`"x = x ] ; then | |
58 | echo affcrypto did not find the right passphrase | |
59 | 59 | exit 1 |
60 | 60 | else |
61 | echo afcrypto found the correct pasphrase | |
61 | echo affcrypto found the correct pasphrase | |
62 | 62 | fi |
63 | 63 | |
64 | 64 | rm $BLANK_ISO $BLANK_AFF $BLANK_ENCRYPTED_AFF $WORDS |
35 | 35 | cp $RECOVERY_ISO $RECOVERY_BAK |
36 | 36 | echo =========== |
37 | 37 | echo Step 1: SIGNING $RECOVERY_ISO |
38 | if ! afsign -k $RECOVERY_PEM $RECOVERY_ISO ; then exit 1 ; fi | |
38 | if ! affsign -k $RECOVERY_PEM $RECOVERY_ISO ; then exit 1 ; fi | |
39 | 39 | ls -l $RECOVERY_ISO $RECOVERY_AFM |
40 | 40 | echo =========== |
41 | 41 | echo Step 2: VERIFYING SIGNATURE |
42 | if ! afverify $RECOVERY_AFM ; then exit 1 ; fi | |
42 | if ! affverify $RECOVERY_AFM ; then exit 1 ; fi | |
43 | 43 | echo =========== |
44 | 44 | echo Step 3: CORRUPTING FILE recovery.iso |
45 | 45 | dd if=/dev/random of=$RECOVERY_ISO count=1 skip=1 conv=notrunc |
46 | 46 | echo =========== |
47 | 47 | echo Step 4: ATTEMPTING RECOVERY |
48 | if ! afrecover $RECOVERY_AFM ; then exit 1 ; fi | |
48 | if ! affrecover $RECOVERY_AFM ; then exit 1 ; fi | |
49 | 49 | echo ========== |
50 | 50 | echo Step 5: MAKING SURE THAT THE MD5 HAS NOT CHANGED |
51 | 51 | if ! cmp $RECOVERY_BAK $RECOVERY_ISO ; then echo file changed ; exit 1 ; fi |
52 | 52 | echo MD5 has not changed |
53 | 53 | echo ========== |
54 | 54 | echo Step 6: See if Digital Signature is still good |
55 | if ! afverify $RECOVERY_AFM ; then echo signature no longer good ; exit 1 ; fi | |
55 | if ! affverify $RECOVERY_AFM ; then echo signature no longer good ; exit 1 ; fi | |
56 | 56 | echo Signature still good |
57 | 57 | echo ALL TESTS PASS |
58 | 58 | /bin/rm -f $RECOVERY_KEY $RECOVERY_BAK $RECOVERY_ISO $RECOVERY_AFM $RECOVERY_PEM |
13 | 13 | |
14 | 14 | /bin/rm -f $AGENT_PEM $ANALYST_PEM $ARCHIVES_PEM $EVIDENCE $EVIDENCE2 $EVIDENCE3 |
15 | 15 | |
16 | echo TEST $0 | |
16 | 17 | echo === MAKING THE TEST FILES === |
17 | 18 | |
18 | 19 | export PATH=$srcdir:../tools:../../tools:.:$PATH |
29 | 30 | |
30 | 31 | echo Making an AFF file to sign |
31 | 32 | rm -f $EVIDENCE evidence?.aff |
32 | afconvert -o $EVIDENCE rawevidence.iso | |
33 | affconvert -o $EVIDENCE rawevidence.iso | |
33 | 34 | echo Initial AFF file |
34 | if ! afinfo -a $EVIDENCE ; then exit 1 ; fi | |
35 | if ! affinfo -a $EVIDENCE ; then exit 1 ; fi | |
35 | 36 | |
36 | 37 | echo Signing AFF file... |
37 | echo afsign -k $AGENT_PEM $EVIDENCE | |
38 | if ! afsign -k $AGENT_PEM $EVIDENCE ; then echo afsign failed ; exit 1 ; fi | |
38 | echo affsign -k $AGENT_PEM $EVIDENCE | |
39 | if ! affsign -k $AGENT_PEM $EVIDENCE ; then echo affsign failed ; exit 1 ; fi | |
39 | 40 | |
40 | 41 | echo Verifying Signature... |
41 | echo afverify $EVIDENCE | |
42 | if ! afverify $EVIDENCE ; then echo afverify failed ; exit 1 ; fi ; | |
42 | echo affverify $EVIDENCE | |
43 | if ! affverify $EVIDENCE ; then echo affverify failed ; exit 1 ; fi ; | |
43 | 44 | |
44 | 45 | echo Signature test 1 passed |
45 | 46 | |
46 | 47 | echo Testing chain-of-custody signatures |
47 | 48 | echo Copying original raw file to evidence1.aff |
48 | 49 | |
49 | if ! afcopy -z -k $AGENT_PEM rawevidence.iso evidence1.aff ; then exit 1; fi | |
50 | if ! afinfo -a evidence1.aff ; then exit 1 ; fi | |
51 | if ! afcompare rawevidence.iso evidence1.aff ; then exit 1 ; fi | |
52 | if ! afverify evidence1.aff ; then exit 1 ; fi | |
50 | if ! affcopy -z -k $AGENT_PEM rawevidence.iso evidence1.aff ; then exit 1; fi | |
51 | if ! affinfo -a evidence1.aff ; then exit 1 ; fi | |
52 | if ! affcompare rawevidence.iso evidence1.aff ; then exit 1 ; fi | |
53 | if ! affverify evidence1.aff ; then exit 1 ; fi | |
53 | 54 | |
54 | 55 | echo |
55 | 56 | echo Making the second generation copy |
56 | echo "This copy was made by the analyst" | afcopy -z -k $ANALYST_PEM -n evidence1.aff $EVIDENCE2 | |
57 | if ! afinfo -a $EVIDENCE2 ; then exit 1 ; fi | |
58 | if ! afcompare rawevidence.iso $EVIDENCE2 ; then exit 1 ; fi | |
59 | if ! afverify $EVIDENCE2 ; then exit 1 ; fi | |
57 | echo "This copy was made by the analyst" | affcopy -z -k $ANALYST_PEM -n evidence1.aff $EVIDENCE2 | |
58 | if ! affinfo -a $EVIDENCE2 ; then exit 1 ; fi | |
59 | if ! affcompare rawevidence.iso $EVIDENCE2 ; then exit 1 ; fi | |
60 | if ! affverify $EVIDENCE2 ; then exit 1 ; fi | |
60 | 61 | echo |
61 | 62 | echo Making the third generation copy |
62 | echo "This copy was made by the archives" | afcopy -z -k $ARCHIVES_PEM -n $EVIDENCE2 $EVIDENCE3 | |
63 | if ! afinfo -a $EVIDENCE3 ; then exit 1 ; fi | |
64 | if ! afcompare rawevidence.iso $EVIDENCE3 ; then exit 1 ; fi | |
65 | if ! afverify $EVIDENCE3 ; then exit 1 ; fi | |
63 | echo "This copy was made by the archives" | affcopy -z -k $ARCHIVES_PEM -n $EVIDENCE2 $EVIDENCE3 | |
64 | if ! affinfo -a $EVIDENCE3 ; then exit 1 ; fi | |
65 | if ! affcompare rawevidence.iso $EVIDENCE3 ; then exit 1 ; fi | |
66 | if ! affverify $EVIDENCE3 ; then exit 1 ; fi | |
66 | 67 | |
67 | 68 | |
68 | 69 | echo All tests passed successfully |
0 | # | |
1 | # Make sure that these files get included in our distribution | |
2 | ||
3 | TARGETS = afcompare.exe afconvert.exe afcopy.exe afdiskprint.exe affix.exe afinfo.exe afstats.exe afxml.exe | |
4 | ||
5 | EXTRA_DIST = \ | |
6 | README.txt \ | |
7 | affconfig.h \ | |
8 | afflib.mak \ | |
9 | getopt.c \ | |
10 | getopt.h \ | |
11 | make.bat \ | |
12 | libeay32.dll \ | |
13 | openssl/Win32OpenSSL-0_9_8k.exe \ | |
14 | openssl/Win32OpenSSL_Light-0_9_8k.exe \ | |
15 | libewf-20080501/aclocal.m4 \ | |
16 | libewf-20080501/AUTHORS \ | |
17 | libewf-20080501/ChangeLog \ | |
18 | libewf-20080501/common/character_string.c \ | |
19 | libewf-20080501/common/character_string.h \ | |
20 | libewf-20080501/common/common.h \ | |
21 | libewf-20080501/common/config.h \ | |
22 | libewf-20080501/common/config.h.in \ | |
23 | libewf-20080501/common/config_windows.h \ | |
24 | libewf-20080501/common/date_time.c \ | |
25 | libewf-20080501/common/date_time.h \ | |
26 | libewf-20080501/common/endian.h \ | |
27 | libewf-20080501/common/error_string.c \ | |
28 | libewf-20080501/common/error_string.h \ | |
29 | libewf-20080501/common/file_io.c \ | |
30 | libewf-20080501/common/file_io.h \ | |
31 | libewf-20080501/common/Makefile.am \ | |
32 | libewf-20080501/common/Makefile.in \ | |
33 | libewf-20080501/common/memory.h \ | |
34 | libewf-20080501/common/notify.c \ | |
35 | libewf-20080501/common/notify.h \ | |
36 | libewf-20080501/common/string_conversion.c \ | |
37 | libewf-20080501/common/string_conversion.h \ | |
38 | libewf-20080501/common/system_string.c \ | |
39 | libewf-20080501/common/system_string.h \ | |
40 | libewf-20080501/common/types.h \ | |
41 | libewf-20080501/config.guess \ | |
42 | libewf-20080501/config.sub \ | |
43 | libewf-20080501/configure \ | |
44 | libewf-20080501/configure.ac \ | |
45 | libewf-20080501/COPYING \ | |
46 | libewf-20080501/debian/changelog \ | |
47 | libewf-20080501/debian/changelog.in \ | |
48 | libewf-20080501/debian/compat \ | |
49 | libewf-20080501/debian/control \ | |
50 | libewf-20080501/debian/copyright \ | |
51 | libewf-20080501/debian/cron.d.ex \ | |
52 | libewf-20080501/debian/emacsen-install.ex \ | |
53 | libewf-20080501/debian/emacsen-remove.ex \ | |
54 | libewf-20080501/debian/emacsen-startup.ex \ | |
55 | libewf-20080501/debian/init.d.ex \ | |
56 | libewf-20080501/debian/libewf-default.ex \ | |
57 | libewf-20080501/debian/libewf-dev.dirs \ | |
58 | libewf-20080501/debian/libewf-dev.docs \ | |
59 | libewf-20080501/debian/libewf-dev.install \ | |
60 | libewf-20080501/debian/libewf-tools.dirs \ | |
61 | libewf-20080501/debian/libewf-tools.docs \ | |
62 | libewf-20080501/debian/libewf-tools.install \ | |
63 | libewf-20080501/debian/libewf.dirs \ | |
64 | libewf-20080501/debian/libewf.doc-base.EX \ | |
65 | libewf-20080501/debian/libewf.docs \ | |
66 | libewf-20080501/debian/libewf.install \ | |
67 | libewf-20080501/debian/libewf.postinst.debhelper \ | |
68 | libewf-20080501/debian/libewf.postrm.debhelper \ | |
69 | libewf-20080501/debian/manpage.1.ex \ | |
70 | libewf-20080501/debian/manpage.sgml.ex \ | |
71 | libewf-20080501/debian/manpage.xml.ex \ | |
72 | libewf-20080501/debian/menu.ex \ | |
73 | libewf-20080501/debian/postinst.ex \ | |
74 | libewf-20080501/debian/postrm.ex \ | |
75 | libewf-20080501/debian/preinst.ex \ | |
76 | libewf-20080501/debian/prerm.ex \ | |
77 | libewf-20080501/debian/rules \ | |
78 | libewf-20080501/debian/shlibs.local.ex \ | |
79 | libewf-20080501/debian/shlibs.local.ex.in \ | |
80 | libewf-20080501/debian/watch.ex \ | |
81 | libewf-20080501/depcomp \ | |
82 | libewf-20080501/doc/header.txt \ | |
83 | libewf-20080501/doc/header2.txt \ | |
84 | libewf-20080501/doc/tests.txt \ | |
85 | libewf-20080501/ewftools/ewfacquire.c \ | |
86 | libewf-20080501/ewftools/ewfacquirestream.c \ | |
87 | libewf-20080501/ewftools/ewfalter.c \ | |
88 | libewf-20080501/ewftools/ewfbyte_size_string.c \ | |
89 | libewf-20080501/ewftools/ewfbyte_size_string.h \ | |
90 | libewf-20080501/ewftools/ewfcommon.c \ | |
91 | libewf-20080501/ewftools/ewfcommon.h \ | |
92 | libewf-20080501/ewftools/ewfdigest_context.c \ | |
93 | libewf-20080501/ewftools/ewfdigest_context.h \ | |
94 | libewf-20080501/ewftools/ewfdigest_hash.c \ | |
95 | libewf-20080501/ewftools/ewfdigest_hash.h \ | |
96 | libewf-20080501/ewftools/ewfexport.c \ | |
97 | libewf-20080501/ewftools/ewfgetopt.c \ | |
98 | libewf-20080501/ewftools/ewfgetopt.h \ | |
99 | libewf-20080501/ewftools/ewfglob.c \ | |
100 | libewf-20080501/ewftools/ewfglob.h \ | |
101 | libewf-20080501/ewftools/ewfinfo.c \ | |
102 | libewf-20080501/ewftools/ewfinput.c \ | |
103 | libewf-20080501/ewftools/ewfinput.h \ | |
104 | libewf-20080501/ewftools/ewfmd5.h \ | |
105 | libewf-20080501/ewftools/ewfoutput.c \ | |
106 | libewf-20080501/ewftools/ewfoutput.h \ | |
107 | libewf-20080501/ewftools/ewfsha1.h \ | |
108 | libewf-20080501/ewftools/ewfsignal.c \ | |
109 | libewf-20080501/ewftools/ewfsignal.h \ | |
110 | libewf-20080501/ewftools/ewfstring.c \ | |
111 | libewf-20080501/ewftools/ewfstring.h \ | |
112 | libewf-20080501/ewftools/ewfverify.c \ | |
113 | libewf-20080501/ewftools/Makefile.am \ | |
114 | libewf-20080501/ewftools/Makefile.in \ | |
115 | libewf-20080501/include/libewf/definitions.h \ | |
116 | libewf-20080501/include/libewf/definitions.h.in \ | |
117 | libewf-20080501/include/libewf/extern.h \ | |
118 | libewf-20080501/include/libewf/handle.h \ | |
119 | libewf-20080501/include/libewf/types.h \ | |
120 | libewf-20080501/include/libewf/types.h.in \ | |
121 | libewf-20080501/include/libewf.h \ | |
122 | libewf-20080501/include/libewf.h.in \ | |
123 | libewf-20080501/INSTALL \ | |
124 | libewf-20080501/install-sh \ | |
125 | libewf-20080501/libewf/ewf_char.h \ | |
126 | libewf-20080501/libewf/ewf_crc.h \ | |
127 | libewf-20080501/libewf/ewf_data.h \ | |
128 | libewf-20080501/libewf/ewf_definitions.h \ | |
129 | libewf-20080501/libewf/ewf_digest_hash.h \ | |
130 | libewf-20080501/libewf/ewf_error2.h \ | |
131 | libewf-20080501/libewf/ewf_file_header.h \ | |
132 | libewf-20080501/libewf/ewf_hash.h \ | |
133 | libewf-20080501/libewf/ewf_ltree.h \ | |
134 | libewf-20080501/libewf/ewf_section.h \ | |
135 | libewf-20080501/libewf/ewf_session.h \ | |
136 | libewf-20080501/libewf/ewf_string.h \ | |
137 | libewf-20080501/libewf/ewf_table.h \ | |
138 | libewf-20080501/libewf/ewf_volume.h \ | |
139 | libewf-20080501/libewf/ewf_volume_smart.h \ | |
140 | libewf-20080501/libewf/ewfx_delta_chunk.h \ | |
141 | libewf-20080501/libewf/libewf.c \ | |
142 | libewf-20080501/libewf/libewf_chunk_cache.c \ | |
143 | libewf-20080501/libewf/libewf_chunk_cache.h \ | |
144 | libewf-20080501/libewf/libewf_chunk_offset.h \ | |
145 | libewf-20080501/libewf/libewf_compression.c \ | |
146 | libewf-20080501/libewf/libewf_compression.h \ | |
147 | libewf-20080501/libewf/libewf_debug.c \ | |
148 | libewf-20080501/libewf/libewf_debug.h \ | |
149 | libewf-20080501/libewf/libewf_file.c \ | |
150 | libewf-20080501/libewf/libewf_file.h \ | |
151 | libewf-20080501/libewf/libewf_filename.c \ | |
152 | libewf-20080501/libewf/libewf_filename.h \ | |
153 | libewf-20080501/libewf/libewf_handle.c \ | |
154 | libewf-20080501/libewf/libewf_handle.h \ | |
155 | libewf-20080501/libewf/libewf_hash_sections.c \ | |
156 | libewf-20080501/libewf/libewf_hash_sections.h \ | |
157 | libewf-20080501/libewf/libewf_hash_values.c \ | |
158 | libewf-20080501/libewf/libewf_hash_values.h \ | |
159 | libewf-20080501/libewf/libewf_header_sections.c \ | |
160 | libewf-20080501/libewf/libewf_header_sections.h \ | |
161 | libewf-20080501/libewf/libewf_header_values.c \ | |
162 | libewf-20080501/libewf/libewf_header_values.h \ | |
163 | libewf-20080501/libewf/libewf_interface.c \ | |
164 | libewf-20080501/libewf/libewf_interface.h \ | |
165 | libewf-20080501/libewf/libewf_media_values.c \ | |
166 | libewf-20080501/libewf/libewf_media_values.h \ | |
167 | libewf-20080501/libewf/libewf_offset_table.c \ | |
168 | libewf-20080501/libewf/libewf_offset_table.h \ | |
169 | libewf-20080501/libewf/libewf_read.c \ | |
170 | libewf-20080501/libewf/libewf_read.h \ | |
171 | libewf-20080501/libewf/libewf_section.c \ | |
172 | libewf-20080501/libewf/libewf_section.h \ | |
173 | libewf-20080501/libewf/libewf_section_list.c \ | |
174 | libewf-20080501/libewf/libewf_section_list.h \ | |
175 | libewf-20080501/libewf/libewf_sector_table.c \ | |
176 | libewf-20080501/libewf/libewf_sector_table.h \ | |
177 | libewf-20080501/libewf/libewf_segment_file.c \ | |
178 | libewf-20080501/libewf/libewf_segment_file.h \ | |
179 | libewf-20080501/libewf/libewf_segment_file_handle.c \ | |
180 | libewf-20080501/libewf/libewf_segment_file_handle.h \ | |
181 | libewf-20080501/libewf/libewf_segment_table.c \ | |
182 | libewf-20080501/libewf/libewf_segment_table.h \ | |
183 | libewf-20080501/libewf/libewf_string.c \ | |
184 | libewf-20080501/libewf/libewf_string.h \ | |
185 | libewf-20080501/libewf/libewf_support.c \ | |
186 | libewf-20080501/libewf/libewf_support.h \ | |
187 | libewf-20080501/libewf/libewf_values_table.c \ | |
188 | libewf-20080501/libewf/libewf_values_table.h \ | |
189 | libewf-20080501/libewf/libewf_write.c \ | |
190 | libewf-20080501/libewf/libewf_write.h \ | |
191 | libewf-20080501/libewf/Makefile.am \ | |
192 | libewf-20080501/libewf/Makefile.in \ | |
193 | libewf-20080501/libewf.pc \ | |
194 | libewf-20080501/libewf.pc.in \ | |
195 | libewf-20080501/libewf.spec \ | |
196 | libewf-20080501/libewf.spec.in \ | |
197 | libewf-20080501/ltmain.sh \ | |
198 | libewf-20080501/macosx/Introduction.rtf \ | |
199 | libewf-20080501/macosx/Introduction.rtf.in \ | |
200 | libewf-20080501/macosx/libewf.pmproj \ | |
201 | libewf-20080501/macosx/License.rtf \ | |
202 | libewf-20080501/macosx/Readme.rtf \ | |
203 | libewf-20080501/Makefile.am \ | |
204 | libewf-20080501/Makefile.in \ | |
205 | libewf-20080501/manuals/ewfacquire.1 \ | |
206 | libewf-20080501/manuals/ewfacquirestream.1 \ | |
207 | libewf-20080501/manuals/ewfexport.1 \ | |
208 | libewf-20080501/manuals/ewfinfo.1 \ | |
209 | libewf-20080501/manuals/ewfverify.1 \ | |
210 | libewf-20080501/manuals/libewf.3 \ | |
211 | libewf-20080501/manuals/Makefile.am \ | |
212 | libewf-20080501/manuals/Makefile.in \ | |
213 | libewf-20080501/missing \ | |
214 | libewf-20080501/msvscpp/ewfacquire/ewfacquire.vcproj \ | |
215 | libewf-20080501/msvscpp/ewfacquirestream/ewfacquirestream.vcproj \ | |
216 | libewf-20080501/msvscpp/ewfalter/ewfalter.vcproj \ | |
217 | libewf-20080501/msvscpp/ewfexport/ewfexport.vcproj \ | |
218 | libewf-20080501/msvscpp/ewfinfo/ewfinfo.vcproj \ | |
219 | libewf-20080501/msvscpp/ewfverify/ewfverify.vcproj \ | |
220 | libewf-20080501/msvscpp/libewf.sln \ | |
221 | libewf-20080501/msvscpp/libewf_dll/libewf_dll.vcproj \ | |
222 | libewf-20080501/NEWS \ | |
223 | libewf-20080501/README \ | |
224 | zlib-1.2.3/adler32.c \ | |
225 | zlib-1.2.3/algorithm.txt \ | |
226 | zlib-1.2.3/as400/bndsrc \ | |
227 | zlib-1.2.3/as400/compile.clp \ | |
228 | zlib-1.2.3/as400/readme.txt \ | |
229 | zlib-1.2.3/as400/zlib.inc \ | |
230 | zlib-1.2.3/ChangeLog \ | |
231 | zlib-1.2.3/compress.c \ | |
232 | zlib-1.2.3/configure \ | |
233 | zlib-1.2.3/crc32.c \ | |
234 | zlib-1.2.3/crc32.h \ | |
235 | zlib-1.2.3/deflate.c \ | |
236 | zlib-1.2.3/deflate.h \ | |
237 | zlib-1.2.3/example-res.rc \ | |
238 | zlib-1.2.3/example-static-res.rc \ | |
239 | zlib-1.2.3/example.c \ | |
240 | zlib-1.2.3/examples/fitblk.c \ | |
241 | zlib-1.2.3/examples/gun.c \ | |
242 | zlib-1.2.3/examples/gzappend.c \ | |
243 | zlib-1.2.3/examples/gzjoin.c \ | |
244 | zlib-1.2.3/examples/gzlog.c \ | |
245 | zlib-1.2.3/examples/gzlog.h \ | |
246 | zlib-1.2.3/examples/README.examples \ | |
247 | zlib-1.2.3/examples/zlib_how.html \ | |
248 | zlib-1.2.3/examples/zpipe.c \ | |
249 | zlib-1.2.3/examples/zran.c \ | |
250 | zlib-1.2.3/FAQ \ | |
251 | zlib-1.2.3/gzio.c \ | |
252 | zlib-1.2.3/INDEX \ | |
253 | zlib-1.2.3/infback.c \ | |
254 | zlib-1.2.3/inffast.c \ | |
255 | zlib-1.2.3/inffast.h \ | |
256 | zlib-1.2.3/inffixed.h \ | |
257 | zlib-1.2.3/inflate.c \ | |
258 | zlib-1.2.3/inflate.h \ | |
259 | zlib-1.2.3/inftrees.c \ | |
260 | zlib-1.2.3/inftrees.h \ | |
261 | zlib-1.2.3/make_vms.com \ | |
262 | zlib-1.2.3/Makefile \ | |
263 | zlib-1.2.3/Makefile.in \ | |
264 | zlib-1.2.3/minigzip-res.rc \ | |
265 | zlib-1.2.3/minigzip-static-res.rc \ | |
266 | zlib-1.2.3/minigzip.c \ | |
267 | zlib-1.2.3/patches/foo.gz \ | |
268 | zlib-1.2.3/patches/zlib-1.2.2.diff \ | |
269 | zlib-1.2.3/patches/zlib-1.2.3.diff \ | |
270 | zlib-1.2.3/patches/zlib-dllversion.c \ | |
271 | zlib-1.2.3/patches/zlib-ltversion \ | |
272 | zlib-1.2.3/patches/zlib.ico \ | |
273 | zlib-1.2.3/projects/README.projects \ | |
274 | zlib-1.2.3/projects/visualc6/example.dsp \ | |
275 | zlib-1.2.3/projects/visualc6/minigzip.dsp \ | |
276 | zlib-1.2.3/projects/visualc6/README.txt \ | |
277 | zlib-1.2.3/projects/visualc6/zlib.dsp \ | |
278 | zlib-1.2.3/projects/visualc6/zlib.dsw \ | |
279 | zlib-1.2.3/qnx/package.qpg \ | |
280 | zlib-1.2.3/README \ | |
281 | zlib-1.2.3/trees.c \ | |
282 | zlib-1.2.3/trees.h \ | |
283 | zlib-1.2.3/uncompr.c \ | |
284 | zlib-1.2.3/win32/DLL_FAQ.txt \ | |
285 | zlib-1.2.3/win32/Makefile.bor \ | |
286 | zlib-1.2.3/win32/Makefile.emx \ | |
287 | zlib-1.2.3/win32/Makefile.gcc \ | |
288 | zlib-1.2.3/win32/Makefile.msc \ | |
289 | zlib-1.2.3/win32/VisualC.txt \ | |
290 | zlib-1.2.3/win32/zlib.def \ | |
291 | zlib-1.2.3/win32/zlib1.rc \ | |
292 | zlib-1.2.3/zconf.h \ | |
293 | zlib-1.2.3/zconf.in.h \ | |
294 | zlib-1.2.3/zlib-dll-res.rc \ | |
295 | zlib-1.2.3/zlib-dllversion.c \ | |
296 | zlib-1.2.3/zlib-ltversion \ | |
297 | zlib-1.2.3/zlib.3 \ | |
298 | zlib-1.2.3/zlib.h \ | |
299 | zlib-1.2.3/zlib.ico \ | |
300 | zlib-1.2.3/zutil.c \ | |
301 | zlib-1.2.3/zutil.h \ | |
302 | expat-2.0.1/lib/amigaconfig.h \ | |
303 | expat-2.0.1/lib/ascii.h \ | |
304 | expat-2.0.1/lib/asciitab.h \ | |
305 | expat-2.0.1/lib/expat.h \ | |
306 | expat-2.0.1/lib/expat_external.h \ | |
307 | expat-2.0.1/lib/iasciitab.h \ | |
308 | expat-2.0.1/lib/internal.h \ | |
309 | expat-2.0.1/lib/latin1tab.h \ | |
310 | expat-2.0.1/lib/macconfig.h \ | |
311 | expat-2.0.1/lib/nametab.h \ | |
312 | expat-2.0.1/lib/utf8tab.h \ | |
313 | expat-2.0.1/lib/winconfig.h \ | |
314 | expat-2.0.1/lib/xmlrole.h \ | |
315 | expat-2.0.1/lib/xmltok.h \ | |
316 | expat-2.0.1/lib/xmltok_impl.h \ | |
317 | expat-2.0.1/lib/xmlparse.c \ | |
318 | expat-2.0.1/lib/xmlrole.c \ | |
319 | expat-2.0.1/lib/xmltok.c \ | |
320 | expat-2.0.1/lib/xmltok_impl.c \ | |
321 | expat-2.0.1/lib/xmltok_ns.c | |
322 | ||
323 | ||
324 | BE_DIR = ../../bulk_extractor/java/ | |
325 | $(BE_DIR)/bulk_extractor.jar: | |
326 | (cd $(BE_DIR) ; make bulk_extractor.jar) | |
327 | cp $(BE_DIR)/*.jar . | |
328 | cp $(BE_DIR)/*.bat . | |
329 | ||
330 | RELEASE_USER = simsong@ | |
331 | RELEASE_HOST = www.afflib.org | |
332 | RELEASE_DIR = afflib.org/ | |
333 | ||
334 | RELEASE_LOC = $(RELEASE_DIR)/downloads/ | |
335 | CHANGES_LOC = $(RELEASE_DIR)/ChangeLog.txt | |
336 | RELEASE_FN = $(PACKAGE)_winversion.txt | |
337 | RELEASE_PATH = $(RELEASE_LOC)/$(RELEASE_FN) | |
338 | RELEASE_SSH = $(RELEASE_USER)$(RELEASE_HOST):$(RELEASE_LOC) | |
339 | RELEASE = $(PACKAGE)-$(VERSION) | |
340 | ||
341 | release: | |
342 | make the_release | |
343 | make distribute_release | |
344 | ||
345 | the_release: afflib.lib $(TARGETS) | |
346 | echo "This distribution should be made after the EXEs are created in Windows" | |
347 | cp ../lib/afflib.h . | |
348 | cp $(BE_DIR)/bulk_extractor.jar . | |
349 | zip $(RELEASE)-win.zip $(TARGETS) afflib.lib afflib.h bulk_extractor.jar libeay32.dll | |
350 | rm afflib.h bulk_extractor.jar | |
351 | gpg --detach-sign $(RELEASE).zip | |
352 | ||
353 | distribute_release: | |
354 | scp $(RELEASE)-win.zip{,.sig} $(RELEASE_SSH) | |
355 | ssh $(RELEASE_HOST) 'cd $(RELEASE_LOC);/bin/rm $(PACKAGE)-win.zip;ln -s $(RELEASE)-win.zip $(PACKAGE)-win.zip' | |
356 | ssh $(RELEASE_HOST) 'echo $(RELEASE).zip > $(RELEASE_PATH)' | |
357 | ||
358 | afflib.lib: | |
359 | echo To make afflib.lib, fire up Windows and type make.bat | |
360 | ||
361 | extra_dist: | |
362 | cp /dev/null extra-dist.txt | |
363 | echo README.txt >> extra-dist.txt | |
364 | echo affconfig.h >> extra-dist.txt | |
365 | echo afflib.mak >> extra-dist.txt | |
366 | echo getopt.c >> extra-dist.txt | |
367 | echo getopt.h >> extra-dist.txt | |
368 | echo make.bat >> extra-dist.txt | |
369 | find openssl -type f -print | grep -v .svn >> extra-dist.txt | |
370 | find libewf-20080501 -type f -print | grep -v .svn >> extra-dist.txt | |
371 | find zlib-1.2.3 -type f | grep -v .svn >> extra-dist.txt | |
372 |
130 | 130 | |
131 | 131 | % make afcat.exe |
132 | 132 | |
133 | 5. To open a multi-file EnCase file, just specify the first .E01 file; the AFFLIB | |
133 | 5. To make the library alone: | |
134 | ||
135 | * Open a VS2008 command prompt (run vcvars32.bat). | |
136 | * Make sure you have OpenSSL and zlib installed. | |
137 | * Add OpenSSL and zlib include paths to your INCLUDE path. | |
138 | * Run "make.bat afflib.lib" (inside the win32 directory). | |
139 | * Rename afflib.lib to afflibMT.lib | |
140 | ||
141 | Repeat 3 more times with different COMPILER_MODE to produce 3 more | |
142 | libs: | |
143 | ======================================================================== | |
144 | * Run "make.bat clean" before each build, just to be safe. | |
145 | * COMPILER_MODE /MD /O2 /D NDEBUG => rename to afflibMD.lib | |
146 | * COMPILER_MODE /MTd => rename to afflibMTd.lib | |
147 | * COMPILER_MODE /MDd => rename to afflibMDd.lib | |
148 | * Put libs in world/3rdparty/afflib/VER/lib/vs20XX/win32 | |
149 | ||
150 | Repeat 4 more times to build 64-bit libraries with same names: | |
151 | ============================================================== | |
152 | * Run vcvars64.bat instead of vcvars32.bat to set up environment. | |
153 | * May want to reset INCLUDE path for OpenSSL and zlib, just to be | |
154 | safe. | |
155 | * Don't forget to use /O2 /D NDEBUG when building release (MT and MD). | |
156 | * Note: No need to specify /MACHINE:X64 linker option in afflib.mak | |
157 | because | |
158 | we're only building a static library, not linking to create any | |
159 | EXEs/DLLs. | |
160 | * Run "make.bat clean" before each build, just to be safe. | |
161 | * Put libs in world/3rdparty/afflib/VER/lib/vs20XX/x64 | |
162 | ||
163 | ||
164 | Once it is compiled: | |
165 | ||
166 | 1. To open a multi-file EnCase file, just specify the first .E01 file; the AFFLIB | |
134 | 167 | implementation will automatically look for all of the other EnCase files. |
135 | 168 | |
136 | 6. Right now you should really use this library for READING AFF & E01 | |
169 | 2. Right now you should really use this library for READING AFF & E01 | |
137 | 170 | files, rather than WRITING them. Writing should work, but it's not |
138 | 171 | very well tested on Windows. S3 is currently not supported on Windows. |
139 | 172 | |
140 | 7. If you want to change the compile switches, feel free. They're in afflib.mak | |
173 | 3. If you want to change the compile switches, feel free. They're in afflib.mak | |
174 | ||
175 | ||
141 | 176 | |
142 | 177 | |
143 | 178 | ================================================================ |
0 | #include "../affconfig.h" | |
0 | /* This file is for compiling afflib using Microsoft Visual C++ */ | |
1 | ||
1 | 2 | #undef C_ALLOCA |
2 | 3 | #undef DISABLE_QEMU |
3 | 4 | #undef HAVE_ALLOCA_H |
50 | 51 | #undef HAVE_FLOCK |
51 | 52 | #undef HAVE_INTTYPES_H |
52 | 53 | |
54 | #ifdef USE_EWF | |
53 | 55 | #define HAVE_LIBEWF 1 |
54 | 56 | /* Define to 1 if you have the libewf_get_bytes_per_sector function. */ |
55 | 57 | #define HAVE_LIBEWF_GET_BYTES_PER_SECTOR 1 |
65 | 67 | #define HAVE_LIBEWF_GET_MEDIA_SIZE_ARGUMENT_VALUE 1 |
66 | 68 | /* Define to 1 if you have the <libewf.h> header file. */ |
67 | 69 | #define HAVE_LIBEWF_H 1 |
70 | #endif | |
71 | ||
72 | /* The following lines added per AccessData */ | |
73 | #include <windows.h> | |
74 | #undef USE_LIBEWF | |
75 | #define DISABLE_QEMU | |
76 | #define HAVE_ALLOCA 1 | |
77 | #define HAVE_ASSERT_H 1 | |
78 | #define HAVE_CSTRING 1 | |
79 | #define HAVE_CTYPE_H 1 | |
80 | #define HAVE_EVP_MD_SIZE 1 | |
81 | #define HAVE_EVP_READ_PW_STRING 1 | |
82 | #define HAVE_ERRNO_H 1 | |
83 | #define HAVE_FCNTL_H 1 | |
84 | #define HAVE_ISLNUM 1 | |
85 | #define HAVE_ISDIGIT 1 | |
86 | #define HAVE_MEMORY_H 1 | |
87 | #define HAVE_LIBSSL 1 | |
88 | #define HAVE_LIBZ 1 | |
89 | #define HAVE_MALLOC_H 1 | |
90 | #define HAVE_MD5 1 | |
91 | #define HAVE_MEMORY_H 1 | |
92 | #define HAVE_MEMSET 1 | |
93 | #define HAVE_MKDIR 1 | |
94 | #define HAVE_SHA1 1 | |
95 | #define HAVE_AES_ENCRYPT 1 | |
96 | #define HAVE_OPENSSL_AES_H 1 | |
97 | #define HAVE_OPENSSL_BIO_H 1 | |
98 | #define HAVE_OPENSSL_EVP_H 1 | |
99 | #define HAVE_OPENSSL_HMAC_H 1 | |
100 | #define HAVE_OPENSSL_MD5_H 1 | |
101 | #define HAVE_OPENSSL_PEM_H 1 | |
102 | #define HAVE_OPENSSL_RAND_H 1 | |
103 | #define HAVE_OPENSSL_RSA_H 1 | |
104 | #define HAVE_OPENSSL_SHA_H 1 | |
105 | #define HAVE_OPENSSL_X509_H 1 | |
106 | #define HAVE_PEM_READ_BIO_RSA_PUBKEY 1 | |
107 | #define HAVE_PUTENV 1 | |
108 | #define HAVE_RAND_PSEUDO_BYTES 1 | |
109 | #define HAVE_STDIO_H 1 | |
110 | #define HAVE_STDLIB_H 1 | |
111 | #define HAVE_STRCHR 1 | |
112 | #define HAVE_STRDUP 1 | |
113 | #define HAVE_STRERROR 1 | |
114 | #define HAVE_STRING_H 1 | |
115 | #define HAVE_STRRCHR 1 | |
116 | #define HAVE_SYS_STAT_H 1 | |
117 | #define HAVE_SYS_TYPES_H 1 | |
118 | #define HAVE_ZLIB_H 1 | |
119 | #define PACKAGE_VERSION "3.6.2" | |
120 | typedef SSIZE_T ssize_t; |
2 | 2 | # |
3 | 3 | |
4 | 4 | # What to make: |
5 | TARGETS = afcompare.exe afconvert.exe afcopy.exe afdiskprint.exe affix.exe afinfo.exe afstats.exe afxml.exe | |
5 | TARGETS = affcompare.exe affconvert.exe affcopy.exe affdiskprint.exe affix.exe affinfo.exe affstats.exe affxml.exe | |
6 | 6 | |
7 | 7 | # These are things you may need to change: |
8 | 8 | # |
13 | 13 | |
14 | 14 | # COMPILER_MODE specifies how you want the libaries compiled: |
15 | 15 | |
16 | COMPILE_MODE = /MT | |
16 | COMPILER_MODE = /MT /O2 /D NDEBUG | |
17 | 17 | |
18 | LIBEWF = libewf-20070512 | |
19 | LIBEWF = libewf-20080501 | |
20 | LIBEWFDIR = $(LIBEWF)\libewf | |
21 | 18 | EXPATDIR = expat-2.0.1\lib |
22 | 19 | |
23 | 20 | all: $(TARGETS) |
30 | 27 | /I..\lib \ |
31 | 28 | /I..\lzma443\C \ |
32 | 29 | /I..\lzma443\C\7zip\Compress\LZMA_Alone \ |
33 | /I$(LIBEWF)\include /I$(LIBEWF)\common \ | |
34 | 30 | /I$(EXPATDIR) \ |
35 | 31 | /I$(SDK_DIR)/Include /I$(OPENSSL_DIR)/Include |
36 | 32 | |
37 | EWF_DEFS = /DHAVE_CONFIG_WINDOWS_H /DHAVE_LIBCRYPTO /DHAVE_OPENSSL_EVP_H /DHAVE_WINDOWS_API | |
38 | DEFS = /DWIN32 /DWIN32_NT /DUSE_LIBEWF /DMSC /D_CRT_SECURE_NO_DEPRECATE $(EWF_DEFS) /DHAVE_MEMMOVE | |
33 | DEFS = /DWIN32 /DWIN32_NT /DMSC /D_CRT_SECURE_NO_DEPRECATE /DHAVE_CONFIG_WINDOWS_H /DHAVE_LIBCRYPTO /DHAVE_OPENSSL_EVP_H /DHAVE_WINDOWS_API/DHAVE_MEMMOVE | |
39 | 34 | |
40 | 35 | |
41 | 36 | CC=cl |
112 | 107 | ..\lib\vnode_aff.obj \ |
113 | 108 | ..\lib\vnode_afd.obj \ |
114 | 109 | ..\lib\vnode_afm.obj \ |
115 | ..\lib\vnode_ewf.obj \ | |
116 | 110 | ..\lib\vnode_raw.obj \ |
117 | 111 | ..\lib\vnode_s3.obj \ |
118 | 112 | ..\lib\vnode_split_raw.obj \ |
119 | 113 | ..\lib\utils.obj \ |
120 | 114 | ..\lib\display.obj |
121 | 115 | |
122 | ||
123 | EWF2007_OBJS = \ | |
124 | $(LIBEWFDIR)\ewf_compress.obj \ | |
125 | $(LIBEWFDIR)\ewf_crc.obj \ | |
126 | $(LIBEWFDIR)\ewf_data.obj \ | |
127 | $(LIBEWFDIR)\ewf_error2.obj \ | |
128 | $(LIBEWFDIR)\ewf_file_header.obj \ | |
129 | $(LIBEWFDIR)\ewf_hash.obj \ | |
130 | $(LIBEWFDIR)\ewf_ltree.obj \ | |
131 | $(LIBEWFDIR)\ewf_section.obj \ | |
132 | $(LIBEWFDIR)\ewf_string.obj \ | |
133 | $(LIBEWFDIR)\ewf_table.obj \ | |
134 | $(LIBEWFDIR)\ewf_volume.obj \ | |
135 | $(LIBEWFDIR)\ewf_volume_smart.obj \ | |
136 | $(LIBEWFDIR)\libewf_chunk_cache.obj \ | |
137 | $(LIBEWFDIR)\libewf_common.obj \ | |
138 | $(LIBEWFDIR)\libewf_debug.obj \ | |
139 | $(LIBEWFDIR)\libewf_digest_context.obj \ | |
140 | $(LIBEWFDIR)\libewf_endian.obj \ | |
141 | $(LIBEWFDIR)\libewf_file.obj \ | |
142 | $(LIBEWFDIR)\libewf_hash_values.obj \ | |
143 | $(LIBEWFDIR)\libewf_header_values.obj \ | |
144 | $(LIBEWFDIR)\libewf_internal_handle.obj \ | |
145 | $(LIBEWFDIR)\libewf_notify.obj \ | |
146 | $(LIBEWFDIR)\libewf_offset_table.obj \ | |
147 | $(LIBEWFDIR)\libewf_read.obj \ | |
148 | $(LIBEWFDIR)\libewf_section.obj \ | |
149 | $(LIBEWFDIR)\libewf_section_list.obj \ | |
150 | $(LIBEWFDIR)\libewf_segment_table.obj \ | |
151 | $(LIBEWFDIR)\libewf_string.obj \ | |
152 | $(LIBEWFDIR)\libewf_write.obj | |
153 | ||
154 | EWF_OBJS = \ | |
155 | $(LIBEWFDIR)\libewf.obj\ | |
156 | $(LIBEWFDIR)\libewf_chunk_cache.obj \ | |
157 | $(LIBEWFDIR)\libewf_compression.obj \ | |
158 | $(LIBEWFDIR)\libewf_debug.obj \ | |
159 | $(LIBEWFDIR)\libewf_file.obj \ | |
160 | $(LIBEWFDIR)\libewf_filename.obj \ | |
161 | $(LIBEWFDIR)\libewf_handle.obj \ | |
162 | $(LIBEWFDIR)\libewf_hash_sections.obj \ | |
163 | $(LIBEWFDIR)\libewf_hash_values.obj \ | |
164 | $(LIBEWFDIR)\libewf_header_sections.obj \ | |
165 | $(LIBEWFDIR)\libewf_header_values.obj \ | |
166 | $(LIBEWFDIR)\libewf_interface.obj \ | |
167 | $(LIBEWFDIR)\libewf_media_values.obj \ | |
168 | $(LIBEWFDIR)\libewf_offset_table.obj \ | |
169 | $(LIBEWFDIR)\libewf_read.obj \ | |
170 | $(LIBEWFDIR)\libewf_section.obj \ | |
171 | $(LIBEWFDIR)\libewf_section_list.obj \ | |
172 | $(LIBEWFDIR)\libewf_sector_table.obj \ | |
173 | $(LIBEWFDIR)\libewf_segment_file.obj \ | |
174 | $(LIBEWFDIR)\libewf_segment_file_handle.obj \ | |
175 | $(LIBEWFDIR)\libewf_segment_table.obj \ | |
176 | $(LIBEWFDIR)\libewf_string.obj \ | |
177 | $(LIBEWFDIR)\libewf_support.obj \ | |
178 | $(LIBEWFDIR)\libewf_values_table.obj \ | |
179 | $(LIBEWFDIR)\libewf_write.obj \ | |
180 | $(LIBEWFDIR)\..\common\character_string.obj \ | |
181 | $(LIBEWFDIR)\..\common\date_time.obj \ | |
182 | $(LIBEWFDIR)\..\common\error_string.obj \ | |
183 | $(LIBEWFDIR)\..\common\file_io.obj \ | |
184 | $(LIBEWFDIR)\..\common\notify.obj \ | |
185 | $(LIBEWFDIR)\..\common\string_conversion.obj \ | |
186 | $(LIBEWFDIR)\..\common\system_string.obj | |
187 | 116 | |
188 | 117 | ZLIB_OBJS = zlib-1.2.3\adler32.obj \ |
189 | 118 | zlib-1.2.3\compress.obj \ |
213 | 142 | |
214 | 143 | # LIB_OBJS are all of the objects that we'll put in the library |
215 | 144 | |
216 | LIB_OBJS = $(EWF_OBJS) $(AFF_OBJS) $(LZMA_OBJS) $(WIN32_OBJS) $(ZLIB_OBJS) | |
145 | LIB_OBJS = $(AFF_OBJS) $(LZMA_OBJS) $(WIN32_OBJS) $(ZLIB_OBJS) | |
217 | 146 | |
218 | 147 | afflib.lib: $(LIB_OBJS) |
219 | 148 | lib -out:afflib.lib $(LIB_OBJS) |
229 | 158 | |
230 | 159 | LINK_OPTS = /libpath:$(SDK_DIR)/Lib /nodefaultlib:libc $(WIN32LIBS) |
231 | 160 | |
232 | aftest.exe: ..\lib\aftest.obj afflib.lib | |
233 | link -out:aftest.exe ..\lib\aftest.obj afflib.lib $(LINK_OPTS) | |
161 | afftest.exe: ..\lib\aftest.obj afflib.lib | |
162 | link -out:afftest.exe ..\lib\afftest.obj afflib.lib $(LINK_OPTS) | |
234 | 163 | |
235 | afcat.exe: ..\tools\afcat.obj afflib.lib | |
236 | link -out:afcat.exe ..\tools\afcat.obj afflib.lib $(LINK_OPTS) | |
164 | affcat.exe: ..\tools\affcat.obj afflib.lib | |
165 | link -out:affcat.exe ..\tools\affcat.obj afflib.lib $(LINK_OPTS) | |
237 | 166 | |
238 | afcopy.exe: ..\tools\afcopy.obj ..\tools\aff_bom.obj afflib.lib | |
239 | link -out:afcopy.exe ..\tools\afcopy.obj ..\tools\aff_bom.obj afflib.lib $(LINK_OPTS) | |
167 | affcopy.exe: ..\tools\affcopy.obj ..\tools\aff_bom.obj afflib.lib | |
168 | link -out:affcopy.exe ..\tools\affcopy.obj ..\tools\aff_bom.obj afflib.lib $(LINK_OPTS) | |
240 | 169 | |
241 | afcompare.exe: ..\tools\afcompare.obj afflib.lib | |
242 | link -out:afcompare.exe ..\tools\afcompare.obj afflib.lib $(LINK_OPTS) | |
170 | affcompare.exe: ..\tools\affcompare.obj afflib.lib | |
171 | link -out:affcompare.exe ..\tools\affcompare.obj afflib.lib $(LINK_OPTS) | |
243 | 172 | |
244 | afconvert.exe: ..\tools\afconvert.obj afflib.lib | |
245 | link -out:afconvert.exe ..\tools\afconvert.obj afflib.lib $(LINK_OPTS) | |
173 | affconvert.exe: ..\tools\affconvert.obj afflib.lib | |
174 | link -out:affconvert.exe ..\tools\affconvert.obj afflib.lib $(LINK_OPTS) | |
246 | 175 | |
247 | afdiskprint.exe: ..\tools\afdiskprint.obj afflib.lib $(EXPAT_OBJS) | |
248 | link -out:afdiskprint.exe ..\tools\afdiskprint.obj ..\tools\aff_bom.obj afflib.lib $(EXPAT_OBJS) $(LINK_OPTS) | |
176 | affdiskprint.exe: ..\tools\affdiskprint.obj afflib.lib $(EXPAT_OBJS) | |
177 | link -out:affdiskprint.exe ..\tools\affdiskprint.obj ..\tools\aff_bom.obj afflib.lib $(EXPAT_OBJS) $(LINK_OPTS) | |
249 | 178 | |
250 | 179 | affix.exe: ..\tools\affix.obj afflib.lib |
251 | 180 | link -out:affix.exe ..\tools\affix.obj afflib.lib $(LINK_OPTS) |
252 | 181 | |
253 | afinfo.exe: ..\tools\afinfo.obj afflib.lib | |
254 | link -out:afinfo.exe ..\tools\afinfo.obj afflib.lib $(LINK_OPTS) | |
182 | affinfo.exe: ..\tools\affinfo.obj afflib.lib | |
183 | link -out:affinfo.exe ..\tools\affinfo.obj afflib.lib $(LINK_OPTS) | |
255 | 184 | |
256 | afsegment.exe: ..\tools\afsegment.obj afflib.lib | |
257 | link -out:afsegment.exe ..\tools\afsegment.obj afflib.lib $(LINK_OPTS) | |
185 | affsegment.exe: ..\tools\affsegment.obj afflib.lib | |
186 | link -out:affsegment.exe ..\tools\affsegment.obj afflib.lib $(LINK_OPTS) | |
258 | 187 | |
259 | afstats.exe: ..\tools\afstats.obj afflib.lib | |
260 | link -out:afstats.exe ..\tools\afstats.obj afflib.lib $(LINK_OPTS) | |
188 | affstats.exe: ..\tools\affstats.obj afflib.lib | |
189 | link -out:affstats.exe ..\tools\affstats.obj afflib.lib $(LINK_OPTS) | |
261 | 190 | |
262 | afxml.exe: ..\tools\afxml.obj afflib.lib | |
263 | link -out:afxml.exe ..\tools\afxml.obj afflib.lib $(LINK_OPTS) | |
191 | affxml.exe: ..\tools\affxml.obj afflib.lib | |
192 | link -out:affxml.exe ..\tools\affxml.obj afflib.lib $(LINK_OPTS) | |
264 | 193 |