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