github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+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 OpenWriter(l ulog.Logger, path string) (Writer, error) 37 38 // Reader returns a Reader that allows reading files from a file. 39 Reader(file io.ReaderAt) Reader 40 } 41 42 // GetArchiver finds a registered initramfs archiver by name. 43 // 44 // Good to use with command-line arguments. 45 func GetArchiver(name string) (Archiver, error) { 46 archiver, ok := Archivers[name] 47 if !ok { 48 return nil, fmt.Errorf("couldn't find archival format %q", name) 49 } 50 return archiver, nil 51 } 52 53 // Writer is an initramfs archive that files can be written to. 54 type Writer interface { 55 cpio.RecordWriter 56 57 // Finish finishes the archive. 58 Finish() error 59 } 60 61 // Reader is an object that files can be read from. 62 type Reader cpio.RecordReader 63 64 // Opts are options for building an initramfs archive. 65 type Opts struct { 66 // Files are the files to be included. 67 // 68 // Files here generally have priority over files in DefaultRecords or 69 // BaseArchive. 70 *Files 71 72 // OutputFile is the file to write to. 73 OutputFile Writer 74 75 // BaseArchive is an existing archive to add files to. 76 // 77 // BaseArchive may be nil. 78 BaseArchive Reader 79 80 // UseExistingInit determines whether the init from BaseArchive is used 81 // or not, if BaseArchive is specified. 82 // 83 // If this is false, the "init" file in BaseArchive will be renamed 84 // "inito" (for init-original) in the output archive. 85 UseExistingInit bool 86 } 87 88 // Write uses the given options to determine which files to write to the output 89 // initramfs. 90 func Write(opts *Opts) error { 91 // Write base archive. 92 if opts.BaseArchive != nil { 93 transform := cpio.MakeReproducible 94 95 // Rename init to inito if user doesn't want the existing init. 96 if !opts.UseExistingInit && opts.Contains("init") { 97 transform = func(r cpio.Record) cpio.Record { 98 if r.Name == "init" { 99 r.Name = "inito" 100 } 101 return cpio.MakeReproducible(r) 102 } 103 } 104 // If user wants the base archive init, but specified another 105 // init, make the other one inito. 106 if opts.UseExistingInit && opts.Contains("init") { 107 opts.Rename("init", "inito") 108 } 109 110 for { 111 f, err := opts.BaseArchive.ReadRecord() 112 if err == io.EOF { 113 break 114 } 115 if err != nil { 116 return err 117 } 118 // TODO: ignore only the error where it already exists 119 // in archive. 120 opts.Files.AddRecord(transform(f)) 121 } 122 } 123 124 if err := opts.Files.WriteTo(opts.OutputFile); err != nil { 125 return err 126 } 127 return opts.OutputFile.Finish() 128 }