xref: /openbsd/sys/miscfs/fuse/fuse_vnops.c (revision 51d8761d)
1 /* $OpenBSD: fuse_vnops.c,v 1.72 2024/10/31 13:55:21 claudio 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/dirent.h>
21 #include <sys/fcntl.h>
22 #include <sys/file.h>
23 #include <sys/lockf.h>
24 #include <sys/malloc.h>
25 #include <sys/mount.h>
26 #include <sys/namei.h>
27 #include <sys/pool.h>
28 #include <sys/proc.h>
29 #include <sys/specdev.h>
30 #include <sys/stat.h>
31 #include <sys/statvfs.h>
32 #include <sys/vnode.h>
33 #include <sys/lock.h>
34 #include <sys/fusebuf.h>
35 
36 #include "fusefs_node.h"
37 #include "fusefs.h"
38 
39 /* Prototypes for fusefs vnode ops */
40 int	fusefs_kqfilter(void *);
41 int	fusefs_lookup(void *);
42 int	fusefs_open(void *);
43 int	fusefs_close(void *);
44 int	fusefs_access(void *);
45 int	fusefs_getattr(void *);
46 int	fusefs_setattr(void *);
47 int	fusefs_ioctl(void *);
48 int	fusefs_link(void *);
49 int	fusefs_symlink(void *);
50 int	fusefs_readdir(void *);
51 int	fusefs_readlink(void *);
52 int	fusefs_inactive(void *);
53 int	fusefs_reclaim(void *);
54 int	fusefs_print(void *);
55 int	fusefs_create(void *);
56 int	fusefs_mknod(void *);
57 int	fusefs_read(void *);
58 int	fusefs_write(void *);
59 int	fusefs_remove(void *);
60 int	fusefs_rename(void *);
61 int	fusefs_mkdir(void *);
62 int	fusefs_rmdir(void *);
63 int	fusefs_strategy(void *);
64 int	fusefs_lock(void *);
65 int	fusefs_unlock(void *);
66 int	fusefs_islocked(void *);
67 int	fusefs_advlock(void *);
68 int	fusefs_fsync(void *);
69 
70 /* Prototypes for fusefs kqfilter */
71 int	filt_fusefsread(struct knote *, long);
72 int	filt_fusefswrite(struct knote *, long);
73 int	filt_fusefsvnode(struct knote *, long);
74 void	filt_fusefsdetach(struct knote *);
75 
76 const struct vops fusefs_vops = {
77 	.vop_lookup	= fusefs_lookup,
78 	.vop_create	= fusefs_create,
79 	.vop_mknod	= fusefs_mknod,
80 	.vop_open	= fusefs_open,
81 	.vop_close	= fusefs_close,
82 	.vop_access	= fusefs_access,
83 	.vop_getattr	= fusefs_getattr,
84 	.vop_setattr	= fusefs_setattr,
85 	.vop_read	= fusefs_read,
86 	.vop_write	= fusefs_write,
87 	.vop_ioctl	= fusefs_ioctl,
88 	.vop_kqfilter	= fusefs_kqfilter,
89 	.vop_revoke	= NULL,
90 	.vop_fsync	= fusefs_fsync,
91 	.vop_remove	= fusefs_remove,
92 	.vop_link	= fusefs_link,
93 	.vop_rename	= fusefs_rename,
94 	.vop_mkdir	= fusefs_mkdir,
95 	.vop_rmdir	= fusefs_rmdir,
96 	.vop_symlink	= fusefs_symlink,
97 	.vop_readdir	= fusefs_readdir,
98 	.vop_readlink	= fusefs_readlink,
99 	.vop_abortop	= vop_generic_abortop,
100 	.vop_inactive	= fusefs_inactive,
101 	.vop_reclaim	= fusefs_reclaim,
102 	.vop_lock	= fusefs_lock,
103 	.vop_unlock	= fusefs_unlock,
104 	.vop_bmap	= vop_generic_bmap,
105 	.vop_strategy	= fusefs_strategy,
106 	.vop_print	= fusefs_print,
107 	.vop_islocked	= fusefs_islocked,
108 	.vop_pathconf	= spec_pathconf,
109 	.vop_advlock	= fusefs_advlock,
110 	.vop_bwrite	= NULL,
111 };
112 
113 const struct filterops fusefsread_filtops = {
114 	.f_flags	= FILTEROP_ISFD,
115 	.f_attach	= NULL,
116 	.f_detach	= filt_fusefsdetach,
117 	.f_event	= filt_fusefsread,
118 };
119 
120 const struct filterops fusefswrite_filtops = {
121 	.f_flags	= FILTEROP_ISFD,
122 	.f_attach	= NULL,
123 	.f_detach	= filt_fusefsdetach,
124 	.f_event	= filt_fusefswrite,
125 };
126 
127 const struct filterops fusefsvnode_filtops = {
128 	.f_flags	= FILTEROP_ISFD,
129 	.f_attach	= NULL,
130 	.f_detach	= filt_fusefsdetach,
131 	.f_event	= filt_fusefsvnode,
132 };
133 
134 int
fusefs_kqfilter(void * v)135 fusefs_kqfilter(void *v)
136 {
137 	struct vop_kqfilter_args *ap = v;
138 	struct vnode *vp = ap->a_vp;
139 	struct knote *kn = ap->a_kn;
140 
141 	switch (kn->kn_filter) {
142 	case EVFILT_READ:
143 		kn->kn_fop = &fusefsread_filtops;
144 		break;
145 	case EVFILT_WRITE:
146 		kn->kn_fop = &fusefswrite_filtops;
147 		break;
148 	case EVFILT_VNODE:
149 		kn->kn_fop = &fusefsvnode_filtops;
150 		break;
151 	default:
152 		return (EINVAL);
153 	}
154 
155 	kn->kn_hook = (caddr_t)vp;
156 
157 	klist_insert_locked(&vp->v_klist, kn);
158 
159 	return (0);
160 }
161 
162 void
filt_fusefsdetach(struct knote * kn)163 filt_fusefsdetach(struct knote *kn)
164 {
165 	struct vnode *vp = (struct vnode *)kn->kn_hook;
166 
167 	klist_remove_locked(&vp->v_klist, kn);
168 }
169 
170 int
filt_fusefsread(struct knote * kn,long hint)171 filt_fusefsread(struct knote *kn, long hint)
172 {
173 	struct vnode *vp = (struct vnode *)kn->kn_hook;
174 	struct fusefs_node *ip = VTOI(vp);
175 
176 	/*
177 	 * filesystem is gone, so set the EOF flag and schedule
178 	 * the knote for deletion
179 	 */
180 	if (hint == NOTE_REVOKE) {
181 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
182 		return (1);
183 	}
184 
185 	kn->kn_data = ip->filesize - foffset(kn->kn_fp);
186 	if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
187 		kn->kn_fflags |= NOTE_EOF;
188 		return (1);
189 	}
190 
191 	if (kn->kn_flags & (__EV_POLL | __EV_SELECT))
192 		return (1);
193 
194 	return (kn->kn_data != 0);
195 }
196 
197 int
filt_fusefswrite(struct knote * kn,long hint)198 filt_fusefswrite(struct knote *kn, long hint)
199 {
200 	/*
201 	 * filesystem is gone, so set the EOF flag and schedule
202 	 * the knote for deletion
203 	 */
204 	if (hint == NOTE_REVOKE) {
205 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
206 		return (1);
207 	}
208 
209 	kn->kn_data = 0;
210 	return (1);
211 }
212 
213 int
filt_fusefsvnode(struct knote * kn,long int hint)214 filt_fusefsvnode(struct knote *kn, long int hint)
215 {
216 	if (kn->kn_sfflags & hint)
217 		kn->kn_fflags |= hint;
218 	if (hint == NOTE_REVOKE) {
219 		kn->kn_flags |= EV_EOF;
220 		return (1);
221 	}
222 	return (kn->kn_fflags != 0);
223 }
224 
225 /*
226  * FUSE file systems can maintain a file handle for each VFS file descriptor
227  * that is opened. The OpenBSD VFS does not make file descriptors visible to
228  * us so we fake it by mapping open flags to file handles.
229  * There is no way for FUSE to know which file descriptor is being used
230  * by an application for a file operation. We only maintain 3 descriptors,
231  * one each for O_RDONLY, O_WRONLY and O_RDWR. When reading and writing, the
232  * first open descriptor is used and this may well not be the one that was set
233  * by FUSE open and may have even been opened by another application.
234  */
235 int
fusefs_open(void * v)236 fusefs_open(void *v)
237 {
238 	struct vop_open_args *ap;
239 	struct fusefs_node *ip;
240 	struct fusefs_mnt *fmp;
241 	struct vnode *vp;
242 	enum fufh_type fufh_type = FUFH_RDONLY;
243 	int flags;
244 	int error;
245 	int isdir;
246 
247 	ap = v;
248 	vp = ap->a_vp;
249 	ip = VTOI(vp);
250 	fmp = (struct fusefs_mnt *)ip->i_ump;
251 
252 	if (!fmp->sess_init)
253 		return (ENXIO);
254 
255 	isdir = 0;
256 	if (vp->v_type == VDIR)
257 		isdir = 1;
258 	else {
259 		if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE))
260 			fufh_type = FUFH_RDWR;
261 		else if (ap->a_mode & (FWRITE))
262 			fufh_type = FUFH_WRONLY;
263 
264 		/*
265 		 * Due to possible attribute caching, there is no
266 		 * reliable way to determine if the file was modified
267 		 * externally (e.g. network file system) so clear the
268 		 * UVM cache to ensure that it is not stale. The file
269 		 * can still become stale later on read but this will
270 		 * satisfy most situations.
271 		 */
272 		uvm_vnp_uncache(vp);
273 	}
274 
275 	/* already open i think all is ok */
276 	if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
277 		return (0);
278 
279 	/*
280 	 * The file has already been created and/or truncated so FUSE dictates
281 	 * that no creation and truncation flags are passed to open.
282 	 */
283 	flags = OFLAGS(ap->a_mode) & ~(O_CREAT|O_EXCL|O_TRUNC);
284 	error = fusefs_file_open(fmp, ip, fufh_type, flags, isdir, ap->a_p);
285 
286 	return (error);
287 }
288 
289 int
fusefs_close(void * v)290 fusefs_close(void *v)
291 {
292 	struct vop_close_args *ap;
293 	struct fusefs_node *ip;
294 	struct fusefs_mnt *fmp;
295 	struct fusebuf *fbuf;
296 	enum fufh_type fufh_type = FUFH_RDONLY;
297 	int error = 0;
298 
299 	ap = v;
300 	ip = VTOI(ap->a_vp);
301 	fmp = (struct fusefs_mnt *)ip->i_ump;
302 
303 	if (!fmp->sess_init)
304 		return (0);
305 
306 	/*
307 	 * The file or directory may have been opened more than once so there
308 	 * is no reliable way to determine when to ask the FUSE daemon to
309 	 * release its file descriptor. For files, ask the daemon to flush any
310 	 * buffers to disk now. All open file descriptors will be released on
311 	 * VOP_INACTIVE(9).
312 	 */
313 
314 	if (ap->a_vp->v_type == VDIR)
315 		return (0);
316 
317 	/* Implementing flush is optional so don't error. */
318 	if (fmp->undef_op & UNDEF_FLUSH)
319 		return (0);
320 
321 	/* Only flush writeable file descriptors. */
322 	if ((ap->a_fflag & FREAD) && (ap->a_fflag & FWRITE))
323 		fufh_type = FUFH_RDWR;
324 	else if (ap->a_fflag & (FWRITE))
325 		fufh_type = FUFH_WRONLY;
326 	else
327 		return (0);
328 
329 	if (ip->fufh[fufh_type].fh_type == FUFH_INVALID)
330 		return (EBADF);
331 
332 	fbuf = fb_setup(0, ip->i_number, FBT_FLUSH, ap->a_p);
333 	fbuf->fb_io_fd = ip->fufh[fufh_type].fh_id;
334 	error = fb_queue(fmp->dev, fbuf);
335 	fb_delete(fbuf);
336 	if (error == ENOSYS) {
337 		fmp->undef_op |= UNDEF_FLUSH;
338 
339 		/* Implementing flush is optional so don't error. */
340 		return (0);
341 	}
342 
343 	return (error);
344 }
345 
346 int
fusefs_access(void * v)347 fusefs_access(void *v)
348 {
349 	struct vop_access_args *ap;
350 	struct fusefs_node *ip;
351 	struct fusefs_mnt *fmp;
352 	struct ucred *cred;
353 	struct vattr vattr;
354 	struct proc *p;
355 	int error = 0;
356 
357 	ap = v;
358 	p = ap->a_p;
359 	cred = p->p_ucred;
360 	ip = VTOI(ap->a_vp);
361 	fmp = (struct fusefs_mnt *)ip->i_ump;
362 
363 	/*
364 	 * Only user that mounted the file system can access it unless
365 	 * allow_other mount option was specified.
366 	 */
367 	if (!fmp->allow_other && cred->cr_uid != fmp->mp->mnt_stat.f_owner)
368 		return (EACCES);
369 
370 	if (!fmp->sess_init)
371 		return (ENXIO);
372 
373 	/*
374 	 * Disallow write attempts on filesystems mounted read-only;
375 	 * unless the file is a socket, fifo, or a block or character
376 	 * device resident on the filesystem.
377 	 */
378 	if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY)) {
379 		switch (ap->a_vp->v_type) {
380 		case VREG:
381 		case VDIR:
382 		case VLNK:
383 			return (EROFS);
384 		default:
385 			break;
386 		}
387 	}
388 
389 	if ((error = VOP_GETATTR(ap->a_vp, &vattr, cred, p)) != 0)
390 		return (error);
391 
392 	return (vaccess(ap->a_vp->v_type, vattr.va_mode & ALLPERMS,
393 	    vattr.va_uid, vattr.va_gid, ap->a_mode,
394 	    ap->a_cred));
395 }
396 
397 int
fusefs_getattr(void * v)398 fusefs_getattr(void *v)
399 {
400 	struct vop_getattr_args *ap = v;
401 	struct vnode *vp = ap->a_vp;
402 	struct fusefs_mnt *fmp;
403 	struct vattr *vap = ap->a_vap;
404 	struct proc *p = ap->a_p;
405 	struct ucred *cred = p->p_ucred;
406 	struct fusefs_node *ip;
407 	struct fusebuf *fbuf;
408 	struct stat *st;
409 	int error = 0;
410 
411 	ip = VTOI(vp);
412 	fmp = (struct fusefs_mnt *)ip->i_ump;
413 
414 	/*
415 	 * Only user that mounted the file system can access it unless
416 	 * allow_other mount option was specified. Return dummy values
417 	 * for the root inode in this situation.
418 	 */
419 	if (!fmp->allow_other && cred->cr_uid != fmp->mp->mnt_stat.f_owner) {
420 		memset(vap, 0, sizeof(*vap));
421 		vap->va_type = VNON;
422 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
423 			vap->va_mode = S_IRUSR | S_IXUSR;
424 		else
425 			vap->va_mode = S_IRWXU;
426 		vap->va_nlink = 1;
427 		vap->va_uid = fmp->mp->mnt_stat.f_owner;
428 		vap->va_gid = fmp->mp->mnt_stat.f_owner;
429 		vap->va_fsid = fmp->mp->mnt_stat.f_fsid.val[0];
430 		vap->va_fileid = ip->i_number;
431 		vap->va_size = S_BLKSIZE;
432 		vap->va_blocksize = S_BLKSIZE;
433 		vap->va_atime.tv_sec = fmp->mp->mnt_stat.f_ctime;
434 		vap->va_mtime.tv_sec = fmp->mp->mnt_stat.f_ctime;
435 		vap->va_ctime.tv_sec = fmp->mp->mnt_stat.f_ctime;
436 		vap->va_rdev = fmp->dev;
437 		vap->va_bytes = S_BLKSIZE;
438 		return (0);
439 	}
440 
441 	if (!fmp->sess_init)
442 		return (ENXIO);
443 
444 	fbuf = fb_setup(0, ip->i_number, FBT_GETATTR, p);
445 
446 	error = fb_queue(fmp->dev, fbuf);
447 	if (error) {
448 		fb_delete(fbuf);
449 		return (error);
450 	}
451 
452 	st = &fbuf->fb_attr;
453 
454 	memset(vap, 0, sizeof(*vap));
455 	vap->va_type = IFTOVT(st->st_mode);
456 	vap->va_mode = st->st_mode & ~S_IFMT;
457 	vap->va_nlink = st->st_nlink;
458 	vap->va_uid = st->st_uid;
459 	vap->va_gid = st->st_gid;
460 	vap->va_fsid = fmp->mp->mnt_stat.f_fsid.val[0];
461 	vap->va_fileid = st->st_ino;
462 	vap->va_size = st->st_size;
463 	vap->va_blocksize = st->st_blksize;
464 	vap->va_atime = st->st_atim;
465 	vap->va_mtime = st->st_mtim;
466 	vap->va_ctime = st->st_ctim;
467 	vap->va_rdev = st->st_rdev;
468 	vap->va_bytes = st->st_blocks * S_BLKSIZE;
469 
470 	fb_delete(fbuf);
471 	return (error);
472 }
473 
474 int
fusefs_setattr(void * v)475 fusefs_setattr(void *v)
476 {
477 	struct vop_setattr_args *ap = v;
478 	struct vattr *vap = ap->a_vap;
479 	struct vnode *vp = ap->a_vp;
480 	struct fusefs_node *ip = VTOI(vp);
481 	struct ucred *cred = ap->a_cred;
482 	struct proc *p = ap->a_p;
483 	struct fusefs_mnt *fmp;
484 	struct fusebuf *fbuf;
485 	struct fb_io *io;
486 	int error = 0;
487 
488 	fmp = (struct fusefs_mnt *)ip->i_ump;
489 	/*
490 	 * Check for unsettable attributes.
491 	 */
492 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
493 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
494 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
495 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
496 		return (EINVAL);
497 
498 	if (!fmp->sess_init)
499 		return (ENXIO);
500 
501 	if (fmp->undef_op & UNDEF_SETATTR)
502 		return (ENOSYS);
503 
504 	fbuf = fb_setup(sizeof(*io), ip->i_number, FBT_SETATTR, p);
505 	io = fbtod(fbuf, struct fb_io *);
506 	io->fi_flags = 0;
507 
508 	if (vap->va_uid != (uid_t)VNOVAL) {
509 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
510 			error = EROFS;
511 			goto out;
512 		}
513 		fbuf->fb_attr.st_uid = vap->va_uid;
514 		io->fi_flags |= FUSE_FATTR_UID;
515 	}
516 
517 	if (vap->va_gid != (gid_t)VNOVAL) {
518 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
519 			error = EROFS;
520 			goto out;
521 		}
522 		fbuf->fb_attr.st_gid = vap->va_gid;
523 		io->fi_flags |= FUSE_FATTR_GID;
524 	}
525 
526 	if (vap->va_size != VNOVAL) {
527 		/*
528 		 * Disallow write attempts on read-only file systems;
529 		 * unless the file is a socket, fifo, or a block or
530 		 * character device resident on the file system.
531 		 */
532 		switch (vp->v_type) {
533 		case VDIR:
534 			error = EISDIR;
535 			goto out;
536 		case VLNK:
537 		case VREG:
538 			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
539 				error = EROFS;
540 				goto out;
541 			}
542 			break;
543 		default:
544 			break;
545 		}
546 
547 		fbuf->fb_attr.st_size = vap->va_size;
548 		io->fi_flags |= FUSE_FATTR_SIZE;
549 	}
550 
551 	if (vap->va_atime.tv_nsec != VNOVAL) {
552 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
553 			error = EROFS;
554 			goto out;
555 		}
556 		fbuf->fb_attr.st_atim = vap->va_atime;
557 		io->fi_flags |= FUSE_FATTR_ATIME;
558 	}
559 
560 	if (vap->va_mtime.tv_nsec != VNOVAL) {
561 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
562 			error = EROFS;
563 			goto out;
564 		}
565 		fbuf->fb_attr.st_mtim = vap->va_mtime;
566 		io->fi_flags |= FUSE_FATTR_MTIME;
567 	}
568 	/* XXX should set a flag if (vap->va_vaflags & VA_UTIMES_CHANGE) */
569 
570 	if (vap->va_mode != (mode_t)VNOVAL) {
571 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
572 			error = EROFS;
573 			goto out;
574 		}
575 
576 		/*
577 		 * chmod returns EFTYPE if the effective user ID is not the
578 		 * super-user, the mode includes the sticky bit (S_ISVTX), and
579 		 * path does not refer to a directory
580 		 */
581 		if (cred->cr_uid != 0 && vp->v_type != VDIR &&
582 		    (vap->va_mode & S_ISTXT)) {
583 			error = EFTYPE;
584 			goto out;
585 		}
586 
587 		fbuf->fb_attr.st_mode = vap->va_mode & ALLPERMS;
588 		io->fi_flags |= FUSE_FATTR_MODE;
589 	}
590 
591 	if (!io->fi_flags) {
592 		goto out;
593 	}
594 
595 	error = fb_queue(fmp->dev, fbuf);
596 	if (error) {
597 		if (error == ENOSYS)
598 			fmp->undef_op |= UNDEF_SETATTR;
599 		goto out;
600 	}
601 
602 	/* truncate was successful, let uvm know */
603 	if (vap->va_size != VNOVAL && vap->va_size != ip->filesize) {
604 		ip->filesize = vap->va_size;
605 		uvm_vnp_setsize(vp, vap->va_size);
606 	}
607 
608 	VN_KNOTE(ap->a_vp, NOTE_ATTRIB);
609 
610 out:
611 	fb_delete(fbuf);
612 	return (error);
613 }
614 
615 int
fusefs_ioctl(void * v)616 fusefs_ioctl(void *v)
617 {
618 	return (ENOTTY);
619 }
620 
621 int
fusefs_link(void * v)622 fusefs_link(void *v)
623 {
624 	struct vop_link_args *ap = v;
625 	struct vnode *dvp = ap->a_dvp;
626 	struct vnode *vp = ap->a_vp;
627 	struct componentname *cnp = ap->a_cnp;
628 	struct proc *p = cnp->cn_proc;
629 	struct fusefs_mnt *fmp;
630 	struct fusefs_node *ip;
631 	struct fusefs_node *dip;
632 	struct fusebuf *fbuf;
633 	int error = 0;
634 
635 	ip = VTOI(vp);
636 	dip = VTOI(dvp);
637 	fmp = (struct fusefs_mnt *)ip->i_ump;
638 
639 	if (!fmp->sess_init) {
640 		VOP_ABORTOP(dvp, cnp);
641 		error = ENXIO;
642 		goto out2;
643 	}
644 	if (fmp->undef_op & UNDEF_LINK) {
645 		VOP_ABORTOP(dvp, cnp);
646 		error = ENOSYS;
647 		goto out2;
648 	}
649 	if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
650 		VOP_ABORTOP(dvp, cnp);
651 		goto out2;
652 	}
653 
654 	fbuf = fb_setup(cnp->cn_namelen + 1, dip->i_number,
655 	    FBT_LINK, p);
656 
657 	fbuf->fb_io_ino = ip->i_number;
658 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
659 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
660 
661 	error = fb_queue(fmp->dev, fbuf);
662 
663 	if (error) {
664 		if (error == ENOSYS)
665 			fmp->undef_op |= UNDEF_LINK;
666 
667 		fb_delete(fbuf);
668 		goto out1;
669 	}
670 
671 	fb_delete(fbuf);
672 	VN_KNOTE(vp, NOTE_LINK);
673 	VN_KNOTE(dvp, NOTE_WRITE);
674 
675 out1:
676 	pool_put(&namei_pool, cnp->cn_pnbuf);
677 	if (dvp != vp)
678 		VOP_UNLOCK(vp);
679 out2:
680 	vput(dvp);
681 	return (error);
682 }
683 
684 int
fusefs_symlink(void * v)685 fusefs_symlink(void *v)
686 {
687 	struct vop_symlink_args *ap = v;
688 	struct vnode **vpp = ap->a_vpp;
689 	struct componentname *cnp = ap->a_cnp;
690 	struct vnode *dvp = ap->a_dvp;
691 	struct proc *p = cnp->cn_proc;
692 	char *target = ap->a_target;
693 	struct fusefs_node *dp;
694 	struct fusefs_mnt *fmp;
695 	struct fusebuf *fbuf;
696 	struct vnode *tdp;
697 	int error = 0;
698 	int len;
699 
700 	dp = VTOI(dvp);
701 	fmp = (struct fusefs_mnt *)dp->i_ump;
702 
703 	if (!fmp->sess_init) {
704 		error = ENXIO;
705 		goto bad;
706 	}
707 
708 	if (fmp->undef_op & UNDEF_SYMLINK) {
709 		error = ENOSYS;
710 		goto bad;
711 	}
712 
713 	len = strlen(target) + 1;
714 
715 	fbuf = fb_setup(len + cnp->cn_namelen + 1, dp->i_number,
716 	    FBT_SYMLINK, p);
717 
718 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
719 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
720 	memcpy(&fbuf->fb_dat[cnp->cn_namelen + 1], target, len);
721 
722 	error = fb_queue(fmp->dev, fbuf);
723 	if (error) {
724 		if (error == ENOSYS)
725 			fmp->undef_op |= UNDEF_SYMLINK;
726 
727 		fb_delete(fbuf);
728 		goto bad;
729 	}
730 
731 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
732 		fb_delete(fbuf);
733 		goto bad;
734 	}
735 
736 	tdp->v_type = VLNK;
737 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
738 
739 	*vpp = tdp;
740 	fb_delete(fbuf);
741 	vput(tdp);
742 bad:
743 	pool_put(&namei_pool, cnp->cn_pnbuf);
744 	vput(dvp);
745 	return (error);
746 }
747 
748 int
fusefs_readdir(void * v)749 fusefs_readdir(void *v)
750 {
751 	struct vop_readdir_args *ap = v;
752 	struct fusefs_node *ip;
753 	struct fusefs_mnt *fmp;
754 	struct fusebuf *fbuf;
755 	struct dirent *dp;
756 	char *edp;
757 	struct vnode *vp;
758 	struct proc *p;
759 	struct uio *uio;
760 	int error = 0, eofflag = 0, diropen = 0;
761 
762 	vp = ap->a_vp;
763 	uio = ap->a_uio;
764 	p = uio->uio_procp;
765 
766 	ip = VTOI(vp);
767 	fmp = (struct fusefs_mnt *)ip->i_ump;
768 
769 	if (!fmp->sess_init)
770 		return (ENXIO);
771 
772 	if (uio->uio_resid < sizeof(struct dirent))
773 		return (EINVAL);
774 
775 	if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) {
776 		error = fusefs_file_open(fmp, ip, FUFH_RDONLY, O_RDONLY, 1, p);
777 		if (error)
778 			return (error);
779 
780 		diropen = 1;
781 	}
782 
783 	while (uio->uio_resid > 0) {
784 		fbuf = fb_setup(0, ip->i_number, FBT_READDIR, p);
785 
786 		fbuf->fb_io_fd = ip->fufh[FUFH_RDONLY].fh_id;
787 		fbuf->fb_io_off = uio->uio_offset;
788 		fbuf->fb_io_len = MIN(uio->uio_resid, fmp->max_read);
789 
790 		error = fb_queue(fmp->dev, fbuf);
791 
792 		if (error) {
793 			/*
794 			 * dirent was larger than residual space left in
795 			 * buffer.
796 			 */
797 			if (error == ENOBUFS)
798 				error = 0;
799 
800 			fb_delete(fbuf);
801 			break;
802 		}
803 
804 		/* ack end of readdir */
805 		if (fbuf->fb_len == 0) {
806 			eofflag = 1;
807 			fb_delete(fbuf);
808 			break;
809 		}
810 
811 		/* validate the returned dirents */
812 		dp = (struct dirent *)fbuf->fb_dat;
813 		edp = fbuf->fb_dat + fbuf->fb_len;
814 		while ((char *)dp < edp) {
815 			if ((char *)dp + offsetof(struct dirent, d_name) >= edp
816 			    || dp->d_reclen <= offsetof(struct dirent, d_name)
817 			    || (char *)dp + dp->d_reclen > edp) {
818 				error = EINVAL;
819 				break;
820 			}
821 			if (dp->d_namlen + offsetof(struct dirent, d_name) >=
822 			    dp->d_reclen) {
823 				error = EINVAL;
824 				break;
825 			}
826 			memset(dp->d_name + dp->d_namlen, 0, dp->d_reclen -
827 			    dp->d_namlen - offsetof(struct dirent, d_name));
828 
829 			if (memchr(dp->d_name, '/', dp->d_namlen) != NULL) {
830 				error = EINVAL;
831 				break;
832 			}
833 			dp = (struct dirent *)((char *)dp + dp->d_reclen);
834 		}
835 		if (error) {
836 			fb_delete(fbuf);
837 			break;
838 		}
839 
840 		if ((error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio))) {
841 			fb_delete(fbuf);
842 			break;
843 		}
844 
845 		fb_delete(fbuf);
846 	}
847 
848 	if (!error && ap->a_eofflag != NULL)
849 		*ap->a_eofflag = eofflag;
850 
851 	if (diropen)
852 		fusefs_file_close(fmp, ip, FUFH_RDONLY, O_RDONLY, 1, p);
853 
854 	return (error);
855 }
856 
857 int
fusefs_inactive(void * v)858 fusefs_inactive(void *v)
859 {
860 	struct vop_inactive_args *ap = v;
861 	struct vnode *vp = ap->a_vp;
862 	struct proc *p = ap->a_p;
863 	struct fusefs_node *ip = VTOI(vp);
864 	struct fusefs_filehandle *fufh = NULL;
865 	struct fusefs_mnt *fmp;
866 	int type, flags;
867 
868 	fmp = (struct fusefs_mnt *)ip->i_ump;
869 
870 	/* Close all open file handles. */
871 	for (type = 0; type < FUFH_MAXTYPE; type++) {
872 		fufh = &(ip->fufh[type]);
873 		if (fufh->fh_type != FUFH_INVALID) {
874 
875 			/*
876 			 * FUSE file systems expect the same flags to be sent
877 			 * on release that were sent on open. We don't have a
878 			 * record of them so make a best guess.
879 			 */
880 			switch (type) {
881 			case FUFH_RDONLY:
882 				flags = O_RDONLY;
883 				break;
884 			case FUFH_WRONLY:
885 				flags = O_WRONLY;
886 				break;
887 			default:
888 				flags = O_RDWR;
889 			}
890 
891 			fusefs_file_close(fmp, ip, fufh->fh_type, flags,
892 			    (vp->v_type == VDIR), p);
893 		}
894 	}
895 
896 	VOP_UNLOCK(vp);
897 
898 	/* Don't return error to prevent kernel panic in vclean(9). */
899 	return (0);
900 }
901 
902 int
fusefs_readlink(void * v)903 fusefs_readlink(void *v)
904 {
905 	struct vop_readlink_args *ap = v;
906 	struct vnode *vp = ap->a_vp;
907 	struct fusefs_node *ip;
908 	struct fusefs_mnt *fmp;
909 	struct fusebuf *fbuf;
910 	struct uio *uio;
911 	struct proc *p;
912 	int error = 0;
913 
914 	ip = VTOI(vp);
915 	fmp = (struct fusefs_mnt *)ip->i_ump;
916 	uio = ap->a_uio;
917 	p = uio->uio_procp;
918 
919 	if (!fmp->sess_init)
920 		return (ENXIO);
921 
922 	if (fmp->undef_op & UNDEF_READLINK)
923 		return (ENOSYS);
924 
925 	fbuf = fb_setup(0, ip->i_number, FBT_READLINK, p);
926 
927 	error = fb_queue(fmp->dev, fbuf);
928 
929 	if (error) {
930 		if (error == ENOSYS)
931 			fmp->undef_op |= UNDEF_READLINK;
932 
933 		fb_delete(fbuf);
934 		return (error);
935 	}
936 
937 	error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio);
938 	fb_delete(fbuf);
939 
940 	return (error);
941 }
942 
943 int
fusefs_reclaim(void * v)944 fusefs_reclaim(void *v)
945 {
946 	struct vop_reclaim_args *ap = v;
947 	struct vnode *vp = ap->a_vp;
948 	struct proc *p = ap->a_p;
949 	struct fusefs_node *ip = VTOI(vp);
950 	struct fusefs_filehandle *fufh = NULL;
951 	struct fusefs_mnt *fmp;
952 	struct fusebuf *fbuf;
953 	int type, error = 0;
954 
955 	fmp = (struct fusefs_mnt *)ip->i_ump;
956 
957 	/* Close opened files. */
958 	for (type = 0; type < FUFH_MAXTYPE; type++) {
959 		fufh = &(ip->fufh[type]);
960 		if (fufh->fh_type != FUFH_INVALID) {
961 			printf("fusefs: vnode being reclaimed is valid\n");
962 			fusefs_file_close(fmp, ip, fufh->fh_type, type,
963 			    (vp->v_type == VDIR), ap->a_p);
964 		}
965 	}
966 
967 	/*
968 	 * If the fuse connection is opened ask libfuse to free the vnodes.
969 	 */
970 	if (fmp->sess_init && ip->i_number != FUSE_ROOTINO) {
971 		fbuf = fb_setup(0, ip->i_number, FBT_RECLAIM, p);
972 		error = fb_queue(fmp->dev, fbuf);
973 		if (error)
974 			printf("fusefs: vnode reclaim failed: %d\n", error);
975 		fb_delete(fbuf);
976 	}
977 
978 	/*
979 	 * Remove the inode from its hash chain.
980 	 */
981 	fuse_ihashrem(ip);
982 
983 	free(ip, M_FUSEFS, sizeof(*ip));
984 	vp->v_data = NULL;
985 
986 	/* Must return success otherwise kernel panic in vclean(9). */
987 	return (0);
988 }
989 
990 int
fusefs_print(void * v)991 fusefs_print(void *v)
992 {
993 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG)
994 	struct vop_print_args *ap = v;
995 	struct vnode *vp = ap->a_vp;
996 	struct fusefs_node *ip = VTOI(vp);
997 
998 	/* Complete the information given by vprint(). */
999 	printf("tag VT_FUSE, hash id %llu ", ip->i_number);
1000 	printf("\n");
1001 #endif
1002 	return (0);
1003 }
1004 
1005 int
fusefs_create(void * v)1006 fusefs_create(void *v)
1007 {
1008 	struct vop_create_args *ap = v;
1009 	struct componentname *cnp = ap->a_cnp;
1010 	struct vnode **vpp = ap->a_vpp;
1011 	struct vnode *dvp = ap->a_dvp;
1012 	struct vattr *vap = ap->a_vap;
1013 	struct proc *p = cnp->cn_proc;
1014 	struct vnode *tdp = NULL;
1015 	struct fusefs_mnt *fmp;
1016 	struct fusefs_node *ip;
1017 	struct fusebuf *fbuf;
1018 	int error = 0;
1019 	mode_t mode;
1020 
1021 	ip = VTOI(dvp);
1022 	fmp = (struct fusefs_mnt *)ip->i_ump;
1023 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
1024 
1025 	if (!fmp->sess_init) {
1026 		VOP_ABORTOP(dvp, cnp);
1027 		return (ENXIO);
1028 	}
1029 
1030 	if (fmp->undef_op & UNDEF_MKNOD) {
1031 		VOP_ABORTOP(dvp, cnp);
1032 		return (ENOSYS);
1033 	}
1034 
1035 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number,
1036 	    FBT_MKNOD, p);
1037 
1038 	fbuf->fb_io_mode = mode;
1039 
1040 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1041 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1042 
1043 	error = fb_queue(fmp->dev, fbuf);
1044 	if (error) {
1045 		if (error == ENOSYS)
1046 			fmp->undef_op |= UNDEF_MKNOD;
1047 
1048 		goto out;
1049 	}
1050 
1051 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp)))
1052 		goto out;
1053 
1054 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
1055 
1056 	*vpp = tdp;
1057 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1058 out:
1059 	fb_delete(fbuf);
1060 	pool_put(&namei_pool, cnp->cn_pnbuf);
1061 	return (error);
1062 }
1063 
1064 int
fusefs_mknod(void * v)1065 fusefs_mknod(void *v)
1066 {
1067 	struct vop_mknod_args *ap = v;
1068 	struct componentname *cnp = ap->a_cnp;
1069 	struct vnode **vpp = ap->a_vpp;
1070 	struct vnode *dvp = ap->a_dvp;
1071 	struct vattr *vap = ap->a_vap;
1072 	struct proc *p = cnp->cn_proc;
1073 	struct vnode *tdp = NULL;
1074 	struct fusefs_mnt *fmp;
1075 	struct fusefs_node *ip;
1076 	struct fusebuf *fbuf;
1077 	int error = 0;
1078 
1079 	ip = VTOI(dvp);
1080 	fmp = (struct fusefs_mnt *)ip->i_ump;
1081 
1082 	if (!fmp->sess_init) {
1083 		VOP_ABORTOP(dvp, cnp);
1084 		return (ENXIO);
1085 	}
1086 
1087 	if (fmp->undef_op & UNDEF_MKNOD) {
1088 		VOP_ABORTOP(dvp, cnp);
1089 		return (ENOSYS);
1090 	}
1091 
1092 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number,
1093 	    FBT_MKNOD, p);
1094 
1095 	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1096 	if (vap->va_rdev != VNOVAL)
1097 		fbuf->fb_io_rdev = vap->va_rdev;
1098 
1099 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1100 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1101 
1102 	error = fb_queue(fmp->dev, fbuf);
1103 	if (error) {
1104 		if (error == ENOSYS)
1105 			fmp->undef_op |= UNDEF_MKNOD;
1106 
1107 		goto out;
1108 	}
1109 
1110 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp)))
1111 		goto out;
1112 
1113 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
1114 
1115 	*vpp = tdp;
1116 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1117 
1118 	/* Remove inode so that it will be reloaded by VFS_VGET and
1119 	 * checked to see if it is an alias of an existing entry in
1120 	 * the inode cache.
1121 	 */
1122 	vput(*vpp);
1123 	(*vpp)->v_type = VNON;
1124 	vgone(*vpp);
1125 	*vpp = NULL;
1126 out:
1127 	fb_delete(fbuf);
1128 	pool_put(&namei_pool, cnp->cn_pnbuf);
1129 	return (error);
1130 }
1131 
1132 int
fusefs_read(void * v)1133 fusefs_read(void *v)
1134 {
1135 	struct vop_read_args *ap = v;
1136 	struct vnode *vp = ap->a_vp;
1137 	struct uio *uio = ap->a_uio;
1138 	struct proc *p = uio->uio_procp;
1139 	struct fusefs_node *ip;
1140 	struct fusefs_mnt *fmp;
1141 	struct fusebuf *fbuf = NULL;
1142 	size_t size;
1143 	int error=0;
1144 
1145 	ip = VTOI(vp);
1146 	fmp = (struct fusefs_mnt *)ip->i_ump;
1147 
1148 	if (!fmp->sess_init)
1149 		return (ENXIO);
1150 	if (uio->uio_resid == 0)
1151 		return (error);
1152 	if (uio->uio_offset < 0)
1153 		return (EINVAL);
1154 
1155 	while (uio->uio_resid > 0) {
1156 		fbuf = fb_setup(0, ip->i_number, FBT_READ, p);
1157 
1158 		size = MIN(uio->uio_resid, fmp->max_read);
1159 		fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_RDONLY);
1160 		fbuf->fb_io_off = uio->uio_offset;
1161 		fbuf->fb_io_len = size;
1162 
1163 		error = fb_queue(fmp->dev, fbuf);
1164 
1165 		if (error)
1166 			break;
1167 
1168 		error = uiomove(fbuf->fb_dat, ulmin(size, fbuf->fb_len), uio);
1169 		if (error)
1170 			break;
1171 
1172 		if (fbuf->fb_len < size)
1173 			break;
1174 
1175 		fb_delete(fbuf);
1176 		fbuf = NULL;
1177 	}
1178 
1179 	fb_delete(fbuf);
1180 	return (error);
1181 }
1182 
1183 int
fusefs_write(void * v)1184 fusefs_write(void *v)
1185 {
1186 	struct vop_write_args *ap = v;
1187 	struct vnode *vp = ap->a_vp;
1188 	struct uio *uio = ap->a_uio;
1189 	struct proc *p = uio->uio_procp;
1190 	struct ucred *cred = p->p_ucred;
1191 	struct vattr vattr;
1192 	int ioflag = ap->a_ioflag;
1193 	struct fusefs_node *ip;
1194 	struct fusefs_mnt *fmp;
1195 	struct fusebuf *fbuf = NULL;
1196 	size_t len, diff;
1197 	int error=0;
1198 
1199 	ip = VTOI(vp);
1200 	fmp = (struct fusefs_mnt *)ip->i_ump;
1201 
1202 	if (!fmp->sess_init)
1203 		return (ENXIO);
1204 	if (uio->uio_resid == 0)
1205 		return (error);
1206 
1207 	if (ioflag & IO_APPEND) {
1208 		if ((error = VOP_GETATTR(vp, &vattr, cred, p)) != 0)
1209 			return (error);
1210 
1211 		uio->uio_offset = vattr.va_size;
1212 	}
1213 
1214 	while (uio->uio_resid > 0) {
1215 		len = MIN(uio->uio_resid, fmp->max_read);
1216 		fbuf = fb_setup(len, ip->i_number, FBT_WRITE, p);
1217 
1218 		fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_WRONLY);
1219 		fbuf->fb_io_off = uio->uio_offset;
1220 		fbuf->fb_io_len = len;
1221 
1222 		if ((error = uiomove(fbuf->fb_dat, len, uio))) {
1223 			printf("fusefs: uio error %i\n", error);
1224 			break;
1225 		}
1226 
1227 		error = fb_queue(fmp->dev, fbuf);
1228 
1229 		if (error)
1230 			break;
1231 
1232 		diff = len - fbuf->fb_io_len;
1233 		if (fbuf->fb_io_len > len) {
1234 			error = EINVAL;
1235 			break;
1236 		}
1237 
1238 		uio->uio_resid += diff;
1239 		uio->uio_offset -= diff;
1240 
1241 		if (uio->uio_offset > ip->filesize) {
1242 			ip->filesize = uio->uio_offset;
1243 			uvm_vnp_setsize(vp, uio->uio_offset);
1244 		}
1245 		uvm_vnp_uncache(vp);
1246 
1247 		fb_delete(fbuf);
1248 		fbuf = NULL;
1249 	}
1250 
1251 	fb_delete(fbuf);
1252 	return (error);
1253 }
1254 
1255 int
fusefs_rename(void * v)1256 fusefs_rename(void *v)
1257 {
1258 	struct vop_rename_args *ap = v;
1259 	struct vnode *tvp = ap->a_tvp;
1260 	struct vnode *tdvp = ap->a_tdvp;
1261 	struct vnode *fvp = ap->a_fvp;
1262 	struct vnode *fdvp = ap->a_fdvp;
1263 	struct componentname *tcnp = ap->a_tcnp;
1264 	struct componentname *fcnp = ap->a_fcnp;
1265 	struct proc *p = fcnp->cn_proc;
1266 	struct fusefs_node *ip, *dp;
1267 	struct fusefs_mnt *fmp;
1268 	struct fusebuf *fbuf;
1269 	int error = 0;
1270 
1271 #ifdef DIAGNOSTIC
1272 	if ((tcnp->cn_flags & HASBUF) == 0 ||
1273 	    (fcnp->cn_flags & HASBUF) == 0)
1274 		panic("fusefs_rename: no name");
1275 #endif
1276 	/*
1277 	 * Check for cross-device rename.
1278 	 */
1279 	if ((fvp->v_mount != tdvp->v_mount) ||
1280 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
1281 		error = EXDEV;
1282 abortit:
1283 		VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1284 		if (tdvp == tvp)
1285 			vrele(tdvp);
1286 		else
1287 			vput(tdvp);
1288 		if (tvp)
1289 			vput(tvp);
1290 		VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1291 		vrele(fdvp);
1292 		vrele(fvp);
1293 		return (error);
1294 	}
1295 
1296 	/*
1297 	 * If source and dest are the same, do nothing.
1298 	 */
1299 	if (tvp == fvp) {
1300 		error = 0;
1301 		goto abortit;
1302 	}
1303 
1304 	if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY)) != 0)
1305 		goto abortit;
1306 	dp = VTOI(fdvp);
1307 	ip = VTOI(fvp);
1308 	fmp = (struct fusefs_mnt *)ip->i_ump;
1309 
1310 	/*
1311 	 * Be sure we are not renaming ".", "..", or an alias of ".". This
1312 	 * leads to a crippled directory tree.  It's pretty tough to do a
1313 	 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
1314 	 * doesn't work if the ".." entry is missing.
1315 	 */
1316 	if (fvp->v_type == VDIR) {
1317 		/*
1318 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
1319 		 */
1320 		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1321 		    dp == ip ||
1322 		    (fcnp->cn_flags & ISDOTDOT) ||
1323 		    (tcnp->cn_flags & ISDOTDOT)) {
1324 			VOP_UNLOCK(fvp);
1325 			error = EINVAL;
1326 			goto abortit;
1327 		}
1328 	}
1329 	VN_KNOTE(fdvp, NOTE_WRITE);	/* XXX right place? */
1330 
1331 	if (!fmp->sess_init) {
1332 		error = ENXIO;
1333 		VOP_UNLOCK(fvp);
1334 		goto abortit;
1335 	}
1336 
1337 	if (fmp->undef_op & UNDEF_RENAME) {
1338 		error = ENOSYS;
1339 		VOP_UNLOCK(fvp);
1340 		goto abortit;
1341 	}
1342 
1343 	fbuf = fb_setup(fcnp->cn_namelen + tcnp->cn_namelen + 2,
1344 	    dp->i_number, FBT_RENAME, p);
1345 
1346 	memcpy(fbuf->fb_dat, fcnp->cn_nameptr, fcnp->cn_namelen);
1347 	fbuf->fb_dat[fcnp->cn_namelen] = '\0';
1348 	memcpy(fbuf->fb_dat + fcnp->cn_namelen + 1, tcnp->cn_nameptr,
1349 	    tcnp->cn_namelen);
1350 	fbuf->fb_dat[fcnp->cn_namelen + tcnp->cn_namelen + 1] = '\0';
1351 	fbuf->fb_io_ino = VTOI(tdvp)->i_number;
1352 
1353 	error = fb_queue(fmp->dev, fbuf);
1354 
1355 	if (error) {
1356 		if (error == ENOSYS) {
1357 			fmp->undef_op |= UNDEF_RENAME;
1358 		}
1359 
1360 		fb_delete(fbuf);
1361 		VOP_UNLOCK(fvp);
1362 		goto abortit;
1363 	}
1364 
1365 	fb_delete(fbuf);
1366 	VN_KNOTE(fvp, NOTE_RENAME);
1367 
1368 	VOP_UNLOCK(fvp);
1369 	if (tdvp == tvp)
1370 		vrele(tdvp);
1371 	else
1372 		vput(tdvp);
1373 	if (tvp)
1374 		vput(tvp);
1375 	vrele(fdvp);
1376 	vrele(fvp);
1377 
1378 	return (error);
1379 }
1380 
1381 int
fusefs_mkdir(void * v)1382 fusefs_mkdir(void *v)
1383 {
1384 	struct vop_mkdir_args *ap = v;
1385 	struct vnode *dvp = ap->a_dvp;
1386 	struct vnode **vpp = ap->a_vpp;
1387 	struct componentname *cnp = ap->a_cnp;
1388 	struct vattr *vap = ap->a_vap;
1389 	struct proc *p = cnp->cn_proc;
1390 	struct vnode *tdp = NULL;
1391 	struct fusefs_node *ip;
1392 	struct fusefs_mnt *fmp;
1393 	struct fusebuf *fbuf;
1394 	int error = 0;
1395 
1396 	ip = VTOI(dvp);
1397 	fmp = (struct fusefs_mnt *)ip->i_ump;
1398 
1399 
1400 	if (!fmp->sess_init) {
1401 		error = ENXIO;
1402 		goto out;
1403 	}
1404 
1405 	if (fmp->undef_op & UNDEF_MKDIR) {
1406 		error = ENOSYS;
1407 		goto out;
1408 	}
1409 
1410 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number,
1411 	    FBT_MKDIR, p);
1412 
1413 	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1414 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1415 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1416 
1417 	error = fb_queue(fmp->dev, fbuf);
1418 	if (error) {
1419 		if (error == ENOSYS)
1420 			fmp->undef_op |= UNDEF_MKDIR;
1421 
1422 		fb_delete(fbuf);
1423 		goto out;
1424 	}
1425 
1426 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
1427 		fb_delete(fbuf);
1428 		goto out;
1429 	}
1430 
1431 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
1432 
1433 	*vpp = tdp;
1434 	VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
1435 	fb_delete(fbuf);
1436 out:
1437 	pool_put(&namei_pool, cnp->cn_pnbuf);
1438 	vput(dvp);
1439 	return (error);
1440 }
1441 
1442 int
fusefs_rmdir(void * v)1443 fusefs_rmdir(void *v)
1444 {
1445 	struct vop_rmdir_args *ap = v;
1446 	struct vnode *vp = ap->a_vp;
1447 	struct vnode *dvp = ap->a_dvp;
1448 	struct componentname *cnp = ap->a_cnp;
1449 	struct proc *p = cnp->cn_proc;
1450 	struct fusefs_node *ip, *dp;
1451 	struct fusefs_mnt *fmp;
1452 	struct fusebuf *fbuf;
1453 	int error;
1454 
1455 	ip = VTOI(vp);
1456 	dp = VTOI(dvp);
1457 	fmp = (struct fusefs_mnt *)ip->i_ump;
1458 
1459 	if (!fmp->sess_init) {
1460 		error = ENXIO;
1461 		goto out;
1462 	}
1463 
1464 	if (fmp->undef_op & UNDEF_RMDIR) {
1465 		error = ENOSYS;
1466 		goto out;
1467 	}
1468 
1469 	VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1470 
1471 	fbuf = fb_setup(cnp->cn_namelen + 1, dp->i_number,
1472 	    FBT_RMDIR, p);
1473 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1474 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1475 
1476 	error = fb_queue(fmp->dev, fbuf);
1477 
1478 	if (error) {
1479 		if (error == ENOSYS)
1480 			fmp->undef_op |= UNDEF_RMDIR;
1481 		if (error != ENOTEMPTY)
1482 			VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1483 
1484 		fb_delete(fbuf);
1485 		goto out;
1486 	}
1487 
1488 	vput(dvp);
1489 	dvp = NULL;
1490 
1491 	fb_delete(fbuf);
1492 out:
1493 	if (dvp)
1494 		vput(dvp);
1495 	VN_KNOTE(vp, NOTE_DELETE);
1496 	pool_put(&namei_pool, cnp->cn_pnbuf);
1497 	vput(vp);
1498 	return (error);
1499 }
1500 
1501 int
fusefs_remove(void * v)1502 fusefs_remove(void *v)
1503 {
1504 	struct vop_remove_args *ap = v;
1505 	struct vnode *vp = ap->a_vp;
1506 	struct vnode *dvp = ap->a_dvp;
1507 	struct componentname *cnp = ap->a_cnp;
1508 	struct proc *p = cnp->cn_proc;
1509 	struct fusefs_node *ip;
1510 	struct fusefs_node *dp;
1511 	struct fusefs_mnt *fmp;
1512 	struct fusebuf *fbuf;
1513 	int error = 0;
1514 
1515 	ip = VTOI(vp);
1516 	dp = VTOI(dvp);
1517 	fmp = (struct fusefs_mnt *)ip->i_ump;
1518 
1519 	if (!fmp->sess_init) {
1520 		error = ENXIO;
1521 		goto out;
1522 	}
1523 
1524 	if (fmp->undef_op & UNDEF_REMOVE) {
1525 		error = ENOSYS;
1526 		goto out;
1527 	}
1528 
1529 	fbuf = fb_setup(cnp->cn_namelen + 1, dp->i_number,
1530 	    FBT_UNLINK, p);
1531 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1532 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1533 
1534 	error = fb_queue(fmp->dev, fbuf);
1535 	if (error) {
1536 		if (error == ENOSYS)
1537 			fmp->undef_op |= UNDEF_REMOVE;
1538 
1539 		fb_delete(fbuf);
1540 		goto out;
1541 	}
1542 
1543 	VN_KNOTE(vp, NOTE_DELETE);
1544 	VN_KNOTE(dvp, NOTE_WRITE);
1545 	fb_delete(fbuf);
1546 out:
1547 	pool_put(&namei_pool, cnp->cn_pnbuf);
1548 	return (error);
1549 }
1550 
1551 int
fusefs_strategy(void * v)1552 fusefs_strategy(void *v)
1553 {
1554 	return (0);
1555 }
1556 
1557 int
fusefs_lock(void * v)1558 fusefs_lock(void *v)
1559 {
1560 	struct vop_lock_args *ap = v;
1561 	struct vnode *vp = ap->a_vp;
1562 
1563 	return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
1564 }
1565 
1566 int
fusefs_unlock(void * v)1567 fusefs_unlock(void *v)
1568 {
1569 	struct vop_unlock_args *ap = v;
1570 	struct vnode *vp = ap->a_vp;
1571 
1572 	rrw_exit(&VTOI(vp)->i_lock);
1573 	return 0;
1574 }
1575 
1576 int
fusefs_islocked(void * v)1577 fusefs_islocked(void *v)
1578 {
1579 	struct vop_islocked_args *ap = v;
1580 
1581 	return rrw_status(&VTOI(ap->a_vp)->i_lock);
1582 }
1583 
1584 int
fusefs_advlock(void * v)1585 fusefs_advlock(void *v)
1586 {
1587 	struct vop_advlock_args *ap = v;
1588 	struct fusefs_node *ip = VTOI(ap->a_vp);
1589 
1590 	return (lf_advlock(&ip->i_lockf, ip->filesize, ap->a_id,
1591 	    ap->a_op, ap->a_fl, ap->a_flags));
1592 }
1593 
1594 int
fusefs_fsync(void * v)1595 fusefs_fsync(void *v)
1596 {
1597 	struct vop_fsync_args *ap = v;
1598 	struct vnode *vp = ap->a_vp;
1599 	struct proc *p = ap->a_p;
1600 	struct fusefs_node *ip;
1601 	struct fusefs_mnt *fmp;
1602 	struct fusefs_filehandle *fufh;
1603 	struct fusebuf *fbuf;
1604 	int type, error = 0;
1605 
1606 	/*
1607 	 * Can't write to directory file handles so no need to fsync.
1608 	 * FUSE has fsyncdir but it doesn't make sense on OpenBSD.
1609 	 */
1610 	if (vp->v_type == VDIR)
1611 		return (0);
1612 
1613 	ip = VTOI(vp);
1614 	fmp = (struct fusefs_mnt *)ip->i_ump;
1615 
1616 	if (!fmp->sess_init)
1617 		return (ENXIO);
1618 
1619 	/* Implementing fsync is optional so don't error. */
1620 	if (fmp->undef_op & UNDEF_FSYNC)
1621 		return (0);
1622 
1623 	/* Sync all writeable file descriptors. */
1624 	for (type = 0; type < FUFH_MAXTYPE; type++) {
1625 		fufh = &(ip->fufh[type]);
1626 		if (fufh->fh_type == FUFH_WRONLY ||
1627 		    fufh->fh_type == FUFH_RDWR) {
1628 
1629 			fbuf = fb_setup(0, ip->i_number, FBT_FSYNC, p);
1630 			fbuf->fb_io_fd = fufh->fh_id;
1631 
1632 			/* Always behave as if ap->a_waitfor = MNT_WAIT. */
1633 			error = fb_queue(fmp->dev, fbuf);
1634 			fb_delete(fbuf);
1635 			if (error)
1636 				break;
1637 		}
1638 	}
1639 
1640 	if (error == ENOSYS) {
1641 		fmp->undef_op |= UNDEF_FSYNC;
1642 
1643 		/* Implementing fsync is optional so don't error. */
1644 		return (0);
1645 	}
1646 
1647 	return (error);
1648 }
1649