blob: 72bc08624477b8976e7ed51ac31bc7d27cd75457 [file] [log] [blame]
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001/* md5sum.c - Compute MD5 checksum of files or strings according to the
2 * definition of MD5 in RFC 1321 from April 1992.
3 * Copyright (C) 1995-1999 Free Software Foundation, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
21/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
22
Eric Andersendb15cb72001-06-29 20:44:51 +000023/*
24 * June 29, 2001 Manuel Novoa III
25 *
26 * Added MD5SUM_SIZE_VS_SPEED configuration option.
27 *
28 * Current valid values, with data from my system for comparison, are:
29 * (using uClibc and running on linux-2.4.4.tar.bz2)
30 * user times (sec) text size (386)
31 * 0 (fastest) 1.1 6144
32 * 1 1.4 5392
33 * 2 3.0 5088
34 * 3 (smallest) 5.1 4912
35 */
36
37#define MD5SUM_SIZE_VS_SPEED 2
38
39/**********************************************************************/
40
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000041#include <stdio.h>
42#include <errno.h>
43#include <ctype.h>
Eric Andersen999bf722000-07-09 06:59:58 +000044#include <getopt.h>
Eric Andersene0c07572001-06-23 13:49:14 +000045#include <stdlib.h>
46#include <string.h>
47#include <endian.h>
48#include <sys/types.h>
49#if defined HAVE_LIMITS_H
50# include <limits.h>
51#endif
Eric Andersencbe31da2001-02-20 06:14:08 +000052#include "busybox.h"
Eric Andersen999bf722000-07-09 06:59:58 +000053
Eric Andersene111d692000-12-20 23:19:42 +000054/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
55#undef TRUE
56#undef FALSE
57#define FALSE ((int) 1)
58#define TRUE ((int) 0)
59
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000060//----------------------------------------------------------------------------
61//--------md5.c
62//----------------------------------------------------------------------------
63
64/* md5.c - Functions to compute MD5 message digest of files or memory blocks
65 * according to the definition of MD5 in RFC 1321 from April 1992.
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000066 */
67
68/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
69
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000070//----------------------------------------------------------------------------
71//--------md5.h
72//----------------------------------------------------------------------------
73
74/* md5.h - Declaration of functions and data types used for MD5 sum
Eric Andersen55522082001-07-10 16:31:29 +000075 computing library functions. */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000076
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000077typedef u_int32_t md5_uint32;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000078
79/* Structure to save state of computation between the single steps. */
80struct md5_ctx
81{
82 md5_uint32 A;
83 md5_uint32 B;
84 md5_uint32 C;
85 md5_uint32 D;
86
87 md5_uint32 total[2];
88 md5_uint32 buflen;
89 char buffer[128];
90};
91
92/*
93 * The following three functions are build up the low level used in
94 * the functions `md5_stream' and `md5_buffer'.
95 */
96
97/* Initialize structure containing state of computation.
98 (RFC 1321, 3.3: Step 3) */
Eric Andersen55522082001-07-10 16:31:29 +000099static void md5_init_ctx __P ((struct md5_ctx *ctx));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000100
101/* Starting with the result of former calls of this function (or the
102 initialization function update the context for the next LEN bytes
103 starting at BUFFER.
104 It is necessary that LEN is a multiple of 64!!! */
Eric Andersen55522082001-07-10 16:31:29 +0000105static void md5_process_block __P ((const void *buffer, size_t len,
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000106 struct md5_ctx *ctx));
107
108/* Starting with the result of former calls of this function (or the
109 initialization function update the context for the next LEN bytes
110 starting at BUFFER.
111 It is NOT required that LEN is a multiple of 64. */
Eric Andersen55522082001-07-10 16:31:29 +0000112static void md5_process_bytes __P ((const void *buffer, size_t len,
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000113 struct md5_ctx *ctx));
114
115/* Process the remaining bytes in the buffer and put result from CTX
116 in first 16 bytes following RESBUF. The result is always in little
117 endian byte order, so that a byte-wise output yields to the wanted
118 ASCII representation of the message digest.
119
120 IMPORTANT: On some systems it is required that RESBUF is correctly
121 aligned for a 32 bits value. */
Eric Andersen55522082001-07-10 16:31:29 +0000122static void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000123
124
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000125
126
127/* Compute MD5 message digest for bytes read from STREAM. The
128 resulting message digest number will be written into the 16 bytes
129 beginning at RESBLOCK. */
Eric Andersen55522082001-07-10 16:31:29 +0000130static int md5_stream __P ((FILE *stream, void *resblock));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000131
132/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
133 result is always in little endian byte order, so that a byte-wise
134 output yields to the wanted ASCII representation of the message
135 digest. */
Eric Andersen55522082001-07-10 16:31:29 +0000136static void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000137
138//----------------------------------------------------------------------------
139//--------end of md5.h
140//----------------------------------------------------------------------------
141
Eric Andersen4a2e4632001-04-14 03:33:33 +0000142/* Handle endian-ness */
143#if __BYTE_ORDER == __LITTLE_ENDIAN
144 #define SWAP(n) (n)
145#else
146 #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
147#endif
148
149
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000150
Eric Andersendb15cb72001-06-29 20:44:51 +0000151#if MD5SUM_SIZE_VS_SPEED == 0
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000152/* This array contains the bytes used to pad the buffer to the next
153 64-byte boundary. (RFC 1321, 3.1: Step 1) */
154static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
Eric Andersendb15cb72001-06-29 20:44:51 +0000155#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000156
157/* Initialize structure containing state of computation.
158 (RFC 1321, 3.3: Step 3) */
159void md5_init_ctx(struct md5_ctx *ctx)
160{
161 ctx->A = 0x67452301;
162 ctx->B = 0xefcdab89;
163 ctx->C = 0x98badcfe;
164 ctx->D = 0x10325476;
165
166 ctx->total[0] = ctx->total[1] = 0;
167 ctx->buflen = 0;
168}
169
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000170/* Process the remaining bytes in the internal buffer and the usual
171 prolog according to the standard and write the result to RESBUF.
172
173 IMPORTANT: On some systems it is required that RESBUF is correctly
174 aligned for a 32 bits value. */
Eric Andersen55522082001-07-10 16:31:29 +0000175static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000176{
177 /* Take yet unprocessed bytes into account. */
178 md5_uint32 bytes = ctx->buflen;
179 size_t pad;
180
181 /* Now count remaining bytes. */
182 ctx->total[0] += bytes;
183 if (ctx->total[0] < bytes)
184 ++ctx->total[1];
185
186 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
Eric Andersendb15cb72001-06-29 20:44:51 +0000187#if MD5SUM_SIZE_VS_SPEED > 0
188 memset(&ctx->buffer[bytes], 0, pad);
189 ctx->buffer[bytes] = 0x80;
190#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000191 memcpy(&ctx->buffer[bytes], fillbuf, pad);
Eric Andersendb15cb72001-06-29 20:44:51 +0000192#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000193
194 /* Put the 64-bit file length in *bits* at the end of the buffer. */
195 *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
196 *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
Eric Andersen5a9d4412001-05-24 14:16:28 +0000197 SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000198
199 /* Process last bytes. */
200 md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
201
Eric Andersen55522082001-07-10 16:31:29 +0000202/* Put result from CTX in first 16 bytes following RESBUF. The result is
203 always in little endian byte order, so that a byte-wise output yields
204 to the wanted ASCII representation of the message digest.
205
206 IMPORTANT: On some systems it is required that RESBUF is correctly
207 aligned for a 32 bits value. */
208 ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
209 ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
210 ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
211 ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
212
213 return resbuf;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000214}
215
216/* Compute MD5 message digest for bytes read from STREAM. The
217 resulting message digest number will be written into the 16 bytes
218 beginning at RESBLOCK. */
Eric Andersen55522082001-07-10 16:31:29 +0000219static int md5_stream(FILE *stream, void *resblock)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000220{
221 /* Important: BLOCKSIZE must be a multiple of 64. */
Mark Whitley59ab0252001-01-23 22:30:04 +0000222static const int BLOCKSIZE = 4096;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000223 struct md5_ctx ctx;
224 char buffer[BLOCKSIZE + 72];
225 size_t sum;
226
227 /* Initialize the computation context. */
228 md5_init_ctx(&ctx);
229
230 /* Iterate over full file contents. */
231 while (1) {
232 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
233 computation function processes the whole buffer so that with the
234 next round of the loop another block can be read. */
235 size_t n;
236 sum = 0;
237
238 /* Read block. Take care for partial reads. */
239 do {
240 n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
241
242 sum += n;
243 }
244 while (sum < BLOCKSIZE && n != 0);
245 if (n == 0 && ferror(stream))
246 return 1;
247
248 /* If end of file is reached, end the loop. */
249 if (n == 0)
250 break;
251
252 /* Process buffer with BLOCKSIZE bytes. Note that
253 BLOCKSIZE % 64 == 0
254 */
255 md5_process_block(buffer, BLOCKSIZE, &ctx);
256 }
257
258 /* Add the last bytes if necessary. */
259 if (sum > 0)
260 md5_process_bytes(buffer, sum, &ctx);
261
262 /* Construct result in desired memory. */
263 md5_finish_ctx(&ctx, resblock);
264 return 0;
265}
266
267/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
268 result is always in little endian byte order, so that a byte-wise
269 output yields to the wanted ASCII representation of the message
270 digest. */
Eric Andersen55522082001-07-10 16:31:29 +0000271static void *md5_buffer(const char *buffer, size_t len, void *resblock)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000272{
273 struct md5_ctx ctx;
274
275 /* Initialize the computation context. */
276 md5_init_ctx(&ctx);
277
278 /* Process whole buffer but last len % 64 bytes. */
279 md5_process_bytes(buffer, len, &ctx);
280
281 /* Put result in desired memory area. */
282 return md5_finish_ctx(&ctx, resblock);
283}
284
Eric Andersen55522082001-07-10 16:31:29 +0000285static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000286{
287 /* When we already have some bits in our internal buffer concatenate
288 both inputs first. */
289 if (ctx->buflen != 0) {
290 size_t left_over = ctx->buflen;
291 size_t add = 128 - left_over > len ? len : 128 - left_over;
292
293 memcpy(&ctx->buffer[left_over], buffer, add);
294 ctx->buflen += add;
295
296 if (left_over + add > 64) {
297 md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
298 /* The regions in the following copy operation cannot overlap. */
299 memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
300 (left_over + add) & 63);
301 ctx->buflen = (left_over + add) & 63;
302 }
303
304 buffer = (const char *) buffer + add;
305 len -= add;
306 }
307
308 /* Process available complete blocks. */
309 if (len > 64) {
310 md5_process_block(buffer, len & ~63, ctx);
311 buffer = (const char *) buffer + (len & ~63);
312 len &= 63;
313 }
314
315 /* Move remaining bytes in internal buffer. */
316 if (len > 0) {
317 memcpy(ctx->buffer, buffer, len);
318 ctx->buflen = len;
319 }
320}
321
322/* These are the four functions used in the four steps of the MD5 algorithm
323 and defined in the RFC 1321. The first function is a little bit optimized
324 (as found in Colin Plumbs public domain implementation). */
325/* #define FF(b, c, d) ((b & c) | (~b & d)) */
326#define FF(b, c, d) (d ^ (b & (c ^ d)))
327#define FG(b, c, d) FF (d, b, c)
328#define FH(b, c, d) (b ^ c ^ d)
329#define FI(b, c, d) (c ^ (b | ~d))
330
331/* Process LEN bytes of BUFFER, accumulating context into CTX.
332 It is assumed that LEN % 64 == 0. */
Eric Andersen55522082001-07-10 16:31:29 +0000333static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000334{
335 md5_uint32 correct_words[16];
336 const md5_uint32 *words = buffer;
337 size_t nwords = len / sizeof(md5_uint32);
338 const md5_uint32 *endp = words + nwords;
Eric Andersendb15cb72001-06-29 20:44:51 +0000339#if MD5SUM_SIZE_VS_SPEED > 0
340 static const md5_uint32 C_array[] = {
341 /* round 1 */
342 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
343 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
344 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
345 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
346 /* round 2 */
347 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
348 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
349 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
350 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
351 /* round 3 */
352 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
353 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
354 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
355 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
356 /* round 4 */
357 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
358 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
359 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
360 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
361 };
362
363 static const char P_array[] = {
364#if MD5SUM_SIZE_VS_SPEED > 1
365 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
366#endif
367 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
368 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
369 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
370 };
371
372#if MD5SUM_SIZE_VS_SPEED > 1
373 static const char S_array[] = {
374 7, 12, 17, 22,
375 5, 9, 14, 20,
376 4, 11, 16, 23,
377 6, 10, 15, 21
378 };
379#endif
380#endif
381
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000382 md5_uint32 A = ctx->A;
383 md5_uint32 B = ctx->B;
384 md5_uint32 C = ctx->C;
385 md5_uint32 D = ctx->D;
386
387 /* First increment the byte count. RFC 1321 specifies the possible
388 length of the file up to 2^64 bits. Here we only compute the
389 number of bytes. Do a double word increment. */
390 ctx->total[0] += len;
391 if (ctx->total[0] < len)
392 ++ctx->total[1];
393
394 /* Process all bytes in the buffer with 64 bytes in each round of
395 the loop. */
396 while (words < endp) {
397 md5_uint32 *cwp = correct_words;
398 md5_uint32 A_save = A;
399 md5_uint32 B_save = B;
400 md5_uint32 C_save = C;
401 md5_uint32 D_save = D;
402
Eric Andersendb15cb72001-06-29 20:44:51 +0000403#if MD5SUM_SIZE_VS_SPEED > 1
404#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
405
406 const md5_uint32 *pc;
407 const char *pp;
408 const char *ps;
409 int i;
410 md5_uint32 temp;
411
412 for ( i=0 ; i < 16 ; i++ ) {
413 cwp[i] = SWAP(words[i]);
414 }
415 words += 16;
416
417#if MD5SUM_SIZE_VS_SPEED > 2
418 pc = C_array; pp = P_array; ps = S_array - 4;
419
420 for ( i = 0 ; i < 64 ; i++ ) {
421 if ((i&0x0f) == 0) ps += 4;
422 temp = A;
423 switch (i>>4) {
424 case 0:
425 temp += FF(B,C,D);
426 break;
427 case 1:
428 temp += FG(B,C,D);
429 break;
430 case 2:
431 temp += FH(B,C,D);
432 break;
433 case 3:
434 temp += FI(B,C,D);
Eric Andersendb15cb72001-06-29 20:44:51 +0000435 }
436 temp += cwp[(int)(*pp++)] + *pc++;
437 temp = CYCLIC (temp, ps[i&3]);
438 temp += B;
439 A = D; D = C; C = B; B = temp;
440 }
441#else
442 pc = C_array; pp = P_array; ps = S_array;
443
444 for ( i = 0 ; i < 16 ; i++ ) {
445 temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
446 temp = CYCLIC (temp, ps[i&3]);
447 temp += B;
448 A = D; D = C; C = B; B = temp;
449 }
450
451 ps += 4;
452 for ( i = 0 ; i < 16 ; i++ ) {
453 temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
454 temp = CYCLIC (temp, ps[i&3]);
455 temp += B;
456 A = D; D = C; C = B; B = temp;
457 }
458 ps += 4;
459 for ( i = 0 ; i < 16 ; i++ ) {
460 temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
461 temp = CYCLIC (temp, ps[i&3]);
462 temp += B;
463 A = D; D = C; C = B; B = temp;
464 }
465 ps += 4;
466 for ( i = 0 ; i < 16 ; i++ ) {
467 temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
468 temp = CYCLIC (temp, ps[i&3]);
469 temp += B;
470 A = D; D = C; C = B; B = temp;
471 }
472
473#endif
474#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000475 /* First round: using the given function, the context and a constant
476 the next context is computed. Because the algorithms processing
477 unit is a 32-bit word and it is determined to work on words in
478 little endian byte order we perhaps have to change the byte order
479 before the computation. To reduce the work for the next steps
480 we store the swapped words in the array CORRECT_WORDS. */
481
482#define OP(a, b, c, d, s, T) \
483 do \
484 { \
485 a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
486 ++words; \
487 CYCLIC (a, s); \
488 a += b; \
489 } \
490 while (0)
491
492 /* It is unfortunate that C does not provide an operator for
493 cyclic rotation. Hope the C compiler is smart enough. */
Eric Andersen55522082001-07-10 16:31:29 +0000494 /* gcc 2.95.4 seems to be --aaronl */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000495#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
496
497 /* Before we start, one word to the strange constants.
498 They are defined in RFC 1321 as
499
500 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
501 */
502
Eric Andersendb15cb72001-06-29 20:44:51 +0000503#if MD5SUM_SIZE_VS_SPEED == 1
504 const md5_uint32 *pc;
505 const char *pp;
506 int i;
507#endif
508
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000509 /* Round 1. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000510#if MD5SUM_SIZE_VS_SPEED == 1
511 pc = C_array;
512 for ( i=0 ; i < 4 ; i++ ) {
513 OP(A, B, C, D, 7, *pc++);
514 OP(D, A, B, C, 12, *pc++);
515 OP(C, D, A, B, 17, *pc++);
516 OP(B, C, D, A, 22, *pc++);
517 }
518#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000519 OP(A, B, C, D, 7, 0xd76aa478);
520 OP(D, A, B, C, 12, 0xe8c7b756);
521 OP(C, D, A, B, 17, 0x242070db);
522 OP(B, C, D, A, 22, 0xc1bdceee);
523 OP(A, B, C, D, 7, 0xf57c0faf);
524 OP(D, A, B, C, 12, 0x4787c62a);
525 OP(C, D, A, B, 17, 0xa8304613);
526 OP(B, C, D, A, 22, 0xfd469501);
527 OP(A, B, C, D, 7, 0x698098d8);
528 OP(D, A, B, C, 12, 0x8b44f7af);
529 OP(C, D, A, B, 17, 0xffff5bb1);
530 OP(B, C, D, A, 22, 0x895cd7be);
531 OP(A, B, C, D, 7, 0x6b901122);
532 OP(D, A, B, C, 12, 0xfd987193);
533 OP(C, D, A, B, 17, 0xa679438e);
534 OP(B, C, D, A, 22, 0x49b40821);
Eric Andersendb15cb72001-06-29 20:44:51 +0000535#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000536
537 /* For the second to fourth round we have the possibly swapped words
538 in CORRECT_WORDS. Redefine the macro to take an additional first
539 argument specifying the function to use. */
540#undef OP
541#define OP(f, a, b, c, d, k, s, T) \
542 do \
543 { \
544 a += f (b, c, d) + correct_words[k] + T; \
545 CYCLIC (a, s); \
546 a += b; \
547 } \
548 while (0)
549
550 /* Round 2. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000551#if MD5SUM_SIZE_VS_SPEED == 1
552 pp = P_array;
553 for ( i=0 ; i < 4 ; i++ ) {
554 OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
555 OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
556 OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
557 OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
558 }
559#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000560 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
561 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
562 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
563 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
564 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
565 OP(FG, D, A, B, C, 10, 9, 0x02441453);
566 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
567 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
568 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
569 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
570 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
571 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
572 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
573 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
574 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
575 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
Eric Andersendb15cb72001-06-29 20:44:51 +0000576#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000577
578 /* Round 3. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000579#if MD5SUM_SIZE_VS_SPEED == 1
580 for ( i=0 ; i < 4 ; i++ ) {
581 OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
582 OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
583 OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
584 OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
585 }
586#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000587 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
588 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
589 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
590 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
591 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
592 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
593 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
594 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
595 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
596 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
597 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
598 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
599 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
600 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
601 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
602 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
Eric Andersendb15cb72001-06-29 20:44:51 +0000603#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000604
605 /* Round 4. */
Eric Andersendb15cb72001-06-29 20:44:51 +0000606#if MD5SUM_SIZE_VS_SPEED == 1
607 for ( i=0 ; i < 4 ; i++ ) {
608 OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
609 OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
610 OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
611 OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
612 }
613#else
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000614 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
615 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
616 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
617 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
618 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
619 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
620 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
621 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
622 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
623 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
624 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
625 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
626 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
627 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
628 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
629 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
Eric Andersendb15cb72001-06-29 20:44:51 +0000630#endif
631#endif
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000632
633 /* Add the starting values of the context. */
634 A += A_save;
635 B += B_save;
636 C += C_save;
637 D += D_save;
638 }
639
640 /* Put checksum in context given as argument. */
641 ctx->A = A;
642 ctx->B = B;
643 ctx->C = C;
644 ctx->D = D;
645}
646
647//----------------------------------------------------------------------------
648//--------end of md5.c
649//----------------------------------------------------------------------------
650
651#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
Eric Andersen55522082001-07-10 16:31:29 +0000652#define ISXDIGIT(c) (isxdigit (c))
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000653
654/* The minimum length of a valid digest line in a file produced
655 by `md5sum FILE' and read by `md5sum -c'. This length does
656 not include any newline character at the end of a line. */
Mark Whitley59ab0252001-01-23 22:30:04 +0000657static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000658 2 - blank and binary indicator
659 1 - minimum filename length */
660
661static int have_read_stdin; /* Nonzero if any of the files read were
662 the standard input. */
663
664static int status_only = 0; /* With -c, don't generate any output.
665 The exit code indicates success or failure */
666static int warn = 0; /* With -w, print a message to standard error warning
667 about each improperly formatted MD5 checksum line */
668
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000669static int split_3(char *s,
670 size_t s_len,
671 unsigned char **u,
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000672 char **w)
673{
674 size_t i = 0;
675 int escaped_filename = 0;
676
677 while (ISWHITE(s[i]))
678 ++i;
679
680 /* The line must have at least 35 (36 if the first is a backslash)
681 more characters to contain correct message digest information.
682 Ignore this line if it is too short. */
683 if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
684 || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
685 return FALSE;
686
687 if (s[i] == '\\') {
688 ++i;
689 escaped_filename = 1;
690 }
691 *u = (unsigned char *) &s[i];
692
693 /* The first field has to be the 32-character hexadecimal
694 representation of the message digest. If it is not followed
695 immediately by a white space it's an error. */
696 i += 32;
697 if (!ISWHITE(s[i]))
698 return FALSE;
699
700 s[i++] = '\0';
701
Eric Andersen55522082001-07-10 16:31:29 +0000702 if (s[i] != ' ' && s[i++] != '*')
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000703 return FALSE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000704
705 /* All characters between the type indicator and end of line are
706 significant -- that includes leading and trailing white space. */
707 *w = &s[i];
708
709 if (escaped_filename) {
710 /* Translate each `\n' string in the file name to a NEWLINE,
711 and each `\\' string to a backslash. */
712
713 char *dst = &s[i];
714
715 while (i < s_len) {
716 switch (s[i]) {
717 case '\\':
718 if (i == s_len - 1) {
719 /* A valid line does not end with a backslash. */
720 return FALSE;
721 }
722 ++i;
723 switch (s[i++]) {
724 case 'n':
725 *dst++ = '\n';
726 break;
727 case '\\':
728 *dst++ = '\\';
729 break;
730 default:
731 /* Only `\' or `n' may follow a backslash. */
732 return FALSE;
733 }
734 break;
735
736 case '\0':
737 /* The file name may not contain a NUL. */
738 return FALSE;
739 break;
740
741 default:
742 *dst++ = s[i++];
743 break;
744 }
745 }
746 *dst = '\0';
747 }
748 return TRUE;
749}
750
Eric Andersen55522082001-07-10 16:31:29 +0000751static inline int hex_digits(unsigned char const *s)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000752{
753 while (*s) {
754 if (!ISXDIGIT(*s))
755 return TRUE;
756 ++s;
757 }
758 return FALSE;
759}
760
761/* An interface to md5_stream. Operate on FILENAME (it may be "-") and
762 put the result in *MD5_RESULT. Return non-zero upon failure, zero
763 to indicate success. */
764static int md5_file(const char *filename,
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000765 unsigned char *md5_result)
766{
767 FILE *fp;
768
Eric Andersen55522082001-07-10 16:31:29 +0000769 if (filename[0] == '-' && filename[1] == '\0') {
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000770 have_read_stdin = 1;
771 fp = stdin;
772 } else {
Eric Andersen55522082001-07-10 16:31:29 +0000773 fp = fopen(filename, "r");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000774 if (fp == NULL) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000775 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000776 return FALSE;
777 }
778 }
779
780 if (md5_stream(fp, md5_result)) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000781 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000782
783 if (fp != stdin)
784 fclose(fp);
785 return FALSE;
786 }
787
788 if (fp != stdin && fclose(fp) == EOF) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000789 perror_msg("%s", filename);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000790 return FALSE;
791 }
792
793 return TRUE;
794}
795
796static int md5_check(const char *checkfile_name)
797{
798 FILE *checkfile_stream;
799 int n_properly_formated_lines = 0;
800 int n_mismatched_checksums = 0;
801 int n_open_or_read_failures = 0;
802 unsigned char md5buffer[16];
803 size_t line_number;
Eric Andersen70da6a62000-12-20 22:59:16 +0000804 char line[BUFSIZ];
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000805
Eric Andersen55522082001-07-10 16:31:29 +0000806 if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000807 have_read_stdin = 1;
808 checkfile_stream = stdin;
809 } else {
810 checkfile_stream = fopen(checkfile_name, "r");
811 if (checkfile_stream == NULL) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000812 perror_msg("%s", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000813 return FALSE;
814 }
815 }
816
817 line_number = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000818
819 do {
820 char *filename;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000821 unsigned char *md5num;
822 int line_length;
823
824 ++line_number;
825
Eric Andersen70da6a62000-12-20 22:59:16 +0000826 fgets(line, BUFSIZ-1, checkfile_stream);
827 line_length = strlen(line);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000828
Eric Andersene111d692000-12-20 23:19:42 +0000829 if (line_length <= 0 || line==NULL)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000830 break;
831
832 /* Ignore comment lines, which begin with a '#' character. */
833 if (line[0] == '#')
834 continue;
835
836 /* Remove any trailing newline. */
837 if (line[line_length - 1] == '\n')
838 line[--line_length] = '\0';
839
Eric Andersen55522082001-07-10 16:31:29 +0000840 if (split_3(line, line_length, &md5num, &filename)
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000841 || !hex_digits(md5num)) {
842 if (warn) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000843 error_msg("%s: %lu: improperly formatted MD5 checksum line",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000844 checkfile_name, (unsigned long) line_number);
845 }
846 } else {
847 static const char bin2hex[] = {
848 '0', '1', '2', '3',
849 '4', '5', '6', '7',
850 '8', '9', 'a', 'b',
851 'c', 'd', 'e', 'f'
852 };
853
854 ++n_properly_formated_lines;
855
Eric Andersen55522082001-07-10 16:31:29 +0000856 if (md5_file(filename, md5buffer)) {
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000857 ++n_open_or_read_failures;
858 if (!status_only) {
859 printf("%s: FAILED open or read\n", filename);
860 fflush(stdout);
861 }
862 } else {
863 size_t cnt;
864 /* Compare generated binary number with text representation
865 in check file. Ignore case of hex digits. */
866 for (cnt = 0; cnt < 16; ++cnt) {
Eric Andersen55522082001-07-10 16:31:29 +0000867 if (tolower(md5num[2 * cnt])
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000868 != bin2hex[md5buffer[cnt] >> 4]
Eric Andersen55522082001-07-10 16:31:29 +0000869 || (tolower(md5num[2 * cnt + 1])
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000870 != (bin2hex[md5buffer[cnt] & 0xf])))
871 break;
872 }
873 if (cnt != 16)
874 ++n_mismatched_checksums;
875
876 if (!status_only) {
877 printf("%s: %s\n", filename,
878 (cnt != 16 ? "FAILED" : "OK"));
879 fflush(stdout);
880 }
881 }
882 }
883 }
884
885 while (!feof(checkfile_stream) && !ferror(checkfile_stream));
886
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000887 if (ferror(checkfile_stream)) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000888 error_msg("%s: read error", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000889 return FALSE;
890 }
891
892 if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000893 perror_msg("md5sum: %s", checkfile_name);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000894 return FALSE;
895 }
896
897 if (n_properly_formated_lines == 0) {
898 /* Warn if no tests are found. */
Matt Kraaidd19c692001-01-31 19:00:21 +0000899 error_msg("%s: no properly formatted MD5 checksum lines found",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000900 checkfile_name);
901 return FALSE;
902 } else {
903 if (!status_only) {
904 int n_computed_checkums = (n_properly_formated_lines
905 - n_open_or_read_failures);
906
907 if (n_open_or_read_failures > 0) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000908 error_msg("WARNING: %d of %d listed files could not be read",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000909 n_open_or_read_failures, n_properly_formated_lines);
910 return FALSE;
911 }
912
913 if (n_mismatched_checksums > 0) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000914 error_msg("WARNING: %d of %d computed checksums did NOT match",
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000915 n_mismatched_checksums, n_computed_checkums);
916 return FALSE;
917 }
918 }
919 }
920
921 return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
922 && n_open_or_read_failures == 0) ? 0 : 1);
923}
924
925int md5sum_main(int argc,
926 char **argv)
927{
928 unsigned char md5buffer[16];
929 int do_check = 0;
930 int opt;
931 char **string = NULL;
932 size_t n_strings = 0;
933 size_t err = 0;
Eric Andersen55522082001-07-10 16:31:29 +0000934 char file_type_specified = 0;
935 char binary = 0;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000936
937 while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
938 switch (opt) {
939 case 'g': { /* read a string */
940 if (string == NULL)
941 string = (char **) xmalloc ((argc - 1) * sizeof (char *));
942
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000943 string[n_strings++] = optarg;
944 break;
945 }
946
947 case 'b': /* read files in binary mode */
948 file_type_specified = 1;
949 binary = 1;
950 break;
951
952 case 'c': /* check MD5 sums against given list */
953 do_check = 1;
954 break;
955
956 case 's': /* don't output anything, status code shows success */
957 status_only = 1;
958 warn = 0;
959 break;
960
961 case 't': /* read files in text mode (default) */
962 file_type_specified = 1;
963 binary = 0;
964 break;
965
966 case 'w': /* warn about improperly formated MD5 checksum lines */
967 status_only = 0;
968 warn = 1;
969 break;
970
971 default:
Eric Andersen67991cf2001-02-14 21:23:06 +0000972 show_usage();
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000973 }
974 }
975
976 if (file_type_specified && do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000977 error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000978 }
979
980 if (n_strings > 0 && do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000981 error_msg_and_die("the -g and -c options are mutually exclusive");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000982 }
983
984 if (status_only && !do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000985 error_msg_and_die("the -s option is meaningful only when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000986 }
987
988 if (warn && !do_check) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000989 error_msg_and_die("the -w option is meaningful only when verifying checksums");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000990 }
991
992 if (n_strings > 0) {
993 size_t i;
994
995 if (optind < argc) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000996 error_msg_and_die("no files may be specified when using -g");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000997 }
998 for (i = 0; i < n_strings; ++i) {
999 size_t cnt;
1000 md5_buffer (string[i], strlen (string[i]), md5buffer);
1001
1002 for (cnt = 0; cnt < 16; ++cnt)
1003 printf ("%02x", md5buffer[cnt]);
1004
1005 printf (" \"%s\"\n", string[i]);
1006 }
1007 } else if (do_check) {
1008 if (optind + 1 < argc) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001009 error_msg("only one argument may be specified when using -c");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001010 }
1011
1012 err = md5_check ((optind == argc) ? "-" : argv[optind]);
1013 } else {
1014 if (optind == argc)
1015 argv[argc++] = "-";
1016
1017 for (; optind < argc; ++optind) {
1018 int fail;
1019 char *file = argv[optind];
1020
Eric Andersen55522082001-07-10 16:31:29 +00001021 fail = md5_file (file, md5buffer);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001022 err |= fail;
Eric Andersen55522082001-07-10 16:31:29 +00001023 if (!fail && file[0]=='-' && file[1] == '\0') {
Eric Andersen7aa1f5c2001-02-22 04:59:16 +00001024 size_t i;
1025 for (i = 0; i < 16; ++i)
1026 printf ("%02x", md5buffer[i]);
1027 putchar ('\n');
1028 } else if (!fail) {
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001029 size_t i;
1030 /* Output a leading backslash if the file name contains
1031 a newline or backslash. */
1032 if (strchr (file, '\n') || strchr (file, '\\'))
1033 putchar ('\\');
1034
1035 for (i = 0; i < 16; ++i)
1036 printf ("%02x", md5buffer[i]);
1037
1038 putchar (' ');
1039 if (binary)
1040 putchar ('*');
1041 else
1042 putchar (' ');
1043
1044 /* Translate each NEWLINE byte to the string, "\\n",
1045 and each backslash to "\\\\". */
1046 for (i = 0; i < strlen (file); ++i) {
1047 switch (file[i]) {
1048 case '\n':
1049 fputs ("\\n", stdout);
1050 break;
1051
1052 case '\\':
1053 fputs ("\\\\", stdout);
1054 break;
1055
1056 default:
1057 putchar (file[i]);
1058 break;
1059 }
1060 }
1061 putchar ('\n');
1062 }
1063 }
1064 }
1065
1066 if (fclose (stdout) == EOF) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001067 error_msg_and_die("write error");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001068 }
1069
1070 if (have_read_stdin && fclose (stdin) == EOF) {
Matt Kraaidd19c692001-01-31 19:00:21 +00001071 error_msg_and_die("standard input");
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001072 }
1073
Matt Kraai3e856ce2000-12-01 02:55:13 +00001074 if (err == 0)
1075 return EXIT_SUCCESS;
1076 else
1077 return EXIT_FAILURE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001078}