mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-07 03:38:31 +00:00
Remove old stack code and improve dirstream
This commit is contained in:
parent
74caabb823
commit
dc6c67256f
61 changed files with 463 additions and 595 deletions
|
@ -25,13 +25,19 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nopl.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/critbit0.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.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/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/win32finddata.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -60,18 +66,20 @@ int sys_getdents(unsigned, void *, unsigned, long *);
|
|||
struct dirstream {
|
||||
int fd;
|
||||
bool iszip;
|
||||
long tell;
|
||||
int64_t hand;
|
||||
int64_t tell;
|
||||
char16_t *name;
|
||||
pthread_mutex_t lock;
|
||||
struct {
|
||||
uint64_t offset;
|
||||
uint64_t records;
|
||||
size_t prefixlen;
|
||||
uint8_t prefix[ZIPOS_PATH_MAX];
|
||||
} zip;
|
||||
struct dirent ent;
|
||||
union {
|
||||
struct {
|
||||
struct Zipos *zipos;
|
||||
uint64_t inode;
|
||||
uint64_t offset;
|
||||
uint64_t records;
|
||||
size_t prefixlen;
|
||||
uint8_t prefix[ZIPOS_PATH_MAX];
|
||||
struct critbit0 found;
|
||||
} zip;
|
||||
struct {
|
||||
unsigned buf_pos;
|
||||
unsigned buf_end;
|
||||
|
@ -80,6 +88,8 @@ struct dirstream {
|
|||
struct {
|
||||
bool isdone;
|
||||
struct NtWin32FindData windata;
|
||||
char16_t name16[PATH_MAX];
|
||||
uint32_t name16len;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -119,69 +129,40 @@ struct dirent_netbsd {
|
|||
char d_name[512];
|
||||
};
|
||||
|
||||
// TODO(jart): wipe these locks when forking
|
||||
|
||||
void _lockdir(DIR *dir) {
|
||||
pthread_mutex_lock(&dir->lock);
|
||||
}
|
||||
|
||||
void _unlockdir(DIR *dir) {
|
||||
pthread_mutex_unlock(&dir->lock);
|
||||
}
|
||||
|
||||
#ifdef _NOPL1
|
||||
#define _lockdir(d) _NOPL1("__threadcalls", _lockdir, d)
|
||||
#define _unlockdir(d) _NOPL1("__threadcalls", _unlockdir, d)
|
||||
#else
|
||||
#define _lockdir(d) (__threaded ? _lockdir(d) : 0)
|
||||
#define _unlockdir(d) (__threaded ? _unlockdir(d) : 0)
|
||||
#endif
|
||||
|
||||
static textwindows DIR *opendir_nt_impl(char16_t *name, size_t len) {
|
||||
DIR *res;
|
||||
if (len + 2 + 1 <= PATH_MAX) {
|
||||
if (len == 1 && name[0] == '.') {
|
||||
name[0] = '*';
|
||||
} else {
|
||||
if (len > 1 && name[len - 1] != u'\\') {
|
||||
name[len++] = u'\\';
|
||||
}
|
||||
name[len++] = u'*';
|
||||
}
|
||||
name[len] = u'\0';
|
||||
if ((res = calloc(1, sizeof(DIR)))) {
|
||||
if ((res->hand = FindFirstFile(name, &res->windata)) != -1) {
|
||||
return res;
|
||||
}
|
||||
__fix_enotdir(-1, name);
|
||||
free(res);
|
||||
}
|
||||
} else {
|
||||
enametoolong();
|
||||
static void _lockdir(DIR *dir) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_lock(&dir->lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static textwindows dontinline DIR *fdopendir_nt(int fd) {
|
||||
DIR *res;
|
||||
char16_t *name;
|
||||
if (__isfdkind(fd, kFdFile)) {
|
||||
if ((name = calloc(1, PATH_MAX * 2))) {
|
||||
if ((res = opendir_nt_impl(
|
||||
name, GetFinalPathNameByHandle(
|
||||
g_fds.p[fd].handle, name, PATH_MAX,
|
||||
kNtFileNameNormalized | kNtVolumeNameDos)))) {
|
||||
res->name = name;
|
||||
res->fd = -1;
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
} else {
|
||||
ebadf();
|
||||
static void _unlockdir(DIR *dir) {
|
||||
if (__threaded) {
|
||||
pthread_mutex_unlock(&dir->lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static textwindows dontinline int fdopendir_nt(DIR *res, int fd) {
|
||||
if (!__isfdkind(fd, kFdFile)) {
|
||||
return ebadf();
|
||||
}
|
||||
res->name16len = GetFinalPathNameByHandle(
|
||||
g_fds.p[fd].handle, res->name16, ARRAYLEN(res->name16),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (!res->name16len) {
|
||||
return __winerr();
|
||||
}
|
||||
if (res->name16len + 2 + 1 > ARRAYLEN(res->name16)) {
|
||||
return enametoolong();
|
||||
}
|
||||
if (res->name16len > 1 && res->name16[res->name16len - 1] != u'\\') {
|
||||
res->name16[res->name16len++] = u'\\';
|
||||
}
|
||||
res->name16[res->name16len++] = u'*';
|
||||
res->name16[res->name16len] = u'\0';
|
||||
if ((res->hand = FindFirstFile(res->name16, &res->windata)) == -1) {
|
||||
return __fix_enotdir(-1, res->name16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static textwindows uint8_t GetNtDirentType(struct NtWin32FindData *w) {
|
||||
|
@ -204,26 +185,57 @@ static textwindows uint8_t GetNtDirentType(struct NtWin32FindData *w) {
|
|||
}
|
||||
|
||||
static textwindows dontinline struct dirent *readdir_nt(DIR *dir) {
|
||||
size_t i;
|
||||
if (!dir->isdone) {
|
||||
bzero(&dir->ent, sizeof(dir->ent));
|
||||
dir->ent.d_ino++;
|
||||
dir->ent.d_off = dir->tell++;
|
||||
dir->ent.d_reclen =
|
||||
tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name) - 2,
|
||||
dir->windata.cFileName)
|
||||
.ax;
|
||||
for (i = 0; i < dir->ent.d_reclen; ++i) {
|
||||
if (dir->ent.d_name[i] == '\\') {
|
||||
dir->ent.d_name[i] = '/';
|
||||
}
|
||||
}
|
||||
dir->ent.d_type = GetNtDirentType(&dir->windata);
|
||||
dir->isdone = !FindNextFile(dir->hand, &dir->windata);
|
||||
return &dir->ent;
|
||||
} else {
|
||||
if (dir->isdone) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// join absolute path
|
||||
uint64_t ino = 0;
|
||||
size_t i = dir->name16len - 1;
|
||||
char16_t *p = dir->windata.cFileName;
|
||||
while (*p) {
|
||||
if (i + 1 < ARRAYLEN(dir->name16)) {
|
||||
dir->name16[i++] = *p++;
|
||||
} else {
|
||||
// ignore errors and set inode to zero
|
||||
goto GiveUpOnGettingInode;
|
||||
}
|
||||
}
|
||||
dir->name16[i] = u'\0';
|
||||
|
||||
// get inode that's consistent with stat()
|
||||
int e = errno;
|
||||
int64_t fh =
|
||||
CreateFile(dir->name16, kNtFileReadAttributes, 0, 0, kNtOpenExisting,
|
||||
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||
kNtFileFlagOpenReparsePoint,
|
||||
0);
|
||||
if (fh != -1) {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (GetFileInformationByHandle(fh, &wst)) {
|
||||
ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
|
||||
}
|
||||
CloseHandle(fh);
|
||||
} else {
|
||||
// ignore errors and set inode to zero
|
||||
// TODO(jart): How do we handle "." and ".."?
|
||||
errno = e;
|
||||
}
|
||||
|
||||
GiveUpOnGettingInode:
|
||||
// restore original directory search path
|
||||
dir->name16[dir->name16len - 1] = u'*';
|
||||
dir->name16[dir->name16len] = u'\0';
|
||||
|
||||
// create result object
|
||||
bzero(&dir->ent, sizeof(dir->ent));
|
||||
dir->ent.d_ino = ino;
|
||||
dir->ent.d_off = dir->tell++;
|
||||
tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name),
|
||||
dir->windata.cFileName);
|
||||
dir->ent.d_type = GetNtDirentType(&dir->windata);
|
||||
dir->isdone = !FindNextFile(dir->hand, &dir->windata);
|
||||
return &dir->ent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,8 +258,12 @@ DIR *fdopendir(int fd) {
|
|||
dir->fd = fd;
|
||||
if (!__isfdkind(fd, kFdZip)) {
|
||||
if (IsWindows()) {
|
||||
free(dir);
|
||||
return fdopendir_nt(fd);
|
||||
if (!fdopendir_nt(dir, fd)) {
|
||||
return dir;
|
||||
} else {
|
||||
free(dir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
@ -285,6 +301,8 @@ DIR *fdopendir(int fd) {
|
|||
dir->zip.prefixlen = len;
|
||||
|
||||
// setup state values for directory iterator
|
||||
dir->zip.zipos = h->zipos;
|
||||
dir->zip.inode = h->cfile;
|
||||
dir->zip.offset = GetZipCdirOffset(h->zipos->cdir);
|
||||
dir->zip.records = GetZipCdirRecords(h->zipos->cdir);
|
||||
|
||||
|
@ -325,124 +343,123 @@ DIR *opendir(const char *name) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static struct dirent *readdir_impl(DIR *dir) {
|
||||
size_t n;
|
||||
int rc, mode;
|
||||
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;
|
||||
if (dir->iszip) {
|
||||
ent = 0;
|
||||
zip = _weaken(__zipos_get)();
|
||||
while (!ent && dir->tell < dir->zip.records + 2) {
|
||||
if (!dir->tell) {
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = 1;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
} else if (dir->tell == 1) {
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = 2;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
} else {
|
||||
s = ZIP_CFILE_NAME(zip->map + dir->zip.offset);
|
||||
n = ZIP_CFILE_NAMESIZE(zip->map + dir->zip.offset);
|
||||
if (dir->zip.prefixlen < n &&
|
||||
!memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) {
|
||||
s += dir->zip.prefixlen;
|
||||
n -= dir->zip.prefixlen;
|
||||
p = memchr(s, '/', n);
|
||||
if (!p || p + 1 - s == n) {
|
||||
if (p + 1 - s == n) --n;
|
||||
mode = GetZipCfileMode(zip->map + dir->zip.offset);
|
||||
ent = (struct dirent *)dir->buf;
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = MIN(n, 255);
|
||||
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
|
||||
if (ent->d_reclen) {
|
||||
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;
|
||||
mode = GetZipCfileMode(zip->map + dir->zip.offset);
|
||||
ent->d_ino++;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_reclen = n;
|
||||
ent->d_type = S_ISDIR(mode) ? DT_DIR : DT_REG;
|
||||
if (ent->d_reclen) {
|
||||
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);
|
||||
}
|
||||
dir->tell++;
|
||||
}
|
||||
return ent;
|
||||
} else if (!IsWindows()) {
|
||||
if (dir->buf_pos >= dir->buf_end) {
|
||||
long basep = dir->tell;
|
||||
rc = sys_getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep);
|
||||
STRACE("sys_getdents(%d) → %d% m", dir->fd, rc);
|
||||
if (!rc || rc == -1) return NULL;
|
||||
dir->buf_pos = 0;
|
||||
dir->buf_end = rc;
|
||||
}
|
||||
if (IsLinux()) {
|
||||
ent = (struct dirent *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += ent->d_reclen;
|
||||
dir->tell = ent->d_off;
|
||||
} else if (IsOpenbsd()) {
|
||||
obsd = (struct dirent_openbsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += obsd->d_reclen;
|
||||
dir->tell = obsd->d_off;
|
||||
static struct dirent *readdir_zipos(DIR *dir) {
|
||||
struct dirent *ent = 0;
|
||||
while (!ent && dir->tell < dir->zip.records + 2) {
|
||||
size_t n;
|
||||
if (!dir->tell) {
|
||||
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 if (IsNetbsd()) {
|
||||
nbsd = (struct dirent_netbsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += nbsd->d_reclen;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_ino = dir->zip.inode;
|
||||
ent->d_type = DT_DIR;
|
||||
ent->d_name[0] = '.';
|
||||
ent->d_name[1] = 0;
|
||||
n = 1;
|
||||
} else if (dir->tell == 1) {
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = nbsd->d_fileno;
|
||||
ent->d_off = (dir->tell += nbsd->d_reclen);
|
||||
ent->d_reclen = nbsd->d_reclen;
|
||||
ent->d_type = nbsd->d_type;
|
||||
memcpy(ent->d_name, nbsd->d_name, MAX(256, nbsd->d_namlen + 1));
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_ino = 0; // TODO
|
||||
ent->d_type = DT_DIR;
|
||||
ent->d_name[0] = '.';
|
||||
ent->d_name[1] = '.';
|
||||
ent->d_name[2] = 0;
|
||||
n = 2;
|
||||
} else {
|
||||
bsd = (struct dirent_bsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += bsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = bsd->d_fileno;
|
||||
ent->d_off = dir->tell++;
|
||||
ent->d_reclen = bsd->d_reclen;
|
||||
ent->d_type = bsd->d_type;
|
||||
memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1);
|
||||
uint8_t *s = ZIP_CFILE_NAME(dir->zip.zipos->map + dir->zip.offset);
|
||||
n = ZIP_CFILE_NAMESIZE(dir->zip.zipos->map + dir->zip.offset);
|
||||
if (n > dir->zip.prefixlen &&
|
||||
!memcmp(dir->zip.prefix, s, dir->zip.prefixlen)) {
|
||||
s += dir->zip.prefixlen;
|
||||
n -= dir->zip.prefixlen;
|
||||
uint8_t *p = memchr(s, '/', n);
|
||||
if (p) n = p - s;
|
||||
if ((n = MIN(n, sizeof(ent->d_name) - 1)) &&
|
||||
critbit0_emplace(&dir->zip.found, s, n) == 1) {
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = dir->zip.offset;
|
||||
ent->d_off = dir->tell;
|
||||
ent->d_type =
|
||||
S_ISDIR(GetZipCfileMode(dir->zip.zipos->map + dir->zip.offset))
|
||||
? DT_DIR
|
||||
: DT_REG;
|
||||
memcpy(ent->d_name, s, n);
|
||||
ent->d_name[n] = 0;
|
||||
}
|
||||
}
|
||||
dir->zip.offset +=
|
||||
ZIP_CFILE_HDRSIZE(dir->zip.zipos->map + dir->zip.offset);
|
||||
}
|
||||
return ent;
|
||||
dir->tell++;
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
|
||||
static struct dirent *readdir_unix(DIR *dir) {
|
||||
if (dir->buf_pos >= dir->buf_end) {
|
||||
long basep = dir->tell;
|
||||
int rc = sys_getdents(dir->fd, dir->buf, sizeof(dir->buf) - 256, &basep);
|
||||
STRACE("sys_getdents(%d) → %d% m", dir->fd, rc);
|
||||
if (!rc || rc == -1) {
|
||||
return NULL;
|
||||
}
|
||||
dir->buf_pos = 0;
|
||||
dir->buf_end = rc;
|
||||
}
|
||||
struct dirent *ent;
|
||||
if (IsLinux()) {
|
||||
ent = (struct dirent *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += ent->d_reclen;
|
||||
dir->tell = ent->d_off;
|
||||
} else if (IsOpenbsd()) {
|
||||
struct dirent_openbsd *obsd =
|
||||
(struct dirent_openbsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += obsd->d_reclen;
|
||||
dir->tell = obsd->d_off;
|
||||
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 if (IsNetbsd()) {
|
||||
struct dirent_netbsd *nbsd =
|
||||
(struct dirent_netbsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += nbsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = nbsd->d_fileno;
|
||||
ent->d_off = (dir->tell += nbsd->d_reclen);
|
||||
ent->d_reclen = nbsd->d_reclen;
|
||||
ent->d_type = nbsd->d_type;
|
||||
size_t n =
|
||||
MIN(nbsd->d_namlen, MIN(sizeof(ent->d_name) - 1, sizeof(nbsd->d_name)));
|
||||
memcpy(ent->d_name, nbsd->d_name, n);
|
||||
ent->d_name[n] = 0;
|
||||
} else {
|
||||
struct dirent_bsd *bsd =
|
||||
(struct dirent_bsd *)((char *)dir->buf + dir->buf_pos);
|
||||
dir->buf_pos += bsd->d_reclen;
|
||||
ent = &dir->ent;
|
||||
ent->d_ino = bsd->d_fileno;
|
||||
ent->d_off = dir->tell++;
|
||||
ent->d_reclen = bsd->d_reclen;
|
||||
ent->d_type = bsd->d_type;
|
||||
memcpy(ent->d_name, bsd->d_name, bsd->d_namlen + 1);
|
||||
}
|
||||
if (ent) {
|
||||
ent->d_reclen =
|
||||
ROUNDUP(offsetof(struct dirent, d_name) + strlen(ent->d_name) + 1, 8);
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
|
||||
static struct dirent *readdir_impl(DIR *dir) {
|
||||
if (dir->iszip) {
|
||||
return readdir_zipos(dir);
|
||||
}
|
||||
if (IsWindows()) {
|
||||
return readdir_nt(dir);
|
||||
}
|
||||
return readdir_unix(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -509,10 +526,12 @@ errno_t readdir_r(DIR *dir, struct dirent *output, struct dirent **result) {
|
|||
int closedir(DIR *dir) {
|
||||
int rc = 0;
|
||||
if (dir) {
|
||||
if (dir->iszip) {
|
||||
critbit0_clear(&dir->zip.found);
|
||||
}
|
||||
if (dir->fd != -1) {
|
||||
rc |= close(dir->fd);
|
||||
}
|
||||
free(dir->name);
|
||||
if (IsWindows() && !dir->iszip) {
|
||||
if (!FindClose(dir->hand)) {
|
||||
rc = __winerr();
|
||||
|
@ -540,11 +559,7 @@ long telldir(DIR *dir) {
|
|||
* @threadsafe
|
||||
*/
|
||||
int dirfd(DIR *dir) {
|
||||
int rc;
|
||||
_lockdir(dir);
|
||||
rc = dir->fd;
|
||||
_unlockdir(dir);
|
||||
return rc;
|
||||
return dir->fd;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,8 +569,9 @@ int dirfd(DIR *dir) {
|
|||
void rewinddir(DIR *dir) {
|
||||
_lockdir(dir);
|
||||
if (dir->iszip) {
|
||||
critbit0_clear(&dir->zip.found);
|
||||
dir->tell = 0;
|
||||
dir->zip.offset = GetZipCdirOffset(_weaken(__zipos_get)()->cdir);
|
||||
dir->zip.offset = GetZipCdirOffset(dir->zip.zipos->cdir);
|
||||
} else if (!IsWindows()) {
|
||||
if (!lseek(dir->fd, 0, SEEK_SET)) {
|
||||
dir->buf_pos = dir->buf_end = 0;
|
||||
|
@ -563,7 +579,7 @@ void rewinddir(DIR *dir) {
|
|||
}
|
||||
} else {
|
||||
FindClose(dir->hand);
|
||||
if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) {
|
||||
if ((dir->hand = FindFirstFile(dir->name16, &dir->windata)) != -1) {
|
||||
dir->isdone = false;
|
||||
dir->tell = 0;
|
||||
} else {
|
||||
|
@ -577,27 +593,26 @@ void rewinddir(DIR *dir) {
|
|||
* Seeks in directory stream.
|
||||
* @threadsafe
|
||||
*/
|
||||
void seekdir(DIR *dir, long off) {
|
||||
long i;
|
||||
struct Zipos *zip;
|
||||
void seekdir(DIR *dir, long tell) {
|
||||
_lockdir(dir);
|
||||
zip = _weaken(__zipos_get)();
|
||||
if (dir->iszip) {
|
||||
dir->zip.offset = GetZipCdirOffset(_weaken(__zipos_get)()->cdir);
|
||||
for (i = 0; i < off && i < dir->zip.records; ++i) {
|
||||
if (i >= 2) {
|
||||
dir->zip.offset += ZIP_CFILE_HDRSIZE(zip->map + dir->zip.offset);
|
||||
critbit0_clear(&dir->zip.found);
|
||||
dir->tell = 0;
|
||||
dir->zip.offset = GetZipCdirOffset(dir->zip.zipos->cdir);
|
||||
while (dir->tell < tell) {
|
||||
if (!readdir_zipos(dir)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
i = lseek(dir->fd, off, SEEK_SET);
|
||||
dir->tell = lseek(dir->fd, tell, SEEK_SET);
|
||||
dir->buf_pos = dir->buf_end = 0;
|
||||
} else {
|
||||
i = 0;
|
||||
dir->tell = 0;
|
||||
dir->isdone = false;
|
||||
FindClose(dir->hand);
|
||||
if ((dir->hand = FindFirstFile(dir->name, &dir->windata)) != -1) {
|
||||
for (; i < off; ++i) {
|
||||
if ((dir->hand = FindFirstFile(dir->name16, &dir->windata)) != -1) {
|
||||
for (; dir->tell < tell; ++dir->tell) {
|
||||
if (!FindNextFile(dir->hand, &dir->windata)) {
|
||||
dir->isdone = true;
|
||||
break;
|
||||
|
@ -607,7 +622,6 @@ void seekdir(DIR *dir, long off) {
|
|||
dir->isdone = true;
|
||||
}
|
||||
}
|
||||
dir->tell = i;
|
||||
_unlockdir(dir);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ o//libc/stdio/appendw.o: private \
|
|||
CFLAGS += \
|
||||
-Os
|
||||
|
||||
o/$(MODE)/libc/stdio/dirstream.o \
|
||||
o/$(MODE)/libc/stdio/posix_spawnattr.o \
|
||||
o/$(MODE)/libc/stdio/posix_spawn_file_actions.o \
|
||||
o/$(MODE)/libc/stdio/mt19937.o: private \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue