GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libfuse/fuse_ops.c Lines: 0 600 0.0 %
Date: 2017-11-13 Branches: 0 371 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: fuse_ops.c,v 1.26 2016/09/07 17:53:35 natano Exp $ */
2
/*
3
 * Copyright (c) 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 <errno.h>
19
#include <string.h>
20
#include <stdlib.h>
21
22
#include "fuse_private.h"
23
#include "debug.h"
24
25
#define CHECK_OPT(opname)	DPRINTF("Opcode:\t%s\n", #opname);	\
26
				DPRINTF("Inode:\t%llu\n",		\
27
				    (unsigned long long)fbuf->fb_ino);	\
28
				if (!f->op.opname) {			\
29
					fbuf->fb_err = -ENOSYS;		\
30
					return (0);			\
31
				}
32
33
static int
34
update_attr(struct fuse *f, struct stat *attr, const char *realname,
35
    struct fuse_vnode *vn)
36
{
37
	int ret;
38
39
	memset(attr, 0, sizeof(struct stat));
40
	ret = f->op.getattr(realname, attr);
41
42
	if (attr->st_blksize == 0)
43
		attr->st_blksize = 512;
44
	if (attr->st_blocks == 0)
45
		attr->st_blocks = 4;
46
47
	attr->st_ino = vn->ino;
48
49
	if (f->conf.set_mode)
50
		attr->st_mode = (attr->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
51
52
	if (f->conf.set_uid)
53
		attr->st_uid = f->conf.uid;
54
55
	if (f->conf.set_gid)
56
		attr->st_gid = f->conf.gid;
57
58
	return (ret);
59
}
60
61
static int
62
ifuse_ops_init(struct fuse *f)
63
{
64
	struct fuse_conn_info fci;
65
66
	DPRINTF("Opcode:\tinit\n");
67
68
	if (f->op.init) {
69
		bzero(&fci, sizeof fci);
70
		fci.proto_minor = FUSE_MINOR_VERSION;
71
		fci.proto_major = FUSE_MAJOR_VERSION;
72
73
		f->op.init(&fci);
74
	}
75
	return (0);
76
}
77
78
static int
79
ifuse_ops_getattr(struct fuse *f, struct fusebuf *fbuf)
80
{
81
	struct fuse_vnode *vn;
82
	char *realname;
83
84
	DPRINTF("Opcode:\tgetattr\n");
85
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
86
87
	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
88
89
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
90
	if (vn == NULL) {
91
		fbuf->fb_err = -errno;
92
		return (0);
93
	}
94
95
	realname = build_realname(f, vn->ino);
96
	if (realname == NULL) {
97
		fbuf->fb_err = -errno;
98
		return (0);
99
	}
100
101
	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
102
	free(realname);
103
104
	return (0);
105
}
106
107
static int
108
ifuse_ops_access(struct fuse *f, struct fusebuf *fbuf)
109
{
110
	struct fuse_vnode *vn;
111
	char *realname;
112
113
	CHECK_OPT(access);
114
115
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
116
	if (vn == NULL) {
117
		fbuf->fb_err = -errno;
118
		return (0);
119
	}
120
121
	realname = build_realname(f, vn->ino);
122
	if (realname == NULL) {
123
		fbuf->fb_err = -errno;
124
		return (0);
125
	}
126
127
	fbuf->fb_err = f->op.access(realname, fbuf->fb_io_mode);
128
	free(realname);
129
130
	return (0);
131
}
132
133
static int
134
ifuse_ops_open(struct fuse *f, struct fusebuf *fbuf)
135
{
136
	struct fuse_file_info ffi;
137
	struct fuse_vnode *vn;
138
	char *realname;
139
140
	CHECK_OPT(open);
141
142
	bzero(&ffi, sizeof(ffi));
143
	ffi.flags = fbuf->fb_io_flags;
144
145
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
146
	if (vn == NULL) {
147
		fbuf->fb_err = -errno;
148
		return (0);
149
	}
150
151
	realname = build_realname(f, vn->ino);
152
	if (realname == NULL) {
153
		fbuf->fb_err = -errno;
154
		return (0);
155
	}
156
157
	fbuf->fb_err = f->op.open(realname, &ffi);
158
	free(realname);
159
160
	if (!fbuf->fb_err)
161
		fbuf->fb_io_fd = ffi.fh;
162
163
	return (0);
164
}
165
166
static int
167
ifuse_ops_opendir(struct fuse *f, struct fusebuf *fbuf)
168
{
169
	struct fuse_file_info ffi;
170
	struct fuse_vnode *vn;
171
	char *realname;
172
173
	DPRINTF("Opcode:\topendir\n");
174
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
175
176
	memset(&ffi, 0, sizeof(ffi));
177
	ffi.flags = fbuf->fb_io_flags;
178
179
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
180
	if (vn == NULL) {
181
		fbuf->fb_err = -errno;
182
		return (0);
183
	}
184
185
	if (f->op.opendir) {
186
		realname = build_realname(f, vn->ino);
187
		if (realname == NULL) {
188
			fbuf->fb_err = -errno;
189
			return (0);
190
		}
191
192
		fbuf->fb_err = f->op.opendir(realname, &ffi);
193
		free(realname);
194
	}
195
196
	if (!fbuf->fb_err) {
197
		fbuf->fb_io_fd = ffi.fh;
198
199
		vn->fd = calloc(1, sizeof(*vn->fd));
200
		if (vn->fd == NULL) {
201
			fbuf->fb_err = -errno;
202
			return (0);
203
		}
204
205
		vn->fd->filled = 0;
206
		vn->fd->size = 0;
207
		vn->fd->start = 0;
208
	}
209
210
	return (0);
211
}
212
213
#define GENERIC_DIRSIZ(NLEN) \
214
((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((NLEN+1 + 7) &~ 7))
215
216
static int
217
ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf,
218
    off_t off)
219
{
220
	struct fuse_dirhandle *fd = dh;
221
	struct fusebuf *fbuf;
222
	struct dirent *dir;
223
	uint32_t namelen;
224
	uint32_t len;
225
226
	fbuf = fd->buf;
227
	namelen = strnlen(name, MAXNAMLEN);
228
	len = GENERIC_DIRSIZ(namelen);
229
230
	if (fd->full || (fbuf->fb_len + len > fd->size)) {
231
		fd->full = 1;
232
		return (0);
233
	}
234
235
	if (fd->start != 0 &&  fd->idx < fd->start) {
236
		fd->idx += len;
237
		return (0);
238
	}
239
240
	dir = (struct dirent *) &fbuf->fb_dat[fbuf->fb_len];
241
242
	if (off)
243
		fd->filled = 0;
244
245
	if (stbuf) {
246
		dir->d_fileno = stbuf->st_ino;
247
		dir->d_type = IFTODT(stbuf->st_mode);
248
	} else {
249
		dir->d_fileno = 0xffffffff;
250
		dir->d_type = DT_UNKNOWN;
251
	}
252
	dir->d_reclen = len;
253
	dir->d_off = off + len;		/* XXX */
