2 * md5drvr - md5 driver code
4 * @(#) $Revision: 13.1 $
5 * @(#) $Id: md5io.c,v 13.1 2006/08/14 03:16:33 chongo Exp $
6 * @(#) $Source: /usr/local/src/cmd/hash/RCS/md5io.c,v $
8 * This file was written by Landon Curt Noll.
10 * This code has been placed in the public domain. Please do not
11 * copyright this code.
13 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO
14 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MER-
15 * CHANTABILITY AND FITNESS. IN NO EVENT SHALL LANDON CURT
16 * NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
19 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * chongo (was here) /\oo/\
23 * http://www.isthe.com/chongo/index.html
25 * Share and enjoy! :-)
27 * See md5drvr.c for version and modification history.
33 #include <sys/types.h>
36 #include <sys/resource.h>
40 /* global variables */
41 ULONG md5_zero
[MD5_MAXBLOCK
/sizeof(ULONG
)]; /* block of zeros */
45 * MD5Stream - digest a open file stream
48 MD5Stream(pre_str
, pre_len
, stream
, dig
)
49 BYTE
*pre_str
; /* data prefix or NULL */
50 UINT pre_len
; /* length of pre_str */
51 FILE *stream
; /* the stream to process */
52 MD5_CTX
*dig
; /* current digest */
54 ULONG data
[MD5_READWORDS
]; /* our read buffer */
55 int bytes
; /* bytes last read */
56 int ret
; /* partial fread return value */
59 * pre-process prefix if needed
61 if (pre_str
!= NULL
) {
62 MD5Update(dig
, pre_str
, pre_len
);
63 MD5COUNT(dig
, pre_len
);
67 * if we have a partial chunk, try to read until we have a full chunk
70 if (dig
->datalen
> 0) {
72 /* determine what we have so far */
75 /* try to read what we need to fill the chunk */
76 while (bytes
< MD5_CHUNKSIZE
) {
78 /* try to read what we need */
79 ret
= fread((char*)data
+bytes
, 1, MD5_CHUNKSIZE
-bytes
, stream
);
81 /* carefully examine the result */
82 if (ret
< 0 || ferror(stream
)) {
83 /* error processing */
84 fprintf(stderr
, "%s: ", program
);
85 perror("read #3 error");
87 } else if (ret
== 0 || feof(stream
)) {
89 MD5COUNT(dig
, MD5_CHUNKSIZE
-dig
->datalen
);
90 MD5Update(dig
, (BYTE
*)data
+dig
->datalen
,
91 MD5_CHUNKSIZE
-dig
->datalen
);
95 /* note that we have more bytes */
98 MD5COUNT(dig
, MD5_CHUNKSIZE
-dig
->datalen
);
99 MD5Update(dig
, (BYTE
*)data
+dig
->datalen
, MD5_CHUNKSIZE
-dig
->datalen
);
103 * process the contents of the file
105 while ((bytes
= fread((char *)data
, 1, MD5_READSIZE
, stream
)) > 0) {
108 * if we got a partial read, try to read up to a full chunk
110 while (bytes
< MD5_READSIZE
) {
112 /* try to read more */
113 ret
= fread((char *)data
+bytes
, 1, MD5_READSIZE
-bytes
, stream
);
115 /* carefully examine the result */
116 if (ret
< 0 || ferror(stream
)) {
117 /* error processing */
118 fprintf(stderr
, "%s: ", program
);
119 perror("read #1 error");
121 } else if (ret
== 0 || feof(stream
)) {
123 MD5Update(dig
, (BYTE
*)data
, bytes
);
124 MD5COUNT(dig
, bytes
);
128 /* note that we have more bytes */
135 MD5fullUpdate(dig
, (BYTE
*)data
, bytes
);
136 MD5COUNT(dig
, bytes
);
142 if (bytes
< 0 || ferror(stream
)) {
143 /* error processing */
144 fprintf(stderr
, "%s: ", program
);
145 perror("read #2 error");
153 * MD5File - digest a file
156 MD5File(pre_str
, pre_len
, filename
, inode
, dig
)
157 BYTE
*pre_str
; /* string prefix or NULL */
158 UINT pre_len
; /* length of pre_str */
159 char *filename
; /* the filename to process */
160 int inode
; /* 1 => process inode & filename */
161 MD5_CTX
*dig
; /* current digest */
163 FILE *inFile
; /* the open file stream */
164 struct stat buf
; /* stat or lstat of file */
165 struct md5_stat hashbuf
; /* stat data to digest */
166 struct md5_stat hashlbuf
; /* lstat data to digest */
167 ULONG filename_len
; /* length of the filename */
172 inFile
= fopen(filename
, "rb");
173 if (inFile
== NULL
) {
174 fprintf(stderr
, "%s: cannot open %s: ", program
, filename
);
180 * pre-process prefix if needed
182 if (pre_str
== NULL
) {
184 filename_len
= strlen(filename
);
185 MD5Update(dig
, (BYTE
*)filename
, filename_len
);
186 MD5COUNT(dig
, filename_len
);
190 MD5Update(dig
, pre_str
, pre_len
);
191 filename_len
= strlen(filename
);
192 MD5Update(dig
, (BYTE
*)filename
, filename_len
);
193 MD5COUNT(dig
, pre_len
+ filename_len
);
195 MD5Update(dig
, pre_str
, pre_len
);
196 MD5COUNT(dig
, pre_len
);
201 * digest file stat and lstat
204 if (fstat(fileno(inFile
), &buf
) < 0) {
205 printf("%s can't be stated.\n", filename
);
208 hashbuf
.stat_dev
= buf
.st_dev
;
209 hashbuf
.stat_ino
= buf
.st_ino
;
210 hashbuf
.stat_mode
= buf
.st_mode
;
211 hashbuf
.stat_nlink
= buf
.st_nlink
;
212 hashbuf
.stat_uid
= buf
.st_uid
;
213 hashbuf
.stat_gid
= buf
.st_gid
;
214 hashbuf
.stat_size
= buf
.st_size
;
215 hashbuf
.stat_mtime
= buf
.st_mtime
;
216 hashbuf
.stat_ctime
= buf
.st_ctime
;
217 MD5Update(dig
, (BYTE
*)&hashbuf
, sizeof(hashbuf
));
218 if (lstat(filename
, &buf
) < 0) {
219 printf("%s can't be lstated.\n", filename
);
222 hashlbuf
.stat_dev
= buf
.st_dev
;
223 hashlbuf
.stat_ino
= buf
.st_ino
;
224 hashlbuf
.stat_mode
= buf
.st_mode
;
225 hashlbuf
.stat_nlink
= buf
.st_nlink
;
226 hashlbuf
.stat_uid
= buf
.st_uid
;
227 hashlbuf
.stat_gid
= buf
.st_gid
;
228 hashlbuf
.stat_size
= buf
.st_size
;
229 hashlbuf
.stat_mtime
= buf
.st_mtime
;
230 hashlbuf
.stat_ctime
= buf
.st_ctime
;
231 MD5Update(dig
, (BYTE
*)&hashlbuf
, sizeof(hashlbuf
));
234 * pad with zeros to process file data faster
236 if (dig
->datalen
> 0) {
237 MD5COUNT(dig
, sizeof(hashbuf
) + sizeof(hashlbuf
) +
238 MD5_CHUNKSIZE
- dig
->datalen
);
239 MD5Update(dig
, (BYTE
*)md5_zero
, MD5_CHUNKSIZE
- dig
->datalen
);
241 MD5COUNT(dig
, sizeof(hashbuf
) + sizeof(hashlbuf
));
246 * process the data stream
248 MD5Stream(NULL
, 0, inFile
, dig
);