]> git.proxmox.com Git - mirror_zfs.git/blob - contrib/pyzfs/libzfs_core/_error_translation.py
ZVOLs should not be allowed to have children
[mirror_zfs.git] / contrib / pyzfs / libzfs_core / _error_translation.py
1 #
2 # Copyright 2015 ClusterHQ
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 """
18 Helper routines for converting ``errno`` style error codes from C functions
19 to Python exceptions defined by `libzfs_core` API.
20
21 The conversion heavily depends on the context of the error: the attempted
22 operation and the input parameters. For this reason, there is a conversion
23 routine for each `libzfs_core` interface function. The conversion routines
24 have the return code as a parameter as well as all the parameters of the
25 corresponding interface functions.
26
27 The parameters and exceptions are documented in the `libzfs_core` interfaces.
28 """
29 from __future__ import absolute_import, division, print_function
30
31 import errno
32 import re
33 import string
34 from . import exceptions as lzc_exc
35 from ._constants import (
36 MAXNAMELEN,
37 ZFS_ERR_CHECKPOINT_EXISTS,
38 ZFS_ERR_DISCARDING_CHECKPOINT,
39 ZFS_ERR_NO_CHECKPOINT,
40 ZFS_ERR_DEVRM_IN_PROGRESS,
41 ZFS_ERR_VDEV_TOO_BIG,
42 ZFS_ERR_WRONG_PARENT
43 )
44
45
46 def lzc_create_translate_error(ret, name, ds_type, props):
47 if ret == 0:
48 return
49 if ret == errno.EINVAL:
50 _validate_fs_name(name)
51 raise lzc_exc.PropertyInvalid(name)
52 if ret == errno.EEXIST:
53 raise lzc_exc.FilesystemExists(name)
54 if ret == errno.ENOENT:
55 raise lzc_exc.ParentNotFound(name)
56 if ret == ZFS_ERR_WRONG_PARENT:
57 raise lzc_exc.WrongParent(_fs_name(name))
58 raise _generic_exception(ret, name, "Failed to create filesystem")
59
60
61 def lzc_clone_translate_error(ret, name, origin, props):
62 if ret == 0:
63 return
64 if ret == errno.EINVAL:
65 _validate_fs_name(name)
66 _validate_snap_name(origin)
67 raise lzc_exc.PropertyInvalid(name)
68 if ret == errno.EXDEV:
69 raise lzc_exc.PoolsDiffer(name)
70 if ret == errno.EEXIST:
71 raise lzc_exc.FilesystemExists(name)
72 if ret == errno.ENOENT:
73 if not _is_valid_snap_name(origin):
74 raise lzc_exc.SnapshotNameInvalid(origin)
75 raise lzc_exc.DatasetNotFound(name)
76 raise _generic_exception(ret, name, "Failed to create clone")
77
78
79 def lzc_rollback_translate_error(ret, name):
80 if ret == 0:
81 return
82 if ret == errno.ESRCH:
83 raise lzc_exc.SnapshotNotFound(name)
84 if ret == errno.EINVAL:
85 _validate_fs_name(name)
86 raise lzc_exc.NameInvalid(name)
87 if ret == errno.ENOENT:
88 if not _is_valid_fs_name(name):
89 raise lzc_exc.NameInvalid(name)
90 else:
91 raise lzc_exc.FilesystemNotFound(name)
92 raise _generic_exception(ret, name, "Failed to rollback")
93
94
95 def lzc_rollback_to_translate_error(ret, name, snap):
96 if ret == errno.EEXIST:
97 raise lzc_exc.SnapshotNotLatest(snap)
98 else:
99 lzc_rollback_translate_error(ret, name)
100
101
102 def lzc_snapshot_translate_errors(ret, errlist, snaps, props):
103 if ret == 0:
104 return
105
106 def _map(ret, name):
107 if ret == errno.EXDEV:
108 pool_names = iter(map(_pool_name, snaps))
109 pool_name = next(pool_names, None)
110 same_pool = all(x == pool_name for x in pool_names)
111 if same_pool:
112 return lzc_exc.DuplicateSnapshots(name)
113 else:
114 return lzc_exc.PoolsDiffer(name)
115 elif ret == errno.EINVAL:
116 if any(not _is_valid_snap_name(s) for s in snaps):
117 return lzc_exc.NameInvalid(name)
118 elif any(len(s) > MAXNAMELEN for s in snaps):
119 return lzc_exc.NameTooLong(name)
120 else:
121 return lzc_exc.PropertyInvalid(name)
122
123 if ret == errno.EEXIST:
124 return lzc_exc.SnapshotExists(name)
125 if ret == errno.ENOENT:
126 return lzc_exc.FilesystemNotFound(name)
127 return _generic_exception(ret, name, "Failed to create snapshot")
128
129 _handle_err_list(ret, errlist, snaps, lzc_exc.SnapshotFailure, _map)
130
131
132 def lzc_destroy_snaps_translate_errors(ret, errlist, snaps, defer):
133 if ret == 0:
134 return
135
136 def _map(ret, name):
137 if ret == errno.EEXIST:
138 return lzc_exc.SnapshotIsCloned(name)
139 if ret == errno.ENOENT:
140 return lzc_exc.PoolNotFound(name)
141 if ret == errno.EBUSY:
142 return lzc_exc.SnapshotIsHeld(name)
143 return _generic_exception(ret, name, "Failed to destroy snapshot")
144
145 _handle_err_list(
146 ret, errlist, snaps, lzc_exc.SnapshotDestructionFailure, _map)
147
148
149 def lzc_bookmark_translate_errors(ret, errlist, bookmarks):
150 if ret == 0:
151 return
152
153 def _map(ret, name):
154 if ret == errno.EINVAL:
155 if name:
156 snap = bookmarks[name]
157 pool_names = map(_pool_name, bookmarks.keys())
158 if not _is_valid_bmark_name(name):
159 return lzc_exc.BookmarkNameInvalid(name)
160 elif not _is_valid_snap_name(snap):
161 return lzc_exc.SnapshotNameInvalid(snap)
162 elif _fs_name(name) != _fs_name(snap):
163 return lzc_exc.BookmarkMismatch(name)
164 elif any(x != _pool_name(name) for x in pool_names):
165 return lzc_exc.PoolsDiffer(name)
166 else:
167 invalid_names = [
168 b for b in bookmarks.keys() if not _is_valid_bmark_name(b)]
169 if invalid_names:
170 return lzc_exc.BookmarkNameInvalid(invalid_names[0])
171 if ret == errno.EEXIST:
172 return lzc_exc.BookmarkExists(name)
173 if ret == errno.ENOENT:
174 return lzc_exc.SnapshotNotFound(name)
175 if ret == errno.ENOTSUP:
176 return lzc_exc.BookmarkNotSupported(name)
177 return _generic_exception(ret, name, "Failed to create bookmark")
178
179 _handle_err_list(
180 ret, errlist, bookmarks.keys(), lzc_exc.BookmarkFailure, _map)
181
182
183 def lzc_get_bookmarks_translate_error(ret, fsname, props):
184 if ret == 0:
185 return
186 if ret == errno.ENOENT:
187 raise lzc_exc.FilesystemNotFound(fsname)
188 raise _generic_exception(ret, fsname, "Failed to list bookmarks")
189
190
191 def lzc_destroy_bookmarks_translate_errors(ret, errlist, bookmarks):
192 if ret == 0:
193 return
194
195 def _map(ret, name):
196 if ret == errno.EINVAL:
197 return lzc_exc.NameInvalid(name)
198 return _generic_exception(ret, name, "Failed to destroy bookmark")
199
200 _handle_err_list(
201 ret, errlist, bookmarks, lzc_exc.BookmarkDestructionFailure, _map)
202
203
204 def lzc_snaprange_space_translate_error(ret, firstsnap, lastsnap):
205 if ret == 0:
206 return
207 if ret == errno.EXDEV and firstsnap is not None:
208 if _pool_name(firstsnap) != _pool_name(lastsnap):
209 raise lzc_exc.PoolsDiffer(lastsnap)
210 else:
211 raise lzc_exc.SnapshotMismatch(lastsnap)
212 if ret == errno.EINVAL:
213 if not _is_valid_snap_name(firstsnap):
214 raise lzc_exc.NameInvalid(firstsnap)
215 elif not _is_valid_snap_name(lastsnap):
216 raise lzc_exc.NameInvalid(lastsnap)
217 elif len(firstsnap) > MAXNAMELEN:
218 raise lzc_exc.NameTooLong(firstsnap)
219 elif len(lastsnap) > MAXNAMELEN:
220 raise lzc_exc.NameTooLong(lastsnap)
221 elif _pool_name(firstsnap) != _pool_name(lastsnap):
222 raise lzc_exc.PoolsDiffer(lastsnap)
223 else:
224 raise lzc_exc.SnapshotMismatch(lastsnap)
225 if ret == errno.ENOENT:
226 raise lzc_exc.SnapshotNotFound(lastsnap)
227 raise _generic_exception(
228 ret, lastsnap, "Failed to calculate space used by range of snapshots")
229
230
231 def lzc_hold_translate_errors(ret, errlist, holds, fd):
232 if ret == 0:
233 return
234
235 def _map(ret, name):
236 if ret == errno.EXDEV:
237 return lzc_exc.PoolsDiffer(name)
238 elif ret == errno.EINVAL:
239 if name:
240 pool_names = map(_pool_name, holds.keys())
241 if not _is_valid_snap_name(name):
242 return lzc_exc.NameInvalid(name)
243 elif len(name) > MAXNAMELEN:
244 return lzc_exc.NameTooLong(name)
245 elif any(x != _pool_name(name) for x in pool_names):
246 return lzc_exc.PoolsDiffer(name)
247 else:
248 invalid_names = [
249 b for b in holds.keys() if not _is_valid_snap_name(b)]
250 if invalid_names:
251 return lzc_exc.NameInvalid(invalid_names[0])
252 fs_name = None
253 hold_name = None
254 pool_name = None
255 if name is not None:
256 fs_name = _fs_name(name)
257 pool_name = _pool_name(name)
258 hold_name = holds[name]
259 if ret == errno.ENOENT:
260 return lzc_exc.FilesystemNotFound(fs_name)
261 if ret == errno.EEXIST:
262 return lzc_exc.HoldExists(name)
263 if ret == errno.E2BIG:
264 return lzc_exc.NameTooLong(hold_name)
265 if ret == errno.ENOTSUP:
266 return lzc_exc.FeatureNotSupported(pool_name)
267 return _generic_exception(ret, name, "Failed to hold snapshot")
268
269 if ret == errno.EBADF:
270 raise lzc_exc.BadHoldCleanupFD()
271 _handle_err_list(ret, errlist, holds.keys(), lzc_exc.HoldFailure, _map)
272
273
274 def lzc_release_translate_errors(ret, errlist, holds):
275 if ret == 0:
276 return
277 for snap in holds:
278 hold_list = holds[snap]
279 if not isinstance(hold_list, list):
280 raise lzc_exc.TypeError('holds must be in a list')
281
282 def _map(ret, name):
283 if ret == errno.EXDEV:
284 return lzc_exc.PoolsDiffer(name)
285 elif ret == errno.EINVAL:
286 if name:
287 pool_names = map(_pool_name, holds.keys())
288 if not _is_valid_snap_name(name):
289 return lzc_exc.NameInvalid(name)
290 elif len(name) > MAXNAMELEN:
291 return lzc_exc.NameTooLong(name)
292 elif any(x != _pool_name(name) for x in pool_names):
293 return lzc_exc.PoolsDiffer(name)
294 else:
295 invalid_names = [
296 b for b in holds.keys() if not _is_valid_snap_name(b)]
297 if invalid_names:
298 return lzc_exc.NameInvalid(invalid_names[0])
299 elif ret == errno.ENOENT:
300 return lzc_exc.HoldNotFound(name)
301 elif ret == errno.E2BIG:
302 tag_list = holds[name]
303 too_long_tags = [t for t in tag_list if len(t) > MAXNAMELEN]
304 return lzc_exc.NameTooLong(too_long_tags[0])
305 elif ret == errno.ENOTSUP:
306 pool_name = None
307 if name is not None:
308 pool_name = _pool_name(name)
309 return lzc_exc.FeatureNotSupported(pool_name)
310 else:
311 return _generic_exception(
312 ret, name, "Failed to release snapshot hold")
313
314 _handle_err_list(
315 ret, errlist, holds.keys(), lzc_exc.HoldReleaseFailure, _map)
316
317
318 def lzc_get_holds_translate_error(ret, snapname):
319 if ret == 0:
320 return
321 if ret == errno.EINVAL:
322 _validate_snap_name(snapname)
323 if ret == errno.ENOENT:
324 raise lzc_exc.SnapshotNotFound(snapname)
325 if ret == errno.ENOTSUP:
326 raise lzc_exc.FeatureNotSupported(_pool_name(snapname))
327 raise _generic_exception(ret, snapname, "Failed to get holds on snapshot")
328
329
330 def lzc_send_translate_error(ret, snapname, fromsnap, fd, flags):
331 if ret == 0:
332 return
333 if ret == errno.EXDEV and fromsnap is not None:
334 if _pool_name(fromsnap) != _pool_name(snapname):
335 raise lzc_exc.PoolsDiffer(snapname)
336 else:
337 raise lzc_exc.SnapshotMismatch(snapname)
338 elif ret == errno.EINVAL:
339 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
340 not _is_valid_bmark_name(fromsnap)):
341 raise lzc_exc.NameInvalid(fromsnap)
342 elif (not _is_valid_snap_name(snapname) and
343 not _is_valid_fs_name(snapname)):
344 raise lzc_exc.NameInvalid(snapname)
345 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN:
346 raise lzc_exc.NameTooLong(fromsnap)
347 elif len(snapname) > MAXNAMELEN:
348 raise lzc_exc.NameTooLong(snapname)
349 elif (fromsnap is not None and
350 _pool_name(fromsnap) != _pool_name(snapname)):
351 raise lzc_exc.PoolsDiffer(snapname)
352 elif ret == errno.ENOENT:
353 if (fromsnap is not None and not _is_valid_snap_name(fromsnap) and
354 not _is_valid_bmark_name(fromsnap)):
355 raise lzc_exc.NameInvalid(fromsnap)
356 raise lzc_exc.SnapshotNotFound(snapname)
357 elif ret == errno.ENAMETOOLONG:
358 if fromsnap is not None and len(fromsnap) > MAXNAMELEN:
359 raise lzc_exc.NameTooLong(fromsnap)
360 else:
361 raise lzc_exc.NameTooLong(snapname)
362 raise lzc_exc.StreamIOError(ret)
363
364
365 def lzc_send_space_translate_error(ret, snapname, fromsnap):
366 if ret == 0:
367 return
368 if ret == errno.EXDEV and fromsnap is not None:
369 if _pool_name(fromsnap) != _pool_name(snapname):
370 raise lzc_exc.PoolsDiffer(snapname)
371 else:
372 raise lzc_exc.SnapshotMismatch(snapname)
373 elif ret == errno.EINVAL:
374 if fromsnap is not None and not _is_valid_snap_name(fromsnap):
375 raise lzc_exc.NameInvalid(fromsnap)
376 elif not _is_valid_snap_name(snapname):
377 raise lzc_exc.NameInvalid(snapname)
378 elif fromsnap is not None and len(fromsnap) > MAXNAMELEN:
379 raise lzc_exc.NameTooLong(fromsnap)
380 elif len(snapname) > MAXNAMELEN:
381 raise lzc_exc.NameTooLong(snapname)
382 elif (fromsnap is not None and
383 _pool_name(fromsnap) != _pool_name(snapname)):
384 raise lzc_exc.PoolsDiffer(snapname)
385 elif ret == errno.ENOENT and fromsnap is not None:
386 if not _is_valid_snap_name(fromsnap):
387 raise lzc_exc.NameInvalid(fromsnap)
388 if ret == errno.ENOENT:
389 raise lzc_exc.SnapshotNotFound(snapname)
390 raise _generic_exception(
391 ret, snapname, "Failed to estimate backup stream size")
392
393
394 def lzc_receive_translate_errors(
395 ret, snapname, fd, force, raw, resumable, embedded, origin, properrs
396 ):
397 if ret == 0:
398 if properrs is not None and len(properrs) > 0:
399 def _map(ret, name):
400 if ret == errno.EINVAL:
401 return lzc_exc.PropertyInvalid(name)
402 return _generic_exception(ret, name, "Failed to set property")
403 _handle_err_list(
404 errno.EINVAL, properrs, [snapname],
405 lzc_exc.ReceivePropertyFailure, _map)
406 else:
407 return
408 if ret == errno.EINVAL:
409 if (not _is_valid_snap_name(snapname) and
410 not _is_valid_fs_name(snapname)):
411 raise lzc_exc.NameInvalid(snapname)
412 elif len(snapname) > MAXNAMELEN:
413 raise lzc_exc.NameTooLong(snapname)
414 elif origin is not None and not _is_valid_snap_name(origin):
415 raise lzc_exc.NameInvalid(origin)
416 elif resumable:
417 raise lzc_exc.StreamFeatureInvalid()
418 elif embedded and not raw:
419 raise lzc_exc.StreamFeatureIncompatible()
420 else:
421 raise lzc_exc.BadStream()
422 if ret == errno.ENOENT:
423 if not _is_valid_snap_name(snapname):
424 raise lzc_exc.NameInvalid(snapname)
425 else:
426 raise lzc_exc.DatasetNotFound(snapname)
427 if ret == errno.EEXIST:
428 raise lzc_exc.DatasetExists(snapname)
429 if ret == errno.ENOTSUP:
430 raise lzc_exc.StreamFeatureNotSupported()
431 if ret == errno.ENODEV:
432 raise lzc_exc.StreamMismatch(_fs_name(snapname))
433 if ret == errno.ETXTBSY:
434 raise lzc_exc.DestinationModified(_fs_name(snapname))
435 if ret == errno.EBUSY:
436 raise lzc_exc.DatasetBusy(_fs_name(snapname))
437 if ret == errno.ENOSPC:
438 raise lzc_exc.NoSpace(_fs_name(snapname))
439 if ret == errno.EDQUOT:
440 raise lzc_exc.QuotaExceeded(_fs_name(snapname))
441 if ret == errno.ENAMETOOLONG:
442 raise lzc_exc.NameTooLong(snapname)
443 if ret == errno.EROFS:
444 raise lzc_exc.ReadOnlyPool(_pool_name(snapname))
445 if ret == errno.EAGAIN:
446 raise lzc_exc.SuspendedPool(_pool_name(snapname))
447 if ret == errno.EBADE: # ECKSUM
448 raise lzc_exc.BadStream()
449 if ret == ZFS_ERR_WRONG_PARENT:
450 raise lzc_exc.WrongParent(_fs_name(snapname))
451
452 raise lzc_exc.StreamIOError(ret)
453
454
455 def lzc_promote_translate_error(ret, name):
456 if ret == 0:
457 return
458 if ret == errno.EINVAL:
459 _validate_fs_name(name)
460 raise lzc_exc.NotClone(name)
461 if ret == errno.ENOTSOCK:
462 raise lzc_exc.NotClone(name)
463 if ret == errno.ENOENT:
464 raise lzc_exc.FilesystemNotFound(name)
465 if ret == errno.EEXIST:
466 raise lzc_exc.SnapshotExists(name)
467 raise _generic_exception(ret, name, "Failed to promote dataset")
468
469
470 def lzc_change_key_translate_error(ret, name):
471 if ret == 0:
472 return
473 if ret == errno.EINVAL:
474 _validate_fs_name(name)
475 raise lzc_exc.PropertyInvalid(name)
476 if ret == errno.ENOENT:
477 raise lzc_exc.FilesystemNotFound(name)
478 if ret == errno.EACCES:
479 raise lzc_exc.EncryptionKeyNotLoaded()
480 raise _generic_exception(ret, name, "Failed to change encryption key")
481
482
483 def lzc_load_key_translate_error(ret, name, noop):
484 if ret == 0:
485 return
486 if ret == errno.EINVAL:
487 _validate_fs_name(name)
488 raise lzc_exc.PropertyInvalid(name)
489 if ret == errno.ENOENT:
490 raise lzc_exc.FilesystemNotFound(name)
491 if ret == errno.EACCES:
492 raise lzc_exc.EncryptionKeyInvalid()
493 if ret == errno.EEXIST:
494 raise lzc_exc.EncryptionKeyAlreadyLoaded()
495 if noop:
496 raise _generic_exception(ret, name, "Failed to load encryption key")
497 else:
498 raise _generic_exception(ret, name, "Failed to verify encryption key")
499
500
501 def lzc_unload_key_translate_error(ret, name):
502 if ret == 0:
503 return
504 if ret == errno.EINVAL:
505 _validate_fs_name(name)
506 raise lzc_exc.PropertyInvalid(name)
507 if ret == errno.ENOENT:
508 raise lzc_exc.FilesystemNotFound(name)
509 if ret == errno.EACCES:
510 raise lzc_exc.EncryptionKeyNotLoaded()
511 raise _generic_exception(ret, name, "Failed to unload encryption key")
512
513
514 def lzc_sync_translate_error(ret, name):
515 if ret == 0:
516 return
517 if ret == errno.ENOENT:
518 raise lzc_exc.PoolNotFound(name)
519 raise _generic_exception(ret, name, "Failed to sync pool")
520
521
522 def lzc_reopen_translate_error(ret, name):
523 if ret == 0:
524 return
525 if ret == errno.ENOENT:
526 raise lzc_exc.PoolNotFound(name)
527 raise _generic_exception(ret, name, "Failed to reopen pool")
528
529
530 def lzc_channel_program_translate_error(ret, name, error):
531 if ret == 0:
532 return
533 if ret == errno.ENOENT:
534 raise lzc_exc.PoolNotFound(name)
535 if ret == errno.ETIME:
536 raise lzc_exc.ZCPTimeout()
537 if ret == errno.ENOMEM:
538 raise lzc_exc.ZCPMemoryError()
539 if ret == errno.ENOSPC:
540 raise lzc_exc.ZCPSpaceError()
541 if ret == errno.EPERM:
542 raise lzc_exc.ZCPPermissionError()
543 if ret == errno.ECHRNG:
544 raise lzc_exc.ZCPRuntimeError(error)
545 if ret == errno.EINVAL:
546 if error is None:
547 raise lzc_exc.ZCPLimitInvalid()
548 else:
549 raise lzc_exc.ZCPSyntaxError(error)
550 raise _generic_exception(ret, name, "Failed to execute channel program")
551
552
553 def lzc_remap_translate_error(ret, name):
554 if ret == 0:
555 return
556 if ret == errno.ENOENT:
557 raise lzc_exc.DatasetNotFound(name)
558 if ret == errno.EINVAL:
559 _validate_fs_name(name)
560 if ret == errno.ENOTSUP:
561 return lzc_exc.FeatureNotSupported(name)
562 raise _generic_exception(ret, name, "Failed to remap dataset")
563
564
565 def lzc_pool_checkpoint_translate_error(ret, name, discard=False):
566 if ret == 0:
567 return
568 if ret == errno.ENOENT:
569 raise lzc_exc.PoolNotFound(name)
570 if ret == ZFS_ERR_CHECKPOINT_EXISTS:
571 raise lzc_exc.CheckpointExists()
572 if ret == ZFS_ERR_NO_CHECKPOINT:
573 raise lzc_exc.CheckpointNotFound()
574 if ret == ZFS_ERR_DISCARDING_CHECKPOINT:
575 raise lzc_exc.CheckpointDiscarding()
576 if ret == ZFS_ERR_DEVRM_IN_PROGRESS:
577 raise lzc_exc.DeviceRemovalRunning()
578 if ret == ZFS_ERR_VDEV_TOO_BIG:
579 raise lzc_exc.DeviceTooBig()
580 if discard:
581 raise _generic_exception(
582 ret, name, "Failed to discard pool checkpoint")
583 else:
584 raise _generic_exception(ret, name, "Failed to create pool checkpoint")
585
586
587 def lzc_pool_checkpoint_discard_translate_error(ret, name):
588 lzc_pool_checkpoint_translate_error(ret, name, discard=True)
589
590
591 def lzc_rename_translate_error(ret, source, target):
592 if ret == 0:
593 return
594 if ret == errno.EINVAL:
595 _validate_fs_name(source)
596 _validate_fs_name(target)
597 if _pool_name(source) != _pool_name(target):
598 raise lzc_exc.PoolsDiffer(source)
599 if ret == errno.EEXIST:
600 raise lzc_exc.FilesystemExists(target)
601 if ret == errno.ENOENT:
602 raise lzc_exc.FilesystemNotFound(source)
603 if ret == ZFS_ERR_WRONG_PARENT:
604 raise lzc_exc.WrongParent(target)
605 raise _generic_exception(ret, source, "Failed to rename dataset")
606
607
608 def lzc_destroy_translate_error(ret, name):
609 if ret == 0:
610 return
611 if ret == errno.EINVAL:
612 _validate_fs_name(name)
613 if ret == errno.ENOENT:
614 raise lzc_exc.FilesystemNotFound(name)
615 raise _generic_exception(ret, name, "Failed to destroy dataset")
616
617
618 def lzc_inherit_prop_translate_error(ret, name, prop):
619 if ret == 0:
620 return
621 if ret == errno.EINVAL:
622 _validate_fs_name(name)
623 raise lzc_exc.PropertyInvalid(prop)
624 if ret == errno.ENOENT:
625 raise lzc_exc.DatasetNotFound(name)
626 raise _generic_exception(ret, name, "Failed to inherit a property")
627
628
629 def lzc_set_prop_translate_error(ret, name, prop, val):
630 if ret == 0:
631 return
632 if ret == errno.EINVAL:
633 _validate_fs_or_snap_name(name)
634 raise lzc_exc.PropertyInvalid(prop)
635 if ret == errno.ENOENT:
636 raise lzc_exc.DatasetNotFound(name)
637 raise _generic_exception(ret, name, "Failed to set a property")
638
639
640 def lzc_get_props_translate_error(ret, name):
641 if ret == 0:
642 return
643 if ret == errno.EINVAL:
644 _validate_fs_or_snap_name(name)
645 if ret == errno.ENOENT:
646 raise lzc_exc.DatasetNotFound(name)
647 raise _generic_exception(ret, name, "Failed to get properties")
648
649
650 def lzc_list_children_translate_error(ret, name):
651 if ret == 0:
652 return
653 if ret == errno.EINVAL:
654 _validate_fs_name(name)
655 raise _generic_exception(ret, name, "Error while iterating children")
656
657
658 def lzc_list_snaps_translate_error(ret, name):
659 if ret == 0:
660 return
661 if ret == errno.EINVAL:
662 _validate_fs_name(name)
663 raise _generic_exception(ret, name, "Error while iterating snapshots")
664
665
666 def lzc_list_translate_error(ret, name, opts):
667 if ret == 0:
668 return
669 if ret == errno.ENOENT:
670 raise lzc_exc.DatasetNotFound(name)
671 if ret == errno.EINVAL:
672 _validate_fs_or_snap_name(name)
673 raise _generic_exception(ret, name, "Error obtaining a list")
674
675
676 def _handle_err_list(ret, errlist, names, exception, mapper):
677 '''
678 Convert one or more errors from an operation into the requested exception.
679
680 :param int ret: the overall return code.
681 :param errlist: the dictionary that maps entity names to their specific
682 error codes.
683 :type errlist: dict of bytes:int
684 :param names: the list of all names of the entities on which the operation
685 was attempted.
686 :param type exception: the type of the exception to raise if an error
687 occurred. The exception should be a subclass of
688 ``MultipleOperationsFailure``.
689 :param function mapper: the function that maps an error code and a name to
690 a Python exception.
691
692 Unless ``ret`` is zero this function will raise the ``exception``.
693 If the ``errlist`` is not empty, then the compound exception will contain
694 a list of exceptions corresponding to each individual error code in the
695 ``errlist``.
696 Otherwise, the ``exception`` will contain a list with a single exception
697 corresponding to the ``ret`` value. If the ``names`` list contains only one
698 element, that is, the operation was attempted on a single entity, then the
699 name of that entity is passed to the ``mapper``.
700 If the operation was attempted on multiple entities, but the ``errlist``
701 is empty, then we can not know which entity caused the error and, thus,
702 ``None`` is used as a name to signify that fact.
703
704 .. note::
705 Note that the ``errlist`` can contain a special element with a key of
706 "N_MORE_ERRORS".
707 That element means that there were too many errors to place on the
708 ``errlist``.
709 Those errors are suppressed and only their count is provided as a
710 value of the special ``N_MORE_ERRORS`` element.
711 '''
712 if ret == 0:
713 return
714
715 if len(errlist) == 0:
716 suppressed_count = 0
717 names = list(zip(names, range(2)))
718 if len(names) == 1:
719 name, _ = names[0]
720 else:
721 name = None
722 errors = [mapper(ret, name)]
723 else:
724 errors = []
725 suppressed_count = errlist.pop('N_MORE_ERRORS', 0)
726 for name in errlist:
727 err = errlist[name]
728 errors.append(mapper(err, name))
729
730 raise exception(errors, suppressed_count)
731
732
733 def _pool_name(name):
734 '''
735 Extract a pool name from the given dataset or bookmark name.
736
737 '/' separates dataset name components.
738 '@' separates a snapshot name from the rest of the dataset name.
739 '#' separates a bookmark name from the rest of the dataset name.
740 '''
741 return re.split(b'[/@#]', name, 1)[0]
742
743
744 def _fs_name(name):
745 '''
746 Extract a dataset name from the given snapshot or bookmark name.
747
748 '@' separates a snapshot name from the rest of the dataset name.
749 '#' separates a bookmark name from the rest of the dataset name.
750 '''
751 return re.split(b'[@#]', name, 1)[0]
752
753
754 def _is_valid_name_component(component):
755 allowed = string.ascii_letters + string.digits + u'-_.: '
756 return component and all(x in allowed.encode() for x in component)
757
758
759 def _is_valid_fs_name(name):
760 return name and all(_is_valid_name_component(c) for c in name.split(b'/'))
761
762
763 def _is_valid_snap_name(name):
764 parts = name.split(b'@')
765 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and
766 _is_valid_name_component(parts[1]))
767
768
769 def _is_valid_bmark_name(name):
770 parts = name.split(b'#')
771 return (len(parts) == 2 and _is_valid_fs_name(parts[0]) and
772 _is_valid_name_component(parts[1]))
773
774
775 def _validate_fs_name(name):
776 if not _is_valid_fs_name(name):
777 raise lzc_exc.FilesystemNameInvalid(name)
778 elif len(name) > MAXNAMELEN:
779 raise lzc_exc.NameTooLong(name)
780
781
782 def _validate_snap_name(name):
783 if not _is_valid_snap_name(name):
784 raise lzc_exc.SnapshotNameInvalid(name)
785 elif len(name) > MAXNAMELEN:
786 raise lzc_exc.NameTooLong(name)
787
788
789 def _validate_bmark_name(name):
790 if not _is_valid_bmark_name(name):
791 raise lzc_exc.BookmarkNameInvalid(name)
792 elif len(name) > MAXNAMELEN:
793 raise lzc_exc.NameTooLong(name)
794
795
796 def _validate_fs_or_snap_name(name):
797 if not _is_valid_fs_name(name) and not _is_valid_snap_name(name):
798 raise lzc_exc.NameInvalid(name)
799 elif len(name) > MAXNAMELEN:
800 raise lzc_exc.NameTooLong(name)
801
802
803 def _generic_exception(err, name, message):
804 if err in _error_to_exception:
805 return _error_to_exception[err](name)
806 else:
807 return lzc_exc.ZFSGenericError(err, message, name)
808
809
810 _error_to_exception = {e.errno: e for e in [
811 lzc_exc.ZIOError,
812 lzc_exc.NoSpace,
813 lzc_exc.QuotaExceeded,
814 lzc_exc.DatasetBusy,
815 lzc_exc.NameTooLong,
816 lzc_exc.ReadOnlyPool,
817 lzc_exc.SuspendedPool,
818 lzc_exc.PoolsDiffer,
819 lzc_exc.PropertyNotSupported,
820 ]}
821
822
823 # vim: softtabstop=4 tabstop=4 expandtab shiftwidth=4