From bd2c337e5bd1a3532f42776f55f80f4e273cfeac Mon Sep 17 00:00:00 2001 From: Ducksan Cho Date: Wed, 18 Nov 2015 02:16:03 +1300 Subject: [PATCH 1/4] Avoid using Dir.glob with absolute path the absolute path including '[', '{', '?', or '*' could change the outcome --- lib/jekyll/cleaner.rb | 11 ++++++++--- lib/jekyll/collection.rb | 7 +++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb index d23da78f..a8bbf24e 100644 --- a/lib/jekyll/cleaner.rb +++ b/lib/jekyll/cleaner.rb @@ -36,13 +36,18 @@ module Jekyll # # Returns a Set with the file paths def existing_files + return Set.new unless Dir.exist?(site.in_dest_dir) + files = Set.new regex = keep_file_regex dirs = keep_dirs - Dir.glob(site.in_dest_dir("**", "*"), File::FNM_DOTMATCH) do |file| - next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file) - files << file + Dir.chdir(site.in_dest_dir) do + Dir.glob("**/*", File::FNM_DOTMATCH).each do |f| + file = File.join(site.in_dest_dir, f) + next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file) + files << file + end end files diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index 4363aee1..4d4b9bd0 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -74,8 +74,11 @@ module Jekyll def entries return Array.new unless exists? @entries ||= - Dir.glob(collection_dir("**", "*.*")).map do |entry| - entry["#{collection_dir}/"] = ''; entry + Dir.chdir(collection_dir) do + Dir.glob("**/*.*").map do |f| + entry = collection_dir(f) + entry["#{collection_dir}/"] = ''; entry + end end end From a168edae45cf6878dfe7408cc396252b8899c17a Mon Sep 17 00:00:00 2001 From: Ducksan Cho Date: Thu, 19 Nov 2015 00:46:46 +1300 Subject: [PATCH 2/4] Add Utils.safe_glob method which works the same way as Dir.glob but seperating the input into two parts ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act as a pattern. --- lib/jekyll/utils.rb | 29 +++++++++++++++++++++++++++ test/safe_glob_test[/find_me.txt | 0 test/test_utils.rb | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 test/safe_glob_test[/find_me.txt diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb index c30a986a..ab516767 100644 --- a/lib/jekyll/utils.rb +++ b/lib/jekyll/utils.rb @@ -207,5 +207,34 @@ module Jekyll template end + + # Work the same way as Dir.glob but seperating the input into two parts + # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act + # as a pattern. + # + # For example, Dir.glob("path[/*") always returns an empty array, + # because the method fails to find the closing pattern to '[' which is ']' + # + # Examples: + # safe_glob("path[", "*") + # # => ["path[/file1", "path[/file2"] + # + # safe_glob("path", "*", File::FNM_DOTMATCH) + # # => ["path/.", "path/..", "path/file1"] + # + # dir - the dir where glob will be executed under + # (the dir will be included to each result) + # pattern - the pattern which will be applied under the dir + # flags - the flags which will be applied to the pattern + # + # Returns matched pathes + def safe_glob(dir, pattern, flags = 0) + return [] unless Dir.exist?(dir) + return [dir] if pattern.nil? || pattern.empty? + Dir.chdir(dir) do + Dir.glob(pattern, flags).map { |f| File.join(dir, f) } + end + end + end end diff --git a/test/safe_glob_test[/find_me.txt b/test/safe_glob_test[/find_me.txt new file mode 100644 index 00000000..e69de29b diff --git a/test/test_utils.rb b/test/test_utils.rb index 9d4a5a4d..02ebb09a 100644 --- a/test/test_utils.rb +++ b/test/test_utils.rb @@ -180,4 +180,38 @@ class TestUtils < JekyllUnitTest assert_equal "/:basename", Utils.add_permalink_suffix("/:basename", "/:title") end end + + context "The \`Utils.safe_glob\` method" do + should "not apply pattern to the dir" do + dir = "test/safe_glob_test[" + assert_equal [], Dir.glob(dir + "/*") + assert_equal ["test/safe_glob_test[/find_me.txt"], Utils.safe_glob(dir, "*") + end + + should "return the same data to #glob" do + dir = "test" + assert_equal Dir.glob(dir + "/*"), Utils.safe_glob(dir, "*") + assert_equal Dir.glob(dir + "/**/*"), Utils.safe_glob(dir, "**/*") + end + + should "return the same data to #glob if dir is not found" do + dir = "dir_not_exist" + assert_equal [], Utils.safe_glob(dir, "*") + assert_equal Dir.glob(dir + "/*"), Utils.safe_glob(dir, "*") + end + + should "return the same data to #glob if pattern is blank" do + dir = "test" + assert_equal [dir], Utils.safe_glob(dir, "") + assert_equal Dir.glob(dir), Utils.safe_glob(dir, "") + assert_equal Dir.glob(dir), Utils.safe_glob(dir, nil) + end + + should "return the same data to #glob if flag is given" do + dir = "test" + assert_equal Dir.glob(dir + "/*", File::FNM_DOTMATCH), + Utils.safe_glob(dir, "*", File::FNM_DOTMATCH) + end + end + end From 20735e12f9ea1ffd49294bb8e5bf3ec724853dc6 Mon Sep 17 00:00:00 2001 From: Ducksan Cho Date: Thu, 19 Nov 2015 01:02:48 +1300 Subject: [PATCH 3/4] Use safe_glob to unsafe glob --- lib/jekyll/cleaner.rb | 11 +++-------- lib/jekyll/collection.rb | 7 ++----- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb index a8bbf24e..9146e7de 100644 --- a/lib/jekyll/cleaner.rb +++ b/lib/jekyll/cleaner.rb @@ -36,18 +36,13 @@ module Jekyll # # Returns a Set with the file paths def existing_files - return Set.new unless Dir.exist?(site.in_dest_dir) - files = Set.new regex = keep_file_regex dirs = keep_dirs - Dir.chdir(site.in_dest_dir) do - Dir.glob("**/*", File::FNM_DOTMATCH).each do |f| - file = File.join(site.in_dest_dir, f) - next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file) - files << file - end + Utils.safe_glob(site.in_dest_dir, "**/*", File::FNM_DOTMATCH).each do |file| + next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file) + files << file end files diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index 4d4b9bd0..e4725718 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -74,11 +74,8 @@ module Jekyll def entries return Array.new unless exists? @entries ||= - Dir.chdir(collection_dir) do - Dir.glob("**/*.*").map do |f| - entry = collection_dir(f) - entry["#{collection_dir}/"] = ''; entry - end + Utils.safe_glob(collection_dir, "**/*.*").map do |entry| + entry["#{collection_dir}/"] = ''; entry end end From e9f8b4df749eb793db744e7ba379de9f5bd89377 Mon Sep 17 00:00:00 2001 From: ducksan cho Date: Thu, 19 Nov 2015 17:15:51 +1300 Subject: [PATCH 4/4] Add Windows support to Utils.safe_glob --- lib/jekyll/cleaner.rb | 2 +- lib/jekyll/collection.rb | 2 +- lib/jekyll/utils.rb | 14 +++++++++----- test/test_utils.rb | 5 +++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb index 9146e7de..ca8a0ca9 100644 --- a/lib/jekyll/cleaner.rb +++ b/lib/jekyll/cleaner.rb @@ -40,7 +40,7 @@ module Jekyll regex = keep_file_regex dirs = keep_dirs - Utils.safe_glob(site.in_dest_dir, "**/*", File::FNM_DOTMATCH).each do |file| + Utils.safe_glob(site.in_dest_dir, ["**", "*"], File::FNM_DOTMATCH).each do |file| next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file) files << file end diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb index e4725718..00906352 100644 --- a/lib/jekyll/collection.rb +++ b/lib/jekyll/collection.rb @@ -74,7 +74,7 @@ module Jekyll def entries return Array.new unless exists? @entries ||= - Utils.safe_glob(collection_dir, "**/*.*").map do |entry| + Utils.safe_glob(collection_dir, ["**", "*.*"]).map do |entry| entry["#{collection_dir}/"] = ''; entry end end diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb index ab516767..54f400f8 100644 --- a/lib/jekyll/utils.rb +++ b/lib/jekyll/utils.rb @@ -222,15 +222,19 @@ module Jekyll # safe_glob("path", "*", File::FNM_DOTMATCH) # # => ["path/.", "path/..", "path/file1"] # - # dir - the dir where glob will be executed under + # safe_glob("path", ["**", "*"]) + # # => ["path[/file1", "path[/folder/file2"] + # + # dir - the dir where glob will be executed under # (the dir will be included to each result) - # pattern - the pattern which will be applied under the dir - # flags - the flags which will be applied to the pattern + # patterns - the patterns (or the pattern) which will be applied under the dir + # flags - the flags which will be applied to the pattern # # Returns matched pathes - def safe_glob(dir, pattern, flags = 0) + def safe_glob(dir, patterns, flags = 0) return [] unless Dir.exist?(dir) - return [dir] if pattern.nil? || pattern.empty? + pattern = File.join(Array patterns) + return [dir] if pattern.empty? Dir.chdir(dir) do Dir.glob(pattern, flags).map { |f| File.join(dir, f) } end diff --git a/test/test_utils.rb b/test/test_utils.rb index 02ebb09a..133aba0a 100644 --- a/test/test_utils.rb +++ b/test/test_utils.rb @@ -212,6 +212,11 @@ class TestUtils < JekyllUnitTest assert_equal Dir.glob(dir + "/*", File::FNM_DOTMATCH), Utils.safe_glob(dir, "*", File::FNM_DOTMATCH) end + + should "support pattern as an array to support windows" do + dir = "test" + assert_equal Dir.glob(dir + "/**/*"), Utils.safe_glob(dir, ["**", "*"]) + end end end