Skip to content

Commit 4992c0c

Browse files
authored
Merge pull request #517 from raphaeldussin/zipstore_perm_fix
Fixing permissions for files inside a ZipStore
2 parents 11eed3e + 6dfe4d1 commit 4992c0c

File tree

4 files changed

+37
-2
lines changed

4 files changed

+37
-2
lines changed

docs/release.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Release notes
44
Upcoming Release
55
----------------
66

7+
* Add intermediate step (using ``zipfile.ZipInfo`` object) to write
8+
inside ``ZipStore`` to solve too restrictive permission issue.
9+
By :user:`Raphael Dussin <raphaeldussin>`; :issue:`505`.
10+
711
* Add key normalization option for ``DirectoryStore``, ``NestedDirectoryStore``,
812
``TempStore``, and ``N5Store``.
913
By :user:`James Bourbeau <jrbourbeau>`; :issue:`459`.

zarr/creation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def normalize_store_arg(store, clobber=False, default=dict):
132132
return default()
133133
elif isinstance(store, str):
134134
if store.endswith('.zip'):
135-
mode = 'w' if clobber else 'a'
135+
mode = 'w' if clobber else 'r'
136136
return ZipStore(store, mode=mode)
137137
elif store.endswith('.n5'):
138138
return N5Store(store)

zarr/storage.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from pickle import PicklingError
3434
from threading import Lock, RLock
3535
import uuid
36+
import time
3637

3738
from numcodecs.compat import ensure_bytes, ensure_contiguous_ndarray
3839
from numcodecs.registry import codec_registry
@@ -1254,7 +1255,19 @@ def __setitem__(self, key, value):
12541255
err_read_only()
12551256
value = ensure_contiguous_ndarray(value)
12561257
with self.mutex:
1257-
self.zf.writestr(key, value)
1258+
# writestr(key, value) writes with default permissions from
1259+
# zipfile (600) that are too restrictive, build ZipInfo for
1260+
# the key to work around limitation
1261+
keyinfo = zipfile.ZipInfo(filename=key,
1262+
date_time=time.localtime(time.time())[:6])
1263+
keyinfo.compress_type = self.compression
1264+
if keyinfo.filename[-1] == os.sep:
1265+
keyinfo.external_attr = 0o40775 << 16 # drwxrwxr-x
1266+
keyinfo.external_attr |= 0x10 # MS-DOS directory flag
1267+
else:
1268+
keyinfo.external_attr = 0o644 << 16 # ?rw-r--r--
1269+
1270+
self.zf.writestr(keyinfo, value)
12581271

12591272
def __delitem__(self, key):
12601273
raise NotImplementedError

zarr/tests/test_storage.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import unittest
1010
from contextlib import contextmanager
1111
from pickle import PicklingError
12+
from zipfile import ZipFile
1213

1314
import numpy as np
1415
import pytest
@@ -947,6 +948,23 @@ def test_popitem(self):
947948
with pytest.raises(NotImplementedError):
948949
store.popitem()
949950

951+
def test_permissions(self):
952+
store = ZipStore('data/store.zip', mode='w')
953+
store['foo'] = b'bar'
954+
store['baz/'] = b''
955+
store.flush()
956+
store.close()
957+
z = ZipFile('data/store.zip', 'r')
958+
info = z.getinfo('foo')
959+
perm = oct(info.external_attr >> 16)
960+
assert perm == '0o644'
961+
info = z.getinfo('baz/')
962+
perm = oct(info.external_attr >> 16)
963+
# only for posix platforms
964+
if os.name == 'posix':
965+
assert perm == '0o40775'
966+
z.close()
967+
950968

951969
class TestDBMStore(StoreTests, unittest.TestCase):
952970

0 commit comments

Comments
 (0)