mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-02 12:30:24 +08:00
Cygwin: lseek: improve seeking posix_getdents descriptors
Transfer code lseeking on posix_getdents() directory descriptor into its own static function and rework it so SEEK_END, SEEK_DATA and SEEK_HOLE work here as expected, too. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
c77a5689f7
commit
6d93691547
@ -1596,6 +1596,66 @@ open (const char *unix_path, int flags, ...)
|
||||
|
||||
EXPORT_ALIAS (open, _open )
|
||||
|
||||
static int
|
||||
posix_getdents_lseek (cygheap_fdget &cfd, off_t pos, int dir)
|
||||
{
|
||||
long cur = cfd->telldir (cfd->getdents_dir ());
|
||||
long abs_pos;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
abs_pos = cur + pos;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
case SEEK_DATA:
|
||||
abs_pos = pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
case SEEK_HOLE:
|
||||
/* First read full dir to learn end-of-dir position. */
|
||||
while (::readdir (cfd->getdents_dir ()))
|
||||
;
|
||||
long eod = cfd->telldir (cfd->getdents_dir ());
|
||||
/* Seek back so it looks like nothing happend in error case */
|
||||
cfd->seekdir (cfd->getdents_dir (), cur);
|
||||
if (dir == SEEK_HOLE)
|
||||
{
|
||||
if (pos > eod)
|
||||
{
|
||||
set_errno (ENXIO);
|
||||
return -1;
|
||||
}
|
||||
abs_pos = eod;
|
||||
}
|
||||
else
|
||||
abs_pos = eod + pos;
|
||||
break;
|
||||
}
|
||||
if (abs_pos < 0)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
if (abs_pos != cur)
|
||||
{
|
||||
cfd->seekdir (cfd->getdents_dir (), abs_pos);
|
||||
/* In SEEK_DATA case, check that we didn't seek beyond EOF */
|
||||
if (dir == SEEK_DATA || dir == SEEK_HOLE)
|
||||
{
|
||||
pos = cfd->telldir (cfd->getdents_dir ());
|
||||
if (pos < abs_pos)
|
||||
{
|
||||
/* Seek back so it looks like nothing happend */
|
||||
cfd->seekdir (cfd->getdents_dir (), cur);
|
||||
set_errno (ENXIO);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return abs_pos;
|
||||
}
|
||||
|
||||
extern "C" off_t
|
||||
lseek (int fd, off_t pos, int dir)
|
||||
{
|
||||
@ -1612,28 +1672,7 @@ lseek (int fd, off_t pos, int dir)
|
||||
if (cfd < 0)
|
||||
res = -1;
|
||||
else if (cfd->getdents_dir ())
|
||||
{
|
||||
if (dir != SEEK_SET && dir != SEEK_CUR) /* No SEEK_END */
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
long cur;
|
||||
|
||||
cur = cfd->telldir (cfd->getdents_dir ());
|
||||
if (dir == SEEK_CUR && cur == 0)
|
||||
res = cur;
|
||||
else
|
||||
{
|
||||
if (dir == SEEK_CUR)
|
||||
pos = cur + pos;
|
||||
cfd->seekdir (cfd->getdents_dir (), pos);
|
||||
res = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
res = posix_getdents_lseek (cfd, pos, dir);
|
||||
else
|
||||
res = cfd->lseek (pos, dir);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user