Skip to content

Commit edb4c5c

Browse files
authored
fix: Several fixes and features for rootfs file systems (#2676)
Reviewed-by: Alexander Jung <alex@unikraft.com> Approved-by: Alexander Jung <alex@unikraft.com>
2 parents 5bbbe9b + 888fab5 commit edb4c5c

File tree

10 files changed

+126
-8
lines changed

10 files changed

+126
-8
lines changed

fs/cpio/create.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,19 @@ func CreateFS(ctx context.Context, output string, source string, opts ...CpioCre
7474
return fmt.Errorf("could not create CPIO archive from OCI image: %w", err)
7575
}
7676
case fsutils.IsCpioFile(source):
77-
if err := c.CreateFSFromCpio(ctx, writer, source); err != nil {
77+
// If the source is already a CPIO file, we can simply copy its contents to the output.
78+
// This means we close the writer and re-open is as a simple byte writer.
79+
writer.Close()
80+
_, err := f.Seek(0, io.SeekStart)
81+
if err != nil {
82+
return fmt.Errorf("could not seek to start of CPIO archive: %w", err)
83+
}
84+
85+
if err := c.CreateFSFromCpio(ctx, io.Writer(f), source); err != nil {
7886
return fmt.Errorf("could not create CPIO archive from CPIO file: %w", err)
7987
}
88+
case fsutils.IsErofsFile(source):
89+
return fmt.Errorf("creating CPIO from EroFS files is not currently supported")
8090
case fsutils.IsTarFile(source),
8191
fsutils.IsTarGzFile(source):
8292
if err := c.CreateFSFromTar(ctx, writer, source); err != nil {
@@ -553,7 +563,7 @@ func (c *createOptions) CreateFSFromDirectory(ctx context.Context, writer *cpio.
553563
}
554564

555565
// CreateFSFromCpio creates a CPIO filesystem from an existing CPIO file.
556-
func (c *createOptions) CreateFSFromCpio(ctx context.Context, writer *cpio.Writer, source string) error {
566+
func (c *createOptions) CreateFSFromCpio(ctx context.Context, writer io.Writer, source string) error {
557567
// Open and copy all contents from 'source' to the writer
558568
f, err := os.Open(source)
559569
if err != nil {

fsutils/fsutils.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ func IsCpioFile(path string) bool {
126126
return string(magic) == "070701" || string(magic) == "070702"
127127
}
128128

129+
// IsRegularFile checks if the given path is a regular file.
130+
func IsRegularFile(path string) bool {
131+
fi, err := os.Stat(path)
132+
if err != nil {
133+
return false
134+
}
135+
136+
return fi.Mode().IsRegular()
137+
}
138+
129139
type FileInfo struct {
130140
Uid int
131141
Gid int

initrd/detect.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,41 @@ package initrd
77
import (
88
"context"
99
"fmt"
10+
11+
"kraftkit.sh/log"
1012
)
1113

1214
// New attempts to return the builder for a supplied path which
1315
// will allow the provided ...
1416
func New(ctx context.Context, path string, opts ...InitrdOption) (Initrd, error) {
1517
if builder, err := NewFromDockerfile(ctx, path, opts...); err == nil {
1618
return builder, nil
17-
} else if builder, err := NewFromTarball(ctx, path, opts...); err == nil {
19+
} else {
20+
log.G(ctx).Tracef("could not build initrd from Dockerfile: %s", err)
21+
}
22+
23+
if builder, err := NewFromTarball(ctx, path, opts...); err == nil {
1824
return builder, nil
19-
} else if builder, err := NewFromFile(ctx, path, opts...); err == nil {
25+
} else {
26+
log.G(ctx).Tracef("could not build initrd from tarball: %s", err)
27+
}
28+
29+
if builder, err := NewFromFile(ctx, path, opts...); err == nil {
2030
return builder, nil
21-
} else if builder, err := NewFromDirectory(ctx, path, opts...); err == nil {
31+
} else {
32+
log.G(ctx).Tracef("could not build initrd from file: %s", err)
33+
}
34+
35+
if builder, err := NewFromDirectory(ctx, path, opts...); err == nil {
2236
return builder, nil
23-
} else if builder, err := NewFromOCIImage(ctx, path, opts...); err == nil {
37+
} else {
38+
log.G(ctx).Tracef("could not build initrd from directory: %s", err)
39+
}
40+
41+
if builder, err := NewFromOCIImage(ctx, path, opts...); err == nil {
2442
return builder, nil
43+
} else {
44+
log.G(ctx).Tracef("could not build initrd from OCI image: %s", err)
2545
}
2646

2747
return nil, fmt.Errorf("could not determine how to build initrd from: %s", path)

initrd/directory.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ func (initrd *directory) Build(ctx context.Context) (string, error) {
7979
}
8080

8181
switch initrd.opts.fsType {
82+
case FsTypeUnknown:
83+
return "", fmt.Errorf("cannot build initrd from directory with unknown filesystem type")
84+
case FsTypeFile:
85+
return "", fmt.Errorf("cannot build initrd from directory with file output type")
8286
case FsTypeErofs:
8387
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
8488
erofs.WithAllRoot(!initrd.opts.keepOwners),

initrd/dockerfile.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,10 @@ func (initrd *dockerfile) Build(ctx context.Context) (string, error) {
417417
}
418418

419419
switch initrd.opts.fsType {
420+
case FsTypeUnknown:
421+
return "", fmt.Errorf("cannot build initrd from dockerfile with unknown filesystem type")
422+
case FsTypeFile:
423+
return "", fmt.Errorf("cannot build initrd from dockerfile with file output type")
420424
case FsTypeErofs:
421425
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, tarOutput.Name(),
422426
erofs.WithAllRoot(!initrd.opts.keepOwners),

initrd/file.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"kraftkit.sh/fs/cpio"
1414
"kraftkit.sh/fs/erofs"
15+
"kraftkit.sh/fsutils"
1516
)
1617

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

74+
reevaluateFsType:
7375
switch initrd.opts.fsType {
76+
case FsTypeUnknown:
77+
initrd.opts.fsType = detectFsType(initrd.path)
78+
if initrd.opts.fsType == FsTypeUnknown {
79+
return "", fmt.Errorf("could not detect filesystem type of input file, please specify it explicitly via the --fs-type flag")
80+
}
81+
goto reevaluateFsType
82+
case FsTypeFile:
83+
return initrd.opts.output, copyFile(initrd.path, initrd.opts.output)
7484
case FsTypeErofs:
7585
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
7686
erofs.WithAllRoot(!initrd.opts.keepOwners),
@@ -84,6 +94,23 @@ func (initrd *file) Build(ctx context.Context) (string, error) {
8494
}
8595
}
8696

97+
// detectFsType attempts to convert from the 'unknown' filesystem type to one
98+
// of the known types like 'cpio'/'erofs'/'file'.
99+
func detectFsType(source string) FsType {
100+
switch {
101+
case fsutils.IsErofsFile(source):
102+
return FsTypeErofs
103+
case fsutils.IsCpioFile(source):
104+
return FsTypeCpio
105+
case fsutils.IsTarFile(source),
106+
fsutils.IsTarGzFile(source),
107+
fsutils.IsRegularFile(source):
108+
return FsTypeFile
109+
default:
110+
return FsTypeUnknown
111+
}
112+
}
113+
87114
// Options implements Initrd.
88115
func (initrd *file) Options() InitrdOptions {
89116
return initrd.opts

initrd/ociimage.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ func (initrd *ociimage) Build(ctx context.Context) (string, error) {
196196
}
197197

198198
switch initrd.opts.fsType {
199+
case FsTypeUnknown:
200+
return "", fmt.Errorf("cannot build initrd from oci image with unknown filesystem type")
201+
case FsTypeFile:
202+
return "", fmt.Errorf("cannot build initrd from oci image with file output type")
199203
case FsTypeErofs:
200204
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, ociTarballPath,
201205
erofs.WithAllRoot(!initrd.opts.keepOwners),

initrd/options.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,16 @@ func WithOutput(output string) InitrdOption {
128128
// WithOutputType sets the output type of the resulting root filesystem.
129129
func WithOutputType(fsType FsType) InitrdOption {
130130
return func(opts *InitrdOptions) error {
131-
opts.fsType = fsType
132-
return nil
131+
if fsType == "" {
132+
return nil
133+
}
134+
for _, validType := range FsTypes() {
135+
if fsType == validType {
136+
opts.fsType = fsType
137+
return nil
138+
}
139+
}
140+
return fmt.Errorf("invalid output type '%s', valid types are: %v", fsType, FsTypeNames())
133141
}
134142
}
135143

@@ -207,6 +215,8 @@ func FsTypes() []FsType {
207215
return []FsType{
208216
FsTypeCpio,
209217
FsTypeErofs,
218+
FsTypeFile,
219+
FsTypeUnknown,
210220
}
211221
}
212222

initrd/tarball.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ func (initrd *tarball) Build(ctx context.Context) (string, error) {
7070
}
7171

7272
switch initrd.opts.fsType {
73+
case FsTypeUnknown:
74+
return "", fmt.Errorf("cannot build initrd from tarball with unknown filesystem type")
75+
case FsTypeFile:
76+
return initrd.opts.output, copyFile(initrd.path, initrd.opts.output)
7377
case FsTypeErofs:
7478
return initrd.opts.output, erofs.CreateFS(ctx, initrd.opts.output, initrd.path,
7579
erofs.WithAllRoot(!initrd.opts.keepOwners),

initrd/utils.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"io"
1111
"os"
12+
"path/filepath"
1213
)
1314

1415
func compressFiles(output string, path string) error {
@@ -48,3 +49,27 @@ func compressFiles(output string, path string) error {
4849

4950
return nil
5051
}
52+
53+
func copyFile(src, dst string) error {
54+
input, err := os.Open(src)
55+
if err != nil {
56+
return fmt.Errorf("opening source file: %w", err)
57+
}
58+
defer input.Close()
59+
60+
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
61+
return fmt.Errorf("creating destination directory: %w", err)
62+
}
63+
64+
output, err := os.Create(dst)
65+
if err != nil {
66+
return fmt.Errorf("creating destination file: %w", err)
67+
}
68+
defer output.Close()
69+
70+
if _, err := io.Copy(output, input); err != nil {
71+
return fmt.Errorf("copying file contents: %w", err)
72+
}
73+
74+
return nil
75+
}

0 commit comments

Comments
 (0)