1 /* sum -- checksum and count the blocks in a file
2 Copyright (C) 1986-2023 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */
19 /* Written by Kayvan Aghaiepour and David MacKenzie. */
24 #include <sys/types.h>
30 #ifdef WORDS_BIGENDIAN
33 # define SWAP(n) bswap_16 (n)
36 /* Calculate the checksum and the size in bytes of stream STREAM.
37 Return -1 on error, 0 on success. */
40 bsd_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
44 int checksum
= 0; /* The checksum mod 2^16. */
45 uintmax_t total_bytes
= 0; /* The number of bytes. */
46 static const size_t buffer_length
= 32768;
47 uint8_t *buffer
= malloc (buffer_length
);
60 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
63 if (buffer_length
== sum
)
77 for (size_t i
= 0; i
< sum
; i
++)
79 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
80 checksum
+= buffer
[i
];
81 checksum
&= 0xffff; /* Keep it within bounds. */
83 if (total_bytes
+ sum
< total_bytes
)
93 for (size_t i
= 0; i
< sum
; i
++)
95 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
96 checksum
+= buffer
[i
];
97 checksum
&= 0xffff; /* Keep it within bounds. */
99 if (total_bytes
+ sum
< total_bytes
)
106 memcpy (resstream
, &checksum
, sizeof checksum
);
107 *length
= total_bytes
;
114 /* Calculate the checksum and the size in bytes of stream STREAM.
115 Return -1 on error, 0 on success. */
118 sysv_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
122 uintmax_t total_bytes
= 0;
123 static const size_t buffer_length
= 32768;
124 uint8_t *buffer
= malloc (buffer_length
);
129 /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
140 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
143 if (buffer_length
== sum
)
157 for (size_t i
= 0; i
< sum
; i
++)
159 if (total_bytes
+ sum
< total_bytes
)
169 for (size_t i
= 0; i
< sum
; i
++)
171 if (total_bytes
+ sum
< total_bytes
)
178 int r
= (s
& 0xffff) + ((s
& 0xffffffff) >> 16);
179 int checksum
= (r
& 0xffff) + (r
>> 16);
181 memcpy (resstream
, &checksum
, sizeof checksum
);
182 *length
= total_bytes
;
189 /* Print the checksum and size (in 1024 byte blocks) to stdout.
190 If ARGS is true, also print the FILE name. */
193 output_bsd (char const *file
, int binary_file
, void const *digest
,
194 bool raw
, bool tagged
, unsigned char delim
, bool args
,
199 /* Output in network byte order (big endian). */
200 uint16_t out_int
= SWAP (*(uint16_t *)digest
);
201 fwrite (&out_int
, 1, 16/8, stdout
);
205 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
206 printf ("%05d %5s", *(int *)digest
,
207 human_readable (length
, hbuf
, human_ceiling
, 1, 1024));
209 printf (" %s", file
);
213 /* Print the checksum and size (in 512 byte blocks) to stdout.
214 If ARGS is true, also print the FILE name. */
217 output_sysv (char const *file
, int binary_file
, void const *digest
,
218 bool raw
, bool tagged
, unsigned char delim
, bool args
,
223 /* Output in network byte order (big endian). */
224 uint16_t out_int
= SWAP (*(uint16_t *)digest
);
225 fwrite (&out_int
, 1, 16/8, stdout
);
229 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
230 printf ("%d %s", *(int *)digest
,
231 human_readable (length
, hbuf
, human_ceiling
, 1, 512));
233 printf (" %s", file
);