Make improvements
- Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader - Whipped up a webserver named redbean. It services 150k requests per second on a single core. Bundling assets inside zip enables extremely fast serving for two reasons. The first is that zip central directory lookups go faster than stat() system calls. The second is that both zip and gzip content-encoding use DEFLATE, therefore, compressed responses can be served via the sendfile() system call which does an in-kernel copy directly from the zip executable structure. Also note that red bean zip executables can be deployed easily to all platforms, since these native executables work on Linux, Mac, BSD, and Windows. - Address sanitizer now works very well
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/win32finddata.h"
|
||||
@@ -31,9 +33,18 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct dirent$freebsd {
|
||||
uint32_t d_fileno;
|
||||
uint16_t d_reclen;
|
||||
uint8_t d_type;
|
||||
uint8_t d_namlen;
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
struct dirstream {
|
||||
int64_t tell;
|
||||
int64_t fd;
|
||||
struct dirent ent;
|
||||
union {
|
||||
struct {
|
||||
unsigned buf_pos;
|
||||
@@ -41,8 +52,6 @@ struct dirstream {
|
||||
char buf[BUFSIZ];
|
||||
};
|
||||
struct {
|
||||
struct dirent winent;
|
||||
char __d_name[PATH_MAX];
|
||||
bool isdone;
|
||||
struct NtWin32FindData windata;
|
||||
};
|
||||
@@ -71,17 +80,60 @@ static textwindows noinline DIR *opendir$nt(const char *name) {
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows noinline struct dirent *readdir$nt(DIR *dir) {
|
||||
if (!dir->isdone) {
|
||||
memset(&dir->ent, 0, sizeof(dir->ent));
|
||||
dir->ent.d_ino = 0;
|
||||
dir->ent.d_off = dir->tell++;
|
||||
dir->ent.d_reclen = sizeof(dir->ent) +
|
||||
tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name),
|
||||
dir->windata.cFileName) +
|
||||
1;
|
||||
switch (dir->windata.dwFileType) {
|
||||
case kNtFileTypeDisk:
|
||||
dir->ent.d_type = DT_BLK;
|
||||
break;
|
||||
case kNtFileTypeChar:
|
||||
dir->ent.d_type = DT_CHR;
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
dir->ent.d_type = DT_FIFO;
|
||||
break;
|
||||
default:
|
||||
if (dir->windata.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
dir->ent.d_type = DT_DIR;
|
||||
} else {
|
||||
dir->ent.d_type = DT_REG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dir->isdone = !FindNextFile(dir->fd, &dir->windata);
|
||||
return &dir->ent;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens directory so readdir() and closedir() may be called.
|
||||
* Opens directory, e.g.
|
||||
*
|
||||
* DIR *d;
|
||||
* struct dirent *e;
|
||||
* CHECK((d = opendir(path)));
|
||||
* while ((e = readdir(d))) {
|
||||
* printf("%s/%s\n", path, e->d_name);
|
||||
* }
|
||||
* LOGIFNEG1(closedir(d));
|
||||
*
|
||||
* @returns newly allocated DIR object, or NULL w/ errno
|
||||
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
|
||||
* @see glob()
|
||||
*/
|
||||
DIR *opendir(const char *name) {
|
||||
int fd;
|
||||
DIR *res;
|
||||
if (!IsWindows() && !IsXnu()) {
|
||||
int fd;
|
||||
DIR *res = NULL;
|
||||
res = NULL;
|
||||
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) {
|
||||
if (!(res = fdopendir(fd))) close(fd);
|
||||
}
|
||||
@@ -103,8 +155,8 @@ DIR *opendir(const char *name) {
|
||||
* @errors ENOMEM and fd is closed
|
||||
*/
|
||||
DIR *fdopendir(int fd) {
|
||||
DIR *dir;
|
||||
if (!IsWindows() && !IsXnu()) {
|
||||
DIR *dir;
|
||||
if ((dir = calloc(1, sizeof(*dir)))) {
|
||||
dir->fd = fd;
|
||||
return dir;
|
||||
@@ -125,35 +177,36 @@ DIR *fdopendir(int fd) {
|
||||
* differentiated by setting errno to 0 beforehand
|
||||
*/
|
||||
struct dirent *readdir(DIR *dir) {
|
||||
int rc;
|
||||
struct dirent *ent;
|
||||
struct dirent$freebsd *freebsd;
|
||||
if (!IsWindows()) {
|
||||
if (dir->buf_pos >= dir->buf_end) {
|
||||
int rc;
|
||||
if (!(rc = getdents(dir->fd, dir->buf, BUFSIZ)) || rc == -1) {
|
||||
if (!(rc = getdents(dir->fd, dir->buf,
|
||||
sizeof(dir->buf) - sizeof(dir->ent.d_name))) ||
|
||||
rc == -1) {
|
||||
return NULL;
|
||||
}
|
||||
dir->buf_pos = 0;
|
||||
dir->buf_end = rc;
|
||||
}
|
||||
/* TODO(jart): Check FreeBSD and OpenBSD again regarding this */
|
||||
char *record = dir->buf + dir->buf_pos;
|
||||
char *name = record + 8 + 8 + 2;
|
||||
size_t namelen = strlen(name);
|
||||
unsigned char dtype = name[namelen + 1];
|
||||
memmove(name + 1, name, namelen + 1); /* shove forward one byte */
|
||||
*name = dtype; /* is dirent d_type field */
|
||||
struct dirent *ent = (void *)record;
|
||||
dir->buf_pos += ent->d_reclen;
|
||||
dir->tell = ent->d_off;
|
||||
if (IsLinux()) {
|
||||
ent = (struct dirent *)(dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += ent->d_reclen;
|
||||
dir->tell = ent->d_off;
|
||||
} else {
|
||||
freebsd = (struct dirent$freebsd *)(dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += freebsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = freebsd->d_fileno;
|
||||
ent->d_off = dir->tell++;
|
||||
ent->d_reclen = freebsd->d_reclen;
|
||||
ent->d_type = freebsd->d_type;
|
||||
memcpy(ent->d_name, freebsd->d_name, freebsd->d_namlen + 1);
|
||||
}
|
||||
return ent;
|
||||
} else {
|
||||
if (dir->isdone) return NULL;
|
||||
struct dirent *ent = &dir->winent;
|
||||
memset(ent, 0, sizeof(*ent));
|
||||
ent->d_reclen =
|
||||
sizeof(*ent) +
|
||||
tprecode16to8(ent->d_name, PATH_MAX, dir->windata.cFileName) + 1;
|
||||
dir->isdone = FindNextFile(dir->fd, &dir->windata);
|
||||
return ent;
|
||||
return readdir$nt(dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +230,7 @@ int closedir(DIR *dir) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current byte offset into directory data.
|
||||
* Returns offset into directory data.
|
||||
*/
|
||||
long telldir(DIR *dir) {
|
||||
return dir->tell;
|
||||
|
||||
Reference in New Issue
Block a user