github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/cmd/ft_personality/internal/cas/sql.go (about) 1 // Copyright 2020 Google LLC. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package cas contains a Content Addressable Store. 16 package cas 17 18 import ( 19 "database/sql" 20 21 "google.golang.org/grpc/codes" 22 "google.golang.org/grpc/status" 23 ) 24 25 // BinaryStorage is a CAS intended for storing binary images keyed by their hash string 26 // that uses a SQL Database as its backing store. 27 type BinaryStorage struct { 28 db *sql.DB 29 } 30 31 // NewBinaryStorage creates a new CAS that uses the given DB as a backend. 32 // The DB will be initialized if needed. 33 func NewBinaryStorage(db *sql.DB) (*BinaryStorage, error) { 34 cas := &BinaryStorage{ 35 db: db, 36 } 37 return cas, cas.init() 38 } 39 40 // init creates the database tables if needed. 41 func (bs *BinaryStorage) init() error { 42 _, err := bs.db.Exec("CREATE TABLE IF NOT EXISTS images (key BLOB PRIMARY KEY, data BLOB)") 43 return err 44 } 45 46 // Store stores a binary image under the given key (which should be a hash of its data). 47 // If there was an existing value under the key then it will not be updated. 48 // TODO(mhutchinson): Consider validating that the image is exactly the same if the key 49 // already exists. This should only happen if the hash function isn't strong. 50 func (bs *BinaryStorage) Store(key, image []byte) error { 51 _, err := bs.db.Exec("INSERT OR IGNORE INTO images (key, data) VALUES (?, ?)", key, image) 52 return err 53 } 54 55 // Retrieve gets a binary image that was previously stored. 56 func (bs *BinaryStorage) Retrieve(key []byte) ([]byte, error) { 57 var res []byte 58 row := bs.db.QueryRow("SELECT data FROM images WHERE key=?", key) 59 if err := row.Err(); err != nil { 60 return nil, err 61 } 62 63 if err := row.Scan(&res); err != nil { 64 if err == sql.ErrNoRows { 65 return nil, status.Errorf(codes.NotFound, "unknown hash: %q", err) 66 } 67 return nil, err 68 69 } 70 return res, nil 71 }