summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2010-10-28 15:02:42 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2010-10-28 15:02:42 +0000
commitad39b297930f7aeb9f57f3283cb31dad08c3a9ac (patch)
tree686235f31d6eb66ef3d8180a61333f611d32602b /sys/kern
parent24c64c90c25711433236441e0509ebae8231f426 (diff)
Change basep parameter of getdirentries() to be off_t *, not long *
so it works correctly with large offsets (and matches other systems). This requires adding a new getdirentries syscall, with the old one renamed to ogetdirentries. All in-tree consumers of getdirentries() have been updated. Bump libc and libpthread major numbers. OK and with deraadt@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/syscalls.master6
-rw-r--r--sys/kern/vfs_syscalls.c75
2 files changed, 61 insertions, 20 deletions
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index f2c9d815572..be442ccd32c 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.103 2010/09/20 07:18:03 deraadt Exp $
+; $OpenBSD: syscalls.master,v 1.104 2010/10/28 15:02:41 millert Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -372,7 +372,7 @@
struct rlimit *rlp); }
195 STD { int sys_setrlimit(int which, \
const struct rlimit *rlp); }
-196 STD { int sys_getdirentries(int fd, char *buf, \
+196 STD { int sys_ogetdirentries(int fd, char *buf, \
int count, long *basep); }
197 STD { void *sys_mmap(void *addr, size_t len, int prot, \
int flags, int fd, long pad, off_t pos); }
@@ -607,3 +607,5 @@
struct statfs *buf); }
310 STD { int sys_setrtable(int rtableid); }
311 STD { int sys_getrtable(void); }
+312 STD { int sys_getdirentries(int fd, char *buf, \
+ int count, off_t *basep); }
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 879545bf637..660c88bdad0 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_syscalls.c,v 1.164 2010/10/27 17:11:08 deraadt Exp $ */
+/* $OpenBSD: vfs_syscalls.c,v 1.165 2010/10/28 15:02:41 millert Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
/*
@@ -68,6 +68,9 @@ void checkdirs(struct vnode *);
int copyout_statfs(struct statfs *, void *, struct proc *);
+int getdirentries_internal(struct proc *, int, char *, int, off_t *,
+ register_t *);
+
/*
* Virtual File System System Calls
*/
@@ -2289,57 +2292,93 @@ out:
* Read a block of directory entries in a file system independent format.
*/
int
-sys_getdirentries(struct proc *p, void *v, register_t *retval)
+getdirentries_internal(struct proc *p, int fd, char *buf, int count,
+ off_t *basep, register_t *retval)
{
- struct sys_getdirentries_args /* {
- syscallarg(int) fd;
- syscallarg(char *) buf;
- syscallarg(int) count;
- syscallarg(long *) basep;
- } */ *uap = v;
struct vnode *vp;
struct file *fp;
struct uio auio;
struct iovec aiov;
- long loff;
int error, eofflag;
- if (SCARG(uap, count) < 0)
+ if (count < 0)
return EINVAL;
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ if ((error = getvnode(p->p_fd, fd, &fp)) != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
error = EBADF;
goto bad;
}
+ if (fp->f_offset < 0) {
+ error = EINVAL;
+ goto bad;
+ }
vp = (struct vnode *)fp->f_data;
if (vp->v_type != VDIR) {
error = EINVAL;
goto bad;
}
- aiov.iov_base = SCARG(uap, buf);
- aiov.iov_len = SCARG(uap, count);
+ aiov.iov_base = buf;
+ aiov.iov_len = count;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
- auio.uio_resid = SCARG(uap, count);
+ auio.uio_resid = count;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
- loff = auio.uio_offset = fp->f_offset;
+ *basep = auio.uio_offset = fp->f_offset;
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0);
fp->f_offset = auio.uio_offset;
VOP_UNLOCK(vp, 0, p);
if (error)
goto bad;
- error = copyout(&loff, SCARG(uap, basep),
- sizeof(long));
- *retval = SCARG(uap, count) - auio.uio_resid;
+ *retval = count - auio.uio_resid;
bad:
FRELE(fp);
return (error);
}
+int
+sys_getdirentries(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_getdirentries_args /* {
+ syscallarg(int) fd;
+ syscallarg(char *) buf;
+ syscallarg(int) count;
+ syscallarg(off_t *) basep;
+ } */ *uap = v;
+ int error;
+ off_t off;
+
+ error = getdirentries_internal(p, SCARG(uap, fd), SCARG(uap, buf),
+ SCARG(uap, count), &off, retval);
+ if (!error)
+ error = copyout(&off, SCARG(uap, basep), sizeof(off_t));
+ return error;
+}
+
+int
+sys_ogetdirentries(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_getdirentries_args /* {
+ syscallarg(int) fd;
+ syscallarg(char *) buf;
+ syscallarg(int) count;
+ syscallarg(long *) basep;
+ } */ *uap = v;
+ int error;
+ off_t off;
+
+ error = getdirentries_internal(p, SCARG(uap, fd), SCARG(uap, buf),
+ SCARG(uap, count), &off, retval);
+ if (!error) {
+ long loff = (long)off;
+ error = copyout(&loff, SCARG(uap, basep), sizeof(long));
+ }
+ return error;
+}
+
/*
* Set the mode mask for creation of filesystem nodes.
*/