Skip to content

Commit

Permalink
flat_hash: use mkstemp in _setitem
Browse files Browse the repository at this point in the history
Fix the _setitem method to use mkstemp in order to avoid a
race condition when multiple pid namespaces share the same
cache directory.

Reported-by: Mike Frysinger <vapier@chromium.org>
X-Chromium-Bug: 477727
X-Chromium-Bug-url: https://bugs.chromium.org/p/chromium/issues/detail?id=477727
  • Loading branch information
zmedico committed Jul 24, 2016
1 parent bb2f061 commit 5652bc8
Showing 1 changed file with 24 additions and 25 deletions.
49 changes: 24 additions & 25 deletions pym/portage/cache/flat_hash.py
@@ -1,4 +1,4 @@
# Copyright 2005-2014 Gentoo Foundation
# Copyright 2005-2016 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# Author(s): Brian Harring (ferringb@gentoo.org)

Expand All @@ -10,6 +10,7 @@
import io
import stat
import sys
import tempfile
import os as _os
from portage import os
from portage import _encodings
Expand Down Expand Up @@ -66,27 +67,14 @@ def _parse_data(self, data, cpv):
raise cache_errors.CacheCorruption(cpv, e)

def _setitem(self, cpv, values):
s = cpv.rfind("/")
fp = os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
try:
myf = io.open(_unicode_encode(fp,
encoding=_encodings['fs'], errors='strict'),
mode='w', encoding=_encodings['repo.content'],
errors='backslashreplace')
except (IOError, OSError) as e:
if errno.ENOENT == e.errno:
try:
self._ensure_dirs(cpv)
myf = io.open(_unicode_encode(fp,
encoding=_encodings['fs'], errors='strict'),
mode='w', encoding=_encodings['repo.content'],
errors='backslashreplace')
except (OSError, IOError) as e:
raise cache_errors.CacheCorruption(cpv, e)
else:
raise cache_errors.CacheCorruption(cpv, e)
fd, fp = tempfile.mkstemp(dir=self.location)
except EnvironmentError as e:
raise cache_errors.CacheCorruption(cpv, e)

try:
with io.open(fd, mode='w',
encoding=_encodings['repo.content'],
errors='backslashreplace') as myf:
for k in self._write_keys:
v = values.get(k)
if not v:
Expand All @@ -95,18 +83,29 @@ def _setitem(self, cpv, values):
# k and v are coerced to unicode, in order to prevent TypeError
# when writing raw bytes to TextIOWrapper with Python 2.
myf.write("%s=%s\n" % (k, v))
finally:
myf.close()

self._ensure_access(fp)

#update written. now we move it.

new_fp = os.path.join(self.location,cpv)
try:
os.rename(fp, new_fp)
except (OSError, IOError) as e:
os.remove(fp)
raise cache_errors.CacheCorruption(cpv, e)
except EnvironmentError as e:
success = False
try:
if errno.ENOENT == e.errno:
try:
self._ensure_dirs(cpv)
os.rename(fp, new_fp)
success = True
except EnvironmentError as e:
raise cache_errors.CacheCorruption(cpv, e)
else:
raise cache_errors.CacheCorruption(cpv, e)
finally:
if not success:
os.remove(fp)

def _delitem(self, cpv):
# import pdb;pdb.set_trace()
Expand Down

0 comments on commit 5652bc8

Please sign in to comment.