diff --git a/filesystem/ext4/ext4.go b/filesystem/ext4/ext4.go index 1224560..1831880 100644 --- a/filesystem/ext4/ext4.go +++ b/filesystem/ext4/ext4.go @@ -1272,6 +1272,9 @@ func (fs *FileSystem) OpenFile(p string, flag int) (filesystem.File, error) { } return fs.OpenFile(linkTarget, flag) } + if inode.extents == nil { + return nil, fmt.Errorf("cannot open special file %s (inode %d): no extent tree", p, inodeNumber) + } offset := int64(0) if flag&os.O_APPEND == os.O_APPEND { offset = int64(inode.size) @@ -1306,6 +1309,9 @@ func (fs *FileSystem) openFileViaInode(inodeNumber uint32, flag int) (filesystem if inode.fileType == fileTypeSymbolicLink { return nil, fmt.Errorf("cannot open file via inode: inode %d is a symbolic link", inodeNumber) } + if inode.extents == nil { + return nil, fmt.Errorf("cannot open special file (inode %d): no extent tree", inodeNumber) + } offset := int64(0) if flag&os.O_APPEND == os.O_APPEND { offset = int64(inode.size) diff --git a/filesystem/ext4/ext4_integration_test.go b/filesystem/ext4/ext4_integration_test.go index 045be73..8265627 100644 --- a/filesystem/ext4/ext4_integration_test.go +++ b/filesystem/ext4/ext4_integration_test.go @@ -122,6 +122,8 @@ func compareFileSystems(src, dst fs.FS) error { return compareDir(src, dst, ".") } +// compareDir compares two directories in src and dst filesystems. +// Special files (devices, fifos, sockets) are skipped since CopyFileSystem does not copy them. func compareDir(src, dst fs.FS, dir string) error { srcEntries, err := fs.ReadDir(src, dir) if err != nil { @@ -132,16 +134,21 @@ func compareDir(src, dst fs.FS, dir string) error { return fmt.Errorf("read dir %s (dst): %w", dir, err) } + isSpecialFile := func(e fs.DirEntry) bool { + t := e.Type() + return t&(fs.ModeDevice|fs.ModeNamedPipe|fs.ModeSocket) != 0 + } + srcMap := make(map[string]fs.DirEntry, len(srcEntries)) for _, entry := range srcEntries { - if excludedPaths[entry.Name()] { + if excludedPaths[entry.Name()] || isSpecialFile(entry) { continue } srcMap[entry.Name()] = entry } dstMap := make(map[string]fs.DirEntry, len(dstEntries)) for _, entry := range dstEntries { - if excludedPaths[entry.Name()] { + if excludedPaths[entry.Name()] || isSpecialFile(entry) { continue } dstMap[entry.Name()] = entry diff --git a/filesystem/ext4/specialfile_test.go b/filesystem/ext4/specialfile_test.go new file mode 100644 index 0000000..00c5299 --- /dev/null +++ b/filesystem/ext4/specialfile_test.go @@ -0,0 +1,31 @@ +package ext4 + +import ( + "os" + "strings" + "testing" + + "github.com/diskfs/go-diskfs/backend/file" +) + +func TestOpenFileSpecialFileReturnsError(t *testing.T) { + f, err := os.Open(imgFile) + if err != nil { + t.Fatalf("Error opening test image: %v", err) + } + defer f.Close() + + b := file.New(f, true) + fs, err := Read(b, 100*MB, 0, 512) + if err != nil { + t.Fatalf("Error reading filesystem: %v", err) + } + + _, err = fs.OpenFile("/chardev", os.O_RDONLY) + if err == nil { + t.Fatal("OpenFile on character device should return an error, not succeed") + } + if !strings.Contains(err.Error(), "cannot open special file") { + t.Errorf("expected 'cannot open special file' error, got: %v", err) + } +} diff --git a/filesystem/ext4/testdata/buildimg.sh b/filesystem/ext4/testdata/buildimg.sh index a399b3f..ddb272c 100755 --- a/filesystem/ext4/testdata/buildimg.sh +++ b/filesystem/ext4/testdata/buildimg.sh @@ -31,6 +31,8 @@ ln -s nonexistent deadlink ln -s /some/really/long/path/that/does/not/exist/and/does/not/fit/in/symlink deadlonglink # the target here is >60 chars and so will not fit within the inode # hardlink ln random.dat hardlink.dat +# character device for special file tests +mknod chardev c 1 3 cd /data umount /mnt