summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2023-05-02 22:30:32 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2023-05-02 22:30:32 (EDT)
commitf48fc107cbc1cf28cbd305b37c399cd180cefeed (patch)
tree9e6c05f053d5b9f11935bfdefff5864e9e10cfc8
parent619f09be066777b8296acf93bd6b51771ca64bd2 (diff)
ustar: Improve compatibility of written headers
-rw-r--r--src/ustar.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/ustar.c b/src/ustar.c
index d70a616..b5b0310 100644
--- a/src/ustar.c
+++ b/src/ustar.c
@@ -28,6 +28,8 @@
#define OPKG_OPK_USTAR_NUM_BASE_ 8
+/* #define OPKG_OPK_USTAR_BB_EXACT_HEADER_ 1 */
+
struct _opkg_opk_ustar_header {
char name [100];
char mode [8];
@@ -284,13 +286,16 @@ opkg_opk_ustar_write_header(struct opkg_opk_ustar *ustar,
sizeof(ustar->header.prefix)) != OPKG_OPK_OK) {
return OPKG_OPK_ERROR;
}
- sprintf(ustar->header.mode, "%o", mode);
- sprintf(ustar->header.uid, "%o", uid);
- sprintf(ustar->header.gid, "%o", gid);
- strncpy(ustar->header.uname, uname, sizeof(ustar->header.uname));
- strncpy(ustar->header.gname, gname, sizeof(ustar->header.gname));
- sprintf(ustar->header.size, "%o", size);
- sprintf(ustar->header.mtime, "%o", mtime);
+ /* POSIX doesn't say to NUL-terminate mode, uid, gid, size, or mtime.
+ * GNU and BB tar accept values that aren't (but generate values that
+ * ARE) NUL-terminated. But more importantly, opkg-lede (see file
+ * libbb/unarchive.c) parses these with simple strtol() calls, without
+ * even checking endptr, so we have to NUL-terminate these fields. */
+ sprintf(ustar->header.mode, "%07o", mode);
+ sprintf(ustar->header.uid, "%07o", uid);
+ sprintf(ustar->header.gid, "%07o", gid);
+ sprintf(ustar->header.size, "%011o", size);
+ sprintf(ustar->header.mtime, "%011o", mtime);
switch (type) {
case '-': /* Regular file */
*ustar->header.typeflag = '0';
@@ -315,9 +320,24 @@ opkg_opk_ustar_write_header(struct opkg_opk_ustar *ustar,
default:
return OPKG_OPK_ERROR; /* Unsupported */
}
+ strncpy(ustar->header.uname, uname, sizeof(ustar->header.uname));
+ strncpy(ustar->header.gname, gname, sizeof(ustar->header.gname));
+
+ /* In these fields POSIX says to write: But GNU and BB tar write: */
+ strcpy(ustar->header.magic, "ustar"); /* "ustar " */
+ memcpy(ustar->header.version, "00", 2); /* " \0" i.e. 0x20 0x00 */
+ /* See files in BusyBox:
+ * include/bb_archive.h
+ * archival/chksum_and_xwrite_tar_header.c
+ * archival/libarchive/get_header_tar.c
+ * GNU and BB tar accept POSIX-conformant magic and version fields.
+ * opkg-lede libbb/unarchive.c only checks first 5 bytes of magic and
+ * ignores version. So conforming to POSIX seems safe.
+ */
+#if OPKG_OPK_USTAR_BB_EXACT_HEADER_
+ strcpy(ustar->header.magic, "ustar ");
+#endif
- strcpy(ustar->header.magic, "ustar");
- memcpy(ustar->header.version, "00", 2);
chksum = 0;
for (i = 0; i < sizeof(ustar->header.chksum); ++i) {
ustar->header.chksum[i] = ' ';
@@ -326,7 +346,17 @@ opkg_opk_ustar_write_header(struct opkg_opk_ustar *ustar,
for (i = 0; i < OPKG_OPK_USTAR_RECORD_SIZE; ++i) {
chksum += header_uc[i];
}
- sprintf(ustar->header.chksum, "%o", chksum);
+ /* See above about NUL-terminating and strtol() in opkg-lede. */
+ /* Since commit 5661fe078eed752780b11f3f4fdd33bbd76a6c5e, BB tar has
+ * filled chksum with "[6] digits, a null, then a space -- rather than
+ * digits, followed by a null like the other fields...". The maxiumum
+ * checksum is (255 x 512 = octal 377000), i.e. a maximum of 6 octal
+ * digits, so it doesn't matter whether we use 6 or 7 digits. */
+#if OPKG_OPK_USTAR_BB_EXACT_HEADER_
+ sprintf(ustar->header.chksum, "%06o", chksum);
+#else
+ sprintf(ustar->header.chksum, "%07o", chksum);
+#endif
if (opkg_opk_gzip_write(ustar->gzip, &ustar->header,
OPKG_OPK_USTAR_RECORD_SIZE) != OPKG_OPK_OK) {