xref: /src/sys/contrib/openzfs/contrib/pyzfs/libzfs_core/_libzfs_core.py (revision 8a62a2a5659d1839d8799b4274c04469d7f17c78)
1# SPDX-License-Identifier: Apache-2.0
2#
3# Copyright 2015 ClusterHQ
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#    http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18"""
19Python wrappers for libzfs_core interfaces.
20
21As a rule, there is a Python function for each C function.
22The signatures of the Python functions generally follow those of the
23functions, but the argument types are natural to Python.
24nvlists are wrapped as dictionaries or lists depending on their usage.
25Some parameters have default values depending on typical use for
26increased convenience.  Output parameters are not used and return values
27are directly returned.  Error conditions are signalled by exceptions
28rather than by integer error codes.
29"""
30from __future__ import absolute_import, division, print_function
31
32import errno
33import os
34import threading
35from . import exceptions
36from . import _error_translation as errors
37from .bindings import libzfs_core
38from ._constants import (  # noqa: F401
39    MAXNAMELEN,
40    ZCP_DEFAULT_INSTRLIMIT,
41    ZCP_DEFAULT_MEMLIMIT,
42    WRAPPING_KEY_LEN,
43    zfs_key_location,
44    zfs_keyformat,
45    zio_encrypt
46)
47from .ctypes import uint64_t
48from ._nvlist import nvlist_in, nvlist_out
49
50
51def lzc_create(name, ds_type='zfs', props=None, key=None):
52    '''
53    Create a ZFS filesystem or a ZFS volume ("zvol").
54
55    :param bytes name: a name of the dataset to be created.
56    :param str ds_type: the type of the dataset to be created,
57        currently supported types are "zfs" (the default) for a filesystem and
58        "zvol" for a volume.
59    :param props: a `dict` of ZFS dataset property name-value pairs
60        (empty by default).
61    :type props: dict of bytes:Any
62    :param key: dataset encryption key data (empty by default).
63    :type key: bytes
64
65    :raises FilesystemExists: if a dataset with the given name already exists.
66    :raises ParentNotFound: if a parent dataset of the requested dataset does
67        not exist.
68    :raises PropertyInvalid: if one or more of the specified properties is
69        invalid or has an invalid type or value.
70    :raises NameInvalid: if the name is not a valid dataset name.
71    :raises NameTooLong: if the name is too long.
72    :raises WrongParent: if the parent dataset of the requested dataset is not
73        a filesystem (e.g. ZVOL)
74    '''
75    if props is None:
76        props = {}
77    if key is None:
78        key = b""
79    else:
80        key = bytes(key)
81    if ds_type == 'zfs':
82        ds_type = _lib.DMU_OST_ZFS
83    elif ds_type == 'zvol':
84        ds_type = _lib.DMU_OST_ZVOL
85    else:
86        raise exceptions.DatasetTypeInvalid(ds_type)
87    nvlist = nvlist_in(props)
88    ret = _lib.lzc_create(name, ds_type, nvlist, key, len(key))
89    errors.lzc_create_translate_error(ret, name, ds_type, props)
90
91
92def lzc_clone(name, origin, props=None):
93    '''
94    Clone a ZFS filesystem or a ZFS volume ("zvol") from a given snapshot.
95
96    :param bytes name: a name of the dataset to be created.
97    :param bytes origin: a name of the origin snapshot.
98    :param props: a `dict` of ZFS dataset property name-value pairs
99        (empty by default).
100    :type props: dict of bytes:Any
101
102    :raises FilesystemExists: if a dataset with the given name already exists.
103    :raises DatasetNotFound: if either a parent dataset of the requested
104        dataset or the origin snapshot does not exist.
105    :raises PropertyInvalid: if one or more of the specified properties is
106        invalid or has an invalid type or value.
107    :raises FilesystemNameInvalid: if the name is not a valid dataset name.
108    :raises SnapshotNameInvalid: if the origin is not a valid snapshot name.
109    :raises NameTooLong: if the name or the origin name is too long.
110    :raises PoolsDiffer: if the clone and the origin have different pool names.
111
112    .. note::
113        Because of a deficiency of the underlying C interface
114        :exc:`.DatasetNotFound` can mean that either a parent filesystem of
115        the target or the origin snapshot does not exist.
116        It is currently impossible to distinguish between the cases.
117        :func:`lzc_hold` can be used to check that the snapshot exists and
118        ensure that it is not destroyed before cloning.
119    '''
120    if props is None:
121        props = {}
122    nvlist = nvlist_in(props)
123    ret = _lib.lzc_clone(name, origin, nvlist)
124    errors.lzc_clone_translate_error(ret, name, origin, props)
125
126
127def lzc_rollback(name):
128    '''
129    Roll back a filesystem or volume to its most recent snapshot.
130
131    Note that the latest snapshot may change if a new one is concurrently
132    created or the current one is destroyed.  lzc_rollback_to can be used
133    to roll back to a specific latest snapshot.
134
135    :param bytes name: a name of the dataset to be rolled back.
136    :return: a name of the most recent snapshot.
137    :rtype: bytes
138
139    :raises FilesystemNotFound: if the dataset does not exist.
140    :raises SnapshotNotFound: if the dataset does not have any snapshots.
141    :raises NameInvalid: if the dataset name is invalid.
142    :raises NameTooLong: if the dataset name is too long.
143    '''
144    # Account for terminating NUL in C strings.
145    snapnamep = _ffi.new('char[]', MAXNAMELEN + 1)
146    ret = _lib.lzc_rollback(name, snapnamep, MAXNAMELEN + 1)
147    errors.lzc_rollback_translate_error(ret, name)
148    return _ffi.string(snapnamep)
149
150
151def lzc_rollback_to(name, snap):
152    '''
153    Roll back this filesystem or volume to the specified snapshot, if possible.
154
155    :param bytes name: a name of the dataset to be rolled back.
156    :param bytes snap: a name of the snapshot to be rolled back.
157
158    :raises FilesystemNotFound: if the dataset does not exist.
159    :raises SnapshotNotFound: if the dataset does not have any snapshots.
160    :raises NameInvalid: if the dataset name is invalid.
161    :raises NameTooLong: if the dataset name is too long.
162    :raises SnapshotNotLatest: if the snapshot is not the latest.
163    '''
164    ret = _lib.lzc_rollback_to(name, snap)
165    errors.lzc_rollback_to_translate_error(ret, name, snap)
166
167
168def lzc_snapshot(snaps, props=None):
169    '''
170    Create snapshots.
171
172    All snapshots must be in the same pool.
173
174    Optionally snapshot properties can be set on all snapshots.
175    Currently  only user properties (prefixed with "user:") are supported.
176
177    Either all snapshots are successfully created or none are created if
178    an exception is raised.
179
180    :param snaps: a list of names of snapshots to be created.
181    :type snaps: list of bytes
182    :param props: a `dict` of ZFS dataset property name-value pairs
183        (empty by default).
184    :type props: dict of bytes:bytes
185
186    :raises SnapshotFailure: if one or more snapshots could not be created.
187
188    .. note::
189        :exc:`.SnapshotFailure` is a compound exception that provides at least
190        one detailed error object in :attr:`SnapshotFailure.errors` `list`.
191
192    .. warning::
193        The underlying implementation reports an individual, per-snapshot error
194        only for :exc:`.SnapshotExists` condition and *sometimes* for
195        :exc:`.NameTooLong`.
196        In all other cases a single error is reported without connection to any
197        specific snapshot name(s).
198
199        This has the following implications:
200
201        * if multiple error conditions are encountered only one of them is
202          reported
203
204        * unless only one snapshot is requested then it is impossible to tell
205          how many snapshots are problematic and what they are
206
207        * only if there are no other error conditions :exc:`.SnapshotExists`
208          is reported for all affected snapshots
209
210        * :exc:`.NameTooLong` can behave either in the same way as
211          :exc:`.SnapshotExists` or as all other exceptions.
212          The former is the case where the full snapshot name exceeds the
213          maximum allowed length but the short snapshot name (after '@') is
214          within the limit.
215          The latter is the case when the short name alone exceeds the maximum
216          allowed length.
217    '''
218    snaps_dict = {name: None for name in snaps}
219    errlist = {}
220    snaps_nvlist = nvlist_in(snaps_dict)
221    if props is None:
222        props = {}
223    props_nvlist = nvlist_in(props)
224    with nvlist_out(errlist) as errlist_nvlist:
225        ret = _lib.lzc_snapshot(snaps_nvlist, props_nvlist, errlist_nvlist)
226    errors.lzc_snapshot_translate_errors(ret, errlist, snaps, props)
227
228
229lzc_snap = lzc_snapshot
230
231
232def lzc_destroy_snaps(snaps, defer):
233    '''
234    Destroy snapshots.
235
236    They must all be in the same pool.
237    Snapshots that do not exist will be silently ignored.
238
239    If 'defer' is not set, and a snapshot has user holds or clones, the
240    destroy operation will fail and none of the snapshots will be
241    destroyed.
242
243    If 'defer' is set, and a snapshot has user holds or clones, it will be
244    marked for deferred destruction, and will be destroyed when the last hold
245    or clone is removed/destroyed.
246
247    The operation succeeds if all snapshots were destroyed (or marked for
248    later destruction if 'defer' is set) or didn't exist to begin with.
249
250    :param snaps: a list of names of snapshots to be destroyed.
251    :type snaps: list of bytes
252    :param bool defer: whether to mark busy snapshots for deferred destruction
253        rather than immediately failing.
254
255    :raises SnapshotDestructionFailure: if one or more snapshots could not be
256        created.
257
258    .. note::
259        :exc:`.SnapshotDestructionFailure` is a compound exception that
260        provides at least one detailed error object in
261        :attr:`SnapshotDestructionFailure.errors` `list`.
262
263        Typical error is :exc:`SnapshotIsCloned` if `defer` is `False`.
264        The snapshot names are validated quite loosely and invalid names are
265        typically ignored as nonexisting snapshots.
266
267        A snapshot name referring to a filesystem that doesn't exist is
268        ignored.
269        However, non-existent pool name causes :exc:`PoolNotFound`.
270    '''
271    snaps_dict = {name: None for name in snaps}
272    errlist = {}
273    snaps_nvlist = nvlist_in(snaps_dict)
274    with nvlist_out(errlist) as errlist_nvlist:
275        ret = _lib.lzc_destroy_snaps(snaps_nvlist, defer, errlist_nvlist)
276    errors.lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer)
277
278
279def lzc_bookmark(bookmarks):
280    '''
281    Create bookmarks.
282
283    :param bookmarks: a dict that maps names of wanted bookmarks to names of
284        existing snapshots or bookmarks.
285    :type bookmarks: dict of bytes to bytes
286    :raises BookmarkFailure: if any of the bookmarks can not be created for any
287        reason.
288
289    The bookmarks `dict` maps from name of the bookmark
290    (e.g. :file:`{pool}/{fs}#{bmark}`) to the name of the snapshot
291    (e.g. :file:`{pool}/{fs}@{snap}`) or existint bookmark
292    :file:`{pool}/{fs}@{snap}`. All the bookmarks and snapshots must
293    be in the same pool.
294    '''
295    errlist = {}
296    nvlist = nvlist_in(bookmarks)
297    with nvlist_out(errlist) as errlist_nvlist:
298        ret = _lib.lzc_bookmark(nvlist, errlist_nvlist)
299    errors.lzc_bookmark_translate_errors(ret, errlist, bookmarks)
300
301
302def lzc_get_bookmarks(fsname, props=None):
303    '''
304    Retrieve a listing of bookmarks for the given file system.
305
306    :param bytes fsname: a name of the filesystem.
307    :param props: a `list` of properties that will be returned for each
308        bookmark.
309    :type props: list of bytes
310    :return: a `dict` that maps the bookmarks' short names to their properties.
311    :rtype: dict of bytes:dict
312
313    :raises FilesystemNotFound: if the filesystem is not found.
314
315    The following are valid properties on bookmarks:
316
317    guid : integer
318        globally unique identifier of the snapshot the bookmark refers to
319    createtxg : integer
320        txg when the snapshot the bookmark refers to was created
321    creation : integer
322        timestamp when the snapshot the bookmark refers to was created
323
324    Any other properties passed in ``props`` are ignored without reporting
325    any error.
326    Values in the returned dictionary map the names of the requested properties
327    to their respective values.
328    '''
329    bmarks = {}
330    if props is None:
331        props = []
332    props_dict = {name: None for name in props}
333    nvlist = nvlist_in(props_dict)
334    with nvlist_out(bmarks) as bmarks_nvlist:
335        ret = _lib.lzc_get_bookmarks(fsname, nvlist, bmarks_nvlist)
336    errors.lzc_get_bookmarks_translate_error(ret, fsname, props)
337    return bmarks
338
339
340def lzc_destroy_bookmarks(bookmarks):
341    '''
342    Destroy bookmarks.
343
344    :param bookmarks: a list of the bookmarks to be destroyed. The bookmarks
345        are specified as :file:`{fs}#{bmark}`.
346    :type bookmarks: list of bytes
347
348    :raises BookmarkDestructionFailure: if any of the bookmarks may not be
349        destroyed.
350
351    The bookmarks must all be in the same pool.
352    Bookmarks that do not exist will be silently ignored.
353    This also includes the case where the filesystem component of the bookmark
354    name does not exist.
355    However, an invalid bookmark name will cause :exc:`.NameInvalid` error
356    reported in :attr:`SnapshotDestructionFailure.errors`.
357
358    Either all bookmarks that existed are destroyed or an exception is raised.
359    '''
360    errlist = {}
361    bmarks_dict = {name: None for name in bookmarks}
362    nvlist = nvlist_in(bmarks_dict)
363    with nvlist_out(errlist) as errlist_nvlist:
364        ret = _lib.lzc_destroy_bookmarks(nvlist, errlist_nvlist)
365    errors.lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks)
366
367
368def lzc_snaprange_space(firstsnap, lastsnap):
369    '''
370    Calculate a size of data referenced by snapshots in the inclusive range
371    between the ``firstsnap`` and the ``lastsnap`` and not shared with any
372    other datasets.
373
374    :param bytes firstsnap: the name of the first snapshot in the range.
375    :param bytes lastsnap: the name of the last snapshot in the range.
376    :return: the calculated stream size, in bytes.
377    :rtype: `int` or `long`
378
379    :raises SnapshotNotFound: if either of the snapshots does not exist.
380    :raises NameInvalid: if the name of either snapshot is invalid.
381    :raises NameTooLong: if the name of either snapshot is too long.
382    :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
383        ``snapname``.
384    :raises PoolsDiffer: if the snapshots belong to different pools.
385
386    ``lzc_snaprange_space`` calculates total size of blocks that exist
387    because they are referenced only by one or more snapshots in the given
388    range but no other dataset.
389    In other words, this is the set of blocks that were born after the snap
390    before firstsnap, and died before the snap after the last snap.
391    Yet another interpretation is that the result of ``lzc_snaprange_space``
392    is the size of the space that would be freed if the snapshots in the range
393    are destroyed.
394
395    If the same snapshot is given as both the ``firstsnap`` and the
396    ``lastsnap``.
397    In that case ``lzc_snaprange_space`` calculates space used by the snapshot.
398    '''
399    valp = _ffi.new('uint64_t *')
400    ret = _lib.lzc_snaprange_space(firstsnap, lastsnap, valp)
401    errors.lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap)
402    return int(valp[0])
403
404
405def lzc_hold(holds, fd=None):
406    '''
407    Create *user holds* on snapshots.  If there is a hold on a snapshot,
408    the snapshot can not be destroyed.  (However, it can be marked for
409    deletion by :func:`lzc_destroy_snaps` ( ``defer`` = `True` ).)
410
411    :param holds: the dictionary of names of the snapshots to hold mapped to
412        the hold names.
413    :type holds: dict of bytes : bytes
414    :type fd: int or None
415    :param fd: if not None then it must be the result of :func:`os.open`
416        called as ``os.open("/dev/zfs", O_EXCL)``.
417    :type fd: int or None
418    :return: a list of the snapshots that do not exist.
419    :rtype: list of bytes
420
421    :raises HoldFailure: if a hold was impossible on one or more of the
422        snapshots.
423    :raises BadHoldCleanupFD: if ``fd`` is not a valid file descriptor
424        associated with :file:`/dev/zfs`.
425
426    The snapshots must all be in the same pool.
427
428    If ``fd`` is not None, then when the ``fd`` is closed (including on process
429    termination), the holds will be released.  If the system is shut down
430    uncleanly, the holds will be released when the pool is next opened
431    or imported.
432
433    Holds for snapshots which don't exist will be skipped and have an entry
434    added to the return value, but will not cause an overall failure.
435    No exceptions is raised if all holds, for snapshots that existed, were
436    successfully created.
437    Otherwise :exc:`.HoldFailure` exception is raised and no holds will be
438    created.
439    :attr:`.HoldFailure.errors` may contain a single element for an error that
440    is not specific to any hold / snapshot, or it may contain one or more
441    elements detailing specific error per each affected hold.
442    '''
443    errlist = {}
444    if fd is None:
445        fd = -1
446    nvlist = nvlist_in(holds)
447    with nvlist_out(errlist) as errlist_nvlist:
448        ret = _lib.lzc_hold(nvlist, fd, errlist_nvlist)
449    errors.lzc_hold_translate_errors(ret, errlist, holds, fd)
450    # If there is no error (no exception raised by _handleErrList), but errlist
451    # is not empty, then it contains missing snapshots.
452    assert all(errlist[x] == errno.ENOENT for x in errlist)
453    return list(errlist.keys())
454
455
456def lzc_release(holds):
457    '''
458    Release *user holds* on snapshots.
459
460    If the snapshot has been marked for
461    deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
462    any clones, and all the user holds are removed, then the snapshot will be
463    destroyed.
464
465    The snapshots must all be in the same pool.
466
467    :param holds: a ``dict`` where keys are snapshot names and values are
468        lists of hold tags to remove.
469    :type holds: dict of bytes : list of bytes
470    :return: a list of any snapshots that do not exist and of any tags that do
471        not exist for existing snapshots.
472        Such tags are qualified with a corresponding snapshot name using the
473        following format :file:`{pool}/{fs}@{snap}#{tag}`
474    :rtype: list of bytes
475
476    :raises HoldReleaseFailure: if one or more existing holds could not be
477        released.
478
479    Holds which failed to release because they didn't exist will have an entry
480    added to errlist, but will not cause an overall failure.
481
482    This call is success if ``holds`` was empty or all holds that
483    existed, were successfully removed.
484    Otherwise an exception will be raised.
485    '''
486    errlist = {}
487    holds_dict = {}
488    for snap in holds:
489        hold_list = holds[snap]
490        if not isinstance(hold_list, list):
491            raise TypeError('holds must be in a list')
492        holds_dict[snap] = {hold: None for hold in hold_list}
493    nvlist = nvlist_in(holds_dict)
494    with nvlist_out(errlist) as errlist_nvlist:
495        ret = _lib.lzc_release(nvlist, errlist_nvlist)
496    errors.lzc_release_translate_errors(ret, errlist, holds)
497    # If there is no error (no exception raised by _handleErrList), but errlist
498    # is not empty, then it contains missing snapshots and tags.
499    assert all(errlist[x] == errno.ENOENT for x in errlist)
500    return list(errlist.keys())
501
502
503def lzc_get_holds(snapname):
504    '''
505    Retrieve list of *user holds* on the specified snapshot.
506
507    :param bytes snapname: the name of the snapshot.
508    :return: holds on the snapshot along with their creation times
509        in seconds since the epoch
510    :rtype: dict of bytes : int
511    '''
512    holds = {}
513    with nvlist_out(holds) as nvlist:
514        ret = _lib.lzc_get_holds(snapname, nvlist)
515    errors.lzc_get_holds_translate_error(ret, snapname)
516    return holds
517
518
519def lzc_send(snapname, fromsnap, fd, flags=None):
520    '''
521    Generate a zfs send stream for the specified snapshot and write it to
522    the specified file descriptor.
523
524    :param bytes snapname: the name of the snapshot to send.
525    :param fromsnap: if not None the name of the starting snapshot
526        for the incremental stream.
527    :type fromsnap: bytes or None
528    :param int fd: the file descriptor to write the send stream to.
529    :param flags: the flags that control what enhanced features can be used in
530        the stream.
531    :type flags: list of bytes
532
533    :raises SnapshotNotFound: if either the starting snapshot is not `None` and
534        does not exist, or if the ending snapshot does not exist.
535    :raises NameInvalid: if the name of either snapshot is invalid.
536    :raises NameTooLong: if the name of either snapshot is too long.
537    :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
538        ``snapname``.
539    :raises PoolsDiffer: if the snapshots belong to different pools.
540    :raises IOError: if an input / output error occurs while writing to ``fd``.
541    :raises UnknownStreamFeature: if the ``flags`` contain an unknown flag
542        name.
543
544    If ``fromsnap`` is None, a full (non-incremental) stream will be sent.
545    If ``fromsnap`` is not None, it must be the full name of a snapshot or
546    bookmark to send an incremental from, e.g.
547    :file:`{pool}/{fs}@{earlier_snap}` or :file:`{pool}/{fs}#{earlier_bmark}`.
548
549    The specified snapshot or bookmark must represent an earlier point in the
550    history of ``snapname``.
551    It can be an earlier snapshot in the same filesystem or zvol as
552    ``snapname``, or it can be the origin of ``snapname``'s filesystem, or an
553    earlier snapshot in the origin, etc.
554    ``fromsnap`` must be strictly an earlier snapshot, specifying the same
555    snapshot as both ``fromsnap`` and ``snapname`` is an error.
556
557    If ``flags`` contains *"large_blocks"*, the stream is permitted
558    to contain ``DRR_WRITE`` records with ``drr_length`` > 128K,
559    and ``DRR_OBJECT`` records with ``drr_blksz`` > 128K.
560
561    If ``flags`` contains *"embedded_data"*, the stream is permitted
562    to contain ``DRR_WRITE_EMBEDDED`` records with
563    ``drr_etype`` == ``BP_EMBEDDED_TYPE_DATA``,
564    which the receiving system must support (as indicated by support
565    for the *embedded_data* feature).
566
567    If ``flags`` contains *"compress"*, the stream is generated by using
568    compressed WRITE records for blocks which are compressed on disk and
569    in memory.  If the *lz4_compress* feature is active on the sending
570    system, then the receiving system must have that feature enabled as well.
571
572    If ``flags`` contains *"raw"*, the stream is generated, for encrypted
573    datasets, by sending data exactly as it exists on disk.  This allows
574    backups to be taken even if encryption keys are not currently loaded.
575
576    .. note::
577        ``lzc_send`` can actually accept a filesystem name as the ``snapname``.
578        In that case ``lzc_send`` acts as if a temporary snapshot was created
579        after the start of the call and before the stream starts being
580        produced.
581
582    .. note::
583        ``lzc_send`` does not return until all of the stream is written to
584        ``fd``.
585
586    .. note::
587        ``lzc_send`` does *not* close ``fd`` upon returning.
588    '''
589    if fromsnap is not None:
590        c_fromsnap = fromsnap
591    else:
592        c_fromsnap = _ffi.NULL
593    c_flags = 0
594    if flags is None:
595        flags = []
596    for flag in flags:
597        c_flag = {
598            'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
599            'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
600            'compress': _lib.LZC_SEND_FLAG_COMPRESS,
601            'raw': _lib.LZC_SEND_FLAG_RAW,
602        }.get(flag)
603        if c_flag is None:
604            raise exceptions.UnknownStreamFeature(flag)
605        c_flags |= c_flag
606
607    ret = _lib.lzc_send(snapname, c_fromsnap, fd, c_flags)
608    errors.lzc_send_translate_error(ret, snapname, fromsnap, fd, flags)
609
610
611def lzc_send_space(snapname, fromsnap=None, flags=None):
612    '''
613    Estimate size of a full or incremental backup stream
614    given the optional starting snapshot and the ending snapshot.
615
616    :param bytes snapname: the name of the snapshot for which the estimate
617        should be done.
618    :param fromsnap: the optional starting snapshot name.
619        If not `None` then an incremental stream size is estimated, otherwise
620        a full stream is estimated.
621    :type fromsnap: `bytes` or `None`
622    :param flags: the flags that control what enhanced features can be used
623        in the stream.
624    :type flags: list of bytes
625
626    :return: the estimated stream size, in bytes.
627    :rtype: `int` or `long`
628
629    :raises SnapshotNotFound: if either the starting snapshot is not `None` and
630        does not exist, or if the ending snapshot does not exist.
631    :raises NameInvalid: if the name of either snapshot is invalid.
632    :raises NameTooLong: if the name of either snapshot is too long.
633    :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
634        ``snapname``.
635    :raises PoolsDiffer: if the snapshots belong to different pools.
636
637    ``fromsnap``, if not ``None``,  must be strictly an earlier snapshot,
638    specifying the same snapshot as both ``fromsnap`` and ``snapname`` is an
639    error.
640    '''
641    if fromsnap is not None:
642        c_fromsnap = fromsnap
643    else:
644        c_fromsnap = _ffi.NULL
645    c_flags = 0
646    if flags is None:
647        flags = []
648    for flag in flags:
649        c_flag = {
650            'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
651            'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
652            'compress': _lib.LZC_SEND_FLAG_COMPRESS,
653            'raw': _lib.LZC_SEND_FLAG_RAW,
654        }.get(flag)
655        if c_flag is None:
656            raise exceptions.UnknownStreamFeature(flag)
657        c_flags |= c_flag
658    valp = _ffi.new('uint64_t *')
659
660    ret = _lib.lzc_send_space(snapname, c_fromsnap, c_flags, valp)
661    errors.lzc_send_space_translate_error(ret, snapname, fromsnap)
662    return int(valp[0])
663
664
665def lzc_receive(snapname, fd, force=False, raw=False, origin=None, props=None):
666    '''
667    Receive from the specified ``fd``, creating the specified snapshot.
668
669    :param bytes snapname: the name of the snapshot to create.
670    :param int fd: the file descriptor from which to read the stream.
671    :param bool force: whether to roll back or destroy the target filesystem
672        if that is required to receive the stream.
673    :param bool raw: whether this is a "raw" stream.
674    :param origin: the optional origin snapshot name if the stream is for a
675        clone.
676    :type origin: bytes or None
677    :param props: the properties to set on the snapshot as *received*
678        properties.
679    :type props: dict of bytes : Any
680
681    :raises IOError: if an input / output error occurs while reading from the
682        ``fd``.
683    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
684    :raises DatasetExists: if the stream is a full stream and the destination
685        filesystem already exists.
686    :raises DatasetExists: if ``force`` is `True` but the destination
687        filesystem could not be rolled back to a matching snapshot because a
688        newer snapshot exists and it is an origin of a cloned filesystem.
689    :raises StreamMismatch: if an incremental stream is received and the latest
690        snapshot of the destination filesystem does not match the source
691        snapshot of the stream.
692    :raises StreamMismatch: if a full stream is received and the destination
693        filesystem already exists and it has at least one snapshot, and
694        ``force`` is `False`.
695    :raises StreamMismatch: if an incremental clone stream is received but the
696        specified ``origin`` is not the actual received origin.
697    :raises DestinationModified: if an incremental stream is received and the
698        destination filesystem has been modified since the last snapshot and
699        ``force`` is `False`.
700    :raises DestinationModified: if a full stream is received and the
701        destination filesystem already exists and it does not have any
702        snapshots, and ``force`` is `False`.
703    :raises DatasetNotFound: if the destination filesystem and its parent do
704        not exist.
705    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
706        exist.
707    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
708        could not be rolled back to a matching snapshot because a newer
709        snapshot is held and could not be destroyed.
710    :raises DatasetBusy: if another receive operation is being performed on the
711        destination filesystem.
712    :raises BadStream: if the stream is corrupt or it is not recognized or it
713        is a compound stream or it is a clone stream, but ``origin`` is `None`.
714    :raises BadStream: if a clone stream is received and the destination
715        filesystem already exists.
716    :raises StreamFeatureNotSupported: if the stream has a feature that is not
717        supported on this side.
718    :raises NameInvalid: if the name of either snapshot is invalid.
719    :raises NameTooLong: if the name of either snapshot is too long.
720    :raises WrongParent: if the parent dataset of the received destination is
721        not a filesystem (e.g. ZVOL)
722
723    .. note::
724        The ``origin`` is ignored if the actual stream is an incremental stream
725        that is not a clone stream and the destination filesystem exists.
726        If the stream is a full stream and the destination filesystem does not
727        exist then the ``origin`` is checked for existence: if it does not
728        exist :exc:`.DatasetNotFound` is raised, otherwise
729        :exc:`.StreamMismatch` is raised, because that snapshot can not have
730        any relation to the stream.
731
732    .. note::
733        If ``force`` is `True` and the stream is incremental then the
734        destination filesystem is rolled back to a matching source snapshot if
735        necessary. Intermediate snapshots are destroyed in that case.
736
737        However, none of the existing snapshots may have the same name as
738        ``snapname`` even if such a snapshot were to be destroyed.
739        The existing ``snapname`` snapshot always causes
740        :exc:`.SnapshotExists` to be raised.
741
742        If ``force`` is `True` and the stream is a full stream then the
743        destination filesystem is replaced with the received filesystem unless
744        the former has any snapshots.  This prevents the destination filesystem
745        from being rolled back / replaced.
746
747    .. note::
748        This interface does not work on dedup'd streams
749        (those with ``DMU_BACKUP_FEATURE_DEDUP``).
750
751    .. note::
752        ``lzc_receive`` does not return until all of the stream is read from
753        ``fd`` and applied to the pool.
754
755    .. note::
756        ``lzc_receive`` does *not* close ``fd`` upon returning.
757    '''
758
759    if origin is not None:
760        c_origin = origin
761    else:
762        c_origin = _ffi.NULL
763    if props is None:
764        props = {}
765    nvlist = nvlist_in(props)
766    ret = _lib.lzc_receive(snapname, nvlist, c_origin, force, raw, fd)
767    errors.lzc_receive_translate_errors(
768        ret, snapname, fd, force, raw, False, False, origin, None
769    )
770
771
772lzc_recv = lzc_receive
773
774
775def lzc_exists(name):
776    '''
777    Check if a dataset (a filesystem, or a volume, or a snapshot)
778    with the given name exists.
779
780    :param bytes name: the dataset name to check.
781    :return: `True` if the dataset exists, `False` otherwise.
782    :rtype: bool
783
784    .. note::
785        ``lzc_exists`` can not be used to check for existence of bookmarks.
786    '''
787    ret = _lib.lzc_exists(name)
788    return bool(ret)
789
790
791def lzc_change_key(fsname, crypt_cmd, props=None, key=None):
792    '''
793    Change encryption key on the specified dataset.
794
795    :param bytes fsname: the name of the dataset.
796    :param str crypt_cmd: the encryption "command" to be executed, currently
797        supported values are "new_key", "inherit", "force_new_key" and
798        "force_inherit".
799    :param props: a `dict` of encryption-related property name-value pairs;
800        only "keyformat", "keylocation" and "pbkdf2iters" are supported
801        (empty by default).
802    :type props: dict of bytes:Any
803    :param key: dataset encryption key data (empty by default).
804    :type key: bytes
805
806    :raises PropertyInvalid: if ``props`` contains invalid values.
807    :raises FilesystemNotFound: if the dataset does not exist.
808    :raises UnknownCryptCommand: if ``crypt_cmd`` is invalid.
809    :raises EncryptionKeyNotLoaded: if the encryption key is not currently
810        loaded and therefore cannot be changed.
811    '''
812    if props is None:
813        props = {}
814    if key is None:
815        key = b""
816    else:
817        key = bytes(key)
818    cmd = {
819        'new_key': _lib.DCP_CMD_NEW_KEY,
820        'inherit': _lib.DCP_CMD_INHERIT,
821        'force_new_key': _lib.DCP_CMD_FORCE_NEW_KEY,
822        'force_inherit': _lib.DCP_CMD_FORCE_INHERIT,
823    }.get(crypt_cmd)
824    if cmd is None:
825        raise exceptions.UnknownCryptCommand(crypt_cmd)
826    nvlist = nvlist_in(props)
827    ret = _lib.lzc_change_key(fsname, cmd, nvlist, key, len(key))
828    errors.lzc_change_key_translate_error(ret, fsname)
829
830
831def lzc_load_key(fsname, noop, key):
832    '''
833    Load or verify encryption key on the specified dataset.
834
835    :param bytes fsname: the name of the dataset.
836    :param bool noop: if `True` the encryption key will only be verified,
837        not loaded.
838    :param key: dataset encryption key data.
839    :type key: bytes
840
841    :raises FilesystemNotFound: if the dataset does not exist.
842    :raises EncryptionKeyAlreadyLoaded: if the encryption key is already
843        loaded.
844    :raises EncryptionKeyInvalid: if the encryption key provided is incorrect.
845    '''
846    ret = _lib.lzc_load_key(fsname, noop, key, len(key))
847    errors.lzc_load_key_translate_error(ret, fsname, noop)
848
849
850def lzc_unload_key(fsname):
851    '''
852    Unload encryption key from the specified dataset.
853
854    :param bytes fsname: the name of the dataset.
855
856    :raises FilesystemNotFound: if the dataset does not exist.
857    :raises DatasetBusy: if the encryption key is still being used. This
858        usually occurs when the dataset is mounted.
859    :raises EncryptionKeyNotLoaded: if the encryption key is not currently
860        loaded.
861    '''
862    ret = _lib.lzc_unload_key(fsname)
863    errors.lzc_unload_key_translate_error(ret, fsname)
864
865
866def lzc_channel_program(
867    poolname, program, instrlimit=ZCP_DEFAULT_INSTRLIMIT,
868    memlimit=ZCP_DEFAULT_MEMLIMIT, params=None
869):
870    '''
871    Executes a script as a ZFS channel program on pool ``poolname``.
872
873    :param bytes poolname: the name of the pool.
874    :param bytes program: channel program text.
875    :param int instrlimit: execution time limit, in milliseconds.
876    :param int memlimit: execution memory limit, in bytes.
877    :param bytes params: a `list` of parameters passed to the channel program
878        (empty by default).
879    :type params: dict of bytes:Any
880    :return: a dictionary of result values procuced by the channel program,
881        if any.
882    :rtype: dict
883
884    :raises PoolNotFound: if the pool does not exist.
885    :raises ZCPLimitInvalid: if either instruction or memory limit are invalid.
886    :raises ZCPSyntaxError: if the channel program contains syntax errors.
887    :raises ZCPTimeout: if the channel program took too long to execute.
888    :raises ZCPSpaceError: if the channel program exhausted the memory limit.
889    :raises ZCPMemoryError: if the channel program return value was too large.
890    :raises ZCPPermissionError: if the user lacks the permission to run the
891        channel program. Channel programs must be run as root.
892    :raises ZCPRuntimeError: if the channel program encountered a runtime
893        error.
894    '''
895    output = {}
896    params_nv = nvlist_in({b"argv": params})
897    with nvlist_out(output) as outnvl:
898        ret = _lib.lzc_channel_program(
899            poolname, program, instrlimit, memlimit, params_nv, outnvl)
900    errors.lzc_channel_program_translate_error(
901        ret, poolname, output.get(b"error"))
902    return output.get(b"return")
903
904
905def lzc_channel_program_nosync(
906    poolname, program, instrlimit=ZCP_DEFAULT_INSTRLIMIT,
907    memlimit=ZCP_DEFAULT_MEMLIMIT, params=None
908):
909    '''
910    Executes a script as a read-only ZFS channel program on pool ``poolname``.
911    A read-only channel program works programmatically the same way as a
912    normal channel program executed with
913    :func:`lzc_channel_program`. The only difference is it runs exclusively in
914    open-context and therefore can return faster.
915    The downside to that, is that the program cannot change on-disk state by
916    calling functions from the zfs.sync submodule.
917
918    :param bytes poolname: the name of the pool.
919    :param bytes program: channel program text.
920    :param int instrlimit: execution time limit, in milliseconds.
921    :param int memlimit: execution memory limit, in bytes.
922    :param bytes params: a `list` of parameters passed to the channel program
923        (empty by default).
924    :type params: dict of bytes:Any
925    :return: a dictionary of result values procuced by the channel program,
926        if any.
927    :rtype: dict
928
929    :raises PoolNotFound: if the pool does not exist.
930    :raises ZCPLimitInvalid: if either instruction or memory limit are invalid.
931    :raises ZCPSyntaxError: if the channel program contains syntax errors.
932    :raises ZCPTimeout: if the channel program took too long to execute.
933    :raises ZCPSpaceError: if the channel program exhausted the memory limit.
934    :raises ZCPMemoryError: if the channel program return value was too large.
935    :raises ZCPPermissionError: if the user lacks the permission to run the
936        channel program. Channel programs must be run as root.
937    :raises ZCPRuntimeError: if the channel program encountered a runtime
938        error.
939    '''
940    output = {}
941    params_nv = nvlist_in({b"argv": params})
942    with nvlist_out(output) as outnvl:
943        ret = _lib.lzc_channel_program_nosync(
944            poolname, program, instrlimit, memlimit, params_nv, outnvl)
945    errors.lzc_channel_program_translate_error(
946        ret, poolname, output.get(b"error"))
947    return output.get(b"return")
948
949
950def lzc_receive_resumable(
951    snapname, fd, force=False, raw=False, origin=None, props=None
952):
953    '''
954    Like :func:`lzc_receive`, but if the receive fails due to premature stream
955    termination, the intermediate state will be preserved on disk.  In this
956    case, ECKSUM will be returned.  The receive may subsequently be resumed
957    with a resuming send stream generated by lzc_send_resume().
958
959    :param bytes snapname: the name of the snapshot to create.
960    :param int fd: the file descriptor from which to read the stream.
961    :param bool force: whether to roll back or destroy the target filesystem
962        if that is required to receive the stream.
963    :param bool raw: whether this is a "raw" stream.
964    :param origin: the optional origin snapshot name if the stream is for a
965        clone.
966    :type origin: bytes or None
967    :param props: the properties to set on the snapshot as *received*
968        properties.
969    :type props: dict of bytes : Any
970
971    :raises IOError: if an input / output error occurs while reading from the
972        ``fd``.
973    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
974    :raises DatasetExists: if the stream is a full stream and the destination
975        filesystem already exists.
976    :raises DatasetExists: if ``force`` is `True` but the destination
977        filesystem could not be rolled back to a matching snapshot because a
978        newer snapshot exists and it is an origin of a cloned filesystem.
979    :raises StreamMismatch: if an incremental stream is received and the latest
980        snapshot of the destination filesystem does not match the source
981        snapshot of the stream.
982    :raises StreamMismatch: if a full stream is received and the destination
983        filesystem already exists and it has at least one snapshot, and
984        ``force`` is `False`.
985    :raises StreamMismatch: if an incremental clone stream is received but the
986        specified ``origin`` is not the actual received origin.
987    :raises DestinationModified: if an incremental stream is received and the
988        destination filesystem has been modified since the last snapshot and
989        ``force`` is `False`.
990    :raises DestinationModified: if a full stream is received and the
991        destination filesystem already exists and it does not have any
992        snapshots, and ``force`` is `False`.
993    :raises DatasetNotFound: if the destination filesystem and its parent do
994        not exist.
995    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
996        exist.
997    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
998        could not be rolled back to a matching snapshot because a newer
999        snapshot is held and could not be destroyed.
1000    :raises DatasetBusy: if another receive operation is being performed on the
1001        destination filesystem.
1002    :raises BadStream: if the stream is corrupt or it is not recognized or it
1003        is a compound stream or it is a clone stream, but ``origin`` is `None`.
1004    :raises BadStream: if a clone stream is received and the destination
1005        filesystem already exists.
1006    :raises StreamFeatureNotSupported: if the stream has a feature that is not
1007        supported on this side.
1008    :raises NameInvalid: if the name of either snapshot is invalid.
1009    :raises NameTooLong: if the name of either snapshot is too long.
1010    '''
1011
1012    if origin is not None:
1013        c_origin = origin
1014    else:
1015        c_origin = _ffi.NULL
1016    if props is None:
1017        props = {}
1018    nvlist = nvlist_in(props)
1019    ret = _lib.lzc_receive_resumable(
1020        snapname, nvlist, c_origin, force, raw, fd)
1021    errors.lzc_receive_translate_errors(
1022        ret, snapname, fd, force, raw, False, False, origin, None)
1023
1024
1025def lzc_receive_with_header(
1026    snapname, fd, begin_record, force=False, resumable=False, raw=False,
1027    origin=None, props=None
1028):
1029    '''
1030    Like :func:`lzc_receive`, but allows the caller to read the begin record
1031    and then to pass it in.
1032
1033    That could be useful if the caller wants to derive, for example,
1034    the snapname or the origin parameters based on the information contained in
1035    the begin record.
1036    :func:`receive_header` can be used to receive the begin record from the
1037    file descriptor.
1038
1039    :param bytes snapname: the name of the snapshot to create.
1040    :param int fd: the file descriptor from which to read the stream.
1041    :param begin_record: the stream's begin record.
1042    :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1043        structure.
1044    :param bool force: whether to roll back or destroy the target filesystem
1045        if that is required to receive the stream.
1046    :param bool resumable: whether this stream should be treated as resumable.
1047        If the receive fails due to premature stream termination, the
1048        intermediate state will be preserved on disk and may subsequently be
1049        resumed with :func:`lzc_send_resume`.
1050    :param bool raw: whether this is a "raw" stream.
1051    :param origin: the optional origin snapshot name if the stream is for a
1052        clone.
1053    :type origin: bytes or None
1054    :param props: the properties to set on the snapshot as *received*
1055        properties.
1056    :type props: dict of bytes : Any
1057
1058    :raises IOError: if an input / output error occurs while reading from the
1059        ``fd``.
1060    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1061    :raises DatasetExists: if the stream is a full stream and the destination
1062        filesystem already exists.
1063    :raises DatasetExists: if ``force`` is `True` but the destination
1064        filesystem could not be rolled back to a matching snapshot because a
1065        newer snapshot exists and it is an origin of a cloned filesystem.
1066    :raises StreamMismatch: if an incremental stream is received and the latest
1067        snapshot of the destination filesystem does not match the source
1068        snapshot of the stream.
1069    :raises StreamMismatch: if a full stream is received and the destination
1070        filesystem already exists and it has at least one snapshot, and
1071        ``force`` is `False`.
1072    :raises StreamMismatch: if an incremental clone stream is received but the
1073        specified ``origin`` is not the actual received origin.
1074    :raises DestinationModified: if an incremental stream is received and the
1075        destination filesystem has been modified since the last snapshot and
1076        ``force`` is `False`.
1077    :raises DestinationModified: if a full stream is received and the
1078        destination filesystem already exists and it does not have any
1079        snapshots, and ``force`` is `False`.
1080    :raises DatasetNotFound: if the destination filesystem and its parent do
1081        not exist.
1082    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1083        exist.
1084    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1085        could not be rolled back to a matching snapshot because a newer
1086        snapshot is held and could not be destroyed.
1087    :raises DatasetBusy: if another receive operation is being performed on the
1088        destination filesystem.
1089    :raises BadStream: if the stream is corrupt or it is not recognized or it
1090        is a compound stream or it is a clone stream, but ``origin`` is `None`.
1091    :raises BadStream: if a clone stream is received and the destination
1092        filesystem already exists.
1093    :raises StreamFeatureNotSupported: if the stream has a feature that is not
1094        supported on this side.
1095    :raises NameInvalid: if the name of either snapshot is invalid.
1096    :raises NameTooLong: if the name of either snapshot is too long.
1097    '''
1098
1099    if origin is not None:
1100        c_origin = origin
1101    else:
1102        c_origin = _ffi.NULL
1103    if props is None:
1104        props = {}
1105    nvlist = nvlist_in(props)
1106    ret = _lib.lzc_receive_with_header(
1107        snapname, nvlist, c_origin, force, resumable, raw, fd, begin_record)
1108    errors.lzc_receive_translate_errors(
1109        ret, snapname, fd, force, raw, False, False, origin, None)
1110
1111
1112def receive_header(fd):
1113    '''
1114    Read the begin record of the ZFS backup stream from the given file
1115    descriptor.
1116
1117    This is a helper function for :func:`lzc_receive_with_header`.
1118
1119    :param int fd: the file descriptor from which to read the stream.
1120    :return: a tuple with two elements where the first one is a Python `dict`
1121        representing the fields of the begin record and the second one is an
1122        opaque object suitable for passing to :func:`lzc_receive_with_header`.
1123    :raises IOError: if an input / output error occurs while reading from the
1124        ``fd``.
1125
1126    At present the following fields can be of interest in the header:
1127
1128    drr_toname : bytes
1129        the name of the snapshot for which the stream has been created
1130    drr_toguid : integer
1131        the GUID of the snapshot for which the stream has been created
1132    drr_fromguid : integer
1133        the GUID of the starting snapshot in the case the stream is
1134        incremental, zero otherwise
1135    drr_flags : integer
1136        the flags describing the stream's properties
1137    drr_type : integer
1138        the type of the dataset for which the stream has been created
1139        (volume, filesystem)
1140    '''
1141    # read sizeof(dmu_replay_record_t) bytes directly into the memory backing
1142    # 'record'
1143    record = _ffi.new("dmu_replay_record_t *")
1144    _ffi.buffer(record)[:] = os.read(fd, _ffi.sizeof(record[0]))
1145    # get drr_begin member and its representation as a Python dict
1146    drr_begin = record.drr_u.drr_begin
1147    header = {}
1148    for field, descr in _ffi.typeof(drr_begin).fields:
1149        if descr.type.kind == 'primitive':
1150            header[field] = getattr(drr_begin, field)
1151        elif descr.type.kind == 'enum':
1152            header[field] = getattr(drr_begin, field)
1153        elif descr.type.kind == 'array' and descr.type.item.cname == 'char':
1154            header[field] = _ffi.string(getattr(drr_begin, field))
1155        else:
1156            raise TypeError(
1157                'Unexpected field type in drr_begin: ' + str(descr.type))
1158    return (header, record)
1159
1160
1161def lzc_receive_one(
1162    snapname, fd, begin_record, force=False, resumable=False, raw=False,
1163    origin=None, props=None, cleanup_fd=-1, action_handle=0
1164):
1165    '''
1166    Like :func:`lzc_receive`, but allows the caller to pass all supported
1167    arguments and retrieve all values returned.  The only additional input
1168    parameter is 'cleanup_fd' which is used to set a cleanup-on-exit file
1169    descriptor.
1170
1171    :param bytes snapname: the name of the snapshot to create.
1172    :param int fd: the file descriptor from which to read the stream.
1173    :param begin_record: the stream's begin record.
1174    :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1175        structure.
1176    :param bool force: whether to roll back or destroy the target filesystem
1177        if that is required to receive the stream.
1178    :param bool resumable: whether this stream should be treated as resumable.
1179        If the receive fails due to premature stream termination, the
1180        intermediate state will be preserved on disk and may subsequently be
1181        resumed with :func:`lzc_send_resume`.
1182    :param bool raw: whether this is a "raw" stream.
1183    :param origin: the optional origin snapshot name if the stream is for a
1184        clone.
1185    :type origin: bytes or None
1186    :param props: the properties to set on the snapshot as *received*
1187        properties.
1188    :type props: dict of bytes : Any
1189    :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1190        descriptor.
1191    :param int action_handle: variable used to pass the handle for guid/ds
1192        mapping: this should be set to zero on first call and will contain an
1193        updated handle on success, which should be passed in subsequent calls.
1194
1195    :return: a tuple with two elements where the first one is the number of
1196        bytes read from the file descriptor and the second one is the
1197        action_handle return value.
1198
1199    :raises IOError: if an input / output error occurs while reading from the
1200        ``fd``.
1201    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1202    :raises DatasetExists: if the stream is a full stream and the destination
1203        filesystem already exists.
1204    :raises DatasetExists: if ``force`` is `True` but the destination
1205        filesystem could not be rolled back to a matching snapshot because a
1206        newer snapshot exists and it is an origin of a cloned filesystem.
1207    :raises StreamMismatch: if an incremental stream is received and the latest
1208        snapshot of the destination filesystem does not match the source
1209        snapshot of the stream.
1210    :raises StreamMismatch: if a full stream is received and the destination
1211        filesystem already exists and it has at least one snapshot, and
1212        ``force`` is `False`.
1213    :raises StreamMismatch: if an incremental clone stream is received but the
1214        specified ``origin`` is not the actual received origin.
1215    :raises DestinationModified: if an incremental stream is received and the
1216        destination filesystem has been modified since the last snapshot and
1217        ``force`` is `False`.
1218    :raises DestinationModified: if a full stream is received and the
1219        destination filesystem already exists and it does not have any
1220        snapshots, and ``force`` is `False`.
1221    :raises DatasetNotFound: if the destination filesystem and its parent do
1222        not exist.
1223    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1224        exist.
1225    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1226        could not be rolled back to a matching snapshot because a newer
1227        snapshot is held and could not be destroyed.
1228    :raises DatasetBusy: if another receive operation is being performed on the
1229        destination filesystem.
1230    :raises BadStream: if the stream is corrupt or it is not recognized or it
1231        is a compound stream or it is a clone stream, but ``origin`` is `None`.
1232    :raises BadStream: if a clone stream is received and the destination
1233        filesystem already exists.
1234    :raises StreamFeatureNotSupported: if the stream has a feature that is not
1235        supported on this side.
1236    :raises ReceivePropertyFailure: if one or more of the specified properties
1237        is invalid or has an invalid type or value.
1238    :raises NameInvalid: if the name of either snapshot is invalid.
1239    :raises NameTooLong: if the name of either snapshot is too long.
1240    '''
1241
1242    if origin is not None:
1243        c_origin = origin
1244    else:
1245        c_origin = _ffi.NULL
1246    if action_handle is not None:
1247        c_action_handle = _ffi.new("uint64_t *")
1248    else:
1249        c_action_handle = _ffi.NULL
1250    c_read_bytes = _ffi.new("uint64_t *")
1251    c_errflags = _ffi.new("uint64_t *")
1252    if props is None:
1253        props = {}
1254    nvlist = nvlist_in(props)
1255    properrs = {}
1256    with nvlist_out(properrs) as c_errors:
1257        ret = _lib.lzc_receive_one(
1258            snapname, nvlist, c_origin, force, resumable, raw, fd,
1259            begin_record, cleanup_fd, c_read_bytes, c_errflags,
1260            c_action_handle, c_errors)
1261    errors.lzc_receive_translate_errors(
1262        ret, snapname, fd, force, raw, False, False, origin, properrs)
1263    return (int(c_read_bytes[0]), action_handle)
1264
1265
1266def lzc_receive_with_cmdprops(
1267    snapname, fd, begin_record, force=False, resumable=False, raw=False,
1268    origin=None, props=None, cmdprops=None, key=None, cleanup_fd=-1,
1269    action_handle=0
1270):
1271    '''
1272    Like :func:`lzc_receive_one`, but allows the caller to pass an additional
1273    'cmdprops' argument. The 'cmdprops' nvlist contains both override
1274    ('zfs receive -o') and exclude ('zfs receive -x') properties.
1275
1276    :param bytes snapname: the name of the snapshot to create.
1277    :param int fd: the file descriptor from which to read the stream.
1278    :param begin_record: the stream's begin record.
1279    :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1280        structure.
1281    :param bool force: whether to roll back or destroy the target filesystem
1282        if that is required to receive the stream.
1283    :param bool resumable: whether this stream should be treated as resumable.
1284        If the receive fails due to premature stream termination, the
1285        intermediate state will be preserved on disk and may subsequently be
1286        resumed with :func:`lzc_send_resume`.
1287    :param bool raw: whether this is a "raw" stream.
1288    :param origin: the optional origin snapshot name if the stream is for a
1289        clone.
1290    :type origin: bytes or None
1291    :param props: the properties to set on the snapshot as *received*
1292        properties.
1293    :type props: dict of bytes : Any
1294    :param cmdprops: the properties to set on the snapshot as local overrides
1295        to *received* properties. `bool` values are forcefully inherited while
1296        every other value is set locally as if the command "zfs set" was
1297        invoked immediately before the receive.
1298    :type cmdprops: dict of bytes : Any
1299    :param key: raw bytes representing user's wrapping key
1300    :type key: bytes
1301    :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1302        descriptor.
1303    :param int action_handle: variable used to pass the handle for guid/ds
1304        mapping: this should be set to zero on first call and will contain an
1305        updated handle on success, it should be passed in subsequent calls.
1306
1307    :return: a tuple with two elements where the first one is the number of
1308        bytes read from the file descriptor and the second one is the
1309        action_handle return value.
1310
1311    :raises IOError: if an input / output error occurs while reading from the
1312        ``fd``.
1313    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1314    :raises DatasetExists: if the stream is a full stream and the destination
1315        filesystem already exists.
1316    :raises DatasetExists: if ``force`` is `True` but the destination
1317        filesystem could not be rolled back to a matching snapshot because a
1318        newer snapshot exists and it is an origin of a cloned filesystem.
1319    :raises StreamMismatch: if an incremental stream is received and the latest
1320        snapshot of the destination filesystem does not match the source
1321        snapshot of the stream.
1322    :raises StreamMismatch: if a full stream is received and the destination
1323        filesystem already exists and it has at least one snapshot, and
1324        ``force`` is `False`.
1325    :raises StreamMismatch: if an incremental clone stream is received but the
1326        specified ``origin`` is not the actual received origin.
1327    :raises DestinationModified: if an incremental stream is received and the
1328        destination filesystem has been modified since the last snapshot and
1329        ``force`` is `False`.
1330    :raises DestinationModified: if a full stream is received and the
1331        destination filesystem already exists and it does not have any
1332        snapshots, and ``force`` is `False`.
1333    :raises DatasetNotFound: if the destination filesystem and its parent do
1334        not exist.
1335    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1336        exist.
1337    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1338        could not be rolled back to a matching snapshot because a newer
1339        snapshot is held and could not be destroyed.
1340    :raises DatasetBusy: if another receive operation is being performed on the
1341        destination filesystem.
1342    :raises BadStream: if the stream is corrupt or it is not recognized or it
1343        is a compound stream or it is a clone stream, but ``origin`` is `None`.
1344    :raises BadStream: if a clone stream is received and the destination
1345        filesystem already exists.
1346    :raises StreamFeatureNotSupported: if the stream has a feature that is not
1347        supported on this side.
1348    :raises ReceivePropertyFailure: if one or more of the specified properties
1349        is invalid or has an invalid type or value.
1350    :raises NameInvalid: if the name of either snapshot is invalid.
1351    :raises NameTooLong: if the name of either snapshot is too long.
1352    '''
1353
1354    if origin is not None:
1355        c_origin = origin
1356    else:
1357        c_origin = _ffi.NULL
1358    if action_handle is not None:
1359        c_action_handle = _ffi.new("uint64_t *")
1360    else:
1361        c_action_handle = _ffi.NULL
1362    c_read_bytes = _ffi.new("uint64_t *")
1363    c_errflags = _ffi.new("uint64_t *")
1364    if props is None:
1365        props = {}
1366    if cmdprops is None:
1367        cmdprops = {}
1368    if key is None:
1369        key = b""
1370    else:
1371        key = bytes(key)
1372
1373    nvlist = nvlist_in(props)
1374    cmdnvlist = nvlist_in(cmdprops)
1375    properrs = {}
1376    with nvlist_out(properrs) as c_errors:
1377        ret = _lib.lzc_receive_with_cmdprops(
1378            snapname, nvlist, cmdnvlist, key, len(key), c_origin,
1379            force, resumable, raw, fd, begin_record, cleanup_fd, c_read_bytes,
1380            c_errflags, c_action_handle, c_errors)
1381    errors.lzc_receive_translate_errors(
1382        ret, snapname, fd, force, raw, False, False, origin, properrs)
1383    return (int(c_read_bytes[0]), action_handle)
1384
1385
1386def lzc_receive_with_heal(
1387    snapname, fd, begin_record, force=False, corrective=True, resumable=False,
1388    raw=False, origin=None, props=None, cmdprops=None, key=None, cleanup_fd=-1,
1389    action_handle=0
1390):
1391    '''
1392    Like :func:`lzc_receive_cmdprops`, but allows the caller to pass an
1393    additional 'corrective' argument. The 'corrective' boolean set to true
1394    indicates that a corruption healing receive should be performed.
1395
1396    :param bytes snapname: the name of the snapshot to create.
1397    :param int fd: the file descriptor from which to read the stream.
1398    :param begin_record: the stream's begin record.
1399    :type begin_record: ``cffi`` `CData` representing the dmu_replay_record_t
1400        structure.
1401    :param bool force: whether to roll back or destroy the target filesystem
1402        if that is required to receive the stream.
1403    :param bool corrective: whether this stream should be used to heal data.
1404    :param bool resumable: whether this stream should be treated as resumable.
1405        If the receive fails due to premature stream termination, the
1406        intermediate state will be preserved on disk and may subsequently be
1407        resumed with :func:`lzc_send_resume`.
1408    :param bool raw: whether this is a "raw" stream.
1409    :param origin: the optional origin snapshot name if the stream is for a
1410        clone.
1411    :type origin: bytes or None
1412    :param props: the properties to set on the snapshot as *received*
1413        properties.
1414    :type props: dict of bytes : Any
1415    :param cmdprops: the properties to set on the snapshot as local overrides
1416        to *received* properties. `bool` values are forcefully inherited while
1417        every other value is set locally as if the command "zfs set" was
1418        invoked immediately before the receive.
1419    :type cmdprops: dict of bytes : Any
1420    :param key: raw bytes representing user's wrapping key
1421    :type key: bytes
1422    :param int cleanup_fd: file descriptor used to set a cleanup-on-exit file
1423        descriptor.
1424    :param int action_handle: variable used to pass the handle for guid/ds
1425        mapping: this should be set to zero on first call and will contain an
1426        updated handle on success, it should be passed in subsequent calls.
1427
1428    :return: a tuple with two elements where the first one is the number of
1429        bytes read from the file descriptor and the second one is the
1430        action_handle return value.
1431
1432    :raises IOError: if an input / output error occurs while reading from the
1433        ``fd``.
1434    :raises DatasetExists: if the snapshot named ``snapname`` already exists.
1435    :raises DatasetExists: if the stream is a full stream and the destination
1436        filesystem already exists.
1437    :raises DatasetExists: if ``force`` is `True` but the destination
1438        filesystem could not be rolled back to a matching snapshot because a
1439        newer snapshot exists and it is an origin of a cloned filesystem.
1440    :raises StreamMismatch: if an incremental stream is received and the latest
1441        snapshot of the destination filesystem does not match the source
1442        snapshot of the stream.
1443    :raises StreamMismatch: if a full stream is received and the destination
1444        filesystem already exists and it has at least one snapshot, and
1445        ``force`` is `False`.
1446    :raises StreamMismatch: if an incremental clone stream is received but the
1447        specified ``origin`` is not the actual received origin.
1448    :raises DestinationModified: if an incremental stream is received and the
1449        destination filesystem has been modified since the last snapshot and
1450        ``force`` is `False`.
1451    :raises DestinationModified: if a full stream is received and the
1452        destination filesystem already exists and it does not have any
1453        snapshots, and ``force`` is `False`.
1454    :raises DatasetNotFound: if the destination filesystem and its parent do
1455        not exist.
1456    :raises DatasetNotFound: if the ``origin`` is not `None` and does not
1457        exist.
1458    :raises DatasetBusy: if ``force`` is `True` but the destination filesystem
1459        could not be rolled back to a matching snapshot because a newer
1460        snapshot is held and could not be destroyed.
1461    :raises DatasetBusy: if another receive operation is being performed on the
1462        destination filesystem.
1463    :raises EncryptionKeyNotLoaded: if corrective is set to true indicates the
1464            key must be loaded to do a non-raw corrective recv on an encrypted
1465            dataset.
1466    :raises BadStream: if corrective is set to true indicates that
1467        corrective recv was not able to reconstruct a corrupted block.
1468    :raises BadStream: if the stream is corrupt or it is not recognized or it
1469        is a compound stream or it is a clone stream, but ``origin`` is `None`.
1470    :raises BadStream: if a clone stream is received and the destination
1471        filesystem already exists.
1472    :raises StreamFeatureNotSupported: if corrective is set to true indicates
1473        stream is not compatible with the data in the pool.
1474    :raises StreamFeatureNotSupported: if the stream has a feature that is not
1475        supported on this side.
1476    :raises ReceivePropertyFailure: if one or more of the specified properties
1477        is invalid or has an invalid type or value.
1478    :raises NameInvalid: if the name of either snapshot is invalid.
1479    :raises NameTooLong: if the name of either snapshot is too long.
1480    '''
1481
1482    if origin is not None:
1483        c_origin = origin
1484    else:
1485        c_origin = _ffi.NULL
1486    if action_handle is not None:
1487        c_action_handle = _ffi.new("uint64_t *")
1488    else:
1489        c_action_handle = _ffi.NULL
1490    c_read_bytes = _ffi.new("uint64_t *")
1491    c_errflags = _ffi.new("uint64_t *")
1492    if props is None:
1493        props = {}
1494    if cmdprops is None:
1495        cmdprops = {}
1496    if key is None:
1497        key = b""
1498    else:
1499        key = bytes(key)
1500
1501    nvlist = nvlist_in(props)
1502    cmdnvlist = nvlist_in(cmdprops)
1503    properrs = {}
1504    with nvlist_out(properrs) as c_errors:
1505        ret = _lib.lzc_receive_with_heal(
1506            snapname, nvlist, cmdnvlist, key, len(key), c_origin,
1507            force, corrective, resumable, raw, fd, begin_record, cleanup_fd,
1508            c_read_bytes, c_errflags, c_action_handle, c_errors)
1509    errors.lzc_receive_translate_errors(
1510        ret, snapname, fd, force, raw, False, False, origin, properrs)
1511    return (int(c_read_bytes[0]), action_handle)
1512
1513
1514def lzc_reopen(poolname, restart=True):
1515    '''
1516    Reopen a pool
1517
1518    :param bytes poolname: the name of the pool.
1519    :param bool restart: whether to restart an in-progress scrub operation.
1520
1521    :raises PoolNotFound: if the pool does not exist.
1522    '''
1523    ret = _lib.lzc_reopen(poolname, restart)
1524    errors.lzc_reopen_translate_error(ret, poolname)
1525
1526
1527def lzc_send_resume(
1528    snapname, fromsnap, fd, flags=None, resumeobj=0, resumeoff=0
1529):
1530    '''
1531    Resume a previously interrupted send operation generating a zfs send stream
1532    for the specified snapshot and writing it to the specified file descriptor.
1533
1534    :param bytes snapname: the name of the snapshot to send.
1535    :param fromsnap: if not None the name of the starting snapshot
1536        for the incremental stream.
1537    :type fromsnap: bytes or None
1538    :param int fd: the file descriptor to write the send stream to.
1539    :param flags: the flags that control what enhanced features can be used in
1540        the stream.
1541    :type flags: list of bytes
1542    :param int resumeobj: the object number where this send stream should
1543        resume from.
1544    :param int resumeoff: the offset where this send stream should resume from.
1545
1546    :raises SnapshotNotFound: if either the starting snapshot is not `None` and
1547        does not exist, or if the ending snapshot does not exist.
1548    :raises NameInvalid: if the name of either snapshot is invalid.
1549    :raises NameTooLong: if the name of either snapshot is too long.
1550    :raises SnapshotMismatch: if ``fromsnap`` is not an ancestor snapshot of
1551        ``snapname``.
1552    :raises PoolsDiffer: if the snapshots belong to different pools.
1553    :raises IOError: if an input / output error occurs while writing to ``fd``.
1554    :raises UnknownStreamFeature: if the ``flags`` contain an unknown flag
1555        name.
1556
1557    .. note::
1558        See :func:`lzc_send` for more information.
1559    '''
1560    if fromsnap is not None:
1561        c_fromsnap = fromsnap
1562    else:
1563        c_fromsnap = _ffi.NULL
1564    c_flags = 0
1565    if flags is None:
1566        flags = []
1567    for flag in flags:
1568        c_flag = {
1569            'embedded_data': _lib.LZC_SEND_FLAG_EMBED_DATA,
1570            'large_blocks': _lib.LZC_SEND_FLAG_LARGE_BLOCK,
1571            'compress': _lib.LZC_SEND_FLAG_COMPRESS,
1572            'raw': _lib.LZC_SEND_FLAG_RAW,
1573        }.get(flag)
1574        if c_flag is None:
1575            raise exceptions.UnknownStreamFeature(flag)
1576        c_flags |= c_flag
1577
1578    ret = _lib.lzc_send_resume(
1579        snapname, c_fromsnap, fd, c_flags, uint64_t(resumeobj),
1580        uint64_t(resumeoff))
1581    errors.lzc_send_translate_error(ret, snapname, fromsnap, fd, flags)
1582
1583
1584def lzc_sync(poolname, force=False):
1585    '''
1586    Forces all in-core dirty data to be written to the primary pool storage
1587    and not the ZIL.
1588
1589    :param bytes poolname: the name of the pool.
1590    :param bool force: whether to force uberblock update even if there is no
1591        dirty data.
1592
1593    :raises PoolNotFound: if the pool does not exist.
1594
1595    .. note::
1596        This method signature is different from its C libzfs_core counterpart:
1597        `innvl` has been replaced by the `force` boolean and `outnvl` has been
1598        conveniently removed since it's not used.
1599    '''
1600    innvl = nvlist_in({b"force": force})
1601    with nvlist_out({}) as outnvl:
1602        ret = _lib.lzc_sync(poolname, innvl, outnvl)
1603    errors.lzc_sync_translate_error(ret, poolname)
1604
1605
1606def is_supported(func):
1607    '''
1608    Check whether C *libzfs_core* provides implementation required
1609    for the given Python wrapper.
1610
1611    If `is_supported` returns ``False`` for the function, then
1612    calling the function would result in :exc:`NotImplementedError`.
1613
1614    :param function func: the function to check.
1615    :return bool: whether the function can be used.
1616    '''
1617    fname = func.__name__
1618    if fname not in globals():
1619        raise ValueError(fname + ' is not from libzfs_core')
1620    if not callable(func):
1621        raise ValueError(fname + ' is not a function')
1622    if not fname.startswith("lzc_"):
1623        raise ValueError(fname + ' is not a libzfs_core API function')
1624    check_func = getattr(func, "_check_func", None)
1625    if check_func is not None:
1626        return is_supported(check_func)
1627    return getattr(_lib, fname, None) is not None
1628
1629
1630def lzc_promote(name):
1631    '''
1632    Promotes the ZFS dataset.
1633
1634    :param bytes name: the name of the dataset to promote.
1635    :raises NameInvalid: if the dataset name is invalid.
1636    :raises NameTooLong: if the dataset name is too long.
1637    :raises NameTooLong: if the dataset's origin has a snapshot that, if
1638        transferred to the dataset, would get a too long name.
1639    :raises NotClone: if the dataset is not a clone.
1640    :raises FilesystemNotFound: if the dataset does not exist.
1641    :raises SnapshotExists: if the dataset already has a snapshot with the same
1642        name as one of the origin's snapshots.
1643    '''
1644    ret = _lib.lzc_promote(name, _ffi.NULL, _ffi.NULL)
1645    errors.lzc_promote_translate_error(ret, name)
1646
1647
1648def lzc_pool_checkpoint(name):
1649    '''
1650    Creates a checkpoint for the specified pool.
1651
1652    :param bytes name: the name of the pool to create a checkpoint for.
1653    :raises CheckpointExists: if the pool already has a checkpoint.
1654    :raises CheckpointDiscarding: if ZFS is in the middle of discarding a
1655        checkpoint for this pool.
1656    :raises DeviceRemovalRunning: if a vdev is currently being removed.
1657    :raises DeviceTooBig: if one or more top-level vdevs exceed the maximum
1658        vdev size.
1659    '''
1660    ret = _lib.lzc_pool_checkpoint(name)
1661    errors.lzc_pool_checkpoint_translate_error(ret, name)
1662
1663
1664def lzc_pool_checkpoint_discard(name):
1665    '''
1666    Discard the checkpoint from the specified pool.
1667
1668    :param bytes name: the name of the pool to discard the checkpoint from.
1669    :raises CheckpointNotFound: if pool does not have a checkpoint.
1670    :raises CheckpointDiscarding: if ZFS is in the middle of discarding a
1671        checkpoint for this pool.
1672    '''
1673    ret = _lib.lzc_pool_checkpoint_discard(name)
1674    errors.lzc_pool_checkpoint_discard_translate_error(ret, name)
1675
1676
1677def lzc_rename(source, target):
1678    '''
1679    Rename the ZFS dataset.
1680
1681    :param source name: the current name of the dataset to rename.
1682    :param target name: the new name of the dataset.
1683    :raises NameInvalid: if either the source or target name is invalid.
1684    :raises NameTooLong: if either the source or target name is too long.
1685    :raises NameTooLong: if a snapshot of the source would get a too long name
1686        after renaming.
1687    :raises FilesystemNotFound: if the source does not exist.
1688    :raises FilesystemNotFound: if the target's parent does not exist.
1689    :raises FilesystemExists: if the target already exists.
1690    :raises PoolsDiffer: if the source and target belong to different pools.
1691    :raises WrongParent: if the "new" parent dataset is not a filesystem
1692        (e.g. ZVOL)
1693    '''
1694    ret = _lib.lzc_rename(source, target)
1695    errors.lzc_rename_translate_error(ret, source, target)
1696
1697
1698def lzc_destroy(name):
1699    '''
1700    Destroy the ZFS dataset.
1701
1702    :param bytes name: the name of the dataset to destroy.
1703    :raises NameInvalid: if the dataset name is invalid.
1704    :raises NameTooLong: if the dataset name is too long.
1705    :raises FilesystemNotFound: if the dataset does not exist.
1706    '''
1707    ret = _lib.lzc_destroy(name)
1708    errors.lzc_destroy_translate_error(ret, name)
1709
1710
1711# TODO: a better way to init and uninit the library
1712def _initialize():
1713    class LazyInit(object):
1714
1715        def __init__(self, lib):
1716            self._lib = lib
1717            self._inited = False
1718            self._lock = threading.Lock()
1719
1720        def __getattr__(self, name):
1721            if not self._inited:
1722                with self._lock:
1723                    if not self._inited:
1724                        ret = self._lib.libzfs_core_init()
1725                        if ret != 0:
1726                            raise exceptions.ZFSInitializationFailed(ret)
1727                        self._inited = True
1728            return getattr(self._lib, name)
1729
1730    return LazyInit(libzfs_core.lib)
1731
1732
1733_ffi = libzfs_core.ffi
1734_lib = _initialize()
1735
1736
1737# vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4
1738