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; }
/* flags: 1 - need free sec, 2 - need bad sec */ int fat_dstat(DRIVE *dv, struct fat_dstat *st, int flags) { unsigned clsh = dv->clust_sh - dv->sec_sh; struct buf *boot; int err; u8 *p; if(!(dv->flags & DRV_OPEN)) /* XXX ? */ return reterr(-ENODEV); err = get_buf(dv, 0, &boot, 1); if(err<0) return reterr(err); memcpy(st->oemid, boot->data+3, 8); st->serial = 0; st->label[0] = 0; p = boot->data + ((dv->flags&DRV_FAT) != DRV_FAT32 ? 0x26 : 0x42); if(*p == 0x29 || *p == 0x28 /*?*/) { int l; st->serial = get32(p+1); p += 5; for(l=11; l>0; l--) if(p[l-1]!=' ') break; memcpy(st->label, p, l); st->label[l] = 0; } st->sector_sh = dv->sec_sh; st->cluster_sh = clsh; st->size = dv->totsec; st->capacity = (dv->clust_max-1)<<clsh; st->free = 0; st->bad = 0; /* if(flags==1 && (dv->flags&DRV_FAT)==DRV_FAT32) { int sec = get32(boot->data+48); u8 *b = get_fsinfosec(dv, sec); if(b) { st->free = get32(b+488); flags = 0; } }*/ if(flags & 3) { int n, m=dv->clust_max; unsigned s=0, b=0; for(n=2; n<=m; n++) { int v = fat_get(dv, n, 1); s += (v == FAT_FREE); b += (v == FAT_BAD); } st->free = s<<clsh; st->bad = b<<clsh; } switch(dv->flags & DRV_FAT) { case DRV_FAT12: st->fat_type = fat_fat12; break; case DRV_FAT16: st->fat_type = fat_fat16; break; case DRV_FAT32: st->fat_type = fat_fat32; break; } return 0; }