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