1 1.19 christos /* $NetBSD: psbuf.c,v 1.19 2012/11/04 22:46:08 christos 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.19 christos __RCSID("$NetBSD: psbuf.c,v 1.19 2012/11/04 22:46:08 christos 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.19 christos #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