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