From d98f7fd7644c16a454a485d195f8df942dee5e95 Mon Sep 17 00:00:00 2001 From: Guilherme Rugai Freire Date: Fri, 21 Feb 2025 15:55:42 -0300 Subject: [PATCH 1/4] fail moveElement if the dst is inside src --- src/internal/file_operations.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal/file_operations.go b/src/internal/file_operations.go index 8632512a..cd82cdae 100644 --- a/src/internal/file_operations.go +++ b/src/internal/file_operations.go @@ -48,6 +48,9 @@ func getDriveLetter(path string) string { // moveElement moves a file or directory efficiently func moveElement(src, dst string) error { + if strings.HasPrefix(dst, src) { + return fmt.Errorf("failed to move: cannot move folder '%s' inside itself: '%s'", src, dst) + } // Check if source and destination are on the same partition sameDev, err := isSamePartition(src, dst) if err != nil { From 412738a89e7efd8d8df9cf90cb2a3f22997cc909 Mon Sep 17 00:00:00 2001 From: Guilherme Rugai Freire Date: Sat, 22 Feb 2025 11:24:43 -0300 Subject: [PATCH 2/4] fail pasteItem is dst belongs to src in all cases before, this would fail only when cuting and pasting a directory, now the file path is checked before any pasting operation (copy, cut, etc) --- src/internal/file_operations.go | 3 --- src/internal/handle_file_operations.go | 11 ++++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/internal/file_operations.go b/src/internal/file_operations.go index cd82cdae..8632512a 100644 --- a/src/internal/file_operations.go +++ b/src/internal/file_operations.go @@ -48,9 +48,6 @@ func getDriveLetter(path string) string { // moveElement moves a file or directory efficiently func moveElement(src, dst string) error { - if strings.HasPrefix(dst, src) { - return fmt.Errorf("failed to move: cannot move folder '%s' inside itself: '%s'", src, dst) - } // Check if source and destination are on the same partition sameDev, err := isSamePartition(src, dst) if err != nil { diff --git a/src/internal/handle_file_operations.go b/src/internal/handle_file_operations.go index 98f47800..b3fe6af4 100644 --- a/src/internal/handle_file_operations.go +++ b/src/internal/handle_file_operations.go @@ -1,6 +1,7 @@ package internal import ( + "fmt" "log/slog" "os" "os/exec" @@ -470,10 +471,14 @@ func (m *model) pasteItem() { } errMessage := "cut item error" - if m.copyItems.cut && !isExternalDiskPath(filePath) { - err = moveElement(filePath, filepath.Join(panel.location, filepath.Base(filePath))) + + dstPath := filepath.Join(panel.location, filepath.Base(filePath)) + if strings.HasPrefix(dstPath, filePath) { + err = fmt.Errorf("failed to paste: cannot paste item '%s' into itself: %s", filePath, dstPath) + } else if m.copyItems.cut && !isExternalDiskPath(filePath) { + err = moveElement(filePath, dstPath) } else { - err = pasteDir(filePath, filepath.Join(panel.location, filepath.Base(filePath)), id, m) + err = pasteDir(filePath, dstPath, id, m) if err != nil { errMessage = "paste item error" } else { From 61de0d7e7c4d33ca4893d1433cfcfa6729de19bf Mon Sep 17 00:00:00 2001 From: Guilherme Rugai Freire Date: Sat, 22 Feb 2025 12:18:26 -0300 Subject: [PATCH 3/4] use filepath package to determine if a path is inside another --- src/internal/file_operations.go | 24 ++++++++++++++++++++++++ src/internal/handle_file_operations.go | 8 ++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/internal/file_operations.go b/src/internal/file_operations.go index 8632512a..36d27a27 100644 --- a/src/internal/file_operations.go +++ b/src/internal/file_operations.go @@ -46,6 +46,30 @@ func getDriveLetter(path string) string { return strings.ToUpper(string(path[0])) } +// isSubDir check if a path is inside another path to prevent unwanted recursive operations +func isSubDir(src string, dst string) (bool, error) { + absSrc, err := filepath.Abs(src) + if err != nil { + return false, err + } + + absDst, err := filepath.Abs(filepath.Dir(dst)) + if err != nil { + return false, err + } + + rel, err := filepath.Rel(absSrc, absDst) + if err != nil { + return false, err + } + if strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + return false, nil + } + + return true, nil + +} + // moveElement moves a file or directory efficiently func moveElement(src, dst string) error { // Check if source and destination are on the same partition diff --git a/src/internal/handle_file_operations.go b/src/internal/handle_file_operations.go index b3fe6af4..f8fcd22d 100644 --- a/src/internal/handle_file_operations.go +++ b/src/internal/handle_file_operations.go @@ -473,8 +473,12 @@ func (m *model) pasteItem() { errMessage := "cut item error" dstPath := filepath.Join(panel.location, filepath.Base(filePath)) - if strings.HasPrefix(dstPath, filePath) { - err = fmt.Errorf("failed to paste: cannot paste item '%s' into itself: %s", filePath, dstPath) + subDir, err := isSubDir(filePath, dstPath) + + if err != nil { + // cannot compare source and destination paths, so just fail with the given error + } else if subDir { + err = fmt.Errorf("failed to paste: cannot paste item, '%s', into itself, %s", filePath, dstPath) } else if m.copyItems.cut && !isExternalDiskPath(filePath) { err = moveElement(filePath, dstPath) } else { From ac46bdc6127923d5d12e8704111a37e3f7de95d4 Mon Sep 17 00:00:00 2001 From: Guilherme Rugai Freire Date: Sat, 22 Feb 2025 12:30:22 -0300 Subject: [PATCH 4/4] fix: isSubDir should handle files in the same dir --- src/internal/file_operations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/file_operations.go b/src/internal/file_operations.go index 36d27a27..3019d443 100644 --- a/src/internal/file_operations.go +++ b/src/internal/file_operations.go @@ -62,7 +62,7 @@ func isSubDir(src string, dst string) (bool, error) { if err != nil { return false, err } - if strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { return false, nil }