restoreSnapshot.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package hybridBackup
  2. import (
  3. "errors"
  4. "log"
  5. "os"
  6. "path/filepath"
  7. )
  8. /*
  9. restoreSnapshot.go
  10. Restore snapshot for a certain user in the snapshot
  11. The steps basically as follows.
  12. 1. Check and validate the snapshot
  13. 2. Iterate and restore all files contained in that snapshot to source drive if it is owned by the user
  14. 3. Get the snapshot link file. Restore all files with pointer still exists and owned by the user
  15. */
  16. //Restore a snapshot by task and name
  17. func restoreSnapshotByName(backupTask *BackupTask, snapshotName string, username *string) error {
  18. //Step 1: Check and validate snapshot
  19. snapshotBaseFolder := filepath.Join(backupTask.DiskPath, "/version/", snapshotName)
  20. snapshotRestoreDirectory := filepath.ToSlash(filepath.Clean(backupTask.ParentPath))
  21. if !fileExists(snapshotBaseFolder) {
  22. return errors.New("Given snapshot ID not found")
  23. }
  24. if !fileExists(filepath.Join(snapshotBaseFolder, "snapshot.datalink")) {
  25. return errors.New("Snapshot corrupted. snapshot.datalink pointer file not found.")
  26. }
  27. log.Println("[HybridBackup] Restoring from snapshot ID: ", filepath.Base(snapshotBaseFolder))
  28. //Step 2: Restore all the files changed during that snapshot period
  29. fastWalk(snapshotBaseFolder, func(filename string) error {
  30. //Skip the datalink file
  31. if filepath.Base(filename) == "snapshot.datalink" {
  32. return nil
  33. }
  34. //Calculate the relative path of this file
  35. relPath, err := filepath.Rel(snapshotBaseFolder, filepath.ToSlash(filename))
  36. if err != nil {
  37. //Just skip this cycle
  38. return nil
  39. }
  40. assumedRestoreLocation := filepath.ToSlash(filepath.Join(snapshotRestoreDirectory, relPath))
  41. allowRestore := false
  42. if username == nil {
  43. //Restore all files
  44. allowRestore = true
  45. } else {
  46. //Restore only files owned by this user
  47. isOwnedByThisUser := snapshotFileBelongsToUser("/"+filepath.ToSlash(relPath), *username)
  48. if isOwnedByThisUser {
  49. allowRestore = true
  50. }
  51. }
  52. if allowRestore {
  53. //Check if the restore file parent folder exists.
  54. if !fileExists(filepath.Dir(assumedRestoreLocation)) {
  55. os.MkdirAll(filepath.Dir(assumedRestoreLocation), 0775)
  56. }
  57. //Copy this file from backup to source, overwriting source if exists
  58. err := BufferedLargeFileCopy(filepath.ToSlash(filename), filepath.ToSlash(assumedRestoreLocation), 0775)
  59. if err != nil {
  60. log.Println("[HybridBackup] Restore failed: " + err.Error())
  61. }
  62. }
  63. return nil
  64. })
  65. //Step 3: Restore files from datalinking file
  66. linkMap, err := readLinkFile(snapshotBaseFolder)
  67. if err != nil {
  68. return err
  69. }
  70. for relPath, restorePointer := range linkMap.UnchangedFile {
  71. //Get the assume restore position and source location
  72. sourceFileLocation := filepath.ToSlash(filepath.Join(backupTask.DiskPath, "/version/", "/"+restorePointer+"/", relPath))
  73. assumedRestoreLocation := filepath.ToSlash(filepath.Join(snapshotRestoreDirectory, relPath))
  74. //Check if the restore file parent folder exists.
  75. if snapshotFileBelongsToUser(filepath.ToSlash(relPath), *username) {
  76. if !fileExists(filepath.Dir(assumedRestoreLocation)) {
  77. os.MkdirAll(filepath.Dir(assumedRestoreLocation), 0775)
  78. }
  79. //Copy this file from backup to source, overwriting source if exists
  80. BufferedLargeFileCopy(filepath.ToSlash(sourceFileLocation), filepath.ToSlash(assumedRestoreLocation), 0775)
  81. log.Println("[HybridBackup] Restored " + assumedRestoreLocation + " for user " + *username)
  82. }
  83. }
  84. return nil
  85. }