cosmopolitan/libc/str/getzipcfiletimestamps.c
Justine Tunney 4a59210008
Introduce #include <cosmo.h> to toolchain users
This change improves the way internal APIs are being hidden behind the
`COSMO` define. The cosmo.h header will take care of defining that, so
that a separate define statement isn't needed. This change also does a
lot more to define which APIs are standard, and which belong to Cosmo.
2023-06-09 18:03:05 -07:00

102 lines
5 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/fmt/conv.h"
#include "libc/zip.internal.h"
static inline int pop(int x) {
return !!(x & 1) + !!(x & 2) + !!(x & 4);
}
/**
* Extracts modified/access/creation timestamps from zip entry.
*
* @param cf is pointer to central directory header for file
* @param mtim optionally receives last modified timestamp
* @param atim optionally receives modified timestamp
* @param ctim optionally receives creation timestamp
* @param gmtoff is seconds adjustment for legacy dos timestamps
*/
void GetZipCfileTimestamps(const uint8_t *cf, struct timespec *mtim,
struct timespec *atim, struct timespec *ctim,
int gmtoff) {
const uint8_t *p, *pe;
if (mtim) *mtim = (struct timespec){0};
if (atim) *atim = (struct timespec){0};
if (ctim) *ctim = (struct timespec){0};
for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
p += ZIP_EXTRA_SIZE(p)) {
if (ZIP_EXTRA_HEADERID(p) == kZipExtraNtfs &&
ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 &&
READ16LE(ZIP_EXTRA_CONTENT(p) + 4) == 1 &&
READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 8) {
if (mtim) {
*mtim = WindowsTimeToTimeSpec(READ64LE(ZIP_EXTRA_CONTENT(p) + 8));
}
if (atim && ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 2 &&
READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 16) {
*atim = WindowsTimeToTimeSpec(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 2));
}
if (ctim && ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4 + 8 * 3 &&
READ16LE(ZIP_EXTRA_CONTENT(p) + 6) >= 24) {
*ctim = WindowsTimeToTimeSpec(READ64LE(ZIP_EXTRA_CONTENT(p) + 8 * 3));
}
return;
}
}
for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
p += ZIP_EXTRA_SIZE(p)) {
if (ZIP_EXTRA_HEADERID(p) == kZipExtraExtendedTimestamp &&
ZIP_EXTRA_CONTENTSIZE(p) > 1 &&
ZIP_EXTRA_CONTENTSIZE(p) == 1 + 4 * pop(*ZIP_EXTRA_CONTENT(p) & 7)) {
if (mtim) {
if (*ZIP_EXTRA_CONTENT(p) & 1) {
mtim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1);
} else {
mtim->tv_sec = DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(cf),
ZIP_CFILE_LASTMODIFIEDTIME(cf)) -
gmtoff;
}
}
if (atim && (*ZIP_EXTRA_CONTENT(p) & 2)) {
atim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
4 * (*ZIP_EXTRA_CONTENT(p) & 1));
}
if (ctim && (*ZIP_EXTRA_CONTENT(p) & 4)) {
ctim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 1 +
4 * pop(*ZIP_EXTRA_CONTENT(p) & 3));
}
return;
}
}
for (p = ZIP_CFILE_EXTRA(cf), pe = p + ZIP_CFILE_EXTRASIZE(cf); p + 4 <= pe;
p += ZIP_EXTRA_SIZE(p)) {
if (ZIP_EXTRA_HEADERID(p) == kZipExtraUnix &&
ZIP_EXTRA_CONTENTSIZE(p) >= 4 + 4) {
if (atim) atim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 0);
if (mtim) mtim->tv_sec = (int32_t)READ32LE(ZIP_EXTRA_CONTENT(p) + 4);
return;
}
}
if (mtim) {
mtim->tv_sec = DosDateTimeToUnix(ZIP_CFILE_LASTMODIFIEDDATE(cf),
ZIP_CFILE_LASTMODIFIEDTIME(cf)) -
gmtoff;
}
}