[2030] in Athena Bugs
lseek() fix in kernel
daemon@ATHENA.MIT.EDU (Ilhamuddin Ahmed)
Tue Apr 4 20:03:58 1989
Date: Tue, 4 Apr 89 20:02:57 EDT
From: Ilhamuddin Ahmed <ilham@ATHENA.MIT.EDU>
To: athena-ws@ATHENA.MIT.EDU, bugs@ATHENA.MIT.EDU
Cc: probe@ATHENA.MIT.EDU, ilham@ATHENA.MIT.EDU
Reply-To: ilham@ATHENA.MIT.EDU
The context diff to fix the problem with lseek() is enclosed. The
problem was that even if you have a negative file descriptor, it does
not returns -1 (or any error). According to the man page, it should.
The problem is the the file descriptor is kept in a signed int. So in
case of memory (/dev/kmem) we *can* have negative file descriptors as it
is signed.
The fix takes into consideration that this can and will occur (I had a
problem with machtype when I made a kernel which just checked if
negative and returned an error, as machtype accesses /dev/kmem and lseek
returns a very high address (thus a negative number)).
When a command such as :
lseek(fd, -100, L_INCR)
is executed and if the file descriptor goes from positive to negative
(when offset is negative [-100 in the example]) and the operation is
L_INCR, (not L_SET or L_XTND), then it will give and error returned in
errno. The error message is ERANGE. This seemed to the best one to use
out of all the error message in /usr/include/errno.h.
One problem could be that if there is a very large offset it might
wraparound and give an error and this is only in case of memory as this
spans the full 2^32 bits. Of course most lseek to memory is of type
L_SET and not L_INCR so this should not occur.
I have built an RT kernel and tested it on crash.mit.edu. It seems to be
working properly. Any comments, suggestions about the suitability of
ERANGE, the problem with large offset and anything else is welcome.
- Ilham
Watchmaker
===============================================================================
*** /minos/sys/sys/vfs_syscalls.c Wed Apr 27 18:43:31 1988
--- /garfield/u1/sys/sys/vfs_syscalls.c Tue Apr 4 19:28:12 1989
***************
*** 415,429 ****
off_t off;
int sbase;
} *uap = (struct a *) u.u_ap;
struct file *fp;
u.u_error = getvnodefp(uap->fd, &fp);
if (u.u_error)
return;
- switch (uap->sbase) {
case L_INCR:
! fp->f_offset += uap->off;
break;
case L_XTND: {
--- 415,432 ----
off_t off;
int sbase;
} *uap = (struct a *) u.u_ap;
+ register off_t offset;
struct file *fp;
u.u_error = getvnodefp(uap->fd, &fp);
if (u.u_error)
return;
+ offset = fp->f_offset;
+
+ switch (uap->sbase) {
case L_INCR:
! offset += uap->off;
break;
case L_XTND: {
***************
*** 433,450 ****
VOP_GETATTR((struct vnode *)fp->f_data, &vattr, u.u_cred);
if (u.u_error)
return;
! fp->f_offset = uap->off + vattr.va_size;
break;
}
case L_SET:
! fp->f_offset = uap->off;
break;
default:
u.u_error = EINVAL;
}
! u.u_r.r_off = fp->f_offset;
}
/*
--- 436,458 ----
VOP_GETATTR((struct vnode *)fp->f_data, &vattr, u.u_cred);
if (u.u_error)
return;
! offset = uap->off + vattr.va_size;
break;
}
case L_SET:
! offset = uap->off;
break;
default:
u.u_error = EINVAL;
}
!
! if ((uap->sbase == L_INCR) && (uap->off < 0) &&
! (offset < 0) && (fp->f_offset >= 0))
! u.u_error = ERANGE;
! else
! u.u_r.r_off = fp->f_offset = offset;
}
/*