github.com/linuxboot/fiano@v1.2.0/pkg/visitors/remove.go (about) 1 // Copyright 2018 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package visitors 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 12 "github.com/linuxboot/fiano/pkg/uefi" 13 ) 14 15 // Remove all firmware files with the given GUID. 16 type Remove struct { 17 // Input 18 Predicate func(f uefi.Firmware) bool 19 Pad bool 20 RemoveDxes bool // I hate this, but there's no good way to work around our current structure 21 22 // Output 23 Matches []uefi.Firmware 24 // Calling this function undoes the removals performed by this visitor. 25 Undo func() 26 // logs are written to this writer. 27 W io.Writer 28 } 29 30 func (v *Remove) printf(format string, a ...interface{}) { 31 if v.W != nil { 32 fmt.Fprintf(v.W, format, a...) 33 } 34 } 35 36 // Run wraps Visit and performs some setup and teardown tasks. 37 func (v *Remove) Run(f uefi.Firmware) error { 38 // First run "find" to generate a list of matches to delete. 39 find := Find{ 40 Predicate: v.Predicate, 41 } 42 if v.RemoveDxes { 43 dxeFV, err := FindDXEFV(f) 44 if err != nil { 45 return err 46 } 47 if err := find.Run(dxeFV); err != nil { 48 return err 49 } 50 // We've found all the files in the blacklist 51 // now, we invert the matches 52 // Note, we can't use the NotPredicate here because that will match the 53 // sections of all files even if they are supposed to be excluded. 54 // This is terrible and my fault. 55 newMatches := []uefi.Firmware{} 56 for _, file := range dxeFV.Files { 57 var keep bool 58 for _, match := range find.Matches { 59 if match == file { 60 keep = true 61 break 62 } 63 } 64 if !keep { 65 newMatches = append(newMatches, file) 66 } 67 } 68 69 // Use this list of matches when removing files. 70 v.Matches = newMatches 71 return dxeFV.Apply(v) 72 } 73 if err := find.Run(f); err != nil { 74 return err 75 } 76 77 // Use this list of matches when removing files. 78 v.Matches = find.Matches 79 return f.Apply(v) 80 } 81 82 // Visit applies the Remove visitor to any Firmware type. 83 func (v *Remove) Visit(f uefi.Firmware) error { 84 switch f := f.(type) { 85 case *uefi.FirmwareVolume: 86 for i := 0; i < len(f.Files); i++ { 87 for _, m := range v.Matches { 88 if f.Files[i] == m { 89 originalList := append([]*uefi.File{}, f.Files...) 90 91 m := m.(*uefi.File) 92 if v.Pad || m.Header.Type == uefi.FVFileTypePEIM { 93 // Create a new pad file of the exact same size 94 pf, err := uefi.CreatePadFile(m.Header.ExtendedSize) 95 if err != nil { 96 return err 97 } 98 f.Files[i] = pf 99 } else { 100 f.Files = append(f.Files[:i], f.Files[i+1:]...) 101 } 102 v.printf("Remove: %d files now\n", len(f.Files)) 103 104 // Creates a stack of undoes in case there are multiple FVs. 105 prev := v.Undo 106 v.Undo = func() { 107 f.Files = originalList 108 v.printf("Undo: %d files now\n", len(f.Files)) 109 v.Undo = prev 110 } 111 } 112 } 113 } 114 } 115 116 return f.ApplyChildren(v) 117 } 118 119 func init() { 120 RegisterCLI("remove", "remove a file from the volume", 1, func(args []string) (uefi.Visitor, error) { 121 pred, err := FindFilePredicate(args[0]) 122 if err != nil { 123 return nil, err 124 } 125 return &Remove{ 126 Predicate: pred, 127 Pad: false, 128 W: os.Stdout, 129 }, nil 130 }) 131 RegisterCLI("remove_pad", "remove a file from the volume and replace it with a pad file of the same size", 1, func(args []string) (uefi.Visitor, error) { 132 pred, err := FindFilePredicate(args[0]) 133 if err != nil { 134 return nil, err 135 } 136 return &Remove{ 137 Predicate: pred, 138 Pad: true, 139 W: os.Stdout, 140 }, nil 141 }) 142 RegisterCLI("remove_dxes_except", "remove all files from the volume except those in the specified file", 1, func(args []string) (uefi.Visitor, error) { 143 fileName := args[0] 144 fileContents, err := os.ReadFile(fileName) 145 if err != nil { 146 return nil, fmt.Errorf("cannot read blacklist file %q: %v", fileName, err) 147 } 148 blackListRegex, err := parseBlackList(fileName, string(fileContents)) 149 if err != nil { 150 return nil, err 151 } 152 blackListPredicate, err := FindFilePredicate(blackListRegex) 153 if err != nil { 154 return nil, err 155 } 156 pred := blackListPredicate 157 158 return &Remove{ 159 Predicate: pred, 160 RemoveDxes: true, 161 }, nil 162 }) 163 }