1 /*- 2 * Copyright (c) 1994 Jan-Simon Pendry 3 * Copyright (c) 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 6 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 36 * $FreeBSD: src/sys/fs/unionfs/union_subr.c,v 1.99 2008/01/24 12:34:27 attilio Exp $ 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <sys/malloc.h> 45 #include <sys/mount.h> 46 #include <sys/namei.h> 47 #include <sys/proc.h> 48 #include <sys/vnode.h> 49 #include <sys/dirent.h> 50 #include <sys/fcntl.h> 51 #include <sys/filedesc.h> 52 #include <sys/stat.h> 53 #include <sys/kauth.h> 54 #include <sys/resourcevar.h> 55 56 #include <fs/unionfs/unionfs.h> 57 58 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part"); 59 60 /* 61 * Make a new or get existing unionfs node. 62 * 63 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is 64 * locked, uppervp or lowervp is locked too. In order to prevent dead lock, 65 * you should not lock plurality simultaneously. 66 */ 67 int 68 unionfs_nodeget(struct mount *mp, struct vnode *uppervp, 69 struct vnode *lowervp, struct vnode *dvp, 70 struct vnode **vpp, struct componentname *cnp) 71 { 72 struct unionfs_mount *ump; 73 struct unionfs_node *unp; 74 struct vnode *vp; 75 int error; 76 const char *path; 77 78 ump = MOUNTTOUNIONFSMOUNT(mp); 79 path = (cnp ? cnp->cn_nameptr : NULL); 80 81 if (uppervp == NULLVP && lowervp == NULLVP) 82 panic("unionfs_nodeget: upper and lower is null"); 83 84 /* If it has no ISLASTCN flag, path check is skipped. */ 85 if (cnp && !(cnp->cn_flags & ISLASTCN)) 86 path = NULL; 87 88 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) || 89 (lowervp == NULLVP || ump->um_lowervp != lowervp)) { 90 if (dvp == NULLVP) 91 return (EINVAL); 92 } 93 94 /* 95 * Get a new vnode and share the lock with upper layer vnode, 96 * unless layers are inverted. 97 */ 98 vnode_t *svp = (uppervp != NULLVP) ? uppervp : lowervp; 99 error = getnewvnode(VT_UNION, mp, unionfs_vnodeop_p, 100 svp->v_interlock, &vp); 101 if (error != 0) { 102 return (error); 103 } 104 if (dvp != NULLVP) 105 vref(dvp); 106 if (uppervp != NULLVP) 107 vref(uppervp); 108 if (lowervp != NULLVP) 109 vref(lowervp); 110 111 unp = kmem_zalloc(sizeof(*unp), KM_SLEEP); 112 unp->un_vnode = vp; 113 unp->un_uppervp = uppervp; 114 unp->un_lowervp = lowervp; 115 unp->un_dvp = dvp; 116 117 if (path != NULL) { 118 unp->un_path = (char *) 119 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO); 120 memcpy(unp->un_path, cnp->cn_nameptr, cnp->cn_namelen); 121 unp->un_path[cnp->cn_namelen] = '\0'; 122 } 123 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type); 124 vp->v_data = unp; 125 uvm_vnp_setsize(vp, 0); 126 127 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) && 128 (lowervp != NULLVP && ump->um_lowervp == lowervp)) 129 vp->v_vflag |= VV_ROOT; 130 131 *vpp = vp; 132 133 return (0); 134 } 135 136 /* 137 * Clean up the unionfs node. 138 */ 139 void 140 unionfs_noderem(struct vnode *vp) 141 { 142 struct unionfs_mount *ump; 143 struct unionfs_node *unp; 144 struct unionfs_node_status *unsp; 145 struct vnode *lvp; 146 struct vnode *uvp; 147 148 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount); 149 150 /* 151 * Use the interlock to protect the clearing of v_data to 152 * prevent faults in unionfs_lock(). 153 */ 154 unp = VTOUNIONFS(vp); 155 lvp = unp->un_lowervp; 156 uvp = unp->un_uppervp; 157 unp->un_lowervp = unp->un_uppervp = NULLVP; 158 vp->v_data = NULL; 159 160 if (lvp != NULLVP) 161 vrele(lvp); 162 if (uvp != NULLVP) 163 vrele(uvp); 164 if (unp->un_dvp != NULLVP) { 165 vrele(unp->un_dvp); 166 unp->un_dvp = NULLVP; 167 } 168 if (unp->un_path) { 169 free(unp->un_path, M_UNIONFSPATH); 170 unp->un_path = NULL; 171 } 172 173 while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) { 174 LIST_REMOVE(unsp, uns_list); 175 free(unsp, M_TEMP); 176 } 177 kmem_free(unp, sizeof(*unp)); 178 } 179 180 /* 181 * Get the unionfs node status. 182 * You need exclusive lock this vnode. 183 */ 184 void 185 unionfs_get_node_status(struct unionfs_node *unp, 186 struct unionfs_node_status **unspp) 187 { 188 struct unionfs_node_status *unsp; 189 pid_t pid; 190 lwpid_t lid; 191 192 KASSERT(NULL != unspp); 193 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 194 195 pid = curproc->p_pid; 196 lid = curlwp->l_lid; 197 198 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) { 199 if (unsp->uns_pid == pid && unsp->uns_lid == lid) { 200 *unspp = unsp; 201 return; 202 } 203 } 204 205 /* create a new unionfs node status */ 206 unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP); 207 unsp->uns_pid = pid; 208 unsp->uns_lid = lid; 209 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list); 210 211 *unspp = unsp; 212 } 213 214 /* 215 * Remove the unionfs node status, if you can. 216 * You need exclusive lock this vnode. 217 */ 218 void 219 unionfs_tryrem_node_status(struct unionfs_node *unp, 220 struct unionfs_node_status *unsp) 221 { 222 KASSERT(NULL != unsp); 223 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 224 225 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt) 226 return; 227 228 LIST_REMOVE(unsp, uns_list); 229 kmem_free(unsp, sizeof(*unsp)); 230 } 231 232 /* 233 * Create upper node attr. 234 */ 235 void 236 unionfs_create_uppervattr_core(struct unionfs_mount *ump, 237 struct vattr *lva, 238 struct vattr *uva) 239 { 240 vattr_null(uva); 241 uva->va_type = lva->va_type; 242 uva->va_atime = lva->va_atime; 243 uva->va_mtime = lva->va_mtime; 244 uva->va_ctime = lva->va_ctime; 245 246 switch (ump->um_copymode) { 247 case UNIONFS_TRANSPARENT: 248 uva->va_mode = lva->va_mode; 249 uva->va_uid = lva->va_uid; 250 uva->va_gid = lva->va_gid; 251 break; 252 case UNIONFS_MASQUERADE: 253 if (ump->um_uid == lva->va_uid) { 254 uva->va_mode = lva->va_mode & 077077; 255 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700; 256 uva->va_uid = lva->va_uid; 257 uva->va_gid = lva->va_gid; 258 } else { 259 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile); 260 uva->va_uid = ump->um_uid; 261 uva->va_gid = ump->um_gid; 262 } 263 break; 264 default: /* UNIONFS_TRADITIONAL */ 265 uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask; 266 uva->va_uid = ump->um_uid; 267 uva->va_gid = ump->um_gid; 268 break; 269 } 270 } 271 272 /* 273 * Create upper node attr. 274 */ 275 int 276 unionfs_create_uppervattr(struct unionfs_mount *ump, 277 struct vnode *lvp, 278 struct vattr *uva, 279 kauth_cred_t cred) 280 { 281 int error; 282 struct vattr lva; 283 284 if ((error = VOP_GETATTR(lvp, &lva, cred))) 285 return (error); 286 287 unionfs_create_uppervattr_core(ump, &lva, uva); 288 289 return (error); 290 } 291 292 /* 293 * relookup 294 * 295 * dvp should be locked on entry and will be locked on return. 296 * 297 * If an error is returned, *vpp will be invalid, otherwise it will hold a 298 * locked, referenced vnode. If *vpp == dvp then remember that only one 299 * LK_EXCLUSIVE lock is held. 300 */ 301 static int 302 unionfs_relookup(struct vnode *dvp, struct vnode **vpp, 303 struct componentname *cnp, struct componentname *cn, 304 char **pnbuf_ret, 305 const char *path, int pathlen, u_long nameiop) 306 { 307 int error; 308 char *pnbuf; 309 310 cn->cn_namelen = pathlen; 311 pnbuf = PNBUF_GET(); 312 memcpy(pnbuf, path, pathlen); 313 pnbuf[pathlen] = '\0'; 314 315 cn->cn_nameiop = nameiop; 316 cn->cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN); 317 cn->cn_cred = cnp->cn_cred; 318 319 cn->cn_nameptr = pnbuf; 320 cn->cn_consume = cnp->cn_consume; 321 322 if (nameiop == DELETE) 323 cn->cn_flags |= (cnp->cn_flags & DOWHITEOUT); 324 325 vref(dvp); 326 VOP_UNLOCK(dvp); 327 328 if ((error = relookup(dvp, vpp, cn, 0))) { 329 PNBUF_PUT(pnbuf); 330 *pnbuf_ret = NULL; 331 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 332 } else { 333 *pnbuf_ret = pnbuf; 334 vrele(dvp); 335 } 336 337 return (error); 338 } 339 340 /* 341 * relookup for CREATE namei operation. 342 * 343 * dvp is unionfs vnode. dvp should be locked. 344 * 345 * If it called 'unionfs_copyfile' function by unionfs_link etc, 346 * VOP_LOOKUP information is broken. 347 * So it need relookup in order to create link etc. 348 */ 349 int 350 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp) 351 { 352 int error; 353 struct vnode *udvp; 354 struct vnode *vp; 355 struct componentname cn; 356 char *pnbuf; 357 358 udvp = UNIONFSVPTOUPPERVP(dvp); 359 vp = NULLVP; 360 361 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, 362 cnp->cn_nameptr, 363 strlen(cnp->cn_nameptr), CREATE); 364 if (error) 365 return (error); 366 367 if (vp != NULLVP) { 368 if (udvp == vp) 369 vrele(vp); 370 else 371 vput(vp); 372 373 error = EEXIST; 374 } 375 376 PNBUF_PUT(pnbuf); 377 378 if (!error) { 379 cnp->cn_flags = cn.cn_flags; 380 } 381 382 return (error); 383 } 384 385 /* 386 * relookup for DELETE namei operation. 387 * 388 * dvp is unionfs vnode. dvp should be locked. 389 */ 390 int 391 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp) 392 { 393 int error; 394 struct vnode *udvp; 395 struct vnode *vp; 396 struct componentname cn; 397 char *pnbuf; 398 399 udvp = UNIONFSVPTOUPPERVP(dvp); 400 vp = NULLVP; 401 402 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 403 strlen(cnp->cn_nameptr), DELETE); 404 if (error) 405 return (error); 406 407 if (vp == NULLVP) 408 error = ENOENT; 409 else { 410 if (udvp == vp) 411 vrele(vp); 412 else 413 vput(vp); 414 } 415 416 PNBUF_PUT(pnbuf); 417 418 if (!error) { 419 cnp->cn_flags = cn.cn_flags; 420 } 421 422 return (error); 423 } 424 425 /* 426 * relookup for RENAME namei operation. 427 * 428 * dvp is unionfs vnode. dvp should be locked. 429 */ 430 int 431 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp) 432 { 433 int error; 434 struct vnode *udvp; 435 struct vnode *vp; 436 struct componentname cn; 437 char *pnbuf; 438 439 udvp = UNIONFSVPTOUPPERVP(dvp); 440 vp = NULLVP; 441 442 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 443 strlen(cnp->cn_nameptr), RENAME); 444 if (error) 445 return (error); 446 447 if (vp != NULLVP) { 448 if (udvp == vp) 449 vrele(vp); 450 else 451 vput(vp); 452 } 453 454 PNBUF_PUT(pnbuf); 455 456 if (!error) { 457 cnp->cn_flags = cn.cn_flags; 458 } 459 460 return (error); 461 462 } 463 464 /* 465 * Update the unionfs_node. 466 * 467 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the 468 * uvp's lock and lower's lock will be unlocked. 469 */ 470 static void 471 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp) 472 { 473 struct vnode *vp; 474 struct vnode *lvp; 475 476 vp = UNIONFSTOV(unp); 477 lvp = unp->un_lowervp; 478 479 /* 480 * lock update 481 */ 482 mutex_enter(vp->v_interlock); 483 unp->un_uppervp = uvp; 484 KASSERT(VOP_ISLOCKED(lvp) == LK_EXCLUSIVE); 485 mutex_exit(vp->v_interlock); 486 } 487 488 /* 489 * Create a new shadow dir. 490 * 491 * udvp should be locked on entry and will be locked on return. 492 * 493 * If no error returned, unp will be updated. 494 */ 495 int 496 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, 497 struct unionfs_node *unp, struct componentname *cnp) 498 { 499 int error; 500 struct vnode *lvp; 501 struct vnode *uvp; 502 struct vattr va; 503 struct vattr lva; 504 struct componentname cn; 505 char *pnbuf; 506 507 if (unp->un_uppervp != NULLVP) 508 return (EEXIST); 509 510 lvp = unp->un_lowervp; 511 uvp = NULLVP; 512 513 memset(&cn, 0, sizeof(cn)); 514 515 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred))) 516 goto unionfs_mkshadowdir_abort; 517 518 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, &pnbuf, 519 cnp->cn_nameptr, cnp->cn_namelen, CREATE))) 520 goto unionfs_mkshadowdir_abort; 521 if (uvp != NULLVP) { 522 if (udvp == uvp) 523 vrele(uvp); 524 else 525 vput(uvp); 526 527 error = EEXIST; 528 goto unionfs_mkshadowdir_free_out; 529 } 530 531 unionfs_create_uppervattr_core(ump, &lva, &va); 532 533 error = VOP_MKDIR(udvp, &uvp, &cn, &va); 534 535 if (!error) { 536 unionfs_node_update(unp, uvp); 537 538 /* 539 * XXX The bug which cannot set uid/gid was corrected. 540 * Ignore errors. XXXNETBSD Why is this done as root? 541 */ 542 va.va_type = VNON; 543 VOP_SETATTR(uvp, &va, lwp0.l_cred); 544 } 545 546 unionfs_mkshadowdir_free_out: 547 PNBUF_PUT(pnbuf); 548 549 unionfs_mkshadowdir_abort: 550 551 return (error); 552 } 553 554 /* 555 * Create a new whiteout. 556 * 557 * dvp should be locked on entry and will be locked on return. 558 */ 559 int 560 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path) 561 { 562 int error; 563 struct vnode *wvp; 564 struct componentname cn; 565 char *pnbuf; 566 567 if (path == NULL) 568 path = cnp->cn_nameptr; 569 570 wvp = NULLVP; 571 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, &pnbuf, 572 path, strlen(path), CREATE))) 573 return (error); 574 if (wvp != NULLVP) { 575 PNBUF_PUT(pnbuf); 576 if (dvp == wvp) 577 vrele(wvp); 578 else 579 vput(wvp); 580 581 return (EEXIST); 582 } 583 584 PNBUF_PUT(pnbuf); 585 586 return (error); 587 } 588 589 /* 590 * Create a new vnode for create a new shadow file. 591 * 592 * If an error is returned, *vpp will be invalid, otherwise it will hold a 593 * locked, referenced and opened vnode. 594 * 595 * unp is never updated. 596 */ 597 static int 598 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp, 599 struct unionfs_node *unp, struct vattr *uvap) 600 { 601 struct unionfs_mount *ump; 602 struct vnode *vp; 603 struct vnode *lvp; 604 kauth_cred_t cred; 605 struct vattr lva; 606 int fmode; 607 int error; 608 struct componentname cn; 609 char *pnbuf; 610 611 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); 612 vp = NULLVP; 613 lvp = unp->un_lowervp; 614 cred = kauth_cred_get(); 615 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL); 616 error = 0; 617 618 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0) 619 return (error); 620 unionfs_create_uppervattr_core(ump, &lva, uvap); 621 622 if (unp->un_path == NULL) 623 panic("unionfs: un_path is null"); 624 625 cn.cn_namelen = strlen(unp->un_path); 626 pnbuf = PNBUF_GET(); 627 memcpy(pnbuf, unp->un_path, cn.cn_namelen + 1); 628 cn.cn_nameiop = CREATE; 629 cn.cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN); 630 cn.cn_cred = cred; 631 cn.cn_nameptr = pnbuf; 632 cn.cn_consume = 0; 633 634 vref(udvp); 635 if ((error = relookup(udvp, &vp, &cn, 0)) != 0) 636 goto unionfs_vn_create_on_upper_free_out2; 637 vrele(udvp); 638 639 if (vp != NULLVP) { 640 if (vp == udvp) 641 vrele(vp); 642 else 643 vput(vp); 644 error = EEXIST; 645 goto unionfs_vn_create_on_upper_free_out1; 646 } 647 648 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) 649 goto unionfs_vn_create_on_upper_free_out1; 650 651 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) { 652 vput(vp); 653 goto unionfs_vn_create_on_upper_free_out1; 654 } 655 vp->v_writecount++; 656 *vpp = vp; 657 658 unionfs_vn_create_on_upper_free_out1: 659 VOP_UNLOCK(udvp); 660 661 unionfs_vn_create_on_upper_free_out2: 662 PNBUF_PUT(pnbuf); 663 664 return (error); 665 } 666 667 /* 668 * Copy from lvp to uvp. 669 * 670 * lvp and uvp should be locked and opened on entry and will be locked and 671 * opened on return. 672 */ 673 static int 674 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp, 675 kauth_cred_t cred) 676 { 677 int error; 678 off_t offset; 679 int count; 680 int bufoffset; 681 char *buf; 682 struct uio uio; 683 struct iovec iov; 684 685 error = 0; 686 memset(&uio, 0, sizeof(uio)); 687 UIO_SETUP_SYSSPACE(&uio); 688 uio.uio_offset = 0; 689 690 buf = kmem_alloc(MAXBSIZE, KM_SLEEP); 691 while (error == 0) { 692 offset = uio.uio_offset; 693 694 uio.uio_iov = &iov; 695 uio.uio_iovcnt = 1; 696 iov.iov_base = buf; 697 iov.iov_len = MAXBSIZE; 698 uio.uio_resid = iov.iov_len; 699 uio.uio_rw = UIO_READ; 700 701 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0) 702 break; 703 if ((count = MAXBSIZE - uio.uio_resid) == 0) 704 break; 705 706 bufoffset = 0; 707 while (bufoffset < count) { 708 uio.uio_iov = &iov; 709 uio.uio_iovcnt = 1; 710 iov.iov_base = buf + bufoffset; 711 iov.iov_len = count - bufoffset; 712 uio.uio_offset = offset + bufoffset; 713 uio.uio_resid = iov.iov_len; 714 uio.uio_rw = UIO_WRITE; 715 716 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0) 717 break; 718 719 bufoffset += (count - bufoffset) - uio.uio_resid; 720 } 721 722 uio.uio_offset = offset + bufoffset; 723 } 724 725 kmem_free(buf, MAXBSIZE); 726 727 return (error); 728 } 729 730 /* 731 * Copy file from lower to upper. 732 * 733 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to 734 * docopy. 735 * 736 * If no error returned, unp will be updated. 737 */ 738 int 739 unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred) 740 { 741 int error; 742 struct vnode *udvp; 743 struct vnode *lvp; 744 struct vnode *uvp; 745 struct vattr uva; 746 747 lvp = unp->un_lowervp; 748 uvp = NULLVP; 749 750 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY)) 751 return (EROFS); 752 if (unp->un_dvp == NULLVP) 753 return (EINVAL); 754 if (unp->un_uppervp != NULLVP) 755 return (EEXIST); 756 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp; 757 if (udvp == NULLVP) 758 return (EROFS); 759 if ((udvp->v_mount->mnt_flag & MNT_RDONLY)) 760 return (EROFS); 761 762 error = VOP_ACCESS(lvp, VREAD, cred); 763 if (error != 0) 764 return (error); 765 766 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva); 767 if (error != 0) 768 return (error); 769 770 if (docopy != 0) { 771 error = VOP_OPEN(lvp, FREAD, cred); 772 if (error == 0) { 773 error = unionfs_copyfile_core(lvp, uvp, cred); 774 VOP_CLOSE(lvp, FREAD, cred); 775 } 776 } 777 VOP_CLOSE(uvp, FWRITE, cred); 778 uvp->v_writecount--; 779 780 if (error == 0) { 781 /* Reset the attributes. Ignore errors. */ 782 uva.va_type = VNON; 783 VOP_SETATTR(uvp, &uva, cred); 784 } 785 786 unionfs_node_update(unp, uvp); 787 788 return (error); 789 } 790 791 /* 792 * It checks whether vp can rmdir. (check empty) 793 * 794 * vp is unionfs vnode. 795 * vp should be locked. 796 */ 797 int 798 unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred) 799 { 800 int error; 801 int eofflag; 802 int lookuperr; 803 struct vnode *uvp; 804 struct vnode *lvp; 805 struct vnode *tvp; 806 struct vattr va; 807 struct componentname cn; 808 /* 809 * The size of buf needs to be larger than DIRBLKSIZ. 810 */ 811 char buf[256 * 6]; 812 struct dirent *dp; 813 struct dirent *edp; 814 struct uio uio; 815 struct iovec iov; 816 817 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 818 819 eofflag = 0; 820 uvp = UNIONFSVPTOUPPERVP(vp); 821 lvp = UNIONFSVPTOLOWERVP(vp); 822 823 /* check opaque */ 824 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0) 825 return (error); 826 if (va.va_flags & OPAQUE) 827 return (0); 828 829 /* open vnode */ 830 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0) 831 return (error); 832 if ((error = VOP_OPEN(vp, FREAD, cred)) != 0) 833 return (error); 834 835 UIO_SETUP_SYSSPACE(&uio); 836 uio.uio_rw = UIO_READ; 837 uio.uio_offset = 0; 838 839 while (!error && !eofflag) { 840 iov.iov_base = buf; 841 iov.iov_len = sizeof(buf); 842 uio.uio_iov = &iov; 843 uio.uio_iovcnt = 1; 844 uio.uio_resid = iov.iov_len; 845 846 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL); 847 if (error) 848 break; 849 850 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid]; 851 for (dp = (struct dirent*)buf; !error && dp < edp; 852 dp = (struct dirent*)((char *)dp + dp->d_reclen)) { 853 if (dp->d_type == DT_WHT || 854 (dp->d_namlen == 1 && dp->d_name[0] == '.') || 855 (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2))) 856 continue; 857 858 cn.cn_namelen = dp->d_namlen; 859 cn.cn_nameptr = dp->d_name; 860 cn.cn_nameiop = LOOKUP; 861 cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN); 862 cn.cn_cred = cred; 863 cn.cn_consume = 0; 864 865 /* 866 * check entry in lower. 867 * Sometimes, readdir function returns 868 * wrong entry. 869 */ 870 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn); 871 872 if (!lookuperr) 873 vput(tvp); 874 else 875 continue; /* skip entry */ 876 877 /* 878 * check entry 879 * If it has no exist/whiteout entry in upper, 880 * directory is not empty. 881 */ 882 cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN); 883 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn); 884 885 if (!lookuperr) 886 vput(tvp); 887 888 /* ignore exist or whiteout entry */ 889 if (!lookuperr || 890 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT))) 891 continue; 892 893 error = ENOTEMPTY; 894 } 895 } 896 897 /* close vnode */ 898 VOP_CLOSE(vp, FREAD, cred); 899 900 return (error); 901 } 902 903 #ifdef DIAGNOSTIC 904 905 struct vnode * 906 unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno) 907 { 908 struct unionfs_node *unp; 909 910 unp = VTOUNIONFS(vp); 911 912 #ifdef notyet 913 if (vp->v_op != unionfs_vnodeop_p) { 914 printf("unionfs_checkuppervp: on non-unionfs-node.\n"); 915 #ifdef KDB 916 kdb_enter(KDB_WHY_UNIONFS, 917 "unionfs_checkuppervp: on non-unionfs-node.\n"); 918 #endif 919 panic("unionfs_checkuppervp"); 920 }; 921 #endif 922 return (unp->un_uppervp); 923 } 924 925 struct vnode * 926 unionfs_checklowervp(struct vnode *vp, const char *fil, int lno) 927 { 928 struct unionfs_node *unp; 929 930 unp = VTOUNIONFS(vp); 931 932 #ifdef notyet 933 if (vp->v_op != unionfs_vnodeop_p) { 934 printf("unionfs_checklowervp: on non-unionfs-node.\n"); 935 #ifdef KDB 936 kdb_enter(KDB_WHY_UNIONFS, 937 "unionfs_checklowervp: on non-unionfs-node.\n"); 938 #endif 939 panic("unionfs_checklowervp"); 940 }; 941 #endif 942 return (unp->un_lowervp); 943 } 944 #endif 945