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