Skip to content

Commit 40ea4c3

Browse files
🐛 filsystem IsFile should return true for special unix files not just regular files (#666)
<!-- Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved. SPDX-License-Identifier: Apache-2.0 --> ### Description <!-- Please add any detail or context that would be useful to a reviewer. --> IsFile should return true for special unix files not just regular files ### Test Coverage <!-- Please put an `x` in the correct box e.g. `[x]` to indicate the testing coverage of this change. --> - [x] This change is covered by existing or additional automated tests. - [ ] Manual testing has been performed (and evidence provided) as automated testing was not feasible. - [ ] Additional tests are not required for this change (e.g. documentation update).
1 parent d0cf161 commit 40ea4c3

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

changes/20250801151058.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:bug: `filesystem` IsFile should return true for special unix files not just regular files

utils/filesystem/files.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"errors"
1212
"fmt"
1313
"io"
14+
"io/fs"
1415
"os"
1516
"os/user"
1617
"path/filepath"
@@ -777,7 +778,7 @@ func (fs *VFS) IsFile(path string) (result bool, err error) {
777778
if err != nil {
778779
return
779780
}
780-
result = IsRegularFile(fi)
781+
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)
781782
return
782783
}
783784

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

792+
// IsSpecialFile returns true for files that are not regular files. This includes: unix socket files, device files, and named pipes
793+
func IsSpecialFile(fi os.FileInfo) bool {
794+
if fi == nil {
795+
return false
796+
}
797+
mode := fi.Mode()
798+
isSocket := mode&fs.ModeSocket != 0
799+
isDevice := mode&fs.ModeDevice != 0
800+
isNamedPipe := mode&fs.ModeNamedPipe != 0
801+
return isSocket || isDevice || isNamedPipe
802+
}
803+
791804
func (fs *VFS) IsLink(path string) (result bool, err error) {
792805
err = fs.checkWhetherUnderlyingResourceIsClosed()
793806
if err != nil {

utils/filesystem/files_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"context"
1010
"fmt"
1111
"io"
12+
"net"
1213
"os"
1314
"path/filepath"
1415
"reflect"
@@ -22,6 +23,7 @@ import (
2223
"github.com/spf13/afero"
2324
"github.com/stretchr/testify/assert"
2425
"github.com/stretchr/testify/require"
26+
"golang.org/x/sys/unix"
2527

2628
"github.com/ARM-software/golang-utils/utils/collection"
2729
"github.com/ARM-software/golang-utils/utils/commonerrors"
@@ -546,6 +548,61 @@ func TestConvertPaths(t *testing.T) {
546548
}
547549
}
548550

551+
func TestIsFile(t *testing.T) {
552+
if platform.IsWindows() {
553+
t.Skip("Windows doesn't have features such as named pipes or unix sockets")
554+
}
555+
for _, fsType := range FileSystemTypes {
556+
t.Run(fmt.Sprint(fsType), func(t *testing.T) {
557+
fs := NewFs(fsType)
558+
559+
tmpDir := t.TempDir()
560+
561+
t.Run("normal file", func(t *testing.T) {
562+
filePath := filepath.Join(tmpDir, faker.Word())
563+
err := fs.Touch(filePath)
564+
require.NoError(t, err)
565+
b, err := fs.IsFile(filePath)
566+
require.NoError(t, err)
567+
assert.True(t, b)
568+
})
569+
570+
t.Run("special file", func(t *testing.T) {
571+
if fsType == InMemoryFS {
572+
t.Skip("In-memory file system won't have hardware devices or special files")
573+
}
574+
575+
b, err := fs.IsFile("/dev/null")
576+
require.NoError(t, err)
577+
assert.True(t, b)
578+
579+
fifoPath := filepath.Join(tmpDir, faker.Word())
580+
require.NoError(t, err)
581+
defer func() { _ = fs.Rm(fifoPath) }()
582+
err = unix.Mkfifo(fifoPath, 0666)
583+
require.NoError(t, err)
584+
b, err = fs.IsFile(fifoPath)
585+
require.NoError(t, err)
586+
assert.True(t, b)
587+
err = fs.Rm(fifoPath)
588+
require.NoError(t, err)
589+
590+
socketPath := filepath.Join(tmpDir, faker.Word())
591+
require.NoError(t, err)
592+
defer func() { _ = fs.Rm(socketPath) }()
593+
l, err := net.Listen("unix", socketPath)
594+
require.NoError(t, err)
595+
defer func() { _ = l.Close() }()
596+
b, err = fs.IsFile(socketPath)
597+
require.NoError(t, err)
598+
assert.True(t, b)
599+
err = fs.Rm(socketPath)
600+
require.NoError(t, err)
601+
})
602+
})
603+
}
604+
}
605+
549606
func TestLink(t *testing.T) {
550607
if platform.IsWindows() {
551608
fmt.Println("In order to run TestLink on Windows, Developer mode must be enabled: https://github.com/golang/go/pull/24307")

0 commit comments

Comments
 (0)