diff options
author | Björn Gustavsson <[email protected]> | 2019-08-19 15:45:46 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2019-08-22 12:23:45 +0200 |
commit | 72f704c7b83643bec889eabe3f9fe378639bb06e (patch) | |
tree | 6812843aaa76b489604466c687e15c90dc64a43b /lib/stdlib/src | |
parent | d14919b70af5d08970f0e92aded2b375a79f4d94 (diff) | |
download | otp-72f704c7b83643bec889eabe3f9fe378639bb06e.tar.gz otp-72f704c7b83643bec889eabe3f9fe378639bb06e.tar.bz2 otp-72f704c7b83643bec889eabe3f9fe378639bb06e.zip |
Fix filelib:wildcard/1,2 for patterns containing ".." and/or "@"
`..` was broken and only worked when it was used in the beginning
of the pattern before any wildcard characters. For example:
1> filelib:wildcard("erts/..").
["erts/.."]
Using `..` preceded by wildcard characters would not work:
1> filelib:wildcard("*/..").
[]
`@` is not a wildcard character but is used internally in `filelib` as
an escape character and was not handled as other literal
characters. That could lead to performance degradation as it disabled
an optimization of the matching of the literal prefix of a pattern. It
would also cause the following example to fail:
1> filelib:wildcard("@/..").
[]
This commit corrects the handling `..` and also makes sure that the
use of `@` in a pattern does not degrade performance.
https://bugs.erlang.org/browse/ERL-1029
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r-- | lib/stdlib/src/filelib.erl | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl index de839be5cf..d1a5a4dc35 100644 --- a/lib/stdlib/src/filelib.erl +++ b/lib/stdlib/src/filelib.erl @@ -281,6 +281,14 @@ do_wildcard_2([], _, Result, _Mod) -> do_wildcard_3(Base, [[double_star]|Rest], Result, Mod) -> do_double_star(".", [Base], Rest, Result, Mod, true); +do_wildcard_3(Base, [".."|Rest], Result, Mod) -> + case do_is_dir(Base, Mod) of + true -> + Matches = [filename:join(Base, "..")], + do_wildcard_2(Matches, Rest, Result, Mod); + false -> + Result + end; do_wildcard_3(Base0, [Pattern|Rest], Result, Mod) -> case do_list_dir(Base0, Mod) of {ok, Files} -> @@ -387,15 +395,29 @@ compile_wildcard(Pattern0, Cwd0) -> end. compile_wildcard_2([Part|Rest], Root) -> - case compile_part(Part) of - Part -> - compile_wildcard_2(Rest, compile_join(Root, Part)); - Pattern -> - compile_wildcard_3(Rest, [Pattern,Root]) + Pattern = compile_part(Part), + case is_literal_pattern(Pattern) of + true -> + %% Add this literal pattern to the literal pattern prefix. + %% This is an optimization to avoid listing all files of + %% a directory only to discard all but one. For example, + %% without this optimizaton, there would be three + %% redundant directory listings when executing this + %% wildcard: "./lib/compiler/ebin/*.beam" + compile_wildcard_2(Rest, compile_join(Root, Pattern)); + false -> + %% This is the end of the literal prefix. Compile the + %% rest of the pattern. + compile_wildcard_3(Rest, [Pattern,Root]) end; compile_wildcard_2([], {root,PrefixLen,Root}) -> {{exists,Root},PrefixLen}. +is_literal_pattern([H|T]) -> + is_integer(H) andalso is_literal_pattern(T); +is_literal_pattern([]) -> + true. + compile_wildcard_3([Part|Rest], Result) -> compile_wildcard_3(Rest, [compile_part(Part)|Result]); compile_wildcard_3([], Result) -> |