1 /* $NetBSD: vfs_syscalls_12.c,v 1.37 2019/01/27 02:08:39 pgoyette Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * From: @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_12.c,v 1.37 2019/01/27 02:08:39 pgoyette Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_compat_netbsd.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/namei.h> 49 #include <sys/filedesc.h> 50 #include <sys/kernel.h> 51 #include <sys/file.h> 52 #include <sys/stat.h> 53 #include <sys/socketvar.h> 54 #include <sys/vnode.h> 55 #include <sys/proc.h> 56 #include <sys/uio.h> 57 #include <sys/dirent.h> 58 #include <sys/vfs_syscalls.h> 59 60 #include <sys/syscall.h> 61 #include <sys/syscallvar.h> 62 #include <sys/syscallargs.h> 63 64 #include <compat/sys/stat.h> 65 #include <compat/sys/dirent.h> 66 67 #include <compat/common/compat_mod.h> 68 69 static const struct syscall_package vfs_syscalls_12_syscalls[] = { 70 { SYS_compat_12_fstat12, 0, (sy_call_t *)compat_12_sys_fstat }, 71 { SYS_compat_12_getdirentries, 0, 72 (sy_call_t *)compat_12_sys_getdirentries }, 73 { SYS_compat_12_lstat12, 0, (sy_call_t *)compat_12_sys_lstat }, 74 { SYS_compat_12_stat12, 0, (sy_call_t *)compat_12_sys_stat }, 75 { 0, 0, NULL } 76 }; 77 78 /* 79 * Convert from a new to an old stat structure. 80 */ 81 void 82 compat_12_stat_conv(const struct stat *st, struct stat12 *ost) 83 { 84 85 ost->st_dev = st->st_dev; 86 ost->st_ino = st->st_ino; 87 ost->st_mode = st->st_mode & 0xffff; 88 if (st->st_nlink >= (1 << 15)) 89 ost->st_nlink = (1 << 15) - 1; 90 else 91 ost->st_nlink = st->st_nlink; 92 ost->st_uid = st->st_uid; 93 ost->st_gid = st->st_gid; 94 ost->st_rdev = st->st_rdev; 95 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 96 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 97 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 98 ost->st_size = st->st_size; 99 ost->st_blocks = st->st_blocks; 100 ost->st_blksize = st->st_blksize; 101 ost->st_flags = st->st_flags; 102 ost->st_gen = st->st_gen; 103 } 104 105 /* 106 * Read a block of directory entries in a file system independent format. 107 */ 108 int 109 compat_12_sys_getdirentries(struct lwp *l, 110 const struct compat_12_sys_getdirentries_args *uap, register_t *retval) 111 { 112 /* { 113 syscallarg(int) fd; 114 syscallarg(char *) buf; 115 syscallarg(u_int) count; 116 syscallarg(long *) basep; 117 } */ 118 struct dirent *bdp; 119 struct vnode *vp; 120 char *inp, *tbuf; /* Current-format */ 121 int len, reclen; /* Current-format */ 122 char *outp; /* Dirent12-format */ 123 int resid, old_reclen = 0; /* Dirent12-format */ 124 struct file *fp; 125 struct uio auio; 126 struct iovec aiov; 127 struct dirent12 idb; 128 off_t off; /* true file offset */ 129 int buflen, error, eofflag, nbytes; 130 struct vattr va; 131 off_t *cookiebuf = NULL, *cookie; 132 int ncookies; 133 long loff; 134 135 /* fd_getvnode() will use the descriptor for us */ 136 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 137 return (error); 138 139 if ((fp->f_flag & FREAD) == 0) { 140 error = EBADF; 141 goto out1; 142 } 143 144 vp = (struct vnode *)fp->f_vnode; 145 if (vp->v_type != VDIR) { 146 error = ENOTDIR; 147 goto out1; 148 } 149 150 vn_lock(vp, LK_SHARED | LK_RETRY); 151 error = VOP_GETATTR(vp, &va, l->l_cred); 152 VOP_UNLOCK(vp); 153 if (error) 154 goto out1; 155 156 loff = fp->f_offset; 157 nbytes = SCARG(uap, count); 158 buflen = uimin(MAXBSIZE, nbytes); 159 if (buflen < va.va_blocksize) 160 buflen = va.va_blocksize; 161 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 162 163 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 164 off = fp->f_offset; 165 again: 166 aiov.iov_base = tbuf; 167 aiov.iov_len = buflen; 168 auio.uio_iov = &aiov; 169 auio.uio_iovcnt = 1; 170 auio.uio_rw = UIO_READ; 171 auio.uio_resid = buflen; 172 auio.uio_offset = off; 173 UIO_SETUP_SYSSPACE(&auio); 174 /* 175 * First we read into the malloc'ed buffer, then 176 * we massage it into user space, one record at a time. 177 */ 178 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 179 &ncookies); 180 if (error) 181 goto out; 182 183 inp = tbuf; 184 outp = SCARG(uap, buf); 185 resid = nbytes; 186 if ((len = buflen - auio.uio_resid) == 0) 187 goto eof; 188 189 for (cookie = cookiebuf; len > 0; len -= reclen) { 190 bdp = (struct dirent *)inp; 191 reclen = bdp->d_reclen; 192 if (reclen & 3) { 193 error = EIO; 194 goto out; 195 } 196 if (bdp->d_fileno == 0) { 197 inp += reclen; /* it is a hole; squish it out */ 198 if (cookie) 199 off = *cookie++; 200 else 201 off += reclen; 202 continue; 203 } 204 if (bdp->d_namlen >= sizeof(idb.d_name)) 205 idb.d_namlen = sizeof(idb.d_name) - 1; 206 else 207 idb.d_namlen = bdp->d_namlen; 208 old_reclen = _DIRENT_RECLEN(&idb, bdp->d_namlen); 209 if (reclen > len || resid < old_reclen) { 210 /* entry too big for buffer, so just stop */ 211 outp++; 212 break; 213 } 214 /* 215 * Massage in place to make a Dirent12-shaped dirent (otherwise 216 * we have to worry about touching user memory outside of 217 * the copyout() call). 218 */ 219 idb.d_fileno = (uint32_t)bdp->d_fileno; 220 idb.d_reclen = (uint16_t)old_reclen; 221 idb.d_type = (uint8_t)bdp->d_type; 222 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 223 memset(idb.d_name + idb.d_namlen, 0, 224 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 225 if ((error = copyout(&idb, outp, old_reclen))) 226 goto out; 227 /* advance past this real entry */ 228 inp += reclen; 229 if (cookie) 230 off = *cookie++; /* each entry points to itself */ 231 else 232 off += reclen; 233 /* advance output past Dirent12-shaped entry */ 234 outp += old_reclen; 235 resid -= old_reclen; 236 } 237 238 /* if we squished out the whole block, try again */ 239 if (outp == SCARG(uap, buf)) { 240 if (cookiebuf) 241 free(cookiebuf, M_TEMP); 242 cookiebuf = NULL; 243 goto again; 244 } 245 fp->f_offset = off; /* update the vnode offset */ 246 247 eof: 248 *retval = nbytes - resid; 249 out: 250 VOP_UNLOCK(vp); 251 if (cookiebuf) 252 free(cookiebuf, M_TEMP); 253 free(tbuf, M_TEMP); 254 out1: 255 fd_putfile(SCARG(uap, fd)); 256 if (error) 257 return error; 258 return copyout(&loff, SCARG(uap, basep), sizeof(long)); 259 } 260 261 /* 262 * Get file status; this version follows links. 263 */ 264 /* ARGSUSED */ 265 int 266 compat_12_sys_stat(struct lwp *l, const struct compat_12_sys_stat_args *uap, 267 register_t *retval) 268 { 269 /* { 270 syscallarg(const char *) path; 271 syscallarg(struct stat12 *) ub; 272 } */ 273 struct stat sb; 274 struct stat12 osb; 275 int error; 276 277 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 278 if (error) 279 return (error); 280 compat_12_stat_conv(&sb, &osb); 281 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 282 return (error); 283 } 284 285 286 /* 287 * Get file status; this version does not follow links. 288 */ 289 /* ARGSUSED */ 290 int 291 compat_12_sys_lstat(struct lwp *l, const struct compat_12_sys_lstat_args *uap, 292 register_t *retval) 293 { 294 /* { 295 syscallarg(const char *) path; 296 syscallarg(struct stat12 *) ub; 297 } */ 298 struct stat sb; 299 struct stat12 osb; 300 int error; 301 302 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 303 if (error) 304 return (error); 305 compat_12_stat_conv(&sb, &osb); 306 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 307 return (error); 308 } 309 310 /* 311 * Return status information about a file descriptor. 312 */ 313 /* ARGSUSED */ 314 int 315 compat_12_sys_fstat(struct lwp *l, const struct compat_12_sys_fstat_args *uap, 316 register_t *retval) 317 { 318 /* { 319 syscallarg(int) fd; 320 syscallarg(struct stat12 *) sb; 321 } */ 322 struct stat ub; 323 struct stat12 oub; 324 int error; 325 326 error = do_sys_fstat(SCARG(uap, fd), &ub); 327 if (error == 0) { 328 compat_12_stat_conv(&ub, &oub); 329 error = copyout(&oub, SCARG(uap, sb), sizeof (oub)); 330 } 331 return (error); 332 } 333 334 int 335 vfs_syscalls_12_init(void) 336 { 337 338 return syscall_establish(NULL, vfs_syscalls_12_syscalls); 339 } 340 341 int 342 vfs_syscalls_12_fini(void) 343 { 344 345 return syscall_disestablish(NULL, vfs_syscalls_12_syscalls); 346 } 347