Skip to content

Commit f5e27f6

Browse files
committed
Fix File.cp/3 in case of a file coping to itself
1 parent dcefbca commit f5e27f6

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

lib/elixir/lib/file.ex

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ defmodule File do
461461
error will be returned.
462462
"""
463463
@spec cp(Path.t, Path.t, (Path.t, Path.t -> boolean)) :: :ok | {:error, posix}
464-
def cp(source, destination, callback \\ fn(_, _) -> true end) do
464+
def cp(source, destination, callback \\ &path_differs?/2) do
465465
source = IO.chardata_to_string(source)
466466
destination = IO.chardata_to_string(destination)
467467

@@ -471,12 +471,19 @@ defmodule File do
471471
end
472472
end
473473

474+
defp path_differs?(path, path),
475+
do: false
476+
477+
defp path_differs?(p1, p2) do
478+
Path.expand(p1) !== Path.expand(p2)
479+
end
480+
474481
@doc """
475482
The same as `cp/3`, but raises `File.CopyError` if it fails.
476483
Returns the list of copied files otherwise.
477484
"""
478485
@spec cp!(Path.t, Path.t, (Path.t, Path.t -> boolean)) :: :ok | no_return
479-
def cp!(source, destination, callback \\ fn(_, _) -> true end) do
486+
def cp!(source, destination, callback \\ &path_differs?/2) do
480487
case cp(source, destination, callback) do
481488
:ok -> :ok
482489
{:error, reason} ->
@@ -599,8 +606,6 @@ defmodule File do
599606
[dest|acc]
600607
{:error, :eexist} ->
601608
if callback.(src, dest) do
602-
# If rm/1 fails, copy/2 will fail
603-
_ = rm(dest)
604609
case copy(src, dest) do
605610
{:ok, _} ->
606611
copy_file_mode!(src, dest)
@@ -621,7 +626,7 @@ defmodule File do
621626
[dest|acc]
622627
{:error, :eexist} ->
623628
if callback.(src, dest) do
624-
# If rm/1 fails, iF.make_symlink/2 will fail
629+
# If rm/1 fails, F.make_symlink/2 will fail
625630
_ = rm(dest)
626631
case F.make_symlink(link, dest) do
627632
:ok -> [dest|acc]

lib/elixir/test/elixir/file_test.exs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ defmodule FileTest do
129129
end
130130
end
131131

132+
test :cp_file_to_itself do
133+
src = dest = tmp_path("tmp.file")
134+
135+
File.write!(src, "here")
136+
137+
try do
138+
assert File.cp(src, dest) == :ok
139+
assert File.read!(dest) == "here"
140+
after
141+
File.rm(dest)
142+
end
143+
end
144+
132145
test :cp_r_with_src_file_and_dest_file do
133146
src = fixture_path("file.txt")
134147
dest = tmp_path("sample.txt")

0 commit comments

Comments
 (0)