1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2000 5 * Poul-Henning Kamp. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 32 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 33 * 34 * $FreeBSD$ 35 */ 36 37 /* 38 * TODO: 39 * remove empty directories 40 * mknod: hunt down DE_DELETED, compare name, reinstantiate. 41 * mkdir: want it ? 42 */ 43 44 #include <opt_devfs.h> 45 #ifndef NODEVFS 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/conf.h> 50 #include <sys/dirent.h> 51 #include <sys/kernel.h> 52 #include <sys/lock.h> 53 #include <sys/malloc.h> 54 #include <sys/mount.h> 55 #include <sys/namei.h> 56 #include <sys/proc.h> 57 #include <sys/time.h> 58 #include <sys/unistd.h> 59 #include <sys/vnode.h> 60 61 #include <fs/devfs/devfs.h> 62 63 static int devfs_access __P((struct vop_access_args *ap)); 64 static int devfs_getattr __P((struct vop_getattr_args *ap)); 65 static int devfs_lookupx __P((struct vop_lookup_args *ap)); 66 static int devfs_mknod __P((struct vop_mknod_args *ap)); 67 static int devfs_pathconf __P((struct vop_pathconf_args *ap)); 68 static int devfs_print __P((struct vop_print_args *ap)); 69 static int devfs_read __P((struct vop_read_args *ap)); 70 static int devfs_readdir __P((struct vop_readdir_args *ap)); 71 static int devfs_readlink __P((struct vop_readlink_args *ap)); 72 static int devfs_reclaim __P((struct vop_reclaim_args *ap)); 73 static int devfs_remove __P((struct vop_remove_args *ap)); 74 static int devfs_revoke __P((struct vop_revoke_args *ap)); 75 static int devfs_setattr __P((struct vop_setattr_args *ap)); 76 static int devfs_symlink __P((struct vop_symlink_args *ap)); 77 78 /* 79 * Construct the fully qualified path name relative to the mountpoint 80 */ 81 static char * 82 devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp) 83 { 84 int i; 85 struct devfs_dirent *de, *dd; 86 struct devfs_mount *dmp; 87 88 dmp = VFSTODEVFS(dvp->v_mount); 89 dd = dvp->v_data; 90 i = SPECNAMELEN; 91 buf[i] = '\0'; 92 i -= cnp->cn_namelen; 93 if (i < 0) 94 return (NULL); 95 bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); 96 de = dd; 97 while (de != dmp->dm_basedir) { 98 i--; 99 if (i < 0) 100 return (NULL); 101 buf[i] = '/'; 102 i -= de->de_dirent->d_namlen; 103 if (i < 0) 104 return (NULL); 105 bcopy(de->de_dirent->d_name, buf + i, 106 de->de_dirent->d_namlen); 107 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 108 de = TAILQ_NEXT(de, de_list); /* ".." */ 109 de = de->de_dir; 110 } 111 return (buf + i); 112 } 113 114 int 115 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td) 116 { 117 int error; 118 struct vnode *vp; 119 dev_t dev; 120 121 if (td == NULL) 122 td = curthread; /* XXX */ 123 loop: 124 vp = de->de_vnode; 125 if (vp != NULL) { 126 if (vget(vp, LK_EXCLUSIVE, td ? td : curthread)) 127 goto loop; 128 *vpp = vp; 129 return (0); 130 } 131 if (de->de_dirent->d_type == DT_CHR) { 132 dev = *devfs_itod(de->de_inode); 133 if (dev == NULL) 134 return (ENOENT); 135 } else { 136 dev = NODEV; 137 } 138 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp); 139 if (error != 0) { 140 printf("devfs_allocv: failed to allocate new vnode\n"); 141 return (error); 142 } 143 144 if (de->de_dirent->d_type == DT_CHR) { 145 vp->v_type = VCHR; 146 vp = addaliasu(vp, dev->si_udev); 147 vp->v_op = devfs_specop_p; 148 } else if (de->de_dirent->d_type == DT_DIR) { 149 vp->v_type = VDIR; 150 } else if (de->de_dirent->d_type == DT_LNK) { 151 vp->v_type = VLNK; 152 } else { 153 vp->v_type = VBAD; 154 } 155 vp->v_data = de; 156 de->de_vnode = vp; 157 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 158 *vpp = vp; 159 return (0); 160 } 161 162 static int 163 devfs_access(ap) 164 struct vop_access_args /* { 165 struct vnode *a_vp; 166 int a_mode; 167 struct ucred *a_cred; 168 struct thread *a_td; 169 } */ *ap; 170 { 171 struct vnode *vp = ap->a_vp; 172 struct devfs_dirent *de; 173 174 de = vp->v_data; 175 if (vp->v_type == VDIR) 176 de = de->de_dir; 177 178 return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 179 ap->a_mode, ap->a_cred, NULL)); 180 } 181 182 static int 183 devfs_getattr(ap) 184 struct vop_getattr_args /* { 185 struct vnode *a_vp; 186 struct vattr *a_vap; 187 struct ucred *a_cred; 188 struct thread *a_td; 189 } */ *ap; 190 { 191 struct vnode *vp = ap->a_vp; 192 struct vattr *vap = ap->a_vap; 193 int error = 0; 194 struct devfs_dirent *de; 195 dev_t dev; 196 197 de = vp->v_data; 198 if (vp->v_type == VDIR) 199 de = de->de_dir; 200 bzero((caddr_t) vap, sizeof(*vap)); 201 vattr_null(vap); 202 vap->va_uid = de->de_uid; 203 vap->va_gid = de->de_gid; 204 vap->va_mode = de->de_mode; 205 if (vp->v_type == VLNK) 206 vap->va_size = de->de_dirent->d_namlen; 207 else if (vp->v_type == VDIR) 208 vap->va_size = vap->va_bytes = DEV_BSIZE; 209 else 210 vap->va_size = 0; 211 if (vp->v_type != VDIR) 212 vap->va_bytes = 0; 213 vap->va_blocksize = DEV_BSIZE; 214 vap->va_type = vp->v_type; 215 216 #define fix(aa) \ 217 do { \ 218 if ((aa).tv_sec == 0) { \ 219 (aa).tv_sec = boottime.tv_sec; \ 220 (aa).tv_nsec = boottime.tv_usec * 1000; \ 221 } \ 222 } while (0) 223 224 if (vp->v_type != VCHR) { 225 fix(de->de_atime); 226 vap->va_atime = de->de_atime; 227 fix(de->de_mtime); 228 vap->va_mtime = de->de_mtime; 229 fix(de->de_ctime); 230 vap->va_ctime = de->de_ctime; 231 } else { 232 dev = vp->v_rdev; 233 fix(dev->si_atime); 234 vap->va_atime = dev->si_atime; 235 fix(dev->si_mtime); 236 vap->va_mtime = dev->si_mtime; 237 fix(dev->si_ctime); 238 vap->va_ctime = dev->si_ctime; 239 vap->va_rdev = dev->si_udev; 240 } 241 vap->va_gen = 0; 242 vap->va_flags = 0; 243 vap->va_nlink = de->de_links; 244 vap->va_fileid = de->de_inode; 245 246 return (error); 247 } 248 249 static int 250 devfs_lookupx(ap) 251 struct vop_lookup_args /* { 252 struct vnode * a_dvp; 253 struct vnode ** a_vpp; 254 struct componentname * a_cnp; 255 } */ *ap; 256 { 257 struct componentname *cnp; 258 struct vnode *dvp, **vpp; 259 struct thread *td; 260 struct devfs_dirent *de, *dd; 261 struct devfs_mount *dmp; 262 dev_t cdev, *cpdev; 263 int error, cloned, flags, nameiop; 264 char specname[SPECNAMELEN + 1], *pname; 265 266 cnp = ap->a_cnp; 267 vpp = ap->a_vpp; 268 dvp = ap->a_dvp; 269 pname = cnp->cn_nameptr; 270 td = cnp->cn_thread; 271 flags = cnp->cn_flags; 272 nameiop = cnp->cn_nameiop; 273 dmp = VFSTODEVFS(dvp->v_mount); 274 cloned = 0; 275 dd = dvp->v_data; 276 277 *vpp = NULLVP; 278 279 if (nameiop == RENAME) 280 return (EOPNOTSUPP); 281 282 if (dvp->v_type != VDIR) 283 return (ENOTDIR); 284 285 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) 286 return (EIO); 287 288 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 289 if (error) 290 return (error); 291 292 if (cnp->cn_namelen == 1 && *pname == '.') { 293 if (nameiop != LOOKUP) 294 return (EINVAL); 295 *vpp = dvp; 296 VREF(dvp); 297 return (0); 298 } 299 300 if (flags & ISDOTDOT) { 301 if (nameiop != LOOKUP) 302 return (EINVAL); 303 VOP_UNLOCK(dvp, 0, td); 304 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 305 de = TAILQ_NEXT(de, de_list); /* ".." */ 306 de = de->de_dir; 307 error = devfs_allocv(de, dvp->v_mount, vpp, td); 308 if (error) { 309 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 310 return (error); 311 } 312 if ((flags & LOCKPARENT) && (flags & ISLASTCN)) 313 error = vn_lock(dvp, LK_EXCLUSIVE, td); 314 if (error) 315 vput(*vpp); 316 return (error); 317 } 318 319 devfs_populate(dmp); 320 dd = dvp->v_data; 321 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 322 if (cnp->cn_namelen != de->de_dirent->d_namlen) 323 continue; 324 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 325 de->de_dirent->d_namlen) != 0) 326 continue; 327 if (de->de_flags & DE_WHITEOUT) 328 goto notfound; 329 goto found; 330 } 331 332 if (nameiop == DELETE) 333 goto notfound; 334 335 /* 336 * OK, we didn't have an entry for the name we were asked for 337 * so we try to see if anybody can create it on demand. 338 */ 339 pname = devfs_fqpn(specname, dvp, cnp); 340 if (pname == NULL) 341 goto notfound; 342 343 cdev = NODEV; 344 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev); 345 if (cdev == NODEV) 346 goto notfound; 347 348 devfs_populate(dmp); 349 dd = dvp->v_data; 350 351 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 352 cpdev = devfs_itod(de->de_inode); 353 if (cpdev != NULL && cdev == *cpdev) 354 goto found; 355 continue; 356 } 357 358 notfound: 359 360 if ((nameiop == CREATE || nameiop == RENAME) && 361 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 362 cnp->cn_flags |= SAVENAME; 363 if (!(flags & LOCKPARENT)) 364 VOP_UNLOCK(dvp, 0, td); 365 return (EJUSTRETURN); 366 } 367 return (ENOENT); 368 369 370 found: 371 372 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 373 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 374 if (error) 375 return (error); 376 if (*vpp == dvp) { 377 VREF(dvp); 378 *vpp = dvp; 379 return (0); 380 } 381 error = devfs_allocv(de, dvp->v_mount, vpp, td); 382 if (error) 383 return (error); 384 if (!(flags & LOCKPARENT)) 385 VOP_UNLOCK(dvp, 0, td); 386 return (0); 387 } 388 error = devfs_allocv(de, dvp->v_mount, vpp, td); 389 if (error) 390 return (error); 391 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) 392 VOP_UNLOCK(dvp, 0, td); 393 return (0); 394 } 395 396 static int 397 devfs_lookup(struct vop_lookup_args *ap) 398 { 399 int j; 400 struct devfs_mount *dmp; 401 402 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 403 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 404 j = devfs_lookupx(ap); 405 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 406 return (j); 407 } 408 409 static int 410 devfs_mknod(struct vop_mknod_args *ap) 411 /* 412 struct vop_mknod_args { 413 struct vnodeop_desc *a_desc; 414 struct vnode *a_dvp; 415 struct vnode **a_vpp; 416 struct componentname *a_cnp; 417 struct vattr *a_vap; 418 }; 419 */ 420 { 421 struct componentname *cnp; 422 struct vnode *dvp, **vpp; 423 struct thread *td; 424 struct devfs_dirent *dd, *de; 425 struct devfs_mount *dmp; 426 int cloned, flags, nameiop; 427 int error; 428 429 dvp = ap->a_dvp; 430 dmp = VFSTODEVFS(dvp->v_mount); 431 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 432 433 cnp = ap->a_cnp; 434 vpp = ap->a_vpp; 435 td = cnp->cn_thread; 436 flags = cnp->cn_flags; 437 nameiop = cnp->cn_nameiop; 438 cloned = 0; 439 dd = dvp->v_data; 440 441 error = ENOENT; 442 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 443 if (cnp->cn_namelen != de->de_dirent->d_namlen) 444 continue; 445 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 446 de->de_dirent->d_namlen) != 0) 447 continue; 448 if (de->de_flags & DE_WHITEOUT) 449 break; 450 goto notfound; 451 } 452 if (de == NULL) 453 goto notfound; 454 de->de_flags &= ~DE_WHITEOUT; 455 error = devfs_allocv(de, dvp->v_mount, vpp, td); 456 notfound: 457 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 458 return (error); 459 } 460 461 462 static int 463 devfs_pathconf(ap) 464 struct vop_pathconf_args /* { 465 struct vnode *a_vp; 466 int a_name; 467 int *a_retval; 468 } */ *ap; 469 { 470 471 switch (ap->a_name) { 472 case _PC_NAME_MAX: 473 *ap->a_retval = NAME_MAX; 474 return (0); 475 case _PC_PATH_MAX: 476 *ap->a_retval = PATH_MAX; 477 return (0); 478 default: 479 return (vop_stdpathconf(ap)); 480 } 481 /* NOTREACHED */ 482 } 483 484 /* ARGSUSED */ 485 static int 486 devfs_print(ap) 487 struct vop_print_args /* { 488 struct vnode *a_vp; 489 } */ *ap; 490 { 491 492 printf("tag VT_DEVFS, devfs vnode\n"); 493 return (0); 494 } 495 496 static int 497 devfs_read(ap) 498 struct vop_read_args /* { 499 struct vnode *a_vp; 500 struct uio *a_uio; 501 int a_ioflag; 502 struct ucred *a_cred; 503 } */ *ap; 504 { 505 506 if (ap->a_vp->v_type != VDIR) 507 return (EINVAL); 508 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 509 } 510 511 static int 512 devfs_readdir(ap) 513 struct vop_readdir_args /* { 514 struct vnode *a_vp; 515 struct uio *a_uio; 516 struct ucred *a_cred; 517 int *a_eofflag; 518 int *a_ncookies; 519 u_long **a_cookies; 520 } */ *ap; 521 { 522 int error; 523 struct uio *uio; 524 struct dirent *dp; 525 struct devfs_dirent *dd; 526 struct devfs_dirent *de; 527 struct devfs_mount *dmp; 528 off_t off, oldoff; 529 int ncookies = 0; 530 u_long *cookiebuf, *cookiep; 531 struct dirent *dps, *dpe; 532 533 if (ap->a_vp->v_type != VDIR) 534 return (ENOTDIR); 535 536 uio = ap->a_uio; 537 if (uio->uio_offset < 0) 538 return (EINVAL); 539 540 dmp = VFSTODEVFS(ap->a_vp->v_mount); 541 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 542 devfs_populate(dmp); 543 error = 0; 544 de = ap->a_vp->v_data; 545 off = 0; 546 oldoff = uio->uio_offset; 547 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 548 if (dd->de_flags & DE_WHITEOUT) 549 continue; 550 if (dd->de_dirent->d_type == DT_DIR) 551 de = dd->de_dir; 552 else 553 de = dd; 554 dp = dd->de_dirent; 555 if (dp->d_reclen > uio->uio_resid) 556 break; 557 dp->d_fileno = de->de_inode; 558 if (off >= uio->uio_offset) { 559 ncookies++; 560 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 561 if (error) 562 break; 563 } 564 off += dp->d_reclen; 565 } 566 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 567 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 568 M_TEMP, M_WAITOK); 569 cookiep = cookiebuf; 570 dps = (struct dirent *) 571 (uio->uio_iov->iov_base - (uio->uio_offset - oldoff)); 572 dpe = (struct dirent *) uio->uio_iov->iov_base; 573 for( dp = dps; 574 dp < dpe; 575 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 576 oldoff += dp->d_reclen; 577 *cookiep++ = (u_long) oldoff; 578 } 579 *ap->a_ncookies = ncookies; 580 *ap->a_cookies = cookiebuf; 581 } 582 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 583 uio->uio_offset = off; 584 return (error); 585 } 586 587 static int 588 devfs_readlink(ap) 589 struct vop_readlink_args /* { 590 struct vnode *a_vp; 591 struct uio *a_uio; 592 struct ucred *a_cead; 593 } */ *ap; 594 { 595 int error; 596 struct devfs_dirent *de; 597 598 de = ap->a_vp->v_data; 599 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 600 return (error); 601 } 602 603 static int 604 devfs_reclaim(ap) 605 struct vop_reclaim_args /* { 606 struct vnode *a_vp; 607 } */ *ap; 608 { 609 struct vnode *vp = ap->a_vp; 610 struct devfs_dirent *de; 611 int i; 612 613 de = vp->v_data; 614 if (de != NULL) 615 de->de_vnode = NULL; 616 vp->v_data = NULL; 617 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 618 i = vcount(vp); 619 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 620 (vp->v_rdev->si_flags & SI_NAMED)) 621 destroy_dev(vp->v_rdev); 622 } 623 return (0); 624 } 625 626 static int 627 devfs_remove(ap) 628 struct vop_remove_args /* { 629 struct vnode *a_dvp; 630 struct vnode *a_vp; 631 struct componentname *a_cnp; 632 } */ *ap; 633 { 634 struct vnode *vp = ap->a_vp; 635 struct devfs_dirent *dd; 636 struct devfs_dirent *de; 637 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 638 639 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 640 dd = ap->a_dvp->v_data; 641 de = vp->v_data; 642 if (de->de_dirent->d_type == DT_LNK) { 643 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 644 if (de->de_vnode) 645 de->de_vnode->v_data = NULL; 646 FREE(de, M_DEVFS); 647 } else { 648 de->de_flags |= DE_WHITEOUT; 649 } 650 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 651 return (0); 652 } 653 654 /* 655 * Revoke is called on a tty when a terminal session ends. The vnode 656 * is orphaned by setting v_op to deadfs so we need to let go of it 657 * as well so that we create a new one next time around. 658 */ 659 static int 660 devfs_revoke(ap) 661 struct vop_revoke_args /* { 662 struct vnode *a_vp; 663 int a_flags; 664 } */ *ap; 665 { 666 struct vnode *vp = ap->a_vp; 667 struct devfs_dirent *de; 668 669 de = vp->v_data; 670 de->de_vnode = NULL; 671 vop_revoke(ap); 672 return (0); 673 } 674 675 static int 676 devfs_setattr(ap) 677 struct vop_setattr_args /* { 678 struct vnode *a_vp; 679 struct vattr *a_vap; 680 struct ucred *a_cred; 681 struct proc *a_p; 682 } */ *ap; 683 { 684 struct devfs_dirent *de; 685 struct vattr *vap; 686 struct vnode *vp; 687 int c, error; 688 uid_t uid; 689 gid_t gid; 690 691 vap = ap->a_vap; 692 vp = ap->a_vp; 693 if ((vap->va_type != VNON) || 694 (vap->va_nlink != VNOVAL) || 695 (vap->va_fsid != VNOVAL) || 696 (vap->va_fileid != VNOVAL) || 697 (vap->va_blocksize != VNOVAL) || 698 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 699 (vap->va_rdev != VNOVAL) || 700 ((int)vap->va_bytes != VNOVAL) || 701 (vap->va_gen != VNOVAL)) { 702 return (EINVAL); 703 } 704 705 de = vp->v_data; 706 if (vp->v_type == VDIR) 707 de = de->de_dir; 708 709 error = c = 0; 710 if (vap->va_uid == (uid_t)VNOVAL) 711 uid = de->de_uid; 712 else 713 uid = vap->va_uid; 714 if (vap->va_gid == (gid_t)VNOVAL) 715 gid = de->de_gid; 716 else 717 gid = vap->va_gid; 718 if (uid != de->de_uid || gid != de->de_gid) { 719 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 720 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 721 (error = suser(ap->a_td->td_proc)) != 0) 722 return (error); 723 de->de_uid = uid; 724 de->de_gid = gid; 725 c = 1; 726 } 727 728 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 729 /* see comment in ufs_vnops::ufs_setattr() */ 730 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 731 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 732 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 733 return (error); 734 } 735 736 if (vap->va_mode != (mode_t)VNOVAL) { 737 if ((ap->a_cred->cr_uid != de->de_uid) && 738 (error = suser(ap->a_td->td_proc))) 739 return (error); 740 de->de_mode = vap->va_mode; 741 c = 1; 742 } 743 if (vap->va_atime.tv_sec != VNOVAL) { 744 if ((ap->a_cred->cr_uid != de->de_uid) && 745 (error = suser(ap->a_td->td_proc))) 746 return (error); 747 de->de_atime = vap->va_atime; 748 c = 1; 749 } 750 if (vap->va_mtime.tv_sec != VNOVAL) { 751 if ((ap->a_cred->cr_uid != de->de_uid) && 752 (error = suser(ap->a_td->td_proc))) 753 return (error); 754 de->de_mtime = vap->va_mtime; 755 c = 1; 756 } 757 758 if (c) 759 vfs_timestamp(&de->de_ctime); 760 return (0); 761 } 762 763 static int 764 devfs_symlink(ap) 765 struct vop_symlink_args /* { 766 struct vnode *a_dvp; 767 struct vnode **a_vpp; 768 struct componentname *a_cnp; 769 struct vattr *a_vap; 770 char *a_target; 771 } */ *ap; 772 { 773 int i, error; 774 struct devfs_dirent *dd; 775 struct devfs_dirent *de; 776 struct devfs_mount *dmp; 777 778 error = suser(ap->a_cnp->cn_thread->td_proc); 779 if (error) 780 return(error); 781 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 782 dd = ap->a_dvp->v_data; 783 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 784 de->de_uid = 0; 785 de->de_gid = 0; 786 de->de_mode = 0755; 787 de->de_inode = dmp->dm_inode++; 788 de->de_dirent->d_type = DT_LNK; 789 i = strlen(ap->a_target) + 1; 790 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 791 bcopy(ap->a_target, de->de_symlink, i); 792 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 793 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 794 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 795 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 796 return (0); 797 } 798 799 static vop_t **devfs_vnodeop_p; 800 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 801 { &vop_default_desc, (vop_t *) vop_defaultop }, 802 { &vop_access_desc, (vop_t *) devfs_access }, 803 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 804 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 805 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 806 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 807 { &vop_print_desc, (vop_t *) devfs_print }, 808 { &vop_read_desc, (vop_t *) devfs_read }, 809 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 810 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 811 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 812 { &vop_remove_desc, (vop_t *) devfs_remove }, 813 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 814 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 815 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 816 { NULL, NULL } 817 }; 818 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 819 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 820 821 VNODEOP_SET(devfs_vnodeop_opv_desc); 822 823 static vop_t **devfs_specop_p; 824 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 825 { &vop_default_desc, (vop_t *) spec_vnoperate }, 826 { &vop_access_desc, (vop_t *) devfs_access }, 827 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 828 { &vop_print_desc, (vop_t *) devfs_print }, 829 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 830 { &vop_remove_desc, (vop_t *) devfs_remove }, 831 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 832 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 833 { NULL, NULL } 834 }; 835 static struct vnodeopv_desc devfs_specop_opv_desc = 836 { &devfs_specop_p, devfs_specop_entries }; 837 838 VNODEOP_SET(devfs_specop_opv_desc); 839 #endif 840