Skip to content

Commit

Permalink
dsync/dcmp: support symlinks targets changes
Browse files Browse the repository at this point in the history
Update dsync and dcmp to detect a symlinks targets changes. In this
case, the symlinks are reported to be different by dcmp and are updated
by dsync.

Note this works for dsync both with or without c, --contents.

New function mfu_compare_symlinks() is introduced in library API to
factorize the logic for all commands.

Signed-off-by: Rémi Palancher <[email protected]>
  • Loading branch information
rezib committed Jan 28, 2025
1 parent 4581ec5 commit 8115e8b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 14 deletions.
28 changes: 28 additions & 0 deletions src/common/mfu_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,34 @@ int mfu_compare_contents(
return rc;
}

/* compares targets of two symlinks, returns 0 if equal, negative or positive
* value if different, -1 on error when reading symlink. */
int mfu_compare_symlinks(
const char* src_name, /* IN - path name to source file */
const char* dst_name, /* IN - path name to destination file */
mfu_file_t* mfu_src_file, /* IN - I/O filesystem functions to use for source */
mfu_file_t* mfu_dst_file) /* IN - I/O filesystem functions to use for destination */
{
char src_target[PATH_MAX + 1], dst_target[PATH_MAX + 1];
ssize_t readlink_rc = mfu_file_readlink(src_name, src_target, sizeof(src_target) - 1, mfu_src_file);
if(readlink_rc < 0) {
MFU_LOG(MFU_LOG_ERR, "Failed to read source link `%s' readlink() (errno=%d %s)",
src_name, errno, strerror(errno)
);
return -1;
}
readlink_rc = mfu_file_readlink(dst_name, dst_target, sizeof(dst_target) - 1, mfu_dst_file);
if(readlink_rc < 0) {
MFU_LOG(MFU_LOG_ERR, "Failed to read destination link `%s' readlink() (errno=%d %s)",
dst_name, errno, strerror(errno)
);
return -1;
}
/* ensure that strings end with NUL */
src_target[readlink_rc] = dst_target[readlink_rc] = '\0';
return strcmp(src_target, dst_target);
}

/* uses the lustre api to obtain stripe count and stripe size of a file */
int mfu_stripe_get(const char *path, uint64_t *stripe_size, uint64_t *stripe_count)
{
Expand Down
9 changes: 9 additions & 0 deletions src/common/mfu_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,15 @@ int mfu_compare_contents(
mfu_file_t* mfu_dst_file /* IN - I/O filesystem functions to use for destination */
);

/* compares targets of two symlinks, returns 0 if equal, negative or positive
* value if different, -1 on error when reading symlink. */
int mfu_compare_symlinks(
const char* src_name, /* IN - path name to souce file */
const char* dst_name, /* IN - path name to destination file */
mfu_file_t* mfu_src_file, /* IN - I/O filesystem functions to use for source */
mfu_file_t* mfu_dst_file /* IN - I/O filesystem functions to use for destination */
);

/* uses the lustre api to obtain stripe count and stripe size of a file */
int mfu_stripe_get(const char *path, uint64_t *stripe_size, uint64_t *stripe_count);

Expand Down
23 changes: 19 additions & 4 deletions src/dcmp/dcmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1084,15 +1084,30 @@ static int dcmp_strmap_compare(
continue;
}

/* for now, we can only compare content of regular files */
/* TODO: add support for symlinks */
if (! S_ISREG(dst_mode)) {
/* not regular file, take them as common content */
/* for now, we can only compare content of regular files and symlinks */
if (! S_ISREG(dst_mode) && ! S_ISLNK(dst_mode)) {
/* not regular file or symlink, take them as common content */
dcmp_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_COMMON);
dcmp_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_COMMON);
continue;
}

/* For symlinks, compare targets */
if (S_ISLNK(dst_mode)) {
if (mfu_compare_symlinks(mfu_flist_file_get_name(src_list, src_index),
mfu_flist_file_get_name(dst_list, dst_index),
mfu_src_file, mfu_dst_file) == 0) {
/* update to say contents of the symlinks were found to be the same */
dcmp_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_COMMON);
dcmp_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_COMMON);
} else {
/* update to say contents of the symlinks were found to be different */
dcmp_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_DIFFER);
dcmp_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_DIFFER);
}
continue;
}

