/**
@file mjrCSUM.c
@author Mitch Richling <http://www.mitchr.me/>
@Copyright Copyright 1995,1998,2005 by Mitch Richling. All rights reserved.
@brief Compute custom "checksum" for files.@EOL
@Keywords md5 sha1 checksum
@Std C99
This little C program is intended to read a single file
given on the command line and produce single line of output
that can be used to later check the file's content via
check-sums. The intended application is incremental backup,
backup integrity, and backup cataloging.
The output (v1) is:
TIME MD5 SHA1 NUM_BIN_CHARS NUM_LINES NUM_CHARS FILE_NAME
The output (v2) is:
TIME ATIME CTIME MTIME MD5 SHA1 NUM_BIN_CHARS NUM_LINES NUM_CHARS FILE_NAME
Parse note:
v1 may be diffienterated from v2 by noteing that the MD5
value is prefixed with "MD5:". Thus, v1 has one integer
before the MD5, and v2 has four.
Compile on linux with something like this:
gcc -Wall -O5 mjrCSUM.c -lcrypto -o mjrCSUM
*/
#include <ctype.h>
#include <errno.h> /* error stf POSIX */
#include <fcntl.h> /* UNIX file ctrl UNIX */
#include <openssl/ssl.h>
#include <stdio.h> /* I/O lib ISOC */
#include <stdlib.h> /* Standard Lib ISOC */
#include <sys/stat.h> /* UNIX stat POSIX */
#include <time.h>
#include <unistd.h> /* UNIX std stf POSIX */
int main(int argc, char *argv[]);
#define READ_SIZE 1024*128
/* Version of the output to deliver. */
#define OUTPUT_VERSION 2
int main(int argc, char *argv[]) {
int FD;
char fileBuf[READ_SIZE+10];
int returnValue;
unsigned long numLines = 0;
unsigned long numChars = 0;
unsigned long numBinChars = 0;
EVP_MD_CTX md5ctx, sha1ctx;
unsigned char md5val[EVP_MAX_MD_SIZE], sha1val[EVP_MAX_MD_SIZE];
unsigned int md5len, i, sha1len;
struct stat s;
/* Make sure we got an argument */
if(argc < 2) {
fprintf(stderr, "ERROR: One argument required (a file name)\n");
exit(1);
}
/* Stat the file. */
if(lstat(argv[1], &s) < 0) {
printf("ERROR: Could not stat file: '%s'\n", argv[1]);
exit(2);
} /* end if */
if(s.st_mode & S_IFREG) {
/* Open our file... */
if((FD = open(argv[1], O_RDONLY)) < 0) {
perror("ERROR: File open");
exit(10);
} /* end if */
/* Intialize the hash objects. */
EVP_DigestInit(&md5ctx, EVP_md5());
EVP_DigestInit(&sha1ctx, EVP_sha1());
/* Read the file and feed data to the counters and hash functions. */
while((returnValue = read(FD, fileBuf, READ_SIZE)) > 0) {
for(i=0; i<returnValue; i++) {
// Check for Binary chars
if( !(isprint(fileBuf[i]) || isspace(fileBuf[i])) )
numBinChars++;
// Add up chars
numChars++;
// Check for NL
if(fileBuf[i] == 10)
numLines++;
}
EVP_DigestUpdate(&md5ctx, fileBuf, returnValue);
EVP_DigestUpdate(&sha1ctx, fileBuf, returnValue);
} /* end while */
/* Make sure we exited well. */
if(returnValue < 0) {
perror("ERROR: File read");
exit(11);
} /* end if */
/* We are done with the file, so we close it now. */
if(close(FD) < 0) {
perror("ERROR: File close");
exit(13);
} /* end if */
/* Finish up the hash function computation. */
EVP_DigestFinal(&md5ctx, md5val, &md5len);
EVP_DigestFinal(&sha1ctx, sha1val, &sha1len);
/* Print out the results */
printf("%lu ", (unsigned long)time(NULL));
if(OUTPUT_VERSION >= 2) {
printf("%lu ", (unsigned long)s.st_atime);
printf("%lu ", (unsigned long)s.st_ctime);
printf("%lu ", (unsigned long)s.st_mtime);
}
printf("MD5:");
for(i=0; i<md5len; i++)
printf("%02x", md5val[i]);
printf(" SHA1:");
for(i=0; i<sha1len; i++)
printf("%02x", sha1val[i]);
printf(" %lu %lu %lu %s\n", numBinChars, numLines, numChars, argv[1]);
}
return 0;
}
Generated by GNU Enscript 1.6.5.2.