1 /* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)vfs_vnops.c 8.2 (Berkeley) 01/21/94 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/kernel.h> 18 #include <sys/file.h> 19 #include <sys/stat.h> 20 #include <sys/buf.h> 21 #include <sys/proc.h> 22 #include <sys/mount.h> 23 #include <sys/namei.h> 24 #include <sys/vnode.h> 25 #include <sys/ioctl.h> 26 #include <sys/tty.h> 27 28 #include <vm/vm.h> 29 30 struct fileops vnops = 31 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; 32 33 /* 34 * Common code for vnode open operations. 35 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 36 */ 37 vn_open(ndp, fmode, cmode) 38 register struct nameidata *ndp; 39 int fmode, cmode; 40 { 41 register struct vnode *vp; 42 register struct proc *p = ndp->ni_cnd.cn_proc; 43 register struct ucred *cred = p->p_ucred; 44 struct vattr vat; 45 struct vattr *vap = &vat; 46 int error; 47 48 if (fmode & O_CREAT) { 49 ndp->ni_cnd.cn_nameiop = CREATE; 50 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 51 if ((fmode & O_EXCL) == 0) 52 ndp->ni_cnd.cn_flags |= FOLLOW; 53 if (error = namei(ndp)) 54 return (error); 55 if (ndp->ni_vp == NULL) { 56 VATTR_NULL(vap); 57 vap->va_type = VREG; 58 vap->va_mode = cmode; 59 LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE); 60 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 61 &ndp->ni_cnd, vap)) 62 return (error); 63 fmode &= ~O_TRUNC; 64 vp = ndp->ni_vp; 65 } else { 66 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 67 if (ndp->ni_dvp == ndp->ni_vp) 68 vrele(ndp->ni_dvp); 69 else 70 vput(ndp->ni_dvp); 71 ndp->ni_dvp = NULL; 72 vp = ndp->ni_vp; 73 if (fmode & O_EXCL) { 74 error = EEXIST; 75 goto bad; 76 } 77 fmode &= ~O_CREAT; 78 } 79 } else { 80 ndp->ni_cnd.cn_nameiop = LOOKUP; 81 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 82 if (error = namei(ndp)) 83 return (error); 84 vp = ndp->ni_vp; 85 } 86 if (vp->v_type == VSOCK) { 87 error = EOPNOTSUPP; 88 goto bad; 89 } 90 if ((fmode & O_CREAT) == 0) { 91 if (fmode & FREAD) { 92 if (error = VOP_ACCESS(vp, VREAD, cred, p)) 93 goto bad; 94 } 95 if (fmode & (FWRITE | O_TRUNC)) { 96 if (vp->v_type == VDIR) { 97 error = EISDIR; 98 goto bad; 99 } 100 if ((error = vn_writechk(vp)) || 101 (error = VOP_ACCESS(vp, VWRITE, cred, p))) 102 goto bad; 103 } 104 } 105 if (fmode & O_TRUNC) { 106 VOP_UNLOCK(vp); /* XXX */ 107 LEASE_CHECK(vp, p, cred, LEASE_WRITE); 108 VOP_LOCK(vp); /* XXX */ 109 VATTR_NULL(vap); 110 vap->va_size = 0; 111 if (error = VOP_SETATTR(vp, vap, cred, p)) 112 goto bad; 113 } 114 if (error = VOP_OPEN(vp, fmode, cred, p)) 115 goto bad; 116 if (fmode & FWRITE) 117 vp->v_writecount++; 118 return (0); 119 bad: 120 vput(vp); 121 return (error); 122 } 123 124 /* 125 * Check for write permissions on the specified vnode. 126 * The read-only status of the file system is checked. 127 * Also, prototype text segments cannot be written. 128 */ 129 vn_writechk(vp) 130 register struct vnode *vp; 131 { 132 133 /* 134 * Disallow write attempts on read-only file systems; 135 * unless the file is a socket or a block or character 136 * device resident on the file system. 137 */ 138 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 139 switch (vp->v_type) { 140 case VREG: case VDIR: case VLNK: 141 return (EROFS); 142 } 143 } 144 /* 145 * If there's shared text associated with 146 * the vnode, try to free it up once. If 147 * we fail, we can't allow writing. 148 */ 149 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 150 return (ETXTBSY); 151 return (0); 152 } 153 154 /* 155 * Vnode close call 156 */ 157 vn_close(vp, flags, cred, p) 158 register struct vnode *vp; 159 int flags; 160 struct ucred *cred; 161 struct proc *p; 162 { 163 int error; 164 165 if (flags & FWRITE) 166 vp->v_writecount--; 167 error = VOP_CLOSE(vp, flags, cred, p); 168 vrele(vp); 169 return (error); 170 } 171 172 /* 173 * Package up an I/O request on a vnode into a uio and do it. 174 */ 175 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 176 enum uio_rw rw; 177 struct vnode *vp; 178 caddr_t base; 179 int len; 180 off_t offset; 181 enum uio_seg segflg; 182 int ioflg; 183 struct ucred *cred; 184 int *aresid; 185 struct proc *p; 186 { 187 struct uio auio; 188 struct iovec aiov; 189 int error; 190 191 if ((ioflg & IO_NODELOCKED) == 0) 192 VOP_LOCK(vp); 193 auio.uio_iov = &aiov; 194 auio.uio_iovcnt = 1; 195 aiov.iov_base = base; 196 aiov.iov_len = len; 197 auio.uio_resid = len; 198 auio.uio_offset = offset; 199 auio.uio_segflg = segflg; 200 auio.uio_rw = rw; 201 auio.uio_procp = p; 202 if (rw == UIO_READ) { 203 error = VOP_READ(vp, &auio, ioflg, cred); 204 } else { 205 error = VOP_WRITE(vp, &auio, ioflg, cred); 206 } 207 if (aresid) 208 *aresid = auio.uio_resid; 209 else 210 if (auio.uio_resid && error == 0) 211 error = EIO; 212 if ((ioflg & IO_NODELOCKED) == 0) 213 VOP_UNLOCK(vp); 214 return (error); 215 } 216 217 /* 218 * File table vnode read routine. 219 */ 220 vn_read(fp, uio, cred) 221 struct file *fp; 222 struct uio *uio; 223 struct ucred *cred; 224 { 225 register struct vnode *vp = (struct vnode *)fp->f_data; 226 int count, error; 227 228 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ); 229 VOP_LOCK(vp); 230 uio->uio_offset = fp->f_offset; 231 count = uio->uio_resid; 232 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 233 cred); 234 fp->f_offset += count - uio->uio_resid; 235 VOP_UNLOCK(vp); 236 return (error); 237 } 238 239 /* 240 * File table vnode write routine. 241 */ 242 vn_write(fp, uio, cred) 243 struct file *fp; 244 struct uio *uio; 245 struct ucred *cred; 246 { 247 register struct vnode *vp = (struct vnode *)fp->f_data; 248 int count, error, ioflag = 0; 249 250 if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 251 ioflag |= IO_APPEND; 252 if (fp->f_flag & FNONBLOCK) 253 ioflag |= IO_NDELAY; 254 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE); 255 VOP_LOCK(vp); 256 uio->uio_offset = fp->f_offset; 257 count = uio->uio_resid; 258 error = VOP_WRITE(vp, uio, ioflag, cred); 259 if (ioflag & IO_APPEND) 260 fp->f_offset = uio->uio_offset; 261 else 262 fp->f_offset += count - uio->uio_resid; 263 VOP_UNLOCK(vp); 264 return (error); 265 } 266 267 /* 268 * File table vnode stat routine. 269 */ 270 vn_stat(vp, sb, p) 271 struct vnode *vp; 272 register struct stat *sb; 273 struct proc *p; 274 { 275 struct vattr vattr; 276 register struct vattr *vap; 277 int error; 278 u_short mode; 279 280 vap = &vattr; 281 error = VOP_GETATTR(vp, vap, p->p_ucred, p); 282 if (error) 283 return (error); 284 /* 285 * Copy from vattr table 286 */ 287 sb->st_dev = vap->va_fsid; 288 sb->st_ino = vap->va_fileid; 289 mode = vap->va_mode; 290 switch (vp->v_type) { 291 case VREG: 292 mode |= S_IFREG; 293 break; 294 case VDIR: 295 mode |= S_IFDIR; 296 break; 297 case VBLK: 298 mode |= S_IFBLK; 299 break; 300 case VCHR: 301 mode |= S_IFCHR; 302 break; 303 case VLNK: 304 mode |= S_IFLNK; 305 break; 306 case VSOCK: 307 mode |= S_IFSOCK; 308 break; 309 case VFIFO: 310 mode |= S_IFIFO; 311 break; 312 default: 313 return (EBADF); 314 }; 315 sb->st_mode = mode; 316 sb->st_nlink = vap->va_nlink; 317 sb->st_uid = vap->va_uid; 318 sb->st_gid = vap->va_gid; 319 sb->st_rdev = vap->va_rdev; 320 sb->st_size = vap->va_size; 321 sb->st_atimespec = vap->va_atime; 322 sb->st_mtimespec= vap->va_mtime; 323 sb->st_ctimespec = vap->va_ctime; 324 sb->st_blksize = vap->va_blocksize; 325 sb->st_flags = vap->va_flags; 326 sb->st_gen = vap->va_gen; 327 sb->st_blocks = vap->va_bytes / S_BLKSIZE; 328 return (0); 329 } 330 331 /* 332 * File table vnode ioctl routine. 333 */ 334 vn_ioctl(fp, com, data, p) 335 struct file *fp; 336 int com; 337 caddr_t data; 338 struct proc *p; 339 { 340 register struct vnode *vp = ((struct vnode *)fp->f_data); 341 struct vattr vattr; 342 int error; 343 344 switch (vp->v_type) { 345 346 case VREG: 347 case VDIR: 348 if (com == FIONREAD) { 349 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 350 return (error); 351 *(int *)data = vattr.va_size - fp->f_offset; 352 return (0); 353 } 354 if (com == FIONBIO || com == FIOASYNC) /* XXX */ 355 return (0); /* XXX */ 356 /* fall into ... */ 357 358 default: 359 return (ENOTTY); 360 361 case VFIFO: 362 case VCHR: 363 case VBLK: 364 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 365 if (error == 0 && com == TIOCSCTTY) { 366 p->p_session->s_ttyvp = vp; 367 VREF(vp); 368 } 369 return (error); 370 } 371 } 372 373 /* 374 * File table vnode select routine. 375 */ 376 vn_select(fp, which, p) 377 struct file *fp; 378 int which; 379 struct proc *p; 380 { 381 382 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 383 fp->f_cred, p)); 384 } 385 386 /* 387 * File table vnode close routine. 388 */ 389 vn_closefile(fp, p) 390 struct file *fp; 391 struct proc *p; 392 { 393 394 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 395 fp->f_cred, p)); 396 } 397