diff --git a/pkg/filesystem/path/component_walker.go b/pkg/filesystem/path/component_walker.go index 2a09ee08..c7b5651c 100644 --- a/pkg/filesystem/path/component_walker.go +++ b/pkg/filesystem/path/component_walker.go @@ -23,7 +23,7 @@ type GotSymlink struct { Parent ScopeWalker // The contents of the symbolic link. - Target string + Target Parser } // GotDirectoryOrSymlink is a union type of GotDirectory and GotSymlink. diff --git a/pkg/filesystem/path/loop_detecting_scope_walker_test.go b/pkg/filesystem/path/loop_detecting_scope_walker_test.go index 9354cd28..bd044b17 100644 --- a/pkg/filesystem/path/loop_detecting_scope_walker_test.go +++ b/pkg/filesystem/path/loop_detecting_scope_walker_test.go @@ -22,7 +22,7 @@ func TestLoopDetectingScopeWalker(t *testing.T) { componentWalker := mock.NewMockComponentWalker(ctrl) scopeWalker.EXPECT().OnRelative().Return(componentWalker, nil).Times(41) componentWalker.EXPECT().OnTerminal(path.MustNewComponent("foo")). - Return(&path.GotSymlink{Parent: scopeWalker, Target: "foo"}, nil). + Return(&path.GotSymlink{Parent: scopeWalker, Target: path.MustNewUNIXParser("foo")}, nil). Times(41) require.Equal( @@ -38,7 +38,7 @@ func TestLoopDetectingScopeWalker(t *testing.T) { scopeWalker1.EXPECT().OnAbsolute().Return(componentWalker1, nil) scopeWalker2 := mock.NewMockScopeWalker(ctrl) componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("tmp")). - Return(&path.GotSymlink{Parent: scopeWalker2, Target: "private/tmp"}, nil) + Return(&path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("private/tmp")}, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) componentWalker3 := mock.NewMockComponentWalker(ctrl) diff --git a/pkg/filesystem/path/resolve.go b/pkg/filesystem/path/resolve.go index 1ce52101..fef50de3 100644 --- a/pkg/filesystem/path/resolve.go +++ b/pkg/filesystem/path/resolve.go @@ -47,16 +47,17 @@ func (rs *resolverState) resolve() error { case GotDirectory: rs.componentWalker = rv.Child case GotSymlink: - target, err := NewUNIXParser(rv.Target) - if err != nil { - return err - } - if err := rs.push(rv.Parent, target); err != nil { + if err := rs.push(rv.Parent, rv.Target); err != nil { return err } default: panic("Missing result") - case nil: // Do nothing + case nil: + // Parsed a terminal component. This should only be permitted at the + // very end of the path resolution process. + if len(rs.stack) > 0 { + panic("Parser.ParseFirstComponent() did not respect mustBeDirectory") + } } } diff --git a/pkg/filesystem/path/resolve_test.go b/pkg/filesystem/path/resolve_test.go index 1ca57522..c028b123 100644 --- a/pkg/filesystem/path/resolve_test.go +++ b/pkg/filesystem/path/resolve_test.go @@ -108,7 +108,7 @@ func TestResolve(t *testing.T) { scopeWalker1.EXPECT().OnRelative().Return(componentWalker1, nil) scopeWalker2 := mock.NewMockScopeWalker(ctrl) componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("a")). - Return(&path.GotSymlink{Parent: scopeWalker2, Target: "b"}, nil) + Return(&path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("b")}, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) componentWalker2.EXPECT().OnTerminal(path.MustNewComponent("b")) @@ -122,7 +122,7 @@ func TestResolve(t *testing.T) { scopeWalker1.EXPECT().OnRelative().Return(componentWalker1, nil) scopeWalker2 := mock.NewMockScopeWalker(ctrl) componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("a")). - Return(&path.GotSymlink{Parent: scopeWalker2, Target: "b/"}, nil) + Return(&path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("b/")}, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) componentWalker3 := mock.NewMockComponentWalker(ctrl) @@ -138,7 +138,7 @@ func TestResolve(t *testing.T) { scopeWalker1.EXPECT().OnRelative().Return(componentWalker1, nil) scopeWalker2 := mock.NewMockScopeWalker(ctrl) componentWalker1.EXPECT().OnDirectory(path.MustNewComponent("a")). - Return(path.GotSymlink{Parent: scopeWalker2, Target: "b"}, nil) + Return(path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("b")}, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) componentWalker3 := mock.NewMockComponentWalker(ctrl) @@ -154,17 +154,17 @@ func TestResolve(t *testing.T) { scopeWalker1.EXPECT().OnRelative().Return(componentWalker1, nil) scopeWalker2 := mock.NewMockScopeWalker(ctrl) componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("a")). - Return(&path.GotSymlink{Parent: scopeWalker2, Target: "b/z"}, nil) + Return(&path.GotSymlink{Parent: scopeWalker2, Target: path.MustNewUNIXParser("b/z")}, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) scopeWalker3 := mock.NewMockScopeWalker(ctrl) componentWalker2.EXPECT().OnDirectory(path.MustNewComponent("b")). - Return(path.GotSymlink{Parent: scopeWalker3, Target: "c/y"}, nil) + Return(path.GotSymlink{Parent: scopeWalker3, Target: path.MustNewUNIXParser("c/y")}, nil) componentWalker3 := mock.NewMockComponentWalker(ctrl) scopeWalker3.EXPECT().OnRelative().Return(componentWalker3, nil) scopeWalker4 := mock.NewMockScopeWalker(ctrl) componentWalker3.EXPECT().OnDirectory(path.MustNewComponent("c")). - Return(path.GotSymlink{Parent: scopeWalker4, Target: "x"}, nil) + Return(path.GotSymlink{Parent: scopeWalker4, Target: path.MustNewUNIXParser("x")}, nil) componentWalker4 := mock.NewMockComponentWalker(ctrl) scopeWalker4.EXPECT().OnRelative().Return(componentWalker4, nil) componentWalker5 := mock.NewMockComponentWalker(ctrl) diff --git a/pkg/filesystem/path/virtual_root_scope_walker_factory.go b/pkg/filesystem/path/virtual_root_scope_walker_factory.go index 250b7944..2077dc2b 100644 --- a/pkg/filesystem/path/virtual_root_scope_walker_factory.go +++ b/pkg/filesystem/path/virtual_root_scope_walker_factory.go @@ -22,7 +22,7 @@ type namelessVirtualRootNode struct { // that point into the root directory. type namedVirtualRootNode struct { nameless namelessVirtualRootNode - target string + target Parser } // virtualRootNodeCreator is an implementation of ComponentWalker that @@ -37,7 +37,7 @@ type virtualRootNodeCreator struct { func (cw *virtualRootNodeCreator) OnDirectory(name Component) (GotDirectoryOrSymlink, error) { n, ok := cw.namelessNode.down[name] if ok { - if n.nameless.isRoot || n.target != "" { + if n.nameless.isRoot || n.target != nil { return nil, status.Error(codes.InvalidArgument, "Path resides at or below an already registered path") } } else { @@ -129,7 +129,7 @@ func NewVirtualRootScopeWalkerFactory(rootPath string, aliases map[string]string path, err := NewUNIXParser(rootPath) if err != nil { - return nil, err + return nil, util.StatusWrapf(err, "Failed to parse root path %#v", rootPath) } if err := Resolve(path, rootPathWalker); err != nil { return nil, util.StatusWrapf(err, "Failed to resolve root path %#v", rootPath) @@ -139,11 +139,11 @@ func NewVirtualRootScopeWalkerFactory(rootPath string, aliases map[string]string for alias, target := range aliases { aliasPath, err := NewUNIXParser(alias) if err != nil { - return nil, err + return nil, util.StatusWrapf(err, "Failed to parse alias path %#v", rootPath) } targetPath, err := NewUNIXParser(target) if err != nil { - return nil, err + return nil, util.StatusWrapf(err, "Failed to parse target path %#v", targetPath) } // Resolve the location at which we want to create a fictive // symlink that points into the virtual root directory. @@ -165,7 +165,11 @@ func NewVirtualRootScopeWalkerFactory(rootPath string, aliases map[string]string if err := Resolve(targetPath, targetPathWalker); err != nil { return nil, util.StatusWrapf(err, "Failed to resolve alias target %#v", target) } - aliasCreator.namedNode.target = targetPathBuilder.String() + parser, err := NewUNIXParser(targetPathBuilder.String()) + if err != nil { + return nil, err + } + aliasCreator.namedNode.target = parser } return wf, nil } @@ -242,7 +246,7 @@ func (cw *pendingVirtualRootComponentWalker) OnDirectory(name Component) (GotDir // the full path. return VoidComponentWalker.OnDirectory(name) } - if n.target != "" { + if n.target != nil { // Found an alias to the underlying root directory. return GotSymlink{ Parent: cw.walker, diff --git a/pkg/filesystem/path/virtual_root_scope_walker_factory_test.go b/pkg/filesystem/path/virtual_root_scope_walker_factory_test.go index 610274f8..d8c5faae 100644 --- a/pkg/filesystem/path/virtual_root_scope_walker_factory_test.go +++ b/pkg/filesystem/path/virtual_root_scope_walker_factory_test.go @@ -120,7 +120,7 @@ func TestVirtualRootScopeWalkerFactoryCreationSuccess(t *testing.T) { componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("a")). Return(&path.GotSymlink{ Parent: scopeWalker2, - Target: "b", + Target: path.MustNewUNIXParser("b"), }, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnRelative().Return(componentWalker2, nil) @@ -139,7 +139,7 @@ func TestVirtualRootScopeWalkerFactoryCreationSuccess(t *testing.T) { componentWalker1.EXPECT().OnTerminal(path.MustNewComponent("a")). Return(&path.GotSymlink{ Parent: scopeWalker2, - Target: "/root/b", + Target: path.MustNewUNIXParser("/root/b"), }, nil) componentWalker2 := mock.NewMockComponentWalker(ctrl) scopeWalker2.EXPECT().OnAbsolute().Return(componentWalker2, nil) @@ -159,7 +159,7 @@ func TestVirtualRootScopeWalkerFactoryCreationSuccess(t *testing.T) { componentWalker.EXPECT().OnTerminal(path.MustNewComponent("a")). Return(&path.GotSymlink{ Parent: scopeWalker2, - Target: "/hello", + Target: path.MustNewUNIXParser("/hello"), }, nil) require.NoError(t, path.Resolve(path.MustNewUNIXParser("a"), factory.New(scopeWalker1)))