Skip to content

Commit 52c58c7

Browse files
authored
Preserve directory permissions in File.cp_r/3 (#15155)
The documentation states that `cp_r/3` maintains "modes" when copying, but directory permissions were not being preserved - only file permissions.
1 parent d566697 commit 52c58c7

2 files changed

Lines changed: 38 additions & 12 deletions

File tree

lib/elixir/lib/file.ex

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,18 +1277,24 @@ defmodule File do
12771277
{:ok, files} ->
12781278
case mkdir(dest) do
12791279
success when success in [:ok, {:error, :eexist}] ->
1280-
Enum.reduce_while(files, [dest | acc], fn x, acc ->
1281-
case do_cp_r(
1282-
Path.join(src, x),
1283-
Path.join(dest, x),
1284-
on_conflict,
1285-
dereference,
1286-
acc
1287-
) do
1288-
{:error, _, _} = error -> {:halt, error}
1289-
acc -> {:cont, acc}
1290-
end
1291-
end)
1280+
case copy_file_mode(src, dest) do
1281+
:ok ->
1282+
Enum.reduce_while(files, [dest | acc], fn x, acc ->
1283+
case do_cp_r(
1284+
Path.join(src, x),
1285+
Path.join(dest, x),
1286+
on_conflict,
1287+
dereference,
1288+
acc
1289+
) do
1290+
{:error, _, _} = error -> {:halt, error}
1291+
acc -> {:cont, acc}
1292+
end
1293+
end)
1294+
1295+
{:error, reason} ->
1296+
{:error, reason, src}
1297+
end
12921298

12931299
{:error, reason} ->
12941300
{:error, reason, dest}

lib/elixir/test/elixir/file_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,26 @@ defmodule FileTest do
869869
assert src_mode == dest_mode
870870
end
871871

872+
test "cp_r preserves directory mode" do
873+
src = tmp_path("tmp/src_dir")
874+
dest = tmp_path("tmp/dest_dir")
875+
inner = Path.join(src, "inner")
876+
877+
File.mkdir_p!(inner)
878+
File.chmod!(inner, 0o700)
879+
880+
try do
881+
File.cp_r!(src, dest)
882+
883+
%File.Stat{mode: src_mode} = File.stat!(inner)
884+
%File.Stat{mode: dest_mode} = File.stat!(Path.join(dest, "inner"))
885+
assert src_mode == dest_mode
886+
after
887+
File.rm_rf!(src)
888+
File.rm_rf!(dest)
889+
end
890+
end
891+
872892
@tag :unix
873893
test "cp_r skips sockets and other special files" do
874894
# We use tmpdir because macOS has a limit on socket paths

0 commit comments

Comments
 (0)