Skip to content

Commit f2394ab

Browse files
committed
md5: support all OpenSSL EVP digests
Add option "-c digest" to use any of supported EVP message digests inplace of insecure MD5. This generates checksum files named by the digest by default, e.g .SHA256.CHECKSUMS For backwards compatibility -m translates to -c md5 The "-M filename" option to rename the checksums file remains untouched
1 parent da1ba1a commit f2394ab

File tree

5 files changed

+131
-58
lines changed

5 files changed

+131
-58
lines changed

cpdup.1

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
.Nm
1313
.Op Fl C
1414
.Op Fl v Ns Op Cm v Ns Op Cm v
15+
.Op Fl c
1516
.Op Fl d
1617
.Op Fl n
1718
.Op Fl u
@@ -73,6 +74,27 @@ modifications made to the destination.
7374
.Fl vvv
7475
will cause all files and directories to be reported whether or not
7576
modifications are made.
77+
.It Fl c Ar digest
78+
Generate and maintain a checksum file using the specified message
79+
.Ar digest
80+
called
81+
.Pa \&.DIGEST.CHECKSUMS
82+
in each directory on the source where
83+
.Pa DIGEST
84+
is replaced by the upperscale name of the message digest used.
85+
An alternate file name may be specified with the
86+
.Fl M Ar file
87+
option. Supported are all localy available OpenSSL
88+
.Xr EVP 7
89+
message digests, e.g. md5, rmd160, sha1, sha256 or sha512.
90+
A checksum check is done on each file of the destination when the destination
91+
appears to be the same as the source. If the check fails,
92+
the source is recopied to the destination. When you specify a destination
93+
directory, the checksum file is only updated as needed and may not be updated
94+
even if modifications are made to a source file. If you do not specify a
95+
destination directory the
96+
.Nm
97+
command forcefully regenerates the checksum for every file in the source.
7698
.It Fl d
7799
Print directories as they are being traversed.
78100
Useful to watch the progress;
@@ -120,21 +142,14 @@ Quiet operation.
120142
.It Fl o
121143
Do not remove any files, just overwrite/add.
122144
.It Fl m
123-
Generate and maintain a MD5 checkfile called
124-
.Pa \&.MD5.CHECKSUMS
125-
in each directory on the source
126-
and do an MD5 check on each file of the destination when the destination
127-
appears to be the same as the source. If the check fails,
128-
the source is recopied to the destination. When you specify a destination
129-
directory, the MD5 checkfile is only updated as needed and may not be updated
130-
even if modifications are made to a source file. If you do not specify a
131-
destination directory the
132-
.Nm
133-
command forcefully regenerates the MD5 checkfile for every file in the source.
134-
.It Fl M Ar file
135145
Works the same as
136-
.Fl m
137-
but allows you to specify the name of the MD5 checkfile.
146+
.Fl c Ar md5
147+
for compatibility purposes
148+
.It Fl M Ar file
149+
allows you to specify the name of the checksum file generated by options
150+
.Fl c
151+
or
152+
.Fl m.
138153
.It Fl H Ar path
139154
.Nm
140155
will create a hardlink from a file found under

src/cpdup.c

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@
5959
* standard wildcarded ( ? / * style, NOT regex) exclusions.
6060
* - tries to play permissions and flags smart in regards to overwriting
6161
* schg files and doing related stuff.
62-
* - Can do MD5 consistancy checks
62+
* - Can do checksum consistancy checks with any supported OpenSSL EVP
63+
* message digest
6364
* - Is able to do incremental mirroring/backups via hardlinks from
6465
* the 'previous' version (supplied with -H path).
6566
*/
6667

6768
#include "cpdup.h"
6869
#include "hclink.h"
6970
#include "hcproto.h"
71+
#include <ctype.h>
7072

7173
#define HSIZE 8192
7274
#define HMASK (HSIZE-1)
@@ -188,23 +190,43 @@ int64_t CountLinkedItems;
188190
static struct HostConf SrcHost;
189191
static struct HostConf DstHost;
190192

