1 /* sum -- checksum and count the blocks in a file
2 Copyright (C) 1986-2022 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>
29 /* Calculate the checksum and the size in bytes of stream STREAM.
30 Return -1 on error, 0 on success. */
33 bsd_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
37 int checksum
= 0; /* The checksum mod 2^16. */
38 uintmax_t total_bytes
= 0; /* The number of bytes. */
39 static const size_t buffer_length
= 32768;
40 uint8_t *buffer
= malloc (buffer_length
);
53 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
56 if (buffer_length
== sum
)
70 for (size_t i
= 0; i
< sum
; i
++)
72 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
73 checksum
+= buffer
[i
];
74 checksum
&= 0xffff; /* Keep it within bounds. */
76 if (total_bytes
+ sum
< total_bytes
)
86 for (size_t i
= 0; i
< sum
; i
++)
88 checksum
= (checksum
>> 1) + ((checksum
& 1) << 15);
89 checksum
+= buffer
[i
];
90 checksum
&= 0xffff; /* Keep it within bounds. */
92 if (total_bytes
+ sum
< total_bytes
)
99 memcpy (resstream
, &checksum
, sizeof checksum
);
100 *length
= total_bytes
;
107 /* Calculate the checksum and the size in bytes of stream STREAM.
108 Return -1 on error, 0 on success. */
111 sysv_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
115 uintmax_t total_bytes
= 0;
116 static const size_t buffer_length
= 32768;
117 uint8_t *buffer
= malloc (buffer_length
);
122 /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
133 n
= fread (buffer
+ sum
, 1, buffer_length
- sum
, stream
);
136 if (buffer_length
== sum
)
150 for (size_t i
= 0; i
< sum
; i
++)
152 if (total_bytes
+ sum
< total_bytes
)
162 for (size_t i
= 0; i
< sum
; i
++)
164 if (total_bytes
+ sum
< total_bytes
)
171 int r
= (s
& 0xffff) + ((s
& 0xffffffff) >> 16);
172 int checksum
= (r
& 0xffff) + (r
>> 16);
174 memcpy (resstream
, &checksum
, sizeof checksum
);
175 *length
= total_bytes
;
182 /* Print the checksum and size (in 1024 byte blocks) to stdout.
183 If ARGS is true, also print the FILE name. */
186 output_bsd (char const *file
, int binary_file
, void const *digest
,
187 bool tagged
, unsigned char delim
, bool args
,
191 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
192 printf ("%05d %5s", *(int *)digest
,
193 human_readable (length
, hbuf
, human_ceiling
, 1, 1024));
195 printf (" %s", file
);
199 /* Print the checksum and size (in 512 byte blocks) to stdout.
200 If ARGS is true, also print the FILE name. */
203 output_sysv (char const *file
, int binary_file
, void const *digest
,
204 bool tagged
, unsigned char delim
, bool args
,
208 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
209 printf ("%d %s", *(int *)digest
,
210 human_readable (length
, hbuf
, human_ceiling
, 1, 512));
212 printf (" %s", file
);