Improve zipos path handling (#579)

This change adds opendir, readdir, and stat support for the /zip/ root,
as well as directories not explicitly encoded in the zip file.
This commit is contained in:
Gavin Hayes 2022-09-04 01:50:23 -04:00 committed by GitHub
parent 494d74271b
commit 1ef955c33b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 10 deletions

View file

@ -326,6 +326,7 @@ static struct dirent *readdir_impl(DIR *dir) {
uint8_t *s, *p; uint8_t *s, *p;
struct Zipos *zip; struct Zipos *zip;
struct dirent *ent; struct dirent *ent;
struct dirent *lastent;
struct dirent_bsd *bsd; struct dirent_bsd *bsd;
struct dirent_netbsd *nbsd; struct dirent_netbsd *nbsd;
struct dirent_openbsd *obsd; struct dirent_openbsd *obsd;
@ -351,6 +352,20 @@ static struct dirent *readdir_impl(DIR *dir) {
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG; ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
memcpy(ent->d_name, s, ent->d_reclen); memcpy(ent->d_name, s, ent->d_reclen);
ent->d_name[ent->d_reclen] = 0; ent->d_name[ent->d_reclen] = 0;
} else {
lastent = (struct dirent *)dir->buf;
n = p - s;
n = MIN(n, 255);
if (!lastent->d_ino || (n != lastent->d_reclen) ||
memcmp(lastent->d_name, s, n)) {
ent = lastent;
ent->d_ino++;
ent->d_off = -1;
ent->d_reclen = n;
ent->d_type = DT_DIR;
memcpy(ent->d_name, s, ent->d_reclen);
ent->d_name[ent->d_reclen] = 0;
}
} }
} }
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset); dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);

View file

@ -28,6 +28,9 @@
ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) { ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) {
const char *zname; const char *zname;
size_t i, n, c, znamesize; size_t i, n, c, znamesize;
if (!name->len) {
return 0;
}
c = GetZipCdirOffset(zipos->cdir); c = GetZipCdirOffset(zipos->cdir);
n = GetZipCdirRecords(zipos->cdir); n = GetZipCdirRecords(zipos->cdir);
for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) { for (i = 0; i < n; ++i, c += ZIP_CFILE_HDRSIZE(zipos->map + c)) {
@ -38,6 +41,13 @@ ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) {
(name->len + 1 == znamesize && !memcmp(name->path, zname, name->len) && (name->len + 1 == znamesize && !memcmp(name->path, zname, name->len) &&
zname[name->len] == '/')) { zname[name->len] == '/')) {
return c; return c;
} else if ((name->len < znamesize &&
!memcmp(name->path, zname, name->len) &&
zname[name->len - 1] == '/') ||
(name->len + 1 < znamesize &&
!memcmp(name->path, zname, name->len) &&
zname[name->len] == '/')) {
return 0;
} }
} }
return -1; return -1;

View file

@ -16,9 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/zip.h" #include "libc/zip.h"
#include "libc/zipos/zipos.internal.h" #include "libc/zipos/zipos.internal.h"
@ -27,14 +28,18 @@ int __zipos_stat_impl(struct Zipos *zipos, size_t cf, struct stat *st) {
size_t lf; size_t lf;
if (zipos && st) { if (zipos && st) {
bzero(st, sizeof(*st)); bzero(st, sizeof(*st));
lf = GetZipCfileOffset(zipos->map + cf); if (cf) {
st->st_mode = GetZipCfileMode(zipos->map + cf); lf = GetZipCfileOffset(zipos->map + cf);
st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); st->st_mode = GetZipCfileMode(zipos->map + cf);
st->st_blocks = st->st_size = GetZipLfileUncompressedSize(zipos->map + lf);
roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; st->st_blocks =
GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim, roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512;
&st->st_ctim, 0); GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim,
st->st_birthtim = st->st_ctim; &st->st_ctim, 0);
st->st_birthtim = st->st_ctim;
} else {
st->st_mode = 0444 | S_IFDIR | 0111;
}
return 0; return 0;
} else { } else {
return einval(); return einval();

View file

@ -64,6 +64,10 @@ TEST(stat, zipos) {
stat("/zip/.python/test/" stat("/zip/.python/test/"
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt", "tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
&st)); &st));
EXPECT_SYS(0, 0, stat("/zip", &st));
EXPECT_SYS(0, 0, stat("/zip/", &st));
EXPECT_SYS(0, 0, stat("/zip/.python", &st));
EXPECT_SYS(0, 0, stat("/zip/.python/", &st));
} }
static long Stat(const char *path, struct stat *st) { static long Stat(const char *path, struct stat *st) {

View file

@ -20,9 +20,9 @@
#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/dirent.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/stdio/rand.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/dt.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
@ -57,6 +57,35 @@ TEST(opendir, enotdir) {
ASSERT_SYS(ENOTDIR, NULL, opendir("yo/there")); ASSERT_SYS(ENOTDIR, NULL, opendir("yo/there"));
} }
TEST(opendir, zipTest_fake) {
ASSERT_NE(NULL, (dir = opendir("/zip")));
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("echo", ent->d_name);
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("usr", ent->d_name);
EXPECT_EQ(NULL, (ent = readdir(dir)));
EXPECT_EQ(0, closedir(dir));
ASSERT_NE(NULL, (dir = opendir("/zip/")));
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("echo", ent->d_name);
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("usr", ent->d_name);
EXPECT_EQ(NULL, (ent = readdir(dir)));
EXPECT_EQ(0, closedir(dir));
ASSERT_NE(NULL, (dir = opendir("/zip/usr")));
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("share", ent->d_name);
EXPECT_EQ(NULL, (ent = readdir(dir)));
EXPECT_EQ(0, closedir(dir));
ASSERT_NE(NULL, (dir = opendir("/zip/usr/")));
EXPECT_NE(NULL, (ent = readdir(dir)));
EXPECT_STREQ("share", ent->d_name);
EXPECT_EQ(NULL, (ent = readdir(dir)));
EXPECT_EQ(0, closedir(dir));
EXPECT_EQ(NULL, (dir = opendir("/zip/us")));
EXPECT_EQ(NULL, (dir = opendir("/zip/us/")));
}
TEST(dirstream, testDots) { TEST(dirstream, testDots) {
int hasdot = 0; int hasdot = 0;
int hasdotdot = 0; int hasdotdot = 0;