1 /* $NetBSD: psbuf.c,v 1.17 2010/01/07 21:19:45 pooka Exp $ */
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: psbuf.c,v 1.17 2010/01/07 21:19:45 pooka Exp $");
34 * buffering functions for network input/output. slightly different
35 * from the average joe buffer routines, as is usually the case ...
36 * these use efuns for now.
39 #include <sys/types.h>
41 #include <sys/vnode.h>
50 #include "sftp_proto.h"
52 #define FAILRV(x) do { int rv; if ((rv=x)) return (rv); } while (/*CONSTCOND*/0)
53 #define READSTATE_LENGTH(off) (off < 4)
56 #define SFTP_TYPEOFF 4
57 #define SFTP_REQIDOFF 5
59 #define CHECK(v) if (!(v)) abort()
62 psbuf_get_type(struct puffs_framebuf
*pb
)
66 puffs_framebuf_getdata_atoff(pb
, SFTP_TYPEOFF
, &type
, 1);
71 psbuf_get_len(struct puffs_framebuf
*pb
)
75 puffs_framebuf_getdata_atoff(pb
, SFTP_LENOFF
, &len
, 4);
80 psbuf_get_reqid(struct puffs_framebuf
*pb
)
84 puffs_framebuf_getdata_atoff(pb
, SFTP_REQIDOFF
, &req
, 4);
88 #define CUROFF(pb) (puffs_framebuf_telloff(pb))
90 psbuf_read(struct puffs_usermount
*pu
, struct puffs_framebuf
*pb
,
95 size_t howmuch
, winlen
;
99 if ((lenstate
= READSTATE_LENGTH(CUROFF(pb
))))
100 howmuch
= 4 - CUROFF(pb
);
102 howmuch
= psbuf_get_len(pb
) - (CUROFF(pb
) - 4);
104 if (puffs_framebuf_reserve_space(pb
, howmuch
) == -1)
109 if (puffs_framebuf_getwindow(pb
, CUROFF(pb
), &win
, &winlen
)==-1)
111 n
= recv(fd
, win
, winlen
, MSG_NOSIGNAL
);
121 puffs_framebuf_seekset(pb
, CUROFF(pb
) + n
);
127 /* XXX: initial exchange shorter.. but don't worry, be happy */
128 puffs_framebuf_seekset(pb
, 9);
136 psbuf_write(struct puffs_usermount
*pu
, struct puffs_framebuf
*pb
,
141 size_t winlen
, howmuch
;
143 /* finalize buffer.. could be elsewhere ... */
144 if (CUROFF(pb
) == 0) {
147 len
= htobe32(puffs_framebuf_tellsize(pb
) - 4);
148 puffs_framebuf_putdata_atoff(pb
, 0, &len
, 4);
151 howmuch
= puffs_framebuf_tellsize(pb
) - CUROFF(pb
);
154 if (puffs_framebuf_getwindow(pb
, CUROFF(pb
), &win
, &winlen
)==-1)
156 n
= send(fd
, win
, winlen
, MSG_NOSIGNAL
);
166 puffs_framebuf_seekset(pb
, CUROFF(pb
) + n
);
177 psbuf_cmp(struct puffs_usermount
*pu
,
178 struct puffs_framebuf
*cmp1
, struct puffs_framebuf
*cmp2
, int *notresp
)
181 return psbuf_get_reqid(cmp1
) != psbuf_get_reqid(cmp2
);
184 struct puffs_framebuf
*
187 struct puffs_framebuf
*pb
;
189 pb
= puffs_framebuf_make();
190 puffs_framebuf_seekset(pb
, 4);
195 psbuf_recycleout(struct puffs_framebuf
*pb
)
198 puffs_framebuf_recycle(pb
);
199 puffs_framebuf_seekset(pb
, 4);
203 psbuf_put_1(struct puffs_framebuf
*pb
, uint8_t val
)
207 rv
= puffs_framebuf_putdata(pb
, &val
, 1);
212 psbuf_put_2(struct puffs_framebuf
*pb
, uint16_t val
)
217 rv
= puffs_framebuf_putdata(pb
, &val
, 2);
222 psbuf_put_4(struct puffs_framebuf
*pb
, uint32_t val
)
227 rv
= puffs_framebuf_putdata(pb
, &val
, 4);
232 psbuf_put_8(struct puffs_framebuf
*pb
, uint64_t val
)
237 rv
= puffs_framebuf_putdata(pb
, &val
, 8);
242 psbuf_put_data(struct puffs_framebuf
*pb
, const void *data
, uint32_t dlen
)
246 psbuf_put_4(pb
, dlen
);
247 rv
= puffs_framebuf_putdata(pb
, data
, dlen
);
252 psbuf_put_str(struct puffs_framebuf
*pb
, const char *str
)
255 psbuf_put_data(pb
, str
, strlen(str
));
259 psbuf_put_vattr(struct puffs_framebuf
*pb
, const struct vattr
*va
,
260 const struct psshfs_ctx
*pctx
)
263 uint32_t theuid
= -1, thegid
= -1;
266 if (va
->va_size
!= (uint64_t)PUFFS_VNOVAL
)
267 flags
|= SSH_FILEXFER_ATTR_SIZE
;
268 if (va
->va_uid
!= (uid_t
)PUFFS_VNOVAL
) {
270 if (pctx
->domangleuid
&& theuid
== pctx
->myuid
)
271 theuid
= pctx
->mangleuid
;
272 flags
|= SSH_FILEXFER_ATTR_UIDGID
;
274 if (va
->va_gid
!= (gid_t
)PUFFS_VNOVAL
) {
276 if (pctx
->domanglegid
&& thegid
== pctx
->mygid
)
277 thegid
= pctx
->manglegid
;
278 flags
|= SSH_FILEXFER_ATTR_UIDGID
;
280 if (va
->va_mode
!= (mode_t
)PUFFS_VNOVAL
)
281 flags
|= SSH_FILEXFER_ATTR_PERMISSIONS
;
283 if (va
->va_atime
.tv_sec
!= PUFFS_VNOVAL
)
284 flags
|= SSH_FILEXFER_ATTR_ACCESSTIME
;
286 psbuf_put_4(pb
, flags
);
287 if (flags
& SSH_FILEXFER_ATTR_SIZE
)
288 psbuf_put_8(pb
, va
->va_size
);
289 if (flags
& SSH_FILEXFER_ATTR_UIDGID
) {
290 psbuf_put_4(pb
, theuid
);
291 psbuf_put_4(pb
, thegid
);
293 if (flags
& SSH_FILEXFER_ATTR_PERMISSIONS
)
294 psbuf_put_4(pb
, va
->va_mode
);
296 /* XXX: this is totally wrong for protocol v3, see OpenSSH */
297 if (flags
& SSH_FILEXFER_ATTR_ACCESSTIME
) {
298 psbuf_put_4(pb
, va
->va_atime
.tv_sec
);
299 psbuf_put_4(pb
, va
->va_mtime
.tv_sec
);
303 #define ERETURN(rv) return ((rv) == -1 ? errno : 0)
306 psbuf_get_1(struct puffs_framebuf
*pb
, uint8_t *val
)
309 ERETURN(puffs_framebuf_getdata(pb
, val
, 1));
313 psbuf_get_2(struct puffs_framebuf
*pb
, uint16_t *val
)
317 rv
= puffs_framebuf_getdata(pb
, val
, 2);
324 psbuf_get_4(struct puffs_framebuf
*pb
, uint32_t *val
)
328 rv
= puffs_framebuf_getdata(pb
, val
, 4);
335 psbuf_get_8(struct puffs_framebuf
*pb
, uint64_t *val
)
339 rv
= puffs_framebuf_getdata(pb
, val
, 8);
346 psbuf_get_str(struct puffs_framebuf
*pb
, char **strp
, uint32_t *strlenp
)
351 FAILRV(psbuf_get_4(pb
, &len
));
353 if (puffs_framebuf_remaining(pb
) < len
)
356 str
= emalloc(len
+1);
357 puffs_framebuf_getdata(pb
, str
, len
);
368 psbuf_get_vattr(struct puffs_framebuf
*pb
, struct vattr
*vap
)
373 puffs_vattr_null(vap
);
375 FAILRV(psbuf_get_4(pb
, &flags
));
377 if (flags
& SSH_FILEXFER_ATTR_SIZE
) {
378 FAILRV(psbuf_get_8(pb
, &vap
->va_size
));
379 vap
->va_bytes
= vap
->va_size
;
381 if (flags
& SSH_FILEXFER_ATTR_UIDGID
) {
382 FAILRV(psbuf_get_4(pb
, &vap
->va_uid
));
383 FAILRV(psbuf_get_4(pb
, &vap
->va_gid
));
385 if (flags
& SSH_FILEXFER_ATTR_PERMISSIONS
) {
386 FAILRV(psbuf_get_4(pb
, &vap
->va_mode
));
387 vap
->va_type
= puffs_mode2vt(vap
->va_mode
);
389 if (flags
& SSH_FILEXFER_ATTR_ACCESSTIME
) {
391 * XXX: this is utterly wrong if we want to speak
392 * protocol version 3, but it seems like the
393 * "internet standard" for doing this
395 FAILRV(psbuf_get_4(pb
, &val
));
396 vap
->va_atime
.tv_sec
= val
;
397 FAILRV(psbuf_get_4(pb
, &val
));
398 vap
->va_mtime
.tv_sec
= val
;
399 /* make ctime the same as mtime */
400 vap
->va_ctime
.tv_sec
= val
;
402 vap
->va_atime
.tv_nsec
= 0;
403 vap
->va_ctime
.tv_nsec
= 0;
404 vap
->va_mtime
.tv_nsec
= 0;
411 * Buffer content helpers. Caller frees all data.
415 * error mapping.. most are not expected for a file system, but
416 * should help with diagnosing a possible error
418 static int emap
[] = {
421 ENOENT
, /* NO_SUCH_FILE */
422 EPERM
, /* PERMISSION_DENIED */
424 EBADMSG
, /* BAD_MESSAGE */
425 ENOTCONN
, /* NO_CONNECTION */
426 ECONNRESET
, /* CONNECTION_LOST */
427 EOPNOTSUPP
, /* OP_UNSUPPORTED */
428 EINVAL
, /* INVALID_HANDLE */
429 ENXIO
, /* NO_SUCH_PATH */
430 EEXIST
, /* FILE_ALREADY_EXISTS */
431 ENODEV
/* WRITE_PROTECT */
433 #define NERRORS ((int)(sizeof(emap) / sizeof(emap[0])))
436 sftperr_to_errno(int error
)
442 if (error
>= NERRORS
|| error
< 0)
448 #define INVALRESPONSE EPROTO
451 expectcode(struct puffs_framebuf
*pb
, int value
)
456 type
= psbuf_get_type(pb
);
460 if (type
!= SSH_FXP_STATUS
)
461 return INVALRESPONSE
;
463 FAILRV(psbuf_get_4(pb
, &error
));
465 return sftperr_to_errno(error
);
468 #define CHECKCODE(pb,val) \
471 rv = expectcode(pb, val); \
474 } while (/*CONSTCOND*/0)
477 psbuf_expect_status(struct puffs_framebuf
*pb
)
481 if (psbuf_get_type(pb
) != SSH_FXP_STATUS
)
482 return INVALRESPONSE
;
484 FAILRV(psbuf_get_4(pb
, &error
));
486 return sftperr_to_errno(error
);
490 psbuf_expect_handle(struct puffs_framebuf
*pb
, char **hand
, uint32_t *handlen
)
493 CHECKCODE(pb
, SSH_FXP_HANDLE
);
494 FAILRV(psbuf_get_str(pb
, hand
, handlen
));
499 /* no memory allocation, direct copy */
501 psbuf_do_data(struct puffs_framebuf
*pb
, uint8_t *data
, uint32_t *dlen
)
504 size_t bufoff
, winlen
;
505 uint32_t len
, dataoff
;
507 if (psbuf_get_type(pb
) != SSH_FXP_DATA
) {
510 if (psbuf_get_type(pb
) != SSH_FXP_STATUS
)
511 return INVALRESPONSE
;
513 if (psbuf_get_4(pb
, &val
) != 0)
514 return INVALRESPONSE
;
516 if (val
!= SSH_FX_EOF
)
517 return sftperr_to_errno(val
);
522 if (psbuf_get_4(pb
, &len
) != 0)
523 return INVALRESPONSE
;
531 while (dataoff
< len
) {
532 winlen
= len
-dataoff
;
533 bufoff
= puffs_framebuf_telloff(pb
);
534 if (puffs_framebuf_getwindow(pb
, bufoff
,
535 &win
, &winlen
) == -1)
540 memcpy(data
+ dataoff
, win
, winlen
);
550 psbuf_expect_name(struct puffs_framebuf
*pb
, uint32_t *count
)
553 CHECKCODE(pb
, SSH_FXP_NAME
);
554 FAILRV(psbuf_get_4(pb
, count
));
560 psbuf_expect_attrs(struct puffs_framebuf
*pb
, struct vattr
*vap
)
563 CHECKCODE(pb
, SSH_FXP_ATTRS
);
564 FAILRV(psbuf_get_vattr(pb
, vap
));
570 * More helpers: larger-scale put functions
574 psbuf_req_data(struct puffs_framebuf
*pb
, int type
, uint32_t reqid
,
575 const void *data
, uint32_t dlen
)
578 psbuf_put_1(pb
, type
);
579 psbuf_put_4(pb
, reqid
);
580 psbuf_put_data(pb
, data
, dlen
);
584 psbuf_req_str(struct puffs_framebuf
*pb
, int type
, uint32_t reqid
,
588 psbuf_req_data(pb
, type
, reqid
, str
, strlen(str
));