1 /* $OpenBSD: sftp-client.c,v 1.90 2009/10/11 10:41:26 dtucker Exp $ */ 2 /* 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* XXX: memleaks */ 19 /* XXX: signed vs unsigned */ 20 /* XXX: remove all logging, only return status codes */ 21 /* XXX: copy between two remote sites */ 22 23 #include "includes.h" 24 25 #include <sys/types.h> 26 #include <sys/param.h> 27 #ifdef HAVE_SYS_STATVFS_H 28 #include <sys/statvfs.h> 29 #endif 30 #include "openbsd-compat/sys-queue.h" 31 #ifdef HAVE_SYS_STAT_H 32 # include <sys/stat.h> 33 #endif 34 #ifdef HAVE_SYS_TIME_H 35 # include <sys/time.h> 36 #endif 37 #include <sys/uio.h> 38 39 #include <dirent.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <signal.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "xmalloc.h" 49 #include "buffer.h" 50 #include "log.h" 51 #include "atomicio.h" 52 #include "progressmeter.h" 53 #include "misc.h" 54 55 #include "sftp.h" 56 #include "sftp-common.h" 57 #include "sftp-client.h" 58 59 extern volatile sig_atomic_t interrupted; 60 extern int showprogress; 61 62 /* Minimum amount of data to read at a time */ 63 #define MIN_READ_SIZE 512 64 65 /* Maximum depth to descend in directory trees */ 66 #define MAX_DIR_DEPTH 64 67 68 struct sftp_conn { 69 int fd_in; 70 int fd_out; 71 u_int transfer_buflen; 72 u_int num_requests; 73 u_int version; 74 u_int msg_id; 75 #define SFTP_EXT_POSIX_RENAME 0x00000001 76 #define SFTP_EXT_STATVFS 0x00000002 77 #define SFTP_EXT_FSTATVFS 0x00000004 78 u_int exts; 79 }; 80 81 static char * 82 get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) 83 __attribute__((format(printf, 4, 5))); 84 85 static void 86 send_msg(int fd, Buffer *m) 87 { 88 u_char mlen[4]; 89 struct iovec iov[2]; 90 91 if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) 92 fatal("Outbound message too long %u", buffer_len(m)); 93 94 /* Send length first */ 95 put_u32(mlen, buffer_len(m)); 96 iov[0].iov_base = mlen; 97 iov[0].iov_len = sizeof(mlen); 98 iov[1].iov_base = buffer_ptr(m); 99 iov[1].iov_len = buffer_len(m); 100 101 if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen)) 102 fatal("Couldn't send packet: %s", strerror(errno)); 103 104 buffer_clear(m); 105 } 106 107 static void 108 get_msg(int fd, Buffer *m) 109 { 110 u_int msg_len; 111 112 buffer_append_space(m, 4); 113 if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { 114 if (errno == EPIPE) 115 fatal("Connection closed"); 116 else 117 fatal("Couldn't read packet: %s", strerror(errno)); 118 } 119 120 msg_len = buffer_get_int(m); 121 if (msg_len > SFTP_MAX_MSG_LENGTH) 122 fatal("Received message too long %u", msg_len); 123 124 buffer_append_space(m, msg_len); 125 if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { 126 if (errno == EPIPE) 127 fatal("Connection closed"); 128 else 129 fatal("Read packet: %s", strerror(errno)); 130 } 131 } 132 133 static void 134 send_string_request(int fd, u_int id, u_int code, char *s, 135 u_int len) 136 { 137 Buffer msg; 138 139 buffer_init(&msg); 140 buffer_put_char(&msg, code); 141 buffer_put_int(&msg, id); 142 buffer_put_string(&msg, s, len); 143 send_msg(fd, &msg); 144 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 145 buffer_free(&msg); 146 } 147 148 static void 149 send_string_attrs_request(int fd, u_int id, u_int code, char *s, 150 u_int len, Attrib *a) 151 { 152 Buffer msg; 153 154 buffer_init(&msg); 155 buffer_put_char(&msg, code); 156 buffer_put_int(&msg, id); 157 buffer_put_string(&msg, s, len); 158 encode_attrib(&msg, a); 159 send_msg(fd, &msg); 160 debug3("Sent message fd %d T:%u I:%u", fd, code, id); 161 buffer_free(&msg); 162 } 163 164 static u_int 165 get_status(int fd, u_int expected_id) 166 { 167 Buffer msg; 168 u_int type, id, status; 169 170 buffer_init(&msg); 171 get_msg(fd, &msg); 172 type = buffer_get_char(&msg); 173 id = buffer_get_int(&msg); 174 175 if (id != expected_id) 176 fatal("ID mismatch (%u != %u)", id, expected_id); 177 if (type != SSH2_FXP_STATUS) 178 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 179 SSH2_FXP_STATUS, type); 180 181 status = buffer_get_int(&msg); 182 buffer_free(&msg); 183 184 debug3("SSH2_FXP_STATUS %u", status); 185 186 return(status); 187 } 188 189 static char * 190 get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) 191 { 192 Buffer msg; 193 u_int type, id; 194 char *handle, errmsg[256]; 195 va_list args; 196 int status; 197 198 va_start(args, errfmt); 199 if (errfmt != NULL) 200 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 201 va_end(args); 202 203 buffer_init(&msg); 204 get_msg(fd, &msg); 205 type = buffer_get_char(&msg); 206 id = buffer_get_int(&msg); 207 208 if (id != expected_id) 209 fatal("%s: ID mismatch (%u != %u)", 210 errfmt == NULL ? __func__ : errmsg, id, expected_id); 211 if (type == SSH2_FXP_STATUS) { 212 status = buffer_get_int(&msg); 213 if (errfmt != NULL) 214 error("%s: %s", errmsg, fx2txt(status)); 215 buffer_free(&msg); 216 return(NULL); 217 } else if (type != SSH2_FXP_HANDLE) 218 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 219 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 220 221 handle = buffer_get_string(&msg, len); 222 buffer_free(&msg); 223 224 return(handle); 225 } 226 227 static Attrib * 228 get_decode_stat(int fd, u_int expected_id, int quiet) 229 { 230 Buffer msg; 231 u_int type, id; 232 Attrib *a; 233 234 buffer_init(&msg); 235 get_msg(fd, &msg); 236 237 type = buffer_get_char(&msg); 238 id = buffer_get_int(&msg); 239 240 debug3("Received stat reply T:%u I:%u", type, id); 241 if (id != expected_id) 242 fatal("ID mismatch (%u != %u)", id, expected_id); 243 if (type == SSH2_FXP_STATUS) { 244 int status = buffer_get_int(&msg); 245 246 if (quiet) 247 debug("Couldn't stat remote file: %s", fx2txt(status)); 248 else 249 error("Couldn't stat remote file: %s", fx2txt(status)); 250 buffer_free(&msg); 251 return(NULL); 252 } else if (type != SSH2_FXP_ATTRS) { 253 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 254 SSH2_FXP_ATTRS, type); 255 } 256 a = decode_attrib(&msg); 257 buffer_free(&msg); 258 259 return(a); 260 } 261 262 static int 263 get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, 264 int quiet) 265 { 266 Buffer msg; 267 u_int type, id, flag; 268 269 buffer_init(&msg); 270 get_msg(fd, &msg); 271 272 type = buffer_get_char(&msg); 273 id = buffer_get_int(&msg); 274 275 debug3("Received statvfs reply T:%u I:%u", type, id); 276 if (id != expected_id) 277 fatal("ID mismatch (%u != %u)", id, expected_id); 278 if (type == SSH2_FXP_STATUS) { 279 int status = buffer_get_int(&msg); 280 281 if (quiet) 282 debug("Couldn't statvfs: %s", fx2txt(status)); 283 else 284 error("Couldn't statvfs: %s", fx2txt(status)); 285 buffer_free(&msg); 286 return -1; 287 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 288 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 289 SSH2_FXP_EXTENDED_REPLY, type); 290 } 291 292 bzero(st, sizeof(*st)); 293 st->f_bsize = buffer_get_int64(&msg); 294 st->f_frsize = buffer_get_int64(&msg); 295 st->f_blocks = buffer_get_int64(&msg); 296 st->f_bfree = buffer_get_int64(&msg); 297 st->f_bavail = buffer_get_int64(&msg); 298 st->f_files = buffer_get_int64(&msg); 299 st->f_ffree = buffer_get_int64(&msg); 300 st->f_favail = buffer_get_int64(&msg); 301 st->f_fsid = buffer_get_int64(&msg); 302 flag = buffer_get_int64(&msg); 303 st->f_namemax = buffer_get_int64(&msg); 304 305 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 306 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 307 308 buffer_free(&msg); 309 310 return 0; 311 } 312 313 struct sftp_conn * 314 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) 315 { 316 u_int type, exts = 0; 317 int version; 318 Buffer msg; 319 struct sftp_conn *ret; 320 321 buffer_init(&msg); 322 buffer_put_char(&msg, SSH2_FXP_INIT); 323 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 324 send_msg(fd_out, &msg); 325 326 buffer_clear(&msg); 327 328 get_msg(fd_in, &msg); 329 330 /* Expecting a VERSION reply */ 331 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 332 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 333 type); 334 buffer_free(&msg); 335 return(NULL); 336 } 337 version = buffer_get_int(&msg); 338 339 debug2("Remote version: %d", version); 340 341 /* Check for extensions */ 342 while (buffer_len(&msg) > 0) { 343 char *name = buffer_get_string(&msg, NULL); 344 char *value = buffer_get_string(&msg, NULL); 345 int known = 0; 346 347 if (strcmp(name, "posix-rename@openssh.com") == 0 && 348 strcmp(value, "1") == 0) { 349 exts |= SFTP_EXT_POSIX_RENAME; 350 known = 1; 351 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 352 strcmp(value, "2") == 0) { 353 exts |= SFTP_EXT_STATVFS; 354 known = 1; 355 } if (strcmp(name, "fstatvfs@openssh.com") == 0 && 356 strcmp(value, "2") == 0) { 357 exts |= SFTP_EXT_FSTATVFS; 358 known = 1; 359 } 360 if (known) { 361 debug2("Server supports extension \"%s\" revision %s", 362 name, value); 363 } else { 364 debug2("Unrecognised server extension \"%s\"", name); 365 } 366 xfree(name); 367 xfree(value); 368 } 369 370 buffer_free(&msg); 371 372 ret = xmalloc(sizeof(*ret)); 373 ret->fd_in = fd_in; 374 ret->fd_out = fd_out; 375 ret->transfer_buflen = transfer_buflen; 376 ret->num_requests = num_requests; 377 ret->version = version; 378 ret->msg_id = 1; 379 ret->exts = exts; 380 381 /* Some filexfer v.0 servers don't support large packets */ 382 if (version == 0) 383 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); 384 385 return(ret); 386 } 387 388 u_int 389 sftp_proto_version(struct sftp_conn *conn) 390 { 391 return(conn->version); 392 } 393 394 int 395 do_close(struct sftp_conn *conn, char *handle, u_int handle_len) 396 { 397 u_int id, status; 398 Buffer msg; 399 400 buffer_init(&msg); 401 402 id = conn->msg_id++; 403 buffer_put_char(&msg, SSH2_FXP_CLOSE); 404 buffer_put_int(&msg, id); 405 buffer_put_string(&msg, handle, handle_len); 406 send_msg(conn->fd_out, &msg); 407 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 408 409 status = get_status(conn->fd_in, id); 410 if (status != SSH2_FX_OK) 411 error("Couldn't close file: %s", fx2txt(status)); 412 413 buffer_free(&msg); 414 415 return(status); 416 } 417 418 419 static int 420 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, 421 SFTP_DIRENT ***dir) 422 { 423 Buffer msg; 424 u_int count, type, id, handle_len, i, expected_id, ents = 0; 425 char *handle; 426 427 id = conn->msg_id++; 428 429 buffer_init(&msg); 430 buffer_put_char(&msg, SSH2_FXP_OPENDIR); 431 buffer_put_int(&msg, id); 432 buffer_put_cstring(&msg, path); 433 send_msg(conn->fd_out, &msg); 434 435 buffer_clear(&msg); 436 437 handle = get_handle(conn->fd_in, id, &handle_len, 438 "remote readdir(\"%s\")", path); 439 if (handle == NULL) 440 return(-1); 441 442 if (dir) { 443 ents = 0; 444 *dir = xmalloc(sizeof(**dir)); 445 (*dir)[0] = NULL; 446 } 447 448 for (; !interrupted;) { 449 id = expected_id = conn->msg_id++; 450 451 debug3("Sending SSH2_FXP_READDIR I:%u", id); 452 453 buffer_clear(&msg); 454 buffer_put_char(&msg, SSH2_FXP_READDIR); 455 buffer_put_int(&msg, id); 456 buffer_put_string(&msg, handle, handle_len); 457 send_msg(conn->fd_out, &msg); 458 459 buffer_clear(&msg); 460 461 get_msg(conn->fd_in, &msg); 462 463 type = buffer_get_char(&msg); 464 id = buffer_get_int(&msg); 465 466 debug3("Received reply T:%u I:%u", type, id); 467 468 if (id != expected_id) 469 fatal("ID mismatch (%u != %u)", id, expected_id); 470 471 if (type == SSH2_FXP_STATUS) { 472 int status = buffer_get_int(&msg); 473 474 debug3("Received SSH2_FXP_STATUS %d", status); 475 476 if (status == SSH2_FX_EOF) { 477 break; 478 } else { 479 error("Couldn't read directory: %s", 480 fx2txt(status)); 481 do_close(conn, handle, handle_len); 482 xfree(handle); 483 return(status); 484 } 485 } else if (type != SSH2_FXP_NAME) 486 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 487 SSH2_FXP_NAME, type); 488 489 count = buffer_get_int(&msg); 490 if (count == 0) 491 break; 492 debug3("Received %d SSH2_FXP_NAME responses", count); 493 for (i = 0; i < count; i++) { 494 char *filename, *longname; 495 Attrib *a; 496 497 filename = buffer_get_string(&msg, NULL); 498 longname = buffer_get_string(&msg, NULL); 499 a = decode_attrib(&msg); 500 501 if (printflag) 502 printf("%s\n", longname); 503 504 /* 505 * Directory entries should never contain '/' 506 * These can be used to attack recursive ops 507 * (e.g. send '../../../../etc/passwd') 508 */ 509 if (strchr(filename, '/') != NULL) { 510 error("Server sent suspect path \"%s\" " 511 "during readdir of \"%s\"", filename, path); 512 goto next; 513 } 514 515 if (dir) { 516 *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); 517 (*dir)[ents] = xmalloc(sizeof(***dir)); 518 (*dir)[ents]->filename = xstrdup(filename); 519 (*dir)[ents]->longname = xstrdup(longname); 520 memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 521 (*dir)[++ents] = NULL; 522 } 523 next: 524 xfree(filename); 525 xfree(longname); 526 } 527 } 528 529 buffer_free(&msg); 530 do_close(conn, handle, handle_len); 531 xfree(handle); 532 533 /* Don't return partial matches on interrupt */ 534 if (interrupted && dir != NULL && *dir != NULL) { 535 free_sftp_dirents(*dir); 536 *dir = xmalloc(sizeof(**dir)); 537 **dir = NULL; 538 } 539 540 return(0); 541 } 542 543 int 544 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 545 { 546 return(do_lsreaddir(conn, path, 0, dir)); 547 } 548 549 void free_sftp_dirents(SFTP_DIRENT **s) 550 { 551 int i; 552 553 for (i = 0; s[i]; i++) { 554 xfree(s[i]->filename); 555 xfree(s[i]->longname); 556 xfree(s[i]); 557 } 558 xfree(s); 559 } 560 561 int 562 do_rm(struct sftp_conn *conn, char *path) 563 { 564 u_int status, id; 565 566 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 567 568 id = conn->msg_id++; 569 send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, 570 strlen(path)); 571 status = get_status(conn->fd_in, id); 572 if (status != SSH2_FX_OK) 573 error("Couldn't delete file: %s", fx2txt(status)); 574 return(status); 575 } 576 577 int 578 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) 579 { 580 u_int status, id; 581 582 id = conn->msg_id++; 583 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, 584 strlen(path), a); 585 586 status = get_status(conn->fd_in, id); 587 if (status != SSH2_FX_OK && printflag) 588 error("Couldn't create directory: %s", fx2txt(status)); 589 590 return(status); 591 } 592 593 int 594 do_rmdir(struct sftp_conn *conn, char *path) 595 { 596 u_int status, id; 597 598 id = conn->msg_id++; 599 send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, 600 strlen(path)); 601 602 status = get_status(conn->fd_in, id); 603 if (status != SSH2_FX_OK) 604 error("Couldn't remove directory: %s", fx2txt(status)); 605 606 return(status); 607 } 608 609 Attrib * 610 do_stat(struct sftp_conn *conn, char *path, int quiet) 611 { 612 u_int id; 613 614 id = conn->msg_id++; 615 616 send_string_request(conn->fd_out, id, 617 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 618 path, strlen(path)); 619 620 return(get_decode_stat(conn->fd_in, id, quiet)); 621 } 622 623 Attrib * 624 do_lstat(struct sftp_conn *conn, char *path, int quiet) 625 { 626 u_int id; 627 628 if (conn->version == 0) { 629 if (quiet) 630 debug("Server version does not support lstat operation"); 631 else 632 logit("Server version does not support lstat operation"); 633 return(do_stat(conn, path, quiet)); 634 } 635 636 id = conn->msg_id++; 637 send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, 638 strlen(path)); 639 640 return(get_decode_stat(conn->fd_in, id, quiet)); 641 } 642 643 #ifdef notyet 644 Attrib * 645 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 646 { 647 u_int id; 648 649 id = conn->msg_id++; 650 send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, 651 handle_len); 652 653 return(get_decode_stat(conn->fd_in, id, quiet)); 654 } 655 #endif 656 657 int 658 do_setstat(struct sftp_conn *conn, char *path, Attrib *a) 659 { 660 u_int status, id; 661 662 id = conn->msg_id++; 663 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, 664 strlen(path), a); 665 666 status = get_status(conn->fd_in, id); 667 if (status != SSH2_FX_OK) 668 error("Couldn't setstat on \"%s\": %s", path, 669 fx2txt(status)); 670 671 return(status); 672 } 673 674 int 675 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 676 Attrib *a) 677 { 678 u_int status, id; 679 680 id = conn->msg_id++; 681 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, 682 handle_len, a); 683 684 status = get_status(conn->fd_in, id); 685 if (status != SSH2_FX_OK) 686 error("Couldn't fsetstat: %s", fx2txt(status)); 687 688 return(status); 689 } 690 691 char * 692 do_realpath(struct sftp_conn *conn, char *path) 693 { 694 Buffer msg; 695 u_int type, expected_id, count, id; 696 char *filename, *longname; 697 Attrib *a; 698 699 expected_id = id = conn->msg_id++; 700 send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, 701 strlen(path)); 702 703 buffer_init(&msg); 704 705 get_msg(conn->fd_in, &msg); 706 type = buffer_get_char(&msg); 707 id = buffer_get_int(&msg); 708 709 if (id != expected_id) 710 fatal("ID mismatch (%u != %u)", id, expected_id); 711 712 if (type == SSH2_FXP_STATUS) { 713 u_int status = buffer_get_int(&msg); 714 715 error("Couldn't canonicalise: %s", fx2txt(status)); 716 return(NULL); 717 } else if (type != SSH2_FXP_NAME) 718 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 719 SSH2_FXP_NAME, type); 720 721 count = buffer_get_int(&msg); 722 if (count != 1) 723 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 724 725 filename = buffer_get_string(&msg, NULL); 726 longname = buffer_get_string(&msg, NULL); 727 a = decode_attrib(&msg); 728 729 debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 730 731 xfree(longname); 732 733 buffer_free(&msg); 734 735 return(filename); 736 } 737 738 int 739 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 740 { 741 Buffer msg; 742 u_int status, id; 743 744 buffer_init(&msg); 745 746 /* Send rename request */ 747 id = conn->msg_id++; 748 if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { 749 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 750 buffer_put_int(&msg, id); 751 buffer_put_cstring(&msg, "posix-rename@openssh.com"); 752 } else { 753 buffer_put_char(&msg, SSH2_FXP_RENAME); 754 buffer_put_int(&msg, id); 755 } 756 buffer_put_cstring(&msg, oldpath); 757 buffer_put_cstring(&msg, newpath); 758 send_msg(conn->fd_out, &msg); 759 debug3("Sent message %s \"%s\" -> \"%s\"", 760 (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : 761 "SSH2_FXP_RENAME", oldpath, newpath); 762 buffer_free(&msg); 763 764 status = get_status(conn->fd_in, id); 765 if (status != SSH2_FX_OK) 766 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 767 newpath, fx2txt(status)); 768 769 return(status); 770 } 771 772 int 773 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 774 { 775 Buffer msg; 776 u_int status, id; 777 778 if (conn->version < 3) { 779 error("This server does not support the symlink operation"); 780 return(SSH2_FX_OP_UNSUPPORTED); 781 } 782 783 buffer_init(&msg); 784 785 /* Send symlink request */ 786 id = conn->msg_id++; 787 buffer_put_char(&msg, SSH2_FXP_SYMLINK); 788 buffer_put_int(&msg, id); 789 buffer_put_cstring(&msg, oldpath); 790 buffer_put_cstring(&msg, newpath); 791 send_msg(conn->fd_out, &msg); 792 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 793 newpath); 794 buffer_free(&msg); 795 796 status = get_status(conn->fd_in, id); 797 if (status != SSH2_FX_OK) 798 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 799 newpath, fx2txt(status)); 800 801 return(status); 802 } 803 804 #ifdef notyet 805 char * 806 do_readlink(struct sftp_conn *conn, char *path) 807 { 808 Buffer msg; 809 u_int type, expected_id, count, id; 810 char *filename, *longname; 811 Attrib *a; 812 813 expected_id = id = conn->msg_id++; 814 send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, 815 strlen(path)); 816 817 buffer_init(&msg); 818 819 get_msg(conn->fd_in, &msg); 820 type = buffer_get_char(&msg); 821 id = buffer_get_int(&msg); 822 823 if (id != expected_id) 824 fatal("ID mismatch (%u != %u)", id, expected_id); 825 826 if (type == SSH2_FXP_STATUS) { 827 u_int status = buffer_get_int(&msg); 828 829 error("Couldn't readlink: %s", fx2txt(status)); 830 return(NULL); 831 } else if (type != SSH2_FXP_NAME) 832 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 833 SSH2_FXP_NAME, type); 834 835 count = buffer_get_int(&msg); 836 if (count != 1) 837 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 838 839 filename = buffer_get_string(&msg, NULL); 840 longname = buffer_get_string(&msg, NULL); 841 a = decode_attrib(&msg); 842 843 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 844 845 xfree(longname); 846 847 buffer_free(&msg); 848 849 return(filename); 850 } 851 #endif 852 853 int 854 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 855 int quiet) 856 { 857 Buffer msg; 858 u_int id; 859 860 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 861 error("Server does not support statvfs@openssh.com extension"); 862 return -1; 863 } 864 865 id = conn->msg_id++; 866 867 buffer_init(&msg); 868 buffer_clear(&msg); 869 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 870 buffer_put_int(&msg, id); 871 buffer_put_cstring(&msg, "statvfs@openssh.com"); 872 buffer_put_cstring(&msg, path); 873 send_msg(conn->fd_out, &msg); 874 buffer_free(&msg); 875 876 return get_decode_statvfs(conn->fd_in, st, id, quiet); 877 } 878 879 #ifdef notyet 880 int 881 do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, 882 struct sftp_statvfs *st, int quiet) 883 { 884 Buffer msg; 885 u_int id; 886 887 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 888 error("Server does not support fstatvfs@openssh.com extension"); 889 return -1; 890 } 891 892 id = conn->msg_id++; 893 894 buffer_init(&msg); 895 buffer_clear(&msg); 896 buffer_put_char(&msg, SSH2_FXP_EXTENDED); 897 buffer_put_int(&msg, id); 898 buffer_put_cstring(&msg, "fstatvfs@openssh.com"); 899 buffer_put_string(&msg, handle, handle_len); 900 send_msg(conn->fd_out, &msg); 901 buffer_free(&msg); 902 903 return get_decode_statvfs(conn->fd_in, st, id, quiet); 904 } 905 #endif 906 907 static void 908 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, 909 char *handle, u_int handle_len) 910 { 911 Buffer msg; 912 913 buffer_init(&msg); 914 buffer_clear(&msg); 915 buffer_put_char(&msg, SSH2_FXP_READ); 916 buffer_put_int(&msg, id); 917 buffer_put_string(&msg, handle, handle_len); 918 buffer_put_int64(&msg, offset); 919 buffer_put_int(&msg, len); 920 send_msg(fd_out, &msg); 921 buffer_free(&msg); 922 } 923 924 int 925 do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 926 Attrib *a, int pflag) 927 { 928 Attrib junk; 929 Buffer msg; 930 char *handle; 931 int local_fd, status = 0, write_error; 932 int read_error, write_errno; 933 u_int64_t offset, size; 934 u_int handle_len, mode, type, id, buflen, num_req, max_req; 935 off_t progress_counter; 936 struct request { 937 u_int id; 938 u_int len; 939 u_int64_t offset; 940 TAILQ_ENTRY(request) tq; 941 }; 942 TAILQ_HEAD(reqhead, request) requests; 943 struct request *req; 944 945 TAILQ_INIT(&requests); 946 947 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 948 return -1; 949 950 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 951 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 952 mode = a->perm & 0777; 953 else 954 mode = 0666; 955 956 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 957 (!S_ISREG(a->perm))) { 958 error("Cannot download non-regular file: %s", remote_path); 959 return(-1); 960 } 961 962 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 963 size = a->size; 964 else 965 size = 0; 966 967 buflen = conn->transfer_buflen; 968 buffer_init(&msg); 969 970 /* Send open request */ 971 id = conn->msg_id++; 972 buffer_put_char(&msg, SSH2_FXP_OPEN); 973 buffer_put_int(&msg, id); 974 buffer_put_cstring(&msg, remote_path); 975 buffer_put_int(&msg, SSH2_FXF_READ); 976 attrib_clear(&junk); /* Send empty attributes */ 977 encode_attrib(&msg, &junk); 978 send_msg(conn->fd_out, &msg); 979 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 980 981 handle = get_handle(conn->fd_in, id, &handle_len, 982 "remote open(\"%s\")", remote_path); 983 if (handle == NULL) { 984 buffer_free(&msg); 985 return(-1); 986 } 987 988 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 989 mode | S_IWRITE); 990 if (local_fd == -1) { 991 error("Couldn't open local file \"%s\" for writing: %s", 992 local_path, strerror(errno)); 993 do_close(conn, handle, handle_len); 994 buffer_free(&msg); 995 xfree(handle); 996 return(-1); 997 } 998 999 /* Read from remote and write to local */ 1000 write_error = read_error = write_errno = num_req = offset = 0; 1001 max_req = 1; 1002 progress_counter = 0; 1003 1004 if (showprogress && size != 0) 1005 start_progress_meter(remote_path, size, &progress_counter); 1006 1007 while (num_req > 0 || max_req > 0) { 1008 char *data; 1009 u_int len; 1010 1011 /* 1012 * Simulate EOF on interrupt: stop sending new requests and 1013 * allow outstanding requests to drain gracefully 1014 */ 1015 if (interrupted) { 1016 if (num_req == 0) /* If we haven't started yet... */ 1017 break; 1018 max_req = 0; 1019 } 1020 1021 /* Send some more requests */ 1022 while (num_req < max_req) { 1023 debug3("Request range %llu -> %llu (%d/%d)", 1024 (unsigned long long)offset, 1025 (unsigned long long)offset + buflen - 1, 1026 num_req, max_req); 1027 req = xmalloc(sizeof(*req)); 1028 req->id = conn->msg_id++; 1029 req->len = buflen; 1030 req->offset = offset; 1031 offset += buflen; 1032 num_req++; 1033 TAILQ_INSERT_TAIL(&requests, req, tq); 1034 send_read_request(conn->fd_out, req->id, req->offset, 1035 req->len, handle, handle_len); 1036 } 1037 1038 buffer_clear(&msg); 1039 get_msg(conn->fd_in, &msg); 1040 type = buffer_get_char(&msg); 1041 id = buffer_get_int(&msg); 1042 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1043 1044 /* Find the request in our queue */ 1045 for (req = TAILQ_FIRST(&requests); 1046 req != NULL && req->id != id; 1047 req = TAILQ_NEXT(req, tq)) 1048 ; 1049 if (req == NULL) 1050 fatal("Unexpected reply %u", id); 1051 1052 switch (type) { 1053 case SSH2_FXP_STATUS: 1054 status = buffer_get_int(&msg); 1055 if (status != SSH2_FX_EOF) 1056 read_error = 1; 1057 max_req = 0; 1058 TAILQ_REMOVE(&requests, req, tq); 1059 xfree(req); 1060 num_req--; 1061 break; 1062 case SSH2_FXP_DATA: 1063 data = buffer_get_string(&msg, &len); 1064 debug3("Received data %llu -> %llu", 1065 (unsigned long long)req->offset, 1066 (unsigned long long)req->offset + len - 1); 1067 if (len > req->len) 1068 fatal("Received more data than asked for " 1069 "%u > %u", len, req->len); 1070 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1071 atomicio(vwrite, local_fd, data, len) != len) && 1072 !write_error) { 1073 write_errno = errno; 1074 write_error = 1; 1075 max_req = 0; 1076 } 1077 progress_counter += len; 1078 xfree(data); 1079 1080 if (len == req->len) { 1081 TAILQ_REMOVE(&requests, req, tq); 1082 xfree(req); 1083 num_req--; 1084 } else { 1085 /* Resend the request for the missing data */ 1086 debug3("Short data block, re-requesting " 1087 "%llu -> %llu (%2d)", 1088 (unsigned long long)req->offset + len, 1089 (unsigned long long)req->offset + 1090 req->len - 1, num_req); 1091 req->id = conn->msg_id++; 1092 req->len -= len; 1093 req->offset += len; 1094 send_read_request(conn->fd_out, req->id, 1095 req->offset, req->len, handle, handle_len); 1096 /* Reduce the request size */ 1097 if (len < buflen) 1098 buflen = MAX(MIN_READ_SIZE, len); 1099 } 1100 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1101 if (size > 0 && offset > size) { 1102 /* Only one request at a time 1103 * after the expected EOF */ 1104 debug3("Finish at %llu (%2d)", 1105 (unsigned long long)offset, 1106 num_req); 1107 max_req = 1; 1108 } else if (max_req <= conn->num_requests) { 1109 ++max_req; 1110 } 1111 } 1112 break; 1113 default: 1114 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1115 SSH2_FXP_DATA, type); 1116 } 1117 } 1118 1119 if (showprogress && size) 1120 stop_progress_meter(); 1121 1122 /* Sanity check */ 1123 if (TAILQ_FIRST(&requests) != NULL) 1124 fatal("Transfer complete, but requests still in queue"); 1125 1126 if (read_error) { 1127 error("Couldn't read from remote file \"%s\" : %s", 1128 remote_path, fx2txt(status)); 1129 do_close(conn, handle, handle_len); 1130 } else if (write_error) { 1131 error("Couldn't write to \"%s\": %s", local_path, 1132 strerror(write_errno)); 1133 status = -1; 1134 do_close(conn, handle, handle_len); 1135 } else { 1136 status = do_close(conn, handle, handle_len); 1137 1138 /* Override umask and utimes if asked */ 1139 #ifdef HAVE_FCHMOD 1140 if (pflag && fchmod(local_fd, mode) == -1) 1141 #else 1142 if (pflag && chmod(local_path, mode) == -1) 1143 #endif /* HAVE_FCHMOD */ 1144 error("Couldn't set mode on \"%s\": %s", local_path, 1145 strerror(errno)); 1146 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1147 struct timeval tv[2]; 1148 tv[0].tv_sec = a->atime; 1149 tv[1].tv_sec = a->mtime; 1150 tv[0].tv_usec = tv[1].tv_usec = 0; 1151 if (utimes(local_path, tv) == -1) 1152 error("Can't set times on \"%s\": %s", 1153 local_path, strerror(errno)); 1154 } 1155 } 1156 close(local_fd); 1157 buffer_free(&msg); 1158 xfree(handle); 1159 1160 return(status); 1161 } 1162 1163 static int 1164 download_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1165 Attrib *dirattrib, int pflag, int printflag, int depth) 1166 { 1167 int i, ret = 0; 1168 SFTP_DIRENT **dir_entries; 1169 char *filename, *new_src, *new_dst; 1170 mode_t mode = 0777; 1171 1172 if (depth >= MAX_DIR_DEPTH) { 1173 error("Maximum directory depth exceeded: %d levels", depth); 1174 return -1; 1175 } 1176 1177 if (dirattrib == NULL && 1178 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1179 error("Unable to stat remote directory \"%s\"", src); 1180 return -1; 1181 } 1182 if (!S_ISDIR(dirattrib->perm)) { 1183 error("\"%s\" is not a directory", src); 1184 return -1; 1185 } 1186 if (printflag) 1187 printf("Retrieving %s\n", src); 1188 1189 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1190 mode = dirattrib->perm & 01777; 1191 else { 1192 debug("Server did not send permissions for " 1193 "directory \"%s\"", dst); 1194 } 1195 1196 if (mkdir(dst, mode) == -1 && errno != EEXIST) { 1197 error("mkdir %s: %s", dst, strerror(errno)); 1198 return -1; 1199 } 1200 1201 if (do_readdir(conn, src, &dir_entries) == -1) { 1202 error("%s: Failed to get directory contents", src); 1203 return -1; 1204 } 1205 1206 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1207 filename = dir_entries[i]->filename; 1208 1209 new_dst = path_append(dst, filename); 1210 new_src = path_append(src, filename); 1211 1212 if (S_ISDIR(dir_entries[i]->a.perm)) { 1213 if (strcmp(filename, ".") == 0 || 1214 strcmp(filename, "..") == 0) 1215 continue; 1216 if (download_dir_internal(conn, new_src, new_dst, 1217 &(dir_entries[i]->a), pflag, printflag, 1218 depth + 1) == -1) 1219 ret = -1; 1220 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1221 if (do_download(conn, new_src, new_dst, 1222 &(dir_entries[i]->a), pflag) == -1) { 1223 error("Download of file %s to %s failed", 1224 new_src, new_dst); 1225 ret = -1; 1226 } 1227 } else 1228 logit("%s: not a regular file\n", new_src); 1229 1230 xfree(new_dst); 1231 xfree(new_src); 1232 } 1233 1234 if (pflag) { 1235 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1236 struct timeval tv[2]; 1237 tv[0].tv_sec = dirattrib->atime; 1238 tv[1].tv_sec = dirattrib->mtime; 1239 tv[0].tv_usec = tv[1].tv_usec = 0; 1240 if (utimes(dst, tv) == -1) 1241 error("Can't set times on \"%s\": %s", 1242 dst, strerror(errno)); 1243 } else 1244 debug("Server did not send times for directory " 1245 "\"%s\"", dst); 1246 } 1247 1248 free_sftp_dirents(dir_entries); 1249 1250 return ret; 1251 } 1252 1253 int 1254 download_dir(struct sftp_conn *conn, char *src, char *dst, 1255 Attrib *dirattrib, int pflag, int printflag) 1256 { 1257 char *src_canon; 1258 int ret; 1259 1260 if ((src_canon = do_realpath(conn, src)) == NULL) { 1261 error("Unable to canonicalise path \"%s\"", src); 1262 return -1; 1263 } 1264 1265 ret = download_dir_internal(conn, src_canon, dst, 1266 dirattrib, pflag, printflag, 0); 1267 xfree(src_canon); 1268 return ret; 1269 } 1270 1271 int 1272 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1273 int pflag) 1274 { 1275 int local_fd; 1276 int status = SSH2_FX_OK; 1277 u_int handle_len, id, type; 1278 off_t offset; 1279 char *handle, *data; 1280 Buffer msg; 1281 struct stat sb; 1282 Attrib a; 1283 u_int32_t startid; 1284 u_int32_t ackid; 1285 struct outstanding_ack { 1286 u_int id; 1287 u_int len; 1288 off_t offset; 1289 TAILQ_ENTRY(outstanding_ack) tq; 1290 }; 1291 TAILQ_HEAD(ackhead, outstanding_ack) acks; 1292 struct outstanding_ack *ack = NULL; 1293 1294 TAILQ_INIT(&acks); 1295 1296 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1297 error("Couldn't open local file \"%s\" for reading: %s", 1298 local_path, strerror(errno)); 1299 return(-1); 1300 } 1301 if (fstat(local_fd, &sb) == -1) { 1302 error("Couldn't fstat local file \"%s\": %s", 1303 local_path, strerror(errno)); 1304 close(local_fd); 1305 return(-1); 1306 } 1307 if (!S_ISREG(sb.st_mode)) { 1308 error("%s is not a regular file", local_path); 1309 close(local_fd); 1310 return(-1); 1311 } 1312 stat_to_attrib(&sb, &a); 1313 1314 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1315 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1316 a.perm &= 0777; 1317 if (!pflag) 1318 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1319 1320 buffer_init(&msg); 1321 1322 /* Send open request */ 1323 id = conn->msg_id++; 1324 buffer_put_char(&msg, SSH2_FXP_OPEN); 1325 buffer_put_int(&msg, id); 1326 buffer_put_cstring(&msg, remote_path); 1327 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1328 encode_attrib(&msg, &a); 1329 send_msg(conn->fd_out, &msg); 1330 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1331 1332 buffer_clear(&msg); 1333 1334 handle = get_handle(conn->fd_in, id, &handle_len, 1335 "remote open(\"%s\")", remote_path); 1336 if (handle == NULL) { 1337 close(local_fd); 1338 buffer_free(&msg); 1339 return -1; 1340 } 1341 1342 startid = ackid = id + 1; 1343 data = xmalloc(conn->transfer_buflen); 1344 1345 /* Read from local and write to remote */ 1346 offset = 0; 1347 if (showprogress) 1348 start_progress_meter(local_path, sb.st_size, &offset); 1349 1350 for (;;) { 1351 int len; 1352 1353 /* 1354 * Can't use atomicio here because it returns 0 on EOF, 1355 * thus losing the last block of the file. 1356 * Simulate an EOF on interrupt, allowing ACKs from the 1357 * server to drain. 1358 */ 1359 if (interrupted || status != SSH2_FX_OK) 1360 len = 0; 1361 else do 1362 len = read(local_fd, data, conn->transfer_buflen); 1363 while ((len == -1) && 1364 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); 1365 1366 if (len == -1) 1367 fatal("Couldn't read from \"%s\": %s", local_path, 1368 strerror(errno)); 1369 1370 if (len != 0) { 1371 ack = xmalloc(sizeof(*ack)); 1372 ack->id = ++id; 1373 ack->offset = offset; 1374 ack->len = len; 1375 TAILQ_INSERT_TAIL(&acks, ack, tq); 1376 1377 buffer_clear(&msg); 1378 buffer_put_char(&msg, SSH2_FXP_WRITE); 1379 buffer_put_int(&msg, ack->id); 1380 buffer_put_string(&msg, handle, handle_len); 1381 buffer_put_int64(&msg, offset); 1382 buffer_put_string(&msg, data, len); 1383 send_msg(conn->fd_out, &msg); 1384 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1385 id, (unsigned long long)offset, len); 1386 } else if (TAILQ_FIRST(&acks) == NULL) 1387 break; 1388 1389 if (ack == NULL) 1390 fatal("Unexpected ACK %u", id); 1391 1392 if (id == startid || len == 0 || 1393 id - ackid >= conn->num_requests) { 1394 u_int r_id; 1395 1396 buffer_clear(&msg); 1397 get_msg(conn->fd_in, &msg); 1398 type = buffer_get_char(&msg); 1399 r_id = buffer_get_int(&msg); 1400 1401 if (type != SSH2_FXP_STATUS) 1402 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1403 "got %d", SSH2_FXP_STATUS, type); 1404 1405 status = buffer_get_int(&msg); 1406 debug3("SSH2_FXP_STATUS %d", status); 1407 1408 /* Find the request in our queue */ 1409 for (ack = TAILQ_FIRST(&acks); 1410 ack != NULL && ack->id != r_id; 1411 ack = TAILQ_NEXT(ack, tq)) 1412 ; 1413 if (ack == NULL) 1414 fatal("Can't find request for ID %u", r_id); 1415 TAILQ_REMOVE(&acks, ack, tq); 1416 debug3("In write loop, ack for %u %u bytes at %lld", 1417 ack->id, ack->len, (long long)ack->offset); 1418 ++ackid; 1419 xfree(ack); 1420 } 1421 offset += len; 1422 if (offset < 0) 1423 fatal("%s: offset < 0", __func__); 1424 } 1425 buffer_free(&msg); 1426 1427 if (showprogress) 1428 stop_progress_meter(); 1429 xfree(data); 1430 1431 if (status != SSH2_FX_OK) { 1432 error("Couldn't write to remote file \"%s\": %s", 1433 remote_path, fx2txt(status)); 1434 status = -1; 1435 } 1436 1437 if (close(local_fd) == -1) { 1438 error("Couldn't close local file \"%s\": %s", local_path, 1439 strerror(errno)); 1440 status = -1; 1441 } 1442 1443 /* Override umask and utimes if asked */ 1444 if (pflag) 1445 do_fsetstat(conn, handle, handle_len, &a); 1446 1447 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1448 status = -1; 1449 xfree(handle); 1450 1451 return status; 1452 } 1453 1454 static int 1455 upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1456 int pflag, int printflag, int depth) 1457 { 1458 int ret = 0, status; 1459 DIR *dirp; 1460 struct dirent *dp; 1461 char *filename, *new_src, *new_dst; 1462 struct stat sb; 1463 Attrib a; 1464 1465 if (depth >= MAX_DIR_DEPTH) { 1466 error("Maximum directory depth exceeded: %d levels", depth); 1467 return -1; 1468 } 1469 1470 if (stat(src, &sb) == -1) { 1471 error("Couldn't stat directory \"%s\": %s", 1472 src, strerror(errno)); 1473 return -1; 1474 } 1475 if (!S_ISDIR(sb.st_mode)) { 1476 error("\"%s\" is not a directory", src); 1477 return -1; 1478 } 1479 if (printflag) 1480 printf("Entering %s\n", src); 1481 1482 attrib_clear(&a); 1483 stat_to_attrib(&sb, &a); 1484 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1485 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1486 a.perm &= 01777; 1487 if (!pflag) 1488 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1489 1490 status = do_mkdir(conn, dst, &a, 0); 1491 /* 1492 * we lack a portable status for errno EEXIST, 1493 * so if we get a SSH2_FX_FAILURE back we must check 1494 * if it was created successfully. 1495 */ 1496 if (status != SSH2_FX_OK) { 1497 if (status != SSH2_FX_FAILURE) 1498 return -1; 1499 if (do_stat(conn, dst, 0) == NULL) 1500 return -1; 1501 } 1502 1503 if ((dirp = opendir(src)) == NULL) { 1504 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1505 return -1; 1506 } 1507 1508 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1509 if (dp->d_ino == 0) 1510 continue; 1511 filename = dp->d_name; 1512 new_dst = path_append(dst, filename); 1513 new_src = path_append(src, filename); 1514 1515 if (lstat(new_src, &sb) == -1) { 1516 logit("%s: lstat failed: %s", filename, 1517 strerror(errno)); 1518 ret = -1; 1519 } else if (S_ISDIR(sb.st_mode)) { 1520 if (strcmp(filename, ".") == 0 || 1521 strcmp(filename, "..") == 0) 1522 continue; 1523 1524 if (upload_dir_internal(conn, new_src, new_dst, 1525 pflag, depth + 1, printflag) == -1) 1526 ret = -1; 1527 } else if (S_ISREG(sb.st_mode)) { 1528 if (do_upload(conn, new_src, new_dst, pflag) == -1) { 1529 error("Uploading of file %s to %s failed!", 1530 new_src, new_dst); 1531 ret = -1; 1532 } 1533 } else 1534 logit("%s: not a regular file\n", filename); 1535 xfree(new_dst); 1536 xfree(new_src); 1537 } 1538 1539 do_setstat(conn, dst, &a); 1540 1541 (void) closedir(dirp); 1542 return ret; 1543 } 1544 1545 int 1546 upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, 1547 int pflag) 1548 { 1549 char *dst_canon; 1550 int ret; 1551 1552 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1553 error("Unable to canonicalise path \"%s\"", dst); 1554 return -1; 1555 } 1556 1557 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); 1558 xfree(dst_canon); 1559 return ret; 1560 } 1561 1562 char * 1563 path_append(char *p1, char *p2) 1564 { 1565 char *ret; 1566 size_t len = strlen(p1) + strlen(p2) + 2; 1567 1568 ret = xmalloc(len); 1569 strlcpy(ret, p1, len); 1570 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 1571 strlcat(ret, "/", len); 1572 strlcat(ret, p2, len); 1573 1574 return(ret); 1575 } 1576 1577