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