From fd176d62029ff2829b2631868e66b4f8d58f5452 Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Sat, 22 Jun 2024 21:12:07 +0200 Subject: [PATCH] Don't assume terminal components are reversible ComponentWalker.OnTerminal() isn't capable of returning whether a component is reversible. Right now Builder assumes it is, whereas that isn't necessarily safe. When joining "/hello" and "..", we may not necessarily be able to simplify the result to "/". It should remain "/hello/..", as "/hello" may not be a directory. --- pkg/filesystem/path/builder.go | 1 + pkg/filesystem/path/builder_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pkg/filesystem/path/builder.go b/pkg/filesystem/path/builder.go index 08627570..0314e226 100644 --- a/pkg/filesystem/path/builder.go +++ b/pkg/filesystem/path/builder.go @@ -261,6 +261,7 @@ func (cw *buildingComponentWalker) OnTerminal(name Component) (*GotSymlink, erro } if r == nil { cw.b.components = append(cw.b.components, name.String()) + cw.b.firstReversibleIndex = len(cw.b.components) cw.b.suffix = "" return nil, nil } diff --git a/pkg/filesystem/path/builder_test.go b/pkg/filesystem/path/builder_test.go index 3f21fe26..7ba58ca0 100644 --- a/pkg/filesystem/path/builder_test.go +++ b/pkg/filesystem/path/builder_test.go @@ -301,4 +301,28 @@ func TestBuilder(t *testing.T) { require.NoError(t, path.Resolve(path.NewUNIXParser("/hello/world/.."), s)) require.Equal(t, "/hello/", builder.GetUNIXString()) }) + + // OnTerminal() does not allow returning information whether the + // component is reversible. This means that joining and + // appending ".." can't necessarily be simplified. + t.Run("OnTerminalIsNonReversible", func(t *testing.T) { + scopeWalker1 := mock.NewMockScopeWalker(ctrl) + componentWalker1 := mock.NewMockComponentWalker(ctrl) + scopeWalker1.EXPECT().OnAbsolute().Return(componentWalker1, nil) + componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("hello")) + + builder1, s1 := path.EmptyBuilder.Join(scopeWalker1) + require.NoError(t, path.Resolve(path.NewUNIXParser("/hello"), s1)) + require.Equal(t, "/hello", builder1.GetUNIXString()) + + scopeWalker2 := mock.NewMockScopeWalker(ctrl) + componentWalker2 := mock.NewMockComponentWalker(ctrl) + scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) + componentWalker3 := mock.NewMockComponentWalker(ctrl) + componentWalker2.EXPECT().OnUp().Return(componentWalker3, nil) + + builder2, s2 := builder1.Join(scopeWalker2) + require.NoError(t, path.Resolve(path.NewUNIXParser(".."), s2)) + require.Equal(t, "/hello/..", builder2.GetUNIXString()) + }) }