254
	strlcpy(dir->d_name, name, sizeof(dir->d_name));
255
	dir->d_namlen = strlen(dir->d_name);
256
257
	fbuf->fb_len += len;
258
	fd->start += len;
259
	fd->idx += len;
260
261
	return (0);
262
}
263
264
static int
265
ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino)
266
{
267
	struct stat st;
268
269
	bzero(&st, sizeof(st));
270
	st.st_mode = type << 12;
271
	if (ino == 0)
272
		st.st_ino = 0xffffffff;
273
	else
274
		st.st_ino = ino;
275
276
	return (fd->filler(fd, name, &st, 0));
277
}
278
279
static int
280
ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf)
281
{
282
	struct fuse_file_info ffi;
283
	struct fuse_vnode *vn;
284
	char *realname;
285
	uint64_t offset;
286
	uint32_t size;
287
	uint32_t startsave;
288
289
	DPRINTF("Opcode:\treaddir\n");
290
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
291
	DPRINTF("Offset:\t%llu\n", fbuf->fb_io_off);
292
	DPRINTF("Size:\t%lu\n", fbuf->fb_io_len);
293
294
	bzero(&ffi, sizeof(ffi));
295
	ffi.fh = fbuf->fb_io_fd;
296
	offset = fbuf->fb_io_off;
297
	size = fbuf->fb_io_len;
298
	startsave = 0;
299
300
	fbuf->fb_dat = calloc(1, size);
301
302
	if (fbuf->fb_dat == NULL) {
303
		fbuf->fb_err = -errno;
304
		return (0);
305
	}
306
307
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
308
	if (vn == NULL) {
309
		fbuf->fb_err = -errno;
310
		free(fbuf->fb_dat);
311
		return (0);
312
	}
313
314
	if (!vn->fd->filled) {
315
		vn->fd->filler = ifuse_fill_readdir;
316
		vn->fd->buf = fbuf;
317
		vn->fd->filled = 0;
318
		vn->fd->full = 0;
319
		vn->fd->size = size;
320
		vn->fd->off = offset;
321
		vn->fd->idx = 0;
322
		startsave = vn->fd->start;
323
324
		realname = build_realname(f, vn->ino);
325
		if (realname == NULL) {
326
			fbuf->fb_err = -errno;
327
			free(fbuf->fb_dat);
328
			return (0);
329
		}
330
331
		if (f->op.readdir)
332
			fbuf->fb_err = f->op.readdir(realname, vn->fd,
333
			    ifuse_fill_readdir, offset, &ffi);
334
		else if (f->op.getdir)
335
			fbuf->fb_err = f->op.getdir(realname, vn->fd,
336
			    ifuse_fill_getdir);
337
		else
338
			fbuf->fb_err = -ENOSYS;
339
		free(realname);
340
	}
341
342
	if (!vn->fd->full && vn->fd->start == startsave)
343
		vn->fd->filled = 1;
344
345
	if (fbuf->fb_err) {
346
		fbuf->fb_len = 0;
347
		vn->fd->filled = 1;
348
	}
349
350
	if (fbuf->fb_len == 0)
351
		free(fbuf->fb_dat);
352
353
	return (0);
354
}
355
356
static int
357
ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf)
358
{
359
	struct fuse_file_info ffi;
360
	struct fuse_vnode *vn;
361
	char *realname;
362
363
	DPRINTF("Opcode:\treleasedir\n");
364
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
365
366
	bzero(&ffi, sizeof(ffi));
367
	ffi.fh = fbuf->fb_io_fd;
368
	ffi.fh_old = ffi.fh;
369
	ffi.flags = fbuf->fb_io_flags;
370
371
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
372
	if (vn == NULL) {
373
		fbuf->fb_err = -errno;
374
		return (0);
375
	}
376
377
	if (f->op.releasedir) {
378
		realname = build_realname(f, vn->ino);
379
		if (realname == NULL) {
380
			fbuf->fb_err = -errno;
381
			return (0);
382
		}
383
384
		fbuf->fb_err = f->op.releasedir(realname, &ffi);
385
		free(realname);
386
	}
387
388
	if (!fbuf->fb_err)
389
		free(vn->fd);
390
391
	return (0);
392
}
393
394
static int
395
ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
396
{
397
	struct fuse_file_info ffi;
398
	struct fuse_vnode *vn;
399
	char *realname;
400
401
	CHECK_OPT(release);
402
403
	bzero(&ffi, sizeof(ffi));
404
	ffi.fh = fbuf->fb_io_fd;
405
	ffi.fh_old = ffi.fh;
406
	ffi.flags = fbuf->fb_io_flags;
407
408
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
409
	if (vn == NULL) {
410
		fbuf->fb_err = -errno;
411
		return (0);
412
	}
413
414
	realname = build_realname(f, vn->ino);
415
	if (realname == NULL) {
416
		fbuf->fb_err = -errno;
417
		return (0);
418
	}
419
	fbuf->fb_err = f->op.release(realname, &ffi);
420
	free(realname);
421
422
	return (0);
423
}
424
425
static int
426
ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
427
{
428
	struct fuse_vnode *vn;
429
	char *realname;
430
431
	DPRINTF("Opcode:\tlookup\n");
432
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
433
	DPRINTF("For file %s\n", fbuf->fb_dat);
434
435
	if (strcmp((const char *)fbuf->fb_dat, "..") == 0) {
436
		vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
437
		if (vn == NULL || vn->parent == NULL) {
438
			fbuf->fb_err = -ENOENT;
439
			return (0);
440
		}
441
		vn = vn->parent;
442
		if (vn->ino != FUSE_ROOT_INO)
443
			ref_vn(vn);
444
	} else {
445
		vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
446
		if (vn == NULL) {
447
			vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1,
448
			    fbuf->fb_ino);
449
			if (vn == NULL) {
450
				fbuf->fb_err = -errno;
451
				free(fbuf->fb_dat);
452
				return (0);
453
			}
454
			set_vn(f, vn); /*XXX*/
455
		} else if (vn->ino != FUSE_ROOT_INO)
456
			ref_vn(vn);
457
	}
