// RemoveBackup removes the given backup. func (a *App) RemoveBackup(timestamp string) error { // Create the backup directory path. path := a.BackupDirectoryPath() + "/" + timestamp // Check if the backup exists. if !btrfs.IsSubvolume(path) { return fmt.Errorf("no backup '%s' found!", timestamp) } log.Infof("Removing backup '%s' of app '%s'.", timestamp, a.name) // Remove the backup subvolume. err := btrfs.DeleteSubvolume(path) if err != nil { return fmt.Errorf("failed to delete backup subvolume '%s': %v", timestamp, err) } return nil }
// loadApp loads the app with the given name from the apps directory. func loadApp(name string) (*App, error) { // Create a new app value. a, err := newApp(name) if err != nil { return nil, err } // The app directory has to be a btrfs subvolume. if !btrfs.IsSubvolume(a.path) { return nil, fmt.Errorf("the app's directory '%s' is not a btrfs subvolume!", a.path) } // Load the app settings. err = a.loadSettings() if err != nil { return nil, err } return a, nil }
// RestoreBackup restores the given app backup. func (a *App) RestoreBackup(timestamp string) (err error) { // Lock the task mutex. // The app should not be started during a backup process. a.taskMutex.Lock() defer a.taskMutex.Unlock() // Abort if any app ask is running. if a.IsTaskRunning() { return fmt.Errorf("the app is running!") } // Create the backup directory path. backupPath := a.BackupDirectoryPath() + "/" + timestamp // Check if the backup exists. if !btrfs.IsSubvolume(backupPath) { return fmt.Errorf("no backup '%s' found!", timestamp) } // Create the apps backup path for the current data. newAppBackupPath := a.BackupDirectoryPath() + "/" + strconv.FormatInt(time.Now().Unix(), 10) // Log log.Infof("restoring backup of app '%s': %s", a.name, timestamp) // Reload the turtlefile and settings on defer. defer func() { err = a.reload() }() // Move the current subvolume to the backup location with the current timestamp. err = os.Rename(a.path, newAppBackupPath) if err != nil { return fmt.Errorf("failed to move apps current subvolume: %v", err) } // Restore the current backup subvolume on failure. defer func() { if err != nil { errR := os.Rename(newAppBackupPath, a.path) if errR != nil { log.Errorf("failed to restore apps current subvolume backup: %v", errR) } else { // Remove the readonly flag again. errR = btrfs.SetSubvolumeReadonly(a.path, false) if errR != nil { log.Errorf("failed to restore apps subvolume flag: %v", errR) } } } }() // Set the readonly flag on the moved subvolume. err = btrfs.SetSubvolumeReadonly(newAppBackupPath, true) if err != nil { return err } // Create a snapshot of the backup and restore it to the app path. err = btrfs.Snapshot(backupPath, a.path, false) if err != nil { return fmt.Errorf("failed to restore app '%s': %v", a.name, err) } return nil }