Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions fs/cpio/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,19 @@ func CreateFS(ctx context.Context, output string, source string, opts ...CpioCre
return fmt.Errorf("could not create CPIO archive from OCI image: %w", err)
}
case fsutils.IsCpioFile(source):
if err := c.CreateFSFromCpio(ctx, writer, source); err != nil {
// If the source is already a CPIO file, we can simply copy its contents to the output.
// This means we close the writer and re-open is as a simple byte writer.
writer.Close()
_, err := f.Seek(0, io.SeekStart)
if err != nil {
return fmt.Errorf("could not seek to start of CPIO archive: %w", err)
}

if err := c.CreateFSFromCpio(ctx, io.Writer(f), source); err != nil {
return fmt.Errorf("could not create CPIO archive from CPIO file: %w", err)
}
case fsutils.IsErofsFile(source):
return fmt.Errorf("creating CPIO from EroFS files is not currently supported")
case fsutils.IsTarFile(source),
fsutils.IsTarGzFile(source):
if err := c.CreateFSFromTar(ctx, writer, source); err != nil {
Expand Down Expand Up @@ -553,7 +563,7 @@ func (c *createOptions) CreateFSFromDirectory(ctx context.Context, writer *cpio.
}

// CreateFSFromCpio creates a CPIO filesystem from an existing CPIO file.
func (c *createOptions) CreateFSFromCpio(ctx context.Context, writer *cpio.Writer, source string) error {
func (c *createOptions) CreateFSFromCpio(ctx context.Context, writer io.Writer, source string) error {
// Open and copy all contents from 'source' to the writer
f, err := os.Open(source)
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions fsutils/fsutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ func IsCpioFile(path string) bool {
return string(magic) == "070701" || string(magic) == "070702"
}

// IsRegularFile checks if the given path is a regular file.
func IsRegularFile(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return false
}

return fi.Mode().IsRegular()
}

type FileInfo struct {
Uid int
Gid int
Expand Down
28 changes: 24 additions & 4 deletions initrd/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,41 @@ package initrd
import (
"context"
"fmt"

"kraftkit.sh/log"
)

// New attempts to return the builder for a supplied path which
// will allow the provided ...
func New(ctx context.Context, path string, opts ...InitrdOption) (Initrd, error) {
if builder, err := NewFromDockerfile(ctx, path, opts...); err == nil {
return builder, nil
} else if builder, err := NewFromTarball(ctx, path, opts...); err == nil {
} else {
log.G(ctx).Tracef("could not build initrd from Dockerfile: %s", err)
}

if builder, err := NewFromTarball(ctx, path, opts...); err == nil {
return builder, nil
} else if builder, err := NewFromFile(ctx, path, opts...); err == nil {
} else {
log.G(ctx).Tracef("could not build initrd from tarball: %s", err)
}

if builder, err := NewFromFile(ctx, path, opts...); err == nil {
return builder, nil
} else if builder, err := NewFromDirectory(ctx, path, opts...); err == nil {
} else {
log.G(ctx).Tracef("could not build initrd from file: %s", err)
}

if builder, err := NewFromDirectory(ctx, path, opts...); err == nil {
return builder, nil
} else if builder, err := NewFromOCIImage(ctx, path, opts...); err == nil {
} else {
log.G(ctx).Tracef("could not build initrd from directory: %s", err)
}

if builder, err := NewFromOCIImage(ctx, path, opts...); err == nil {
return builder, nil
} else {
log.G(ctx).Tracef("could not build initrd from OCI image: %s", err)
}

return nil, fmt.Errorf("could not determine how to build initrd from: %s", path)
Expand Down
4 changes: 4 additions & 0 deletions initrd/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func (initrd *directory) Build(ctx context.Context) (string, error) {
}

switch initrd.opts.fsType {
case FsTypeUnknown:
return "", fmt.Errorf("cannot build initrd from directory with unknown filesystem type")
case FsTypeFile:
return "", fmt.Errorf("cannot build initrd from directory with file output type")
case FsTypeErofs:
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
erofs.WithAllRoot(!initrd.opts.keepOwners),
Expand Down
4 changes: 4 additions & 0 deletions initrd/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,10 @@ func (initrd *dockerfile) Build(ctx context.Context) (string, error) {
}

switch initrd.opts.fsType {
case FsTypeUnknown:
return "", fmt.Errorf("cannot build initrd from dockerfile with unknown filesystem type")
case FsTypeFile:
return "", fmt.Errorf("cannot build initrd from dockerfile with file output type")
case FsTypeErofs:
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, tarOutput.Name(),
erofs.WithAllRoot(!initrd.opts.keepOwners),
Expand Down
27 changes: 27 additions & 0 deletions initrd/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"kraftkit.sh/fs/cpio"
"kraftkit.sh/fs/erofs"
"kraftkit.sh/fsutils"
)

type file struct {
Expand Down Expand Up @@ -70,7 +71,16 @@ func (initrd *file) Build(ctx context.Context) (string, error) {
return "", fmt.Errorf("CPIO archive path is the same as the source path, this is not allowed as it creates corrupted archives")
}

reevaluateFsType:
switch initrd.opts.fsType {
case FsTypeUnknown:
initrd.opts.fsType = detectFsType(initrd.path)
if initrd.opts.fsType == FsTypeUnknown {
return "", fmt.Errorf("could not detect filesystem type of input file, please specify it explicitly via the --fs-type flag")
}
goto reevaluateFsType
case FsTypeFile:
return initrd.opts.output, copyFile(initrd.path, initrd.opts.output)
case FsTypeErofs:
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
erofs.WithAllRoot(!initrd.opts.keepOwners),
Expand All @@ -84,6 +94,23 @@ func (initrd *file) Build(ctx context.Context) (string, error) {
}
}

// detectFsType attempts to convert from the 'unknown' filesystem type to one
// of the known types like 'cpio'/'erofs'/'file'.
func detectFsType(source string) FsType {
switch {
case fsutils.IsErofsFile(source):
return FsTypeErofs
case fsutils.IsCpioFile(source):
return FsTypeCpio
case fsutils.IsTarFile(source),
fsutils.IsTarGzFile(source),
fsutils.IsRegularFile(source):
return FsTypeFile
default:
return FsTypeUnknown
}
}

// Options implements Initrd.
func (initrd *file) Options() InitrdOptions {
return initrd.opts
Expand Down
4 changes: 4 additions & 0 deletions initrd/ociimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ func (initrd *ociimage) Build(ctx context.Context) (string, error) {
}

switch initrd.opts.fsType {
case FsTypeUnknown:
return "", fmt.Errorf("cannot build initrd from oci image with unknown filesystem type")
case FsTypeFile:
return "", fmt.Errorf("cannot build initrd from oci image with file output type")
case FsTypeErofs:
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, ociTarballPath,
erofs.WithAllRoot(!initrd.opts.keepOwners),
Expand Down
14 changes: 12 additions & 2 deletions initrd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,16 @@ func WithOutput(output string) InitrdOption {
// WithOutputType sets the output type of the resulting root filesystem.
func WithOutputType(fsType FsType) InitrdOption {
return func(opts *InitrdOptions) error {
opts.fsType = fsType
return nil
if fsType == "" {
return nil
}
for _, validType := range FsTypes() {
if fsType == validType {
opts.fsType = fsType
return nil
}
}
return fmt.Errorf("invalid output type '%s', valid types are: %v", fsType, FsTypeNames())
}
}

Expand Down Expand Up @@ -207,6 +215,8 @@ func FsTypes() []FsType {
return []FsType{
FsTypeCpio,
FsTypeErofs,
FsTypeFile,
FsTypeUnknown,
}
}

Expand Down
4 changes: 4 additions & 0 deletions initrd/tarball.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ func (initrd *tarball) Build(ctx context.Context) (string, error) {
}

switch initrd.opts.fsType {
case FsTypeUnknown:
return "", fmt.Errorf("cannot build initrd from tarball with unknown filesystem type")
case FsTypeFile:
return initrd.opts.output, copyFile(initrd.path, initrd.opts.output)
case FsTypeErofs:
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
erofs.WithAllRoot(!initrd.opts.keepOwners),
Expand Down
25 changes: 25 additions & 0 deletions initrd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
)

func compressFiles(output string, path string) error {
Expand Down Expand Up @@ -48,3 +49,27 @@ func compressFiles(output string, path string) error {

return nil
}

func copyFile(src, dst string) error {
input, err := os.Open(src)
if err != nil {
return fmt.Errorf("opening source file: %w", err)
}
defer input.Close()

if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
return fmt.Errorf("creating destination directory: %w", err)
}

output, err := os.Create(dst)
if err != nil {
return fmt.Errorf("creating destination file: %w", err)
}
defer output.Close()

if _, err := io.Copy(output, input); err != nil {
return fmt.Errorf("copying file contents: %w", err)
}

return nil
}