1 /* 2 * Copyright (c) 2001 Damien Miller. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 /* XXX: memleaks */ 26 /* XXX: signed vs unsigned */ 27 /* XXX: redesign to allow concurrent overlapped operations */ 28 /* XXX: we use fatal too much, error may be more appropriate in places */ 29 /* XXX: copy between two remote sites */ 30 31 #include "includes.h" 32 RCSID("$OpenBSD: sftp-client.c,v 1.16 2001/04/05 10:42:52 markus Exp $"); 33 34 #include "ssh.h" 35 #include "buffer.h" 36 #include "bufaux.h" 37 #include "getput.h" 38 #include "xmalloc.h" 39 #include "log.h" 40 #include "atomicio.h" 41 #include "pathnames.h" 42 43 #include "sftp.h" 44 #include "sftp-common.h" 45 #include "sftp-client.h" 46 47 /* How much data to read/write at at time during copies */ 48 /* XXX: what should this be? */ 49 #define COPY_SIZE 8192 50 51 /* Message ID */ 52 static u_int msg_id = 1; 53 54 void 55 send_msg(int fd, Buffer *m) 56 { 57 int mlen = buffer_len(m); 58 int len; 59 Buffer oqueue; 60 61 buffer_init(&oqueue); 62 buffer_put_int(&oqueue, mlen); 63 buffer_append(&oqueue, buffer_ptr(m), mlen); 64 buffer_consume(m, mlen); 65 66 len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue)); 67 if (len <= 0) 68 fatal("Couldn't send packet: %s", strerror(errno)); 69 70 buffer_free(&oqueue); 71 } 72 73 void 74 get_msg(int fd, Buffer *m) 75 { 76 u_int len, msg_len; 77 unsigned char buf[4096]; 78 79 len = atomicio(read, fd, buf, 4); 80 if (len == 0) 81 fatal("Connection closed"); 82 else if (len == -1) 83 fatal("Couldn't read packet: %s", strerror(errno)); 84 85 msg_len = GET_32BIT(buf); 86 if (msg_len > 256 * 1024) 87 fatal("Received message too long %d", msg_len); 88 89 while (msg_len) { 90 len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); 91 if (len == 0) 92 fatal("Connection closed"); 93 else if (len == -1) 94 fatal("Couldn't read packet: %s", strerror(errno)); 95 96 msg_len -= len; 97 buffer_append(m, buf, len); 98 } 99 } 100 101 void 102 send_string_request(int fd, u_int id, u_int code, char *s, 103 u_int len) 104 { 105 Buffer msg; 106 107 buffer_init(&msg); 108 buffer_put_char(&msg, code); 109 buffer_put_int(&msg, id); 110 buffer_put_string(&msg, s, len); 111 send_msg(fd, &msg); 112 debug3("Sent message fd %d T:%d I:%d", fd, code, id); 113 buffer_free(&msg); 114 } 115 116 void 117 send_string_attrs_request(int fd, u_int id, u_int code, char *s, 118 u_int len, Attrib *a) 119 { 120 Buffer msg; 121 122 buffer_init(&msg); 123 buffer_put_char(&msg, code); 124 buffer_put_int(&msg, id); 125 buffer_put_string(&msg, s, len); 126 encode_attrib(&msg, a); 127 send_msg(fd, &msg); 128 debug3("Sent message fd %d T:%d I:%d", fd, code, id); 129 buffer_free(&msg); 130 } 131 132 u_int 133 get_status(int fd, int expected_id) 134 { 135 Buffer msg; 136 u_int type, id, status; 137 138 buffer_init(&msg); 139 get_msg(fd, &msg); 140 type = buffer_get_char(&msg); 141 id = buffer_get_int(&msg); 142 143 if (id != expected_id) 144 fatal("ID mismatch (%d != %d)", id, expected_id); 145 if (type != SSH2_FXP_STATUS) 146 fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d", 147 SSH2_FXP_STATUS, type); 148 149 status = buffer_get_int(&msg); 150 buffer_free(&msg); 151 152 debug3("SSH2_FXP_STATUS %d", status); 153 154 return(status); 155 } 156 157 char * 158 get_handle(int fd, u_int expected_id, u_int *len) 159 { 160 Buffer msg; 161 u_int type, id; 162 char *handle; 163 164 buffer_init(&msg); 165 get_msg(fd, &msg); 166 type = buffer_get_char(&msg); 167 id = buffer_get_int(&msg); 168 169 if (id != expected_id) 170 fatal("ID mismatch (%d != %d)", id, expected_id); 171 if (type == SSH2_FXP_STATUS) { 172 int status = buffer_get_int(&msg); 173 174 error("Couldn't get handle: %s", fx2txt(status)); 175 return(NULL); 176 } else if (type != SSH2_FXP_HANDLE) 177 fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d", 178 SSH2_FXP_HANDLE, type); 179 180 handle = buffer_get_string(&msg, len); 181 buffer_free(&msg); 182 183 return(handle); 184 } 185 186 Attrib * 187 get_decode_stat(int fd, u_int expected_id, int quiet) 188 { 189 Buffer msg; 190 u_int type, id; 191 Attrib *a; 192 193 buffer_init(&msg); 194 get_msg(fd, &msg); 195 196 type = buffer_get_char(&msg); 197 id = buffer_get_int(&msg); 198 199 debug3("Received stat reply T:%d I:%d", type, id); 200 if (id != expected_id) 201 fatal("ID mismatch (%d != %d)", id, expected_id); 202 if (type == SSH2_FXP_STATUS) { 203 int status = buffer_get_int(&msg); 204 205 if (quiet) 206 debug("Couldn't stat remote file: %s", fx2txt(status)); 207 else 208 error("Couldn't stat remote file: %s", fx2txt(status)); 209 return(NULL); 210 } else if (type != SSH2_FXP_ATTRS) { 211 fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d", 212 SSH2_FXP_ATTRS, type); 213 } 214 a = decode_attrib(&msg); 215 buffer_free(&msg); 216 217 return(a); 218 } 219 220 int 221 do_init(int fd_in, int fd_out) 222 { 223 int type, version; 224 Buffer msg; 225 226 buffer_init(&msg); 227 buffer_put_char(&msg, SSH2_FXP_INIT); 228 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 229 send_msg(fd_out, &msg); 230 231 buffer_clear(&msg); 232 233 get_msg(fd_in, &msg); 234 235 /* Expecting a VERSION reply */ 236 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 237 error("Invalid packet back from SSH2_FXP_INIT (type %d)", 238 type); 239 buffer_free(&msg); 240 return(-1); 241 } 242 version = buffer_get_int(&msg); 243 244 debug2("Remote version: %d", version); 245 246 /* Check for extensions */ 247 while (buffer_len(&msg) > 0) { 248 char *name = buffer_get_string(&msg, NULL); 249 char *value = buffer_get_string(&msg, NULL); 250 251 debug2("Init extension: \"%s\"", name); 252 xfree(name); 253 xfree(value); 254 } 255 256 buffer_free(&msg); 257 258 return(version); 259 } 260 261 int 262 do_close(int fd_in, int fd_out, char *handle, u_int handle_len) 263 { 264 u_int id, status; 265 Buffer msg; 266 267 buffer_init(&msg); 268 269 id = msg_id++; 270 buffer_put_char(&msg, SSH2_FXP_CLOSE); 271 buffer_put_int(&msg, id); 272 buffer_put_string(&msg, handle, handle_len); 273 send_msg(fd_out, &msg); 274 debug3("Sent message SSH2_FXP_CLOSE I:%d", id); 275 276 status = get_status(fd_in, id); 277 if (status != SSH2_FX_OK) 278 error("Couldn't close file: %s", fx2txt(status)); 279 280 buffer_free(&msg); 281 282 return(status); 283 } 284 285 286 int 287 do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, 288 SFTP_DIRENT ***dir) 289 { 290 Buffer msg; 291 u_int type, id, handle_len, i, expected_id, ents = 0; 292 char *handle; 293 294 id = msg_id++; 295 296 buffer_init(&msg); 297 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 298 buffer_put_int(&msg, id); 299 buffer_put_cstring(&msg, path); 300 send_msg(fd_out, &msg); 301 302 buffer_clear(&msg); 303 304 handle = get_handle(fd_in, id, &handle_len); 305 if (handle == NULL) 306 return(-1); 307 308 if (dir) { 309 ents = 0; 310 *dir = xmalloc(sizeof(**dir)); 311 (*dir)[0] = NULL; 312 } 313 314 315 for(;;) { 316 int count; 317 318 id = expected_id = msg_id++; 319 320 debug3("Sending SSH2_FXP_READDIR I:%d", id); 321 322 buffer_clear(&msg); 323 buffer_put_char(&msg, SSH2_FXP_READDIR); 324 buffer_put_int(&msg, id); 325 buffer_put_string(&msg, handle, handle_len); 326 send_msg(fd_out, &msg); 327 328 buffer_clear(&msg); 329 330 get_msg(fd_in, &msg); 331 332 type = buffer_get_char(&msg); 333 id = buffer_get_int(&msg); 334 335 debug3("Received reply T:%d I:%d", type, id); 336 337 if (id != expected_id) 338 fatal("ID mismatch (%d != %d)", id, expected_id); 339 340 if (type == SSH2_FXP_STATUS) { 341 int status = buffer_get_int(&msg); 342 343 debug3("Received SSH2_FXP_STATUS %d", status); 344 345 if (status == SSH2_FX_EOF) { 346 break; 347 } else { 348 error("Couldn't read directory: %s", 349 fx2txt(status)); 350 do_close(fd_in, fd_out, handle, handle_len); 351 return(status); 352 } 353 } else if (type != SSH2_FXP_NAME) 354 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 355 SSH2_FXP_NAME, type); 356 357 count = buffer_get_int(&msg); 358 if (count == 0) 359 break; 360 debug3("Received %d SSH2_FXP_NAME responses", count); 361 for(i = 0; i < count; i++) { 362 char *filename, *longname; 363 Attrib *a; 364 365 filename = buffer_get_string(&msg, NULL); 366 longname = buffer_get_string(&msg, NULL); 367 a = decode_attrib(&msg); 368 369 if (printflag) 370 printf("%s\n", longname); 371 372 if (dir) { 373 *dir = xrealloc(*dir, sizeof(**dir) * 374 (ents + 2)); 375 (*dir)[ents] = xmalloc(sizeof(***dir)); 376 (*dir)[ents]->filename = xstrdup(filename); 377 (*dir)[ents]->longname = xstrdup(longname); 378 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 379 (*dir)[++ents] = NULL; 380 } 381 382 xfree(filename); 383 xfree(longname); 384 } 385 } 386 387 buffer_free(&msg); 388 do_close(fd_in, fd_out, handle, handle_len); 389 xfree(handle); 390 391 return(0); 392 } 393 394 int 395 do_ls(int fd_in, int fd_out, char *path) 396 { 397 return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); 398 } 399 400 int 401 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) 402 { 403 return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); 404 } 405 406 void free_sftp_dirents(SFTP_DIRENT **s) 407 { 408 int i; 409 410 for(i = 0; s[i]; i++) { 411 xfree(s[i]->filename); 412 xfree(s[i]->longname); 413 xfree(s[i]); 414 } 415 xfree(s); 416 } 417 418 int 419 do_rm(int fd_in, int fd_out, char *path) 420 { 421 u_int status, id; 422 423 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 424 425 id = msg_id++; 426 send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); 427 status = get_status(fd_in, id); 428 if (status != SSH2_FX_OK) 429 error("Couldn't delete file: %s", fx2txt(status)); 430 return(status); 431 } 432 433 int 434 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) 435 { 436 u_int status, id; 437 438 id = msg_id++; 439 send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path, 440 strlen(path), a); 441 442 status = get_status(fd_in, id); 443 if (status != SSH2_FX_OK) 444 error("Couldn't create directory: %s", fx2txt(status)); 445 446 return(status); 447 } 448 449 int 450 do_rmdir(int fd_in, int fd_out, char *path) 451 { 452 u_int status, id; 453 454 id = msg_id++; 455 send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); 456 457 status = get_status(fd_in, id); 458 if (status != SSH2_FX_OK) 459 error("Couldn't remove directory: %s", fx2txt(status)); 460 461 return(status); 462 } 463 464 Attrib * 465 do_stat(int fd_in, int fd_out, char *path, int quiet) 466 { 467 u_int id; 468 469 id = msg_id++; 470 send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); 471 return(get_decode_stat(fd_in, id, quiet)); 472 } 473 474 Attrib * 475 do_lstat(int fd_in, int fd_out, char *path, int quiet) 476 { 477 u_int id; 478 479 id = msg_id++; 480 send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); 481 return(get_decode_stat(fd_in, id, quiet)); 482 } 483 484 Attrib * 485 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet) 486 { 487 u_int id; 488 489 id = msg_id++; 490 send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); 491 return(get_decode_stat(fd_in, id, quiet)); 492 } 493 494 int 495 do_setstat(int fd_in, int fd_out, char *path, Attrib *a) 496 { 497 u_int status, id; 498 499 id = msg_id++; 500 send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path, 501 strlen(path), a); 502 503 status = get_status(fd_in, id); 504 if (status != SSH2_FX_OK) 505 error("Couldn't setstat on \"%s\": %s", path, 506 fx2txt(status)); 507 508 return(status); 509 } 510 511 int 512 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, 513 Attrib *a) 514 { 515 u_int status, id; 516 517 id = msg_id++; 518 send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle, 519 handle_len, a); 520 521 status = get_status(fd_in, id); 522 if (status != SSH2_FX_OK) 523 error("Couldn't fsetstat: %s", fx2txt(status)); 524 525 return(status); 526 } 527 528 char * 529 do_realpath(int fd_in, int fd_out, char *path) 530 { 531 Buffer msg; 532 u_int type, expected_id, count, id; 533 char *filename, *longname; 534 Attrib *a; 535 536 expected_id = id = msg_id++; 537 send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); 538 539 buffer_init(&msg); 540 541 get_msg(fd_in, &msg); 542 type = buffer_get_char(&msg); 543 id = buffer_get_int(&msg); 544 545 if (id != expected_id) 546 fatal("ID mismatch (%d != %d)", id, expected_id); 547 548 if (type == SSH2_FXP_STATUS) { 549 u_int status = buffer_get_int(&msg); 550 551 error("Couldn't canonicalise: %s", fx2txt(status)); 552 return(NULL); 553 } else if (type != SSH2_FXP_NAME) 554 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 555 SSH2_FXP_NAME, type); 556 557 count = buffer_get_int(&msg); 558 if (count != 1) 559 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 560 561 filename = buffer_get_string(&msg, NULL); 562 longname = buffer_get_string(&msg, NULL); 563 a = decode_attrib(&msg); 564 565 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 566 567 xfree(longname); 568 569 buffer_free(&msg); 570 571 return(filename); 572 } 573 574 int 575 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) 576 { 577 Buffer msg; 578 u_int status, id; 579 580 buffer_init(&msg); 581 582 /* Send rename request */ 583 id = msg_id++; 584 buffer_put_char(&msg, SSH2_FXP_RENAME); 585 buffer_put_int(&msg, id); 586 buffer_put_cstring(&msg, oldpath); 587 buffer_put_cstring(&msg, newpath); 588 send_msg(fd_out, &msg); 589 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, 590 newpath); 591 buffer_free(&msg); 592 593 status = get_status(fd_in, id); 594 if (status != SSH2_FX_OK) 595 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 596 fx2txt(status)); 597 598 return(status); 599 } 600 601 int 602 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath) 603 { 604 Buffer msg; 605 u_int status, id; 606 607 buffer_init(&msg); 608 609 /* Send rename request */ 610 id = msg_id++; 611 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 612 buffer_put_int(&msg, id); 613 buffer_put_cstring(&msg, oldpath); 614 buffer_put_cstring(&msg, newpath); 615 send_msg(fd_out, &msg); 616 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 617 newpath); 618 buffer_free(&msg); 619 620 status = get_status(fd_in, id); 621 if (status != SSH2_FX_OK) 622 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, 623 fx2txt(status)); 624 625 return(status); 626 } 627 628 char * 629 do_readlink(int fd_in, int fd_out, char *path) 630 { 631 Buffer msg; 632 u_int type, expected_id, count, id; 633 char *filename, *longname; 634 Attrib *a; 635 636 expected_id = id = msg_id++; 637 send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); 638 639 buffer_init(&msg); 640 641 get_msg(fd_in, &msg); 642 type = buffer_get_char(&msg); 643 id = buffer_get_int(&msg); 644 645 if (id != expected_id) 646 fatal("ID mismatch (%d != %d)", id, expected_id); 647 648 if (type == SSH2_FXP_STATUS) { 649 u_int status = buffer_get_int(&msg); 650 651 error("Couldn't readlink: %s", fx2txt(status)); 652 return(NULL); 653 } else if (type != SSH2_FXP_NAME) 654 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d", 655 SSH2_FXP_NAME, type); 656 657 count = buffer_get_int(&msg); 658 if (count != 1) 659 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 660 661 filename = buffer_get_string(&msg, NULL); 662 longname = buffer_get_string(&msg, NULL); 663 a = decode_attrib(&msg); 664 665 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 666 667 xfree(longname); 668 669 buffer_free(&msg); 670 671 return(filename); 672 } 673 674 int 675 do_download(int fd_in, int fd_out, char *remote_path, char *local_path, 676 int pflag) 677 { 678 int local_fd; 679 u_int expected_id, handle_len, mode, type, id; 680 u_int64_t offset; 681 char *handle; 682 Buffer msg; 683 Attrib junk, *a; 684 int status; 685 686 a = do_stat(fd_in, fd_out, remote_path, 0); 687 if (a == NULL) 688 return(-1); 689 690 /* XXX: should we preserve set[ug]id? */ 691 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 692 mode = S_IWRITE | (a->perm & 0777); 693 else 694 mode = 0666; 695 696 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 697 (a->perm & S_IFDIR)) { 698 error("Cannot download a directory: %s", remote_path); 699 return(-1); 700 } 701 702 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); 703 if (local_fd == -1) { 704 error("Couldn't open local file \"%s\" for writing: %s", 705 local_path, strerror(errno)); 706 return(-1); 707 } 708 709 buffer_init(&msg); 710 711 /* Send open request */ 712 id = msg_id++; 713 buffer_put_char(&msg, SSH2_FXP_OPEN); 714 buffer_put_int(&msg, id); 715 buffer_put_cstring(&msg, remote_path); 716 buffer_put_int(&msg, SSH2_FXF_READ); 717 attrib_clear(&junk); /* Send empty attributes */ 718 encode_attrib(&msg, &junk); 719 send_msg(fd_out, &msg); 720 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 721 722 handle = get_handle(fd_in, id, &handle_len); 723 if (handle == NULL) { 724 buffer_free(&msg); 725 close(local_fd); 726 return(-1); 727 } 728 729 /* Read from remote and write to local */ 730 offset = 0; 731 for(;;) { 732 u_int len; 733 char *data; 734 735 id = expected_id = msg_id++; 736 737 buffer_clear(&msg); 738 buffer_put_char(&msg, SSH2_FXP_READ); 739 buffer_put_int(&msg, id); 740 buffer_put_string(&msg, handle, handle_len); 741 buffer_put_int64(&msg, offset); 742 buffer_put_int(&msg, COPY_SIZE); 743 send_msg(fd_out, &msg); 744 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u", 745 id, (unsigned long long)offset, COPY_SIZE); 746 747 buffer_clear(&msg); 748 749 get_msg(fd_in, &msg); 750 type = buffer_get_char(&msg); 751 id = buffer_get_int(&msg); 752 debug3("Received reply T:%d I:%d", type, id); 753 if (id != expected_id) 754 fatal("ID mismatch (%d != %d)", id, expected_id); 755 if (type == SSH2_FXP_STATUS) { 756 status = buffer_get_int(&msg); 757 758 if (status == SSH2_FX_EOF) 759 break; 760 else { 761 error("Couldn't read from remote " 762 "file \"%s\" : %s", remote_path, 763 fx2txt(status)); 764 do_close(fd_in, fd_out, handle, handle_len); 765 goto done; 766 } 767 } else if (type != SSH2_FXP_DATA) { 768 fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", 769 SSH2_FXP_DATA, type); 770 } 771 772 data = buffer_get_string(&msg, &len); 773 if (len > COPY_SIZE) 774 fatal("Received more data than asked for %d > %d", 775 len, COPY_SIZE); 776 777 debug3("In read loop, got %d offset %llu", len, 778 (unsigned long long)offset); 779 if (atomicio(write, local_fd, data, len) != len) { 780 error("Couldn't write to \"%s\": %s", local_path, 781 strerror(errno)); 782 do_close(fd_in, fd_out, handle, handle_len); 783 status = -1; 784 xfree(data); 785 goto done; 786 } 787 788 offset += len; 789 xfree(data); 790 } 791 status = do_close(fd_in, fd_out, handle, handle_len); 792 793 /* Override umask and utimes if asked */ 794 if (pflag && fchmod(local_fd, mode) == -1) 795 error("Couldn't set mode on \"%s\": %s", local_path, 796 strerror(errno)); 797 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 798 struct timeval tv[2]; 799 tv[0].tv_sec = a->atime; 800 tv[1].tv_sec = a->mtime; 801 tv[0].tv_usec = tv[1].tv_usec = 0; 802 if (utimes(local_path, tv) == -1) 803 error("Can't set times on \"%s\": %s", local_path, 804 strerror(errno)); 805 } 806 807 done: 808 close(local_fd); 809 buffer_free(&msg); 810 xfree(handle); 811 return status; 812 } 813 814 int 815 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, 816 int pflag) 817 { 818 int local_fd; 819 u_int handle_len, id; 820 u_int64_t offset; 821 char *handle; 822 Buffer msg; 823 struct stat sb; 824 Attrib a; 825 int status; 826 827 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 828 error("Couldn't open local file \"%s\" for reading: %s", 829 local_path, strerror(errno)); 830 return(-1); 831 } 832 if (fstat(local_fd, &sb) == -1) { 833 error("Couldn't fstat local file \"%s\": %s", 834 local_path, strerror(errno)); 835 close(local_fd); 836 return(-1); 837 } 838 stat_to_attrib(&sb, &a); 839 840 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 841 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 842 a.perm &= 0777; 843 if (!pflag) 844 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 845 846 buffer_init(&msg); 847 848 /* Send open request */ 849 id = msg_id++; 850 buffer_put_char(&msg, SSH2_FXP_OPEN); 851 buffer_put_int(&msg, id); 852 buffer_put_cstring(&msg, remote_path); 853 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 854 encode_attrib(&msg, &a); 855 send_msg(fd_out, &msg); 856 debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); 857 858 buffer_clear(&msg); 859 860 handle = get_handle(fd_in, id, &handle_len); 861 if (handle == NULL) { 862 close(local_fd); 863 buffer_free(&msg); 864 return(-1); 865 } 866 867 /* Read from local and write to remote */ 868 offset = 0; 869 for(;;) { 870 int len; 871 char data[COPY_SIZE]; 872 873 /* 874 * Can't use atomicio here because it returns 0 on EOF, thus losing 875 * the last block of the file 876 */ 877 do 878 len = read(local_fd, data, COPY_SIZE); 879 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 880 881 if (len == -1) 882 fatal("Couldn't read from \"%s\": %s", local_path, 883 strerror(errno)); 884 if (len == 0) 885 break; 886 887 buffer_clear(&msg); 888 buffer_put_char(&msg, SSH2_FXP_WRITE); 889 buffer_put_int(&msg, ++id); 890 buffer_put_string(&msg, handle, handle_len); 891 buffer_put_int64(&msg, offset); 892 buffer_put_string(&msg, data, len); 893 send_msg(fd_out, &msg); 894 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", 895 id, (unsigned long long)offset, len); 896 897 status = get_status(fd_in, id); 898 if (status != SSH2_FX_OK) { 899 error("Couldn't write to remote file \"%s\": %s", 900 remote_path, fx2txt(status)); 901 do_close(fd_in, fd_out, handle, handle_len); 902 close(local_fd); 903 goto done; 904 } 905 debug3("In write loop, got %d offset %llu", len, 906 (unsigned long long)offset); 907 908 offset += len; 909 } 910 911 if (close(local_fd) == -1) { 912 error("Couldn't close local file \"%s\": %s", local_path, 913 strerror(errno)); 914 do_close(fd_in, fd_out, handle, handle_len); 915 status = -1; 916 goto done; 917 } 918 919 /* Override umask and utimes if asked */ 920 if (pflag) 921 do_fsetstat(fd_in, fd_out, handle, handle_len, &a); 922 923 status = do_close(fd_in, fd_out, handle, handle_len); 924 925 done: 926 xfree(handle); 927 buffer_free(&msg); 928 return status; 929 } 930 931