193+
#ifndef NOMD5
194+
const EVP_MD *CsumAlgo;
195+
#endif
196+
191197
int
192198
main(int ac, char **av)
193199
{
194200
int i;
201+
#ifndef NOMD5
202+
int len;
203+
#endif
195204
int opt;
196205
char *src = NULL;
197206
char *dst = NULL;
198207
char *ptr;
199208
struct timeval start;
200209
struct copy_info info;
201210

211+
#ifndef NOMD5
212+
char *MD5AlgoStr;
213+
char *MD5CacheFileStr;
214+
const char *CsumAlgoStrArg = NULL;
215+
const char *MD5CacheFileArg = NULL;
216+
#endif
217+
202218
signal(SIGPIPE, SIG_IGN);
203219

204220
gettimeofday(&start, NULL);
205221
opterr = 0;
206-
while ((opt = getopt(ac, av, ":CdF:fH:hIi:j:lM:mnoqRSs:uVvX:x")) != -1) {
222+
while ((opt = getopt(ac, av, ":c:CdF:fH:hIi:j:lM:mnoqRSs:uVvX:x")) != -1) {
207223
switch (opt) {
224+
case 'c':
225+
UseMD5Opt = 1;
226+
#ifndef NOMD5
227+
CsumAlgoStrArg = optarg;
228+
#endif
229+
break;
208230
case 'C':
209231
CompressOpt = 1;
210232
break;
@@ -241,11 +263,17 @@ main(int ac, char **av)
241263
break;
242264
case 'M':
243265
UseMD5Opt = 1;
244-
MD5CacheFile = optarg;
266+
if (strnlen(optarg, PATH_MAX) == PATH_MAX)
267+
fatal("Cache file string too long");
268+
#ifndef NOMD5
269+
MD5CacheFileArg = optarg;
270+
#endif
245271
break;
246272
case 'm':
247273
UseMD5Opt = 1;
248-
MD5CacheFile = ".MD5.CHECKSUMS";
274+
#ifndef NOMD5
275+
CsumAlgoStrArg = "MD5";
276+
#endif
249277
break;
250278
case 'n':
251279
NotForRealOpt = 1;
@@ -303,6 +331,27 @@ main(int ac, char **av)
303331
if (ac > 2)
304332
fatal("too many arguments");
305333

334+
#ifndef NOMD5
335+
if (UseMD5Opt) {
336+
if (CsumAlgoStrArg == NULL)
337+
CsumAlgoStrArg = "MD5";
338+
CsumAlgo = EVP_get_digestbyname(CsumAlgoStrArg);
339+
if (CsumAlgo == NULL)
340+
fatal("Unknown digest algorithm: %s", CsumAlgoStrArg);
341+
len = strlen(CsumAlgoStrArg);
342+
CsumAlgoStr = malloc(len + 1);
343+
for (i = 0; i < len; i++)
344+
CsumAlgoStr[i] = toupper(CsumAlgoStrArg[i]);
345+
CsumAlgoStr[i] = '\0';
346+
if (MD5CacheFileArg == NULL) {
347+
if (asprintf(&MD5CacheFileStr, ".%s.CHECKSUMS", CsumAlgoStr) < 0)
348+
fatal("Memory allocation error\n");
349+
} else
350+
MD5CacheFileStr = strdup(MD5CacheFileArg);
351+
MD5CacheFile = MD5CacheFileStr;
352+
}
353+
#endif
354+
306355
/*
307356
* If we are told to go into slave mode, run the HC protocol
308357
*/
@@ -320,7 +369,7 @@ main(int ac, char **av)
320369
SrcHost.host = src;
321370
src = ptr;
322371
if (UseMD5Opt)
323-
fatal("The MD5 options are not currently supported for remote sources");
372+
fatal("The checksum options are not currently supported for remote sources");
324373
if (hc_connect(&SrcHost, ReadOnlyOpt) < 0)
325374
exit(1);
326375
} else {
@@ -339,8 +388,8 @@ main(int ac, char **av)
339388
}
340389

341390
/*
342-
* dst may be NULL only if -m option is specified,
343-
* which forces an update of the MD5 checksums
391+
* dst may be NULL only if -c checksum or -m option is specified,
392+
* which forces an update of the checksums
344393
*/
345394
if (dst == NULL && UseMD5Opt == 0) {
346395
fatal(NULL);
@@ -830,7 +879,7 @@ DoCopy(copy_info_t info, struct stat *stat1, int depth)
830879
OwnerMatch(stat1, &st2)
831880
#ifndef NOMD5
832881
&& (UseMD5Opt == 0 || !S_ISREG(stat1->st_mode) ||
833-
(mres = md5_check(spath, dpath)) == 0)
882+
(mres = md5_check(CsumAlgo, spath, dpath)) == 0)
834883
#endif
835884
&& (ValidateOpt == 0 || !S_ISREG(stat1->st_mode) ||
836885
validate_check(spath, dpath) == 0)
@@ -858,7 +907,7 @@ DoCopy(copy_info_t info, struct stat *stat1, int depth)
858907
if (VerboseOpt >= 3) {
859908
#ifndef NOMD5
860909
if (UseMD5Opt) {
861-
logstd("%-32s md5-nochange",
910+
logstd("%-32s checksum-nochange",
862911
(dpath ? dpath : spath));
863912
} else
864913
#endif
@@ -1063,22 +1112,22 @@ DoCopy(copy_info_t info, struct stat *stat1, int depth)
10631112
}
10641113
} else if (dpath == NULL) {
10651114
/*
1066-
* If dpath is NULL, we are just updating the MD5
1115+
* If dpath is NULL, we are just updating the checksum
10671116
*/
10681117
#ifndef NOMD5
10691118
if (UseMD5Opt && S_ISREG(stat1->st_mode)) {
1070-
mres = md5_update(spath);
1119+
mres = md5_update(CsumAlgo, spath);
10711120

10721121
if (mres < 0) {
1073-
logerr("%-32s md5-CHECK-FAILED\n", spath);
1122+
logerr("%-32s checksum-CHECK-FAILED\n", spath);
10741123
} else {
10751124
if (VerboseOpt > 1) {
10761125
if (mres > 0)
1077-
logstd("%-32s md5-update\n", spath);
1126+
logstd("%-32s checksum-update\n", spath);
10781127
else
1079-
logstd("%-32s md5-ok\n", spath);
1128+
logstd("%-32s checksum-ok\n", spath);
10801129
} else if (!QuietOpt && mres > 0) {
1081-
logstd("%-32s md5-update\n", spath);
1130+
logstd("%-32s checksum-update\n", spath);
10821131
}
10831132
}
10841133
}
@@ -1099,7 +1148,7 @@ DoCopy(copy_info_t info, struct stat *stat1, int depth)
10991148
* Handle check failure message.
11001149
*/
11011150
if (mres < 0)
1102-
logerr("%-32s md5-CHECK-FAILED\n", (dpath) ? dpath : spath);
1151+
logerr("%-32s checksum-CHECK-FAILED\n", (dpath) ? dpath : spath);
11031152
#endif
11041153

11051154
/*

src/cpdup.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
#include <fnmatch.h>
5353
#include <assert.h>
5454

55+
#ifndef NOMD5
56+
#include <openssl/evp.h>
57+
#endif
58+
5559
#ifdef __linux
5660

5761
/*
@@ -100,8 +104,8 @@ int32_t hc_bswap32(int32_t var);
100104
int64_t hc_bswap64(int64_t var);
101105

102106
#ifndef NOMD5
103-
int md5_update(const char *spath);
104-
int md5_check(const char *spath, const char *dpath);
107+
int md5_update(const EVP_MD *algo, const char *spath);
108+
int md5_check(const EVP_MD *algo, const char *spath, const char *dpath);
105109
void md5_flush(void);
106110
#endif
107111

0 commit comments

Comments
 (0)