1 /* $NetBSD: vfs_syscalls_30.c,v 1.9 2006/05/14 21:24:49 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_30.c,v 1.9 2006/05/14 21:24:49 elad Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/namei.h> 44 #include <sys/filedesc.h> 45 #include <sys/kernel.h> 46 #include <sys/file.h> 47 #include <sys/stat.h> 48 #include <sys/socketvar.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/dirent.h> 54 #include <sys/malloc.h> 55 #include <sys/kauth.h> 56 57 #include <sys/sa.h> 58 #include <sys/syscallargs.h> 59 60 #include <compat/common/compat_util.h> 61 #include <compat/sys/stat.h> 62 #include <compat/sys/dirent.h> 63 64 static void cvtstat(struct stat13 *, const struct stat *); 65 66 /* 67 * Convert from a new to an old stat structure. 68 */ 69 static void 70 cvtstat(struct stat13 *ost, const struct stat *st) 71 { 72 73 ost->st_dev = st->st_dev; 74 ost->st_ino = (uint32_t)st->st_ino; 75 ost->st_mode = st->st_mode; 76 ost->st_nlink = st->st_nlink; 77 ost->st_uid = st->st_uid; 78 ost->st_gid = st->st_gid; 79 ost->st_rdev = st->st_rdev; 80 ost->st_atimespec = st->st_atimespec; 81 ost->st_mtimespec = st->st_mtimespec; 82 ost->st_ctimespec = st->st_ctimespec; 83 ost->st_birthtimespec = st->st_birthtimespec; 84 ost->st_size = st->st_size; 85 ost->st_blocks = st->st_blocks; 86 ost->st_blksize = st->st_blksize; 87 ost->st_flags = st->st_flags; 88 ost->st_gen = st->st_gen; 89 } 90 91 /* 92 * Get file status; this version follows links. 93 */ 94 /* ARGSUSED */ 95 int 96 compat_30_sys___stat13(struct lwp *l, void *v, register_t *retval) 97 { 98 struct compat_30_sys___stat13_args /* { 99 syscallarg(const char *) path; 100 syscallarg(struct stat13 *) ub; 101 } */ *uap = v; 102 struct stat sb; 103 struct stat13 osb; 104 int error; 105 struct nameidata nd; 106 107 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 108 SCARG(uap, path), l); 109 if ((error = namei(&nd)) != 0) 110 return error; 111 error = vn_stat(nd.ni_vp, &sb, l); 112 vput(nd.ni_vp); 113 if (error) 114 return error; 115 cvtstat(&osb, &sb); 116 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 117 return error; 118 } 119 120 121 /* 122 * Get file status; this version does not follow links. 123 */ 124 /* ARGSUSED */ 125 int 126 compat_30_sys___lstat13(struct lwp *l, void *v, register_t *retval) 127 { 128 struct compat_30_sys___lstat13_args /* { 129 syscallarg(const char *) path; 130 syscallarg(struct stat13 *) ub; 131 } */ *uap = v; 132 struct stat sb; 133 struct stat13 osb; 134 int error; 135 struct nameidata nd; 136 137 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 138 SCARG(uap, path), l); 139 if ((error = namei(&nd)) != 0) 140 return error; 141 error = vn_stat(nd.ni_vp, &sb, l); 142 vput(nd.ni_vp); 143 if (error) 144 return error; 145 cvtstat(&osb, &sb); 146 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 147 return error; 148 } 149 150 /* ARGSUSED */ 151 int 152 compat_30_sys_fhstat(struct lwp *l, void *v, register_t *retval) 153 { 154 struct compat_30_sys_fhstat_args /* { 155 syscallarg(const fhandle_t *) fhp; 156 syscallarg(struct stat13 *) sb; 157 } */ *uap = v; 158 struct proc *p = l->l_proc; 159 struct stat sb; 160 struct stat13 osb; 161 int error; 162 fhandle_t fh; 163 struct mount *mp; 164 struct vnode *vp; 165 166 /* 167 * Must be super user 168 */ 169 if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, 170 &p->p_acflag))) 171 return (error); 172 173 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 174 return (error); 175 176 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 177 return (ESTALE); 178 if (mp->mnt_op->vfs_fhtovp == NULL) 179 return EOPNOTSUPP; 180 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 181 return (error); 182 error = vn_stat(vp, &sb, l); 183 vput(vp); 184 if (error) 185 return (error); 186 cvtstat(&osb, &sb); 187 error = copyout(&osb, SCARG(uap, sb), sizeof(sb)); 188 return (error); 189 } 190 191 /* 192 * Return status information about a file descriptor. 193 */ 194 /* ARGSUSED */ 195 int 196 compat_30_sys___fstat13(struct lwp *l, void *v, register_t *retval) 197 { 198 struct compat_30_sys___fstat13_args /* { 199 syscallarg(int) fd; 200 syscallarg(struct stat13 *) sb; 201 } */ *uap = v; 202 struct proc *p = l->l_proc; 203 int fd = SCARG(uap, fd); 204 struct filedesc *fdp = p->p_fd; 205 struct file *fp; 206 struct stat sb; 207 struct stat13 osb; 208 int error; 209 210 if ((fp = fd_getfile(fdp, fd)) == NULL) 211 return EBADF; 212 213 FILE_USE(fp); 214 error = (*fp->f_ops->fo_stat)(fp, &sb, l); 215 FILE_UNUSE(fp, l); 216 217 if (error) 218 return error; 219 cvtstat(&osb, &sb); 220 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 221 return error; 222 } 223 224 /* 225 * Read a block of directory entries in a file system independent format. 226 */ 227 int 228 compat_30_sys_getdents(struct lwp *l, void *v, register_t *retval) 229 { 230 struct compat_30_sys_getdents_args /* { 231 syscallarg(int) fd; 232 syscallarg(char *) buf; 233 syscallarg(size_t) count; 234 } */ *uap = v; 235 struct proc *p = l->l_proc; 236 struct dirent *bdp; 237 struct vnode *vp; 238 caddr_t inp, tbuf; /* BSD-format */ 239 int len, reclen; /* BSD-format */ 240 caddr_t outp; /* NetBSD-3.0-format */ 241 int resid; 242 struct file *fp; 243 struct uio auio; 244 struct iovec aiov; 245 struct dirent12 idb; 246 off_t off; /* true file offset */ 247 int buflen, error, eofflag; 248 off_t *cookiebuf = NULL, *cookie; 249 int ncookies; 250 251 /* getvnode() will use the descriptor for us */ 252 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 253 return error; 254 255 if ((fp->f_flag & FREAD) == 0) { 256 error = EBADF; 257 goto out1; 258 } 259 260 vp = (struct vnode *)fp->f_data; 261 if (vp->v_type != VDIR) { 262 error = EINVAL; 263 goto out1; 264 } 265 266 buflen = min(MAXBSIZE, SCARG(uap, count)); 267 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 268 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 269 off = fp->f_offset; 270 again: 271 aiov.iov_base = tbuf; 272 aiov.iov_len = buflen; 273 auio.uio_iov = &aiov; 274 auio.uio_iovcnt = 1; 275 auio.uio_rw = UIO_READ; 276 auio.uio_resid = buflen; 277 auio.uio_offset = off; 278 UIO_SETUP_SYSSPACE(&auio); 279 /* 280 * First we read into the malloc'ed buffer, then 281 * we massage it into user space, one record at a time. 282 */ 283 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 284 &ncookies); 285 if (error) 286 goto out; 287 288 inp = tbuf; 289 outp = SCARG(uap, buf); 290 resid = SCARG(uap, count); 291 if ((len = buflen - auio.uio_resid) == 0) 292 goto eof; 293 294 for (cookie = cookiebuf; len > 0; len -= reclen) { 295 bdp = (struct dirent *)inp; 296 reclen = bdp->d_reclen; 297 if (reclen & _DIRENT_ALIGN(bdp)) 298 panic("netbsd30_getdents: bad reclen %d", reclen); 299 if (cookie) 300 off = *cookie++; /* each entry points to the next */ 301 else 302 off += reclen; 303 if ((off >> 32) != 0) { 304 compat_offseterr(vp, "netbsd30_getdents"); 305 error = EINVAL; 306 goto out; 307 } 308 if (bdp->d_namlen >= sizeof(idb.d_name)) 309 idb.d_namlen = sizeof(idb.d_name) - 1; 310 else 311 idb.d_namlen = bdp->d_namlen; 312 idb.d_reclen = _DIRENT_SIZE(&idb); 313 if (reclen > len || resid < idb.d_reclen) { 314 /* entry too big for buffer, so just stop */ 315 outp++; 316 break; 317 } 318 /* 319 * Massage in place to make a NetBSD-3.0-shaped dirent 320 * (otherwise we have to worry about touching user memory 321 * outside of the copyout() call). 322 */ 323 idb.d_fileno = (u_int32_t)bdp->d_fileno; 324 idb.d_type = bdp->d_type; 325 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 326 memset(idb.d_name + idb.d_namlen, 0, 327 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 328 if ((error = copyout(&idb, outp, idb.d_reclen)) != 0) 329 goto out; 330 /* advance past this real entry */ 331 inp += reclen; 332 /* advance output past NetBSD-3.0-shaped entry */ 333 outp += idb.d_reclen; 334 resid -= idb.d_reclen; 335 } 336 337 /* if we squished out the whole block, try again */ 338 if (outp == SCARG(uap, buf)) 339 goto again; 340 fp->f_offset = off; /* update the vnode offset */ 341 342 eof: 343 *retval = SCARG(uap, count) - resid; 344 out: 345 VOP_UNLOCK(vp, 0); 346 if (cookiebuf) 347 free(cookiebuf, M_TEMP); 348 free(tbuf, M_TEMP); 349 out1: 350 FILE_UNUSE(fp, l); 351 return error; 352 } 353