github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/blob/gcs.go (about) 1 // Copyright 2025 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package blob 5 6 import ( 7 "context" 8 "fmt" 9 "io" 10 "path" 11 "regexp" 12 13 "github.com/google/syzkaller/pkg/gcs" 14 ) 15 16 type gcsDriver struct { 17 bucket string 18 client gcs.Client 19 } 20 21 func NewGCSClient(ctx context.Context, bucket string) (Storage, error) { 22 client, err := gcs.NewClient(ctx) 23 if err != nil { 24 return nil, err 25 } 26 return &gcsDriver{ 27 bucket: bucket, 28 client: client, 29 }, nil 30 } 31 32 func (gcs *gcsDriver) Write(source io.Reader, parts ...string) (string, error) { 33 if len(parts) == 0 { 34 return "", fmt.Errorf("no identifiers for the object were passed to Write") 35 } 36 object := path.Join(gcs.bucket, path.Join(parts...)) 37 w, err := gcs.client.FileWriter(object, "", "") 38 if err != nil { 39 return "", err 40 } 41 defer w.Close() 42 _, err = io.Copy(w, source) 43 if err != nil { 44 return "", err 45 } 46 return "gcs://" + object, nil 47 } 48 49 func (gcs *gcsDriver) Read(uri string) (io.ReadCloser, error) { 50 bucket, object, err := gcs.parseURI(uri) 51 if err != nil { 52 return nil, err 53 } 54 return gcs.client.FileReader(path.Join(bucket, object)) 55 } 56 57 var gcsObjectRe = regexp.MustCompile(`^gcs://([\w-]+)/(.+)$`) 58 59 func (gcs *gcsDriver) parseURI(uri string) (string, string, error) { 60 match := gcsObjectRe.FindStringSubmatch(uri) 61 if len(match) == 0 { 62 return "", "", fmt.Errorf("invalid GCS URI") 63 } else if match[1] != gcs.bucket { 64 return "", "", fmt.Errorf("unexpected GCS bucket") 65 } 66 return gcs.bucket, match[2], nil 67 }