diff --git a/assets/coverage-badge.svg b/assets/coverage-badge.svg
index 4257307..339faa1 100644
--- a/assets/coverage-badge.svg
+++ b/assets/coverage-badge.svg
@@ -11,7 +11,7 @@
coverage
coverage
- 19.8%
- 19.8%
+ 19.9%
+ 19.9%
diff --git a/internal/shutils/helpers/dirlfs.go b/internal/shutils/helpers/dirlfs.go
new file mode 100644
index 0000000..e93c568
--- /dev/null
+++ b/internal/shutils/helpers/dirlfs.go
@@ -0,0 +1,53 @@
+// ALR - Any Linux Repository
+// Copyright (C) 2025 The ALR Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package helpers
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+)
+
+// dirLfs implements fs.FS like os.DirFS but uses LStat instead of Stat.
+// This means symbolic links are treated as links themselves rather than
+// being followed to their targets.
+type dirLfs struct {
+ fs.FS
+ dir string
+}
+
+func NewDirLFS(dir string) *dirLfs {
+ return &dirLfs{
+ FS: os.DirFS(dir),
+ dir: dir,
+ }
+}
+
+func (d *dirLfs) Stat(name string) (fs.FileInfo, error) {
+ if !fs.ValidPath(name) {
+ return nil, &fs.PathError{Op: "stat", Path: name, Err: fs.ErrInvalid}
+ }
+
+ fullPath := filepath.Join(d.dir, filepath.FromSlash(name))
+
+ info, err := os.Lstat(fullPath)
+ if err != nil {
+ return nil, &fs.PathError{Op: "stat", Path: name, Err: err}
+ }
+
+ return info, nil
+}
diff --git a/internal/shutils/helpers/files_find.go b/internal/shutils/helpers/files_find.go
index 86da65a..25e8b1f 100644
--- a/internal/shutils/helpers/files_find.go
+++ b/internal/shutils/helpers/files_find.go
@@ -160,7 +160,7 @@ func filesFindCmd(hc interp.HandlerContext, cmd string, args []string) error {
searchPath := path.Join(hc.Dir, globPattern)
basepath, pattern := doublestar.SplitPattern(searchPath)
- fsys := os.DirFS(basepath)
+ fsys := NewDirLFS(basepath)
matches, err := doublestar.Glob(fsys, pattern, doublestar.WithNoFollow(), doublestar.WithFailOnPatternNotExist())
if err != nil {
return fmt.Errorf("files-find: glob pattern error: %w", err)
diff --git a/internal/shutils/helpers/helpers_internal_test.go b/internal/shutils/helpers/helpers_internal_test.go
index f45386e..26658c9 100644
--- a/internal/shutils/helpers/helpers_internal_test.go
+++ b/internal/shutils/helpers/helpers_internal_test.go
@@ -236,6 +236,7 @@ func TestFindFiles(t *testing.T) {
"opt/app",
"opt/app/internal",
"opt/app/with space",
+ "usr/bin",
},
filesToCreate: []string{
"usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
@@ -249,6 +250,10 @@ func TestFindFiles(t *testing.T) {
linkPath: "/opt/app/etc",
targetPath: "/etc",
},
+ {
+ linkPath: "/usr/bin/file",
+ targetPath: "/not-existing",
+ },
},
expectedOutput: []string{
"./usr/share/locale/ru/LC_MESSAGES/yandex-disk.mo",
@@ -259,8 +264,9 @@ func TestFindFiles(t *testing.T) {
"./opt/app/internal/test",
"./opt/app/with space",
"./opt/app/with space/file",
+ "./usr/bin/file",
},
- args: "\"/usr/share/locale/*/LC_MESSAGES/*.mo\" \"/opt/app/**/*\"",
+ args: "\"/usr/share/locale/*/LC_MESSAGES/*.mo\" \"/opt/app/**/*\" \"/usr/bin/file\"",
expectedError: nil,
},
{