Fixed generation of rsyncsums v1.14-ish
authorSteve McIntyre <steve@einval.com>
Sun, 13 Mar 2005 22:28:14 +0000 (22:28 +0000)
committerSteve McIntyre <steve@einval.com>
Sun, 13 Mar 2005 22:28:14 +0000 (22:28 +0000)
Added -d option to mkjigsnap to specify DIRNAME
Minor prettiness tweaks to output UI of mkimage and jigit
64-bit printf fixes

JTE-patch1.gz
Makefile
jigdump.c
md5.c
mkimage.c
mkisofs-JTE.gz
mkjigsnap
mkjigsnap.8
rsync.c [new file with mode: 0644]

index 5c7dca4..9636296 100644 (file)
Binary files a/JTE-patch1.gz and b/JTE-patch1.gz differ
index aae0a18..eac209f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-BINS = jigdump mkimage jigsum
+BINS = jigdump mkimage jigsum rsyncsum
 CFLAGS = -g -Wall -Werror -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
 CC = gcc
 
@@ -10,6 +10,12 @@ mkimage: mkimage.o endian.o md5.o
 jigsum: jigsum.o md5.o
        $(CC) -o $@ $+
 
+rsyncsum: rsync.o md5.o
+       $(CC) -o $@ $+
+
+jigdump: jigdump.o md5.o
+       $(CC) -o $@ $+
+
 clean:
        rm -f *.o $(BINS) *~
 
index 7d7b610..e13a2b9 100644 (file)
--- a/jigdump.c
+++ b/jigdump.c
@@ -9,8 +9,10 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include "md5.h"
 
 typedef unsigned long long UINT64;
+typedef long long INT64;
 typedef unsigned long      UINT32;
 
 #define BUF_SIZE 65536
@@ -25,10 +27,10 @@ typedef enum state_
     ERROR
 } e_state;
 
-off_t find_string(unsigned char *buf, size_t buf_size, char *search)
+INT64 find_string(unsigned char *buf, size_t buf_size, char *search)
 {
     size_t length = strlen(search);
-    off_t result;
+    INT64 result;
     
     for (result = 0; result < (buf_size - length); result++)
     {
@@ -38,7 +40,7 @@ off_t find_string(unsigned char *buf, size_t buf_size, char *search)
     return -1;
 }
 
-off_t parse_data_block(off_t offset, unsigned char *buf, size_t buf_size)
+INT64 parse_data_block(INT64 offset, unsigned char *buf, size_t buf_size)
 {
     /* Parse the contents of this data block... */
     UINT64 dataLen = 0;
@@ -64,31 +66,7 @@ off_t parse_data_block(off_t offset, unsigned char *buf, size_t buf_size)
     return dataLen;
 }
 
-void base64_dump(unsigned char *buf, size_t buf_size)
-{
-    const char *b64_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-    int value = 0;
-    unsigned int i;
-    int bits = 0;
-
-    for (i = 0; i < buf_size ; i++)
-    {
-        value = (value << 8) | buf[i];
-        bits += 2;
-        printf("%c", b64_enc[(value >> bits) & 63U]);
-        if (bits >= 8) {
-            bits -= 6;
-            printf("%c", b64_enc[(value >> bits) & 63U]);
-        }
-    }
-    if (bits > 0)
-    {
-        value <<= 8 - bits;
-        printf("%c", b64_enc[(value >> bits) & 63U]);
-    }
-}
-
-off_t parse_desc_block(off_t offset, unsigned char *buf, size_t buf_size)
+INT64 parse_desc_block(INT64 offset, unsigned char *buf, size_t buf_size)
 {
     /* Parse the contents of this data block... */
     UINT64 descLen = 0;
@@ -105,7 +83,7 @@ off_t parse_desc_block(off_t offset, unsigned char *buf, size_t buf_size)
     return 10;
 }
 
-off_t parse_desc_data(off_t offset, unsigned char *buf, size_t buf_size)
+INT64 parse_desc_data(INT64 offset, unsigned char *buf, size_t buf_size)
 {
     int type = buf[0];
     printf("  DESC entry: block type %d\n", type);
@@ -146,10 +124,8 @@ off_t parse_desc_data(off_t offset, unsigned char *buf, size_t buf_size)
             printf("    Image MD5: ");
             for (i = 7; i < 23; i++)
                 printf("%2.2x", buf[i]);
-            printf(" (");
-            base64_dump(&buf[7], 16);
-            printf(")");
-            printf("\n    MD5 block length %lu bytes\n", blocklen);
+            printf(" (%s)\n", base64_dump(&buf[7], 16));
+            printf("    Rsync block length %lu bytes\n", blocklen);
             return 0; /* i.e. we're finished! */
         }
         case 6:
@@ -168,13 +144,11 @@ off_t parse_desc_data(off_t offset, unsigned char *buf, size_t buf_size)
             printf("    file rsyncsum: ");
             for (i = 7; i < 15; i++)
                 printf("%2.2x", buf[i]);
-            printf("\n    file md5: ");
+            printf(" (%s)\n", base64_dump(&buf[7], 8));
+            printf("    file md5: ");
             for (i = 15; i < 31; i++)
                 printf("%2.2x", buf[i]);
-            printf(" (");
-            base64_dump(&buf[15], 16);
-            printf(")");
-            printf("\n");
+            printf(" (%s)\n", base64_dump(&buf[15], 16));
             return 31;
         }
         default:
