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