github.com/andrewsun2898/u-root@v6.0.1-0.20200616011413-4b2895c1b815+incompatible/pkg/uroot/initramfs/archive.go (about) 1 // Copyright 2015-2017 the u-root 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 initramfs 6 7 import ( 8 "fmt" 9 "io" 10 11 "github.com/u-root/u-root/pkg/cpio" 12 "github.com/u-root/u-root/pkg/ulog" 13 ) 14 15 var ( 16 CPIO = CPIOArchiver{ 17 RecordFormat: cpio.Newc, 18 } 19 20 Dir = DirArchiver{} 21 22 // Archivers are the supported initramfs archivers at the moment. 23 // 24 // - cpio: writes the initramfs to a cpio. 25 // - dir: writes the initramfs relative to a specified directory. 26 Archivers = map[string]Archiver{ 27 "cpio": CPIO, 28 "dir": Dir, 29 } 30 ) 31 32 // Archiver is an archive format that builds an archive using a given set of 33 // files. 34 type Archiver interface { 35 // OpenWriter opens an archive writer at `path`. 36 // 37 // If `path` is unspecified, implementations may choose an arbitrary 38 // default location, potentially based on `goos` and `goarch`. 39 OpenWriter(l ulog.Logger, path, goos, goarch string) (Writer, error) 40 41 // Reader returns a Reader that allows reading files from a file. 42 Reader(file io.ReaderAt) Reader 43 } 44 45 // GetArchiver finds a registered initramfs archiver by name. 46 // 47 // Good to use with command-line arguments. 48 func GetArchiver(name string) (Archiver, error) { 49 archiver, ok := Archivers[name] 50 if !ok { 51 return nil, fmt.Errorf("couldn't find archival format %q", name) 52 } 53 return archiver, nil 54 } 55 56 // Writer is an initramfs archive that files can be written to. 57 type Writer interface { 58 cpio.RecordWriter 59 60 // Finish finishes the archive. 61 Finish() error 62 } 63 64 // Reader is an object that files can be read from. 65 type Reader cpio.RecordReader 66 67 // Opts are options for building an initramfs archive. 68 type Opts struct { 69 // Files are the files to be included. 70 // 71 // Files here generally have priority over files in DefaultRecords or 72 // BaseArchive. 73 *Files 74 75 // OutputFile is the file to write to. 76 OutputFile Writer 77 78 // BaseArchive is an existing archive to add files to. 79 // 80 // BaseArchive may be nil. 81 BaseArchive Reader 82 83 // UseExistingInit determines whether the init from BaseArchive is used 84 // or not, if BaseArchive is specified. 85 // 86 // If this is false, the "init" file in BaseArchive will be renamed 87 // "inito" (for init-original) in the output archive. 88 UseExistingInit bool 89 } 90 91 // Write uses the given options to determine which files to write to the output 92 // initramfs. 93 func Write(opts *Opts) error { 94 // Write base archive. 95 if opts.BaseArchive != nil { 96 transform := cpio.MakeReproducible 97 98 // Rename init to inito if user doesn't want the existing init. 99 if !opts.UseExistingInit && opts.Contains("init") { 100 transform = func(r cpio.Record) cpio.Record { 101 if r.Name == "init" { 102 r.Name = "inito" 103 } 104 return cpio.MakeReproducible(r) 105 } 106 } 107 // If user wants the base archive init, but specified another 108 // init, make the other one inito. 109 if opts.UseExistingInit && opts.Contains("init") { 110 opts.Rename("init", "inito") 111 } 112 113 for { 114 f, err := opts.BaseArchive.ReadRecord() 115 if err == io.EOF { 116 break 117 } 118 if err != nil { 119 return err 120 } 121 // TODO: ignore only the error where it already exists 122 // in archive. 123 opts.Files.AddRecord(transform(f)) 124 } 125 } 126 127 if err := opts.Files.WriteTo(opts.OutputFile); err != nil { 128 return err 129 } 130 return opts.OutputFile.Finish() 131 }