Fix some zipos directory related bugs

This commit is contained in:
Justine Tunney 2023-09-18 22:17:56 -07:00
parent ec480f5aa0
commit ececec4c94
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
8 changed files with 114 additions and 30 deletions

View file

@ -16,6 +16,7 @@
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/kprintf.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/zipos.internal.h" #include "libc/runtime/zipos.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -23,6 +24,22 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/zip.internal.h" #include "libc/zip.internal.h"
static ssize_t __zipos_match(struct Zipos *z, struct ZiposUri *name, int len,
int i) {
size_t cfile = z->index[i];
const char *zname = ZIP_CFILE_NAME(z->map + cfile);
int zsize = ZIP_CFILE_NAMESIZE(z->map + cfile);
if ((len == zsize || (len + 1 == zsize && zname[len] == '/')) &&
!memcmp(name->path, zname, len)) {
return cfile;
} else if (len + 1 < zsize && zname[len] == '/' &&
!memcmp(name->path, zname, len)) {
return ZIPOS_SYNTHETIC_DIRECTORY;
} else {
return -1;
}
}
ssize_t __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) { ssize_t __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
// strip trailing slash from search name // strip trailing slash from search name
@ -61,17 +78,32 @@ ssize_t __zipos_scan(struct Zipos *zipos, struct ZiposUri *name) {
} }
} }
// return pointer to leftmost record if it matches
if (l < zipos->records) { if (l < zipos->records) {
int dx;
size_t cfile = zipos->index[l]; size_t cfile = zipos->index[l];
const char *zname = ZIP_CFILE_NAME(zipos->map + cfile); const char *zname = ZIP_CFILE_NAME(zipos->map + cfile);
int zsize = ZIP_CFILE_NAMESIZE(zipos->map + cfile); int zsize = ZIP_CFILE_NAMESIZE(zipos->map + cfile);
if ((len == zsize || (len + 1 == zsize && zname[len] == '/')) && if (zsize > len && (dx = '/' - (zname[len] & 255))) {
!memcmp(name->path, zname, len)) { // since the index is asciibetical, we need to specially handle
return cfile; // the case where, when searching for a directory, regular files
} else if (len + 1 < zsize && zname[len] == '/' && // exist whose names share the same prefix as the directory name.
!memcmp(name->path, zname, len)) { dx = dx > +1 ? +1 : dx;
return ZIPOS_SYNTHETIC_DIRECTORY; dx = dx < -1 ? -1 : dx;
for (l += dx; 0 <= l && l < zipos->records; l += dx) {
ssize_t cf;
if ((cf = __zipos_match(zipos, name, len, l)) != -1) {
return cf;
}
cfile = zipos->index[l];
zname = ZIP_CFILE_NAME(zipos->map + cfile);
zsize = ZIP_CFILE_NAMESIZE(zipos->map + cfile);
if (zsize < len || (len && zname[len - 1] != name->path[len - 1])) {
break;
}
}
} else {
// otherwise just return pointer to leftmost record if it matches
return __zipos_match(zipos, name, len, l);
} }
} }

View file

