1 /* $NetBSD: ops.c,v 1.44 2011/11/10 16:21:09 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 2010-2011 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/socket.h> 38 #include <sys/socket.h> 39 #include <sys/extattr.h> 40 #include <machine/vmparam.h> 41 42 #include "perfuse_priv.h" 43 #include "fuse.h" 44 45 extern int perfuse_diagflags; 46 47 static void set_expire(puffs_cookie_t, struct fuse_entry_out *, 48 struct fuse_attr_out *); 49 static int attr_expired(puffs_cookie_t); 50 static int entry_expired(puffs_cookie_t); 51 static int xchg_msg(struct puffs_usermount *, puffs_cookie_t, 52 perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply); 53 static int mode_access(puffs_cookie_t, const struct puffs_cred *, mode_t); 54 static int sticky_access(struct puffs_node *, const struct puffs_cred *); 55 static void fuse_attr_to_vap(struct perfuse_state *, 56 struct vattr *, struct fuse_attr *); 57 static int node_lookup_dir_nodot(struct puffs_usermount *, 58 puffs_cookie_t, char *, size_t, struct puffs_node **); 59 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t, 60 const char *, const struct puffs_cred *, struct puffs_node **); 61 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t, 62 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *); 63 static int node_mk_common_final(struct puffs_usermount *, puffs_cookie_t, 64 struct puffs_node *, const struct puffs_cn *pcn); 65 static uint64_t readdir_last_cookie(struct fuse_dirent *, size_t); 66 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t, 67 struct fuse_dirent *, size_t); 68 static int readdir_buffered(puffs_cookie_t, struct dirent *, off_t *, 69 size_t *); 70 static void requeue_request(struct puffs_usermount *, 71 puffs_cookie_t opc, enum perfuse_qtype); 72 static int dequeue_requests(struct perfuse_state *, 73 puffs_cookie_t opc, enum perfuse_qtype, int); 74 #define DEQUEUE_ALL 0 75 76 /* 77 * From <sys/vnode>, inside #ifdef _KERNEL section 78 */ 79 #define IO_SYNC (0x40|IO_DSYNC) 80 #define IO_DSYNC 0x00200 81 #define IO_DIRECT 0x02000 82 83 /* 84 * From <fcntl>, inside #ifdef _KERNEL section 85 */ 86 #define F_WAIT 0x010 87 #define F_FLOCK 0x020 88 #define OFLAGS(fflags) ((fflags) - 1) 89 90 /* 91 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h 92 */ 93 const enum vtype iftovt_tab[16] = { 94 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 95 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 96 }; 97 const int vttoif_tab[9] = { 98 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 99 S_IFSOCK, S_IFIFO, S_IFMT, 100 }; 101 102 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) 103 #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) 104 105 int 106 perfuse_node_close_common(pu, opc, mode) 107 struct puffs_usermount *pu; 108 puffs_cookie_t opc; 109 int mode; 110 { 111 struct perfuse_state *ps; 112 perfuse_msg_t *pm; 113 int op; 114 uint64_t fh; 115 struct fuse_release_in *fri; 116 struct perfuse_node_data *pnd; 117 struct puffs_node *pn; 118 int error; 119 120 ps = puffs_getspecific(pu); 121 pn = (struct puffs_node *)opc; 122 pnd = PERFUSE_NODE_DATA(pn); 123 124 if (puffs_pn_getvap(pn)->va_type == VDIR) { 125 op = FUSE_RELEASEDIR; 126 mode = FREAD; 127 } else { 128 op = FUSE_RELEASE; 129 } 130 131 /* 132 * Destroy the filehandle before sending the 133 * request to the FUSE filesystem, otherwise 134 * we may get a second close() while we wait 135 * for the reply, and we would end up closing 136 * the same fh twice instead of closng both. 137 */ 138 fh = perfuse_get_fh(opc, mode); 139 perfuse_destroy_fh(pn, fh); 140 141 /* 142 * release_flags may be set to FUSE_RELEASE_FLUSH 143 * to flush locks. lock_owner must be set in that case 144 * 145 * ps_new_msg() is called with NULL creds, which will 146 * be interpreted as FUSE superuser. We come here from the 147 * inactive method, which provides no creds, but obviously 148 * runs with kernel privilege. 149 */ 150 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL); 151 fri = GET_INPAYLOAD(ps, pm, fuse_release_in); 152 fri->fh = fh; 153 fri->flags = 0; 154 fri->release_flags = 0; 155 fri->lock_owner = pnd->pnd_lock_owner; 156 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0; 157 158 #ifdef PERFUSE_DEBUG 159 if (perfuse_diagflags & PDF_FH) 160 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 161 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 162 #endif 163 164 if ((error = xchg_msg(pu, opc, pm, 165 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 166 goto out; 167 168 ps->ps_destroy_msg(pm); 169 170 error = 0; 171 172 out: 173 if (error != 0) 174 DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem " 175 "returned error = %d", __func__, fh, error); 176 177 return error; 178 } 179 180 /* ARGSUSED1 */ 181 static int 182 xchg_msg(pu, opc, pm, len, wait) 183 struct puffs_usermount *pu; 184 puffs_cookie_t opc; 185 perfuse_msg_t *pm; 186 size_t len; 187 enum perfuse_xchg_pb_reply wait; 188 { 189 struct perfuse_state *ps; 190 struct perfuse_node_data *pnd; 191 int error; 192 193 ps = puffs_getspecific(pu); 194 pnd = NULL; 195 if ((struct puffs_node *)opc != NULL) 196 pnd = PERFUSE_NODE_DATA(opc); 197 198 #ifdef PERFUSE_DEBUG 199 if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0)) 200 DPRINTF("file = \"%s\", ino = %"PRIu64" flags = 0x%x\n", 201 perfuse_node_path(opc), 202 ((struct puffs_node *)opc)->pn_va.va_fileid, 203 PERFUSE_NODE_DATA(opc)->pnd_flags); 204 #endif 205 if (pnd) 206 pnd->pnd_flags |= PND_INXCHG; 207 208 error = ps->ps_xchg_msg(pu, pm, len, wait); 209 210 if (pnd) { 211 pnd->pnd_flags &= ~PND_INXCHG; 212 (void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL); 213 } 214 215 return error; 216 } 217 218 static int 219 mode_access(opc, pcr, mode) 220 puffs_cookie_t opc; 221 const struct puffs_cred *pcr; 222 mode_t mode; 223 { 224 struct puffs_node *pn; 225 struct vattr *va; 226 227 /* 228 * pcr is NULL for self open through fsync or readdir. 229 * In both case, access control is useless, as it was 230 * done before, at open time. 231 */ 232 if (pcr == NULL) 233 return 0; 234 235 pn = (struct puffs_node *)opc; 236 va = puffs_pn_getvap(pn); 237 return puffs_access(va->va_type, va->va_mode, 238 va->va_uid, va->va_gid, 239 mode, pcr); 240 } 241 242 static int 243 sticky_access(targ, pcr) 244 struct puffs_node *targ; 245 const struct puffs_cred *pcr; 246 { 247 uid_t uid; 248 struct puffs_node *tdir; 249 int sticky, owner; 250 251 tdir = PERFUSE_NODE_DATA(targ)->pnd_parent; 252 253 /* 254 * This covers the case where the kernel requests a DELETE 255 * or RENAME on its own, and where puffs_cred_getuid would 256 * return -1. While such a situation should not happen, 257 * we allow it here. 258 * 259 * This also allows root to tamper with other users' files 260 * that have the sticky bit. 261 */ 262 if (puffs_cred_isjuggernaut(pcr)) 263 return 0; 264 265 if (puffs_cred_getuid(pcr, &uid) != 0) 266 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__); 267 268 sticky = puffs_pn_getvap(tdir)->va_mode & S_ISTXT; 269 owner = puffs_pn_getvap(targ)->va_uid == uid; 270 271 if (sticky && !owner) 272 return EACCES; 273 274 return 0; 275 } 276 277 278 static void 279 fuse_attr_to_vap(ps, vap, fa) 280 struct perfuse_state *ps; 281 struct vattr *vap; 282 struct fuse_attr *fa; 283 { 284 vap->va_type = IFTOVT(fa->mode); 285 vap->va_mode = fa->mode & ALLPERMS; 286 vap->va_nlink = fa->nlink; 287 vap->va_uid = fa->uid; 288 vap->va_gid = fa->gid; 289 vap->va_fsid = (long)ps->ps_fsid; 290 vap->va_fileid = fa->ino; 291 vap->va_size = fa->size; 292 vap->va_blocksize = fa->blksize; 293 vap->va_atime.tv_sec = (time_t)fa->atime; 294 vap->va_atime.tv_nsec = (long) fa->atimensec; 295 vap->va_mtime.tv_sec = (time_t)fa->mtime; 296 vap->va_mtime.tv_nsec = (long)fa->mtimensec; 297 vap->va_ctime.tv_sec = (time_t)fa->ctime; 298 vap->va_ctime.tv_nsec = (long)fa->ctimensec; 299 vap->va_birthtime.tv_sec = 0; 300 vap->va_birthtime.tv_nsec = 0; 301 vap->va_gen = 0; 302 vap->va_flags = 0; 303 vap->va_rdev = fa->rdev; 304 vap->va_bytes = fa->size; 305 vap->va_filerev = (u_quad_t)PUFFS_VNOVAL; 306 vap->va_vaflags = 0; 307 308 if (vap->va_blocksize == 0) 309 vap->va_blocksize = DEV_BSIZE; 310 311 if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */ 312 vap->va_size = 0; 313 314 return; 315 } 316 317 static void 318 set_expire(opc, feo, fao) 319 puffs_cookie_t opc; 320 struct fuse_entry_out *feo; 321 struct fuse_attr_out *fao; 322 { 323 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 324 struct timespec entry_ts; 325 struct timespec attr_ts; 326 struct timespec now; 327 328 if ((feo == NULL) && (fao == NULL)) 329 DERRX(EX_SOFTWARE, "%s: feo and fao NULL", __func__); 330 331 if ((feo != NULL) && (fao != NULL)) 332 DERRX(EX_SOFTWARE, "%s: feo and fao != NULL", __func__); 333 334 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 335 DERR(EX_OSERR, "clock_gettime failed"); 336 337 if (feo != NULL) { 338 entry_ts.tv_sec = (time_t)feo->entry_valid; 339 entry_ts.tv_nsec = (long)feo->entry_valid_nsec; 340 341 timespecadd(&now, &entry_ts, &pnd->pnd_entry_expire); 342 343 attr_ts.tv_sec = (time_t)feo->attr_valid; 344 attr_ts.tv_nsec = (long)feo->attr_valid_nsec; 345 346 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire); 347 } 348 349 if (fao != NULL) { 350 attr_ts.tv_sec = (time_t)fao->attr_valid; 351 attr_ts.tv_nsec = (long)fao->attr_valid_nsec; 352 353 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire); 354 } 355 356 return; 357 } 358 359 static int 360 attr_expired(opc) 361 puffs_cookie_t opc; 362 { 363 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 364 struct timespec now; 365 366 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 367 DERR(EX_OSERR, "clock_gettime failed"); 368 369 return timespeccmp(&pnd->pnd_attr_expire, &now, <); 370 } 371 372 static int 373 entry_expired(opc) 374 puffs_cookie_t opc; 375 { 376 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 377 struct timespec now; 378 379 if (clock_gettime(CLOCK_REALTIME, &now) != 0) 380 DERR(EX_OSERR, "clock_gettime failed"); 381 382 return timespeccmp(&pnd->pnd_entry_expire, &now, <); 383 } 384 385 386 /* 387 * Lookup name in directory opc 388 * We take special care of name being . or .. 389 * These are returned by readdir and deserve tweaks. 390 */ 391 static int 392 node_lookup_dir_nodot(pu, opc, name, namelen, pnp) 393 struct puffs_usermount *pu; 394 puffs_cookie_t opc; 395 char *name; 396 size_t namelen; 397 struct puffs_node **pnp; 398 { 399 /* 400 * "dot" is easy as we already know it 401 */ 402 if (strncmp(name, ".", namelen) == 0) { 403 *pnp = (struct puffs_node *)opc; 404 return 0; 405 } 406 407 /* 408 * "dotdot" is also known 409 */ 410 if (strncmp(name, "..", namelen) == 0) { 411 *pnp = PERFUSE_NODE_DATA(opc)->pnd_parent; 412 return 0; 413 } 414 415 return node_lookup_common(pu, opc, name, NULL, pnp); 416 } 417 418 static int 419 node_lookup_common(pu, opc, path, pcr, pnp) 420 struct puffs_usermount *pu; 421 puffs_cookie_t opc; 422 const char *path; 423 const struct puffs_cred *pcr; 424 struct puffs_node **pnp; 425 { 426 struct perfuse_state *ps; 427 struct perfuse_node_data *oldpnd; 428 perfuse_msg_t *pm; 429 struct fuse_entry_out *feo; 430 struct puffs_node *pn; 431 size_t len; 432 int error; 433 434 if (pnp == NULL) 435 DERRX(EX_SOFTWARE, "pnp must be != NULL"); 436 437 ps = puffs_getspecific(pu); 438 439 #ifdef PERFUSE_DEBUG 440 if (perfuse_diagflags & PDF_FILENAME) 441 DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n", 442 __func__, (void *)opc, perfuse_node_path(opc), path); 443 #endif 444 /* 445 * Is the node already known? 446 */ 447 TAILQ_FOREACH(oldpnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) { 448 if ((oldpnd->pnd_flags & PND_REMOVED) || 449 (strcmp(oldpnd->pnd_name, path) != 0)) 450 continue; 451 452 #ifdef PERFUSE_DEBUG 453 if (perfuse_diagflags & PDF_FILENAME) 454 DPRINTF("%s: opc = %p, file = \"%s\" found " 455 "cookie = %p, nodeid = 0x%"PRIx64" for \"%s\"\n", 456 __func__, (void *)opc, perfuse_node_path(opc), 457 (void *)oldpnd->pnd_pn, oldpnd->pnd_nodeid, 458 path); 459 #endif 460 break; 461 } 462 463 /* 464 * Check for cached name 465 */ 466 if ((oldpnd != NULL) && !entry_expired(oldpnd->pnd_pn)) { 467 *pnp = oldpnd->pnd_pn; 468 return 0; 469 } 470 471 len = strlen(path) + 1; 472 473 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, pcr); 474 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len); 475 476 error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply); 477 478 switch (error) { 479 case 0: 480 break; 481 case ENOENT: 482 if (oldpnd != NULL) { 483 oldpnd->pnd_flags |= PND_REMOVED; 484 #ifdef PERFUSE_DEBUG 485 if (perfuse_diagflags & PDF_FILENAME) 486 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" " 487 "file = \"%s\" removed\n", __func__, 488 oldpnd->pnd_pn, oldpnd->pnd_nodeid, 489 oldpnd->pnd_name); 490 #endif 491 } 492 /* FALLTHROUGH */ 493 default: 494 goto out; 495 /* NOTREACHED */ 496 break; 497 } 498 499 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 500 501 if (oldpnd != NULL) { 502 if (oldpnd->pnd_nodeid == feo->nodeid) { 503 oldpnd->pnd_nlookup++; 504 *pnp = oldpnd->pnd_pn; 505 goto out; 506 } else { 507 oldpnd->pnd_flags |= PND_REMOVED; 508 #ifdef PERFUSE_DEBUG 509 if (perfuse_diagflags & PDF_FILENAME) 510 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" " 511 "file = \"%s\" replaced\n", __func__, 512 oldpnd->pnd_pn, oldpnd->pnd_nodeid, 513 oldpnd->pnd_name); 514 #endif 515 } 516 } 517 518 pn = perfuse_new_pn(pu, path, opc); 519 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 520 521 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 522 pn->pn_va.va_gen = (u_long)(feo->generation); 523 set_expire((puffs_cookie_t)pn, feo, NULL); 524 525 *pnp = pn; 526 527 #ifdef PERFUSE_DEBUG 528 if (perfuse_diagflags & PDF_FILENAME) 529 DPRINTF("%s: opc = %p, looked up opc = %p, " 530 "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__, 531 (void *)opc, pn, feo->nodeid, path); 532 #endif 533 534 out: 535 ps->ps_destroy_msg(pm); 536 537 return error; 538 } 539 540 541 /* 542 * Common code for methods that create objects: 543 * perfuse_node_mkdir 544 * perfuse_node_mknod 545 * perfuse_node_symlink 546 */ 547 static int 548 node_mk_common(pu, opc, pni, pcn, pm) 549 struct puffs_usermount *pu; 550 puffs_cookie_t opc; 551 struct puffs_newinfo *pni; 552 const struct puffs_cn *pcn; 553 perfuse_msg_t *pm; 554 { 555 struct perfuse_state *ps; 556 struct puffs_node *pn; 557 struct fuse_entry_out *feo; 558 int error; 559 560 ps = puffs_getspecific(pu); 561 562 if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0) 563 goto out; 564 565 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 566 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 567 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 568 569 pn = perfuse_new_pn(pu, pcn->pcn_name, opc); 570 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 571 572 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 573 pn->pn_va.va_gen = (u_long)(feo->generation); 574 set_expire((puffs_cookie_t)pn, feo, NULL); 575 576 puffs_newinfo_setcookie(pni, pn); 577 578 #ifdef PERFUSE_DEBUG 579 if (perfuse_diagflags & PDF_FILENAME) 580 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 581 "nodeid = 0x%"PRIx64"\n", 582 __func__, (void *)pn, pcn->pcn_name, 583 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid); 584 #endif 585 ps->ps_destroy_msg(pm); 586 587 return node_mk_common_final(pu, opc, pn, pcn); 588 589 out: 590 ps->ps_destroy_msg(pm); 591 592 return error; 593 } 594 595 /* 596 * Common final code for methods that create objects: 597 * perfuse_node_mkdir via node_mk_common 598 * perfuse_node_mknod via node_mk_common 599 * perfuse_node_symlink via node_mk_common 600 * perfuse_node_create 601 */ 602 static int 603 node_mk_common_final(pu, opc, pn, pcn) 604 struct puffs_usermount *pu; 605 puffs_cookie_t opc; 606 struct puffs_node *pn; 607 const struct puffs_cn *pcn; 608 { 609 struct perfuse_state *ps; 610 perfuse_msg_t *pm; 611 struct fuse_setattr_in *fsi; 612 struct fuse_attr_out *fao; 613 int error; 614 615 ps = puffs_getspecific(pu); 616 617 /* 618 * Set owner and group. The kernel cannot create a file 619 * on its own (puffs_cred_getuid would return -1), right? 620 */ 621 if (puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid) != 0) 622 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__); 623 if (puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid) != 0) 624 DERRX(EX_SOFTWARE, "puffs_cred_getgid fails in %s", __func__); 625 626 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, 627 FUSE_SETATTR, sizeof(*fsi), pcn->pcn_cred); 628 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 629 fsi->uid = pn->pn_va.va_uid; 630 fsi->gid = pn->pn_va.va_gid; 631 fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID; 632 633 if ((error = xchg_msg(pu, (puffs_cookie_t)pn, pm, 634 sizeof(*fao), wait_reply)) != 0) 635 goto out; 636 637 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 638 fuse_attr_to_vap(ps, &pn->pn_va, &fao->attr); 639 set_expire((puffs_cookie_t)pn, NULL, fao); 640 641 /* 642 * The parent directory needs a sync 643 */ 644 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 645 646 out: 647 if (pm != NULL) 648 ps->ps_destroy_msg(pm); 649 650 return error; 651 } 652 653 static uint64_t 654 readdir_last_cookie(fd, fd_len) 655 struct fuse_dirent *fd; 656 size_t fd_len; 657 { 658 size_t len; 659 size_t seen = 0; 660 char *ndp; 661 662 do { 663 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 664 seen += len; 665 666 if (seen >= fd_len) 667 break; 668 669 ndp = (char *)(void *)fd + (size_t)len; 670 fd = (struct fuse_dirent *)(void *)ndp; 671 } while (1 /* CONSTCOND */); 672 673 return fd->off; 674 } 675 676 static ssize_t 677 fuse_to_dirent(pu, opc, fd, fd_len) 678 struct puffs_usermount *pu; 679 puffs_cookie_t opc; 680 struct fuse_dirent *fd; 681 size_t fd_len; 682 { 683 struct dirent *dents; 684 size_t dents_len; 685 ssize_t written; 686 uint64_t fd_offset; 687 struct fuse_dirent *fd_base; 688 size_t len; 689 690 fd_base = fd; 691 fd_offset = 0; 692 written = 0; 693 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 694 dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len; 695 696 do { 697 char *ndp; 698 size_t reclen; 699 700 reclen = _DIRENT_RECLEN(dents, fd->namelen); 701 702 /* 703 * Check we do not overflow the output buffer 704 * struct fuse_dirent is bigger than struct dirent, 705 * so we should always use fd_len and never reallocate 706 * later. 707 * If we have to reallocate,try to double the buffer 708 * each time so that we do not have to do it too often. 709 */ 710 if (written + reclen > dents_len) { 711 if (dents_len == 0) 712 dents_len = fd_len; 713 else 714 dents_len = 715 MAX(2 * dents_len, written + reclen); 716 717 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 718 if ((dents = realloc(dents, dents_len)) == NULL) 719 DERR(EX_OSERR, "%s: malloc failed", __func__); 720 721 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents; 722 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len; 723 724 /* 725 * (void *) for delint 726 */ 727 ndp = (char *)(void *)dents + written; 728 dents = (struct dirent *)(void *)ndp; 729 } 730 731 /* 732 * Filesystem was mounted without -o use_ino 733 * Perform a lookup to find it. 734 */ 735 if (fd->ino == PERFUSE_UNKNOWN_INO) { 736 struct puffs_node *pn; 737 738 if (node_lookup_dir_nodot(pu, opc, fd->name, 739 fd->namelen, &pn) != 0) { 740 DWARNX("node_lookup_dir_nodot failed"); 741 } else { 742 fd->ino = pn->pn_va.va_fileid; 743 } 744 } 745 746 dents->d_fileno = fd->ino; 747 dents->d_reclen = (unsigned short)reclen; 748 dents->d_namlen = fd->namelen; 749 dents->d_type = fd->type; 750 strlcpy(dents->d_name, fd->name, fd->namelen + 1); 751 752 #ifdef PERFUSE_DEBUG 753 if (perfuse_diagflags & PDF_READDIR) 754 DPRINTF("%s: translated \"%s\" ino = %"PRIu64"\n", 755 __func__, dents->d_name, dents->d_fileno); 756 #endif 757 758 dents = _DIRENT_NEXT(dents); 759 written += reclen; 760 761 /* 762 * Move to the next record. 763 * fd->off is not the offset, it is an opaque cookie 764 * given by the filesystem to keep state across multiple 765 * readdir() operation. 766 * Use record alignement instead. 767 */ 768 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 769 #ifdef PERFUSE_DEBUG 770 if (perfuse_diagflags & PDF_READDIR) 771 DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" " 772 "length = %zd/0x%zx. " 773 "next record at %"PRId64"/0x%"PRIx64" " 774 "max %zd/0x%zx\n", 775 __func__, fd_offset, fd_offset, len, len, 776 fd_offset + len, fd_offset + len, 777 fd_len, fd_len); 778 #endif 779 fd_offset += len; 780 781 /* 782 * Check if next record is still within the packet 783 * If it is not, we reached the end of the buffer. 784 */ 785 if (fd_offset >= fd_len) 786 break; 787 788 /* 789 * (void *) for delint 790 */ 791 ndp = (char *)(void *)fd_base + (size_t)fd_offset; 792 fd = (struct fuse_dirent *)(void *)ndp; 793 794 } while (1 /* CONSTCOND */); 795 796 /* 797 * Adjust the dirent output length 798 */ 799 if (written != -1) 800 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written; 801 802 return written; 803 } 804 805 static int 806 readdir_buffered(opc, dent, readoff, reslen) 807 puffs_cookie_t opc; 808 struct dirent *dent; 809 off_t *readoff; 810 size_t *reslen; 811 { 812 struct dirent *fromdent; 813 struct perfuse_node_data *pnd; 814 char *ndp; 815 816 pnd = PERFUSE_NODE_DATA(opc); 817 818 while (*readoff < pnd->pnd_dirent_len) { 819 /* 820 * (void *) for delint 821 */ 822 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff; 823 fromdent = (struct dirent *)(void *)ndp; 824 825 if (*reslen < _DIRENT_SIZE(fromdent)) 826 break; 827 828 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent)); 829 *readoff += _DIRENT_SIZE(fromdent); 830 *reslen -= _DIRENT_SIZE(fromdent); 831 832 dent = _DIRENT_NEXT(dent); 833 } 834 835 #ifdef PERFUSE_DEBUG 836 if (perfuse_diagflags & PDF_READDIR) 837 DPRINTF("%s: readoff = %"PRId64", " 838 "pnd->pnd_dirent_len = %"PRId64"\n", 839 __func__, *readoff, pnd->pnd_dirent_len); 840 #endif 841 if (*readoff >= pnd->pnd_dirent_len) { 842 free(pnd->pnd_dirent); 843 pnd->pnd_dirent = NULL; 844 pnd->pnd_dirent_len = 0; 845 } 846 847 return 0; 848 } 849 850 static void 851 requeue_request(pu, opc, type) 852 struct puffs_usermount *pu; 853 puffs_cookie_t opc; 854 enum perfuse_qtype type; 855 { 856 struct perfuse_cc_queue pcq; 857 struct perfuse_node_data *pnd; 858 #ifdef PERFUSE_DEBUG 859 struct perfuse_state *ps; 860 861 ps = perfuse_getspecific(pu); 862 #endif 863 864 pnd = PERFUSE_NODE_DATA(opc); 865 pcq.pcq_type = type; 866 pcq.pcq_cc = puffs_cc_getcc(pu); 867 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next); 868 869 #ifdef PERFUSE_DEBUG 870 if (perfuse_diagflags & PDF_REQUEUE) 871 DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n", 872 __func__, (void *)opc, pcq.pcq_cc, 873 perfuse_qtypestr[type]); 874 #endif 875 876 puffs_cc_yield(pcq.pcq_cc); 877 TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next); 878 879 #ifdef PERFUSE_DEBUG 880 if (perfuse_diagflags & PDF_REQUEUE) 881 DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n", 882 __func__, (void *)opc, pcq.pcq_cc, 883 perfuse_qtypestr[type]); 884 #endif 885 886 return; 887 } 888 889 /* ARGSUSED0 */ 890 static int 891 dequeue_requests(ps, opc, type, max) 892 struct perfuse_state *ps; 893 puffs_cookie_t opc; 894 enum perfuse_qtype type; 895 int max; 896 { 897 struct perfuse_cc_queue *pcq; 898 struct perfuse_node_data *pnd; 899 int dequeued; 900 901 pnd = PERFUSE_NODE_DATA(opc); 902 dequeued = 0; 903 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) { 904 if (pcq->pcq_type != type) 905 continue; 906 907 #ifdef PERFUSE_DEBUG 908 if (perfuse_diagflags & PDF_REQUEUE) 909 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n", 910 __func__, (void *)opc, pcq->pcq_cc, 911 perfuse_qtypestr[type]); 912 #endif 913 puffs_cc_schedule(pcq->pcq_cc); 914 915 if (++dequeued == max) 916 break; 917 } 918 919 #ifdef PERFUSE_DEBUG 920 if (perfuse_diagflags & PDF_REQUEUE) 921 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc); 922 #endif 923 924 return dequeued; 925 } 926 927 void 928 perfuse_fs_init(pu) 929 struct puffs_usermount *pu; 930 { 931 struct perfuse_state *ps; 932 perfuse_msg_t *pm; 933 struct fuse_init_in *fii; 934 struct fuse_init_out *fio; 935 int error; 936 937 ps = puffs_getspecific(pu); 938 939 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0) 940 DERR(EX_OSERR, "%s: puffs_mount failed", __func__); 941 942 /* 943 * Linux 2.6.34.1 sends theses flags: 944 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC 945 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK 946 * 947 * Linux also sets max_readahead at 32 pages (128 kB) 948 * 949 * ps_new_msg() is called with NULL creds, which will 950 * be interpreted as FUSE superuser. 951 */ 952 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL); 953 fii = GET_INPAYLOAD(ps, pm, fuse_init_in); 954 fii->major = FUSE_KERNEL_VERSION; 955 fii->minor = FUSE_KERNEL_MINOR_VERSION; 956 fii->max_readahead = (unsigned int)(32 * sysconf(_SC_PAGESIZE)); 957 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC); 958 959 if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0) 960 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error); 961 962 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out); 963 ps->ps_max_readahead = fio->max_readahead; 964 ps->ps_max_write = fio->max_write; 965 966 ps->ps_destroy_msg(pm); 967 968 return; 969 } 970 971 int 972 perfuse_fs_unmount(pu, flags) 973 struct puffs_usermount *pu; 974 int flags; 975 { 976 perfuse_msg_t *pm; 977 struct perfuse_state *ps; 978 puffs_cookie_t opc; 979 int error; 980 981 ps = puffs_getspecific(pu); 982 opc = (puffs_cookie_t)puffs_getroot(pu); 983 984 /* 985 * ps_new_msg() is called with NULL creds, which will 986 * be interpreted as FUSE superuser. 987 */ 988 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL); 989 990 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){ 991 DWARN("unmount %s", ps->ps_target); 992 if (!(flags & MNT_FORCE)) 993 goto out; 994 } 995 996 ps->ps_umount(pu); 997 998 if (perfuse_diagflags & PDF_MISC) 999 DPRINTF("%s unmounted, exit\n", ps->ps_target); 1000 1001 return 0; 1002 out: 1003 ps->ps_destroy_msg(pm); 1004 1005 return error; 1006 } 1007 1008 int 1009 perfuse_fs_statvfs(pu, svfsb) 1010 struct puffs_usermount *pu; 1011 struct statvfs *svfsb; 1012 { 1013 struct perfuse_state *ps; 1014 perfuse_msg_t *pm; 1015 puffs_cookie_t opc; 1016 struct fuse_statfs_out *fso; 1017 int error; 1018 1019 ps = puffs_getspecific(pu); 1020 opc = (puffs_cookie_t)puffs_getroot(pu); 1021 1022 /* 1023 * ps_new_msg() is called with NULL creds, which will 1024 * be interpreted as FUSE superuser. 1025 */ 1026 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 1027 1028 if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0) 1029 goto out; 1030 1031 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 1032 svfsb->f_flag = ps->ps_mountflags; 1033 svfsb->f_bsize = fso->st.bsize; 1034 svfsb->f_frsize = fso->st.frsize; 1035 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize; 1036 svfsb->f_blocks = fso->st.blocks; 1037 svfsb->f_bfree = fso->st.bfree; 1038 svfsb->f_bavail = fso->st.bavail; 1039 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail; 1040 svfsb->f_files = fso->st.files; 1041 svfsb->f_ffree = fso->st.ffree; 1042 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */ 1043 svfsb->f_fresvd = 0; /* files reserved for root */ 1044 1045 svfsb->f_syncreads = ps->ps_syncreads; 1046 svfsb->f_syncwrites = ps->ps_syncwrites; 1047 1048 svfsb->f_asyncreads = ps->ps_asyncreads; 1049 svfsb->f_asyncwrites = ps->ps_asyncwrites; 1050 1051 (void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid)); 1052 svfsb->f_fsid = (unsigned long)ps->ps_fsid; 1053 svfsb->f_namemax = MAXPATHLEN; /* XXX */ 1054 svfsb->f_owner = ps->ps_owner_uid; 1055 1056 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN); 1057 1058 if (ps->ps_filesystemtype != NULL) 1059 (void)strlcpy(svfsb->f_fstypename, 1060 ps->ps_filesystemtype, _VFS_NAMELEN); 1061 else 1062 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN); 1063 1064 if (ps->ps_source != NULL) 1065 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN); 1066 else 1067 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN); 1068 out: 1069 ps->ps_destroy_msg(pm); 1070 1071 return error; 1072 } 1073 1074 int 1075 perfuse_fs_sync(pu, waitfor, pcr) 1076 struct puffs_usermount *pu; 1077 int waitfor; 1078 const struct puffs_cred *pcr; 1079 { 1080 /* 1081 * FUSE does not seem to have a FS sync callback. 1082 * Maybe do not even register this callback 1083 */ 1084 return puffs_fsnop_sync(pu, waitfor, pcr); 1085 } 1086 1087 /* ARGSUSED0 */ 1088 int 1089 perfuse_fs_fhtonode(pu, fid, fidsize, pni) 1090 struct puffs_usermount *pu; 1091 void *fid; 1092 size_t fidsize; 1093 struct puffs_newinfo *pni; 1094 { 1095 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1096 return 0; 1097 } 1098 1099 /* ARGSUSED0 */ 1100 int 1101 perfuse_fs_nodetofh(pu, cookie, fid, fidsize) 1102 struct puffs_usermount *pu; 1103 puffs_cookie_t cookie; 1104 void *fid; 1105 size_t *fidsize; 1106 { 1107 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1108 return 0; 1109 } 1110 1111 #if 0 1112 /* ARGSUSED0 */ 1113 void 1114 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname) 1115 struct puffs_usermount *pu; 1116 int cmd, 1117 puffs_cookie_t *cookie; 1118 int flags; 1119 int namespace; 1120 const char *attrname; 1121 { 1122 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1123 return 0; 1124 } 1125 #endif /* 0 */ 1126 1127 /* ARGSUSED0 */ 1128 void 1129 perfuse_fs_suspend(pu, status) 1130 struct puffs_usermount *pu; 1131 int status; 1132 { 1133 return; 1134 } 1135 1136 1137 1138 int 1139 perfuse_node_lookup(pu, opc, pni, pcn) 1140 struct puffs_usermount *pu; 1141 puffs_cookie_t opc; 1142 struct puffs_newinfo *pni; 1143 const struct puffs_cn *pcn; 1144 { 1145 struct puffs_node *pn; 1146 mode_t mode; 1147 int error; 1148 1149 /* 1150 * Check permissions 1151 */ 1152 switch(pcn->pcn_nameiop) { 1153 case NAMEI_DELETE: /* FALLTHROUGH */ 1154 case NAMEI_RENAME: /* FALLTHROUGH */ 1155 case NAMEI_CREATE: 1156 if (pcn->pcn_flags & NAMEI_ISLASTCN) 1157 mode = PUFFS_VEXEC|PUFFS_VWRITE; 1158 else 1159 mode = PUFFS_VEXEC; 1160 break; 1161 case NAMEI_LOOKUP: /* FALLTHROUGH */ 1162 default: 1163 mode = PUFFS_VEXEC; 1164 break; 1165 } 1166 1167 if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0) 1168 return error; 1169 1170 /* 1171 * Special case for .. 1172 */ 1173 if (strcmp(pcn->pcn_name, "..") == 0) 1174 pn = PERFUSE_NODE_DATA(opc)->pnd_parent; 1175 else 1176 error = node_lookup_common(pu, (puffs_cookie_t)opc, 1177 pcn->pcn_name, pcn->pcn_cred, &pn); 1178 if (error != 0) 1179 return error; 1180 1181 /* 1182 * Removed node 1183 */ 1184 if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED) 1185 return ENOENT; 1186 1187 /* 1188 * Check for sticky bit. Unfortunately there is no way to 1189 * do this before creating the puffs_node, since we require 1190 * this operation to get the node owner. 1191 */ 1192 switch (pcn->pcn_nameiop) { 1193 case NAMEI_DELETE: /* FALLTHROUGH */ 1194 case NAMEI_RENAME: 1195 error = sticky_access(pn, pcn->pcn_cred); 1196 if (error != 0) { 1197 /* 1198 * kernel will never know about it and will 1199 * not reclaim it. The filesystem needs to 1200 * clean it up anyway, therefore mimick a forget. 1201 */ 1202 PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_RECLAIMED; 1203 (void)perfuse_node_reclaim(pu, (puffs_cookie_t)pn); 1204 return error; 1205 } 1206 break; 1207 default: 1208 break; 1209 } 1210 1211 /* 1212 * If that node had a pending reclaim, wipe it out. 1213 */ 1214 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED; 1215 1216 puffs_newinfo_setcookie(pni, pn); 1217 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 1218 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size); 1219 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 1220 1221 return error; 1222 } 1223 1224 int 1225 perfuse_node_create(pu, opc, pni, pcn, vap) 1226 struct puffs_usermount *pu; 1227 puffs_cookie_t opc; 1228 struct puffs_newinfo *pni; 1229 const struct puffs_cn *pcn; 1230 const struct vattr *vap; 1231 { 1232 perfuse_msg_t *pm; 1233 struct perfuse_state *ps; 1234 struct fuse_create_in *fci; 1235 struct fuse_entry_out *feo; 1236 struct fuse_open_out *foo; 1237 struct puffs_node *pn; 1238 const char *name; 1239 size_t namelen; 1240 size_t len; 1241 int error; 1242 1243 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1244 return ENOENT; 1245 1246 /* 1247 * If create is unimplemented: Check that it does not 1248 * already exists, and if not, do mknod and open 1249 */ 1250 ps = puffs_getspecific(pu); 1251 if (ps->ps_flags & PS_NO_CREAT) { 1252 error = node_lookup_common(pu, opc, pcn->pcn_name, 1253 pcn->pcn_cred, &pn); 1254 if (error == 0) 1255 return EEXIST; 1256 1257 error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 1258 if (error != 0) 1259 return error; 1260 1261 error = node_lookup_common(pu, opc, pcn->pcn_name, 1262 pcn->pcn_cred, &pn); 1263 if (error != 0) 1264 return error; 1265 1266 /* 1267 * FUSE does the open at create time, while 1268 * NetBSD will open in a subsequent operation. 1269 * We need to open now, in order to retain FUSE 1270 * semantics. The calling process will not get 1271 * a file descriptor before the kernel sends 1272 * the open operation. 1273 */ 1274 opc = (puffs_cookie_t)pn; 1275 error = perfuse_node_open(pu, opc, FWRITE, pcn->pcn_cred); 1276 if (error != 0) 1277 return error; 1278 1279 return 0; 1280 } 1281 1282 name = pcn->pcn_name; 1283 namelen = pcn->pcn_namelen + 1; 1284 len = sizeof(*fci) + namelen; 1285 1286 /* 1287 * flags should use O_WRONLY instead of O_RDWR, but it 1288 * breaks when the caller tries to read from file. 1289 * 1290 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1291 */ 1292 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred); 1293 fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 1294 fci->flags = O_CREAT | O_TRUNC | O_RDWR; 1295 fci->mode = vap->va_mode | VTTOIF(vap->va_type); 1296 fci->umask = 0; /* Seems unused by libfuse */ 1297 (void)strlcpy((char*)(void *)(fci + 1), name, namelen); 1298 1299 len = sizeof(*feo) + sizeof(*foo); 1300 if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0) 1301 goto out; 1302 1303 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 1304 foo = (struct fuse_open_out *)(void *)(feo + 1); 1305 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 1306 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 1307 1308 /* 1309 * Save the file handle and inode in node private data 1310 * so that we can reuse it later 1311 */ 1312 pn = perfuse_new_pn(pu, name, opc); 1313 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); 1314 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 1315 1316 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 1317 pn->pn_va.va_gen = (u_long)(feo->generation); 1318 set_expire((puffs_cookie_t)pn, feo, NULL); 1319 1320 puffs_newinfo_setcookie(pni, pn); 1321 1322 #ifdef PERFUSE_DEBUG 1323 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1324 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 1325 "nodeid = 0x%"PRIx64", wfh = 0x%"PRIx64"\n", 1326 __func__, (void *)pn, pcn->pcn_name, 1327 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, 1328 foo->fh); 1329 #endif 1330 1331 ps->ps_destroy_msg(pm); 1332 1333 return node_mk_common_final(pu, opc, pn, pcn); 1334 1335 out: 1336 ps->ps_destroy_msg(pm); 1337 1338 /* 1339 * create is unimplmented, remember it for later, 1340 * and start over using mknod and open instead. 1341 */ 1342 if (error == ENOSYS) { 1343 ps->ps_flags |= PS_NO_CREAT; 1344 return perfuse_node_create(pu, opc, pni, pcn, vap); 1345 } 1346 1347 return error; 1348 } 1349 1350 1351 int 1352 perfuse_node_mknod(pu, opc, pni, pcn, vap) 1353 struct puffs_usermount *pu; 1354 puffs_cookie_t opc; 1355 struct puffs_newinfo *pni; 1356 const struct puffs_cn *pcn; 1357 const struct vattr *vap; 1358 { 1359 struct perfuse_state *ps; 1360 perfuse_msg_t *pm; 1361 struct fuse_mknod_in *fmi; 1362 const char* path; 1363 size_t len; 1364 1365 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1366 return ENOENT; 1367 1368 /* 1369 * Only superuser can mknod objects other than 1370 * directories, files, socks, fifo and links. 1371 * 1372 * Create an object require -WX permission in the parent directory 1373 */ 1374 switch (vap->va_type) { 1375 case VDIR: /* FALLTHROUGH */ 1376 case VREG: /* FALLTHROUGH */ 1377 case VFIFO: /* FALLTHROUGH */ 1378 case VSOCK: 1379 break; 1380 default: /* VNON, VBLK, VCHR, VBAD */ 1381 if (!puffs_cred_isjuggernaut(pcn->pcn_cred)) 1382 return EACCES; 1383 break; 1384 } 1385 1386 1387 ps = puffs_getspecific(pu); 1388 path = pcn->pcn_name; 1389 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 1390 1391 /* 1392 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1393 */ 1394 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred); 1395 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in); 1396 fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 1397 fmi->rdev = (uint32_t)vap->va_rdev; 1398 fmi->umask = 0; /* Seems unused bu libfuse */ 1399 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 1400 1401 return node_mk_common(pu, opc, pni, pcn, pm); 1402 } 1403 1404 1405 int 1406 perfuse_node_open(pu, opc, mode, pcr) 1407 struct puffs_usermount *pu; 1408 puffs_cookie_t opc; 1409 int mode; 1410 const struct puffs_cred *pcr; 1411 { 1412 struct perfuse_state *ps; 1413 struct perfuse_node_data *pnd; 1414 perfuse_msg_t *pm; 1415 mode_t fmode; 1416 int op; 1417 struct fuse_open_in *foi; 1418 struct fuse_open_out *foo; 1419 struct puffs_node *pn; 1420 int error; 1421 1422 ps = puffs_getspecific(pu); 1423 pn = (struct puffs_node *)opc; 1424 pnd = PERFUSE_NODE_DATA(opc); 1425 pm = NULL; 1426 error = 0; 1427 1428 if (pnd->pnd_flags & PND_REMOVED) 1429 return ENOENT; 1430 1431 if (puffs_pn_getvap(pn)->va_type == VDIR) 1432 op = FUSE_OPENDIR; 1433 else 1434 op = FUSE_OPEN; 1435 1436 /* 1437 * libfuse docs says 1438 * - O_CREAT and O_EXCL should never be set. 1439 * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX 1440 * 1441 * O_APPEND makes no sense since FUSE always sends 1442 * the file offset for write operations. If the 1443 * filesystem uses pwrite(), O_APPEND would cause 1444 * the offset to be ignored and cause file corruption. 1445 */ 1446 mode &= ~(O_CREAT|O_EXCL|O_APPEND); 1447 1448 /* 1449 * Do not open twice, and do not reopen for reading 1450 * if we already have write handle. 1451 */ 1452 if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) || 1453 ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) || 1454 ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) { 1455 error = 0; 1456 goto out; 1457 } 1458 1459 /* 1460 * Queue open on a node so that we do not open 1461 * twice. This would be better with read and 1462 * write distinguished. 1463 */ 1464 while (pnd->pnd_flags & PND_INOPEN) 1465 requeue_request(pu, opc, PCQ_OPEN); 1466 pnd->pnd_flags |= PND_INOPEN; 1467 1468 /* 1469 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE 1470 * to O_RDONLY/O_WRONLY while perserving the other options. 1471 */ 1472 fmode = mode & ~(FREAD|FWRITE); 1473 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY; 1474 1475 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1476 foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1477 foi->flags = fmode; 1478 foi->unused = 0; 1479 1480 if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0) 1481 goto out; 1482 1483 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1484 1485 /* 1486 * Save the file handle in node private data 1487 * so that we can reuse it later 1488 */ 1489 perfuse_new_fh(opc, foo->fh, mode); 1490 1491 #ifdef PERFUSE_DEBUG 1492 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1493 DPRINTF("%s: opc = %p, file = \"%s\", " 1494 "nodeid = 0x%"PRIx64", %s%sfh = 0x%"PRIx64"\n", 1495 __func__, (void *)opc, perfuse_node_path(opc), 1496 pnd->pnd_nodeid, mode & FREAD ? "r" : "", 1497 mode & FWRITE ? "w" : "", foo->fh); 1498 #endif 1499 1500 out: 1501 if (pm != NULL) 1502 ps->ps_destroy_msg(pm); 1503 1504 pnd->pnd_flags &= ~PND_INOPEN; 1505 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 1506 1507 return error; 1508 } 1509 1510 /* ARGSUSED0 */ 1511 int 1512 perfuse_node_close(pu, opc, flags, pcr) 1513 struct puffs_usermount *pu; 1514 puffs_cookie_t opc; 1515 int flags; 1516 const struct puffs_cred *pcr; 1517 { 1518 struct perfuse_node_data *pnd; 1519 1520 pnd = PERFUSE_NODE_DATA(opc); 1521 1522 if (!(pnd->pnd_flags & PND_OPEN)) 1523 return EBADF; 1524 1525 /* 1526 * Actual close is postponed at inactive time. 1527 */ 1528 return 0; 1529 } 1530 1531 int 1532 perfuse_node_access(pu, opc, mode, pcr) 1533 struct puffs_usermount *pu; 1534 puffs_cookie_t opc; 1535 int mode; 1536 const struct puffs_cred *pcr; 1537 { 1538 perfuse_msg_t *pm; 1539 struct perfuse_state *ps; 1540 struct fuse_access_in *fai; 1541 int error; 1542 1543 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1544 return ENOENT; 1545 1546 /* 1547 * If we previously detected the filesystem does not 1548 * implement access(), short-circuit the call and skip 1549 * to libpuffs access() emulation. 1550 */ 1551 ps = puffs_getspecific(pu); 1552 if (ps->ps_flags & PS_NO_ACCESS) { 1553 const struct vattr *vap; 1554 1555 vap = puffs_pn_getvap((struct puffs_node *)opc); 1556 1557 error = puffs_access(IFTOVT(vap->va_mode), 1558 vap->va_mode & ACCESSPERMS, 1559 vap->va_uid, vap->va_gid, 1560 (mode_t)mode, pcr); 1561 return error; 1562 } 1563 1564 /* 1565 * Plain access call 1566 */ 1567 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr); 1568 fai = GET_INPAYLOAD(ps, pm, fuse_access_in); 1569 fai->mask = 0; 1570 fai->mask |= (mode & PUFFS_VREAD) ? R_OK : 0; 1571 fai->mask |= (mode & PUFFS_VWRITE) ? W_OK : 0; 1572 fai->mask |= (mode & PUFFS_VEXEC) ? X_OK : 0; 1573 1574 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 1575 1576 ps->ps_destroy_msg(pm); 1577 1578 /* 1579 * If unimplemented, start over with emulation 1580 */ 1581 if (error == ENOSYS) { 1582 ps->ps_flags |= PS_NO_ACCESS; 1583 return perfuse_node_access(pu, opc, mode, pcr); 1584 } 1585 1586 return error; 1587 } 1588 1589 int 1590 perfuse_node_getattr(pu, opc, vap, pcr) 1591 struct puffs_usermount *pu; 1592 puffs_cookie_t opc; 1593 struct vattr *vap; 1594 const struct puffs_cred *pcr; 1595 { 1596 perfuse_msg_t *pm = NULL; 1597 struct perfuse_state *ps; 1598 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 1599 struct fuse_getattr_in *fgi; 1600 struct fuse_attr_out *fao; 1601 int error = 0; 1602 1603 if (pnd->pnd_flags & PND_REMOVED) 1604 return ENOENT; 1605 1606 /* 1607 * Serialize size access, see comment in perfuse_node_setattr(). 1608 */ 1609 while (pnd->pnd_flags & PND_INRESIZE) 1610 requeue_request(pu, opc, PCQ_RESIZE); 1611 pnd->pnd_flags |= PND_INRESIZE; 1612 1613 ps = puffs_getspecific(pu); 1614 1615 /* 1616 * Check for cached attributes 1617 * This still require serialized access to size. 1618 */ 1619 if (!attr_expired(opc)) { 1620 (void)memcpy(vap, puffs_pn_getvap((struct puffs_node *)opc), 1621 sizeof(*vap)); 1622 goto out; 1623 } 1624 1625 /* 1626 * FUSE_GETATTR_FH must be set in fgi->flags 1627 * if we use for fgi->fh 1628 */ 1629 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr); 1630 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1631 fgi->getattr_flags = 0; 1632 fgi->dummy = 0; 1633 fgi->fh = 0; 1634 1635 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1636 fgi->fh = perfuse_get_fh(opc, FREAD); 1637 fgi->getattr_flags |= FUSE_GETATTR_FH; 1638 } 1639 1640 #ifdef PERFUSE_DEBUG 1641 if (perfuse_diagflags & PDF_RESIZE) 1642 DPRINTF(">> %s %p %" PRIu64 "\n", __func__, (void *)opc, 1643 vap->va_size); 1644 #endif 1645 1646 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1647 goto out; 1648 1649 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1650 1651 #ifdef PERFUSE_DEBUG 1652 if (perfuse_diagflags & PDF_RESIZE) 1653 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1654 (void *)opc, vap->va_size, fao->attr.size); 1655 #endif 1656 1657 /* 1658 * We set birthtime, flags, filerev,vaflags to 0. 1659 * This seems the best bet, since the information is 1660 * not available from filesystem. 1661 */ 1662 fuse_attr_to_vap(ps, vap, &fao->attr); 1663 set_expire(opc, NULL, fao); 1664 1665 out: 1666 if (pm != NULL) 1667 ps->ps_destroy_msg(pm); 1668 1669 pnd->pnd_flags &= ~PND_INRESIZE; 1670 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 1671 1672 return error; 1673 } 1674 1675 int 1676 perfuse_node_setattr(pu, opc, vap, pcr) 1677 struct puffs_usermount *pu; 1678 puffs_cookie_t opc; 1679 const struct vattr *vap; 1680 const struct puffs_cred *pcr; 1681 { 1682 perfuse_msg_t *pm; 1683 uint64_t fh; 1684 struct perfuse_state *ps; 1685 struct perfuse_node_data *pnd; 1686 struct fuse_setattr_in *fsi; 1687 struct fuse_attr_out *fao; 1688 struct vattr *old_va; 1689 int error; 1690 #ifdef PERFUSE_DEBUG 1691 struct vattr *old_vap; 1692 int resize_debug = 0; 1693 #endif 1694 1695 ps = puffs_getspecific(pu); 1696 pnd = PERFUSE_NODE_DATA(opc); 1697 pm = NULL; 1698 1699 /* 1700 * The only operation we can do once the file is removed 1701 * is to resize it, and we can do it only if it is open. 1702 * Do not even send the operation to the filesystem: the 1703 * file is not there anymore. 1704 */ 1705 if (pnd->pnd_flags & PND_REMOVED) { 1706 if (!(pnd->pnd_flags & PND_OPEN)) 1707 return ENOENT; 1708 1709 error = 0; 1710 goto out; 1711 } 1712 1713 old_va = puffs_pn_getvap((struct puffs_node *)opc); 1714 1715 /* 1716 * Check for permission to change size 1717 */ 1718 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1719 (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) 1720 return error; 1721 1722 /* 1723 * Check for permission to change dates 1724 */ 1725 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || 1726 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && 1727 (puffs_access_times(old_va->va_uid, old_va->va_gid, 1728 old_va->va_mode, 0, pcr) != 0)) 1729 return EACCES; 1730 1731 /* 1732 * Check for permission to change owner and group 1733 */ 1734 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1735 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1736 (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1737 vap->va_uid, vap->va_gid, pcr)) != 0) 1738 return EACCES; 1739 1740 /* 1741 * Check for permission to change permissions 1742 */ 1743 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1744 (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1745 old_va->va_type, vap->va_mode, pcr)) != 0) 1746 return EACCES; 1747 1748 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1749 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1750 fsi->valid = 0; 1751 1752 /* 1753 * Get a fh if the node is open for writing 1754 */ 1755 if (pnd->pnd_flags & PND_WFH) { 1756 fh = perfuse_get_fh(opc, FWRITE); 1757 fsi->fh = fh; 1758 fsi->valid |= FUSE_FATTR_FH; 1759 } 1760 1761 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1762 fsi->size = vap->va_size; 1763 fsi->valid |= FUSE_FATTR_SIZE; 1764 1765 /* 1766 * Serialize anything that can touch file size 1767 * to avoid reordered GETATTR and SETATTR. 1768 * Out of order SETATTR can report stale size, 1769 * which will cause the kernel to truncate the file. 1770 */ 1771 while (pnd->pnd_flags & PND_INRESIZE) 1772 requeue_request(pu, opc, PCQ_RESIZE); 1773 pnd->pnd_flags |= PND_INRESIZE; 1774 } 1775 1776 /* 1777 * Setting mtime without atime or vice versa leads to 1778 * dates being reset to Epoch on glusterfs. If one 1779 * is missing, use the old value. 1780 */ 1781 if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) || 1782 (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) { 1783 1784 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1785 fsi->atime = vap->va_atime.tv_sec; 1786 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec; 1787 } else { 1788 fsi->atime = old_va->va_atime.tv_sec; 1789 fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec; 1790 } 1791 1792 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 1793 fsi->mtime = vap->va_mtime.tv_sec; 1794 fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec; 1795 } else { 1796 fsi->mtime = old_va->va_mtime.tv_sec; 1797 fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec; 1798 } 1799 1800 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME); 1801 } 1802 1803 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { 1804 fsi->mode = vap->va_mode; 1805 fsi->valid |= FUSE_FATTR_MODE; 1806 } 1807 1808 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1809 fsi->uid = vap->va_uid; 1810 fsi->valid |= FUSE_FATTR_UID; 1811 } 1812 1813 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1814 fsi->gid = vap->va_gid; 1815 fsi->valid |= FUSE_FATTR_GID; 1816 } 1817 1818 if (pnd->pnd_lock_owner != 0) { 1819 fsi->lock_owner = pnd->pnd_lock_owner; 1820 fsi->valid |= FUSE_FATTR_LOCKOWNER; 1821 } 1822 1823 /* 1824 * ftruncate() sends only va_size, and metadata cache 1825 * flush adds va_atime and va_mtime. Some FUSE 1826 * filesystems will attempt to detect ftruncate by 1827 * checking for FATTR_SIZE being set without 1828 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE 1829 * 1830 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME 1831 * if we suspect a ftruncate(). 1832 */ 1833 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1834 ((vap->va_mode == (mode_t)PUFFS_VNOVAL) && 1835 (vap->va_uid == (uid_t)PUFFS_VNOVAL) && 1836 (vap->va_gid == (gid_t)PUFFS_VNOVAL))) { 1837 fsi->atime = 0; 1838 fsi->atimensec = 0; 1839 fsi->mtime = 0; 1840 fsi->mtimensec = 0; 1841 fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); 1842 } 1843 1844 /* 1845 * If nothing remain, discard the operation. 1846 */ 1847 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| 1848 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { 1849 error = 0; 1850 goto out; 1851 } 1852 1853 #ifdef PERFUSE_DEBUG 1854 old_vap = puffs_pn_getvap((struct puffs_node *)opc); 1855 1856 if ((perfuse_diagflags & PDF_RESIZE) && 1857 (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) { 1858 resize_debug = 1; 1859 1860 DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1861 (void *)opc, 1862 puffs_pn_getvap((struct puffs_node *)opc)->va_size, 1863 fsi->size); 1864 } 1865 #endif 1866 1867 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1868 goto out; 1869 1870 /* 1871 * Copy back the new values 1872 */ 1873 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1874 1875 #ifdef PERFUSE_DEBUG 1876 if (resize_debug) 1877 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1878 (void *)opc, old_vap->va_size, fao->attr.size); 1879 #endif 1880 1881 fuse_attr_to_vap(ps, old_va, &fao->attr); 1882 set_expire(opc, NULL, fao); 1883 1884 out: 1885 if (pm != NULL) 1886 ps->ps_destroy_msg(pm); 1887 1888 if (pnd->pnd_flags & PND_INRESIZE) { 1889 pnd->pnd_flags &= ~PND_INRESIZE; 1890 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 1891 } 1892 1893 return error; 1894 } 1895 1896 int 1897 perfuse_node_poll(pu, opc, events) 1898 struct puffs_usermount *pu; 1899 puffs_cookie_t opc; 1900 int *events; 1901 { 1902 struct perfuse_state *ps; 1903 perfuse_msg_t *pm; 1904 struct fuse_poll_in *fpi; 1905 struct fuse_poll_out *fpo; 1906 int error; 1907 1908 ps = puffs_getspecific(pu); 1909 /* 1910 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1911 * 1912 * XXX ps_new_msg() is called with NULL creds, which will 1913 * be interpreted as FUSE superuser. We have no way to 1914 * know the requesting process' credential, but since poll 1915 * is supposed to operate on a file that has been open, 1916 * permission should have already been checked at open time. 1917 * That still may breaks on filesystems that provides odd 1918 * semantics. 1919 */ 1920 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1921 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1922 fpi->fh = perfuse_get_fh(opc, FREAD); 1923 fpi->kh = 0; 1924 fpi->flags = 0; 1925 1926 #ifdef PERFUSE_DEBUG 1927 if (perfuse_diagflags & PDF_FH) 1928 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 1929 __func__, (void *)opc, 1930 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh); 1931 #endif 1932 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0) 1933 goto out; 1934 1935 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1936 *events = fpo->revents; 1937 out: 1938 ps->ps_destroy_msg(pm); 1939 1940 return error; 1941 } 1942 1943 /* ARGSUSED0 */ 1944 int 1945 perfuse_node_mmap(pu, opc, flags, pcr) 1946 struct puffs_usermount *pu; 1947 puffs_cookie_t opc; 1948 int flags; 1949 const struct puffs_cred *pcr; 1950 { 1951 /* 1952 * Not implemented anymore in libfuse 1953 */ 1954 return ENOSYS; 1955 } 1956 1957 /* ARGSUSED2 */ 1958 int 1959 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi) 1960 struct puffs_usermount *pu; 1961 puffs_cookie_t opc; 1962 const struct puffs_cred *pcr; 1963 int flags; 1964 off_t offlo; 1965 off_t offhi; 1966 { 1967 int op; 1968 perfuse_msg_t *pm; 1969 struct perfuse_state *ps; 1970 struct perfuse_node_data *pnd; 1971 struct fuse_fsync_in *ffi; 1972 uint64_t fh; 1973 int error; 1974 1975 pm = NULL; 1976 ps = puffs_getspecific(pu); 1977 pnd = PERFUSE_NODE_DATA(opc); 1978 1979 /* 1980 * No need to sync a removed node 1981 */ 1982 if (pnd->pnd_flags & PND_REMOVED) 1983 return 0; 1984 1985 /* 1986 * We do not sync closed files. They have been 1987 * sync at inactive time already. 1988 */ 1989 if (!(pnd->pnd_flags & PND_OPEN)) 1990 return 0; 1991 1992 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 1993 op = FUSE_FSYNCDIR; 1994 else /* VREG but also other types such as VLNK */ 1995 op = FUSE_FSYNC; 1996 1997 /* 1998 * Do not sync if there are no change to sync 1999 * XXX remove that test on files if we implement mmap 2000 */ 2001 #ifdef PERFUSE_DEBUG 2002 if (perfuse_diagflags & PDF_SYNC) 2003 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 2004 __func__, (void*)opc, perfuse_node_path(opc), 2005 pnd->pnd_flags & PND_DIRTY ? "" : "not "); 2006 #endif 2007 if (!(pnd->pnd_flags & PND_DIRTY)) 2008 return 0; 2009 2010 /* 2011 * It seems NetBSD can call fsync without open first 2012 * glusterfs complain in such a situation: 2013 * "FSYNC() ERR => -1 (Invalid argument)" 2014 * The file will be closed at inactive time. 2015 * 2016 * We open the directory for reading in order to sync. 2017 * This sounds rather counterintuitive, but it works. 2018 */ 2019 if (!(pnd->pnd_flags & PND_WFH)) { 2020 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2021 goto out; 2022 } 2023 2024 if (op == FUSE_FSYNCDIR) 2025 fh = perfuse_get_fh(opc, FREAD); 2026 else 2027 fh = perfuse_get_fh(opc, FWRITE); 2028 2029 /* 2030 * If fsync_flags is set, meta data should not be flushed. 2031 */ 2032 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr); 2033 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 2034 ffi->fh = fh; 2035 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 2036 2037 #ifdef PERFUSE_DEBUG 2038 if (perfuse_diagflags & PDF_FH) 2039 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2040 __func__, (void *)opc, 2041 PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh); 2042 #endif 2043 2044 if ((error = xchg_msg(pu, opc, pm, 2045 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 2046 goto out; 2047 2048 /* 2049 * No reply beyond fuse_out_header: nothing to do on success 2050 * just clear the dirty flag 2051 */ 2052 pnd->pnd_flags &= ~PND_DIRTY; 2053 2054 #ifdef PERFUSE_DEBUG 2055 if (perfuse_diagflags & PDF_SYNC) 2056 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 2057 __func__, (void*)opc, perfuse_node_path(opc)); 2058 #endif 2059 2060 out: 2061 /* 2062 * ENOSYS is not returned to kernel, 2063 */ 2064 if (error == ENOSYS) 2065 error = 0; 2066 2067 if (pm != NULL) 2068 ps->ps_destroy_msg(pm); 2069 2070 return error; 2071 } 2072 2073 /* ARGSUSED0 */ 2074 int 2075 perfuse_node_seek(pu, opc, oldoff, newoff, pcr) 2076 struct puffs_usermount *pu; 2077 puffs_cookie_t opc; 2078 off_t oldoff; 2079 off_t newoff; 2080 const struct puffs_cred *pcr; 2081 { 2082 return 0; 2083 } 2084 2085 int 2086 perfuse_node_remove(pu, opc, targ, pcn) 2087 struct puffs_usermount *pu; 2088 puffs_cookie_t opc; 2089 puffs_cookie_t targ; 2090 const struct puffs_cn *pcn; 2091 { 2092 struct perfuse_state *ps; 2093 struct perfuse_node_data *pnd; 2094 perfuse_msg_t *pm; 2095 char *path; 2096 const char *name; 2097 size_t len; 2098 int error; 2099 2100 pnd = PERFUSE_NODE_DATA(opc); 2101 2102 if ((pnd->pnd_flags & PND_REMOVED) || 2103 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED)) 2104 return ENOENT; 2105 2106 #ifdef PERFUSE_DEBUG 2107 if (targ == NULL) 2108 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 2109 2110 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 2111 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n", 2112 __func__, (void *)opc, (void *)targ, pcn->pcn_name); 2113 #endif 2114 /* 2115 * Await for all operations on the deleted node to drain, 2116 * as the filesystem may be confused to have it deleted 2117 * during a getattr 2118 */ 2119 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2120 requeue_request(pu, targ, PCQ_AFTERXCHG); 2121 2122 ps = puffs_getspecific(pu); 2123 pnd = PERFUSE_NODE_DATA(opc); 2124 name = pcn->pcn_name; 2125 len = pcn->pcn_namelen + 1; 2126 2127 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); 2128 path = _GET_INPAYLOAD(ps, pm, char *); 2129 (void)strlcpy(path, name, len); 2130 2131 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2132 goto out; 2133 2134 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2135 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2136 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2137 2138 /* 2139 * The parent directory needs a sync 2140 */ 2141 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2142 2143 #ifdef PERFUSE_DEBUG 2144 if (perfuse_diagflags & PDF_FILENAME) 2145 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2146 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2147 pcn->pcn_name); 2148 #endif 2149 out: 2150 ps->ps_destroy_msg(pm); 2151 2152 return error; 2153 } 2154 2155 int 2156 perfuse_node_link(pu, opc, targ, pcn) 2157 struct puffs_usermount *pu; 2158 puffs_cookie_t opc; 2159 puffs_cookie_t targ; 2160 const struct puffs_cn *pcn; 2161 { 2162 struct perfuse_state *ps; 2163 perfuse_msg_t *pm; 2164 const char *name; 2165 size_t len; 2166 struct puffs_node *pn; 2167 struct fuse_link_in *fli; 2168 int error; 2169 2170 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2171 return ENOENT; 2172 2173 ps = puffs_getspecific(pu); 2174 pn = (struct puffs_node *)targ; 2175 name = pcn->pcn_name; 2176 len = sizeof(*fli) + pcn->pcn_namelen + 1; 2177 2178 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred); 2179 fli = GET_INPAYLOAD(ps, pm, fuse_link_in); 2180 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid; 2181 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli)); 2182 2183 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 2184 2185 ps->ps_destroy_msg(pm); 2186 2187 return error; 2188 } 2189 2190 int 2191 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ) 2192 struct puffs_usermount *pu; 2193 puffs_cookie_t opc; 2194 puffs_cookie_t src; 2195 const struct puffs_cn *pcn_src; 2196 puffs_cookie_t targ_dir; 2197 puffs_cookie_t targ; 2198 const struct puffs_cn *pcn_targ; 2199 { 2200 struct perfuse_state *ps; 2201 perfuse_msg_t *pm; 2202 struct fuse_rename_in *fri; 2203 const char *newname; 2204 const char *oldname; 2205 char *np; 2206 int error; 2207 size_t len; 2208 size_t newname_len; 2209 size_t oldname_len; 2210 2211 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) || 2212 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) || 2213 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED)) 2214 return ENOENT; 2215 2216 /* 2217 * Await for all operations on the deleted node to drain, 2218 * as the filesystem may be confused to have it deleted 2219 * during a getattr 2220 */ 2221 if ((struct puffs_node *)targ != NULL) { 2222 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2223 requeue_request(pu, targ, PCQ_AFTERXCHG); 2224 } else { 2225 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG) 2226 requeue_request(pu, src, PCQ_AFTERXCHG); 2227 } 2228 2229 ps = puffs_getspecific(pu); 2230 newname = pcn_targ->pcn_name; 2231 newname_len = pcn_targ->pcn_namelen + 1; 2232 oldname = pcn_src->pcn_name; 2233 oldname_len = pcn_src->pcn_namelen + 1; 2234 2235 len = sizeof(*fri) + oldname_len + newname_len; 2236 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred); 2237 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in); 2238 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid; 2239 np = (char *)(void *)(fri + 1); 2240 (void)strlcpy(np, oldname, oldname_len); 2241 np += oldname_len; 2242 (void)strlcpy(np, newname, newname_len); 2243 2244 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2245 goto out; 2246 2247 if (opc != targ_dir) { 2248 struct perfuse_node_data *srcdir_pnd; 2249 struct perfuse_node_data *dstdir_pnd; 2250 struct perfuse_node_data *src_pnd; 2251 2252 srcdir_pnd = PERFUSE_NODE_DATA(opc); 2253 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir); 2254 src_pnd = PERFUSE_NODE_DATA(src); 2255 2256 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next); 2257 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next); 2258 2259 srcdir_pnd->pnd_childcount--; 2260 dstdir_pnd->pnd_childcount++; 2261 2262 src_pnd->pnd_parent = targ_dir; 2263 2264 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY; 2265 } 2266 2267 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN); 2268 2269 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2270 2271 if ((struct puffs_node *)targ != NULL) 2272 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2273 2274 #ifdef PERFUSE_DEBUG 2275 if (perfuse_diagflags & PDF_FILENAME) 2276 DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" " 2277 "nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n", 2278 __func__, PERFUSE_NODE_DATA(src)->pnd_nodeid, 2279 pcn_src->pcn_name, pcn_targ->pcn_name, 2280 PERFUSE_NODE_DATA(opc)->pnd_nodeid, 2281 PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid, 2282 perfuse_node_path(targ_dir)); 2283 #endif 2284 2285 out: 2286 if (pm != NULL) 2287 ps->ps_destroy_msg(pm); 2288 2289 return error; 2290 } 2291 2292 int 2293 perfuse_node_mkdir(pu, opc, pni, pcn, vap) 2294 struct puffs_usermount *pu; 2295 puffs_cookie_t opc; 2296 struct puffs_newinfo *pni; 2297 const struct puffs_cn *pcn; 2298 const struct vattr *vap; 2299 { 2300 struct perfuse_state *ps; 2301 perfuse_msg_t *pm; 2302 struct fuse_mkdir_in *fmi; 2303 const char *path; 2304 size_t len; 2305 2306 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2307 return ENOENT; 2308 2309 ps = puffs_getspecific(pu); 2310 path = pcn->pcn_name; 2311 len = sizeof(*fmi) + pcn->pcn_namelen + 1; 2312 2313 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred); 2314 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in); 2315 fmi->mode = vap->va_mode; 2316 fmi->umask = 0; /* Seems unused by libfuse? */ 2317 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 2318 2319 return node_mk_common(pu, opc, pni, pcn, pm); 2320 } 2321 2322 2323 int 2324 perfuse_node_rmdir(pu, opc, targ, pcn) 2325 struct puffs_usermount *pu; 2326 puffs_cookie_t opc; 2327 puffs_cookie_t targ; 2328 const struct puffs_cn *pcn; 2329 { 2330 struct perfuse_state *ps; 2331 struct perfuse_node_data *pnd; 2332 perfuse_msg_t *pm; 2333 char *path; 2334 const char *name; 2335 size_t len; 2336 int error; 2337 2338 pnd = PERFUSE_NODE_DATA(opc); 2339 if (pnd->pnd_flags & PND_REMOVED) 2340 return ENOENT; 2341 2342 /* 2343 * Await for all operations on the deleted node to drain, 2344 * as the filesystem may be confused to have it deleted 2345 * during a getattr 2346 */ 2347 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG) 2348 requeue_request(pu, targ, PCQ_AFTERXCHG); 2349 2350 ps = puffs_getspecific(pu); 2351 name = pcn->pcn_name; 2352 len = pcn->pcn_namelen + 1; 2353 2354 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred); 2355 path = _GET_INPAYLOAD(ps, pm, char *); 2356 (void)strlcpy(path, name, len); 2357 2358 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2359 goto out; 2360 2361 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2362 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2363 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2364 2365 /* 2366 * The parent directory needs a sync 2367 */ 2368 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2369 2370 #ifdef PERFUSE_DEBUG 2371 if (perfuse_diagflags & PDF_FILENAME) 2372 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2373 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2374 perfuse_node_path(targ)); 2375 #endif 2376 out: 2377 ps->ps_destroy_msg(pm); 2378 2379 return error; 2380 } 2381 2382 /* vap is unused */ 2383 /* ARGSUSED4 */ 2384 int 2385 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target) 2386 struct puffs_usermount *pu; 2387 puffs_cookie_t opc; 2388 struct puffs_newinfo *pni; 2389 const struct puffs_cn *pcn_src; 2390 const struct vattr *vap; 2391 const char *link_target; 2392 { 2393 struct perfuse_state *ps; 2394 perfuse_msg_t *pm; 2395 char *np; 2396 const char *path; 2397 size_t path_len; 2398 size_t linkname_len; 2399 size_t len; 2400 2401 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2402 return ENOENT; 2403 2404 ps = puffs_getspecific(pu); 2405 path = pcn_src->pcn_name; 2406 path_len = pcn_src->pcn_namelen + 1; 2407 linkname_len = strlen(link_target) + 1; 2408 len = path_len + linkname_len; 2409 2410 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred); 2411 np = _GET_INPAYLOAD(ps, pm, char *); 2412 (void)strlcpy(np, path, path_len); 2413 np += path_len; 2414 (void)strlcpy(np, link_target, linkname_len); 2415 2416 return node_mk_common(pu, opc, pni, pcn_src, pm); 2417 } 2418 2419 /* ARGSUSED4 */ 2420 int 2421 perfuse_node_readdir(pu, opc, dent, readoff, 2422 reslen, pcr, eofflag, cookies, ncookies) 2423 struct puffs_usermount *pu; 2424 puffs_cookie_t opc; 2425 struct dirent *dent; 2426 off_t *readoff; 2427 size_t *reslen; 2428 const struct puffs_cred *pcr; 2429 int *eofflag; 2430 off_t *cookies; 2431 size_t *ncookies; 2432 { 2433 perfuse_msg_t *pm; 2434 uint64_t fh; 2435 struct perfuse_state *ps; 2436 struct perfuse_node_data *pnd; 2437 struct fuse_read_in *fri; 2438 struct fuse_out_header *foh; 2439 struct fuse_dirent *fd; 2440 size_t foh_len; 2441 int error; 2442 size_t fd_maxlen; 2443 2444 pm = NULL; 2445 error = 0; 2446 ps = puffs_getspecific(pu); 2447 2448 /* 2449 * readdir state is kept at node level, and several readdir 2450 * requests can be issued at the same time on the same node. 2451 * We need to queue requests so that only one is in readdir 2452 * code at the same time. 2453 */ 2454 pnd = PERFUSE_NODE_DATA(opc); 2455 while (pnd->pnd_flags & PND_INREADDIR) 2456 requeue_request(pu, opc, PCQ_READDIR); 2457 pnd->pnd_flags |= PND_INREADDIR; 2458 2459 #ifdef PERFUSE_DEBUG 2460 if (perfuse_diagflags & PDF_READDIR) 2461 DPRINTF("%s: READDIR opc = %p enter critical section\n", 2462 __func__, (void *)opc); 2463 #endif 2464 /* 2465 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node 2466 */ 2467 if (*readoff == 0) 2468 pnd->pnd_fd_cookie = 0; 2469 2470 /* 2471 * Do we already have the data bufered? 2472 */ 2473 if (pnd->pnd_dirent != NULL) 2474 goto out; 2475 pnd->pnd_dirent_len = 0; 2476 2477 /* 2478 * It seems NetBSD can call readdir without open first 2479 * libfuse will crash if it is done that way, hence open first. 2480 */ 2481 if (!(pnd->pnd_flags & PND_OPEN)) { 2482 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2483 goto out; 2484 } 2485 2486 fh = perfuse_get_fh(opc, FREAD); 2487 2488 #ifdef PERFUSE_DEBUG 2489 if (perfuse_diagflags & PDF_FH) 2490 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", rfh = 0x%"PRIx64"\n", 2491 __func__, (void *)opc, 2492 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh); 2493 #endif 2494 2495 pnd->pnd_all_fd = NULL; 2496 pnd->pnd_all_fd_len = 0; 2497 fd_maxlen = ps->ps_max_readahead - sizeof(*foh); 2498 2499 do { 2500 size_t fd_len; 2501 char *afdp; 2502 2503 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 2504 2505 /* 2506 * read_flags, lock_owner and flags are unused in libfuse 2507 */ 2508 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2509 fri->fh = fh; 2510 fri->offset = pnd->pnd_fd_cookie; 2511 fri->size = (uint32_t)fd_maxlen; 2512 fri->read_flags = 0; 2513 fri->lock_owner = 0; 2514 fri->flags = 0; 2515 2516 if ((error = xchg_msg(pu, opc, pm, 2517 UNSPEC_REPLY_LEN, wait_reply)) != 0) 2518 goto out; 2519 2520 /* 2521 * There are many puffs_framebufs calls later, 2522 * therefore foh will not be valid for a long time. 2523 * Just get the length and forget it. 2524 */ 2525 foh = GET_OUTHDR(ps, pm); 2526 foh_len = foh->len; 2527 2528 /* 2529 * Empty read: we reached the end of the buffer. 2530 */ 2531 if (foh_len == sizeof(*foh)) { 2532 *eofflag = 1; 2533 break; 2534 } 2535 2536 /* 2537 * Check for corrupted message. 2538 */ 2539 if (foh_len < sizeof(*foh) + sizeof(*fd)) { 2540 DWARNX("readdir reply too short"); 2541 error = EIO; 2542 goto out; 2543 } 2544 2545 2546 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent); 2547 fd_len = foh_len - sizeof(*foh); 2548 2549 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd, 2550 pnd->pnd_all_fd_len + fd_len); 2551 if (pnd->pnd_all_fd == NULL) 2552 DERR(EX_OSERR, "%s: malloc failed", __func__); 2553 2554 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len; 2555 (void)memcpy(afdp, fd, fd_len); 2556 2557 pnd->pnd_all_fd_len += fd_len; 2558 2559 /* 2560 * The fd->off field is used as a cookie for 2561 * resuming the next readdir() where this one was left. 2562 */ 2563 pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len); 2564 2565 ps->ps_destroy_msg(pm); 2566 pm = NULL; 2567 } while (1 /* CONSTCOND */); 2568 2569 if (pnd->pnd_all_fd != NULL) { 2570 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, 2571 pnd->pnd_all_fd_len) == -1) 2572 error = EIO; 2573 } 2574 2575 out: 2576 if (pnd->pnd_all_fd != NULL) { 2577 free(pnd->pnd_all_fd); 2578 pnd->pnd_all_fd = NULL; 2579 pnd->pnd_all_fd_len = 0; 2580 } 2581 2582 if (pm != NULL) 2583 ps->ps_destroy_msg(pm); 2584 2585 if (error == 0) 2586 error = readdir_buffered(opc, dent, readoff, reslen); 2587 2588 /* 2589 * Schedule queued readdir requests 2590 */ 2591 pnd->pnd_flags &= ~PND_INREADDIR; 2592 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL); 2593 2594 #ifdef PERFUSE_DEBUG 2595 if (perfuse_diagflags & PDF_READDIR) 2596 DPRINTF("%s: READDIR opc = %p exit critical section\n", 2597 __func__, (void *)opc); 2598 #endif 2599 2600 return error; 2601 } 2602 2603 int 2604 perfuse_node_readlink(pu, opc, pcr, linkname, linklen) 2605 struct puffs_usermount *pu; 2606 puffs_cookie_t opc; 2607 const struct puffs_cred *pcr; 2608 char *linkname; 2609 size_t *linklen; 2610 { 2611 struct perfuse_state *ps; 2612 perfuse_msg_t *pm; 2613 int error; 2614 size_t len; 2615 struct fuse_out_header *foh; 2616 2617 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2618 return ENOENT; 2619 2620 ps = puffs_getspecific(pu); 2621 2622 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr); 2623 2624 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2625 goto out; 2626 2627 foh = GET_OUTHDR(ps, pm); 2628 len = foh->len - sizeof(*foh); 2629 if (len > *linklen) 2630 DERRX(EX_PROTOCOL, "path len = %zd too long", len); 2631 if (len == 0) 2632 DERRX(EX_PROTOCOL, "path len = %zd too short", len); 2633 2634 /* 2635 * FUSE filesystems return a NUL terminated string, we 2636 * do not want to trailing \0 2637 */ 2638 *linklen = len - 1; 2639 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len); 2640 out: 2641 ps->ps_destroy_msg(pm); 2642 2643 return error; 2644 } 2645 2646 int 2647 perfuse_node_reclaim(pu, opc) 2648 struct puffs_usermount *pu; 2649 puffs_cookie_t opc; 2650 { 2651 struct perfuse_state *ps; 2652 perfuse_msg_t *pm; 2653 struct perfuse_node_data *pnd; 2654 struct fuse_forget_in *ffi; 2655 struct puffs_node *pn; 2656 struct puffs_node *pn_root; 2657 2658 ps = puffs_getspecific(pu); 2659 pnd = PERFUSE_NODE_DATA(opc); 2660 2661 /* 2662 * Never forget the root. 2663 */ 2664 if (pnd->pnd_nodeid == FUSE_ROOT_ID) 2665 return 0; 2666 2667 pnd->pnd_flags |= PND_RECLAIMED; 2668 2669 #ifdef PERFUSE_DEBUG 2670 if (perfuse_diagflags & PDF_RECLAIM) 2671 DPRINTF("%s (nodeid %"PRId64") reclaimed\n", 2672 perfuse_node_path(opc), pnd->pnd_nodeid); 2673 #endif 2674 2675 pn_root = puffs_getroot(pu); 2676 pn = (struct puffs_node *)opc; 2677 while (pn != pn_root) { 2678 struct puffs_node *parent_pn; 2679 2680 pnd = PERFUSE_NODE_DATA(pn); 2681 2682 #ifdef PERFUSE_DEBUG 2683 if (perfuse_diagflags & PDF_RECLAIM) 2684 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, " 2685 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n", 2686 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_nodeid, 2687 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2688 pnd->pnd_childcount, 2689 pnd->pnd_flags & PND_OPEN ? "open " : "not open", 2690 pnd->pnd_flags & PND_RFH ? "r" : "", 2691 pnd->pnd_flags & PND_WFH ? "w" : "", 2692 pnd->pnd_flags & PND_BUSY ? "" : " none", 2693 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "", 2694 pnd->pnd_flags & PND_INWRITE ? " write" : "", 2695 pnd->pnd_flags & PND_INOPEN ? " open" : ""); 2696 #endif 2697 2698 if (!(pnd->pnd_flags & PND_RECLAIMED) || 2699 (pnd->pnd_childcount != 0)) 2700 return 0; 2701 2702 #ifdef PERFUSE_DEBUG 2703 if ((pnd->pnd_flags & PND_OPEN) || 2704 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2705 DERRX(EX_SOFTWARE, "%s: opc = %p: still open", 2706 __func__, (void *)opc); 2707 2708 if ((pnd->pnd_flags & PND_BUSY) || 2709 !TAILQ_EMPTY(&pnd->pnd_pcq)) 2710 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations", 2711 __func__, (void *)opc); 2712 #endif 2713 2714 /* 2715 * Send the FORGET message 2716 * 2717 * ps_new_msg() is called with NULL creds, which will 2718 * be interpreted as FUSE superuser. This is obviously 2719 * fine since we operate with kernel creds here. 2720 */ 2721 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET, 2722 sizeof(*ffi), NULL); 2723 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2724 ffi->nlookup = pnd->pnd_nlookup; 2725 2726 /* 2727 * No reply is expected, pm is freed in xchg_msg 2728 */ 2729 (void)xchg_msg(pu, (puffs_cookie_t)pn, 2730 pm, UNSPEC_REPLY_LEN, no_reply); 2731 2732 parent_pn = pnd->pnd_parent; 2733 2734 perfuse_destroy_pn(pn); 2735 2736 pn = parent_pn; 2737 } 2738 2739 return 0; 2740 } 2741 2742 int 2743 perfuse_node_inactive(pu, opc) 2744 struct puffs_usermount *pu; 2745 puffs_cookie_t opc; 2746 { 2747 struct perfuse_state *ps; 2748 struct perfuse_node_data *pnd; 2749 2750 ps = puffs_getspecific(pu); 2751 pnd = PERFUSE_NODE_DATA(opc); 2752 2753 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED))) 2754 return 0; 2755 2756 /* 2757 * Make sure all operation are finished 2758 * There can be an ongoing write. Other 2759 * operation wait for all data before 2760 * the close/inactive. 2761 */ 2762 while (pnd->pnd_flags & PND_INWRITE) 2763 requeue_request(pu, opc, PCQ_AFTERWRITE); 2764 2765 /* 2766 * The inactive operation may be cancelled. 2767 * If no open is in progress, set PND_INOPEN 2768 * so that a new open will be queued. 2769 */ 2770 if (pnd->pnd_flags & PND_INOPEN) 2771 return 0; 2772 2773 pnd->pnd_flags |= PND_INOPEN; 2774 2775 /* 2776 * Sync data 2777 */ 2778 if (pnd->pnd_flags & PND_DIRTY) 2779 (void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0); 2780 2781 /* 2782 * Close handles 2783 */ 2784 if (pnd->pnd_flags & PND_WFH) 2785 (void)perfuse_node_close_common(pu, opc, FWRITE); 2786 2787 if (pnd->pnd_flags & PND_RFH) 2788 (void)perfuse_node_close_common(pu, opc, FREAD); 2789 2790 /* 2791 * This will cause a reclaim to be sent 2792 */ 2793 if (pnd->pnd_flags & PND_REMOVED) 2794 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 2795 2796 /* 2797 * Schedule awaiting operations 2798 */ 2799 pnd->pnd_flags &= ~PND_INOPEN; 2800 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL); 2801 2802 return 0; 2803 } 2804 2805 2806 /* ARGSUSED0 */ 2807 int 2808 perfuse_node_print(pu, opc) 2809 struct puffs_usermount *pu; 2810 puffs_cookie_t opc; 2811 { 2812 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2813 return 0; 2814 } 2815 2816 /* ARGSUSED0 */ 2817 int 2818 perfuse_node_pathconf(pu, opc, name, retval) 2819 struct puffs_usermount *pu; 2820 puffs_cookie_t opc; 2821 int name; 2822 int *retval; 2823 { 2824 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2825 return 0; 2826 } 2827 2828 /* id is unused */ 2829 /* ARGSUSED2 */ 2830 int 2831 perfuse_node_advlock(pu, opc, id, op, fl, flags) 2832 struct puffs_usermount *pu; 2833 puffs_cookie_t opc; 2834 void *id; 2835 int op; 2836 struct flock *fl; 2837 int flags; 2838 { 2839 struct perfuse_state *ps; 2840 int fop; 2841 perfuse_msg_t *pm; 2842 struct fuse_lk_in *fli; 2843 struct fuse_out_header *foh; 2844 struct fuse_lk_out *flo; 2845 uint32_t owner; 2846 size_t len; 2847 int error; 2848 2849 ps = puffs_getspecific(pu); 2850 2851 if (op == F_GETLK) 2852 fop = FUSE_GETLK; 2853 else 2854 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2855 2856 /* 2857 * XXX ps_new_msg() is called with NULL creds, which will 2858 * be interpreted as FUSE superuser. We have no way to 2859 * know the requesting process' credential, but since advlock() 2860 * is supposed to operate on a file that has been open(), 2861 * permission should have already been checked at open() time. 2862 */ 2863 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 2864 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 2865 fli->fh = perfuse_get_fh(opc, FWRITE); 2866 fli->owner = fl->l_pid; 2867 fli->lk.start = fl->l_start; 2868 fli->lk.end = fl->l_start + fl->l_len; 2869 fli->lk.type = fl->l_type; 2870 fli->lk.pid = fl->l_pid; 2871 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 2872 2873 owner = fl->l_pid; 2874 2875 #ifdef PERFUSE_DEBUG 2876 if (perfuse_diagflags & PDF_FH) 2877 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2878 __func__, (void *)opc, 2879 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh); 2880 #endif 2881 2882 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2883 goto out; 2884 2885 foh = GET_OUTHDR(ps, pm); 2886 len = foh->len - sizeof(*foh); 2887 2888 /* 2889 * Save or clear the lock 2890 */ 2891 switch (op) { 2892 case F_GETLK: 2893 if (len != sizeof(*flo)) 2894 DERRX(EX_SOFTWARE, 2895 "%s: Unexpected lock reply len %zd", 2896 __func__, len); 2897 2898 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out); 2899 fl->l_start = flo->lk.start; 2900 fl->l_len = flo->lk.end - flo->lk.start; 2901 fl->l_pid = flo->lk.pid; 2902 fl->l_type = flo->lk.type; 2903 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */ 2904 2905 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid; 2906 break; 2907 case F_UNLCK: 2908 owner = 0; 2909 /* FALLTHROUGH */ 2910 case F_SETLK: 2911 /* FALLTHROUGH */ 2912 case F_SETLKW: 2913 if (error != 0) 2914 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner; 2915 2916 if (len != 0) 2917 DERRX(EX_SOFTWARE, 2918 "%s: Unexpected unlock reply len %zd", 2919 __func__, len); 2920 2921 break; 2922 default: 2923 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op); 2924 break; 2925 } 2926 2927 out: 2928 ps->ps_destroy_msg(pm); 2929 2930 return error; 2931 } 2932 2933 int 2934 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag) 2935 struct puffs_usermount *pu; 2936 puffs_cookie_t opc; 2937 uint8_t *buf; 2938 off_t offset; 2939 size_t *resid; 2940 const struct puffs_cred *pcr; 2941 int ioflag; 2942 { 2943 struct perfuse_state *ps; 2944 struct perfuse_node_data *pnd; 2945 const struct vattr *vap; 2946 perfuse_msg_t *pm; 2947 struct fuse_read_in *fri; 2948 struct fuse_out_header *foh; 2949 size_t readen; 2950 int error; 2951 2952 ps = puffs_getspecific(pu); 2953 pnd = PERFUSE_NODE_DATA(opc); 2954 vap = puffs_pn_getvap((struct puffs_node *)opc); 2955 pm = NULL; 2956 2957 /* 2958 * NetBSD turns that into a getdents(2) output 2959 * We just do a EISDIR as this feature is of little use. 2960 */ 2961 if (vap->va_type == VDIR) 2962 return EISDIR; 2963 2964 if ((u_quad_t)offset + *resid > vap->va_size) 2965 DWARNX("%s %p read %lld@%zu beyond EOF %" PRIu64 "\n", 2966 __func__, (void *)opc, (long long)offset, 2967 *resid, vap->va_size); 2968 2969 do { 2970 size_t max_read; 2971 2972 max_read = ps->ps_max_readahead - sizeof(*foh); 2973 /* 2974 * flags may be set to FUSE_READ_LOCKOWNER 2975 * if lock_owner is provided. 2976 */ 2977 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 2978 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2979 fri->fh = perfuse_get_fh(opc, FREAD); 2980 fri->offset = offset; 2981 fri->size = (uint32_t)MIN(*resid, max_read); 2982 fri->read_flags = 0; /* XXX Unused by libfuse? */ 2983 fri->lock_owner = pnd->pnd_lock_owner; 2984 fri->flags = 0; 2985 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 2986 2987 #ifdef PERFUSE_DEBUG 2988 if (perfuse_diagflags & PDF_FH) 2989 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2990 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 2991 #endif 2992 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 2993 2994 if (error != 0) 2995 goto out; 2996 2997 foh = GET_OUTHDR(ps, pm); 2998 readen = foh->len - sizeof(*foh); 2999 3000 #ifdef PERFUSE_DEBUG 3001 if (readen > *resid) 3002 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd", 3003 __func__, readen); 3004 #endif 3005 3006 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 3007 3008 buf += readen; 3009 offset += readen; 3010 *resid -= readen; 3011 3012 ps->ps_destroy_msg(pm); 3013 pm = NULL; 3014 } while ((*resid != 0) && (readen != 0)); 3015 3016 if (ioflag & (IO_SYNC|IO_DSYNC)) 3017 ps->ps_syncreads++; 3018 else 3019 ps->ps_asyncreads++; 3020 3021 out: 3022 if (pm != NULL) 3023 ps->ps_destroy_msg(pm); 3024 3025 return error; 3026 } 3027 3028 int 3029 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag) 3030 struct puffs_usermount *pu; 3031 puffs_cookie_t opc; 3032 uint8_t *buf; 3033 off_t offset; 3034 size_t *resid; 3035 const struct puffs_cred *pcr; 3036 int ioflag; 3037 { 3038 struct perfuse_state *ps; 3039 struct perfuse_node_data *pnd; 3040 struct vattr *vap; 3041 perfuse_msg_t *pm; 3042 struct fuse_write_in *fwi; 3043 struct fuse_write_out *fwo; 3044 size_t data_len; 3045 size_t payload_len; 3046 size_t written; 3047 int inresize; 3048 int error; 3049 3050 ps = puffs_getspecific(pu); 3051 pnd = PERFUSE_NODE_DATA(opc); 3052 vap = puffs_pn_getvap((struct puffs_node *)opc); 3053 written = 0; 3054 inresize = 0; 3055 pm = NULL; 3056 3057 if (vap->va_type == VDIR) 3058 return EISDIR; 3059 3060 /* 3061 * We need to queue write requests in order to avoid 3062 * dequeueing PCQ_AFTERWRITE when there are pending writes. 3063 */ 3064 while (pnd->pnd_flags & PND_INWRITE) 3065 requeue_request(pu, opc, PCQ_WRITE); 3066 pnd->pnd_flags |= PND_INWRITE; 3067 3068 /* 3069 * Serialize size access, see comment in perfuse_node_setattr(). 3070 */ 3071 if ((u_quad_t)offset + *resid > vap->va_size) { 3072 while (pnd->pnd_flags & PND_INRESIZE) 3073 requeue_request(pu, opc, PCQ_RESIZE); 3074 pnd->pnd_flags |= PND_INRESIZE; 3075 inresize = 1; 3076 } 3077 3078 /* 3079 * append flag: re-read the file size so that 3080 * we get the latest value. 3081 */ 3082 if (ioflag & PUFFS_IO_APPEND) { 3083 DWARNX("%s: PUFFS_IO_APPEND set, untested code", __func__); 3084 3085 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0) 3086 goto out; 3087 3088 offset = vap->va_size; 3089 } 3090 3091 pm = NULL; 3092 3093 #ifdef PERFUSE_DEBUG 3094 if (perfuse_diagflags & PDF_RESIZE) 3095 DPRINTF(">> %s %p %" PRIu64 "\n", __func__, 3096 (void *)opc, vap->va_size); 3097 #endif 3098 3099 do { 3100 size_t max_write; 3101 /* 3102 * There is a writepage flag when data 3103 * is aligned to page size. Use it for 3104 * everything but the data after the last 3105 * page boundary. 3106 */ 3107 max_write = ps->ps_max_write - sizeof(*fwi); 3108 3109 data_len = MIN(*resid, max_write); 3110 if (data_len > (size_t)sysconf(_SC_PAGESIZE)) 3111 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1); 3112 3113 payload_len = data_len + sizeof(*fwi); 3114 3115 /* 3116 * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 3117 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 3118 * write_flags is set to 1 for writepage. 3119 */ 3120 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 3121 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 3122 fwi->fh = perfuse_get_fh(opc, FWRITE); 3123 fwi->offset = offset; 3124 fwi->size = (uint32_t)data_len; 3125 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1; 3126 fwi->lock_owner = pnd->pnd_lock_owner; 3127 fwi->flags = 0; 3128 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 3129 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE; 3130 (void)memcpy((fwi + 1), buf, data_len); 3131 3132 3133 #ifdef PERFUSE_DEBUG 3134 if (perfuse_diagflags & PDF_FH) 3135 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " 3136 "fh = 0x%"PRIx64"\n", __func__, 3137 (void *)opc, pnd->pnd_nodeid, fwi->fh); 3138 #endif 3139 if ((error = xchg_msg(pu, opc, pm, 3140 sizeof(*fwo), wait_reply)) != 0) 3141 goto out; 3142 3143 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 3144 written = fwo->size; 3145 #ifdef PERFUSE_DEBUG 3146 if (written > *resid) 3147 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd", 3148 __func__, written); 3149 #endif 3150 *resid -= written; 3151 offset += written; 3152 buf += written; 3153 3154 ps->ps_destroy_msg(pm); 3155 pm = NULL; 3156 } while (*resid != 0); 3157 3158 /* 3159 * puffs_ops(3) says 3160 * "everything must be written or an error will be generated" 3161 */ 3162 if (*resid != 0) 3163 error = EFBIG; 3164 3165 #ifdef PERFUSE_DEBUG 3166 if (perfuse_diagflags & PDF_RESIZE) { 3167 if (offset > (off_t)vap->va_size) 3168 DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__, 3169 (void *)opc, vap->va_size, (long long)offset); 3170 else 3171 DPRINTF("<< %s %p \n", __func__, (void *)opc); 3172 } 3173 #endif 3174 3175 /* 3176 * Update file size if we wrote beyond the end 3177 */ 3178 if (offset > (off_t)vap->va_size) 3179 vap->va_size = offset; 3180 3181 if (inresize) { 3182 #ifdef PERFUSE_DEBUG 3183 if (!(pnd->pnd_flags & PND_INRESIZE)) 3184 DERRX(EX_SOFTWARE, "file write grow without resize"); 3185 #endif 3186 pnd->pnd_flags &= ~PND_INRESIZE; 3187 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL); 3188 } 3189 3190 3191 /* 3192 * Statistics 3193 */ 3194 if (ioflag & (IO_SYNC|IO_DSYNC)) 3195 ps->ps_syncwrites++; 3196 else 3197 ps->ps_asyncwrites++; 3198 3199 /* 3200 * Remember to sync the file 3201 */ 3202 pnd->pnd_flags |= PND_DIRTY; 3203 3204 #ifdef PERFUSE_DEBUG 3205 if (perfuse_diagflags & PDF_SYNC) 3206 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", 3207 __func__, (void*)opc, perfuse_node_path(opc)); 3208 #endif 3209 out: 3210 if (pm != NULL) 3211 ps->ps_destroy_msg(pm); 3212 3213 /* 3214 * If there are no more queued write, we can resume 3215 * an operation awaiting write completion. 3216 */ 3217 pnd->pnd_flags &= ~PND_INWRITE; 3218 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0) 3219 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL); 3220 3221 return error; 3222 } 3223 3224 /* ARGSUSED0 */ 3225 void 3226 perfuse_cache_write(pu, opc, size, runs) 3227 struct puffs_usermount *pu; 3228 puffs_cookie_t opc; 3229 size_t size; 3230 struct puffs_cacherun *runs; 3231 { 3232 return; 3233 } 3234 3235 /* ARGSUSED4 */ 3236 int 3237 perfuse_node_getextattr(pu, opc, attrns, attrname, attrsize, attr, resid, pcr) 3238 struct puffs_usermount *pu; 3239 puffs_cookie_t opc; 3240 int attrns; 3241 const char *attrname; 3242 size_t *attrsize; 3243 uint8_t *attr; 3244 size_t *resid; 3245 const struct puffs_cred *pcr; 3246 { 3247 struct perfuse_state *ps; 3248 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3249 perfuse_msg_t *pm; 3250 struct fuse_getxattr_in *fgi; 3251 struct fuse_getxattr_out *fgo; 3252 struct fuse_out_header *foh; 3253 size_t attrnamelen; 3254 size_t len; 3255 char *np; 3256 int error; 3257 3258 ps = puffs_getspecific(pu); 3259 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3260 attrnamelen = strlen(attrname) + 1; 3261 len = sizeof(*fgi) + attrnamelen; 3262 3263 pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr); 3264 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3265 fgi->size = (unsigned int)((resid != NULL) ? *resid : 0); 3266 np = (char *)(void *)(fgi + 1); 3267 (void)strlcpy(np, attrname, attrnamelen); 3268 3269 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3270 goto out; 3271 3272 /* 3273 * We just get fuse_getattr_out with list size if we requested 3274 * a null size. 3275 */ 3276 if (resid == NULL) { 3277 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3278 3279 if (attrsize != NULL) 3280 *attrsize = fgo->size; 3281 3282 goto out; 3283 } 3284 3285 /* 3286 * And with a non null requested size, we get the list just 3287 * after the header 3288 */ 3289 foh = GET_OUTHDR(ps, pm); 3290 np = (char *)(void *)(foh + 1); 3291 3292 if (resid != NULL) { 3293 len = MAX(foh->len - sizeof(*foh), *resid); 3294 (void)memcpy(attr, np, len); 3295 *resid -= len; 3296 } 3297 3298 out: 3299 ps->ps_destroy_msg(pm); 3300 3301 return error; 3302 } 3303 3304 int 3305 perfuse_node_setextattr(pu, opc, attrns, attrname, attr, resid, pcr) 3306 struct puffs_usermount *pu; 3307 puffs_cookie_t opc; 3308 int attrns; 3309 const char *attrname; 3310 uint8_t *attr; 3311 size_t *resid; 3312 const struct puffs_cred *pcr; 3313 { 3314 struct perfuse_state *ps; 3315 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3316 perfuse_msg_t *pm; 3317 struct fuse_setxattr_in *fsi; 3318 size_t attrnamelen; 3319 size_t len; 3320 char *np; 3321 int error; 3322 3323 ps = puffs_getspecific(pu); 3324 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3325 attrnamelen = strlen(attrname) + 1; 3326 len = sizeof(*fsi) + attrnamelen + *resid; 3327 3328 pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr); 3329 fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in); 3330 fsi->size = (unsigned int)*resid; 3331 fsi->flags = 0; 3332 np = (char *)(void *)(fsi + 1); 3333 (void)strlcpy(np, attrname, attrnamelen); 3334 np += attrnamelen; 3335 (void)memcpy(np, (char *)attr, *resid); 3336 3337 if ((error = xchg_msg(pu, opc, pm, 3338 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 3339 goto out; 3340 3341 *resid = 0; 3342 out: 3343 ps->ps_destroy_msg(pm); 3344 3345 return error; 3346 } 3347 3348 /* ARGSUSED2 */ 3349 int 3350 perfuse_node_listextattr(pu, opc, attrns, attrsize, attrs, resid, flag, pcr) 3351 struct puffs_usermount *pu; 3352 puffs_cookie_t opc; 3353 int attrns; 3354 size_t *attrsize; 3355 uint8_t *attrs; 3356 size_t *resid; 3357 int flag; 3358 const struct puffs_cred *pcr; 3359 { 3360 struct perfuse_state *ps; 3361 perfuse_msg_t *pm; 3362 struct fuse_getxattr_in *fgi; 3363 struct fuse_getxattr_out *fgo; 3364 struct fuse_out_header *foh; 3365 char *np; 3366 size_t len, puffs_len; 3367 int error; 3368 3369 ps = puffs_getspecific(pu); 3370 len = sizeof(*fgi); 3371 3372 pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr); 3373 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3374 if (resid != NULL) 3375 fgi->size = (unsigned int)*resid; 3376 else 3377 fgi->size = 0; 3378 3379 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3380 goto out; 3381 3382 /* 3383 * We just get fuse_getattr_out with list size if we requested 3384 * a null size. 3385 */ 3386 if (resid == NULL) { 3387 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3388 3389 if (attrsize != NULL) 3390 *attrsize = fgo->size; 3391 3392 goto out; 3393 } 3394 3395 /* 3396 * And with a non null requested size, we get the list just 3397 * after the header 3398 */ 3399 foh = GET_OUTHDR(ps, pm); 3400 np = (char *)(void *)(foh + 1); 3401 puffs_len = foh->len - sizeof(*foh); 3402 3403 if (attrs != NULL) { 3404 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX 3405 /* 3406 * Convert the FUSE reply to length prefixed strings 3407 * if this is what the kernel wants. 3408 */ 3409 if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) { 3410 size_t i, attrlen; 3411 3412 for (i = 0; i < puffs_len; i += attrlen + 1) { 3413 attrlen = strlen(np + i); 3414 (void)memmove(np + i + 1, np + i, attrlen); 3415 *(np + i) = (uint8_t)attrlen; 3416 } 3417 } 3418 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */ 3419 (void)memcpy(attrs, np, puffs_len); 3420 *resid -= puffs_len; 3421 } 3422 3423 if (attrsize != NULL) 3424 *attrsize = puffs_len; 3425 3426 out: 3427 ps->ps_destroy_msg(pm); 3428 3429 return error; 3430 } 3431 3432 int 3433 perfuse_node_deleteextattr(pu, opc, attrns, attrname, pcr) 3434 struct puffs_usermount *pu; 3435 puffs_cookie_t opc; 3436 int attrns; 3437 const char *attrname; 3438 const struct puffs_cred *pcr; 3439 { 3440 struct perfuse_state *ps; 3441 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3442 perfuse_msg_t *pm; 3443 size_t attrnamelen; 3444 char *np; 3445 int error; 3446 3447 ps = puffs_getspecific(pu); 3448 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3449 attrnamelen = strlen(attrname) + 1; 3450 3451 pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr); 3452 np = _GET_INPAYLOAD(ps, pm, char *); 3453 (void)strlcpy(np, attrname, attrnamelen); 3454 3455 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 3456 3457 ps->ps_destroy_msg(pm); 3458 3459 return error; 3460 } 3461