| 
					
				 | 
			
			
				@@ -1,6 +1,8 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import glob 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import logging 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import os 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import shlex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import shutil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import subprocess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import borgmatic.config.paths 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -65,8 +67,7 @@ def dump_data_sources( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         (dataset_name, mount_point) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for line in list_output.splitlines() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (dataset_name, mount_point, user_property_value) in (line.rstrip().split('\t'),) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if mount_point in source_directories_set 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        or user_property_value == 'auto' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if mount_point in source_directories_set or user_property_value == 'auto' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # Snapshot each dataset, rewriting source directories to use the snapshot paths. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -97,7 +98,9 @@ def dump_data_sources( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             mount_point.lstrip(os.path.sep), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         snapshot_path = os.path.normpath(snapshot_path_for_borg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        logger.debug(f'{log_prefix}: Mounting ZFS snapshot {full_snapshot_name} at {snapshot_path}{dry_run_label}') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.debug( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            f'{log_prefix}: Mounting ZFS snapshot {full_snapshot_name} at {snapshot_path}{dry_run_label}' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if not dry_run: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             os.makedirs(snapshot_path, mode=0o700, exist_ok=True) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -154,15 +157,26 @@ def remove_data_source_dumps(hook_config, config, log_prefix, borgmatic_runtime_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for line in list_datasets_output.splitlines() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (dataset_name, mount_point) in (line.rstrip().split('\t'),) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # FIXME: This doesn't necessarily find snapshot mounts from previous borgmatic runs, because 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # borgmatic_runtime_directory could be in a tempfile-created directory that has a random name. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    snapshots_directory = os.path.join( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        os.path.normpath(borgmatic_runtime_directory), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    snapshots_glob = os.path.join( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        borgmatic.config.paths.replace_temporary_subdirectory_with_glob( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            os.path.normpath(borgmatic_runtime_directory) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         'zfs_snapshots', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    logger.debug(f'{log_prefix}: Looking for snapshots to remove in {snapshots_directory}{dry_run_label}') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.debug( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        f'{log_prefix}: Looking for snapshots to remove in {snapshots_glob}{dry_run_label}' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for snapshots_directory in glob.glob(snapshots_glob): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if not os.path.isdir(snapshots_directory): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # This might fail if the directory is already mounted, but we swallow errors here since 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # we'll try again below. The point of doing it here is that we don't want to try to unmount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # a non-mounted directory (which *will* fail), and probing for whether a directory is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # mounted is tough to do in a cross-platform way. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        shutil.rmtree(snapshots_directory, ignore_errors=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if os.path.isdir(snapshots_directory): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for mount_point in mount_points: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             snapshot_path = os.path.join(snapshots_directory, mount_point.lstrip(os.path.sep)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             logger.debug(f'{log_prefix}: Unmounting ZFS snapshot at {snapshot_path}{dry_run_label}') 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -176,6 +190,8 @@ def remove_data_source_dumps(hook_config, config, log_prefix, borgmatic_runtime_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     output_log_level=logging.DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        shutil.rmtree(snapshots_directory) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # Destroy snapshots. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     list_snapshots_command = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         zfs_command, 
			 |