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, }, {