/netbsd/src/sys/ufs/ufs/ufs_vnops.c
C | 2065 lines | 1436 code | 105 blank | 524 comment | 388 complexity | 741b03f0ae7ca1d6b076130a6a94787f MD5 | raw file
1/* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */ 2 3/* 4 * Copyright (c) 1982, 1986, 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94 41 */ 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/namei.h> 46#include <sys/resourcevar.h> 47#include <sys/kernel.h> 48#include <sys/file.h> 49#include <sys/stat.h> 50#include <sys/buf.h> 51#include <sys/proc.h> 52#include <sys/conf.h> 53#include <sys/mount.h> 54#include <sys/vnode.h> 55#include <sys/malloc.h> 56#include <sys/dirent.h> 57#include <sys/lockf.h> 58 59#include <vm/vm.h> 60 61#include <miscfs/specfs/specdev.h> 62#include <miscfs/fifofs/fifo.h> 63 64#include <ufs/ufs/quota.h> 65#include <ufs/ufs/inode.h> 66#include <ufs/ufs/dir.h> 67#include <ufs/ufs/ufsmount.h> 68#include <ufs/ufs/ufs_extern.h> 69 70static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *)); 71static int ufs_chown 72 __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *)); 73 74union _qcvt { 75 int64_t qcvt; 76 int32_t val[2]; 77}; 78#define SETHIGH(q, h) { \ 79 union _qcvt tmp; \ 80 tmp.qcvt = (q); \ 81 tmp.val[_QUAD_HIGHWORD] = (h); \ 82 (q) = tmp.qcvt; \ 83} 84#define SETLOW(q, l) { \ 85 union _qcvt tmp; \ 86 tmp.qcvt = (q); \ 87 tmp.val[_QUAD_LOWWORD] = (l); \ 88 (q) = tmp.qcvt; \ 89} 90 91/* 92 * Create a regular file 93 */ 94int 95ufs_create(v) 96 void *v; 97{ 98 struct vop_create_args /* { 99 struct vnode *a_dvp; 100 struct vnode **a_vpp; 101 struct componentname *a_cnp; 102 struct vattr *a_vap; 103 } */ *ap = v; 104 return 105 ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), 106 ap->a_dvp, ap->a_vpp, ap->a_cnp); 107} 108 109/* 110 * Mknod vnode call 111 */ 112/* ARGSUSED */ 113int 114ufs_mknod(v) 115 void *v; 116{ 117 struct vop_mknod_args /* { 118 struct vnode *a_dvp; 119 struct vnode **a_vpp; 120 struct componentname *a_cnp; 121 struct vattr *a_vap; 122 } */ *ap = v; 123 register struct vattr *vap = ap->a_vap; 124 register struct vnode **vpp = ap->a_vpp; 125 register struct inode *ip; 126 int error; 127 128 if ((error = 129 ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 130 ap->a_dvp, vpp, ap->a_cnp)) != 0) 131 return (error); 132 ip = VTOI(*vpp); 133 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 134 if (vap->va_rdev != VNOVAL) { 135 /* 136 * Want to be able to use this to make badblock 137 * inodes, so don't truncate the dev number. 138 */ 139 ip->i_rdev = vap->va_rdev; 140 } 141 /* 142 * Remove inode so that it will be reloaded by VFS_VGET and 143 * checked to see if it is an alias of an existing entry in 144 * the inode cache. 145 */ 146 vput(*vpp); 147 (*vpp)->v_type = VNON; 148 vgone(*vpp); 149 *vpp = 0; 150 return (0); 151} 152 153/* 154 * Open called. 155 * 156 * Nothing to do. 157 */ 158/* ARGSUSED */ 159int 160ufs_open(v) 161 void *v; 162{ 163 struct vop_open_args /* { 164 struct vnode *a_vp; 165 int a_mode; 166 struct ucred *a_cred; 167 struct proc *a_p; 168 } */ *ap = v; 169 170 /* 171 * Files marked append-only must be opened for appending. 172 */ 173 if ((VTOI(ap->a_vp)->i_flags & APPEND) && 174 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 175 return (EPERM); 176 return (0); 177} 178 179/* 180 * Close called. 181 * 182 * Update the times on the inode. 183 */ 184/* ARGSUSED */ 185int 186ufs_close(v) 187 void *v; 188{ 189 struct vop_close_args /* { 190 struct vnode *a_vp; 191 int a_fflag; 192 struct ucred *a_cred; 193 struct proc *a_p; 194 } */ *ap = v; 195 register struct vnode *vp = ap->a_vp; 196 register struct inode *ip = VTOI(vp); 197 198 if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) 199 ITIMES(ip, &time, &time); 200 return (0); 201} 202 203int 204ufs_access(v) 205 void *v; 206{ 207 struct vop_access_args /* { 208 struct vnode *a_vp; 209 int a_mode; 210 struct ucred *a_cred; 211 struct proc *a_p; 212 } */ *ap = v; 213 register struct vnode *vp = ap->a_vp; 214 register struct inode *ip = VTOI(vp); 215 mode_t mode = ap->a_mode; 216 217#ifdef DIAGNOSTIC 218 if (!VOP_ISLOCKED(vp)) { 219 vprint("ufs_access: not locked", vp); 220 panic("ufs_access: not locked"); 221 } 222#endif 223#ifdef QUOTA 224 if (mode & VWRITE) 225 switch (vp->v_type) { 226 int error; 227 case VDIR: 228 case VLNK: 229 case VREG: 230 if ((error = getinoquota(ip)) != 0) 231 return (error); 232 break; 233 case VBAD: 234 case VBLK: 235 case VCHR: 236 case VSOCK: 237 case VFIFO: 238 case VNON: 239 break; 240 } 241#endif 242 243 /* If immutable bit set, nobody gets to write it. */ 244 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE)) 245 return (EPERM); 246 247 return (vaccess(ip->i_mode, ip->i_uid, ip->i_gid, mode, ap->a_cred)); 248} 249 250/* ARGSUSED */ 251int 252ufs_getattr(v) 253 void *v; 254{ 255 struct vop_getattr_args /* { 256 struct vnode *a_vp; 257 struct vattr *a_vap; 258 struct ucred *a_cred; 259 struct proc *a_p; 260 } */ *ap = v; 261 register struct vnode *vp = ap->a_vp; 262 register struct inode *ip = VTOI(vp); 263 register struct vattr *vap = ap->a_vap; 264 265 ITIMES(ip, &time, &time); 266 /* 267 * Copy from inode table 268 */ 269 vap->va_fsid = ip->i_dev; 270 vap->va_fileid = ip->i_number; 271 vap->va_mode = ip->i_mode & ~IFMT; 272 vap->va_nlink = ip->i_nlink; 273 vap->va_uid = ip->i_uid; 274 vap->va_gid = ip->i_gid; 275 vap->va_rdev = (dev_t)ip->i_rdev; 276 vap->va_size = ip->i_din.di_size; 277 vap->va_atime.tv_sec = ip->i_atime; 278 vap->va_atime.tv_nsec = ip->i_atimensec; 279 vap->va_mtime.tv_sec = ip->i_mtime; 280 vap->va_mtime.tv_nsec = ip->i_mtimensec; 281 vap->va_ctime.tv_sec = ip->i_ctime; 282 vap->va_ctime.tv_nsec = ip->i_ctimensec; 283 vap->va_flags = ip->i_flags; 284 vap->va_gen = ip->i_gen; 285 /* this doesn't belong here */ 286 if (vp->v_type == VBLK) 287 vap->va_blocksize = BLKDEV_IOSIZE; 288 else if (vp->v_type == VCHR) 289 vap->va_blocksize = MAXBSIZE; 290 else 291 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 292 vap->va_bytes = dbtob(ip->i_blocks); 293 vap->va_type = vp->v_type; 294 vap->va_filerev = ip->i_modrev; 295 return (0); 296} 297 298/* 299 * Set attribute vnode op. called from several syscalls 300 */ 301int 302ufs_setattr(v) 303 void *v; 304{ 305 struct vop_setattr_args /* { 306 struct vnode *a_vp; 307 struct vattr *a_vap; 308 struct ucred *a_cred; 309 struct proc *a_p; 310 } */ *ap = v; 311 register struct vattr *vap = ap->a_vap; 312 register struct vnode *vp = ap->a_vp; 313 register struct inode *ip = VTOI(vp); 314 register struct ucred *cred = ap->a_cred; 315 register struct proc *p = ap->a_p; 316 int error; 317 318 /* 319 * Check for unsettable attributes. 320 */ 321 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 322 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 323 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 324 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 325 return (EINVAL); 326 } 327 if (vap->va_flags != VNOVAL) { 328 if (cred->cr_uid != ip->i_uid && 329 (error = suser(cred, &p->p_acflag))) 330 return (error); 331 if (cred->cr_uid == 0) { 332 if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) && 333 securelevel > 0) 334 return (EPERM); 335 ip->i_flags = vap->va_flags; 336 } else { 337 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) 338 return (EPERM); 339 ip->i_flags &= SF_SETTABLE; 340 ip->i_flags |= (vap->va_flags & UF_SETTABLE); 341 } 342 ip->i_flag |= IN_CHANGE; 343 if (vap->va_flags & (IMMUTABLE | APPEND)) 344 return (0); 345 } 346 if (ip->i_flags & (IMMUTABLE | APPEND)) 347 return (EPERM); 348 /* 349 * Go through the fields and update iff not VNOVAL. 350 */ 351 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 352 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p); 353 if (error) 354 return (error); 355 } 356 if (vap->va_size != VNOVAL) { 357 if (vp->v_type == VDIR) 358 return (EISDIR); 359 error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p); 360 if (error) 361 return (error); 362 } 363 ip = VTOI(vp); 364 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 365 if (cred->cr_uid != ip->i_uid && 366 (error = suser(cred, &p->p_acflag)) && 367 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 368 (error = VOP_ACCESS(vp, VWRITE, cred, p)))) 369 return (error); 370 if (vap->va_atime.tv_sec != VNOVAL) 371 ip->i_flag |= IN_ACCESS; 372 if (vap->va_mtime.tv_sec != VNOVAL) 373 ip->i_flag |= IN_CHANGE | IN_UPDATE; 374 error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 1); 375 if (error) 376 return (error); 377 } 378 error = 0; 379 if (vap->va_mode != (mode_t)VNOVAL) 380 error = ufs_chmod(vp, (int)vap->va_mode, cred, p); 381 return (error); 382} 383 384/* 385 * Change the mode on a file. 386 * Inode must be locked before calling. 387 */ 388static int 389ufs_chmod(vp, mode, cred, p) 390 register struct vnode *vp; 391 register int mode; 392 register struct ucred *cred; 393 struct proc *p; 394{ 395 register struct inode *ip = VTOI(vp); 396 int error; 397 398 if (cred->cr_uid != ip->i_uid && 399 (error = suser(cred, &p->p_acflag))) 400 return (error); 401 if (cred->cr_uid) { 402 if (vp->v_type != VDIR && (mode & S_ISTXT)) 403 return (EFTYPE); 404 if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) 405 return (EPERM); 406 } 407 ip->i_mode &= ~ALLPERMS; 408 ip->i_mode |= (mode & ALLPERMS); 409 ip->i_flag |= IN_CHANGE; 410 if ((vp->v_flag & VTEXT) && (ip->i_mode & S_ISTXT) == 0) 411 (void) vnode_pager_uncache(vp); 412 return (0); 413} 414 415/* 416 * Perform chown operation on inode ip; 417 * inode must be locked prior to call. 418 */ 419static int 420ufs_chown(vp, uid, gid, cred, p) 421 register struct vnode *vp; 422 uid_t uid; 423 gid_t gid; 424 struct ucred *cred; 425 struct proc *p; 426{ 427 register struct inode *ip = VTOI(vp); 428 uid_t ouid; 429 gid_t ogid; 430 int error = 0; 431#ifdef QUOTA 432 register int i; 433 long change; 434#endif 435 436 if (uid == (uid_t)VNOVAL) 437 uid = ip->i_uid; 438 if (gid == (gid_t)VNOVAL) 439 gid = ip->i_gid; 440 /* 441 * If we don't own the file, are trying to change the owner 442 * of the file, or are not a member of the target group, 443 * the caller must be superuser or the call fails. 444 */ 445 if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || 446 (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) && 447 (error = suser(cred, &p->p_acflag))) 448 return (error); 449 ogid = ip->i_gid; 450 ouid = ip->i_uid; 451#ifdef QUOTA 452 if ((error = getinoquota(ip)) != 0) 453 return (error); 454 if (ouid == uid) { 455 dqrele(vp, ip->i_dquot[USRQUOTA]); 456 ip->i_dquot[USRQUOTA] = NODQUOT; 457 } 458 if (ogid == gid) { 459 dqrele(vp, ip->i_dquot[GRPQUOTA]); 460 ip->i_dquot[GRPQUOTA] = NODQUOT; 461 } 462 change = ip->i_blocks; 463 (void) chkdq(ip, -change, cred, CHOWN); 464 (void) chkiq(ip, -1, cred, CHOWN); 465 for (i = 0; i < MAXQUOTAS; i++) { 466 dqrele(vp, ip->i_dquot[i]); 467 ip->i_dquot[i] = NODQUOT; 468 } 469#endif 470 ip->i_gid = gid; 471 ip->i_uid = uid; 472#ifdef QUOTA 473 if ((error = getinoquota(ip)) == 0) { 474 if (ouid == uid) { 475 dqrele(vp, ip->i_dquot[USRQUOTA]); 476 ip->i_dquot[USRQUOTA] = NODQUOT; 477 } 478 if (ogid == gid) { 479 dqrele(vp, ip->i_dquot[GRPQUOTA]); 480 ip->i_dquot[GRPQUOTA] = NODQUOT; 481 } 482 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { 483 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) 484 goto good; 485 else 486 (void) chkdq(ip, -change, cred, CHOWN|FORCE); 487 } 488 for (i = 0; i < MAXQUOTAS; i++) { 489 dqrele(vp, ip->i_dquot[i]); 490 ip->i_dquot[i] = NODQUOT; 491 } 492 } 493 ip->i_gid = ogid; 494 ip->i_uid = ouid; 495 if (getinoquota(ip) == 0) { 496 if (ouid == uid) { 497 dqrele(vp, ip->i_dquot[USRQUOTA]); 498 ip->i_dquot[USRQUOTA] = NODQUOT; 499 } 500 if (ogid == gid) { 501 dqrele(vp, ip->i_dquot[GRPQUOTA]); 502 ip->i_dquot[GRPQUOTA] = NODQUOT; 503 } 504 (void) chkdq(ip, change, cred, FORCE|CHOWN); 505 (void) chkiq(ip, 1, cred, FORCE|CHOWN); 506 (void) getinoquota(ip); 507 } 508 return (error); 509good: 510 if (getinoquota(ip)) 511 panic("chown: lost quota"); 512#endif /* QUOTA */ 513 if (ouid != uid || ogid != gid) 514 ip->i_flag |= IN_CHANGE; 515 if (ouid != uid && cred->cr_uid != 0) 516 ip->i_mode &= ~ISUID; 517 if (ogid != gid && cred->cr_uid != 0) 518 ip->i_mode &= ~ISGID; 519 return (0); 520} 521 522/* ARGSUSED */ 523int 524ufs_ioctl(v) 525 void *v; 526{ 527#if 0 528 struct vop_ioctl_args /* { 529 struct vnode *a_vp; 530 u_long a_command; 531 caddr_t a_data; 532 int a_fflag; 533 struct ucred *a_cred; 534 struct proc *a_p; 535 } */ *ap = v; 536#endif 537 return (ENOTTY); 538} 539 540/* ARGSUSED */ 541int 542ufs_select(v) 543 void *v; 544{ 545#if 0 546 struct vop_select_args /* { 547 struct vnode *a_vp; 548 int a_which; 549 int a_fflags; 550 struct ucred *a_cred; 551 struct proc *a_p; 552 } */ *ap = v; 553#endif 554 555 /* 556 * We should really check to see if I/O is possible. 557 */ 558 return (1); 559} 560 561/* 562 * Mmap a file 563 * 564 * NB Currently unsupported. 565 */ 566/* ARGSUSED */ 567int 568ufs_mmap(v) 569 void *v; 570{ 571#if 0 572 struct vop_mmap_args /* { 573 struct vnode *a_vp; 574 int a_fflags; 575 struct ucred *a_cred; 576 struct proc *a_p; 577 } */ *ap = v; 578#endif 579 580 return (EINVAL); 581} 582 583/* 584 * Seek on a file 585 * 586 * Nothing to do, so just return. 587 */ 588/* ARGSUSED */ 589int 590ufs_seek(v) 591 void *v; 592{ 593#if 0 594 struct vop_seek_args /* { 595 struct vnode *a_vp; 596 off_t a_oldoff; 597 off_t a_newoff; 598 struct ucred *a_cred; 599 } */ *ap = v; 600#endif 601 602 return (0); 603} 604 605int 606ufs_remove(v) 607 void *v; 608{ 609 struct vop_remove_args /* { 610 struct vnode *a_dvp; 611 struct vnode *a_vp; 612 struct componentname *a_cnp; 613 } */ *ap = v; 614 register struct inode *ip; 615 register struct vnode *vp = ap->a_vp; 616 register struct vnode *dvp = ap->a_dvp; 617 int error; 618 619 if (vp->v_type == VDIR) { 620 error = EISDIR; 621 goto out; 622 } 623 ip = VTOI(vp); 624 if ((ip->i_flags & (IMMUTABLE | APPEND)) || 625 (VTOI(dvp)->i_flags & APPEND)) { 626 error = EPERM; 627 goto out; 628 } 629 if ((error = ufs_dirremove(dvp, ap->a_cnp)) == 0) { 630 ip->i_nlink--; 631 ip->i_flag |= IN_CHANGE; 632 } 633out: 634 if (dvp == vp) 635 vrele(vp); 636 else 637 vput(vp); 638 vput(dvp); 639 return (error); 640} 641 642/* 643 * link vnode call 644 */ 645int 646ufs_link(v) 647 void *v; 648{ 649 struct vop_link_args /* { 650 struct vnode *a_dvp; 651 struct vnode *a_vp; 652 struct componentname *a_cnp; 653 } */ *ap = v; 654 register struct vnode *dvp = ap->a_dvp; 655 register struct vnode *vp = ap->a_vp; 656 register struct componentname *cnp = ap->a_cnp; 657 register struct inode *ip; 658 struct timespec ts; 659 int error; 660 661#ifdef DIAGNOSTIC 662 if ((cnp->cn_flags & HASBUF) == 0) 663 panic("ufs_link: no name"); 664#endif 665 if (vp->v_type == VDIR) { 666 VOP_ABORTOP(dvp, cnp); 667 error = EISDIR; 668 goto out2; 669 } 670 if (dvp->v_mount != vp->v_mount) { 671 VOP_ABORTOP(dvp, cnp); 672 error = EXDEV; 673 goto out2; 674 } 675 if (dvp != vp && (error = VOP_LOCK(vp))) { 676 VOP_ABORTOP(dvp, cnp); 677 goto out2; 678 } 679 ip = VTOI(vp); 680 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 681 VOP_ABORTOP(dvp, cnp); 682 error = EMLINK; 683 goto out1; 684 } 685 if (ip->i_flags & (IMMUTABLE | APPEND)) { 686 VOP_ABORTOP(dvp, cnp); 687 error = EPERM; 688 goto out1; 689 } 690 ip->i_nlink++; 691 ip->i_flag |= IN_CHANGE; 692 TIMEVAL_TO_TIMESPEC(&time, &ts); 693 error = VOP_UPDATE(vp, &ts, &ts, 1); 694 if (!error) 695 error = ufs_direnter(ip, dvp, cnp); 696 if (error) { 697 ip->i_nlink--; 698 ip->i_flag |= IN_CHANGE; 699 } 700 FREE(cnp->cn_pnbuf, M_NAMEI); 701out1: 702 if (dvp != vp) 703 VOP_UNLOCK(vp); 704out2: 705 vput(dvp); 706 return (error); 707} 708 709/* 710 * whiteout vnode call 711 */ 712int 713ufs_whiteout(v) 714 void *v; 715{ 716 struct vop_whiteout_args /* { 717 struct vnode *a_dvp; 718 struct componentname *a_cnp; 719 int a_flags; 720 } */ *ap = v; 721 struct vnode *dvp = ap->a_dvp; 722 struct componentname *cnp = ap->a_cnp; 723 struct direct newdir; 724 int error = 0; 725 726 switch (ap->a_flags) { 727 case LOOKUP: 728 /* 4.4 format directories support whiteout operations */ 729 if (dvp->v_mount->mnt_maxsymlinklen > 0) 730 return (0); 731 return (EOPNOTSUPP); 732 733 case CREATE: 734 /* create a new directory whiteout */ 735#ifdef DIAGNOSTIC 736 if ((cnp->cn_flags & SAVENAME) == 0) 737 panic("ufs_whiteout: missing name"); 738 if (dvp->v_mount->mnt_maxsymlinklen <= 0) 739 panic("ufs_whiteout: old format filesystem"); 740#endif 741 742 newdir.d_ino = WINO; 743 newdir.d_namlen = cnp->cn_namelen; 744 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); 745 newdir.d_type = DT_WHT; 746 error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc); 747 break; 748 749 case DELETE: 750 /* remove an existing directory whiteout */ 751#ifdef DIAGNOSTIC 752 if (dvp->v_mount->mnt_maxsymlinklen <= 0) 753 panic("ufs_whiteout: old format filesystem"); 754#endif 755 756 cnp->cn_flags &= ~DOWHITEOUT; 757 error = ufs_dirremove(dvp, cnp); 758 break; 759 } 760 if (cnp->cn_flags & HASBUF) { 761 FREE(cnp->cn_pnbuf, M_NAMEI); 762 cnp->cn_flags &= ~HASBUF; 763 } 764 return (error); 765} 766 767 768/* 769 * Rename system call. 770 * rename("foo", "bar"); 771 * is essentially 772 * unlink("bar"); 773 * link("foo", "bar"); 774 * unlink("foo"); 775 * but ``atomically''. Can't do full commit without saving state in the 776 * inode on disk which isn't feasible at this time. Best we can do is 777 * always guarantee the target exists. 778 * 779 * Basic algorithm is: 780 * 781 * 1) Bump link count on source while we're linking it to the 782 * target. This also ensure the inode won't be deleted out 783 * from underneath us while we work (it may be truncated by 784 * a concurrent `trunc' or `open' for creation). 785 * 2) Link source to destination. If destination already exists, 786 * delete it first. 787 * 3) Unlink source reference to inode if still around. If a 788 * directory was moved and the parent of the destination 789 * is different from the source, patch the ".." entry in the 790 * directory. 791 */ 792int 793ufs_rename(v) 794 void *v; 795{ 796 struct vop_rename_args /* { 797 struct vnode *a_fdvp; 798 struct vnode *a_fvp; 799 struct componentname *a_fcnp; 800 struct vnode *a_tdvp; 801 struct vnode *a_tvp; 802 struct componentname *a_tcnp; 803 } */ *ap = v; 804 struct vnode *tvp = ap->a_tvp; 805 register struct vnode *tdvp = ap->a_tdvp; 806 struct vnode *fvp = ap->a_fvp; 807 register struct vnode *fdvp = ap->a_fdvp; 808 register struct componentname *tcnp = ap->a_tcnp; 809 register struct componentname *fcnp = ap->a_fcnp; 810 register struct inode *ip, *xp, *dp; 811 struct dirtemplate dirbuf; 812 struct timespec ts; 813 int doingdirectory = 0, oldparent = 0, newparent = 0; 814 int error = 0; 815 u_char namlen; 816 817#ifdef DIAGNOSTIC 818 if ((tcnp->cn_flags & HASBUF) == 0 || 819 (fcnp->cn_flags & HASBUF) == 0) 820 panic("ufs_rename: no name"); 821#endif 822 /* 823 * Check for cross-device rename. 824 */ 825 if ((fvp->v_mount != tdvp->v_mount) || 826 (tvp && (fvp->v_mount != tvp->v_mount))) { 827 error = EXDEV; 828abortit: 829 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ 830 if (tdvp == tvp) 831 vrele(tdvp); 832 else 833 vput(tdvp); 834 if (tvp) 835 vput(tvp); 836 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ 837 vrele(fdvp); 838 vrele(fvp); 839 return (error); 840 } 841 842 /* 843 * Check if just deleting a link name. 844 */ 845 if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) || 846 (VTOI(tdvp)->i_flags & APPEND))) { 847 error = EPERM; 848 goto abortit; 849 } 850 if (fvp == tvp) { 851 if (fvp->v_type == VDIR) { 852 error = EINVAL; 853 goto abortit; 854 } 855 856 /* Release destination completely. */ 857 VOP_ABORTOP(tdvp, tcnp); 858 vput(tdvp); 859 vput(tvp); 860 861 /* Delete source. */ 862 vrele(fdvp); 863 vrele(fvp); 864 fcnp->cn_flags &= ~MODMASK; 865 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 866 if ((fcnp->cn_flags & SAVESTART) == 0) 867 panic("ufs_rename: lost from startdir"); 868 fcnp->cn_nameiop = DELETE; 869 (void) relookup(fdvp, &fvp, fcnp); 870 return (VOP_REMOVE(fdvp, fvp, fcnp)); 871 } 872 if ((error = VOP_LOCK(fvp)) != 0) 873 goto abortit; 874 dp = VTOI(fdvp); 875 ip = VTOI(fvp); 876 if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) { 877 VOP_UNLOCK(fvp); 878 error = EPERM; 879 goto abortit; 880 } 881 if ((ip->i_mode & IFMT) == IFDIR) { 882 /* 883 * Avoid ".", "..", and aliases of "." for obvious reasons. 884 */ 885 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 886 dp == ip || (fcnp->cn_flags&ISDOTDOT) || 887 (ip->i_flag & IN_RENAME)) { 888 VOP_UNLOCK(fvp); 889 error = EINVAL; 890 goto abortit; 891 } 892 ip->i_flag |= IN_RENAME; 893 oldparent = dp->i_number; 894 doingdirectory++; 895 } 896 vrele(fdvp); 897 898 /* 899 * When the target exists, both the directory 900 * and target vnodes are returned locked. 901 */ 902 dp = VTOI(tdvp); 903 xp = NULL; 904 if (tvp) 905 xp = VTOI(tvp); 906 907 /* 908 * 1) Bump link count while we're moving stuff 909 * around. If we crash somewhere before 910 * completing our work, the link count 911 * may be wrong, but correctable. 912 */ 913 ip->i_nlink++; 914 ip->i_flag |= IN_CHANGE; 915 TIMEVAL_TO_TIMESPEC(&time, &ts); 916 if ((error = VOP_UPDATE(fvp, &ts, &ts, 1)) != 0) { 917 VOP_UNLOCK(fvp); 918 goto bad; 919 } 920 921 /* 922 * If ".." must be changed (ie the directory gets a new 923 * parent) then the source directory must not be in the 924 * directory heirarchy above the target, as this would 925 * orphan everything below the source directory. Also 926 * the user must have write permission in the source so 927 * as to be able to change "..". We must repeat the call 928 * to namei, as the parent directory is unlocked by the 929 * call to checkpath(). 930 */ 931 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); 932 VOP_UNLOCK(fvp); 933 if (oldparent != dp->i_number) 934 newparent = dp->i_number; 935 if (doingdirectory && newparent) { 936 if (error) /* write access check above */ 937 goto bad; 938 if (xp != NULL) 939 vput(tvp); 940 if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) 941 goto out; 942 if ((tcnp->cn_flags & SAVESTART) == 0) 943 panic("ufs_rename: lost to startdir"); 944 if ((error = relookup(tdvp, &tvp, tcnp)) != 0) 945 goto out; 946 dp = VTOI(tdvp); 947 xp = NULL; 948 if (tvp) 949 xp = VTOI(tvp); 950 } 951 /* 952 * 2) If target doesn't exist, link the target 953 * to the source and unlink the source. 954 * Otherwise, rewrite the target directory 955 * entry to reference the source inode and 956 * expunge the original entry's existence. 957 */ 958 if (xp == NULL) { 959 if (dp->i_dev != ip->i_dev) 960 panic("rename: EXDEV"); 961 /* 962 * Account for ".." in new directory. 963 * When source and destination have the same 964 * parent we don't fool with the link count. 965 */ 966 if (doingdirectory && newparent) { 967 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 968 error = EMLINK; 969 goto bad; 970 } 971 dp->i_nlink++; 972 dp->i_flag |= IN_CHANGE; 973 if ((error = VOP_UPDATE(tdvp, &ts, &ts, 1)) != 0) 974 goto bad; 975 } 976 if ((error = ufs_direnter(ip, tdvp, tcnp)) != 0) { 977 if (doingdirectory && newparent) { 978 dp->i_nlink--; 979 dp->i_flag |= IN_CHANGE; 980 (void)VOP_UPDATE(tdvp, &ts, &ts, 1); 981 } 982 goto bad; 983 } 984 vput(tdvp); 985 } else { 986 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) 987 panic("rename: EXDEV"); 988 /* 989 * Short circuit rename(foo, foo). 990 */ 991 if (xp->i_number == ip->i_number) 992 panic("rename: same file"); 993 /* 994 * If the parent directory is "sticky", then the user must 995 * own the parent directory, or the destination of the rename, 996 * otherwise the destination may not be changed (except by 997 * root). This implements append-only directories. 998 */ 999 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && 1000 tcnp->cn_cred->cr_uid != dp->i_uid && 1001 xp->i_uid != tcnp->cn_cred->cr_uid) { 1002 error = EPERM; 1003 goto bad; 1004 } 1005 /* 1006 * Target must be empty if a directory and have no links 1007 * to it. Also, ensure source and target are compatible 1008 * (both directories, or both not directories). 1009 */ 1010 if ((xp->i_mode&IFMT) == IFDIR) { 1011 if (!ufs_dirempty(xp, dp->i_number, tcnp->cn_cred) || 1012 xp->i_nlink > 2) { 1013 error = ENOTEMPTY; 1014 goto bad; 1015 } 1016 if (!doingdirectory) { 1017 error = ENOTDIR; 1018 goto bad; 1019 } 1020 cache_purge(tdvp); 1021 } else if (doingdirectory) { 1022 error = EISDIR; 1023 goto bad; 1024 } 1025 if ((error = ufs_dirrewrite(dp, ip, tcnp)) != 0) 1026 goto bad; 1027 /* 1028 * If the target directory is in the same 1029 * directory as the source directory, 1030 * decrement the link count on the parent 1031 * of the target directory. 1032 */ 1033 if (doingdirectory && !newparent) { 1034 dp->i_nlink--; 1035 dp->i_flag |= IN_CHANGE; 1036 } 1037 vput(tdvp); 1038 /* 1039 * Adjust the link count of the target to 1040 * reflect the dirrewrite above. If this is 1041 * a directory it is empty and there are 1042 * no links to it, so we can squash the inode and 1043 * any space associated with it. We disallowed 1044 * renaming over top of a directory with links to 1045 * it above, as the remaining link would point to 1046 * a directory without "." or ".." entries. 1047 */ 1048 xp->i_nlink--; 1049 if (doingdirectory) { 1050 if (--xp->i_nlink != 0) 1051 panic("rename: linked directory"); 1052 error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC, 1053 tcnp->cn_cred, tcnp->cn_proc); 1054 } 1055 xp->i_flag |= IN_CHANGE; 1056 vput(tvp); 1057 xp = NULL; 1058 } 1059 1060 /* 1061 * 3) Unlink the source. 1062 */ 1063 fcnp->cn_flags &= ~MODMASK; 1064 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 1065 if ((fcnp->cn_flags & SAVESTART) == 0) 1066 panic("ufs_rename: lost from startdir"); 1067 (void) relookup(fdvp, &fvp, fcnp); 1068 if (fvp != NULL) { 1069 xp = VTOI(fvp); 1070 dp = VTOI(fdvp); 1071 } else { 1072 /* 1073 * From name has disappeared. 1074 */ 1075 if (doingdirectory) 1076 panic("rename: lost dir entry"); 1077 vrele(ap->a_fvp); 1078 return (0); 1079 } 1080 /* 1081 * Ensure that the directory entry still exists and has not 1082 * changed while the new name has been entered. If the source is 1083 * a file then the entry may have been unlinked or renamed. In 1084 * either case there is no further work to be done. If the source 1085 * is a directory then it cannot have been rmdir'ed; its link 1086 * count of three would cause a rmdir to fail with ENOTEMPTY. 1087 * The IRENAME flag ensures that it cannot be moved by another 1088 * rename. 1089 */ 1090 if (xp != ip) { 1091 if (doingdirectory) 1092 panic("rename: lost dir entry"); 1093 } else { 1094 /* 1095 * If the source is a directory with a 1096 * new parent, the link count of the old 1097 * parent directory must be decremented 1098 * and ".." set to point to the new parent. 1099 */ 1100 if (doingdirectory && newparent) { 1101 dp->i_nlink--; 1102 dp->i_flag |= IN_CHANGE; 1103 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, 1104 sizeof (struct dirtemplate), (off_t)0, 1105 UIO_SYSSPACE, IO_NODELOCKED, 1106 tcnp->cn_cred, (int *)0, (struct proc *)0); 1107 if (error == 0) { 1108# if (BYTE_ORDER == LITTLE_ENDIAN) 1109 if (fvp->v_mount->mnt_maxsymlinklen <= 0) 1110 namlen = dirbuf.dotdot_type; 1111 else 1112 namlen = dirbuf.dotdot_namlen; 1113# else 1114 namlen = dirbuf.dotdot_namlen; 1115# endif 1116 if (namlen != 2 || 1117 dirbuf.dotdot_name[0] != '.' || 1118 dirbuf.dotdot_name[1] != '.') { 1119 ufs_dirbad(xp, (doff_t)12, 1120 "rename: mangled dir"); 1121 } else { 1122 dirbuf.dotdot_ino = newparent; 1123 (void) vn_rdwr(UIO_WRITE, fvp, 1124 (caddr_t)&dirbuf, 1125 sizeof (struct dirtemplate), 1126 (off_t)0, UIO_SYSSPACE, 1127 IO_NODELOCKED|IO_SYNC, 1128 tcnp->cn_cred, (int *)0, 1129 (struct proc *)0); 1130 cache_purge(fdvp); 1131 } 1132 } 1133 } 1134 error = ufs_dirremove(fdvp, fcnp); 1135 if (!error) { 1136 xp->i_nlink--; 1137 xp->i_flag |= IN_CHANGE; 1138 } 1139 xp->i_flag &= ~IN_RENAME; 1140 } 1141 if (dp) 1142 vput(fdvp); 1143 if (xp) 1144 vput(fvp); 1145 vrele(ap->a_fvp); 1146 return (error); 1147 1148bad: 1149 if (xp) 1150 vput(ITOV(xp)); 1151 vput(ITOV(dp)); 1152out: 1153 if (doingdirectory) 1154 ip->i_flag &= ~IN_RENAME; 1155 if (VOP_LOCK(fvp) == 0) { 1156 ip->i_nlink--; 1157 ip->i_flag |= IN_CHANGE; 1158 vput(fvp); 1159 } else 1160 vrele(fvp); 1161 return (error); 1162} 1163 1164/* 1165 * A virgin directory (no blushing please). 1166 */ 1167static struct dirtemplate mastertemplate = { 1168 0, 12, DT_DIR, 1, ".", 1169 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." 1170}; 1171static struct odirtemplate omastertemplate = { 1172 0, 12, 1, ".", 1173 0, DIRBLKSIZ - 12, 2, ".." 1174}; 1175 1176/* 1177 * Mkdir system call 1178 */ 1179int 1180ufs_mkdir(v) 1181 void *v; 1182{ 1183 struct vop_mkdir_args /* { 1184 struct vnode *a_dvp; 1185 struct vnode **a_vpp; 1186 struct componentname *a_cnp; 1187 struct vattr *a_vap; 1188 } */ *ap = v; 1189 register struct vnode *dvp = ap->a_dvp; 1190 register struct vattr *vap = ap->a_vap; 1191 register struct componentname *cnp = ap->a_cnp; 1192 register struct inode *ip, *dp; 1193 struct vnode *tvp; 1194 struct dirtemplate dirtemplate, *dtp; 1195 struct timespec ts; 1196 int error, dmode; 1197 1198#ifdef DIAGNOSTIC 1199 if ((cnp->cn_flags & HASBUF) == 0) 1200 panic("ufs_mkdir: no name"); 1201#endif 1202 dp = VTOI(dvp); 1203 if ((nlink_t)dp->i_nlink >= LINK_MAX) { 1204 error = EMLINK; 1205 goto out; 1206 } 1207 dmode = vap->va_mode & 0777; 1208 dmode |= IFDIR; 1209 /* 1210 * Must simulate part of ufs_makeinode here to acquire the inode, 1211 * but not have it entered in the parent directory. The entry is 1212 * made later after writing "." and ".." entries. 1213 */ 1214 if ((error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) != 0) 1215 goto out; 1216 ip = VTOI(tvp); 1217 ip->i_uid = cnp->cn_cred->cr_uid; 1218 ip->i_gid = dp->i_gid; 1219#ifdef QUOTA 1220 if ((error = getinoquota(ip)) || 1221 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 1222 free(cnp->cn_pnbuf, M_NAMEI); 1223 VOP_VFREE(tvp, ip->i_number, dmode); 1224 vput(tvp); 1225 vput(dvp); 1226 return (error); 1227 } 1228#endif 1229 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1230 ip->i_mode = dmode; 1231 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ 1232 ip->i_nlink = 2; 1233 if (cnp->cn_flags & ISWHITEOUT) 1234 ip->i_flags |= UF_OPAQUE; 1235 TIMEVAL_TO_TIMESPEC(&time, &ts); 1236 error = VOP_UPDATE(tvp, &ts, &ts, 1); 1237 1238 /* 1239 * Bump link count in parent directory 1240 * to reflect work done below. Should 1241 * be done before reference is created 1242 * so reparation is possible if we crash. 1243 */ 1244 dp->i_nlink++; 1245 dp->i_flag |= IN_CHANGE; 1246 if ((error = VOP_UPDATE(dvp, &ts, &ts, 1)) != 0) 1247 goto bad; 1248 1249 /* Initialize directory with "." and ".." from static template. */ 1250 if (dvp->v_mount->mnt_maxsymlinklen > 0) 1251 dtp = &mastertemplate; 1252 else 1253 dtp = (struct dirtemplate *)&omastertemplate; 1254 dirtemplate = *dtp; 1255 dirtemplate.dot_ino = ip->i_number; 1256 dirtemplate.dotdot_ino = dp->i_number; 1257 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, 1258 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, 1259 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); 1260 if (error) { 1261 dp->i_nlink--; 1262 dp->i_flag |= IN_CHANGE; 1263 goto bad; 1264 } 1265 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 1266 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ 1267 else { 1268 ip->i_size = DIRBLKSIZ; 1269 ip->i_flag |= IN_CHANGE; 1270 } 1271 1272 /* Directory set up, now install it's entry in the parent directory. */ 1273 if ((error = ufs_direnter(ip, dvp, cnp)) != 0) { 1274 dp->i_nlink--; 1275 dp->i_flag |= IN_CHANGE; 1276 } 1277bad: 1278 /* 1279 * No need to do an explicit VOP_TRUNCATE here, vrele will do this 1280 * for us because we set the link count to 0. 1281 */ 1282 if (error) { 1283 ip->i_nlink = 0; 1284 ip->i_flag |= IN_CHANGE; 1285 vput(tvp); 1286 } else 1287 *ap->a_vpp = tvp; 1288out: 1289 FREE(cnp->cn_pnbuf, M_NAMEI); 1290 vput(dvp); 1291 return (error); 1292} 1293 1294/* 1295 * Rmdir system call. 1296 */ 1297int 1298ufs_rmdir(v) 1299 void *v; 1300{ 1301 struct vop_rmdir_args /* { 1302 struct vnode *a_dvp; 1303 struct vnode *a_vp; 1304 struct componentname *a_cnp; 1305 } */ *ap = v; 1306 register struct vnode *vp = ap->a_vp; 1307 register struct vnode *dvp = ap->a_dvp; 1308 register struct componentname *cnp = ap->a_cnp; 1309 register struct inode *ip, *dp; 1310 int error; 1311 1312 ip = VTOI(vp); 1313 dp = VTOI(dvp); 1314 /* 1315 * No rmdir "." please. 1316 */ 1317 if (dp == ip) { 1318 vrele(dvp); 1319 vput(vp); 1320 return (EINVAL); 1321 } 1322 /* 1323 * Verify the directory is empty (and valid). 1324 * (Rmdir ".." won't be valid since 1325 * ".." will contain a reference to 1326 * the current directory and thus be 1327 * non-empty.) 1328 */ 1329 error = 0; 1330 if (ip->i_nlink != 2 || 1331 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 1332 error = ENOTEMPTY; 1333 goto out; 1334 } 1335 if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) { 1336 error = EPERM; 1337 goto out; 1338 } 1339 /* 1340 * Delete reference to directory before purging 1341 * inode. If we crash in between, the directory 1342 * will be reattached to lost+found, 1343 */ 1344 if ((error = ufs_dirremove(dvp, cnp)) != 0) 1345 goto out; 1346 dp->i_nlink--; 1347 dp->i_flag |= IN_CHANGE; 1348 cache_purge(dvp); 1349 vput(dvp); 1350 dvp = NULL; 1351 /* 1352 * Truncate inode. The only stuff left 1353 * in the directory is "." and "..". The 1354 * "." reference is inconsequential since 1355 * we're quashing it. The ".." reference 1356 * has already been adjusted above. We've 1357 * removed the "." reference and the reference 1358 * in the parent directory, but there may be 1359 * other hard links so decrement by 2 and 1360 * worry about them later. 1361 */ 1362 ip->i_nlink -= 2; 1363 error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, 1364 cnp->cn_proc); 1365 cache_purge(ITOV(ip)); 1366out: 1367 if (dvp) 1368 vput(dvp); 1369 vput(vp); 1370 return (error); 1371} 1372 1373/* 1374 * symlink -- make a symbolic link 1375 */ 1376int 1377ufs_symlink(v) 1378 void *v; 1379{ 1380 struct vop_symlink_args /* { 1381 struct vnode *a_dvp; 1382 struct vnode **a_vpp; 1383 struct componentname *a_cnp; 1384 struct vattr *a_vap; 1385 char *a_target; 1386 } */ *ap = v; 1387 register struct vnode *vp, **vpp = ap->a_vpp; 1388 register struct inode *ip; 1389 int len, error; 1390 1391 error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, 1392 vpp, ap->a_cnp); 1393 if (error) 1394 return (error); 1395 vp = *vpp; 1396 len = strlen(ap->a_target); 1397 if (len < vp->v_mount->mnt_maxsymlinklen) { 1398 ip = VTOI(vp); 1399 bcopy(ap->a_target, (char *)ip->i_shortlink, len); 1400 ip->i_size = len; 1401 ip->i_flag |= IN_CHANGE | IN_UPDATE; 1402 } else 1403 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, 1404 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, 1405 (struct proc *)0); 1406 vput(vp); 1407 return (error); 1408} 1409 1410/* 1411 * Vnode op for reading directories. 1412 * 1413 * The routine below assumes that the on-disk format of a directory 1414 * is the same as that defined by <sys/dirent.h>. If the on-disk 1415 * format changes, then it will be necessary to do a conversion 1416 * from the on-disk format that read returns to the format defined 1417 * by <sys/dirent.h>. 1418 */ 1419int 1420ufs_readdir(v) 1421 void *v; 1422{ 1423 struct vop_readdir_args /* { 1424 struct vnode *a_vp; 1425 struct uio *a_uio; 1426 struct ucred *a_cred; 1427 int *a_eofflag; 1428 u_long *a_cookies; 1429 int ncookies; 1430 } */ *ap = v; 1431 register struct uio *uio = ap->a_uio; 1432 int error; 1433 size_t count, lost; 1434 off_t off = uio->uio_offset; 1435 1436 count = uio->uio_resid; 1437 /* Make sure we don't return partial entries. */ 1438 count -= (uio->uio_offset + count) & (DIRBLKSIZ -1); 1439 if (count <= 0) 1440 return (EINVAL); 1441 lost = uio->uio_resid - count; 1442 uio->uio_resid = count; 1443 uio->uio_iov->iov_len = count; 1444# if (BYTE_ORDER == LITTLE_ENDIAN) 1445 if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) { 1446 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred); 1447 } else { 1448 struct dirent *dp, *edp; 1449 struct uio auio; 1450 struct iovec aiov; 1451 caddr_t dirbuf; 1452 int readcnt; 1453 u_char tmp; 1454 1455 auio = *uio; 1456 auio.uio_iov = &aiov; 1457 auio.uio_iovcnt = 1; 1458 auio.uio_segflg = UIO_SYSSPACE; 1459 aiov.iov_len = count; 1460 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK); 1461 aiov.iov_base = dirbuf; 1462 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); 1463 if (error == 0) { 1464 readcnt = count - auio.uio_resid; 1465 edp = (struct dirent *)&dirbuf[readcnt]; 1466 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 1467 tmp = dp->d_namlen; 1468 dp->d_namlen = dp->d_type; 1469 dp->d_type = tmp; 1470 if (dp->d_reclen > 0) { 1471 dp = (struct dirent *) 1472 ((char *)dp + dp->d_reclen); 1473 } else { 1474 error = EIO; 1475 break; 1476 } 1477 } 1478 if (dp >= edp) 1479 error = uiomove(dirbuf, readcnt, uio); 1480 } 1481 FREE(dirbuf, M_TEMP); 1482 } 1483# else 1484 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred); 1485# endif 1486 if (!error && ap->a_ncookies) { 1487 register struct dirent *dp; 1488 register u_long *cookies = ap->a_cookies; 1489 register int ncookies = ap->a_ncookies; 1490 1491 /* 1492 * Only the NFS server and emulations use cookies, and they 1493 * load the directory block into system space, so we can 1494 * just look at it directly. 1495 */ 1496 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) 1497 panic("ufs_readdir: lost in space"); 1498 dp = (struct dirent *) 1499 (uio->uio_iov->iov_base - (uio->uio_offset - off)); 1500 while (ncookies-- && off < uio->uio_offset) { 1501 if (dp->d_reclen == 0) 1502 break; 1503 off += dp->d_reclen; 1504 *(cookies++) = off; 1505 dp = (struct dirent *)((caddr_t)dp + dp->d_reclen); 1506 } 1507 lost += uio->uio_offset - off; 1508 uio->uio_offset = off; 1509 } 1510 uio->uio_resid += lost; 1511 *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset; 1512 return (error); 1513} 1514 1515/* 1516 * Return target name of a symbolic link 1517 */ 1518int 1519ufs_readlink(v) 1520 void *v; 1521{ 1522 struct vop_readlink_args /* { 1523 struct vnode *a_vp; 1524 struct uio *a_uio; 1525 struct ucred *a_cred; 1526 } */ *ap = v; 1527 register struct vnode *vp = ap->a_vp; 1528 register struct inode *ip = VTOI(vp); 1529 int isize; 1530 1531 isize = ip->i_size; 1532 if (isize < vp->v_mount->mnt_maxsymlinklen || 1533 (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_din.di_blocks == 0)) { 1534 uiomove((char *)ip->i_shortlink, isize, ap->a_uio); 1535 return (0); 1536 } 1537 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); 1538} 1539 1540/* 1541 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 1542 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 1543 */ 1544/* ARGSUSED */ 1545int 1546ufs_abortop(v) 1547 void *v; 1548{ 1549 struct vop_abortop_args /* { 1550 struct vnode *a_dvp; 1551 struct componentname *a_cnp; 1552 } */ *ap = v; 1553 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 1554 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 1555 return (0); 1556} 1557 1558/* 1559 * Lock an inode. If its already locked, set the WANT bit and sleep. 1560 */ 1561int 1562ufs_lock(v) 1563 void *v; 1564{ 1565 struct vop_lock_args /* { 1566 struct vnode *a_vp; 1567 } */ *ap = v; 1568 register struct vnode *vp = ap->a_vp; 1569 register struct inode *ip; 1570#ifdef DIAGNOSTIC 1571 struct proc *p = curproc; /* XXX */ 1572#endif 1573 1574start: 1575 while (vp->v_flag & VXLOCK) { 1576 vp->v_flag |= VXWANT; 1577 sleep((caddr_t)vp, PINOD); 1578 } 1579 if (vp->v_tag == VT_NON) 1580 return (ENOENT); 1581 ip = VTOI(vp); 1582 if (ip->i_flag & IN_LOCKED) { 1583 ip->i_flag |= IN_WANTED; 1584#ifdef DIAGNOSTIC 1585 if (p) { 1586 if (p->p_pid == ip->i_lockholder) 1587 panic("locking against myself"); 1588 ip->i_lockwaiter = p->p_pid; 1589 } else 1590 ip->i_lockwaiter = -1; 1591#endif 1592 (void) sleep((caddr_t)ip, PINOD); 1593 goto start; 1594 } 1595#ifdef DIAGNOSTIC 1596 ip->i_lockwaiter = 0; 1597 if (ip->i_lockholder != 0) 1598 panic("lockholder (%d) != 0", ip->i_lockholder); 1599 if (p && p->p_pid == 0) 1600 printf("locking by process 0\n"); 1601 if (p) 1602 ip->i_lockholder = p->p_pid; 1603 else 1604 ip->i_lockholder = -1; 1605#endif 1606 ip->i_flag |= IN_LOCKED; 1607 return (0); 1608} 1609 1610/* 1611 * Unlock an inode. If WANT bit is on, wakeup. 1612 */ 1613int lockcount = 90; 1614int 1615ufs_unlock(v) 1616 void *v; 1617{ 1618 struct vop_unlock_args /* { 1619 struct vnode *a_vp; 1620 } */ *ap = v; 1621 register struct inode *ip = VTOI(ap->a_vp); 1622#ifdef DIAGNOSTIC 1623 struct proc *p = curproc; /* XXX */ 1624#endif 1625 1626#ifdef DIAGNOSTIC 1627 if ((ip->i_flag & IN_LOCKED) == 0) { 1628 vprint("ufs_unlock: unlocked inode", ap->a_vp); 1629 panic("ufs_unlock NOT LOCKED"); 1630 } 1631 if (p && p->p_pid != ip->i_lockholder && p->p_pid > -1 && 1632 ip->i_lockholder > -1 && lockcount++ < 100) 1633 panic("unlocker (%d) != lock holder (%d)", 1634 p->p_pid, ip->i_lockholder); 1635 ip->i_lockholder = 0; 1636#endif 1637 ip->i_flag &= ~IN_LOCKED; 1638 if (ip->i_flag & IN_WANTED) { 1639 ip->i_flag &= ~IN_WANTED; 1640 wakeup((caddr_t)ip); 1641 } 1642 return (0); 1643} 1644 1645/* 1646 * Check for a locked inode. 1647 */ 1648int 1649ufs_islocked(v) 1650 void *v; 1651{ 1652 struct vop_islocked_args /* { 1653 struct vnode *a_vp; 1654 } */ *ap = v; 1655 1656 if (VTOI(ap->a_vp)->i_flag & IN_LOCKED) 1657 return (1); 1658 return (0); 1659} 1660 1661/* 1662 * Calculate the logical to physical mapping if not done already, 1663 * then call the device strategy routine. 1664 */ 1665int 1666ufs_strategy(v) 1667 void *v; 1668{ 1669 struct vop_strategy_args /* { 1670 struct buf *a_bp; 1671 } */ *ap = v; 1672 register struct buf *bp = ap->a_bp; 1673 register struct vnode *vp = bp->b_vp; 1674 register struct inode *ip; 1675 int error; 1676 1677 ip = VTOI(vp); 1678 if (vp->v_type == VBLK || vp->v_type == VCHR) 1679 panic("ufs_strategy: spec"); 1680 if (bp->b_blkno == bp->b_lblkno) { 1681 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, 1682 NULL); 1683 if (error) { 1684 bp->b_error = error; 1685 bp->b_flags |= B_ERROR; 1686 biodone(bp); 1687 return (error); 1688 } 1689 if ((long)bp->b_blkno == -1) 1690 clrbuf(bp); 1691 } 1692 if ((long)bp->b_blkno == -1) { 1693 biodone(bp); 1694 return (0); 1695 } 1696 vp = ip->i_devvp; 1697 bp->b_dev = vp->v_rdev; 1698 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); 1699 return (0); 1700} 1701 1702/* 1703 * Print out the contents of an inode. 1704 */ 1705int 1706ufs_print(v) 1707 void *v; 1708{ 1709 struct vop_print_args /* { 1710 struct vnode *a_vp; 1711 } */ *ap = v; 1712 register struct vnode *vp = ap->a_vp; 1713 register struct inode *ip = VTOI(vp); 1714 1715 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number, 1716 major(ip->i_dev), minor(ip->i_dev)); 1717#ifdef FIFO 1718 if (vp->v_type == VFIFO) 1719 fifo_printinfo(vp); 1720#endif /* FIFO */ 1721 printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : ""); 1722 if (ip->i_lockholder == 0) 1723 return (0); 1724 printf("\towner pid %d", ip->i_lockholder); 1725 if (ip->i_lockwaiter) 1726 printf(" waiting pid %d", ip->i_lockwaiter); 1727 printf("\n"); 1728 return (0); 1729} 1730 1731/* 1732 * Read wrapper for special devices. 1733 */ 1734int 1735ufsspec_read(v) 1736 void *v; 1737{ 1738 struct vop_read_args /* { 1739 struct vnode *a_vp; 1740 struct uio *a_uio; 1741 int a_ioflag; 1742 struct ucred *a_cred; 1743 } */ *ap = v; 1744 1745 /* 1746 * Set access flag. 1747 */ 1748 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 1749 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); 1750} 1751 1752/* 1753 * Write wrapper for special devices. 1754 */ 1755int 1756ufsspec_write(v) 1757 void *v; 1758{ 1759 struct vop_write_args /* { 1760 struct vnode *a_vp; 1761 struct uio *a_uio; 1762 int a_ioflag; 1763 struct ucred *a_cred; 1764 } */ *ap = v; 1765 1766 /* 1767 * Set update and change flags. 1768 */ 1769 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; 1770 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); 1771} 1772 1773/* 1774 * Close wrapper for special devices. 1775 * 1776 * Update the times on the inode then do device close. 1777 */ 1778int 1779ufsspec_close(v) 1780 void *v; 1781{ 1782 struct vop_close_args /* { 1783 struct vnode *a_vp; 1784 int a_fflag; 1785 struct ucred *a_cred; 1786 struct proc *a_p; 1787 } */ *ap = v; 1788 register struct inode *ip = VTOI(ap->a_vp); 1789 1790 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) 1791 ITIMES(ip, &time, &time); 1792 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); 1793} 1794 1795#ifdef FIFO 1796/* 1797 * Read wrapper for fifo's 1798 */ 1799int 1800ufsfifo_read(v) 1801 void *v; 1802{ 1803 struct vop_read_args /* { 1804 struct vnode *a_vp; 1805 struct uio *a_uio; 1806 int a_ioflag; 1807 struct ucred *a_cred; 1808 } */ *ap = v; 1809 extern int (**fifo_vnodeop_p) __P((void *)); 1810 1811 /* 1812 * Set access flag. 1813 */ 1814 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 1815 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); 1816} 1817 1818/* 1819 * Write wrapper for fifo's. 1820 */ 1821int 1822ufsfifo_write(v) 1823 void *v; 1824{ 1825 struct vop_write_args /* { 1826 struct vnode *a_vp; 1827 struct uio *a_uio; 1828 int a_ioflag; 1829 struct ucred *a_cred; 1830 } */ *ap = v; 1831 extern int (**fifo_vnodeop_p) __P((void *)); 1832 1833 /* 1834 * Set update and change flags. 1835 */ 1836 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; 1837 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); 1838} 1839 1840/* 1841 * Close wrapper for fifo's. 1842 * 1843 * Update the times on the inode then do device close. 1844 */ 1845int 1846ufsfifo_close(v) 1847 void *v; 1848{ 1849 struct vop_close_args /* { 1850 struct vnode *a_vp; 1851 int a_fflag; 1852 struct ucred *a_cred; 1853 struct proc *a_p; 1854 } */ *ap = v; 1855 extern int (**fifo_vnodeop_p) __P((void *)); 1856 register struct inode *ip = VTOI(ap->a_vp); 1857 1858 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED)) 1859 ITIMES(ip, &time, &time); 1860 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap)); 1861} 1862#endif /* FIFO */ 1863 1864/* 1865 * Return POSIX pathconf information applicable to ufs filesystems. 1866 */ 1867int 1868ufs_pathconf(v) 1869 void *v; 1870{ 1871 struct vop_pathconf_args /* { 1872 struct vnode *a_vp; 1873 int a_name; 1874 register_t *a_retval; 1875 } */ *ap = v; 1876 1877 switch (ap->a_name) { 1878 case _PC_LINK_MAX: 1879 *ap->a_retval = LINK_MAX; 1880 return (0); 1881 case _PC_NAME_MAX: 1882 *ap->a_retval = NAME_MAX; 1883 return (0); 1884 case _PC_PATH_MAX: 1885 *ap->a_retval = PATH_MAX; 1886 return (0); 1887 case _PC_PIPE_BUF: 1888 *ap->a_retval = PIPE_BUF; 1889 return (0); 1890 case _PC_CHOWN_RESTRICTED: 1891 *ap->a_retval = 1; 1892 return (0); 1893 case _PC_NO_TRUNC: 1894 *ap->a_retval = 1; 1895 return (0); 1896 default: 1897 return (EINVAL); 1898 } 1899 /* NOTREACHED */ 1900} 1901 1902/* 1903 * Advisory record locking support 1904 */ 1905int 1906ufs_advlock(v) 1907 void *v; 1908{ 1909 struct vop_advlock_args /* { 1910 struct vnode *a_vp; 1911 caddr_t a_id; 1912 int a_op; 1913 struct flock *a_fl; 1914 int a_flags; 1915 } */ *ap = v; 1916 register struct inode *ip = VTOI(ap->a_vp); 1917 1918 return (lf_advlock(&ip->i_lockf, ip->i_size, ap->a_id, ap->a_op, 1919 ap->a_fl, ap->a_flags)); 1920} 1921 1922/* 1923 * Initialize the vnode associated with a new inode, handle aliased 1924 * vnodes. 1925 */ 1926int 1927ufs_vinit(mntp, specops, fifoops, vpp) 1928 struct mount *mntp; 1929 int (**specops) __P((void *)); 1930 int (**fifoops) __P((void *)); 1931 struct vnode **vpp; 1932{ 1933 struct inode *ip; 1934 struct vnode *vp, *nvp; 1935 1936 vp = *vpp; 1937 ip = VTOI(vp); 1938 switch(vp->v_type = IFTOVT(ip->i_mode)) { 1939 case VCHR: 1940 case VBLK: 1941 vp->v_op = specops; 1942 if ((nvp = checkalias(vp, ip->i_rdev, mntp)) != NULL) { 1943 /* 1944 * Discard unneeded vnode, but save its inode. 1945 */ 1946 ufs_ihashrem(ip); 1947 VOP_UNLOCK(vp); 1948 nvp->v_data = vp->v_data; 1949 vp->v_data = NULL; 1950 vp->v_op = spec_vnodeop_p; 1951 vrele(vp); 1952 vgone(vp); 1953 /* 1954 * Reinitialize aliased inode. 1955 */ 1956 vp = nvp; 1957 ip->i_vnode = vp; 1958 ufs_ihashins(ip); 1959 } 1960 break; 1961 case VFIFO: 1962#ifdef FIFO 1963 vp->v_op = fifoops; 1964 break; 1965#else 1966 return (EOPNOTSUPP); 1967#endif 1968 case VNON: 1969 case VBAD: 1970 case VSOCK: 1971 case VLNK: 1972 case VDIR: 1973 case VREG: 1974 break; 1975 } 1976 if (ip->i_number == ROOTINO) 1977 vp->v_flag |= VROOT; 1978 /* 1979 * Initialize modrev times 1980 */ 1981 SETHIGH(ip->i_modrev, mono_time.tv_sec); 1982 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294); 1983 *vpp = vp; 1984 return (0); 1985} 1986 1987/* 1988 * Allocate a new inode. 1989 */ 1990int 1991ufs_makeinode(mode, dvp, vpp, cnp) 1992 int mode; 1993 struct vnode *dvp; 1994 struct vnode **vpp; 1995 struct componentname *cnp; 1996{ 1997 register struct inode *ip, *pdir; 1998 struct timespec ts; 1999 struct vnode *tvp; 2000 int error; 2001 2002 pdir = VTOI(dvp); 2003#ifdef DIAGNOSTIC 2004 if ((cnp->cn_flags & HASBUF) == 0) 2005 panic("ufs_makeinode: no name"); 2006#endif 2007 *vpp = NULL; 2008 if ((mode & IFMT) == 0) 2009 mode |= IFREG; 2010 2011 if ((error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) != 0) { 2012 free(cnp->cn_pnbuf, M_NAMEI); 2013 vput(dvp); 2014 return (error); 2015 } 2016 ip = VTOI(tvp); 2017 ip->i_gid = pdir->i_gid; 2018 ip->i_uid = cnp->cn_cred->cr_uid; 2019#ifdef QUOTA 2020 if ((error = getinoquota(ip)) || 2021 (error = chkiq(ip, 1, cnp->cn_cred, 0))) { 2022 free(cnp->cn_pnbuf, M_NAMEI); 2023 VOP_VFREE(tvp, ip->i_number, mode); 2024 vput(tvp); 2025 vput(dvp); 2026 return (error); 2027 } 2028#endif 2029 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 2030 ip->i_mode = mode; 2031 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ 2032 ip->i_nlink = 1; 2033 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && 2034 suser(cnp->cn_cred, NULL)) 2035 ip->i_mode &= ~ISGID; 2036 2037 if (cnp->cn_flags & ISWHITEOUT) 2038 ip->i_flags |= UF_OPAQUE; 2039 2040 /* 2041 * Make sure inode goes to disk before directory entry. 2042 */ 2043 TIMEVAL_TO_TIMESPEC(&time, &ts); 2044 if ((error = VOP_UPDATE(tvp, &ts, &ts, 1)) != 0) 2045 goto bad; 2046 if ((error = ufs_direnter(ip, dvp, cnp)) != 0) 2047 goto bad; 2048 if ((cnp->cn_flags & SAVESTART) == 0) 2049 FREE(cnp->cn_pnbuf, M_NAMEI); 2050 vput(dvp); 2051 *vpp = tvp; 2052 return (0); 2053 2054bad: 2055 /* 2056 * Write error occurred trying to update the inode 2057 * or the directory so must deallocate the inode. 2058 */ 2059 free(cnp->cn_pnbuf, M_NAMEI); 2060 vput(dvp); 2061 ip->i_nlink = 0; 2062 ip->i_flag |= IN_CHANGE; 2063 vput(tvp); 2064 return (error); 2065}