From ee63f15526002a5d173608e2011c62da04fe9b86 Mon Sep 17 00:00:00 2001 From: dockes Date: Fri, 9 Jan 2009 12:23:10 +0000 Subject: [PATCH] implement md5 convenience file and string wrappers. Modify readfile to support this --- src/utils/Makefile | 10 +++- src/utils/md5.cpp | 128 ++++++++++++++++++++++++++++++++++++++++- src/utils/md5.h | 18 ++++-- src/utils/readfile.cpp | 62 +++++++++++++------- src/utils/readfile.h | 13 ++++- 5 files changed, 200 insertions(+), 31 deletions(-) diff --git a/src/utils/Makefile b/src/utils/Makefile index 576f41c1..d063607a 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -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) diff --git a/src/utils/md5.cpp b/src/utils/md5.cpp index d10bbcf2..a2815f92 100644 --- a/src/utils/md5.cpp +++ b/src/utils/md5.cpp @@ -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 #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 + +#include +#include +#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 diff --git a/src/utils/md5.h b/src/utils/md5.h index 7146da80..ecbc85ff 100644 --- a/src/utils/md5.h +++ b/src/utils/md5.h @@ -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 +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_ */ diff --git a/src/utils/readfile.cpp b/src/utils/readfile.cpp index 17c92c06..92f5732d 100644 --- a/src/utils/readfile.cpp +++ b/src/utils/readfile.cpp @@ -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; diff --git a/src/utils/readfile.h b/src/utils/readfile.h index 88dc2c2c..ca067db7 100644 --- a/src/utils/readfile.h +++ b/src/utils/readfile.h @@ -19,12 +19,21 @@ /* @(#$Id: readfile.h,v 1.3 2007-06-02 08:30:42 dockes Exp $ (C) 2004 J.F.Dockes */ #include +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_ */