/*
Copyright (C) Cronosys, LLC 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This file contains code used by the --link-by-hash option. */
#include "rsync.h"
#include "inums.h"
extern int protocol_version;
extern char *link_by_hash_dir;
extern char sender_file_sum[MAX_DIGEST_LEN];
char link_by_hash_extra_sum[MAX_DIGEST_LEN]; /* Only used when md4 sums are in the transfer */
#ifdef HAVE_LINK
/* This function is always called after a file is received, so the
* sender_file_sum buffer has whatever the last checksum was for the
* transferred file. */
void link_by_hash(const char *fname, const char *fnametmp, struct file_struct *file)
{
STRUCT_STAT st;
char *hashname, *last_slash, *num_str;
const char *hex;
int num = 0;
/* We don't bother to hard-link 0-length files. */
if (F_LENGTH(file) == 0)
return;
hex = sum_as_hex(5, protocol_version >= 30 ? sender_file_sum : link_by_hash_extra_sum, 0);
if (asprintf(&hashname, "%s/%.3s/%.3s/%.3s/%s.%s.000000",
link_by_hash_dir, hex, hex+3, hex+6, hex+9, big_num(F_LENGTH(file))) < 0)
{
out_of_memory("make_hash_name");
}
last_slash = strrchr(hashname, '/');
num_str = strrchr(last_slash, '.') + 1;
while (1) {
if (num >= 999999) { /* Surely we'll never reach this... */
if (DEBUG_GTE(HASHLINK, 1))
rprintf(FINFO, "link-by-hash: giving up after \"%s\".\n", hashname);
goto cleanup;
}
if (num > 0 && DEBUG_GTE(HASHLINK, 1))
rprintf(FINFO, "link-by-hash: max link count exceeded, starting new file \"%s\".\n", hashname);
snprintf(num_str, 7, "%d", num++);
if (do_stat(hashname, &st) < 0)
break;
if (do_link(hashname, fnametmp) < 0) {
if (errno == EMLINK)
continue;
rsyserr(FERROR, errno, "link \"%s\" -> \"%s\"", hashname, full_fname(fname));
} else {
if (DEBUG_GTE(HASHLINK, 2))
rprintf(FINFO, "link-by-hash (existing): \"%s\" -> %s\n", hashname, full_fname(fname));
robust_rename(fnametmp, fname, NULL, 0644);
}
goto cleanup;
}
if (DEBUG_GTE(HASHLINK, 2))
rprintf(FINFO, "link-by-hash (new): %s -> \"%s\"\n", full_fname(fname), hashname);
if (do_link(fname, hashname) < 0
&& (errno != ENOENT || make_path(hashname, MKP_DROP_NAME) < 0 || do_link(fname, hashname) < 0))
rsyserr(FERROR, errno, "link \"%s\" -> \"%s\"", full_fname(fname), hashname);
cleanup:
free(hashname);
}
#endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>