dcmp_state state;
tmp_rc = dcmp_strmap_item_state(src_map, key, DCMPF_SIZE, &state);
assert(tmp_rc == 0);
Expand Down
46 changes: 36 additions & 10 deletions src/dsync/dsync.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ static int dsync_strmap_compare_data(
/* get chunk size for copying files (just hard-coded for now) */
uint64_t chunk_size = copy_opts->chunk_size;

/* get the linked list of file chunks for the src and dest */
/* get the linked list of regular file chunks for the src and dest */
mfu_file_chunk* src_head = mfu_file_chunk_list_alloc(src_compare_list, chunk_size);
mfu_file_chunk* dst_head = mfu_file_chunk_list_alloc(dst_compare_list, chunk_size);

Expand Down Expand Up @@ -963,8 +963,18 @@ static int dsync_strmap_compare_data(
/* ignore prefix portion of path to use as key */
name += strlen_prefix;

/* get comparison results for this item */
int flag = results[i];
mfu_filetype type = mfu_flist_file_get_type(src_compare_list, i);
int flag = 0;
if (type == MFU_TYPE_LINK) {
/* symlinks have not been compared above, their targets are compared now */
flag = mfu_compare_symlinks(mfu_flist_file_get_name(src_compare_list, i),
mfu_flist_file_get_name(dst_compare_list, i),
mfu_src_file, mfu_dst_file);
} else {
/* get comparison results for this regular file */
flag = results[i];
}


/* set flag in strmap to record status of file */
if (flag != 0) {
Expand All @@ -973,7 +983,7 @@ static int dsync_strmap_compare_data(
dsync_strmap_item_update(dst_map, name, DCMPF_CONTENT, DCMPS_DIFFER);

/* mark file to be deleted from destination, copied from source */
if (use_hardlinks) {
if (use_hardlinks || type == MFU_TYPE_LINK) {
mfu_flist_file_copy(dst_compare_list, i, dst_remove_list);
mfu_flist_file_copy(src_compare_list, i, src_cp_list);
}
Expand Down Expand Up @@ -1171,7 +1181,9 @@ static int dsync_strmap_compare_lite(
mfu_flist dst_remove_list,
strmap* dst_map,
size_t strlen_prefix,
bool use_hardlinks)
bool use_hardlinks,
mfu_file_t* mfu_src_file,
mfu_file_t* mfu_dst_file)
{
/* assume we'll succeed */
int rc = 0;
Expand All @@ -1184,6 +1196,7 @@ static int dsync_strmap_compare_lite(
for (idx = 0; idx < size; idx++) {
/* lookup name of file based on id to send to strmap updata call */
const char* name = mfu_flist_file_get_name(src_compare_list, idx);
const mfu_filetype type = mfu_flist_file_get_type(src_compare_list, idx);

/* ignore prefix portion of path to use as key */
name += strlen_prefix;
Expand Down Expand Up @@ -1211,6 +1224,20 @@ static int dsync_strmap_compare_lite(
mfu_flist_file_copy(dst_compare_list, idx, dst_remove_list);
mfu_flist_file_copy(src_compare_list, idx, src_cp_list);
}
/* if symlink, check if targets of source and destination files match. If not, mark the
* files as being different. */
} else if (type == MFU_TYPE_LINK) {
if (mfu_compare_symlinks(mfu_flist_file_get_name(src_compare_list, idx),
mfu_flist_file_get_name(dst_compare_list, idx),
mfu_src_file, mfu_dst_file) == 0) {
/* update to say contents of the files were found to be the same */
dsync_strmap_item_update(src_map, name, DCMPF_CONTENT, DCMPS_COMMON);
dsync_strmap_item_update(dst_map, name, DCMPF_CONTENT, DCMPS_COMMON);
} else {
/* update to say contents of the symlinks were found to be different */
dsync_strmap_item_update(src_map, name, DCMPF_CONTENT, DCMPS_DIFFER);
dsync_strmap_item_update(dst_map, name, DCMPF_CONTENT, DCMPS_DIFFER);
}
} else {
/* update to say contents of the files were found to be the same */
dsync_strmap_item_update(src_map, name, DCMPF_CONTENT, DCMPS_COMMON);
Expand Down Expand Up @@ -1748,10 +1775,9 @@ static int dsync_strmap_compare(
continue;
}

/* for now, we can only compare content of regular files */
/* TODO: add support for symlinks */
if (! S_ISREG(dst_mode)) {
/* not regular file, take them as common content */
/* for now, we can only compare content of regular files and symlinks */
if (! S_ISREG(dst_mode) && !S_ISLNK(dst_mode)) {
/* not regular file or symlink, take them as common content */
dsync_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_COMMON);
dsync_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_COMMON);
continue;
Expand Down Expand Up @@ -1832,7 +1858,7 @@ static int dsync_strmap_compare(
* adds files to remove and copy lists if different */
tmp_rc = dsync_strmap_compare_lite(src_compare_list, src_cp_list, dst_same_list,
src_map, dst_compare_list, dst_remove_list, dst_map,
strlen_prefix, use_hardlinks
strlen_prefix, use_hardlinks, mfu_src_file, mfu_dst_file
);
if (tmp_rc < 0) {
rc = -1;
Expand Down

0 comments on commit 8115e8b

Please sign in to comment.