puffs.c revision 1.23 1 /* $NetBSD: puffs.c,v 1.23 2007/01/11 18:18:36 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.23 2007/01/11 18:18:36 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 /* XXX: not here, john */
387 struct pathinfo {
388 char *old;
389 size_t oldlen;
390 char *new;
391 size_t newlen;
392 };
393
394 /* substitute all (child) patch prefixes. needed with paths & rename */
395
396 #define SPATHERR ((void *)-1)
397 static void *
398 spathprefix(struct puffs_node *pn, void *arg)
399 {
400 struct pathinfo *pi = arg;
401 char *p, *pnew;
402 size_t plen, pnewlen;
403
404 /* len includes terminating nul */
405 if (strncmp(pn->pn_path, pi->old, pi->oldlen-1) != 0)
406 return NULL;
407
408 /* otherwise we'd have two nodes with an equal path */
409 assert(pn->pn_plen > pi->oldlen);
410
411 /* not a complete directory prefix? */
412 if (*(pn->pn_path + pi->oldlen-1) != '/')
413 return NULL;
414
415 /* found a matching prefix */
416 p = pn->pn_path + pi->oldlen;
417 plen = strlen(p);
418
419 pnewlen = pi->newlen + plen + 1;
420 pnew = malloc(pnewlen);
421 if (pnew == NULL)
422 return SPATHERR; /* XXX: can't recover, should die */
423 strcpy(pnew, pi->new);
424 strcat(pnew, "/");
425 strcat(pnew, p);
426
427 free(pn->pn_path);
428 pn->pn_path = pnew;
429 pn->pn_plen = pnewlen;
430
431 return NULL;
432 }
433
434 /* library private, but linked from callcontext.c */
435
436 void
437 puffs_calldispatcher(struct puffs_cc *pcc)
438 {
439 struct puffs_usermount *pu = pcc->pcc_pu;
440 struct puffs_ops *pops = &pu->pu_ops;
441 struct puffs_req *preq = pcc->pcc_preq;
442 void *auxbuf = preq; /* help with typecasting */
443 int error, rv, buildpath;
444
445 assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
446
447 if (PUFFSOP_WANTREPLY(preq->preq_opclass))
448 rv = PUFFCALL_ANSWER;
449 else
450 rv = PUFFCALL_IGNORE;
451
452 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
453
454 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
455 switch (preq->preq_optype) {
456 case PUFFS_VFS_UNMOUNT:
457 {
458 struct puffs_vfsreq_unmount *auxt = auxbuf;
459
460 pu->pu_state = PUFFS_STATE_UNMOUNTING;
461 error = pops->puffs_fs_unmount(pcc,
462 auxt->pvfsr_flags, auxt->pvfsr_pid);
463 if (!error)
464 pu->pu_state = PUFFS_STATE_UNMOUNTED;
465 else
466 pu->pu_state = PUFFS_STATE_RUNNING;
467 break;
468 }
469 case PUFFS_VFS_STATVFS:
470 {
471 struct puffs_vfsreq_statvfs *auxt = auxbuf;
472
473 error = pops->puffs_fs_statvfs(pcc,
474 &auxt->pvfsr_sb, auxt->pvfsr_pid);
475 break;
476 }
477 case PUFFS_VFS_SYNC:
478 {
479 struct puffs_vfsreq_sync *auxt = auxbuf;
480
481 error = pops->puffs_fs_sync(pcc,
482 auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
483 auxt->pvfsr_pid);
484 break;
485 }
486 default:
487 /*
488 * I guess the kernel sees this one coming
489 */
490 error = EINVAL;
491 break;
492 }
493
494 /* XXX: audit return values */
495 /* XXX: sync with kernel */
496 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
497 switch (preq->preq_optype) {
498 case PUFFS_VN_LOOKUP:
499 {
500 struct puffs_vnreq_lookup *auxt = auxbuf;
501 struct puffs_cn pcn;
502
503 pcn.pcn_pkcnp = &auxt->pvnr_cn;
504 if (buildpath) {
505 if (pcn.pcn_flags & PUFFS_ISDOTDOT) {
506 buildpath = 0;
507 } else {
508 error = do_buildpath(&pcn,
509 preq->preq_cookie);
510 if (error)
511 break;
512 }
513 }
514
515 /* lookup *must* be present */
516 error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
517 &auxt->pvnr_newnode, &auxt->pvnr_vtype,
518 &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
519
520 if (buildpath) {
521 if (error) {
522 free(pcn.pcn_fullpath);
523 } else {
524 struct puffs_node *pn;
525
526 /*
527 * did we get a new node or a
528 * recycled node?
529 * XXX: mapping assumption
530 */
531 pn = auxt->pvnr_newnode;
532 if (pn->pn_path == NULL) {
533 pn->pn_path = pcn.pcn_fullpath;
534 pn->pn_plen
535 = pcn.pcn_fullplen;
536 }
537 }
538 }
539
540 break;
541 }
542
543 case PUFFS_VN_CREATE:
544 {
545 struct puffs_vnreq_create *auxt = auxbuf;
546 struct puffs_cn pcn;
547 if (pops->puffs_node_create == NULL) {
548 error = 0;
549 break;
550 }
551
552 pcn.pcn_pkcnp = &auxt->pvnr_cn;
553 if (buildpath) {
554 error = do_buildpath(&pcn, preq->preq_cookie);
555 if (error)
556 break;
557 }
558
559 error = pops->puffs_node_create(pcc,
560 preq->preq_cookie, &auxt->pvnr_newnode,
561 &pcn, &auxt->pvnr_va);
562
563 if (buildpath) {
564 if (error) {
565 free(pcn.pcn_fullpath);
566 } else {
567 struct puffs_node *pn;
568
569 pn = auxt->pvnr_newnode;
570 pn->pn_path = pcn.pcn_fullpath;
571 pn->pn_plen = pcn.pcn_fullplen;
572 }
573 }
574
575 break;
576 }
577
578 case PUFFS_VN_MKNOD:
579 {
580 struct puffs_vnreq_mknod *auxt = auxbuf;
581 struct puffs_cn pcn;
582 if (pops->puffs_node_mknod == NULL) {
583 error = 0;
584 break;
585 }
586
587 pcn.pcn_pkcnp = &auxt->pvnr_cn;
588 if (buildpath) {
589 error = do_buildpath(&pcn, preq->preq_cookie);
590 if (error)
591 break;
592 }
593
594 error = pops->puffs_node_mknod(pcc,
595 preq->preq_cookie, &auxt->pvnr_newnode,
596 &pcn, &auxt->pvnr_va);
597
598 if (buildpath) {
599 if (error) {
600 free(pcn.pcn_fullpath);
601 } else {
602 struct puffs_node *pn;
603
604 pn = auxt->pvnr_newnode;
605 pn->pn_path = pcn.pcn_fullpath;
606 pn->pn_plen = pcn.pcn_fullplen;
607 }
608 }
609
610 break;
611 }
612
613 case PUFFS_VN_OPEN:
614 {
615 struct puffs_vnreq_open *auxt = auxbuf;
616 if (pops->puffs_node_open == NULL) {
617 error = 0;
618 break;
619 }
620
621 error = pops->puffs_node_open(pcc,
622 preq->preq_cookie, auxt->pvnr_mode,
623 &auxt->pvnr_cred, auxt->pvnr_pid);
624 break;
625 }
626
627 case PUFFS_VN_CLOSE:
628 {
629 struct puffs_vnreq_close *auxt = auxbuf;
630 if (pops->puffs_node_close == NULL) {
631 error = 0;
632 break;
633 }
634
635 error = pops->puffs_node_close(pcc,
636 preq->preq_cookie, auxt->pvnr_fflag,
637 &auxt->pvnr_cred, auxt->pvnr_pid);
638 break;
639 }
640
641 case PUFFS_VN_ACCESS:
642 {
643 struct puffs_vnreq_access *auxt = auxbuf;
644 if (pops->puffs_node_access == NULL) {
645 error = 0;
646 break;
647 }
648
649 error = pops->puffs_node_access(pcc,
650 preq->preq_cookie, auxt->pvnr_mode,
651 &auxt->pvnr_cred, auxt->pvnr_pid);
652 break;
653 }
654
655 case PUFFS_VN_GETATTR:
656 {
657 struct puffs_vnreq_getattr *auxt = auxbuf;
658 if (pops->puffs_node_getattr == NULL) {
659 error = EOPNOTSUPP;
660 break;
661 }
662
663 error = pops->puffs_node_getattr(pcc,
664 preq->preq_cookie, &auxt->pvnr_va,
665 &auxt->pvnr_cred, auxt->pvnr_pid);
666 break;
667 }
668
669 case PUFFS_VN_SETATTR:
670 {
671 struct puffs_vnreq_setattr *auxt = auxbuf;
672 if (pops->puffs_node_setattr == NULL) {
673 error = EOPNOTSUPP;
674 break;
675 }
676
677 error = pops->puffs_node_setattr(pcc,
678 preq->preq_cookie, &auxt->pvnr_va,
679 &auxt->pvnr_cred, auxt->pvnr_pid);
680 break;
681 }
682
683 case PUFFS_VN_MMAP:
684 {
685 struct puffs_vnreq_mmap *auxt = auxbuf;
686 if (pops->puffs_node_mmap == NULL) {
687 error = 0;
688 break;
689 }
690
691 error = pops->puffs_node_mmap(pcc,
692 preq->preq_cookie, auxt->pvnr_fflags,
693 &auxt->pvnr_cred, auxt->pvnr_pid);
694 break;
695 }
696
697 case PUFFS_VN_REVOKE:
698 {
699 struct puffs_vnreq_revoke *auxt = auxbuf;
700 if (pops->puffs_node_revoke == NULL) {
701 error = 0;
702 break;
703 }
704
705 error = pops->puffs_node_revoke(pcc,
706 preq->preq_cookie, auxt->pvnr_flags);
707 break;
708 }
709
710 case PUFFS_VN_FSYNC:
711 {
712 struct puffs_vnreq_fsync *auxt = auxbuf;
713 if (pops->puffs_node_fsync == NULL) {
714 error = 0;
715 break;
716 }
717
718 error = pops->puffs_node_fsync(pcc,
719 preq->preq_cookie, &auxt->pvnr_cred,
720 auxt->pvnr_flags, auxt->pvnr_offlo,
721 auxt->pvnr_offhi, auxt->pvnr_pid);
722 break;
723 }
724
725 case PUFFS_VN_SEEK:
726 {
727 struct puffs_vnreq_seek *auxt = auxbuf;
728 if (pops->puffs_node_seek == NULL) {
729 error = 0;
730 break;
731 }
732
733 error = pops->puffs_node_seek(pcc,
734 preq->preq_cookie, auxt->pvnr_oldoff,
735 auxt->pvnr_newoff, &auxt->pvnr_cred);
736 break;
737 }
738
739 case PUFFS_VN_REMOVE:
740 {
741 struct puffs_vnreq_remove *auxt = auxbuf;
742 struct puffs_cn pcn;
743 if (pops->puffs_node_remove == NULL) {
744 error = 0;
745 break;
746 }
747
748 pcn.pcn_pkcnp = &auxt->pvnr_cn;
749
750 error = pops->puffs_node_remove(pcc,
751 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
752 break;
753 }
754
755 case PUFFS_VN_LINK:
756 {
757 struct puffs_vnreq_link *auxt = auxbuf;
758 struct puffs_cn pcn;
759 if (pops->puffs_node_link == NULL) {
760 error = 0;
761 break;
762 }
763
764 pcn.pcn_pkcnp = &auxt->pvnr_cn;
765 if (buildpath) {
766 error = do_buildpath(&pcn, preq->preq_cookie);
767 if (error)
768 break;
769 }
770
771 error = pops->puffs_node_link(pcc,
772 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
773 if (buildpath)
774 free(pcn.pcn_fullpath);
775
776 break;
777 }
778
779 case PUFFS_VN_RENAME:
780 {
781 struct puffs_vnreq_rename *auxt = auxbuf;
782 struct puffs_cn pcn_src, pcn_targ;
783 struct puffs_node *pn_src;
784
785 if (pops->puffs_node_rename == NULL) {
786 error = 0;
787 break;
788 }
789
790 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
791 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
792 if (buildpath) {
793 pn_src = auxt->pvnr_cookie_src;
794 pcn_src.pcn_fullpath = pn_src->pn_path;
795 pcn_src.pcn_fullplen = pn_src->pn_plen;
796
797 error = do_buildpath(&pcn_targ,
798 auxt->pvnr_cookie_targdir);
799 if (error)
800 break;
801 }
802
803 error = pops->puffs_node_rename(pcc,
804 preq->preq_cookie, auxt->pvnr_cookie_src,
805 &pcn_src, auxt->pvnr_cookie_targdir,
806 auxt->pvnr_cookie_targ, &pcn_targ);
807
808 if (buildpath) {
809 if (error) {
810 free(pcn_targ.pcn_fullpath);
811 } else {
812 struct pathinfo pi;
813 char *oldpath;
814
815 /* handle this node */
816 oldpath = pn_src->pn_path;
817
818 pn_src->pn_path = pcn_targ.pcn_fullpath;
819 pn_src->pn_plen = pcn_targ.pcn_fullplen;
820
821 if (pn_src->pn_va.va_type != VDIR) {
822 free(oldpath);
823 break;
824 }
825
826 /* handle all child nodes for DIRs */
827 pi.old = pcn_src.pcn_fullpath;
828 pi.oldlen = pcn_src.pcn_fullplen;
829 pi.new = pcn_targ.pcn_fullpath;
830 pi.newlen = pcn_targ.pcn_fullplen;
831
832 if (puffs_pn_nodewalk(pu,
833 spathprefix, &pi) == SPATHERR)
834 error = ENOMEM;
835 free(oldpath);
836 }
837 }
838 break;
839 }
840
841 case PUFFS_VN_MKDIR:
842 {
843 struct puffs_vnreq_mkdir *auxt = auxbuf;
844 struct puffs_cn pcn;
845 if (pops->puffs_node_mkdir == NULL) {
846 error = 0;
847 break;
848 }
849
850 pcn.pcn_pkcnp = &auxt->pvnr_cn;
851 if (buildpath) {
852 error = do_buildpath(&pcn, preq->preq_cookie);
853 if (error)
854 break;
855 }
856
857 error = pops->puffs_node_mkdir(pcc,
858 preq->preq_cookie, &auxt->pvnr_newnode,
859 &pcn, &auxt->pvnr_va);
860
861 if (buildpath) {
862 if (error) {
863 free(pcn.pcn_fullpath);
864 } else {
865 struct puffs_node *pn;
866
867 pn = auxt->pvnr_newnode;
868 pn->pn_path = pcn.pcn_fullpath;
869 pn->pn_plen = pcn.pcn_fullplen;
870 }
871 }
872
873 break;
874 }
875
876 case PUFFS_VN_RMDIR:
877 {
878 struct puffs_vnreq_rmdir *auxt = auxbuf;
879 struct puffs_cn pcn;
880 if (pops->puffs_node_rmdir == NULL) {
881 error = 0;
882 break;
883 }
884
885 pcn.pcn_pkcnp = &auxt->pvnr_cn;
886
887 error = pops->puffs_node_rmdir(pcc,
888 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
889 break;
890 }
891
892 case PUFFS_VN_SYMLINK:
893 {
894 struct puffs_vnreq_symlink *auxt = auxbuf;
895 struct puffs_cn pcn;
896 if (pops->puffs_node_symlink == NULL) {
897 error = 0;
898 break;
899 }
900
901 pcn.pcn_pkcnp = &auxt->pvnr_cn;
902 if (buildpath) {
903 error = do_buildpath(&pcn, preq->preq_cookie);
904 if (error)
905 break;
906 }
907
908 error = pops->puffs_node_symlink(pcc,
909 preq->preq_cookie, &auxt->pvnr_newnode,
910 &pcn, &auxt->pvnr_va, auxt->pvnr_link);
911
912 if (buildpath) {
913 if (error) {
914 free(pcn.pcn_fullpath);
915 } else {
916 struct puffs_node *pn;
917
918 pn = auxt->pvnr_newnode;
919 pn->pn_path = pcn.pcn_fullpath;
920 pn->pn_plen = pcn.pcn_fullplen;
921 }
922 }
923
924 break;
925 }
926
927 case PUFFS_VN_READDIR:
928 {
929 struct puffs_vnreq_readdir *auxt = auxbuf;
930 size_t res;
931
932 if (pops->puffs_node_readdir == NULL) {
933 error = 0;
934 break;
935 }
936
937 res = auxt->pvnr_resid;
938 error = pops->puffs_node_readdir(pcc,
939 preq->preq_cookie, auxt->pvnr_dent,
940 &auxt->pvnr_cred, &auxt->pvnr_offset,
941 &auxt->pvnr_resid);
942
943 /* need to move a bit more */
944 preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
945 + (res - auxt->pvnr_resid);
946 break;
947 }
948
949 case PUFFS_VN_READLINK:
950 {
951 struct puffs_vnreq_readlink *auxt = auxbuf;
952 if (pops->puffs_node_readlink == NULL) {
953 error = EOPNOTSUPP;
954 break;
955 }
956
957 error = pops->puffs_node_readlink(pcc,
958 preq->preq_cookie, &auxt->pvnr_cred,
959 auxt->pvnr_link, &auxt->pvnr_linklen);
960 break;
961 }
962
963 case PUFFS_VN_RECLAIM:
964 {
965 struct puffs_vnreq_reclaim *auxt = auxbuf;
966 if (pops->puffs_node_reclaim == NULL) {
967 error = 0;
968 break;
969 }
970
971 error = pops->puffs_node_reclaim(pcc,
972 preq->preq_cookie, auxt->pvnr_pid);
973 break;
974 }
975
976 case PUFFS_VN_INACTIVE:
977 {
978 struct puffs_vnreq_inactive *auxt = auxbuf;
979 if (pops->puffs_node_inactive == NULL) {
980 error = EOPNOTSUPP;
981 break;
982 }
983
984 error = pops->puffs_node_inactive(pcc,
985 preq->preq_cookie, auxt->pvnr_pid,
986 &auxt->pvnr_backendrefs);
987 break;
988 }
989
990 case PUFFS_VN_PATHCONF:
991 {
992 struct puffs_vnreq_pathconf *auxt = auxbuf;
993 if (pops->puffs_node_pathconf == NULL) {
994 error = 0;
995 break;
996 }
997
998 error = pops->puffs_node_pathconf(pcc,
999 preq->preq_cookie, auxt->pvnr_name,
1000 &auxt->pvnr_retval);
1001 break;
1002 }
1003
1004 case PUFFS_VN_ADVLOCK:
1005 {
1006 struct puffs_vnreq_advlock *auxt = auxbuf;
1007 if (pops->puffs_node_advlock == NULL) {
1008 error = 0;
1009 break;
1010 }
1011
1012 error = pops->puffs_node_advlock(pcc,
1013 preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
1014 &auxt->pvnr_fl, auxt->pvnr_flags);
1015 break;
1016 }
1017
1018 case PUFFS_VN_PRINT:
1019 {
1020 if (pops->puffs_node_print == NULL) {
1021 error = 0;
1022 break;
1023 }
1024
1025 error = pops->puffs_node_print(pcc,
1026 preq->preq_cookie);
1027 break;
1028 }
1029
1030 case PUFFS_VN_READ:
1031 {
1032 struct puffs_vnreq_read *auxt = auxbuf;
1033 size_t res;
1034
1035 if (pops->puffs_node_read == NULL) {
1036 error = EIO;
1037 break;
1038 }
1039
1040 res = auxt->pvnr_resid;
1041 error = pops->puffs_node_read(pcc,
1042 preq->preq_cookie, auxt->pvnr_data,
1043 auxt->pvnr_offset, &auxt->pvnr_resid,
1044 &auxt->pvnr_cred, auxt->pvnr_ioflag);
1045
1046 /* need to move a bit more */
1047 preq->preq_buflen = sizeof(struct puffs_vnreq_read)
1048 + (res - auxt->pvnr_resid);
1049 break;
1050 }
1051
1052 case PUFFS_VN_WRITE:
1053 {
1054 struct puffs_vnreq_write *auxt = auxbuf;
1055
1056 if (pops->puffs_node_write == NULL) {
1057 error = EIO;
1058 break;
1059 }
1060
1061 error = pops->puffs_node_write(pcc,
1062 preq->preq_cookie, auxt->pvnr_data,
1063 auxt->pvnr_offset, &auxt->pvnr_resid,
1064 &auxt->pvnr_cred, auxt->pvnr_ioflag);
1065
1066 /* don't need to move data back to the kernel */
1067 preq->preq_buflen = sizeof(struct puffs_vnreq_write);
1068 break;
1069 }
1070
1071 /* holy bitrot, ryydman! */
1072 #if 0
1073 case PUFFS_VN_IOCTL:
1074 error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
1075 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1076 if (error != 0)
1077 break;
1078 pop.pso_reqid = preq->preq_id;
1079
1080 /* let the kernel do it's intermediate duty */
1081 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1082 /*
1083 * XXX: I don't actually know what the correct
1084 * thing to do in case of an error is, so I'll
1085 * just ignore it for the time being.
1086 */
1087 error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
1088 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1089 break;
1090
1091 case PUFFS_VN_FCNTL:
1092 error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
1093 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1094 if (error != 0)
1095 break;
1096 pop.pso_reqid = preq->preq_id;
1097
1098 /* let the kernel do it's intermediate duty */
1099 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1100 /*
1101 * XXX: I don't actually know what the correct
1102 * thing to do in case of an error is, so I'll
1103 * just ignore it for the time being.
1104 */
1105 error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
1106 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1107 break;
1108 #endif
1109
1110 default:
1111 printf("inval op %d\n", preq->preq_optype);
1112 error = EINVAL;
1113 break;
1114 }
1115 } else {
1116 /*
1117 * this one also
1118 */
1119 error = EINVAL;
1120 }
1121
1122 preq->preq_rv = error;
1123
1124 pcc->pcc_rv = rv;
1125 pcc->pcc_flags |= PCC_DONE;
1126 }
1127
1128 static int
1129 do_buildpath(struct puffs_cn *pcn, void *parent)
1130 {
1131 struct puffs_node *pn_parent;
1132 size_t plen;
1133
1134 pn_parent = parent; /* XXX */
1135 assert(pn_parent->pn_path != NULL);
1136
1137 /* +1 not for nul but for / */
1138 plen = pn_parent->pn_plen + pcn->pcn_namelen + 1;
1139 pcn->pcn_fullpath = malloc(plen);
1140 if (!pcn->pcn_fullpath)
1141 return errno;
1142
1143 strcpy(pcn->pcn_fullpath, pn_parent->pn_path);
1144 strcat(pcn->pcn_fullpath, "/");
1145 strcat(pcn->pcn_fullpath, pcn->pcn_name);
1146 pcn->pcn_fullpath[plen-1] = '\0'; /* paranoia */
1147 pcn->pcn_fullplen = plen;
1148
1149 return 0;
1150 }
1151
1152
1153 #if 0
1154 case PUFFS_VN_POLL:
1155 {
1156 struct puffs_vnreq_poll *auxt = auxbuf;
1157 if (pops->puffs_node_poll == NULL) {
1158 error = 0;
1159 break;
1160 }
1161
1162 error = pops->puffs_node_poll(pcc,
1163 preq->preq_cookie, preq-);
1164 break;
1165 }
1166
1167 case PUFFS_VN_KQFILTER:
1168 {
1169 struct puffs_vnreq_kqfilter *auxt = auxbuf;
1170 if (pops->puffs_node_kqfilter == NULL) {
1171 error = 0;
1172 break;
1173 }
1174
1175 error = pops->puffs_node_kqfilter(pcc,
1176 preq->preq_cookie, );
1177 break;
1178 }
1179
1180 case PUFFS_VN_CLOSEEXTATTR:
1181 {
1182 struct puffs_vnreq_closeextattr *auxt = auxbuf;
1183 if (pops->puffs_closeextattr == NULL) {
1184 error = 0;
1185 break;
1186 }
1187
1188 error = pops->puffs_closeextattr(pcc,
1189 preq->preq_cookie, );
1190 break;
1191 }
1192
1193 case PUFFS_VN_GETEXTATTR:
1194 {
1195 struct puffs_vnreq_getextattr *auxt = auxbuf;
1196 if (pops->puffs_getextattr == NULL) {
1197 error = 0;
1198 break;
1199 }
1200
1201 error = pops->puffs_getextattr(pcc,
1202 preq->preq_cookie, );
1203 break;
1204 }
1205
1206 case PUFFS_VN_LISTEXTATTR:
1207 {
1208 struct puffs_vnreq_listextattr *auxt = auxbuf;
1209 if (pops->puffs_listextattr == NULL) {
1210 error = 0;
1211 break;
1212 }
1213
1214 error = pops->puffs_listextattr(pcc,
1215 preq->preq_cookie, );
1216 break;
1217 }
1218
1219 case PUFFS_VN_OPENEXTATTR:
1220 {
1221 struct puffs_vnreq_openextattr *auxt = auxbuf;
1222 if (pops->puffs_openextattr == NULL) {
1223 error = 0;
1224 break;
1225 }
1226
1227 error = pops->puffs_openextattr(pcc,
1228 preq->preq_cookie, );
1229 break;
1230 }
1231
1232 case PUFFS_VN_DELETEEXTATTR:
1233 {
1234 struct puffs_vnreq_deleteextattr *auxt = auxbuf;
1235 if (pops->puffs_deleteextattr == NULL) {
1236 error = 0;
1237 break;
1238 }
1239
1240 error = pops->puffs_deleteextattr(pcc,
1241 preq->preq_cookie, );
1242 break;
1243 }
1244
1245 case PUFFS_VN_SETEXTATTR:
1246 {
1247 struct puffs_vnreq_setextattr *auxt = auxbuf;
1248 if (pops->puffs_setextattr == NULL) {
1249 error = 0;
1250 break;
1251 }
1252
1253 error = pops->puffs_setextattr(pcc,
1254 preq->preq_cookie, );
1255 break;
1256 }
1257
1258 #endif
1259