1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2015, Joyent, Inc. All rights reserved. 26 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 27 */ 28 29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 /* 33 * Portions of this source code were derived from Berkeley 4.3 BSD 34 * under license from the Regents of the University of California. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/inttypes.h> 40 #include <sys/sysmacros.h> 41 #include <sys/cred.h> 42 #include <sys/user.h> 43 #include <sys/systm.h> 44 #include <sys/errno.h> 45 #include <sys/vnode.h> 46 #include <sys/file.h> 47 #include <sys/proc.h> 48 #include <sys/uio.h> 49 #include <sys/debug.h> 50 51 #include <libfksmbfs.h> 52 53 #define set_errno(e) (-(e)) 54 55 ssize_t 56 fake_pread(vnode_t *vp, void *cbuf, size_t count, off_t offset) 57 { 58 struct uio auio; 59 struct iovec aiov; 60 int fflag, ioflag, rwflag; 61 ssize_t bcount; 62 int error = 0; 63 u_offset_t fileoff = (u_offset_t)(ulong_t)offset; 64 const u_offset_t maxoff = MAXOFF32_T; 65 66 if ((bcount = (ssize_t)count) < 0) 67 return (set_errno(EINVAL)); 68 fflag = FREAD; 69 70 rwflag = 0; 71 72 if (vp->v_type == VREG) { 73 74 if (bcount == 0) 75 goto out; 76 77 /* 78 * Return EINVAL if an invalid offset comes to pread. 79 * Negative offset from user will cause this error. 80 */ 81 82 if (fileoff > maxoff) { 83 error = EINVAL; 84 goto out; 85 } 86 /* 87 * Limit offset such that we don't read or write 88 * a file beyond the maximum offset representable in 89 * an off_t structure. 90 */ 91 if (fileoff + bcount > maxoff) 92 bcount = (ssize_t)((offset_t)maxoff - fileoff); 93 } else if (vp->v_type == VFIFO) { 94 error = ESPIPE; 95 goto out; 96 } 97 98 aiov.iov_base = cbuf; 99 aiov.iov_len = bcount; 100 (void) VOP_RWLOCK(vp, rwflag, NULL); 101 auio.uio_loffset = fileoff; 102 auio.uio_iov = &aiov; 103 auio.uio_iovcnt = 1; 104 auio.uio_resid = bcount; 105 auio.uio_segflg = UIO_USERSPACE; 106 auio.uio_llimit = MAXOFFSET_T; 107 auio.uio_fmode = fflag; 108 auio.uio_extflg = UIO_COPY_CACHED; 109 110 ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 111 112 /* If read sync is not asked for, filter sync flags */ 113 if ((ioflag & FRSYNC) == 0) 114 ioflag &= ~(FSYNC|FDSYNC); 115 error = VOP_READ(vp, &auio, ioflag, CRED(), NULL); 116 bcount -= auio.uio_resid; 117 VOP_RWUNLOCK(vp, rwflag, NULL); 118 119 if (error == EINTR && bcount != 0) 120 error = 0; 121 out: 122 if (error) 123 return (set_errno(error)); 124 return (bcount); 125 } 126 127 ssize_t 128 fake_pwrite(vnode_t *vp, void *cbuf, size_t count, off_t offset) 129 { 130 struct uio auio; 131 struct iovec aiov; 132 int fflag, ioflag, rwflag; 133 ssize_t bcount; 134 int error = 0; 135 u_offset_t fileoff = (u_offset_t)(ulong_t)offset; 136 const u_offset_t maxoff = MAXOFF32_T; 137 138 if ((bcount = (ssize_t)count) < 0) 139 return (set_errno(EINVAL)); 140 fflag = FREAD | FWRITE; 141 142 rwflag = 1; 143 144 if (vp->v_type == VREG) { 145 146 if (bcount == 0) 147 goto out; 148 149 /* 150 * return EINVAL for offsets that cannot be 151 * represented in an off_t. 152 */ 153 if (fileoff > maxoff) { 154 error = EINVAL; 155 goto out; 156 } 157 /* 158 * Don't allow pwrite to cause file sizes to exceed 159 * maxoff. 160 */ 161 if (fileoff == maxoff) { 162 error = EFBIG; 163 goto out; 164 } 165 if (fileoff + count > maxoff) 166 bcount = (ssize_t)((u_offset_t)maxoff - fileoff); 167 } else if (vp->v_type == VFIFO) { 168 error = ESPIPE; 169 goto out; 170 } 171 172 aiov.iov_base = cbuf; 173 aiov.iov_len = bcount; 174 (void) VOP_RWLOCK(vp, rwflag, NULL); 175 auio.uio_loffset = fileoff; 176 auio.uio_iov = &aiov; 177 auio.uio_iovcnt = 1; 178 auio.uio_resid = bcount; 179 auio.uio_segflg = UIO_USERSPACE; 180 auio.uio_llimit = MAXOFFSET_T; 181 auio.uio_fmode = fflag; 182 auio.uio_extflg = UIO_COPY_CACHED; 183 184 /* 185 * The SUSv4 POSIX specification states: 186 * The pwrite() function shall be equivalent to write(), except 187 * that it writes into a given position and does not change 188 * the file offset (regardless of whether O_APPEND is set). 189 * To make this be true, we omit the FAPPEND flag from ioflag. 190 */ 191 ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC); 192 193 error = VOP_WRITE(vp, &auio, ioflag, CRED(), NULL); 194 bcount -= auio.uio_resid; 195 VOP_RWUNLOCK(vp, rwflag, NULL); 196 197 if (error == EINTR && bcount != 0) 198 error = 0; 199 out: 200 if (error) 201 return (set_errno(error)); 202 return (bcount); 203 } 204