package main import ( "encoding/json" "net/http" "path/filepath" "imuslab.com/arozos/mod/disk/hybridBackup" prout "imuslab.com/arozos/mod/prouter" ) func backup_init() { //Register HybridBackup storage restore endpoints router := prout.NewModuleRouter(prout.RouterOption{ AdminOnly: false, UserHandler: userHandler, DeniedHandler: func(w http.ResponseWriter, r *http.Request) { sendErrorResponse(w, "Permission Denied") }, }) //Register API endpoints router.HandleFunc("/system/backup/listRestorable", backup_listRestorable) router.HandleFunc("/system/backup/restoreFile", backup_restoreSelected) } //Restore a given file func backup_restoreSelected(w http.ResponseWriter, r *http.Request) { //Get user accessiable storage pools userinfo, err := userHandler.GetUserInfoFromRequest(w, r) if err != nil { sendErrorResponse(w, "User not logged in") return } //Get Backup disk ID from request bdid, err := mv(r, "bdid", true) if err != nil { sendErrorResponse(w, "Invalid backup disk ID given") return } //Get fsh from the id fsh, err := GetFsHandlerByUUID(bdid) if err != nil { sendErrorResponse(w, err.Error()) return } //Get the relative path for the restorable file relpath, err := mv(r, "relpath", true) if err != nil { sendErrorResponse(w, "Invalid relative path given") return } //Handle restore of the file err = userinfo.HomeDirectories.HyperBackupManager.HandleRestore(fsh.UUID, relpath) if err != nil { sendErrorResponse(w, err.Error()) return } type RestoreResult struct { RestoreDiskID string TargetDiskID string RestoredVirtualPath string } result := RestoreResult{ RestoreDiskID: fsh.UUID, } //Get access path for this file parentDiskId, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID) if err != nil { //Unable to get parent disk ID??? } else { //Get the path of the parent disk parentDiskHandler, err := GetFsHandlerByUUID(parentDiskId) if err == nil { //Join the result to create a virtual path assumedRestoreRealPath := filepath.ToSlash(filepath.Join(parentDiskHandler.Path, relpath)) restoreVpath, err := userinfo.RealPathToVirtualPath(assumedRestoreRealPath) if err == nil { result.RestoredVirtualPath = restoreVpath } result.TargetDiskID = parentDiskId } } js, _ := json.Marshal(result) sendJSONResponse(w, string(js)) } //Generate and return a restorable report func backup_listRestorable(w http.ResponseWriter, r *http.Request) { //Get user accessiable storage pools userinfo, err := userHandler.GetUserInfoFromRequest(w, r) if err != nil { sendErrorResponse(w, "User not logged in") return } //Get Vroot ID from request vroot, err := mv(r, "vroot", true) if err != nil { sendErrorResponse(w, "Invalid vroot given") return } //Get fsh from the id fsh, err := GetFsHandlerByUUID(vroot) if err != nil { sendErrorResponse(w, err.Error()) return } userBackupManager := userinfo.HomeDirectories.HyperBackupManager //Get the user's storage pool and list restorable by the user's storage pool access restorableReport, err := userBackupManager.ListRestorable(fsh.UUID) if err != nil { sendErrorResponse(w, err.Error()) return } //Get and check if the parent disk has a user Hierarcy paretnfsh, err := GetFsHandlerByUUID(restorableReport.ParentUID) if err != nil { sendErrorResponse(w, err.Error()) return } result := hybridBackup.RestorableReport{ ParentUID: restorableReport.ParentUID, RestorableFiles: []*hybridBackup.RestorableFile{}, } if paretnfsh.Hierarchy == "user" { //The file system is user based. Filter out those file that is not belong to this user for _, restorableFile := range restorableReport.RestorableFiles { if restorableFile.IsSnapshot { //Is snapshot. Always allow access result.RestorableFiles = append(result.RestorableFiles, restorableFile) } else { //Is file fileAbsPath := filepath.Join(fsh.Path, restorableFile.RelpathOnDisk) _, err := userinfo.RealPathToVirtualPath(fileAbsPath) if err != nil { //Cannot translate this file. That means the file is not owned by this user } else { //Can translate the path. result.RestorableFiles = append(result.RestorableFiles, restorableFile) } } } } else { result = restorableReport } js, _ := json.Marshal(result) sendJSONResponse(w, string(js)) }