TODO: add an item for a chmod optimization
[platform/upstream/coreutils.git] / src / cksum.c
1 /* cksum -- calculate and print POSIX checksums and sizes of files
2    Copyright (C) 92, 1995-2006, 2008 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 3 of the License, or
7    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
16 \f
17 /* Written by Q. Frank Xia, qx@math.columbia.edu.
18    Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
19
20   Usage: cksum [file...]
21
22   The code segment between "#ifdef CRCTAB" and "#else" is the code
23   which calculates the "crctab". It is included for those who want
24   verify the correctness of the "crctab". To recreate the "crctab",
25   do something like the following:
26
27       cc -DCRCTAB -o crctab cksum.c
28       crctab > crctab.h
29
30   This software is compatible with neither the System V nor the BSD
31   `sum' program.  It is supposed to conform to POSIX, except perhaps
32   for foreign language support.  Any inconsistency with the standard
33   (other than foreign language support) is a bug.  */
34
35 #include <config.h>
36
37 /* The official name of this program (e.g., no `g' prefix).  */
38 #define PROGRAM_NAME "cksum"
39
40 #define AUTHORS proper_name ("Q. Frank Xia")
41
42 #include <stdio.h>
43 #include <sys/types.h>
44 #include <stdint.h>
45 #include "system.h"
46
47 #ifdef CRCTAB
48
49 # define BIT(x) ((uint_fast32_t) 1 << (x))
50 # define SBIT   BIT (31)
51
52 /* The generating polynomial is
53
54           32   26   23   22   16   12   11   10   8   7   5   4   2   1
55     G(X)=X  + X  + X  + X  + X  + X  + X  + X  + X + X + X + X + X + X + 1
56
57   The i bit in GEN is set if X^i is a summand of G(X) except X^32.  */
58
59 # define GEN    (BIT (26) | BIT (23) | BIT (22) | BIT (16) | BIT (12) \
60                  | BIT (11) | BIT (10) | BIT (8) | BIT (7) | BIT (5) \
61                  | BIT (4) | BIT (2) | BIT (1) | BIT (0))
62
63 static uint_fast32_t r[8];
64
65 static void
66 fill_r (void)
67 {
68   int i;
69
70   r[0] = GEN;
71   for (i = 1; i < 8; i++)
72     r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0);
73 }
74
75 static uint_fast32_t
76 crc_remainder (int m)
77 {
78   uint_fast32_t rem = 0;
79   int i;
80
81   for (i = 0; i < 8; i++)
82     if (BIT (i) & m)
83       rem ^= r[i];
84
85   return rem & 0xFFFFFFFF;      /* Make it run on 64-bit machine.  */
86 }
87
88 int
89 main (void)
90 {
91   int i;
92
93   fill_r ();
94   printf ("static uint_fast32_t const crctab[256] =\n{\n  0x00000000");
95   for (i = 0; i < 51; i++)
96     {
97       printf (",\n  0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
98               crc_remainder (i * 5 + 1), crc_remainder (i * 5 + 2),
99               crc_remainder (i * 5 + 3), crc_remainder (i * 5 + 4),
100               crc_remainder (i * 5 + 5));
101     }
102   printf ("\n};\n");
103   exit (EXIT_SUCCESS);
104 }
105
106 #else /* !CRCTAB */
107
108 # include <getopt.h>
109 # include "long-options.h"
110 # include "error.h"
111
112 /* Number of bytes to read at once.  */
113 # define BUFLEN (1 << 16)
114
115 static uint_fast32_t const crctab[256] =
116 {
117   0x00000000,
118   0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
119   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
120   0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
121   0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
122   0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
123   0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
124   0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
125   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
126   0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
127   0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
128   0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
129   0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
130   0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
131   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
132   0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
133   0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
134   0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
135   0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
136   0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
137   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
138   0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
139   0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
140   0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
141   0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
142   0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
143   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
144   0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
145   0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
146   0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
147   0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
148   0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
149   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
150   0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
151   0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
152   0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
153   0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
154   0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
155   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
156   0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
157   0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
158   0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
159   0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
160   0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
161   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
162   0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
163   0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
164   0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
165   0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
166   0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
167   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
168   0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
169 };
170
171 /* Nonzero if any of the files read were the standard input. */
172 static bool have_read_stdin;
173
174 /* Calculate and print the checksum and length in bytes
175    of file FILE, or of the standard input if FILE is "-".
176    If PRINT_NAME is true, print FILE next to the checksum and size.
177    Return true if successful.  */
178
179 static bool
180 cksum (const char *file, bool print_name)
181 {
182   unsigned char buf[BUFLEN];
183   uint_fast32_t crc = 0;
184   uintmax_t length = 0;
185   size_t bytes_read;
186   FILE *fp;
187   char length_buf[INT_BUFSIZE_BOUND (uintmax_t)];
188   char const *hp;
189
190   if (STREQ (file, "-"))
191     {
192       fp = stdin;
193       have_read_stdin = true;
194       if (O_BINARY && ! isatty (STDIN_FILENO))
195         freopen (NULL, "rb", stdin);
196     }
197   else
198     {
199       fp = fopen (file, (O_BINARY ? "rb" : "r"));
200       if (fp == NULL)
201         {
202           error (0, errno, "%s", file);
203           return false;
204         }
205     }
206
207   while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
208     {
209       unsigned char *cp = buf;
210
211       if (length + bytes_read < length)
212         error (EXIT_FAILURE, 0, _("%s: file too long"), file);
213       length += bytes_read;
214       while (bytes_read--)
215         crc = (crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
216       if (feof (fp))
217         break;
218     }
219
220   if (ferror (fp))
221     {
222       error (0, errno, "%s", file);
223       if (!STREQ (file, "-"))
224         fclose (fp);
225       return false;
226     }
227
228   if (!STREQ (file, "-") && fclose (fp) == EOF)
229     {
230       error (0, errno, "%s", file);
231       return false;
232     }
233
234   hp = umaxtostr (length, length_buf);
235
236   for (; length; length >>= 8)
237     crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
238
239   crc = ~crc & 0xFFFFFFFF;
240
241   if (print_name)
242     printf ("%u %s %s\n", (unsigned int) crc, hp, file);
243   else
244     printf ("%u %s\n", (unsigned int) crc, hp);
245
246   if (ferror (stdout))
247     error (EXIT_FAILURE, errno, "-: %s", _("write error"));
248
249   return true;
250 }
251
252 void
253 usage (int status)
254 {
255   if (status != EXIT_SUCCESS)
256     fprintf (stderr, _("Try `%s --help' for more information.\n"),
257              program_name);
258   else
259     {
260       printf (_("\
261 Usage: %s [FILE]...\n\
262   or:  %s [OPTION]\n\
263 "),
264               program_name, program_name);
265       fputs (_("\
266 Print CRC checksum and byte counts of each FILE.\n\
267 \n\
268 "), stdout);
269       fputs (HELP_OPTION_DESCRIPTION, stdout);
270       fputs (VERSION_OPTION_DESCRIPTION, stdout);
271       emit_bug_reporting_address ();
272     }
273   exit (status);
274 }
275
276 int
277 main (int argc, char **argv)
278 {
279   int i;
280   bool ok;
281
282   initialize_main (&argc, &argv);
283   set_program_name (argv[0]);
284   setlocale (LC_ALL, "");
285   bindtextdomain (PACKAGE, LOCALEDIR);
286   textdomain (PACKAGE);
287
288   atexit (close_stdout);
289
290   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
291                       usage, AUTHORS, (char const *) NULL);
292   if (getopt_long (argc, argv, "", NULL, NULL) != -1)
293     usage (EXIT_FAILURE);
294
295   have_read_stdin = false;
296
297   if (optind == argc)
298     ok = cksum ("-", false);
299   else
300     {
301       ok = true;
302       for (i = optind; i < argc; i++)
303         ok &= cksum (argv[i], true);
304     }
305
306   if (have_read_stdin && fclose (stdin) == EOF)
307     error (EXIT_FAILURE, errno, "-");
308   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
309 }
310
311 #endif /* !CRCTAB */