Imported Upstream version 1.0.7
authorGui Chen <gui.chen@intel.com>
Wed, 23 Jul 2014 10:54:33 +0000 (06:54 -0400)
committerGui Chen <gui.chen@intel.com>
Wed, 23 Jul 2014 10:54:33 +0000 (06:54 -0400)
16 files changed:
.gitignore [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
checkisomd5.1 [new file with mode: 0644]
checkisomd5.c [new file with mode: 0644]
implantisomd5.1 [new file with mode: 0644]
implantisomd5.c [new file with mode: 0644]
libcheckisomd5.c [new file with mode: 0644]
libcheckisomd5.h [new file with mode: 0644]
libimplantisomd5.c [new file with mode: 0644]
libimplantisomd5.h [new file with mode: 0644]
md5.c [new file with mode: 0644]
md5.h [new file with mode: 0644]
pyisomd5sum.c [new file with mode: 0644]
testpyisomd5sum.py [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..eb89a59
--- /dev/null
@@ -0,0 +1,7 @@
+checkisomd5
+implantisomd5
+*.o
+*.so
+*~
+*.a
+*.tar.bz2
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2ed24a5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,71 @@
+PYVER  := $(shell python -c 'import sys; print sys.version[0:3]')
+PYTHON = python$(PYVER)
+PYTHONINCLUDE = /usr/include/$(PYTHON)
+
+VERSION=1.0.7
+
+ifneq (,$(filter sparc64 ppc64 x86_64 s390x,$(shell uname -m)))
+LIBDIR = lib64
+else
+LIBDIR = lib
+endif
+
+CFLAGS = $(RPM_OPT_FLAGS) -Wall -Werror -D_GNU_SOURCE=1 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -fPIC -I$(PYTHONINCLUDE)
+
+OBJECTS = md5.o libimplantisomd5.o checkisomd5.o implantisomd5
+SOURCES = $(patsubst %.o,%.c,$(OBJECTS))
+LDFLAGS += -fPIC
+
+PYOBJS = pyisomd5sum.o libcheckisomd5.a libimplantisomd5.a
+
+all: implantisomd5 checkisomd5 pyisomd5sum.so libimplantisomd5.a libcheckisomd5.a
+
+%.o: %.c
+       $(CC) -c -O $(CFLAGS) -o $@ $<
+
+implantisomd5: implantisomd5.o libimplantisomd5.a
+       $(CC) -lpopt $(CFLAGS) implantisomd5.o libimplantisomd5.a -o implantisomd5
+
+checkisomd5: checkisomd5.o libcheckisomd5.a
+       $(CC) -lpopt $(CFLAGS) checkisomd5.o libcheckisomd5.a -o checkisomd5
+
+libimplantisomd5.a: libimplantisomd5.a(libimplantisomd5.o md5.o)
+
+libcheckisomd5.a: libcheckisomd5.a(libcheckisomd5.o md5.o)
+
+pyisomd5sum.so: $(PYOBJS)
+       $(CC) -shared -g -o pyisomd5sum.so -fpic $(PYOBJS) $(LDFLAGS)
+
+install: all install-bin install-python install-devel
+
+install-bin:
+       install -d -m 0755 $(DESTDIR)/usr/bin
+       install -d -m 0755 $(DESTDIR)/usr/share/man/man1
+       install -m 0755 implantisomd5 $(DESTDIR)/usr/bin
+       install -m 0755 checkisomd5 $(DESTDIR)/usr/bin
+       install -m 0644 implantisomd5.1 $(DESTDIR)/usr/share/man/man1
+       install -m 0644 checkisomd5.1 $(DESTDIR)/usr/share/man/man1
+
+install-python:
+       install -d -m 0755 $(DESTDIR)/usr/$(LIBDIR)/$(PYTHON)/site-packages
+       install -m 0755 pyisomd5sum.so $(DESTDIR)/usr/$(LIBDIR)/$(PYTHON)/site-packages
+
+install-devel:
+       install -d -m 0755 $(DESTDIR)/usr/include
+       install -d -m 0755 $(DESTDIR)/usr/$(LIBDIR)
+       install -m 0644 libimplantisomd5.h $(DESTDIR)/usr/include/
+       install -m 0644 libcheckisomd5.h $(DESTDIR)/usr/include/
+       install -m 0644 libimplantisomd5.a $(DESTDIR)/usr/$(LIBDIR)
+       install -m 0644 libcheckisomd5.a $(DESTDIR)/usr/$(LIBDIR)
+
+clean:
+       rm -f *.o *.so *.pyc *.a .depend *~
+       rm -f implantisomd5 checkisomd5 
+
+tag:
+       @git tag -a -m "Tag as $(VERSION)" -f $(VERSION)
+       @echo "Tagged as $(VERSION)"
+
+archive:
+       @git archive --format=tar --prefix=isomd5sum-$(VERSION)/ HEAD |bzip2 > isomd5sum-$(VERSION).tar.bz2
+       @echo "The final archive is in isomd5sum-$(VERSION).tar.bz2"
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e848cd4
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+isomd5sum provides a way of making use of the ISO9660 application data
+area to store md5sum data about the iso.  This allows you to check the
+iso given nothing more than the iso itself.
+
+isomd5sum is hosted as a fedorahosted project.  The source can be
+grabbed via git with
+  git clone git://git.fedorahosted.org/isomd5sum.git
+or browsed via gitweb at
+  http://git.fedorahosted.org/git/?p=isomd5sum.git;a=summary
+
+Releases of isomd5sum are located at
+  http://fedorahosted.org/releases/i/s/isomd5sum
+
+You can send questions, enhancements, etc to anaconda-devel-list@redhat.com.
diff --git a/checkisomd5.1 b/checkisomd5.1
new file mode 100644 (file)
index 0000000..78a3fa1
--- /dev/null
@@ -0,0 +1,25 @@
+.TH "CHECKISOMD5" "1"
+.SH "NAME"
+checkisomd5 \(em check an MD5 checksum implanted by \fBimplantisomd5\fR
+.SH "SYNOPSIS"
+.PP
+\fBcheckisomd5\fR [\fB\-\-md5sumonly\fP]  [\fB\-\-verbose\fP]  [\fB\-\-gauge\fP]  [isofilename  | blockdevice ]
+.SH "DESCRIPTION"
+.PP
+This manual page documents briefly the \fBcheckisomd5\fR command.  \fBcheckisomd5\fR is a program that checks an embedded MD5 checksum in a ISO9660 image (.iso), or block device.  The checksum is embedded by the corresponding \fBimplantisomd5\fR command.
+.PP
+The check can be aborted by pressing Esc key.
+.SH "EXIT STATUS"
+.PP
+Program returns exit status 0 if the checksum is correct, or 1 if the checksum is incorrect, non-existent, or check was aborted.
+.SH "OPTIONS"
+.IP "\fB\-\-md5sumonly\fP" 10
+Do not check the target.  Instead, output human-readable information about the target's checksums.
+.IP "\fB\-\-verbose\fP" 10
+Display human-readable progress as the target is checked.  Without this option, nothing is outputted except errors.
+.IP "\fB\-\-gauge\fP" 10
+Display a series of numbers from 0 to 100, corresponding to check progress.  This output can be piped to \fBdialog \-\-gauge\fR for a user-friendly progress bar.
+.SH "SEE ALSO"
+.PP
+implantisomd5 (1).
+.\" created by instant / docbook-to-man, Thu 07 Feb 2008, 13:43
diff --git a/checkisomd5.c b/checkisomd5.c
new file mode 100644 (file)
index 0000000..df06f5f
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * checkosmd5 - simple program to check implanted md5sum
+ * Copyright (C) 2001-2007 Red Hat, Inc.
+ * Michael Fulbright <msf@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <popt.h>
+#include <termios.h>
+
+#include "md5.h"
+#include "libcheckisomd5.h"
+
+struct progressCBData {
+    int verbose;
+    int gauge;
+    int gaugeat;
+};
+
+int user_bailing_out() {
+  int retval = 0;
+  struct timeval timev;
+  fd_set rfds;
+  char ch;
+
+  FD_ZERO(&rfds);
+  FD_SET(0,&rfds);
+
+  timev.tv_sec = 0;
+  timev.tv_usec = 0;
+
+  if (select(1, &rfds, NULL, NULL, &timev))
+    if ((ch = getchar()) == 27)
+      retval = 1;
+
+  return retval;
+}
+
+static int outputCB(void *co, long long offset, long long total) {
+    struct progressCBData *data = co;
+    int gaugeval = -1;
+
+    if (data->verbose) {
+        printf("\rChecking: %05.1f%%", (100.0*offset)/(total));
+        fflush(stdout);
+    }
+    if (data->gauge) {
+        gaugeval = (100.0*offset)/(total);
+        if (gaugeval != data->gaugeat) {
+            printf("%d\n", gaugeval);
+            fflush(stdout);
+            data->gaugeat = gaugeval;
+        }
+    }
+
+    return user_bailing_out();
+}
+
+static void usage(void) {
+    fprintf(stderr, "Usage: checkisomd5 [--md5sumonly] [--verbose] [--gauge] <isofilename>|<blockdevice>\n\n");
+    exit(1);
+}
+
+
+/* Process the result code and return the proper exit status value
+ */
+int processExitStatus(int rc) {
+    char * result;
+
+    switch (rc) {
+       case ISOMD5SUM_CHECK_FAILED:
+               result = "FAIL.\n\nIt is not recommended to use this media.";
+               break;
+       case ISOMD5SUM_CHECK_ABORTED:
+               result = "UNKNOWN.\n\nThe media check was aborted.";
+               break;
+       case ISOMD5SUM_CHECK_NOT_FOUND:
+               result = "NA.\n\nNo checksum information available, unable to verify media.";
+               break;
+        case ISOMD5SUM_FILE_NOT_FOUND:
+                result = "NA.\n\nFile not found.";
+                break;
+       case ISOMD5SUM_CHECK_PASSED:
+               result = "PASS.\n\nIt is OK to use this media.";
+               break;
+       default:
+               result = "checkisomd5 ERROR - bad return value";
+               break;
+    }
+
+    fprintf(stderr, "\nThe media check is complete, the result is: %s\n", result);
+
+    return(rc != ISOMD5SUM_CHECK_PASSED);
+}
+
+
+int main(int argc, char **argv) {
+    int rc;
+    const char **args;
+    int md5only;
+    int help;
+    struct progressCBData data;
+    poptContext optCon;
+
+    memset(&data, 0, sizeof(struct progressCBData));
+
+    md5only = 0;
+    help = 0;
+    data.verbose = 0;
+    data.gauge = 0;
+
+    struct poptOption options[] = {
+       { "md5sumonly", 'o', POPT_ARG_NONE, &md5only, 0 },
+       { "verbose", 'v', POPT_ARG_NONE, &data.verbose, 0 },
+       { "gauge", 'g', POPT_ARG_NONE, &data.gauge, 0},
+       { "help", 'h', POPT_ARG_NONE, &help, 0},
+       { 0, 0, 0, 0, 0}
+    };
+
+    static struct termios oldt, newt;
+
+    optCon = poptGetContext("checkisomd5", argc, (const char **)argv, options, 0);
+
+    if ((rc = poptGetNextOpt(optCon)) < -1) {
+       fprintf(stderr, "bad option %s: %s\n",
+               poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+               poptStrerror(rc));
+       exit(1);
+    }
+
+    if (help)
+       usage();
+
+    args = poptGetArgs(optCon);
+    if (!args || !args[0] || !args[0][0])
+       usage();
+
+    if (md5only|data.verbose) {
+       rc = printMD5SUM((char *)args[0]);
+        if (rc < 0) {
+            exit(processExitStatus(rc));
+        }
+    }
+
+    if (md5only)
+       exit(0);
+
+    printf("Press [Esc] to abort check.\n");
+
+    tcgetattr(0, &oldt);
+    newt = oldt;
+    newt.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
+    tcsetattr(0, TCSANOW, &newt);
+    rc = mediaCheckFile((char *)args[0], outputCB, &data);
+    tcsetattr(0, TCSANOW, &oldt);
+
+    if (data.verbose)
+       printf("\n");
+
+    exit(processExitStatus(rc));
+}
diff --git a/implantisomd5.1 b/implantisomd5.1
new file mode 100644 (file)
index 0000000..e6219f1
--- /dev/null
@@ -0,0 +1,18 @@
+.TH "IMPLANTISOMD5" "1"
+.SH "NAME"
+implantisomd5 \(em implant an MD5 checksum in an ISO9660 image
+.SH "SYNOPSIS"
+.PP
+\fBimplantisomd5\fR [\fB\-\-force\fP]  [\fB\-\-supported-iso\fP]  [isofilename]
+.SH "DESCRIPTION"
+.PP
+This manual page documents briefly the \fBimplantisomd5\fR command. \fBimplantisomd5\fR is a program that embeds an MD5 checksum in an unused section of and ISO9660 (.iso) image.  This checksum can later be compared to the .iso, or a block device, using the corresponding \fBcheckisomd5\fR command.
+.SH "OPTIONS"
+.IP "\fB\-\-force\fP" 10
+Force an existing checksum to be overwritten.
+.IP "\fB\-\-supported-iso\fP" 10
+Indicate that the image will be written to a "supported" media, such as pressed CD.  On Red Hat-based Anaconda installers, this bypasses the prompt to check the CD.
+.SH "SEE ALSO"
+.PP
+checkisomd5 (1).
+.\" created by instant / docbook-to-man, Thu 07 Feb 2008, 12:11
diff --git a/implantisomd5.c b/implantisomd5.c
new file mode 100644 (file)
index 0000000..759f841
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * simple program to insert an md5sum into application data area of iso99660
+ * Copyright (C) 2001-2007 Red Hat, Inc.
+ * Michael Fulbright <msf@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <popt.h>
+
+#include "md5.h"
+#include "libimplantisomd5.h"
+
+
+static void usage(void) {
+    fprintf(stderr, "implantisomd5:         implantisomd5 [--force] [--supported-iso] <isofilename>\n");
+    exit(1);
+}
+
+
+int main(int argc, char **argv) {
+    int rc;
+    char *errstr;
+    const char **args;
+
+    int forceit=0;
+    int supported=0;
+    int help=0;
+
+    poptContext optCon;
+    struct poptOption options[] = {
+       { "force", 'f', POPT_ARG_NONE, &forceit, 0 },
+       { "supported-iso", 'S', POPT_ARG_NONE, &supported, 0 },
+       { "help", 'h', POPT_ARG_NONE, &help, 0},
+       { 0, 0, 0, 0, 0}
+    };
+
+
+    optCon = poptGetContext("implantisomd5", argc, (const char **)argv, options, 0);
+
+    if ((rc = poptGetNextOpt(optCon)) < -1) {
+        fprintf(stderr, "bad option %s: %s\n",
+               poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+               poptStrerror(rc));
+        exit(1);
+    }
+
+    if (help)
+       usage();
+
+    args = poptGetArgs(optCon);
+    if (!args || !args[0] || !args[0][0])
+        usage();
+
+    rc = implantISOFile((char *)args[0], supported, forceit, 0, &errstr);
+    if (rc) {
+        fprintf(stderr, "ERROR: ");
+        fprintf(stderr, errstr, (char *)args[0]);
+       exit(1);
+    } else {
+       exit(0);
+    }
+}
diff --git a/libcheckisomd5.c b/libcheckisomd5.c
new file mode 100644 (file)
index 0000000..8bca842
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2001-2007 Red Hat, Inc.
+ *
+ * Michael Fulbright <msf@redhat.com>
+ * Dustin Kirkland  <dustin.dirkland@gmail.com>
+ *     Added support for checkpoint fragment sums;                
+ *     Exits media check as soon as bad fragment md5sum'ed        
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "md5.h"
+#include "libcheckisomd5.h"
+
+#define APPDATA_OFFSET 883
+#define SIZE_OFFSET 84
+
+/* Length in characters of string used for fragment md5sum checking */
+#define FRAGMENT_SUM_LENGTH 60
+
+#define MAX(x, y)  ((x > y) ? x : y)
+#define MIN(x, y)  ((x < y) ? x : y)
+
+/* finds primary volume descriptor and returns info from it */
+/* mediasum must be a preallocated buffer at least 33 bytes long */
+/* fragmentsums must be a preallocated buffer at least FRAGMENT_SUM_LENGTH+1 bytes long */
+static int parsepvd(int isofd, char *mediasum, int *skipsectors, long long *isosize, int *supported, char *fragmentsums, long long *fragmentcount) {
+    unsigned char buf[2048];
+    char buf2[512];
+    char tmpbuf[512];
+    int skipfnd, md5fnd, supportedfnd, fragsumfnd, fragcntfnd;
+    unsigned int loc;
+    long long offset;
+    char *p;
+
+    if (lseek(isofd, (off_t)(16L * 2048L), SEEK_SET) == -1)
+       return ((long long)-1);
+
+    offset = (16L * 2048L);
+    for (;1;) {
+       if (read(isofd, buf, 2048) <= 0)
+           return ((long long)-1);
+
+       if (buf[0] == 1)
+           /* found primary volume descriptor */
+           break;
+       else if (buf[0] == 255)
+           /* hit end and didn't find primary volume descriptor */
+           return ((long long)-1);
+       offset += 2048L;
+    }
+
+    /* read out md5sum */
+    memcpy(buf2, buf + APPDATA_OFFSET, 512);
+    buf2[511] = '\0';
+
+    *supported = 0;
+
+    md5fnd = 0;
+    skipfnd = 0;
+    fragsumfnd = 0;
+    fragcntfnd = 0;
+    supportedfnd = 0;
+    loc = 0;
+    while (loc < 512) {
+       if (!strncmp(buf2 + loc, "ISO MD5SUM = ", 13)) {
+
+           /* make sure we dont walk off end */
+           if ((loc + 32 + 13) > 511)
+               return -1;
+
+           memcpy(mediasum, buf2 + loc + 13, 32);
+           mediasum[32] = '\0';
+           md5fnd = 1;
+           loc += 45;
+           for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+       } else if (!strncmp(buf2 + loc, "SKIPSECTORS = ", 14)) {
+           char *errptr;
+
+           /* make sure we dont walk off end */
+           if ((loc + 14) > 511)
+               return -1;
+
+           loc = loc + 14;
+           for (p=tmpbuf; buf2[loc] != ';' && loc < 512; p++, loc++)
+               *p = buf2[loc];
+
+           *p = '\0';
+
+           *skipsectors = strtol(tmpbuf, &errptr, 10);
+           if (errptr && *errptr) {
+               return -1;
+           } else {
+               skipfnd = 1;
+           }
+
+           for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+       } else if (!strncmp(buf2 + loc, "RHLISOSTATUS=1", 14)) {
+           *supported = 1;
+           supportedfnd = 1;
+           for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+       } else if (!strncmp(buf2 + loc, "RHLISOSTATUS=0", 14)) {
+           *supported = 0;
+           supportedfnd = 1;
+           for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+       } else if (!strncmp(buf2 + loc, "FRAGMENT SUMS = ", 16)) {
+            /* make sure we dont walk off end */
+            if ((loc + FRAGMENT_SUM_LENGTH) > 511)
+                return -1;
+
+            memcpy(fragmentsums, buf2 + loc + 16, FRAGMENT_SUM_LENGTH);
+            fragmentsums[FRAGMENT_SUM_LENGTH] = '\0';
+            fragsumfnd = 1;
+            loc += FRAGMENT_SUM_LENGTH + 16;
+            for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+        } else if (!strncmp(buf2 + loc, "FRAGMENT COUNT = ", 17)) {
+            char *errptr;
+            /* make sure we dont walk off end */
+            if ((loc + 17) > 511)
+                return -1;
+
+            loc = loc + 17;
+            for (p=tmpbuf; buf2[loc] != ';' && loc < 512; p++, loc++)
+                *p = buf2[loc];
+
+            *p = '\0';
+
+            *fragmentcount = strtol(tmpbuf, &errptr, 10);
+            if (errptr && *errptr) {
+                return -1;
+            } else {
+                fragcntfnd = 1;
+            }
+
+            for (p=buf2+loc; *p != ';' && loc < 512; p++, loc++);
+        } else {
+           loc++;
+       }
+
+       if ((skipfnd & md5fnd & fragsumfnd & fragcntfnd) & supportedfnd)
+           break;
+    }
+
+    if (!(skipfnd & md5fnd))
+       return -1;
+
+    /* get isosize */
+    *isosize = (buf[SIZE_OFFSET]*0x1000000+buf[SIZE_OFFSET+1]*0x10000 +
+               buf[SIZE_OFFSET+2]*0x100 + buf[SIZE_OFFSET+3]) * 2048LL;
+
+    return offset;
+}
+
+/* mediasum is the sum encoded in media, computedsum is one we compute   */
+/* both strings must be pre-allocated at least 33 chars in length        */
+static int checkmd5sum(int isofd, char *mediasum, char *computedsum, checkCallback cb, void *cbdata) {
+    int nread;
+    int i, j;
+    int appdata_start_offset, appdata_end_offset;
+    int nattempt;
+    int skipsectors;
+    int supported;
+    int current_fragment = 0;
+    int previous_fragment = 0;
+    unsigned int bufsize = 32768;
+    unsigned char md5sum[16];
+    unsigned char fragmd5sum[16];
+    unsigned int len;
+    unsigned char *buf;
+    long long isosize, offset, pvd_offset, apoff;
+    char fragmentsums[FRAGMENT_SUM_LENGTH+1];
+    char thisfragsum[FRAGMENT_SUM_LENGTH+1];
+    long long fragmentcount = 0;
+    MD5_CTX md5ctx, fragmd5ctx;
+
+    if ((pvd_offset = parsepvd(isofd, mediasum, &skipsectors, &isosize, &supported, fragmentsums, &fragmentcount)) < 0)
+       return ISOMD5SUM_CHECK_NOT_FOUND;
+
+    /*    printf("Mediasum = %s\n",mediasum); */
+
+    /* rewind, compute md5sum */
+    lseek(isofd, 0L, SEEK_SET);
+
+    MD5_Init(&md5ctx);
+
+    offset = 0;
+    apoff = pvd_offset + APPDATA_OFFSET;
+
+    buf = malloc(bufsize * sizeof(unsigned char));
+    if (cb)
+        cb(cbdata, 0, isosize - skipsectors*2048);
+
+    while (offset < isosize - skipsectors*2048) {
+       nattempt = MIN(isosize - skipsectors*2048 - offset, bufsize);
+
+       /*      printf("%lld %lld %lld %d\n", offset, isosize, isosize-SKIPSECTORS*2048, nattempt); */
+
+       nread = read(isofd, buf, nattempt);
+       if (nread <= 0)
+           break;
+
+        if (nread > nattempt) {
+            nread = nattempt;
+            lseek(isofd, offset+nread, SEEK_SET);
+        }
+       /* overwrite md5sum we implanted with original data */
+       if (offset < apoff && offset+nread >= apoff) {
+           appdata_start_offset = apoff - offset;
+           appdata_end_offset = MIN(appdata_start_offset+MIN(nread, 512),
+                                    offset + nread - apoff);
+           len = appdata_end_offset - appdata_start_offset;
+           memset(buf+appdata_start_offset, ' ', len);
+       } else if (offset >= apoff && offset+nread < apoff + 512) {
+           appdata_start_offset = 0;
+           appdata_end_offset = nread;
+           len = appdata_end_offset - appdata_start_offset;
+           memset(buf+appdata_start_offset, ' ', len);
+       } else if (offset < apoff + 512 && offset+nread >= apoff + 512) {
+           appdata_start_offset = 0;
+           appdata_end_offset = apoff + 512 - offset;
+           len = appdata_end_offset - appdata_start_offset;
+           memset(buf+appdata_start_offset, ' ', len);
+       }
+
+       MD5_Update(&md5ctx, buf, nread);
+        if (fragmentcount) {
+            current_fragment = offset * (fragmentcount+1) / (isosize - skipsectors*2048);
+            /* if we're onto the next fragment, calculate the previous sum and check */
+            if ( current_fragment != previous_fragment ) {
+               memcpy(&fragmd5ctx, &md5ctx, sizeof(MD5_CTX));
+                MD5_Final(fragmd5sum, &fragmd5ctx);
+                *computedsum = '\0';
+                j = (current_fragment-1)*FRAGMENT_SUM_LENGTH/fragmentcount;
+                for (i=0; i<FRAGMENT_SUM_LENGTH/fragmentcount; i++) {
+                    char tmpstr[2];
+                    snprintf(tmpstr, 2, "%01x", fragmd5sum[i]);
+                    strncat(computedsum, tmpstr, 2);
+                    thisfragsum[i] = fragmentsums[j++];
+                }
+                thisfragsum[j] = '\0';
+                previous_fragment = current_fragment;
+                /* Exit immediately if current fragment sum is incorrect */
+                if (strcmp(thisfragsum, computedsum) != 0) {
+                    return ISOMD5SUM_CHECK_FAILED;
+                }
+            }
+        }
+       offset = offset + nread;
+       if (cb)
+          if(cb(cbdata, offset, isosize - skipsectors*2048)) return ISOMD5SUM_CHECK_ABORTED;
+    }
+
+    if (cb)
+        cb(cbdata, isosize, isosize - skipsectors*2048);
+
+    sleep(1);
+
+    free(buf);
+
+    MD5_Final(md5sum, &md5ctx);
+
+    *computedsum = '\0';
+    for (i=0; i<16; i++) {
+       char tmpstr[4];
+       snprintf (tmpstr, 4, "%02x", md5sum[i]);
+       strncat(computedsum, tmpstr, 2);
+    }
+
+    /*    printf("mediasum, computedsum = %s %s\n", mediasum, computedsum); */
+
+    if (strcmp(mediasum, computedsum))
+       return ISOMD5SUM_CHECK_FAILED;
+    else
+       return ISOMD5SUM_CHECK_PASSED;
+}
+
+
+static int doMediaCheck(int isofd, char *mediasum, char *computedsum, long long *isosize, int *supported, checkCallback cb, void *cbdata) {
+    int rc;
+    int skipsectors;
+    long long fragmentcount = 0;
+    char fragmentsums[FRAGMENT_SUM_LENGTH+1];
+
+    if (parsepvd(isofd, mediasum, &skipsectors, isosize, supported, fragmentsums, &fragmentcount) < 0) {
+       return ISOMD5SUM_CHECK_NOT_FOUND;
+    }
+
+    rc = checkmd5sum(isofd, mediasum, computedsum, cb, cbdata);
+
+    return rc;
+}
+
+int mediaCheckFile(char *file, checkCallback cb, void *cbdata) {
+    int isofd;
+    int rc;
+    char mediasum[33], computedsum[33];
+    long long isosize;
+    int supported;
+
+    isofd = open(file, O_RDONLY);
+
+    if (isofd < 0) {
+       return ISOMD5SUM_FILE_NOT_FOUND;
+    }
+
+    rc = doMediaCheck(isofd, mediasum, computedsum, &isosize, &supported, cb, cbdata);
+
+    close(isofd);
+
+    /*    printf("isosize = %lld\n", isosize); 
+         printf("%s\n%s\n", mediasum, computedsum);*/
+
+    return rc;
+}
+
+int printMD5SUM(char *file) {
+    int isofd;
+    char mediasum[64];
+    long long isosize;
+    char fragmentsums[FRAGMENT_SUM_LENGTH+1];
+    long long fragmentcount = 0;
+    int supported;
+    int skipsectors;
+
+    isofd = open(file, O_RDONLY);
+
+    if (isofd < 0) {
+        return ISOMD5SUM_FILE_NOT_FOUND;
+    }
+
+    if (parsepvd(isofd, mediasum, &skipsectors, &isosize, &supported, fragmentsums, &fragmentcount) < 0) {
+        return ISOMD5SUM_CHECK_NOT_FOUND;
+    }
+
+    close(isofd);
+    
+    printf("%s:   %s\n", file, mediasum);
+    if ( (strlen(fragmentsums) > 0) && (fragmentcount > 0) ) {
+        printf("Fragment sums: %s\n", fragmentsums);
+        printf("Fragment count: %lld\n", fragmentcount); 
+    }
+
+    return 0;
+}
diff --git a/libcheckisomd5.h b/libcheckisomd5.h
new file mode 100644 (file)
index 0000000..78213d1
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LIBCHECKISOMD5_H__
+#define  __LIBCHECKISOMD5_H__
+
+#define ISOMD5SUM_CHECK_PASSED          1
+#define ISOMD5SUM_CHECK_FAILED          0
+#define ISOMD5SUM_CHECK_ABORTED         2
+#define ISOMD5SUM_CHECK_NOT_FOUND       -1
+#define ISOMD5SUM_FILE_NOT_FOUND        -2
+
+/* for non-zero return value, check is aborted */
+typedef int (*checkCallback)(void *, long long offset, long long total);
+
+int mediaCheckFile(char *iso, checkCallback cb, void *cbdata);
+int printMD5SUM(char *file);
+
+#endif
diff --git a/libimplantisomd5.c b/libimplantisomd5.c
new file mode 100644 (file)
index 0000000..4009809
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2001-2007 Red Hat, Inc.
+ *
+ * Michael Fulbright <msf@redhat.com>
+ * Dustin Kirkland  <dustin.dirkland@gmail.com>
+ *     Added support for checkpoint fragment sums;                
+ *     Exits media check as soon as bad fragment md5sum'ed        
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md5.h"
+#include "libimplantisomd5.h"
+
+#define APPDATA_OFFSET 883
+#define SIZE_OFFSET 84
+
+/* Length in characters of string used for fragment md5sum checking  */
+#define FRAGMENT_SUM_LENGTH 60
+/* FRAGMENT_COUNT must be an integral divisor or FRAGMENT_SUM_LENGTH */
+/* 60 => 2, 3, 4, 5, 6, 10, 12, 15, 20, or 30 */
+#define FRAGMENT_COUNT 20
+
+/* number of sectors to ignore at end of iso when computing sum */
+#define SKIPSECTORS 15
+
+#define MAX(x, y)  ((x > y) ? x : y)
+#define MIN(x, y)  ((x < y) ? x : y)
+
+/* finds primary volume descriptor and returns info from it */
+/* mediasum must be a preallocated buffer at least 33 bytes long */
+static int parsepvd(int isofd, char *mediasum, long long *isosize) {
+    unsigned char buf[2048];
+    long long offset;
+    unsigned char *p __attribute__((unused));
+
+    if (lseek(isofd, 16*2048, SEEK_SET) == -1)
+       return ((long long)-1);
+    
+    offset = (16 * 2048);
+    for (;1;) {
+        if (read(isofd, buf, 2048L) == -1)
+           return ((long long)-1);
+
+       if (buf[0] == 1)
+           /* found primary volume descriptor */
+           break;
+       else if (buf[0] == 255)
+           /* hit end and didn't find primary volume descriptor */
+           return ((long long)-1);
+       offset += 2048L;
+    }
+    
+    /* read out md5sum */
+#if 0
+    memcpy(mediasum, buf + APPDATA_OFFSET + 13, 32);
+    mediasum[32] = '\0';
+
+    for (p=mediasum; *p; p++)
+       if (*p != ' ')
+           break;
+
+    /* if the md5sum was all spaces, we didn't find md5sum */
+    if (!*p)
+       return -1;
+#endif
+
+    /* get isosize */
+    *isosize = (buf[SIZE_OFFSET]*0x1000000+buf[SIZE_OFFSET+1]*0x10000 +
+               buf[SIZE_OFFSET+2]*0x100 + buf[SIZE_OFFSET+3]) * 2048LL;
+
+    return offset;
+}
+
+
+static unsigned int writeAppData(unsigned char *appdata, char *valstr, unsigned int loc) {
+    if (loc + strlen(valstr) > 511) {
+       printf("Attempted to write too much appdata, exiting...\n");
+       exit(-1);
+    }
+
+    memcpy(appdata + loc, valstr, strlen(valstr));
+
+    return loc+strlen(valstr);
+}
+
+
+
+
+int implantISOFile(char *fname, int supported, int forceit, int quiet, char **errstr) {
+    int i;
+    int isofd;
+    int nread;
+    int dirty;
+    int pvd_offset;
+    int current_fragment = 0;
+    int previous_fragment = 0;
+    int nattempt;
+    long long isosize, total;
+    unsigned char md5sum[16];
+    unsigned char fragmd5sum[16];
+    unsigned int loc;
+    unsigned int bufsize = 32768;
+    unsigned char *buf;
+    unsigned char orig_appdata[512];
+    unsigned char new_appdata[512];
+    char mediasum[33];
+    char md5str[40];
+    char fragstr[FRAGMENT_SUM_LENGTH+1];
+    MD5_CTX md5ctx, fragmd5ctx;
+
+    isofd = open(fname, O_RDWR);
+
+    if (isofd < 0) {
+       *errstr = "Error - Unable to open file %s\n\n";
+       return -1;
+    }
+
+    pvd_offset = parsepvd(isofd, mediasum, &isosize);
+    if (pvd_offset < 0) {
+       *errstr = "Could not find primary volumne!\n\n";
+       return -1;
+    }
+
+    lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
+    nread = read(isofd, orig_appdata, 512);
+
+    if (!forceit) {
+       dirty = 0;
+       for (i=0; i < 512; i++)
+           if (orig_appdata[i] != ' ')
+               dirty = 1;
+
+       if (dirty) {
+           *errstr = "Application data has been used - not implanting md5sum!\n";
+           return -1;
+       }
+    } else {
+       /* write out blanks to erase old app data */
+       lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
+       memset(new_appdata, ' ', 512);
+       i = write(isofd, new_appdata, 512);
+       if (i<0) {
+           printf("write failed %d\n", i);
+           perror("");
+       }
+    }
+
+    /* now do md5sum */
+    lseek(isofd, 0L, SEEK_SET);
+
+    MD5_Init(&md5ctx);
+    *fragstr = '\0';
+    buf = malloc(bufsize * sizeof(unsigned char));
+
+    total = 0;
+    /* read up to 15 sectors from end, due to problems reading last few */
+    /* sectors on burned CDs                                            */
+    while (total < isosize - SKIPSECTORS*2048) {
+        nattempt = MIN(isosize - SKIPSECTORS*2048 - total, bufsize);
+       nread = read(isofd, buf, nattempt);
+
+       if (nread <= 0)
+           break;
+       
+       MD5_Update(&md5ctx, buf, nread);
+
+        /* if we're onto the next fragment, calculate the previous sum and write */
+        current_fragment = total * (FRAGMENT_COUNT+1) / (isosize - SKIPSECTORS*2048);
+        if ( current_fragment != previous_fragment ) {
+           memcpy(&fragmd5ctx, &md5ctx, sizeof(MD5_CTX));
+            MD5_Final(fragmd5sum, &fragmd5ctx);
+            for (i=0; i<FRAGMENT_SUM_LENGTH/FRAGMENT_COUNT; i++) {
+                char tmpstr[2];
+                snprintf(tmpstr, 2, "%01x", fragmd5sum[i]);
+                strncat(fragstr, tmpstr, 2);
+            }
+            /*  printf("\nFragment [%i]: %s\n", previous_fragment, fragstr);  */
+            previous_fragment = current_fragment;
+        }
+
+       total = total + nread;
+    }
+    free(buf);
+
+    MD5_Final(md5sum, &md5ctx);
+
+    *md5str = '\0';
+    for (i=0; i<16; i++) {
+       char tmpstr[4];
+       snprintf (tmpstr, 4, "%02x", md5sum[i]);
+       strncat(md5str, tmpstr, 2);
+    }
+
+    if (!quiet) {
+       printf("Inserting md5sum into iso image...\n");
+       printf("md5 = %s\n", md5str);
+       printf("Inserting fragment md5sums into iso image...\n");
+       printf("fragmd5 = %s\n", fragstr);
+       printf("frags = %d\n", FRAGMENT_COUNT);
+    }
+    /*    memcpy(new_appdata, orig_appdata, 512); */
+    memset(new_appdata, ' ', 512);
+
+    loc = 0;
+    loc = writeAppData(new_appdata, "ISO MD5SUM = ", loc);
+    loc = writeAppData(new_appdata, md5str, loc);
+    loc = writeAppData(new_appdata, ";", loc);
+
+    buf = malloc(512 * sizeof(unsigned char));
+    snprintf((char *)buf, 512, "SKIPSECTORS = %d", SKIPSECTORS);
+
+    loc = writeAppData(new_appdata, (char *)buf, loc);
+    loc = writeAppData(new_appdata, ";", loc);
+    free(buf);
+
+    if (supported) {
+       if (!quiet)
+           printf("Setting supported flag to 1\n");
+       loc = writeAppData(new_appdata, "RHLISOSTATUS=1", loc);
+    } else {
+       if (!quiet)
+           printf("Setting supported flag to 0\n");
+       loc = writeAppData(new_appdata, "RHLISOSTATUS=0", loc);
+    }
+       
+    loc = writeAppData(new_appdata, ";", loc);
+
+    loc = writeAppData(new_appdata, "FRAGMENT SUMS = ", loc);
+    loc = writeAppData(new_appdata, fragstr, loc);
+    loc = writeAppData(new_appdata, ";", loc);
+
+    buf = malloc(512 * sizeof(unsigned char));
+    snprintf((char *)buf, 512, "FRAGMENT COUNT = %d", FRAGMENT_COUNT);
+    loc = writeAppData(new_appdata, (char *)buf, loc);
+    loc = writeAppData(new_appdata, ";", loc);
+    free(buf);
+
+    loc = writeAppData(new_appdata, "THIS IS NOT THE SAME AS RUNNING MD5SUM ON THIS ISO!!", loc);
+    
+    i = lseek(isofd, pvd_offset + APPDATA_OFFSET, SEEK_SET);
+    if (i<0)
+       printf("seek failed\n");
+
+    i = write(isofd, new_appdata, 512);
+    if (i<0) {
+       printf("write failed %d\n", i);
+       perror("");
+    }
+
+    close(isofd);
+    errstr = NULL;
+    return 0;
+}
diff --git a/libimplantisomd5.h b/libimplantisomd5.h
new file mode 100644 (file)
index 0000000..92fddb5
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef __LIBIMPLANTISOMD5_H__
+#define __LIBIMPLANTISOMD5_H__
+int implantISOFile(char *iso, int supported, int forceit, int quiet, char **errstr);
+#endif
+
diff --git a/md5.c b/md5.c
new file mode 100644 (file)
index 0000000..a1bdd4a
--- /dev/null
+++ b/md5.c
@@ -0,0 +1,265 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Modified 12 June 2003 Jeremy Katz <katzj@redhat.com> to handle 
+ *    endianness better
+ *
+ */
+
+#include <string.h>
+#include <endian.h>
+#include "md5.h"
+
+void MD5_Transform(uint32 *buf, uint32 const *in);
+
+#define IS_BIG_ENDIAN() (__BYTE_ORDER == __BIG_ENDIAN)
+#define IS_LITTLE_ENDIAN() (__BYTE_ORDER == __LITTLE_ENDIAN)
+
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+       uint32 t;
+       do {
+               t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+                   ((unsigned) buf[1] << 8 | buf[0]);
+               *(uint32 *) buf = t;
+               buf += 4;
+       } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5_Init(struct MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301U;
+       ctx->buf[1] = 0xefcdab89U;
+       ctx->buf[2] = 0x98badcfeU;
+       ctx->buf[3] = 0x10325476U;
+
+       ctx->bits[0] = 0;
+       ctx->bits[1] = 0;
+
+
+       if (IS_BIG_ENDIAN())
+            ctx->doByteReverse = 1;
+       else 
+            ctx->doByteReverse = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5_Update(struct MD5Context *ctx, unsigned const char *buf, unsigned len)
+{
+       uint32 t;
+
+       /* Update bitcount */
+
+       t = ctx->bits[0];
+       if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+               ctx->bits[1]++; /* Carry from low to high */
+       ctx->bits[1] += len >> 29;
+
+       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+       /* Handle any leading odd-sized chunks */
+
+       if (t) {
+               unsigned char *p = (unsigned char *) ctx->in + t;
+
+               t = 64 - t;
+               if (len < t) {
+                       memcpy(p, buf, len);
+                       return;
+               }
+               memcpy(p, buf, t);
+               if (ctx->doByteReverse) byteReverse(ctx->in, 16);
+               MD5_Transform(ctx->buf, (uint32 *) ctx->in);
+               buf += t;
+               len -= t;
+       }
+       /* Process data in 64-byte chunks */
+
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               if (ctx->doByteReverse) byteReverse(ctx->in, 16);
+               MD5_Transform(ctx->buf, (uint32 *) ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5_Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+       unsigned count;
+       unsigned char *p;
+
+       /* Compute number of bytes mod 64 */
+       count = (ctx->bits[0] >> 3) & 0x3F;
+
+       /* Set the first char of padding to 0x80.  This is safe since there is
+          always at least one byte free */
+       p = ctx->in + count;
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 64 bytes */
+       count = 64 - 1 - count;
+
+       /* Pad out to 56 mod 64 */
+       if (count < 8) {
+               /* Two lots of padding:  Pad the first block to 64 bytes */
+               memset(p, 0, count);
+               if (ctx->doByteReverse) byteReverse(ctx->in, 16);
+               MD5_Transform(ctx->buf, (uint32 *) ctx->in);
+
+               /* Now fill the next block with 56 bytes */
+               memset(ctx->in, 0, 56);
+       } else {
+               /* Pad block to 56 bytes */
+               memset(p, 0, count - 8);
+       }
+       if (ctx->doByteReverse) byteReverse(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ((uint32 *) ctx->in)[14] = ctx->bits[0];
+       ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+       MD5_Transform(ctx->buf, (uint32 *) ctx->in);
+       if (ctx->doByteReverse) byteReverse((unsigned char *) ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5_Transform(uint32 buf[4], uint32 const in[16])
+{
+       register uint32 a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+#endif
diff --git a/md5.h b/md5.h
new file mode 100644 (file)
index 0000000..fd4ea0e
--- /dev/null
+++ b/md5.h
@@ -0,0 +1,26 @@
+
+#ifndef MD5_H
+#define MD5_H
+
+#include <sys/types.h>
+
+typedef u_int32_t uint32;
+
+struct MD5Context {
+       uint32 buf[4];
+       uint32 bits[2];
+       unsigned char in[64];
+       int doByteReverse;
+};
+
+void MD5_Init(struct MD5Context *);
+void MD5_Update(struct MD5Context *, unsigned const char *, unsigned);
+void MD5_Final(unsigned char digest[16], struct MD5Context *);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+
+typedef struct MD5Context MD5_CTX;
+
+#endif                         /* MD5_H */
diff --git a/pyisomd5sum.c b/pyisomd5sum.c
new file mode 100644 (file)
index 0000000..a0c40da
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2001-2007 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <Python.h>
+#include <stdio.h>
+
+#include "libcheckisomd5.h"
+#include "libimplantisomd5.h"
+
+static PyObject * doCheckIsoMD5Sum(PyObject * s, PyObject * args);
+static PyObject * doImplantIsoMD5Sum(PyObject * s, PyObject * args);
+
+static PyMethodDef isomd5sumMethods[] = {
+    { "checkisomd5sum", (PyCFunction) doCheckIsoMD5Sum, METH_VARARGS, NULL },
+    { "implantisomd5sum", (PyCFunction) doImplantIsoMD5Sum, METH_VARARGS, NULL },
+    { NULL }
+} ;
+
+
+static PyObject * doCheckIsoMD5Sum(PyObject * s, PyObject * args) {
+    char *isofile;
+    int rc;
+
+    if (!PyArg_ParseTuple(args, "s", &isofile))
+       return NULL;
+    rc = mediaCheckFile(isofile, NULL, NULL);
+
+    return Py_BuildValue("i", rc);
+}
+
+static PyObject * doImplantIsoMD5Sum(PyObject * s, PyObject * args) {
+    char *isofile, *errstr;
+    int forceit, supported;
+    int rc;
+
+    if (!PyArg_ParseTuple(args, "sii", &isofile, &supported, &forceit))
+       return NULL;
+
+    rc = implantISOFile(isofile, supported, forceit, 1, &errstr);
+
+    return Py_BuildValue("i", rc);
+}
+
+
+void initpyisomd5sum(void) {
+    PyObject * m, * d;
+
+    m = Py_InitModule("pyisomd5sum", isomd5sumMethods);
+    d = PyModule_GetDict(m);
+}
diff --git a/testpyisomd5sum.py b/testpyisomd5sum.py
new file mode 100755 (executable)
index 0000000..6f79830
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+import os
+import pyisomd5sum
+
+# create iso file
+os.system("mkisofs -quiet . > testiso.iso")
+
+# implant it
+print "Implanting -> ", pyisomd5sum.implantisomd5sum("testiso.iso", 1, 0)
+
+# do it again without forcing, should get error
+print "Implanting again w/o forcing -> ", pyisomd5sum.implantisomd5sum("testiso.iso", 1, 0)
+
+# do it again with forcing, should work
+print "Implanting again forcing -> ", pyisomd5sum.implantisomd5sum("testiso.iso", 1, 1)
+
+# check it
+print "Checking -> ",pyisomd5sum.checkisomd5sum("testiso.iso")
+
+# clean up
+os.unlink("testiso.iso")