puffs.c revision 1.22 1 /* $NetBSD: puffs.c,v 1.22 2007/01/10 23:02:50 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the company nor the name of the author may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #if !defined(lint)
37 __RCSID("$NetBSD: puffs.c,v 1.22 2007/01/10 23:02:50 pooka Exp $");
38 #endif /* !lint */
39
40 #include <sys/param.h>
41 #include <sys/mount.h>
42
43 #include <assert.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <mntopts.h>
48 #include <puffs.h>
49 #include <puffsdump.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <syslog.h>
55 #include <unistd.h>
56
57 #include "puffs_priv.h"
58
59 /* Most file systems want this for opts, so just give it to them */
60 const struct mntopt puffsmopts[] = {
61 MOPT_STDOPTS,
62 PUFFSMOPT_STD,
63 MOPT_NULL,
64 };
65
66 static int do_buildpath(struct puffs_cn *, void *);
67
68 #define FILLOP(lower, upper) \
69 do { \
70 if (pops->puffs_node_##lower) \
71 opmask[PUFFS_VN_##upper] = 1; \
72 } while (/*CONSTCOND*/0)
73 static void
74 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
75 {
76
77 memset(opmask, 0, PUFFS_VN_MAX);
78
79 FILLOP(create, CREATE);
80 FILLOP(mknod, MKNOD);
81 FILLOP(open, OPEN);
82 FILLOP(close, CLOSE);
83 FILLOP(access, ACCESS);
84 FILLOP(getattr, GETATTR);
85 FILLOP(setattr, SETATTR);
86 FILLOP(poll, POLL); /* XXX: not ready in kernel */
87 FILLOP(revoke, REVOKE);
88 FILLOP(mmap, MMAP);
89 FILLOP(fsync, FSYNC);
90 FILLOP(seek, SEEK);
91 FILLOP(remove, REMOVE);
92 FILLOP(link, LINK);
93 FILLOP(rename, RENAME);
94 FILLOP(mkdir, MKDIR);
95 FILLOP(rmdir, RMDIR);
96 FILLOP(symlink, SYMLINK);
97 FILLOP(readdir, READDIR);
98 FILLOP(readlink, READLINK);
99 FILLOP(reclaim, RECLAIM);
100 FILLOP(inactive, INACTIVE);
101 FILLOP(print, PRINT);
102 FILLOP(read, READ);
103 FILLOP(write, WRITE);
104
105 /* XXX: not implemented in the kernel */
106 FILLOP(getextattr, GETEXTATTR);
107 FILLOP(setextattr, SETEXTATTR);
108 FILLOP(listextattr, LISTEXTATTR);
109 }
110 #undef FILLOP
111
112 int
113 puffs_getselectable(struct puffs_usermount *pu)
114 {
115
116 return pu->pu_fd;
117 }
118
119 int
120 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
121 {
122 int x;
123
124 x = mode;
125 return ioctl(pu->pu_fd, FIONBIO, &x);
126 }
127
128 int
129 puffs_getstate(struct puffs_usermount *pu)
130 {
131
132 return pu->pu_state;
133 }
134
135 void
136 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
137 {
138
139 pu->pu_cc_stacksize = ss;
140 }
141
142 /*
143 * in case the server wants to use some other scheme for paths, it
144 * can (*must*) call this in mount.
145 */
146 int
147 puffs_setrootpath(struct puffs_usermount *pu, const char *rootpath)
148 {
149 struct puffs_node *pnr;
150
151 pnr = pu->pu_pn_root;
152 if (pnr == NULL) {
153 errno = ENOENT;
154 return -1;
155 }
156
157 free(pnr->pn_path);
158 pnr->pn_path = strdup(rootpath);
159 if (pnr->pn_path == NULL)
160 return -1;
161 pnr->pn_plen = strlen(pnr->pn_path) + 1; /* yes, count nul */
162
163 return 0;
164 }
165
166
167 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
168
169 struct puffs_usermount *
170 _puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
171 const char *puffsname, void *priv, uint32_t pflags, size_t maxreqlen)
172 {
173 struct puffs_args pargs;
174 struct puffs_usermount *pu;
175 int fd = 0;
176
177 if (develv != PUFFS_DEVEL_LIBVERSION) {
178 warnx("puffs_mount: mounting with lib version %d, need %d",
179 develv, PUFFS_DEVEL_LIBVERSION);
180 errno = EINVAL;
181 return NULL;
182 }
183
184 fd = open("/dev/puffs", O_RDONLY);
185 if (fd == -1)
186 return NULL;
187 if (fd <= 2)
188 warnx("puffs_mount: device fd %d (<= 2), sure this is "
189 "what you want?", fd);
190
191 pargs.pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
192 pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
193 pargs.pa_fd = fd;
194 pargs.pa_maxreqlen = maxreqlen;
195 fillvnopmask(pops, pargs.pa_vnopmask);
196 (void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
197
198 pu = malloc(sizeof(struct puffs_usermount));
199 if (!pu)
200 return NULL;
201
202 pu->pu_flags = pflags;
203 pu->pu_ops = *pops;
204 free(pops); /* XXX */
205 pu->pu_fd = fd;
206 pu->pu_privdata = priv;
207 pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
208 LIST_INIT(&pu->pu_pnodelst);
209
210 pu->pu_state = PUFFS_STATE_MOUNTING;
211 if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
212 goto failfree;
213 pu->pu_maxreqlen = pargs.pa_maxreqlen;
214
215 return pu;
216
217 failfree:
218 /* can't unmount() from here for obvious reasons */
219 if (fd)
220 close(fd);
221 free(pu);
222 return NULL;
223 }
224
225 int
226 puffs_start(struct puffs_usermount *pu, void *rootcookie, struct statvfs *sbp)
227 {
228 struct puffs_startreq sreq;
229
230 memset(&sreq, 0, sizeof(struct puffs_startreq));
231 sreq.psr_cookie = rootcookie;
232 sreq.psr_sb = *sbp;
233
234 /* tell kernel we're flying */
235 if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
236 return -1;
237
238 pu->pu_state = PUFFS_STATE_RUNNING;
239
240 return 0;
241 }
242
243 /*
244 * XXX: there's currently no clean way to request unmount from
245 * within the user server, so be very brutal about it.
246 */
247 /*ARGSUSED*/
248 int
249 puffs_exit(struct puffs_usermount *pu, int force)
250 {
251
252 force = 1; /* currently */
253
254 if (pu->pu_fd)
255 close(pu->pu_fd);
256
257 /* XXX: should free all contents like pnodes */
258
259 free(pu);
260
261 return 0; /* always succesful for now, WILL CHANGE */
262 }
263
264 int
265 puffs_mainloop(struct puffs_usermount *pu, int flags)
266 {
267 struct puffs_getreq *pgr;
268 struct puffs_putreq *ppr;
269 int rv;
270
271 rv = -1;
272 pgr = puffs_makegetreq(pu, pu->pu_maxreqlen, 0);
273 if (pgr == NULL)
274 return -1;
275
276 ppr = puffs_makeputreq(pu);
277 if (ppr == NULL) {
278 puffs_destroygetreq(pgr);
279 return -1;
280 }
281
282 if ((flags & PUFFSLOOP_NODAEMON) == 0)
283 if (daemon(1, 0) == -1)
284 goto out;
285
286 /* XXX: should be a bit more robust with errors here */
287 while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
288 || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
289 puffs_resetputreq(ppr);
290
291 if (puffs_handlereqs(pu, pgr, ppr, 0) == -1) {
292 rv = -1;
293 break;
294 }
295 if (puffs_putputreq(ppr) == -1) {
296 rv = -1;
297 break;
298 }
299 }
300
301 out:
302 puffs_destroyputreq(ppr);
303 puffs_destroygetreq(pgr);
304 return rv;
305 }
306
307 int
308 puffs_handlereqs(struct puffs_usermount *pu, struct puffs_getreq *pgr,
309 struct puffs_putreq *ppr, int maxops)
310 {
311 struct puffs_req *preq;
312 int pval;
313
314 puffs_setmaxgetreq(pgr, maxops);
315 if (puffs_loadgetreq(pgr) == -1)
316 return -1;
317
318 /* interlink pgr and ppr for diagnostic asserts */
319 pgr->pgr_nppr++;
320 ppr->ppr_pgr = pgr;
321
322 pval = 0;
323 while ((preq = puffs_getreq(pgr)) != NULL
324 && pu->pu_state != PUFFS_STATE_UNMOUNTED)
325 pval = puffs_dopreq(pu, ppr, preq);
326
327 return pval;
328 }
329
330 int
331 puffs_dopreq(struct puffs_usermount *pu, struct puffs_putreq *ppr,
332 struct puffs_req *preq)
333 {
334 struct puffs_cc *pcc;
335 int rv;
336
337 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
338 puffsdump_req(preq);
339
340 pcc = puffs_cc_create(pu);
341
342 /* XXX: temporary kludging */
343 pcc->pcc_preq = malloc(preq->preq_buflen);
344 if (pcc->pcc_preq == NULL)
345 return -1;
346 (void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
347
348 rv = puffs_docc(ppr, pcc);
349
350 if ((pcc->pcc_flags & PCC_DONE) == 0)
351 return 0;
352
353 return rv;
354 }
355
356 int
357 puffs_docc(struct puffs_putreq *ppr, struct puffs_cc *pcc)
358 {
359 int rv;
360
361 assert((pcc->pcc_flags & PCC_DONE) == 0);
362
363 puffs_cc_continue(pcc);
364 rv = pcc->pcc_rv;
365
366 if ((pcc->pcc_flags & PCC_DONE) == 0)
367 rv = PUFFCALL_AGAIN;
368
369 /* check if we need to store this reply */
370 switch (rv) {
371 case PUFFCALL_ANSWER:
372 puffs_putreq_cc(ppr, pcc);
373 break;
374 case PUFFCALL_IGNORE:
375 puffs_cc_destroy(pcc);
376 break;
377 case PUFFCALL_AGAIN:
378 break;
379 default:
380 assert(/*CONSTCOND*/0);
381 }
382
383 return 0;
384 }
385
386 /* library private, but linked from callcontext.c */
387
388 void
389 puffs_calldispatcher(struct puffs_cc *pcc)
390 {
391 struct puffs_usermount *pu = pcc->pcc_pu;
392 struct puffs_ops *pops = &pu->pu_ops;
393 struct puffs_req *preq = pcc->pcc_preq;
394 void *auxbuf = preq; /* help with typecasting */
395 int error, rv, buildpath;
396
397 assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
398
399 if (PUFFSOP_WANTREPLY(preq->preq_opclass))
400 rv = PUFFCALL_ANSWER;
401 else
402 rv = PUFFCALL_IGNORE;
403
404 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
405
406 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
407 switch (preq->preq_optype) {
408 case PUFFS_VFS_UNMOUNT:
409 {
410 struct puffs_vfsreq_unmount *auxt = auxbuf;
411
412 pu->pu_state = PUFFS_STATE_UNMOUNTING;
413 error = pops->puffs_fs_unmount(pcc,
414 auxt->pvfsr_flags, auxt->pvfsr_pid);
415 if (!error)
416 pu->pu_state = PUFFS_STATE_UNMOUNTED;
417 else
418 pu->pu_state = PUFFS_STATE_RUNNING;
419 break;
420 }
421 case PUFFS_VFS_STATVFS:
422 {
423 struct puffs_vfsreq_statvfs *auxt = auxbuf;
424
425 error = pops->puffs_fs_statvfs(pcc,
426 &auxt->pvfsr_sb, auxt->pvfsr_pid);
427 break;
428 }
429 case PUFFS_VFS_SYNC:
430 {
431 struct puffs_vfsreq_sync *auxt = auxbuf;
432
433 error = pops->puffs_fs_sync(pcc,
434 auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
435 auxt->pvfsr_pid);
436 break;
437 }
438 default:
439 /*
440 * I guess the kernel sees this one coming
441 */
442 error = EINVAL;
443 break;
444 }
445
446 /* XXX: audit return values */
447 /* XXX: sync with kernel */
448 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
449 switch (preq->preq_optype) {
450 case PUFFS_VN_LOOKUP:
451 {
452 struct puffs_vnreq_lookup *auxt = auxbuf;
453 struct puffs_cn pcn;
454
455 pcn.pcn_pkcnp = &auxt->pvnr_cn;
456 if (buildpath) {
457 if (pcn.pcn_flags & PUFFS_ISDOTDOT) {
458 buildpath = 0;
459 } else {
460 error = do_buildpath(&pcn,
461 preq->preq_cookie);
462 if (error)
463 break;
464 }
465 }
466
467 /* lookup *must* be present */
468 error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
469 &auxt->pvnr_newnode, &auxt->pvnr_vtype,
470 &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
471
472 if (buildpath) {
473 if (error) {
474 free(pcn.pcn_fullpath);
475 } else {
476 struct puffs_node *pn;
477
478 /*
479 * did we get a new node or a
480 * recycled node?
481 * XXX: mapping assumption
482 */
483 pn = auxt->pvnr_newnode;
484 if (pn->pn_path == NULL) {
485 pn->pn_path = pcn.pcn_fullpath;
486 pn->pn_plen
487 = pcn.pcn_fullplen;
488 }
489 }
490 }
491
492 break;
493 }
494
495 case PUFFS_VN_CREATE:
496 {
497 struct puffs_vnreq_create *auxt = auxbuf;
498 struct puffs_cn pcn;
499 if (pops->puffs_node_create == NULL) {
500 error = 0;
501 break;
502 }
503
504 pcn.pcn_pkcnp = &auxt->pvnr_cn;
505 if (buildpath) {
506 error = do_buildpath(&pcn, preq->preq_cookie);
507 if (error)
508 break;
509 }
510
511 error = pops->puffs_node_create(pcc,
512 preq->preq_cookie, &auxt->pvnr_newnode,
513 &pcn, &auxt->pvnr_va);
514
515 if (buildpath) {
516 if (error) {
517 free(pcn.pcn_fullpath);
518 } else {
519 struct puffs_node *pn;
520
521 pn = auxt->pvnr_newnode;
522 pn->pn_path = pcn.pcn_fullpath;
523 pn->pn_plen = pcn.pcn_fullplen;
524 }
525 }
526
527 break;
528 }
529
530 case PUFFS_VN_MKNOD:
531 {
532 struct puffs_vnreq_mknod *auxt = auxbuf;
533 struct puffs_cn pcn;
534 if (pops->puffs_node_mknod == NULL) {
535 error = 0;
536 break;
537 }
538
539 pcn.pcn_pkcnp = &auxt->pvnr_cn;
540 if (buildpath) {
541 error = do_buildpath(&pcn, preq->preq_cookie);
542 if (error)
543 break;
544 }
545
546 error = pops->puffs_node_mknod(pcc,
547 preq->preq_cookie, &auxt->pvnr_newnode,
548 &pcn, &auxt->pvnr_va);
549
550 if (buildpath) {
551 if (error) {
552 free(pcn.pcn_fullpath);
553 } else {
554 struct puffs_node *pn;
555
556 pn = auxt->pvnr_newnode;
557 pn->pn_path = pcn.pcn_fullpath;
558 pn->pn_plen = pcn.pcn_fullplen;
559 }
560 }
561
562 break;
563 }
564
565 case PUFFS_VN_OPEN:
566 {
567 struct puffs_vnreq_open *auxt = auxbuf;
568 if (pops->puffs_node_open == NULL) {
569 error = 0;
570 break;
571 }
572
573 error = pops->puffs_node_open(pcc,
574 preq->preq_cookie, auxt->pvnr_mode,
575 &auxt->pvnr_cred, auxt->pvnr_pid);
576 break;
577 }
578
579 case PUFFS_VN_CLOSE:
580 {
581 struct puffs_vnreq_close *auxt = auxbuf;
582 if (pops->puffs_node_close == NULL) {
583 error = 0;
584 break;
585 }
586
587 error = pops->puffs_node_close(pcc,
588 preq->preq_cookie, auxt->pvnr_fflag,
589 &auxt->pvnr_cred, auxt->pvnr_pid);
590 break;
591 }
592
593 case PUFFS_VN_ACCESS:
594 {
595 struct puffs_vnreq_access *auxt = auxbuf;
596 if (pops->puffs_node_access == NULL) {
597 error = 0;
598 break;
599 }
600
601 error = pops->puffs_node_access(pcc,
602 preq->preq_cookie, auxt->pvnr_mode,
603 &auxt->pvnr_cred, auxt->pvnr_pid);
604 break;
605 }
606
607 case PUFFS_VN_GETATTR:
608 {
609 struct puffs_vnreq_getattr *auxt = auxbuf;
610 if (pops->puffs_node_getattr == NULL) {
611 error = EOPNOTSUPP;
612 break;
613 }
614
615 error = pops->puffs_node_getattr(pcc,
616 preq->preq_cookie, &auxt->pvnr_va,
617 &auxt->pvnr_cred, auxt->pvnr_pid);
618 break;
619 }
620
621 case PUFFS_VN_SETATTR:
622 {
623 struct puffs_vnreq_setattr *auxt = auxbuf;
624 if (pops->puffs_node_setattr == NULL) {
625 error = EOPNOTSUPP;
626 break;
627 }
628
629 error = pops->puffs_node_setattr(pcc,
630 preq->preq_cookie, &auxt->pvnr_va,
631 &auxt->pvnr_cred, auxt->pvnr_pid);
632 break;
633 }
634
635 case PUFFS_VN_MMAP:
636 {
637 struct puffs_vnreq_mmap *auxt = auxbuf;
638 if (pops->puffs_node_mmap == NULL) {
639 error = 0;
640 break;
641 }
642
643 error = pops->puffs_node_mmap(pcc,
644 preq->preq_cookie, auxt->pvnr_fflags,
645 &auxt->pvnr_cred, auxt->pvnr_pid);
646 break;
647 }
648
649 case PUFFS_VN_REVOKE:
650 {
651 struct puffs_vnreq_revoke *auxt = auxbuf;
652 if (pops->puffs_node_revoke == NULL) {
653 error = 0;
654 break;
655 }
656
657 error = pops->puffs_node_revoke(pcc,
658 preq->preq_cookie, auxt->pvnr_flags);
659 break;
660 }
661
662 case PUFFS_VN_FSYNC:
663 {
664 struct puffs_vnreq_fsync *auxt = auxbuf;
665 if (pops->puffs_node_fsync == NULL) {
666 error = 0;
667 break;
668 }
669
670 error = pops->puffs_node_fsync(pcc,
671 preq->preq_cookie, &auxt->pvnr_cred,
672 auxt->pvnr_flags, auxt->pvnr_offlo,
673 auxt->pvnr_offhi, auxt->pvnr_pid);
674 break;
675 }
676
677 case PUFFS_VN_SEEK:
678 {
679 struct puffs_vnreq_seek *auxt = auxbuf;
680 if (pops->puffs_node_seek == NULL) {
681 error = 0;
682 break;
683 }
684
685 error = pops->puffs_node_seek(pcc,
686 preq->preq_cookie, auxt->pvnr_oldoff,
687 auxt->pvnr_newoff, &auxt->pvnr_cred);
688 break;
689 }
690
691 case PUFFS_VN_REMOVE:
692 {
693 struct puffs_vnreq_remove *auxt = auxbuf;
694 struct puffs_cn pcn;
695 if (pops->puffs_node_remove == NULL) {
696 error = 0;
697 break;
698 }
699
700 pcn.pcn_pkcnp = &auxt->pvnr_cn;
701
702 error = pops->puffs_node_remove(pcc,
703 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
704 break;
705 }
706
707 case PUFFS_VN_LINK:
708 {
709 struct puffs_vnreq_link *auxt = auxbuf;
710 struct puffs_cn pcn;
711 if (pops->puffs_node_link == NULL) {
712 error = 0;
713 break;
714 }
715
716 pcn.pcn_pkcnp = &auxt->pvnr_cn;
717 if (buildpath) {
718 error = do_buildpath(&pcn, preq->preq_cookie);
719 if (error)
720 break;
721 }
722
723 error = pops->puffs_node_link(pcc,
724 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
725 if (buildpath)
726 free(pcn.pcn_fullpath);
727
728 break;
729 }
730
731 case PUFFS_VN_RENAME:
732 {
733 struct puffs_vnreq_rename *auxt = auxbuf;
734 struct puffs_cn pcn_src, pcn_targ;
735 struct puffs_node *pn_src;
736
737 if (pops->puffs_node_rename == NULL) {
738 error = 0;
739 break;
740 }
741
742 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
743 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
744 if (buildpath) {
745 pn_src = auxt->pvnr_cookie_src;
746 pcn_src.pcn_fullpath = pn_src->pn_path;
747 pcn_src.pcn_fullplen = pn_src->pn_plen;
748
749 error = do_buildpath(&pcn_targ,
750 auxt->pvnr_cookie_targdir);
751 if (error)
752 break;
753 }
754
755 error = pops->puffs_node_rename(pcc,
756 preq->preq_cookie, auxt->pvnr_cookie_src,
757 &pcn_src, auxt->pvnr_cookie_targdir,
758 auxt->pvnr_cookie_targ, &pcn_targ);
759
760 if (buildpath) {
761 if (error) {
762 free(pcn_targ.pcn_fullpath);
763 } else {
764 free(pn_src->pn_path);
765 pn_src->pn_path = pcn_targ.pcn_fullpath;
766 pn_src->pn_plen = pcn_targ.pcn_fullplen;
767 }
768 }
769 break;
770 }
771
772 case PUFFS_VN_MKDIR:
773 {
774 struct puffs_vnreq_mkdir *auxt = auxbuf;
775 struct puffs_cn pcn;
776 if (pops->puffs_node_mkdir == NULL) {
777 error = 0;
778 break;
779 }
780
781 pcn.pcn_pkcnp = &auxt->pvnr_cn;
782 if (buildpath) {
783 error = do_buildpath(&pcn, preq->preq_cookie);
784 if (error)
785 break;
786 }
787
788 error = pops->puffs_node_mkdir(pcc,
789 preq->preq_cookie, &auxt->pvnr_newnode,
790 &pcn, &auxt->pvnr_va);
791
792 if (buildpath) {
793 if (error) {
794 free(pcn.pcn_fullpath);
795 } else {
796 struct puffs_node *pn;
797
798 pn = auxt->pvnr_newnode;
799 pn->pn_path = pcn.pcn_fullpath;
800 pn->pn_plen = pcn.pcn_fullplen;
801 }
802 }
803
804 break;
805 }
806
807 case PUFFS_VN_RMDIR:
808 {
809 struct puffs_vnreq_rmdir *auxt = auxbuf;
810 struct puffs_cn pcn;
811 if (pops->puffs_node_rmdir == NULL) {
812 error = 0;
813 break;
814 }
815
816 pcn.pcn_pkcnp = &auxt->pvnr_cn;
817
818 error = pops->puffs_node_rmdir(pcc,
819 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
820 break;
821 }
822
823 case PUFFS_VN_SYMLINK:
824 {
825 struct puffs_vnreq_symlink *auxt = auxbuf;
826 struct puffs_cn pcn;
827 if (pops->puffs_node_symlink == NULL) {
828 error = 0;
829 break;
830 }
831
832 pcn.pcn_pkcnp = &auxt->pvnr_cn;
833 if (buildpath) {
834 error = do_buildpath(&pcn, preq->preq_cookie);
835 if (error)
836 break;
837 }
838
839 error = pops->puffs_node_symlink(pcc,
840 preq->preq_cookie, &auxt->pvnr_newnode,
841 &pcn, &auxt->pvnr_va, auxt->pvnr_link);
842
843 if (buildpath) {
844 if (error) {
845 free(pcn.pcn_fullpath);
846 } else {
847 struct puffs_node *pn;
848
849 pn = auxt->pvnr_newnode;
850 pn->pn_path = pcn.pcn_fullpath;
851 pn->pn_plen = pcn.pcn_fullplen;
852 }
853 }
854
855 break;
856 }
857
858 case PUFFS_VN_READDIR:
859 {
860 struct puffs_vnreq_readdir *auxt = auxbuf;
861 size_t res;
862
863 if (pops->puffs_node_readdir == NULL) {
864 error = 0;
865 break;
866 }
867
868 res = auxt->pvnr_resid;
869 error = pops->puffs_node_readdir(pcc,
870 preq->preq_cookie, auxt->pvnr_dent,
871 &auxt->pvnr_cred, &auxt->pvnr_offset,
872 &auxt->pvnr_resid);
873
874 /* need to move a bit more */
875 preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
876 + (res - auxt->pvnr_resid);
877 break;
878 }
879
880 case PUFFS_VN_READLINK:
881 {
882 struct puffs_vnreq_readlink *auxt = auxbuf;
883 if (pops->puffs_node_readlink == NULL) {
884 error = EOPNOTSUPP;
885 break;
886 }
887
888 error = pops->puffs_node_readlink(pcc,
889 preq->preq_cookie, &auxt->pvnr_cred,
890 auxt->pvnr_link, &auxt->pvnr_linklen);
891 break;
892 }
893
894 case PUFFS_VN_RECLAIM:
895 {
896 struct puffs_vnreq_reclaim *auxt = auxbuf;
897 if (pops->puffs_node_reclaim == NULL) {
898 error = 0;
899 break;
900 }
901
902 error = pops->puffs_node_reclaim(pcc,
903 preq->preq_cookie, auxt->pvnr_pid);
904 break;
905 }
906
907 case PUFFS_VN_INACTIVE:
908 {
909 struct puffs_vnreq_inactive *auxt = auxbuf;
910 if (pops->puffs_node_inactive == NULL) {
911 error = EOPNOTSUPP;
912 break;
913 }
914
915 error = pops->puffs_node_inactive(pcc,
916 preq->preq_cookie, auxt->pvnr_pid,
917 &auxt->pvnr_backendrefs);
918 break;
919 }
920
921 case PUFFS_VN_PATHCONF:
922 {
923 struct puffs_vnreq_pathconf *auxt = auxbuf;
924 if (pops->puffs_node_pathconf == NULL) {
925 error = 0;
926 break;
927 }
928
929 error = pops->puffs_node_pathconf(pcc,
930 preq->preq_cookie, auxt->pvnr_name,
931 &auxt->pvnr_retval);
932 break;
933 }
934
935 case PUFFS_VN_ADVLOCK:
936 {
937 struct puffs_vnreq_advlock *auxt = auxbuf;
938 if (pops->puffs_node_advlock == NULL) {
939 error = 0;
940 break;
941 }
942
943 error = pops->puffs_node_advlock(pcc,
944 preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
945 &auxt->pvnr_fl, auxt->pvnr_flags);
946 break;
947 }
948
949 case PUFFS_VN_PRINT:
950 {
951 if (pops->puffs_node_print == NULL) {
952 error = 0;
953 break;
954 }
955
956 error = pops->puffs_node_print(pcc,
957 preq->preq_cookie);
958 break;
959 }
960
961 case PUFFS_VN_READ:
962 {
963 struct puffs_vnreq_read *auxt = auxbuf;
964 size_t res;
965
966 if (pops->puffs_node_read == NULL) {
967 error = EIO;
968 break;
969 }
970
971 res = auxt->pvnr_resid;
972 error = pops->puffs_node_read(pcc,
973 preq->preq_cookie, auxt->pvnr_data,
974 auxt->pvnr_offset, &auxt->pvnr_resid,
975 &auxt->pvnr_cred, auxt->pvnr_ioflag);
976
977 /* need to move a bit more */
978 preq->preq_buflen = sizeof(struct puffs_vnreq_read)
979 + (res - auxt->pvnr_resid);
980 break;
981 }
982
983 case PUFFS_VN_WRITE:
984 {
985 struct puffs_vnreq_write *auxt = auxbuf;
986
987 if (pops->puffs_node_write == NULL) {
988 error = EIO;
989 break;
990 }
991
992 error = pops->puffs_node_write(pcc,
993 preq->preq_cookie, auxt->pvnr_data,
994 auxt->pvnr_offset, &auxt->pvnr_resid,
995 &auxt->pvnr_cred, auxt->pvnr_ioflag);
996
997 /* don't need to move data back to the kernel */
998 preq->preq_buflen = sizeof(struct puffs_vnreq_write);
999 break;
1000 }
1001
1002 /* holy bitrot, ryydman! */
1003 #if 0
1004 case PUFFS_VN_IOCTL:
1005 error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
1006 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1007 if (error != 0)
1008 break;
1009 pop.pso_reqid = preq->preq_id;
1010
1011 /* let the kernel do it's intermediate duty */
1012 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1013 /*
1014 * XXX: I don't actually know what the correct
1015 * thing to do in case of an error is, so I'll
1016 * just ignore it for the time being.
1017 */
1018 error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
1019 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1020 break;
1021
1022 case PUFFS_VN_FCNTL:
1023 error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
1024 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1025 if (error != 0)
1026 break;
1027 pop.pso_reqid = preq->preq_id;
1028
1029 /* let the kernel do it's intermediate duty */
1030 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1031 /*
1032 * XXX: I don't actually know what the correct
1033 * thing to do in case of an error is, so I'll
1034 * just ignore it for the time being.
1035 */
1036 error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
1037 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1038 break;
1039 #endif
1040
1041 default:
1042 printf("inval op %d\n", preq->preq_optype);
1043 error = EINVAL;
1044 break;
1045 }
1046 } else {
1047 /*
1048 * this one also
1049 */
1050 error = EINVAL;
1051 }
1052
1053 preq->preq_rv = error;
1054
1055 pcc->pcc_rv = rv;
1056 pcc->pcc_flags |= PCC_DONE;
1057 }
1058
1059 static int
1060 do_buildpath(struct puffs_cn *pcn, void *parent)
1061 {
1062 struct puffs_node *pn_parent;
1063 size_t plen;
1064
1065 pn_parent = parent; /* XXX */
1066 assert(pn_parent->pn_path != NULL);
1067
1068 /* +1 not for nul but for / */
1069 plen = pn_parent->pn_plen + pcn->pcn_namelen + 1;
1070 pcn->pcn_fullpath = malloc(plen);
1071 if (!pcn->pcn_fullpath)
1072 return errno;
1073
1074 strcpy(pcn->pcn_fullpath, pn_parent->pn_path);
1075 strcat(pcn->pcn_fullpath, "/");
1076 strcat(pcn->pcn_fullpath, pcn->pcn_name);
1077 pcn->pcn_fullpath[plen-1] = '\0'; /* paranoia */
1078 pcn->pcn_fullplen = plen;
1079
1080 return 0;
1081 }
1082
1083
1084 #if 0
1085 case PUFFS_VN_POLL:
1086 {
1087 struct puffs_vnreq_poll *auxt = auxbuf;
1088 if (pops->puffs_node_poll == NULL) {
1089 error = 0;
1090 break;
1091 }
1092
1093 error = pops->puffs_node_poll(pcc,
1094 preq->preq_cookie, preq-);
1095 break;
1096 }
1097
1098 case PUFFS_VN_KQFILTER:
1099 {
1100 struct puffs_vnreq_kqfilter *auxt = auxbuf;
1101 if (pops->puffs_node_kqfilter == NULL) {
1102 error = 0;
1103 break;
1104 }
1105
1106 error = pops->puffs_node_kqfilter(pcc,
1107 preq->preq_cookie, );
1108 break;
1109 }
1110
1111 case PUFFS_VN_CLOSEEXTATTR:
1112 {
1113 struct puffs_vnreq_closeextattr *auxt = auxbuf;
1114 if (pops->puffs_closeextattr == NULL) {
1115 error = 0;
1116 break;
1117 }
1118
1119 error = pops->puffs_closeextattr(pcc,
1120 preq->preq_cookie, );
1121 break;
1122 }
1123
1124 case PUFFS_VN_GETEXTATTR:
1125 {
1126 struct puffs_vnreq_getextattr *auxt = auxbuf;
1127 if (pops->puffs_getextattr == NULL) {
1128 error = 0;
1129 break;
1130 }
1131
1132 error = pops->puffs_getextattr(pcc,
1133 preq->preq_cookie, );
1134 break;
1135 }
1136
1137 case PUFFS_VN_LISTEXTATTR:
1138 {
1139 struct puffs_vnreq_listextattr *auxt = auxbuf;
1140 if (pops->puffs_listextattr == NULL) {
1141 error = 0;
1142 break;
1143 }
1144
1145 error = pops->puffs_listextattr(pcc,
1146 preq->preq_cookie, );
1147 break;
1148 }
1149
1150 case PUFFS_VN_OPENEXTATTR:
1151 {
1152 struct puffs_vnreq_openextattr *auxt = auxbuf;
1153 if (pops->puffs_openextattr == NULL) {
1154 error = 0;
1155 break;
1156 }
1157
1158 error = pops->puffs_openextattr(pcc,
1159 preq->preq_cookie, );
1160 break;
1161 }
1162
1163 case PUFFS_VN_DELETEEXTATTR:
1164 {
1165 struct puffs_vnreq_deleteextattr *auxt = auxbuf;
1166 if (pops->puffs_deleteextattr == NULL) {
1167 error = 0;
1168 break;
1169 }
1170
1171 error = pops->puffs_deleteextattr(pcc,
1172 preq->preq_cookie, );
1173 break;
1174 }
1175
1176 case PUFFS_VN_SETEXTATTR:
1177 {
1178 struct puffs_vnreq_setextattr *auxt = auxbuf;
1179 if (pops->puffs_setextattr == NULL) {
1180 error = 0;
1181 break;
1182 }
1183
1184 error = pops->puffs_setextattr(pcc,
1185 preq->preq_cookie, );
1186 break;
1187 }
1188
1189 #endif
1190