458
459
	DPRINTF("new ino %llu\n", (unsigned long long)vn->ino);
460
	realname = build_realname(f, vn->ino);
461
	if (realname == NULL) {
462
		fbuf->fb_err = -errno;
463
		free(fbuf->fb_dat);
464
		return (0);
465
	}
466
467
	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
468
	free(fbuf->fb_dat);
469
	free(realname);
470
471
	return (0);
472
}
473
474
static int
475
ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
476
{
477
	struct fuse_file_info ffi;
478
	struct fuse_vnode *vn;
479
	char *realname;
480
	uint64_t offset;
481
	uint32_t size;
482
	int ret;
483
484
	CHECK_OPT(read);
485
486
	bzero(&ffi, sizeof(ffi));
487
	ffi.fh = fbuf->fb_io_fd;
488
	size = fbuf->fb_io_len;
489
	offset = fbuf->fb_io_off;
490
491
	fbuf->fb_dat = malloc(size);
492
	if (fbuf->fb_dat == NULL) {
493
		fbuf->fb_err = -errno;
494
		return (0);
495
	}
496
497
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
498
	if (vn == NULL) {
499
		fbuf->fb_err = -errno;
500
		free(fbuf->fb_dat);
501
		return (0);
502
	}
503
504
	realname = build_realname(f, vn->ino);
505
	if (realname == NULL) {
506
		fbuf->fb_err = -errno;
507
		free(fbuf->fb_dat);
508
		return (0);
509
	}
510
511
	ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
512
	free(realname);
513
	if (ret >= 0)
514
		fbuf->fb_len = ret;
515
	else
516
		fbuf->fb_err = ret;
517
518
	if (fbuf->fb_len == 0)
519
		free(fbuf->fb_dat);
520
521
	return (0);
522
}
523
524
static int
525
ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
526
{
527
	struct fuse_file_info ffi;
528
	struct fuse_vnode *vn;
529
	char *realname;
530
	uint64_t offset;
531
	uint32_t size;
532
	int ret;
533
534
	CHECK_OPT(write);
535
536
	bzero(&ffi, sizeof(ffi));
537
	ffi.fh = fbuf->fb_io_fd;
538
	ffi.fh_old = ffi.fh;
539
	ffi.writepage = fbuf->fb_io_flags & 1;
540
	size = fbuf->fb_io_len;
541
	offset = fbuf->fb_io_off;
542
543
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
544
	if (vn == NULL) {
545
		fbuf->fb_err = -errno;
546
		free(fbuf->fb_dat);
547
		return (0);
548
	}
549
550
	realname = build_realname(f, vn->ino);
551
	if (realname == NULL) {
552
		fbuf->fb_err = -errno;
553
		free(fbuf->fb_dat);
554
		return (0);
555
	}
556
557
	ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
558
	free(realname);
559
	free(fbuf->fb_dat);
560
561
	if (ret >= 0)
562
		fbuf->fb_io_len = ret;
563
	else
564
		fbuf->fb_err = ret;
565
566
	return (0);
567
}
568
569
static int
570
ifuse_ops_create(struct fuse *f, struct fusebuf *fbuf)
571
{
572
	struct fuse_file_info ffi;
573
	struct fuse_vnode *vn;
574
	uint32_t mode;
575
576
	char *realname;
577
578
	DPRINTF("Opcode:\tcreate\n");
579
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
580
581
	bzero(&ffi, sizeof(ffi));
582
	ffi.flags = fbuf->fb_io_flags;
583
	mode = fbuf->fb_io_mode;
584
585
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
586
	if (vn == NULL) {
587
		fbuf->fb_err = -errno;
588
		free(fbuf->fb_dat);
589
		return (0);
590
	}
591
592
	free(fbuf->fb_dat);
593
	realname = build_realname(f, vn->ino);
594
	if (realname == NULL) {
595
		fbuf->fb_err = -errno;
596
		return (0);
597
	}
598
599
	if (f->op.create)
600
		fbuf->fb_err = f->op.create(realname, mode,  &ffi);
601
	else if (f->op.mknod)
602
		fbuf->fb_err = f->op.mknod(realname, S_IFREG | mode, 0);
603
	else
604
		fbuf->fb_err = -ENOSYS;
605
606
	if (!fbuf->fb_err) {
607
		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
608
		fbuf->fb_ino = fbuf->fb_attr.st_ino;
609
		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
610
	}
611
	free(realname);
612
613
	return (0);
614
}
615
616
static int
617
ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
618
{
619
	struct fuse_vnode *vn;
620
	char *realname;
621
	uint32_t mode;
622
623
	CHECK_OPT(mkdir);
624
625
	mode = fbuf->fb_io_mode;
626
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
627
	if (vn == NULL) {
628
		fbuf->fb_err = -errno;
629
		free(fbuf->fb_dat);
630
		return (0);
631
	}
632
633
	free(fbuf->fb_dat);
634
	realname = build_realname(f, vn->ino);
635
	if (realname == NULL) {
636
		fbuf->fb_err = -errno;
637
		return (0);
638
	}
639
640
	fbuf->fb_err = f->op.mkdir(realname, mode);
641
642
	if (!fbuf->fb_err) {
643
		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
644
		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
645
		fbuf->fb_ino = vn->ino;
646
	}
647
	free(realname);
648
649
	return (0);
650
}
651
652
static int
653
ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
654
{
655
	struct fuse_vnode *vn;
656
	char *realname;
657
658
	CHECK_OPT(rmdir);
659
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
660
	if (vn == NULL) {
661
		fbuf->fb_err = -errno;
662
		free(fbuf->fb_dat);
663
		return (0);
664
	}
665
666
	free(fbuf->fb_dat);
667
	realname = build_realname(f, vn->ino);
668
	if (realname == NULL) {
669
		fbuf->fb_err = -errno;
670
		return (0);
671
	}
672
673
	fbuf->fb_err = f->op.rmdir(realname);
674
	free(realname);
675
676
	return (0);
677
}
678
679
static int
680
ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
681
{
682
	struct fuse_vnode *vn;
683
	char *realname;
684
	char name[PATH_MAX + 1];
685
	int len, ret;
686
687
	DPRINTF("Opcode:\treadlink\n");
688
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
689
690
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
691
	if (vn == NULL) {
692
		fbuf->fb_err = -errno;
693
		return (0);
694
	}
695
696
	realname = build_realname(f, vn->ino);
697
	if (realname == NULL) {
698
		fbuf->fb_err = -errno;
699
		return (0);
700
	}
701
702
	if (f->op.readlink)
703
		ret = f->op.readlink(realname, name, sizeof(name));
704
	else
705
		ret = -ENOSYS;
706
	free(realname);
707
708
	fbuf->fb_err = ret;
709
	if (!ret) {
710
		len = strnlen(name, PATH_MAX);
711
		fbuf->fb_len = len;
712
		fbuf->fb_dat = malloc(fbuf->fb_len);
713
		if (fbuf->fb_dat == NULL) {
714
			fbuf->fb_err = -errno;
715
			return (0);
716
		}
717
		memcpy(fbuf->fb_dat, name, len);
718
	} else
719
		fbuf->fb_len = 0;
720
721
	return (0);
722
}
723
724
static int
725
ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
726
{
727
	struct fuse_vnode *vn;
728
	char *realname;
729
730
	CHECK_OPT(unlink);
731
732
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
733
	if (vn == NULL) {
734
		free(fbuf->fb_dat);
735
		fbuf->fb_err = -errno;
736
		return (0);
737
	}
738
739
	free(fbuf->fb_dat);
740
	realname = build_realname(f, vn->ino);
741
	if (realname == NULL) {
742
		fbuf->fb_err = -errno;
743
		return (0);
744
	}
745
746
	fbuf->fb_err = f->op.unlink(realname);
747
	free(realname);
748
749
	return (0);
750
}
751
752
static int
753
ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
754
{
755
	struct fuse_vnode *vn;
756
	char *realname;
757
758
	bzero(&fbuf->fb_stat, sizeof(fbuf->fb_stat));
759
760
	CHECK_OPT(statfs);
761
762
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
763
	if (vn == NULL) {
764
		fbuf->fb_err = -errno;
765
		return (0);
766
	}
767
768
	realname = build_realname(f, vn->ino);
769
	if (realname == NULL) {
770
		fbuf->fb_err = -errno;
771
		return (0);
772
	}
773
774
	fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
775
	free(realname);
776
777
	return (0);
778
}
779
780
static int
781
ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
782
{
783
	struct fuse_vnode *vn;
784
	char *realname;
785
	char *realname_ln;
786
	ino_t oldnodeid;
787
788
	CHECK_OPT(link);
789
	oldnodeid = fbuf->fb_io_ino;
790
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
791
	if (vn == NULL) {
792
		fbuf->fb_err = -errno;
793
		free(fbuf->fb_dat);
794
		return (0);
795
	}
796
797
	free(fbuf->fb_dat);
798
	realname = build_realname(f, oldnodeid);
799
	if (realname == NULL) {
800
		fbuf->fb_err = -errno;
801
		return (0);
802
	}
803
804
	realname_ln = build_realname(f, vn->ino);
805
	if (realname_ln == NULL) {
806
		fbuf->fb_err = -errno;
807
		free(realname);
808
		return (0);
809
	}
810
811
	fbuf->fb_err = f->op.link(realname, realname_ln);
812
	free(realname);
813
	free(realname_ln);
814
815
	return (0);
816
}
817
818
static int
819
ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
820
{
821
	struct fuse_vnode *vn;
822
	struct timespec ts[2];
823
	struct utimbuf tbuf;
824
	struct fb_io *io;
825
	char *realname;
826
	uid_t uid;
827
	gid_t gid;
828
829
	DPRINTF("Opcode:\tsetattr\n");
830
	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
831
832
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
833
	if (vn == NULL) {
834
		fbuf->fb_err = -errno;
835
		free(fbuf->fb_dat);
836
		return (0);
837
	}
838
839
	realname = build_realname(f, vn->ino);
840
	if (realname == NULL) {
841
		fbuf->fb_err = -errno;
842
		free(fbuf->fb_dat);
843
		return (0);
844
	}
845
	io = fbtod(fbuf, struct fb_io *);
846
847
	if (io->fi_flags & FUSE_FATTR_MODE) {
848
		if (f->op.chmod)
849
			fbuf->fb_err = f->op.chmod(realname,
850
			    fbuf->fb_attr.st_mode);
851
		else
852
			fbuf->fb_err = -ENOSYS;
853
	}
854
855
	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
856
	    io->fi_flags & FUSE_FATTR_GID) ) {
857
		uid = (io->fi_flags & FUSE_FATTR_UID) ?
858
		    fbuf->fb_attr.st_uid : (gid_t)-1;
859
		gid = (io->fi_flags & FUSE_FATTR_GID) ?
860
		    fbuf->fb_attr.st_gid : (uid_t)-1;
861
		if (f->op.chown)
862
			fbuf->fb_err = f->op.chown(realname, uid, gid);
863
		else
864
			fbuf->fb_err = -ENOSYS;
865
	}
