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