95d4f5cd859bc3ff5ce2842d64dbd5ffbd1ac0f7
[platform/upstream/coreutils.git] / src / cksum.c
1 /* cksum -- calculate and print POSIX.2 checksums and sizes of files
2    Copyright (C) 92, 1995-2001 Free Software Foundation, Inc.
3
4    This program 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 program 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 program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17 \f
18 /* Written by Q. Frank Xia, qx@math.columbia.edu.
19    Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
20
21   Usage: cksum [file...]
22
23   The code segment between "#ifdef CRCTAB" and "#else" is the code
24   which calculates the "crctab". It is included for those who want
25   verify the correctness of the "crctab". To recreate the "crctab",
26   do following:
27
28       cc -DCRCTAB -o crctab cksum.c
29       crctab > crctab.h
30
31   As Bruce Evans pointed out to me, the crctab in the sample C code
32   in 4.9.10 Rationale of P1003.2/D11.2 is represented in reversed order.
33   Namely, 0x01 is represented as 0x80, 0x02 is represented as 0x40, etc.
34   The generating polynomial is crctab[0x80]=0xedb88320 instead of
35   crctab[1]=0x04C11DB7.  But the code works only for a non-reverse order
36   crctab.  Therefore, the sample implementation is wrong.
37
38   This software is compatible with neither the System V nor the BSD
39   `sum' program.  It is supposed to conform to P1003.2/D11.2,
40   except foreign language interface (4.9.5.3 of P1003.2/D11.2) support.
41   Any inconsistency with the standard except 4.9.5.3 is a bug.  */
42
43 #include <config.h>
44
45 /* The official name of this program (e.g., no `g' prefix).  */
46 #define PROGRAM_NAME "cksum"
47
48 #define AUTHORS "Q. Frank Xia"
49
50 #include <stdio.h>
51 #include "system.h"
52
53 #if !defined UINT_FAST32_MAX && !defined uint_fast32_t
54 # define uint_fast32_t unsigned int
55 #endif
56
57 #ifdef CRCTAB
58
59 # define BIT(x) ((uint_fast32_t) 1 << (x))
60 # define SBIT   BIT (31)
61
62 /* The generating polynomial is
63
64           32   26   23   22   16   12   11   10   8   7   5   4   2   1
65     G(X)=X  + X  + X  + X  + X  + X  + X  + X  + X + X + X + X + X + X + 1
66
67   The i bit in GEN is set if X^i is a summand of G(X) except X^32.  */
68
69 # define GEN    (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \
70                  | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \
71                  | BIT (4) | BIT (2) | BIT (1) | BIT (0))
72
73 static uint_fast32_t r[8];
74
75 static void
76 fill_r (void)
77 {
78   int i;
79
80   r[0] = GEN;
81   for (i = 1; i < 8; i++)
82     r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0);
83 }
84
85 static uint_fast32_t
86 remainder (int m)
87 {
88   uint_fast32_t rem = 0;
89   int i;
90
91   for (i = 0; i < 8; i++)
92     if (BIT (i) & m)
93       rem ^= r[i];
94
95   return rem & 0xFFFFFFFF;      /* Make it run on 64-bit machine.  */
96 }
97
98 int
99 main (void)
100 {
101   int i;
102
103   fill_r ();
104   printf ("static uint_fast32_t crctab[256] =\n{\n  0x0");
105   for (i = 0; i < 51; i++)
106     {
107       printf (",\n  0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X",
108               remainder (i * 5 + 1), remainder (i * 5 + 2),
109               remainder (i * 5 + 3), remainder (i * 5 + 4),
110               remainder (i * 5 + 5));
111     }
112   printf ("\n};\n");
113   exit (EXIT_SUCCESS);
114 }
115
116 #else /* !CRCTAB */
117
118 # include <getopt.h>
119 # include <sys/types.h>
120 # include "closeout.h"
121 # include "long-options.h"
122 # include "error.h"
123 # include "human.h"
124
125 /* Number of bytes to read at once.  */
126 # define BUFLEN (1 << 16)
127
128 /* The name this program was run with.  */
129 char *program_name;
130
131 static struct option const long_options[] =
132 {
133   {0, 0, 0, 0}
134 };
135
136 static uint_fast32_t crctab[256] =
137 {
138   0x0,
139   0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
140   0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
141   0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
142   0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
143   0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
144   0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
145   0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
146   0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
147   0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
148   0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
149   0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
150   0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
151   0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
152   0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
153   0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
154   0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
155   0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
156   0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
157   0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
158   0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
159   0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
160   0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
161   0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
162   0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
163   0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
164   0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
165   0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
166   0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
167   0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
168   0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
169   0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
170   0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
171   0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
172   0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
173   0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
174   0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
175   0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
176   0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
177   0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
178   0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
179   0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
180   0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
181   0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
182   0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
183   0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
184   0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
185   0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
186   0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
187   0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
188   0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
189   0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
190 };
191
192 /* Nonzero if any of the files read were the standard input. */
193 static int have_read_stdin;
194
195 /* Calculate and print the checksum and length in bytes
196    of file FILE, or of the standard input if FILE is "-".
197    If PRINT_NAME is nonzero, print FILE next to the checksum and size.
198    Return 0 if successful, -1 if an error occurs. */
199
200 static int
201 cksum (const char *file, int print_name)
202 {
203   unsigned char buf[BUFLEN];
204   uint_fast32_t crc = 0;
205   uintmax_t length = 0;
206   size_t bytes_read;
207   register FILE *fp;
208   char hbuf[LONGEST_HUMAN_READABLE + 1];
209   char *hp;
210
211   if (STREQ (file, "-"))
212     {
213       fp = stdin;
214       have_read_stdin = 1;
215     }
216   else
217     {
218       fp = fopen (file, "r");
219       if (fp == NULL)
220         {
221           error (0, errno, "%s", file);
222           return -1;
223         }
224     }
225
226   /* Read input in BINARY mode, unless it is a console device.  */
227   SET_BINARY (fileno (fp));
228
229   while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
230     {
231       unsigned char *cp = buf;
232
233       if (length + bytes_read < length)
234         error (EXIT_FAILURE, 0, _("%s: file too long"), file);
235       length += bytes_read;
236       while (bytes_read--)
237         crc = (crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
238     }
239
240   if (ferror (fp))
241     {
242       error (0, errno, "%s", file);
243       if (!STREQ (file, "-"))
244         fclose (fp);
245       return -1;
246     }
247
248   if (!STREQ (file, "-") && fclose (fp) == EOF)
249     {
250       error (0, errno, "%s", file);
251       return -1;
252     }
253
254   hp = human_readable (length, hbuf, 1, 1);
255
256   for (; length; length >>= 8)
257     crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
258
259   crc = ~crc & 0xFFFFFFFF;
260
261   if (print_name)
262     printf ("%u %s %s\n", (unsigned) crc, hp, file);
263   else
264     printf ("%u %s\n", (unsigned) crc, hp);
265
266   if (ferror (stdout))
267     error (EXIT_FAILURE, errno, "-: %s", _("write error"));
268
269   return 0;
270 }
271
272 void
273 usage (int status)
274 {
275   if (status != 0)
276     fprintf (stderr, _("Try `%s --help' for more information.\n"),
277              program_name);
278   else
279     {
280       printf (_("\
281 Usage: %s [FILE]...\n\
282   or:  %s [OPTION]\n\
283 "),
284               program_name, program_name);
285       printf (_("\
286 Print CRC checksum and byte counts of each FILE.\n\
287 \n\
288   --help      display this help and exit\n\
289   --version   output version information and exit\n\
290 "));
291       puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
292     }
293   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
294 }
295
296 int
297 main (int argc, char **argv)
298 {
299   int i, c;
300   int errors = 0;
301
302   program_name = argv[0];
303   setlocale (LC_ALL, "");
304   bindtextdomain (PACKAGE, LOCALEDIR);
305   textdomain (PACKAGE);
306
307   atexit (close_stdout);
308
309   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
310                       AUTHORS, usage);
311
312   have_read_stdin = 0;
313
314   while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
315     {
316       switch (c)
317         {
318         case 0:
319           break;
320
321         default:
322           usage (1);
323         }
324     }
325
326   if (optind == argc)
327     errors |= cksum ("-", 0);
328   else
329     {
330       for (i = optind; i < argc; i++)
331         errors |= cksum (argv[i], 1);
332     }
333
334   if (have_read_stdin && fclose (stdin) == EOF)
335     error (EXIT_FAILURE, errno, "-");
336   exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
337 }
338
339 #endif /* !CRCTAB */