Skip to content
This repository was archived by the owner on Sep 12, 2018. It is now read-only.

Commit 1ceba48

Browse files
committed
xattrs: monkey patch, instead of vendor
Docker-DCO-1.1-Signed-off-by: Vincent Batts <[email protected]> (github: vbatts)
1 parent 0c7dac6 commit 1ceba48

File tree

5 files changed

+113
-2631
lines changed

5 files changed

+113
-2631
lines changed

docker_registry/images.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
from .lib import checksums
2020
from .lib import layers
2121
from .lib import mirroring
22-
from .vendor import xtarfile
22+
from .lib import xtarfile
23+
24+
25+
tarfile = xtarfile.tarfile
2326

2427

2528
store = storage.load()
@@ -244,13 +247,13 @@ def put_image_layer(image_id):
244247
tarsum = checksums.TarSum(json_data)
245248
try:
246249
tmp.seek(0)
247-
tar = xtarfile.open(mode='r|*', fileobj=tmp)
250+
tar = tarfile.open(mode='r|*', fileobj=tmp)
248251
tarfilesinfo = layers.TarFilesInfo()
249252
for member in tar:
250253
tarsum.append(member, tar)
251254
tarfilesinfo.append(member)
252255
layers.set_image_files_cache(image_id, tarfilesinfo.json())
253-
except (IOError, xtarfile.TarError) as e:
256+
except (IOError, tarfile.TarError) as e:
254257
logger.debug('put_image_layer: Error when reading Tar stream '
255258
'tarsum. Disabling TarSum, TarFilesInfo. '
256259
'Error: {0}'.format(e))
@@ -433,7 +436,7 @@ def get_private_image_files(image_id, headers):
433436
return toolkit.response(data, headers=headers, raw=True)
434437
except exceptions.FileNotFoundError:
435438
return toolkit.api_error('Image not found', 404)
436-
except xtarfile.TarError:
439+
except tarfile.TarError:
437440
return toolkit.api_error('Layer format not supported', 400)
438441

439442

@@ -452,7 +455,7 @@ def get_image_files(image_id, headers):
452455
return toolkit.response(data, headers=headers, raw=True)
453456
except exceptions.FileNotFoundError:
454457
return toolkit.api_error('Image not found', 404)
455-
except xtarfile.TarError:
458+
except tarfile.TarError:
456459
return toolkit.api_error('Layer format not supported', 400)
457460

458461

@@ -479,5 +482,5 @@ def get_image_diff(image_id, headers):
479482
return toolkit.response(diff_json, headers=headers, raw=True)
480483
except exceptions.FileNotFoundError:
481484
return toolkit.api_error('Image not found', 404)
482-
except xtarfile.TarError:
485+
except tarfile.TarError:
483486
return toolkit.api_error('Layer format not supported', 400)

docker_registry/lib/layers.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,28 @@
1010
from .. import storage
1111
from . import cache
1212
from . import rqueue
13-
# this is our vendored 'tarfile' from python v2.7.6, with xattr support
14-
from ..vendor import xtarfile
13+
# this is our monkey patched 'tarfile' from python v2.7.6, with xattr support
14+
from . import xtarfile
15+
16+
17+
tarfile = xtarfile.tarfile
1518

1619

1720
store = storage.load()
1821

1922
FILE_TYPES = {
20-
xtarfile.REGTYPE: 'f',
21-
xtarfile.AREGTYPE: 'f',
22-
xtarfile.LNKTYPE: 'l',
23-
xtarfile.SYMTYPE: 's',
24-
xtarfile.CHRTYPE: 'c',
25-
xtarfile.BLKTYPE: 'b',
26-
xtarfile.DIRTYPE: 'd',
27-
xtarfile.FIFOTYPE: 'i',
28-
xtarfile.CONTTYPE: 't',
29-
xtarfile.GNUTYPE_LONGNAME: 'L',
30-
xtarfile.GNUTYPE_LONGLINK: 'K',
31-
xtarfile.GNUTYPE_SPARSE: 'S',
23+
tarfile.REGTYPE: 'f',
24+
tarfile.AREGTYPE: 'f',
25+
tarfile.LNKTYPE: 'l',
26+
tarfile.SYMTYPE: 's',
27+
tarfile.CHRTYPE: 'c',
28+
tarfile.BLKTYPE: 'b',
29+
tarfile.DIRTYPE: 'd',
30+
tarfile.FIFOTYPE: 'i',
31+
tarfile.CONTTYPE: 't',
32+
tarfile.GNUTYPE_LONGNAME: 'L',
33+
tarfile.GNUTYPE_LONGLINK: 'K',
34+
tarfile.GNUTYPE_SPARSE: 'S',
3235
}
3336

