Avoid subprocess-writable temp file race condition · gitpython-developers/GitPython@9e5d0aa (original) (raw)
`@@ -6,7 +6,7 @@
`
6
6
`"""Module containing IndexFile, an Index implementation facilitating all kinds of index
`
7
7
`manipulations such as querying and merging."""
`
8
8
``
9
``
`-
from contextlib import ExitStack
`
``
9
`+
import contextlib
`
10
10
`import datetime
`
11
11
`import glob
`
12
12
`from io import BytesIO
`
67
67
`BinaryIO,
`
68
68
`Callable,
`
69
69
`Dict,
`
``
70
`+
Generator,
`
70
71
`IO,
`
71
72
`Iterable,
`
72
73
`Iterator,
`
96
97
`all = ("IndexFile", "CheckoutError", "StageType")
`
97
98
``
98
99
``
``
100
`+
@contextlib.contextmanager
`
``
101
`+
def _named_temporary_file_for_subprocess(directory: PathLike) -> Generator[str, None, None]:
`
``
102
`+
"""Create a named temporary file git subprocesses can open, deleting it afterward.
`
``
103
+
``
104
`+
:param directory: The directory in which the file is created.
`
``
105
+
``
106
`+
:return: A context manager object that creates the file and provides its name on
`
``
107
`+
entry, and deletes it on exit.
`
``
108
`+
"""
`
``
109
`+
if os.name == "nt":
`
``
110
`+
fd, name = tempfile.mkstemp(dir=directory)
`
``
111
`+
os.close(fd)
`
``
112
`+
try:
`
``
113
`+
yield name
`
``
114
`+
finally:
`
``
115
`+
os.remove(name)
`
``
116
`+
else:
`
``
117
`+
with tempfile.NamedTemporaryFile(dir=directory) as ctx:
`
``
118
`+
yield ctx.name
`
``
119
+
``
120
+
99
121
`class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
`
100
122
`"""An Index that can be manipulated using a native implementation in order to save
`
101
123
` git command function calls wherever possible.
`
`@@ -359,11 +381,9 @@ def from_tree(cls, repo: "Repo", *treeish: Treeish, **kwargs: Any) -> "IndexFile
`
359
381
``
360
382
`# tmp file created in git home directory to be sure renaming
`
361
383
`# works - /tmp/ dirs could be on another device.
`
362
``
`-
with ExitStack() as stack:
`
363
``
`-
tmp_index = stack.enter_context(tempfile.NamedTemporaryFile(dir=repo.git_dir))
`
364
``
`-
if os.name == "nt":
`
365
``
`-
tmp_index.close()
`
366
``
`-
arg_list.append("--index-output=%s" % tmp_index.name)
`
``
384
`+
with contextlib.ExitStack() as stack:
`
``
385
`+
tmp_index = stack.enter_context(_named_temporary_file_for_subprocess(repo.git_dir))
`
``
386
`+
arg_list.append("--index-output=%s" % tmp_index)
`
367
387
`arg_list.extend(treeish)
`
368
388
``
369
389
`# Move current index out of the way - otherwise the merge may fail
`
`@@ -373,7 +393,7 @@ def from_tree(cls, repo: "Repo", *treeish: Treeish, **kwargs: Any) -> "IndexFile
`
373
393
``
374
394
`stack.enter_context(TemporaryFileSwap(join_path_native(repo.git_dir, "index")))
`
375
395
`repo.git.read_tree(*arg_list, **kwargs)
`
376
``
`-
index = cls(repo, tmp_index.name)
`
``
396
`+
index = cls(repo, tmp_index)
`
377
397
`index.entries # Force it to read the file as we will delete the temp-file.
`
378
398
`return index
`
379
399
`# END index merge handling
`