Skip to content

Commit c89670a

Browse files
committed
Merge pull request #3344 from lexmag/self-cp-fix
Fix a file coping to itself
2 parents dcefbca + 87c3157 commit c89670a

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

lib/elixir/lib/file.ex

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -471,16 +471,23 @@ 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.
476-
Returns the list of copied files otherwise.
483+
Returns `:ok` otherwise.
477484
"""
478485
@spec cp!(Path.t, Path.t, (Path.t, Path.t -> boolean)) :: :ok | no_return
479486
def cp!(source, destination, callback \\ fn(_, _) -> true end) do
480487
case cp(source, destination, callback) do
481488
:ok -> :ok
482489
{:error, reason} ->
483-
raise File.CopyError, reason: reason, action: "copy recursively",
490+
raise File.CopyError, reason: reason, action: "copy",
484491
source: IO.chardata_to_string(source), destination: IO.chardata_to_string(destination)
485492
end
486493
end
@@ -598,9 +605,7 @@ defmodule File do
598605
copy_file_mode!(src, dest)
599606
[dest|acc]
600607
{:error, :eexist} ->
601-
if callback.(src, dest) do
602-
# If rm/1 fails, copy/2 will fail
603-
_ = rm(dest)
608+
if path_differs?(src, dest) and callback.(src, dest) do
604609
case copy(src, dest) do
605610
{:ok, _} ->
606611
copy_file_mode!(src, dest)
@@ -620,8 +625,8 @@ defmodule File do
620625
:ok ->
621626
[dest|acc]
622627
{:error, :eexist} ->
623-
if callback.(src, dest) do
624-
# If rm/1 fails, iF.make_symlink/2 will fail
628+
if path_differs?(src, dest) and callback.(src, dest) do
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: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,26 @@ defmodule FileTest do
123123
test :cp_with_src_dir! do
124124
src = fixture_path("cp_r")
125125
dest = tmp_path("tmp.file")
126-
assert_raise File.CopyError, "could not copy recursively from #{src} to #{dest}: " <>
126+
assert_raise File.CopyError, "could not copy from #{src} to #{dest}: " <>
127127
"illegal operation on a directory", fn ->
128128
File.cp!(src, dest)
129129
end
130130
end
131131

132+
test :copy_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+
assert File.cp_r(src, dest) == {:ok, []}
141+
after
142+
File.rm(dest)
143+
end
144+
end
145+
132146
test :cp_r_with_src_file_and_dest_file do
133147
src = fixture_path("file.txt")
134148
dest = tmp_path("sample.txt")
@@ -869,7 +883,7 @@ defmodule FileTest do
869883
end
870884
end
871885

872-
test :lstat do
886+
test :lstat do
873887
{:ok, info} = File.lstat(__ENV__.file)
874888
assert info.mtime
875889
end

0 commit comments

Comments
 (0)