Home | History | Annotate | Line # | Download | only in mount_psshfs
psbuf.c revision 1.18.12.1
      1  1.18.12.1    tls /*      $NetBSD: psbuf.c,v 1.18.12.1 2012/11/20 03:03:04 tls Exp $        */
      2        1.1  pooka 
      3        1.1  pooka /*
      4       1.14  pooka  * Copyright (c) 2006-2009  Antti Kantee.  All Rights Reserved.
      5        1.1  pooka  *
      6        1.1  pooka  * Redistribution and use in source and binary forms, with or without
      7        1.1  pooka  * modification, are permitted provided that the following conditions
      8        1.1  pooka  * are met:
      9        1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     10        1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     11        1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12        1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     13        1.1  pooka  *    documentation and/or other materials provided with the distribution.
     14        1.1  pooka  *
     15        1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16        1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17        1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18        1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19        1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20        1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21        1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22        1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23        1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24        1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25        1.1  pooka  * SUCH DAMAGE.
     26        1.1  pooka  */
     27        1.1  pooka 
     28        1.1  pooka #include <sys/cdefs.h>
     29        1.1  pooka #ifndef lint
     30  1.18.12.1    tls __RCSID("$NetBSD: psbuf.c,v 1.18.12.1 2012/11/20 03:03:04 tls Exp $");
     31        1.1  pooka #endif /* !lint */
     32        1.1  pooka 
     33        1.1  pooka /*
     34        1.1  pooka  * buffering functions for network input/output.  slightly different
     35        1.1  pooka  * from the average joe buffer routines, as is usually the case ...
     36        1.1  pooka  * these use efuns for now.
     37        1.1  pooka  */
     38        1.1  pooka 
     39        1.1  pooka #include <sys/types.h>
     40        1.1  pooka #include <sys/time.h>
     41        1.1  pooka #include <sys/vnode.h>
     42  1.18.12.1    tls #include <sys/socket.h>
     43        1.1  pooka 
     44        1.1  pooka #include <err.h>
     45        1.1  pooka #include <errno.h>
     46        1.1  pooka #include <stdlib.h>
     47        1.1  pooka #include <util.h>
     48        1.1  pooka #include <unistd.h>
     49        1.1  pooka 
     50        1.1  pooka #include "psshfs.h"
     51        1.1  pooka #include "sftp_proto.h"
     52        1.1  pooka 
     53        1.5  pooka #define FAILRV(x) do { int rv; if ((rv=x)) return (rv); } while (/*CONSTCOND*/0)
     54        1.5  pooka #define READSTATE_LENGTH(off) (off < 4)
     55        1.1  pooka 
     56        1.5  pooka #define SFTP_LENOFF	0
     57        1.5  pooka #define SFTP_TYPEOFF	4
     58        1.5  pooka #define SFTP_REQIDOFF	5
     59        1.1  pooka 
     60        1.5  pooka #define CHECK(v) if (!(v)) abort()
     61        1.1  pooka 
     62        1.5  pooka uint8_t
     63        1.5  pooka psbuf_get_type(struct puffs_framebuf *pb)
     64        1.5  pooka {
     65        1.5  pooka 	uint8_t type;
     66        1.1  pooka 
     67        1.5  pooka 	puffs_framebuf_getdata_atoff(pb, SFTP_TYPEOFF, &type, 1);
     68        1.5  pooka 	return type;
     69        1.5  pooka }
     70        1.1  pooka 
     71        1.5  pooka uint32_t
     72        1.5  pooka psbuf_get_len(struct puffs_framebuf *pb)
     73        1.5  pooka {
     74        1.5  pooka 	uint32_t len;
     75        1.1  pooka 
     76        1.5  pooka 	puffs_framebuf_getdata_atoff(pb, SFTP_LENOFF, &len, 4);
     77        1.5  pooka 	return be32toh(len);
     78        1.5  pooka }
     79        1.1  pooka 
     80        1.5  pooka uint32_t
     81        1.5  pooka psbuf_get_reqid(struct puffs_framebuf *pb)
     82        1.5  pooka {
     83        1.5  pooka 	uint32_t req;
     84        1.1  pooka 
     85        1.5  pooka 	puffs_framebuf_getdata_atoff(pb, SFTP_REQIDOFF, &req, 4);
     86        1.5  pooka 	return be32toh(req);
     87        1.5  pooka }
     88        1.1  pooka 
     89        1.5  pooka #define CUROFF(pb) (puffs_framebuf_telloff(pb))
     90        1.5  pooka int
     91        1.5  pooka psbuf_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
     92        1.5  pooka 	int fd, int *done)
     93        1.5  pooka {
     94        1.5  pooka 	void *win;
     95        1.5  pooka 	ssize_t n;
     96        1.5  pooka 	size_t howmuch, winlen;
     97        1.5  pooka 	int lenstate;
     98        1.1  pooka 
     99        1.5  pooka  the_next_level:
    100        1.5  pooka 	if ((lenstate = READSTATE_LENGTH(CUROFF(pb))))
    101        1.5  pooka 		howmuch = 4 - CUROFF(pb);
    102        1.5  pooka 	else
    103        1.5  pooka 		howmuch = psbuf_get_len(pb) - (CUROFF(pb) - 4);
    104        1.1  pooka 
    105        1.5  pooka 	if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
    106        1.5  pooka 		return errno;
    107        1.1  pooka 
    108        1.5  pooka 	while (howmuch) {
    109        1.5  pooka 		winlen = howmuch;
    110        1.5  pooka 		if (puffs_framebuf_getwindow(pb, CUROFF(pb), &win, &winlen)==-1)
    111        1.5  pooka 			return errno;
    112       1.13  pooka 		n = recv(fd, win, winlen, MSG_NOSIGNAL);
    113        1.5  pooka 		switch (n) {
    114        1.5  pooka 		case 0:
    115        1.5  pooka 			return ECONNRESET;
    116        1.5  pooka 		case -1:
    117        1.5  pooka 			if (errno == EAGAIN)
    118        1.5  pooka 				return 0;
    119        1.5  pooka 			return errno;
    120        1.5  pooka 		default:
    121        1.5  pooka 			howmuch -= n;
    122        1.5  pooka 			puffs_framebuf_seekset(pb, CUROFF(pb) + n);
    123        1.5  pooka 			break;
    124        1.5  pooka 		}
    125        1.5  pooka 	}
    126        1.5  pooka 
    127        1.5  pooka 	if (!lenstate) {
    128        1.5  pooka 		/* XXX: initial exchange shorter.. but don't worry, be happy */
    129        1.5  pooka 		puffs_framebuf_seekset(pb, 9);
    130        1.5  pooka 		*done = 1;
    131        1.5  pooka 		return 0;
    132        1.5  pooka 	} else
    133        1.5  pooka 		goto the_next_level;
    134        1.1  pooka }
    135        1.1  pooka 
    136        1.1  pooka int
    137        1.5  pooka psbuf_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
    138        1.5  pooka 	int fd, int *done)
    139        1.1  pooka {
    140        1.5  pooka 	void *win;
    141        1.1  pooka 	ssize_t n;
    142        1.5  pooka 	size_t winlen, howmuch;
    143        1.5  pooka 
    144        1.5  pooka 	/* finalize buffer.. could be elsewhere ... */
    145        1.5  pooka 	if (CUROFF(pb) == 0) {
    146        1.1  pooka 		uint32_t len;
    147        1.1  pooka 
    148        1.5  pooka 		len = htobe32(puffs_framebuf_tellsize(pb) - 4);
    149        1.5  pooka 		puffs_framebuf_putdata_atoff(pb, 0, &len, 4);
    150        1.1  pooka 	}
    151        1.1  pooka 
    152        1.5  pooka 	howmuch = puffs_framebuf_tellsize(pb) - CUROFF(pb);
    153        1.5  pooka 	while (howmuch) {
    154        1.5  pooka 		winlen = howmuch;
    155        1.5  pooka 		if (puffs_framebuf_getwindow(pb, CUROFF(pb), &win, &winlen)==-1)
    156        1.5  pooka 			return errno;
    157        1.8  pooka 		n = send(fd, win, winlen, MSG_NOSIGNAL);
    158        1.5  pooka 		switch (n) {
    159        1.5  pooka 		case 0:
    160        1.5  pooka 			return ECONNRESET;
    161        1.5  pooka 		case -1:
    162        1.5  pooka 			if (errno == EAGAIN)
    163        1.5  pooka 				return 0;
    164        1.5  pooka 			return errno;
    165        1.5  pooka 		default:
    166        1.5  pooka 			howmuch -= n;
    167        1.5  pooka 			puffs_framebuf_seekset(pb, CUROFF(pb) + n);
    168        1.5  pooka 			break;
    169        1.5  pooka 		}
    170        1.1  pooka 	}
    171        1.1  pooka 
    172        1.5  pooka 	*done = 1;
    173        1.5  pooka 	return 0;
    174        1.5  pooka }
    175        1.5  pooka #undef CUROFF
    176        1.1  pooka 
    177        1.5  pooka int
    178        1.5  pooka psbuf_cmp(struct puffs_usermount *pu,
    179       1.12  pooka 	struct puffs_framebuf *cmp1, struct puffs_framebuf *cmp2, int *notresp)
    180        1.5  pooka {
    181        1.1  pooka 
    182        1.9  pooka 	return psbuf_get_reqid(cmp1) != psbuf_get_reqid(cmp2);
    183        1.1  pooka }
    184        1.1  pooka 
    185        1.5  pooka struct puffs_framebuf *
    186        1.5  pooka psbuf_makeout()
    187        1.1  pooka {
    188        1.5  pooka 	struct puffs_framebuf *pb;
    189        1.1  pooka 
    190        1.5  pooka 	pb = puffs_framebuf_make();
    191        1.5  pooka 	puffs_framebuf_seekset(pb, 4);
    192        1.1  pooka 	return pb;
    193        1.1  pooka }
    194        1.1  pooka 
    195        1.1  pooka void
    196        1.5  pooka psbuf_recycleout(struct puffs_framebuf *pb)
    197        1.1  pooka {
    198        1.1  pooka 
    199        1.5  pooka 	puffs_framebuf_recycle(pb);
    200        1.5  pooka 	puffs_framebuf_seekset(pb, 4);
    201        1.1  pooka }
    202        1.1  pooka 
    203        1.1  pooka void
    204        1.5  pooka psbuf_put_1(struct puffs_framebuf *pb, uint8_t val)
    205        1.1  pooka {
    206        1.5  pooka 	int rv;
    207        1.1  pooka 
    208        1.5  pooka 	rv = puffs_framebuf_putdata(pb, &val, 1);
    209        1.5  pooka 	CHECK(rv == 0);
    210        1.1  pooka }
    211        1.1  pooka 
    212        1.5  pooka void
    213        1.5  pooka psbuf_put_2(struct puffs_framebuf *pb, uint16_t val)
    214        1.1  pooka {
    215        1.5  pooka 	int rv;
    216        1.1  pooka 
    217        1.5  pooka 	HTOBE16(val);
    218        1.5  pooka 	rv = puffs_framebuf_putdata(pb, &val, 2);
    219        1.5  pooka 	CHECK(rv == 0);
    220        1.1  pooka }
    221        1.1  pooka 
    222        1.5  pooka void
    223        1.5  pooka psbuf_put_4(struct puffs_framebuf *pb, uint32_t val)
    224        1.1  pooka {
    225        1.5  pooka 	int rv;
    226        1.1  pooka 
    227        1.5  pooka 	HTOBE32(val);
    228        1.5  pooka 	rv = puffs_framebuf_putdata(pb, &val, 4);
    229        1.5  pooka 	CHECK(rv == 0);
    230        1.1  pooka }
    231        1.1  pooka 
    232        1.5  pooka void
    233        1.5  pooka psbuf_put_8(struct puffs_framebuf *pb, uint64_t val)
    234        1.1  pooka {
    235        1.5  pooka 	int rv;
    236        1.1  pooka 
    237        1.5  pooka 	HTOBE64(val);
    238        1.5  pooka 	rv = puffs_framebuf_putdata(pb, &val, 8);
    239        1.5  pooka 	CHECK(rv == 0);
    240        1.1  pooka }
    241        1.1  pooka 
    242        1.5  pooka void
    243        1.5  pooka psbuf_put_data(struct puffs_framebuf *pb, const void *data, uint32_t dlen)
    244        1.1  pooka {
    245        1.5  pooka 	int rv;
    246        1.1  pooka 
    247        1.1  pooka 	psbuf_put_4(pb, dlen);
    248        1.5  pooka 	rv = puffs_framebuf_putdata(pb, data, dlen);
    249        1.5  pooka 	CHECK(rv == 0);
    250        1.1  pooka }
    251        1.1  pooka 
    252        1.5  pooka void
    253        1.5  pooka psbuf_put_str(struct puffs_framebuf *pb, const char *str)
    254        1.1  pooka {
    255        1.1  pooka 
    256        1.5  pooka 	psbuf_put_data(pb, str, strlen(str));
    257        1.1  pooka }
    258        1.1  pooka 
    259        1.5  pooka void
    260       1.16  pooka psbuf_put_vattr(struct puffs_framebuf *pb, const struct vattr *va,
    261       1.16  pooka 	const struct psshfs_ctx *pctx)
    262        1.1  pooka {
    263        1.1  pooka 	uint32_t flags;
    264       1.18  pooka 	uint32_t theuid = -1, thegid = -1;
    265        1.1  pooka 	flags = 0;
    266        1.1  pooka 
    267       1.15  pooka 	if (va->va_size != (uint64_t)PUFFS_VNOVAL)
    268        1.1  pooka 		flags |= SSH_FILEXFER_ATTR_SIZE;
    269       1.17  pooka 	if (va->va_uid != (uid_t)PUFFS_VNOVAL) {
    270       1.17  pooka 		theuid = va->va_uid;
    271       1.17  pooka 		if (pctx->domangleuid && theuid == pctx->myuid)
    272       1.17  pooka 			theuid = pctx->mangleuid;
    273        1.1  pooka 		flags |= SSH_FILEXFER_ATTR_UIDGID;
    274       1.17  pooka 	}
    275       1.17  pooka 	if (va->va_gid != (gid_t)PUFFS_VNOVAL) {
    276       1.17  pooka 		thegid = va->va_gid;
    277       1.17  pooka 		if (pctx->domanglegid && thegid == pctx->mygid)
    278       1.17  pooka 			thegid = pctx->manglegid;
    279       1.17  pooka 		flags |= SSH_FILEXFER_ATTR_UIDGID;
    280       1.17  pooka 	}
    281       1.15  pooka 	if (va->va_mode != (mode_t)PUFFS_VNOVAL)
    282        1.1  pooka 		flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
    283        1.2  pooka 
    284        1.1  pooka 	if (va->va_atime.tv_sec != PUFFS_VNOVAL)
    285        1.1  pooka 		flags |= SSH_FILEXFER_ATTR_ACCESSTIME;
    286        1.1  pooka 
    287        1.1  pooka 	psbuf_put_4(pb, flags);
    288        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_SIZE)
    289        1.1  pooka 		psbuf_put_8(pb, va->va_size);
    290        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_UIDGID) {
    291       1.16  pooka 		psbuf_put_4(pb, theuid);
    292       1.16  pooka 		psbuf_put_4(pb, thegid);
    293        1.1  pooka 	}
    294        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_PERMISSIONS)
    295        1.1  pooka 		psbuf_put_4(pb, va->va_mode);
    296        1.2  pooka 
    297        1.2  pooka 	/* XXX: this is totally wrong for protocol v3, see OpenSSH */
    298        1.2  pooka 	if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
    299        1.1  pooka 		psbuf_put_4(pb, va->va_atime.tv_sec);
    300        1.1  pooka 		psbuf_put_4(pb, va->va_mtime.tv_sec);
    301        1.2  pooka 	}
    302        1.1  pooka }
    303        1.1  pooka 
    304        1.5  pooka #define ERETURN(rv) return ((rv) == -1 ? errno : 0)
    305        1.1  pooka 
    306        1.1  pooka int
    307        1.5  pooka psbuf_get_1(struct puffs_framebuf *pb, uint8_t *val)
    308        1.1  pooka {
    309        1.1  pooka 
    310        1.5  pooka 	ERETURN(puffs_framebuf_getdata(pb, val, 1));
    311        1.1  pooka }
    312        1.1  pooka 
    313        1.1  pooka int
    314        1.5  pooka psbuf_get_2(struct puffs_framebuf *pb, uint16_t *val)
    315        1.1  pooka {
    316        1.5  pooka 	int rv;
    317        1.1  pooka 
    318        1.5  pooka 	rv = puffs_framebuf_getdata(pb, val, 2);
    319        1.5  pooka 	BE16TOH(*val);
    320        1.1  pooka 
    321        1.5  pooka 	ERETURN(rv);
    322        1.1  pooka }
    323        1.1  pooka 
    324        1.1  pooka int
    325        1.5  pooka psbuf_get_4(struct puffs_framebuf *pb, uint32_t *val)
    326        1.1  pooka {
    327        1.5  pooka 	int rv;
    328        1.1  pooka 
    329        1.5  pooka 	rv = puffs_framebuf_getdata(pb, val, 4);
    330        1.5  pooka 	BE32TOH(*val);
    331        1.1  pooka 
    332        1.5  pooka 	ERETURN(rv);
    333        1.1  pooka }
    334        1.1  pooka 
    335        1.1  pooka int
    336        1.5  pooka psbuf_get_8(struct puffs_framebuf *pb, uint64_t *val)
    337        1.1  pooka {
    338        1.5  pooka 	int rv;
    339        1.1  pooka 
    340        1.5  pooka 	rv = puffs_framebuf_getdata(pb, val, 8);
    341        1.5  pooka 	BE64TOH(*val);
    342        1.1  pooka 
    343        1.5  pooka 	ERETURN(rv);
    344        1.1  pooka }
    345        1.1  pooka 
    346        1.1  pooka int
    347        1.5  pooka psbuf_get_str(struct puffs_framebuf *pb, char **strp, uint32_t *strlenp)
    348        1.1  pooka {
    349        1.1  pooka 	char *str;
    350        1.1  pooka 	uint32_t len;
    351        1.1  pooka 
    352        1.5  pooka 	FAILRV(psbuf_get_4(pb, &len));
    353        1.1  pooka 
    354        1.6  pooka 	if (puffs_framebuf_remaining(pb) < len)
    355        1.5  pooka 		return EPROTO;
    356        1.1  pooka 
    357        1.1  pooka 	str = emalloc(len+1);
    358        1.5  pooka 	puffs_framebuf_getdata(pb, str, len);
    359        1.1  pooka 	str[len] = '\0';
    360        1.1  pooka 	*strp = str;
    361        1.1  pooka 
    362        1.1  pooka 	if (strlenp)
    363        1.1  pooka 		*strlenp = len;
    364        1.1  pooka 
    365        1.5  pooka 	return 0;
    366        1.1  pooka }
    367        1.1  pooka 
    368        1.1  pooka int
    369        1.5  pooka psbuf_get_vattr(struct puffs_framebuf *pb, struct vattr *vap)
    370        1.1  pooka {
    371        1.1  pooka 	uint32_t flags;
    372        1.1  pooka 	uint32_t val;
    373        1.1  pooka 
    374        1.1  pooka 	puffs_vattr_null(vap);
    375        1.1  pooka 
    376        1.5  pooka 	FAILRV(psbuf_get_4(pb, &flags));
    377        1.1  pooka 
    378        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_SIZE) {
    379        1.5  pooka 		FAILRV(psbuf_get_8(pb, &vap->va_size));
    380        1.1  pooka 		vap->va_bytes = vap->va_size;
    381        1.1  pooka 	}
    382        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_UIDGID) {
    383        1.5  pooka 		FAILRV(psbuf_get_4(pb, &vap->va_uid));
    384        1.5  pooka 		FAILRV(psbuf_get_4(pb, &vap->va_gid));
    385        1.1  pooka 	}
    386        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
    387        1.5  pooka 		FAILRV(psbuf_get_4(pb, &vap->va_mode));
    388        1.1  pooka 		vap->va_type = puffs_mode2vt(vap->va_mode);
    389        1.1  pooka 	}
    390        1.1  pooka 	if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
    391        1.1  pooka 		/*
    392        1.1  pooka 		 * XXX: this is utterly wrong if we want to speak
    393        1.1  pooka 		 * protocol version 3, but it seems like the
    394        1.1  pooka 		 * "internet standard" for doing this
    395        1.1  pooka 		 */
    396        1.5  pooka 		FAILRV(psbuf_get_4(pb, &val));
    397        1.1  pooka 		vap->va_atime.tv_sec = val;
    398        1.5  pooka 		FAILRV(psbuf_get_4(pb, &val));
    399        1.1  pooka 		vap->va_mtime.tv_sec = val;
    400        1.1  pooka 		/* make ctime the same as mtime */
    401        1.1  pooka 		vap->va_ctime.tv_sec = val;
    402        1.1  pooka 
    403        1.1  pooka 		vap->va_atime.tv_nsec = 0;
    404        1.1  pooka 		vap->va_ctime.tv_nsec = 0;
    405        1.1  pooka 		vap->va_mtime.tv_nsec = 0;
    406        1.1  pooka 	}
    407        1.1  pooka 
    408        1.5  pooka 	return 0;
    409        1.1  pooka }
    410        1.1  pooka 
    411        1.1  pooka /*
    412        1.1  pooka  * Buffer content helpers.  Caller frees all data.
    413        1.1  pooka  */
    414        1.1  pooka 
    415        1.1  pooka /*
    416        1.1  pooka  * error mapping.. most are not expected for a file system, but
    417        1.1  pooka  * should help with diagnosing a possible error
    418        1.1  pooka  */
    419        1.1  pooka static int emap[] = {
    420        1.1  pooka 	0,			/* OK			*/
    421        1.1  pooka 	0,			/* EOF			*/
    422        1.1  pooka 	ENOENT,			/* NO_SUCH_FILE		*/
    423        1.1  pooka 	EPERM,			/* PERMISSION_DENIED	*/
    424        1.1  pooka 	EIO,			/* FAILURE		*/
    425        1.1  pooka 	EBADMSG,		/* BAD_MESSAGE		*/
    426        1.1  pooka 	ENOTCONN,		/* NO_CONNECTION	*/
    427        1.1  pooka 	ECONNRESET,		/* CONNECTION_LOST	*/
    428        1.1  pooka 	EOPNOTSUPP,		/* OP_UNSUPPORTED	*/
    429        1.1  pooka 	EINVAL,			/* INVALID_HANDLE	*/
    430        1.1  pooka 	ENXIO,			/* NO_SUCH_PATH		*/
    431        1.1  pooka 	EEXIST,			/* FILE_ALREADY_EXISTS	*/
    432        1.1  pooka 	ENODEV			/* WRITE_PROTECT	*/
    433        1.1  pooka };
    434       1.15  pooka #define NERRORS ((int)(sizeof(emap) / sizeof(emap[0])))
    435        1.1  pooka 
    436        1.1  pooka static int
    437        1.1  pooka sftperr_to_errno(int error)
    438        1.1  pooka {
    439        1.1  pooka 
    440        1.1  pooka 	if (!error)
    441        1.1  pooka 		return 0;
    442        1.1  pooka 
    443        1.1  pooka 	if (error >= NERRORS || error < 0)
    444        1.1  pooka 		return EPROTO;
    445        1.1  pooka 
    446        1.1  pooka 	return emap[error];
    447        1.1  pooka }
    448        1.1  pooka 
    449        1.1  pooka #define INVALRESPONSE EPROTO
    450        1.1  pooka 
    451        1.1  pooka static int
    452        1.5  pooka expectcode(struct puffs_framebuf *pb, int value)
    453        1.1  pooka {
    454        1.1  pooka 	uint32_t error;
    455        1.5  pooka 	uint8_t type;
    456        1.1  pooka 
    457        1.5  pooka 	type = psbuf_get_type(pb);
    458        1.5  pooka 	if (type == value)
    459        1.1  pooka 		return 0;
    460        1.1  pooka 
    461        1.5  pooka 	if (type != SSH_FXP_STATUS)
    462        1.1  pooka 		return INVALRESPONSE;
    463        1.1  pooka 
    464        1.5  pooka 	FAILRV(psbuf_get_4(pb, &error));
    465        1.1  pooka 
    466        1.1  pooka 	return sftperr_to_errno(error);
    467        1.1  pooka }
    468        1.1  pooka 
    469        1.1  pooka #define CHECKCODE(pb,val)						\
    470        1.1  pooka do {									\
    471        1.1  pooka 	int rv;								\
    472        1.1  pooka 	rv = expectcode(pb, val);					\
    473        1.1  pooka 	if (rv)								\
    474        1.1  pooka 		return rv;						\
    475        1.1  pooka } while (/*CONSTCOND*/0)
    476        1.1  pooka 
    477        1.1  pooka int
    478        1.5  pooka psbuf_expect_status(struct puffs_framebuf *pb)
    479        1.1  pooka {
    480        1.1  pooka 	uint32_t error;
    481        1.1  pooka 
    482        1.5  pooka 	if (psbuf_get_type(pb) != SSH_FXP_STATUS)
    483        1.1  pooka 		return INVALRESPONSE;
    484        1.1  pooka 
    485        1.5  pooka 	FAILRV(psbuf_get_4(pb, &error));
    486        1.1  pooka 
    487        1.1  pooka 	return sftperr_to_errno(error);
    488        1.1  pooka }
    489        1.1  pooka 
    490        1.1  pooka int
    491        1.5  pooka psbuf_expect_handle(struct puffs_framebuf *pb, char **hand, uint32_t *handlen)
    492        1.1  pooka {
    493        1.1  pooka 
    494        1.1  pooka 	CHECKCODE(pb, SSH_FXP_HANDLE);
    495        1.5  pooka 	FAILRV(psbuf_get_str(pb, hand, handlen));
    496        1.1  pooka 
    497        1.1  pooka 	return 0;
    498        1.1  pooka }
    499        1.1  pooka 
    500        1.1  pooka /* no memory allocation, direct copy */
    501        1.1  pooka int
    502        1.5  pooka psbuf_do_data(struct puffs_framebuf *pb, uint8_t *data, uint32_t *dlen)
    503        1.1  pooka {
    504        1.5  pooka 	void *win;
    505        1.7  pooka 	size_t bufoff, winlen;
    506        1.7  pooka 	uint32_t len, dataoff;
    507        1.1  pooka 
    508        1.5  pooka 	if (psbuf_get_type(pb) != SSH_FXP_DATA) {
    509        1.1  pooka 		uint32_t val;
    510        1.1  pooka 
    511        1.5  pooka 		if (psbuf_get_type(pb) != SSH_FXP_STATUS)
    512        1.1  pooka 			return INVALRESPONSE;
    513        1.1  pooka 
    514       1.11  pooka 		if (psbuf_get_4(pb, &val) != 0)
    515        1.1  pooka 			return INVALRESPONSE;
    516        1.1  pooka 
    517        1.1  pooka 		if (val != SSH_FX_EOF)
    518        1.1  pooka 			return sftperr_to_errno(val);
    519        1.1  pooka 
    520        1.1  pooka 		*dlen = 0;
    521        1.1  pooka 		return 0;
    522        1.1  pooka 	}
    523       1.11  pooka 	if (psbuf_get_4(pb, &len) != 0)
    524        1.1  pooka 		return INVALRESPONSE;
    525        1.1  pooka 
    526        1.1  pooka 	if (*dlen < len)
    527        1.1  pooka 		return EINVAL;
    528        1.1  pooka 
    529        1.5  pooka 	*dlen = 0;
    530        1.1  pooka 
    531        1.5  pooka 	dataoff = 0;
    532        1.5  pooka 	while (dataoff < len) {
    533        1.5  pooka 		winlen = len-dataoff;
    534        1.5  pooka 		bufoff = puffs_framebuf_telloff(pb);
    535        1.5  pooka 		if (puffs_framebuf_getwindow(pb, bufoff,
    536        1.5  pooka 		    &win, &winlen) == -1)
    537        1.5  pooka 			return EINVAL;
    538        1.5  pooka 		if (winlen == 0)
    539        1.5  pooka 			break;
    540        1.5  pooka 
    541        1.5  pooka 		memcpy(data + dataoff, win, winlen);
    542        1.5  pooka 		dataoff += winlen;
    543        1.5  pooka 	}
    544        1.1  pooka 
    545        1.5  pooka 	*dlen = dataoff;
    546        1.1  pooka 
    547        1.1  pooka 	return 0;
    548        1.1  pooka }
    549        1.1  pooka 
    550        1.1  pooka int
    551        1.5  pooka psbuf_expect_name(struct puffs_framebuf *pb, uint32_t *count)
    552        1.1  pooka {
    553        1.1  pooka 
    554        1.1  pooka 	CHECKCODE(pb, SSH_FXP_NAME);
    555        1.5  pooka 	FAILRV(psbuf_get_4(pb, count));
    556        1.1  pooka 
    557        1.1  pooka 	return 0;
    558        1.1  pooka }
    559        1.1  pooka 
    560        1.1  pooka int
    561        1.5  pooka psbuf_expect_attrs(struct puffs_framebuf *pb, struct vattr *vap)
    562        1.1  pooka {
    563        1.1  pooka 
    564        1.1  pooka 	CHECKCODE(pb, SSH_FXP_ATTRS);
    565        1.5  pooka 	FAILRV(psbuf_get_vattr(pb, vap));
    566        1.1  pooka 
    567        1.1  pooka 	return 0;
    568        1.1  pooka }
    569        1.1  pooka 
    570        1.1  pooka /*
    571        1.1  pooka  * More helpers: larger-scale put functions
    572        1.1  pooka  */
    573        1.1  pooka 
    574        1.5  pooka void
    575        1.5  pooka psbuf_req_data(struct puffs_framebuf *pb, int type, uint32_t reqid,
    576        1.5  pooka 	const void *data, uint32_t dlen)
    577        1.1  pooka {
    578        1.1  pooka 
    579        1.1  pooka 	psbuf_put_1(pb, type);
    580        1.1  pooka 	psbuf_put_4(pb, reqid);
    581        1.1  pooka 	psbuf_put_data(pb, data, dlen);
    582        1.1  pooka }
    583        1.1  pooka 
    584        1.5  pooka void
    585        1.5  pooka psbuf_req_str(struct puffs_framebuf *pb, int type, uint32_t reqid,
    586        1.5  pooka 	const char *str)
    587        1.1  pooka {
    588        1.1  pooka 
    589        1.5  pooka 	psbuf_req_data(pb, type, reqid, str, strlen(str));
    590        1.1  pooka }
    591