/* no memory allocation, direct copy */ int psbuf_do_data(struct puffs_framebuf *pb, uint8_t *data, uint32_t *dlen) { void *win; size_t bufoff, winlen; uint32_t len, dataoff; if (psbuf_get_type(pb) != SSH_FXP_DATA) { uint32_t val; if (psbuf_get_type(pb) != SSH_FXP_STATUS) return INVALRESPONSE; if (psbuf_get_4(pb, &val) != 0) return INVALRESPONSE; if (val != SSH_FX_EOF) return sftperr_to_errno(val); *dlen = 0; return 0; } if (psbuf_get_4(pb, &len) != 0) return INVALRESPONSE; if (*dlen < len) return EINVAL; *dlen = 0; dataoff = 0; while (dataoff < len) { winlen = len-dataoff; bufoff = puffs_framebuf_telloff(pb); if (puffs_framebuf_getwindow(pb, bufoff, &win, &winlen) == -1) return EINVAL; if (winlen == 0) break; memcpy(data + dataoff, win, winlen); dataoff += winlen; } *dlen = dataoff; return 0; }
int psbuf_expect_name(struct puffs_framebuf *pb, uint32_t *count) { CHECKCODE(pb, SSH_FXP_NAME); FAILRV(psbuf_get_4(pb, count)); return 0; }
int psbuf_expect_status(struct puffs_framebuf *pb) { uint32_t error; if (psbuf_get_type(pb) != SSH_FXP_STATUS) return INVALRESPONSE; FAILRV(psbuf_get_4(pb, &error)); return sftperr_to_errno(error); }
static int expectcode(struct puffs_framebuf *pb, int value) { uint32_t error; uint8_t type; type = psbuf_get_type(pb); if (type == value) return 0; if (type != SSH_FXP_STATUS) return INVALRESPONSE; FAILRV(psbuf_get_4(pb, &error)); return sftperr_to_errno(error); }
int psbuf_get_str(struct puffs_framebuf *pb, char **strp, uint32_t *strlenp) { char *str; uint32_t len; FAILRV(psbuf_get_4(pb, &len)); if (puffs_framebuf_remaining(pb) < len) return EPROTO; str = emalloc(len+1); puffs_framebuf_getdata(pb, str, len); str[len] = '\0'; *strp = str; if (strlenp) *strlenp = len; return 0; }
int psbuf_get_vattr(struct puffs_framebuf *pb, struct vattr *vap) { uint32_t flags; uint32_t val; uint32_t tmpval; puffs_vattr_null(vap); FAILRV(psbuf_get_4(pb, &flags)); if (flags & SSH_FILEXFER_ATTR_SIZE) { FAILRV(psbuf_get_8(pb, &vap->va_size)); vap->va_bytes = vap->va_size; } if (flags & SSH_FILEXFER_ATTR_UIDGID) { FAILRV(psbuf_get_4(pb, &vap->va_uid)); FAILRV(psbuf_get_4(pb, &vap->va_gid)); } if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) { FAILRV(psbuf_get_4(pb, &tmpval)); vap->va_mode = tmpval; vap->va_type = puffs_mode2vt(vap->va_mode); } if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) { /* * XXX: this is utterly wrong if we want to speak * protocol version 3, but it seems like the * "internet standard" for doing this */ FAILRV(psbuf_get_4(pb, &val)); vap->va_atime.tv_sec = val; FAILRV(psbuf_get_4(pb, &val)); vap->va_mtime.tv_sec = val; /* make ctime the same as mtime */ vap->va_ctime.tv_sec = val; vap->va_atime.tv_nsec = 0; vap->va_ctime.tv_nsec = 0; vap->va_mtime.tv_nsec = 0; } return 0; }
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; }