@ -62,8 +62,7 @@ static void __zipos_dismiss(uint8_t *map, const uint8_t *cdir, long pg) {
mo = ROUNDDOWN(lo, FRAMESIZE); mo = ROUNDDOWN(lo, FRAMESIZE);
if (mo) munmap(map, mo); if (mo) munmap(map, mo);
// this is supposed to reduce our rss usage but does it // this is supposed to reduce our rss usage but does it really?
pg = getauxval(AT_PAGESZ);
lo = ROUNDDOWN(lo, pg); lo = ROUNDDOWN(lo, pg);
hi = MIN(ROUNDUP(hi, pg), ROUNDDOWN(c, pg)); hi = MIN(ROUNDUP(hi, pg), ROUNDDOWN(c, pg));
if (hi > lo) { if (hi > lo) {

View file

@ -948,7 +948,7 @@ static textwindows int sock_update(struct PortState *port_state,
updated event mask. */ updated event mask. */
} else if (sock_state->poll_status == kPollPending) { } else if (sock_state->poll_status == kPollPending) {
/* A poll operation is already pending, but it's not monitoring for /* A poll operation is already pending, but it's not monitoring for
all the *events that the user is interested in .Therefore, cancel all the *events that the user is interested in. Therefore, cancel
the pending *poll operation; when we receive it's completion the pending *poll operation; when we receive it's completion
package, a new poll *operation will be submitted with the correct package, a new poll *operation will be submitted with the correct
event mask. */ event mask. */

View file

@ -404,16 +404,22 @@ static struct dirent *readdir_zipos(DIR *dir) {
s += dir->zip.prefix.len; s += dir->zip.prefix.len;
n -= dir->zip.prefix.len; n -= dir->zip.prefix.len;
const char *p = memchr(s, '/', n); const char *p = memchr(s, '/', n);
if (p) n = p - s; int d_type;
if (p) {
n = p - s;
d_type = DT_DIR;
} else if (S_ISDIR(GetZipCfileMode(dir->zip.zipos->map +
dir->zip.offset))) {
d_type = DT_DIR;
} else {
d_type = DT_REG;
}
if ((n = MIN(n, sizeof(ent->d_name) - 1)) && if ((n = MIN(n, sizeof(ent->d_name) - 1)) &&
critbit0_emplace(&dir->zip.found, s, n) == 1) { critbit0_emplace(&dir->zip.found, s, n) == 1) {
ent = &dir->ent; ent = &dir->ent;
ent->d_ino = dir->zip.offset; ent->d_ino = dir->zip.offset;
ent->d_off = dir->tell; ent->d_off = dir->tell;
ent->d_type = ent->d_type = d_type;
S_ISDIR(GetZipCfileMode(dir->zip.zipos->map + dir->zip.offset))
? DT_DIR
: DT_REG;
memcpy(ent->d_name, s, n); memcpy(ent->d_name, s, n);
ent->d_name[n] = 0; ent->d_name[n] = 0;
} }

1
libc/testlib-test.txt Normal file
View file

@ -0,0 +1 @@
ignore this file

View file

@ -87,7 +87,8 @@ LIBC_TESTLIB_A_SRCS = \
LIBC_TESTLIB_A_OBJS = \ LIBC_TESTLIB_A_OBJS = \
$(LIBC_TESTLIB_A_SRCS_C:%.c=o/$(MODE)/%.o) \ $(LIBC_TESTLIB_A_SRCS_C:%.c=o/$(MODE)/%.o) \
$(LIBC_TESTLIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \ $(LIBC_TESTLIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_TESTLIB_A_ASSETS:%=o/$(MODE)/%.zip.o) $(LIBC_TESTLIB_A_ASSETS:%=o/$(MODE)/%.zip.o) \
o/$(MODE)/libc/testlib-test.txt.zip.o
LIBC_TESTLIB_A_DIRECTDEPS = \ LIBC_TESTLIB_A_DIRECTDEPS = \
LIBC_CALLS \ LIBC_CALLS \

View file

@ -16,6 +16,7 @@
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/calls/calls.h"
#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -28,48 +29,99 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/s.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
__static_yoink("zipos"); __static_yoink("zipos");
__static_yoink("libc/testlib/hyperion.txt"); __static_yoink("libc/testlib/hyperion.txt");
__static_yoink("libc/testlib/moby.txt"); __static_yoink("libc/testlib/moby.txt");
__static_yoink("libc/testlib-test.txt");
__static_yoink("usr/share/zoneinfo/");
__static_yoink("usr/share/zoneinfo/New_York"); __static_yoink("usr/share/zoneinfo/New_York");
DIR *dir; DIR *dir;
struct dirent *ent; struct dirent *ent;
TEST(zipdir, test) { TEST(zipdir, testDirectoryThatHasRealZipEntry) {
const char *path = "/zip/libc/testlib///"; const char *path = "/zip/libc/testlib///";
ASSERT_NE(NULL, (dir = opendir(path))); ASSERT_NE(NULL, (dir = opendir(path)));
ASSERT_EQ(0, telldir(dir)); ASSERT_EQ(0, telldir(dir));
ASSERT_NE(NULL, (ent = readdir(dir))); ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_EQ(0, strcmp(ent->d_name, ".")); ASSERT_STREQ(".", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type); ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir))); ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_EQ(0, strcmp(ent->d_name, "..")); ASSERT_STREQ("..", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type); ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir))); ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_EQ(0, strcmp(ent->d_name, "hyperion.txt")); ASSERT_STREQ("hyperion.txt", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type); ASSERT_EQ(DT_REG, ent->d_type);
long pos = telldir(dir); long pos = telldir(dir);
ASSERT_NE(NULL, (ent = readdir(dir))); ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_EQ(0, strcmp(ent->d_name, "moby.txt")); ASSERT_STREQ("moby.txt", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type); ASSERT_EQ(DT_REG, ent->d_type);
ASSERT_EQ(NULL, (ent = readdir(dir))); ASSERT_EQ(NULL, (ent = readdir(dir)));
seekdir(dir, pos); seekdir(dir, pos);
ASSERT_NE(NULL, (ent = readdir(dir))); ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_EQ(0, strcmp(ent->d_name, "moby.txt")); ASSERT_STREQ("moby.txt", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type); ASSERT_EQ(DT_REG, ent->d_type);
ASSERT_EQ(NULL, (ent = readdir(dir))); ASSERT_EQ(NULL, (ent = readdir(dir)));
ASSERT_EQ(NULL, (ent = readdir(dir))); ASSERT_EQ(NULL, (ent = readdir(dir)));
ASSERT_SYS(0, 0, closedir(dir)); ASSERT_SYS(0, 0, closedir(dir));
} }
TEST(zipdir, testDirectoryWithSyntheticOrMissingEntry) {
const char *path = "/zip/libc/";
ASSERT_NE(NULL, (dir = opendir(path)));
ASSERT_EQ(0, telldir(dir));
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ(".", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("..", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("testlib", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("testlib-test.txt", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type);
ASSERT_EQ(NULL, (ent = readdir(dir)));
ASSERT_SYS(0, 0, closedir(dir));
}
TEST(zipdir, testListZip) {
const char *path = "/zip";
ASSERT_NE(NULL, (dir = opendir(path)));
ASSERT_EQ(0, telldir(dir));
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ(".", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("..", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("echo.com", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("libc", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ("usr", ent->d_name);
ASSERT_EQ(DT_DIR, ent->d_type);
ASSERT_NE(NULL, (ent = readdir(dir)));
ASSERT_STREQ(".cosmo", ent->d_name);
ASSERT_EQ(DT_REG, ent->d_type);
ASSERT_EQ(NULL, (ent = readdir(dir)));
ASSERT_SYS(0, 0, closedir(dir));
}
TEST(dirstream, hasDirectoryEntry) { TEST(dirstream, hasDirectoryEntry) {
struct stat st; struct stat st;
bool gotsome = false; bool gotsome = false;
const char *path = "/zip/usr/share/zoneinfo"; const char *path = "/zip/usr/share/zoneinfo";
ASSERT_SYS(0, 0, fstatat(AT_FDCWD, path, &st, 0)); ASSERT_SYS(0, 0, fstatat(AT_FDCWD, path, &st, 0));
ASSERT_TRUE(S_ISDIR(st.st_mode));
ASSERT_NE(NULL, (dir = opendir(path))); ASSERT_NE(NULL, (dir = opendir(path)));
while ((ent = readdir(dir))) { while ((ent = readdir(dir))) {
gotsome = true; gotsome = true;

View file

@ -172,15 +172,8 @@ int mbedtls_test_write(const char *fmt, ...) {
n = vfprintf(stderr, fmt, va); n = vfprintf(stderr, fmt, va);
} else { } else {
char buf[512]; char buf[512];
const char *s;
vsnprintf(buf, 512, fmt, va); vsnprintf(buf, 512, fmt, va);
if ((s = strchr(buf, '\n')) && // n = appends(&output, buf);
s == buf + strlen(buf) - 1 && //
strstr(buf, "PASS")) {
n = 0; // ignore pointless success lines
} else {
n = appends(&output, buf);
}
} }
va_end(va); va_end(va);
return n; return n;