Refix readdir() on OpenBSD

We now have better tests which are catching these kinds of bugs.
This commit is contained in:
Justine Tunney 2021-01-29 01:25:14 -08:00
parent f7c7b949fd
commit a5f3456333
2 changed files with 25 additions and 2 deletions

View file

@ -73,6 +73,19 @@ struct dirent$bsd {
char d_name[256];
};
/**
* OpenBSD getdents() ABI.
*/
struct dirent$openbsd {
uint64_t d_fileno;
int64_t d_off;
uint16_t d_reclen;
uint8_t d_type;
uint8_t d_namlen;
uint8_t __zomg[4];
char d_name[256];
};
static textwindows noinline DIR *opendir$nt(const char *name) {
int len;
DIR *res;
@ -194,6 +207,7 @@ struct dirent *readdir(DIR *dir) {
long basep;
struct dirent *ent;
struct dirent$bsd *bsd;
struct dirent$openbsd *obsd;
if (!IsWindows()) {
if (dir->buf_pos >= dir->buf_end) {
basep = dir->tell; /* <- what does xnu do */
@ -202,10 +216,19 @@ struct dirent *readdir(DIR *dir) {
dir->buf_pos = 0;
dir->buf_end = rc;
}
if (IsLinux() || IsOpenbsd()) {
if (IsLinux()) {
ent = (struct dirent *)(dir->buf + dir->buf_pos);
dir->buf_pos += ent->d_reclen;
dir->tell = ent->d_off;
} else if (IsOpenbsd()) {
obsd = (struct dirent$openbsd *)(dir->buf + dir->buf_pos);
dir->buf_pos += obsd->d_reclen;
ent = &dir->ent;
ent->d_ino = obsd->d_fileno;
ent->d_off = obsd->d_off;
ent->d_reclen = obsd->d_reclen;
ent->d_type = obsd->d_type;
memcpy(ent->d_name, obsd->d_name, obsd->d_namlen + 1);
} else {
bsd = (struct dirent$bsd *)(dir->buf + dir->buf_pos);
dir->buf_pos += bsd->d_reclen;

View file

@ -2,7 +2,7 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct dirent { /* openbsd and linux getdents64 abi */
struct dirent { /* linux getdents64 abi */
uint64_t d_ino; /* inode number */
int64_t d_off; /* implementation-dependent location number */
uint16_t d_reclen; /* byte length of this whole struct and string */