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