1 /* sum -- checksum and count the blocks in a file
2 Copyright (C) 1986-2024 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 /* Calculate the checksum and the size in bytes of stream STREAM.
31 Return -1 on error, 0 on success. */
34 bsd_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
38 int checksum
= 0; /* The checksum mod 2^16. */
39 uintmax_t total_bytes
= 0; /* The number of bytes. */
40 static const size_t buffer_length
= 32768;
41 uint8_t *buffer
= malloc (buffer_length
);
54 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
57 if (buffer_length
== sum
)
71 for (size_t i
= 0; i
< sum
; i
++)
73 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
74 checksum
+= buffer
[i
];
75 checksum
&= 0xffff; /* Keep it within bounds. */
77 if (total_bytes
+ sum
< total_bytes
)
87 for (size_t i
= 0; i
< sum
; i
++)
89 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
90 checksum
+= buffer
[i
];
91 checksum
&= 0xffff; /* Keep it within bounds. */
93 if (total_bytes
+ sum
< total_bytes
)
100 memcpy (resstream
, &checksum
, sizeof checksum
);
101 *length
= total_bytes
;
108 /* Calculate the checksum and the size in bytes of stream STREAM.
109 Return -1 on error, 0 on success. */
112 sysv_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
116 uintmax_t total_bytes
= 0;
117 static const size_t buffer_length
= 32768;
118 uint8_t *buffer
= malloc (buffer_length
);
123 /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
134 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
137 if (buffer_length
== sum
)
151 for (size_t i
= 0; i
< sum
; i
++)
153 if (total_bytes
+ sum
< total_bytes
)
163 for (size_t i
= 0; i
< sum
; i
++)
165 if (total_bytes
+ sum
< total_bytes
)
172 int r
= (s
& 0xffff) + ((s
& 0xffffffff) >> 16);
173 int checksum
= (r
& 0xffff) + (r
>> 16);
175 memcpy (resstream
, &checksum
, sizeof checksum
);
176 *length
= total_bytes
;
183 /* Print the checksum and size (in 1024 byte blocks) to stdout.
184 If ARGS is true, also print the FILE name. */
187 output_bsd (char const *file
, int binary_file
, void const *digest
,
188 bool raw
, bool tagged
, unsigned char delim
, bool args
,
193 /* Output in network byte order (big endian). */
194 uint16_t out_int
= *(int *)digest
;
195 out_int
= htobe16 (out_int
);
196 fwrite (&out_int
, 1, 16/8, stdout
);
200 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
201 printf ("%05d %5s", *(int *)digest
,
202 human_readable (length
, hbuf
, human_ceiling
, 1, 1024));
204 printf (" %s", file
);
208 /* Print the checksum and size (in 512 byte blocks) to stdout.
209 If ARGS is true, also print the FILE name. */
212 output_sysv (char const *file
, int binary_file
, void const *digest
,
213 bool raw
, bool tagged
, unsigned char delim
, bool args
,
218 /* Output in network byte order (big endian). */
219 uint16_t out_int
= *(int *)digest
;
220 out_int
= htobe16 (out_int
);
221 fwrite (&out_int
, 1, 16/8, stdout
);
225 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
226 printf ("%d %s", *(int *)digest
,
227 human_readable (length
, hbuf
, human_ceiling
, 1, 512));
229 printf (" %s", file
);