| 849 | } |
| 850 | |
| 851 | extern "C" int ceph_open_snapdiff(struct ceph_mount_info* cmount, |
| 852 | const char* root_path, |
| 853 | const char* rel_path, |
| 854 | const char* snap1, |
| 855 | const char* snap2, |
| 856 | struct ceph_snapdiff_info* out) |
| 857 | { |
| 858 | if (!cmount->is_mounted()) { |
| 859 | /* we set errno to signal errors. */ |
| 860 | errno = ENOTCONN; |
| 861 | return -errno; |
| 862 | } |
| 863 | if (!out || !root_path || !rel_path || |
| 864 | !snap1 || !*snap1 || !snap2 || !*snap2) { |
| 865 | errno = EINVAL; |
| 866 | return -errno; |
| 867 | } |
| 868 | out->cmount = cmount; |
| 869 | out->dir1 = out->dir_aux = nullptr; |
| 870 | |
| 871 | char full_path1[PATH_MAX]; |
| 872 | char snapdir[PATH_MAX]; |
| 873 | cmount->conf_get("client_snapdir", snapdir, sizeof(snapdir) - 1); |
| 874 | int n = snprintf(full_path1, PATH_MAX, |
| 875 | "%s/%s/%s/%s", root_path, snapdir, snap1, rel_path); |
| 876 | if (n < 0 || n == PATH_MAX) { |
| 877 | errno = ENAMETOOLONG; |
| 878 | return -errno; |
| 879 | } |
| 880 | char full_path2[PATH_MAX]; |
| 881 | n = snprintf(full_path2, PATH_MAX, |
| 882 | "%s/%s/%s/%s", root_path, snapdir, snap2, rel_path); |
| 883 | if (n < 0 || n == PATH_MAX) { |
| 884 | errno = ENAMETOOLONG; |
| 885 | return -errno; |
| 886 | } |
| 887 | |
| 888 | int r = ceph_opendir(cmount, full_path1, &(out->dir1)); |
| 889 | if (r != 0) { |
| 890 | //it's OK to have one of the snap paths absent - attempting another one |
| 891 | r = ceph_opendir(cmount, full_path2, &(out->dir1)); |
| 892 | if (r != 0) { |
| 893 | // both snaps are absent, giving up |
| 894 | errno = ENOENT; |
| 895 | return -errno; |
| 896 | } |
| 897 | std::swap(snap1, snap2); // will use snap1 to learn snap_other below |
| 898 | } else { |
| 899 | // trying to open second snapshot to learn snapid and |
| 900 | // get the entry loaded into the client cache if any. |
| 901 | r = ceph_opendir(cmount, full_path2, &(out->dir_aux)); |
| 902 | //paranoic, rely on this value below |
| 903 | out->dir_aux = r == 0 ? out->dir_aux : nullptr; |
| 904 | } |
| 905 | if (!out->dir_aux) { |
| 906 | // now trying to learn the second snapshot's id by using snapshot's root |
| 907 | n = snprintf(full_path2, PATH_MAX, |
| 908 | "%s/%s/%s", root_path, snapdir, snap2); |