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 321 if (nameiop == DELETE) 322 cn->cn_flags |= (cnp->cn_flags & DOWHITEOUT); 323 324 vref(dvp); 325 VOP_UNLOCK(dvp); 326 327 if ((error = relookup(dvp, vpp, cn, 0))) { 328 PNBUF_PUT(pnbuf); 329 *pnbuf_ret = NULL; 330 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 331 } else { 332 *pnbuf_ret = pnbuf; 333 vrele(dvp); 334 } 335 336 return (error); 337 } 338 339 /* 340 * relookup for CREATE namei operation. 341 * 342 * dvp is unionfs vnode. dvp should be locked. 343 * 344 * If it called 'unionfs_copyfile' function by unionfs_link etc, 345 * VOP_LOOKUP information is broken. 346 * So it need relookup in order to create link etc. 347 */ 348 int 349 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp) 350 { 351 int error; 352 struct vnode *udvp; 353 struct vnode *vp; 354 struct componentname cn; 355 char *pnbuf; 356 357 udvp = UNIONFSVPTOUPPERVP(dvp); 358 vp = NULLVP; 359 360 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, 361 cnp->cn_nameptr, 362 strlen(cnp->cn_nameptr), CREATE); 363 if (error) 364 return (error); 365 366 if (vp != NULLVP) { 367 if (udvp == vp) 368 vrele(vp); 369 else 370 vput(vp); 371 372 error = EEXIST; 373 } 374 375 PNBUF_PUT(pnbuf); 376 377 if (!error) { 378 cnp->cn_flags = cn.cn_flags; 379 } 380 381 return (error); 382 } 383 384 /* 385 * relookup for DELETE namei operation. 386 * 387 * dvp is unionfs vnode. dvp should be locked. 388 */ 389 int 390 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp) 391 { 392 int error; 393 struct vnode *udvp; 394 struct vnode *vp; 395 struct componentname cn; 396 char *pnbuf; 397 398 udvp = UNIONFSVPTOUPPERVP(dvp); 399 vp = NULLVP; 400 401 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 402 strlen(cnp->cn_nameptr), DELETE); 403 if (error) 404 return (error); 405 406 if (vp == NULLVP) 407 error = ENOENT; 408 else { 409 if (udvp == vp) 410 vrele(vp); 411 else 412 vput(vp); 413 } 414 415 PNBUF_PUT(pnbuf); 416 417 if (!error) { 418 cnp->cn_flags = cn.cn_flags; 419 } 420 421 return (error); 422 } 423 424 /* 425 * relookup for RENAME namei operation. 426 * 427 * dvp is unionfs vnode. dvp should be locked. 428 */ 429 int 430 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp) 431 { 432 int error; 433 struct vnode *udvp; 434 struct vnode *vp; 435 struct componentname cn; 436 char *pnbuf; 437 438 udvp = UNIONFSVPTOUPPERVP(dvp); 439 vp = NULLVP; 440 441 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 442 strlen(cnp->cn_nameptr), RENAME); 443 if (error) 444 return (error); 445 446 if (vp != NULLVP) { 447 if (udvp == vp) 448 vrele(vp); 449 else 450 vput(vp); 451 } 452 453 PNBUF_PUT(pnbuf); 454 455 if (!error) { 456 cnp->cn_flags = cn.cn_flags; 457 } 458 459 return (error); 460 461 } 462 463 /* 464 * Update the unionfs_node. 465 * 466 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the 467 * uvp's lock and lower's lock will be unlocked. 468 */ 469 static void 470 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp) 471 { 472 struct vnode *vp; 473 struct vnode *lvp; 474 475 vp = UNIONFSTOV(unp); 476 lvp = unp->un_lowervp; 477 478 /* 479 * lock update 480 */ 481 mutex_enter(vp->v_interlock); 482 unp->un_uppervp = uvp; 483 KASSERT(VOP_ISLOCKED(lvp) == LK_EXCLUSIVE); 484 mutex_exit(vp->v_interlock); 485 } 486 487 /* 488 * Create a new shadow dir. 489 * 490 * udvp should be locked on entry and will be locked on return. 491 * 492 * If no error returned, unp will be updated. 493 */ 494 int 495 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, 496 struct unionfs_node *unp, struct componentname *cnp) 497 { 498 int error; 499 struct vnode *lvp; 500 struct vnode *uvp; 501 struct vattr va; 502 struct vattr lva; 503 struct componentname cn; 504 char *pnbuf; 505 506 if (unp->un_uppervp != NULLVP) 507 return (EEXIST); 508 509 lvp = unp->un_lowervp; 510 uvp = NULLVP; 511 512 memset(&cn, 0, sizeof(cn)); 513 514 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred))) 515 goto unionfs_mkshadowdir_abort; 516 517 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, &pnbuf, 518 cnp->cn_nameptr, cnp->cn_namelen, CREATE))) 519 goto unionfs_mkshadowdir_abort; 520 if (uvp != NULLVP) { 521 if (udvp == uvp) 522 vrele(uvp); 523 else 524 vput(uvp); 525 526 error = EEXIST; 527 goto unionfs_mkshadowdir_free_out; 528 } 529 530 unionfs_create_uppervattr_core(ump, &lva, &va); 531 532 error = VOP_MKDIR(udvp, &uvp, &cn, &va); 533 534 if (!error) { 535 unionfs_node_update(unp, uvp); 536 537 /* 538 * XXX The bug which cannot set uid/gid was corrected. 539 * Ignore errors. XXXNETBSD Why is this done as root? 540 */ 541 va.va_type = VNON; 542 VOP_SETATTR(uvp, &va, lwp0.l_cred); 543 } 544 545 unionfs_mkshadowdir_free_out: 546 PNBUF_PUT(pnbuf); 547 548 unionfs_mkshadowdir_abort: 549 550 return (error); 551 } 552 553 /* 554 * Create a new whiteout. 555 * 556 * dvp should be locked on entry and will be locked on return. 557 */ 558 int 559 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path) 560 { 561 int error; 562 struct vnode *wvp; 563 struct componentname cn; 564 char *pnbuf; 565 566 if (path == NULL) 567 path = cnp->cn_nameptr; 568 569 wvp = NULLVP; 570 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, &pnbuf, 571 path, strlen(path), CREATE))) 572 return (error); 573 if (wvp != NULLVP) { 574 PNBUF_PUT(pnbuf); 575 if (dvp == wvp) 576 vrele(wvp); 577 else 578 vput(wvp); 579 580 return (EEXIST); 581 } 582 583 PNBUF_PUT(pnbuf); 584 585 return (error); 586 } 587 588 /* 589 * Create a new vnode for create a new shadow file. 590 * 591 * If an error is returned, *vpp will be invalid, otherwise it will hold a 592 * locked, referenced and opened vnode. 593 * 594 * unp is never updated. 595 */ 596 static int 597 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp, 598 struct unionfs_node *unp, struct vattr *uvap) 599 { 600 struct unionfs_mount *ump; 601 struct vnode *vp; 602 struct vnode *lvp; 603 kauth_cred_t cred; 604 struct vattr lva; 605 int fmode; 606 int error; 607 struct componentname cn; 608 char *pnbuf; 609 610 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); 611 vp = NULLVP; 612 lvp = unp->un_lowervp; 613 cred = kauth_cred_get(); 614 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL); 615 error = 0; 616 617 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0) 618 return (error); 619 unionfs_create_uppervattr_core(ump, &lva, uvap); 620 621 if (unp->un_path == NULL) 622 panic("unionfs: un_path is null"); 623 624 cn.cn_namelen = strlen(unp->un_path); 625 pnbuf = PNBUF_GET(); 626 memcpy(pnbuf, unp->un_path, cn.cn_namelen + 1); 627 cn.cn_nameiop = CREATE; 628 cn.cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN); 629 cn.cn_cred = cred; 630 cn.cn_nameptr = pnbuf; 631 632 vref(udvp); 633 if ((error = relookup(udvp, &vp, &cn, 0)) != 0) 634 goto unionfs_vn_create_on_upper_free_out2; 635 vrele(udvp); 636 637 if (vp != NULLVP) { 638 if (vp == udvp) 639 vrele(vp); 640 else 641 vput(vp); 642 error = EEXIST; 643 goto unionfs_vn_create_on_upper_free_out1; 644 } 645 646 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) 647 goto unionfs_vn_create_on_upper_free_out1; 648 649 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) { 650 vput(vp); 651 goto unionfs_vn_create_on_upper_free_out1; 652 } 653 vp->v_writecount++; 654 *vpp = vp; 655 656 unionfs_vn_create_on_upper_free_out1: 657 VOP_UNLOCK(udvp); 658 659 unionfs_vn_create_on_upper_free_out2: 660 PNBUF_PUT(pnbuf); 661 662 return (error); 663 } 664 665 /* 666 * Copy from lvp to uvp. 667 * 668 * lvp and uvp should be locked and opened on entry and will be locked and 669 * opened on return. 670 */ 671 static int 672 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp, 673 kauth_cred_t cred) 674 { 675 int error; 676 off_t offset; 677 int count; 678 int bufoffset; 679 char *buf; 680 struct uio uio; 681 struct iovec iov; 682 683 error = 0; 684 memset(&uio, 0, sizeof(uio)); 685 UIO_SETUP_SYSSPACE(&uio); 686 uio.uio_offset = 0; 687 688 buf = kmem_alloc(MAXBSIZE, KM_SLEEP); 689 while (error == 0) { 690 offset = uio.uio_offset; 691 692 uio.uio_iov = &iov; 693 uio.uio_iovcnt = 1; 694 iov.iov_base = buf; 695 iov.iov_len = MAXBSIZE; 696 uio.uio_resid = iov.iov_len; 697 uio.uio_rw = UIO_READ; 698 699 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0) 700 break; 701 if ((count = MAXBSIZE - uio.uio_resid) == 0) 702 break; 703 704 bufoffset = 0; 705 while (bufoffset < count) { 706 uio.uio_iov = &iov; 707 uio.uio_iovcnt = 1; 708 iov.iov_base = buf + bufoffset; 709 iov.iov_len = count - bufoffset; 710 uio.uio_offset = offset + bufoffset; 711 uio.uio_resid = iov.iov_len; 712 uio.uio_rw = UIO_WRITE; 713 714 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0) 715 break; 716 717 bufoffset += (count - bufoffset) - uio.uio_resid; 718 } 719 720 uio.uio_offset = offset + bufoffset; 721 } 722 723 kmem_free(buf, MAXBSIZE); 724 725 return (error); 726 } 727 728 /* 729 * Copy file from lower to upper. 730 * 731 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to 732 * docopy. 733 * 734 * If no error returned, unp will be updated. 735 */ 736 int 737 unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred) 738 { 739 int error; 740 struct vnode *udvp; 741 struct vnode *lvp; 742 struct vnode *uvp; 743 struct vattr uva; 744 745 lvp = unp->un_lowervp; 746 uvp = NULLVP; 747 748 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY)) 749 return (EROFS); 750 if (unp->un_dvp == NULLVP) 751 return (EINVAL); 752 if (unp->un_uppervp != NULLVP) 753 return (EEXIST); 754 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp; 755 if (udvp == NULLVP) 756 return (EROFS); 757 if ((udvp->v_mount->mnt_flag & MNT_RDONLY)) 758 return (EROFS); 759 760 error = VOP_ACCESS(lvp, VREAD, cred); 761 if (error != 0) 762 return (error); 763 764 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva); 765 if (error != 0) 766 return (error); 767 768 if (docopy != 0) { 769 error = VOP_OPEN(lvp, FREAD, cred); 770 if (error == 0) { 771 error = unionfs_copyfile_core(lvp, uvp, cred); 772 VOP_CLOSE(lvp, FREAD, cred); 773 } 774 } 775 VOP_CLOSE(uvp, FWRITE, cred); 776 uvp->v_writecount--; 777 778 if (error == 0) { 779 /* Reset the attributes. Ignore errors. */ 780 uva.va_type = VNON; 781 VOP_SETATTR(uvp, &uva, cred); 782 } 783 784 unionfs_node_update(unp, uvp); 785 786 return (error); 787 } 788 789 /* 790 * It checks whether vp can rmdir. (check empty) 791 * 792 * vp is unionfs vnode. 793 * vp should be locked. 794 */ 795 int 796 unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred) 797 { 798 int error; 799 int eofflag; 800 int lookuperr; 801 struct vnode *uvp; 802 struct vnode *lvp; 803 struct vnode *tvp; 804 struct vattr va; 805 struct componentname cn; 806 /* 807 * The size of buf needs to be larger than DIRBLKSIZ. 808 */ 809 char buf[256 * 6]; 810 struct dirent *dp; 811 struct dirent *edp; 812 struct uio uio; 813 struct iovec iov; 814 815 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 816 817 eofflag = 0; 818 uvp = UNIONFSVPTOUPPERVP(vp); 819 lvp = UNIONFSVPTOLOWERVP(vp); 820 821 /* check opaque */ 822 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0) 823 return (error); 824 if (va.va_flags & OPAQUE) 825 return (0); 826 827 /* open vnode */ 828 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0) 829 return (error); 830 if ((error = VOP_OPEN(vp, FREAD, cred)) != 0) 831 return (error); 832 833 UIO_SETUP_SYSSPACE(&uio); 834 uio.uio_rw = UIO_READ; 835 uio.uio_offset = 0; 836 837 while (!error && !eofflag) { 838 iov.iov_base = buf; 839 iov.iov_len = sizeof(buf); 840 uio.uio_iov = &iov; 841 uio.uio_iovcnt = 1; 842 uio.uio_resid = iov.iov_len; 843 844 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL); 845 if (error) 846 break; 847 848 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid]; 849 for (dp = (struct dirent*)buf; !error && dp < edp; 850 dp = (struct dirent*)((char *)dp + dp->d_reclen)) { 851 if (dp->d_type == DT_WHT || 852 (dp->d_namlen == 1 && dp->d_name[0] == '.') || 853 (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2))) 854 continue; 855 856 cn.cn_namelen = dp->d_namlen; 857 cn.cn_nameptr = dp->d_name; 858 cn.cn_nameiop = LOOKUP; 859 cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN); 860 cn.cn_cred = cred; 861 862 /* 863 * check entry in lower. 864 * Sometimes, readdir function returns 865 * wrong entry. 866 */ 867 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn); 868 869 if (!lookuperr) 870 vput(tvp); 871 else 872 continue; /* skip entry */ 873 874 /* 875 * check entry 876 * If it has no exist/whiteout entry in upper, 877 * directory is not empty. 878 */ 879 cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN); 880 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn); 881 882 if (!lookuperr) 883 vput(tvp); 884 885 /* ignore exist or whiteout entry */ 886 if (!lookuperr || 887 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT))) 888 continue; 889 890 error = ENOTEMPTY; 891 } 892 } 893 894 /* close vnode */ 895 VOP_CLOSE(vp, FREAD, cred); 896 897 return (error); 898 } 899 900 #ifdef DIAGNOSTIC 901 902 struct vnode * 903 unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno) 904 { 905 struct unionfs_node *unp; 906 907 unp = VTOUNIONFS(vp); 908 909 #ifdef notyet 910 if (vp->v_op != unionfs_vnodeop_p) { 911 printf("unionfs_checkuppervp: on non-unionfs-node.\n"); 912 #ifdef KDB 913 kdb_enter(KDB_WHY_UNIONFS, 914 "unionfs_checkuppervp: on non-unionfs-node.\n"); 915 #endif 916 panic("unionfs_checkuppervp"); 917 }; 918 #endif 919 return (unp->un_uppervp); 920 } 921 922 struct vnode * 923 unionfs_checklowervp(struct vnode *vp, const char *fil, int lno) 924 { 925 struct unionfs_node *unp; 926 927 unp = VTOUNIONFS(vp); 928 929 #ifdef notyet 930 if (vp->v_op != unionfs_vnodeop_p) { 931 printf("unionfs_checklowervp: on non-unionfs-node.\n"); 932 #ifdef KDB 933 kdb_enter(KDB_WHY_UNIONFS, 934 "unionfs_checklowervp: on non-unionfs-node.\n"); 935 #endif 936 panic("unionfs_checklowervp"); 937 }; 938 #endif 939 return (unp->un_lowervp); 940 } 941 #endif 942