csync: Do not ignore hard links anymore

There is no reason to ignore them. Downloading a file that is hardlinked
will break the link.

Will solve syncing NTFS directories #3241
This commit is contained in:
Olivier Goffart 2015-07-01 12:54:56 +02:00
parent 4a541a9ab4
commit 575ca50aac
7 changed files with 53 additions and 50 deletions

View file

@ -100,7 +100,6 @@ enum csync_status_codes_e {
CSYNC_STATUS_ABORTED,
/* Codes for file individual status: */
CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK,
CSYNC_STATUS_INDIVIDUAL_IS_HARDLINK,
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME,
@ -174,7 +173,7 @@ enum csync_vio_file_stat_fields_e {
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
// CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
@ -213,7 +212,6 @@ struct csync_vio_file_stat_s {
dev_t device;
uint64_t inode;
nlink_t nlink;
int fields; // actually enum csync_vio_file_stat_fields_e fields;
enum csync_vio_file_type_e type;

View file

@ -183,7 +183,6 @@ struct csync_file_stat_s {
size_t pathlen; /* u64 */
uint64_t inode; /* u64 */
mode_t mode; /* u32 */
int nlink; /* u32 */
int type; /* u32 */
int child_modified;/*bool*/
int should_update_etag; /*bool */

View file

@ -210,11 +210,6 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
/* check hardlink count */
if (type == CSYNC_FTW_TYPE_FILE ) {
if( fs->nlink > 1) {
st->instruction = CSYNC_INSTRUCTION_IGNORE;
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_HARDLINK;
goto out;
}
if (fs->mtime == 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
@ -442,7 +437,6 @@ out:
st->mode = fs->mode;
st->size = fs->size;
st->modtime = fs->mtime;
st->nlink = fs->nlink;
st->type = type;
st->etag = NULL;
if( fs->etag ) {

View file

@ -338,9 +338,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->ctime = sb.st_ctime;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
buf->nlink = sb.st_nlink;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
buf->size = sb.st_size;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;

View file

@ -167,7 +167,6 @@ static void teardown_rm(void **state) {
/* create a file stat, caller must free memory */
static csync_vio_file_stat_t* create_fstat(const char *name,
ino_t inode,
nlink_t nlink,
time_t mtime)
{
csync_vio_file_stat_t *fs = NULL;
@ -207,12 +206,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
fs->size = 157459;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
if (nlink == 0) {
fs->nlink = 1;
} else {
fs->nlink = nlink;
}
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
if (mtime == 0) {
@ -383,31 +376,6 @@ static void check_csync_detect_update_db_new(void **state)
csync_vio_file_stat_destroy(fs);
}
static void check_csync_detect_update_nlink(void **state)
{
CSYNC *csync = *state;
csync_file_stat_t *st;
csync_vio_file_stat_t *fs;
int rc;
/* create vio file stat with nlink greater than 1 */
fs = create_fstat("file.txt", 0, 7, 0);
assert_non_null(fs);
/* add it to local tree */
rc = _csync_detect_update(csync,
"/tmp/check_csync1/file.txt",
fs,
CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, 0);
/* the instruction should be set to ignore */
st = c_rbtree_node_data(csync->local.tree->root);
assert_int_equal(st->instruction, CSYNC_INSTRUCTION_IGNORE);
csync_vio_file_stat_destroy(fs);
}
static void check_csync_detect_update_null(void **state)
{
CSYNC *csync = *state;
@ -467,7 +435,6 @@ int torture_run_tests(void)
unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
unit_test_setup_teardown(check_csync_detect_update_nlink, setup, teardown_rm),
unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),

View file

@ -29,7 +29,16 @@ use ownCloud::Test;
use strict;
print "Hello, this is t4, a tester for A) files that cannot be stated and B) excluded files\n";
sub getInode($)
{
my ($filename) = @_;
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
return $ino;
}
print "Hello, this is t4, a tester for A) files that cannot be stated and B) excluded files C) hard links\n";
# stat error occours on windsows when the file is busy for example
initTesting();
@ -167,6 +176,48 @@ assertLocalAndRemoteDir( '', 0 );
assert(! -e localDir(). 'anotherdir' );
printInfo("Test hardlinks\n");
#make a hard link
mkdir( localDir() . 'subdir' );
createLocalFile( localDir() .'subdir/original.data', 1568 );
system( "ln " . localDir() . 'subdir/original.data ' . localDir() . 'file.link');
csync();
assertLocalAndRemoteDir( '', 0 );
my $inode = getInode(localDir() . 'subdir/original.data');
my $inode2 = getInode(localDir() . 'file.link');
assert( $inode == $inode2, "Inode is not the same!");
printInfo("Modify hard link\n");
system( "echo 'another line' >> " . localDir() . 'file.link');
csync();
assertLocalAndRemoteDir( '', 0 );
my $inode1 = getInode(localDir() .'subdir/original.data');
$inode2 = getInode( localDir() .'file.link');
assert( $inode == $inode1, "Inode is not the same!");
assert( $inode == $inode2, "Inode is not the same!");
printInfo("Rename a hard link\n");
move( localDir() . 'subdir/original.data', localDir() . 'subdir/kernelcrash.txt' );
csync();
assertLocalAndRemoteDir( '', 0 );
$inode1 = getInode(localDir() .'subdir/kernelcrash.txt');
$inode2 = getInode(localDir() .'file.link');
assert( $inode == $inode1, "Inode is not the same!");
assert( $inode == $inode2, "Inode is not the same!");
printInfo("Modify a hard link on the server\n");
put_to_dir( '/tmp/kernelcrash.txt', 'subdir' );
csync();
assertLocalAndRemoteDir( '', 0 );
$inode1 = getInode(localDir() .'subdir/kernelcrash.txt');
$inode2 = getInode( localDir() .'file.link');
# only the first inode must change
print(" $inode $inode1 $inode2" );
assert( $inode != $inode1, "Inode did not change");
assert( $inode == $inode2, "Inode is not the same!");
cleanup();
# --

View file

@ -367,9 +367,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK:
item->_errorString = tr("Symbolic links are not supported in syncing.");
break;
case CSYNC_STATUS_INDIVIDUAL_IS_HARDLINK:
item->_errorString = tr("Hard links are not supported in syncing.");
break;
case CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST:
item->_errorString = tr("File is listed on the ignore list.");
break;