1. Overview
The Snapshot class represents a single BastionGuard Backup snapshot and provides the runtime model used to load, inspect, update, tag, validate, and delete it.
The class supports both snapshot engines:
- RSYNC snapshots – filesystem copies stored below a
localhostdirectory - BTRFS snapshots – native subvolume snapshots based on
@and optionally@home
Each object combines filesystem information with metadata loaded from the snapshot control file. It also exposes paths for exclusion files and RSYNC logs, loads the snapshot’s fstab and crypttab, manages tags and comments, and delegates physical deletion to the appropriate backend.
The class integrates the following internal components:
- SnapshotRepo – repository paths, mount points, and device associations
- Subvolume – BTRFS subvolume metadata and deletion
- DeleteFileTask – asynchronous deletion of RSYNC snapshots
- RsyncTask – parsing and generation of RSYNC change logs
- FsTabEntry – parsing of the snapshot’s
fstab - CryptTabEntry – parsing of the snapshot’s
crypttab - LinuxDistro – detection of the Linux distribution stored inside the snapshot
- Json – reading and writing snapshot metadata
- Gee – lists and maps used for tags, exclusions, and subvolumes
2. Class Definition
The class derives from GLib.Object:
public class Snapshot : GLib.Object
A Snapshot object is initialized from an existing snapshot directory and an associated SnapshotRepo.
The object is responsible for loading the snapshot state from disk during construction.
3. Core Snapshot Properties
3.1 Filesystem Identity
The snapshot location and directory name are stored in:
public string path = "";
public string name = "";
path– complete filesystem path of the snapshotname– final directory component, normally the snapshot timestamp
A typical snapshot name is:
2026-07-12_10-30-00
3.2 Creation Date
public DateTime date;
The creation date is loaded from the Unix timestamp stored in info.json.
The timestamp is interpreted as UTC and converted to local time:
DateTime date_utc = new DateTime.from_unix_utc(int64.parse(val));
date = date_utc.to_local();
Before metadata is loaded, the constructor initializes the date to Unix epoch time.
3.3 Source System Information
The class stores information about the system from which the snapshot was created:
public string sys_uuid = "";
public string sys_distro = "";
public string app_version = "";
sys_uuid– UUID of the source root filesystemsys_distro– distribution description recorded during snapshot creationapp_version– BastionGuard Backup version that created the snapshot
3.4 Description and File Count
public string description = "";
public int64 file_count = 0;
The description contains user comments associated with the snapshot.
The file count normally represents the number of entries processed during an RSYNC snapshot. BTRFS snapshots commonly store a value of zero because they are created at the subvolume level.
3.5 Validity and Runtime Flags
public bool valid = true;
public bool live = false;
public bool marked_for_deletion = false;
valid– indicates whether the required snapshot metadata is availablelive– identifies a live or pre-restore BTRFS snapshotmarked_for_deletion– mirrors the presence of the snapshot deletion marker
4. Snapshot Collections
The class maintains several collections:
public Gee.ArrayList<string> tags;
public Gee.ArrayList<string> exclude_list;
public Gee.HashMap<string, Subvolume> subvolumes;
public Gee.ArrayList<FsTabEntry> fstab_list;
public Gee.ArrayList<CryptTabEntry> cryttab_list;
tags– schedule and classification tagsexclude_list– backup exclusions stored with the snapshotsubvolumes– BTRFS subvolumes belonging to the snapshotfstab_list– parsed filesystem table from the snapshotcryttab_list– parsed encrypted-volume table from the snapshot
5. BTRFS-Specific State
BTRFS behavior is controlled by:
public bool btrfs_mode = false;
The class also maintains a map of snapshot paths for individual subvolumes:
public Gee.HashMap<string, string> paths;
The map normally contains entries for:
@
@home
Additional mount-path fields are declared for the root and home subvolumes:
public string mount_path_root = "";
public string mount_path_home = "";
In the current implementation, subvolume path resolution is primarily performed through paths and the repository’s mount_paths map.
6. Repository and Deletion Task
Each snapshot retains a reference to its repository:
public SnapshotRepo repo;
RSYNC snapshot deletion is delegated to:
public DeleteFileTask delete_file_task;
The task provides deletion progress, remaining-time estimates, status messages, and cancellation state.
7. Constructor
7.1 Snapshot()
public Snapshot(
string dir_path,
bool btrfs_snapshot,
SnapshotRepo _repo
)
The constructor receives:
- The snapshot directory path
- The snapshot engine type
- The repository containing the snapshot
The initialization sequence is:
- Create a
Gio.Fileobject for the directory - Read the directory information
- Store the path and directory name
- Store the BTRFS mode and repository reference
- Initialize the date and all collections
- Create the RSYNC deletion task
- Read the snapshot control file
- Read the exclusion list
- Read the snapshot’s
fstab - Read the snapshot’s
crypttab
Filesystem errors are caught and written to the application log.
8. Formatted Date Property
8.1 date_formatted
public string date_formatted
This read-only property formats the snapshot creation date using the application-wide date format:
return date.format(App.date_format);
The resulting value is suitable for display in snapshot lists and dialogs.
9. RSYNC Log Path Properties
The class exposes computed paths for the main RSYNC logs.
9.1 Backup Log
public string rsync_log_file
Returns:
<snapshot>/rsync-log
9.2 Backup Changes Log
public string rsync_changes_log_file
Returns:
<snapshot>/rsync-log-changes
9.3 Restore Log
public string rsync_restore_log_file
Returns:
<snapshot>/rsync-log-restore
9.4 Restore Changes Log
public string rsync_restore_changes_log_file
Returns:
<snapshot>/rsync-log-restore-changes
10. Exclusion File Properties
10.1 Backup Exclusion File
public string exclude_file_for_backup
Returns:
<snapshot>/exclude.list
10.2 Restore Exclusion File
public string exclude_file_for_restore
Returns:
<snapshot>/exclude-restore.list
11. Tag Management
Snapshot tags identify the reason or schedule associated with a snapshot.
Supported values normally include:
ondemand
boot
hourly
daily
weekly
monthly
11.1 taglist
public string taglist
The getter joins all tags into a space-separated string.
Example:
daily weekly monthly
The setter clears the existing list, splits the supplied string by spaces, and adds unique values.
11.2 taglist_short
public string taglist_short
This read-only property converts long tag names into compact display codes:
ondemand → O
boot → B
hourly → H
daily → D
weekly → W
monthly → M
For example:
daily weekly monthly
becomes:
D W M
11.3 add_tag()
public void add_tag(string tag)
The supplied value is trimmed and added only when it is not already present.
After insertion, the control file is updated immediately.
11.4 remove_tag()
public void remove_tag(string tag)
The supplied tag is removed when present. The updated tag list is then persisted to info.json.
11.5 has_tag()
public bool has_tag(string tag)
Returns whether the normalized tag exists in the snapshot’s tag list.
12. Snapshot Control File
The primary metadata file for every snapshot is:
<snapshot>/info.json
This file records the snapshot creation time, source system, application version, tags, comments, engine type, and BTRFS subvolume metadata.
13. Reading the Control File
13.1 read_control_file()
public void read_control_file()
The method checks for info.json and loads it through Json.Parser.
If the file is missing, the snapshot is marked invalid:
valid = false;
If the parsed root node or JSON object is unavailable, the snapshot is also marked invalid.
13.2 Loaded Metadata
The following keys are read:
created
sys-uuid
sys-distro
tags
comments
app-version
file_count
live
type
subvolumes
The values are mapped as follows:
created→datesys-uuid→sys_uuidsys-distro→sys_distrotags→taglistcomments→descriptionapp-version→app_versionfile_count→file_countlive→live
13.3 Snapshot Type and Distribution Detection
The metadata key type defaults to:
rsync
The class selects a filesystem root for distribution detection:
localhostfor RSYNC snapshots@for BTRFS snapshots
The distribution is detected through:
LinuxDistro.get_dist_info()
14. BTRFS Subvolume Metadata Loading
When info.json contains a subvolumes object, only the following names are accepted:
@
@home
Other subvolume names are ignored.
14.1 Repository Path Translation
A snapshot may span separate root and home BTRFS filesystems.
The path for each subvolume is calculated by replacing the repository’s primary mount path with the mount path associated with that subvolume:
paths[subvol_name] =
path.replace(
repo.mount_path,
repo.mount_paths[subvol_name]
);
The actual subvolume path is then assembled by appending the subvolume name.
14.2 Subvolume Object Creation
If the calculated directory exists, a new Subvolume object is created and inserted into the snapshot’s map:
subvolumes.set(subvol_name, subvolume);
14.3 Stored Subvolume Fields
Each subvolume is represented in JSON as an ordered array containing:
- Subvolume name
- Subvolume ID
- Total referenced bytes
- Unshared bytes
- Device UUID
Example logical structure:
"@": [
"@",
"256",
"21474836480",
"10737418240",
"filesystem-uuid"
]
The numeric values are stored as strings and parsed into their respective integer fields.
15. Deletion Marker Detection
After loading the control file, the method checks for:
<snapshot>/delete
If the file exists:
marked_for_deletion = true;
The marker allows deletion state to persist across application sessions.
16. Reading the Backup Exclusion List
16.1 read_exclude_list()
public void read_exclude_list()
The method reads:
<snapshot>/exclude.list
Before loading the file, the current exclusion collection is cleared.
Each line is:
- Trimmed
- Ignored when empty
- Added only when it is not already present
If the file is missing:
- An RSYNC snapshot is marked invalid
- A BTRFS snapshot remains valid
BTRFS snapshots do not require an RSYNC exclusion list because their contents are captured through native subvolume snapshots.
17. Reading fstab
17.1 read_fstab_file()
public void read_fstab_file()
For RSYNC snapshots, the filesystem table is read from:
<snapshot>/localhost/etc/fstab
For BTRFS snapshots, it is read from:
<snapshot>/@/etc/fstab
Parsing is delegated to:
FsTabEntry.read_file(fstab_path)
The resulting entries are used during restore-target mapping and filesystem configuration repair.
18. Reading crypttab
18.1 read_crypttab_file()
public void read_crypttab_file()
For RSYNC snapshots, the encrypted-volume table is read from:
<snapshot>/localhost/etc/crypttab
For BTRFS snapshots, it is read from:
<snapshot>/@/etc/crypttab
Parsing is delegated to:
CryptTabEntry.read_file(crypttab_path)
The stored data is later used when reconstructing encrypted target mappings during restoration.
19. Updating the Control File
19.1 update_control_file()
public void update_control_file()
The method updates mutable snapshot metadata without rebuilding the complete snapshot.
The following values are replaced:
tagscommentslivesubvolumes, when using BTRFS
19.2 BTRFS Subvolume Serialization
For each subvolume, the method writes an array containing:
name
id
total_bytes
unshared_bytes
device_uuid
All values are serialized as JSON strings.
19.3 JSON Rewrite
The JSON generator is configured with:
json.pretty = true;
json.indent = 2;
The existing info.json file is deleted before the updated document is written.
Filesystem and JSON errors are caught and logged.
20. Removing the Control File
20.1 remove_control_file()
public void remove_control_file()
The method deletes:
<snapshot>/info.json
Deletion is delegated to the shared file_delete() utility.
Removing the control file causes the snapshot to be considered invalid during future loading.
21. Creating a Control File
21.1 write_control_file()
public static Snapshot write_control_file(
string snapshot_path,
DateTime dt_created,
string root_uuid,
string distro_full_name,
string tag,
string comments,
int64 item_count,
bool is_btrfs,
bool is_live,
SnapshotRepo repo,
bool silent = false
)
This static factory method creates the initial info.json document for a new snapshot.
21.2 Initial Metadata
The following keys are written:
created
sys-uuid
sys-distro
app-version
file_count
tags
comments
live
type
The creation date is converted to UTC and stored as a Unix timestamp:
dt_created.to_utc().to_unix()
The snapshot type is written as:
btrfs
rsync
depending on the selected engine.
21.3 Existing File Replacement
If an info.json file already exists, it is deleted before the new file is written.
Unless silent is enabled, the created control-file path is written to the application log.
21.4 Snapshot Factory Behavior
After writing the file, the method creates and returns a fully initialized Snapshot object:
return new Snapshot(
snapshot_path,
is_btrfs,
repo
);
This causes the newly written metadata, exclusion list, fstab, and crypttab to be loaded immediately.
22. Subvolume Detection
22.1 has_subvolumes()
public bool has_subvolumes()
The method scans the loaded fstab entries and checks whether any mount options contain:
subvol=@
It returns true when an Ubuntu-style BTRFS root subvolume is referenced.
This check is based on the stored filesystem table rather than directly inspecting the subvolumes map.
23. Sorted Subvolume List
23.1 subvolumes_sorted
public Gee.ArrayList<Subvolume> subvolumes_sorted
This read-only property copies all values from the subvolume map into a new list.
The list is sorted alphabetically by subvolume name before being returned.
Typical order:
@
@home
24. Snapshot Removal Dispatcher
24.1 remove()
public bool remove(bool wait)
This method is the common deletion entry point.
If the snapshot directory no longer exists, deletion is considered successful.
Otherwise, the method delegates to:
remove_btrfs()for BTRFS snapshotsremove_rsync(wait)for RSYNC snapshots
25. RSYNC Snapshot Removal
25.1 remove_rsync()
public bool remove_rsync(bool wait)
The method configures the snapshot’s DeleteFileTask with:
- The snapshot directory as the destination path
- A localized deletion status message
- The estimated first-snapshot file count for progress calculation
The destination path is passed with a trailing slash:
<snapshot-path>/
The deletion task is then started through:
delete_file_task.execute();
25.2 Synchronous Waiting
When wait is true, the method waits while the task status is RUNNING.
During the wait loop it:
- Sleeps for one second
- Processes pending GTK events
- Prints the deletion percentage
- Prints the estimated remaining time
- Flushes standard output
After completion, the progress line is cleared and a removal message is written to the log.
26. BTRFS Snapshot Removal
26.1 remove_btrfs()
public bool remove_btrfs()
BTRFS deletion is performed in multiple phases.
- Delete every BTRFS subvolume
- Delete the corresponding per-filesystem snapshot directories
- Delete the primary snapshot directory
- Write a success message to the log
26.2 Subvolume Deletion
Each subvolume is removed through:
subvol.remove()
If any subvolume cannot be deleted, the operation stops immediately and returns false.
26.3 Directory Cleanup
Directories are removed only after all subvolume deletions have succeeded.
The method first deletes each path stored in:
paths[subvol.name]
It then removes the primary snapshot path.
Failure during any directory-cleanup step causes the method to return false.
27. Persistent Deletion Marking
27.1 mark_for_deletion()
public void mark_for_deletion()
The method uses the following marker file:
<snapshot>/delete
Its behavior is toggle-based:
- If the marker does not exist, it is created and
marked_for_deletionbecomestrue - If the marker already exists, it is removed and
marked_for_deletionbecomesfalse
The deletion state therefore persists even when the application is closed and reopened.
28. RSYNC Log Parsing
28.1 parse_log_file()
public void parse_log_file()
The method creates a temporary RsyncTask and delegates parsing of:
<snapshot>/rsync-log
The parser is responsible for archiving the primary log and generating:
<snapshot>/rsync-log-changes
This secondary file contains a simplified list of filesystem changes associated with the snapshot.
29. Snapshot Directory Layout
29.1 RSYNC Snapshot
A typical RSYNC snapshot contains:
snapshot/
├── info.json
├── exclude.list
├── localhost/
│ ├── etc/
│ │ ├── fstab
│ │ └── crypttab
│ └── ...
├── rsync-log
├── rsync-log-changes
└── delete
The delete file exists only when the snapshot is marked for removal.
29.2 BTRFS Snapshot
A typical BTRFS snapshot contains metadata and one or more native subvolumes:
snapshot/
├── info.json
├── @/
│ ├── etc/
│ │ ├── fstab
│ │ └── crypttab
│ └── ...
├── @home/
└── delete
When @home resides on another BTRFS filesystem, its physical snapshot path is resolved through the repository’s per-subvolume mount map.
30. Snapshot Loading Flow
The complete object-loading flow is:
- Read the snapshot directory information
- Initialize collections and task objects
- Read
info.json - Load tags, comments, source-system data, and creation date
- Detect the distribution stored inside the snapshot
- Reconstruct BTRFS subvolume objects when present
- Check for the persistent deletion marker
- Load the backup exclusion list
- Parse the snapshot’s
fstab - Parse the snapshot’s
crypttab
31. Runtime and Security Considerations
- Metadata validation: snapshots without a readable control file are marked invalid.
- RSYNC validation: an RSYNC snapshot without
exclude.listis considered invalid. - BTRFS flexibility: BTRFS snapshots do not require an RSYNC exclusion file.
- Persistent deletion state: a marker file retains deletion selection across sessions.
- Engine-specific deletion: RSYNC and BTRFS snapshots use separate deletion implementations.
- Ordered BTRFS cleanup: subvolumes are deleted before their parent directories.
- Repository awareness: BTRFS paths are translated using repository mount information.
- Restore metadata: the stored
fstabandcrypttabsupport target-system reconstruction. - Local-time display: creation timestamps are stored in UTC and converted for presentation.
- Error containment: filesystem and JSON errors are logged rather than propagated to most callers.
32. Implementation Considerations
- Constructor error state: a filesystem exception during construction is logged, but the constructor does not explicitly set
validtofalse. - JSON parser state: after a parser exception, the method still attempts to access the parser’s root node.
- Tag normalization: tags are trimmed but are not converted to a uniform letter case.
- Empty tag handling: assigning an empty
taglistmay add an empty string to the collection after splitting the value. - Snapshot engine authority:
btrfs_modeis supplied to the constructor; thetypefield from JSON is used for distribution-path selection but does not directly replace the constructor value. - Control-file rewrite:
update_control_file()deletes the existing metadata file before writing the replacement, without using a temporary-file rename strategy. - String-encoded values: numeric and Boolean metadata is frequently stored as JSON strings instead of native JSON numbers or Boolean values.
- Initial BTRFS metadata:
write_control_file()does not initially add thesubvolumesobject; it is written by a laterupdate_control_file()call. - RSYNC deletion result:
remove_rsync()returnstruewithout inspecting the final task status or cancellation result. - Deletion method naming:
mark_for_deletion()toggles the marker instead of only marking the snapshot. - Synchronous polling: waiting for RSYNC deletion uses a polling loop with GTK event processing.
- Subvolume detection:
has_subvolumes()inspectsfstaboptions instead of checking the populated subvolume map. - Limited subvolume names: metadata loading accepts only
@and@home. - Path replacement: BTRFS path translation assumes that the repository mount path occurs in the snapshot path.
33. Licensing
The source file is distributed under the GNU General Public License, version 2 or, at the user’s option, any later version.
The original copyright notice identifies:
Copyright 2012-2018 Tony George
<teejeetech@gmail.com>
The software is provided without warranty, including implied warranties of merchantability or fitness for a particular purpose.
