utarfile: Fix read/write handling of nulls in tar header.

For reading, the size is always terminated by a null, so just ignore it by
using 11 for the uctypes entry (this fixes a regression introduced in
7128d423c2).

For writing, the size must always be terminated by a null.

Signed-off-by: Damien George <damien@micropython.org>
pull/411/head
Damien George 2023-07-21 12:57:08 +10:00
rodzic da5ddfc6e2
commit 0a5b635594
4 zmienionych plików z 16 dodań i 21 usunięć

Wyświetl plik

@ -1,4 +1,4 @@
metadata(description="Adds write (create/append) support to utarfile.", version="0.1")
metadata(description="Adds write (create/append) support to utarfile.", version="0.1.1")
require("utarfile")
package("utarfile")

Wyświetl plik

@ -11,9 +11,9 @@ import os
# http://www.gnu.org/software/tar/manual/html_node/Standard.html
_TAR_HEADER = {
"name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100),
"mode": (uctypes.ARRAY | 100, uctypes.UINT8 | 7),
"uid": (uctypes.ARRAY | 108, uctypes.UINT8 | 7),
"gid": (uctypes.ARRAY | 116, uctypes.UINT8 | 7),
"mode": (uctypes.ARRAY | 100, uctypes.UINT8 | 8),
"uid": (uctypes.ARRAY | 108, uctypes.UINT8 | 8),
"gid": (uctypes.ARRAY | 116, uctypes.UINT8 | 8),
"size": (uctypes.ARRAY | 124, uctypes.UINT8 | 12),
"mtime": (uctypes.ARRAY | 136, uctypes.UINT8 | 12),
"chksum": (uctypes.ARRAY | 148, uctypes.UINT8 | 8),
@ -26,12 +26,6 @@ _BLOCKSIZE = const(512) # length of processing blocks
_RECORDSIZE = const(_BLOCKSIZE * 20) # length of records
# Write a string into a bytearray by copying each byte.
def _setstring(b, s, maxlen):
for i, c in enumerate(s.encode("utf-8")[:maxlen]):
b[i] = c
def _open_write(self, name, mode, fileobj):
if mode == "w":
if not fileobj:
@ -72,18 +66,18 @@ def addfile(self, tarinfo, fileobj=None):
if not name.endswith("/"):
name += "/"
hdr = uctypes.struct(uctypes.addressof(buf), _TAR_HEADER, uctypes.LITTLE_ENDIAN)
_setstring(hdr.name, name, 100)
_setstring(hdr.mode, "%06o " % (tarinfo.mode & 0o7777), 7)
_setstring(hdr.uid, "%06o " % tarinfo.uid, 7)
_setstring(hdr.gid, "%06o " % tarinfo.gid, 7)
_setstring(hdr.size, "%011o " % size, 12)
_setstring(hdr.mtime, "%011o " % tarinfo.mtime, 12)
_setstring(hdr.typeflag, "5" if tarinfo.isdir() else "0", 1)
hdr.name[:] = name.encode("utf-8")[:100]
hdr.mode[:] = b"%07o\0" % (tarinfo.mode & 0o7777)
hdr.uid[:] = b"%07o\0" % tarinfo.uid
hdr.gid[:] = b"%07o\0" % tarinfo.gid
hdr.size[:] = b"%011o\0" % size
hdr.mtime[:] = b"%011o\0" % tarinfo.mtime
hdr.typeflag[:] = b"5" if tarinfo.isdir() else b"0"
# Checksum is calculated with checksum field all blanks.
_setstring(hdr.chksum, " " * 8, 8)
hdr.chksum[:] = b" "
# Calculate and insert the actual checksum.
chksum = sum(buf)
_setstring(hdr.chksum, "%06o\0" % chksum, 7)
hdr.chksum[:] = b"%06o\0 " % chksum
# Emit the header.
self.f.write(buf)
self.offset += len(buf)

Wyświetl plik

@ -1,4 +1,4 @@
metadata(description="Read-only implementation of Python's tarfile.", version="0.4.0")
metadata(description="Read-only implementation of Python's tarfile.", version="0.4.1")
# Originally written by Paul Sokolovsky.

Wyświetl plik

@ -4,9 +4,10 @@ import uctypes
# Minimal set of tar header fields for reading.
# http://www.gnu.org/software/tar/manual/html_node/Standard.html
# The "size" entry is 11 (not 12) to implicitly cut off the null terminator.
_TAR_HEADER = {
"name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100),
"size": (uctypes.ARRAY | 124, uctypes.UINT8 | 12),
"size": (uctypes.ARRAY | 124, uctypes.UINT8 | 11),
}
DIRTYPE = const("dir")