Line data Source code
1 : /* $OpenBSD: fuse_lookup.c,v 1.21 2018/06/21 14:53:36 helg Exp $ */
2 : /*
3 : * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
4 : *
5 : * Permission to use, copy, modify, and distribute this software for any
6 : * purpose with or without fee is hereby granted, provided that the above
7 : * copyright notice and this permission notice appear in all copies.
8 : *
9 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : */
17 :
18 : #include <sys/param.h>
19 : #include <sys/systm.h>
20 : #include <sys/mount.h>
21 : #include <sys/namei.h>
22 : #include <sys/stat.h>
23 : #include <sys/statvfs.h>
24 : #include <sys/vnode.h>
25 : #include <sys/lock.h>
26 : #include <sys/fusebuf.h>
27 :
28 : #include "fusefs_node.h"
29 : #include "fusefs.h"
30 :
31 : int fusefs_lookup(void *);
32 :
33 : int
34 0 : fusefs_lookup(void *v)
35 : {
36 0 : struct vop_lookup_args *ap = v;
37 : struct vnode *vdp; /* vnode for directory being searched */
38 : struct fusefs_node *dp; /* inode for directory being searched */
39 : struct fusefs_mnt *fmp; /* file system that directory is in */
40 : int lockparent; /* 1 => lockparent flag is set */
41 0 : struct vnode *tdp; /* returned by VOP_VGET */
42 : struct fusebuf *fbuf;
43 0 : struct vnode **vpp = ap->a_vpp;
44 0 : struct componentname *cnp = ap->a_cnp;
45 0 : struct proc *p = cnp->cn_proc;
46 0 : struct ucred *cred = cnp->cn_cred;
47 : uint64_t nid;
48 : enum vtype nvtype;
49 : int flags;
50 0 : int nameiop = cnp->cn_nameiop;
51 : int wantparent;
52 : int error = 0;
53 :
54 0 : flags = cnp->cn_flags;
55 0 : *vpp = NULL;
56 0 : vdp = ap->a_dvp;
57 0 : dp = VTOI(vdp);
58 0 : fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump;
59 0 : lockparent = flags & LOCKPARENT;
60 0 : wantparent = flags & (LOCKPARENT | WANTPARENT);
61 :
62 0 : if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
63 0 : return (error);
64 :
65 0 : if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
66 0 : (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
67 0 : return (EROFS);
68 :
69 0 : if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
70 0 : nid = dp->ufs_ino.i_number;
71 0 : } else {
72 0 : if (!fmp->sess_init)
73 0 : return (ENOENT);
74 :
75 : /* got a real entry */
76 0 : fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number,
77 : FBT_LOOKUP, p);
78 :
79 0 : memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
80 0 : fbuf->fb_dat[cnp->cn_namelen] = '\0';
81 :
82 0 : error = fb_queue(fmp->dev, fbuf);
83 :
84 0 : if (error) {
85 0 : fb_delete(fbuf);
86 :
87 : /* file system is dead */
88 0 : if (error == ENXIO)
89 0 : return (error);
90 :
91 0 : if ((nameiop == CREATE || nameiop == RENAME) &&
92 : (flags & ISLASTCN)) {
93 : /*
94 : * Access for write is interpreted as allowing
95 : * creation of files in the directory.
96 : */
97 0 : if ((error = VOP_ACCESS(vdp, VWRITE, cred,
98 0 : cnp->cn_proc)) != 0)
99 0 : return (error);
100 :
101 0 : cnp->cn_flags |= SAVENAME;
102 :
103 0 : if (!lockparent) {
104 0 : VOP_UNLOCK(vdp);
105 0 : cnp->cn_flags |= PDIRUNLOCK;
106 0 : }
107 :
108 0 : return (EJUSTRETURN);
109 : }
110 :
111 0 : return (ENOENT);
112 : }
113 :
114 0 : nid = fbuf->fb_ino;
115 0 : nvtype = IFTOVT(fbuf->fb_attr.st_mode);
116 0 : fb_delete(fbuf);
117 : }
118 :
119 0 : if (nameiop == DELETE && (flags & ISLASTCN)) {
120 : /*
121 : * Write access to directory required to delete files.
122 : */
123 0 : error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
124 0 : if (error)
125 : goto reclaim;
126 :
127 0 : cnp->cn_flags |= SAVENAME;
128 0 : }
129 :
130 0 : if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
131 : /*
132 : * Write access to directory required to delete files.
133 : */
134 0 : if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
135 : goto reclaim;
136 :
137 0 : if (nid == dp->ufs_ino.i_number)
138 0 : return (EISDIR);
139 :
140 0 : error = VFS_VGET(fmp->mp, nid, &tdp);
141 0 : if (error)
142 : goto reclaim;
143 :
144 0 : tdp->v_type = nvtype;
145 0 : *vpp = tdp;
146 0 : cnp->cn_flags |= SAVENAME;
147 :
148 0 : return (0);
149 : }
150 :
151 0 : if (flags & ISDOTDOT) {
152 0 : VOP_UNLOCK(vdp); /* race to get the inode */
153 0 : cnp->cn_flags |= PDIRUNLOCK;
154 :
155 0 : error = VFS_VGET(fmp->mp, nid, &tdp);
156 :
157 0 : if (error) {
158 0 : if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY) == 0)
159 0 : cnp->cn_flags &= ~PDIRUNLOCK;
160 :
161 : goto reclaim;
162 : }
163 :
164 0 : tdp->v_type = nvtype;
165 :
166 0 : if (lockparent && (flags & ISLASTCN)) {
167 0 : if ((error = vn_lock(vdp, LK_EXCLUSIVE))) {
168 0 : vput(tdp);
169 0 : return (error);
170 : }
171 0 : cnp->cn_flags &= ~PDIRUNLOCK;
172 0 : }
173 0 : *vpp = tdp;
174 :
175 0 : } else if (nid == dp->ufs_ino.i_number) {
176 0 : vref(vdp);
177 0 : *vpp = vdp;
178 : error = 0;
179 0 : } else {
180 0 : error = VFS_VGET(fmp->mp, nid, &tdp);
181 0 : if (error)
182 : goto reclaim;
183 :
184 0 : tdp->v_type = nvtype;
185 :
186 0 : if (!lockparent || !(flags & ISLASTCN)) {
187 0 : VOP_UNLOCK(vdp);
188 0 : cnp->cn_flags |= PDIRUNLOCK;
189 0 : }
190 :
191 0 : *vpp = tdp;
192 : }
193 :
194 0 : return (error);
195 :
196 : reclaim:
197 0 : if (nid != dp->ufs_ino.i_number && nid != FUSE_ROOTINO) {
198 0 : fbuf = fb_setup(0, nid, FBT_RECLAIM, p);
199 0 : if (fb_queue(fmp->dev, fbuf))
200 0 : printf("fusefs: libfuse vnode reclaim failed\n");
201 0 : fb_delete(fbuf);
202 0 : }
203 0 : return (error);
204 0 : }
|