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