implement md5 convenience file and string wrappers. Modify readfile to support this

This commit is contained in:
dockes 2009-01-09 12:23:10 +00:00
parent b6f3c99c1a
commit ee63f15526
5 changed files with 200 additions and 31 deletions

View File

@ -1,7 +1,8 @@
depth = ..
include $(depth)/mk/sysconf
PROGS = trreadfile trfileudi trconftree wipedir smallut trfstreewalk trpathut \
PROGS = trmd5 trreadfile trfileudi trconftree wipedir smallut \
trfstreewalk trpathut \
transcode trbase64 \
trmimeparse trexecmd utf8iter idfile
@ -25,6 +26,13 @@ trreadfile.o : readfile.cpp readfile.h
$(CXX) -o trreadfile.o -c $(ALL_CXXFLAGS) \
-DTEST_READFILE readfile.cpp
MD5_OBJS= trmd5.o md5.o $(BIGLIB)
trmd5 : $(MD5_OBJS)
$(CXX) -o trmd5 $(MD5_OBJS) $(LIBICONV) $(LIBSYS)
trmd5.o : md5.cpp md5.h
$(CXX) -o trmd5.o -c $(ALL_CXXFLAGS) \
-DTEST_MD5 md5.cpp
PATHUT_OBJS= trpathut.o $(BIGLIB)
trpathut : $(PATHUT_OBJS)
$(CXX) $(ALL_CXXFLAGS) -o trpathut $(PATHUT_OBJS) $(LIBICONV)

View File

@ -27,7 +27,7 @@
* This code is the same as the code published by RSA Inc. It has been
* edited for clarity and style only.
*/
#ifndef TEST_MD5
#include <string.h>
#include "md5.h"
@ -316,3 +316,129 @@ MD5Transform (md5uint32 state[4], const unsigned char block[64])
/* Zeroize sensitive information. */
memset ((void *)x, 0, sizeof (x));
}
/*************** Convenience / utilities */
void MD5Final(string &digest, MD5_CTX *context)
{
unsigned char d[16];
MD5Final (d, context);
digest.assign((const char *)d, 16);
}
string& MD5String(const string& data, string& digest)
{
MD5_CTX ctx;
MD5Init(&ctx);
MD5Update(&ctx, (const unsigned char*)data.c_str(), data.length());
MD5Final(digest, &ctx);
return digest;
}
string& MD5HexPrint(const string& digest, string &out)
{
out.erase();
out.reserve(33);
static const char hex[]="0123456789abcdef";
const unsigned char *hash = (const unsigned char *)digest.c_str();
for (int i = 0; i < 16; i++) {
out.append(1, hex[hash[i] >> 4]);
out.append(1, hex[hash[i] & 0x0f]);
}
return out;
}
string& MD5HexScan(const string& xdigest, string& digest)
{
digest.erase();
if (xdigest.length() != 32) {
return digest;
}
for (unsigned int i = 0; i < 16; i++) {
unsigned int val;
if (sscanf(xdigest.c_str() + 2*i, "%2x", &val) != 1) {
digest.erase();
return digest;
}
digest.append(1, (unsigned char)val);
}
return digest;
}
#include "readfile.h"
class FileScanMd5 : public FileScanDo {
public:
FileScanMd5(string& d) : digest(d) {}
virtual bool init(unsigned int size, string *reason)
{
MD5Init(&ctx);
return true;
}
virtual bool data(const char *buf, int cnt, string* reason)
{
MD5Update(&ctx, (const unsigned char*)buf, cnt);
return true;
}
string &digest;
MD5_CTX ctx;
};
bool MD5File(const string& filename, string &digest, string *reason)
{
FileScanMd5 md5er(digest);
if (!file_scan(filename, &md5er, reason))
return false;
// We happen to know that digest and md5er.digest are the same object
MD5Final(md5er.digest, &md5er.ctx);
return true;
}
#else
// Test driver
#include <stdlib.h>
#include <string>
#include <iostream>
#include "md5.h"
using namespace std;
static const char *thisprog;
static char usage [] =
"trmd5 filename\n\n"
;
static void
Usage(void)
{
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
exit(1);
}
int main(int argc, const char **argv)
{
thisprog = argv[0];
argc--; argv++;
if (argc != 1)
Usage();
string filename = *argv++;argc--;
string reason, digest;
if (!MD5File(filename, digest, &reason)) {
cerr << reason << endl;
exit(1);
} else {
string hex;
cout << "MD5 (" << filename << ") = " << MD5HexPrint(digest, hex) << endl;
string digest1;
MD5HexScan(hex, digest1);
if (digest1.compare(digest)) {
cout << "MD5HexScan Failure" << endl;
cout << MD5HexPrint(digest, hex) << " " << digest.length() << " -> "
<< MD5HexPrint(digest1, hex) << " " << digest1.length() << endl;
exit(1);
}
}
exit(0);
}
#endif

View File