@@ -189,8 +163,8 @@ int main(int argc, char **argv)
     char *filename = NULL;
     int fd = -1;
     unsigned char *buf = NULL;
-    off_t offset = 0;
-    off_t bytes = 0;
+    INT64 offset = 0;
+    INT64 bytes = 0;
     e_state state = STARTING;
     
     if (argc != 2)
@@ -218,7 +192,7 @@ int main(int argc, char **argv)
     /* Find the beginning of the data - read the first chunk, including the header */
     while (STARTING == state)
     {
-        off_t start_offset = -1;
+        INT64 start_offset = -1;
 
         bytes = read(fd, buf, BUF_SIZE);
         if (0 >= bytes)
@@ -238,7 +212,7 @@ int main(int argc, char **argv)
 
     while (DONE != state && ERROR != state)
     {
-        off_t start_offset = -1;
+        INT64 start_offset = -1;
         lseek(fd, offset, SEEK_SET);
         bytes = read(fd, buf, BUF_SIZE);
         if (0 >= bytes)
diff --git a/md5.c b/md5.c
index a0cbc3a..7f6bd3e 100644 (file)
--- a/md5.c
+++ b/md5.c
@@ -309,15 +309,15 @@ char *base64_dump(unsigned char *buf, size_t buf_size)
         value = (value << 8) | buf[i];
         bits += 2;
         out[out_pos++] = b64_enc[(value >> bits) & 63U];
-        if (bits >= 8) {
+        if (bits >= 6) {
             bits -= 6;
             out[out_pos++] = b64_enc[(value >> bits) & 63U];
         }
     }
     if (bits > 0)
     {
-        value <<= 8 - bits;
-        out[out_pos++] = b64_enc[(value >> bits) & 63U];
+        value <<= 6 - bits;
+        out[out_pos++] = b64_enc[value & 63U];
     }
     return out;
 }
index ad843ea..0fa99eb 100644 (file)
--- a/mkimage.c
+++ b/mkimage.c
 #include "endian.h"
 #include "md5.h"
 
+typedef long long INT64;
 typedef unsigned long long UINT64;
 typedef unsigned long      UINT32;
 
+#ifndef LLONG_MAX
+#   define LLONG_MAX (INT64)INT_MAX * INT_MAX
+#endif
+
 #define BUF_SIZE 65536
 #define MISSING -1
 
@@ -34,8 +39,8 @@ typedef unsigned long      UINT32;
 FILE *logfile = NULL;
 FILE *outfile = NULL;
 FILE *missing_file = NULL;
-unsigned long long start_offset = 0;
-unsigned long long end_offset = 0;
+long long start_offset = 0;
+long long end_offset = 0;
 int quick = 0;
 int verbose = 0;
 UINT64 out_size = 0;
@@ -63,7 +68,7 @@ match_list_t *match_list_tail = NULL;
 typedef struct md5_list_
 {
     struct md5_list_ *next;
-    off_t file_size;
+    INT64 file_size;
     char *md5;
     char *full_path;
 } md5_list_t;
@@ -74,9 +79,9 @@ md5_list_t *md5_list_tail = NULL;
 struct
 {
     char   *data_buf;
-    size_t  buf_size;
-    off_t   offset_in_curr_buf;
-    off_t   total_offset;
+    INT64  buf_size;
+    INT64   offset_in_curr_buf;
+    INT64   total_offset;
 } zip_state;
 
 /* Grab the file component from a full path */
@@ -109,7 +114,7 @@ static void write_missing_entry(char *missing, char *filename)
     fprintf(missing_file, "%s\n", filename);
 }
 
