1 /* $NetBSD: sftp-client.c,v 1.26 2021/03/05 17:47:16 christos Exp $ */ 2 /* $OpenBSD: sftp-client.c,v 1.139 2020/12/04 02:41:10 djm Exp $ */ 3 4 /* 5 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* XXX: memleaks */ 21 /* XXX: signed vs unsigned */ 22 /* XXX: remove all logging, only return status codes */ 23 /* XXX: copy between two remote sites */ 24 25 #include "includes.h" 26 __RCSID("$NetBSD: sftp-client.c,v 1.26 2021/03/05 17:47:16 christos Exp $"); 27 28 #include <sys/param.h> /* MIN MAX */ 29 #include <sys/types.h> 30 #include <sys/poll.h> 31 #include <sys/queue.h> 32 #include <sys/stat.h> 33 #include <sys/time.h> 34 #include <sys/statvfs.h> 35 #include <sys/uio.h> 36 37 #include <dirent.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <signal.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "xmalloc.h" 48 #include "ssherr.h" 49 #include "sshbuf.h" 50 #include "log.h" 51 #include "atomicio.h" 52 #include "progressmeter.h" 53 #include "misc.h" 54 #include "utf8.h" 55 56 #include "sftp.h" 57 #include "sftp-common.h" 58 #include "sftp-client.h" 59 60 extern volatile sig_atomic_t interrupted; 61 extern int showprogress; 62 63 /* Minimum amount of data to read at a time */ 64 #define MIN_READ_SIZE 512 65 66 /* Maximum depth to descend in directory trees */ 67 #define MAX_DIR_DEPTH 64 68 69 struct sftp_conn { 70 int fd_in; 71 int fd_out; 72 u_int transfer_buflen; 73 u_int num_requests; 74 u_int version; 75 u_int msg_id; 76 #define SFTP_EXT_POSIX_RENAME 0x00000001 77 #define SFTP_EXT_STATVFS 0x00000002 78 #define SFTP_EXT_FSTATVFS 0x00000004 79 #define SFTP_EXT_HARDLINK 0x00000008 80 #define SFTP_EXT_FSYNC 0x00000010 81 #define SFTP_EXT_LSETSTAT 0x00000020 82 u_int exts; 83 u_int64_t limit_kbps; 84 struct bwlimit bwlimit_in, bwlimit_out; 85 }; 86 87 static u_char * 88 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 89 const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 90 91 /* ARGSUSED */ 92 static int 93 sftpio(void *_bwlimit, size_t amount) 94 { 95 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 96 97 refresh_progress_meter(0); 98 if (bwlimit != NULL) 99 bandwidth_limit(bwlimit, amount); 100 return 0; 101 } 102 103 static void 104 send_msg(struct sftp_conn *conn, struct sshbuf *m) 105 { 106 u_char mlen[4]; 107 struct iovec iov[2]; 108 109 if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH) 110 fatal("Outbound message too long %zu", sshbuf_len(m)); 111 112 /* Send length first */ 113 put_u32(mlen, sshbuf_len(m)); 114 iov[0].iov_base = mlen; 115 iov[0].iov_len = sizeof(mlen); 116 iov[1].iov_base = __UNCONST(sshbuf_ptr(m)); 117 iov[1].iov_len = sshbuf_len(m); 118 119 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio, 120 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) != 121 sshbuf_len(m) + sizeof(mlen)) 122 fatal("Couldn't send packet: %s", strerror(errno)); 123 124 sshbuf_reset(m); 125 } 126 127 static void 128 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial) 129 { 130 u_int msg_len; 131 u_char *p; 132 int r; 133 134 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 135 fatal_fr(r, "reserve"); 136 if (atomicio6(read, conn->fd_in, p, 4, sftpio, 137 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) { 138 if (errno == EPIPE || errno == ECONNRESET) 139 fatal("Connection closed"); 140 else 141 fatal("Couldn't read packet: %s", strerror(errno)); 142 } 143 144 if ((r = sshbuf_get_u32(m, &msg_len)) != 0) 145 fatal_fr(r, "sshbuf_get_u32"); 146 if (msg_len > SFTP_MAX_MSG_LENGTH) { 147 do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL, 148 "Received message too long %u", msg_len); 149 fatal("Ensure the remote shell produces no output " 150 "for non-interactive sessions."); 151 } 152 153 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 154 fatal_fr(r, "reserve"); 155 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio, 156 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) 157 != msg_len) { 158 if (errno == EPIPE) 159 fatal("Connection closed"); 160 else 161 fatal("Read packet: %s", strerror(errno)); 162 } 163 } 164 165 static void 166 get_msg(struct sftp_conn *conn, struct sshbuf *m) 167 { 168 get_msg_extended(conn, m, 0); 169 } 170 171 static void 172 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, 173 u_int len) 174 { 175 struct sshbuf *msg; 176 int r; 177 178 if ((msg = sshbuf_new()) == NULL) 179 fatal_f("sshbuf_new failed"); 180 if ((r = sshbuf_put_u8(msg, code)) != 0 || 181 (r = sshbuf_put_u32(msg, id)) != 0 || 182 (r = sshbuf_put_string(msg, s, len)) != 0) 183 fatal_fr(r, "compose"); 184 send_msg(conn, msg); 185 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 186 sshbuf_free(msg); 187 } 188 189 static void 190 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 191 const void *s, u_int len, Attrib *a) 192 { 193 struct sshbuf *msg; 194 int r; 195 196 if ((msg = sshbuf_new()) == NULL) 197 fatal_f("sshbuf_new failed"); 198 if ((r = sshbuf_put_u8(msg, code)) != 0 || 199 (r = sshbuf_put_u32(msg, id)) != 0 || 200 (r = sshbuf_put_string(msg, s, len)) != 0 || 201 (r = encode_attrib(msg, a)) != 0) 202 fatal_fr(r, "compose"); 203 send_msg(conn, msg); 204 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 205 sshbuf_free(msg); 206 } 207 208 static u_int 209 get_status(struct sftp_conn *conn, u_int expected_id) 210 { 211 struct sshbuf *msg; 212 u_char type; 213 u_int id, status; 214 int r; 215 216 if ((msg = sshbuf_new()) == NULL) 217 fatal_f("sshbuf_new failed"); 218 get_msg(conn, msg); 219 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 220 (r = sshbuf_get_u32(msg, &id)) != 0) 221 fatal_fr(r, "compose"); 222 223 if (id != expected_id) 224 fatal("ID mismatch (%u != %u)", id, expected_id); 225 if (type != SSH2_FXP_STATUS) 226 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 227 SSH2_FXP_STATUS, type); 228 229 if ((r = sshbuf_get_u32(msg, &status)) != 0) 230 fatal_fr(r, "parse"); 231 sshbuf_free(msg); 232 233 debug3("SSH2_FXP_STATUS %u", status); 234 235 return status; 236 } 237 238 static u_char * 239 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 240 const char *errfmt, ...) 241 { 242 struct sshbuf *msg; 243 u_int id, status; 244 u_char type; 245 u_char *handle; 246 char errmsg[256]; 247 va_list args; 248 int r; 249 250 va_start(args, errfmt); 251 if (errfmt != NULL) 252 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 253 va_end(args); 254 255 if ((msg = sshbuf_new()) == NULL) 256 fatal_f("sshbuf_new failed"); 257 get_msg(conn, msg); 258 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 259 (r = sshbuf_get_u32(msg, &id)) != 0) 260 fatal_fr(r, "parse"); 261 262 if (id != expected_id) 263 fatal("%s: ID mismatch (%u != %u)", 264 errfmt == NULL ? __func__ : errmsg, id, expected_id); 265 if (type == SSH2_FXP_STATUS) { 266 if ((r = sshbuf_get_u32(msg, &status)) != 0) 267 fatal_fr(r, "parse status"); 268 if (errfmt != NULL) 269 error("%s: %s", errmsg, fx2txt(status)); 270 sshbuf_free(msg); 271 return(NULL); 272 } else if (type != SSH2_FXP_HANDLE) 273 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 274 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 275 276 if ((r = sshbuf_get_string(msg, &handle, len)) != 0) 277 fatal_fr(r, "parse handle"); 278 sshbuf_free(msg); 279 280 return handle; 281 } 282 283 static Attrib * 284 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 285 { 286 struct sshbuf *msg; 287 u_int id; 288 u_char type; 289 int r; 290 static Attrib a; 291 292 if ((msg = sshbuf_new()) == NULL) 293 fatal_f("sshbuf_new failed"); 294 get_msg(conn, msg); 295 296 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 297 (r = sshbuf_get_u32(msg, &id)) != 0) 298 fatal_fr(r, "parse"); 299 300 debug3("Received stat reply T:%u I:%u", type, id); 301 if (id != expected_id) 302 fatal("ID mismatch (%u != %u)", id, expected_id); 303 if (type == SSH2_FXP_STATUS) { 304 u_int status; 305 306 if ((r = sshbuf_get_u32(msg, &status)) != 0) 307 fatal_fr(r, "parse status"); 308 if (quiet) 309 debug("Couldn't stat remote file: %s", fx2txt(status)); 310 else 311 error("Couldn't stat remote file: %s", fx2txt(status)); 312 sshbuf_free(msg); 313 return(NULL); 314 } else if (type != SSH2_FXP_ATTRS) { 315 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 316 SSH2_FXP_ATTRS, type); 317 } 318 if ((r = decode_attrib(msg, &a)) != 0) { 319 error_fr(r, "decode_attrib"); 320 sshbuf_free(msg); 321 return NULL; 322 } 323 sshbuf_free(msg); 324 325 return &a; 326 } 327 328 static int 329 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 330 u_int expected_id, int quiet) 331 { 332 struct sshbuf *msg; 333 u_char type; 334 u_int id; 335 u_int64_t flag; 336 int r; 337 338 if ((msg = sshbuf_new()) == NULL) 339 fatal_f("sshbuf_new failed"); 340 get_msg(conn, msg); 341 342 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 343 (r = sshbuf_get_u32(msg, &id)) != 0) 344 fatal_fr(r, "parse"); 345 346 debug3("Received statvfs reply T:%u I:%u", type, id); 347 if (id != expected_id) 348 fatal("ID mismatch (%u != %u)", id, expected_id); 349 if (type == SSH2_FXP_STATUS) { 350 u_int status; 351 352 if ((r = sshbuf_get_u32(msg, &status)) != 0) 353 fatal_fr(r, "parse status"); 354 if (quiet) 355 debug("Couldn't statvfs: %s", fx2txt(status)); 356 else 357 error("Couldn't statvfs: %s", fx2txt(status)); 358 sshbuf_free(msg); 359 return -1; 360 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 361 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 362 SSH2_FXP_EXTENDED_REPLY, type); 363 } 364 365 memset(st, 0, sizeof(*st)); 366 if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 || 367 (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 || 368 (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 || 369 (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 || 370 (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 || 371 (r = sshbuf_get_u64(msg, &st->f_files)) != 0 || 372 (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 || 373 (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 || 374 (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 || 375 (r = sshbuf_get_u64(msg, &flag)) != 0 || 376 (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0) 377 fatal_fr(r, "parse statvfs"); 378 379 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 380 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 381 382 sshbuf_free(msg); 383 384 return 0; 385 } 386 387 struct sftp_conn * 388 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 389 u_int64_t limit_kbps) 390 { 391 u_char type; 392 struct sshbuf *msg; 393 struct sftp_conn *ret; 394 int r; 395 396 ret = xcalloc(1, sizeof(*ret)); 397 ret->msg_id = 1; 398 ret->fd_in = fd_in; 399 ret->fd_out = fd_out; 400 ret->transfer_buflen = transfer_buflen; 401 ret->num_requests = num_requests; 402 ret->exts = 0; 403 ret->limit_kbps = 0; 404 405 if ((msg = sshbuf_new()) == NULL) 406 fatal_f("sshbuf_new failed"); 407 if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 || 408 (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0) 409 fatal_fr(r, "parse"); 410 411 send_msg(ret, msg); 412 413 sshbuf_reset(msg); 414 415 get_msg_extended(ret, msg, 1); 416 417 /* Expecting a VERSION reply */ 418 if ((r = sshbuf_get_u8(msg, &type)) != 0) 419 fatal_fr(r, "parse type"); 420 if (type != SSH2_FXP_VERSION) { 421 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 422 type); 423 sshbuf_free(msg); 424 free(ret); 425 return(NULL); 426 } 427 if ((r = sshbuf_get_u32(msg, &ret->version)) != 0) 428 fatal_fr(r, "parse version"); 429 430 debug2("Remote version: %u", ret->version); 431 432 /* Check for extensions */ 433 while (sshbuf_len(msg) > 0) { 434 char *name; 435 u_char *value; 436 size_t vlen; 437 int known = 0; 438 439 if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 || 440 (r = sshbuf_get_string(msg, &value, &vlen)) != 0) 441 fatal_fr(r, "parse extension"); 442 if (strcmp(name, "posix-rename@openssh.com") == 0 && 443 strcmp((char *)value, "1") == 0) { 444 ret->exts |= SFTP_EXT_POSIX_RENAME; 445 known = 1; 446 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 447 strcmp((char *)value, "2") == 0) { 448 ret->exts |= SFTP_EXT_STATVFS; 449 known = 1; 450 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 451 strcmp((char *)value, "2") == 0) { 452 ret->exts |= SFTP_EXT_FSTATVFS; 453 known = 1; 454 } else if (strcmp(name, "hardlink@openssh.com") == 0 && 455 strcmp((char *)value, "1") == 0) { 456 ret->exts |= SFTP_EXT_HARDLINK; 457 known = 1; 458 } else if (strcmp(name, "fsync@openssh.com") == 0 && 459 strcmp((char *)value, "1") == 0) { 460 ret->exts |= SFTP_EXT_FSYNC; 461 known = 1; 462 } else if (strcmp(name, "lsetstat@openssh.com") == 0 && 463 strcmp((char *)value, "1") == 0) { 464 ret->exts |= SFTP_EXT_LSETSTAT; 465 known = 1; 466 } 467 if (known) { 468 debug2("Server supports extension \"%s\" revision %s", 469 name, value); 470 } else { 471 debug2("Unrecognised server extension \"%s\"", name); 472 } 473 free(name); 474 free(value); 475 } 476 477 sshbuf_free(msg); 478 479 /* Some filexfer v.0 servers don't support large packets */ 480 if (ret->version == 0) 481 ret->transfer_buflen = MINIMUM(ret->transfer_buflen, 20480); 482 483 ret->limit_kbps = limit_kbps; 484 if (ret->limit_kbps > 0) { 485 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 486 ret->transfer_buflen); 487 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 488 ret->transfer_buflen); 489 } 490 491 return ret; 492 } 493 494 u_int 495 sftp_proto_version(struct sftp_conn *conn) 496 { 497 return conn->version; 498 } 499 500 int 501 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) 502 { 503 u_int id, status; 504 struct sshbuf *msg; 505 int r; 506 507 if ((msg = sshbuf_new()) == NULL) 508 fatal_f("sshbuf_new failed"); 509 510 id = conn->msg_id++; 511 if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 || 512 (r = sshbuf_put_u32(msg, id)) != 0 || 513 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 514 fatal_fr(r, "parse"); 515 send_msg(conn, msg); 516 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 517 518 status = get_status(conn, id); 519 if (status != SSH2_FX_OK) 520 error("Couldn't close file: %s", fx2txt(status)); 521 522 sshbuf_free(msg); 523 524 return status == SSH2_FX_OK ? 0 : -1; 525 } 526 527 528 static int 529 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, 530 SFTP_DIRENT ***dir) 531 { 532 struct sshbuf *msg; 533 u_int count, id, i, expected_id, ents = 0; 534 size_t handle_len; 535 u_char type, *handle; 536 int status = SSH2_FX_FAILURE; 537 int r; 538 539 if (dir) 540 *dir = NULL; 541 542 id = conn->msg_id++; 543 544 if ((msg = sshbuf_new()) == NULL) 545 fatal_f("sshbuf_new failed"); 546 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 || 547 (r = sshbuf_put_u32(msg, id)) != 0 || 548 (r = sshbuf_put_cstring(msg, path)) != 0) 549 fatal_fr(r, "compose OPENDIR"); 550 send_msg(conn, msg); 551 552 handle = get_handle(conn, id, &handle_len, 553 "remote readdir(\"%s\")", path); 554 if (handle == NULL) { 555 sshbuf_free(msg); 556 return -1; 557 } 558 559 if (dir) { 560 ents = 0; 561 *dir = xcalloc(1, sizeof(**dir)); 562 (*dir)[0] = NULL; 563 } 564 565 for (; !interrupted;) { 566 id = expected_id = conn->msg_id++; 567 568 debug3("Sending SSH2_FXP_READDIR I:%u", id); 569 570 sshbuf_reset(msg); 571 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 || 572 (r = sshbuf_put_u32(msg, id)) != 0 || 573 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 574 fatal_fr(r, "compose READDIR"); 575 send_msg(conn, msg); 576 577 sshbuf_reset(msg); 578 579 get_msg(conn, msg); 580 581 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 582 (r = sshbuf_get_u32(msg, &id)) != 0) 583 fatal_fr(r, "parse"); 584 585 debug3("Received reply T:%u I:%u", type, id); 586 587 if (id != expected_id) 588 fatal("ID mismatch (%u != %u)", id, expected_id); 589 590 if (type == SSH2_FXP_STATUS) { 591 u_int rstatus; 592 593 if ((r = sshbuf_get_u32(msg, &rstatus)) != 0) 594 fatal_fr(r, "parse status"); 595 debug3("Received SSH2_FXP_STATUS %d", rstatus); 596 if (rstatus == SSH2_FX_EOF) 597 break; 598 error("Couldn't read directory: %s", fx2txt(rstatus)); 599 goto out; 600 } else if (type != SSH2_FXP_NAME) 601 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 602 SSH2_FXP_NAME, type); 603 604 if ((r = sshbuf_get_u32(msg, &count)) != 0) 605 fatal_fr(r, "parse count"); 606 if (count > SSHBUF_SIZE_MAX) 607 fatal_f("nonsensical number of entries"); 608 if (count == 0) 609 break; 610 debug3("Received %d SSH2_FXP_NAME responses", count); 611 for (i = 0; i < count; i++) { 612 char *filename, *longname; 613 Attrib a; 614 615 if ((r = sshbuf_get_cstring(msg, &filename, 616 NULL)) != 0 || 617 (r = sshbuf_get_cstring(msg, &longname, 618 NULL)) != 0) 619 fatal_fr(r, "parse filenames"); 620 if ((r = decode_attrib(msg, &a)) != 0) { 621 error_fr(r, "couldn't decode attrib"); 622 free(filename); 623 free(longname); 624 goto out; 625 } 626 627 if (print_flag) 628 mprintf("%s\n", longname); 629 630 /* 631 * Directory entries should never contain '/' 632 * These can be used to attack recursive ops 633 * (e.g. send '../../../../etc/passwd') 634 */ 635 if (strchr(filename, '/') != NULL) { 636 error("Server sent suspect path \"%s\" " 637 "during readdir of \"%s\"", filename, path); 638 } else if (dir) { 639 *dir = xreallocarray(*dir, ents + 2, sizeof(**dir)); 640 (*dir)[ents] = xcalloc(1, sizeof(***dir)); 641 (*dir)[ents]->filename = xstrdup(filename); 642 (*dir)[ents]->longname = xstrdup(longname); 643 memcpy(&(*dir)[ents]->a, &a, sizeof(a)); 644 (*dir)[++ents] = NULL; 645 } 646 free(filename); 647 free(longname); 648 } 649 } 650 status = 0; 651 652 out: 653 sshbuf_free(msg); 654 do_close(conn, handle, handle_len); 655 free(handle); 656 657 if (status != 0 && dir != NULL) { 658 /* Don't return results on error */ 659 free_sftp_dirents(*dir); 660 *dir = NULL; 661 } else if (interrupted && dir != NULL && *dir != NULL) { 662 /* Don't return partial matches on interrupt */ 663 free_sftp_dirents(*dir); 664 *dir = xcalloc(1, sizeof(**dir)); 665 **dir = NULL; 666 } 667 668 return status == SSH2_FX_OK ? 0 : -1; 669 } 670 671 int 672 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) 673 { 674 return(do_lsreaddir(conn, path, 0, dir)); 675 } 676 677 void free_sftp_dirents(SFTP_DIRENT **s) 678 { 679 int i; 680 681 if (s == NULL) 682 return; 683 for (i = 0; s[i]; i++) { 684 free(s[i]->filename); 685 free(s[i]->longname); 686 free(s[i]); 687 } 688 free(s); 689 } 690 691 int 692 do_rm(struct sftp_conn *conn, const char *path) 693 { 694 u_int status, id; 695 696 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 697 698 id = conn->msg_id++; 699 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 700 status = get_status(conn, id); 701 if (status != SSH2_FX_OK) 702 error("Couldn't delete file: %s", fx2txt(status)); 703 return status == SSH2_FX_OK ? 0 : -1; 704 } 705 706 int 707 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) 708 { 709 u_int status, id; 710 711 id = conn->msg_id++; 712 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 713 strlen(path), a); 714 715 status = get_status(conn, id); 716 if (status != SSH2_FX_OK && print_flag) 717 error("Couldn't create directory: %s", fx2txt(status)); 718 719 return status == SSH2_FX_OK ? 0 : -1; 720 } 721 722 int 723 do_rmdir(struct sftp_conn *conn, const char *path) 724 { 725 u_int status, id; 726 727 id = conn->msg_id++; 728 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 729 strlen(path)); 730 731 status = get_status(conn, id); 732 if (status != SSH2_FX_OK) 733 error("Couldn't remove directory: %s", fx2txt(status)); 734 735 return status == SSH2_FX_OK ? 0 : -1; 736 } 737 738 Attrib * 739 do_stat(struct sftp_conn *conn, const char *path, int quiet) 740 { 741 u_int id; 742 743 id = conn->msg_id++; 744 745 send_string_request(conn, id, 746 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 747 path, strlen(path)); 748 749 return(get_decode_stat(conn, id, quiet)); 750 } 751 752 Attrib * 753 do_lstat(struct sftp_conn *conn, const char *path, int quiet) 754 { 755 u_int id; 756 757 if (conn->version == 0) { 758 if (quiet) 759 debug("Server version does not support lstat operation"); 760 else 761 logit("Server version does not support lstat operation"); 762 return(do_stat(conn, path, quiet)); 763 } 764 765 id = conn->msg_id++; 766 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 767 strlen(path)); 768 769 return(get_decode_stat(conn, id, quiet)); 770 } 771 772 #ifdef notyet 773 Attrib * 774 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 775 int quiet) 776 { 777 u_int id; 778 779 id = conn->msg_id++; 780 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 781 handle_len); 782 783 return(get_decode_stat(conn, id, quiet)); 784 } 785 #endif 786 787 int 788 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) 789 { 790 u_int status, id; 791 792 id = conn->msg_id++; 793 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 794 strlen(path), a); 795 796 status = get_status(conn, id); 797 if (status != SSH2_FX_OK) 798 error("Couldn't setstat on \"%s\": %s", path, 799 fx2txt(status)); 800 801 return status == SSH2_FX_OK ? 0 : -1; 802 } 803 804 int 805 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 806 Attrib *a) 807 { 808 u_int status, id; 809 810 id = conn->msg_id++; 811 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 812 handle_len, a); 813 814 status = get_status(conn, id); 815 if (status != SSH2_FX_OK) 816 error("Couldn't fsetstat: %s", fx2txt(status)); 817 818 return status == SSH2_FX_OK ? 0 : -1; 819 } 820 821 char * 822 do_realpath(struct sftp_conn *conn, const char *path) 823 { 824 struct sshbuf *msg; 825 u_int expected_id, count, id; 826 char *filename, *longname; 827 Attrib a; 828 u_char type; 829 int r; 830 831 expected_id = id = conn->msg_id++; 832 send_string_request(conn, id, SSH2_FXP_REALPATH, path, 833 strlen(path)); 834 835 if ((msg = sshbuf_new()) == NULL) 836 fatal_f("sshbuf_new failed"); 837 838 get_msg(conn, msg); 839 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 840 (r = sshbuf_get_u32(msg, &id)) != 0) 841 fatal_fr(r, "parse"); 842 843 if (id != expected_id) 844 fatal("ID mismatch (%u != %u)", id, expected_id); 845 846 if (type == SSH2_FXP_STATUS) { 847 u_int status; 848 849 if ((r = sshbuf_get_u32(msg, &status)) != 0) 850 fatal_fr(r, "parse status"); 851 error("Couldn't canonicalize: %s", fx2txt(status)); 852 sshbuf_free(msg); 853 return NULL; 854 } else if (type != SSH2_FXP_NAME) 855 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 856 SSH2_FXP_NAME, type); 857 858 if ((r = sshbuf_get_u32(msg, &count)) != 0) 859 fatal_fr(r, "parse count"); 860 if (count != 1) 861 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 862 863 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 864 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 865 (r = decode_attrib(msg, &a)) != 0) 866 fatal_fr(r, "parse filename/attrib"); 867 868 debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename, 869 (unsigned long)a.size); 870 871 free(longname); 872 873 sshbuf_free(msg); 874 875 return(filename); 876 } 877 878 int 879 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, 880 int force_legacy) 881 { 882 struct sshbuf *msg; 883 u_int status, id; 884 int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; 885 886 if ((msg = sshbuf_new()) == NULL) 887 fatal_f("sshbuf_new failed"); 888 889 /* Send rename request */ 890 id = conn->msg_id++; 891 if (use_ext) { 892 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 893 (r = sshbuf_put_u32(msg, id)) != 0 || 894 (r = sshbuf_put_cstring(msg, 895 "posix-rename@openssh.com")) != 0) 896 fatal_fr(r, "compose posix-rename"); 897 } else { 898 if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 || 899 (r = sshbuf_put_u32(msg, id)) != 0) 900 fatal_fr(r, "compose rename"); 901 } 902 if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 || 903 (r = sshbuf_put_cstring(msg, newpath)) != 0) 904 fatal_fr(r, "compose paths"); 905 send_msg(conn, msg); 906 debug3("Sent message %s \"%s\" -> \"%s\"", 907 use_ext ? "posix-rename@openssh.com" : 908 "SSH2_FXP_RENAME", oldpath, newpath); 909 sshbuf_free(msg); 910 911 status = get_status(conn, id); 912 if (status != SSH2_FX_OK) 913 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 914 newpath, fx2txt(status)); 915 916 return status == SSH2_FX_OK ? 0 : -1; 917 } 918 919 int 920 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 921 { 922 struct sshbuf *msg; 923 u_int status, id; 924 int r; 925 926 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 927 error("Server does not support hardlink@openssh.com extension"); 928 return -1; 929 } 930 931 if ((msg = sshbuf_new()) == NULL) 932 fatal_f("sshbuf_new failed"); 933 934 /* Send link request */ 935 id = conn->msg_id++; 936 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 937 (r = sshbuf_put_u32(msg, id)) != 0 || 938 (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || 939 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 940 (r = sshbuf_put_cstring(msg, newpath)) != 0) 941 fatal_fr(r, "compose"); 942 send_msg(conn, msg); 943 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 944 oldpath, newpath); 945 sshbuf_free(msg); 946 947 status = get_status(conn, id); 948 if (status != SSH2_FX_OK) 949 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 950 newpath, fx2txt(status)); 951 952 return status == SSH2_FX_OK ? 0 : -1; 953 } 954 955 int 956 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 957 { 958 struct sshbuf *msg; 959 u_int status, id; 960 int r; 961 962 if (conn->version < 3) { 963 error("This server does not support the symlink operation"); 964 return(SSH2_FX_OP_UNSUPPORTED); 965 } 966 967 if ((msg = sshbuf_new()) == NULL) 968 fatal_f("sshbuf_new failed"); 969 970 /* Send symlink request */ 971 id = conn->msg_id++; 972 if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 || 973 (r = sshbuf_put_u32(msg, id)) != 0 || 974 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 975 (r = sshbuf_put_cstring(msg, newpath)) != 0) 976 fatal_fr(r, "compose"); 977 send_msg(conn, msg); 978 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 979 newpath); 980 sshbuf_free(msg); 981 982 status = get_status(conn, id); 983 if (status != SSH2_FX_OK) 984 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 985 newpath, fx2txt(status)); 986 987 return status == SSH2_FX_OK ? 0 : -1; 988 } 989 990 int 991 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) 992 { 993 struct sshbuf *msg; 994 u_int status, id; 995 int r; 996 997 /* Silently return if the extension is not supported */ 998 if ((conn->exts & SFTP_EXT_FSYNC) == 0) 999 return -1; 1000 1001 /* Send fsync request */ 1002 if ((msg = sshbuf_new()) == NULL) 1003 fatal_f("sshbuf_new failed"); 1004 id = conn->msg_id++; 1005 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1006 (r = sshbuf_put_u32(msg, id)) != 0 || 1007 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || 1008 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1009 fatal_fr(r, "compose"); 1010 send_msg(conn, msg); 1011 debug3("Sent message fsync@openssh.com I:%u", id); 1012 sshbuf_free(msg); 1013 1014 status = get_status(conn, id); 1015 if (status != SSH2_FX_OK) 1016 error("Couldn't sync file: %s", fx2txt(status)); 1017 1018 return status == SSH2_FX_OK ? 0 : -1; 1019 } 1020 1021 #ifdef notyet 1022 char * 1023 do_readlink(struct sftp_conn *conn, const char *path) 1024 { 1025 struct sshbuf *msg; 1026 u_int expected_id, count, id; 1027 char *filename, *longname; 1028 Attrib a; 1029 u_char type; 1030 int r; 1031 1032 expected_id = id = conn->msg_id++; 1033 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 1034 1035 if ((msg = sshbuf_new()) == NULL) 1036 fatal_f("sshbuf_new failed"); 1037 1038 get_msg(conn, msg); 1039 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1040 (r = sshbuf_get_u32(msg, &id)) != 0) 1041 fatal_fr(r, "parse"); 1042 1043 if (id != expected_id) 1044 fatal("ID mismatch (%u != %u)", id, expected_id); 1045 1046 if (type == SSH2_FXP_STATUS) { 1047 u_int status; 1048 1049 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1050 fatal_fr(r, "parse status"); 1051 error("Couldn't readlink: %s", fx2txt(status)); 1052 sshbuf_free(msg); 1053 return(NULL); 1054 } else if (type != SSH2_FXP_NAME) 1055 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1056 SSH2_FXP_NAME, type); 1057 1058 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1059 fatal_fr(r, "parse count"); 1060 if (count != 1) 1061 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 1062 1063 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1064 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1065 (r = decode_attrib(msg, &a)) != 0) 1066 fatal_fr(r, "parse filenames/attrib"); 1067 1068 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 1069 1070 free(longname); 1071 1072 sshbuf_free(msg); 1073 1074 return filename; 1075 } 1076 #endif 1077 1078 int 1079 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 1080 int quiet) 1081 { 1082 struct sshbuf *msg; 1083 u_int id; 1084 int r; 1085 1086 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 1087 error("Server does not support statvfs@openssh.com extension"); 1088 return -1; 1089 } 1090 1091 id = conn->msg_id++; 1092 1093 if ((msg = sshbuf_new()) == NULL) 1094 fatal_f("sshbuf_new failed"); 1095 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1096 (r = sshbuf_put_u32(msg, id)) != 0 || 1097 (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || 1098 (r = sshbuf_put_cstring(msg, path)) != 0) 1099 fatal_fr(r, "compose"); 1100 send_msg(conn, msg); 1101 sshbuf_free(msg); 1102 1103 return get_decode_statvfs(conn, st, id, quiet); 1104 } 1105 1106 #ifdef notyet 1107 int 1108 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 1109 struct sftp_statvfs *st, int quiet) 1110 { 1111 struct sshbuf *msg; 1112 u_int id; 1113 1114 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 1115 error("Server does not support fstatvfs@openssh.com extension"); 1116 return -1; 1117 } 1118 1119 id = conn->msg_id++; 1120 1121 if ((msg = sshbuf_new()) == NULL) 1122 fatal_f("sshbuf_new failed"); 1123 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1124 (r = sshbuf_put_u32(msg, id)) != 0 || 1125 (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || 1126 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1127 fatal_fr(r, "compose"); 1128 send_msg(conn, msg); 1129 sshbuf_free(msg); 1130 1131 return get_decode_statvfs(conn, st, id, quiet); 1132 } 1133 #endif 1134 1135 int 1136 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) 1137 { 1138 struct sshbuf *msg; 1139 u_int status, id; 1140 int r; 1141 1142 if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) { 1143 error("Server does not support lsetstat@openssh.com extension"); 1144 return -1; 1145 } 1146 1147 id = conn->msg_id++; 1148 if ((msg = sshbuf_new()) == NULL) 1149 fatal_f("sshbuf_new failed"); 1150 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1151 (r = sshbuf_put_u32(msg, id)) != 0 || 1152 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || 1153 (r = sshbuf_put_cstring(msg, path)) != 0 || 1154 (r = encode_attrib(msg, a)) != 0) 1155 fatal_fr(r, "compose"); 1156 send_msg(conn, msg); 1157 sshbuf_free(msg); 1158 1159 status = get_status(conn, id); 1160 if (status != SSH2_FX_OK) 1161 error("Couldn't setstat on \"%s\": %s", path, 1162 fx2txt(status)); 1163 1164 return status == SSH2_FX_OK ? 0 : -1; 1165 } 1166 1167 static void 1168 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 1169 u_int len, const u_char *handle, u_int handle_len) 1170 { 1171 struct sshbuf *msg; 1172 int r; 1173 1174 if ((msg = sshbuf_new()) == NULL) 1175 fatal_f("sshbuf_new failed"); 1176 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 || 1177 (r = sshbuf_put_u32(msg, id)) != 0 || 1178 (r = sshbuf_put_string(msg, handle, handle_len)) != 0 || 1179 (r = sshbuf_put_u64(msg, offset)) != 0 || 1180 (r = sshbuf_put_u32(msg, len)) != 0) 1181 fatal_fr(r, "compose"); 1182 send_msg(conn, msg); 1183 sshbuf_free(msg); 1184 } 1185 1186 int 1187 do_download(struct sftp_conn *conn, const char *remote_path, 1188 const char *local_path, Attrib *a, int preserve_flag, int resume_flag, 1189 int fsync_flag) 1190 { 1191 Attrib junk; 1192 struct sshbuf *msg; 1193 u_char *handle; 1194 int local_fd = -1, write_error; 1195 int read_error, write_errno, lmodified = 0, reordered = 0, r; 1196 u_int64_t offset = 0, size, highwater; 1197 u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; 1198 off_t progress_counter; 1199 size_t handle_len; 1200 struct stat st; 1201 struct request { 1202 u_int id; 1203 size_t len; 1204 u_int64_t offset; 1205 TAILQ_ENTRY(request) tq; 1206 }; 1207 TAILQ_HEAD(reqhead, request) requests; 1208 struct request *req; 1209 u_char type; 1210 1211 status = -1; 1212 TAILQ_INIT(&requests); 1213 1214 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1215 return -1; 1216 1217 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1218 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1219 mode = a->perm & 0777; 1220 else 1221 mode = 0666; 1222 1223 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1224 (!S_ISREG(a->perm))) { 1225 error("Cannot download non-regular file: %s", remote_path); 1226 return(-1); 1227 } 1228 1229 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1230 size = a->size; 1231 else 1232 size = 0; 1233 1234 buflen = conn->transfer_buflen; 1235 if ((msg = sshbuf_new()) == NULL) 1236 fatal_f("sshbuf_new failed"); 1237 1238 attrib_clear(&junk); /* Send empty attributes */ 1239 1240 /* Send open request */ 1241 id = conn->msg_id++; 1242 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || 1243 (r = sshbuf_put_u32(msg, id)) != 0 || 1244 (r = sshbuf_put_cstring(msg, remote_path)) != 0 || 1245 (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 || 1246 (r = encode_attrib(msg, &junk)) != 0) 1247 fatal_fr(r, "compose"); 1248 send_msg(conn, msg); 1249 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1250 1251 handle = get_handle(conn, id, &handle_len, 1252 "remote open(\"%s\")", remote_path); 1253 if (handle == NULL) { 1254 sshbuf_free(msg); 1255 return(-1); 1256 } 1257 1258 local_fd = open(local_path, 1259 O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); 1260 if (local_fd == -1) { 1261 error("Couldn't open local file \"%s\" for writing: %s", 1262 local_path, strerror(errno)); 1263 goto fail; 1264 } 1265 offset = highwater = 0; 1266 if (resume_flag) { 1267 if (fstat(local_fd, &st) == -1) { 1268 error("Unable to stat local file \"%s\": %s", 1269 local_path, strerror(errno)); 1270 goto fail; 1271 } 1272 if (st.st_size < 0) { 1273 error("\"%s\" has negative size", local_path); 1274 goto fail; 1275 } 1276 if ((u_int64_t)st.st_size > size) { 1277 error("Unable to resume download of \"%s\": " 1278 "local file is larger than remote", local_path); 1279 fail: 1280 do_close(conn, handle, handle_len); 1281 sshbuf_free(msg); 1282 free(handle); 1283 if (local_fd != -1) 1284 close(local_fd); 1285 return -1; 1286 } 1287 offset = highwater = st.st_size; 1288 } 1289 1290 /* Read from remote and write to local */ 1291 write_error = read_error = write_errno = num_req = 0; 1292 max_req = 1; 1293 progress_counter = offset; 1294 1295 if (showprogress && size != 0) 1296 start_progress_meter(remote_path, size, &progress_counter); 1297 1298 while (num_req > 0 || max_req > 0) { 1299 u_char *data; 1300 size_t len; 1301 1302 /* 1303 * Simulate EOF on interrupt: stop sending new requests and 1304 * allow outstanding requests to drain gracefully 1305 */ 1306 if (interrupted) { 1307 if (num_req == 0) /* If we haven't started yet... */ 1308 break; 1309 max_req = 0; 1310 } 1311 1312 /* Send some more requests */ 1313 while (num_req < max_req) { 1314 debug3("Request range %llu -> %llu (%d/%d)", 1315 (unsigned long long)offset, 1316 (unsigned long long)offset + buflen - 1, 1317 num_req, max_req); 1318 req = xcalloc(1, sizeof(*req)); 1319 req->id = conn->msg_id++; 1320 req->len = buflen; 1321 req->offset = offset; 1322 offset += buflen; 1323 num_req++; 1324 TAILQ_INSERT_TAIL(&requests, req, tq); 1325 send_read_request(conn, req->id, req->offset, 1326 req->len, handle, handle_len); 1327 } 1328 1329 sshbuf_reset(msg); 1330 get_msg(conn, msg); 1331 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1332 (r = sshbuf_get_u32(msg, &id)) != 0) 1333 fatal_fr(r, "parse"); 1334 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1335 1336 /* Find the request in our queue */ 1337 for (req = TAILQ_FIRST(&requests); 1338 req != NULL && req->id != id; 1339 req = TAILQ_NEXT(req, tq)) 1340 ; 1341 if (req == NULL) 1342 fatal("Unexpected reply %u", id); 1343 1344 switch (type) { 1345 case SSH2_FXP_STATUS: 1346 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1347 fatal_fr(r, "parse status"); 1348 if (status != SSH2_FX_EOF) 1349 read_error = 1; 1350 max_req = 0; 1351 TAILQ_REMOVE(&requests, req, tq); 1352 free(req); 1353 num_req--; 1354 break; 1355 case SSH2_FXP_DATA: 1356 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 1357 fatal_fr(r, "parse data"); 1358 debug3("Received data %llu -> %llu", 1359 (unsigned long long)req->offset, 1360 (unsigned long long)req->offset + len - 1); 1361 if (len > req->len) 1362 fatal("Received more data than asked for " 1363 "%zu > %zu", len, req->len); 1364 lmodified = 1; 1365 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1366 atomicio(vwrite, local_fd, data, len) != len) && 1367 !write_error) { 1368 write_errno = errno; 1369 write_error = 1; 1370 max_req = 0; 1371 } 1372 else if (!reordered && req->offset <= highwater) 1373 highwater = req->offset + len; 1374 else if (!reordered && req->offset > highwater) 1375 reordered = 1; 1376 progress_counter += len; 1377 free(data); 1378 1379 if (len == req->len) { 1380 TAILQ_REMOVE(&requests, req, tq); 1381 free(req); 1382 num_req--; 1383 } else { 1384 /* Resend the request for the missing data */ 1385 debug3("Short data block, re-requesting " 1386 "%llu -> %llu (%2d)", 1387 (unsigned long long)req->offset + len, 1388 (unsigned long long)req->offset + 1389 req->len - 1, num_req); 1390 req->id = conn->msg_id++; 1391 req->len -= len; 1392 req->offset += len; 1393 send_read_request(conn, req->id, 1394 req->offset, req->len, handle, handle_len); 1395 /* Reduce the request size */ 1396 if (len < buflen) 1397 buflen = MAXIMUM(MIN_READ_SIZE, len); 1398 } 1399 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1400 if (size > 0 && offset > size) { 1401 /* Only one request at a time 1402 * after the expected EOF */ 1403 debug3("Finish at %llu (%2d)", 1404 (unsigned long long)offset, 1405 num_req); 1406 max_req = 1; 1407 } else if (max_req < conn->num_requests) { 1408 ++max_req; 1409 } 1410 } 1411 break; 1412 default: 1413 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1414 SSH2_FXP_DATA, type); 1415 } 1416 } 1417 1418 if (showprogress && size) 1419 stop_progress_meter(); 1420 1421 /* Sanity check */ 1422 if (TAILQ_FIRST(&requests) != NULL) 1423 fatal("Transfer complete, but requests still in queue"); 1424 /* Truncate at highest contiguous point to avoid holes on interrupt */ 1425 if (read_error || write_error || interrupted) { 1426 if (reordered && resume_flag) { 1427 error("Unable to resume download of \"%s\": " 1428 "server reordered requests", local_path); 1429 } 1430 debug("truncating at %llu", (unsigned long long)highwater); 1431 if (ftruncate(local_fd, highwater) == -1) 1432 error("ftruncate \"%s\": %s", local_path, 1433 strerror(errno)); 1434 } 1435 if (read_error) { 1436 error("Couldn't read from remote file \"%s\" : %s", 1437 remote_path, fx2txt(status)); 1438 status = -1; 1439 do_close(conn, handle, handle_len); 1440 } else if (write_error) { 1441 error("Couldn't write to \"%s\": %s", local_path, 1442 strerror(write_errno)); 1443 status = SSH2_FX_FAILURE; 1444 do_close(conn, handle, handle_len); 1445 } else { 1446 if (do_close(conn, handle, handle_len) != 0 || interrupted) 1447 status = SSH2_FX_FAILURE; 1448 else 1449 status = SSH2_FX_OK; 1450 /* Override umask and utimes if asked */ 1451 if (preserve_flag && fchmod(local_fd, mode) == -1) 1452 error("Couldn't set mode on \"%s\": %s", local_path, 1453 strerror(errno)); 1454 if (preserve_flag && 1455 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1456 struct timeval tv[2]; 1457 tv[0].tv_sec = a->atime; 1458 tv[1].tv_sec = a->mtime; 1459 tv[0].tv_usec = tv[1].tv_usec = 0; 1460 if (utimes(local_path, tv) == -1) 1461 error("Can't set times on \"%s\": %s", 1462 local_path, strerror(errno)); 1463 } 1464 if (resume_flag && !lmodified) 1465 logit("File \"%s\" was not modified", local_path); 1466 else if (fsync_flag) { 1467 debug("syncing \"%s\"", local_path); 1468 if (fsync(local_fd) == -1) 1469 error("Couldn't sync file \"%s\": %s", 1470 local_path, strerror(errno)); 1471 } 1472 } 1473 close(local_fd); 1474 sshbuf_free(msg); 1475 free(handle); 1476 1477 return status == SSH2_FX_OK ? 0 : -1; 1478 } 1479 1480 static int 1481 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1482 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 1483 int resume_flag, int fsync_flag) 1484 { 1485 int i, ret = 0; 1486 SFTP_DIRENT **dir_entries; 1487 char *filename, *new_src = NULL, *new_dst = NULL; 1488 mode_t mode = 0777, tmpmode = mode; 1489 1490 if (depth >= MAX_DIR_DEPTH) { 1491 error("Maximum directory depth exceeded: %d levels", depth); 1492 return -1; 1493 } 1494 1495 if (dirattrib == NULL && 1496 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1497 error("Unable to stat remote directory \"%s\"", src); 1498 return -1; 1499 } 1500 if (!S_ISDIR(dirattrib->perm)) { 1501 error("\"%s\" is not a directory", src); 1502 return -1; 1503 } 1504 if (print_flag) 1505 mprintf("Retrieving %s\n", src); 1506 1507 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 1508 mode = dirattrib->perm & 01777; 1509 tmpmode = mode | (S_IWUSR|S_IXUSR); 1510 } else { 1511 debug("Server did not send permissions for " 1512 "directory \"%s\"", dst); 1513 } 1514 1515 if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) { 1516 error("mkdir %s: %s", dst, strerror(errno)); 1517 return -1; 1518 } 1519 1520 if (do_readdir(conn, src, &dir_entries) == -1) { 1521 error("%s: Failed to get directory contents", src); 1522 return -1; 1523 } 1524 1525 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1526 free(new_dst); 1527 free(new_src); 1528 1529 filename = dir_entries[i]->filename; 1530 new_dst = path_append(dst, filename); 1531 new_src = path_append(src, filename); 1532 1533 if (S_ISDIR(dir_entries[i]->a.perm)) { 1534 if (strcmp(filename, ".") == 0 || 1535 strcmp(filename, "..") == 0) 1536 continue; 1537 if (download_dir_internal(conn, new_src, new_dst, 1538 depth + 1, &(dir_entries[i]->a), preserve_flag, 1539 print_flag, resume_flag, fsync_flag) == -1) 1540 ret = -1; 1541 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1542 if (do_download(conn, new_src, new_dst, 1543 &(dir_entries[i]->a), preserve_flag, 1544 resume_flag, fsync_flag) == -1) { 1545 error("Download of file %s to %s failed", 1546 new_src, new_dst); 1547 ret = -1; 1548 } 1549 } else 1550 logit("%s: not a regular file\n", new_src); 1551 1552 } 1553 free(new_dst); 1554 free(new_src); 1555 1556 if (preserve_flag) { 1557 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1558 struct timeval tv[2]; 1559 tv[0].tv_sec = dirattrib->atime; 1560 tv[1].tv_sec = dirattrib->mtime; 1561 tv[0].tv_usec = tv[1].tv_usec = 0; 1562 if (utimes(dst, tv) == -1) 1563 error("Can't set times on \"%s\": %s", 1564 dst, strerror(errno)); 1565 } else 1566 debug("Server did not send times for directory " 1567 "\"%s\"", dst); 1568 } 1569 1570 if (mode != tmpmode && chmod(dst, mode) == -1) 1571 error("Can't set final mode on \"%s\": %s", dst, 1572 strerror(errno)); 1573 1574 free_sftp_dirents(dir_entries); 1575 1576 return ret; 1577 } 1578 1579 int 1580 download_dir(struct sftp_conn *conn, const char *src, const char *dst, 1581 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, 1582 int fsync_flag) 1583 { 1584 char *src_canon; 1585 int ret; 1586 1587 if ((src_canon = do_realpath(conn, src)) == NULL) { 1588 error("Unable to canonicalize path \"%s\"", src); 1589 return -1; 1590 } 1591 1592 ret = download_dir_internal(conn, src_canon, dst, 0, 1593 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag); 1594 free(src_canon); 1595 return ret; 1596 } 1597 1598 int 1599 do_upload(struct sftp_conn *conn, const char *local_path, 1600 const char *remote_path, int preserve_flag, int resume, int fsync_flag) 1601 { 1602 int r, local_fd; 1603 u_int status = SSH2_FX_OK; 1604 u_int id; 1605 u_char type; 1606 off_t offset, progress_counter; 1607 u_char *handle, *data; 1608 struct sshbuf *msg; 1609 struct stat sb; 1610 Attrib a, *c = NULL; 1611 u_int32_t startid; 1612 u_int32_t ackid; 1613 struct outstanding_ack { 1614 u_int id; 1615 u_int len; 1616 off_t offset; 1617 TAILQ_ENTRY(outstanding_ack) tq; 1618 }; 1619 TAILQ_HEAD(ackhead, outstanding_ack) acks; 1620 struct outstanding_ack *ack = NULL; 1621 size_t handle_len; 1622 1623 TAILQ_INIT(&acks); 1624 1625 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1626 error("Couldn't open local file \"%s\" for reading: %s", 1627 local_path, strerror(errno)); 1628 return(-1); 1629 } 1630 if (fstat(local_fd, &sb) == -1) { 1631 error("Couldn't fstat local file \"%s\": %s", 1632 local_path, strerror(errno)); 1633 close(local_fd); 1634 return(-1); 1635 } 1636 if (!S_ISREG(sb.st_mode)) { 1637 error("%s is not a regular file", local_path); 1638 close(local_fd); 1639 return(-1); 1640 } 1641 stat_to_attrib(&sb, &a); 1642 1643 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1644 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1645 a.perm &= 0777; 1646 if (!preserve_flag) 1647 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1648 1649 if (resume) { 1650 /* Get remote file size if it exists */ 1651 if ((c = do_stat(conn, remote_path, 0)) == NULL) { 1652 close(local_fd); 1653 return -1; 1654 } 1655 1656 if ((off_t)c->size >= sb.st_size) { 1657 error("destination file bigger or same size as " 1658 "source file"); 1659 close(local_fd); 1660 return -1; 1661 } 1662 1663 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { 1664 close(local_fd); 1665 return -1; 1666 } 1667 } 1668 1669 if ((msg = sshbuf_new()) == NULL) 1670 fatal_f("sshbuf_new failed"); 1671 1672 /* Send open request */ 1673 id = conn->msg_id++; 1674 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || 1675 (r = sshbuf_put_u32(msg, id)) != 0 || 1676 (r = sshbuf_put_cstring(msg, remote_path)) != 0 || 1677 (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| 1678 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 || 1679 (r = encode_attrib(msg, &a)) != 0) 1680 fatal_fr(r, "compose"); 1681 send_msg(conn, msg); 1682 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1683 1684 sshbuf_reset(msg); 1685 1686 handle = get_handle(conn, id, &handle_len, 1687 "remote open(\"%s\")", remote_path); 1688 if (handle == NULL) { 1689 close(local_fd); 1690 sshbuf_free(msg); 1691 return -1; 1692 } 1693 1694 startid = ackid = id + 1; 1695 data = xmalloc(conn->transfer_buflen); 1696 1697 /* Read from local and write to remote */ 1698 offset = progress_counter = (resume ? c->size : 0); 1699 if (showprogress) 1700 start_progress_meter(local_path, sb.st_size, 1701 &progress_counter); 1702 1703 for (;;) { 1704 int len; 1705 1706 /* 1707 * Can't use atomicio here because it returns 0 on EOF, 1708 * thus losing the last block of the file. 1709 * Simulate an EOF on interrupt, allowing ACKs from the 1710 * server to drain. 1711 */ 1712 if (interrupted || status != SSH2_FX_OK) 1713 len = 0; 1714 else do 1715 len = read(local_fd, data, conn->transfer_buflen); 1716 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1717 1718 if (len == -1) 1719 fatal("Couldn't read from \"%s\": %s", local_path, 1720 strerror(errno)); 1721 1722 if (len != 0) { 1723 ack = xcalloc(1, sizeof(*ack)); 1724 ack->id = ++id; 1725 ack->offset = offset; 1726 ack->len = len; 1727 TAILQ_INSERT_TAIL(&acks, ack, tq); 1728 1729 sshbuf_reset(msg); 1730 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 1731 (r = sshbuf_put_u32(msg, ack->id)) != 0 || 1732 (r = sshbuf_put_string(msg, handle, 1733 handle_len)) != 0 || 1734 (r = sshbuf_put_u64(msg, offset)) != 0 || 1735 (r = sshbuf_put_string(msg, data, len)) != 0) 1736 fatal_fr(r, "compose"); 1737 send_msg(conn, msg); 1738 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1739 id, (unsigned long long)offset, len); 1740 } else if (TAILQ_FIRST(&acks) == NULL) 1741 break; 1742 1743 if (ack == NULL) 1744 fatal("Unexpected ACK %u", id); 1745 1746 if (id == startid || len == 0 || 1747 id - ackid >= conn->num_requests) { 1748 u_int rid; 1749 1750 sshbuf_reset(msg); 1751 get_msg(conn, msg); 1752 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1753 (r = sshbuf_get_u32(msg, &rid)) != 0) 1754 fatal_fr(r, "parse"); 1755 1756 if (type != SSH2_FXP_STATUS) 1757 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1758 "got %d", SSH2_FXP_STATUS, type); 1759 1760 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1761 fatal_fr(r, "parse status"); 1762 debug3("SSH2_FXP_STATUS %u", status); 1763 1764 /* Find the request in our queue */ 1765 for (ack = TAILQ_FIRST(&acks); 1766 ack != NULL && ack->id != rid; 1767 ack = TAILQ_NEXT(ack, tq)) 1768 ; 1769 if (ack == NULL) 1770 fatal("Can't find request for ID %u", rid); 1771 TAILQ_REMOVE(&acks, ack, tq); 1772 debug3("In write loop, ack for %u %u bytes at %lld", 1773 ack->id, ack->len, (long long)ack->offset); 1774 ++ackid; 1775 progress_counter += ack->len; 1776 free(ack); 1777 } 1778 offset += len; 1779 if (offset < 0) 1780 fatal_f("offset < 0"); 1781 } 1782 sshbuf_free(msg); 1783 1784 if (showprogress) 1785 stop_progress_meter(); 1786 free(data); 1787 1788 if (status != SSH2_FX_OK) { 1789 error("Couldn't write to remote file \"%s\": %s", 1790 remote_path, fx2txt(status)); 1791 status = SSH2_FX_FAILURE; 1792 } 1793 1794 if (close(local_fd) == -1) { 1795 error("Couldn't close local file \"%s\": %s", local_path, 1796 strerror(errno)); 1797 status = SSH2_FX_FAILURE; 1798 } 1799 1800 /* Override umask and utimes if asked */ 1801 if (preserve_flag) 1802 do_fsetstat(conn, handle, handle_len, &a); 1803 1804 if (fsync_flag) 1805 (void)do_fsync(conn, handle, handle_len); 1806 1807 if (do_close(conn, handle, handle_len) != 0) 1808 status = SSH2_FX_FAILURE; 1809 1810 free(handle); 1811 1812 return status == SSH2_FX_OK ? 0 : -1; 1813 } 1814 1815 static int 1816 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1817 int depth, int preserve_flag, int print_flag, int resume, int fsync_flag) 1818 { 1819 int ret = 0; 1820 DIR *dirp; 1821 struct dirent *dp; 1822 char *filename, *new_src = NULL, *new_dst = NULL; 1823 struct stat sb; 1824 Attrib a, *dirattrib; 1825 u_int32_t saved_perm; 1826 1827 if (depth >= MAX_DIR_DEPTH) { 1828 error("Maximum directory depth exceeded: %d levels", depth); 1829 return -1; 1830 } 1831 1832 if (stat(src, &sb) == -1) { 1833 error("Couldn't stat directory \"%s\": %s", 1834 src, strerror(errno)); 1835 return -1; 1836 } 1837 if (!S_ISDIR(sb.st_mode)) { 1838 error("\"%s\" is not a directory", src); 1839 return -1; 1840 } 1841 if (print_flag) 1842 mprintf("Entering %s\n", src); 1843 1844 attrib_clear(&a); 1845 stat_to_attrib(&sb, &a); 1846 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1847 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1848 a.perm &= 01777; 1849 if (!preserve_flag) 1850 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1851 1852 /* 1853 * sftp lacks a portable status value to match errno EEXIST, 1854 * so if we get a failure back then we must check whether 1855 * the path already existed and is a directory. Ensure we can 1856 * write to the directory we create for the duration of the transfer. 1857 */ 1858 saved_perm = a.perm; 1859 a.perm |= (S_IWUSR|S_IXUSR); 1860 if (do_mkdir(conn, dst, &a, 0) != 0) { 1861 if ((dirattrib = do_stat(conn, dst, 0)) == NULL) 1862 return -1; 1863 if (!S_ISDIR(dirattrib->perm)) { 1864 error("\"%s\" exists but is not a directory", dst); 1865 return -1; 1866 } 1867 } 1868 a.perm = saved_perm; 1869 1870 if ((dirp = opendir(src)) == NULL) { 1871 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1872 return -1; 1873 } 1874 1875 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1876 if (dp->d_ino == 0) 1877 continue; 1878 free(new_dst); 1879 free(new_src); 1880 filename = dp->d_name; 1881 new_dst = path_append(dst, filename); 1882 new_src = path_append(src, filename); 1883 1884 if (lstat(new_src, &sb) == -1) { 1885 logit("%s: lstat failed: %s", filename, 1886 strerror(errno)); 1887 ret = -1; 1888 } else if (S_ISDIR(sb.st_mode)) { 1889 if (strcmp(filename, ".") == 0 || 1890 strcmp(filename, "..") == 0) 1891 continue; 1892 1893 if (upload_dir_internal(conn, new_src, new_dst, 1894 depth + 1, preserve_flag, print_flag, resume, 1895 fsync_flag) == -1) 1896 ret = -1; 1897 } else if (S_ISREG(sb.st_mode)) { 1898 if (do_upload(conn, new_src, new_dst, 1899 preserve_flag, resume, fsync_flag) == -1) { 1900 error("Uploading of file %s to %s failed!", 1901 new_src, new_dst); 1902 ret = -1; 1903 } 1904 } else 1905 logit("%s: not a regular file\n", filename); 1906 } 1907 free(new_dst); 1908 free(new_src); 1909 1910 do_setstat(conn, dst, &a); 1911 1912 (void) closedir(dirp); 1913 return ret; 1914 } 1915 1916 int 1917 upload_dir(struct sftp_conn *conn, const char *src, const char *dst, 1918 int preserve_flag, int print_flag, int resume, int fsync_flag) 1919 { 1920 char *dst_canon; 1921 int ret; 1922 1923 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1924 error("Unable to canonicalize path \"%s\"", dst); 1925 return -1; 1926 } 1927 1928 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 1929 print_flag, resume, fsync_flag); 1930 1931 free(dst_canon); 1932 return ret; 1933 } 1934 1935 char * 1936 path_append(const char *p1, const char *p2) 1937 { 1938 char *ret; 1939 size_t len = strlen(p1) + strlen(p2) + 2; 1940 1941 ret = xmalloc(len); 1942 strlcpy(ret, p1, len); 1943 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 1944 strlcat(ret, "/", len); 1945 strlcat(ret, p2, len); 1946 1947 return(ret); 1948 } 1949 1950 char * 1951 make_absolute(char *p, const char *pwd) 1952 { 1953 char *abs_str; 1954 1955 /* Derelativise */ 1956 if (p && !path_absolute(p)) { 1957 abs_str = path_append(pwd, p); 1958 free(p); 1959 return(abs_str); 1960 } else 1961 return(p); 1962 } 1963 1964 int 1965 remote_is_dir(struct sftp_conn *conn, const char *path) 1966 { 1967 Attrib *a; 1968 1969 /* XXX: report errors? */ 1970 if ((a = do_stat(conn, path, 1)) == NULL) 1971 return(0); 1972 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 1973 return(0); 1974 return(S_ISDIR(a->perm)); 1975 } 1976 1977 1978 int 1979 local_is_dir(const char *path) 1980 { 1981 struct stat sb; 1982 1983 /* XXX: report errors? */ 1984 if (stat(path, &sb) == -1) 1985 return(0); 1986 1987 return(S_ISDIR(sb.st_mode)); 1988 } 1989 1990 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 1991 int 1992 globpath_is_dir(const char *pathname) 1993 { 1994 size_t l = strlen(pathname); 1995 1996 return l > 0 && pathname[l - 1] == '/'; 1997 } 1998 1999