Ensure recursive file/path ops raise on paths with null bytes
This commit is contained in:
+23
-5
@@ -670,15 +670,21 @@ defmodule File do
|
||||
File.cp_r "samples", "tmp"
|
||||
|
||||
# Same as before, but asks the user how to proceed in case of conflicts
|
||||
File.cp_r "samples", "tmp", fn(source, destination) ->
|
||||
File.cp_r "samples", "tmp", fn source, destination ->
|
||||
IO.gets("Overwriting #{destination} by #{source}. Type y to confirm. ") == "y\n"
|
||||
end
|
||||
|
||||
"""
|
||||
@spec cp_r(Path.t, Path.t, (Path.t, Path.t -> boolean)) :: {:ok, [binary]} | {:error, posix, binary}
|
||||
def cp_r(source, destination, callback \\ fn(_, _) -> true end) when is_function(callback, 2) do
|
||||
source = IO.chardata_to_string(source)
|
||||
destination = IO.chardata_to_string(destination)
|
||||
def cp_r(source, destination, callback \\ fn _, _ -> true end) when is_function(callback, 2) do
|
||||
source =
|
||||
source
|
||||
|> IO.chardata_to_string()
|
||||
|> assert_no_null_byte!("File.cp_r/3")
|
||||
destination =
|
||||
destination
|
||||
|> IO.chardata_to_string()
|
||||
|> assert_no_null_byte!("File.cp_r/3")
|
||||
|
||||
case do_cp_r(source, destination, callback, []) do
|
||||
{:error, _, _} = error -> error
|
||||
@@ -947,7 +953,10 @@ defmodule File do
|
||||
"""
|
||||
@spec rm_rf(Path.t) :: {:ok, [binary]} | {:error, posix, binary}
|
||||
def rm_rf(path) do
|
||||
do_rm_rf(IO.chardata_to_string(path), {:ok, []})
|
||||
path
|
||||
|> IO.chardata_to_string()
|
||||
|> assert_no_null_byte!("File.cp_r/3")
|
||||
|> do_rm_rf({:ok, []})
|
||||
end
|
||||
|
||||
defp do_rm_rf(path, {:ok, _} = entry) do
|
||||
@@ -1454,6 +1463,15 @@ defmodule File do
|
||||
|
||||
@read_ahead_size 64 * 1024
|
||||
|
||||
defp assert_no_null_byte!(binary, operation) do
|
||||
case :binary.match(binary, "\0") do
|
||||
{_, _} ->
|
||||
raise ArgumentError, "cannot execute #{operation} for path with null byte, got: #{inspect binary}"
|
||||
:nomatch ->
|
||||
binary
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_modes([:utf8 | rest], binary?) do
|
||||
[encoding: :utf8] ++ normalize_modes(rest, binary?)
|
||||
end
|
||||
|
||||
@@ -615,17 +615,19 @@ defmodule Path do
|
||||
def wildcard(glob, opts \\ []) do
|
||||
mod = if Keyword.get(opts, :match_dot), do: :file, else: Path.Wildcard
|
||||
glob
|
||||
|> chardata_to_list()
|
||||
|> chardata_to_list!()
|
||||
|> :filelib.wildcard(mod)
|
||||
|> Enum.map(&IO.chardata_to_string/1)
|
||||
end
|
||||
|
||||
# expand_dot the given path by expanding "..", "." and "~".
|
||||
|
||||
defp chardata_to_list(chardata) do
|
||||
defp chardata_to_list!(chardata) do
|
||||
case :unicode.characters_to_list(chardata) do
|
||||
result when is_list(result) ->
|
||||
result
|
||||
if 0 in result do
|
||||
raise ArgumentError, "cannot execute Path.wildcard/2 for path with null byte, got: #{inspect chardata}"
|
||||
else
|
||||
result
|
||||
end
|
||||
|
||||
{:error, encoded, rest} ->
|
||||
raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid
|
||||
@@ -654,6 +656,8 @@ defmodule Path do
|
||||
end
|
||||
end
|
||||
|
||||
# expand_dot the given path by expanding "..", "." and "~".
|
||||
|
||||
defp expand_dot(<<"/", rest::binary>>),
|
||||
do: "/" <> do_expand_dot(rest)
|
||||
defp expand_dot(<<letter, ":/", rest::binary>>) when letter in ?a..?z,
|
||||
|
||||
@@ -460,6 +460,11 @@ defmodule FileTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "cp_r raises on path with null byte" do
|
||||
assert_raise ArgumentError, ~r/null byte/, fn -> File.cp_r("source", "foo\0bar") end
|
||||
assert_raise ArgumentError, ~r/null byte/, fn -> File.cp_r("foo\0bar", "dest") end
|
||||
end
|
||||
|
||||
test "cp_r with src file and dest file" do
|
||||
src = fixture_path("file.txt")
|
||||
dest = tmp_path("sample.txt")
|
||||
@@ -1113,6 +1118,10 @@ defmodule FileTest do
|
||||
refute File.exists?(fixture)
|
||||
end
|
||||
|
||||
test "rm_rf raises on path with null byte" do
|
||||
assert_raise ArgumentError, ~r/null byte/, fn -> File.rm_rf("foo\0bar") end
|
||||
end
|
||||
|
||||
test "rm_rf with symlink" do
|
||||
from = tmp_path("tmp/from")
|
||||
to = tmp_path("tmp/to")
|
||||
|
||||
@@ -32,6 +32,10 @@ defmodule PathTest do
|
||||
File.rm_rf tmp_path("wildcard")
|
||||
end
|
||||
|
||||
test "wildcard/2 raises on null byte" do
|
||||
assert_raise ArgumentError, ~r/null byte/, fn -> Path.wildcard("foo\0bar") end
|
||||
end
|
||||
|
||||
if windows?() do
|
||||
describe "Windows" do
|
||||
test "relative/1" do
|
||||
|
||||
Reference in New Issue
Block a user