Skip to content

Commit b85a246

Browse files
committed
utarfile: Lightweight tarfile module subset.
1 parent a03e185 commit b85a246

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

utarfile/utarfile.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import uctypes
2+
3+
# http://www.gnu.org/software/tar/manual/html_node/Standard.html
4+
TAR_HEADER = {
5+
"name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100),
6+
"size": (uctypes.ARRAY | 124, uctypes.UINT8 | 12),
7+
}
8+
9+
DIRTYPE = "dir"
10+
REGTYPE = "file"
11+
12+
def roundup(val, align):
13+
return (val + align - 1) & ~(align - 1)
14+
15+
def skip(f, size):
16+
assert size % 512 == 0
17+
buf = bytearray(512)
18+
while size:
19+
size -= f.readinto(buf)
20+
21+
class FileSection:
22+
23+
def __init__(self, f, content_len, aligned_len):
24+
self.f = f
25+
self.content_len = content_len
26+
self.align = aligned_len - content_len
27+
28+
def read(self, sz=65536):
29+
if self.content_len == 0:
30+
return b""
31+
if sz > self.content_len:
32+
sz = self.content_len
33+
data = self.f.read(sz)
34+
sz = len(data)
35+
self.content_len -= sz
36+
return data
37+
38+
def skip(self):
39+
self.f.read(self.content_len + self.align)
40+
41+
class TarInfo:
42+
43+
def __str__(self):
44+
return "TarInfo(%r, %s, %d)" % (self.name, self.type, self.size)
45+
46+
class TarFile:
47+
48+
def __init__(self, name):
49+
self.f = open(name, "rb")
50+
self.subf = None
51+
52+
def next(self):
53+
if self.subf:
54+
self.subf.skip()
55+
buf = self.f.read(512)
56+
if not buf:
57+
return None
58+
59+
h = uctypes.struct(TAR_HEADER, uctypes.addressof(buf), uctypes.LITTLE_ENDIAN)
60+
61+
# Empty block means end of archive
62+
if h.name[0] == 0:
63+
return None
64+
65+
d = TarInfo()
66+
d.name = str(h.name, "utf-8").rstrip()
67+
d.size = int(bytes(h.size).rstrip(), 8)
68+
d.type = [REGTYPE, DIRTYPE][d.name[-1] == "/"]
69+
self.subf = d.subf = FileSection(self.f, d.size, roundup(d.size, 512))
70+
return d
71+
72+
def __iter__(self):
73+
return self
74+
75+
def __next__(self):
76+
v = self.next()
77+
if v is None:
78+
raise StopIteration
79+
return v
80+
81+
def extractfile(self, tarinfo):
82+
return tarinfo.subf

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy