Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/20250801151058.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:bug: `filesystem` IsFile should return true for special unix files not just regular files
15 changes: 14 additions & 1 deletion utils/filesystem/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"os/user"
"path/filepath"
Expand Down Expand Up @@ -777,7 +778,7 @@ func (fs *VFS) IsFile(path string) (result bool, err error) {
if err != nil {
return
}
result = IsRegularFile(fi)
result = IsRegularFile(fi) || IsSpecialFile(fi) // We want to treat special files as files (otherwise the only distinction is a directory which special files are not)
return
}

Expand All @@ -788,6 +789,18 @@ func IsRegularFile(fi os.FileInfo) bool {
return fi.Mode().IsRegular()
}

// IsSpecialFile returns true for files that are not regular files. This includes: unix socket files, device files, and named pipes
func IsSpecialFile(fi os.FileInfo) bool {
if fi == nil {
return false
}
mode := fi.Mode()
isSocket := mode&fs.ModeSocket != 0
isDevice := mode&fs.ModeDevice != 0
isNamedPipe := mode&fs.ModeNamedPipe != 0
return isSocket || isDevice || isNamedPipe
}

func (fs *VFS) IsLink(path string) (result bool, err error) {
err = fs.checkWhetherUnderlyingResourceIsClosed()
if err != nil {
Expand Down
57 changes: 57 additions & 0 deletions utils/filesystem/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"context"
"fmt"
"io"
"net"
"os"
"path/filepath"
"reflect"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"

"github.com/ARM-software/golang-utils/utils/collection"
"github.com/ARM-software/golang-utils/utils/commonerrors"
Expand Down Expand Up @@ -546,6 +548,61 @@ func TestConvertPaths(t *testing.T) {
}
}

func TestIsFile(t *testing.T) {
if platform.IsWindows() {
t.Skip("Windows doesn't have features such as named pipes or unix sockets")
}
for _, fsType := range FileSystemTypes {
t.Run(fmt.Sprint(fsType), func(t *testing.T) {
fs := NewFs(fsType)

tmpDir := t.TempDir()

t.Run("normal file", func(t *testing.T) {
filePath := filepath.Join(tmpDir, faker.Word())
err := fs.Touch(filePath)
require.NoError(t, err)
b, err := fs.IsFile(filePath)
require.NoError(t, err)
assert.True(t, b)
})

t.Run("special file", func(t *testing.T) {
if fsType == InMemoryFS {
t.Skip("In-memory file system won't have hardware devices or special files")
}

b, err := fs.IsFile("/dev/null")
require.NoError(t, err)
assert.True(t, b)

fifoPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(fifoPath) }()
err = unix.Mkfifo(fifoPath, 0666)
require.NoError(t, err)
b, err = fs.IsFile(fifoPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(fifoPath)
require.NoError(t, err)

socketPath := filepath.Join(tmpDir, faker.Word())
require.NoError(t, err)
defer func() { _ = fs.Rm(socketPath) }()
l, err := net.Listen("unix", socketPath)
require.NoError(t, err)
defer func() { _ = l.Close() }()
b, err = fs.IsFile(socketPath)
require.NoError(t, err)
assert.True(t, b)
err = fs.Rm(socketPath)
require.NoError(t, err)
})
})
}
}

func TestLink(t *testing.T) {
if platform.IsWindows() {
fmt.Println("In order to run TestLink on Windows, Developer mode must be enabled: https://github.com/golang/go/pull/24307")
Expand Down
Loading