File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / hashlink.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 2 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

/*
   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>