psbuf.c revision 1.2 1 1.2 pooka /* $NetBSD: psbuf.c,v 1.2 2007/01/07 19:31:48 pooka Exp $ */
2 1.1 pooka
3 1.1 pooka /*
4 1.1 pooka * Copyright (c) 2006 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.2 pooka __RCSID("$NetBSD: psbuf.c,v 1.2 2007/01/07 19:31:48 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 <assert.h>
47 1.1 pooka #include <err.h>
48 1.1 pooka #include <errno.h>
49 1.1 pooka #include <stdlib.h>
50 1.1 pooka #include <util.h>
51 1.1 pooka #include <unistd.h>
52 1.1 pooka
53 1.1 pooka #include "psshfs.h"
54 1.1 pooka #include "sftp_proto.h"
55 1.1 pooka
56 1.1 pooka #define FAILRV(x, rv) do { if (!(x)) return (rv); } while (/*CONSTCOND*/0)
57 1.1 pooka
58 1.1 pooka int
59 1.1 pooka psbuf_read(struct psshfs_ctx *pctx, struct psbuf *pb)
60 1.1 pooka {
61 1.1 pooka ssize_t n;
62 1.1 pooka
63 1.1 pooka assert(pb->state != PSBUF_PUT);
64 1.1 pooka
65 1.1 pooka again:
66 1.1 pooka n = read(pctx->sshfd, pb->buf+pb->offset, pb->remain);
67 1.1 pooka switch (n) {
68 1.1 pooka case 0:
69 1.1 pooka errno = EIO;
70 1.1 pooka return -1;
71 1.1 pooka case -1:
72 1.1 pooka if (errno == EAGAIN)
73 1.1 pooka return 0;
74 1.1 pooka return -1;
75 1.1 pooka default:
76 1.1 pooka pb->offset += n;
77 1.1 pooka pb->remain -= n;
78 1.1 pooka }
79 1.1 pooka
80 1.1 pooka if (pb->remain != 0)
81 1.1 pooka return 0;
82 1.1 pooka
83 1.1 pooka /* ok, at least there's something to do */
84 1.1 pooka assert(pb->state == PSBUF_GETLEN || pb->state == PSBUF_GETDATA);
85 1.1 pooka
86 1.1 pooka if (pb->state == PSBUF_GETLEN) {
87 1.1 pooka memcpy(&pb->len, pb->buf, 4);
88 1.1 pooka pb->len = htonl(pb->len);
89 1.1 pooka pb->remain = pb->len;
90 1.1 pooka pb->offset = 0;
91 1.1 pooka
92 1.1 pooka free(pb->buf); /* XXX */
93 1.1 pooka pb->buf = emalloc(pb->len);
94 1.1 pooka pb->state = PSBUF_GETDATA;
95 1.1 pooka goto again;
96 1.1 pooka
97 1.1 pooka } else if (pb->state == PSBUF_GETDATA) {
98 1.1 pooka pb->remain = pb->offset;
99 1.1 pooka pb->offset = 0;
100 1.1 pooka
101 1.1 pooka pb->state = PSBUF_GETREADY;
102 1.1 pooka
103 1.1 pooka /* sloppy */
104 1.1 pooka if (!psbuf_get_1(pb, &pb->type))
105 1.1 pooka errx(1, "invalid server response, no type");
106 1.1 pooka if (!psbuf_get_4(pb, &pb->reqid))
107 1.1 pooka errx(1, "invalid server response, no reqid");
108 1.1 pooka
109 1.1 pooka return 1;
110 1.1 pooka }
111 1.1 pooka
112 1.1 pooka return -1; /* XXX: impossible */
113 1.1 pooka }
114 1.1 pooka
115 1.1 pooka int
116 1.1 pooka psbuf_write(struct psshfs_ctx *pctx, struct psbuf *pb)
117 1.1 pooka {
118 1.1 pooka ssize_t n;
119 1.1 pooka
120 1.1 pooka if (pb->state == PSBUF_PUT) {
121 1.1 pooka uint32_t len;
122 1.1 pooka
123 1.1 pooka len = htonl(pb->offset - sizeof(len));
124 1.1 pooka memcpy(pb->buf, &len, sizeof(len));
125 1.1 pooka
126 1.1 pooka pb->remain = pb->offset;
127 1.1 pooka pb->offset = 0;
128 1.1 pooka
129 1.1 pooka pb->state = PSBUF_PUTDONE;
130 1.1 pooka }
131 1.1 pooka
132 1.1 pooka assert(pb->state == PSBUF_PUTDONE);
133 1.1 pooka
134 1.1 pooka n = write(pctx->sshfd, pb->buf + pb->offset, pb->remain);
135 1.1 pooka if (n == 0) {
136 1.1 pooka errno = EIO;
137 1.1 pooka return -1;
138 1.1 pooka }
139 1.1 pooka
140 1.1 pooka if (n == -1) {
141 1.1 pooka if (errno == EAGAIN)
142 1.1 pooka return 0;
143 1.1 pooka else
144 1.1 pooka return -1;
145 1.1 pooka }
146 1.1 pooka
147 1.1 pooka pb->offset += n;
148 1.1 pooka pb->remain -= n;
149 1.1 pooka
150 1.1 pooka if (pb->remain == 0)
151 1.1 pooka return 1;
152 1.1 pooka else
153 1.1 pooka return 0;
154 1.1 pooka }
155 1.1 pooka
156 1.1 pooka struct psbuf *
157 1.1 pooka psbuf_make(int incoming)
158 1.1 pooka {
159 1.1 pooka struct psbuf *pb;
160 1.1 pooka
161 1.1 pooka pb = emalloc(sizeof(struct psbuf));
162 1.1 pooka memset(pb, 0, sizeof(struct psbuf));
163 1.1 pooka pb->buf = emalloc(PSDEFALLOC);
164 1.1 pooka pb->len = PSDEFALLOC;
165 1.1 pooka
166 1.1 pooka psbuf_recycle(pb, incoming);
167 1.1 pooka
168 1.1 pooka return pb;
169 1.1 pooka }
170 1.1 pooka
171 1.1 pooka void
172 1.1 pooka psbuf_destroy(struct psbuf *pb)
173 1.1 pooka {
174 1.1 pooka
175 1.1 pooka free(pb->buf);
176 1.1 pooka free(pb);
177 1.1 pooka }
178 1.1 pooka
179 1.1 pooka void
180 1.1 pooka psbuf_recycle(struct psbuf *pb, int incoming)
181 1.1 pooka {
182 1.1 pooka
183 1.1 pooka if (incoming) {
184 1.1 pooka pb->offset = 0;
185 1.1 pooka pb->remain = 4;
186 1.1 pooka pb->state = PSBUF_GETLEN;
187 1.1 pooka } else {
188 1.1 pooka /* save space for len */
189 1.1 pooka pb->remain = pb->len - 4;
190 1.1 pooka pb->offset = 4;
191 1.1 pooka
192 1.1 pooka pb->state = PSBUF_PUT;
193 1.1 pooka }
194 1.1 pooka }
195 1.1 pooka
196 1.1 pooka static void
197 1.1 pooka psbuf_putspace(struct psbuf *pb, size_t space)
198 1.1 pooka {
199 1.1 pooka size_t morespace;
200 1.1 pooka uint8_t *nb;
201 1.1 pooka
202 1.1 pooka if (pb->remain >= space)
203 1.1 pooka return;
204 1.1 pooka
205 1.1 pooka for (morespace = PSDEFALLOC; morespace < space; morespace += PSDEFALLOC)
206 1.1 pooka if (morespace > PSBUFMAX)
207 1.1 pooka err(1, "too much memory");
208 1.1 pooka
209 1.1 pooka nb = erealloc(pb->buf, pb->len + morespace);
210 1.1 pooka pb->len += morespace;
211 1.1 pooka pb->remain += morespace;
212 1.1 pooka pb->buf = nb;
213 1.1 pooka }
214 1.1 pooka
215 1.1 pooka int
216 1.1 pooka psbuf_put_1(struct psbuf *pb, uint8_t val)
217 1.1 pooka {
218 1.1 pooka
219 1.1 pooka assert(pb->state == PSBUF_PUT);
220 1.1 pooka
221 1.1 pooka psbuf_putspace(pb, 1);
222 1.1 pooka memcpy(pb->buf + pb->offset, &val, 1);
223 1.1 pooka pb->offset += 1;
224 1.1 pooka pb->remain -= 1;
225 1.1 pooka
226 1.1 pooka return 1;
227 1.1 pooka }
228 1.1 pooka
229 1.1 pooka int
230 1.1 pooka psbuf_put_2(struct psbuf *pb, uint16_t val)
231 1.1 pooka {
232 1.1 pooka
233 1.1 pooka assert(pb->state == PSBUF_PUT);
234 1.1 pooka
235 1.1 pooka psbuf_putspace(pb, 2);
236 1.1 pooka val = htons(val);
237 1.1 pooka memcpy(pb->buf + pb->offset, &val, 2);
238 1.1 pooka pb->offset += 2;
239 1.1 pooka pb->remain -= 2;
240 1.1 pooka
241 1.1 pooka return 1;
242 1.1 pooka }
243 1.1 pooka
244 1.1 pooka int
245 1.1 pooka psbuf_put_4(struct psbuf *pb, uint32_t val)
246 1.1 pooka {
247 1.1 pooka
248 1.1 pooka assert(pb->state == PSBUF_PUT);
249 1.1 pooka
250 1.1 pooka psbuf_putspace(pb, 4);
251 1.1 pooka val = htonl(val);
252 1.1 pooka memcpy(pb->buf + pb->offset, &val, 4);
253 1.1 pooka pb->offset += 4;
254 1.1 pooka pb->remain -= 4;
255 1.1 pooka
256 1.1 pooka return 1;
257 1.1 pooka }
258 1.1 pooka
259 1.1 pooka int
260 1.1 pooka psbuf_put_8(struct psbuf *pb, uint64_t val)
261 1.1 pooka {
262 1.1 pooka
263 1.1 pooka assert(pb->state == PSBUF_PUT);
264 1.1 pooka
265 1.1 pooka psbuf_putspace(pb, 8);
266 1.1 pooka #if BYTE_ORDER == LITTLE_ENDIAN
267 1.1 pooka val = bswap64(val);
268 1.1 pooka #endif
269 1.1 pooka memcpy(pb->buf + pb->offset, &val, 8);
270 1.1 pooka pb->offset += 8;
271 1.1 pooka pb->remain -= 8;
272 1.1 pooka
273 1.1 pooka return 1;
274 1.1 pooka }
275 1.1 pooka
276 1.1 pooka int
277 1.1 pooka psbuf_put_data(struct psbuf *pb, const void *data, uint32_t dlen)
278 1.1 pooka {
279 1.1 pooka
280 1.1 pooka assert(pb->state == PSBUF_PUT);
281 1.1 pooka
282 1.1 pooka psbuf_put_4(pb, dlen);
283 1.1 pooka
284 1.1 pooka psbuf_putspace(pb, dlen);
285 1.1 pooka memcpy(pb->buf + pb->offset, data, dlen);
286 1.1 pooka pb->offset += dlen;
287 1.1 pooka pb->remain -= dlen;
288 1.1 pooka
289 1.1 pooka return 1;
290 1.1 pooka }
291 1.1 pooka
292 1.1 pooka int
293 1.1 pooka psbuf_put_str(struct psbuf *pb, const char *str)
294 1.1 pooka {
295 1.1 pooka
296 1.1 pooka return psbuf_put_data(pb, str, strlen(str));
297 1.1 pooka }
298 1.1 pooka
299 1.1 pooka int
300 1.1 pooka psbuf_put_vattr(struct psbuf *pb, const struct vattr *va)
301 1.1 pooka {
302 1.1 pooka uint32_t flags;
303 1.1 pooka flags = 0;
304 1.1 pooka
305 1.1 pooka if (va->va_size != PUFFS_VNOVAL)
306 1.1 pooka flags |= SSH_FILEXFER_ATTR_SIZE;
307 1.1 pooka if (va->va_uid != PUFFS_VNOVAL)
308 1.1 pooka flags |= SSH_FILEXFER_ATTR_UIDGID;
309 1.1 pooka if (va->va_mode != PUFFS_VNOVAL)
310 1.1 pooka flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
311 1.2 pooka
312 1.1 pooka if (va->va_atime.tv_sec != PUFFS_VNOVAL)
313 1.1 pooka flags |= SSH_FILEXFER_ATTR_ACCESSTIME;
314 1.1 pooka
315 1.1 pooka psbuf_put_4(pb, flags);
316 1.1 pooka if (flags & SSH_FILEXFER_ATTR_SIZE)
317 1.1 pooka psbuf_put_8(pb, va->va_size);
318 1.1 pooka if (flags & SSH_FILEXFER_ATTR_UIDGID) {
319 1.1 pooka psbuf_put_4(pb, va->va_uid);
320 1.1 pooka psbuf_put_4(pb, va->va_gid);
321 1.1 pooka }
322 1.1 pooka if (flags & SSH_FILEXFER_ATTR_PERMISSIONS)
323 1.1 pooka psbuf_put_4(pb, va->va_mode);
324 1.2 pooka
325 1.2 pooka /* XXX: this is totally wrong for protocol v3, see OpenSSH */
326 1.2 pooka if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
327 1.1 pooka psbuf_put_4(pb, va->va_atime.tv_sec);
328 1.1 pooka psbuf_put_4(pb, va->va_mtime.tv_sec);
329 1.2 pooka }
330 1.1 pooka
331 1.1 pooka return 1;
332 1.1 pooka }
333 1.1 pooka
334 1.1 pooka
335 1.1 pooka int
336 1.1 pooka psbuf_get_1(struct psbuf *pb, uint8_t *val)
337 1.1 pooka {
338 1.1 pooka
339 1.1 pooka assert(pb->state == PSBUF_GETREADY);
340 1.1 pooka
341 1.1 pooka if (pb->remain < 1)
342 1.1 pooka return 0;
343 1.1 pooka
344 1.1 pooka memcpy(val, pb->buf + pb->offset, 1);
345 1.1 pooka pb->offset += 1;
346 1.1 pooka pb->remain -= 1;
347 1.1 pooka
348 1.1 pooka return 1;
349 1.1 pooka }
350 1.1 pooka
351 1.1 pooka int
352 1.1 pooka psbuf_get_2(struct psbuf *pb, uint16_t *val)
353 1.1 pooka {
354 1.1 pooka uint16_t v;
355 1.1 pooka
356 1.1 pooka assert(pb->state == PSBUF_GETREADY);
357 1.1 pooka
358 1.1 pooka if (pb->remain < 2)
359 1.1 pooka return 0;
360 1.1 pooka
361 1.1 pooka memcpy(&v, pb->buf + pb->offset, 2);
362 1.1 pooka pb->offset += 2;
363 1.1 pooka pb->remain -= 2;
364 1.1 pooka
365 1.1 pooka *val = ntohs(v);
366 1.1 pooka
367 1.1 pooka return 1;
368 1.1 pooka }
369 1.1 pooka
370 1.1 pooka int
371 1.1 pooka psbuf_get_4(struct psbuf *pb, uint32_t *val)
372 1.1 pooka {
373 1.1 pooka uint32_t v;
374 1.1 pooka
375 1.1 pooka assert(pb->state == PSBUF_GETREADY);
376 1.1 pooka
377 1.1 pooka if (pb->remain < 4)
378 1.1 pooka return 0;
379 1.1 pooka
380 1.1 pooka memcpy(&v, pb->buf + pb->offset, 4);
381 1.1 pooka pb->offset += 4;
382 1.1 pooka pb->remain -= 4;
383 1.1 pooka
384 1.1 pooka *val = ntohl(v);
385 1.1 pooka
386 1.1 pooka return 1;
387 1.1 pooka }
388 1.1 pooka
389 1.1 pooka int
390 1.1 pooka psbuf_get_8(struct psbuf *pb, uint64_t *val)
391 1.1 pooka {
392 1.1 pooka uint64_t v;
393 1.1 pooka
394 1.1 pooka assert(pb->state == PSBUF_GETREADY);
395 1.1 pooka
396 1.1 pooka if (pb->remain < 8)
397 1.1 pooka return 0;
398 1.1 pooka
399 1.1 pooka memcpy(&v, pb->buf + pb->offset, 8);
400 1.1 pooka pb->offset += 8;
401 1.1 pooka pb->remain -= 8;
402 1.1 pooka
403 1.1 pooka #if BYTE_ORDER == LITTLE_ENDIAN
404 1.1 pooka v = bswap64(v);
405 1.1 pooka #endif
406 1.1 pooka *val = v;
407 1.1 pooka
408 1.1 pooka return 1;
409 1.1 pooka
410 1.1 pooka }
411 1.1 pooka
412 1.1 pooka int
413 1.1 pooka psbuf_get_str(struct psbuf *pb, char **strp, uint32_t *strlenp)
414 1.1 pooka {
415 1.1 pooka char *str;
416 1.1 pooka uint32_t len;
417 1.1 pooka
418 1.1 pooka assert(pb->state == PSBUF_GETREADY);
419 1.1 pooka
420 1.1 pooka FAILRV(psbuf_get_4(pb, &len), 0);
421 1.1 pooka
422 1.1 pooka if (pb->remain < len)
423 1.1 pooka return 0;
424 1.1 pooka
425 1.1 pooka str = emalloc(len+1);
426 1.1 pooka memcpy(str, pb->buf + pb->offset, len);
427 1.1 pooka str[len] = '\0';
428 1.1 pooka *strp = str;
429 1.1 pooka
430 1.1 pooka pb->offset += len;
431 1.1 pooka pb->remain -= len;
432 1.1 pooka
433 1.1 pooka if (strlenp)
434 1.1 pooka *strlenp = len;
435 1.1 pooka
436 1.1 pooka return 1;
437 1.1 pooka }
438 1.1 pooka
439 1.1 pooka int
440 1.1 pooka psbuf_get_vattr(struct psbuf *pb, struct vattr *vap)
441 1.1 pooka {
442 1.1 pooka uint32_t flags;
443 1.1 pooka uint32_t val;
444 1.1 pooka
445 1.1 pooka puffs_vattr_null(vap);
446 1.1 pooka
447 1.1 pooka FAILRV(psbuf_get_4(pb, &flags), 0);
448 1.1 pooka
449 1.1 pooka if (flags & SSH_FILEXFER_ATTR_SIZE) {
450 1.1 pooka FAILRV(psbuf_get_8(pb, &vap->va_size), 0);
451 1.1 pooka vap->va_bytes = vap->va_size;
452 1.1 pooka }
453 1.1 pooka if (flags & SSH_FILEXFER_ATTR_UIDGID) {
454 1.1 pooka FAILRV(psbuf_get_4(pb, &vap->va_uid), 0);
455 1.1 pooka FAILRV(psbuf_get_4(pb, &vap->va_gid), 0);
456 1.1 pooka }
457 1.1 pooka if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
458 1.1 pooka FAILRV(psbuf_get_4(pb, &vap->va_mode), 0);
459 1.1 pooka vap->va_type = puffs_mode2vt(vap->va_mode);
460 1.1 pooka }
461 1.1 pooka if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
462 1.1 pooka /*
463 1.1 pooka * XXX: this is utterly wrong if we want to speak
464 1.1 pooka * protocol version 3, but it seems like the
465 1.1 pooka * "internet standard" for doing this
466 1.1 pooka */
467 1.1 pooka FAILRV(psbuf_get_4(pb, &val), 0);
468 1.1 pooka vap->va_atime.tv_sec = val;
469 1.1 pooka FAILRV(psbuf_get_4(pb, &val), 0);
470 1.1 pooka vap->va_mtime.tv_sec = val;
471 1.1 pooka /* make ctime the same as mtime */
472 1.1 pooka vap->va_ctime.tv_sec = val;
473 1.1 pooka
474 1.1 pooka vap->va_atime.tv_nsec = 0;
475 1.1 pooka vap->va_ctime.tv_nsec = 0;
476 1.1 pooka vap->va_mtime.tv_nsec = 0;
477 1.1 pooka }
478 1.1 pooka
479 1.1 pooka return 1;
480 1.1 pooka }
481 1.1 pooka
482 1.1 pooka /*
483 1.1 pooka * Buffer content helpers. Caller frees all data.
484 1.1 pooka */
485 1.1 pooka
486 1.1 pooka /*
487 1.1 pooka * error mapping.. most are not expected for a file system, but
488 1.1 pooka * should help with diagnosing a possible error
489 1.1 pooka */
490 1.1 pooka static int emap[] = {
491 1.1 pooka 0, /* OK */
492 1.1 pooka 0, /* EOF */
493 1.1 pooka ENOENT, /* NO_SUCH_FILE */
494 1.1 pooka EPERM, /* PERMISSION_DENIED */
495 1.1 pooka EIO, /* FAILURE */
496 1.1 pooka EBADMSG, /* BAD_MESSAGE */
497 1.1 pooka ENOTCONN, /* NO_CONNECTION */
498 1.1 pooka ECONNRESET, /* CONNECTION_LOST */
499 1.1 pooka EOPNOTSUPP, /* OP_UNSUPPORTED */
500 1.1 pooka EINVAL, /* INVALID_HANDLE */
501 1.1 pooka ENXIO, /* NO_SUCH_PATH */
502 1.1 pooka EEXIST, /* FILE_ALREADY_EXISTS */
503 1.1 pooka ENODEV /* WRITE_PROTECT */
504 1.1 pooka };
505 1.1 pooka #define NERRORS (sizeof(emap) / sizeof(emap[0]))
506 1.1 pooka
507 1.1 pooka static int
508 1.1 pooka sftperr_to_errno(int error)
509 1.1 pooka {
510 1.1 pooka
511 1.1 pooka if (!error)
512 1.1 pooka return 0;
513 1.1 pooka
514 1.1 pooka if (error >= NERRORS || error < 0)
515 1.1 pooka return EPROTO;
516 1.1 pooka
517 1.1 pooka return emap[error];
518 1.1 pooka }
519 1.1 pooka
520 1.1 pooka #define INVALRESPONSE EPROTO
521 1.1 pooka
522 1.1 pooka static int
523 1.1 pooka expectcode(struct psbuf *pb, int value)
524 1.1 pooka {
525 1.1 pooka uint32_t error;
526 1.1 pooka
527 1.1 pooka if (pb->type == value)
528 1.1 pooka return 0;
529 1.1 pooka
530 1.1 pooka if (pb->type != SSH_FXP_STATUS)
531 1.1 pooka return INVALRESPONSE;
532 1.1 pooka
533 1.1 pooka FAILRV(psbuf_get_4(pb, &error), INVALRESPONSE);
534 1.1 pooka
535 1.1 pooka return sftperr_to_errno(error);
536 1.1 pooka }
537 1.1 pooka
538 1.1 pooka #define CHECKCODE(pb,val) \
539 1.1 pooka do { \
540 1.1 pooka int rv; \
541 1.1 pooka rv = expectcode(pb, val); \
542 1.1 pooka if (rv) \
543 1.1 pooka return rv; \
544 1.1 pooka } while (/*CONSTCOND*/0)
545 1.1 pooka
546 1.1 pooka int
547 1.1 pooka psbuf_expect_status(struct psbuf *pb)
548 1.1 pooka {
549 1.1 pooka uint32_t error;
550 1.1 pooka
551 1.1 pooka if (pb->type != SSH_FXP_STATUS)
552 1.1 pooka return INVALRESPONSE;
553 1.1 pooka
554 1.1 pooka FAILRV(psbuf_get_4(pb, &error), INVALRESPONSE);
555 1.1 pooka
556 1.1 pooka return sftperr_to_errno(error);
557 1.1 pooka }
558 1.1 pooka
559 1.1 pooka int
560 1.1 pooka psbuf_expect_handle(struct psbuf *pb, char **hand, size_t *handlen)
561 1.1 pooka {
562 1.1 pooka
563 1.1 pooka CHECKCODE(pb, SSH_FXP_HANDLE);
564 1.1 pooka FAILRV(psbuf_get_str(pb, hand, handlen), INVALRESPONSE);
565 1.1 pooka
566 1.1 pooka return 0;
567 1.1 pooka }
568 1.1 pooka
569 1.1 pooka /* no memory allocation, direct copy */
570 1.1 pooka int
571 1.1 pooka psbuf_do_data(struct psbuf *pb, uint8_t *data, uint32_t *dlen)
572 1.1 pooka {
573 1.1 pooka uint32_t len;
574 1.1 pooka
575 1.1 pooka if (pb->type != SSH_FXP_DATA) {
576 1.1 pooka uint32_t val;
577 1.1 pooka
578 1.1 pooka if (pb->type != SSH_FXP_STATUS)
579 1.1 pooka return INVALRESPONSE;
580 1.1 pooka
581 1.1 pooka if (!psbuf_get_4(pb, &val))
582 1.1 pooka return INVALRESPONSE;
583 1.1 pooka
584 1.1 pooka if (val != SSH_FX_EOF)
585 1.1 pooka return sftperr_to_errno(val);
586 1.1 pooka
587 1.1 pooka *dlen = 0;
588 1.1 pooka return 0;
589 1.1 pooka }
590 1.1 pooka if (!psbuf_get_4(pb, &len))
591 1.1 pooka return INVALRESPONSE;
592 1.1 pooka
593 1.1 pooka if (*dlen < len)
594 1.1 pooka return EINVAL;
595 1.1 pooka
596 1.1 pooka memcpy(data, pb->buf + pb->offset, len);
597 1.1 pooka
598 1.1 pooka pb->offset += len;
599 1.1 pooka pb->remain -= len;
600 1.1 pooka
601 1.1 pooka *dlen = len;
602 1.1 pooka
603 1.1 pooka return 0;
604 1.1 pooka }
605 1.1 pooka
606 1.1 pooka int
607 1.1 pooka psbuf_expect_name(struct psbuf *pb, uint32_t *count)
608 1.1 pooka {
609 1.1 pooka
610 1.1 pooka CHECKCODE(pb, SSH_FXP_NAME);
611 1.1 pooka FAILRV(psbuf_get_4(pb, count), INVALRESPONSE);
612 1.1 pooka
613 1.1 pooka return 0;
614 1.1 pooka }
615 1.1 pooka
616 1.1 pooka int
617 1.1 pooka psbuf_expect_attrs(struct psbuf *pb, struct vattr *vap)
618 1.1 pooka {
619 1.1 pooka
620 1.1 pooka CHECKCODE(pb, SSH_FXP_ATTRS);
621 1.1 pooka FAILRV(psbuf_get_vattr(pb, vap), INVALRESPONSE);
622 1.1 pooka
623 1.1 pooka return 0;
624 1.1 pooka }
625 1.1 pooka
626 1.1 pooka /*
627 1.1 pooka * More helpers: larger-scale put functions
628 1.1 pooka */
629 1.1 pooka
630 1.1 pooka int
631 1.1 pooka psbuf_req_data(struct psbuf *pb, int type, uint32_t reqid, const void *data,
632 1.1 pooka size_t dlen)
633 1.1 pooka {
634 1.1 pooka
635 1.1 pooka psbuf_put_1(pb, type);
636 1.1 pooka psbuf_put_4(pb, reqid);
637 1.1 pooka psbuf_put_data(pb, data, dlen);
638 1.1 pooka
639 1.1 pooka return 1;
640 1.1 pooka }
641 1.1 pooka
642 1.1 pooka int
643 1.1 pooka psbuf_req_str(struct psbuf *pb, int type, uint32_t reqid, const char *str)
644 1.1 pooka {
645 1.1 pooka
646 1.1 pooka return psbuf_req_data(pb, type, reqid, str, strlen(str));
647 1.1 pooka }
648