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
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
15 changes: 15 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,13 @@ func (c *RunContext) setupPort() error {

return nil
}

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

c.Logger.Info("setup source code disk")
return vhdx.ExtractSourceCode(c.ImageDir)
}
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, "sourcecode.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.
54 changes: 54 additions & 0 deletions pkg/winapi/vhdx/vhdx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
package vhdx

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

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

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

var targetFile *zip.File
for _, f := range reader.File {
// Only extract the file named sourcecode.vhdx
if f.Name == "sourcecode.vhdx" {
targetFile = f
break
}
}

if targetFile == nil {
return fmt.Errorf("sourcecode.vhdx not found in zip")
}

sourceCodeDiskPath := filepath.Join(targetPath, targetFile.Name)

if err := os.MkdirAll(filepath.Dir(sourceCodeDiskPath), 0755); err != nil {
return fmt.Errorf("create directory for vhdx: %w", err)
}

rc, err := targetFile.Open()
if err != nil {
return fmt.Errorf("open zip file entry: %w", err)
}
defer rc.Close()

out, err := os.OpenFile(sourceCodeDiskPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("create target file %s: %w", sourceCodeDiskPath, err)
}
defer out.Close()

_, err = io.Copy(out, rc)
if err != nil {
return fmt.Errorf("copy content to %s: %w", sourceCodeDiskPath, err)
}

return nil
}
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
}
return fmt.Errorf("wsl umount %s failed: %w", path, err)
}
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, "sourcecode.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