Skip to content

Commit e6667aa

Browse files
jrbourbeaujakirkham
authored andcommitted
Fix permissions issue with DirectoryStore (#493)
* Set file permissions in DirectoryStorage according to umask Fixes #325 * Use built-in open function * Adds link to GH issue * Adds release notes entry
1 parent 55ae9eb commit e6667aa

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

docs/release.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Upcoming Release
2424
* Removed support for Python 2.
2525
By :user:`jhamman`; :issue:`393`, :issue:`470`.
2626

27+
* Update ``DirectoryStore`` to create files with more permissive permissions.
28+
By :user:`Eduardo Gonzalez <eddienko>` and :user:`James Bourbeau <jrbourbeau>`; :issue:`493`
29+
2730
.. _release_2.3.2:
2831

2932
2.3.2

zarr/storage.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from os import scandir
3333
from pickle import PicklingError
3434
from threading import Lock, RLock
35+
import uuid
3536

3637
from numcodecs.compat import ensure_bytes, ensure_contiguous_ndarray
3738
from numcodecs.registry import codec_registry
@@ -768,20 +769,19 @@ def __setitem__(self, key, value):
768769
raise KeyError(key)
769770

770771
# write to temporary file
771-
temp_path = None
772+
# note we're not using tempfile.NamedTemporaryFile to avoid restrictive file permissions
773+
temp_name = file_name + '.' + uuid.uuid4().hex + '.partial'
774+
temp_path = os.path.join(dir_path, temp_name)
772775
try:
773-
with tempfile.NamedTemporaryFile(mode='wb', delete=False, dir=dir_path,
774-
prefix=file_name + '.',
775-
suffix='.partial') as f:
776-
temp_path = f.name
776+
with open(temp_path, mode='wb') as f:
777777
f.write(value)
778778

779779
# move temporary file into place
780780
replace(temp_path, file_path)
781781

782782
finally:
783783
# clean up if temp file still exists for whatever reason
784-
if temp_path is not None and os.path.exists(temp_path): # pragma: no cover
784+
if os.path.exists(temp_path): # pragma: no cover
785785
os.remove(temp_path)
786786

787787
def __delitem__(self, key):

zarr/tests/test_storage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,14 @@ def test_filesystem_path(self):
753753
store['foo'] = b'bar'
754754
assert os.path.isdir(path)
755755

756+
# check correct permissions
757+
# regression test for https://github.com/zarr-developers/zarr-python/issues/325
758+
stat = os.stat(path)
759+
mode = stat.st_mode & 0o666
760+
umask = os.umask(0)
761+
os.umask(umask)
762+
assert mode == (0o666 & ~umask)
763+
756764
# test behaviour with file path
757765
with tempfile.NamedTemporaryFile() as f:
758766
with pytest.raises(ValueError):

0 commit comments

Comments
 (0)