From f4298f10c2155b10e6d8d94f83afae7e529e497a Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 1 Mar 2021 06:24:11 -0800 Subject: [PATCH] Generate ZIP files the same way as Windows --- ape/ape.lds | 14 +++++--- build/bootstrap/zipobj.com | Bin 126976 -> 122376 bytes libc/nexgen32e/zip.S | 4 +-- libc/str/zipfindcentraldir.c | 38 ++++++++++++++------ libc/zip.h | 4 +-- libc/zipos/find.c | 1 + libc/zipos/get.c | 25 ++++++++----- test/libc/release/emulate.sh | 2 +- test/libc/release/metal.sh | 2 +- test/libc/str/undeflate_test.c | 1 - tool/build/zipobj.c | 64 ++++++++++++++++++++++++++------- 11 files changed, 112 insertions(+), 43 deletions(-) diff --git a/ape/ape.lds b/ape/ape.lds index 1d9cf917a..4d8695d37 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -364,13 +364,18 @@ SECTIONS { PROVIDE_HIDDEN(edata = .); } :Ram +/*END: file content that's loaded by o/s */ +/*BEGIN: bss memory void */ + .zip . : { KEEP(*(SORT_BY_NAME(.zip.*))) - . = ALIGN(PAGESIZE); - HIDDEN(_efile = .); + HIDDEN(_ezip = .); } - .bss . : { +/*END: file content */ +/*BEGIN: bss memory that's addressable */ + + .bss ALIGN(__SIZEOF_POINTER__) : { KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) *(.piro.bss) KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) @@ -540,8 +545,9 @@ HIDDEN(v_ape_highsectors = #define ZIPCONST(NAME, VAL) HIDDEN(NAME = DEFINED(__zip_start) ? VAL : 0); ZIPCONST(v_zip_cdoffset, __zip_start - IMAGE_BASE_VIRTUAL); ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start); +ASSERT(v_zip_cdirsize % kZipCdirHdrLinkableSize == 0, "bad zip cdir"); ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize); -ZIPCONST(v_zip_commentsize, _efile - __zip_end - kZipCdirHdrMinSize); +ZIPCONST(v_zip_commentsize, _ezip - __zip_end - kZipCdirHdrMinSize); #if SupportsXnu() /* Generates deterministic ID. */ diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com index 7c31177b534d5471e018265255ec63e2da8034c4..c9361bf7a8085e28f49071d0776faf0ca96b60d1 100755 GIT binary patch delta 23939 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 AU;qFB diff --git a/libc/nexgen32e/zip.S b/libc/nexgen32e/zip.S index 0d3778770..ba51602f0 100644 --- a/libc/nexgen32e/zip.S +++ b/libc/nexgen32e/zip.S @@ -25,19 +25,17 @@ .hidden __zip_start .globl __zip_start .type __zip_start,@object - .align kZipCdirAlign __zip_start: .previous/* ... decentralized content ... */.section .zip.5,"",@progbits - .align kZipCdirAlign __zip_end: .long kZipCdirHdrMagic # magic .short 0 # disk .short 0 # starting disk - .short v_zip_records # records on disk + .short v_zip_records # number of records on disk .short v_zip_records # records .long v_zip_cdirsize # size of central directory .long RVA(__zip_start) # central directory offset diff --git a/libc/str/zipfindcentraldir.c b/libc/str/zipfindcentraldir.c index 13a76cc86..431a75ea1 100644 --- a/libc/str/zipfindcentraldir.c +++ b/libc/str/zipfindcentraldir.c @@ -18,16 +18,34 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/zip.h" -uint8_t *zipfindcentraldir(const uint8_t *map, size_t mapsize) { - const uint8_t *p, *pe; - for (p = map + mapsize - kZipCdirHdrMinSize, - pe = mapsize > 65536 + kZipCdirHdrMinSize - ? map + mapsize - 65536 - kZipCdirHdrMinSize - : map; - p >= pe; --p) { - if (ZIP_CDIR_MAGIC(p) == kZipCdirHdrMagic) { - return (/*unconst*/ uint8_t *)p; - } +/** + * Locates End Of Central Directory record in ZIP file. + * + * We search backwards for the End Of Central Directory Record magnum. + * The ZIP spec says this can be anywhere in the last 64kb. We go all + * the way since .com.dbg binaries will have lots of DWARF stuff after + * the embedded .com binary. As such, we sanity check the other fields + * too to make sure the record seems legit and it's not just a random + * occurrence of the magnum. + * + * @param p points to file memory + * @param n is byte size of file + */ +uint8_t *zipfindcentraldir(const uint8_t *p, size_t n) { + size_t i; + if (n >= kZipCdirHdrMinSize) { + i = n - kZipCdirHdrMinSize; + do { + if (ZIP_CDIR_MAGIC(p + i) == kZipCdirHdrMagic && + i + ZIP_CDIR_HDRSIZE(p + i) <= n && + ZIP_CDIR_DISK(p + i) == ZIP_CDIR_STARTINGDISK(p + i) && + ZIP_CDIR_RECORDSONDISK(p + i) == ZIP_CDIR_RECORDS(p + i) && + ZIP_CDIR_RECORDS(p + i) * kZipCdirHdrMinSize <= + ZIP_CDIR_SIZE(p + i) && + ZIP_CDIR_OFFSET(p + i) + ZIP_CDIR_SIZE(p + i) <= i) { + return (/*unconst*/ uint8_t *)(p + i); + } + } while (i--); } return NULL; } diff --git a/libc/zip.h b/libc/zip.h index c7d5ae971..00946f118 100644 --- a/libc/zip.h +++ b/libc/zip.h @@ -10,7 +10,7 @@ #define kZipAlign 2 -#define kZipCosmopolitanVersion 1 +#define kZipCosmopolitanVersion 20 #define kZipOsDos 0 #define kZipOsAmiga 1 @@ -45,7 +45,7 @@ #define kZipCdirHdrMagic 0x06054b50 /* PK♣♠ "PK\5\6" */ #define kZipCdirHdrMinSize 22 -#define kZipCdirAlign 64 /* our choice; actually 2 */ +#define kZipCdirAlign kZipAlign #define kZipCdirHdrLinkableSize \ ROUNDUP(kZipCfileHdrMinSize + PATH_MAX, kZipCdirAlign) diff --git a/libc/zipos/find.c b/libc/zipos/find.c index e38571305..fa7d7a0ee 100644 --- a/libc/zipos/find.c +++ b/libc/zipos/find.c @@ -29,6 +29,7 @@ ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) { for (i = 0, cf = ZIP_CDIR_OFFSET(zipos->cdir); i < ZIP_CDIR_RECORDS(zipos->cdir); ++i, cf += ZIP_CFILE_HDRSIZE(zipos->map + cf)) { + if (ZIP_CFILE_MAGIC(zipos->map + cf) != kZipCfileHdrMagic) DebugBreak(); assert(ZIP_CFILE_MAGIC(zipos->map + cf) == kZipCfileHdrMagic); if (name->len == ZIP_CFILE_NAMESIZE(zipos->map + cf) && memcmp(name->path, ZIP_CFILE_NAME(zipos->map + cf), name->len) == 0) { diff --git a/libc/zipos/get.c b/libc/zipos/get.c index b9ae10473..985ef310b 100644 --- a/libc/zipos/get.c +++ b/libc/zipos/get.c @@ -21,6 +21,7 @@ #include "libc/calls/struct/stat.h" #include "libc/limits.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" @@ -36,9 +37,8 @@ struct Zipos *__zipos_get(void) { static bool once; const char *exe, *dir; char path[PATH_MAX]; - size_t mapsize; - uint8_t *cdir; - void *map; + size_t size; + uint8_t *map, *base, *cdir; if (!once) { dir = nulltoempty(getenv("PWD")); /* suboptimal */ exe = (const char *)getauxval(AT_EXECFN); @@ -47,14 +47,23 @@ struct Zipos *__zipos_get(void) { exe = path; } if ((zipos.fd = open(exe, O_RDONLY)) != -1) { - if ((mapsize = getfiledescriptorsize(zipos.fd)) != SIZE_MAX && - (map = mmap(NULL, mapsize, PROT_READ, MAP_SHARED, zipos.fd, 0)) != + if ((size = getfiledescriptorsize(zipos.fd)) != SIZE_MAX && + (map = mmap(NULL, size, PROT_READ, MAP_SHARED, zipos.fd, 0)) != MAP_FAILED) { - if ((cdir = zipfindcentraldir(map, mapsize))) { - zipos.map = map; + if (endswith(exe, ".com.dbg")) { + if ((base = memmem(map, size, "MZqFpD", 6))) { + size -= base - map; + } else { + base = map; + } + } else { + base = map; + } + if ((cdir = zipfindcentraldir(base, size))) { + zipos.map = base; zipos.cdir = cdir; } else { - munmap(map, mapsize); + munmap(map, size); } } } diff --git a/test/libc/release/emulate.sh b/test/libc/release/emulate.sh index 99b7c2b25..9b3457f0c 100755 --- a/test/libc/release/emulate.sh +++ b/test/libc/release/emulate.sh @@ -1,6 +1,6 @@ #!/bin/sh -if [ $MODE = dbg ]; then +if [ "$MODE" = dbg ]; then exit # TODO fi diff --git a/test/libc/release/metal.sh b/test/libc/release/metal.sh index 21ab566ac..e12edee59 100755 --- a/test/libc/release/metal.sh +++ b/test/libc/release/metal.sh @@ -1,6 +1,6 @@ #!/bin/sh -if [ $MODE = dbg ]; then +if [ "$MODE" = dbg ]; then exit # TODO fi diff --git a/test/libc/str/undeflate_test.c b/test/libc/str/undeflate_test.c index fd7664b0f..c368e0095 100644 --- a/test/libc/str/undeflate_test.c +++ b/test/libc/str/undeflate_test.c @@ -93,7 +93,6 @@ TEST(undeflate, testEmbeddedCompressedZipFile_theHardWay) { ASSERT_GE(ZIP_CDIR_RECORDS(cd), 1); for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < ZIP_CDIR_RECORDS(cd); ++i, cf += ZIP_CFILE_HDRSIZE(cf)) { - fprintf(stderr, "%.*s\n", ZIP_CFILE_NAMESIZE(cf), ZIP_CFILE_NAME(cf)); if (strncmp("libc/testlib/hyperion.txt", ZIP_CFILE_NAME(cf), ZIP_CFILE_NAMESIZE(cf)) == 0) { lf = map + ZIP_CFILE_OFFSET(cf); diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index 76c842ec2..c0fbfb0b6 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -60,6 +60,10 @@ #define PUT32(P, V) \ P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P[2] = V >> 020 & 0xff, \ P[3] = V >> 030 & 0xff, P += 4 +#define PUT64(P, V) \ + P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P[2] = V >> 020 & 0xff, \ + P[3] = V >> 030 & 0xff, P[4] = V >> 040 & 0xff, P[5] = V >> 050 & 0xff, \ + P[6] = V >> 060 & 0xff, P[7] = V >> 070 & 0xff, P += 8 #define DOS_DATE(YEAR, MONTH_IDX1, DAY_IDX1) \ (((YEAR)-1980) << 9 | (MONTH_IDX1) << 5 | (DAY_IDX1)) @@ -149,7 +153,7 @@ static unsigned char *EmitZipLfileHdr(unsigned char *op, const void *name, uint16_t mdate, size_t compsize, size_t uncompsize) { PUT32(op, kZipLfileHdrMagic); - PUT8(op, era); + PUT8(op, kZipEra1993); PUT8(op, kZipOsDos); PUT16(op, gflags); PUT16(op, method); @@ -168,28 +172,60 @@ static void EmitZipCdirHdr(unsigned char *op, const void *name, size_t namesize, uint16_t method, uint16_t mtime, uint16_t mdate, uint16_t iattrs, uint16_t dosmode, uint16_t unixmode, size_t compsize, size_t uncompsize, - size_t commentsize) { + size_t commentsize, struct stat *st) { + uint64_t mt, at, ct; PUT32(op, kZipCfileHdrMagic); - PUT8(op, kZipCosmopolitanVersion); - PUT8(op, kZipOsUnix); - PUT8(op, era); + PUT8(op, 20); + PUT8(op, kZipOsDos); + PUT8(op, kZipEra1993); PUT8(op, kZipOsDos); PUT16(op, gflags); PUT16(op, method); PUT16(op, mtime); PUT16(op, mdate); + /* 16 */ PUT32(op, crc); PUT32(op, compsize); PUT32(op, uncompsize); PUT16(op, namesize); +#if 0 +#define CFILE_HDR_SIZE kZipCfileHdrMinSize PUT16(op, 0); /* extra size */ + /* 32 */ PUT16(op, commentsize); PUT16(op, 0); /* disk */ PUT16(op, iattrs); PUT16(op, dosmode); PUT16(op, unixmode); PUT32(op, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */ + /* 46 */ memcpy(op, name, namesize); +#else +#define CFILE_HDR_SIZE (kZipCfileHdrMinSize + 36) + PUT16(op, 36); /* extra size */ + /* 32 */ + PUT16(op, commentsize); + PUT16(op, 0); /* disk */ + PUT16(op, iattrs); + PUT32(op, dosmode); + PUT32(op, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */ + /* 46 */ + memcpy(op, name, namesize); + op += namesize; + PUT16(op, kZipExtraNtfs); + PUT16(op, 32); + PUT32(op, 0); + PUT16(op, 1); + PUT16(op, 24); +#define NTTIME(t) \ + (t.tv_sec + MODERNITYSECONDS) * HECTONANOSECONDS + t.tv_nsec / 100 + mt = NTTIME(st->st_mtim); + at = NTTIME(st->st_atim); + ct = NTTIME(st->st_ctim); + PUT64(op, mt); + PUT64(op, at); + PUT64(op, ct); +#endif } void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, @@ -209,7 +245,7 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, crc = crc32_z(0, data, uncompsize); GetDosLocalTime(st->st_mtim.tv_sec, &mtime, &mdate); gflags = IsPureAscii(name, namesize) ? 0 : kZipGflagUtf8; - commentsize = kZipCdirHdrLinkableSize - (kZipCfileHdrMinSize + namesize); + commentsize = kZipCdirHdrLinkableSize - (CFILE_HDR_SIZE + namesize); iattrs = IsPureAscii(data, st->st_size) ? kZipIattrAscii : kZipIattrBinary; dosmode = !(st->st_mode & 0200) ? kNtFileAttributeReadonly : 0; method = (st->st_size >= kMinCompressSize && ShouldCompress(name, namesize)) @@ -217,9 +253,10 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, : kZipCompressionNone; /* emit embedded file content w/ pkzip local file header */ - elfwriter_align(elf, kZipCdirAlign, 0); - elfwriter_startsection( - elf, gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)), SHT_PROGBITS, 0); + elfwriter_align(elf, 1, 0); + elfwriter_startsection(elf, + gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)), + SHT_PROGBITS, SHF_ALLOC); if (method == kZipCompressionDeflate) { CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)), Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, @@ -255,12 +292,13 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize, elfwriter_finishsection(elf); /* emit central directory record */ - elfwriter_align(elf, kZipCdirAlign, 0); - elfwriter_startsection( - elf, gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)), SHT_PROGBITS, 0); + elfwriter_align(elf, 1, 0); + elfwriter_startsection(elf, + gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)), + SHT_PROGBITS, SHF_ALLOC); EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)), name, namesize, crc, era, gflags, method, mtime, mdate, iattrs, - dosmode, st->st_mode, compsize, uncompsize, commentsize); + dosmode, st->st_mode, compsize, uncompsize, commentsize, st); elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+cdir:", name)), ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0, kZipCdirHdrLinkableSize);