github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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 } 39 40 func auxStoreInfoFilename(snapID string) string { 41 return filepath.Join(dirs.SnapAuxStoreInfoDir, snapID) + ".json" 42 } 43 44 // retrieveAuxStoreInfo loads the stored per-snap auxiliary store info into the given *snap.Info 45 func retrieveAuxStoreInfo(info *snap.Info) error { 46 if info.SnapID == "" { 47 return nil 48 } 49 f, err := os.Open(auxStoreInfoFilename(info.SnapID)) 50 if err != nil { 51 if os.IsNotExist(err) { 52 return nil 53 } 54 return err 55 } 56 defer f.Close() 57 58 var aux auxStoreInfo 59 dec := json.NewDecoder(f) 60 if err := dec.Decode(&aux); err != nil { 61 return fmt.Errorf("cannot decode auxiliary store info for snap %q: %v", info.InstanceName(), err) 62 } 63 if dec.More() { 64 return fmt.Errorf("cannot decode auxiliary store info for snap %q: spurious content after document body", info.InstanceName()) 65 } 66 67 info.Media = aux.Media 68 69 return nil 70 } 71 72 // keepAuxStoreInfo saves the given auxiliary store info to disk. 73 func keepAuxStoreInfo(snapID string, aux *auxStoreInfo) error { 74 if snapID == "" { 75 return nil 76 } 77 if err := os.MkdirAll(dirs.SnapAuxStoreInfoDir, 0755); err != nil { 78 return fmt.Errorf("cannot create directory for auxiliary store info: %v", err) 79 } 80 81 af, err := osutil.NewAtomicFile(auxStoreInfoFilename(snapID), 0644, 0, osutil.NoChown, osutil.NoChown) 82 if err != nil { 83 return fmt.Errorf("cannot create file for auxiliary store info for snap %s: %v", snapID, err) 84 } 85 // on success, Cancel becomes a nop 86 defer af.Cancel() 87 88 if err := json.NewEncoder(af).Encode(aux); err != nil { 89 return fmt.Errorf("cannot encode auxiliary store info for snap %s: %v", snapID, err) 90 } 91 92 if err := af.Commit(); err != nil { 93 return fmt.Errorf("cannot commit auxiliary store info file for snap %s: %v", snapID, err) 94 } 95 return nil 96 } 97 98 // discardAuxStoreInfo removes the auxiliary store info for the given snap from disk. 99 func discardAuxStoreInfo(snapID string) error { 100 if snapID == "" { 101 return nil 102 } 103 if err := os.Remove(auxStoreInfoFilename(snapID)); err != nil && !os.IsNotExist(err) { 104 return fmt.Errorf("cannot remove auxiliary store info file for snap %s: %v", snapID, err) 105 } 106 return nil 107 }