Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ $RECYCLE.BIN/
logs

pkg/winapi/vhdx/*_test.go
CLAUDE.md
18 changes: 18 additions & 0 deletions pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/oomol-lab/ovm-win/pkg/types"
"github.com/oomol-lab/ovm-win/pkg/update"
"github.com/oomol-lab/ovm-win/pkg/util"
"github.com/oomol-lab/ovm-win/pkg/winapi/vhdx"
"github.com/oomol-lab/ovm-win/pkg/wsl"
"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -57,6 +58,10 @@ func (c *RunContext) Setup() error {
return fmt.Errorf("failed to get port: %w", err)
}

if err := c.SetupSourceCodeDisk(); err != nil {
return fmt.Errorf("failed to setup source code disk: %w", err)
}

return nil
}

Expand Down Expand Up @@ -154,3 +159,16 @@ func (c *RunContext) setupPort() error {

return nil
}

func (c *RunContext) SetupSourceCodeDisk() error {
p := filepath.Join(c.ImageDir, "source_code.vhdx")
// if source_code.vhdx already exists, skip
_, err := os.Stat(p)
if err == nil {
c.Logger.Info("source code disk already exists")
return nil
}

c.Logger.Info("setup source code disk")
return vhdx.ExtractSourceCode(p)
}
5 changes: 3 additions & 2 deletions pkg/update/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ func (c *Context) updateData() error {
}

dataPath := filepath.Join(c.ImageDir, "data.vhdx")
sourceCodeDiskPath := filepath.Join(c.ImageDir, "source_code.vhdx")

log.Infof("Umounting data: %s", dataPath)
if err := wsl.UmountVHDX(log, dataPath); err != nil {
log.Infof("Umounting data: %s, source code disk: %s", dataPath, sourceCodeDiskPath)
if err := wsl.UmountVHDX(log, dataPath, sourceCodeDiskPath); err != nil {
return fmt.Errorf("failed to unmount data: %w", err)
}

Expand Down
Binary file added pkg/winapi/vhdx/sourcecode.vhdx.zip
Binary file not shown.
56 changes: 56 additions & 0 deletions pkg/winapi/vhdx/vhdx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
package vhdx

import (
"archive/zip"
"bytes"
_ "embed"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"syscall"
)
import "github.com/Microsoft/go-winio/vhd"
Expand Down Expand Up @@ -36,3 +43,52 @@ func Create(path string, maxSizeInBytes uint64) error {
}
return syscall.CloseHandle(handle)
}

//go:embed sourcecode.vhdx.zip
var sourceCodeZip []byte

func ExtractSourceCode(path string) error {
reader, err := zip.NewReader(bytes.NewReader(sourceCodeZip), int64(len(sourceCodeZip)))
if err != nil {
return fmt.Errorf("open embedded zip: %w", err)
}

for _, f := range reader.File {
if err := extractFile(f, path); err != nil {
return fmt.Errorf("extract %s: %w", f.Name, err)
}
}
return nil
}

func extractFile(f *zip.File, destDir string) error {
fpath := filepath.Join(destDir, f.Name)

rel, err := filepath.Rel(destDir, fpath)
if err != nil || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || rel == ".." {
return fmt.Errorf("illegal file path: %s", f.Name)
}

if f.FileInfo().IsDir() {
return os.MkdirAll(fpath, f.Mode())
}

if err := os.MkdirAll(filepath.Dir(fpath), 0755); err != nil {
return err
}

rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()

out, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer out.Close()

_, err = io.Copy(out, rc)
return err
}
39 changes: 22 additions & 17 deletions pkg/wsl/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,29 +104,33 @@ func SafeSyncDisk(log *logger.Context, distroName string) error {
return nil
}

func MountVHDX(log *logger.Context, path string) error {
if _, err := wslExec(log, "--mount", "--bare", "--vhd", path); err != nil {
if strings.Contains(err.Error(), "WSL_E_USER_VHD_ALREADY_ATTACHED") {
log.Infof("VHDX already mounted: %s", path)
return nil
func MountVHDX(log *logger.Context, paths ...string) error {
for _, path := range paths {
if _, err := wslExec(log, "--mount", "--bare", "--vhd", path); err != nil {
if strings.Contains(err.Error(), "WSL_E_USER_VHD_ALREADY_ATTACHED") {
log.Infof("VHDX already mounted: %s", path)
continue
}
return fmt.Errorf("wsl mount %s failed: %w", path, err)
}
return fmt.Errorf("wsl mount %s failed: %w", path, err)
}

return nil
}

func UmountVHDX(log *logger.Context, path string) error {
if err := util.Exists(path); err != nil && os.IsNotExist(err) {
return nil
}
func UmountVHDX(log *logger.Context, paths ...string) error {
for _, path := range paths {
if err := util.Exists(path); err != nil && os.IsNotExist(err) {
continue
}

if _, err := wslExec(log, "--unmount", path); err != nil {
if strings.Contains(err.Error(), "ERROR_FILE_NOT_FOUND") {
log.Infof("VHDX already unmounted: %s", path)
return nil
if _, err := wslExec(log, "--unmount", path); err != nil {
if strings.Contains(err.Error(), "ERROR_FILE_NOT_FOUND") {
log.Infof("VHDX already unmounted: %s", path)
continue
}
log.Warnf("Failed to unmount VHDX: %s", path)
}
return fmt.Errorf("wsl umount %s failed: %w", path, err)
}

return nil
Expand Down Expand Up @@ -175,8 +179,9 @@ func Launch(ctx context.Context, log *logger.Context, opt *types.RunOpt) error {
event.NotifyRun(event.Starting)

dataPath := filepath.Join(opt.ImageDir, "data.vhdx")
if err := MountVHDX(log, dataPath); err != nil {
return fmt.Errorf("failed to mount data.vhdx: %w", err)
sourceCodeDiskPath := filepath.Join(opt.ImageDir, "source_code.vhdx")
if err := MountVHDX(log, dataPath, sourceCodeDiskPath); err != nil {
return fmt.Errorf("failed to mount vhdx disk: %w", err)
}

g, ctx := errgroup.WithContext(ctx)
Expand Down
Loading