3437
logger = logging.getLogger(__name__)
@@ -182,7 +185,7 @@ def get_image_files_from_fobj(layer_file):
182185
'''
183186
layer_file.seek(0)
184187
archive_file = Archive(layer_file)
185-
tar_file = xtarfile.open(fileobj=archive_file)
188+
tar_file = tarfile.open(fileobj=archive_file)
186189
files = read_tarfile(tar_file)
187190
return files
188191

docker_registry/lib/xtarfile.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'''
2+
This is __proc_pax from ./Lib/tarfile.py from v2.7.6
3+
catching raw (non-utf8) bytes to support some xattr headers in tar archives
4+
5+
This is for the use-case of reading the tar archive, not for the use case of
6+
interacting with inodes on the filesystem that have xattr's.
7+
-- vbatts
8+
'''
9+
10+
import re
11+
import tarfile
12+
13+
tarfile.PAX_FIELDS = tarfile.PAX_FIELDS + ("SCHILY.xattr.",)
14+
tarfile.PAX_NUMBER_FIELDS["SCHILY.xattr."] = dict
15+
16+
# class XattrTarInfo(tarfile.TarInfo):
17+
18+
19+
def _proc_pax(self, filetar):
20+
"""Process an extended or global header as described in
21+
POSIX.1-2001.
22+
"""
23+
# Read the header information.
24+
buf = filetar.fileobj.read(self._block(self.size))
25+
26+
# A pax header stores supplemental information for either
27+
# the following file (extended) or all following files
28+
# (global).
29+
if self.type == tarfile.XGLTYPE:
30+
pax_headers = filetar.pax_headers
31+
else:
32+
pax_headers = filetar.pax_headers.copy()
33+
34+
# Parse pax header information. A record looks like that:
35+
# "%d %s=%s\n" % (length, keyword, value). length is the size
36+
# of the complete record including the length field itself and
37+
# the newline. keyword and value are both UTF-8 encoded strings.
38+
regex = re.compile(r"(\d+) ([^=]+)=", re.U)
39+
pos = 0
40+
while True:
41+
match = regex.match(buf, pos)
42+
if not match:
43+
break
44+
45+
length, keyword = match.groups()
46+
length = int(length)
47+
value = buf[match.end(2) + 1:match.start(1) + length - 1]
48+
49+
try:
50+
keyword = keyword.decode("utf8")
51+
except Exception:
52+
# just leave the raw bytes
53+
pass
54+
55+
try:
56+
value = value.decode("utf8")
57+
except Exception:
58+
# just leave the raw bytes
59+
pass
60+
61+
pax_headers[keyword] = value
62+
pos += length
63+
64+
# Fetch the next header.
65+
try:
66+
next = self.fromtarfile(filetar)
67+
except tarfile.HeaderError:
68+
raise tarfile.SubsequentHeaderError("missing or bad subsequent header")
69+
70+
if self.type in (tarfile.XHDTYPE, tarfile.SOLARIS_XHDTYPE):
71+
# Patch the TarInfo object with the extended header info.
72+
next._apply_pax_info(pax_headers, filetar.encoding, filetar.errors)
73+
next.offset = self.offset
74+
75+
if "size" in pax_headers:
76+
# If the extended header replaces the size field,
77+
# we need to recalculate the offset where the next
78+
# header starts.
79+
offset = next.offset_data
80+
if next.isreg() or next.type not in tarfile.SUPPORTED_TYPES:
81+
offset += next._block(next.size)
82+
filetar.offset = offset
83+
84+
return next
85+
86+
tarfile.TarInfo._proc_pax = _proc_pax

docker_registry/vendor/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)