Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Aug 2001 12:52:48 +0400
From:      "Andrey A. Chernov" <ache@nagual.pp.ru>
To:        arch@freebsd.org, current@freebsd.org
Subject:   CFR: lseek() POSIXed patch
Message-ID:  <20010815125248.A2588@nagual.pp.ru>

next in thread | raw e-mail | index | archive | help
Here it is what POSIX says about lseek():

[EINVAL]    

The whence argument is not a proper value, or the resulting file offset
would be negative for a regular file, block special file, or directory.

[EOVERFLOW] 

The resulting file offset would be a value which cannot be represented
correctly in an object of type off_t.

The patch below adds both cases, i.e. disallow negative seeks for VREG,
VDIR, VBLK and add off_t overflow checks.

I plan to commit this, please review.


--- vfs_syscalls.c.old	Wed Aug 15 04:45:30 2001
+++ vfs_syscalls.c	Wed Aug 15 12:46:12 2001
@@ -1614,29 +1614,44 @@
 	register struct filedesc *fdp = p->p_fd;
 	register struct file *fp;
 	struct vattr vattr;
-	int error;
+	off_t offset;
+	int error, no_neg_seek;
 
 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
 		return (EBADF);
 	if (fp->f_type != DTYPE_VNODE)
 		return (ESPIPE);
+	error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
+	no_neg_seek = (!error &&
+		       (vattr.va_type == VREG ||
+			vattr.va_type == VDIR ||
+			vattr.va_type == VBLK));
+	offset = SCARG(uap, offset);
 	switch (SCARG(uap, whence)) {
 	case L_INCR:
-		fp->f_offset += SCARG(uap, offset);
+		if ((fp->f_offset > 0 && offset > 0 &&
+		     offset + fp->f_offset < 0) ||
+		    (fp->f_offset < 0 && offset < 0 &&
+		     offset + fp->f_offset > 0))
+			return (EOVERFLOW);
+		offset += fp->f_offset;
 		break;
 	case L_XTND:
-		error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
 		if (error)
 			return (error);
-		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
+		if (offset > 0 && (off_t)(offset + vattr.va_size) < 0)
+			return (EOVERFLOW);
+		offset += vattr.va_size;
 		break;
 	case L_SET:
-		fp->f_offset = SCARG(uap, offset);
 		break;
 	default:
 		return (EINVAL);
 	}
+	if (no_neg_seek && offset < 0)
+		return (EINVAL);
+	fp->f_offset = offset;
 	*(off_t *)(p->p_retval) = fp->f_offset;
 	return (0);
 }

-- 
Andrey A. Chernov
http://ache.pp.ru/

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010815125248.A2588>