Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix glob not following symdir directories #9910

Merged
merged 4 commits into from
Dec 1, 2020
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
18 changes: 17 additions & 1 deletion spec/std/dir_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe "Dir" do
with_tempfile("mkdir") do |path|
Dir.mkdir(path, 0o700)
Dir.exists?(path).should be_true
Dir.rmdir(path)
Dir.delete(path)
Dir.exists?(path).should be_false
end
end
Expand Down Expand Up @@ -309,6 +309,22 @@ describe "Dir" do
end
end

pending_win32 "matches symlink dir" do
with_tempfile "symlink_dir" do |path|
Dir.mkdir_p(Path[path, "glob"])
target = Path[path, "target"]
Dir.mkdir_p(target)

File.write(target / "a.txt", "")
File.symlink(target, Path[path, "glob", "dir"])

Dir.glob("#{path}/glob/*/a.txt").sort.should eq [] of String
Dir.glob("#{path}/glob/*/a.txt", follow_symlinks: true).sort.should eq [
"#{path}/glob/dir/a.txt",
]
end
end

it "empty pattern" do
Dir[""].should eq [] of String
end
Expand Down
6 changes: 3 additions & 3 deletions src/crystal/system/unix/dir.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ module Crystal::System::Dir
name = String.new(entry.value.d_name.to_unsafe)

dir = case entry.value.d_type
when LibC::DT_DIR then true
when LibC::DT_UNKNOWN then nil
else false
when LibC::DT_DIR then true
when LibC::DT_UNKNOWN, LibC::DT_LINK then nil
else false
end
Entry.new(name, dir)
elsif Errno.value != Errno::NONE
Expand Down
44 changes: 22 additions & 22 deletions src/dir/glob.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ class Dir
# The pattern syntax is similar to shell filename globbing, see `File.match?` for details.
#
# NOTE: Path separator in patterns needs to be always `/`. The returned file names use system-specific path separators.
def self.[](*patterns : Path | String) : Array(String)
glob(patterns)
def self.[](*patterns : Path | String, match_hidden = false, follow_symlinks = false) : Array(String)
glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks)
end

# :ditto:
def self.[](patterns : Enumerable) : Array(String)
glob(patterns)
def self.[](patterns : Enumerable, match_hidden = false, follow_symlinks = false) : Array(String)
glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks)
end

# Returns an array of all files that match against any of *patterns*.
Expand All @@ -20,14 +20,14 @@ class Dir
# If *match_hidden* is `true` the pattern will match hidden files and folders.
#
# NOTE: Path separator in patterns needs to be always `/`. The returned file names use system-specific path separators.
def self.glob(*patterns : Path | String, match_hidden = false) : Array(String)
glob(patterns, match_hidden: match_hidden)
def self.glob(*patterns : Path | String, match_hidden = false, follow_symlinks = false) : Array(String)
glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks)
end

# :ditto:
def self.glob(patterns : Enumerable, match_hidden = false) : Array(String)
def self.glob(patterns : Enumerable, match_hidden = false, follow_symlinks = false) : Array(String)
paths = [] of String
glob(patterns, match_hidden: match_hidden) do |path|
glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks) do |path|
paths << path
end
paths
Expand All @@ -40,15 +40,15 @@ class Dir
# If *match_hidden* is `true` the pattern will match hidden files and folders.
#
# NOTE: Path separator in patterns needs to be always `/`. The returned file names use system-specific path separators.
def self.glob(*patterns : Path | String, match_hidden = false, &block : String -> _)
glob(patterns, match_hidden: match_hidden) do |path|
def self.glob(*patterns : Path | String, match_hidden = false, follow_symlinks = false, &block : String -> _)
glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks) do |path|
yield path
end
end

