github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/snapstate/aux_store_info.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package snapstate 21 22 import ( 23 "encoding/json" 24 "fmt" 25 "os" 26 "path/filepath" 27 28 "github.com/snapcore/snapd/dirs" 29 "github.com/snapcore/snapd/osutil" 30 "github.com/snapcore/snapd/snap" 31 ) 32 33 // auxStoreInfo is information about a snap (*not* a snap revision), not 34 // needed in the state, that may be stored to augment the information 35 // returned for locally-installed snaps 36 type auxStoreInfo struct { 37 Media snap.MediaInfos `json:"media,omitempty"` 38 Website string `json:"website,omitempty"` 39 StoreURL string `json:"store-url,omitempty"` 40 } 41 42 func auxStoreInfoFilename(snapID string) string { 43 return filepath.Join(dirs.SnapAuxStoreInfoDir, snapID) + ".json" 44 } 45 46 // retrieveAuxStoreInfo loads the stored per-snap auxiliary store info into the given *snap.Info 47 func retrieveAuxStoreInfo(info *snap.Info) error { 48 if info.SnapID == "" { 49 return nil 50 } 51 f, err := os.Open(auxStoreInfoFilename(info.SnapID)) 52 if err != nil { 53 if os.IsNotExist(err) { 54 return nil 55 } 56 return err 57 } 58 defer f.Close() 59 60 var aux auxStoreInfo 61 dec := json.NewDecoder(f) 62 if err := dec.Decode(&aux); err != nil { 63 return fmt.Errorf("cannot decode auxiliary store info for snap %q: %v", info.InstanceName(), err) 64 } 65 if dec.More() { 66 return fmt.Errorf("cannot decode auxiliary store info for snap %q: spurious content after document body", info.InstanceName()) 67 } 68 69 info.Media = aux.Media 70 info.Website = aux.Website 71 info.StoreURL = aux.StoreURL 72 73 return nil 74 } 75 76 // keepAuxStoreInfo saves the given auxiliary store info to disk. 77 func keepAuxStoreInfo(snapID string, aux *auxStoreInfo) error { 78 if snapID == "" { 79 return nil 80 } 81 if err := os.MkdirAll(dirs.SnapAuxStoreInfoDir, 0755); err != nil { 82 return fmt.Errorf("cannot create directory for auxiliary store info: %v", err) 83 } 84 85 af, err := osutil.NewAtomicFile(auxStoreInfoFilename(snapID), 0644, 0, osutil.NoChown, osutil.NoChown) 86 if err != nil { 87 return fmt.Errorf("cannot create file for auxiliary store info for snap %s: %v", snapID, err) 88 } 89 // on success, Cancel becomes a nop 90 defer af.Cancel() 91 92 if err := json.NewEncoder(af).Encode(aux); err != nil { 93 return fmt.Errorf("cannot encode auxiliary store info for snap %s: %v", snapID, err) 94 } 95 96 if err := af.Commit(); err != nil { 97 return fmt.Errorf("cannot commit auxiliary store info file for snap %s: %v", snapID, err) 98 } 99 return nil 100 } 101 102 // discardAuxStoreInfo removes the auxiliary store info for the given snap from disk. 103 func discardAuxStoreInfo(snapID string) error { 104 if snapID == "" { 105 return nil 106 } 107 if err := os.Remove(auxStoreInfoFilename(snapID)); err != nil && !os.IsNotExist(err) { 108 return fmt.Errorf("cannot remove auxiliary store info file for snap %s: %v", snapID, err) 109 } 110 return nil 111 }