aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-10-07 23:56:19 +0900
committerOphestra <cat@gensokyo.uk>2025-10-07 23:56:19 +0900
commit1f0226f7e01822a2a5b37d8626b59b7b6f4d0144 (patch)
tree47ca771c20a1073f4c2743c7c1b4189f66ddf336
parent584ce3da685352847e5c6189e5050bd5cb0307e9 (diff)
container/check: relocate overlay escape
This is used in hst to format strings. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--container/check/overlay.go29
-rw-r--r--container/check/overlay_test.go27
-rw-r--r--container/initoverlay.go10
-rw-r--r--container/mount.go25
-rw-r--r--container/mount_test.go20
-rw-r--r--container/path_test.go5
-rw-r--r--hst/fsoverlay.go15
7 files changed, 71 insertions, 60 deletions
diff --git a/container/check/overlay.go b/container/check/overlay.go
new file mode 100644
index 00000000..ab907fbd
--- /dev/null
+++ b/container/check/overlay.go
@@ -0,0 +1,29 @@
+package check
+
+import "strings"
+
+const (
+ // SpecialOverlayEscape is the escape string for overlay mount options.
+ SpecialOverlayEscape = `\`
+ // SpecialOverlayOption is the separator string between overlay mount options.
+ SpecialOverlayOption = ","
+ // SpecialOverlayPath is the separator string between overlay paths.
+ SpecialOverlayPath = ":"
+)
+
+// EscapeOverlayDataSegment escapes a string for formatting into the data argument of an overlay mount call.
+func EscapeOverlayDataSegment(s string) string {
+ if s == "" {
+ return ""
+ }
+
+ if f := strings.SplitN(s, "\x00", 2); len(f) > 0 {
+ s = f[0]
+ }
+
+ return strings.NewReplacer(
+ SpecialOverlayEscape, SpecialOverlayEscape+SpecialOverlayEscape,
+ SpecialOverlayOption, SpecialOverlayEscape+SpecialOverlayOption,
+ SpecialOverlayPath, SpecialOverlayEscape+SpecialOverlayPath,
+ ).Replace(s)
+}
diff --git a/container/check/overlay_test.go b/container/check/overlay_test.go
new file mode 100644
index 00000000..bd90236d
--- /dev/null
+++ b/container/check/overlay_test.go
@@ -0,0 +1,27 @@
+package check_test
+
+import (
+ "testing"
+
+ "hakurei.app/container/check"
+)
+
+func TestEscapeOverlayDataSegment(t *testing.T) {
+ testCases := []struct {
+ name string
+ s string
+ want string
+ }{
+ {"zero", "", ""},
+ {"multi", `\\\:,:,\\\`, `\\\\\\\:\,\:\,\\\\\\`},
+ {"bwrap", `/path :,\`, `/path \:\,\\`},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ if got := check.EscapeOverlayDataSegment(tc.s); got != tc.want {
+ t.Errorf("escapeOverlayDataSegment: %s, want %s", got, tc.want)
+ }
+ })
+ }
+}
diff --git a/container/initoverlay.go b/container/initoverlay.go
index 74ae7d00..5692af4e 100644
--- a/container/initoverlay.go
+++ b/container/initoverlay.go
@@ -139,7 +139,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
if v, err := k.evalSymlinks(o.Upper.String()); err != nil {
return err
} else {
- o.upper = EscapeOverlayDataSegment(toHost(v))
+ o.upper = check.EscapeOverlayDataSegment(toHost(v))
}
}
@@ -147,7 +147,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
return err
} else {
- o.work = EscapeOverlayDataSegment(toHost(v))
+ o.work = check.EscapeOverlayDataSegment(toHost(v))
}
}
}
@@ -157,7 +157,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
if v, err := k.evalSymlinks(a.String()); err != nil {
return err
} else {
- o.lower[i] = EscapeOverlayDataSegment(toHost(v))
+ o.lower[i] = check.EscapeOverlayDataSegment(toHost(v))
}
}
return nil
@@ -199,10 +199,10 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
OptionOverlayWorkdir+"="+o.work)
}
options = append(options,
- OptionOverlayLowerdir+"="+strings.Join(o.lower, SpecialOverlayPath),
+ OptionOverlayLowerdir+"="+strings.Join(o.lower, check.SpecialOverlayPath),
OptionOverlayUserxattr)
- return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, SpecialOverlayOption))
+ return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, check.SpecialOverlayOption))
}
func (o *MountOverlayOp) Is(op Op) bool {
diff --git a/container/mount.go b/container/mount.go
index 2749d0ec..0c459c9c 100644
--- a/container/mount.go
+++ b/container/mount.go
@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"os"
- "strings"
. "syscall"
"hakurei.app/container/vfs"
@@ -85,13 +84,6 @@ const (
// OptionOverlayUserxattr represents the userxattr option of the overlay pseudo-filesystem.
// Use the "user.overlay." xattr namespace instead of "trusted.overlay.".
OptionOverlayUserxattr = "userxattr"
-
- // SpecialOverlayEscape is the escape string for overlay mount options.
- SpecialOverlayEscape = `\`
- // SpecialOverlayOption is the separator string between overlay mount options.
- SpecialOverlayOption = ","
- // SpecialOverlayPath is the separator string between overlay paths.
- SpecialOverlayPath = ":"
)
// bindMount mounts source on target and recursively applies flags if MS_REC is set.
@@ -206,20 +198,3 @@ func parentPerm(perm os.FileMode) os.FileMode {
}
return os.FileMode(pperm)
}
-
-// EscapeOverlayDataSegment escapes a string for formatting into the data argument of an overlay mount call.
-func EscapeOverlayDataSegment(s string) string {
- if s == zeroString {
- return zeroString
- }
-
- if f := strings.SplitN(s, "\x00", 2); len(f) > 0 {
- s = f[0]
- }
-
- return strings.NewReplacer(
- SpecialOverlayEscape, SpecialOverlayEscape+SpecialOverlayEscape,
- SpecialOverlayOption, SpecialOverlayEscape+SpecialOverlayOption,
- SpecialOverlayPath, SpecialOverlayEscape+SpecialOverlayPath,
- ).Replace(s)
-}
diff --git a/container/mount_test.go b/container/mount_test.go
index 5391623c..daa2287a 100644
--- a/container/mount_test.go
+++ b/container/mount_test.go
@@ -281,23 +281,3 @@ func TestParentPerm(t *testing.T) {
})
}
}
-
-func TestEscapeOverlayDataSegment(t *testing.T) {
- testCases := []struct {
- name string
- s string
- want string
- }{
- {"zero", zeroString, zeroString},
- {"multi", `\\\:,:,\\\`, `\\\\\\\:\,\:\,\\\\\\`},
- {"bwrap", `/path :,\`, `/path \:\,\\`},
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- if got := EscapeOverlayDataSegment(tc.s); got != tc.want {
- t.Errorf("escapeOverlayDataSegment: %s, want %s", got, tc.want)
- }
- })
- }
-}
diff --git a/container/path_test.go b/container/path_test.go
index 746e70fe..5af4c821 100644
--- a/container/path_test.go
+++ b/container/path_test.go
@@ -10,6 +10,7 @@ import (
"testing"
"unsafe"
+ "hakurei.app/container/check"
"hakurei.app/container/vfs"
)
@@ -49,8 +50,8 @@ func TestToHost(t *testing.T) {
}
}
-// InternalToHostOvlEscape exports toHost passed to EscapeOverlayDataSegment.
-func InternalToHostOvlEscape(s string) string { return EscapeOverlayDataSegment(toHost(s)) }
+// InternalToHostOvlEscape exports toHost passed to [check.EscapeOverlayDataSegment].
+func InternalToHostOvlEscape(s string) string { return check.EscapeOverlayDataSegment(toHost(s)) }
func TestCreateFile(t *testing.T) {
t.Run("nonexistent", func(t *testing.T) {
diff --git a/hst/fsoverlay.go b/hst/fsoverlay.go
index 2c2a195c..689970df 100644
--- a/hst/fsoverlay.go
+++ b/hst/fsoverlay.go
@@ -4,7 +4,6 @@ import (
"encoding/gob"
"strings"
- "hakurei.app/container"
"hakurei.app/container/check"
)
@@ -82,18 +81,18 @@ func (o *FSOverlay) String() string {
lower := make([]string, len(o.Lower))
for i, a := range o.Lower {
- lower[i] = container.EscapeOverlayDataSegment(a.String())
+ lower[i] = check.EscapeOverlayDataSegment(a.String())
}
if o.Upper != nil && o.Work != nil {
return "w*" + strings.Join(append([]string{
- container.EscapeOverlayDataSegment(o.Target.String()),
- container.EscapeOverlayDataSegment(o.Upper.String()),
- container.EscapeOverlayDataSegment(o.Work.String())},
- lower...), container.SpecialOverlayPath)
+ check.EscapeOverlayDataSegment(o.Target.String()),
+ check.EscapeOverlayDataSegment(o.Upper.String()),
+ check.EscapeOverlayDataSegment(o.Work.String())},
+ lower...), check.SpecialOverlayPath)
} else {
return "*" + strings.Join(append([]string{
- container.EscapeOverlayDataSegment(o.Target.String())},
- lower...), container.SpecialOverlayPath)
+ check.EscapeOverlayDataSegment(o.Target.String())},
+ lower...), check.SpecialOverlayPath)
}
}