github.com/google/osv-scalibr@v0.4.1/artifact/image/whiteout/whiteout.go (about) 1 // Copyright 2025 Google LLC 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 whiteout defines and implements whiteout related functions to be used in the layer 16 // scanning methods and functions. 17 package whiteout 18 19 import ( 20 "fmt" 21 "io/fs" 22 "path" 23 "path/filepath" 24 "strings" 25 26 scalibrfs "github.com/google/osv-scalibr/fs" 27 ) 28 29 const ( 30 // WhiteoutPrefix is the prefix found on whiteout files. 31 WhiteoutPrefix = ".wh." 32 // WhiteoutDirPrefix is the prefix found on whiteout directories. This means the directory cannot 33 // hold any more files in the current layer, as well as future layers. 34 WhiteoutDirPrefix = ".wh..wh..opq." 35 ) 36 37 // Files outputs all of the whiteout files found in an FS. 38 func Files(scalibrfs scalibrfs.FS) (map[string]struct{}, error) { 39 whiteouts := make(map[string]struct{}) 40 41 err := fs.WalkDir(scalibrfs, ".", func(path string, d fs.DirEntry, err error) error { 42 if err != nil { 43 // Continue walking if there is an error. 44 //nolint:nilerr 45 return nil 46 } 47 48 base := filepath.Base(path) 49 50 if d.Type().IsRegular() && strings.HasPrefix(base, WhiteoutPrefix) { 51 whiteouts[path] = struct{}{} 52 } 53 54 if d.IsDir() && strings.HasPrefix(base, WhiteoutDirPrefix) { 55 whiteouts[path] = struct{}{} 56 } 57 return nil 58 }) 59 60 if err != nil { 61 return nil, fmt.Errorf("failed to successfully walk fs to find whiteout files: %w", err) 62 } 63 return whiteouts, nil 64 } 65 66 // IsWhiteout returns true if a path is a whiteout path. 67 func IsWhiteout(p string) bool { 68 _, file := path.Split(p) 69 return strings.HasPrefix(file, WhiteoutPrefix) 70 } 71 72 // ToWhiteout returns the whiteout version of a path. 73 func ToWhiteout(p string) string { 74 dir, file := path.Split(p) 75 return path.Join(dir, fmt.Sprintf("%s%s", WhiteoutPrefix, file)) 76 } 77 78 // ToPath returns the non whiteout version of a path. 79 func ToPath(p string) string { 80 dir, file := path.Split(p) 81 82 file = strings.TrimPrefix(file, WhiteoutPrefix) 83 84 nonWhitoutPath := path.Join(dir, file) 85 86 if dir != "" && file == "" { 87 nonWhitoutPath += "/" 88 } 89 90 return nonWhitoutPath 91 }