-static off_t get_file_size(char *filename)
+static INT64 get_file_size(char *filename)
 {
     struct stat sb;
     int error = 0;
@@ -123,7 +128,7 @@ static off_t get_file_size(char *filename)
 
 static void display_progress(FILE *file, char *text)
 {
-    off_t written = ftello(file);
+    INT64 written = ftello(file);
     if (out_size > 0)
         fprintf(logfile, "\r %5.2f%%  %-60.60s",
                100.0 * written / out_size, text);
@@ -177,7 +182,7 @@ static int add_match_entry(char *match)
     return 0;
 }
 
-static int file_exists(char *path, off_t *size)
+static int file_exists(char *path, INT64 *size)
 {
     struct stat sb;
     int error = 0;
@@ -193,7 +198,7 @@ static int file_exists(char *path, off_t *size)
     return 0;
 }
 
-static int find_file_in_mirror(char *jigdo_entry, char **mirror_path, char **md5sum, off_t *file_size)
+static int find_file_in_mirror(char *jigdo_entry, char **mirror_path, char **md5sum, INT64 *file_size)
 {
     match_list_t *entry = match_list_head;
     char path[PATH_MAX];
@@ -249,7 +254,7 @@ static int find_file_in_mirror(char *jigdo_entry, char **mirror_path, char **md5
 }
 
 
-static int add_md5_entry(off_t size, char *md5, char *path)
+static int add_md5_entry(INT64 size, char *md5, char *path)
 {
     md5_list_t *new = NULL;    
     new = calloc(1, sizeof(*new));
@@ -279,7 +284,7 @@ static int parse_md5_entry(char *md5_entry)
     int error = 0;
     char *file_name = NULL;
     char *md5 = NULL;
-    off_t file_size = 0;
+    INT64 file_size = 0;
 
     md5_entry[22] = 0;
     md5_entry[23] = 0;
@@ -329,7 +334,7 @@ static int add_file_entry(char *jigdo_entry)
     int error = 0;
     char *file_name = NULL;
     char *md5 = NULL;
-    off_t file_size = 0;
+    INT64 file_size = 0;
     
     error = find_file_in_mirror(jigdo_entry, &file_name, &md5, &file_size);
 
@@ -381,7 +386,7 @@ static int parse_jigdo_file(char *filename)
     return error;
 }
 
-static int ungzip_data_block(char *in_buf, size_t in_len, char *out_buf, size_t out_len)
+static int ungzip_data_block(char *in_buf, INT64 in_len, char *out_buf, INT64 out_len)
 {
     int error = 0;
     z_stream uc_stream;
@@ -420,7 +425,7 @@ static int ungzip_data_block(char *in_buf, size_t in_len, char *out_buf, size_t
 }    
 
 #ifdef BZ2_SUPPORT
-static int unbzip_data_block(char *in_buf, size_t in_len, char *out_buf, size_t out_len)
+static int unbzip_data_block(char *in_buf, INT64 in_len, char *out_buf, INT64 out_len)
 {
     int error = 0;
     bz_stream uc_stream;
@@ -459,8 +464,8 @@ static int unbzip_data_block(char *in_buf, size_t in_len, char *out_buf, size_t
 }    
 #endif
 
-static int decompress_data_block(char *in_buf, size_t in_len, char *out_buf,
-                                 size_t out_len, int compress_type)
+static int decompress_data_block(char *in_buf, INT64 in_len, char *out_buf,
+                                 INT64 out_len, int compress_type)
 {
 #ifdef BZ2_SUPPORT
     if (COMP_BZIP == compress_type)
@@ -473,10 +478,10 @@ static int decompress_data_block(char *in_buf, size_t in_len, char *out_buf,
 static int read_data_block(FILE *template_file, int compress_type)
 {
     char inbuf[1024];
-    off_t i = 0;
-    static off_t template_offset = -1;
-    off_t compressed_len = 0;
-    off_t uncompressed_len = 0;
+    INT64 i = 0;
+    static INT64 template_offset = -1;
+    INT64 compressed_len = 0;
+    INT64 uncompressed_len = 0;
     char *comp_buf = NULL;
     int read_num = 0;
     int error = 0;
@@ -552,11 +557,11 @@ static int read_data_block(FILE *template_file, int compress_type)
     return 0;
 }
 
-static int skip_data_block(size_t data_size, FILE *template_file, int compress_type)
+static int skip_data_block(INT64 data_size, FILE *template_file, int compress_type)
 {
     int error = 0;
-    size_t remaining = data_size;
-    size_t size = 0;
+    INT64 remaining = data_size;
+    INT64 size = 0;
 
     /* If we're coming in in the middle of the image, we'll need to
        skip through some compressed data */
@@ -583,16 +588,16 @@ static int skip_data_block(size_t data_size, FILE *template_file, int compress_t
         }
     }
     
-    fprintf(logfile, "skip_data_block: skipped %d bytes of unmatched data\n", data_size);
+    fprintf(logfile, "skip_data_block: skipped %lld bytes of unmatched data\n", data_size);
     return error;
 }
 
-static int parse_data_block(size_t data_size, FILE *template_file,
+static int parse_data_block(INT64 data_size, FILE *template_file,
                             struct mk_MD5Context *context, int compress_type)
 {
     int error = 0;
-    size_t remaining = data_size;
-    size_t size = 0;
+    INT64 remaining = data_size;
+    INT64 size = 0;
     int out_size = 0;
 
     while (remaining)
@@ -611,7 +616,7 @@ static int parse_data_block(size_t data_size, FILE *template_file,
         out_size = fwrite(&zip_state.data_buf[zip_state.offset_in_curr_buf], size, 1, outfile);
         if (!out_size)
         {
-            fprintf(logfile, "parse_data_block: fwrite %d failed with error %d; aborting\n", size, ferror(outfile));
+            fprintf(logfile, "parse_data_block: fwrite %lld failed with error %d; aborting\n", size, ferror(outfile));
             return ferror(outfile);
         }
 
@@ -630,18 +635,18 @@ static int parse_data_block(size_t data_size, FILE *template_file,
         }
     }
     if (verbose > 1)
-        fprintf(logfile, "parse_data_block: wrote %d bytes of unmatched data\n", data_size);
+        fprintf(logfile, "parse_data_block: wrote %lld bytes of unmatched data\n", data_size);
     return error;
 }
 
-static int parse_file_block(off_t offset, size_t data_size, off_t file_size, 
+static int parse_file_block(INT64 offset, INT64 data_size, INT64 file_size, 
                             char *md5, struct mk_MD5Context *image_context,
                             char *missing)
 {
     char *base64_md5 = base64_dump(md5, 16);
     FILE *input_file = NULL;
     char buf[BUF_SIZE];
-    size_t remaining = data_size;
+    INT64 remaining = data_size;
     int num_read = 0;
     struct mk_MD5Context file_context;
     char file_md5[16];
@@ -735,14 +740,14 @@ static int parse_file_block(off_t offset, size_t data_size, off_t file_size,
 
 static int parse_template_file(char *filename, int sizeonly, char *missing, char *output_name)
 {
-    off_t template_offset = 0;
-    off_t bytes = 0;
+    INT64 template_offset = 0;
+    INT64 bytes = 0;
     unsigned char *buf = NULL;
     FILE *file = NULL;
-    off_t file_size = 0;
-    off_t desc_start = 0;
-    off_t written_length = 0;
-    off_t output_offset = 0;
+    INT64 file_size = 0;
+    INT64 desc_start = 0;
+    INT64 written_length = 0;
+    INT64 output_offset = 0;
     int i = 0;
     int error = 0;
     struct mk_MD5Context template_context;
@@ -828,9 +833,9 @@ static int parse_template_file(char *filename, int sizeonly, char *missing, char
     /* Main loop - walk through the template file and expand each entry we find */
     while (1)
     {
-        off_t extent_size;
-        off_t skip = 0;
-        off_t read_length = 0;
+        INT64 extent_size;
+        INT64 skip = 0;
+        INT64 read_length = 0;
 
         if (template_offset >= (file_size - 33))
         {
@@ -1072,7 +1077,7 @@ int main(int argc, char **argv)
     }
 
     if (0 == end_offset)
-        end_offset = (unsigned long long)LONG_MAX * LONG_MAX;
+        end_offset = LLONG_MAX;
 
     if ((NULL == jigdo_filename) &&
         (NULL == md5_filename) && 
index f07906a..87b944f 100644 (file)
Binary files a/mkisofs-JTE.gz and b/mkisofs-JTE.gz differ
index 192abc8..1a47a34 100755 (executable)
--- a/mkjigsnap
+++ b/mkjigsnap
 #      snapshot will be written
 #   the locations of the input jigdo and template files
 #   the keyword to look for (e.g. Debian)
+#   the snapshot dirname (e.g. today's date)
 # Example:
 # ./mkjigsnap -o /tmp/mjs-test -n mjs-test -m /tmp/mirror \
 #      -j ~/jigdo/update/debian-update-3.0r2.01-i386.jigdo \
 #      -t ~/jigdo/update/debian-update-3.0r2.01-i386.template \
 #      -k Debian -k Non-US
+#      -d 20041017
 
 while [ $# -gt 0 ]
 do
@@ -48,6 +50,11 @@ do
             TEMPLATE=$1
             shift
             ;;
+        "-d"x)
+            shift
+            DIRNAME=$1
+            shift
+            ;;
         "-k"x)
             shift
             KEYWORDS="$KEYWORDS $1"
@@ -85,30 +92,33 @@ if [ "$TEMPLATE"x = ""x ] ; then
     exit 1
 fi
     
+if [ "$DIRNAME"x = ""x ] ; then
+    echo "You must specify the snapshot directory name!"
+    exit 1
+fi
+    
 if [ "$KEYWORDS"x = ""x ] ; then
     echo "You must specify the keywords to match!"
     exit 1
 fi
 
-DATE=`date '+%Y-%m-%d'`
-    
 # If we got here, we have all the info we need
 echo "Creating snapshot tree:"
 for KEYWORD in $KEYWORDS
 do
-    NUM=$(( $NUM + `grep "$KEYWORD:" $JIGDO | wc -l`))
+    NUM=$(( $NUM + `zcat -f $JIGDO | grep "$KEYWORD:" | wc -l`))
 done
 LINKS_DONE=0
 for KEYWORD in $KEYWORDS
 do
-    for jentry in `cat $JIGDO | grep =$KEYWORD:`
+    for jentry in `zcat -f $JIGDO | grep =$KEYWORD:`
     do
         file=`echo $jentry | sed "s/^.*$KEYWORD://g"`
-        dir=$OUT/snapshot/$DATE/`dirname $file`
+        dir=$OUT/snapshot/$DIRNAME/`dirname $file`
         if [ ! -d $dir ] ; then
             mkdir -p $dir
         fi
-        ln -f $MIRROR/$file $OUT/snapshot/$DATE/$file
+        ln -f $MIRROR/$file $OUT/snapshot/$DIRNAME/$file
         error=$?
         if [ $error -ne 0 ] ; then
             echo "Unable to link $MIRROR/$file; error $error"
@@ -121,9 +131,9 @@ done
 
 echo
 
-cp $JIGDO $OUT/$CDNAME.jigdo
+zcat -f $JIGDO | sed "s:^Template=.*$:Template=$CDNAME.template:" | gzip -9 > $OUT/$CDNAME.jigdo
 cp $TEMPLATE $OUT/$CDNAME.template
 echo "JIGDO=$CDNAME.jigdo" > $OUT/$CDNAME.conf
 echo "TEMPLATE=$CDNAME.template" >> $OUT/$CDNAME.conf
-echo "SNAPSHOT=snapshot/$DATE" >> $OUT/$CDNAME.conf
+echo "SNAPSHOT=snapshot/$DIRNAME" >> $OUT/$CDNAME.conf
 
index 33d84b7..d61d4fd 100644 (file)
@@ -4,7 +4,8 @@ mkjigsnap \- Create a snapshot tree on a jigdo server
 .SH SYNOPSIS
 .B mkjigsnap
 \-n \f CD name\fR \-m \f mirror\fR \-o \f output directory\fR
-\-j \f jigdo file\fR \-t \f template file\fR \-k \f keyword\fR
+\-d \f dirname\fR \-j \f jigdo file\fR \-t \f template file\fR
+\-k \f keyword\fR
 .SH DESCRIPTION
 .PP
 mkjigsnap will create the directory tree and snapshot needed for jigit
@@ -16,6 +17,10 @@ options.
 \fB\-n CD name\fR
 Specify the output name for jigit (e.g. warty, sarge-i386-1).
 .TP
+\fB\-d dir name\fR
+Specify the output directory name to be used for the snapshot tree
+(e.g. 20041011, rc1).
+.TP
 \fB\-m mirror\fR
 Specify the location of the mirror containing all the files
 needed. This
diff --git a/rsync.c b/rsync.c
new file mode 100644 (file)
index 0000000..ee69be2
--- /dev/null
+++ b/rsync.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "md5.h"
+
+typedef unsigned long UInt32_t;
+
+/* Borrowed from jigdo; original notice:
+
+   These are purely random, no patterns or anything... (I hope)
+
+   I do not claim copyright for the actual numbers below, you may use them
+   for a re-implementation of the algorithm under a license of your choice.
+   -- Richard Atterer. */
+static UInt32_t charTable[256] = {
+  0x51d65c0f, 0x083cd94b, 0x77f73dd8, 0xa0187d36,
+  0x29803d07, 0x7ea8ac0e, 0xea4c16c9, 0xfc576443,
+  0x6213df29, 0x1c012392, 0xb38946ae, 0x2e20ca31,
+  0xe4dc532f, 0xcb281c47, 0x8508b6a5, 0xb93c210d,
+  0xef02b5f3, 0x66548c74, 0x9ae2deab, 0x3b59f472,
+  0x4e546447, 0x45232d1f, 0x0ac0a4b1, 0x6c4c264b,
+  0x5d24ce84, 0x0f2752cc, 0xa35c7ac7, 0x3e31af51,
+  0x79675a59, 0x581f0e81, 0x49053122, 0x7339c9d8,
+  0xf9833565, 0xa3dbe5b3, 0xcc06eeb9, 0x92d0671c,
+  0x3eb220a7, 0x64864eae, 0xca100872, 0xc50977a1,
+  0xd90378e1, 0x7a36cab9, 0x15c15f4b, 0x8b9ef749,
+  0xcc1432dc, 0x1ec578ed, 0x27e6e092, 0xbb06db8f,
+  0x67f661ac, 0x8dd1a3db, 0x2a0ca16b, 0xb229ab84,
+  0x127a3337, 0x347d846f, 0xe1ea4b50, 0x008dbb91,
+  0x414c1426, 0xd2be76f0, 0x08789a39, 0xb4d93e30,
+  0x61667760, 0x8871bee9, 0xab7da12d, 0xe3c58620,
+  0xe9fdfbbe, 0x64fb04f7, 0x8cc5bbf0, 0xf5272d30,
+  0x8f161b50, 0x11122b05, 0x7695e72e, 0xa1c5d169,
+  0x1bfd0e20, 0xef7e6169, 0xf652d08e, 0xa9d0f139,
+  0x2f70aa04, 0xae2c7d6d, 0xa3cb9241, 0x3ae7d364,
+  0x348788f8, 0xf483b8f1, 0x55a011da, 0x189719dc,
+  0xb0c5d723, 0x8b344e33, 0x300d46eb, 0xd44fe34f,
+  0x1a2016c1, 0x66ce4cd7, 0xa45ea5e3, 0x55cb708a,
+  0xbce430df, 0xb01ae6e0, 0x3551163b, 0x2c5b157a,
+  0x574c4209, 0x430fd0e4, 0x3387e4a5, 0xee1d7451,
+  0xa9635623, 0x873ab89b, 0xb96bc6aa, 0x59898937,
+  0xe646c6e7, 0xb79f8792, 0x3f3235d8, 0xef1b5acf,
+  0xd975b22b, 0x427acce6, 0xe47a2411, 0x75f8c1e8,
+  0xa63f799d, 0x53886ad8, 0x9b2d6d32, 0xea822016,
+  0xcdee2254, 0xd98bcd98, 0x2933a544, 0x961f379f,
+  0x49219792, 0xc61c360f, 0x77cc0c64, 0x7b872046,
+  0xb91c7c12, 0x7577154b, 0x196573be, 0xf788813f,
+  0x41e2e56a, 0xec3cd244, 0x8c7401f1, 0xc2e805fe,
+  0xe8872fbe, 0x9e2faf7d, 0x6766456b, 0x888e2197,
+  0x28535c6d, 0x2ce45f3f, 0x24261d2a, 0xd6faab8b,
+  0x7a7b42b8, 0x15f0f6fa, 0xfe1711df, 0x7e5685a6,
+  0x00930268, 0x74755331, 0x1998912c, 0x7b60498b,
+  0x501a5786, 0x92ace0f6, 0x1d9752fe, 0x5a731add,
+  0x5b3b44fc, 0x473673f9, 0xa42c0321, 0xd82f9f18,
+  0xb4b225da, 0xfc89ece2, 0x072e1130, 0x5772aae3,
+  0x29010857, 0x542c970c, 0x94f67fe5, 0x71209e9b,
+  0xdb97ea39, 0x2689b41b, 0xae815804, 0xfc5e2651,
+  0xd4521674, 0x48ed979a, 0x2f617da3, 0xc350353d,
+  0xc3accd94, 0xbd8d313a, 0xc61a8e77, 0xf34940a4,
+  0x8d2c6b0f, 0x0f0e7225, 0x39e183db, 0xd19ebba9,
+  0x6a0f37b9, 0xd18922f3, 0x106420c5, 0xaa5a640b,
+  0x7cf0d273, 0xcf3238a7, 0x3b33204f, 0x476be7bb,
+  0x09d23bca, 0xbe84b2f7, 0xb7a3bace, 0x2528cee1,
+  0x3dcaa1dd, 0x900ad31a, 0xf21dea6d, 0x9ce51463,
+  0xf1540bba, 0x0fab1bdd, 0x89cfb79a, 0x01a2a6e6,
+  0x6f85d67c, 0xd1669ec4, 0x355db722, 0x00ebd5c4,
+  0x926eb385, 0x69ead869, 0x0da2b122, 0x402779fe,
+  0xdaed92d0, 0x57e9aabb, 0x3df64854, 0xfcc774b5,
+  0x2e1740ed, 0xa615e024, 0xf7bac938, 0x377dfd1a,
+  0xd0559d66, 0x25499be8, 0x2d8f2006, 0xfaa9e486,
+  0x95e980e7, 0x82aeba67, 0x5a7f2561, 0xbc60dff6,
+  0x6c8739a2, 0x7ec59a8b, 0x9998f265, 0xdfe37e5e,
+  0xb47cee1e, 0x4dd8bc9e, 0x35c57e09, 0x07850b63,
+  0x06eadbcb, 0x6c1f2956, 0x01685c2c, 0xf5725eef,
+  0xf13b98b5, 0xaab739c2, 0x200b1da2, 0xa716b98b,
+  0xd9ee3058, 0x76acf20b, 0x2f259e04, 0xed11658b,
+  0x1532b331, 0x0ab43204, 0xf0beb023, 0xb1685483,
+  0x58cbdc4f, 0x079384d3, 0x049b141c, 0xc38184b9,
+  0xaf551d9a, 0x66222560, 0x059deeca, 0x535f99e2
+};
+
+unsigned long long rsync64(unsigned char *mem, size_t size)
+{
+    UInt32_t a = 0;
+    UInt32_t b = 0;
+    unsigned char *limit = mem + size;
+    unsigned long long result = 0;
+
+    while (mem < limit)
+    {
+        a += charTable[*mem++];
+        b += a;
+    }
+
+    a = a & 0xffffffff; // Just in case uint32 can be 64 bits
+    b = b & 0xffffffff;
+
+    result = ((unsigned long long)b << 32) | a;
+    
+    return result;
+}
+
+#define BUF_SIZE 1024
+
+#ifndef MIN
+#define MIN(x,y)        ( ((x) < (y)) ? (x) : (y))
+#endif
+
+static int rsyncsum_file(char *filename)
+{
+    FILE *file = NULL;
+    char buf[BUF_SIZE];
+    unsigned long long rsum = 0;
+    char *base64_sum = NULL;
+    int done = 0;
+    int bytes_read = 0;
+
+    /* Check if we're reading from stdin */
+    if (!strcmp("-", filename))
+        file = stdin;
+    else
+    {
+        fprintf(stderr, "\r %-75.75s", filename);
+        file = fopen(filename, "rb");
+        if (!file)
+        {
+            switch (errno)
+            {
+                case EACCES:
+                case EISDIR:
+                    break;
+                default:
+                    fprintf(stderr, "Unable to open file %s; error %d\n", filename, errno);
+                    break;
+            }
+            return errno;
+        }
+    }
+    
+    while (!done)
+    {
+        int used = 0;
+        memset(buf, 0, BUF_SIZE);
+
+        used = fread(buf, 1, BUF_SIZE, file);
+        bytes_read += used;
+        if (used)
+        {
+            rsum = rsync64(buf, BUF_SIZE);
+            done = 1;
+        }
+    }
+    
+    printf("%llx\n", rsum);
+    
+    base64_sum = base64_dump((unsigned char *)&rsum, 8);
+    if (file != stdin)
+    {
+        fclose(file);
+        if (bytes_read)
+            printf("%s  %s\n", base64_sum, filename);
+    }
+    else
+        if (bytes_read)
+            printf("%s\n", base64_sum);
+    fflush(stdout);
+    
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int i = 0;
+    
+    for (i = 1; i < argc; i++)
+        (void) rsyncsum_file(argv[i]);
+
+    return 0;
+}
+