866
867
	if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
868
		io->fi_flags & FUSE_FATTR_ATIME)) {
869
		ts[0] = fbuf->fb_attr.st_atim;
870
		ts[1] = fbuf->fb_attr.st_mtim;
871
		tbuf.actime = ts[0].tv_sec;
872
		tbuf.modtime = ts[1].tv_sec;
873
874
		if (f->op.utimens)
875
			fbuf->fb_err = f->op.utimens(realname, ts);
876
		else if (f->op.utime)
877
			fbuf->fb_err = f->op.utime(realname, &tbuf);
878
		else
879
			fbuf->fb_err = -ENOSYS;
880
	}
881
882
	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) {
883
		if (f->op.truncate)
884
			fbuf->fb_err = f->op.truncate(realname,
885
			    fbuf->fb_attr.st_size);
886
		else
887
			fbuf->fb_err = -ENOSYS;
888
	}
889
890
	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
891
892
	if (!fbuf->fb_err)
893
		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
894
	free(realname);
895
	free(fbuf->fb_dat);
896
897
	return (0);
898
}
899
900
static int
901
ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
902
{
903
	struct fuse_vnode *vn;
904
	char *realname;
905
	int len;
906
907
	CHECK_OPT(symlink);
908
909
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
910
	if (vn == NULL) {
911
		fbuf->fb_err = -errno;
912
		free(fbuf->fb_dat);
913
		return (0);
914
	}
915
916
	len = strlen((char *)fbuf->fb_dat);
917
918
	realname = build_realname(f, vn->ino);
919
	if (realname == NULL) {
920
		fbuf->fb_err = -errno;
921
		free(fbuf->fb_dat);
922
		return (0);
923
	}
924
925
	/* fuse invert the symlink params */
926
	fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1],
927
	    realname);
928
	fbuf->fb_ino = vn->ino;
929
	free(fbuf->fb_dat);
930
	free(realname);
931
932
	return (0);
933
}
934
935
static int
936
ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf)
937
{
938
	struct fuse_vnode *vnt;
939
	struct fuse_vnode *vnf;
940
	char *realnamef;
941
	char *realnamet;
942
	int len;
943
944
	CHECK_OPT(rename);
945
946
	len = strlen((char *)fbuf->fb_dat);
947
	vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
948
	if (vnf == NULL) {
949
		fbuf->fb_err = -errno;
950
		free(fbuf->fb_dat);
951
		return (0);
952
	}
953
954
	vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1],
955
	    fbuf->fb_io_ino);
956
	if (vnt == NULL) {
957
		fbuf->fb_err = -errno;
958
		free(fbuf->fb_dat);
959
		return (0);
960
	}
961
962
	free(fbuf->fb_dat);
963
964
	realnamef = build_realname(f, vnf->ino);
965
	if (realnamef == NULL) {
966
		fbuf->fb_err = -errno;
967
		return (0);
968
	}
969
970
	realnamet = build_realname(f, vnt->ino);
971
	if (realnamet == NULL) {
972
		fbuf->fb_err = -errno;
973
		free(realnamef);
974
		return (0);
975
	}
976
977
	fbuf->fb_err = f->op.rename(realnamef, realnamet);
978
	free(realnamef);
979
	free(realnamet);
980
981
	return (0);
982
}
983
984
static int
985
ifuse_ops_destroy(struct fuse *f)
986
{
987
	struct fuse_context *ctx;
988
989
	DPRINTF("Opcode:\tdestroy\n");
990
991
	if (f->op.destroy) {
992
		ctx = fuse_get_context();
993
994
		f->op.destroy((ctx)?ctx->private_data:NULL);
995
	}
996
997
	f->fc->dead = 1;
998
999
	return (0);
1000
}
1001
1002
static int
1003
ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
1004
{
1005
	struct fuse_vnode *vn;
1006
1007
	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
1008
	if (vn != NULL)
1009
		unref_vn(f, vn);
1010
1011
	return (0);
1012
}
1013
1014
static int
1015
ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
1016
{
1017
	struct fuse_vnode *vn;
1018
	char *realname;
1019
	uint32_t mode;
1020
	dev_t dev;
1021
1022
	CHECK_OPT(mknod);
1023
1024
	mode = fbuf->fb_io_mode;
1025
	dev = fbuf->fb_io_rdev;
1026
	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
1027
	if (vn == NULL) {
1028
		fbuf->fb_err = -errno;
1029
		free(fbuf->fb_dat);
1030
		return (0);
1031
	}
1032
1033
	free(fbuf->fb_dat);
1034
	realname = build_realname(f, vn->ino);
1035
	if (realname == NULL) {
1036
		fbuf->fb_err = -errno;
1037
		return (0);
1038
	}
1039
1040
	fbuf->fb_err = f->op.mknod(realname, mode, dev);
1041
1042
	if (!fbuf->fb_err) {
1043
		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
1044
		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
1045
		fbuf->fb_ino = fbuf->fb_attr.st_ino;
1046
	}
1047
	free(realname);
1048
1049
	return (0);
1050
}
1051
1052
int
1053
ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
1054
{
1055
	int ret = 0;
1056
1057
	fbuf->fb_len = 0;
1058
	fbuf->fb_err = 0;
1059
1060
	switch (fbuf->fb_type) {
1061
	case FBT_LOOKUP:
1062
		ret = ifuse_ops_lookup(f, fbuf);
1063
		break;
1064
	case FBT_GETATTR:
1065
		ret = ifuse_ops_getattr(f, fbuf);
1066
		break;
1067
	case FBT_SETATTR:
1068
		ret = ifuse_ops_setattr(f, fbuf);
1069
		break;
1070
	case FBT_READLINK:
1071
		ret = ifuse_ops_readlink(f, fbuf);
1072
		break;
1073
	case FBT_MKDIR:
1074
		ret = ifuse_ops_mkdir(f, fbuf);
1075
		break;
1076
	case FBT_UNLINK:
1077
		ret = ifuse_ops_unlink(f, fbuf);
1078
		break;
1079
	case FBT_RMDIR:
1080
		ret = ifuse_ops_rmdir(f, fbuf);
1081
		break;
1082
	case FBT_LINK:
1083
		ret = ifuse_ops_link(f, fbuf);
1084
		break;
1085
	case FBT_OPEN:
1086
		ret = ifuse_ops_open(f, fbuf);
1087
		break;
1088
	case FBT_READ:
1089
		ret = ifuse_ops_read(f, fbuf);
1090
		break;
1091
	case FBT_WRITE:
1092
		ret = ifuse_ops_write(f, fbuf);
1093
		break;
1094
	case FBT_STATFS:
1095
		ret = ifuse_ops_statfs(f, fbuf);
1096
		break;
1097
	case FBT_RELEASE:
1098
		ret = ifuse_ops_release(f, fbuf);
1099
		break;
1100
	case FBT_INIT:
1101
		ret = ifuse_ops_init(f);
1102
		break;
1103
	case FBT_OPENDIR:
1104
		ret = ifuse_ops_opendir(f, fbuf);
1105
		break;
1106
	case FBT_READDIR:
1107
		ret = ifuse_ops_readdir(f, fbuf);
1108
		break;
1109
	case FBT_RELEASEDIR:
1110
		ret = ifuse_ops_releasedir(f, fbuf);
1111
		break;
1112
	case FBT_ACCESS:
1113
		ret = ifuse_ops_access(f, fbuf);
1114
		break;
1115
	case FBT_CREATE:
1116
		ret = ifuse_ops_create(f, fbuf);
1117
		break;
1118
	case FBT_SYMLINK:
1119
		ret = ifuse_ops_symlink(f, fbuf);
1120
		break;
1121
	case FBT_RENAME:
1122
		ret = ifuse_ops_rename(f, fbuf);
1123
		break;
1124
	case FBT_DESTROY:
1125
		ret = ifuse_ops_destroy(f);
1126
		break;
1127
	case FBT_RECLAIM:
1128
		ret = ifuse_ops_reclaim(f, fbuf);
1129
		break;
1130
	case FBT_MKNOD:
1131
		ret = ifuse_ops_mknod(f, fbuf);
1132
		break;
1133
	default:
1134
		DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
1135
		DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
1136
1137
		fbuf->fb_err = -ENOSYS;
1138
		fbuf->fb_len = 0;
1139
	}
1140
	DPRINTF("\n");
1141
1142
	/* fuse api use negative errno */
1143
	fbuf->fb_err = -fbuf->fb_err;
1144
	return (ret);
1145
}