summaryrefslogtreecommitdiffstats
path: root/lib/libstand/lseek.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libstand/lseek.c')
-rw-r--r--lib/libstand/lseek.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/lib/libstand/lseek.c b/lib/libstand/lseek.c
index 91f8612..f945460 100644
--- a/lib/libstand/lseek.c
+++ b/lib/libstand/lseek.c
@@ -70,6 +70,7 @@
off_t
lseek(int fd, off_t offset, int where)
{
+ off_t bufpos, filepos, target;
struct open_file *f = &files[fd];
if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
@@ -97,6 +98,36 @@ lseek(int fd, off_t offset, int where)
}
/*
+ * If there is some unconsumed data in the readahead buffer and it
+ * contains the desired offset, simply adjust the buffer offset and
+ * length. We don't bother with SEEK_END here, since the code to
+ * handle it would fail in the same cases where the non-readahead
+ * code fails (namely, for streams which cannot seek backward and whose
+ * size isn't known in advance).
+ */
+ if (f->f_ralen != 0 && where != SEEK_END) {
+ if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1)
+ return (-1);
+ bufpos = filepos - f->f_ralen;
+ switch (where) {
+ case SEEK_SET:
+ target = offset;
+ break;
+ case SEEK_CUR:
+ target = bufpos + offset;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ if (bufpos <= target && target < filepos) {
+ f->f_raoffset += target - bufpos;
+ f->f_ralen -= target - bufpos;
+ return (target);
+ }
+ }
+
+ /*
* If this is a relative seek, we need to correct the offset for
* bytes that we have already read but the caller doesn't know
* about.
OpenPOWER on IntegriCloud