Skip to content

Commit 00d536d

Browse files
committed
backports: Copy mkdir_p TOCTOU fix from elixir PR 14242
See: elixir-lang/elixir#14242
1 parent bc75bb3 commit 00d536d

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

changelog.d/toctou-mkdir.fix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Backport [Elixir PR 14242](https://github.com/elixir-lang/elixir/pull/14242) fixing racy mkdir and lack of error handling of parent directory creation

lib/pleroma/backports.ex

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright 2012 Plataformatec
2+
# Copyright 2021 The Elixir Team
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
defmodule Pleroma.Backports do
6+
import File, only: [dir?: 1]
7+
8+
# <https://github.com/elixir-lang/elixir/pull/14242>
9+
# To be removed when we require Elixir 1.19
10+
@doc """
11+
Tries to create the directory `path`.
12+
13+
Missing parent directories are created. Returns `:ok` if successful, or
14+
`{:error, reason}` if an error occurs.
15+
16+
Typical error reasons are:
17+
18+
* `:eacces` - missing search or write permissions for the parent
19+
directories of `path`
20+
* `:enospc` - there is no space left on the device
21+
* `:enotdir` - a component of `path` is not a directory
22+
23+
"""
24+
@spec mkdir_p(Path.t()) :: :ok | {:error, File.posix() | :badarg}
25+
def mkdir_p(path) do
26+
do_mkdir_p(IO.chardata_to_string(path))
27+
end
28+
29+
defp do_mkdir_p("/") do
30+
:ok
31+
end
32+
33+
defp do_mkdir_p(path) do
34+
parent = Path.dirname(path)
35+
36+
if parent == path do
37+
:ok
38+
else
39+
case do_mkdir_p(parent) do
40+
:ok ->
41+
case :file.make_dir(path) do
42+
{:error, :eexist} ->
43+
if dir?(path), do: :ok, else: {:error, :enotdir}
44+
45+
other ->
46+
other
47+
end
48+
49+
e ->
50+
e
51+
end
52+
end
53+
end
54+
55+
@doc """
56+
Same as `mkdir_p/1`, but raises a `File.Error` exception in case of failure.
57+
Otherwise `:ok`.
58+
"""
59+
@spec mkdir_p!(Path.t()) :: :ok
60+
def mkdir_p!(path) do
61+
case mkdir_p(path) do
62+
:ok ->
63+
:ok
64+
65+
{:error, reason} ->
66+
raise File.Error,
67+
reason: reason,
68+
action: "make directory (with -p)",
69+
path: IO.chardata_to_string(path)
70+
end
71+
end
72+
end

0 commit comments

Comments
 (0)