Skip to content

Commit 07afa71

Browse files
authored
Properly handle permissions errors cascading from parent in File.mkdir (#14242)
1 parent 15a941e commit 07afa71

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

lib/elixir/lib/file.ex

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -310,24 +310,23 @@ defmodule File do
310310
end
311311

312312
defp do_mkdir_p(path) do
313-
if dir?(path) do
313+
parent = Path.dirname(path)
314+
315+
if parent == path do
314316
:ok
315317
else
316-
parent = Path.dirname(path)
317-
318-
if parent == path do
319-
# Protect against infinite loop
320-
{:error, :einval}
321-
else
322-
_ = do_mkdir_p(parent)
323-
324-
case :file.make_dir(path) do
325-
{:error, :eexist} = error ->
326-
if dir?(path), do: :ok, else: error
318+
case do_mkdir_p(parent) do
319+
:ok ->
320+
case :file.make_dir(path) do
321+
{:error, :eexist} ->
322+
if dir?(path), do: :ok, else: {:error, :enotdir}
323+
324+
other ->
325+
other
326+
end
327327

328-
other ->
329-
other
330-
end
328+
e ->
329+
e
331330
end
332331
end
333332
end

lib/elixir/test/elixir/file_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,28 @@ defmodule FileTest do
11461146
File.mkdir_p!(invalid)
11471147
end
11481148
end
1149+
1150+
@tag :unix
1151+
test "mkdir_p with non-accessible parent directory" do
1152+
fixture = tmp_path("tmp_test_parent")
1153+
1154+
try do
1155+
refute File.exists?(fixture)
1156+
assert File.mkdir_p!(fixture) == :ok
1157+
%File.Stat{mode: orig_mode} = File.stat!(fixture)
1158+
assert File.chmod!(fixture, 0o000) == :ok
1159+
1160+
child = Path.join(fixture, "child")
1161+
refute File.exists?(child)
1162+
1163+
assert File.mkdir_p(child) == {:error, :eacces}
1164+
refute File.exists?(child)
1165+
1166+
assert File.chmod!(fixture, orig_mode) == :ok
1167+
after
1168+
File.rm_rf(fixture)
1169+
end
1170+
end
11491171
end
11501172

11511173
describe "rm" do

0 commit comments

Comments
 (0)