Skip to content

Commit 4d94484

Browse files
committed
fix(remount): create parent directory for files
1 parent b065656 commit 4d94484

File tree

4 files changed

+209
-1
lines changed

4 files changed

+209
-1
lines changed

internal/ebutil/mock_fileinfo.go

+127
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/ebutil/mock_mounter_test.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/ebutil/remount.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,17 @@ outer:
8888
}
8989

9090
func remount(m mounter, src, dest string) error {
91-
if err := m.MkdirAll(dest, 0o750); err != nil {
91+
stat, err := m.Stat(src)
92+
if err != nil {
93+
return fmt.Errorf("stat %s: %w", src, err)
94+
}
95+
var dest_dir string
96+
if stat.IsDir() {
97+
dest_dir = dest
98+
} else {
99+
dest_dir = filepath.Dir(dest)
100+
}
101+
if err := m.MkdirAll(dest_dir, 0o750); err != nil {
92102
return fmt.Errorf("ensure path: %w", err)
93103
}
94104
if err := m.Mount(src, dest, "bind", syscall.MS_BIND, ""); err != nil {
@@ -110,6 +120,8 @@ type mounter interface {
110120
Mount(string, string, string, uintptr, string) error
111121
// Unmount wraps syscall.Unmount
112122
Unmount(string, int) error
123+
// Stat wraps os.Stat
124+
Stat(string) (os.FileInfo, error)
113125
}
114126

115127
// realMounter implements mounter and actually does the thing.
@@ -132,3 +144,7 @@ func (m *realMounter) GetMounts() ([]*procfs.MountInfo, error) {
132144
func (m *realMounter) MkdirAll(path string, perm os.FileMode) error {
133145
return os.MkdirAll(path, perm)
134146
}
147+
148+
func (m *realMounter) Stat(path string) (os.FileInfo, error) {
149+
return os.Stat(path)
150+
}

internal/ebutil/remount_internal_test.go

+50
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strings"
66
"syscall"
77
"testing"
8+
time "time"
89

910
"github.com/coder/envbuilder/internal/notcodersdk"
1011
"github.com/stretchr/testify/assert"
@@ -25,9 +26,11 @@ func Test_tempRemount(t *testing.T) {
2526
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
2627

2728
mm.EXPECT().GetMounts().Return(mounts, nil)
29+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
2830
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
2931
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
3032
mm.EXPECT().Unmount("/var/lib/modules", 0).Times(1).Return(nil)
33+
mm.EXPECT().Stat("/.test/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
3134
mm.EXPECT().MkdirAll("/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
3235
mm.EXPECT().Mount("/.test/var/lib/modules", "/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
3336
mm.EXPECT().Unmount("/.test/var/lib/modules", 0).Times(1).Return(nil)
@@ -40,6 +43,31 @@ func Test_tempRemount(t *testing.T) {
4043
_ = remount()
4144
})
4245

46+
t.Run("OKFile", func(t *testing.T) {
47+
t.Parallel()
48+
49+
ctrl := gomock.NewController(t)
50+
mm := NewMockmounter(ctrl)
51+
mounts := fakeMounts("/home", "/usr/bin/utility:ro", "/proc", "/sys")
52+
53+
mm.EXPECT().GetMounts().Return(mounts, nil)
54+
mm.EXPECT().Stat("/usr/bin/utility").Return(&fakeFileInfo{isDir: false}, nil)
55+
mm.EXPECT().MkdirAll("/.test/usr/bin", os.FileMode(0o750)).Times(1).Return(nil)
56+
mm.EXPECT().Mount("/usr/bin/utility", "/.test/usr/bin/utility", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
57+
mm.EXPECT().Unmount("/usr/bin/utility", 0).Times(1).Return(nil)
58+
mm.EXPECT().Stat("/.test/usr/bin/utility").Return(&fakeFileInfo{isDir: false}, nil)
59+
mm.EXPECT().MkdirAll("/usr/bin", os.FileMode(0o750)).Times(1).Return(nil)
60+
mm.EXPECT().Mount("/.test/usr/bin/utility", "/usr/bin/utility", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
61+
mm.EXPECT().Unmount("/.test/usr/bin/utility", 0).Times(1).Return(nil)
62+
63+
remount, err := tempRemount(mm, fakeLog(t), "/.test")
64+
require.NoError(t, err)
65+
err = remount()
66+
require.NoError(t, err)
67+
// sync.Once should handle multiple remount calls
68+
_ = remount()
69+
})
70+
4371
t.Run("IgnorePrefixes", func(t *testing.T) {
4472
t.Parallel()
4573

@@ -75,6 +103,7 @@ func Test_tempRemount(t *testing.T) {
75103
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
76104

77105
mm.EXPECT().GetMounts().Return(mounts, nil)
106+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
78107
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(assert.AnError)
79108

80109
remount, err := tempRemount(mm, fakeLog(t), "/.test")
@@ -91,6 +120,7 @@ func Test_tempRemount(t *testing.T) {
91120
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
92121

93122
mm.EXPECT().GetMounts().Return(mounts, nil)
123+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
94124
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
95125
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(assert.AnError)
96126

@@ -108,6 +138,7 @@ func Test_tempRemount(t *testing.T) {
108138
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
109139

110140
mm.EXPECT().GetMounts().Return(mounts, nil)
141+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
111142
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
112143
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
113144
mm.EXPECT().Unmount("/var/lib/modules", 0).Times(1).Return(assert.AnError)
@@ -126,9 +157,11 @@ func Test_tempRemount(t *testing.T) {
126157
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
127158

128159
mm.EXPECT().GetMounts().Return(mounts, nil)
160+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
129161
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
130162
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
131163
mm.EXPECT().Unmount("/var/lib/modules", 0).Times(1).Return(nil)
164+
mm.EXPECT().Stat("/.test/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
132165
mm.EXPECT().MkdirAll("/var/lib/modules", os.FileMode(0o750)).Times(1).Return(assert.AnError)
133166

134167
remount, err := tempRemount(mm, fakeLog(t), "/.test")
@@ -145,9 +178,11 @@ func Test_tempRemount(t *testing.T) {
145178
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
146179

147180
mm.EXPECT().GetMounts().Return(mounts, nil)
181+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
148182
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
149183
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
150184
mm.EXPECT().Unmount("/var/lib/modules", 0).Times(1).Return(nil)
185+
mm.EXPECT().Stat("/.test/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
151186
mm.EXPECT().MkdirAll("/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
152187
mm.EXPECT().Mount("/.test/var/lib/modules", "/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(assert.AnError)
153188

@@ -165,9 +200,11 @@ func Test_tempRemount(t *testing.T) {
165200
mounts := fakeMounts("/home", "/var/lib/modules:ro", "/proc", "/sys")
166201

167202
mm.EXPECT().GetMounts().Return(mounts, nil)
203+
mm.EXPECT().Stat("/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
168204
mm.EXPECT().MkdirAll("/.test/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
169205
mm.EXPECT().Mount("/var/lib/modules", "/.test/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
170206
mm.EXPECT().Unmount("/var/lib/modules", 0).Times(1).Return(nil)
207+
mm.EXPECT().Stat("/.test/var/lib/modules").Return(&fakeFileInfo{isDir: true}, nil)
171208
mm.EXPECT().MkdirAll("/var/lib/modules", os.FileMode(0o750)).Times(1).Return(nil)
172209
mm.EXPECT().Mount("/.test/var/lib/modules", "/var/lib/modules", "bind", uintptr(syscall.MS_BIND), "").Times(1).Return(nil)
173210
mm.EXPECT().Unmount("/.test/var/lib/modules", 0).Times(1).Return(assert.AnError)
@@ -200,3 +237,16 @@ func fakeLog(t *testing.T) func(notcodersdk.LogLevel, string, ...any) {
200237
t.Logf(s, a...)
201238
}
202239
}
240+
241+
type fakeFileInfo struct {
242+
isDir bool
243+
}
244+
245+
func (fi *fakeFileInfo) Name() string { return "" }
246+
func (fi *fakeFileInfo) Size() int64 { return 0 }
247+
func (fi *fakeFileInfo) Mode() os.FileMode { return 0 }
248+
func (fi *fakeFileInfo) ModTime() time.Time { return time.Time{} }
249+
func (fi *fakeFileInfo) IsDir() bool { return fi.isDir }
250+
func (fi *fakeFileInfo) Sys() any { return nil }
251+
252+
var _ os.FileInfo = &fakeFileInfo{}

0 commit comments

Comments
 (0)