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