github.com/kikitux/packer@v0.10.1-0.20160322154024-6237df566f9f/common/step_create_floppy.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mitchellh/go-fs"
     6  	"github.com/mitchellh/go-fs/fat"
     7  	"github.com/mitchellh/multistep"
     8  	"github.com/mitchellh/packer/packer"
     9  	"io"
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  )
    16  
    17  // StepCreateFloppy will create a floppy disk with the given files.
    18  // The floppy disk doesn't support sub-directories. Only files at the
    19  // root level are supported.
    20  type StepCreateFloppy struct {
    21  	Files []string
    22  
    23  	floppyPath string
    24  
    25  	FilesAdded map[string]bool
    26  }
    27  
    28  func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
    29  	if len(s.Files) == 0 {
    30  		log.Println("No floppy files specified. Floppy disk will not be made.")
    31  		return multistep.ActionContinue
    32  	}
    33  
    34  	s.FilesAdded = make(map[string]bool)
    35  
    36  	ui := state.Get("ui").(packer.Ui)
    37  	ui.Say("Creating floppy disk...")
    38  
    39  	// Create a temporary file to be our floppy drive
    40  	floppyF, err := ioutil.TempFile("", "packer")
    41  	if err != nil {
    42  		state.Put("error",
    43  			fmt.Errorf("Error creating temporary file for floppy: %s", err))
    44  		return multistep.ActionHalt
    45  	}
    46  	defer floppyF.Close()
    47  
    48  	// Set the path so we can remove it later
    49  	s.floppyPath = floppyF.Name()
    50  
    51  	log.Printf("Floppy path: %s", s.floppyPath)
    52  
    53  	// Set the size of the file to be a floppy sized
    54  	if err := floppyF.Truncate(1440 * 1024); err != nil {
    55  		state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
    56  		return multistep.ActionHalt
    57  	}
    58  
    59  	// BlockDevice backed by the file for our filesystem
    60  	log.Println("Initializing block device backed by temporary file")
    61  	device, err := fs.NewFileDisk(floppyF)
    62  	if err != nil {
    63  		state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
    64  		return multistep.ActionHalt
    65  	}
    66  
    67  	// Format the block device so it contains a valid FAT filesystem
    68  	log.Println("Formatting the block device with a FAT filesystem...")
    69  	formatConfig := &fat.SuperFloppyConfig{
    70  		FATType: fat.FAT12,
    71  		Label:   "packer",
    72  		OEMName: "packer",
    73  	}
    74  	if err := fat.FormatSuperFloppy(device, formatConfig); err != nil {
    75  		state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
    76  		return multistep.ActionHalt
    77  	}
    78  
    79  	// The actual FAT filesystem
    80  	log.Println("Initializing FAT filesystem on block device")
    81  	fatFs, err := fat.New(device)
    82  	if err != nil {
    83  		state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
    84  		return multistep.ActionHalt
    85  	}
    86  
    87  	// Get the root directory to the filesystem
    88  	log.Println("Reading the root directory from the filesystem")
    89  	rootDir, err := fatFs.RootDir()
    90  	if err != nil {
    91  		state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
    92  		return multistep.ActionHalt
    93  	}
    94  
    95  	// Go over each file and copy it.
    96  	for _, filename := range s.Files {
    97  		ui.Message(fmt.Sprintf("Copying: %s", filename))
    98  		if err := s.addFilespec(rootDir, filename); err != nil {
    99  			state.Put("error", fmt.Errorf("Error adding file to floppy: %s", err))
   100  			return multistep.ActionHalt
   101  		}
   102  	}
   103  
   104  	// Set the path to the floppy so it can be used later
   105  	state.Put("floppy_path", s.floppyPath)
   106  
   107  	return multistep.ActionContinue
   108  }
   109  
   110  func (s *StepCreateFloppy) Cleanup(multistep.StateBag) {
   111  	if s.floppyPath != "" {
   112  		log.Printf("Deleting floppy disk: %s", s.floppyPath)
   113  		os.Remove(s.floppyPath)
   114  	}
   115  }
   116  
   117  func (s *StepCreateFloppy) addFilespec(dir fs.Directory, src string) error {
   118  	// same as http://golang.org/src/pkg/path/filepath/match.go#L308
   119  	if strings.IndexAny(src, "*?[") >= 0 {
   120  		matches, err := filepath.Glob(src)
   121  		if err != nil {
   122  			return err
   123  		}
   124  		return s.addFiles(dir, matches)
   125  	}
   126  
   127  	finfo, err := os.Stat(src)
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	if finfo.IsDir() {
   133  		return s.addDirectory(dir, src)
   134  	}
   135  
   136  	return s.addSingleFile(dir, src)
   137  }
   138  
   139  func (s *StepCreateFloppy) addFiles(dir fs.Directory, files []string) error {
   140  	for _, file := range files {
   141  		err := s.addFilespec(dir, file)
   142  		if err != nil {
   143  			return err
   144  		}
   145  	}
   146  
   147  	return nil
   148  }
   149  
   150  func (s *StepCreateFloppy) addDirectory(dir fs.Directory, src string) error {
   151  	log.Printf("Adding directory to floppy: %s", src)
   152  
   153  	walkFn := func(path string, finfo os.FileInfo, err error) error {
   154  		if err != nil {
   155  			return err
   156  		}
   157  
   158  		if path == src {
   159  			return nil
   160  		}
   161  
   162  		if finfo.IsDir() {
   163  			return s.addDirectory(dir, path)
   164  		}
   165  
   166  		return s.addSingleFile(dir, path)
   167  	}
   168  
   169  	return filepath.Walk(src, walkFn)
   170  }
   171  
   172  func (s *StepCreateFloppy) addSingleFile(dir fs.Directory, src string) error {
   173  	log.Printf("Adding file to floppy: %s", src)
   174  
   175  	inputF, err := os.Open(src)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	defer inputF.Close()
   180  
   181  	entry, err := dir.AddFile(filepath.Base(src))
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	fatFile, err := entry.File()
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	if _, err := io.Copy(fatFile, inputF); err != nil {
   192  		return err
   193  	}
   194  
   195  	s.FilesAdded[src] = true
   196  
   197  	return nil
   198  }