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 unp = kmem_zalloc(sizeof(*unp), KM_SLEEP); 95 if (unp == NULL) 96 return (ENOMEM); 97 error = getnewvnode(VT_UNION, mp, unionfs_vnodeop_p, &vp); 98 if (error != 0) { 99 kmem_free(unp, sizeof(*unp)); 100 return (error); 101 } 102 if (dvp != NULLVP) 103 vref(dvp); 104 if (uppervp != NULLVP) 105 vref(uppervp); 106 if (lowervp != NULLVP) 107 vref(lowervp); 108 109 unp->un_vnode = vp; 110 unp->un_uppervp = uppervp; 111 unp->un_lowervp = lowervp; 112 unp->un_dvp = dvp; 113 114 if (path != NULL) { 115 unp->un_path = (char *) 116 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO); 117 memcpy(unp->un_path, cnp->cn_nameptr, cnp->cn_namelen); 118 unp->un_path[cnp->cn_namelen] = '\0'; 119 } 120 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type); 121 vp->v_data = unp; 122 uvm_vnp_setsize(vp, 0); 123 124 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) && 125 (lowervp != NULLVP && ump->um_lowervp == lowervp)) 126 vp->v_vflag |= VV_ROOT; 127 128 *vpp = vp; 129 130 return (0); 131 } 132 133 /* 134 * Clean up the unionfs node. 135 */ 136 void 137 unionfs_noderem(struct vnode *vp) 138 { 139 struct unionfs_mount *ump; 140 struct unionfs_node *unp; 141 struct unionfs_node_status *unsp; 142 struct vnode *lvp; 143 struct vnode *uvp; 144 145 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount); 146 147 /* 148 * Use the interlock to protect the clearing of v_data to 149 * prevent faults in unionfs_lock(). 150 */ 151 unp = VTOUNIONFS(vp); 152 lvp = unp->un_lowervp; 153 uvp = unp->un_uppervp; 154 unp->un_lowervp = unp->un_uppervp = NULLVP; 155 vp->v_data = NULL; 156 157 if (lvp != NULLVP) 158 vrele(lvp); 159 if (uvp != NULLVP) 160 vrele(uvp); 161 if (unp->un_dvp != NULLVP) { 162 vrele(unp->un_dvp); 163 unp->un_dvp = NULLVP; 164 } 165 if (unp->un_path) { 166 free(unp->un_path, M_UNIONFSPATH); 167 unp->un_path = NULL; 168 } 169 170 while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) { 171 LIST_REMOVE(unsp, uns_list); 172 free(unsp, M_TEMP); 173 } 174 kmem_free(unp, sizeof(*unp)); 175 } 176 177 /* 178 * Get the unionfs node status. 179 * You need exclusive lock this vnode. 180 */ 181 void 182 unionfs_get_node_status(struct unionfs_node *unp, 183 struct unionfs_node_status **unspp) 184 { 185 struct unionfs_node_status *unsp; 186 pid_t pid; 187 lwpid_t lid; 188 189 KASSERT(NULL != unspp); 190 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 191 192 pid = curproc->p_pid; 193 lid = curlwp->l_lid; 194 195 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) { 196 if (unsp->uns_pid == pid && unsp->uns_lid == lid) { 197 *unspp = unsp; 198 return; 199 } 200 } 201 202 /* create a new unionfs node status */ 203 unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP); 204 unsp->uns_pid = pid; 205 unsp->uns_lid = lid; 206 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list); 207 208 *unspp = unsp; 209 } 210 211 /* 212 * Remove the unionfs node status, if you can. 213 * You need exclusive lock this vnode. 214 */ 215 void 216 unionfs_tryrem_node_status(struct unionfs_node *unp, 217 struct unionfs_node_status *unsp) 218 { 219 KASSERT(NULL != unsp); 220 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 221 222 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt) 223 return; 224 225 LIST_REMOVE(unsp, uns_list); 226 kmem_free(unsp, sizeof(*unsp)); 227 } 228 229 /* 230 * Create upper node attr. 231 */ 232 void 233 unionfs_create_uppervattr_core(struct unionfs_mount *ump, 234 struct vattr *lva, 235 struct vattr *uva) 236 { 237 vattr_null(uva); 238 uva->va_type = lva->va_type; 239 uva->va_atime = lva->va_atime; 240 uva->va_mtime = lva->va_mtime; 241 uva->va_ctime = lva->va_ctime; 242 243 switch (ump->um_copymode) { 244 case UNIONFS_TRANSPARENT: 245 uva->va_mode = lva->va_mode; 246 uva->va_uid = lva->va_uid; 247 uva->va_gid = lva->va_gid; 248 break; 249 case UNIONFS_MASQUERADE: 250 if (ump->um_uid == lva->va_uid) { 251 uva->va_mode = lva->va_mode & 077077; 252 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700; 253 uva->va_uid = lva->va_uid; 254 uva->va_gid = lva->va_gid; 255 } else { 256 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile); 257 uva->va_uid = ump->um_uid; 258 uva->va_gid = ump->um_gid; 259 } 260 break; 261 default: /* UNIONFS_TRADITIONAL */ 262 uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask; 263 uva->va_uid = ump->um_uid; 264 uva->va_gid = ump->um_gid; 265 break; 266 } 267 } 268 269 /* 270 * Create upper node attr. 271 */ 272 int 273 unionfs_create_uppervattr(struct unionfs_mount *ump, 274 struct vnode *lvp, 275 struct vattr *uva, 276 kauth_cred_t cred) 277 { 278 int error; 279 struct vattr lva; 280 281 if ((error = VOP_GETATTR(lvp, &lva, cred))) 282 return (error); 283 284 unionfs_create_uppervattr_core(ump, &lva, uva); 285 286 return (error); 287 } 288 289 /* 290 * relookup 291 * 292 * dvp should be locked on entry and will be locked on return. 293 * 294 * If an error is returned, *vpp will be invalid, otherwise it will hold a 295 * locked, referenced vnode. If *vpp == dvp then remember that only one 296 * LK_EXCLUSIVE lock is held. 297 */ 298 static int 299 unionfs_relookup(struct vnode *dvp, struct vnode **vpp, 300 struct componentname *cnp, struct componentname *cn, 301 char **pnbuf_ret, 302 const char *path, int pathlen, u_long nameiop) 303 { 304 int error; 305 char *pnbuf; 306 307 cn->cn_namelen = pathlen; 308 pnbuf = PNBUF_GET(); 309 memcpy(pnbuf, path, pathlen); 310 pnbuf[pathlen] = '\0'; 311 312 cn->cn_nameiop = nameiop; 313 cn->cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN); 314 cn->cn_cred = cnp->cn_cred; 315 316 cn->cn_nameptr = pnbuf; 317 cn->cn_consume = cnp->cn_consume; 318 319 if (nameiop == DELETE) 320 cn->cn_flags |= (cnp->cn_flags & DOWHITEOUT); 321 322 vref(dvp); 323 VOP_UNLOCK(dvp); 324 325 if ((error = relookup(dvp, vpp, cn, 0))) { 326 PNBUF_PUT(pnbuf); 327 *pnbuf_ret = NULL; 328 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 329 } else { 330 *pnbuf_ret = pnbuf; 331 vrele(dvp); 332 } 333 334 return (error); 335 } 336 337 /* 338 * relookup for CREATE namei operation. 339 * 340 * dvp is unionfs vnode. dvp should be locked. 341 * 342 * If it called 'unionfs_copyfile' function by unionfs_link etc, 343 * VOP_LOOKUP information is broken. 344 * So it need relookup in order to create link etc. 345 */ 346 int 347 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp) 348 { 349 int error; 350 struct vnode *udvp; 351 struct vnode *vp; 352 struct componentname cn; 353 char *pnbuf; 354 355 udvp = UNIONFSVPTOUPPERVP(dvp); 356 vp = NULLVP; 357 358 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, 359 cnp->cn_nameptr, 360 strlen(cnp->cn_nameptr), CREATE); 361 if (error) 362 return (error); 363 364 if (vp != NULLVP) { 365 if (udvp == vp) 366 vrele(vp); 367 else 368 vput(vp); 369 370 error = EEXIST; 371 } 372 373 PNBUF_PUT(pnbuf); 374 375 if (!error) { 376 cnp->cn_flags = cn.cn_flags; 377 } 378 379 return (error); 380 } 381 382 /* 383 * relookup for DELETE namei operation. 384 * 385 * dvp is unionfs vnode. dvp should be locked. 386 */ 387 int 388 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp) 389 { 390 int error; 391 struct vnode *udvp; 392 struct vnode *vp; 393 struct componentname cn; 394 char *pnbuf; 395 396 udvp = UNIONFSVPTOUPPERVP(dvp); 397 vp = NULLVP; 398 399 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 400 strlen(cnp->cn_nameptr), DELETE); 401 if (error) 402 return (error); 403 404 if (vp == NULLVP) 405 error = ENOENT; 406 else { 407 if (udvp == vp) 408 vrele(vp); 409 else 410 vput(vp); 411 } 412 413 PNBUF_PUT(pnbuf); 414 415 if (!error) { 416 cnp->cn_flags = cn.cn_flags; 417 } 418 419 return (error); 420 } 421 422 /* 423 * relookup for RENAME namei operation. 424 * 425 * dvp is unionfs vnode. dvp should be locked. 426 */ 427 int 428 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp) 429 { 430 int error; 431 struct vnode *udvp; 432 struct vnode *vp; 433 struct componentname cn; 434 char *pnbuf; 435 436 udvp = UNIONFSVPTOUPPERVP(dvp); 437 vp = NULLVP; 438 439 error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr, 440 strlen(cnp->cn_nameptr), RENAME); 441 if (error) 442 return (error); 443 444 if (vp != NULLVP) { 445 if (udvp == vp) 446 vrele(vp); 447 else 448 vput(vp); 449 } 450 451 PNBUF_PUT(pnbuf); 452 453 if (!error) { 454 cnp->cn_flags = cn.cn_flags; 455 } 456 457 return (error); 458 459 } 460 461 /* 462 * Update the unionfs_node. 463 * 464 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the 465 * uvp's lock and lower's lock will be unlocked. 466 */ 467 static void 468 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp) 469 { 470 struct vnode *vp; 471 struct vnode *lvp; 472 473 vp = UNIONFSTOV(unp); 474 lvp = unp->un_lowervp; 475 476 /* 477 * lock update 478 */ 479 mutex_enter(&vp->v_interlock); 480 unp->un_uppervp = uvp; 481 KASSERT(VOP_ISLOCKED(lvp) == LK_EXCLUSIVE); 482 mutex_exit(&vp->v_interlock); 483 } 484 485 /* 486 * Create a new shadow dir. 487 * 488 * udvp should be locked on entry and will be locked on return. 489 * 490 * If no error returned, unp will be updated. 491 */ 492 int 493 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, 494 struct unionfs_node *unp, struct componentname *cnp) 495 { 496 int error; 497 struct vnode *lvp; 498 struct vnode *uvp; 499 struct vattr va; 500 struct vattr lva; 501 struct componentname cn; 502 char *pnbuf; 503 504 if (unp->un_uppervp != NULLVP) 505 return (EEXIST); 506 507 lvp = unp->un_lowervp; 508 uvp = NULLVP; 509 510 memset(&cn, 0, sizeof(cn)); 511 512 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred))) 513 goto unionfs_mkshadowdir_abort; 514 515 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, &pnbuf, 516 cnp->cn_nameptr, cnp->cn_namelen, CREATE))) 517 goto unionfs_mkshadowdir_abort; 518 if (uvp != NULLVP) { 519 if (udvp == uvp) 520 vrele(uvp); 521 else 522 vput(uvp); 523 524 error = EEXIST; 525 goto unionfs_mkshadowdir_free_out; 526 } 527 528 unionfs_create_uppervattr_core(ump, &lva, &va); 529 530 error = VOP_MKDIR(udvp, &uvp, &cn, &va); 531 532 if (!error) { 533 unionfs_node_update(unp, uvp); 534 535 /* 536 * XXX The bug which cannot set uid/gid was corrected. 537 * Ignore errors. XXXNETBSD Why is this done as root? 538 */ 539 va.va_type = VNON; 540 VOP_SETATTR(uvp, &va, lwp0.l_cred); 541 } 542 543 unionfs_mkshadowdir_free_out: 544 PNBUF_PUT(pnbuf); 545 546 unionfs_mkshadowdir_abort: 547 548 return (error); 549 } 550 551 /* 552 * Create a new whiteout. 553 * 554 * dvp should be locked on entry and will be locked on return. 555 */ 556 int 557 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path) 558 { 559 int error; 560 struct vnode *wvp; 561 struct componentname cn; 562 char *pnbuf; 563 564 if (path == NULL) 565 path = cnp->cn_nameptr; 566 567 wvp = NULLVP; 568 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, &pnbuf, 569 path, strlen(path), CREATE))) 570 return (error); 571 if (wvp != NULLVP) { 572 PNBUF_PUT(pnbuf); 573 if (dvp == wvp) 574 vrele(wvp); 575 else 576 vput(wvp); 577 578 return (EEXIST); 579 } 580 581 PNBUF_PUT(pnbuf); 582 583 return (error); 584 } 585 586 /* 587 * Create a new vnode for create a new shadow file. 588 * 589 * If an error is returned, *vpp will be invalid, otherwise it will hold a 590 * locked, referenced and opened vnode. 591 * 592 * unp is never updated. 593 */ 594 static int 595 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp, 596 struct unionfs_node *unp, struct vattr *uvap) 597 { 598 struct unionfs_mount *ump; 599 struct vnode *vp; 600 struct vnode *lvp; 601 kauth_cred_t cred; 602 struct vattr lva; 603 int fmode; 604 int error; 605 struct componentname cn; 606 char *pnbuf; 607 608 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); 609 vp = NULLVP; 610 lvp = unp->un_lowervp; 611 cred = kauth_cred_get(); 612 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL); 613 error = 0; 614 615 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0) 616 return (error); 617 unionfs_create_uppervattr_core(ump, &lva, uvap); 618 619 if (unp->un_path == NULL) 620 panic("unionfs: un_path is null"); 621 622 cn.cn_namelen = strlen(unp->un_path); 623 pnbuf = PNBUF_GET(); 624 memcpy(pnbuf, unp->un_path, cn.cn_namelen + 1); 625 cn.cn_nameiop = CREATE; 626 cn.cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN); 627 cn.cn_cred = cred; 628 cn.cn_nameptr = pnbuf; 629 cn.cn_consume = 0; 630 631 vref(udvp); 632 if ((error = relookup(udvp, &vp, &cn, 0)) != 0) 633 goto unionfs_vn_create_on_upper_free_out2; 634 vrele(udvp); 635 636 if (vp != NULLVP) { 637 if (vp == udvp) 638 vrele(vp); 639 else 640 vput(vp); 641 error = EEXIST; 642 goto unionfs_vn_create_on_upper_free_out1; 643 } 644 645 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) 646 goto unionfs_vn_create_on_upper_free_out1; 647 648 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) { 649 vput(vp); 650 goto unionfs_vn_create_on_upper_free_out1; 651 } 652 vp->v_writecount++; 653 *vpp = vp; 654 655 unionfs_vn_create_on_upper_free_out1: 656 VOP_UNLOCK(udvp); 657 658 unionfs_vn_create_on_upper_free_out2: 659 PNBUF_PUT(pnbuf); 660 661 return (error); 662 } 663 664 /* 665 * Copy from lvp to uvp. 666 * 667 * lvp and uvp should be locked and opened on entry and will be locked and 668 * opened on return. 669 */ 670 static int 671 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp, 672 kauth_cred_t cred) 673 { 674 int error; 675 off_t offset; 676 int count; 677 int bufoffset; 678 char *buf; 679 struct uio uio; 680 struct iovec iov; 681 682 error = 0; 683 memset(&uio, 0, sizeof(uio)); 684 UIO_SETUP_SYSSPACE(&uio); 685 uio.uio_offset = 0; 686 687 buf = kmem_alloc(MAXBSIZE, KM_SLEEP); 688 if (buf == NULL) 689 return ENOMEM; 690 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