diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index 4b7aeb7e7..6a62df49c 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -326,6 +326,7 @@ static struct dirent *readdir_impl(DIR *dir) { uint8_t *s, *p; struct Zipos *zip; struct dirent *ent; + struct dirent *lastent; struct dirent_bsd *bsd; struct dirent_netbsd *nbsd; 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; memcpy(ent->d_name, s, ent->d_reclen); 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); diff --git a/libc/zipos/find.c b/libc/zipos/find.c index df5ab4f15..48cbb9820 100644 --- a/libc/zipos/find.c +++ b/libc/zipos/find.c @@ -28,6 +28,9 @@ ssize_t __zipos_find(struct Zipos *zipos, const struct ZiposUri *name) { const char *zname; size_t i, n, c, znamesize; + if (!name->len) { + return 0; + } c = GetZipCdirOffset(zipos->cdir); n = GetZipCdirRecords(zipos->cdir); 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) && zname[name->len] == '/')) { 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; diff --git a/libc/zipos/stat-impl.c b/libc/zipos/stat-impl.c index 54b7ec3c8..0b98c3491 100644 --- a/libc/zipos/stat-impl.c +++ b/libc/zipos/stat-impl.c @@ -16,9 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/safemacros.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/intrin/safemacros.internal.h" #include "libc/str/str.h" +#include "libc/sysv/consts/s.h" #include "libc/sysv/errfuns.h" #include "libc/zip.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; if (zipos && st) { bzero(st, sizeof(*st)); - lf = GetZipCfileOffset(zipos->map + cf); - st->st_mode = GetZipCfileMode(zipos->map + cf); - st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); - st->st_blocks = - roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; - GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim, - &st->st_ctim, 0); - st->st_birthtim = st->st_ctim; + if (cf) { + lf = GetZipCfileOffset(zipos->map + cf); + st->st_mode = GetZipCfileMode(zipos->map + cf); + st->st_size = GetZipLfileUncompressedSize(zipos->map + lf); + st->st_blocks = + roundup(GetZipLfileCompressedSize(zipos->map + lf), 512) / 512; + GetZipCfileTimestamps(zipos->map + cf, &st->st_mtim, &st->st_atim, + &st->st_ctim, 0); + st->st_birthtim = st->st_ctim; + } else { + st->st_mode = 0444 | S_IFDIR | 0111; + } return 0; } else { return einval(); diff --git a/test/libc/calls/stat_test.c b/test/libc/calls/stat_test.c index cd66edc11..ec29205ce 100644 --- a/test/libc/calls/stat_test.c +++ b/test/libc/calls/stat_test.c @@ -64,6 +64,10 @@ TEST(stat, zipos) { stat("/zip/.python/test/" "tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt", &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) { diff --git a/test/libc/stdio/dirstream_test.c b/test/libc/stdio/dirstream_test.c index 80ee0b000..c3ea5d5bd 100644 --- a/test/libc/stdio/dirstream_test.c +++ b/test/libc/stdio/dirstream_test.c @@ -20,9 +20,9 @@ #include "libc/calls/struct/dirent.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/stdio/rand.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" +#include "libc/stdio/rand.h" #include "libc/str/str.h" #include "libc/sysv/consts/dt.h" #include "libc/testlib/testlib.h" @@ -57,6 +57,35 @@ TEST(opendir, enotdir) { 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) { int hasdot = 0; int hasdotdot = 0;