static void setpnva(struct puffs_usermount *pu, struct puffs_node *pn, const struct vattr *vap) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct psshfs_node *psn = pn->pn_data; struct vattr modva; /* * Check if the file was modified from below us. * If so, invalidate page cache. This is the only * sensible place we can do this in. */ if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL) if (pn->pn_va.va_mtime.tv_sec != vap->va_mtime.tv_sec && pn->pn_va.va_type == VREG) puffs_inval_pagecache_node(pu, pn); modva = *vap; if (pctx->domangleuid && modva.va_uid == pctx->mangleuid) modva.va_uid = pctx->myuid; if (pctx->domanglegid && modva.va_gid == pctx->manglegid) modva.va_gid = pctx->mygid; puffs_setvattr(&pn->pn_va, &modva); psn->attrread = time(NULL); }
/* * Ok, time to get clever. There are two possible cases: we are * opening a file or we are opening a directory. * * If it's a directory, don't bother opening it here, but rather * wait until readdir, since it's probable we need to be able to * open a directory there in any case. * * If it's a regular file, open it here with whatever credentials * we happen to have. Let the upper layers of the kernel worry * about permission control. */ int puffs9p_node_open(struct puffs_usermount *pu, void *opc, int mode, const struct puffs_cred *pcr) { struct puffs_cc *pcc = puffs_cc_getcc(pu); struct puffs9p *p9p = puffs_getspecific(pu); struct puffs_node *pn = opc; struct p9pnode *p9n = pn->pn_data; p9pfid_t nfid; int error = 0; puffs_setback(pcc, PUFFS_SETBACK_INACT_N1); if (pn->pn_va.va_type != VDIR) { if (mode & FREAD && p9n->fid_read == P9P_INVALFID) { nfid = NEXTFID(p9p); error = proto_cc_open(pu, p9n->fid_base, nfid, P9PROTO_OMODE_READ); if (error) return error; p9n->fid_read = nfid; } if (mode & FWRITE && p9n->fid_write == P9P_INVALFID) { nfid = NEXTFID(p9p); error = proto_cc_open(pu, p9n->fid_base, nfid, P9PROTO_OMODE_WRITE); if (error) return error; p9n->fid_write = nfid; } } return 0; }
struct puffs_node * allocnode(struct puffs_usermount *pu, struct puffs_node *parent, const char *entryname, const struct vattr *vap) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct psshfs_dir *pd; struct puffs_node *pn; pd = direnter(parent, entryname); pd->va.va_fileid = pctx->nextino++; if (vap->va_type == VDIR) { pd->va.va_nlink = 2; parent->pn_va.va_nlink++; } else { pd->va.va_nlink = 1; } pn = makenode(pu, parent, pd, vap); if (pn) { pd->va.va_fileid = pn->pn_va.va_fileid; pd->entry = pn; } return pn; }
void closehandles(struct puffs_usermount *pu, struct psshfs_node *psn, int which) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct puffs_framebuf *pb1, *pb2; uint32_t reqid; if (psn->fhand_r && (which & HANDLE_READ)) { assert(psn->lazyopen_r == NULL); pb1 = psbuf_makeout(); reqid = NEXTREQ(pctx); psbuf_req_data(pb1, SSH_FXP_CLOSE, reqid, psn->fhand_r, psn->fhand_r_len); puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb1, 1, 0); free(psn->fhand_r); psn->fhand_r = NULL; } if (psn->fhand_w && (which & HANDLE_WRITE)) { assert(psn->lazyopen_w == NULL); pb2 = psbuf_makeout(); reqid = NEXTREQ(pctx); psbuf_req_data(pb2, SSH_FXP_CLOSE, reqid, psn->fhand_w, psn->fhand_w_len); puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb2, 1, 0); free(psn->fhand_w); psn->fhand_w = NULL; } psn->stat |= PSN_HANDLECLOSE; }
int psshfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, struct puffs_newinfo *pni) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct psshfs_fid *pf = fid; struct puffs_node *pn = pf->node; struct psshfs_node *psn; int rv; if (pf->mounttime != pctx->mounttime) return EINVAL; if (pn == 0) return EINVAL; psn = pn->pn_data; if ((psn->stat & PSN_HASFH) == 0) return EINVAL; /* update node attributes */ rv = getnodeattr(pu, pn); if (rv) return EINVAL; puffs_newinfo_setcookie(pni, pn); puffs_newinfo_setvtype(pni, pn->pn_va.va_type); puffs_newinfo_setsize(pni, pn->pn_va.va_size); return 0; }
void perfuse_destroy_pn(struct puffs_usermount *pu, struct puffs_node *pn) { struct perfuse_state *ps = puffs_getspecific(pu); struct perfuse_node_data *pnd; if ((pnd = puffs_pn_getpriv(pn)) != NULL) { if (pnd->pnd_all_fd != NULL) free(pnd->pnd_all_fd); if (pnd->pnd_dirent != NULL) free(pnd->pnd_dirent); #ifdef PERFUSE_DEBUG if (pnd->pnd_flags & PND_OPEN) DERRX(EX_SOFTWARE, "%s: file open", __func__); if (!TAILQ_EMPTY(&pnd->pnd_pcq)) DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__); pnd->pnd_flags |= PND_INVALID; #endif /* PERFUSE_DEBUG */ free(pnd); } puffs_pn_put(pn); ps->ps_nodecount--; return; }
static int pssh_connect(struct puffs_usermount *pu, int which) { struct psshfs_ctx *pctx = puffs_getspecific(pu); char * const *sshargs = pctx->sshargs; int fds[2]; pid_t pid; int dnfd, x; int *sshfd; pid_t *sshpid; if (which == PSSHFD_META) { sshfd = &pctx->sshfd; sshpid = &pctx->sshpid; } else { assert(which == PSSHFD_DATA); sshfd = &pctx->sshfd_data; sshpid = &pctx->sshpid_data; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) return -1; pid = fork(); switch (pid) { case -1: return -1; /*NOTREACHED*/ case 0: /* child */ if (dup2(fds[0], STDIN_FILENO) == -1) err(1, "child dup2"); if (dup2(fds[0], STDOUT_FILENO) == -1) err(1, "child dup2"); close(fds[0]); close(fds[1]); dnfd = open(_PATH_DEVNULL, O_RDWR); if (dnfd != -1) dup2(dnfd, STDERR_FILENO); execvp(sshargs[0], sshargs); /*NOTREACHED*/ break; default: *sshpid = pid; *sshfd = fds[1]; close(fds[0]); break; } if (psshfs_handshake(pu, *sshfd) != 0) errx(1, "handshake failed, server does not support sftp?"); x = 1; if (ioctl(*sshfd, FIONBIO, &x) == -1) err(1, "nonblocking descriptor %d", which); return *sshfd; }
int dtfs_node_mmap(struct puffs_usermount *pu, void *opc, vm_prot_t prot, const struct puffs_cred *pcr) { struct dtfs_mount *dtm = puffs_getspecific(pu); if ((dtm->dtm_allowprot & prot) != prot) return EACCES; return 0; }
int psshfs_fs_unmount(struct puffs_usermount *pu, int flags) { struct psshfs_ctx *pctx = puffs_getspecific(pu); kill(pctx->sshpid, SIGTERM); close(pctx->sshfd); if (pctx->numconnections == 2) { kill(pctx->sshpid_data, SIGTERM); close(pctx->sshfd_data); } return 0; }
void psshfs_notify(struct puffs_usermount *pu, int fd, int what) { struct psshfs_ctx *pctx = puffs_getspecific(pu); int nretry, which, newfd, dummy; if (fd == pctx->sshfd) { which = PSSHFD_META; } else { assert(fd == pctx->sshfd_data); which = PSSHFD_DATA; } if (puffs_getstate(pu) != PUFFS_STATE_RUNNING) return; if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) { puffs_framev_removefd(pu, fd, ECONNRESET); return; } close(fd); /* deal with zmobies, beware of half-eaten brain */ while (waitpid(-1, &dummy, WNOHANG) > 0) continue; for (nretry = 0;;nretry++) { if ((newfd = pssh_connect(pu, which)) == -1) goto retry2; if (puffs_framev_addfd(pu, newfd, PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1) goto retry1; break; retry1: fprintf(stderr, "reconnect failed... "); close(newfd); retry2: if (nretry < RETRY_MAX) { fprintf(stderr, "retry (%d left)\n", RETRY_MAX-nretry); sleep(nretry); } else { fprintf(stderr, "retry count exceeded, going south\n"); exit(1); /* XXXXXXX */ } } }
int psshfs_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid, size_t *fidsize) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct puffs_node *pn = cookie; struct psshfs_node *psn = pn->pn_data; struct psshfs_fid *pf = fid; pf->mounttime = pctx->mounttime; pf->node = pn; psn->stat |= PSN_HASFH; return 0; }
static void loopfun(struct puffs_usermount *pu) { struct dtfs_mount *dtm = puffs_getspecific(pu); struct dtfs_poll *dp; while (dtm->dtm_needwakeup) { dtm->dtm_needwakeup--; dp = LIST_FIRST(&dtm->dtm_pollent); if (dp == NULL) return; LIST_REMOVE(dp, dp_entries); puffs_cc_continue(dp->dp_pcc); } }
int getnodeattr(struct puffs_usermount *pu, struct puffs_node *pn, const char *path) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct psshfs_node *psn = pn->pn_data; struct vattr va; int rv; if (!psn->attrread || REFRESHTIMEOUT(pctx, time(NULL)-psn->attrread)) { rv = getpathattr(pu, path ? path : PNPATH(pn), &va); if (rv) return rv; setpnva(pu, pn, &va); } return 0; }
int dtfs_node_poll(struct puffs_usermount *pu, void *opc, int *events) { struct dtfs_mount *dtm = puffs_getspecific(pu); struct dtfs_poll dp; struct itimerval it; memset(&it, 0, sizeof(struct itimerval)); it.it_value.tv_sec = 4; if (setitimer(ITIMER_REAL, &it, NULL) == -1) return errno; dp.dp_pcc = puffs_cc_getcc(pu); LIST_INSERT_HEAD(&dtm->dtm_pollent, &dp, dp_entries); puffs_cc_yield(dp.dp_pcc); *events = *events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); return 0; }
struct puffs_node * perfuse_new_pn(struct puffs_usermount *pu, const char *name, struct puffs_node *parent) { struct perfuse_state *ps = puffs_getspecific(pu); struct puffs_node *pn; struct perfuse_node_data *pnd; if ((pnd = malloc(sizeof(*pnd))) == NULL) DERR(EX_OSERR, "%s: malloc failed", __func__); if ((pn = puffs_pn_new(pu, pnd)) == NULL) DERR(EX_SOFTWARE, "%s: puffs_pn_new failed", __func__); (void)memset(pnd, 0, sizeof(*pnd)); pnd->pnd_rfh = FUSE_UNKNOWN_FH; pnd->pnd_wfh = FUSE_UNKNOWN_FH; pnd->pnd_nodeid = PERFUSE_UNKNOWN_NODEID; if (parent != NULL) { pnd->pnd_parent_nodeid = PERFUSE_NODE_DATA(parent)->pnd_nodeid; } else { pnd->pnd_parent_nodeid = FUSE_ROOT_ID; } pnd->pnd_fuse_nlookup = 0; pnd->pnd_puffs_nlookup = 0; pnd->pnd_pn = (puffs_cookie_t)pn; if (strcmp(name, "..") != 0) (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN); else pnd->pnd_name[0] = 0; /* anonymous for now */ TAILQ_INIT(&pnd->pnd_pcq); puffs_pn_setpriv(pn, pnd); ps->ps_nodecount++; return pn; }
int psshfs_handshake(struct puffs_usermount *pu, int fd) { struct psshfs_ctx *pctx = puffs_getspecific(pu); struct puffs_framebuf *pb; struct puffs_pathobj *po_root; struct puffs_node *pn_root; struct vattr va, *rva; const struct extunit *extu; char *rootpath; char *ext, *val; uint32_t count; int rv, done; pb = psbuf_makeout(); psbuf_put_1(pb, SSH_FXP_INIT); psbuf_put_4(pb, SFTP_PROTOVERSION); DO_IO(psbuf_write, pu, pb, fd, &done, rv); puffs_framebuf_recycle(pb); DO_IO(psbuf_read, pu, pb, fd, &done, rv); if (psbuf_get_type(pb) != SSH_FXP_VERSION) reterr((stderr, "invalid server response: %d", psbuf_get_type(pb)), EPROTO); pctx->protover = psbuf_get_reqid(pb); /* * Check out which extensions are available. Currently * we are only interested in the openssh statvfs extension. */ for (;;) { if (psbuf_get_str(pb, &ext, NULL) != 0) break; if (psbuf_get_str(pb, &val, NULL) != 0) break; for (extu = exttable; extu->ext; extu++) if (strcmp(ext, extu->ext) == 0 && strcmp(val, extu->val) == 0) pctx->extensions |= extu->extflag; } /* scope out our rootpath */ psbuf_recycleout(pb); psbuf_put_1(pb, SSH_FXP_REALPATH); psbuf_put_4(pb, NEXTREQ(pctx)); psbuf_put_str(pb, pctx->mountpath); DO_IO(psbuf_write, pu, pb, fd, &done, rv); puffs_framebuf_recycle(pb); DO_IO(psbuf_read, pu, pb, fd, &done, rv); if (psbuf_get_type(pb) != SSH_FXP_NAME) reterr((stderr, "invalid server realpath response for \"%s\"", pctx->mountpath), EPROTO); if (psbuf_get_4(pb, &count) == -1) reterr((stderr, "invalid realpath response: count"), EPROTO); if (psbuf_get_str(pb, &rootpath, NULL) == -1) reterr((stderr, "invalid realpath response: rootpath"), EPROTO); /* stat the rootdir so that we know it's a dir */ psbuf_recycleout(pb); psbuf_req_str(pb, SSH_FXP_LSTAT, NEXTREQ(pctx), rootpath); DO_IO(psbuf_write, pu, pb, fd, &done, rv); puffs_framebuf_recycle(pb); DO_IO(psbuf_read, pu, pb, fd, &done, rv); rv = psbuf_expect_attrs(pb, &va); if (rv) reterr((stderr, "couldn't stat rootpath"), rv); puffs_framebuf_destroy(pb); if (puffs_mode2vt(va.va_mode) != VDIR) reterr((stderr, "remote path (%s) not a directory", rootpath), ENOTDIR); pn_root = puffs_getroot(pu); rva = &pn_root->pn_va; puffs_setvattr(rva, &va); po_root = puffs_getrootpathobj(pu); if (po_root == NULL) err(1, "getrootpathobj"); po_root->po_path = rootpath; po_root->po_len = strlen(rootpath); return 0; }