diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2010-10-28 15:02:42 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2010-10-28 15:02:42 +0000 |
commit | ad39b297930f7aeb9f57f3283cb31dad08c3a9ac (patch) | |
tree | 686235f31d6eb66ef3d8180a61333f611d32602b /sys/kern | |
parent | 24c64c90c25711433236441e0509ebae8231f426 (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.master | 6 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 75 |
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. */ |