# :ditto:
def self.glob(patterns : Enumerable, match_hidden = false, &block : String -> _)
Globber.glob(patterns, match_hidden: match_hidden) do |path|
def self.glob(patterns : Enumerable, match_hidden = false, follow_symlinks = false, &block : String -> _)
Globber.glob(patterns, match_hidden: match_hidden, follow_symlinks: follow_symlinks) do |path|
yield path
end
end
Expand All @@ -72,15 +72,15 @@ class Dir
end
alias PatternType = DirectoriesOnly | ConstantEntry | EntryMatch | RecursiveDirectories | ConstantDirectory | RootDirectory | DirectoryMatch

def self.glob(patterns : Enumerable, **options, &block : String -> _)
def self.glob(patterns : Enumerable, *, match_hidden, follow_symlinks, &block : String -> _)
patterns.each do |pattern|
if pattern.is_a?(Path)
pattern = pattern.to_posix.to_s
end
sequences = compile(pattern)

sequences.each do |sequence|
run(sequence, options) do |match|
run(sequence, match_hidden: match_hidden, follow_symlinks: follow_symlinks) do |match|
yield match
end
end
Expand Down Expand Up @@ -147,7 +147,7 @@ class Dir
true
end

private def self.run(sequence, options, &block : String -> _)
private def self.run(sequence, match_hidden, follow_symlinks, &block : String -> _)
return if sequence.empty?

path_stack = [] of Tuple(Int32, String?, Crystal::System::Dir::Entry?)
Expand All @@ -173,13 +173,13 @@ class Dir

if dir_entry && !dir_entry.dir?.nil?
yield fullpath
elsif dir?(fullpath)
elsif dir?(fullpath, follow_symlinks)
yield fullpath
end
in EntryMatch
return if sequence[pos + 1]?.is_a?(RecursiveDirectories)
each_child(path) do |entry|
next if !options[:match_hidden] && entry.name.starts_with?('.')
next if !match_hidden && entry.name.starts_with?('.')
yield join(path, entry.name) if cmd.matches?(entry.name)
end
in DirectoryMatch
Expand All @@ -190,7 +190,7 @@ class Dir
is_dir = entry.dir?
fullpath = join(path, entry.name)
if is_dir.nil?
is_dir = dir?(fullpath)
is_dir = dir?(fullpath, follow_symlinks)
end
if is_dir
path_stack << {next_pos, fullpath, entry}
Expand Down Expand Up @@ -237,7 +237,7 @@ class Dir

if entry = read_entry(dir)
next if entry.name.in?(".", "..")
next if !options[:match_hidden] && entry.name.starts_with?('.')
next if !match_hidden && entry.name.starts_with?('.')

if dir_path.bytesize == 0
fullpath = entry.name
Expand All @@ -254,7 +254,7 @@ class Dir

is_dir = entry.dir?
if is_dir.nil?
is_dir = dir?(fullpath)
is_dir = dir?(fullpath, follow_symlinks)
end

if is_dir
Expand Down Expand Up @@ -287,8 +287,8 @@ class Dir
{% end %}
end

private def self.dir?(path)
if info = File.info?(path, follow_symlinks: false)
private def self.dir?(path, follow_symlinks)
if info = File.info?(path, follow_symlinks: follow_symlinks)
info.type.directory?
else
false
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/aarch64-linux-gnu/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/aarch64-linux-musl/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/arm-linux-gnueabihf/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/i386-linux-gnu/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/i386-linux-musl/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-darwin/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-dragonfly/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_fileno : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-freebsd/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
{% if flag?(:freebsd11) %}
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-linux-gnu/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-linux-musl/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_ino : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-netbsd/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ lib LibC
dd_lock : Void*
end

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_fileno : InoT
Expand Down
5 changes: 3 additions & 2 deletions src/lib_c/x86_64-openbsd/c/dirent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ require "./sys/types"
lib LibC
type DIR = Void

DT_UNKNOWN = 0
DT_DIR = 4
DT_UNKNOWN = 0
DT_DIR = 4
DT_LINK = 10

struct Dirent
d_fileno : InoT
Expand Down