Print this page
FITS: generating send-streams in portable format
This commit adds the command 'zfs fits-send', analogous to zfs send. The
generated send stream is compatible with the stream generated with that
from 'btrfs send' and can in principle easily be received to any filesystem.

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs/common/libzfs_sendrecv.c
          +++ new/usr/src/lib/libzfs/common/libzfs_sendrecv.c
↓ open down ↓ 3189 lines elided ↑ open up ↑
3190 3190                          }
3191 3191                  }
3192 3192                  if (zhp == NULL || clp == NULL || err)
3193 3193                          err = -1;
3194 3194          }
3195 3195          if (top_zfs)
3196 3196                  free(top_zfs);
3197 3197  
3198 3198          return (err);
3199 3199  }
     3200 +
     3201 +/*
     3202 + * Generate a fits stream for the dataset identified by the argument zhp.
     3203 + *
     3204 + * The content of the send stream is the snapshot identified by
     3205 + * 'tosnap'.  Incremental streams are requested from the snapshot identified
     3206 + * by "fromsnap" (if non-null)
     3207 + * Currently no recursive send is implemented
     3208 + */
     3209 +int
     3210 +zfs_fits_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
     3211 +    sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
     3212 +    void *cb_arg)
     3213 +{
     3214 +        char errbuf[1024];
     3215 +        char name[MAXPATHLEN];
     3216 +        zfs_cmd_t zc = { 0 };
     3217 +        libzfs_handle_t *hdl = zhp->zfs_hdl;
     3218 +        zfs_handle_t *thdl;
     3219 +
     3220 +        (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
     3221 +            "cannot send '%s'"), zhp->zfs_name);
     3222 +
     3223 +        if (fromsnap && fromsnap[0] == '\0') {
     3224 +                zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
     3225 +                    "zero-length incremental source"));
     3226 +                return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
     3227 +        }
     3228 +
     3229 +        (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, tosnap);
     3230 +        if ((thdl = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT)) == NULL) {
     3231 +                (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
     3232 +                    "WARNING: could not send %s@%s: does not exist\n"),
     3233 +                    zhp->zfs_name, tosnap);
     3234 +                return (B_TRUE);
     3235 +        }
     3236 +        zc.zc_sendobj = zfs_prop_get_int(thdl, ZFS_PROP_OBJSETID);
     3237 +        zfs_close(thdl);
     3238 +
     3239 +        if (fromsnap) {
     3240 +                (void) snprintf(name, sizeof (name), "%s@%s",
     3241 +                    zhp->zfs_name, fromsnap);
     3242 +                if ((thdl = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT)) == NULL) {
     3243 +                        (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
     3244 +                            "WARNING: could not send %s@%s:\n"
     3245 +                            "incremental source (%s@%s) does not exist\n"),
     3246 +                            zhp->zfs_name, tosnap,
     3247 +                            zhp->zfs_name, fromsnap);
     3248 +                        return (B_TRUE);
     3249 +                }
     3250 +                zc.zc_fromobj = zfs_prop_get_int(thdl, ZFS_PROP_OBJSETID);
     3251 +                zfs_close(thdl);
     3252 +        }
     3253 +
     3254 +        assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
     3255 +
     3256 +        (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
     3257 +            zhp->zfs_name, tosnap);
     3258 +        zc.zc_cookie = outfd;
     3259 +        zc.zc_obj = 0;
     3260 +
     3261 +        if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_FITS_SEND, &zc) != 0) {
     3262 +                char errbuf[1024];
     3263 +                (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
     3264 +                    "warning: cannot send '%s'"), zhp->zfs_name);
     3265 +
     3266 +                switch (errno) {
     3267 +                case EXDEV:
     3268 +                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     3269 +                            "not an earlier snapshot from the same fs"));
     3270 +                        return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
     3271 +                case ENOENT:
     3272 +                        if (zfs_dataset_exists(hdl, zc.zc_name,
     3273 +                            ZFS_TYPE_SNAPSHOT)) {
     3274 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     3275 +                                    "incremental source (@%s) does not exist"),
     3276 +                                    zc.zc_value);
     3277 +                        }
     3278 +                        return (zfs_error(hdl, EZFS_NOENT, errbuf));
     3279 +                case EDQUOT:
     3280 +                case EFBIG:
     3281 +                case EIO:
     3282 +                case ENOLINK:
     3283 +                case ENOSPC:
     3284 +                case ENOSTR:
     3285 +                case ENXIO:
     3286 +                case EPIPE:
     3287 +                case ERANGE:
     3288 +                case EFAULT:
     3289 +                case EROFS:
     3290 +                        zfs_error_aux(hdl, strerror(errno));
     3291 +                        return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
     3292 +                default:
     3293 +                        return (zfs_standard_error(hdl, errno, errbuf));
     3294 +                }
     3295 +        }
     3296 +
     3297 +        return (0);
     3298 +}
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX