From e3bc808686f2594b48fb195d533cc9367cb804fc Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Mon, 3 Aug 2026 22:23:13 +0200 Subject: [PATCH] common: compare the resolved copy paths within the same namespace Signed-off-by: Nicola Murino --- internal/common/connection.go | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/internal/common/connection.go b/internal/common/connection.go index 116275a6..a3cd486c 100644 --- a/internal/common/connection.go +++ b/internal/common/connection.go @@ -628,23 +628,40 @@ func (c *BaseConnection) checkCopy(srcInfo, dstInfo os.FileInfo, virtualSource, if util.IsDirOverlapped(virtualSource, virtualTarget, true, "/") { return fmt.Errorf("nested copy %q => %q is not supported: %w", virtualSource, virtualTarget, c.GetOpUnsupportedError()) } - if util.IsDirOverlapped(fsSourcePath, fsTargetPath, true, c.User.FsConfig.GetPathSeparator()) { - c.Log(logger.LevelWarn, "nested fs copy %q => %q not allowed", fsSourcePath, fsTargetPath) - return fmt.Errorf("nested fs copy is not supported: %w", c.GetOpUnsupportedError()) - } - return nil - } - if dstInfo != nil && dstInfo.IsDir() { + } else if dstInfo != nil && dstInfo.IsDir() { return fmt.Errorf("cannot overwrite file %q with dir %q: %w", virtualSource, virtualTarget, c.GetOpUnsupportedError()) } - if c.IsSameResource(virtualSource, virtualTarget) { - if fsSourcePath == fsTargetPath { + if c.hasSamePathNamespace(virtualSource, virtualTarget) { + if srcInfo.IsDir() { + srcFsConfig := c.User.GetFsConfigForPath(virtualSource) + if util.IsDirOverlapped(fsSourcePath, fsTargetPath, true, srcFsConfig.GetPathSeparator()) { + c.Log(logger.LevelWarn, "nested fs copy %q => %q not allowed", fsSourcePath, fsTargetPath) + return fmt.Errorf("nested fs copy is not supported: %w", c.GetOpUnsupportedError()) + } + } else if fsSourcePath == fsTargetPath { return fmt.Errorf("the copy source and target cannot be the same: %w", c.GetOpUnsupportedError()) } } return nil } +func (c *BaseConnection) hasSamePathNamespace(virtualSourcePath, virtualTargetPath string) bool { + if hasOSPaths(c.User.GetFsConfigForPath(virtualSourcePath)) && + hasOSPaths(c.User.GetFsConfigForPath(virtualTargetPath)) { + return true + } + return c.IsSameResource(virtualSourcePath, virtualTargetPath) +} + +func hasOSPaths(fsConfig vfs.Filesystem) bool { + switch fsConfig.Provider { + case sdk.LocalFilesystemProvider, sdk.CryptedFilesystemProvider: + return true + default: + return false + } +} + func (c *BaseConnection) copyFile(virtualSourcePath, virtualTargetPath string, srcInfo os.FileInfo) error { if !c.User.HasPerm(dataprovider.PermCopy, virtualSourcePath) || !c.User.HasPerm(dataprovider.PermCopy, virtualTargetPath) { return c.GetPermissionDeniedError()