1 /* $NetBSD: vfs_syscalls_12.c,v 1.38 2021/09/07 11:43:02 riastradh 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.38 2021/09/07 11:43:02 riastradh 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 memset(ost, 0, sizeof(*ost)); 86 ost->st_dev = st->st_dev; 87 ost->st_ino = st->st_ino; 88 ost->st_mode = st->st_mode & 0xffff; 89 if (st->st_nlink >= (1 << 15)) 90 ost->st_nlink = (1 << 15) - 1; 91 else 92 ost->st_nlink = st->st_nlink; 93 ost->st_uid = st->st_uid; 94 ost->st_gid = st->st_gid; 95 ost->st_rdev = st->st_rdev; 96 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 97 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 98 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 99 ost->st_size = st->st_size; 100 ost->st_blocks = st->st_blocks; 101 ost->st_blksize = st->st_blksize; 102 ost->st_flags = st->st_flags; 103 ost->st_gen = st->st_gen; 104 } 105 106 /* 107 * Read a block of directory entries in a file system independent format. 108 */ 109 int 110 compat_12_sys_getdirentries(struct lwp *l, 111 const struct compat_12_sys_getdirentries_args *uap, register_t *retval) 112 { 113 /* { 114 syscallarg(int) fd; 115 syscallarg(char *) buf; 116 syscallarg(u_int) count; 117 syscallarg(long *) basep; 118 } */ 119 struct dirent *bdp; 120 struct vnode *vp; 121 char *inp, *tbuf; /* Current-format */ 122 int len, reclen; /* Current-format */ 123 char *outp; /* Dirent12-format */ 124 int resid, old_reclen = 0; /* Dirent12-format */ 125 struct file *fp; 126 struct uio auio; 127 struct iovec aiov; 128 struct dirent12 idb; 129 off_t off; /* true file offset */ 130 int buflen, error, eofflag, nbytes; 131 struct vattr va; 132 off_t *cookiebuf = NULL, *cookie; 133 int ncookies; 134 long loff; 135 136 /* fd_getvnode() will use the descriptor for us */ 137 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 138 return (error); 139 140 if ((fp->f_flag & FREAD) == 0) { 141 error = EBADF; 142 goto out1; 143 } 144 145 vp = (struct vnode *)fp->f_vnode; 146 if (vp->v_type != VDIR) { 147 error = ENOTDIR; 148 goto out1; 149 } 150 151 vn_lock(vp, LK_SHARED | LK_RETRY); 152 error = VOP_GETATTR(vp, &va, l->l_cred); 153 VOP_UNLOCK(vp); 154 if (error) 155 goto out1; 156 157 loff = fp->f_offset; 158 nbytes = SCARG(uap, count); 159 buflen = uimin(MAXBSIZE, nbytes); 160 if (buflen < va.va_blocksize) 161 buflen = va.va_blocksize; 162 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 163 164 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 165 off = fp->f_offset; 166 again: 167 aiov.iov_base = tbuf; 168 aiov.iov_len = buflen; 169 auio.uio_iov = &aiov; 170 auio.uio_iovcnt = 1; 171 auio.uio_rw = UIO_READ; 172 auio.uio_resid = buflen; 173 auio.uio_offset = off; 174 UIO_SETUP_SYSSPACE(&auio); 175 /* 176 * First we read into the malloc'ed buffer, then 177 * we massage it into user space, one record at a time. 178 */ 179 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 180 &ncookies); 181 if (error) 182 goto out; 183 184 inp = tbuf; 185 outp = SCARG(uap, buf); 186 resid = nbytes; 187 if ((len = buflen - auio.uio_resid) == 0) 188 goto eof; 189 190 for (cookie = cookiebuf; len > 0; len -= reclen) { 191 bdp = (struct dirent *)inp; 192 reclen = bdp->d_reclen; 193 if (reclen & 3) { 194 error = EIO; 195 goto out; 196 } 197 if (bdp->d_fileno == 0) { 198 inp += reclen; /* it is a hole; squish it out */ 199 if (cookie) 200 off = *cookie++; 201 else 202 off += reclen; 203 continue; 204 } 205 memset(&idb, 0, sizeof(idb)); 206 if (bdp->d_namlen >= sizeof(idb.d_name)) 207 idb.d_namlen = sizeof(idb.d_name) - 1; 208 else 209 idb.d_namlen = bdp->d_namlen; 210 old_reclen = _DIRENT_RECLEN(&idb, bdp->d_namlen); 211 if (reclen > len || resid < old_reclen) { 212 /* entry too big for buffer, so just stop */ 213 outp++; 214 break; 215 } 216 /* 217 * Massage in place to make a Dirent12-shaped dirent (otherwise 218 * we have to worry about touching user memory outside of 219 * the copyout() call). 220 */ 221 idb.d_fileno = (uint32_t)bdp->d_fileno; 222 idb.d_reclen = (uint16_t)old_reclen; 223 idb.d_type = (uint8_t)bdp->d_type; 224 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 225 memset(idb.d_name + idb.d_namlen, 0, 226 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 227 if ((error = copyout(&idb, outp, old_reclen))) 228 goto out; 229 /* advance past this real entry */ 230 inp += reclen; 231 if (cookie) 232 off = *cookie++; /* each entry points to itself */ 233 else 234 off += reclen; 235 /* advance output past Dirent12-shaped entry */ 236 outp += old_reclen; 237 resid -= old_reclen; 238 } 239 240 /* if we squished out the whole block, try again */ 241 if (outp == SCARG(uap, buf)) { 242 if (cookiebuf) 243 free(cookiebuf, M_TEMP); 244 cookiebuf = NULL; 245 goto again; 246 } 247 fp->f_offset = off; /* update the vnode offset */ 248 249 eof: 250 *retval = nbytes - resid; 251 out: 252 VOP_UNLOCK(vp); 253 if (cookiebuf) 254 free(cookiebuf, M_TEMP); 255 free(tbuf, M_TEMP); 256 out1: 257 fd_putfile(SCARG(uap, fd)); 258 if (error) 259 return error; 260 return copyout(&loff, SCARG(uap, basep), sizeof(long)); 261 } 262 263 /* 264 * Get file status; this version follows links. 265 */ 266 /* ARGSUSED */ 267 int 268 compat_12_sys_stat(struct lwp *l, const struct compat_12_sys_stat_args *uap, 269 register_t *retval) 270 { 271 /* { 272 syscallarg(const char *) path; 273 syscallarg(struct stat12 *) ub; 274 } */ 275 struct stat sb; 276 struct stat12 osb; 277 int error; 278 279 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 280 if (error) 281 return (error); 282 compat_12_stat_conv(&sb, &osb); 283 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 284 return (error); 285 } 286 287 288 /* 289 * Get file status; this version does not follow links. 290 */ 291 /* ARGSUSED */ 292 int 293 compat_12_sys_lstat(struct lwp *l, const struct compat_12_sys_lstat_args *uap, 294 register_t *retval) 295 { 296 /* { 297 syscallarg(const char *) path; 298 syscallarg(struct stat12 *) ub; 299 } */ 300 struct stat sb; 301 struct stat12 osb; 302 int error; 303 304 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 305 if (error) 306 return (error); 307 compat_12_stat_conv(&sb, &osb); 308 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 309 return (error); 310 } 311 312 /* 313 * Return status information about a file descriptor. 314 */ 315 /* ARGSUSED */ 316 int 317 compat_12_sys_fstat(struct lwp *l, const struct compat_12_sys_fstat_args *uap, 318 register_t *retval) 319 { 320 /* { 321 syscallarg(int) fd; 322 syscallarg(struct stat12 *) sb; 323 } */ 324 struct stat ub; 325 struct stat12 oub; 326 int error; 327 328 error = do_sys_fstat(SCARG(uap, fd), &ub); 329 if (error == 0) { 330 compat_12_stat_conv(&ub, &oub); 331 error = copyout(&oub, SCARG(uap, sb), sizeof (oub)); 332 } 333 return (error); 334 } 335 336 int 337 vfs_syscalls_12_init(void) 338 { 339 340 return syscall_establish(NULL, vfs_syscalls_12_syscalls); 341 } 342 343 int 344 vfs_syscalls_12_fini(void) 345 { 346 347 return syscall_disestablish(NULL, vfs_syscalls_12_syscalls); 348 } 349