diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index b9780720e5a3..117258c58c9d 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -3376,30 +3376,24 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl, */ static int recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs, - nvlist_t *stream_nv) + nvlist_t *stream_nv, avl_tree_t *stream_avl) { int err; - nvpair_t *fselem = NULL; - nvlist_t *stream_fss; + nvpair_t *fselem = NULL, *nextfselem; + nvlist_t *local_nv, *stream_fss; + avl_tree_t *local_avl; + boolean_t recursive; + char fsname[ZFS_MAX_DATASET_NAME_LEN], *cp; - stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss"); + recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") == + ENOENT); + stream_fss = fnvlist_lookup_nvlist(stream_nv, "fss"); while ((fselem = nvlist_next_nvpair(stream_fss, fselem)) != NULL) { - zfs_handle_t *zhp = NULL; - uint64_t crypt; - nvlist_t *snaps, *props, *stream_nvfs = NULL; + nvlist_t *snaps, *stream_nvfs; nvpair_t *snapel = NULL; - boolean_t is_encroot, is_clone, stream_encroot; - char *cp; - const char *stream_keylocation = NULL; - char keylocation[MAXNAMELEN]; - char fsname[ZFS_MAX_DATASET_NAME_LEN]; - - keylocation[0] = '\0'; stream_nvfs = fnvpair_value_nvlist(fselem); snaps = fnvlist_lookup_nvlist(stream_nvfs, "snaps"); - props = fnvlist_lookup_nvlist(stream_nvfs, "props"); - stream_encroot = nvlist_exists(stream_nvfs, "is_encroot"); /* find a snapshot from the stream that exists locally */ err = ENOENT; @@ -3413,14 +3407,40 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs, break; } - if (err != 0) - continue; + if (err == 0) + break; + } - cp = strchr(fsname, '@'); - if (cp != NULL) - *cp = '\0'; + if (err != 0) + return (0); - zhp = zfs_open(hdl, fsname, ZFS_TYPE_DATASET); + cp = strchr(fsname, '@'); + if (cp != NULL) + *cp = '\0'; + + if ((err = gather_nvlist(hdl, fsname, NULL, NULL, + recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE, + B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0) + return (err); + + for (fselem = nvlist_next_nvpair(local_nv, NULL); fselem; + fselem = nextfselem) { + zfs_handle_t *zhp = NULL; + uint64_t crypt; + nvlist_t *stream_props, *snaps, *stream_nvfs = NULL, + *nvfs = NULL; + boolean_t is_encroot, is_clone, stream_encroot; + const char *stream_keylocation = NULL, *fs; + char keylocation[MAXNAMELEN]; + nvpair_t *snapelem; + + nextfselem = nvlist_next_nvpair(local_nv, fselem); + + nvfs = fnvpair_value_nvlist(fselem); + snaps = fnvlist_lookup_nvlist(nvfs, "snaps"); + fs = fnvlist_lookup_string(nvfs, "name"); + (void) printf("fs: %s\n", fs); + zhp = zfs_open(hdl, fs, ZFS_TYPE_DATASET); if (zhp == NULL) { err = ENOENT; goto error; @@ -3436,6 +3456,28 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs, continue; } + keylocation[0] = '\0'; + + /* + * First find the stream's fs + */ + for (snapelem = nvlist_next_nvpair(snaps, NULL); + snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) { + uint64_t thisguid; + + thisguid = fnvpair_value_uint64(snapelem); + stream_nvfs = fsavl_find(stream_avl, thisguid, NULL); + + if (stream_nvfs != NULL) + break; + } + + if (stream_nvfs == NULL) + continue; + + stream_props = fnvlist_lookup_nvlist(stream_nvfs, "props"); + stream_encroot = nvlist_exists(stream_nvfs, "is_encroot"); + /* * If the dataset is flagged as an encryption root, was not * received as a clone and is not currently an encryption root, @@ -3451,7 +3493,7 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs, } } - stream_keylocation = fnvlist_lookup_string(props, + stream_keylocation = fnvlist_lookup_string(stream_props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)); /* @@ -3518,14 +3560,14 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, boolean_t needagain, progress, recursive; const char *s1, *s2; + if (flags->dryrun) + return (0); + fromsnap = fnvlist_lookup_string(stream_nv, "fromsnap"); recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") == ENOENT); - if (flags->dryrun) - return (0); - again: needagain = progress = B_FALSE; @@ -3999,9 +4041,9 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, stream_nv, stream_avl, NULL); } - if (raw && softerr == 0 && *top_zfs != NULL) { + if (raw && softerr == 0 && *top_zfs != NULL && !flags->dryrun) { softerr = recv_fix_encryption_hierarchy(hdl, *top_zfs, - stream_nv); + stream_nv, stream_avl); } out: