Skip to content

Commit 353db1d

Browse files
authored
feat(vhdx): support mount source code disk into wsl (#114)
* feat(vhdx): support mount source code disk into wsl * fix issue * fix filename wrong * wrap err msg
1 parent 9a2167f commit 353db1d

File tree

6 files changed

+95
-19
lines changed

6 files changed

+95
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ $RECYCLE.BIN/
99
logs
1010

1111
pkg/winapi/vhdx/*_test.go
12+
CLAUDE.md

pkg/cli/run.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/oomol-lab/ovm-win/pkg/types"
1717
"github.com/oomol-lab/ovm-win/pkg/update"
1818
"github.com/oomol-lab/ovm-win/pkg/util"
19+
"github.com/oomol-lab/ovm-win/pkg/winapi/vhdx"
1920
"github.com/oomol-lab/ovm-win/pkg/wsl"
2021
"golang.org/x/sync/errgroup"
2122
)
@@ -57,6 +58,10 @@ func (c *RunContext) Setup() error {
5758
return fmt.Errorf("failed to get port: %w", err)
5859
}
5960

61+
if err := c.setupSourceCodeDisk(); err != nil {
62+
return fmt.Errorf("failed to setup source code disk: %w", err)
63+
}
64+
6065
return nil
6166
}
6267

@@ -154,3 +159,13 @@ func (c *RunContext) setupPort() error {
154159

155160
return nil
156161
}
162+
163+
func (c *RunContext) setupSourceCodeDisk() error {
164+
if _, err := os.Stat(filepath.Join(c.ImageDir, "sourcecode.vhdx")); err == nil {
165+
c.Logger.Info("source code disk already exists")
166+
return nil
167+
}
168+
169+
c.Logger.Info("setup source code disk")
170+
return vhdx.ExtractSourceCode(c.ImageDir)
171+
}

pkg/update/handler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ func (c *Context) updateData() error {
6161
}
6262

6363
dataPath := filepath.Join(c.ImageDir, "data.vhdx")
64+
sourceCodeDiskPath := filepath.Join(c.ImageDir, "sourcecode.vhdx")
6465

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

135 KB
Binary file not shown.

pkg/winapi/vhdx/vhdx.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
package vhdx
55

66
import (
7+
"archive/zip"
8+
"bytes"
9+
_ "embed"
710
"fmt"
11+
"io"
12+
"os"
13+
"path/filepath"
814
"syscall"
915
)
1016
import "github.com/Microsoft/go-winio/vhd"
@@ -36,3 +42,51 @@ func Create(path string, maxSizeInBytes uint64) error {
3642
}
3743
return syscall.CloseHandle(handle)
3844
}
45+
46+
//go:embed sourcecode.vhdx.zip
47+
var sourceCodeZip []byte
48+
49+
func ExtractSourceCode(targetPath string) error {
50+
reader, err := zip.NewReader(bytes.NewReader(sourceCodeZip), int64(len(sourceCodeZip)))
51+
if err != nil {
52+
return fmt.Errorf("open embedded zip: %w", err)
53+
}
54+
55+
var targetFile *zip.File
56+
for _, f := range reader.File {
57+
// Only extract the file named sourcecode.vhdx
58+
if f.Name == "sourcecode.vhdx" {
59+
targetFile = f
60+
break
61+
}
62+
}
63+
64+
if targetFile == nil {
65+
return fmt.Errorf("sourcecode.vhdx not found in zip")
66+
}
67+
68+
sourceCodeDiskPath := filepath.Join(targetPath, targetFile.Name)
69+
70+
if err := os.MkdirAll(filepath.Dir(sourceCodeDiskPath), 0755); err != nil {
71+
return fmt.Errorf("create directory for vhdx: %w", err)
72+
}
73+
74+
rc, err := targetFile.Open()
75+
if err != nil {
76+
return fmt.Errorf("open zip file entry: %w", err)
77+
}
78+
defer rc.Close()
79+
80+
out, err := os.OpenFile(sourceCodeDiskPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
81+
if err != nil {
82+
return fmt.Errorf("create target file %s: %w", sourceCodeDiskPath, err)
83+
}
84+
defer out.Close()
85+
86+
_, err = io.Copy(out, rc)
87+
if err != nil {
88+
return fmt.Errorf("copy content to %s: %w", sourceCodeDiskPath, err)
89+
}
90+
91+
return nil
92+
}

pkg/wsl/distro.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,29 +104,33 @@ func SafeSyncDisk(log *logger.Context, distroName string) error {
104104
return nil
105105
}
106106

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

116118
return nil
117119
}
118120

119-
func UmountVHDX(log *logger.Context, path string) error {
120-
if err := util.Exists(path); err != nil && os.IsNotExist(err) {
121-
return nil
122-
}
121+
func UmountVHDX(log *logger.Context, paths ...string) error {
122+
for _, path := range paths {
123+
if err := util.Exists(path); err != nil && os.IsNotExist(err) {
124+
continue
125+
}
123126

124-
if _, err := wslExec(log, "--unmount", path); err != nil {
125-
if strings.Contains(err.Error(), "ERROR_FILE_NOT_FOUND") {
126-
log.Infof("VHDX already unmounted: %s", path)
127-
return nil
127+
if _, err := wslExec(log, "--unmount", path); err != nil {
128+
if strings.Contains(err.Error(), "ERROR_FILE_NOT_FOUND") {
129+
log.Infof("VHDX already unmounted: %s", path)
130+
continue
131+
}
132+
return fmt.Errorf("wsl umount %s failed: %w", path, err)
128133
}
129-
return fmt.Errorf("wsl umount %s failed: %w", path, err)
130134
}
131135

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

177181
dataPath := filepath.Join(opt.ImageDir, "data.vhdx")
178-
if err := MountVHDX(log, dataPath); err != nil {
179-
return fmt.Errorf("failed to mount data.vhdx: %w", err)
182+
sourceCodeDiskPath := filepath.Join(opt.ImageDir, "sourcecode.vhdx")
183+
if err := MountVHDX(log, dataPath, sourceCodeDiskPath); err != nil {
184+
return fmt.Errorf("failed to mount vhdx disk: %w", err)
180185
}
181186

182187
g, ctx := errgroup.WithContext(ctx)

0 commit comments

Comments
 (0)