Bump date for previous. New sentence, new line.
[netbsd-mini2440.git] / sys / fs / unionfs / unionfs_subr.c
blob1331035a1107808df06610d0f14da7a3e570e74e
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>
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
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.
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.
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 $
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>
56 #include <fs/unionfs/unionfs.h>
58 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
61 * Make a new or get existing unionfs node.
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.
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)
72 struct unionfs_mount *ump;
73 struct unionfs_node *unp;
74 struct vnode *vp;
75 int error;
76 const char *path;
78 ump = MOUNTTOUNIONFSMOUNT(mp);
79 path = (cnp ? cnp->cn_nameptr : NULL);
81 if (uppervp == NULLVP && lowervp == NULLVP)
82 panic("unionfs_nodeget: upper and lower is null");
84 /* If it has no ISLASTCN flag, path check is skipped. */
85 if (cnp && !(cnp->cn_flags & ISLASTCN))
86 path = NULL;
88 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
89 (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
90 if (dvp == NULLVP)
91 return (EINVAL);
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);
102 if (dvp != NULLVP)
103 vref(dvp);
104 if (uppervp != NULLVP)
105 vref(uppervp);
106 if (lowervp != NULLVP)
107 vref(lowervp);
109 unp->un_vnode = vp;
110 unp->un_uppervp = uppervp;
111 unp->un_lowervp = lowervp;
112 unp->un_dvp = dvp;
113 if (uppervp != NULLVP)
114 vp->v_vnlock = uppervp->v_vnlock;
115 else
116 vp->v_vnlock = lowervp->v_vnlock;
118 if (path != NULL) {
119 unp->un_path = (char *)
120 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
121 memcpy(unp->un_path, cnp->cn_nameptr, cnp->cn_namelen);
122 unp->un_path[cnp->cn_namelen] = '\0';
124 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
125 vp->v_data = unp;
126 uvm_vnp_setsize(vp, 0);
128 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
129 (lowervp != NULLVP && ump->um_lowervp == lowervp))
130 vp->v_vflag |= VV_ROOT;
132 *vpp = vp;
134 return (0);
138 * Clean up the unionfs node.
140 void
141 unionfs_noderem(struct vnode *vp)
143 struct unionfs_mount *ump;
144 struct unionfs_node *unp;
145 struct unionfs_node_status *unsp;
146 struct vnode *lvp;
147 struct vnode *uvp;
149 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount);
152 * Use the interlock to protect the clearing of v_data to
153 * prevent faults in unionfs_lock().
155 unp = VTOUNIONFS(vp);
156 lvp = unp->un_lowervp;
157 uvp = unp->un_uppervp;
158 unp->un_lowervp = unp->un_uppervp = NULLVP;
159 vp->v_vnlock = &(vp->v_lock);
160 vp->v_data = NULL;
162 if (lvp != NULLVP)
163 vrele(lvp);
164 if (uvp != NULLVP)
165 vrele(uvp);
166 if (unp->un_dvp != NULLVP) {
167 vrele(unp->un_dvp);
168 unp->un_dvp = NULLVP;
170 if (unp->un_path) {
171 free(unp->un_path, M_UNIONFSPATH);
172 unp->un_path = NULL;
175 while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) {
176 LIST_REMOVE(unsp, uns_list);
177 free(unsp, M_TEMP);
179 kmem_free(unp, sizeof(*unp));
183 * Get the unionfs node status.
184 * You need exclusive lock this vnode.
186 void
187 unionfs_get_node_status(struct unionfs_node *unp,
188 struct unionfs_node_status **unspp)
190 struct unionfs_node_status *unsp;
191 pid_t pid;
192 lwpid_t lid;
194 KASSERT(NULL != unspp);
195 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
197 pid = curproc->p_pid;
198 lid = curlwp->l_lid;
200 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
201 if (unsp->uns_pid == pid && unsp->uns_lid == lid) {
202 *unspp = unsp;
203 return;
207 /* create a new unionfs node status */
208 unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP);
209 unsp->uns_pid = pid;
210 unsp->uns_lid = lid;
211 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
213 *unspp = unsp;
217 * Remove the unionfs node status, if you can.
218 * You need exclusive lock this vnode.
220 void
221 unionfs_tryrem_node_status(struct unionfs_node *unp,
222 struct unionfs_node_status *unsp)
224 KASSERT(NULL != unsp);
225 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
227 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
228 return;
230 LIST_REMOVE(unsp, uns_list);
231 kmem_free(unsp, sizeof(*unsp));
235 * Create upper node attr.
237 void
238 unionfs_create_uppervattr_core(struct unionfs_mount *ump,
239 struct vattr *lva,
240 struct vattr *uva)
242 VATTR_NULL(uva);
243 uva->va_type = lva->va_type;
244 uva->va_atime = lva->va_atime;
245 uva->va_mtime = lva->va_mtime;
246 uva->va_ctime = lva->va_ctime;
248 switch (ump->um_copymode) {
249 case UNIONFS_TRANSPARENT:
250 uva->va_mode = lva->va_mode;
251 uva->va_uid = lva->va_uid;
252 uva->va_gid = lva->va_gid;
253 break;
254 case UNIONFS_MASQUERADE:
255 if (ump->um_uid == lva->va_uid) {
256 uva->va_mode = lva->va_mode & 077077;
257 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
258 uva->va_uid = lva->va_uid;
259 uva->va_gid = lva->va_gid;
260 } else {
261 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
262 uva->va_uid = ump->um_uid;
263 uva->va_gid = ump->um_gid;
265 break;
266 default: /* UNIONFS_TRADITIONAL */
267 uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask;
268 uva->va_uid = ump->um_uid;
269 uva->va_gid = ump->um_gid;
270 break;
275 * Create upper node attr.
278 unionfs_create_uppervattr(struct unionfs_mount *ump,
279 struct vnode *lvp,
280 struct vattr *uva,
281 kauth_cred_t cred)
283 int error;
284 struct vattr lva;
286 if ((error = VOP_GETATTR(lvp, &lva, cred)))
287 return (error);
289 unionfs_create_uppervattr_core(ump, &lva, uva);
291 return (error);
295 * relookup
297 * dvp should be locked on entry and will be locked on return.
299 * If an error is returned, *vpp will be invalid, otherwise it will hold a
300 * locked, referenced vnode. If *vpp == dvp then remember that only one
301 * LK_EXCLUSIVE lock is held.
303 static int
304 unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
305 struct componentname *cnp, struct componentname *cn,
306 const char *path, int pathlen, u_long nameiop)
308 int error;
310 cn->cn_namelen = pathlen;
311 cn->cn_pnbuf = PNBUF_GET();
312 memcpy(cn->cn_pnbuf, path, pathlen);
313 cn->cn_pnbuf[pathlen] = '\0';
315 cn->cn_nameiop = nameiop;
316 cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
317 cn->cn_cred = cnp->cn_cred;
319 cn->cn_nameptr = cn->cn_pnbuf;
320 cn->cn_consume = cnp->cn_consume;
322 if (nameiop == DELETE)
323 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
324 else if (RENAME == nameiop)
325 cn->cn_flags |= (cnp->cn_flags & SAVESTART);
327 vref(dvp);
328 VOP_UNLOCK(dvp, 0);
330 if ((error = relookup(dvp, vpp, cn))) {
331 PNBUF_PUT(cn->cn_pnbuf);
332 cn->cn_flags &= ~HASBUF;
333 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
334 } else
335 vrele(dvp);
337 return (error);
341 * relookup for CREATE namei operation.
343 * dvp is unionfs vnode. dvp should be locked.
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.
350 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp)
352 int error;
353 struct vnode *udvp;
354 struct vnode *vp;
355 struct componentname cn;
357 udvp = UNIONFSVPTOUPPERVP(dvp);
358 vp = NULLVP;
360 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
361 strlen(cnp->cn_nameptr), CREATE);
362 if (error)
363 return (error);
365 if (vp != NULLVP) {
366 if (udvp == vp)
367 vrele(vp);
368 else
369 vput(vp);
371 error = EEXIST;
374 if (cn.cn_flags & HASBUF) {
375 PNBUF_PUT(cn.cn_pnbuf);
376 cn.cn_flags &= ~HASBUF;
379 if (!error) {
380 cn.cn_flags |= (cnp->cn_flags & HASBUF);
381 cnp->cn_flags = cn.cn_flags;
384 return (error);
388 * relookup for DELETE namei operation.
390 * dvp is unionfs vnode. dvp should be locked.
393 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp)
395 int error;
396 struct vnode *udvp;
397 struct vnode *vp;
398 struct componentname cn;
400 udvp = UNIONFSVPTOUPPERVP(dvp);
401 vp = NULLVP;
403 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
404 strlen(cnp->cn_nameptr), DELETE);
405 if (error)
406 return (error);
408 if (vp == NULLVP)
409 error = ENOENT;
410 else {
411 if (udvp == vp)
412 vrele(vp);
413 else
414 vput(vp);
417 if (cn.cn_flags & HASBUF) {
418 PNBUF_PUT(cn.cn_pnbuf);
419 cn.cn_flags &= ~HASBUF;
422 if (!error) {
423 cn.cn_flags |= (cnp->cn_flags & HASBUF);
424 cnp->cn_flags = cn.cn_flags;
427 return (error);
431 * relookup for RENAME namei operation.
433 * dvp is unionfs vnode. dvp should be locked.
436 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp)
438 int error;
439 struct vnode *udvp;
440 struct vnode *vp;
441 struct componentname cn;
443 udvp = UNIONFSVPTOUPPERVP(dvp);
444 vp = NULLVP;
446 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr,
447 strlen(cnp->cn_nameptr), RENAME);
448 if (error)
449 return (error);
451 if (vp != NULLVP) {
452 if (udvp == vp)
453 vrele(vp);
454 else
455 vput(vp);
458 if (cn.cn_flags & HASBUF) {
459 PNBUF_PUT(cn.cn_pnbuf);
460 cn.cn_flags &= ~HASBUF;
463 if (!error) {
464 cn.cn_flags |= (cnp->cn_flags & HASBUF);
465 cnp->cn_flags = cn.cn_flags;
468 return (error);
473 * Update the unionfs_node.
475 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
476 * uvp's lock and lower's lock will be unlocked.
478 static void
479 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp)
481 int count, lockcnt;
482 struct vnode *vp;
483 struct vnode *lvp;
485 vp = UNIONFSTOV(unp);
486 lvp = unp->un_lowervp;
489 * lock update
491 mutex_enter(&vp->v_interlock);
492 unp->un_uppervp = uvp;
493 vp->v_vnlock = uvp->v_vnlock;
494 lockcnt = lvp->v_vnlock->vl_recursecnt +
495 rw_write_held(&lvp->v_vnlock->vl_lock);
496 if (lockcnt <= 0)
497 panic("unionfs: no exclusive lock");
498 mutex_exit(&vp->v_interlock);
499 for (count = 1; count < lockcnt; count++)
500 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
504 * Create a new shadow dir.
506 * udvp should be locked on entry and will be locked on return.
508 * If no error returned, unp will be updated.
511 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
512 struct unionfs_node *unp, struct componentname *cnp)
514 int error;
515 struct vnode *lvp;
516 struct vnode *uvp;
517 struct vattr va;
518 struct vattr lva;
519 struct componentname cn;
521 if (unp->un_uppervp != NULLVP)
522 return (EEXIST);
524 lvp = unp->un_lowervp;
525 uvp = NULLVP;
527 memset(&cn, 0, sizeof(cn));
529 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
530 goto unionfs_mkshadowdir_abort;
532 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
533 goto unionfs_mkshadowdir_abort;
534 if (uvp != NULLVP) {
535 if (udvp == uvp)
536 vrele(uvp);
537 else
538 vput(uvp);
540 error = EEXIST;
541 goto unionfs_mkshadowdir_free_out;
544 unionfs_create_uppervattr_core(ump, &lva, &va);
546 error = VOP_MKDIR(udvp, &uvp, &cn, &va);
548 if (!error) {
549 unionfs_node_update(unp, uvp);
552 * XXX The bug which cannot set uid/gid was corrected.
553 * Ignore errors. XXXNETBSD Why is this done as root?
555 va.va_type = VNON;
556 VOP_SETATTR(uvp, &va, lwp0.l_cred);
559 unionfs_mkshadowdir_free_out:
560 if (cn.cn_flags & HASBUF) {
561 PNBUF_PUT(cn.cn_pnbuf);
562 cn.cn_flags &= ~HASBUF;
565 unionfs_mkshadowdir_abort:
567 return (error);
571 * Create a new whiteout.
573 * dvp should be locked on entry and will be locked on return.
576 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path)
578 int error;
579 struct vnode *wvp;
580 struct componentname cn;
582 if (path == NULL)
583 path = cnp->cn_nameptr;
585 wvp = NULLVP;
586 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, path, strlen(path), CREATE)))
587 return (error);
588 if (wvp != NULLVP) {
589 if (cn.cn_flags & HASBUF) {
590 PNBUF_PUT(cn.cn_pnbuf);
591 cn.cn_flags &= ~HASBUF;
593 if (dvp == wvp)
594 vrele(wvp);
595 else
596 vput(wvp);
598 return (EEXIST);
601 if (cn.cn_flags & HASBUF) {
602 PNBUF_PUT(cn.cn_pnbuf);
603 cn.cn_flags &= ~HASBUF;
606 return (error);
610 * Create a new vnode for create a new shadow file.
612 * If an error is returned, *vpp will be invalid, otherwise it will hold a
613 * locked, referenced and opened vnode.
615 * unp is never updated.
617 static int
618 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
619 struct unionfs_node *unp, struct vattr *uvap)
621 struct unionfs_mount *ump;
622 struct vnode *vp;
623 struct vnode *lvp;
624 kauth_cred_t cred;
625 struct vattr lva;
626 int fmode;
627 int error;
628 struct componentname cn;
630 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
631 vp = NULLVP;
632 lvp = unp->un_lowervp;
633 cred = kauth_cred_get();
634 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
635 error = 0;
637 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
638 return (error);
639 unionfs_create_uppervattr_core(ump, &lva, uvap);
641 if (unp->un_path == NULL)
642 panic("unionfs: un_path is null");
644 cn.cn_namelen = strlen(unp->un_path);
645 cn.cn_pnbuf = PNBUF_GET();
646 memcpy(cn.cn_pnbuf, unp->un_path, cn.cn_namelen + 1);
647 cn.cn_nameiop = CREATE;
648 cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
649 cn.cn_cred = cred;
650 cn.cn_nameptr = cn.cn_pnbuf;
651 cn.cn_consume = 0;
653 vref(udvp);
654 if ((error = relookup(udvp, &vp, &cn)) != 0)
655 goto unionfs_vn_create_on_upper_free_out2;
656 vrele(udvp);
658 if (vp != NULLVP) {
659 if (vp == udvp)
660 vrele(vp);
661 else
662 vput(vp);
663 error = EEXIST;
664 goto unionfs_vn_create_on_upper_free_out1;
667 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
668 goto unionfs_vn_create_on_upper_free_out1;
670 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) {
671 vput(vp);
672 goto unionfs_vn_create_on_upper_free_out1;
674 vp->v_writecount++;
675 *vpp = vp;
677 unionfs_vn_create_on_upper_free_out1:
678 VOP_UNLOCK(udvp, 0);
680 unionfs_vn_create_on_upper_free_out2:
681 if (cn.cn_flags & HASBUF) {
682 PNBUF_PUT(cn.cn_pnbuf);
683 cn.cn_flags &= ~HASBUF;
686 return (error);
690 * Copy from lvp to uvp.
692 * lvp and uvp should be locked and opened on entry and will be locked and
693 * opened on return.
695 static int
696 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
697 kauth_cred_t cred)
699 int error;
700 off_t offset;
701 int count;
702 int bufoffset;
703 char *buf;
704 struct uio uio;
705 struct iovec iov;
707 error = 0;
708 memset(&uio, 0, sizeof(uio));
709 UIO_SETUP_SYSSPACE(&uio);
710 uio.uio_offset = 0;
712 buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
713 if (buf == NULL)
714 return ENOMEM;
716 while (error == 0) {
717 offset = uio.uio_offset;
719 uio.uio_iov = &iov;
720 uio.uio_iovcnt = 1;
721 iov.iov_base = buf;
722 iov.iov_len = MAXBSIZE;
723 uio.uio_resid = iov.iov_len;
724 uio.uio_rw = UIO_READ;
726 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
727 break;
728 if ((count = MAXBSIZE - uio.uio_resid) == 0)
729 break;
731 bufoffset = 0;
732 while (bufoffset < count) {
733 uio.uio_iov = &iov;
734 uio.uio_iovcnt = 1;
735 iov.iov_base = buf + bufoffset;
736 iov.iov_len = count - bufoffset;
737 uio.uio_offset = offset + bufoffset;
738 uio.uio_resid = iov.iov_len;
739 uio.uio_rw = UIO_WRITE;
741 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
742 break;
744 bufoffset += (count - bufoffset) - uio.uio_resid;
747 uio.uio_offset = offset + bufoffset;
750 kmem_free(buf, MAXBSIZE);
752 return (error);
756 * Copy file from lower to upper.
758 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
759 * docopy.
761 * If no error returned, unp will be updated.
764 unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred)
766 int error;
767 struct vnode *udvp;
768 struct vnode *lvp;
769 struct vnode *uvp;
770 struct vattr uva;
772 lvp = unp->un_lowervp;
773 uvp = NULLVP;
775 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
776 return (EROFS);
777 if (unp->un_dvp == NULLVP)
778 return (EINVAL);
779 if (unp->un_uppervp != NULLVP)
780 return (EEXIST);
781 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
782 if (udvp == NULLVP)
783 return (EROFS);
784 if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
785 return (EROFS);
787 error = VOP_ACCESS(lvp, VREAD, cred);
788 if (error != 0)
789 return (error);
791 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva);
792 if (error != 0)
793 return (error);
795 if (docopy != 0) {
796 error = VOP_OPEN(lvp, FREAD, cred);
797 if (error == 0) {
798 error = unionfs_copyfile_core(lvp, uvp, cred);
799 VOP_CLOSE(lvp, FREAD, cred);
802 VOP_CLOSE(uvp, FWRITE, cred);
803 uvp->v_writecount--;
805 if (error == 0) {
806 /* Reset the attributes. Ignore errors. */
807 uva.va_type = VNON;
808 VOP_SETATTR(uvp, &uva, cred);
811 unionfs_node_update(unp, uvp);
813 return (error);
817 * It checks whether vp can rmdir. (check empty)
819 * vp is unionfs vnode.
820 * vp should be locked.
823 unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred)
825 int error;
826 int eofflag;
827 int lookuperr;
828 struct vnode *uvp;
829 struct vnode *lvp;
830 struct vnode *tvp;
831 struct vattr va;
832 struct componentname cn;
834 * The size of buf needs to be larger than DIRBLKSIZ.
836 char buf[256 * 6];
837 struct dirent *dp;
838 struct dirent *edp;
839 struct uio uio;
840 struct iovec iov;
842 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
844 eofflag = 0;
845 uvp = UNIONFSVPTOUPPERVP(vp);
846 lvp = UNIONFSVPTOLOWERVP(vp);
848 /* check opaque */
849 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
850 return (error);
851 if (va.va_flags & OPAQUE)
852 return (0);
854 /* open vnode */
855 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0)
856 return (error);
857 if ((error = VOP_OPEN(vp, FREAD, cred)) != 0)
858 return (error);
860 UIO_SETUP_SYSSPACE(&uio);
861 uio.uio_rw = UIO_READ;
862 uio.uio_offset = 0;
864 while (!error && !eofflag) {
865 iov.iov_base = buf;
866 iov.iov_len = sizeof(buf);
867 uio.uio_iov = &iov;
868 uio.uio_iovcnt = 1;
869 uio.uio_resid = iov.iov_len;
871 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
872 if (error)
873 break;
875 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
876 for (dp = (struct dirent*)buf; !error && dp < edp;
877 dp = (struct dirent*)((char *)dp + dp->d_reclen)) {
878 if (dp->d_type == DT_WHT ||
879 (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
880 (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2)))
881 continue;
883 cn.cn_namelen = dp->d_namlen;
884 cn.cn_pnbuf = NULL;
885 cn.cn_nameptr = dp->d_name;
886 cn.cn_nameiop = LOOKUP;
887 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
888 cn.cn_cred = cred;
889 cn.cn_consume = 0;
892 * check entry in lower.
893 * Sometimes, readdir function returns
894 * wrong entry.
896 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
898 if (!lookuperr)
899 vput(tvp);
900 else
901 continue; /* skip entry */
904 * check entry
905 * If it has no exist/whiteout entry in upper,
906 * directory is not empty.
908 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
909 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
911 if (!lookuperr)
912 vput(tvp);
914 /* ignore exist or whiteout entry */
915 if (!lookuperr ||
916 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
917 continue;
919 error = ENOTEMPTY;
923 /* close vnode */
924 VOP_CLOSE(vp, FREAD, cred);
926 return (error);
929 #ifdef DIAGNOSTIC
931 struct vnode *
932 unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno)
934 struct unionfs_node *unp;
936 unp = VTOUNIONFS(vp);
938 #ifdef notyet
939 if (vp->v_op != unionfs_vnodeop_p) {
940 printf("unionfs_checkuppervp: on non-unionfs-node.\n");
941 #ifdef KDB
942 kdb_enter(KDB_WHY_UNIONFS,
943 "unionfs_checkuppervp: on non-unionfs-node.\n");
944 #endif
945 panic("unionfs_checkuppervp");
947 #endif
948 return (unp->un_uppervp);
951 struct vnode *
952 unionfs_checklowervp(struct vnode *vp, const char *fil, int lno)
954 struct unionfs_node *unp;
956 unp = VTOUNIONFS(vp);
958 #ifdef notyet
959 if (vp->v_op != unionfs_vnodeop_p) {
960 printf("unionfs_checklowervp: on non-unionfs-node.\n");
961 #ifdef KDB
962 kdb_enter(KDB_WHY_UNIONFS,
963 "unionfs_checklowervp: on non-unionfs-node.\n");
964 #endif
965 panic("unionfs_checklowervp");
967 #endif
968 return (unp->un_lowervp);
970 #endif