199 lines
4.6 KiB
Go
199 lines
4.6 KiB
Go
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/mitchellh/go-fs"
|
|
"github.com/mitchellh/go-fs/fat"
|
|
"github.com/mitchellh/multistep"
|
|
"github.com/mitchellh/packer/packer"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// StepCreateFloppy will create a floppy disk with the given files.
|
|
// The floppy disk doesn't support sub-directories. Only files at the
|
|
// root level are supported.
|
|
type StepCreateFloppy struct {
|
|
Files []string
|
|
|
|
floppyPath string
|
|
|
|
FilesAdded map[string]bool
|
|
}
|
|
|
|
func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
|
|
if len(s.Files) == 0 {
|
|
log.Println("No floppy files specified. Floppy disk will not be made.")
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
s.FilesAdded = make(map[string]bool)
|
|
|
|
ui := state.Get("ui").(packer.Ui)
|
|
ui.Say("Creating floppy disk...")
|
|
|
|
// Create a temporary file to be our floppy drive
|
|
floppyF, err := ioutil.TempFile("", "packer")
|
|
if err != nil {
|
|
state.Put("error",
|
|
fmt.Errorf("Error creating temporary file for floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
defer floppyF.Close()
|
|
|
|
// Set the path so we can remove it later
|
|
s.floppyPath = floppyF.Name()
|
|
|
|
log.Printf("Floppy path: %s", s.floppyPath)
|
|
|
|
// Set the size of the file to be a floppy sized
|
|
if err := floppyF.Truncate(1440 * 1024); err != nil {
|
|
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// BlockDevice backed by the file for our filesystem
|
|
log.Println("Initializing block device backed by temporary file")
|
|
device, err := fs.NewFileDisk(floppyF)
|
|
if err != nil {
|
|
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Format the block device so it contains a valid FAT filesystem
|
|
log.Println("Formatting the block device with a FAT filesystem...")
|
|
formatConfig := &fat.SuperFloppyConfig{
|
|
FATType: fat.FAT12,
|
|
Label: "packer",
|
|
OEMName: "packer",
|
|
}
|
|
if err := fat.FormatSuperFloppy(device, formatConfig); err != nil {
|
|
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// The actual FAT filesystem
|
|
log.Println("Initializing FAT filesystem on block device")
|
|
fatFs, err := fat.New(device)
|
|
if err != nil {
|
|
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Get the root directory to the filesystem
|
|
log.Println("Reading the root directory from the filesystem")
|
|
rootDir, err := fatFs.RootDir()
|
|
if err != nil {
|
|
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Go over each file and copy it.
|
|
for _, filename := range s.Files {
|
|
ui.Message(fmt.Sprintf("Copying: %s", filename))
|
|
if err := s.addFilespec(rootDir, filename); err != nil {
|
|
state.Put("error", fmt.Errorf("Error adding file to floppy: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
}
|
|
|
|
// Set the path to the floppy so it can be used later
|
|
state.Put("floppy_path", s.floppyPath)
|
|
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
func (s *StepCreateFloppy) Cleanup(multistep.StateBag) {
|
|
if s.floppyPath != "" {
|
|
log.Printf("Deleting floppy disk: %s", s.floppyPath)
|
|
os.Remove(s.floppyPath)
|
|
}
|
|
}
|
|
|
|
func (s *StepCreateFloppy) addFilespec(dir fs.Directory, src string) error {
|
|
// same as http://golang.org/src/pkg/path/filepath/match.go#L308
|
|
if strings.IndexAny(src, "*?[") >= 0 {
|
|
matches, err := filepath.Glob(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.addFiles(dir, matches)
|
|
}
|
|
|
|
finfo, err := os.Stat(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if finfo.IsDir() {
|
|
return s.addDirectory(dir, src)
|
|
}
|
|
|
|
return s.addSingleFile(dir, src)
|
|
}
|
|
|
|
func (s *StepCreateFloppy) addFiles(dir fs.Directory, files []string) error {
|
|
for _, file := range files {
|
|
err := s.addFilespec(dir, file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *StepCreateFloppy) addDirectory(dir fs.Directory, src string) error {
|
|
log.Printf("Adding directory to floppy: %s", src)
|
|
|
|
walkFn := func(path string, finfo os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if path == src {
|
|
return nil
|
|
}
|
|
|
|
if finfo.IsDir() {
|
|
return s.addDirectory(dir, path)
|
|
}
|
|
|
|
return s.addSingleFile(dir, path)
|
|
}
|
|
|
|
return filepath.Walk(src, walkFn)
|
|
}
|
|
|
|
func (s *StepCreateFloppy) addSingleFile(dir fs.Directory, src string) error {
|
|
log.Printf("Adding file to floppy: %s", src)
|
|
|
|
inputF, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer inputF.Close()
|
|
|
|
entry, err := dir.AddFile(filepath.Base(src))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fatFile, err := entry.File()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := io.Copy(fatFile, inputF); err != nil {
|
|
return err
|
|
}
|
|
|
|
s.FilesAdded[src] = true
|
|
|
|
return nil
|
|
}
|