diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-06-13 06:54:53 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-06-13 06:54:53 +0000 |
commit | 2b6ab3cbf8c486fd2faa2bec60e7b1d4ed807af1 (patch) | |
tree | d0e98c79dff9374fc3e4229bbf3c4e43164184a0 | |
parent | 053b1462b72feea51b3b8745662447d5f8d18fda (diff) | |
download | busybox-w32-2b6ab3cbf8c486fd2faa2bec60e7b1d4ed807af1.tar.gz busybox-w32-2b6ab3cbf8c486fd2faa2bec60e7b1d4ed807af1.tar.bz2 busybox-w32-2b6ab3cbf8c486fd2faa2bec60e7b1d4ed807af1.zip |
Add new apps md5sum uudecode uuencode, fix some minor formatting things.
-Erik
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | applets/busybox.c | 9 | ||||
-rw-r--r-- | busybox.c | 9 | ||||
-rw-r--r-- | busybox.def.h | 3 | ||||
-rw-r--r-- | chmod_chown_chgrp.c | 3 | ||||
-rw-r--r-- | coreutils/df.c | 1 | ||||
-rw-r--r-- | coreutils/md5sum.c | 1013 | ||||
-rw-r--r-- | coreutils/uudecode.c | 350 | ||||
-rw-r--r-- | coreutils/uuencode.c | 244 | ||||
-rw-r--r-- | df.c | 1 | ||||
-rw-r--r-- | docs/busybox.pod | 81 | ||||
-rw-r--r-- | internal.h | 3 | ||||
-rw-r--r-- | md5sum.c | 1013 | ||||
-rw-r--r-- | uudecode.c | 350 | ||||
-rw-r--r-- | uuencode.c | 244 |
16 files changed, 3318 insertions, 10 deletions
@@ -12,6 +12,8 @@ | |||
12 | Glenn McGrath <bug1@netconnect.com.au> | 12 | Glenn McGrath <bug1@netconnect.com.au> |
13 | * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org> | 13 | * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org> |
14 | * Added setkeycodes, for those that have wierd keyboard buttons. | 14 | * Added setkeycodes, for those that have wierd keyboard buttons. |
15 | * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt | ||
16 | <ams@trillian.itslinux.org> for contributing these. | ||
15 | * Added 'grep -v' option (inverted search) and updated | 17 | * Added 'grep -v' option (inverted search) and updated |
16 | docs accordingly. -beppu | 18 | docs accordingly. -beppu |
17 | * Wrote which | 19 | * Wrote which |
@@ -26,7 +26,7 @@ export VERSION | |||
26 | # Set the following to `true' to make a debuggable build. | 26 | # Set the following to `true' to make a debuggable build. |
27 | # Leave this set to `false' for production use. | 27 | # Leave this set to `false' for production use. |
28 | # eg: `make DODEBUG=true tests' | 28 | # eg: `make DODEBUG=true tests' |
29 | DODEBUG = false | 29 | DODEBUG = true |
30 | 30 | ||
31 | # If you want a static binary, turn this on. | 31 | # If you want a static binary, turn this on. |
32 | DOSTATIC = false | 32 | DOSTATIC = false |
diff --git a/applets/busybox.c b/applets/busybox.c index 9ee5d2e3a..be9aa3e83 100644 --- a/applets/busybox.c +++ b/applets/busybox.c | |||
@@ -189,6 +189,9 @@ const struct BB_applet applets[] = { | |||
189 | #ifdef BB_MATH | 189 | #ifdef BB_MATH |
190 | {"math", math_main, _BB_DIR_USR_BIN}, | 190 | {"math", math_main, _BB_DIR_USR_BIN}, |
191 | #endif | 191 | #endif |
192 | #ifdef BB_MD5SUM | ||
193 | {"md5sum", md5sum_main, _BB_DIR_USR_BIN}, | ||
194 | #endif | ||
192 | #ifdef BB_MKDIR | 195 | #ifdef BB_MKDIR |
193 | {"mkdir", mkdir_main, _BB_DIR_BIN}, | 196 | {"mkdir", mkdir_main, _BB_DIR_BIN}, |
194 | #endif | 197 | #endif |
@@ -324,6 +327,12 @@ const struct BB_applet applets[] = { | |||
324 | #ifdef BB_UPTIME | 327 | #ifdef BB_UPTIME |
325 | {"uptime", uptime_main, _BB_DIR_USR_BIN}, | 328 | {"uptime", uptime_main, _BB_DIR_USR_BIN}, |
326 | #endif | 329 | #endif |
330 | #ifdef BB_UUENCODE | ||
331 | {"uuencode", uuencode_main, _BB_DIR_USR_BIN}, | ||
332 | #endif | ||
333 | #ifdef BB_UUDECODE | ||
334 | {"uudecode", uudecode_main, _BB_DIR_USR_BIN}, | ||
335 | #endif | ||
327 | #ifdef BB_USLEEP | 336 | #ifdef BB_USLEEP |
328 | {"usleep", usleep_main, _BB_DIR_BIN}, | 337 | {"usleep", usleep_main, _BB_DIR_BIN}, |
329 | #endif | 338 | #endif |
@@ -189,6 +189,9 @@ const struct BB_applet applets[] = { | |||
189 | #ifdef BB_MATH | 189 | #ifdef BB_MATH |
190 | {"math", math_main, _BB_DIR_USR_BIN}, | 190 | {"math", math_main, _BB_DIR_USR_BIN}, |
191 | #endif | 191 | #endif |
192 | #ifdef BB_MD5SUM | ||
193 | {"md5sum", md5sum_main, _BB_DIR_USR_BIN}, | ||
194 | #endif | ||
192 | #ifdef BB_MKDIR | 195 | #ifdef BB_MKDIR |
193 | {"mkdir", mkdir_main, _BB_DIR_BIN}, | 196 | {"mkdir", mkdir_main, _BB_DIR_BIN}, |
194 | #endif | 197 | #endif |
@@ -324,6 +327,12 @@ const struct BB_applet applets[] = { | |||
324 | #ifdef BB_UPTIME | 327 | #ifdef BB_UPTIME |
325 | {"uptime", uptime_main, _BB_DIR_USR_BIN}, | 328 | {"uptime", uptime_main, _BB_DIR_USR_BIN}, |
326 | #endif | 329 | #endif |
330 | #ifdef BB_UUENCODE | ||
331 | {"uuencode", uuencode_main, _BB_DIR_USR_BIN}, | ||
332 | #endif | ||
333 | #ifdef BB_UUDECODE | ||
334 | {"uudecode", uudecode_main, _BB_DIR_USR_BIN}, | ||
335 | #endif | ||
327 | #ifdef BB_USLEEP | 336 | #ifdef BB_USLEEP |
328 | {"usleep", usleep_main, _BB_DIR_BIN}, | 337 | {"usleep", usleep_main, _BB_DIR_BIN}, |
329 | #endif | 338 | #endif |
diff --git a/busybox.def.h b/busybox.def.h index 62ea5096e..50ad88ce0 100644 --- a/busybox.def.h +++ b/busybox.def.h | |||
@@ -55,6 +55,7 @@ | |||
55 | #define BB_LSMOD | 55 | #define BB_LSMOD |
56 | #define BB_MAKEDEVS | 56 | #define BB_MAKEDEVS |
57 | #define BB_MATH | 57 | #define BB_MATH |
58 | #define BB_MD5SUM | ||
58 | #define BB_MKDIR | 59 | #define BB_MKDIR |
59 | #define BB_MKFIFO | 60 | #define BB_MKFIFO |
60 | #define BB_MKFS_MINIX | 61 | #define BB_MKFS_MINIX |
@@ -99,6 +100,8 @@ | |||
99 | #define BB_WC | 100 | #define BB_WC |
100 | #define BB_WHICH | 101 | #define BB_WHICH |
101 | #define BB_WHOAMI | 102 | #define BB_WHOAMI |
103 | #define BB_UUENCODE | ||
104 | #define BB_UUDECODE | ||
102 | #define BB_UMOUNT | 105 | #define BB_UMOUNT |
103 | #define BB_UNIQ | 106 | #define BB_UNIQ |
104 | #define BB_UNAME | 107 | #define BB_UNAME |
diff --git a/chmod_chown_chgrp.c b/chmod_chown_chgrp.c index a3af4fbb3..1ff4bde73 100644 --- a/chmod_chown_chgrp.c +++ b/chmod_chown_chgrp.c | |||
@@ -119,7 +119,7 @@ int chmod_chown_chgrp_main(int argc, char **argv) | |||
119 | 119 | ||
120 | /* Parse options */ | 120 | /* Parse options */ |
121 | while (--argc >= 0 && *argv && (**argv == '-')) { | 121 | while (--argc >= 0 && *argv && (**argv == '-')) { |
122 | while (*++(*argv)) | 122 | while (*++(*argv)) { |
123 | switch (**argv) { | 123 | switch (**argv) { |
124 | case 'R': | 124 | case 'R': |
125 | recursiveFlag = TRUE; | 125 | recursiveFlag = TRUE; |
@@ -128,6 +128,7 @@ int chmod_chown_chgrp_main(int argc, char **argv) | |||
128 | fprintf(stderr, invalid_option, invocationName, **argv); | 128 | fprintf(stderr, invalid_option, invocationName, **argv); |
129 | usage(appUsage); | 129 | usage(appUsage); |
130 | } | 130 | } |
131 | } | ||
131 | argv++; | 132 | argv++; |
132 | } | 133 | } |
133 | 134 | ||
diff --git a/coreutils/df.c b/coreutils/df.c index 417065943..07e61d87d 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -51,7 +51,6 @@ static int df(char *device, const char *mountPoint) | |||
51 | blocks_used = s.f_blocks - s.f_bfree; | 51 | blocks_used = s.f_blocks - s.f_bfree; |
52 | blocks_percent_used = (long) | 52 | blocks_percent_used = (long) |
53 | (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); | 53 | (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); |
54 | /* Note that if /etc/fstab is missing, libc can't fix up /dev/root for us */ | ||
55 | if (strcmp(device, "/dev/root") == 0) { | 54 | if (strcmp(device, "/dev/root") == 0) { |
56 | /* Adjusts device to be the real root device, | 55 | /* Adjusts device to be the real root device, |
57 | * or leaves device alone if it can't find it */ | 56 | * or leaves device alone if it can't find it */ |
diff --git a/coreutils/md5sum.c b/coreutils/md5sum.c new file mode 100644 index 000000000..ffa9e6bce --- /dev/null +++ b/coreutils/md5sum.c | |||
@@ -0,0 +1,1013 @@ | |||
1 | /* 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 | |||
23 | #include "internal.h" | ||
24 | #include <stdio.h> | ||
25 | #include <errno.h> | ||
26 | #include <ctype.h> | ||
27 | |||
28 | //---------------------------------------------------------------------------- | ||
29 | //--------md5.c | ||
30 | //---------------------------------------------------------------------------- | ||
31 | |||
32 | /* md5.c - Functions to compute MD5 message digest of files or memory blocks | ||
33 | * according to the definition of MD5 in RFC 1321 from April 1992. | ||
34 | * Copyright (C) 1995, 1996 Free Software Foundation, Inc. | ||
35 | * | ||
36 | * NOTE: The canonical source of this file is maintained with the GNU C | ||
37 | * Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. | ||
38 | * | ||
39 | * This program is free software; you can redistribute it and/or modify it | ||
40 | * under the terms of the GNU General Public License as published by the | ||
41 | * Free Software Foundation; either version 2, or (at your option) any | ||
42 | * later version. | ||
43 | * | ||
44 | * This program is distributed in the hope that it will be useful, | ||
45 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
46 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
47 | * GNU General Public License for more details. | ||
48 | * | ||
49 | * You should have received a copy of the GNU General Public License | ||
50 | * along with this program; if not, write to the Free Software Foundation, | ||
51 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
52 | */ | ||
53 | |||
54 | /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ | ||
55 | |||
56 | #include <sys/types.h> | ||
57 | #include <stdlib.h> | ||
58 | #include <string.h> | ||
59 | #include <endian.h> | ||
60 | |||
61 | #include "internal.h" | ||
62 | //---------------------------------------------------------------------------- | ||
63 | //--------md5.h | ||
64 | //---------------------------------------------------------------------------- | ||
65 | |||
66 | /* md5.h - Declaration of functions and data types used for MD5 sum | ||
67 | computing library functions. | ||
68 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. | ||
69 | NOTE: The canonical source of this file is maintained with the GNU C | ||
70 | Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. | ||
71 | |||
72 | This program is free software; you can redistribute it and/or modify it | ||
73 | under the terms of the GNU General Public License as published by the | ||
74 | Free Software Foundation; either version 2, or (at your option) any | ||
75 | later version. | ||
76 | |||
77 | This program is distributed in the hope that it will be useful, | ||
78 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
79 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
80 | GNU General Public License for more details. | ||
81 | |||
82 | You should have received a copy of the GNU General Public License | ||
83 | along with this program; if not, write to the Free Software Foundation, | ||
84 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
85 | |||
86 | #ifndef _MD5_H | ||
87 | #define _MD5_H 1 | ||
88 | |||
89 | #include <stdio.h> | ||
90 | |||
91 | #if defined HAVE_LIMITS_H || _LIBC | ||
92 | # include <limits.h> | ||
93 | #endif | ||
94 | |||
95 | /* The following contortions are an attempt to use the C preprocessor | ||
96 | to determine an unsigned integral type that is 32 bits wide. An | ||
97 | alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but | ||
98 | doing that would require that the configure script compile and *run* | ||
99 | the resulting executable. Locally running cross-compiled executables | ||
100 | is usually not possible. */ | ||
101 | |||
102 | #ifdef _LIBC | ||
103 | # include <sys/types.h> | ||
104 | typedef u_int32_t md5_uint32; | ||
105 | #else | ||
106 | # if defined __STDC__ && __STDC__ | ||
107 | # define UINT_MAX_32_BITS 4294967295U | ||
108 | # else | ||
109 | # define UINT_MAX_32_BITS 0xFFFFFFFF | ||
110 | # endif | ||
111 | |||
112 | /* If UINT_MAX isn't defined, assume it's a 32-bit type. | ||
113 | This should be valid for all systems GNU cares about because | ||
114 | that doesn't include 16-bit systems, and only modern systems | ||
115 | (that certainly have <limits.h>) have 64+-bit integral types. */ | ||
116 | |||
117 | # ifndef UINT_MAX | ||
118 | # define UINT_MAX UINT_MAX_32_BITS | ||
119 | # endif | ||
120 | |||
121 | # if UINT_MAX == UINT_MAX_32_BITS | ||
122 | typedef unsigned int md5_uint32; | ||
123 | # else | ||
124 | # if USHRT_MAX == UINT_MAX_32_BITS | ||
125 | typedef unsigned short md5_uint32; | ||
126 | # else | ||
127 | # if ULONG_MAX == UINT_MAX_32_BITS | ||
128 | typedef unsigned long md5_uint32; | ||
129 | # else | ||
130 | /* The following line is intended to evoke an error. | ||
131 | Using #error is not portable enough. */ | ||
132 | "Cannot determine unsigned 32-bit data type." | ||
133 | # endif | ||
134 | # endif | ||
135 | # endif | ||
136 | #endif | ||
137 | |||
138 | #undef __P | ||
139 | #if defined (__STDC__) && __STDC__ | ||
140 | #define __P(x) x | ||
141 | #else | ||
142 | #define __P(x) () | ||
143 | #endif | ||
144 | |||
145 | /* Structure to save state of computation between the single steps. */ | ||
146 | struct md5_ctx | ||
147 | { | ||
148 | md5_uint32 A; | ||
149 | md5_uint32 B; | ||
150 | md5_uint32 C; | ||
151 | md5_uint32 D; | ||
152 | |||
153 | md5_uint32 total[2]; | ||
154 | md5_uint32 buflen; | ||
155 | char buffer[128]; | ||
156 | }; | ||
157 | |||
158 | /* | ||
159 | * The following three functions are build up the low level used in | ||
160 | * the functions `md5_stream' and `md5_buffer'. | ||
161 | */ | ||
162 | |||
163 | /* Initialize structure containing state of computation. | ||
164 | (RFC 1321, 3.3: Step 3) */ | ||
165 | extern void md5_init_ctx __P ((struct md5_ctx *ctx)); | ||
166 | |||
167 | /* Starting with the result of former calls of this function (or the | ||
168 | initialization function update the context for the next LEN bytes | ||
169 | starting at BUFFER. | ||
170 | It is necessary that LEN is a multiple of 64!!! */ | ||
171 | extern void md5_process_block __P ((const void *buffer, size_t len, | ||
172 | struct md5_ctx *ctx)); | ||
173 | |||
174 | /* Starting with the result of former calls of this function (or the | ||
175 | initialization function update the context for the next LEN bytes | ||
176 | starting at BUFFER. | ||
177 | It is NOT required that LEN is a multiple of 64. */ | ||
178 | extern void md5_process_bytes __P ((const void *buffer, size_t len, | ||
179 | struct md5_ctx *ctx)); | ||
180 | |||
181 | /* Process the remaining bytes in the buffer and put result from CTX | ||
182 | in first 16 bytes following RESBUF. The result is always in little | ||
183 | endian byte order, so that a byte-wise output yields to the wanted | ||
184 | ASCII representation of the message digest. | ||
185 | |||
186 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
187 | aligned for a 32 bits value. */ | ||
188 | extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); | ||
189 | |||
190 | |||
191 | /* Put result from CTX in first 16 bytes following RESBUF. The result is | ||
192 | always in little endian byte order, so that a byte-wise output yields | ||
193 | to the wanted ASCII representation of the message digest. | ||
194 | |||
195 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
196 | aligned for a 32 bits value. */ | ||
197 | extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); | ||
198 | |||
199 | |||
200 | /* Compute MD5 message digest for bytes read from STREAM. The | ||
201 | resulting message digest number will be written into the 16 bytes | ||
202 | beginning at RESBLOCK. */ | ||
203 | extern int md5_stream __P ((FILE *stream, void *resblock)); | ||
204 | |||
205 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The | ||
206 | result is always in little endian byte order, so that a byte-wise | ||
207 | output yields to the wanted ASCII representation of the message | ||
208 | digest. */ | ||
209 | extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); | ||
210 | |||
211 | #endif | ||
212 | |||
213 | //---------------------------------------------------------------------------- | ||
214 | //--------end of md5.h | ||
215 | //---------------------------------------------------------------------------- | ||
216 | |||
217 | #define SWAP(n) (n) | ||
218 | |||
219 | /* This array contains the bytes used to pad the buffer to the next | ||
220 | 64-byte boundary. (RFC 1321, 3.1: Step 1) */ | ||
221 | static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; | ||
222 | |||
223 | /* Initialize structure containing state of computation. | ||
224 | (RFC 1321, 3.3: Step 3) */ | ||
225 | void md5_init_ctx(struct md5_ctx *ctx) | ||
226 | { | ||
227 | ctx->A = 0x67452301; | ||
228 | ctx->B = 0xefcdab89; | ||
229 | ctx->C = 0x98badcfe; | ||
230 | ctx->D = 0x10325476; | ||
231 | |||
232 | ctx->total[0] = ctx->total[1] = 0; | ||
233 | ctx->buflen = 0; | ||
234 | } | ||
235 | |||
236 | /* Put result from CTX in first 16 bytes following RESBUF. The result | ||
237 | must be in little endian byte order. | ||
238 | |||
239 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
240 | aligned for a 32 bits value. */ | ||
241 | void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf) | ||
242 | { | ||
243 | ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A); | ||
244 | ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B); | ||
245 | ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C); | ||
246 | ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D); | ||
247 | |||
248 | return resbuf; | ||
249 | } | ||
250 | |||
251 | /* Process the remaining bytes in the internal buffer and the usual | ||
252 | prolog according to the standard and write the result to RESBUF. | ||
253 | |||
254 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
255 | aligned for a 32 bits value. */ | ||
256 | void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf) | ||
257 | { | ||
258 | /* Take yet unprocessed bytes into account. */ | ||
259 | md5_uint32 bytes = ctx->buflen; | ||
260 | size_t pad; | ||
261 | |||
262 | /* Now count remaining bytes. */ | ||
263 | ctx->total[0] += bytes; | ||
264 | if (ctx->total[0] < bytes) | ||
265 | ++ctx->total[1]; | ||
266 | |||
267 | pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; | ||
268 | memcpy(&ctx->buffer[bytes], fillbuf, pad); | ||
269 | |||
270 | /* Put the 64-bit file length in *bits* at the end of the buffer. */ | ||
271 | *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3); | ||
272 | *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] = | ||
273 | SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)); | ||
274 | |||
275 | /* Process last bytes. */ | ||
276 | md5_process_block(ctx->buffer, bytes + pad + 8, ctx); | ||
277 | |||
278 | return md5_read_ctx(ctx, resbuf); | ||
279 | } | ||
280 | |||
281 | /* Compute MD5 message digest for bytes read from STREAM. The | ||
282 | resulting message digest number will be written into the 16 bytes | ||
283 | beginning at RESBLOCK. */ | ||
284 | int md5_stream(FILE *stream, void *resblock) | ||
285 | { | ||
286 | /* Important: BLOCKSIZE must be a multiple of 64. */ | ||
287 | #define BLOCKSIZE 4096 | ||
288 | struct md5_ctx ctx; | ||
289 | char buffer[BLOCKSIZE + 72]; | ||
290 | size_t sum; | ||
291 | |||
292 | /* Initialize the computation context. */ | ||
293 | md5_init_ctx(&ctx); | ||
294 | |||
295 | /* Iterate over full file contents. */ | ||
296 | while (1) { | ||
297 | /* We read the file in blocks of BLOCKSIZE bytes. One call of the | ||
298 | computation function processes the whole buffer so that with the | ||
299 | next round of the loop another block can be read. */ | ||
300 | size_t n; | ||
301 | sum = 0; | ||
302 | |||
303 | /* Read block. Take care for partial reads. */ | ||
304 | do { | ||
305 | n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream); | ||
306 | |||
307 | sum += n; | ||
308 | } | ||
309 | while (sum < BLOCKSIZE && n != 0); | ||
310 | if (n == 0 && ferror(stream)) | ||
311 | return 1; | ||
312 | |||
313 | /* If end of file is reached, end the loop. */ | ||
314 | if (n == 0) | ||
315 | break; | ||
316 | |||
317 | /* Process buffer with BLOCKSIZE bytes. Note that | ||
318 | BLOCKSIZE % 64 == 0 | ||
319 | */ | ||
320 | md5_process_block(buffer, BLOCKSIZE, &ctx); | ||
321 | } | ||
322 | |||
323 | /* Add the last bytes if necessary. */ | ||
324 | if (sum > 0) | ||
325 | md5_process_bytes(buffer, sum, &ctx); | ||
326 | |||
327 | /* Construct result in desired memory. */ | ||
328 | md5_finish_ctx(&ctx, resblock); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The | ||
333 | result is always in little endian byte order, so that a byte-wise | ||
334 | output yields to the wanted ASCII representation of the message | ||
335 | digest. */ | ||
336 | void *md5_buffer(const char *buffer, size_t len, void *resblock) | ||
337 | { | ||
338 | struct md5_ctx ctx; | ||
339 | |||
340 | /* Initialize the computation context. */ | ||
341 | md5_init_ctx(&ctx); | ||
342 | |||
343 | /* Process whole buffer but last len % 64 bytes. */ | ||
344 | md5_process_bytes(buffer, len, &ctx); | ||
345 | |||
346 | /* Put result in desired memory area. */ | ||
347 | return md5_finish_ctx(&ctx, resblock); | ||
348 | } | ||
349 | |||
350 | void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx) | ||
351 | { | ||
352 | /* When we already have some bits in our internal buffer concatenate | ||
353 | both inputs first. */ | ||
354 | if (ctx->buflen != 0) { | ||
355 | size_t left_over = ctx->buflen; | ||
356 | size_t add = 128 - left_over > len ? len : 128 - left_over; | ||
357 | |||
358 | memcpy(&ctx->buffer[left_over], buffer, add); | ||
359 | ctx->buflen += add; | ||
360 | |||
361 | if (left_over + add > 64) { | ||
362 | md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx); | ||
363 | /* The regions in the following copy operation cannot overlap. */ | ||
364 | memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], | ||
365 | (left_over + add) & 63); | ||
366 | ctx->buflen = (left_over + add) & 63; | ||
367 | } | ||
368 | |||
369 | buffer = (const char *) buffer + add; | ||
370 | len -= add; | ||
371 | } | ||
372 | |||
373 | /* Process available complete blocks. */ | ||
374 | if (len > 64) { | ||
375 | md5_process_block(buffer, len & ~63, ctx); | ||
376 | buffer = (const char *) buffer + (len & ~63); | ||
377 | len &= 63; | ||
378 | } | ||
379 | |||
380 | /* Move remaining bytes in internal buffer. */ | ||
381 | if (len > 0) { | ||
382 | memcpy(ctx->buffer, buffer, len); | ||
383 | ctx->buflen = len; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* These are the four functions used in the four steps of the MD5 algorithm | ||
388 | and defined in the RFC 1321. The first function is a little bit optimized | ||
389 | (as found in Colin Plumbs public domain implementation). */ | ||
390 | /* #define FF(b, c, d) ((b & c) | (~b & d)) */ | ||
391 | #define FF(b, c, d) (d ^ (b & (c ^ d))) | ||
392 | #define FG(b, c, d) FF (d, b, c) | ||
393 | #define FH(b, c, d) (b ^ c ^ d) | ||
394 | #define FI(b, c, d) (c ^ (b | ~d)) | ||
395 | |||
396 | /* Process LEN bytes of BUFFER, accumulating context into CTX. | ||
397 | It is assumed that LEN % 64 == 0. */ | ||
398 | void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx) | ||
399 | { | ||
400 | md5_uint32 correct_words[16]; | ||
401 | const md5_uint32 *words = buffer; | ||
402 | size_t nwords = len / sizeof(md5_uint32); | ||
403 | const md5_uint32 *endp = words + nwords; | ||
404 | md5_uint32 A = ctx->A; | ||
405 | md5_uint32 B = ctx->B; | ||
406 | md5_uint32 C = ctx->C; | ||
407 | md5_uint32 D = ctx->D; | ||
408 | |||
409 | /* First increment the byte count. RFC 1321 specifies the possible | ||
410 | length of the file up to 2^64 bits. Here we only compute the | ||
411 | number of bytes. Do a double word increment. */ | ||
412 | ctx->total[0] += len; | ||
413 | if (ctx->total[0] < len) | ||
414 | ++ctx->total[1]; | ||
415 | |||
416 | /* Process all bytes in the buffer with 64 bytes in each round of | ||
417 | the loop. */ | ||
418 | while (words < endp) { | ||
419 | md5_uint32 *cwp = correct_words; | ||
420 | md5_uint32 A_save = A; | ||
421 | md5_uint32 B_save = B; | ||
422 | md5_uint32 C_save = C; | ||
423 | md5_uint32 D_save = D; | ||
424 | |||
425 | /* First round: using the given function, the context and a constant | ||
426 | the next context is computed. Because the algorithms processing | ||
427 | unit is a 32-bit word and it is determined to work on words in | ||
428 | little endian byte order we perhaps have to change the byte order | ||
429 | before the computation. To reduce the work for the next steps | ||
430 | we store the swapped words in the array CORRECT_WORDS. */ | ||
431 | |||
432 | #define OP(a, b, c, d, s, T) \ | ||
433 | do \ | ||
434 | { \ | ||
435 | a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ | ||
436 | ++words; \ | ||
437 | CYCLIC (a, s); \ | ||
438 | a += b; \ | ||
439 | } \ | ||
440 | while (0) | ||
441 | |||
442 | /* It is unfortunate that C does not provide an operator for | ||
443 | cyclic rotation. Hope the C compiler is smart enough. */ | ||
444 | #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) | ||
445 | |||
446 | /* Before we start, one word to the strange constants. | ||
447 | They are defined in RFC 1321 as | ||
448 | |||
449 | T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 | ||
450 | */ | ||
451 | |||
452 | /* Round 1. */ | ||
453 | OP(A, B, C, D, 7, 0xd76aa478); | ||
454 | OP(D, A, B, C, 12, 0xe8c7b756); | ||
455 | OP(C, D, A, B, 17, 0x242070db); | ||
456 | OP(B, C, D, A, 22, 0xc1bdceee); | ||
457 | OP(A, B, C, D, 7, 0xf57c0faf); | ||
458 | OP(D, A, B, C, 12, 0x4787c62a); | ||
459 | OP(C, D, A, B, 17, 0xa8304613); | ||
460 | OP(B, C, D, A, 22, 0xfd469501); | ||
461 | OP(A, B, C, D, 7, 0x698098d8); | ||
462 | OP(D, A, B, C, 12, 0x8b44f7af); | ||
463 | OP(C, D, A, B, 17, 0xffff5bb1); | ||
464 | OP(B, C, D, A, 22, 0x895cd7be); | ||
465 | OP(A, B, C, D, 7, 0x6b901122); | ||
466 | OP(D, A, B, C, 12, 0xfd987193); | ||
467 | OP(C, D, A, B, 17, 0xa679438e); | ||
468 | OP(B, C, D, A, 22, 0x49b40821); | ||
469 | |||
470 | /* For the second to fourth round we have the possibly swapped words | ||
471 | in CORRECT_WORDS. Redefine the macro to take an additional first | ||
472 | argument specifying the function to use. */ | ||
473 | #undef OP | ||
474 | #define OP(f, a, b, c, d, k, s, T) \ | ||
475 | do \ | ||
476 | { \ | ||
477 | a += f (b, c, d) + correct_words[k] + T; \ | ||
478 | CYCLIC (a, s); \ | ||
479 | a += b; \ | ||
480 | } \ | ||
481 | while (0) | ||
482 | |||
483 | /* Round 2. */ | ||
484 | OP(FG, A, B, C, D, 1, 5, 0xf61e2562); | ||
485 | OP(FG, D, A, B, C, 6, 9, 0xc040b340); | ||
486 | OP(FG, C, D, A, B, 11, 14, 0x265e5a51); | ||
487 | OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); | ||
488 | OP(FG, A, B, C, D, 5, 5, 0xd62f105d); | ||
489 | OP(FG, D, A, B, C, 10, 9, 0x02441453); | ||
490 | OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); | ||
491 | OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); | ||
492 | OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); | ||
493 | OP(FG, D, A, B, C, 14, 9, 0xc33707d6); | ||
494 | OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); | ||
495 | OP(FG, B, C, D, A, 8, 20, 0x455a14ed); | ||
496 | OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); | ||
497 | OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); | ||
498 | OP(FG, C, D, A, B, 7, 14, 0x676f02d9); | ||
499 | OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); | ||
500 | |||
501 | /* Round 3. */ | ||
502 | OP(FH, A, B, C, D, 5, 4, 0xfffa3942); | ||
503 | OP(FH, D, A, B, C, 8, 11, 0x8771f681); | ||
504 | OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); | ||
505 | OP(FH, B, C, D, A, 14, 23, 0xfde5380c); | ||
506 | OP(FH, A, B, C, D, 1, 4, 0xa4beea44); | ||
507 | OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); | ||
508 | OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); | ||
509 | OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); | ||
510 | OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); | ||
511 | OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); | ||
512 | OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); | ||
513 | OP(FH, B, C, D, A, 6, 23, 0x04881d05); | ||
514 | OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); | ||
515 | OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); | ||
516 | OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); | ||
517 | OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); | ||
518 | |||
519 | /* Round 4. */ | ||
520 | OP(FI, A, B, C, D, 0, 6, 0xf4292244); | ||
521 | OP(FI, D, A, B, C, 7, 10, 0x432aff97); | ||
522 | OP(FI, C, D, A, B, 14, 15, 0xab9423a7); | ||
523 | OP(FI, B, C, D, A, 5, 21, 0xfc93a039); | ||
524 | OP(FI, A, B, C, D, 12, 6, 0x655b59c3); | ||
525 | OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); | ||
526 | OP(FI, C, D, A, B, 10, 15, 0xffeff47d); | ||
527 | OP(FI, B, C, D, A, 1, 21, 0x85845dd1); | ||
528 | OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); | ||
529 | OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); | ||
530 | OP(FI, C, D, A, B, 6, 15, 0xa3014314); | ||
531 | OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); | ||
532 | OP(FI, A, B, C, D, 4, 6, 0xf7537e82); | ||
533 | OP(FI, D, A, B, C, 11, 10, 0xbd3af235); | ||
534 | OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); | ||
535 | OP(FI, B, C, D, A, 9, 21, 0xeb86d391); | ||
536 | |||
537 | /* Add the starting values of the context. */ | ||
538 | A += A_save; | ||
539 | B += B_save; | ||
540 | C += C_save; | ||
541 | D += D_save; | ||
542 | } | ||
543 | |||
544 | /* Put checksum in context given as argument. */ | ||
545 | ctx->A = A; | ||
546 | ctx->B = B; | ||
547 | ctx->C = C; | ||
548 | ctx->D = D; | ||
549 | } | ||
550 | |||
551 | //---------------------------------------------------------------------------- | ||
552 | //--------end of md5.c | ||
553 | //---------------------------------------------------------------------------- | ||
554 | |||
555 | #define ISWHITE(c) ((c) == ' ' || (c) == '\t') | ||
556 | #define IN_CTYPE_DOMAIN(c) 1 | ||
557 | #define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) | ||
558 | #define STREQ(a, b) (strcmp ((a), (b)) == 0) | ||
559 | #define TOLOWER(Ch) tolower (Ch) | ||
560 | #define OPENOPTS(BINARY) "r" | ||
561 | |||
562 | /* The minimum length of a valid digest line in a file produced | ||
563 | by `md5sum FILE' and read by `md5sum -c'. This length does | ||
564 | not include any newline character at the end of a line. */ | ||
565 | #define MIN_DIGEST_LINE_LENGTH 35 /* 32 - message digest length | ||
566 | 2 - blank and binary indicator | ||
567 | 1 - minimum filename length */ | ||
568 | |||
569 | static int have_read_stdin; /* Nonzero if any of the files read were | ||
570 | the standard input. */ | ||
571 | |||
572 | static int status_only = 0; /* With -c, don't generate any output. | ||
573 | The exit code indicates success or failure */ | ||
574 | static int warn = 0; /* With -w, print a message to standard error warning | ||
575 | about each improperly formatted MD5 checksum line */ | ||
576 | |||
577 | static const char md5sum_usage[] = | ||
578 | "md5sum [OPTION] [FILE]...\n" | ||
579 | "or: md5sum [OPTION] -c [FILE]\n" | ||
580 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
581 | "\nPrint or check MD5 checksums.\n\n" | ||
582 | "Options:\n" | ||
583 | "With no FILE, or when FILE is -, read standard input.\n\n" | ||
584 | "\t-b\tread files in binary mode\n" | ||
585 | "\t-c\tcheck MD5 sums against given list\n" | ||
586 | "\t-t\tread files in text mode (default)\n" | ||
587 | "\t-g\tread a string\n" | ||
588 | "\nThe following two options are useful only when verifying checksums:\n" | ||
589 | "\t-s,\tdon't output anything, status code shows success\n" | ||
590 | "\t-w,\twarn about improperly formated MD5 checksum lines\n" | ||
591 | #endif | ||
592 | ; | ||
593 | |||
594 | static int split_3(char *s, | ||
595 | size_t s_len, | ||
596 | unsigned char **u, | ||
597 | int *binary, | ||
598 | char **w) | ||
599 | { | ||
600 | size_t i = 0; | ||
601 | int escaped_filename = 0; | ||
602 | |||
603 | while (ISWHITE(s[i])) | ||
604 | ++i; | ||
605 | |||
606 | /* The line must have at least 35 (36 if the first is a backslash) | ||
607 | more characters to contain correct message digest information. | ||
608 | Ignore this line if it is too short. */ | ||
609 | if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH | ||
610 | || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH))) | ||
611 | return FALSE; | ||
612 | |||
613 | if (s[i] == '\\') { | ||
614 | ++i; | ||
615 | escaped_filename = 1; | ||
616 | } | ||
617 | *u = (unsigned char *) &s[i]; | ||
618 | |||
619 | /* The first field has to be the 32-character hexadecimal | ||
620 | representation of the message digest. If it is not followed | ||
621 | immediately by a white space it's an error. */ | ||
622 | i += 32; | ||
623 | if (!ISWHITE(s[i])) | ||
624 | return FALSE; | ||
625 | |||
626 | s[i++] = '\0'; | ||
627 | |||
628 | if (s[i] != ' ' && s[i] != '*') | ||
629 | return FALSE; | ||
630 | *binary = (s[i++] == '*'); | ||
631 | |||
632 | /* All characters between the type indicator and end of line are | ||
633 | significant -- that includes leading and trailing white space. */ | ||
634 | *w = &s[i]; | ||
635 | |||
636 | if (escaped_filename) { | ||
637 | /* Translate each `\n' string in the file name to a NEWLINE, | ||
638 | and each `\\' string to a backslash. */ | ||
639 | |||
640 | char *dst = &s[i]; | ||
641 | |||
642 | while (i < s_len) { | ||
643 | switch (s[i]) { | ||
644 | case '\\': | ||
645 | if (i == s_len - 1) { | ||
646 | /* A valid line does not end with a backslash. */ | ||
647 | return FALSE; | ||
648 | } | ||
649 | ++i; | ||
650 | switch (s[i++]) { | ||
651 | case 'n': | ||
652 | *dst++ = '\n'; | ||
653 | break; | ||
654 | case '\\': | ||
655 | *dst++ = '\\'; | ||
656 | break; | ||
657 | default: | ||
658 | /* Only `\' or `n' may follow a backslash. */ | ||
659 | return FALSE; | ||
660 | } | ||
661 | break; | ||
662 | |||
663 | case '\0': | ||
664 | /* The file name may not contain a NUL. */ | ||
665 | return FALSE; | ||
666 | break; | ||
667 | |||
668 | default: | ||
669 | *dst++ = s[i++]; | ||
670 | break; | ||
671 | } | ||
672 | } | ||
673 | *dst = '\0'; | ||
674 | } | ||
675 | return TRUE; | ||
676 | } | ||
677 | |||
678 | static int hex_digits(unsigned char const *s) | ||
679 | { | ||
680 | while (*s) { | ||
681 | if (!ISXDIGIT(*s)) | ||
682 | return TRUE; | ||
683 | ++s; | ||
684 | } | ||
685 | return FALSE; | ||
686 | } | ||
687 | |||
688 | /* An interface to md5_stream. Operate on FILENAME (it may be "-") and | ||
689 | put the result in *MD5_RESULT. Return non-zero upon failure, zero | ||
690 | to indicate success. */ | ||
691 | static int md5_file(const char *filename, | ||
692 | int binary, | ||
693 | unsigned char *md5_result) | ||
694 | { | ||
695 | FILE *fp; | ||
696 | |||
697 | if (STREQ(filename, "-")) { | ||
698 | have_read_stdin = 1; | ||
699 | fp = stdin; | ||
700 | } else { | ||
701 | fp = fopen(filename, OPENOPTS(binary)); | ||
702 | if (fp == NULL) { | ||
703 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
704 | return FALSE; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | if (md5_stream(fp, md5_result)) { | ||
709 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
710 | |||
711 | if (fp != stdin) | ||
712 | fclose(fp); | ||
713 | return FALSE; | ||
714 | } | ||
715 | |||
716 | if (fp != stdin && fclose(fp) == EOF) { | ||
717 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
718 | return FALSE; | ||
719 | } | ||
720 | |||
721 | return TRUE; | ||
722 | } | ||
723 | |||
724 | static int md5_check(const char *checkfile_name) | ||
725 | { | ||
726 | FILE *checkfile_stream; | ||
727 | int n_properly_formated_lines = 0; | ||
728 | int n_mismatched_checksums = 0; | ||
729 | int n_open_or_read_failures = 0; | ||
730 | unsigned char md5buffer[16]; | ||
731 | size_t line_number; | ||
732 | char *line; | ||
733 | size_t line_chars_allocated; | ||
734 | |||
735 | if (STREQ(checkfile_name, "-")) { | ||
736 | have_read_stdin = 1; | ||
737 | checkfile_stream = stdin; | ||
738 | } else { | ||
739 | checkfile_stream = fopen(checkfile_name, "r"); | ||
740 | if (checkfile_stream == NULL) { | ||
741 | errorMsg("md5sum: %s: %s\n", checkfile_name, strerror(errno)); | ||
742 | return FALSE; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | line_number = 0; | ||
747 | line = 0; | ||
748 | line_chars_allocated = 0; | ||
749 | |||
750 | do { | ||
751 | char *filename; | ||
752 | int binary; | ||
753 | unsigned char *md5num; | ||
754 | int line_length; | ||
755 | |||
756 | ++line_number; | ||
757 | |||
758 | line_length = getline(&line, &line_chars_allocated, checkfile_stream); | ||
759 | |||
760 | if (line_length <= 0) | ||
761 | break; | ||
762 | |||
763 | /* Ignore comment lines, which begin with a '#' character. */ | ||
764 | if (line[0] == '#') | ||
765 | continue; | ||
766 | |||
767 | /* Remove any trailing newline. */ | ||
768 | if (line[line_length - 1] == '\n') | ||
769 | line[--line_length] = '\0'; | ||
770 | |||
771 | if (split_3(line, line_length, &md5num, &binary, &filename) | ||
772 | || !hex_digits(md5num)) { | ||
773 | if (warn) { | ||
774 | errorMsg("%s: %lu: improperly formatted MD5 checksum line\n", | ||
775 | checkfile_name, (unsigned long) line_number); | ||
776 | } | ||
777 | } else { | ||
778 | static const char bin2hex[] = { | ||
779 | '0', '1', '2', '3', | ||
780 | '4', '5', '6', '7', | ||
781 | '8', '9', 'a', 'b', | ||
782 | 'c', 'd', 'e', 'f' | ||
783 | }; | ||
784 | |||
785 | ++n_properly_formated_lines; | ||
786 | |||
787 | if (md5_file(filename, binary, md5buffer)) { | ||
788 | ++n_open_or_read_failures; | ||
789 | if (!status_only) { | ||
790 | printf("%s: FAILED open or read\n", filename); | ||
791 | fflush(stdout); | ||
792 | } | ||
793 | } else { | ||
794 | size_t cnt; | ||
795 | /* Compare generated binary number with text representation | ||
796 | in check file. Ignore case of hex digits. */ | ||
797 | for (cnt = 0; cnt < 16; ++cnt) { | ||
798 | if (TOLOWER(md5num[2 * cnt]) | ||
799 | != bin2hex[md5buffer[cnt] >> 4] | ||
800 | || (TOLOWER(md5num[2 * cnt + 1]) | ||
801 | != (bin2hex[md5buffer[cnt] & 0xf]))) | ||
802 | break; | ||
803 | } | ||
804 | if (cnt != 16) | ||
805 | ++n_mismatched_checksums; | ||
806 | |||
807 | if (!status_only) { | ||
808 | printf("%s: %s\n", filename, | ||
809 | (cnt != 16 ? "FAILED" : "OK")); | ||
810 | fflush(stdout); | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | } | ||
815 | |||
816 | while (!feof(checkfile_stream) && !ferror(checkfile_stream)); | ||
817 | |||
818 | if (line) | ||
819 | free(line); | ||
820 | |||
821 | if (ferror(checkfile_stream)) { | ||
822 | errorMsg("%s: read error", checkfile_name); /* */ | ||
823 | return FALSE; | ||
824 | } | ||
825 | |||
826 | if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) { | ||
827 | errorMsg("md5sum: %s: %s\n", checkfile_name, strerror(errno)); | ||
828 | return FALSE; | ||
829 | } | ||
830 | |||
831 | if (n_properly_formated_lines == 0) { | ||
832 | /* Warn if no tests are found. */ | ||
833 | errorMsg("%s: no properly formatted MD5 checksum lines found\n", | ||
834 | checkfile_name); | ||
835 | return FALSE; | ||
836 | } else { | ||
837 | if (!status_only) { | ||
838 | int n_computed_checkums = (n_properly_formated_lines | ||
839 | - n_open_or_read_failures); | ||
840 | |||
841 | if (n_open_or_read_failures > 0) { | ||
842 | errorMsg("WARNING: %d of %d listed files could not be read\n", | ||
843 | n_open_or_read_failures, n_properly_formated_lines); | ||
844 | return FALSE; | ||
845 | } | ||
846 | |||
847 | if (n_mismatched_checksums > 0) { | ||
848 | errorMsg("WARNING: %d of %d computed checksums did NOT match\n", | ||
849 | n_mismatched_checksums, n_computed_checkums); | ||
850 | return FALSE; | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | |||
855 | return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0 | ||
856 | && n_open_or_read_failures == 0) ? 0 : 1); | ||
857 | } | ||
858 | |||
859 | int md5sum_main(int argc, | ||
860 | char **argv) | ||
861 | { | ||
862 | unsigned char md5buffer[16]; | ||
863 | int do_check = 0; | ||
864 | int opt; | ||
865 | char **string = NULL; | ||
866 | size_t n_strings = 0; | ||
867 | size_t err = 0; | ||
868 | int file_type_specified = 0; | ||
869 | int binary = 0; | ||
870 | |||
871 | while ((opt = getopt(argc, argv, "g:bcstw")) != -1) { | ||
872 | switch (opt) { | ||
873 | case 'g': { /* read a string */ | ||
874 | if (string == NULL) | ||
875 | string = (char **) xmalloc ((argc - 1) * sizeof (char *)); | ||
876 | |||
877 | if (optarg == NULL) | ||
878 | optarg = ""; | ||
879 | string[n_strings++] = optarg; | ||
880 | break; | ||
881 | } | ||
882 | |||
883 | case 'b': /* read files in binary mode */ | ||
884 | file_type_specified = 1; | ||
885 | binary = 1; | ||
886 | break; | ||
887 | |||
888 | case 'c': /* check MD5 sums against given list */ | ||
889 | do_check = 1; | ||
890 | break; | ||
891 | |||
892 | case 's': /* don't output anything, status code shows success */ | ||
893 | status_only = 1; | ||
894 | warn = 0; | ||
895 | break; | ||
896 | |||
897 | case 't': /* read files in text mode (default) */ | ||
898 | file_type_specified = 1; | ||
899 | binary = 0; | ||
900 | break; | ||
901 | |||
902 | case 'w': /* warn about improperly formated MD5 checksum lines */ | ||
903 | status_only = 0; | ||
904 | warn = 1; | ||
905 | break; | ||
906 | |||
907 | default: | ||
908 | usage(md5sum_usage); | ||
909 | } | ||
910 | } | ||
911 | |||
912 | if (file_type_specified && do_check) { | ||
913 | errorMsg("the -b and -t options are meaningless when verifying checksums\n"); | ||
914 | exit FALSE; | ||
915 | } | ||
916 | |||
917 | if (n_strings > 0 && do_check) { | ||
918 | errorMsg("the -g and -c options are mutually exclusive\n"); | ||
919 | exit FALSE; | ||
920 | } | ||
921 | |||
922 | if (status_only && !do_check) { | ||
923 | errorMsg("the -s option is meaningful only when verifying checksums\n"); | ||
924 | exit FALSE; | ||
925 | } | ||
926 | |||
927 | if (warn && !do_check) { | ||
928 | errorMsg("the -w option is meaningful only when verifying checksums\n"); | ||
929 | exit FALSE; | ||
930 | } | ||
931 | |||
932 | if (n_strings > 0) { | ||
933 | size_t i; | ||
934 | |||
935 | if (optind < argc) { | ||
936 | errorMsg("no files may be specified when using -g\n"); | ||
937 | exit FALSE; | ||
938 | } | ||
939 | for (i = 0; i < n_strings; ++i) { | ||
940 | size_t cnt; | ||
941 | md5_buffer (string[i], strlen (string[i]), md5buffer); | ||
942 | |||
943 | for (cnt = 0; cnt < 16; ++cnt) | ||
944 | printf ("%02x", md5buffer[cnt]); | ||
945 | |||
946 | printf (" \"%s\"\n", string[i]); | ||
947 | } | ||
948 | } else if (do_check) { | ||
949 | if (optind + 1 < argc) { | ||
950 | errorMsg("only one argument may be specified when using -c\n"); | ||
951 | } | ||
952 | |||
953 | err = md5_check ((optind == argc) ? "-" : argv[optind]); | ||
954 | } else { | ||
955 | if (optind == argc) | ||
956 | argv[argc++] = "-"; | ||
957 | |||
958 | for (; optind < argc; ++optind) { | ||
959 | int fail; | ||
960 | char *file = argv[optind]; | ||
961 | |||
962 | fail = md5_file (file, binary, md5buffer); | ||
963 | err |= fail; | ||
964 | if (!fail) { | ||
965 | size_t i; | ||
966 | /* Output a leading backslash if the file name contains | ||
967 | a newline or backslash. */ | ||
968 | if (strchr (file, '\n') || strchr (file, '\\')) | ||
969 | putchar ('\\'); | ||
970 | |||
971 | for (i = 0; i < 16; ++i) | ||
972 | printf ("%02x", md5buffer[i]); | ||
973 | |||
974 | putchar (' '); | ||
975 | if (binary) | ||
976 | putchar ('*'); | ||
977 | else | ||
978 | putchar (' '); | ||
979 | |||
980 | /* Translate each NEWLINE byte to the string, "\\n", | ||
981 | and each backslash to "\\\\". */ | ||
982 | for (i = 0; i < strlen (file); ++i) { | ||
983 | switch (file[i]) { | ||
984 | case '\n': | ||
985 | fputs ("\\n", stdout); | ||
986 | break; | ||
987 | |||
988 | case '\\': | ||
989 | fputs ("\\\\", stdout); | ||
990 | break; | ||
991 | |||
992 | default: | ||
993 | putchar (file[i]); | ||
994 | break; | ||
995 | } | ||
996 | } | ||
997 | putchar ('\n'); | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | if (fclose (stdout) == EOF) { | ||
1003 | errorMsg("write error"); | ||
1004 | exit FALSE; | ||
1005 | } | ||
1006 | |||
1007 | if (have_read_stdin && fclose (stdin) == EOF) { | ||
1008 | errorMsg("standard input"); | ||
1009 | exit FALSE; | ||
1010 | } | ||
1011 | |||
1012 | exit (err == 0 ? TRUE : FALSE); | ||
1013 | } | ||
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c new file mode 100644 index 000000000..4216e336a --- /dev/null +++ b/coreutils/uudecode.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /* uudecode.c -- uudecode utility. | ||
2 | * Copyright (C) 1994, 1995 Free Software Foundation, Inc. | ||
3 | * | ||
4 | * This product is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2, or (at your option) | ||
7 | * any later version. | ||
8 | * | ||
9 | * This product is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this product; see the file COPYING. If not, write to | ||
16 | * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | ||
17 | * 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* Copyright (c) 1983 Regents of the University of California. | ||
21 | * All rights reserved. | ||
22 | * | ||
23 | * Redistribution and use in source and binary forms, with or without | ||
24 | * modification, are permitted provided that the following conditions | ||
25 | * are met: | ||
26 | * 1. Redistributions of source code must retain the above copyright | ||
27 | * notice, this list of conditions and the following disclaimer. | ||
28 | * 2. Redistributions in binary form must reproduce the above copyright | ||
29 | * notice, this list of conditions and the following disclaimer in the | ||
30 | * documentation and/or other materials provided with the distribution. | ||
31 | * 3. All advertising materials mentioning features or use of this software | ||
32 | * must display the following acknowledgement: | ||
33 | * This product includes software developed by the University of | ||
34 | * California, Berkeley and its contributors. | ||
35 | * 4. Neither the name of the University nor the names of its contributors | ||
36 | * may be used to endorse or promote products derived from this software | ||
37 | * without specific prior written permission. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
49 | * SUCH DAMAGE. | ||
50 | */ | ||
51 | |||
52 | /* Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. */ | ||
53 | |||
54 | #include "internal.h" | ||
55 | |||
56 | #include <stdio.h> | ||
57 | #include <errno.h> | ||
58 | #include <pwd.h> | ||
59 | |||
60 | /*struct passwd *getpwnam();*/ | ||
61 | |||
62 | /* Single character decode. */ | ||
63 | #define DEC(Char) (((Char) - ' ') & 077) | ||
64 | |||
65 | static int read_stduu (const char *inname) | ||
66 | { | ||
67 | char buf[2 * BUFSIZ]; | ||
68 | |||
69 | while (1) { | ||
70 | int n; | ||
71 | char *p; | ||
72 | |||
73 | if (fgets (buf, sizeof(buf), stdin) == NULL) { | ||
74 | errorMsg("%s: Short file\n", inname); | ||
75 | return FALSE; | ||
76 | } | ||
77 | p = buf; | ||
78 | |||
79 | /* N is used to avoid writing out all the characters at the end of | ||
80 | the file. */ | ||
81 | n = DEC (*p); | ||
82 | if (n <= 0) | ||
83 | break; | ||
84 | for (++p; n > 0; p += 4, n -= 3) { | ||
85 | char ch; | ||
86 | |||
87 | if (n >= 3) { | ||
88 | ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; | ||
89 | putchar (ch); | ||
90 | ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; | ||
91 | putchar (ch); | ||
92 | ch = DEC (p[2]) << 6 | DEC (p[3]); | ||
93 | putchar (ch); | ||
94 | } else { | ||
95 | if (n >= 1) { | ||
96 | ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; | ||
97 | putchar (ch); | ||
98 | } | ||
99 | if (n >= 2) { | ||
100 | ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; | ||
101 | putchar (ch); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if (fgets (buf, sizeof(buf), stdin) == NULL | ||
108 | || strcmp (buf, "end\n")) { | ||
109 | errorMsg("%s: No `end' line\n", inname); | ||
110 | return FALSE; | ||
111 | } | ||
112 | |||
113 | return TRUE; | ||
114 | } | ||
115 | |||
116 | static int read_base64 (const char *inname) | ||
117 | { | ||
118 | static const char b64_tab[256] = { | ||
119 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/ | ||
120 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/ | ||
121 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/ | ||
122 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/ | ||
123 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/ | ||
124 | '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/ | ||
125 | '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/ | ||
126 | '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/ | ||
127 | '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/ | ||
128 | '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/ | ||
129 | '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/ | ||
130 | '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/ | ||
131 | '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/ | ||
132 | '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/ | ||
133 | '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/ | ||
134 | '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/ | ||
135 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/ | ||
136 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/ | ||
137 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/ | ||
138 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/ | ||
139 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/ | ||
140 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/ | ||
141 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/ | ||
142 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/ | ||
143 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/ | ||
144 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/ | ||
145 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/ | ||
146 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/ | ||
147 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/ | ||
148 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/ | ||
149 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/ | ||
150 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/ | ||
151 | }; | ||
152 | unsigned char buf[2 * BUFSIZ]; | ||
153 | |||
154 | while (1) { | ||
155 | int last_data = 0; | ||
156 | unsigned char *p; | ||
157 | |||
158 | if (fgets (buf, sizeof(buf), stdin) == NULL) { | ||
159 | errorMsg("%s: Short file\n", inname); | ||
160 | return FALSE; | ||
161 | } | ||
162 | p = buf; | ||
163 | |||
164 | if (memcmp (buf, "====", 4) == 0) | ||
165 | break; | ||
166 | if (last_data != 0) { | ||
167 | errorMsg("%s: data following `=' padding character\n", inname); | ||
168 | return FALSE; | ||
169 | } | ||
170 | |||
171 | /* The following implementation of the base64 decoding might look | ||
172 | a bit clumsy but I only try to follow the POSIX standard: | ||
173 | ``All line breaks or other characters not found in the table | ||
174 | [with base64 characters] shall be ignored by decoding | ||
175 | software.'' */ | ||
176 | while (*p != '\n') { | ||
177 | char c1, c2, c3; | ||
178 | |||
179 | while ((b64_tab[*p] & '\100') != 0) | ||
180 | if (*p == '\n' || *p++ == '=') | ||
181 | break; | ||
182 | if (*p == '\n') | ||
183 | /* This leaves the loop. */ | ||
184 | continue; | ||
185 | c1 = b64_tab[*p++]; | ||
186 | |||
187 | while ((b64_tab[*p] & '\100') != 0) | ||
188 | if (*p == '\n' || *p++ == '=') { | ||
189 | errorMsg("%s: illegal line\n", inname); | ||
190 | return FALSE; | ||
191 | } | ||
192 | c2 = b64_tab[*p++]; | ||
193 | |||
194 | while (b64_tab[*p] == '\177') | ||
195 | if (*p++ == '\n') { | ||
196 | errorMsg("%s: illegal line\n", inname); | ||
197 | return FALSE; | ||
198 | } | ||
199 | if (*p == '=') { | ||
200 | putchar (c1 << 2 | c2 >> 4); | ||
201 | last_data = 1; | ||
202 | break; | ||
203 | } | ||
204 | c3 = b64_tab[*p++]; | ||
205 | |||
206 | while (b64_tab[*p] == '\177') | ||
207 | if (*p++ == '\n') { | ||
208 | errorMsg("%s: illegal line\n", inname); | ||
209 | return FALSE; | ||
210 | } | ||
211 | putchar (c1 << 2 | c2 >> 4); | ||
212 | putchar (c2 << 4 | c3 >> 2); | ||
213 | if (*p == '=') { | ||
214 | last_data = 1; | ||
215 | break; | ||
216 | } | ||
217 | else | ||
218 | putchar (c3 << 6 | b64_tab[*p++]); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | return TRUE; | ||
223 | } | ||
224 | |||
225 | static int decode (const char *inname, | ||
226 | const char *forced_outname) | ||
227 | { | ||
228 | struct passwd *pw; | ||
229 | register int n; | ||
230 | register char *p; | ||
231 | int mode, n1; | ||
232 | char buf[2 * BUFSIZ]; | ||
233 | char *outname; | ||
234 | int do_base64 = 0; | ||
235 | |||
236 | /* Search for header line. */ | ||
237 | |||
238 | while (1) { | ||
239 | if (fgets (buf, sizeof (buf), stdin) == NULL) { | ||
240 | errorMsg("%s: No `begin' line\n", inname); | ||
241 | return FALSE; | ||
242 | } | ||
243 | |||
244 | if (strncmp (buf, "begin", 5) == 0) { | ||
245 | if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) { | ||
246 | do_base64 = 1; | ||
247 | break; | ||
248 | } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2) | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* If the output file name is given on the command line this rules. */ | ||
254 | if (forced_outname != NULL) | ||
255 | outname = (char *) forced_outname; | ||
256 | else { | ||
257 | /* Handle ~user/file format. */ | ||
258 | if (buf[0] != '~') | ||
259 | outname = buf; | ||
260 | else { | ||
261 | p = buf + 1; | ||
262 | while (*p != '/') | ||
263 | ++p; | ||
264 | if (*p == '\0') { | ||
265 | errorMsg("%s: Illegal ~user\n", inname); | ||
266 | return FALSE; | ||
267 | } | ||
268 | *p++ = '\0'; | ||
269 | pw = getpwnam (buf + 1); | ||
270 | if (pw == NULL) { | ||
271 | errorMsg("%s: No user `%s'\n", inname, buf + 1); | ||
272 | return FALSE; | ||
273 | } | ||
274 | n = strlen (pw->pw_dir); | ||
275 | n1 = strlen (p); | ||
276 | outname = (char *) alloca ((size_t) (n + n1 + 2)); | ||
277 | memcpy (outname + n + 1, p, (size_t) (n1 + 1)); | ||
278 | memcpy (outname, pw->pw_dir, (size_t) n); | ||
279 | outname[n] = '/'; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* Create output file and set mode. */ | ||
284 | if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0 | ||
285 | && (freopen (outname, "w", stdout) == NULL | ||
286 | || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | ||
287 | )) { | ||
288 | errorMsg("uudeoce %s: %s %s\n", outname, inname, strerror(errno)); /* */ | ||
289 | return FALSE; | ||
290 | } | ||
291 | |||
292 | /* We differenciate decoding standard UU encoding and base64. A | ||
293 | common function would only slow down the program. */ | ||
294 | |||
295 | /* For each input line: */ | ||
296 | if (do_base64) | ||
297 | return read_base64 (inname); | ||
298 | else | ||
299 | return read_stduu (inname); | ||
300 | } | ||
301 | |||
302 | static const char uudecode_usage[] = | ||
303 | "uudecode [FILE]...\n" | ||
304 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
305 | "\nUudecode a file that is uuencoded.\n\n" | ||
306 | "Options:\n" | ||
307 | "\t-o FILE\tdirect output to FILE\n" | ||
308 | #endif | ||
309 | ; | ||
310 | |||
311 | int uudecode_main (int argc, | ||
312 | char **argv) | ||
313 | { | ||
314 | int opt; | ||
315 | int exit_status; | ||
316 | const char *outname; | ||
317 | outname = NULL; | ||
318 | |||
319 | while ((opt = getopt(argc, argv, "o:")) != EOF) { | ||
320 | switch (opt) { | ||
321 | case 0: | ||
322 | break; | ||
323 | |||
324 | case 'o': | ||
325 | outname = optarg; | ||
326 | break; | ||
327 | |||
328 | default: | ||
329 | usage(uudecode_usage); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | if (optind == argc) | ||
334 | exit_status = decode ("stdin", outname) == 0 ? TRUE : FALSE; | ||
335 | else { | ||
336 | exit_status = TRUE; | ||
337 | do { | ||
338 | if (freopen (argv[optind], "r", stdin) != NULL) { | ||
339 | if (decode (argv[optind], outname) != 0) | ||
340 | exit_status = FALSE; | ||
341 | } else { | ||
342 | errorMsg("uudecode: %s: %s\n", argv[optind], strerror(errno)); | ||
343 | exit_status = FALSE; | ||
344 | } | ||
345 | optind++; | ||
346 | } | ||
347 | while (optind < argc); | ||
348 | } | ||
349 | exit(exit_status); | ||
350 | } | ||
diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c new file mode 100644 index 000000000..91136b3e6 --- /dev/null +++ b/coreutils/uuencode.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* uuencode.c -- uuencode utility. | ||
2 | * Copyright (C) 1994, 1995 Free Software Foundation, Inc. | ||
3 | * | ||
4 | * This product is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2, or (at your option) | ||
7 | * any later version. | ||
8 | * | ||
9 | * This product is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this product; see the file COPYING. If not, write to | ||
16 | * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | ||
17 | * 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* Copyright (c) 1983 Regents of the University of California. | ||
21 | * All rights reserved. | ||
22 | * | ||
23 | * Redistribution and use in source and binary forms, with or without | ||
24 | * modification, are permitted provided that the following conditions | ||
25 | * are met: | ||
26 | * 1. Redistributions of source code must retain the above copyright | ||
27 | * notice, this list of conditions and the following disclaimer. | ||
28 | * 2. Redistributions in binary form must reproduce the above copyright | ||
29 | * notice, this list of conditions and the following disclaimer in the | ||
30 | * documentation and/or other materials provided with the distribution. | ||
31 | * 3. All advertising materials mentioning features or use of this software | ||
32 | * must display the following acknowledgement: | ||
33 | * This product includes software developed by the University of | ||
34 | * California, Berkeley and its contributors. | ||
35 | * 4. Neither the name of the University nor the names of its contributors | ||
36 | * may be used to endorse or promote products derived from this software | ||
37 | * without specific prior written permission. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
49 | * SUCH DAMAGE. | ||
50 | */ | ||
51 | |||
52 | /* Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. */ | ||
53 | /* Hacked to work with BusyBox by Alfred M. Szmidt */ | ||
54 | |||
55 | #include "internal.h" | ||
56 | |||
57 | #include <stdio.h> | ||
58 | #include <errno.h> | ||
59 | #include <pwd.h> | ||
60 | |||
61 | #define RW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | ||
62 | |||
63 | static void encode __P ((void)); | ||
64 | |||
65 | /* Pointer to the translation table we currently use. */ | ||
66 | const char *trans_ptr; | ||
67 | |||
68 | /* The two currently defined translation tables. The first is the | ||
69 | standard uuencoding, the second is base64 encoding. */ | ||
70 | const char uu_std[64] = { | ||
71 | '`', '!', '"', '#', '$', '%', '&', '\'', | ||
72 | '(', ')', '*', '+', ',', '-', '.', '/', | ||
73 | '0', '1', '2', '3', '4', '5', '6', '7', | ||
74 | '8', '9', ':', ';', '<', '=', '>', '?', | ||
75 | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', | ||
76 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', | ||
77 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', | ||
78 | 'X', 'Y', 'Z', '[', '\\', ']', '^', '_' | ||
79 | }; | ||
80 | |||
81 | const char uu_base64[64] = { | ||
82 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', | ||
83 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | ||
84 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', | ||
85 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', | ||
86 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', | ||
87 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', | ||
88 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', | ||
89 | '4', '5', '6', '7', '8', '9', '+', '/' | ||
90 | }; | ||
91 | |||
92 | /* ENC is the basic 1 character encoding function to make a char printing. */ | ||
93 | #define ENC(Char) (trans_ptr[(Char) & 077]) | ||
94 | |||
95 | /* Copy from IN to OUT, encoding as you go along. */ | ||
96 | static void encode() | ||
97 | { | ||
98 | register int ch, n; | ||
99 | char *p = NULL; | ||
100 | char buf[80]; | ||
101 | |||
102 | while (1) { | ||
103 | n = 0; | ||
104 | do { | ||
105 | register int m = fread (buf, 1, 45 - n, stdin); | ||
106 | if (m == 0) | ||
107 | break; | ||
108 | n += m; | ||
109 | } | ||
110 | while (n < 45); | ||
111 | |||
112 | if (n == 0) | ||
113 | break; | ||
114 | |||
115 | if (trans_ptr == uu_std) | ||
116 | if (putchar (ENC (n)) == EOF) | ||
117 | break; | ||
118 | for (p = buf; n > 2; n -= 3, p += 3) { | ||
119 | ch = *p >> 2; | ||
120 | ch = ENC (ch); | ||
121 | if (putchar (ch) == EOF) | ||
122 | break; | ||
123 | ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017); | ||
124 | ch = ENC (ch); | ||
125 | if (putchar (ch) == EOF) | ||
126 | break; | ||
127 | ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); | ||
128 | ch = ENC (ch); | ||
129 | if (putchar (ch) == EOF) | ||
130 | break; | ||
131 | ch = p[2] & 077; | ||
132 | ch = ENC (ch); | ||
133 | if (putchar (ch) == EOF) | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | if (n != 0) | ||
138 | break; | ||
139 | |||
140 | if (putchar ('\n') == EOF) | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | while (n != 0) { | ||
145 | char c1 = *p; | ||
146 | char c2 = n == 1 ? 0 : p[1]; | ||
147 | |||
148 | ch = c1 >> 2; | ||
149 | ch = ENC (ch); | ||
150 | if (putchar (ch) == EOF) | ||
151 | break; | ||
152 | |||
153 | ch = ((c1 << 4) & 060) | ((c2 >> 4) & 017); | ||
154 | ch = ENC (ch); | ||
155 | if (putchar (ch) == EOF) | ||
156 | break; | ||
157 | |||
158 | if (n == 1) | ||
159 | ch = trans_ptr == uu_std ? ENC ('\0') : '='; | ||
160 | else { | ||
161 | ch = (c2 << 2) & 074; | ||
162 | ch = ENC (ch); | ||
163 | } | ||
164 | if (putchar (ch) == EOF) | ||
165 | break; | ||
166 | ch = trans_ptr == uu_std ? ENC ('\0') : '='; | ||
167 | if (putchar (ch) == EOF) | ||
168 | break; | ||
169 | putchar ('\n'); | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | if (ferror (stdin)) | ||
174 | errorMsg("Read error\n"); | ||
175 | |||
176 | if (trans_ptr == uu_std) { | ||
177 | putchar (ENC ('\0')); | ||
178 | putchar ('\n'); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | static const char uuencode_usage[] = | ||
183 | "uuencode [OPTION] [INFILE] REMOTEFILE\n" | ||
184 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
185 | "\nUuencode a file.\n\n" | ||
186 | "Options:\n" | ||
187 | "\t-m\tuse base64 encoding as of RFC1521\n" | ||
188 | #endif | ||
189 | ; | ||
190 | |||
191 | int uuencode_main (int argc, | ||
192 | char **argv) | ||
193 | { | ||
194 | int opt; | ||
195 | struct stat sb; | ||
196 | int mode; | ||
197 | |||
198 | trans_ptr = uu_std; /* Standard encoding is old uu format */ | ||
199 | |||
200 | /* Parse any options */ | ||
201 | while ((opt = getopt (argc, argv, "m")) != EOF) { | ||
202 | switch (opt) { | ||
203 | case 'm': | ||
204 | trans_ptr = uu_base64; | ||
205 | break; | ||
206 | |||
207 | case 0: | ||
208 | break; | ||
209 | |||
210 | default: | ||
211 | usage(uuencode_usage); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | switch (argc - optind) { | ||
216 | case 2: | ||
217 | /* Optional first argument is input file. */ | ||
218 | if (!freopen (argv[optind], "r", stdin) || fstat (fileno (stdin), &sb)) { | ||
219 | errorMsg("uuencode: %s: %s\n", argv[optind], strerror(errno)); | ||
220 | exit FALSE; | ||
221 | } | ||
222 | mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); | ||
223 | optind++; | ||
224 | break; | ||
225 | |||
226 | case 1: | ||
227 | mode = RW & ~umask (RW); | ||
228 | break; | ||
229 | |||
230 | case 0: | ||
231 | default: | ||
232 | usage(uuencode_usage); | ||
233 | } | ||
234 | |||
235 | printf("begin%s %o %s\n", trans_ptr == uu_std ? "" : "-base64", | ||
236 | mode, argv[optind]); | ||
237 | encode(); | ||
238 | printf(trans_ptr == uu_std ? "end\n" : "====\n"); | ||
239 | if (ferror (stdout)) { | ||
240 | errorMsg("Write error\n"); | ||
241 | exit FALSE; | ||
242 | } | ||
243 | exit TRUE; | ||
244 | } | ||
@@ -51,7 +51,6 @@ static int df(char *device, const char *mountPoint) | |||
51 | blocks_used = s.f_blocks - s.f_bfree; | 51 | blocks_used = s.f_blocks - s.f_bfree; |
52 | blocks_percent_used = (long) | 52 | blocks_percent_used = (long) |
53 | (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); | 53 | (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); |
54 | /* Note that if /etc/fstab is missing, libc can't fix up /dev/root for us */ | ||
55 | if (strcmp(device, "/dev/root") == 0) { | 54 | if (strcmp(device, "/dev/root") == 0) { |
56 | /* Adjusts device to be the real root device, | 55 | /* Adjusts device to be the real root device, |
57 | * or leaves device alone if it can't find it */ | 56 | * or leaves device alone if it can't find it */ |
diff --git a/docs/busybox.pod b/docs/busybox.pod index 03875a4d7..58576bb56 100644 --- a/docs/busybox.pod +++ b/docs/busybox.pod | |||
@@ -59,11 +59,12 @@ ar, basename, cat, chgrp, chmod, chown, chroot, clear, chvt, cp, cut, date, dd, | |||
59 | df, dirname, dmesg, du, dutmp, echo, false, fbset, fdflush, find, free, | 59 | df, dirname, dmesg, du, dutmp, echo, false, fbset, fdflush, find, free, |
60 | freeramdisk, deallocvt, fsck.minix, grep, gunzip, gzip, halt, head, hostid, | 60 | freeramdisk, deallocvt, fsck.minix, grep, gunzip, gzip, halt, head, hostid, |
61 | hostname, id, init, kill, killall, length, ln, loadacm, loadfont, loadkmap, | 61 | hostname, id, init, kill, killall, length, ln, loadacm, loadfont, loadkmap, |
62 | logger, logname, ls, lsmod, makedevs, math, mkdir, mkfifo, mkfs.minix, mknod, | 62 | logger, logname, ls, lsmod, makedevs, math, md5sum, mkdir, mkfifo, mkfs.minix, |
63 | mkswap, mktemp, nc, more, mount, mt, mv, nslookup, ping, poweroff, printf, ps, | 63 | mknod, mkswap, mktemp, nc, more, mount, mt, mv, nslookup, ping, poweroff, |
64 | pwd, reboot, rm, rmdir, rmmod, sed, setkeycodes, sh, sfdisk, sleep, sort, sync, | 64 | printf, ps, pwd, reboot, rm, rmdir, rmmod, sed, setkeycodes, sh, sfdisk, sleep, |
65 | syslogd, swapon, swapoff, tail, tar, test, tee, touch, tr, true, tty, umount, | 65 | sort, sync, syslogd, swapon, swapoff, tail, tar, test, tee, touch, tr, true, |
66 | uname, uniq, update, uptime, usleep, wc, whoami, yes, zcat, [ | 66 | tty, umount, uname, uniq, update, uptime, usleep, uudecode, uuencode, wc, |
67 | whoami, yes, zcat, [ | ||
67 | 68 | ||
68 | ------------------------------- | 69 | ------------------------------- |
69 | 70 | ||
@@ -1034,6 +1035,35 @@ Example: | |||
1034 | 1035 | ||
1035 | ------------------------------- | 1036 | ------------------------------- |
1036 | 1037 | ||
1038 | =item md5sum | ||
1039 | |||
1040 | Usage: md5sum [OPTION] [file ...] | ||
1041 | |||
1042 | Print or check MD5 checksums. | ||
1043 | |||
1044 | Options: | ||
1045 | |||
1046 | -b read files in binary mode | ||
1047 | -c check MD5 sums against given list | ||
1048 | -t read files in text mode (default) | ||
1049 | -g read a string | ||
1050 | |||
1051 | The following two options are useful only when verifying checksums: | ||
1052 | |||
1053 | -s don't output anything, status code shows success | ||
1054 | -w warn about improperly formated MD5 checksum lines | ||
1055 | |||
1056 | Example: | ||
1057 | |||
1058 | $ md5sum busybox | ||
1059 | 6fd11e98b98a58f64ff3398d7b324003 busybox | ||
1060 | $ md5sum -c - | ||
1061 | 6fd11e98b98a58f64ff3398d7b324003 busybox | ||
1062 | busybox: OK | ||
1063 | ^D | ||
1064 | |||
1065 | ------------------------------- | ||
1066 | |||
1037 | =item mkdir | 1067 | =item mkdir |
1038 | 1068 | ||
1039 | Usage: mkdir [OPTION] DIRECTORY... | 1069 | Usage: mkdir [OPTION] DIRECTORY... |
@@ -1724,6 +1754,45 @@ Example: | |||
1724 | 1754 | ||
1725 | ------------------------------- | 1755 | ------------------------------- |
1726 | 1756 | ||
1757 | =item uuencode | ||
1758 | |||
1759 | Usage: uuencode [OPTION] [INFILE] REMOTEFILE | ||
1760 | |||
1761 | Uuencode a file. | ||
1762 | |||
1763 | Options: | ||
1764 | |||
1765 | -m use base64 encoding as of RFC1521 | ||
1766 | |||
1767 | Example: | ||
1768 | |||
1769 | $ uuencode busybox busybox | ||
1770 | begin 755 busybox | ||
1771 | M?T5,1@$!`0````````````(``P`!````L+@$"#0```!0N@,``````#0`(``& | ||
1772 | ..... | ||
1773 | $ uudecode busybox busybox > busybox.uu | ||
1774 | $ | ||
1775 | |||
1776 | ------------------------------- | ||
1777 | |||
1778 | =item uudecode | ||
1779 | |||
1780 | Usage: uudecode [OPTION] [FILE] | ||
1781 | |||
1782 | Uudecode a uuencoded file | ||
1783 | |||
1784 | Options: | ||
1785 | |||
1786 | -o FILE direct output to FILE | ||
1787 | |||
1788 | Example: | ||
1789 | |||
1790 | $ uudecode -o busybox busybox.uu | ||
1791 | $ ls -l busybox | ||
1792 | -rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox | ||
1793 | |||
1794 | ------------------------------- | ||
1795 | |||
1727 | =item umount | 1796 | =item umount |
1728 | 1797 | ||
1729 | Usage: umount [flags] filesystem|directory | 1798 | Usage: umount [flags] filesystem|directory |
@@ -1952,4 +2021,4 @@ Enrique Zanardi <ezanardi@ull.es> | |||
1952 | 2021 | ||
1953 | =cut | 2022 | =cut |
1954 | 2023 | ||
1955 | # $Id: busybox.pod,v 1.40 2000/06/12 23:04:55 beppu Exp $ | 2024 | # $Id: busybox.pod,v 1.41 2000/06/13 06:54:53 andersen Exp $ |
diff --git a/internal.h b/internal.h index 26248621e..e25c14460 100644 --- a/internal.h +++ b/internal.h | |||
@@ -149,6 +149,7 @@ extern int ls_main(int argc, char** argv); | |||
149 | extern int lsmod_main(int argc, char** argv); | 149 | extern int lsmod_main(int argc, char** argv); |
150 | extern int makedevs_main(int argc, char** argv); | 150 | extern int makedevs_main(int argc, char** argv); |
151 | extern int math_main(int argc, char** argv); | 151 | extern int math_main(int argc, char** argv); |
152 | extern int md5sum_main(int argc, char** argv); | ||
152 | extern int mkdir_main(int argc, char** argv); | 153 | extern int mkdir_main(int argc, char** argv); |
153 | extern int mkfifo_main(int argc, char **argv); | 154 | extern int mkfifo_main(int argc, char **argv); |
154 | extern int mkfs_minix_main(int argc, char **argv); | 155 | extern int mkfs_minix_main(int argc, char **argv); |
@@ -189,6 +190,8 @@ extern int true_main(int argc, char** argv); | |||
189 | extern int tput_main(int argc, char** argv); | 190 | extern int tput_main(int argc, char** argv); |
190 | extern int tryopen_main(int argc, char** argv); | 191 | extern int tryopen_main(int argc, char** argv); |
191 | extern int tty_main(int argc, char** argv); | 192 | extern int tty_main(int argc, char** argv); |
193 | extern int uuencode_main(int argc, char** argv); | ||
194 | extern int uudecode_main(int argc, char** argv); | ||
192 | extern int umount_main(int argc, char** argv); | 195 | extern int umount_main(int argc, char** argv); |
193 | extern int uname_main(int argc, char** argv); | 196 | extern int uname_main(int argc, char** argv); |
194 | extern int uptime_main(int argc, char** argv); | 197 | extern int uptime_main(int argc, char** argv); |
diff --git a/md5sum.c b/md5sum.c new file mode 100644 index 000000000..ffa9e6bce --- /dev/null +++ b/md5sum.c | |||
@@ -0,0 +1,1013 @@ | |||
1 | /* 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 | |||
23 | #include "internal.h" | ||
24 | #include <stdio.h> | ||
25 | #include <errno.h> | ||
26 | #include <ctype.h> | ||
27 | |||
28 | //---------------------------------------------------------------------------- | ||
29 | //--------md5.c | ||
30 | //---------------------------------------------------------------------------- | ||
31 | |||
32 | /* md5.c - Functions to compute MD5 message digest of files or memory blocks | ||
33 | * according to the definition of MD5 in RFC 1321 from April 1992. | ||
34 | * Copyright (C) 1995, 1996 Free Software Foundation, Inc. | ||
35 | * | ||
36 | * NOTE: The canonical source of this file is maintained with the GNU C | ||
37 | * Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. | ||
38 | * | ||
39 | * This program is free software; you can redistribute it and/or modify it | ||
40 | * under the terms of the GNU General Public License as published by the | ||
41 | * Free Software Foundation; either version 2, or (at your option) any | ||
42 | * later version. | ||
43 | * | ||
44 | * This program is distributed in the hope that it will be useful, | ||
45 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
46 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
47 | * GNU General Public License for more details. | ||
48 | * | ||
49 | * You should have received a copy of the GNU General Public License | ||
50 | * along with this program; if not, write to the Free Software Foundation, | ||
51 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
52 | */ | ||
53 | |||
54 | /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ | ||
55 | |||
56 | #include <sys/types.h> | ||
57 | #include <stdlib.h> | ||
58 | #include <string.h> | ||
59 | #include <endian.h> | ||
60 | |||
61 | #include "internal.h" | ||
62 | //---------------------------------------------------------------------------- | ||
63 | //--------md5.h | ||
64 | //---------------------------------------------------------------------------- | ||
65 | |||
66 | /* md5.h - Declaration of functions and data types used for MD5 sum | ||
67 | computing library functions. | ||
68 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. | ||
69 | NOTE: The canonical source of this file is maintained with the GNU C | ||
70 | Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. | ||
71 | |||
72 | This program is free software; you can redistribute it and/or modify it | ||
73 | under the terms of the GNU General Public License as published by the | ||
74 | Free Software Foundation; either version 2, or (at your option) any | ||
75 | later version. | ||
76 | |||
77 | This program is distributed in the hope that it will be useful, | ||
78 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
79 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
80 | GNU General Public License for more details. | ||
81 | |||
82 | You should have received a copy of the GNU General Public License | ||
83 | along with this program; if not, write to the Free Software Foundation, | ||
84 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
85 | |||
86 | #ifndef _MD5_H | ||
87 | #define _MD5_H 1 | ||
88 | |||
89 | #include <stdio.h> | ||
90 | |||
91 | #if defined HAVE_LIMITS_H || _LIBC | ||
92 | # include <limits.h> | ||
93 | #endif | ||
94 | |||
95 | /* The following contortions are an attempt to use the C preprocessor | ||
96 | to determine an unsigned integral type that is 32 bits wide. An | ||
97 | alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but | ||
98 | doing that would require that the configure script compile and *run* | ||
99 | the resulting executable. Locally running cross-compiled executables | ||
100 | is usually not possible. */ | ||
101 | |||
102 | #ifdef _LIBC | ||
103 | # include <sys/types.h> | ||
104 | typedef u_int32_t md5_uint32; | ||
105 | #else | ||
106 | # if defined __STDC__ && __STDC__ | ||
107 | # define UINT_MAX_32_BITS 4294967295U | ||
108 | # else | ||
109 | # define UINT_MAX_32_BITS 0xFFFFFFFF | ||
110 | # endif | ||
111 | |||
112 | /* If UINT_MAX isn't defined, assume it's a 32-bit type. | ||
113 | This should be valid for all systems GNU cares about because | ||
114 | that doesn't include 16-bit systems, and only modern systems | ||
115 | (that certainly have <limits.h>) have 64+-bit integral types. */ | ||
116 | |||
117 | # ifndef UINT_MAX | ||
118 | # define UINT_MAX UINT_MAX_32_BITS | ||
119 | # endif | ||
120 | |||
121 | # if UINT_MAX == UINT_MAX_32_BITS | ||
122 | typedef unsigned int md5_uint32; | ||
123 | # else | ||
124 | # if USHRT_MAX == UINT_MAX_32_BITS | ||
125 | typedef unsigned short md5_uint32; | ||
126 | # else | ||
127 | # if ULONG_MAX == UINT_MAX_32_BITS | ||
128 | typedef unsigned long md5_uint32; | ||
129 | # else | ||
130 | /* The following line is intended to evoke an error. | ||
131 | Using #error is not portable enough. */ | ||
132 | "Cannot determine unsigned 32-bit data type." | ||
133 | # endif | ||
134 | # endif | ||
135 | # endif | ||
136 | #endif | ||
137 | |||
138 | #undef __P | ||
139 | #if defined (__STDC__) && __STDC__ | ||
140 | #define __P(x) x | ||
141 | #else | ||
142 | #define __P(x) () | ||
143 | #endif | ||
144 | |||
145 | /* Structure to save state of computation between the single steps. */ | ||
146 | struct md5_ctx | ||
147 | { | ||
148 | md5_uint32 A; | ||
149 | md5_uint32 B; | ||
150 | md5_uint32 C; | ||
151 | md5_uint32 D; | ||
152 | |||
153 | md5_uint32 total[2]; | ||
154 | md5_uint32 buflen; | ||
155 | char buffer[128]; | ||
156 | }; | ||
157 | |||
158 | /* | ||
159 | * The following three functions are build up the low level used in | ||
160 | * the functions `md5_stream' and `md5_buffer'. | ||
161 | */ | ||
162 | |||
163 | /* Initialize structure containing state of computation. | ||
164 | (RFC 1321, 3.3: Step 3) */ | ||
165 | extern void md5_init_ctx __P ((struct md5_ctx *ctx)); | ||
166 | |||
167 | /* Starting with the result of former calls of this function (or the | ||
168 | initialization function update the context for the next LEN bytes | ||
169 | starting at BUFFER. | ||
170 | It is necessary that LEN is a multiple of 64!!! */ | ||
171 | extern void md5_process_block __P ((const void *buffer, size_t len, | ||
172 | struct md5_ctx *ctx)); | ||
173 | |||
174 | /* Starting with the result of former calls of this function (or the | ||
175 | initialization function update the context for the next LEN bytes | ||
176 | starting at BUFFER. | ||
177 | It is NOT required that LEN is a multiple of 64. */ | ||
178 | extern void md5_process_bytes __P ((const void *buffer, size_t len, | ||
179 | struct md5_ctx *ctx)); | ||
180 | |||
181 | /* Process the remaining bytes in the buffer and put result from CTX | ||
182 | in first 16 bytes following RESBUF. The result is always in little | ||
183 | endian byte order, so that a byte-wise output yields to the wanted | ||
184 | ASCII representation of the message digest. | ||
185 | |||
186 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
187 | aligned for a 32 bits value. */ | ||
188 | extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); | ||
189 | |||
190 | |||
191 | /* Put result from CTX in first 16 bytes following RESBUF. The result is | ||
192 | always in little endian byte order, so that a byte-wise output yields | ||
193 | to the wanted ASCII representation of the message digest. | ||
194 | |||
195 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
196 | aligned for a 32 bits value. */ | ||
197 | extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); | ||
198 | |||
199 | |||
200 | /* Compute MD5 message digest for bytes read from STREAM. The | ||
201 | resulting message digest number will be written into the 16 bytes | ||
202 | beginning at RESBLOCK. */ | ||
203 | extern int md5_stream __P ((FILE *stream, void *resblock)); | ||
204 | |||
205 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The | ||
206 | result is always in little endian byte order, so that a byte-wise | ||
207 | output yields to the wanted ASCII representation of the message | ||
208 | digest. */ | ||
209 | extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); | ||
210 | |||
211 | #endif | ||
212 | |||
213 | //---------------------------------------------------------------------------- | ||
214 | //--------end of md5.h | ||
215 | //---------------------------------------------------------------------------- | ||
216 | |||
217 | #define SWAP(n) (n) | ||
218 | |||
219 | /* This array contains the bytes used to pad the buffer to the next | ||
220 | 64-byte boundary. (RFC 1321, 3.1: Step 1) */ | ||
221 | static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; | ||
222 | |||
223 | /* Initialize structure containing state of computation. | ||
224 | (RFC 1321, 3.3: Step 3) */ | ||
225 | void md5_init_ctx(struct md5_ctx *ctx) | ||
226 | { | ||
227 | ctx->A = 0x67452301; | ||
228 | ctx->B = 0xefcdab89; | ||
229 | ctx->C = 0x98badcfe; | ||
230 | ctx->D = 0x10325476; | ||
231 | |||
232 | ctx->total[0] = ctx->total[1] = 0; | ||
233 | ctx->buflen = 0; | ||
234 | } | ||
235 | |||
236 | /* Put result from CTX in first 16 bytes following RESBUF. The result | ||
237 | must be in little endian byte order. | ||
238 | |||
239 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
240 | aligned for a 32 bits value. */ | ||
241 | void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf) | ||
242 | { | ||
243 | ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A); | ||
244 | ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B); | ||
245 | ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C); | ||
246 | ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D); | ||
247 | |||
248 | return resbuf; | ||
249 | } | ||
250 | |||
251 | /* Process the remaining bytes in the internal buffer and the usual | ||
252 | prolog according to the standard and write the result to RESBUF. | ||
253 | |||
254 | IMPORTANT: On some systems it is required that RESBUF is correctly | ||
255 | aligned for a 32 bits value. */ | ||
256 | void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf) | ||
257 | { | ||
258 | /* Take yet unprocessed bytes into account. */ | ||
259 | md5_uint32 bytes = ctx->buflen; | ||
260 | size_t pad; | ||
261 | |||
262 | /* Now count remaining bytes. */ | ||
263 | ctx->total[0] += bytes; | ||
264 | if (ctx->total[0] < bytes) | ||
265 | ++ctx->total[1]; | ||
266 | |||
267 | pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; | ||
268 | memcpy(&ctx->buffer[bytes], fillbuf, pad); | ||
269 | |||
270 | /* Put the 64-bit file length in *bits* at the end of the buffer. */ | ||
271 | *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3); | ||
272 | *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] = | ||
273 | SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)); | ||
274 | |||
275 | /* Process last bytes. */ | ||
276 | md5_process_block(ctx->buffer, bytes + pad + 8, ctx); | ||
277 | |||
278 | return md5_read_ctx(ctx, resbuf); | ||
279 | } | ||
280 | |||
281 | /* Compute MD5 message digest for bytes read from STREAM. The | ||
282 | resulting message digest number will be written into the 16 bytes | ||
283 | beginning at RESBLOCK. */ | ||
284 | int md5_stream(FILE *stream, void *resblock) | ||
285 | { | ||
286 | /* Important: BLOCKSIZE must be a multiple of 64. */ | ||
287 | #define BLOCKSIZE 4096 | ||
288 | struct md5_ctx ctx; | ||
289 | char buffer[BLOCKSIZE + 72]; | ||
290 | size_t sum; | ||
291 | |||
292 | /* Initialize the computation context. */ | ||
293 | md5_init_ctx(&ctx); | ||
294 | |||
295 | /* Iterate over full file contents. */ | ||
296 | while (1) { | ||
297 | /* We read the file in blocks of BLOCKSIZE bytes. One call of the | ||
298 | computation function processes the whole buffer so that with the | ||
299 | next round of the loop another block can be read. */ | ||
300 | size_t n; | ||
301 | sum = 0; | ||
302 | |||
303 | /* Read block. Take care for partial reads. */ | ||
304 | do { | ||
305 | n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream); | ||
306 | |||
307 | sum += n; | ||
308 | } | ||
309 | while (sum < BLOCKSIZE && n != 0); | ||
310 | if (n == 0 && ferror(stream)) | ||
311 | return 1; | ||
312 | |||
313 | /* If end of file is reached, end the loop. */ | ||
314 | if (n == 0) | ||
315 | break; | ||
316 | |||
317 | /* Process buffer with BLOCKSIZE bytes. Note that | ||
318 | BLOCKSIZE % 64 == 0 | ||
319 | */ | ||
320 | md5_process_block(buffer, BLOCKSIZE, &ctx); | ||
321 | } | ||
322 | |||
323 | /* Add the last bytes if necessary. */ | ||
324 | if (sum > 0) | ||
325 | md5_process_bytes(buffer, sum, &ctx); | ||
326 | |||
327 | /* Construct result in desired memory. */ | ||
328 | md5_finish_ctx(&ctx, resblock); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The | ||
333 | result is always in little endian byte order, so that a byte-wise | ||
334 | output yields to the wanted ASCII representation of the message | ||
335 | digest. */ | ||
336 | void *md5_buffer(const char *buffer, size_t len, void *resblock) | ||
337 | { | ||
338 | struct md5_ctx ctx; | ||
339 | |||
340 | /* Initialize the computation context. */ | ||
341 | md5_init_ctx(&ctx); | ||
342 | |||
343 | /* Process whole buffer but last len % 64 bytes. */ | ||
344 | md5_process_bytes(buffer, len, &ctx); | ||
345 | |||
346 | /* Put result in desired memory area. */ | ||
347 | return md5_finish_ctx(&ctx, resblock); | ||
348 | } | ||
349 | |||
350 | void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx) | ||
351 | { | ||
352 | /* When we already have some bits in our internal buffer concatenate | ||
353 | both inputs first. */ | ||
354 | if (ctx->buflen != 0) { | ||
355 | size_t left_over = ctx->buflen; | ||
356 | size_t add = 128 - left_over > len ? len : 128 - left_over; | ||
357 | |||
358 | memcpy(&ctx->buffer[left_over], buffer, add); | ||
359 | ctx->buflen += add; | ||
360 | |||
361 | if (left_over + add > 64) { | ||
362 | md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx); | ||
363 | /* The regions in the following copy operation cannot overlap. */ | ||
364 | memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], | ||
365 | (left_over + add) & 63); | ||
366 | ctx->buflen = (left_over + add) & 63; | ||
367 | } | ||
368 | |||
369 | buffer = (const char *) buffer + add; | ||
370 | len -= add; | ||
371 | } | ||
372 | |||
373 | /* Process available complete blocks. */ | ||
374 | if (len > 64) { | ||
375 | md5_process_block(buffer, len & ~63, ctx); | ||
376 | buffer = (const char *) buffer + (len & ~63); | ||
377 | len &= 63; | ||
378 | } | ||
379 | |||
380 | /* Move remaining bytes in internal buffer. */ | ||
381 | if (len > 0) { | ||
382 | memcpy(ctx->buffer, buffer, len); | ||
383 | ctx->buflen = len; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* These are the four functions used in the four steps of the MD5 algorithm | ||
388 | and defined in the RFC 1321. The first function is a little bit optimized | ||
389 | (as found in Colin Plumbs public domain implementation). */ | ||
390 | /* #define FF(b, c, d) ((b & c) | (~b & d)) */ | ||
391 | #define FF(b, c, d) (d ^ (b & (c ^ d))) | ||
392 | #define FG(b, c, d) FF (d, b, c) | ||
393 | #define FH(b, c, d) (b ^ c ^ d) | ||
394 | #define FI(b, c, d) (c ^ (b | ~d)) | ||
395 | |||
396 | /* Process LEN bytes of BUFFER, accumulating context into CTX. | ||
397 | It is assumed that LEN % 64 == 0. */ | ||
398 | void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx) | ||
399 | { | ||
400 | md5_uint32 correct_words[16]; | ||
401 | const md5_uint32 *words = buffer; | ||
402 | size_t nwords = len / sizeof(md5_uint32); | ||
403 | const md5_uint32 *endp = words + nwords; | ||
404 | md5_uint32 A = ctx->A; | ||
405 | md5_uint32 B = ctx->B; | ||
406 | md5_uint32 C = ctx->C; | ||
407 | md5_uint32 D = ctx->D; | ||
408 | |||
409 | /* First increment the byte count. RFC 1321 specifies the possible | ||
410 | length of the file up to 2^64 bits. Here we only compute the | ||
411 | number of bytes. Do a double word increment. */ | ||
412 | ctx->total[0] += len; | ||
413 | if (ctx->total[0] < len) | ||
414 | ++ctx->total[1]; | ||
415 | |||
416 | /* Process all bytes in the buffer with 64 bytes in each round of | ||
417 | the loop. */ | ||
418 | while (words < endp) { | ||
419 | md5_uint32 *cwp = correct_words; | ||
420 | md5_uint32 A_save = A; | ||
421 | md5_uint32 B_save = B; | ||
422 | md5_uint32 C_save = C; | ||
423 | md5_uint32 D_save = D; | ||
424 | |||
425 | /* First round: using the given function, the context and a constant | ||
426 | the next context is computed. Because the algorithms processing | ||
427 | unit is a 32-bit word and it is determined to work on words in | ||
428 | little endian byte order we perhaps have to change the byte order | ||
429 | before the computation. To reduce the work for the next steps | ||
430 | we store the swapped words in the array CORRECT_WORDS. */ | ||
431 | |||
432 | #define OP(a, b, c, d, s, T) \ | ||
433 | do \ | ||
434 | { \ | ||
435 | a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ | ||
436 | ++words; \ | ||
437 | CYCLIC (a, s); \ | ||
438 | a += b; \ | ||
439 | } \ | ||
440 | while (0) | ||
441 | |||
442 | /* It is unfortunate that C does not provide an operator for | ||
443 | cyclic rotation. Hope the C compiler is smart enough. */ | ||
444 | #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) | ||
445 | |||
446 | /* Before we start, one word to the strange constants. | ||
447 | They are defined in RFC 1321 as | ||
448 | |||
449 | T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 | ||
450 | */ | ||
451 | |||
452 | /* Round 1. */ | ||
453 | OP(A, B, C, D, 7, 0xd76aa478); | ||
454 | OP(D, A, B, C, 12, 0xe8c7b756); | ||
455 | OP(C, D, A, B, 17, 0x242070db); | ||
456 | OP(B, C, D, A, 22, 0xc1bdceee); | ||
457 | OP(A, B, C, D, 7, 0xf57c0faf); | ||
458 | OP(D, A, B, C, 12, 0x4787c62a); | ||
459 | OP(C, D, A, B, 17, 0xa8304613); | ||
460 | OP(B, C, D, A, 22, 0xfd469501); | ||
461 | OP(A, B, C, D, 7, 0x698098d8); | ||
462 | OP(D, A, B, C, 12, 0x8b44f7af); | ||
463 | OP(C, D, A, B, 17, 0xffff5bb1); | ||
464 | OP(B, C, D, A, 22, 0x895cd7be); | ||
465 | OP(A, B, C, D, 7, 0x6b901122); | ||
466 | OP(D, A, B, C, 12, 0xfd987193); | ||
467 | OP(C, D, A, B, 17, 0xa679438e); | ||
468 | OP(B, C, D, A, 22, 0x49b40821); | ||
469 | |||
470 | /* For the second to fourth round we have the possibly swapped words | ||
471 | in CORRECT_WORDS. Redefine the macro to take an additional first | ||
472 | argument specifying the function to use. */ | ||
473 | #undef OP | ||
474 | #define OP(f, a, b, c, d, k, s, T) \ | ||
475 | do \ | ||
476 | { \ | ||
477 | a += f (b, c, d) + correct_words[k] + T; \ | ||
478 | CYCLIC (a, s); \ | ||
479 | a += b; \ | ||
480 | } \ | ||
481 | while (0) | ||
482 | |||
483 | /* Round 2. */ | ||
484 | OP(FG, A, B, C, D, 1, 5, 0xf61e2562); | ||
485 | OP(FG, D, A, B, C, 6, 9, 0xc040b340); | ||
486 | OP(FG, C, D, A, B, 11, 14, 0x265e5a51); | ||
487 | OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); | ||
488 | OP(FG, A, B, C, D, 5, 5, 0xd62f105d); | ||
489 | OP(FG, D, A, B, C, 10, 9, 0x02441453); | ||
490 | OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); | ||
491 | OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); | ||
492 | OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); | ||
493 | OP(FG, D, A, B, C, 14, 9, 0xc33707d6); | ||
494 | OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); | ||
495 | OP(FG, B, C, D, A, 8, 20, 0x455a14ed); | ||
496 | OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); | ||
497 | OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); | ||
498 | OP(FG, C, D, A, B, 7, 14, 0x676f02d9); | ||
499 | OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); | ||
500 | |||
501 | /* Round 3. */ | ||
502 | OP(FH, A, B, C, D, 5, 4, 0xfffa3942); | ||
503 | OP(FH, D, A, B, C, 8, 11, 0x8771f681); | ||
504 | OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); | ||
505 | OP(FH, B, C, D, A, 14, 23, 0xfde5380c); | ||
506 | OP(FH, A, B, C, D, 1, 4, 0xa4beea44); | ||
507 | OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); | ||
508 | OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); | ||
509 | OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); | ||
510 | OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); | ||
511 | OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); | ||
512 | OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); | ||
513 | OP(FH, B, C, D, A, 6, 23, 0x04881d05); | ||
514 | OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); | ||
515 | OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); | ||
516 | OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); | ||
517 | OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); | ||
518 | |||
519 | /* Round 4. */ | ||
520 | OP(FI, A, B, C, D, 0, 6, 0xf4292244); | ||
521 | OP(FI, D, A, B, C, 7, 10, 0x432aff97); | ||
522 | OP(FI, C, D, A, B, 14, 15, 0xab9423a7); | ||
523 | OP(FI, B, C, D, A, 5, 21, 0xfc93a039); | ||
524 | OP(FI, A, B, C, D, 12, 6, 0x655b59c3); | ||
525 | OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); | ||
526 | OP(FI, C, D, A, B, 10, 15, 0xffeff47d); | ||
527 | OP(FI, B, C, D, A, 1, 21, 0x85845dd1); | ||
528 | OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); | ||
529 | OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); | ||
530 | OP(FI, C, D, A, B, 6, 15, 0xa3014314); | ||
531 | OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); | ||
532 | OP(FI, A, B, C, D, 4, 6, 0xf7537e82); | ||
533 | OP(FI, D, A, B, C, 11, 10, 0xbd3af235); | ||
534 | OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); | ||
535 | OP(FI, B, C, D, A, 9, 21, 0xeb86d391); | ||
536 | |||
537 | /* Add the starting values of the context. */ | ||
538 | A += A_save; | ||
539 | B += B_save; | ||
540 | C += C_save; | ||
541 | D += D_save; | ||
542 | } | ||
543 | |||
544 | /* Put checksum in context given as argument. */ | ||
545 | ctx->A = A; | ||
546 | ctx->B = B; | ||
547 | ctx->C = C; | ||
548 | ctx->D = D; | ||
549 | } | ||
550 | |||
551 | //---------------------------------------------------------------------------- | ||
552 | //--------end of md5.c | ||
553 | //---------------------------------------------------------------------------- | ||
554 | |||
555 | #define ISWHITE(c) ((c) == ' ' || (c) == '\t') | ||
556 | #define IN_CTYPE_DOMAIN(c) 1 | ||
557 | #define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) | ||
558 | #define STREQ(a, b) (strcmp ((a), (b)) == 0) | ||
559 | #define TOLOWER(Ch) tolower (Ch) | ||
560 | #define OPENOPTS(BINARY) "r" | ||
561 | |||
562 | /* The minimum length of a valid digest line in a file produced | ||
563 | by `md5sum FILE' and read by `md5sum -c'. This length does | ||
564 | not include any newline character at the end of a line. */ | ||
565 | #define MIN_DIGEST_LINE_LENGTH 35 /* 32 - message digest length | ||
566 | 2 - blank and binary indicator | ||
567 | 1 - minimum filename length */ | ||
568 | |||
569 | static int have_read_stdin; /* Nonzero if any of the files read were | ||
570 | the standard input. */ | ||
571 | |||
572 | static int status_only = 0; /* With -c, don't generate any output. | ||
573 | The exit code indicates success or failure */ | ||
574 | static int warn = 0; /* With -w, print a message to standard error warning | ||
575 | about each improperly formatted MD5 checksum line */ | ||
576 | |||
577 | static const char md5sum_usage[] = | ||
578 | "md5sum [OPTION] [FILE]...\n" | ||
579 | "or: md5sum [OPTION] -c [FILE]\n" | ||
580 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
581 | "\nPrint or check MD5 checksums.\n\n" | ||
582 | "Options:\n" | ||
583 | "With no FILE, or when FILE is -, read standard input.\n\n" | ||
584 | "\t-b\tread files in binary mode\n" | ||
585 | "\t-c\tcheck MD5 sums against given list\n" | ||
586 | "\t-t\tread files in text mode (default)\n" | ||
587 | "\t-g\tread a string\n" | ||
588 | "\nThe following two options are useful only when verifying checksums:\n" | ||
589 | "\t-s,\tdon't output anything, status code shows success\n" | ||
590 | "\t-w,\twarn about improperly formated MD5 checksum lines\n" | ||
591 | #endif | ||
592 | ; | ||
593 | |||
594 | static int split_3(char *s, | ||
595 | size_t s_len, | ||
596 | unsigned char **u, | ||
597 | int *binary, | ||
598 | char **w) | ||
599 | { | ||
600 | size_t i = 0; | ||
601 | int escaped_filename = 0; | ||
602 | |||
603 | while (ISWHITE(s[i])) | ||
604 | ++i; | ||
605 | |||
606 | /* The line must have at least 35 (36 if the first is a backslash) | ||
607 | more characters to contain correct message digest information. | ||
608 | Ignore this line if it is too short. */ | ||
609 | if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH | ||
610 | || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH))) | ||
611 | return FALSE; | ||
612 | |||
613 | if (s[i] == '\\') { | ||
614 | ++i; | ||
615 | escaped_filename = 1; | ||
616 | } | ||
617 | *u = (unsigned char *) &s[i]; | ||
618 | |||
619 | /* The first field has to be the 32-character hexadecimal | ||
620 | representation of the message digest. If it is not followed | ||
621 | immediately by a white space it's an error. */ | ||
622 | i += 32; | ||
623 | if (!ISWHITE(s[i])) | ||
624 | return FALSE; | ||
625 | |||
626 | s[i++] = '\0'; | ||
627 | |||
628 | if (s[i] != ' ' && s[i] != '*') | ||
629 | return FALSE; | ||
630 | *binary = (s[i++] == '*'); | ||
631 | |||
632 | /* All characters between the type indicator and end of line are | ||
633 | significant -- that includes leading and trailing white space. */ | ||
634 | *w = &s[i]; | ||
635 | |||
636 | if (escaped_filename) { | ||
637 | /* Translate each `\n' string in the file name to a NEWLINE, | ||
638 | and each `\\' string to a backslash. */ | ||
639 | |||
640 | char *dst = &s[i]; | ||
641 | |||
642 | while (i < s_len) { | ||
643 | switch (s[i]) { | ||
644 | case '\\': | ||
645 | if (i == s_len - 1) { | ||
646 | /* A valid line does not end with a backslash. */ | ||
647 | return FALSE; | ||
648 | } | ||
649 | ++i; | ||
650 | switch (s[i++]) { | ||
651 | case 'n': | ||
652 | *dst++ = '\n'; | ||
653 | break; | ||
654 | case '\\': | ||
655 | *dst++ = '\\'; | ||
656 | break; | ||
657 | default: | ||
658 | /* Only `\' or `n' may follow a backslash. */ | ||
659 | return FALSE; | ||
660 | } | ||
661 | break; | ||
662 | |||
663 | case '\0': | ||
664 | /* The file name may not contain a NUL. */ | ||
665 | return FALSE; | ||
666 | break; | ||
667 | |||
668 | default: | ||
669 | *dst++ = s[i++]; | ||
670 | break; | ||
671 | } | ||
672 | } | ||
673 | *dst = '\0'; | ||
674 | } | ||
675 | return TRUE; | ||
676 | } | ||
677 | |||
678 | static int hex_digits(unsigned char const *s) | ||
679 | { | ||
680 | while (*s) { | ||
681 | if (!ISXDIGIT(*s)) | ||
682 | return TRUE; | ||
683 | ++s; | ||
684 | } | ||
685 | return FALSE; | ||
686 | } | ||
687 | |||
688 | /* An interface to md5_stream. Operate on FILENAME (it may be "-") and | ||
689 | put the result in *MD5_RESULT. Return non-zero upon failure, zero | ||
690 | to indicate success. */ | ||
691 | static int md5_file(const char *filename, | ||
692 | int binary, | ||
693 | unsigned char *md5_result) | ||
694 | { | ||
695 | FILE *fp; | ||
696 | |||
697 | if (STREQ(filename, "-")) { | ||
698 | have_read_stdin = 1; | ||
699 | fp = stdin; | ||
700 | } else { | ||
701 | fp = fopen(filename, OPENOPTS(binary)); | ||
702 | if (fp == NULL) { | ||
703 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
704 | return FALSE; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | if (md5_stream(fp, md5_result)) { | ||
709 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
710 | |||
711 | if (fp != stdin) | ||
712 | fclose(fp); | ||
713 | return FALSE; | ||
714 | } | ||
715 | |||
716 | if (fp != stdin && fclose(fp) == EOF) { | ||
717 | errorMsg("md5sum: %s: %s\n", filename, strerror(errno)); | ||
718 | return FALSE; | ||
719 | } | ||
720 | |||
721 | return TRUE; | ||
722 | } | ||
723 | |||
724 | static int md5_check(const char *checkfile_name) | ||
725 | { | ||
726 | FILE *checkfile_stream; | ||
727 | int n_properly_formated_lines = 0; | ||
728 | int n_mismatched_checksums = 0; | ||
729 | int n_open_or_read_failures = 0; | ||
730 | unsigned char md5buffer[16]; | ||
731 | size_t line_number; | ||
732 | char *line; | ||
733 | size_t line_chars_allocated; | ||
734 | |||
735 | if (STREQ(checkfile_name, "-")) { | ||
736 | have_read_stdin = 1; | ||
737 | checkfile_stream = stdin; | ||
738 | } else { | ||
739 | checkfile_stream = fopen(checkfile_name, "r"); | ||
740 | if (checkfile_stream == NULL) { | ||
741 | errorMsg("md5sum: %s: %s\n", checkfile_name, strerror(errno)); | ||
742 | return FALSE; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | line_number = 0; | ||
747 | line = 0; | ||
748 | line_chars_allocated = 0; | ||
749 | |||
750 | do { | ||
751 | char *filename; | ||
752 | int binary; | ||
753 | unsigned char *md5num; | ||
754 | int line_length; | ||
755 | |||
756 | ++line_number; | ||
757 | |||
758 | line_length = getline(&line, &line_chars_allocated, checkfile_stream); | ||
759 | |||
760 | if (line_length <= 0) | ||
761 | break; | ||
762 | |||
763 | /* Ignore comment lines, which begin with a '#' character. */ | ||
764 | if (line[0] == '#') | ||
765 | continue; | ||
766 | |||
767 | /* Remove any trailing newline. */ | ||
768 | if (line[line_length - 1] == '\n') | ||
769 | line[--line_length] = '\0'; | ||
770 | |||
771 | if (split_3(line, line_length, &md5num, &binary, &filename) | ||
772 | || !hex_digits(md5num)) { | ||
773 | if (warn) { | ||
774 | errorMsg("%s: %lu: improperly formatted MD5 checksum line\n", | ||
775 | checkfile_name, (unsigned long) line_number); | ||
776 | } | ||
777 | } else { | ||
778 | static const char bin2hex[] = { | ||
779 | '0', '1', '2', '3', | ||
780 | '4', '5', '6', '7', | ||
781 | '8', '9', 'a', 'b', | ||
782 | 'c', 'd', 'e', 'f' | ||
783 | }; | ||
784 | |||
785 | ++n_properly_formated_lines; | ||
786 | |||
787 | if (md5_file(filename, binary, md5buffer)) { | ||
788 | ++n_open_or_read_failures; | ||
789 | if (!status_only) { | ||
790 | printf("%s: FAILED open or read\n", filename); | ||
791 | fflush(stdout); | ||
792 | } | ||
793 | } else { | ||
794 | size_t cnt; | ||
795 | /* Compare generated binary number with text representation | ||
796 | in check file. Ignore case of hex digits. */ | ||
797 | for (cnt = 0; cnt < 16; ++cnt) { | ||
798 | if (TOLOWER(md5num[2 * cnt]) | ||
799 | != bin2hex[md5buffer[cnt] >> 4] | ||
800 | || (TOLOWER(md5num[2 * cnt + 1]) | ||
801 | != (bin2hex[md5buffer[cnt] & 0xf]))) | ||
802 | break; | ||
803 | } | ||
804 | if (cnt != 16) | ||
805 | ++n_mismatched_checksums; | ||
806 | |||
807 | if (!status_only) { | ||
808 | printf("%s: %s\n", filename, | ||
809 | (cnt != 16 ? "FAILED" : "OK")); | ||
810 | fflush(stdout); | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | } | ||
815 | |||
816 | while (!feof(checkfile_stream) && !ferror(checkfile_stream)); | ||
817 | |||
818 | if (line) | ||
819 | free(line); | ||
820 | |||
821 | if (ferror(checkfile_stream)) { | ||
822 | errorMsg("%s: read error", checkfile_name); /* */ | ||
823 | return FALSE; | ||
824 | } | ||
825 | |||
826 | if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) { | ||
827 | errorMsg("md5sum: %s: %s\n", checkfile_name, strerror(errno)); | ||
828 | return FALSE; | ||
829 | } | ||
830 | |||
831 | if (n_properly_formated_lines == 0) { | ||
832 | /* Warn if no tests are found. */ | ||
833 | errorMsg("%s: no properly formatted MD5 checksum lines found\n", | ||
834 | checkfile_name); | ||
835 | return FALSE; | ||
836 | } else { | ||
837 | if (!status_only) { | ||
838 | int n_computed_checkums = (n_properly_formated_lines | ||
839 | - n_open_or_read_failures); | ||
840 | |||
841 | if (n_open_or_read_failures > 0) { | ||
842 | errorMsg("WARNING: %d of %d listed files could not be read\n", | ||
843 | n_open_or_read_failures, n_properly_formated_lines); | ||
844 | return FALSE; | ||
845 | } | ||
846 | |||
847 | if (n_mismatched_checksums > 0) { | ||
848 | errorMsg("WARNING: %d of %d computed checksums did NOT match\n", | ||
849 | n_mismatched_checksums, n_computed_checkums); | ||
850 | return FALSE; | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | |||
855 | return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0 | ||
856 | && n_open_or_read_failures == 0) ? 0 : 1); | ||
857 | } | ||
858 | |||
859 | int md5sum_main(int argc, | ||
860 | char **argv) | ||
861 | { | ||
862 | unsigned char md5buffer[16]; | ||
863 | int do_check = 0; | ||
864 | int opt; | ||
865 | char **string = NULL; | ||
866 | size_t n_strings = 0; | ||
867 | size_t err = 0; | ||
868 | int file_type_specified = 0; | ||
869 | int binary = 0; | ||
870 | |||
871 | while ((opt = getopt(argc, argv, "g:bcstw")) != -1) { | ||
872 | switch (opt) { | ||
873 | case 'g': { /* read a string */ | ||
874 | if (string == NULL) | ||
875 | string = (char **) xmalloc ((argc - 1) * sizeof (char *)); | ||
876 | |||
877 | if (optarg == NULL) | ||
878 | optarg = ""; | ||
879 | string[n_strings++] = optarg; | ||
880 | break; | ||
881 | } | ||
882 | |||
883 | case 'b': /* read files in binary mode */ | ||
884 | file_type_specified = 1; | ||
885 | binary = 1; | ||
886 | break; | ||
887 | |||
888 | case 'c': /* check MD5 sums against given list */ | ||
889 | do_check = 1; | ||
890 | break; | ||
891 | |||
892 | case 's': /* don't output anything, status code shows success */ | ||
893 | status_only = 1; | ||
894 | warn = 0; | ||
895 | break; | ||
896 | |||
897 | case 't': /* read files in text mode (default) */ | ||
898 | file_type_specified = 1; | ||
899 | binary = 0; | ||
900 | break; | ||
901 | |||
902 | case 'w': /* warn about improperly formated MD5 checksum lines */ | ||
903 | status_only = 0; | ||
904 | warn = 1; | ||
905 | break; | ||
906 | |||
907 | default: | ||
908 | usage(md5sum_usage); | ||
909 | } | ||
910 | } | ||
911 | |||
912 | if (file_type_specified && do_check) { | ||
913 | errorMsg("the -b and -t options are meaningless when verifying checksums\n"); | ||
914 | exit FALSE; | ||
915 | } | ||
916 | |||
917 | if (n_strings > 0 && do_check) { | ||
918 | errorMsg("the -g and -c options are mutually exclusive\n"); | ||
919 | exit FALSE; | ||
920 | } | ||
921 | |||
922 | if (status_only && !do_check) { | ||
923 | errorMsg("the -s option is meaningful only when verifying checksums\n"); | ||
924 | exit FALSE; | ||
925 | } | ||
926 | |||
927 | if (warn && !do_check) { | ||
928 | errorMsg("the -w option is meaningful only when verifying checksums\n"); | ||
929 | exit FALSE; | ||
930 | } | ||
931 | |||
932 | if (n_strings > 0) { | ||
933 | size_t i; | ||
934 | |||
935 | if (optind < argc) { | ||
936 | errorMsg("no files may be specified when using -g\n"); | ||
937 | exit FALSE; | ||
938 | } | ||
939 | for (i = 0; i < n_strings; ++i) { | ||
940 | size_t cnt; | ||
941 | md5_buffer (string[i], strlen (string[i]), md5buffer); | ||
942 | |||
943 | for (cnt = 0; cnt < 16; ++cnt) | ||
944 | printf ("%02x", md5buffer[cnt]); | ||
945 | |||
946 | printf (" \"%s\"\n", string[i]); | ||
947 | } | ||
948 | } else if (do_check) { | ||
949 | if (optind + 1 < argc) { | ||
950 | errorMsg("only one argument may be specified when using -c\n"); | ||
951 | } | ||
952 | |||
953 | err = md5_check ((optind == argc) ? "-" : argv[optind]); | ||
954 | } else { | ||
955 | if (optind == argc) | ||
956 | argv[argc++] = "-"; | ||
957 | |||
958 | for (; optind < argc; ++optind) { | ||
959 | int fail; | ||
960 | char *file = argv[optind]; | ||
961 | |||
962 | fail = md5_file (file, binary, md5buffer); | ||
963 | err |= fail; | ||
964 | if (!fail) { | ||
965 | size_t i; | ||
966 | /* Output a leading backslash if the file name contains | ||
967 | a newline or backslash. */ | ||
968 | if (strchr (file, '\n') || strchr (file, '\\')) | ||
969 | putchar ('\\'); | ||
970 | |||
971 | for (i = 0; i < 16; ++i) | ||
972 | printf ("%02x", md5buffer[i]); | ||
973 | |||
974 | putchar (' '); | ||
975 | if (binary) | ||
976 | putchar ('*'); | ||
977 | else | ||
978 | putchar (' '); | ||
979 | |||
980 | /* Translate each NEWLINE byte to the string, "\\n", | ||
981 | and each backslash to "\\\\". */ | ||
982 | for (i = 0; i < strlen (file); ++i) { | ||
983 | switch (file[i]) { | ||
984 | case '\n': | ||
985 | fputs ("\\n", stdout); | ||
986 | break; | ||
987 | |||
988 | case '\\': | ||
989 | fputs ("\\\\", stdout); | ||
990 | break; | ||
991 | |||
992 | default: | ||
993 | putchar (file[i]); | ||
994 | break; | ||
995 | } | ||
996 | } | ||
997 | putchar ('\n'); | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | if (fclose (stdout) == EOF) { | ||
1003 | errorMsg("write error"); | ||
1004 | exit FALSE; | ||
1005 | } | ||
1006 | |||
1007 | if (have_read_stdin && fclose (stdin) == EOF) { | ||
1008 | errorMsg("standard input"); | ||
1009 | exit FALSE; | ||
1010 | } | ||
1011 | |||
1012 | exit (err == 0 ? TRUE : FALSE); | ||
1013 | } | ||
diff --git a/uudecode.c b/uudecode.c new file mode 100644 index 000000000..4216e336a --- /dev/null +++ b/uudecode.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /* uudecode.c -- uudecode utility. | ||
2 | * Copyright (C) 1994, 1995 Free Software Foundation, Inc. | ||
3 | * | ||
4 | * This product is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2, or (at your option) | ||
7 | * any later version. | ||
8 | * | ||
9 | * This product is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this product; see the file COPYING. If not, write to | ||
16 | * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | ||
17 | * 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* Copyright (c) 1983 Regents of the University of California. | ||
21 | * All rights reserved. | ||
22 | * | ||
23 | * Redistribution and use in source and binary forms, with or without | ||
24 | * modification, are permitted provided that the following conditions | ||
25 | * are met: | ||
26 | * 1. Redistributions of source code must retain the above copyright | ||
27 | * notice, this list of conditions and the following disclaimer. | ||
28 | * 2. Redistributions in binary form must reproduce the above copyright | ||
29 | * notice, this list of conditions and the following disclaimer in the | ||
30 | * documentation and/or other materials provided with the distribution. | ||
31 | * 3. All advertising materials mentioning features or use of this software | ||
32 | * must display the following acknowledgement: | ||
33 | * This product includes software developed by the University of | ||
34 | * California, Berkeley and its contributors. | ||
35 | * 4. Neither the name of the University nor the names of its contributors | ||
36 | * may be used to endorse or promote products derived from this software | ||
37 | * without specific prior written permission. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
49 | * SUCH DAMAGE. | ||
50 | */ | ||
51 | |||
52 | /* Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. */ | ||
53 | |||
54 | #include "internal.h" | ||
55 | |||
56 | #include <stdio.h> | ||
57 | #include <errno.h> | ||
58 | #include <pwd.h> | ||
59 | |||
60 | /*struct passwd *getpwnam();*/ | ||
61 | |||
62 | /* Single character decode. */ | ||
63 | #define DEC(Char) (((Char) - ' ') & 077) | ||
64 | |||
65 | static int read_stduu (const char *inname) | ||
66 | { | ||
67 | char buf[2 * BUFSIZ]; | ||
68 | |||
69 | while (1) { | ||
70 | int n; | ||
71 | char *p; | ||
72 | |||
73 | if (fgets (buf, sizeof(buf), stdin) == NULL) { | ||
74 | errorMsg("%s: Short file\n", inname); | ||
75 | return FALSE; | ||
76 | } | ||
77 | p = buf; | ||
78 | |||
79 | /* N is used to avoid writing out all the characters at the end of | ||
80 | the file. */ | ||
81 | n = DEC (*p); | ||
82 | if (n <= 0) | ||
83 | break; | ||
84 | for (++p; n > 0; p += 4, n -= 3) { | ||
85 | char ch; | ||
86 | |||
87 | if (n >= 3) { | ||
88 | ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; | ||
89 | putchar (ch); | ||
90 | ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; | ||
91 | putchar (ch); | ||
92 | ch = DEC (p[2]) << 6 | DEC (p[3]); | ||
93 | putchar (ch); | ||
94 | } else { | ||
95 | if (n >= 1) { | ||
96 | ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4; | ||
97 | putchar (ch); | ||
98 | } | ||
99 | if (n >= 2) { | ||
100 | ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2; | ||
101 | putchar (ch); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if (fgets (buf, sizeof(buf), stdin) == NULL | ||
108 | || strcmp (buf, "end\n")) { | ||
109 | errorMsg("%s: No `end' line\n", inname); | ||
110 | return FALSE; | ||
111 | } | ||
112 | |||
113 | return TRUE; | ||
114 | } | ||
115 | |||
116 | static int read_base64 (const char *inname) | ||
117 | { | ||
118 | static const char b64_tab[256] = { | ||
119 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/ | ||
120 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/ | ||
121 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/ | ||
122 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/ | ||
123 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/ | ||
124 | '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/ | ||
125 | '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/ | ||
126 | '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/ | ||
127 | '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/ | ||
128 | '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/ | ||
129 | '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/ | ||
130 | '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/ | ||
131 | '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/ | ||
132 | '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/ | ||
133 | '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/ | ||
134 | '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/ | ||
135 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/ | ||
136 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/ | ||
137 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/ | ||
138 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/ | ||
139 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/ | ||
140 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/ | ||
141 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/ | ||
142 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/ | ||
143 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/ | ||
144 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/ | ||
145 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/ | ||
146 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/ | ||
147 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/ | ||
148 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/ | ||
149 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/ | ||
150 | '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/ | ||
151 | }; | ||
152 | unsigned char buf[2 * BUFSIZ]; | ||
153 | |||
154 | while (1) { | ||
155 | int last_data = 0; | ||
156 | unsigned char *p; | ||
157 | |||
158 | if (fgets (buf, sizeof(buf), stdin) == NULL) { | ||
159 | errorMsg("%s: Short file\n", inname); | ||
160 | return FALSE; | ||
161 | } | ||
162 | p = buf; | ||
163 | |||
164 | if (memcmp (buf, "====", 4) == 0) | ||
165 | break; | ||
166 | if (last_data != 0) { | ||
167 | errorMsg("%s: data following `=' padding character\n", inname); | ||
168 | return FALSE; | ||
169 | } | ||
170 | |||
171 | /* The following implementation of the base64 decoding might look | ||
172 | a bit clumsy but I only try to follow the POSIX standard: | ||
173 | ``All line breaks or other characters not found in the table | ||
174 | [with base64 characters] shall be ignored by decoding | ||
175 | software.'' */ | ||
176 | while (*p != '\n') { | ||
177 | char c1, c2, c3; | ||
178 | |||
179 | while ((b64_tab[*p] & '\100') != 0) | ||
180 | if (*p == '\n' || *p++ == '=') | ||
181 | break; | ||
182 | if (*p == '\n') | ||
183 | /* This leaves the loop. */ | ||
184 | continue; | ||
185 | c1 = b64_tab[*p++]; | ||
186 | |||
187 | while ((b64_tab[*p] & '\100') != 0) | ||
188 | if (*p == '\n' || *p++ == '=') { | ||
189 | errorMsg("%s: illegal line\n", inname); | ||
190 | return FALSE; | ||
191 | } | ||
192 | c2 = b64_tab[*p++]; | ||
193 | |||
194 | while (b64_tab[*p] == '\177') | ||
195 | if (*p++ == '\n') { | ||
196 | errorMsg("%s: illegal line\n", inname); | ||
197 | return FALSE; | ||
198 | } | ||
199 | if (*p == '=') { | ||
200 | putchar (c1 << 2 | c2 >> 4); | ||
201 | last_data = 1; | ||
202 | break; | ||
203 | } | ||
204 | c3 = b64_tab[*p++]; | ||
205 | |||
206 | while (b64_tab[*p] == '\177') | ||
207 | if (*p++ == '\n') { | ||
208 | errorMsg("%s: illegal line\n", inname); | ||
209 | return FALSE; | ||
210 | } | ||
211 | putchar (c1 << 2 | c2 >> 4); | ||
212 | putchar (c2 << 4 | c3 >> 2); | ||
213 | if (*p == '=') { | ||
214 | last_data = 1; | ||
215 | break; | ||
216 | } | ||
217 | else | ||
218 | putchar (c3 << 6 | b64_tab[*p++]); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | return TRUE; | ||
223 | } | ||
224 | |||
225 | static int decode (const char *inname, | ||
226 | const char *forced_outname) | ||
227 | { | ||
228 | struct passwd *pw; | ||
229 | register int n; | ||
230 | register char *p; | ||
231 | int mode, n1; | ||
232 | char buf[2 * BUFSIZ]; | ||
233 | char *outname; | ||
234 | int do_base64 = 0; | ||
235 | |||
236 | /* Search for header line. */ | ||
237 | |||
238 | while (1) { | ||
239 | if (fgets (buf, sizeof (buf), stdin) == NULL) { | ||
240 | errorMsg("%s: No `begin' line\n", inname); | ||
241 | return FALSE; | ||
242 | } | ||
243 | |||
244 | if (strncmp (buf, "begin", 5) == 0) { | ||
245 | if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) { | ||
246 | do_base64 = 1; | ||
247 | break; | ||
248 | } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2) | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* If the output file name is given on the command line this rules. */ | ||
254 | if (forced_outname != NULL) | ||
255 | outname = (char *) forced_outname; | ||
256 | else { | ||
257 | /* Handle ~user/file format. */ | ||
258 | if (buf[0] != '~') | ||
259 | outname = buf; | ||
260 | else { | ||
261 | p = buf + 1; | ||
262 | while (*p != '/') | ||
263 | ++p; | ||
264 | if (*p == '\0') { | ||
265 | errorMsg("%s: Illegal ~user\n", inname); | ||
266 | return FALSE; | ||
267 | } | ||
268 | *p++ = '\0'; | ||
269 | pw = getpwnam (buf + 1); | ||
270 | if (pw == NULL) { | ||
271 | errorMsg("%s: No user `%s'\n", inname, buf + 1); | ||
272 | return FALSE; | ||
273 | } | ||
274 | n = strlen (pw->pw_dir); | ||
275 | n1 = strlen (p); | ||
276 | outname = (char *) alloca ((size_t) (n + n1 + 2)); | ||
277 | memcpy (outname + n + 1, p, (size_t) (n1 + 1)); | ||
278 | memcpy (outname, pw->pw_dir, (size_t) n); | ||
279 | outname[n] = '/'; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* Create output file and set mode. */ | ||
284 | if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0 | ||
285 | && (freopen (outname, "w", stdout) == NULL | ||
286 | || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | ||
287 | )) { | ||
288 | errorMsg("uudeoce %s: %s %s\n", outname, inname, strerror(errno)); /* */ | ||
289 | return FALSE; | ||
290 | } | ||
291 | |||
292 | /* We differenciate decoding standard UU encoding and base64. A | ||
293 | common function would only slow down the program. */ | ||
294 | |||
295 | /* For each input line: */ | ||
296 | if (do_base64) | ||
297 | return read_base64 (inname); | ||
298 | else | ||
299 | return read_stduu (inname); | ||
300 | } | ||
301 | |||
302 | static const char uudecode_usage[] = | ||
303 | "uudecode [FILE]...\n" | ||
304 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
305 | "\nUudecode a file that is uuencoded.\n\n" | ||
306 | "Options:\n" | ||
307 | "\t-o FILE\tdirect output to FILE\n" | ||
308 | #endif | ||
309 | ; | ||
310 | |||
311 | int uudecode_main (int argc, | ||
312 | char **argv) | ||
313 | { | ||
314 | int opt; | ||
315 | int exit_status; | ||
316 | const char *outname; | ||
317 | outname = NULL; | ||
318 | |||
319 | while ((opt = getopt(argc, argv, "o:")) != EOF) { | ||
320 | switch (opt) { | ||
321 | case 0: | ||
322 | break; | ||
323 | |||
324 | case 'o': | ||
325 | outname = optarg; | ||
326 | break; | ||
327 | |||
328 | default: | ||
329 | usage(uudecode_usage); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | if (optind == argc) | ||
334 | exit_status = decode ("stdin", outname) == 0 ? TRUE : FALSE; | ||
335 | else { | ||
336 | exit_status = TRUE; | ||
337 | do { | ||
338 | if (freopen (argv[optind], "r", stdin) != NULL) { | ||
339 | if (decode (argv[optind], outname) != 0) | ||
340 | exit_status = FALSE; | ||
341 | } else { | ||
342 | errorMsg("uudecode: %s: %s\n", argv[optind], strerror(errno)); | ||
343 | exit_status = FALSE; | ||
344 | } | ||
345 | optind++; | ||
346 | } | ||
347 | while (optind < argc); | ||
348 | } | ||
349 | exit(exit_status); | ||
350 | } | ||
diff --git a/uuencode.c b/uuencode.c new file mode 100644 index 000000000..91136b3e6 --- /dev/null +++ b/uuencode.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* uuencode.c -- uuencode utility. | ||
2 | * Copyright (C) 1994, 1995 Free Software Foundation, Inc. | ||
3 | * | ||
4 | * This product is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2, or (at your option) | ||
7 | * any later version. | ||
8 | * | ||
9 | * This product is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this product; see the file COPYING. If not, write to | ||
16 | * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | ||
17 | * 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* Copyright (c) 1983 Regents of the University of California. | ||
21 | * All rights reserved. | ||
22 | * | ||
23 | * Redistribution and use in source and binary forms, with or without | ||
24 | * modification, are permitted provided that the following conditions | ||
25 | * are met: | ||
26 | * 1. Redistributions of source code must retain the above copyright | ||
27 | * notice, this list of conditions and the following disclaimer. | ||
28 | * 2. Redistributions in binary form must reproduce the above copyright | ||
29 | * notice, this list of conditions and the following disclaimer in the | ||
30 | * documentation and/or other materials provided with the distribution. | ||
31 | * 3. All advertising materials mentioning features or use of this software | ||
32 | * must display the following acknowledgement: | ||
33 | * This product includes software developed by the University of | ||
34 | * California, Berkeley and its contributors. | ||
35 | * 4. Neither the name of the University nor the names of its contributors | ||
36 | * may be used to endorse or promote products derived from this software | ||
37 | * without specific prior written permission. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
49 | * SUCH DAMAGE. | ||
50 | */ | ||
51 | |||
52 | /* Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93. */ | ||
53 | /* Hacked to work with BusyBox by Alfred M. Szmidt */ | ||
54 | |||
55 | #include "internal.h" | ||
56 | |||
57 | #include <stdio.h> | ||
58 | #include <errno.h> | ||
59 | #include <pwd.h> | ||
60 | |||
61 | #define RW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | ||
62 | |||
63 | static void encode __P ((void)); | ||
64 | |||
65 | /* Pointer to the translation table we currently use. */ | ||
66 | const char *trans_ptr; | ||
67 | |||
68 | /* The two currently defined translation tables. The first is the | ||
69 | standard uuencoding, the second is base64 encoding. */ | ||
70 | const char uu_std[64] = { | ||
71 | '`', '!', '"', '#', '$', '%', '&', '\'', | ||
72 | '(', ')', '*', '+', ',', '-', '.', '/', | ||
73 | '0', '1', '2', '3', '4', '5', '6', '7', | ||
74 | '8', '9', ':', ';', '<', '=', '>', '?', | ||
75 | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', | ||
76 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', | ||
77 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', | ||
78 | 'X', 'Y', 'Z', '[', '\\', ']', '^', '_' | ||
79 | }; | ||
80 | |||
81 | const char uu_base64[64] = { | ||
82 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', | ||
83 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | ||
84 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', | ||
85 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', | ||
86 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', | ||
87 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', | ||
88 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', | ||
89 | '4', '5', '6', '7', '8', '9', '+', '/' | ||
90 | }; | ||
91 | |||
92 | /* ENC is the basic 1 character encoding function to make a char printing. */ | ||
93 | #define ENC(Char) (trans_ptr[(Char) & 077]) | ||
94 | |||
95 | /* Copy from IN to OUT, encoding as you go along. */ | ||
96 | static void encode() | ||
97 | { | ||
98 | register int ch, n; | ||
99 | char *p = NULL; | ||
100 | char buf[80]; | ||
101 | |||
102 | while (1) { | ||
103 | n = 0; | ||
104 | do { | ||
105 | register int m = fread (buf, 1, 45 - n, stdin); | ||
106 | if (m == 0) | ||
107 | break; | ||
108 | n += m; | ||
109 | } | ||
110 | while (n < 45); | ||
111 | |||
112 | if (n == 0) | ||
113 | break; | ||
114 | |||
115 | if (trans_ptr == uu_std) | ||
116 | if (putchar (ENC (n)) == EOF) | ||
117 | break; | ||
118 | for (p = buf; n > 2; n -= 3, p += 3) { | ||
119 | ch = *p >> 2; | ||
120 | ch = ENC (ch); | ||
121 | if (putchar (ch) == EOF) | ||
122 | break; | ||
123 | ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017); | ||
124 | ch = ENC (ch); | ||
125 | if (putchar (ch) == EOF) | ||
126 | break; | ||
127 | ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); | ||
128 | ch = ENC (ch); | ||
129 | if (putchar (ch) == EOF) | ||
130 | break; | ||
131 | ch = p[2] & 077; | ||
132 | ch = ENC (ch); | ||
133 | if (putchar (ch) == EOF) | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | if (n != 0) | ||
138 | break; | ||
139 | |||
140 | if (putchar ('\n') == EOF) | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | while (n != 0) { | ||
145 | char c1 = *p; | ||
146 | char c2 = n == 1 ? 0 : p[1]; | ||
147 | |||
148 | ch = c1 >> 2; | ||
149 | ch = ENC (ch); | ||
150 | if (putchar (ch) == EOF) | ||
151 | break; | ||
152 | |||
153 | ch = ((c1 << 4) & 060) | ((c2 >> 4) & 017); | ||
154 | ch = ENC (ch); | ||
155 | if (putchar (ch) == EOF) | ||
156 | break; | ||
157 | |||
158 | if (n == 1) | ||
159 | ch = trans_ptr == uu_std ? ENC ('\0') : '='; | ||
160 | else { | ||
161 | ch = (c2 << 2) & 074; | ||
162 | ch = ENC (ch); | ||
163 | } | ||
164 | if (putchar (ch) == EOF) | ||
165 | break; | ||
166 | ch = trans_ptr == uu_std ? ENC ('\0') : '='; | ||
167 | if (putchar (ch) == EOF) | ||
168 | break; | ||
169 | putchar ('\n'); | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | if (ferror (stdin)) | ||
174 | errorMsg("Read error\n"); | ||
175 | |||
176 | if (trans_ptr == uu_std) { | ||
177 | putchar (ENC ('\0')); | ||
178 | putchar ('\n'); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | static const char uuencode_usage[] = | ||
183 | "uuencode [OPTION] [INFILE] REMOTEFILE\n" | ||
184 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
185 | "\nUuencode a file.\n\n" | ||
186 | "Options:\n" | ||
187 | "\t-m\tuse base64 encoding as of RFC1521\n" | ||
188 | #endif | ||
189 | ; | ||
190 | |||
191 | int uuencode_main (int argc, | ||
192 | char **argv) | ||
193 | { | ||
194 | int opt; | ||
195 | struct stat sb; | ||
196 | int mode; | ||
197 | |||
198 | trans_ptr = uu_std; /* Standard encoding is old uu format */ | ||
199 | |||
200 | /* Parse any options */ | ||
201 | while ((opt = getopt (argc, argv, "m")) != EOF) { | ||
202 | switch (opt) { | ||
203 | case 'm': | ||
204 | trans_ptr = uu_base64; | ||
205 | break; | ||
206 | |||
207 | case 0: | ||
208 | break; | ||
209 | |||
210 | default: | ||
211 | usage(uuencode_usage); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | switch (argc - optind) { | ||
216 | case 2: | ||
217 | /* Optional first argument is input file. */ | ||
218 | if (!freopen (argv[optind], "r", stdin) || fstat (fileno (stdin), &sb)) { | ||
219 | errorMsg("uuencode: %s: %s\n", argv[optind], strerror(errno)); | ||
220 | exit FALSE; | ||
221 | } | ||
222 | mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); | ||
223 | optind++; | ||
224 | break; | ||
225 | |||
226 | case 1: | ||
227 | mode = RW & ~umask (RW); | ||
228 | break; | ||
229 | |||
230 | case 0: | ||
231 | default: | ||
232 | usage(uuencode_usage); | ||
233 | } | ||
234 | |||
235 | printf("begin%s %o %s\n", trans_ptr == uu_std ? "" : "-base64", | ||
236 | mode, argv[optind]); | ||
237 | encode(); | ||
238 | printf(trans_ptr == uu_std ? "end\n" : "====\n"); | ||
239 | if (ferror (stdout)) { | ||
240 | errorMsg("Write error\n"); | ||
241 | exit FALSE; | ||
242 | } | ||
243 | exit TRUE; | ||
244 | } | ||