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.

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 Feb 10, 2025
1 parent 4581ec5 commit 88f2fb5
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 8 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, 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 abs(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, 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
35 changes: 31 additions & 4 deletions src/dcmp/dcmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1084,15 +1084,42 @@ 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)) {
const char* src_name = mfu_flist_file_get_name(src_list, src_index);
const char* dst_name = mfu_flist_file_get_name(dst_list, dst_index);
int compare_rc = mfu_compare_symlinks(src_name, dst_name, mfu_src_file, mfu_dst_file);
if (compare_rc == -1) {
/* we hit an error while reading the symlink */
rc = -1;
MFU_LOG(MFU_LOG_ERR,
"Failed to readlink on %s and/or %s. Assuming contents are different.",
src_name, dst_name);

/* consider files to be different,
* they could be the same, but we'll draw attention to them this way */
compare_rc = 1;
}
if (!compare_rc) {
/* 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
39 changes: 35 additions & 4 deletions src/dsync/dsync.c
Original file line number Diff line number Diff line change
Expand Up @@ -1748,15 +1748,46 @@ 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;
}

/* if symlink, check if targets of source and destination files match. If not,
* mark the files as being different. */
if (S_ISLNK(dst_mode)) {
const char* src_name = mfu_flist_file_get_name(src_list, src_index);
const char* dst_name = mfu_flist_file_get_name(dst_list, dst_index);
int compare_rc = mfu_compare_symlinks(src_name, dst_name, mfu_src_file, mfu_dst_file);
if (compare_rc == -1) {
/* we hit an error while reading the symlink */
rc = -1;
MFU_LOG(MFU_LOG_ERR,
"Failed to readlink on %s and/or %s. Assuming contents are different.",
src_name, dst_name);
}
if (!compare_rc) {
/* update to say contents of the files were found to be the same */
dsync_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_COMMON);
dsync_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_COMMON);
} else {
/* update to say contents of the symlinks were found to be different */
dsync_strmap_item_update(src_map, key, DCMPF_CONTENT, DCMPS_DIFFER);
dsync_strmap_item_update(dst_map, key, DCMPF_CONTENT, DCMPS_DIFFER);

/* if the destinations are different then we need to remove the file in
* the dst directory, and replace it with the one in the src directory */
if (compare_rc > 0 !options.dry_run) {
mfu_flist_file_copy(src_list, src_index, src_cp_list);
mfu_flist_file_copy(dst_list, dst_index, dst_remove_list);
}
}
continue;
}

/* first check whether file sizes match */
dsync_state state;
tmp_rc = dsync_strmap_item_state(src_map, key, DCMPF_SIZE, &state);
Expand Down

0 comments on commit 88f2fb5

Please sign in to comment.