@ -26,8 +26,7 @@ These notices must be retained in any copies of any part of this
documentation and/or software.
*/
extern "C" {
/* Base functions from original file */
/* MD5 context. */
typedef struct MD5Context {
unsigned int state[4]; /* state (ABCD) */
@ -35,9 +34,16 @@ typedef struct MD5Context {
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init (MD5_CTX *);
void MD5Update (MD5_CTX *, const unsigned char *, unsigned int);
void MD5Final (unsigned char [16], MD5_CTX *);
}
extern void MD5Init (MD5_CTX *);
extern void MD5Update (MD5_CTX *, const unsigned char *, unsigned int);
extern void MD5Final (unsigned char [16], MD5_CTX *);
/* Convenience / utilities */
#include <string>
using std::string;
extern void MD5Final(string& digest, MD5_CTX *);
extern bool MD5File(const string& filename, string& digest, string *reason);
extern string& MD5String(const string& data, string& digest);
extern string& MD5HexPrint(const string& digest, string& xdigest);
extern string& MD5HexScan(const string& xdigest, string& digest);
#endif /* _MD5_H_ */

View File

@ -40,27 +40,53 @@ using std::string;
static void caterrno(string *reason, const char *what)
{
#define ERRBUFSZ 200
char errbuf[ERRBUFSZ];
if (reason) {
*reason += "file_to_string: ";
*reason += what;
*reason += ": ";
reason->append("file_to_string: ");
reason->append(what);
reason->append(": ");
#ifdef sun
// Note: sun strerror is noted mt-safe ??
*reason += strerror(errno);
reason->append(strerror(errno));
#else
#define ERRBUFSZ 200
char errbuf[ERRBUFSZ];
strerror_r(errno, errbuf, ERRBUFSZ);
*reason += errbuf;
reason->append(errbuf);
#endif
}
}
// Note: the fstat() + reserve() calls divide cpu usage almost by 2
class FileToString : public FileScanDo {
public:
FileToString(string& data) : m_data(data) {}
string& m_data;
bool init(unsigned int size, string *reason) {
if (size > 0)
m_data.reserve(size);
return true;
}
bool data(const char *buf, int cnt, string *reason) {
try {
m_data.append(buf, cnt);
} catch (...) {
caterrno(reason, "append");
return false;
}
return true;
}
};
bool file_to_string(const string &fn, string &data, string *reason)
{
FileToString accum(data);
return file_scan(fn, &accum, reason);
}
// Note: the fstat() + reserve() (in init()) calls divide cpu usage almost by 2
// on both linux i586 and macosx (compared to just append())
// Also tried a version with mmap, but it's actually slower on the mac and not
// faster on linux.
bool file_to_string(const string &fn, string &data, string *reason)
bool file_scan(const string &fn, FileScanDo* doer, string *reason)
{
bool ret = false;
bool noclosing = true;
@ -72,19 +98,16 @@ bool file_to_string(const string &fn, string &data, string *reason)
// If we have a file name, open it, else use stdin.
if (!fn.empty()) {
fd = open(fn.c_str(), O_RDONLY|O_STREAMING);
if (fd < 0
#if 1
|| fstat(fd, &st) < 0
#endif
) {
if (fd < 0 || fstat(fd, &st) < 0) {
caterrno(reason, "open/stat");
return false;
}
noclosing = false;
}
if (st.st_size > 0)
data.reserve(st.st_size+1);
doer->init(st.st_size+1, reason);
else
doer->init(0, reason);
char buf[4096];
for (;;) {
int n = read(fd, buf, 4096);
@ -95,10 +118,7 @@ bool file_to_string(const string &fn, string &data, string *reason)
if (n == 0)
break;
try {
data.append(buf, n);
} catch (...) {
caterrno(reason, "append");
if (!doer->data(buf, n, reason)) {
goto out;
}
}
@ -206,7 +226,7 @@ int main(int argc, const char **argv)
} else if (S_ISREG(st.st_mode)) {
string s, reason;
if (!file_to_string(top, s, &reason)) {
cerr << reason;
cerr << reason << endl;
exit(1);
} else {
cout << s;

View File

@ -19,12 +19,21 @@
/* @(#$Id: readfile.h,v 1.3 2007-06-02 08:30:42 dockes Exp $ (C) 2004 J.F.Dockes */
#include <string>
using std::string;
/**
* Read whole file into string.
* @return true for ok, false else
*/
bool file_to_string(const std::string &filename, std::string &data,
std::string *reason = 0);
bool file_to_string(const string &filename, string &data, string *reason = 0);
class FileScanDo {
public:
virtual ~FileScanDo() {}
virtual bool init(unsigned int size, string *reason) = 0;
virtual bool data(const char *buf, int cnt, string* reason) = 0;
};
bool file_scan(const std::string &filename, FileScanDo* doer,
std::string *reason = 0);
#endif /* _READFILE_H_INCLUDED_ */