1 /* $NetBSD: ops.c,v 1.4 2010/08/28 03:46:21 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <libgen.h> 32 #include <errno.h> 33 #include <err.h> 34 #include <sysexits.h> 35 #include <syslog.h> 36 #include <puffs.h> 37 #include <sys/vnode.h> 38 #include <sys/socket.h> 39 #include <machine/vmparam.h> 40 41 #include "perfuse_priv.h" 42 #include "fuse.h" 43 44 static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t); 45 static void fuse_attr_to_vap(struct perfuse_state *, 46 struct vattr *, struct fuse_attr *); 47 static int node_lookup_dir_nodot(struct puffs_usermount *, 48 puffs_cookie_t, char *, size_t, struct puffs_node **); 49 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t, 50 const char*, struct puffs_node **); 51 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t, 52 struct puffs_newinfo *, const struct puffs_cn *pcn, 53 const struct vattr *, perfuse_msg_t *); 54 static const char *basename_r(const char *); 55 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t, 56 struct fuse_dirent *, size_t); 57 static int readdir_buffered(struct perfuse_state *, puffs_cookie_t, 58 struct dirent *, off_t *, size_t *, const struct puffs_cred *, 59 int *, off_t *, size_t *); 60 static void requeue_request(struct puffs_usermount *, 61 puffs_cookie_t opc, enum perfuse_qtype); 62 static void dequeue_requests(struct perfuse_state *, 63 puffs_cookie_t opc, enum perfuse_qtype, int); 64 #define DEQUEUE_ALL 0 65 66 /* 67 * From <sys/vnode>, inside #ifdef _KERNEL section 68 */ 69 #define IO_SYNC (0x40|IO_DSYNC) 70 #define IO_DSYNC 0x00200 71 #define IO_DIRECT 0x02000 72 73 /* 74 * From <fcntl>, inside #ifdef _KERNEL section 75 */ 76 #define F_WAIT 0x010 77 #define F_FLOCK 0x020 78 79 /* 80 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h 81 */ 82 const enum vtype iftovt_tab[16] = { 83 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 84 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 85 }; 86 const int vttoif_tab[9] = { 87 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 88 S_IFSOCK, S_IFIFO, S_IFMT, 89 }; 90 91 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) 92 #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) 93 94 95 static int 96 no_access(opc, pcr, mode) 97 puffs_cookie_t opc; 98 const struct puffs_cred *pcr; 99 mode_t mode; 100 { 101 struct puffs_node *pn; 102 struct vattr *va; 103 104 pn = (struct puffs_node *)opc; 105 va = puffs_pn_getvap(pn); 106 107 return puffs_access(va->va_type, va->va_mode, 108 va->va_uid, va->va_gid, 109 mode, pcr); 110 } 111 112 static void 113 fuse_attr_to_vap(ps, vap, fa) 114 struct perfuse_state *ps; 115 struct vattr *vap; 116 struct fuse_attr *fa; 117 { 118 vap->va_type = IFTOVT(fa->mode); 119 vap->va_mode = fa->mode; 120 vap->va_nlink = fa->nlink; 121 vap->va_uid = fa->uid; 122 vap->va_gid = fa->gid; 123 vap->va_fsid = ps->ps_fsid; 124 vap->va_fileid = fa->ino; 125 vap->va_size = fa->size; 126 vap->va_blocksize = fa->blksize; 127 vap->va_atime.tv_sec = (long)fa->atime; 128 vap->va_atime.tv_nsec = fa->atimensec; 129 vap->va_mtime.tv_sec = (long)fa->mtime; 130 vap->va_mtime.tv_nsec = fa->mtimensec; 131 vap->va_ctime.tv_sec = (long)fa->ctime; 132 vap->va_ctime.tv_nsec = fa->ctimensec; 133 vap->va_birthtime.tv_sec = 0; 134 vap->va_birthtime.tv_nsec = 0; 135 vap->va_gen = 0; 136 vap->va_flags = 0; 137 vap->va_rdev = fa->rdev; 138 vap->va_bytes = fa->size; 139 vap->va_filerev = 0; 140 vap->va_vaflags = 0; 141 142 if (vap->va_blocksize == 0) 143 vap->va_blocksize = DEV_BSIZE; 144 145 if (vap->va_size == (size_t)-1) /* XXX */ 146 vap->va_size = 0; 147 148 return; 149 } 150 151 152 /* 153 * Lookup name in directory opc 154 * We take special care of name being . or .. 155 * These are returned by readdir and deserve tweaks. 156 */ 157 static int 158 node_lookup_dir_nodot(pu, opc, name, namelen, pnp) 159 struct puffs_usermount *pu; 160 puffs_cookie_t opc; 161 char *name; 162 size_t namelen; 163 struct puffs_node **pnp; 164 { 165 char *path; 166 struct puffs_node *dpn = (struct puffs_node *)opc; 167 int error; 168 169 /* 170 * is easy as we already know it 171 */ 172 if (strncmp(name, ".", namelen) == 0) { 173 *pnp = (struct puffs_node *)opc; 174 return 0; 175 } 176 177 /* 178 * For .. we just forget the name part 179 */ 180 if (strncmp(name, "..", namelen) == 0) 181 namelen = 0; 182 183 namelen = PNPLEN(dpn) + 1 + namelen + 1; 184 if ((path = malloc(namelen)) == NULL) 185 DERR(EX_OSERR, "malloc failed"); 186 (void)snprintf(path, namelen, "%s/%s", (char *)PNPATH(dpn), name); 187 188 error = node_lookup_common(pu, opc, path, pnp); 189 190 free(path); 191 192 return error; 193 } 194 195 static int 196 node_lookup_common(pu, opc, path, pnp) 197 struct puffs_usermount *pu; 198 puffs_cookie_t opc; 199 const char *path; 200 struct puffs_node **pnp; 201 { 202 struct perfuse_state *ps; 203 perfuse_msg_t *pm; 204 struct fuse_entry_out *feo; 205 struct puffs_node *pn; 206 size_t len; 207 int error; 208 209 ps = puffs_getspecific(pu); 210 211 path = basename_r(path); 212 len = strlen(path) + 1; 213 214 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, NULL); 215 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len); 216 217 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0) 218 goto out; 219 220 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 221 222 pn = perfuse_new_pn(pu, opc); 223 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; 224 225 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 226 227 if (pnp != NULL) 228 *pnp = pn; 229 230 out: 231 ps->ps_destroy_msg(pm); 232 233 return error; 234 } 235 236 237 /* 238 * Common final code for methods that create objects: 239 * perfuse_node_mkdir 240 * perfuse_node_mknod 241 * perfuse_node_symlink 242 */ 243 static int 244 node_mk_common(pu, opc, pni, pcn, vap, pm) 245 struct puffs_usermount *pu; 246 puffs_cookie_t opc; 247 struct puffs_newinfo *pni; 248 const struct puffs_cn *pcn; 249 const struct vattr *vap; 250 perfuse_msg_t *pm; 251 { 252 struct perfuse_state *ps; 253 struct puffs_node *pn; 254 struct fuse_entry_out *feo; 255 struct fuse_setattr_in *fsi; 256 int error; 257 258 ps = puffs_getspecific(pu); 259 260 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0) 261 goto out; 262 263 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 264 if (feo->nodeid == PERFUSE_UNKNOWN_INO) 265 DERRX(EX_SOFTWARE, "%s: no ino", __func__); 266 267 pn = perfuse_new_pn(pu, opc); 268 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; 269 270 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 271 puffs_newinfo_setcookie(pni, pn); 272 ps->ps_destroy_msg(pm); 273 274 /* 275 * Set owner and group 276 */ 277 (void)puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid); 278 (void)puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid); 279 280 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, 281 FUSE_SETATTR, sizeof(*fsi), NULL); 282 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 283 fsi->uid = pn->pn_va.va_uid; 284 fsi->gid = pn->pn_va.va_gid; 285 fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID; 286 287 /* 288 * A fuse_attr_out is returned, but we ignore it. 289 */ 290 error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out)); 291 292 out: 293 ps->ps_destroy_msg(pm); 294 295 return error; 296 } 297 298 static const char * 299 basename_r(string) 300 const char *string; 301 { 302 char *result; 303 304 if ((result = rindex(string, '/')) == NULL) 305 return string; 306 307 /* 308 * We are finished if this is not a trailing / 309 */ 310 if (result[1] != '\0') 311 return result + 1; 312 313 314 /* 315 * Go back until we found something else than a / 316 */ 317 while (result != string) { 318 result--; 319 if (result[0] != '/') 320 break; 321 } 322 323 if (result == string) 324 return string; 325 326 if ((result = rindex(string, '/')) == NULL) 327 return string; 328 329 return result + 1; 330 331 } 332 333 static ssize_t 334 fuse_to_dirent(pu, opc, fd, fd_len) 335 struct puffs_usermount *pu; 336 puffs_cookie_t opc; 337 struct fuse_dirent *fd; 338 size_t fd_len; 339 { 340 struct dirent *dents; 341 size_t dents_len; 342 ssize_t written; 343 uint64_t fd_offset; 344 struct fuse_dirent *fd_base; 345 size_t len; 346 347 fd_base = fd; 348 fd_offset = 0; 349 written = 0; 350 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 351 dents_len = PERFUSE_NODE_DATA(opc)->pnd_dirent_len; 352 353 do { 354 char *ndp; 355 size_t reclen; 356 357 reclen = _DIRENT_RECLEN(dents, fd->namelen); 358 359 /* 360 * Check we do not overflow the output buffer 361 * struct fuse_dirent is bigger than struct dirent, 362 * so we should always use fd_len and never reallocate 363 * later. 364 * If we have to reallocate,try to double the buffer 365 * each time so that we do not have to do it too often. 366 */ 367 if (written + reclen > dents_len) { 368 if (dents_len == 0) 369 dents_len = fd_len; 370 else 371 dents_len = 372 MAX(2 * dents_len, written + reclen); 373 374 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 375 if ((dents = realloc(dents, dents_len)) == NULL) 376 DERR(EX_OSERR, "malloc failed"); 377 378 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents; 379 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len; 380 381 /* 382 * (void *) for delint 383 */ 384 ndp = (char *)(void *)dents + written; 385 dents = (struct dirent *)(void *)ndp; 386 } 387 388 389 390 /* 391 * Filesystem was mounted without -o use_ino 392 * Perform a lookup to find it. 393 * XXX still broken 394 */ 395 if (fd->ino == PERFUSE_UNKNOWN_INO) { 396 struct puffs_node *pn; 397 398 if (node_lookup_dir_nodot(pu, opc, fd->name, 399 fd->namelen, &pn) != 0) 400 DERRX(EX_SOFTWARE, 401 "node_lookup_dir_nodot failed"); 402 403 fd->ino = PERFUSE_NODE_DATA(pn)->pnd_ino; 404 } 405 406 dents->d_fileno = fd->ino; 407 dents->d_reclen = reclen; 408 dents->d_namlen = fd->namelen; 409 dents->d_type = fd->type; 410 strlcpy(dents->d_name, fd->name, fd->namelen + 1); 411 412 #ifdef PERFUSE_DEBUG 413 if (perfuse_diagflags & PDF_READDIR) 414 DPRINTF("%s: translated \"%s\" ino = %lld\n", 415 __func__, dents->d_name, dents->d_fileno); 416 #endif 417 418 dents = _DIRENT_NEXT(dents); 419 written += reclen; 420 421 /* 422 * Move to the next record. 423 * fd->off seems unreliable, for instance, flusterfs 424 * does not clear the unused bits, and we get 425 * 0xffffffffb9b95040 instead of just 0x40. Use 426 * record alignement instead. 427 */ 428 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 429 #ifdef PERFUSE_DEBUG 430 if (perfuse_diagflags & PDF_READDIR) 431 DPRINTF("%s: record at %lld/0x%llx length = %d/0x%x. " 432 "next record at %lld/0x%llx, max %d/0x%x\n", 433 __func__, fd_offset, fd_offset, len, len, 434 fd_offset + len, fd_offset + len, 435 fd_len, fd_len); 436 #endif 437 fd_offset += len; 438 439 /* 440 * Check if next record is still within the packet 441 * If it is not, we reached the end of the buffer. 442 */ 443 if (fd_offset >= fd_len) 444 break; 445 446 /* 447 * (void *) for delint 448 */ 449 ndp = (char *)(void *)fd_base + (size_t)fd_offset; 450 fd = (struct fuse_dirent *)(void *)ndp; 451 452 } while (1 /* CONSTCOND */); 453 454 /* 455 * Adjust the dirent output length 456 */ 457 if (written != -1) 458 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written; 459 460 return written; 461 } 462 463 /* ARGSUSED0 */ 464 static int 465 readdir_buffered(ps, opc, dent, readoff, 466 reslen, pcr, eofflag, cookies, ncookies) 467 struct perfuse_state *ps; 468 puffs_cookie_t opc; 469 struct dirent *dent; 470 off_t *readoff; 471 size_t *reslen; 472 const struct puffs_cred *pcr; 473 int *eofflag; 474 off_t *cookies; 475 size_t *ncookies; 476 { 477 struct dirent *fromdent; 478 struct perfuse_node_data *pnd; 479 char *ndp; 480 481 pnd = PERFUSE_NODE_DATA(opc); 482 483 while (*readoff < pnd->pnd_dirent_len) { 484 /* 485 * (void *) for delint 486 */ 487 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff; 488 fromdent = (struct dirent *)(void *)ndp; 489 490 if (*reslen < _DIRENT_SIZE(fromdent)) 491 break; 492 493 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent)); 494 *readoff += _DIRENT_SIZE(fromdent); 495 *reslen -= _DIRENT_SIZE(fromdent); 496 497 dent = _DIRENT_NEXT(dent); 498 } 499 500 #ifdef PERFUSE_DEBUG 501 if (perfuse_diagflags & PDF_READDIR) 502 DPRINTF("%s: readoff = %lld, pnd->pnd_dirent_len = %d\n", 503 __func__, *readoff, pnd->pnd_dirent_len); 504 #endif 505 if (*readoff >= pnd->pnd_dirent_len) { 506 free(pnd->pnd_dirent); 507 pnd->pnd_dirent = NULL; 508 pnd->pnd_dirent_len = 0; 509 *eofflag = 1; 510 } 511 512 return 0; 513 } 514 515 /* ARGSUSED0 */ 516 static void 517 requeue_request(pu, opc, type) 518 struct puffs_usermount *pu; 519 puffs_cookie_t opc; 520 enum perfuse_qtype type; 521 { 522 struct perfuse_cc_queue pcq; 523 struct perfuse_node_data *pnd; 524 #ifdef PERFUSE_DEBUG 525 struct perfuse_state *ps; 526 527 ps = perfuse_getspecific(pu); 528 #endif 529 530 /* 531 * XXX Add a lock he day we go multithreaded 532 */ 533 pnd = PERFUSE_NODE_DATA(opc); 534 pcq.pcq_type = type; 535 pcq.pcq_cc = puffs_cc_getcc(pu); 536 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next); 537 538 #ifdef PERFUSE_DEBUG 539 540 if (perfuse_diagflags & PDF_REQUEUE) 541 DPRINTF("%s: REQUEUE opc = %p, pcc = %p\n", 542 __func__, (void *)opc, pcq.pcq_cc); 543 #endif 544 545 puffs_cc_yield(pcq.pcq_cc); 546 547 #ifdef PERFUSE_DEBUG 548 if (perfuse_diagflags & PDF_REQUEUE) 549 DPRINTF("%s: RESUME opc = %p, pcc = %p\n", 550 __func__, (void *)opc, pcq.pcq_cc); 551 #endif 552 553 return; 554 } 555 556 /* ARGSUSED0 */ 557 static void 558 dequeue_requests(ps, opc, type, max) 559 struct perfuse_state *ps; 560 puffs_cookie_t opc; 561 enum perfuse_qtype type; 562 int max; 563 { 564 struct perfuse_cc_queue *pcq; 565 struct perfuse_node_data *pnd; 566 int dequeued; 567 568 /* 569 * XXX Add a lock he day we go multithreaded 570 */ 571 pnd = PERFUSE_NODE_DATA(opc); 572 dequeued = 0; 573 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) { 574 if (pcq->pcq_type != type) 575 continue; 576 577 puffs_cc_schedule(pcq->pcq_cc); 578 TAILQ_REMOVE(&pnd->pnd_pcq, pcq, pcq_next); 579 580 #ifdef PERFUSE_DEBUG 581 if (perfuse_diagflags & PDF_REQUEUE) 582 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p\n", 583 __func__, (void *)opc, pcq->pcq_cc); 584 #endif 585 586 if (++dequeued == max) 587 break; 588 } 589 590 #ifdef PERFUSE_DEBUG 591 if (perfuse_diagflags & PDF_REQUEUE) 592 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc); 593 #endif 594 595 return; 596 } 597 598 void 599 perfuse_fs_init(pu) 600 struct puffs_usermount *pu; 601 { 602 struct perfuse_state *ps; 603 perfuse_msg_t *pm; 604 struct fuse_init_in *fii; 605 struct fuse_init_out *fio; 606 int error; 607 608 ps = puffs_getspecific(pu); 609 610 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0) 611 DERR(EX_OSERR, "puffs_mount failed"); 612 613 /* 614 * Linux 2.6.34.1 sends theses flags: 615 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC 616 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK 617 * 618 * Linux also sets max_readahead at 32 pages (128 kB) 619 */ 620 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL); 621 fii = GET_INPAYLOAD(ps, pm, fuse_init_in); 622 fii->major = FUSE_KERNEL_VERSION; 623 fii->minor = FUSE_KERNEL_MINOR_VERSION; 624 fii->max_readahead = 32 * PAGE_SIZE; 625 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC); 626 627 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fio))) != 0) 628 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error); 629 630 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out); 631 ps->ps_max_readahead = fio->max_readahead; 632 ps->ps_max_write = fio->max_write; 633 634 ps->ps_destroy_msg(pm); 635 636 return; 637 } 638 639 int 640 perfuse_fs_unmount(pu, flags) 641 struct puffs_usermount *pu; 642 int flags; 643 { 644 perfuse_msg_t *pm; 645 struct perfuse_state *ps; 646 puffs_cookie_t opc; 647 int error; 648 649 ps = puffs_getspecific(pu); 650 651 opc = (puffs_cookie_t)puffs_getroot(pu); 652 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL); 653 654 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) { 655 DWARN("unmount %s", ps->ps_target); 656 if (!(flags & MNT_FORCE)) 657 goto out; 658 } 659 660 DPRINTF("%s unmounted, exit\n", ps->ps_target); 661 662 exit(0); 663 out: 664 ps->ps_destroy_msg(pm); 665 666 return error; 667 } 668 669 int 670 perfuse_fs_statvfs(pu, svfsb) 671 struct puffs_usermount *pu; 672 struct statvfs *svfsb; 673 { 674 struct perfuse_state *ps; 675 perfuse_msg_t *pm; 676 puffs_cookie_t opc; 677 struct fuse_statfs_out *fso; 678 int error; 679 680 ps = puffs_getspecific(pu); 681 opc = (puffs_cookie_t)puffs_getroot(pu); 682 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 683 684 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fso))) != 0) 685 goto out; 686 687 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 688 svfsb->f_flag = ps->ps_mountflags; 689 svfsb->f_bsize = fso->st.bsize; 690 svfsb->f_frsize = fso->st.frsize; 691 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize; 692 svfsb->f_blocks = fso->st.blocks; 693 svfsb->f_bfree = fso->st.bfree; 694 svfsb->f_bavail = fso->st.bavail; 695 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail; 696 svfsb->f_files = fso->st.files; 697 svfsb->f_ffree = fso->st.ffree; 698 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */ 699 svfsb->f_fresvd = 0; /* files reserved for root */ 700 701 svfsb->f_syncreads = ps->ps_syncreads; 702 svfsb->f_syncwrites = ps->ps_syncwrites; 703 704 svfsb->f_asyncreads = ps->ps_asyncreads; 705 svfsb->f_asyncwrites = ps->ps_asyncwrites; 706 707 svfsb->f_fsidx.__fsid_val[0] = ps->ps_fsid; 708 svfsb->f_fsidx.__fsid_val[1] = 0; 709 svfsb->f_fsid = ps->ps_fsid; 710 svfsb->f_namemax = MAXPATHLEN; /* XXX */ 711 svfsb->f_owner = ps->ps_owner_uid; 712 713 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN); 714 715 if (ps->ps_filesystemtype != NULL) 716 (void)strlcpy(svfsb->f_fstypename, 717 ps->ps_filesystemtype, _VFS_NAMELEN); 718 else 719 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN); 720 721 if (ps->ps_source != NULL) 722 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN); 723 else 724 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN); 725 out: 726 ps->ps_destroy_msg(pm); 727 728 return error; 729 } 730 731 int 732 perfuse_fs_sync(pu, waitfor, pcr) 733 struct puffs_usermount *pu; 734 int waitfor; 735 const struct puffs_cred *pcr; 736 { 737 /* 738 * FUSE does not seem to have a FS sync callback. 739 * Maybe do not even register this callback 740 */ 741 return puffs_fsnop_sync(pu, waitfor, pcr); 742 } 743 744 /* ARGSUSED0 */ 745 int 746 perfuse_fs_fhtonode(pu, fid, fidsize, pni) 747 struct puffs_usermount *pu; 748 void *fid; 749 size_t fidsize; 750 struct puffs_newinfo *pni; 751 { 752 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 753 return 0; 754 } 755 756 /* ARGSUSED0 */ 757 int 758 perfuse_fs_nodetofh(pu, cookie, fid, fidsize) 759 struct puffs_usermount *pu; 760 puffs_cookie_t cookie; 761 void *fid; 762 size_t *fidsize; 763 { 764 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 765 return 0; 766 } 767 768 #if 0 769 /* ARGSUSED0 */ 770 void 771 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname) 772 struct puffs_usermount *pu; 773 int cmd, 774 puffs_cookie_t *cookie; 775 int flags; 776 int namespace; 777 const char *attrname; 778 { 779 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 780 return 0; 781 } 782 #endif /* 0 */ 783 784 /* ARGSUSED0 */ 785 void 786 perfuse_fs_suspend(pu, status) 787 struct puffs_usermount *pu; 788 int status; 789 { 790 return; 791 } 792 793 794 795 int 796 perfuse_node_lookup(pu, opc, pni, pcn) 797 struct puffs_usermount *pu; 798 puffs_cookie_t opc; 799 struct puffs_newinfo *pni; 800 const struct puffs_cn *pcn; 801 { 802 struct puffs_node *pn; 803 int error; 804 805 /* 806 * XXX This is borrowed from librefuse, 807 * and __UNCONST is said to be fixed. 808 */ 809 pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp, 810 __UNCONST(&pcn->pcn_po_full)); 811 812 if (pn == NULL) { 813 error = node_lookup_common(pu, opc, (char *)PCNPATH(pcn), &pn); 814 if (error != 0) 815 return error; 816 } 817 818 /* 819 * If that node had a pending reclaim, wipe it out. 820 */ 821 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED; 822 823 puffs_newinfo_setcookie(pni, pn); 824 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 825 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size); 826 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 827 828 return 0; 829 } 830 831 int 832 perfuse_node_create(pu, opc, pni, pcn, vap) 833 struct puffs_usermount *pu; 834 puffs_cookie_t opc; 835 struct puffs_newinfo *pni; 836 const struct puffs_cn *pcn; 837 const struct vattr *vap; 838 { 839 perfuse_msg_t *pm; 840 struct perfuse_state *ps; 841 struct fuse_create_in *fci; 842 struct fuse_entry_out *feo; 843 struct fuse_open_out *foo; 844 struct puffs_node *pn; 845 const char *name; 846 size_t namelen; 847 size_t len; 848 int error; 849 850 /* 851 * Create an object require -WX permission in the parent directory 852 */ 853 if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 854 return EACCES; 855 856 /* 857 * If create is unimplemented: Check that it does not 858 * already exists, and if not, do mknod and open 859 */ 860 ps = puffs_getspecific(pu); 861 if (ps->ps_flags & PS_NO_CREAT) { 862 error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn); 863 if (error == 0) 864 return EEXIST; 865 866 error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 867 if (error != 0) 868 return error; 869 870 error = perfuse_node_open(pu, opc, FREAD|FWRITE, pcn->pcn_cred); 871 if (error != 0) 872 return error; 873 874 return 0; 875 } 876 877 name = basename_r((char *)PCNPATH(pcn)); 878 namelen = strlen(name) + 1; 879 len = sizeof(*fci) + namelen; 880 881 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred); 882 fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 883 fci->flags = 0; /* No flags seems available */ 884 fci->mode = vap->va_mode; 885 fci->umask = 0; /* Seems unused bu libfuse */ 886 (void)strlcpy((char*)(void *)(fci + 1), name, namelen); 887 888 len = sizeof(*feo) + sizeof(*foo); 889 if ((error = XCHG_MSG(ps, pu, pm, len)) != 0) 890 goto out; 891 892 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 893 foo = (struct fuse_open_out *)(void *)(feo + 1); 894 if (feo->nodeid == PERFUSE_UNKNOWN_INO) 895 DERRX(EX_SOFTWARE, "%s: no ino", __func__); 896 897 /* 898 * Save the file handle and inode in node private data 899 * so that we can reuse it later 900 */ 901 pn = perfuse_new_pn(pu, opc); 902 perfuse_new_fh((puffs_cookie_t)pn, foo->fh); 903 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; 904 905 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 906 puffs_newinfo_setcookie(pni, pn); 907 908 out: 909 ps->ps_destroy_msg(pm); 910 911 /* 912 * create is unimplmented, remember it for later, 913 * and start over using mknod and open instead. 914 */ 915 if (error == ENOSYS) { 916 ps->ps_flags |= PS_NO_CREAT; 917 return perfuse_node_create(pu, opc, pni, pcn, vap); 918 } 919 920 return error; 921 } 922 923 924 int 925 perfuse_node_mknod(pu, opc, pni, pcn, vap) 926 struct puffs_usermount *pu; 927 puffs_cookie_t opc; 928 struct puffs_newinfo *pni; 929 const struct puffs_cn *pcn; 930 const struct vattr *vap; 931 { 932 struct perfuse_state *ps; 933 perfuse_msg_t *pm; 934 struct fuse_mknod_in *fmi; 935 const char* path; 936 size_t len; 937 938 /* 939 * Only superuser can mknod objects other than 940 * directories, files, socks, fifo and links. 941 * 942 * Create an object require -WX permission in the parent directory 943 */ 944 switch (vap->va_type) { 945 case VDIR: /* FALLTHROUGH */ 946 case VREG: /* FALLTHROUGH */ 947 case VFIFO: /* FALLTHROUGH */ 948 case VSOCK: /* FALLTHROUGH */ 949 case VLNK: 950 if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 951 return EACCES; 952 break; 953 default: /* VNON, VBLK, VCHR, VBAD */ 954 if (!puffs_cred_isjuggernaut(pcn->pcn_cred)) 955 return EACCES; 956 break; 957 } 958 959 960 ps = puffs_getspecific(pu); 961 path = basename_r((char *)PCNPATH(pcn)); 962 len = sizeof(*fmi) + strlen(path) + 1; 963 964 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred); 965 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in); 966 fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 967 fmi->rdev = vap->va_rdev; 968 fmi->umask = 0; /* Seems unused bu libfuse */ 969 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 970 971 return node_mk_common(pu, opc, pni, pcn, vap, pm); 972 } 973 974 975 int 976 perfuse_node_open(pu, opc, mode, pcr) 977 struct puffs_usermount *pu; 978 puffs_cookie_t opc; 979 int mode; 980 const struct puffs_cred *pcr; 981 { 982 struct perfuse_state *ps; 983 perfuse_msg_t *pm; 984 mode_t pmode; 985 int op; 986 struct fuse_open_in *foi; 987 struct fuse_open_out *foo; 988 struct puffs_node *pn; 989 int error; 990 991 ps = puffs_getspecific(pu); 992 993 pn = (struct puffs_node *)opc; 994 if (puffs_pn_getvap(pn)->va_type == VDIR) { 995 op = FUSE_OPENDIR; 996 pmode = PUFFS_VREAD|PUFFS_VEXEC; 997 } else { 998 op = FUSE_OPEN; 999 if (mode & (O_RDWR|O_WRONLY)) 1000 pmode = PUFFS_VWRITE; 1001 else 1002 pmode = PUFFS_VREAD; 1003 } 1004 1005 /* 1006 * Opening a directory require R-X on the directory 1007 * Opening a file requires R-- for reading, -W- for writing 1008 * In both cases, --X is required on the parent. 1009 */ 1010 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1011 pcr, PUFFS_VEXEC)) 1012 return EACCES; 1013 1014 if (no_access(opc, pcr, pmode)) 1015 return EACCES; 1016 1017 /* 1018 * libfuse docs say O_CREAT should not be set. 1019 */ 1020 mode &= ~O_CREAT; 1021 1022 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1023 foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1024 foi->flags = mode & ~O_ACCMODE; 1025 switch (mode & (FREAD|FWRITE)) { 1026 case FREAD|FWRITE: 1027 foi->flags |= O_RDWR; 1028 break; 1029 case FREAD: 1030 foi->flags |= O_RDONLY; 1031 break; 1032 case FWRITE: 1033 foi->flags |= O_WRONLY; 1034 break; 1035 default: 1036 break; 1037 } 1038 foi->unused = 0; 1039 1040 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*foo))) != 0) 1041 goto out; 1042 1043 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1044 1045 /* 1046 * Save the file handle in node private data 1047 * so that we can reuse it later 1048 */ 1049 perfuse_new_fh((puffs_cookie_t)pn, foo->fh); 1050 1051 #ifdef PERFUSE_DEBUG 1052 if (perfuse_diagflags & PDF_FH) 1053 DPRINTF("%s: opc = %p, file = \"%s\", " 1054 "ino = %lld, fh = 0x%llx\n", 1055 __func__, (void *)opc, 1056 (char *)PNPATH((struct puffs_node *)opc), 1057 PERFUSE_NODE_DATA(opc)->pnd_ino, foo->fh); 1058 #endif 1059 out: 1060 ps->ps_destroy_msg(pm); 1061 1062 return error; 1063 } 1064 1065 /* ARGSUSED2 */ 1066 int 1067 perfuse_node_close(pu, opc, flags, pcr) 1068 struct puffs_usermount *pu; 1069 puffs_cookie_t opc; 1070 int flags; 1071 const struct puffs_cred *pcr; 1072 { 1073 struct perfuse_state *ps; 1074 perfuse_msg_t *pm; 1075 int op; 1076 uint64_t fh; 1077 struct perfuse_node_data *pnd; 1078 struct fuse_release_in *fri; 1079 struct puffs_node *pn; 1080 int error; 1081 1082 ps = puffs_getspecific(pu); 1083 pn = (struct puffs_node *)opc; 1084 pnd = PERFUSE_NODE_DATA(pn); 1085 1086 if (puffs_pn_getvap(pn)->va_type == VDIR) 1087 op = FUSE_RELEASEDIR; 1088 else 1089 op = FUSE_RELEASE; 1090 1091 if (!(pnd->pnd_flags & PND_OPEN)) 1092 return EBADF; 1093 1094 fh = perfuse_get_fh(opc); 1095 1096 /* 1097 * Sync before close for files 1098 */ 1099 if ((op == FUSE_RELEASE) && (pnd->pnd_flags & PND_DIRTY)) { 1100 #ifdef PERFUSE_DEBUG 1101 if (perfuse_diagflags & PDF_SYNC) 1102 DPRINTF("%s: SYNC opc = %p, file = \"%s\"\n", 1103 __func__, (void*)opc, (char *)PNPATH(pn)); 1104 #endif 1105 if ((error = perfuse_node_fsync(pu, opc, pcr, 0, 0, 0)) != 0) 1106 return error; 1107 1108 pnd->pnd_flags &= ~PND_DIRTY; 1109 1110 #ifdef PERFUSE_DEBUG 1111 if (perfuse_diagflags & PDF_SYNC) 1112 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 1113 __func__, (void*)opc, (char *)PNPATH((pn))); 1114 #endif 1115 } 1116 1117 /* 1118 * Destroy the filehandle before sending the 1119 * request to the FUSE filesystem, otherwise 1120 * we may get a second close() while we wait 1121 * for the reply, and we would end up closing 1122 * the same fh twice instead of closng both. 1123 */ 1124 perfuse_destroy_fh(pn, fh); 1125 1126 #ifdef PERFUSE_DEBUG 1127 if (perfuse_diagflags & PDF_FH) 1128 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1129 __func__, (void *)opc, pnd->pnd_ino, fh); 1130 #endif 1131 1132 /* 1133 * release_flags may be set to FUSE_RELEASE_FLUSH 1134 * to flush locks. lock_owner must be set in that case 1135 */ 1136 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL); 1137 fri = GET_INPAYLOAD(ps, pm, fuse_release_in); 1138 fri->fh = fh; 1139 fri->flags = 0; 1140 fri->release_flags = 0; 1141 fri->lock_owner = PERFUSE_NODE_DATA(pn)->pnd_lock_owner; 1142 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0; 1143 1144 #ifdef PERFUSE_DEBUG 1145 if (perfuse_diagflags & PDF_FH) 1146 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1147 __func__, (void *)opc, pnd->pnd_ino, fri->fh); 1148 #endif 1149 1150 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0) 1151 goto out; 1152 1153 out: 1154 if (error != 0) 1155 DWARNX("%s: freed fh = 0x%llx but filesystem returned error = %d", 1156 __func__, fh, error); 1157 1158 ps->ps_destroy_msg(pm); 1159 1160 return error; 1161 } 1162 1163 int 1164 perfuse_node_access(pu, opc, mode, pcr) 1165 struct puffs_usermount *pu; 1166 puffs_cookie_t opc; 1167 int mode; 1168 const struct puffs_cred *pcr; 1169 { 1170 perfuse_msg_t *pm; 1171 struct perfuse_state *ps; 1172 struct fuse_access_in *fai; 1173 int error; 1174 1175 /* 1176 * If we previously detected the filesystem does not 1177 * implement access(), short-circuit the call and skip 1178 * to libpffs access() emulation. 1179 */ 1180 ps = puffs_getspecific(pu); 1181 if (ps->ps_flags & PS_NO_ACCESS) { 1182 error = ENOSYS; 1183 } else { 1184 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr); 1185 fai = GET_INPAYLOAD(ps, pm, fuse_access_in); 1186 fai->mask = mode; 1187 1188 error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN); 1189 ps->ps_destroy_msg(pm); 1190 } 1191 1192 if (error == ENOSYS) { 1193 struct fuse_getattr_in *fgi; 1194 struct fuse_attr_out *fao; 1195 1196 ps->ps_flags |= PS_NO_ACCESS; 1197 1198 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, 1199 sizeof(*fgi), NULL); 1200 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1201 fgi->getattr_flags = 0; 1202 fgi->dummy = 0; 1203 fgi->fh = perfuse_get_fh(opc); 1204 1205 #ifdef PERFUSE_DEBUG 1206 if (perfuse_diagflags & PDF_FH) 1207 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1208 __func__, (void *)opc, 1209 PERFUSE_NODE_DATA(opc)->pnd_ino, fgi->fh); 1210 #endif 1211 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) { 1212 ps->ps_destroy_msg(pm); 1213 goto out; 1214 } 1215 1216 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1217 1218 error = puffs_access(VREG, fao->attr.mode, fao->attr.uid, 1219 fao->attr.gid, (mode_t)mode, pcr); 1220 1221 ps->ps_destroy_msg(pm); 1222 } 1223 1224 out: 1225 return error; 1226 } 1227 1228 int 1229 perfuse_node_getattr(pu, opc, vap, pcr) 1230 struct puffs_usermount *pu; 1231 puffs_cookie_t opc; 1232 struct vattr *vap; 1233 const struct puffs_cred *pcr; 1234 { 1235 perfuse_msg_t *pm; 1236 struct perfuse_state *ps; 1237 struct fuse_getattr_in *fgi; 1238 struct fuse_attr_out *fao; 1239 int error; 1240 1241 /* 1242 * getattr requires --X on the parent directory 1243 */ 1244 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1245 pcr, PUFFS_VEXEC)) 1246 return EACCES; 1247 1248 ps = puffs_getspecific(pu); 1249 1250 /* 1251 * FUSE_GETATTR_FH must be set in fgi->flags 1252 * if we use for fgi->fh, but we do not. 1253 */ 1254 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr); 1255 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1256 fgi->getattr_flags = 0; 1257 fgi->dummy = 0; 1258 fgi->fh = 0; 1259 1260 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) 1261 goto out; 1262 1263 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1264 1265 /* 1266 * The message from filesystem has a cache timeout 1267 * XXX this is ignored yet, is that right? 1268 * 1269 * We also set birthtime, flags, filerev,vaflags to 0. 1270 * This seems the best bet, since the information is 1271 * not available from filesystem. 1272 */ 1273 fuse_attr_to_vap(ps, vap, &fao->attr); 1274 1275 out: 1276 ps->ps_destroy_msg(pm); 1277 1278 return error; 1279 } 1280 1281 int 1282 perfuse_node_setattr(pu, opc, vap, pcr) 1283 struct puffs_usermount *pu; 1284 puffs_cookie_t opc; 1285 const struct vattr *vap; 1286 const struct puffs_cred *pcr; 1287 { 1288 perfuse_msg_t *pm; 1289 uint64_t fh; 1290 struct perfuse_state *ps; 1291 struct fuse_setattr_in *fsi; 1292 int error; 1293 struct vattr *old_va; 1294 1295 /* 1296 * setattr requires --X on the parent directory 1297 */ 1298 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1299 pcr, PUFFS_VEXEC)) 1300 return EACCES; 1301 1302 old_va = puffs_pn_getvap((struct puffs_node *)opc); 1303 1304 /* 1305 * Check for permission to change size 1306 */ 1307 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1308 no_access(opc, pcr, PUFFS_VWRITE)) 1309 return EACCES; 1310 1311 /* 1312 * Check for permission to change dates 1313 */ 1314 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || 1315 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && 1316 (puffs_access_times(old_va->va_uid, old_va->va_gid, 1317 old_va->va_mode, 0, pcr) != 0)) 1318 return EACCES; 1319 1320 /* 1321 * Check for permission to change owner and group 1322 */ 1323 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1324 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1325 (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1326 vap->va_uid, vap->va_gid, pcr)) != 0) 1327 return EACCES; 1328 1329 /* 1330 * Check for permission to change permissions 1331 */ 1332 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1333 (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1334 old_va->va_type, vap->va_mode, pcr)) != 0) 1335 return EACCES; 1336 1337 1338 ps = puffs_getspecific(pu); 1339 1340 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1341 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1342 fsi->valid = 0; 1343 1344 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1345 fh = perfuse_get_fh(opc); 1346 fsi->fh = fh; 1347 if (fh != FUSE_UNKNOWN_FH) 1348 fsi->valid |= FUSE_FATTR_FH; 1349 } 1350 1351 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1352 fsi->size = vap->va_size; 1353 fsi->valid |= FUSE_FATTR_SIZE; 1354 } 1355 1356 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1357 fsi->atime = vap->va_atime.tv_sec;; 1358 fsi->atimensec = vap->va_atime.tv_nsec;; 1359 fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW); 1360 } 1361 1362 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 1363 fsi->mtime = vap->va_mtime.tv_sec;; 1364 fsi->mtimensec = vap->va_mtime.tv_nsec;; 1365 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_MTIME_NOW); 1366 } 1367 1368 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { 1369 fsi->mode = vap->va_mode; 1370 fsi->valid |= FUSE_FATTR_MODE; 1371 } 1372 1373 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1374 fsi->uid = vap->va_uid; 1375 fsi->valid |= FUSE_FATTR_UID; 1376 } 1377 1378 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1379 fsi->gid = vap->va_gid; 1380 fsi->valid |= FUSE_FATTR_GID; 1381 } 1382 1383 if (PERFUSE_NODE_DATA(opc)->pnd_lock_owner != 0) { 1384 fsi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 1385 fsi->valid |= FUSE_FATTR_LOCKOWNER; 1386 } 1387 1388 /* 1389 * A fuse_attr_out is returned, but we ignore it. 1390 */ 1391 error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out)); 1392 1393 ps->ps_destroy_msg(pm); 1394 1395 return error; 1396 } 1397 1398 int 1399 perfuse_node_poll(pu, opc, events) 1400 struct puffs_usermount *pu; 1401 puffs_cookie_t opc; 1402 int *events; 1403 { 1404 struct perfuse_state *ps; 1405 perfuse_msg_t *pm; 1406 struct fuse_poll_in *fpi; 1407 struct fuse_poll_out *fpo; 1408 int error; 1409 1410 ps = puffs_getspecific(pu); 1411 /* 1412 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1413 */ 1414 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1415 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1416 fpi->fh = perfuse_get_fh(opc); 1417 fpi->kh = 0; 1418 fpi->flags = 0; 1419 1420 #ifdef PERFUSE_DEBUG 1421 if (perfuse_diagflags & PDF_FH) 1422 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1423 __func__, (void *)opc, 1424 PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh); 1425 #endif 1426 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fpo))) != 0) 1427 goto out; 1428 1429 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1430 *events = fpo->revents; 1431 out: 1432 ps->ps_destroy_msg(pm); 1433 1434 return error; 1435 } 1436 1437 /* ARGSUSED0 */ 1438 int 1439 perfuse_node_mmap(pu, opc, flags, pcr) 1440 struct puffs_usermount *pu; 1441 puffs_cookie_t opc; 1442 int flags; 1443 const struct puffs_cred *pcr; 1444 { 1445 /* 1446 * Not implemented anymore in libfuse 1447 */ 1448 return ENOSYS; 1449 } 1450 1451 /* ARGSUSED2 */ 1452 int 1453 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi) 1454 struct puffs_usermount *pu; 1455 puffs_cookie_t opc; 1456 const struct puffs_cred *pcr; 1457 int flags; 1458 off_t offlo; 1459 off_t offhi; 1460 { 1461 perfuse_msg_t *pm; 1462 struct perfuse_state *ps; 1463 struct perfuse_node_data *pnd; 1464 struct fuse_fsync_in *ffi; 1465 uint64_t fh; 1466 int open_self; 1467 int error; 1468 1469 pm = NULL; 1470 open_self = 0; 1471 1472 /* 1473 * If we previously detected it as unimplemented, 1474 * skip the call to the filesystem. 1475 */ 1476 ps = puffs_getspecific(pu); 1477 if (ps->ps_flags == PS_NO_FSYNC) 1478 return ENOSYS; 1479 1480 /* 1481 * Do not sync if there are no change to sync 1482 * XXX remove that testif we implement mmap 1483 */ 1484 pnd = PERFUSE_NODE_DATA(opc); 1485 #ifdef PERFUSE_DEBUG 1486 if (perfuse_diagflags & PDF_SYNC) 1487 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 1488 __func__, (void*)opc, 1489 (char *)PNPATH((struct puffs_node *)opc), 1490 pnd->pnd_flags & PND_DIRTY ? "" : "not "); 1491 #endif 1492 if (!(pnd->pnd_flags & PND_DIRTY)) 1493 return 0; 1494 1495 /* 1496 * It seems NetBSD can call fsync without open first 1497 * glusterfs complain in such a situation: 1498 * "FSYNC() ERR => -1 (Invalid argument)" 1499 */ 1500 if (!(pnd->pnd_flags & PND_OPEN)) { 1501 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 1502 goto out; 1503 open_self = 1; 1504 } 1505 1506 fh = perfuse_get_fh(opc); 1507 1508 /* 1509 * If fsync_flags is set, meta data should not be flushed. 1510 */ 1511 pm = ps->ps_new_msg(pu, opc, FUSE_FSYNC, sizeof(*ffi), NULL); 1512 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 1513 ffi->fh = fh; 1514 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 1515 1516 #ifdef PERFUSE_DEBUG 1517 if (perfuse_diagflags & PDF_FH) 1518 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1519 __func__, (void *)opc, 1520 PERFUSE_NODE_DATA(opc)->pnd_ino, ffi->fh); 1521 #endif 1522 1523 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0) 1524 goto out; 1525 1526 /* 1527 * No reply beyond fuse_out_header: nothing to do on success 1528 * just clear the dirty flag 1529 */ 1530 pnd->pnd_flags &= ~PND_DIRTY; 1531 1532 #ifdef PERFUSE_DEBUG 1533 if (perfuse_diagflags & PDF_SYNC) 1534 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 1535 __func__, (void*)opc, 1536 (char *)PNPATH((struct puffs_node *)opc)); 1537 #endif 1538 1539 out: 1540 if (error == ENOSYS) 1541 ps->ps_flags |= PS_NO_FSYNC; 1542 1543 if (pm != NULL) 1544 ps->ps_destroy_msg(pm); 1545 1546 if (open_self) 1547 (void)perfuse_node_close(pu, opc, 0, pcr); 1548 1549 return error; 1550 } 1551 1552 /* ARGSUSED0 */ 1553 int 1554 perfuse_node_seek(pu, opc, oldoff, newoff, pcr) 1555 struct puffs_usermount *pu; 1556 puffs_cookie_t opc; 1557 off_t oldoff; 1558 off_t newoff; 1559 const struct puffs_cred *pcr; 1560 { 1561 /* 1562 * XXX what should I do with oldoff? 1563 * XXX where is the newoffset returned? 1564 * XXX the held seek pointer seems just unused 1565 */ 1566 PERFUSE_NODE_DATA(opc)->pnd_offset = newoff; 1567 1568 return 0; 1569 } 1570 1571 int 1572 perfuse_node_remove(pu, opc, targ, pcn) 1573 struct puffs_usermount *pu; 1574 puffs_cookie_t opc; 1575 puffs_cookie_t targ; 1576 const struct puffs_cn *pcn; 1577 { 1578 struct perfuse_state *ps; 1579 perfuse_msg_t *pm; 1580 struct puffs_node *pn; 1581 char *path; 1582 const char *name; 1583 size_t len; 1584 int error; 1585 1586 /* 1587 * remove requires -WX on the parent directory 1588 * no right required on the object. 1589 */ 1590 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1591 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1592 return EACCES; 1593 1594 ps = puffs_getspecific(pu); 1595 1596 if (targ == NULL) 1597 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 1598 1599 pn = (struct puffs_node *)targ; 1600 name = basename_r((char *)PNPATH(pn)); 1601 len = strlen(name) + 1; 1602 1603 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); 1604 path = _GET_INPAYLOAD(ps, pm, char *); 1605 (void)strlcpy(path, name, len); 1606 1607 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1608 goto out; 1609 1610 if (puffs_inval_namecache_dir(pu, opc) != 0) 1611 DERR(EX_OSERR, "puffs_inval_namecache_dir failed"); 1612 1613 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0) 1614 DERR(EX_OSERR, "puffs_inval_namecache_node failed"); 1615 1616 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 1617 1618 /* 1619 * Reclaim should take care of decreasing pnd_childcount 1620 */ 1621 out: 1622 ps->ps_destroy_msg(pm); 1623 1624 return error; 1625 } 1626 1627 int 1628 perfuse_node_link(pu, opc, targ, pcn) 1629 struct puffs_usermount *pu; 1630 puffs_cookie_t opc; 1631 puffs_cookie_t targ; 1632 const struct puffs_cn *pcn; 1633 { 1634 struct perfuse_state *ps; 1635 perfuse_msg_t *pm; 1636 const char *name; 1637 size_t len; 1638 struct puffs_node *pn; 1639 struct fuse_link_in *fli; 1640 int error; 1641 1642 /* 1643 * Create an object require -WX permission in the parent directory 1644 */ 1645 if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1646 return EACCES; 1647 1648 1649 ps = puffs_getspecific(pu); 1650 pn = (struct puffs_node *)targ; 1651 name = basename_r((char *)PCNPATH(pcn)); 1652 len = sizeof(*fli) + strlen(name) + 1; 1653 1654 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred); 1655 fli = GET_INPAYLOAD(ps, pm, fuse_link_in); 1656 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_ino; 1657 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli)); 1658 1659 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN); 1660 1661 ps->ps_destroy_msg(pm); 1662 1663 return error; 1664 } 1665 1666 /* targ is unused since the name is in pcn_targ */ 1667 /* ARGSUSED5 */ 1668 int 1669 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ) 1670 struct puffs_usermount *pu; 1671 puffs_cookie_t opc; 1672 puffs_cookie_t src; 1673 const struct puffs_cn *pcn_src; 1674 puffs_cookie_t targ_dir; 1675 puffs_cookie_t targ; 1676 const struct puffs_cn *pcn_targ; 1677 { 1678 struct perfuse_state *ps; 1679 perfuse_msg_t *pm; 1680 struct fuse_rename_in *fri; 1681 const char *newname; 1682 const char *oldname; 1683 char *np; 1684 int error; 1685 size_t len; 1686 size_t newname_len; 1687 size_t oldname_len; 1688 1689 /* 1690 * move requires -WX on source and destination directory 1691 */ 1692 if (no_access(src, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC) || 1693 no_access(targ, pcn_targ->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1694 return EACCES; 1695 1696 ps = puffs_getspecific(pu); 1697 newname = basename_r((char *)PCNPATH(pcn_targ)); 1698 newname_len = strlen(newname) + 1; 1699 oldname = basename_r((char *)PCNPATH(pcn_src)); 1700 oldname_len = strlen(oldname) + 1; 1701 1702 len = sizeof(*fri) + oldname_len + newname_len; 1703 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_src->pcn_cred); 1704 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in); 1705 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_ino; 1706 np = (char *)(void *)(fri + 1); 1707 (void)strlcpy(np, oldname, oldname_len); 1708 np += oldname_len; 1709 (void)strlcpy(np, newname, newname_len); 1710 1711 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1712 goto out; 1713 1714 /* 1715 * Update source and destination directories child count 1716 * Update moved object parent directory 1717 */ 1718 PERFUSE_NODE_DATA(opc)->pnd_childcount--; 1719 PERFUSE_NODE_DATA(targ_dir)->pnd_childcount++; 1720 PERFUSE_NODE_DATA(src)->pnd_parent = targ_dir; 1721 1722 out: 1723 ps->ps_destroy_msg(pm); 1724 1725 return error; 1726 } 1727 1728 int 1729 perfuse_node_mkdir(pu, opc, pni, pcn, vap) 1730 struct puffs_usermount *pu; 1731 puffs_cookie_t opc; 1732 struct puffs_newinfo *pni; 1733 const struct puffs_cn *pcn; 1734 const struct vattr *vap; 1735 { 1736 struct perfuse_state *ps; 1737 perfuse_msg_t *pm; 1738 struct fuse_mkdir_in *fmi; 1739 const char *path; 1740 size_t len; 1741 1742 /* 1743 * Create an object require -WX permission in the parent directory 1744 */ 1745 if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1746 return EACCES; 1747 1748 ps = puffs_getspecific(pu); 1749 path = basename_r((char *)PCNPATH(pcn)); 1750 len = sizeof(*fmi) + strlen(path) + 1; 1751 1752 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred); 1753 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in); 1754 fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 1755 fmi->umask = 0; /* Seems unused bu libfuse? */ 1756 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 1757 1758 return node_mk_common(pu, opc, pni, pcn, vap, pm); 1759 } 1760 1761 1762 int 1763 perfuse_node_rmdir(pu, opc, targ, pcn) 1764 struct puffs_usermount *pu; 1765 puffs_cookie_t opc; 1766 puffs_cookie_t targ; 1767 const struct puffs_cn *pcn; 1768 { 1769 struct perfuse_state *ps; 1770 perfuse_msg_t *pm; 1771 struct puffs_node *pn; 1772 char *path; 1773 const char *name; 1774 size_t len; 1775 int error; 1776 1777 /* 1778 * remove requires -WX on the parent directory 1779 * no right required on the object. 1780 */ 1781 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1782 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1783 return EACCES; 1784 1785 ps = puffs_getspecific(pu); 1786 pn = (struct puffs_node *)targ; 1787 name = basename_r((char *)PNPATH(pn)); 1788 len = strlen(name) + 1; 1789 1790 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred); 1791 path = _GET_INPAYLOAD(ps, pm, char *); 1792 (void)strlcpy(path, name, len); 1793 1794 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1795 goto out; 1796 1797 if (puffs_inval_namecache_dir(pu, opc) != 0) 1798 DERR(EX_OSERR, "puffs_inval_namecache_dir failed"); 1799 1800 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0) 1801 DERR(EX_OSERR, "puffs_inval_namecache_node failed"); 1802 1803 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 1804 1805 out: 1806 ps->ps_destroy_msg(pm); 1807 1808 return error; 1809 } 1810 1811 /* vap is unused */ 1812 /* ARGSUSED4 */ 1813 int 1814 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target) 1815 struct puffs_usermount *pu; 1816 puffs_cookie_t opc; 1817 struct puffs_newinfo *pni; 1818 const struct puffs_cn *pcn_src; 1819 const struct vattr *vap; 1820 const char *link_target; 1821 { 1822 struct perfuse_state *ps; 1823 perfuse_msg_t *pm; 1824 char *np; 1825 const char *path; 1826 size_t path_len; 1827 size_t linkname_len; 1828 size_t len; 1829 1830 /* 1831 * Create an object require -WX permission in the parent directory 1832 */ 1833 if (no_access(opc, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1834 return EACCES; 1835 1836 ps = puffs_getspecific(pu); 1837 path = basename_r((char *)PCNPATH(pcn_src)); 1838 path_len = strlen(path) + 1; 1839 linkname_len = strlen(link_target) + 1; 1840 len = path_len + linkname_len; 1841 1842 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred); 1843 np = _GET_INPAYLOAD(ps, pm, char *); 1844 (void)strlcpy(np, path, path_len); 1845 np += path_len; 1846 (void)strlcpy(np, link_target, linkname_len); 1847 1848 return node_mk_common(pu, opc, pni, pcn_src, vap, pm); 1849 } 1850 1851 int 1852 perfuse_node_readdir(pu, opc, dent, readoff, 1853 reslen, pcr, eofflag, cookies, ncookies) 1854 struct puffs_usermount *pu; 1855 puffs_cookie_t opc; 1856 struct dirent *dent; 1857 off_t *readoff; 1858 size_t *reslen; 1859 const struct puffs_cred *pcr; 1860 int *eofflag; 1861 off_t *cookies; 1862 size_t *ncookies; 1863 { 1864 perfuse_msg_t *pm; 1865 uint64_t fh; 1866 struct perfuse_state *ps; 1867 struct perfuse_node_data *pnd; 1868 struct fuse_read_in *fri; 1869 struct fuse_out_header *foh; 1870 struct fuse_dirent *fd; 1871 size_t foh_len; 1872 int error; 1873 int open_self; 1874 uint64_t fd_offset; 1875 1876 pm = NULL; 1877 error = 0; 1878 open_self = 0; 1879 ps = puffs_getspecific(pu); 1880 1881 /* 1882 * readdir state is kept at node level, and several readdir 1883 * requests can be issued at the same time on the same node. 1884 * We need to queue requests so that only one is in readdir 1885 * code at the same time. 1886 */ 1887 pnd = PERFUSE_NODE_DATA(opc); 1888 while (pnd->pnd_flags & PND_INREADDIR) 1889 requeue_request(pu, opc, PCQ_READDIR); 1890 pnd->pnd_flags |= PND_INREADDIR; 1891 1892 #ifdef PERFUSE_DEBUG 1893 if (perfuse_diagflags & PDF_READDIR) 1894 DPRINTF("%s: READDIR opc = %p enter critical section\n", 1895 __func__, (void *)opc); 1896 #endif 1897 /* 1898 * Do we already have the data bufered? 1899 */ 1900 if (pnd->pnd_dirent != NULL) 1901 goto out; 1902 pnd->pnd_dirent_len = 0; 1903 1904 /* 1905 * It seems NetBSD can call readdir without open first 1906 * libfuse will crash if it is done that way, hence open first. 1907 */ 1908 if (!(PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN)) { 1909 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 1910 goto out; 1911 open_self = 1; 1912 } 1913 1914 fh = perfuse_get_fh(opc); 1915 1916 #ifdef PERFUSE_DEBUG 1917 if (perfuse_diagflags & PDF_FH) 1918 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 1919 __func__, (void *)opc, 1920 PERFUSE_NODE_DATA(opc)->pnd_ino, fh); 1921 #endif 1922 1923 pnd->pnd_all_fd = NULL; 1924 pnd->pnd_all_fd_len = 0; 1925 fd_offset = 0; 1926 1927 do { 1928 size_t fd_len; 1929 char *afdp; 1930 1931 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 1932 1933 /* 1934 * read_flags, lock_owner and flags are unused in libfuse 1935 * 1936 * XXX if fri->size is too big (bigger than PAGE_SIZE?), * we get strange bugs. ktrace shows 16 bytes or garbage 1937 * at the end of sent frames, but perfused does not receive 1938 * that data. The data length is hoverver the same, which 1939 * cause perfused to use the last 16 bytes of the frame 1940 * as the frame header of the next frame. 1941 * 1942 * This may be a kernel bug. 1943 */ 1944 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 1945 fri->fh = fh; 1946 fri->offset = fd_offset; 1947 fri->size = PAGE_SIZE - sizeof(struct fuse_out_header); 1948 fri->read_flags = 0; 1949 fri->lock_owner = 0; 1950 fri->flags = 0; 1951 1952 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1953 goto out; 1954 1955 /* 1956 * There are many puffs_framebufs calls later, 1957 * therefore foh will not be valid for a long time. 1958 * Just get the length and forget it. 1959 */ 1960 foh = GET_OUTHDR(ps, pm); 1961 foh_len = foh->len; 1962 1963 /* 1964 * It seems that the only way to discover the end 1965 * of the buffer is to get an empty read 1966 */ 1967 if (foh_len == sizeof(*foh)) 1968 break; 1969 1970 /* 1971 * Corrupted message. 1972 */ 1973 if (foh_len < sizeof(*foh) + sizeof(*fd)) { 1974 DWARNX("readdir reply too short"); 1975 error = EIO; 1976 goto out; 1977 } 1978 1979 1980 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent); 1981 fd_len = foh_len - sizeof(*foh); 1982 1983 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd, 1984 pnd->pnd_all_fd_len + fd_len); 1985 if (pnd->pnd_all_fd == NULL) 1986 DERR(EX_OSERR, "malloc failed"); 1987 1988 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len; 1989 (void)memcpy(afdp, fd, fd_len); 1990 1991 pnd->pnd_all_fd_len += fd_len; 1992 fd_offset += fd_len; 1993 1994 ps->ps_destroy_msg(pm); 1995 pm = NULL; 1996 } while (1 /* CONSTCOND */); 1997 1998 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, pnd->pnd_all_fd_len) == -1) 1999 error = EIO; 2000 2001 out: 2002 if (pnd->pnd_all_fd != NULL) { 2003 free(pnd->pnd_all_fd); 2004 pnd->pnd_all_fd = NULL; 2005 pnd->pnd_all_fd_len = 0; 2006 } 2007 2008 if (pm != NULL) 2009 ps->ps_destroy_msg(pm); 2010 2011 /* 2012 * If we opened the directory ourselves, close now 2013 * errors are ignored. 2014 */ 2015 if (open_self) 2016 (void)perfuse_node_close(pu, opc, 0, pcr); 2017 2018 if (error == 0) 2019 error = readdir_buffered(ps, opc, dent, readoff, 2020 reslen, pcr, eofflag, cookies, ncookies); 2021 2022 /* 2023 * Schedule queued readdir requests 2024 */ 2025 dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL); 2026 pnd->pnd_flags &= ~PND_INREADDIR; 2027 2028 #ifdef PERFUSE_DEBUG 2029 if (perfuse_diagflags & PDF_READDIR) 2030 DPRINTF("%s: READDIR opc = %p exit critical section\n", 2031 __func__, (void *)opc); 2032 #endif 2033 2034 return error; 2035 } 2036 2037 int 2038 perfuse_node_readlink(pu, opc, pcr, linkname, linklen) 2039 struct puffs_usermount *pu; 2040 puffs_cookie_t opc; 2041 const struct puffs_cred *pcr; 2042 char *linkname; 2043 size_t *linklen; 2044 { 2045 struct perfuse_state *ps; 2046 perfuse_msg_t *pm; 2047 int error; 2048 size_t len; 2049 struct fuse_out_header *foh; 2050 2051 /* 2052 * --X required on parent, R-- required on link 2053 */ 2054 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 2055 pcr, PUFFS_VEXEC) || 2056 no_access(opc, pcr, PUFFS_VREAD)) 2057 return EACCES; 2058 2059 ps = puffs_getspecific(pu); 2060 2061 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr); 2062 2063 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 2064 goto out; 2065 2066 foh = GET_OUTHDR(ps, pm); 2067 len = foh->len - sizeof(*foh) + 1; 2068 if (len > *linklen) 2069 DERRX(EX_PROTOCOL, "path len = %d too long", len); 2070 2071 *linklen = len; 2072 (void)strlcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len); 2073 out: 2074 ps->ps_destroy_msg(pm); 2075 2076 return error; 2077 } 2078 2079 int 2080 perfuse_node_reclaim(pu, opc) 2081 struct puffs_usermount *pu; 2082 puffs_cookie_t opc; 2083 { 2084 struct perfuse_state *ps; 2085 perfuse_msg_t *pm; 2086 struct perfuse_node_data *pnd; 2087 struct fuse_forget_in *ffi; 2088 struct puffs_node *pn; 2089 struct puffs_node *pn_root; 2090 2091 ps = puffs_getspecific(pu); 2092 pnd = PERFUSE_NODE_DATA(opc); 2093 2094 /* 2095 * Make sure open files are properly closed when reclaimed. 2096 */ 2097 while (pnd->pnd_flags & PND_OPEN) 2098 (void)perfuse_node_close(pu, opc, 0, NULL); 2099 2100 /* 2101 * Never forget the root. 2102 */ 2103 if (pnd->pnd_ino == FUSE_ROOT_ID) 2104 return 0; 2105 2106 pnd->pnd_flags |= PND_RECLAIMED; 2107 2108 #ifdef PERFUSE_DEBUG 2109 if (perfuse_diagflags & PDF_RECLAIM) 2110 DPRINTF("%s (nodeid %lld) reclaimed\n", 2111 (char *)PNPATH((struct puffs_node *)opc), pnd->pnd_ino); 2112 #endif 2113 2114 pn_root = puffs_getroot(pu); 2115 pn = (struct puffs_node *)opc; 2116 while (pn != pn_root) { 2117 struct puffs_node *parent_pn; 2118 2119 pnd = PERFUSE_NODE_DATA(pn); 2120 2121 #ifdef PERFUSE_DEBUG 2122 if (perfuse_diagflags & PDF_RECLAIM) 2123 DPRINTF("%s (nodeid %lld) is %sreclaimed, " 2124 "has childcount %d, %sopen\n", 2125 (char *)PNPATH(pn), pnd->pnd_ino, 2126 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2127 pnd->pnd_childcount, 2128 pnd->pnd_flags & PND_OPEN ? "" : "not "); 2129 2130 if (pnd->pnd_flags & PND_OPEN) 2131 DWARNX("%s: (nodeid %lld) %s is still open", 2132 __func__, pnd->pnd_ino, (char *)PNPATH(pn)); 2133 #endif 2134 2135 if (!(pnd->pnd_flags & PND_RECLAIMED) || 2136 (pnd->pnd_childcount != 0)) 2137 return 0; 2138 2139 /* 2140 * If the file is still open, close all file handles 2141 * XXX no pcr arguement to send. 2142 */ 2143 while(pnd->pnd_flags & PND_OPEN) 2144 (void)perfuse_node_close(pu, opc, 0, NULL); 2145 2146 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET, 2147 sizeof(*ffi), NULL); 2148 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2149 ffi->nlookup = pnd->pnd_nlookup; 2150 2151 /* 2152 * No reply is expected, pm is freed in XCHG_MSG 2153 */ 2154 (void)XCHG_MSG_NOREPLY(ps, pu, pm, UNSPEC_REPLY_LEN); 2155 2156 parent_pn = pnd->pnd_parent; 2157 2158 perfuse_destroy_pn(pn); 2159 puffs_pn_put(pn); 2160 2161 pn = parent_pn; 2162 } 2163 2164 return 0; 2165 } 2166 2167 /* ARGSUSED0 */ 2168 int 2169 perfuse_node_inactive(pu, opc) 2170 struct puffs_usermount *pu; 2171 puffs_cookie_t opc; 2172 { 2173 return 0; 2174 } 2175 2176 2177 /* ARGSUSED0 */ 2178 int 2179 perfuse_node_print(pu, opc) 2180 struct puffs_usermount *pu; 2181 puffs_cookie_t opc; 2182 { 2183 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2184 return 0; 2185 } 2186 2187 /* ARGSUSED0 */ 2188 int 2189 perfuse_node_pathconf(pu, opc, name, retval) 2190 struct puffs_usermount *pu; 2191 puffs_cookie_t opc; 2192 int name; 2193 int *retval; 2194 { 2195 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2196 return 0; 2197 } 2198 2199 /* id is unused */ 2200 /* ARGSUSED2 */ 2201 int 2202 perfuse_node_advlock(pu, opc, id, op, fl, flags) 2203 struct puffs_usermount *pu; 2204 puffs_cookie_t opc; 2205 void *id; 2206 int op; 2207 struct flock *fl; 2208 int flags; 2209 { 2210 struct perfuse_state *ps; 2211 int fop; 2212 perfuse_msg_t *pm; 2213 struct fuse_lk_in *fli; 2214 struct fuse_lk_out *flo; 2215 int error; 2216 2217 ps = puffs_getspecific(pu); 2218 2219 if (op == F_GETLK) 2220 fop = FUSE_GETLK; 2221 else 2222 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2223 2224 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 2225 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 2226 fli->fh = perfuse_get_fh(opc); 2227 fli->owner = fl->l_pid; 2228 fli->lk.start = fl->l_start; 2229 fli->lk.end = fl->l_start + fl->l_len; 2230 fli->lk.type = fl->l_type; 2231 fli->lk.pid = fl->l_pid; 2232 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 2233 2234 #ifdef PERFUSE_DEBUG 2235 if (perfuse_diagflags & PDF_FH) 2236 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 2237 __func__, (void *)opc, 2238 PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh); 2239 #endif 2240 2241 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*flo))) != 0) 2242 goto out; 2243 2244 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out); 2245 fl->l_start = flo->lk.start; 2246 fl->l_len = flo->lk.end - flo->lk.start; 2247 fl->l_pid = flo->lk.pid; 2248 fl->l_type = flo->lk.type; 2249 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */ 2250 2251 /* 2252 * Save or clear the lock 2253 */ 2254 switch (op) { 2255 case F_SETLK: 2256 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid; 2257 break; 2258 case F_UNLCK: 2259 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = 0; 2260 break; 2261 default: 2262 break; 2263 } 2264 2265 out: 2266 ps->ps_destroy_msg(pm); 2267 2268 return error; 2269 } 2270 2271 int 2272 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag) 2273 struct puffs_usermount *pu; 2274 puffs_cookie_t opc; 2275 uint8_t *buf; 2276 off_t offset; 2277 size_t *resid; 2278 const struct puffs_cred *pcr; 2279 int ioflag; 2280 { 2281 struct perfuse_state *ps; 2282 perfuse_msg_t *pm; 2283 struct fuse_read_in *fri; 2284 struct fuse_out_header *foh; 2285 size_t readen; 2286 size_t requested; 2287 int error; 2288 2289 ps = puffs_getspecific(pu); 2290 pm = NULL; 2291 2292 requested = *resid; 2293 if ((ps->ps_readahead + requested) > ps->ps_max_readahead) { 2294 if (perfuse_diagflags & PDF_REQUEUE) 2295 DPRINTF("readahead = %d\n", ps->ps_readahead); 2296 requeue_request(pu, opc, PCQ_READ); 2297 } 2298 ps->ps_readahead += requested; 2299 2300 do { 2301 /* 2302 * flags may be set to FUSE_READ_LOCKOWNER 2303 * if lock_owner is provided. 2304 * 2305 * XXX See comment about fri->size in perfuse_node_readdir 2306 * We encounter the same bug here. 2307 */ 2308 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 2309 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2310 fri->fh = perfuse_get_fh(opc); 2311 fri->offset = offset; 2312 fri->size = MIN(*resid, PAGE_SIZE - sizeof(*foh)); 2313 fri->read_flags = 0; /* XXX Unused by libfuse? */ 2314 fri->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 2315 fri->flags = 0; 2316 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 2317 2318 #ifdef PERFUSE_DEBUG 2319 if (perfuse_diagflags & PDF_FH) 2320 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 2321 __func__, (void *)opc, 2322 PERFUSE_NODE_DATA(opc)->pnd_ino, fri->fh); 2323 #endif 2324 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN); 2325 2326 if (error != 0) 2327 goto out; 2328 2329 foh = GET_OUTHDR(ps, pm); 2330 readen = foh->len - sizeof(*foh); 2331 2332 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 2333 2334 buf += readen; 2335 offset += readen; 2336 *resid -= readen; 2337 2338 ps->ps_destroy_msg(pm); 2339 pm = NULL; 2340 } while ((*resid != 0) && (readen != 0)); 2341 2342 if (ioflag & (IO_SYNC|IO_DSYNC)) 2343 ps->ps_syncreads++; 2344 else 2345 ps->ps_asyncreads++; 2346 2347 out: 2348 if (pm != NULL) 2349 ps->ps_destroy_msg(pm); 2350 2351 ps->ps_readahead -= requested; 2352 dequeue_requests(ps, opc, PCQ_READ, 1); 2353 2354 return error; 2355 } 2356 2357 int 2358 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag) 2359 struct puffs_usermount *pu; 2360 puffs_cookie_t opc; 2361 uint8_t *buf; 2362 off_t offset; 2363 size_t *resid; 2364 const struct puffs_cred *pcr; 2365 int ioflag; 2366 { 2367 struct perfuse_state *ps; 2368 perfuse_msg_t *pm; 2369 struct fuse_write_in *fwi; 2370 struct fuse_write_out *fwo; 2371 size_t data_len; 2372 size_t payload_len; 2373 size_t written; 2374 size_t requested; 2375 int error; 2376 2377 ps = puffs_getspecific(pu); 2378 pm = NULL; 2379 written = 0; 2380 2381 requested = *resid; 2382 if ((ps->ps_write + requested) > ps->ps_max_write) { 2383 if (perfuse_diagflags & PDF_REQUEUE) 2384 DPRINTF("write = %d\n", ps->ps_write); 2385 requeue_request(pu, opc, PCQ_WRITE); 2386 } 2387 ps->ps_write += requested; 2388 2389 do { 2390 /* 2391 * It seems libfuse does not expects big chunks, so 2392 * send it page per page. The writepage feature is 2393 * probably there to minmize data movement. 2394 * XXX use ps->ps_maxwrite? 2395 */ 2396 data_len = MIN(*resid, PAGE_SIZE); 2397 payload_len = data_len + sizeof(*fwi); 2398 2399 /* 2400 * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 2401 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 2402 * write_flags is set to 1 for writepage. 2403 */ 2404 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 2405 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 2406 fwi->fh = perfuse_get_fh(opc); 2407 fwi->offset = offset; 2408 fwi->size = data_len; 2409 fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1; 2410 fwi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 2411 fwi->flags = 0; 2412 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 2413 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE; 2414 (void)memcpy((fwi + 1), buf + written, data_len); 2415 2416 #ifdef PERFUSE_DEBUG 2417 if (perfuse_diagflags & PDF_FH) 2418 DPRINTF("%s: opc = %p, ino = %lld, fh = 0x%llx\n", 2419 __func__, (void *)opc, 2420 PERFUSE_NODE_DATA(opc)->pnd_ino, fwi->fh); 2421 #endif 2422 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fwo))) != 0) 2423 goto out; 2424 2425 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 2426 written = fwo->size; 2427 *resid -= written; 2428 offset += written; 2429 buf += written; 2430 2431 ps->ps_destroy_msg(pm); 2432 pm = NULL; 2433 } while (*resid != 0); 2434 2435 /* 2436 * puffs_ops(3) says 2437 * "everything must be written or an error will be generated" 2438 */ 2439 if (*resid != 0) 2440 error = EFBIG; 2441 2442 if (ioflag & (IO_SYNC|IO_DSYNC)) 2443 ps->ps_syncwrites++; 2444 else 2445 ps->ps_asyncwrites++; 2446 2447 /* 2448 * Remember to sync the file 2449 */ 2450 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2451 2452 #ifdef PERFUSE_DEBUG 2453 if (perfuse_diagflags & PDF_SYNC) 2454 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", 2455 __func__, (void*)opc, 2456 (char *)PNPATH((struct puffs_node *)opc)); 2457 #endif 2458 out: 2459 if (pm != NULL) 2460 ps->ps_destroy_msg(pm); 2461 2462 ps->ps_write -= requested; 2463 dequeue_requests(ps, opc, PCQ_WRITE, 1); 2464 2465 return error; 2466 } 2467 2468 /* ARGSUSED0 */ 2469 void 2470 perfuse_cache_write(pu, opc, size, runs) 2471 struct puffs_usermount *pu; 2472 puffs_cookie_t opc; 2473 size_t size; 2474 struct puffs_cacherun *runs; 2475 { 2476 return; 2477 } 2478 2479