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;
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);

View file

@ -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;

View file

@ -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();

View file

@ -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) {

View file

@ -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;