58 this.mount_path = path;
59 this.parent_window = parent_win;
60 this.btrfs_mode = _btrfs_mode;
83 log_debug(
"SnapshotRepo: from_path(): synthetic device for path %s".printf(path));
91 string std_out, std_err;
92 int rc =
exec_sync(
"df -T -B1 \"%s\"".printf(path), out std_out, out std_err);
93 if (rc != 0){
return null; }
95 string[] lines = std_out.split(
"\n");
96 if (lines.length < 2){
return null; }
99 string data_line =
"";
100 for (
int i = lines.length - 1; i >= 1; i--){
101 if (lines[i].strip().length > 0){ data_line = lines[i];
break; }
103 if (data_line.length == 0){
return null; }
107 foreach (
string val
in data_line.split(
" ")){
108 if (val.strip().length == 0){
continue; }
110 case 1: dev.device = val.strip();
break;
111 case 2: dev.fstype = val.strip();
break;
112 case 3: dev.size_bytes = uint64.parse(val.strip());
break;
113 case 4: dev.used_bytes = uint64.parse(val.strip());
break;
114 case 5: dev.available_bytes = uint64.parse(val.strip());
break;
115 case 6: dev.used_percent = val.strip();
break;
121 dev.uuid =
"smb:%s".printf(path);
128 log_debug(
"SnapshotRepo: from_device(): %s".printf(btrfs_repo ?
"BTRFS" :
"RSYNC"));
132 this.parent_window = parent_win;
133 this.btrfs_mode = btrfs_repo;
144 log_debug(
"SnapshotRepo: from_uuid(): %s".printf(btrfs_repo ?
"BTRFS" :
"RSYNC"));
154 this.parent_window = parent_win;
155 this.btrfs_mode = btrfs_repo;
163 log_debug(
"SnapshotRepo: from_uuid(): exit");
175 log_debug(
"SnapshotRepo: from_null(): exit");
180 log_debug(
"SnapshotRepo: init_from_device()");
199 log_debug(
"SnapshotRepo: init_from_device(): exit");
247 log_debug(
"SnapshotRepo: unlock_and_mount_devices()");
276 if (repo_subvolumes.has_key(
"@home")){
278 var subvol = repo_subvolumes[
"@home"];
296 log_debug(
"SnapshotRepo: unlock_and_mount_device(): exit");
305 log_debug(
"SnapshotRepo: unlock_and_mount_device()");
307 Device dev = device_to_mount;
324 log_debug(
"SnapshotRepo: unlock_and_mount_device(): exit");
330 var mount_options =
"";
332 mount_options =
"subvolid=0";
337 return path_to_mount;
346 log_debug(
"SnapshotRepo: unlock_encrypted_device()");
348 if (luks_device ==
null){
356 string msg_out, msg_err;
358 luks_device,
"",
"",
parent_window, out msg_out, out msg_err);
360 return luks_unlocked;
365 log_debug(
"SnapshotRepo: load_snapshots()");
376 var enumerator = dir.enumerate_children(
"*", 0);
378 var info = enumerator.next_file ();
379 while (info !=
null) {
380 if (info.get_file_type() == FileType.DIRECTORY) {
381 if (info.get_name() !=
".sync") {
394 info = enumerator.next_file ();
410 DateTime dt_boot =
new DateTime.now_local();
417 bak.update_control_file();
420 if (bak.date.difference(dt_boot) < 0){
423 bak.update_control_file();
445 var list =
new Gee.ArrayList<
Snapshot?>();
448 if (bak.valid && (tag.length == 0) || bak.has_tag(tag)){
465 for(
int i = list.size - 1; i >= 0; i--){
467 if (bak.sys_uuid == sys_uuid){
479 for(
int i = 0; i < list.size; i++){
481 if (bak.sys_uuid == sys_uuid){
493 log_debug(
"SnapshotRepo: check_status()");
513 _(
"Snapshot device"),
524 status_code.to_string().replace(
"SNAPSHOT_LOCATION_STATUS_",
"")));
530 log_debug(
"SnapshotRepo: check_status(): exit");
573 log_debug(
"SnapshotRepo: has_btrfs_system()");
576 log_debug(
"root_path=%s".printf(root_path));
581 status_details =
_(
"Select BTRFS system disk with root subvolume (@)");
593 log_debug(
"SnapshotRepo: has_snapshots()");
670 log_msg(
"%-6s : %s".printf(
_(
"Device"),
_(
"Not Selected")));
688 log_debug(
"SnapshotRepo: auto_remove()");
690 DateTime now =
new DateTime.now_local();
699 log_msg(
_(
"Maximum backups exceeded for backup level") +
" '%s'".printf(
"boot"));
701 list[0].remove_tag(
"boot");
702 log_msg(
_(
"Snapshot") +
" '%s' ".printf(list[0].name) +
_(
"un-tagged") +
" '%s'".printf(
"boot"));
709 string[] levels = {
"hourly",
"daily",
"weekly",
"monthly" };
711 foreach(
string level
in levels){
715 if (list.size == 0) {
continue; }
735 dt_limit = now.add_years(-1 * 10);
736 count_limit = 100000;
740 if (list.size > count_limit){
742 log_msg(
_(
"Maximum backups exceeded for backup level") +
" '%s'".printf(level));
744 int snaps_count = list.size;
746 foreach(var snap
in list){
748 if (snap.description.strip().length > 0){
continue; }
750 if ((snap.date.compare(dt_limit) < 0) && (snaps_count > count_limit)){
752 snap.remove_tag(level);
755 log_msg(
_(
"Snapshot") +
" '%s' ".printf(list[0].name) +
_(
"un-tagged") +
" '%s'".printf(level));
826 log_debug(
"SnapshotRepo: remove_untagged()");
828 bool show_msg =
true;
831 if (bak.tags.size == 0){
834 log_msg(
"%s (%s):".printf(
_(
"Removing snapshots"),
_(
"un-tagged")));
847 bool show_msg =
true;
850 if (bak.marked_for_deletion){
853 log_msg(
"%s (%s):".printf(
_(
"Removing snapshots"),
_(
"marked for deletion")));
866 bool show_msg =
true;
871 log_msg(
"%s (%s):".printf(
_(
"Removing snapshots"),
_(
"incomplete")));
885 log_msg(
_(
"Removing snapshots") +
" > " +
_(
"all") +
"...");
907 string sync_dir =
mount_path +
"/bastionguard-backup/snapshots/.sync";
948 Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 100);
980 foreach(
string tag
in bak.tags) {
981 string linkTarget =
"%s-%s/%s".printf(
snapshots_path, tag, bak.name);
982 string linkValue =
"../snapshots/" + bak.name;
984 File f = File.new_for_path(linkTarget);
985 if (!f.make_symbolic_link(linkValue)) {
986 log_error(
_(
"Failed to create symlinks") +
": %s".printf(linkTarget));
990 log_error(
_(
"Failed to create symlinks") +
": %s".printf(linkTarget));
1002 log_error(
_(
"Failed to delete symlinks") +
": '%s'".printf(path));
1005 File f = File.new_for_path(path);
1006 f.make_directory_with_parents();
@ HARDLINKS_NOT_SUPPORTED
@ HAS_SNAPSHOTS_HAS_SPACE
static Gee.ArrayList< Device > get_disk_space_using_df(string dev_name_or_mount_point="")
bool is_encrypted_partition()
static bool mount(string dev_name_or_uuid, string mount_point, string mount_options="", bool silent=false)
static ? Device luks_unlock(Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window, out string message, out string details)
static ? Device get_device_by_uuid(string uuid)
string device_name_with_parent
static uint64 first_snapshot_size
void query_subvolume_info(SnapshotRepo parent_repo)
const uint64 MIN_FREE_SPACE
void delete_directory_thread()
void cleanup_symlink_dir(string tag)
Gee.ArrayList< Snapshot?> snapshots
SnapshotRepo. from_device(Device dev, Gtk.Window? parent_win, bool btrfs_repo)
Gee.ArrayList< Snapshot?> invalid_snapshots
Gtk.? Window parent_window
Gee.HashMap< string, string > mount_paths
bool last_snapshot_failed_space
void remove_marked_for_deletion()
Snapshot? get_oldest_snapshot(string tag, string sys_uuid)
bool remove_timeshift_dir()
bool unlock_and_mount_devices()
string unlock_and_mount_device(Device device_to_mount, string path_to_mount)
Snapshot? get_latest_snapshot(string tag, string sys_uuid)
bool has_space(uint64 needed=0)
SnapshotRepo. from_path(string path, Gtk.Window? parent_win, bool _btrfs_mode)
bool delete_directory(string dir_path)
SnapshotRepo. from_null()
static ? Device build_synthetic_device_for_path(string path)
SnapshotRepo. from_uuid(string uuid, Gtk.Window? parent_win, bool btrfs_repo)
SnapshotLocationStatus status_code
Gee.ArrayList< Snapshot?> get_snapshots_by_tag(string tag="")
Device? unlock_encrypted_device(Device luks_device)
Snapshot(string dir_path, bool btrfs_snapshot, SnapshotRepo _repo)
static Gee.HashMap< string, Subvolume > detect_subvolumes_for_system_by_path(string system_path, SnapshotRepo? repo, Gtk.Window? parent_window)
string path_combine(string path1, string path2)
string format_file_size(uint64 size, bool binary_units=false, string unit="", bool show_units=true, int decimals=1)
bool dir_exists(string dir_path)
void log_debug(string message)
void log_error(string message, bool highlight=false, bool is_warning=false)
void log_msg(string message, bool highlight=false)
int exec_sync(string cmd, out string? std_out=null, out string? std_err=null)
double get_system_uptime_seconds()