Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dsync/dcmp: support symlinks targets changes #618

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
31 changes: 27 additions & 4 deletions src/dcmp/dcmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1084,15 +1084,38 @@ 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);
}
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