1 /* $OpenBSD: sftp-client.c,v 1.155 2021/09/03 05:12:25 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/poll.h> 25 #include <sys/queue.h> 26 #include <sys/stat.h> 27 #include <sys/time.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 <poll.h> 35 #include <signal.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "xmalloc.h" 43 #include "ssherr.h" 44 #include "sshbuf.h" 45 #include "log.h" 46 #include "atomicio.h" 47 #include "progressmeter.h" 48 #include "misc.h" 49 #include "utf8.h" 50 51 #include "sftp.h" 52 #include "sftp-common.h" 53 #include "sftp-client.h" 54 55 extern volatile sig_atomic_t interrupted; 56 extern int showprogress; 57 58 /* Default size of buffer for up/download */ 59 #define DEFAULT_COPY_BUFLEN 32768 60 61 /* Default number of concurrent outstanding requests */ 62 #define DEFAULT_NUM_REQUESTS 64 63 64 /* Minimum amount of data to read at a time */ 65 #define MIN_READ_SIZE 512 66 67 /* Maximum depth to descend in directory trees */ 68 #define MAX_DIR_DEPTH 64 69 70 struct sftp_conn { 71 int fd_in; 72 int fd_out; 73 u_int download_buflen; 74 u_int upload_buflen; 75 u_int num_requests; 76 u_int version; 77 u_int msg_id; 78 #define SFTP_EXT_POSIX_RENAME 0x00000001 79 #define SFTP_EXT_STATVFS 0x00000002 80 #define SFTP_EXT_FSTATVFS 0x00000004 81 #define SFTP_EXT_HARDLINK 0x00000008 82 #define SFTP_EXT_FSYNC 0x00000010 83 #define SFTP_EXT_LSETSTAT 0x00000020 84 #define SFTP_EXT_LIMITS 0x00000040 85 #define SFTP_EXT_PATH_EXPAND 0x00000080 86 u_int exts; 87 u_int64_t limit_kbps; 88 struct bwlimit bwlimit_in, bwlimit_out; 89 }; 90 91 /* Tracks in-progress requests during file transfers */ 92 struct request { 93 u_int id; 94 size_t len; 95 u_int64_t offset; 96 TAILQ_ENTRY(request) tq; 97 }; 98 TAILQ_HEAD(requests, request); 99 100 static u_char * 101 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 102 const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 103 104 static struct request * 105 request_enqueue(struct requests *requests, u_int id, size_t len, 106 uint64_t offset) 107 { 108 struct request *req; 109 110 req = xcalloc(1, sizeof(*req)); 111 req->id = id; 112 req->len = len; 113 req->offset = offset; 114 TAILQ_INSERT_TAIL(requests, req, tq); 115 return req; 116 } 117 118 static struct request * 119 request_find(struct requests *requests, u_int id) 120 { 121 struct request *req; 122 123 for (req = TAILQ_FIRST(requests); 124 req != NULL && req->id != id; 125 req = TAILQ_NEXT(req, tq)) 126 ; 127 return req; 128 } 129 130 /* ARGSUSED */ 131 static int 132 sftpio(void *_bwlimit, size_t amount) 133 { 134 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 135 136 refresh_progress_meter(0); 137 if (bwlimit != NULL) 138 bandwidth_limit(bwlimit, amount); 139 return 0; 140 } 141 142 static void 143 send_msg(struct sftp_conn *conn, struct sshbuf *m) 144 { 145 u_char mlen[4]; 146 struct iovec iov[2]; 147 148 if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH) 149 fatal("Outbound message too long %zu", sshbuf_len(m)); 150 151 /* Send length first */ 152 put_u32(mlen, sshbuf_len(m)); 153 iov[0].iov_base = mlen; 154 iov[0].iov_len = sizeof(mlen); 155 iov[1].iov_base = (u_char *)sshbuf_ptr(m); 156 iov[1].iov_len = sshbuf_len(m); 157 158 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio, 159 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) != 160 sshbuf_len(m) + sizeof(mlen)) 161 fatal("Couldn't send packet: %s", strerror(errno)); 162 163 sshbuf_reset(m); 164 } 165 166 static void 167 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial) 168 { 169 u_int msg_len; 170 u_char *p; 171 int r; 172 173 sshbuf_reset(m); 174 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 175 fatal_fr(r, "reserve"); 176 if (atomicio6(read, conn->fd_in, p, 4, sftpio, 177 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) { 178 if (errno == EPIPE || errno == ECONNRESET) 179 fatal("Connection closed"); 180 else 181 fatal("Couldn't read packet: %s", strerror(errno)); 182 } 183 184 if ((r = sshbuf_get_u32(m, &msg_len)) != 0) 185 fatal_fr(r, "sshbuf_get_u32"); 186 if (msg_len > SFTP_MAX_MSG_LENGTH) { 187 do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL, 188 "Received message too long %u", msg_len); 189 fatal("Ensure the remote shell produces no output " 190 "for non-interactive sessions."); 191 } 192 193 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 194 fatal_fr(r, "reserve"); 195 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio, 196 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) 197 != msg_len) { 198 if (errno == EPIPE) 199 fatal("Connection closed"); 200 else 201 fatal("Read packet: %s", strerror(errno)); 202 } 203 } 204 205 static void 206 get_msg(struct sftp_conn *conn, struct sshbuf *m) 207 { 208 get_msg_extended(conn, m, 0); 209 } 210 211 static void 212 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, 213 u_int len) 214 { 215 struct sshbuf *msg; 216 int r; 217 218 if ((msg = sshbuf_new()) == NULL) 219 fatal_f("sshbuf_new failed"); 220 if ((r = sshbuf_put_u8(msg, code)) != 0 || 221 (r = sshbuf_put_u32(msg, id)) != 0 || 222 (r = sshbuf_put_string(msg, s, len)) != 0) 223 fatal_fr(r, "compose"); 224 send_msg(conn, msg); 225 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 226 sshbuf_free(msg); 227 } 228 229 static void 230 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 231 const void *s, u_int len, Attrib *a) 232 { 233 struct sshbuf *msg; 234 int r; 235 236 if ((msg = sshbuf_new()) == NULL) 237 fatal_f("sshbuf_new failed"); 238 if ((r = sshbuf_put_u8(msg, code)) != 0 || 239 (r = sshbuf_put_u32(msg, id)) != 0 || 240 (r = sshbuf_put_string(msg, s, len)) != 0 || 241 (r = encode_attrib(msg, a)) != 0) 242 fatal_fr(r, "compose"); 243 send_msg(conn, msg); 244 debug3("Sent message fd %d T:%u I:%u F:0x%04x M:%05o", 245 conn->fd_out, code, id, a->flags, a->perm); 246 sshbuf_free(msg); 247 } 248 249 static u_int 250 get_status(struct sftp_conn *conn, u_int expected_id) 251 { 252 struct sshbuf *msg; 253 u_char type; 254 u_int id, status; 255 int r; 256 257 if ((msg = sshbuf_new()) == NULL) 258 fatal_f("sshbuf_new failed"); 259 get_msg(conn, msg); 260 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 261 (r = sshbuf_get_u32(msg, &id)) != 0) 262 fatal_fr(r, "compose"); 263 264 if (id != expected_id) 265 fatal("ID mismatch (%u != %u)", id, expected_id); 266 if (type != SSH2_FXP_STATUS) 267 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 268 SSH2_FXP_STATUS, type); 269 270 if ((r = sshbuf_get_u32(msg, &status)) != 0) 271 fatal_fr(r, "parse"); 272 sshbuf_free(msg); 273 274 debug3("SSH2_FXP_STATUS %u", status); 275 276 return status; 277 } 278 279 static u_char * 280 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 281 const char *errfmt, ...) 282 { 283 struct sshbuf *msg; 284 u_int id, status; 285 u_char type; 286 u_char *handle; 287 char errmsg[256]; 288 va_list args; 289 int r; 290 291 va_start(args, errfmt); 292 if (errfmt != NULL) 293 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 294 va_end(args); 295 296 if ((msg = sshbuf_new()) == NULL) 297 fatal_f("sshbuf_new failed"); 298 get_msg(conn, msg); 299 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 300 (r = sshbuf_get_u32(msg, &id)) != 0) 301 fatal_fr(r, "parse"); 302 303 if (id != expected_id) 304 fatal("%s: ID mismatch (%u != %u)", 305 errfmt == NULL ? __func__ : errmsg, id, expected_id); 306 if (type == SSH2_FXP_STATUS) { 307 if ((r = sshbuf_get_u32(msg, &status)) != 0) 308 fatal_fr(r, "parse status"); 309 if (errfmt != NULL) 310 error("%s: %s", errmsg, fx2txt(status)); 311 sshbuf_free(msg); 312 return(NULL); 313 } else if (type != SSH2_FXP_HANDLE) 314 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 315 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 316 317 if ((r = sshbuf_get_string(msg, &handle, len)) != 0) 318 fatal_fr(r, "parse handle"); 319 sshbuf_free(msg); 320 321 return handle; 322 } 323 324 /* XXX returing &static is error-prone. Refactor to fill *Attrib argument */ 325 static Attrib * 326 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 327 { 328 struct sshbuf *msg; 329 u_int id; 330 u_char type; 331 int r; 332 static Attrib a; 333 334 if ((msg = sshbuf_new()) == NULL) 335 fatal_f("sshbuf_new failed"); 336 get_msg(conn, msg); 337 338 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 339 (r = sshbuf_get_u32(msg, &id)) != 0) 340 fatal_fr(r, "parse"); 341 342 if (id != expected_id) 343 fatal("ID mismatch (%u != %u)", id, expected_id); 344 if (type == SSH2_FXP_STATUS) { 345 u_int status; 346 347 if ((r = sshbuf_get_u32(msg, &status)) != 0) 348 fatal_fr(r, "parse status"); 349 if (quiet) 350 debug("Couldn't stat remote file: %s", fx2txt(status)); 351 else 352 error("Couldn't stat remote file: %s", fx2txt(status)); 353 sshbuf_free(msg); 354 return(NULL); 355 } else if (type != SSH2_FXP_ATTRS) { 356 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 357 SSH2_FXP_ATTRS, type); 358 } 359 if ((r = decode_attrib(msg, &a)) != 0) { 360 error_fr(r, "decode_attrib"); 361 sshbuf_free(msg); 362 return NULL; 363 } 364 debug3("Recevied stat reply T:%u I:%u F:0x%04x M:%05o", 365 type, id, a.flags, a.perm); 366 sshbuf_free(msg); 367 368 return &a; 369 } 370 371 static int 372 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 373 u_int expected_id, int quiet) 374 { 375 struct sshbuf *msg; 376 u_char type; 377 u_int id; 378 u_int64_t flag; 379 int r; 380 381 if ((msg = sshbuf_new()) == NULL) 382 fatal_f("sshbuf_new failed"); 383 get_msg(conn, msg); 384 385 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 386 (r = sshbuf_get_u32(msg, &id)) != 0) 387 fatal_fr(r, "parse"); 388 389 debug3("Received statvfs reply T:%u I:%u", type, id); 390 if (id != expected_id) 391 fatal("ID mismatch (%u != %u)", id, expected_id); 392 if (type == SSH2_FXP_STATUS) { 393 u_int status; 394 395 if ((r = sshbuf_get_u32(msg, &status)) != 0) 396 fatal_fr(r, "parse status"); 397 if (quiet) 398 debug("Couldn't statvfs: %s", fx2txt(status)); 399 else 400 error("Couldn't statvfs: %s", fx2txt(status)); 401 sshbuf_free(msg); 402 return -1; 403 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 404 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 405 SSH2_FXP_EXTENDED_REPLY, type); 406 } 407 408 memset(st, 0, sizeof(*st)); 409 if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 || 410 (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 || 411 (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 || 412 (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 || 413 (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 || 414 (r = sshbuf_get_u64(msg, &st->f_files)) != 0 || 415 (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 || 416 (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 || 417 (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 || 418 (r = sshbuf_get_u64(msg, &flag)) != 0 || 419 (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0) 420 fatal_fr(r, "parse statvfs"); 421 422 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 423 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 424 425 sshbuf_free(msg); 426 427 return 0; 428 } 429 430 struct sftp_conn * 431 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 432 u_int64_t limit_kbps) 433 { 434 u_char type; 435 struct sshbuf *msg; 436 struct sftp_conn *ret; 437 int r; 438 439 ret = xcalloc(1, sizeof(*ret)); 440 ret->msg_id = 1; 441 ret->fd_in = fd_in; 442 ret->fd_out = fd_out; 443 ret->download_buflen = ret->upload_buflen = 444 transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN; 445 ret->num_requests = 446 num_requests ? num_requests : DEFAULT_NUM_REQUESTS; 447 ret->exts = 0; 448 ret->limit_kbps = 0; 449 450 if ((msg = sshbuf_new()) == NULL) 451 fatal_f("sshbuf_new failed"); 452 if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 || 453 (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0) 454 fatal_fr(r, "parse"); 455 456 send_msg(ret, msg); 457 458 get_msg_extended(ret, msg, 1); 459 460 /* Expecting a VERSION reply */ 461 if ((r = sshbuf_get_u8(msg, &type)) != 0) 462 fatal_fr(r, "parse type"); 463 if (type != SSH2_FXP_VERSION) { 464 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 465 type); 466 sshbuf_free(msg); 467 free(ret); 468 return(NULL); 469 } 470 if ((r = sshbuf_get_u32(msg, &ret->version)) != 0) 471 fatal_fr(r, "parse version"); 472 473 debug2("Remote version: %u", ret->version); 474 475 /* Check for extensions */ 476 while (sshbuf_len(msg) > 0) { 477 char *name; 478 u_char *value; 479 size_t vlen; 480 int known = 0; 481 482 if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 || 483 (r = sshbuf_get_string(msg, &value, &vlen)) != 0) 484 fatal_fr(r, "parse extension"); 485 if (strcmp(name, "posix-rename@openssh.com") == 0 && 486 strcmp((char *)value, "1") == 0) { 487 ret->exts |= SFTP_EXT_POSIX_RENAME; 488 known = 1; 489 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 490 strcmp((char *)value, "2") == 0) { 491 ret->exts |= SFTP_EXT_STATVFS; 492 known = 1; 493 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 494 strcmp((char *)value, "2") == 0) { 495 ret->exts |= SFTP_EXT_FSTATVFS; 496 known = 1; 497 } else if (strcmp(name, "hardlink@openssh.com") == 0 && 498 strcmp((char *)value, "1") == 0) { 499 ret->exts |= SFTP_EXT_HARDLINK; 500 known = 1; 501 } else if (strcmp(name, "fsync@openssh.com") == 0 && 502 strcmp((char *)value, "1") == 0) { 503 ret->exts |= SFTP_EXT_FSYNC; 504 known = 1; 505 } else if (strcmp(name, "lsetstat@openssh.com") == 0 && 506 strcmp((char *)value, "1") == 0) { 507 ret->exts |= SFTP_EXT_LSETSTAT; 508 known = 1; 509 } else if (strcmp(name, "limits@openssh.com") == 0 && 510 strcmp((char *)value, "1") == 0) { 511 ret->exts |= SFTP_EXT_LIMITS; 512 known = 1; 513 } else if (strcmp(name, "expand-path@openssh.com") == 0 && 514 strcmp((char *)value, "1") == 0) { 515 ret->exts |= SFTP_EXT_PATH_EXPAND; 516 known = 1; 517 } 518 if (known) { 519 debug2("Server supports extension \"%s\" revision %s", 520 name, value); 521 } else { 522 debug2("Unrecognised server extension \"%s\"", name); 523 } 524 free(name); 525 free(value); 526 } 527 528 sshbuf_free(msg); 529 530 /* Query the server for its limits */ 531 if (ret->exts & SFTP_EXT_LIMITS) { 532 struct sftp_limits limits; 533 if (do_limits(ret, &limits) != 0) 534 fatal_f("limits failed"); 535 536 /* If the caller did not specify, find a good value */ 537 if (transfer_buflen == 0) { 538 ret->download_buflen = limits.read_length; 539 ret->upload_buflen = limits.write_length; 540 debug("Using server download size %u", ret->download_buflen); 541 debug("Using server upload size %u", ret->upload_buflen); 542 } 543 544 /* Use the server limit to scale down our value only */ 545 if (num_requests == 0 && limits.open_handles) { 546 ret->num_requests = 547 MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles); 548 debug("Server handle limit %llu; using %u", 549 (unsigned long long)limits.open_handles, 550 ret->num_requests); 551 } 552 } 553 554 /* Some filexfer v.0 servers don't support large packets */ 555 if (ret->version == 0) { 556 ret->download_buflen = MINIMUM(ret->download_buflen, 20480); 557 ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480); 558 } 559 560 ret->limit_kbps = limit_kbps; 561 if (ret->limit_kbps > 0) { 562 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 563 ret->download_buflen); 564 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 565 ret->upload_buflen); 566 } 567 568 return ret; 569 } 570 571 u_int 572 sftp_proto_version(struct sftp_conn *conn) 573 { 574 return conn->version; 575 } 576 577 int 578 do_limits(struct sftp_conn *conn, struct sftp_limits *limits) 579 { 580 u_int id, msg_id; 581 u_char type; 582 struct sshbuf *msg; 583 int r; 584 585 if ((conn->exts & SFTP_EXT_LIMITS) == 0) { 586 error("Server does not support limits@openssh.com extension"); 587 return -1; 588 } 589 590 if ((msg = sshbuf_new()) == NULL) 591 fatal_f("sshbuf_new failed"); 592 593 id = conn->msg_id++; 594 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 595 (r = sshbuf_put_u32(msg, id)) != 0 || 596 (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0) 597 fatal_fr(r, "compose"); 598 send_msg(conn, msg); 599 debug3("Sent message limits@openssh.com I:%u", id); 600 601 get_msg(conn, msg); 602 603 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 604 (r = sshbuf_get_u32(msg, &msg_id)) != 0) 605 fatal_fr(r, "parse"); 606 607 debug3("Received limits reply T:%u I:%u", type, msg_id); 608 if (id != msg_id) 609 fatal("ID mismatch (%u != %u)", msg_id, id); 610 if (type != SSH2_FXP_EXTENDED_REPLY) { 611 debug_f("expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 612 SSH2_FXP_EXTENDED_REPLY, type); 613 /* Disable the limits extension */ 614 conn->exts &= ~SFTP_EXT_LIMITS; 615 sshbuf_free(msg); 616 return 0; 617 } 618 619 memset(limits, 0, sizeof(*limits)); 620 if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 || 621 (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 || 622 (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 || 623 (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0) 624 fatal_fr(r, "parse limits"); 625 626 sshbuf_free(msg); 627 628 return 0; 629 } 630 631 int 632 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) 633 { 634 u_int id, status; 635 struct sshbuf *msg; 636 int r; 637 638 if ((msg = sshbuf_new()) == NULL) 639 fatal_f("sshbuf_new failed"); 640 641 id = conn->msg_id++; 642 if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 || 643 (r = sshbuf_put_u32(msg, id)) != 0 || 644 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 645 fatal_fr(r, "parse"); 646 send_msg(conn, msg); 647 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 648 649 status = get_status(conn, id); 650 if (status != SSH2_FX_OK) 651 error("Couldn't close file: %s", fx2txt(status)); 652 653 sshbuf_free(msg); 654 655 return status == SSH2_FX_OK ? 0 : -1; 656 } 657 658 659 static int 660 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, 661 SFTP_DIRENT ***dir) 662 { 663 struct sshbuf *msg; 664 u_int count, id, i, expected_id, ents = 0; 665 size_t handle_len; 666 u_char type, *handle; 667 int status = SSH2_FX_FAILURE; 668 int r; 669 670 if (dir) 671 *dir = NULL; 672 673 id = conn->msg_id++; 674 675 if ((msg = sshbuf_new()) == NULL) 676 fatal_f("sshbuf_new failed"); 677 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 || 678 (r = sshbuf_put_u32(msg, id)) != 0 || 679 (r = sshbuf_put_cstring(msg, path)) != 0) 680 fatal_fr(r, "compose OPENDIR"); 681 send_msg(conn, msg); 682 683 handle = get_handle(conn, id, &handle_len, 684 "remote readdir(\"%s\")", path); 685 if (handle == NULL) { 686 sshbuf_free(msg); 687 return -1; 688 } 689 690 if (dir) { 691 ents = 0; 692 *dir = xcalloc(1, sizeof(**dir)); 693 (*dir)[0] = NULL; 694 } 695 696 for (; !interrupted;) { 697 id = expected_id = conn->msg_id++; 698 699 debug3("Sending SSH2_FXP_READDIR I:%u", id); 700 701 sshbuf_reset(msg); 702 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 || 703 (r = sshbuf_put_u32(msg, id)) != 0 || 704 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 705 fatal_fr(r, "compose READDIR"); 706 send_msg(conn, msg); 707 708 sshbuf_reset(msg); 709 710 get_msg(conn, msg); 711 712 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 713 (r = sshbuf_get_u32(msg, &id)) != 0) 714 fatal_fr(r, "parse"); 715 716 debug3("Received reply T:%u I:%u", type, id); 717 718 if (id != expected_id) 719 fatal("ID mismatch (%u != %u)", id, expected_id); 720 721 if (type == SSH2_FXP_STATUS) { 722 u_int rstatus; 723 724 if ((r = sshbuf_get_u32(msg, &rstatus)) != 0) 725 fatal_fr(r, "parse status"); 726 debug3("Received SSH2_FXP_STATUS %d", rstatus); 727 if (rstatus == SSH2_FX_EOF) 728 break; 729 error("Couldn't read directory: %s", fx2txt(rstatus)); 730 goto out; 731 } else if (type != SSH2_FXP_NAME) 732 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 733 SSH2_FXP_NAME, type); 734 735 if ((r = sshbuf_get_u32(msg, &count)) != 0) 736 fatal_fr(r, "parse count"); 737 if (count > SSHBUF_SIZE_MAX) 738 fatal_f("nonsensical number of entries"); 739 if (count == 0) 740 break; 741 debug3("Received %d SSH2_FXP_NAME responses", count); 742 for (i = 0; i < count; i++) { 743 char *filename, *longname; 744 Attrib a; 745 746 if ((r = sshbuf_get_cstring(msg, &filename, 747 NULL)) != 0 || 748 (r = sshbuf_get_cstring(msg, &longname, 749 NULL)) != 0) 750 fatal_fr(r, "parse filenames"); 751 if ((r = decode_attrib(msg, &a)) != 0) { 752 error_fr(r, "couldn't decode attrib"); 753 free(filename); 754 free(longname); 755 goto out; 756 } 757 758 if (print_flag) 759 mprintf("%s\n", longname); 760 761 /* 762 * Directory entries should never contain '/' 763 * These can be used to attack recursive ops 764 * (e.g. send '../../../../etc/passwd') 765 */ 766 if (strchr(filename, '/') != NULL) { 767 error("Server sent suspect path \"%s\" " 768 "during readdir of \"%s\"", filename, path); 769 } else if (dir) { 770 *dir = xreallocarray(*dir, ents + 2, sizeof(**dir)); 771 (*dir)[ents] = xcalloc(1, sizeof(***dir)); 772 (*dir)[ents]->filename = xstrdup(filename); 773 (*dir)[ents]->longname = xstrdup(longname); 774 memcpy(&(*dir)[ents]->a, &a, sizeof(a)); 775 (*dir)[++ents] = NULL; 776 } 777 free(filename); 778 free(longname); 779 } 780 } 781 status = 0; 782 783 out: 784 sshbuf_free(msg); 785 do_close(conn, handle, handle_len); 786 free(handle); 787 788 if (status != 0 && dir != NULL) { 789 /* Don't return results on error */ 790 free_sftp_dirents(*dir); 791 *dir = NULL; 792 } else if (interrupted && dir != NULL && *dir != NULL) { 793 /* Don't return partial matches on interrupt */ 794 free_sftp_dirents(*dir); 795 *dir = xcalloc(1, sizeof(**dir)); 796 **dir = NULL; 797 } 798 799 return status == SSH2_FX_OK ? 0 : -1; 800 } 801 802 int 803 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) 804 { 805 return(do_lsreaddir(conn, path, 0, dir)); 806 } 807 808 void free_sftp_dirents(SFTP_DIRENT **s) 809 { 810 int i; 811 812 if (s == NULL) 813 return; 814 for (i = 0; s[i]; i++) { 815 free(s[i]->filename); 816 free(s[i]->longname); 817 free(s[i]); 818 } 819 free(s); 820 } 821 822 int 823 do_rm(struct sftp_conn *conn, const char *path) 824 { 825 u_int status, id; 826 827 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 828 829 id = conn->msg_id++; 830 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 831 status = get_status(conn, id); 832 if (status != SSH2_FX_OK) 833 error("Couldn't delete file: %s", fx2txt(status)); 834 return status == SSH2_FX_OK ? 0 : -1; 835 } 836 837 int 838 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) 839 { 840 u_int status, id; 841 842 id = conn->msg_id++; 843 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 844 strlen(path), a); 845 846 status = get_status(conn, id); 847 if (status != SSH2_FX_OK && print_flag) 848 error("Couldn't create directory: %s", fx2txt(status)); 849 850 return status == SSH2_FX_OK ? 0 : -1; 851 } 852 853 int 854 do_rmdir(struct sftp_conn *conn, const char *path) 855 { 856 u_int status, id; 857 858 id = conn->msg_id++; 859 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 860 strlen(path)); 861 862 status = get_status(conn, id); 863 if (status != SSH2_FX_OK) 864 error("Couldn't remove directory: %s", fx2txt(status)); 865 866 return status == SSH2_FX_OK ? 0 : -1; 867 } 868 869 Attrib * 870 do_stat(struct sftp_conn *conn, const char *path, int quiet) 871 { 872 u_int id; 873 874 id = conn->msg_id++; 875 876 send_string_request(conn, id, 877 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 878 path, strlen(path)); 879 880 return(get_decode_stat(conn, id, quiet)); 881 } 882 883 Attrib * 884 do_lstat(struct sftp_conn *conn, const char *path, int quiet) 885 { 886 u_int id; 887 888 if (conn->version == 0) { 889 if (quiet) 890 debug("Server version does not support lstat operation"); 891 else 892 logit("Server version does not support lstat operation"); 893 return(do_stat(conn, path, quiet)); 894 } 895 896 id = conn->msg_id++; 897 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 898 strlen(path)); 899 900 return(get_decode_stat(conn, id, quiet)); 901 } 902 903 #ifdef notyet 904 Attrib * 905 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 906 int quiet) 907 { 908 u_int id; 909 910 id = conn->msg_id++; 911 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 912 handle_len); 913 914 return(get_decode_stat(conn, id, quiet)); 915 } 916 #endif 917 918 int 919 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) 920 { 921 u_int status, id; 922 923 id = conn->msg_id++; 924 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 925 strlen(path), a); 926 927 status = get_status(conn, id); 928 if (status != SSH2_FX_OK) 929 error("Couldn't setstat on \"%s\": %s", path, 930 fx2txt(status)); 931 932 return status == SSH2_FX_OK ? 0 : -1; 933 } 934 935 int 936 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 937 Attrib *a) 938 { 939 u_int status, id; 940 941 id = conn->msg_id++; 942 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 943 handle_len, a); 944 945 status = get_status(conn, id); 946 if (status != SSH2_FX_OK) 947 error("Couldn't fsetstat: %s", fx2txt(status)); 948 949 return status == SSH2_FX_OK ? 0 : -1; 950 } 951 952 /* Implements both the realpath and expand-path operations */ 953 static char * 954 do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) 955 { 956 struct sshbuf *msg; 957 u_int expected_id, count, id; 958 char *filename, *longname; 959 Attrib a; 960 u_char type; 961 int r; 962 const char *what = "SSH2_FXP_REALPATH"; 963 964 if (expand) 965 what = "expand-path@openssh.com"; 966 if ((msg = sshbuf_new()) == NULL) 967 fatal_f("sshbuf_new failed"); 968 969 expected_id = id = conn->msg_id++; 970 if (expand) { 971 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 972 (r = sshbuf_put_u32(msg, id)) != 0 || 973 (r = sshbuf_put_cstring(msg, 974 "expand-path@openssh.com")) != 0 || 975 (r = sshbuf_put_cstring(msg, path)) != 0) 976 fatal_fr(r, "compose %s", what); 977 send_msg(conn, msg); 978 } else { 979 send_string_request(conn, id, SSH2_FXP_REALPATH, 980 path, strlen(path)); 981 } 982 get_msg(conn, msg); 983 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 984 (r = sshbuf_get_u32(msg, &id)) != 0) 985 fatal_fr(r, "parse"); 986 987 if (id != expected_id) 988 fatal("ID mismatch (%u != %u)", id, expected_id); 989 990 if (type == SSH2_FXP_STATUS) { 991 u_int status; 992 993 if ((r = sshbuf_get_u32(msg, &status)) != 0) 994 fatal_fr(r, "parse status"); 995 error("Couldn't canonicalize: %s", fx2txt(status)); 996 sshbuf_free(msg); 997 return NULL; 998 } else if (type != SSH2_FXP_NAME) 999 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1000 SSH2_FXP_NAME, type); 1001 1002 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1003 fatal_fr(r, "parse count"); 1004 if (count != 1) 1005 fatal("Got multiple names (%d) from %s", count, what); 1006 1007 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1008 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1009 (r = decode_attrib(msg, &a)) != 0) 1010 fatal_fr(r, "parse filename/attrib"); 1011 1012 debug3("%s %s -> %s", what, path, filename); 1013 1014 free(longname); 1015 1016 sshbuf_free(msg); 1017 1018 return(filename); 1019 } 1020 1021 char * 1022 do_realpath(struct sftp_conn *conn, const char *path) 1023 { 1024 return do_realpath_expand(conn, path, 0); 1025 } 1026 1027 int 1028 can_expand_path(struct sftp_conn *conn) 1029 { 1030 return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0; 1031 } 1032 1033 char * 1034 do_expand_path(struct sftp_conn *conn, const char *path) 1035 { 1036 if (!can_expand_path(conn)) { 1037 debug3_f("no server support, fallback to realpath"); 1038 return do_realpath_expand(conn, path, 0); 1039 } 1040 return do_realpath_expand(conn, path, 1); 1041 } 1042 1043 int 1044 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, 1045 int force_legacy) 1046 { 1047 struct sshbuf *msg; 1048 u_int status, id; 1049 int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; 1050 1051 if ((msg = sshbuf_new()) == NULL) 1052 fatal_f("sshbuf_new failed"); 1053 1054 /* Send rename request */ 1055 id = conn->msg_id++; 1056 if (use_ext) { 1057 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1058 (r = sshbuf_put_u32(msg, id)) != 0 || 1059 (r = sshbuf_put_cstring(msg, 1060 "posix-rename@openssh.com")) != 0) 1061 fatal_fr(r, "compose posix-rename"); 1062 } else { 1063 if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 || 1064 (r = sshbuf_put_u32(msg, id)) != 0) 1065 fatal_fr(r, "compose rename"); 1066 } 1067 if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1068 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1069 fatal_fr(r, "compose paths"); 1070 send_msg(conn, msg); 1071 debug3("Sent message %s \"%s\" -> \"%s\"", 1072 use_ext ? "posix-rename@openssh.com" : 1073 "SSH2_FXP_RENAME", oldpath, newpath); 1074 sshbuf_free(msg); 1075 1076 status = get_status(conn, id); 1077 if (status != SSH2_FX_OK) 1078 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 1079 newpath, fx2txt(status)); 1080 1081 return status == SSH2_FX_OK ? 0 : -1; 1082 } 1083 1084 int 1085 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1086 { 1087 struct sshbuf *msg; 1088 u_int status, id; 1089 int r; 1090 1091 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 1092 error("Server does not support hardlink@openssh.com extension"); 1093 return -1; 1094 } 1095 1096 if ((msg = sshbuf_new()) == NULL) 1097 fatal_f("sshbuf_new failed"); 1098 1099 /* Send link request */ 1100 id = conn->msg_id++; 1101 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1102 (r = sshbuf_put_u32(msg, id)) != 0 || 1103 (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || 1104 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1105 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1106 fatal_fr(r, "compose"); 1107 send_msg(conn, msg); 1108 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 1109 oldpath, newpath); 1110 sshbuf_free(msg); 1111 1112 status = get_status(conn, id); 1113 if (status != SSH2_FX_OK) 1114 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 1115 newpath, fx2txt(status)); 1116 1117 return status == SSH2_FX_OK ? 0 : -1; 1118 } 1119 1120 int 1121 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1122 { 1123 struct sshbuf *msg; 1124 u_int status, id; 1125 int r; 1126 1127 if (conn->version < 3) { 1128 error("This server does not support the symlink operation"); 1129 return(SSH2_FX_OP_UNSUPPORTED); 1130 } 1131 1132 if ((msg = sshbuf_new()) == NULL) 1133 fatal_f("sshbuf_new failed"); 1134 1135 /* Send symlink request */ 1136 id = conn->msg_id++; 1137 if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 || 1138 (r = sshbuf_put_u32(msg, id)) != 0 || 1139 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1140 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1141 fatal_fr(r, "compose"); 1142 send_msg(conn, msg); 1143 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 1144 newpath); 1145 sshbuf_free(msg); 1146 1147 status = get_status(conn, id); 1148 if (status != SSH2_FX_OK) 1149 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 1150 newpath, fx2txt(status)); 1151 1152 return status == SSH2_FX_OK ? 0 : -1; 1153 } 1154 1155 int 1156 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) 1157 { 1158 struct sshbuf *msg; 1159 u_int status, id; 1160 int r; 1161 1162 /* Silently return if the extension is not supported */ 1163 if ((conn->exts & SFTP_EXT_FSYNC) == 0) 1164 return -1; 1165 1166 /* Send fsync request */ 1167 if ((msg = sshbuf_new()) == NULL) 1168 fatal_f("sshbuf_new failed"); 1169 id = conn->msg_id++; 1170 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1171 (r = sshbuf_put_u32(msg, id)) != 0 || 1172 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || 1173 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1174 fatal_fr(r, "compose"); 1175 send_msg(conn, msg); 1176 debug3("Sent message fsync@openssh.com I:%u", id); 1177 sshbuf_free(msg); 1178 1179 status = get_status(conn, id); 1180 if (status != SSH2_FX_OK) 1181 error("Couldn't sync file: %s", fx2txt(status)); 1182 1183 return status == SSH2_FX_OK ? 0 : -1; 1184 } 1185 1186 #ifdef notyet 1187 char * 1188 do_readlink(struct sftp_conn *conn, const char *path) 1189 { 1190 struct sshbuf *msg; 1191 u_int expected_id, count, id; 1192 char *filename, *longname; 1193 Attrib a; 1194 u_char type; 1195 int r; 1196 1197 expected_id = id = conn->msg_id++; 1198 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 1199 1200 if ((msg = sshbuf_new()) == NULL) 1201 fatal_f("sshbuf_new failed"); 1202 1203 get_msg(conn, msg); 1204 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1205 (r = sshbuf_get_u32(msg, &id)) != 0) 1206 fatal_fr(r, "parse"); 1207 1208 if (id != expected_id) 1209 fatal("ID mismatch (%u != %u)", id, expected_id); 1210 1211 if (type == SSH2_FXP_STATUS) { 1212 u_int status; 1213 1214 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1215 fatal_fr(r, "parse status"); 1216 error("Couldn't readlink: %s", fx2txt(status)); 1217 sshbuf_free(msg); 1218 return(NULL); 1219 } else if (type != SSH2_FXP_NAME) 1220 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1221 SSH2_FXP_NAME, type); 1222 1223 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1224 fatal_fr(r, "parse count"); 1225 if (count != 1) 1226 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 1227 1228 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1229 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1230 (r = decode_attrib(msg, &a)) != 0) 1231 fatal_fr(r, "parse filenames/attrib"); 1232 1233 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 1234 1235 free(longname); 1236 1237 sshbuf_free(msg); 1238 1239 return filename; 1240 } 1241 #endif 1242 1243 int 1244 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 1245 int quiet) 1246 { 1247 struct sshbuf *msg; 1248 u_int id; 1249 int r; 1250 1251 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 1252 error("Server does not support statvfs@openssh.com extension"); 1253 return -1; 1254 } 1255 1256 id = conn->msg_id++; 1257 1258 if ((msg = sshbuf_new()) == NULL) 1259 fatal_f("sshbuf_new failed"); 1260 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1261 (r = sshbuf_put_u32(msg, id)) != 0 || 1262 (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || 1263 (r = sshbuf_put_cstring(msg, path)) != 0) 1264 fatal_fr(r, "compose"); 1265 send_msg(conn, msg); 1266 sshbuf_free(msg); 1267 1268 return get_decode_statvfs(conn, st, id, quiet); 1269 } 1270 1271 #ifdef notyet 1272 int 1273 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 1274 struct sftp_statvfs *st, int quiet) 1275 { 1276 struct sshbuf *msg; 1277 u_int id; 1278 1279 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 1280 error("Server does not support fstatvfs@openssh.com extension"); 1281 return -1; 1282 } 1283 1284 id = conn->msg_id++; 1285 1286 if ((msg = sshbuf_new()) == NULL) 1287 fatal_f("sshbuf_new failed"); 1288 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1289 (r = sshbuf_put_u32(msg, id)) != 0 || 1290 (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || 1291 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1292 fatal_fr(r, "compose"); 1293 send_msg(conn, msg); 1294 sshbuf_free(msg); 1295 1296 return get_decode_statvfs(conn, st, id, quiet); 1297 } 1298 #endif 1299 1300 int 1301 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) 1302 { 1303 struct sshbuf *msg; 1304 u_int status, id; 1305 int r; 1306 1307 if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) { 1308 error("Server does not support lsetstat@openssh.com extension"); 1309 return -1; 1310 } 1311 1312 id = conn->msg_id++; 1313 if ((msg = sshbuf_new()) == NULL) 1314 fatal_f("sshbuf_new failed"); 1315 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1316 (r = sshbuf_put_u32(msg, id)) != 0 || 1317 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || 1318 (r = sshbuf_put_cstring(msg, path)) != 0 || 1319 (r = encode_attrib(msg, a)) != 0) 1320 fatal_fr(r, "compose"); 1321 send_msg(conn, msg); 1322 sshbuf_free(msg); 1323 1324 status = get_status(conn, id); 1325 if (status != SSH2_FX_OK) 1326 error("Couldn't setstat on \"%s\": %s", path, 1327 fx2txt(status)); 1328 1329 return status == SSH2_FX_OK ? 0 : -1; 1330 } 1331 1332 static void 1333 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 1334 u_int len, const u_char *handle, u_int handle_len) 1335 { 1336 struct sshbuf *msg; 1337 int r; 1338 1339 if ((msg = sshbuf_new()) == NULL) 1340 fatal_f("sshbuf_new failed"); 1341 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 || 1342 (r = sshbuf_put_u32(msg, id)) != 0 || 1343 (r = sshbuf_put_string(msg, handle, handle_len)) != 0 || 1344 (r = sshbuf_put_u64(msg, offset)) != 0 || 1345 (r = sshbuf_put_u32(msg, len)) != 0) 1346 fatal_fr(r, "compose"); 1347 send_msg(conn, msg); 1348 sshbuf_free(msg); 1349 } 1350 1351 static int 1352 send_open(struct sftp_conn *conn, const char *path, const char *tag, 1353 u_int openmode, Attrib *a, u_char **handlep, size_t *handle_lenp) 1354 { 1355 Attrib junk; 1356 u_char *handle; 1357 size_t handle_len; 1358 struct sshbuf *msg; 1359 int r; 1360 u_int id; 1361 1362 *handlep = NULL; 1363 *handle_lenp = 0; 1364 1365 if (a == NULL) { 1366 attrib_clear(&junk); /* Send empty attributes */ 1367 a = &junk; 1368 } 1369 /* Send open request */ 1370 if ((msg = sshbuf_new()) == NULL) 1371 fatal_f("sshbuf_new failed"); 1372 id = conn->msg_id++; 1373 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || 1374 (r = sshbuf_put_u32(msg, id)) != 0 || 1375 (r = sshbuf_put_cstring(msg, path)) != 0 || 1376 (r = sshbuf_put_u32(msg, openmode)) != 0 || 1377 (r = encode_attrib(msg, a)) != 0) 1378 fatal_fr(r, "compose %s open", tag); 1379 send_msg(conn, msg); 1380 sshbuf_free(msg); 1381 debug3("Sent %s message SSH2_FXP_OPEN I:%u P:%s M:0x%04x", 1382 tag, id, path, openmode); 1383 if ((handle = get_handle(conn, id, &handle_len, 1384 "%s open(\"%s\")", tag, path)) == NULL) 1385 return -1; 1386 /* success */ 1387 *handlep = handle; 1388 *handle_lenp = handle_len; 1389 return 0; 1390 } 1391 1392 static const char * 1393 progress_meter_path(const char *path) 1394 { 1395 const char *progresspath; 1396 1397 if ((progresspath = strrchr(path, '/')) == NULL) 1398 return path; 1399 progresspath++; 1400 if (*progresspath == '\0') 1401 return path; 1402 return progresspath; 1403 } 1404 1405 int 1406 do_download(struct sftp_conn *conn, const char *remote_path, 1407 const char *local_path, Attrib *a, int preserve_flag, int resume_flag, 1408 int fsync_flag) 1409 { 1410 struct sshbuf *msg; 1411 u_char *handle; 1412 int local_fd = -1, write_error; 1413 int read_error, write_errno, lmodified = 0, reordered = 0, r; 1414 u_int64_t offset = 0, size, highwater; 1415 u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; 1416 off_t progress_counter; 1417 size_t handle_len; 1418 struct stat st; 1419 struct requests requests; 1420 struct request *req; 1421 u_char type; 1422 1423 TAILQ_INIT(&requests); 1424 1425 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1426 return -1; 1427 1428 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1429 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1430 mode = a->perm & 0777; 1431 else 1432 mode = 0666; 1433 1434 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1435 (!S_ISREG(a->perm))) { 1436 error("Cannot download non-regular file: %s", remote_path); 1437 return(-1); 1438 } 1439 1440 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1441 size = a->size; 1442 else 1443 size = 0; 1444 1445 buflen = conn->download_buflen; 1446 1447 /* Send open request */ 1448 if (send_open(conn, remote_path, "remote", SSH2_FXF_READ, NULL, 1449 &handle, &handle_len) != 0) 1450 return -1; 1451 1452 local_fd = open(local_path, 1453 O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); 1454 if (local_fd == -1) { 1455 error("Couldn't open local file \"%s\" for writing: %s", 1456 local_path, strerror(errno)); 1457 goto fail; 1458 } 1459 offset = highwater = 0; 1460 if (resume_flag) { 1461 if (fstat(local_fd, &st) == -1) { 1462 error("Unable to stat local file \"%s\": %s", 1463 local_path, strerror(errno)); 1464 goto fail; 1465 } 1466 if (st.st_size < 0) { 1467 error("\"%s\" has negative size", local_path); 1468 goto fail; 1469 } 1470 if ((u_int64_t)st.st_size > size) { 1471 error("Unable to resume download of \"%s\": " 1472 "local file is larger than remote", local_path); 1473 fail: 1474 do_close(conn, handle, handle_len); 1475 free(handle); 1476 if (local_fd != -1) 1477 close(local_fd); 1478 return -1; 1479 } 1480 offset = highwater = st.st_size; 1481 } 1482 1483 /* Read from remote and write to local */ 1484 write_error = read_error = write_errno = num_req = 0; 1485 max_req = 1; 1486 progress_counter = offset; 1487 1488 if (showprogress && size != 0) { 1489 start_progress_meter(progress_meter_path(remote_path), 1490 size, &progress_counter); 1491 } 1492 1493 if ((msg = sshbuf_new()) == NULL) 1494 fatal_f("sshbuf_new failed"); 1495 1496 while (num_req > 0 || max_req > 0) { 1497 u_char *data; 1498 size_t len; 1499 1500 /* 1501 * Simulate EOF on interrupt: stop sending new requests and 1502 * allow outstanding requests to drain gracefully 1503 */ 1504 if (interrupted) { 1505 if (num_req == 0) /* If we haven't started yet... */ 1506 break; 1507 max_req = 0; 1508 } 1509 1510 /* Send some more requests */ 1511 while (num_req < max_req) { 1512 debug3("Request range %llu -> %llu (%d/%d)", 1513 (unsigned long long)offset, 1514 (unsigned long long)offset + buflen - 1, 1515 num_req, max_req); 1516 req = request_enqueue(&requests, conn->msg_id++, 1517 buflen, offset); 1518 offset += buflen; 1519 num_req++; 1520 send_read_request(conn, req->id, req->offset, 1521 req->len, handle, handle_len); 1522 } 1523 1524 sshbuf_reset(msg); 1525 get_msg(conn, msg); 1526 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1527 (r = sshbuf_get_u32(msg, &id)) != 0) 1528 fatal_fr(r, "parse"); 1529 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1530 1531 /* Find the request in our queue */ 1532 if ((req = request_find(&requests, id)) == NULL) 1533 fatal("Unexpected reply %u", id); 1534 1535 switch (type) { 1536 case SSH2_FXP_STATUS: 1537 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1538 fatal_fr(r, "parse status"); 1539 if (status != SSH2_FX_EOF) 1540 read_error = 1; 1541 max_req = 0; 1542 TAILQ_REMOVE(&requests, req, tq); 1543 free(req); 1544 num_req--; 1545 break; 1546 case SSH2_FXP_DATA: 1547 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 1548 fatal_fr(r, "parse data"); 1549 debug3("Received data %llu -> %llu", 1550 (unsigned long long)req->offset, 1551 (unsigned long long)req->offset + len - 1); 1552 if (len > req->len) 1553 fatal("Received more data than asked for " 1554 "%zu > %zu", len, req->len); 1555 lmodified = 1; 1556 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1557 atomicio(vwrite, local_fd, data, len) != len) && 1558 !write_error) { 1559 write_errno = errno; 1560 write_error = 1; 1561 max_req = 0; 1562 } 1563 else if (!reordered && req->offset <= highwater) 1564 highwater = req->offset + len; 1565 else if (!reordered && req->offset > highwater) 1566 reordered = 1; 1567 progress_counter += len; 1568 free(data); 1569 1570 if (len == req->len) { 1571 TAILQ_REMOVE(&requests, req, tq); 1572 free(req); 1573 num_req--; 1574 } else { 1575 /* Resend the request for the missing data */ 1576 debug3("Short data block, re-requesting " 1577 "%llu -> %llu (%2d)", 1578 (unsigned long long)req->offset + len, 1579 (unsigned long long)req->offset + 1580 req->len - 1, num_req); 1581 req->id = conn->msg_id++; 1582 req->len -= len; 1583 req->offset += len; 1584 send_read_request(conn, req->id, 1585 req->offset, req->len, handle, handle_len); 1586 /* Reduce the request size */ 1587 if (len < buflen) 1588 buflen = MAXIMUM(MIN_READ_SIZE, len); 1589 } 1590 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1591 if (size > 0 && offset > size) { 1592 /* Only one request at a time 1593 * after the expected EOF */ 1594 debug3("Finish at %llu (%2d)", 1595 (unsigned long long)offset, 1596 num_req); 1597 max_req = 1; 1598 } else if (max_req < conn->num_requests) { 1599 ++max_req; 1600 } 1601 } 1602 break; 1603 default: 1604 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1605 SSH2_FXP_DATA, type); 1606 } 1607 } 1608 1609 if (showprogress && size) 1610 stop_progress_meter(); 1611 1612 /* Sanity check */ 1613 if (TAILQ_FIRST(&requests) != NULL) 1614 fatal("Transfer complete, but requests still in queue"); 1615 /* Truncate at highest contiguous point to avoid holes on interrupt */ 1616 if (read_error || write_error || interrupted) { 1617 if (reordered && resume_flag) { 1618 error("Unable to resume download of \"%s\": " 1619 "server reordered requests", local_path); 1620 } 1621 debug("truncating at %llu", (unsigned long long)highwater); 1622 if (ftruncate(local_fd, highwater) == -1) 1623 error("ftruncate \"%s\": %s", local_path, 1624 strerror(errno)); 1625 } 1626 if (read_error) { 1627 error("Couldn't read from remote file \"%s\" : %s", 1628 remote_path, fx2txt(status)); 1629 status = -1; 1630 do_close(conn, handle, handle_len); 1631 } else if (write_error) { 1632 error("Couldn't write to \"%s\": %s", local_path, 1633 strerror(write_errno)); 1634 status = SSH2_FX_FAILURE; 1635 do_close(conn, handle, handle_len); 1636 } else { 1637 if (do_close(conn, handle, handle_len) != 0 || interrupted) 1638 status = SSH2_FX_FAILURE; 1639 else 1640 status = SSH2_FX_OK; 1641 /* Override umask and utimes if asked */ 1642 if (preserve_flag && fchmod(local_fd, mode) == -1) 1643 error("Couldn't set mode on \"%s\": %s", local_path, 1644 strerror(errno)); 1645 if (preserve_flag && 1646 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1647 struct timeval tv[2]; 1648 tv[0].tv_sec = a->atime; 1649 tv[1].tv_sec = a->mtime; 1650 tv[0].tv_usec = tv[1].tv_usec = 0; 1651 if (utimes(local_path, tv) == -1) 1652 error("Can't set times on \"%s\": %s", 1653 local_path, strerror(errno)); 1654 } 1655 if (resume_flag && !lmodified) 1656 logit("File \"%s\" was not modified", local_path); 1657 else if (fsync_flag) { 1658 debug("syncing \"%s\"", local_path); 1659 if (fsync(local_fd) == -1) 1660 error("Couldn't sync file \"%s\": %s", 1661 local_path, strerror(errno)); 1662 } 1663 } 1664 close(local_fd); 1665 sshbuf_free(msg); 1666 free(handle); 1667 1668 return status == SSH2_FX_OK ? 0 : -1; 1669 } 1670 1671 static int 1672 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1673 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 1674 int resume_flag, int fsync_flag, int follow_link_flag) 1675 { 1676 int i, ret = 0; 1677 SFTP_DIRENT **dir_entries; 1678 char *filename, *new_src = NULL, *new_dst = NULL; 1679 mode_t mode = 0777, tmpmode = mode; 1680 1681 if (depth >= MAX_DIR_DEPTH) { 1682 error("Maximum directory depth exceeded: %d levels", depth); 1683 return -1; 1684 } 1685 1686 if (dirattrib == NULL && 1687 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1688 error("Unable to stat remote directory \"%s\"", src); 1689 return -1; 1690 } 1691 if (!S_ISDIR(dirattrib->perm)) { 1692 error("\"%s\" is not a directory", src); 1693 return -1; 1694 } 1695 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 1696 mprintf("Retrieving %s\n", src); 1697 1698 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 1699 mode = dirattrib->perm & 01777; 1700 tmpmode = mode | (S_IWUSR|S_IXUSR); 1701 } else { 1702 debug("Server did not send permissions for " 1703 "directory \"%s\"", dst); 1704 } 1705 1706 if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) { 1707 error("mkdir %s: %s", dst, strerror(errno)); 1708 return -1; 1709 } 1710 1711 if (do_readdir(conn, src, &dir_entries) == -1) { 1712 error("%s: Failed to get directory contents", src); 1713 return -1; 1714 } 1715 1716 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1717 free(new_dst); 1718 free(new_src); 1719 1720 filename = dir_entries[i]->filename; 1721 new_dst = path_append(dst, filename); 1722 new_src = path_append(src, filename); 1723 1724 if (S_ISDIR(dir_entries[i]->a.perm)) { 1725 if (strcmp(filename, ".") == 0 || 1726 strcmp(filename, "..") == 0) 1727 continue; 1728 if (download_dir_internal(conn, new_src, new_dst, 1729 depth + 1, &(dir_entries[i]->a), preserve_flag, 1730 print_flag, resume_flag, 1731 fsync_flag, follow_link_flag) == -1) 1732 ret = -1; 1733 } else if (S_ISREG(dir_entries[i]->a.perm) || 1734 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 1735 /* 1736 * If this is a symlink then don't send the link's 1737 * Attrib. do_download() will do a FXP_STAT operation 1738 * and get the link target's attributes. 1739 */ 1740 if (do_download(conn, new_src, new_dst, 1741 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 1742 &(dir_entries[i]->a), 1743 preserve_flag, resume_flag, fsync_flag) == -1) { 1744 error("Download of file %s to %s failed", 1745 new_src, new_dst); 1746 ret = -1; 1747 } 1748 } else 1749 logit("%s: not a regular file\n", new_src); 1750 1751 } 1752 free(new_dst); 1753 free(new_src); 1754 1755 if (preserve_flag) { 1756 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1757 struct timeval tv[2]; 1758 tv[0].tv_sec = dirattrib->atime; 1759 tv[1].tv_sec = dirattrib->mtime; 1760 tv[0].tv_usec = tv[1].tv_usec = 0; 1761 if (utimes(dst, tv) == -1) 1762 error("Can't set times on \"%s\": %s", 1763 dst, strerror(errno)); 1764 } else 1765 debug("Server did not send times for directory " 1766 "\"%s\"", dst); 1767 } 1768 1769 if (mode != tmpmode && chmod(dst, mode) == -1) 1770 error("Can't set final mode on \"%s\": %s", dst, 1771 strerror(errno)); 1772 1773 free_sftp_dirents(dir_entries); 1774 1775 return ret; 1776 } 1777 1778 int 1779 download_dir(struct sftp_conn *conn, const char *src, const char *dst, 1780 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, 1781 int fsync_flag, int follow_link_flag) 1782 { 1783 char *src_canon; 1784 int ret; 1785 1786 if ((src_canon = do_realpath(conn, src)) == NULL) { 1787 error("Unable to canonicalize path \"%s\"", src); 1788 return -1; 1789 } 1790 1791 ret = download_dir_internal(conn, src_canon, dst, 0, 1792 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, 1793 follow_link_flag); 1794 free(src_canon); 1795 return ret; 1796 } 1797 1798 int 1799 do_upload(struct sftp_conn *conn, const char *local_path, 1800 const char *remote_path, int preserve_flag, int resume, int fsync_flag) 1801 { 1802 int r, local_fd; 1803 u_int status = SSH2_FX_OK; 1804 u_int id; 1805 u_char type; 1806 off_t offset, progress_counter; 1807 u_char *handle, *data; 1808 struct sshbuf *msg; 1809 struct stat sb; 1810 Attrib a, *c = NULL; 1811 u_int32_t startid; 1812 u_int32_t ackid; 1813 struct request *ack = NULL; 1814 struct requests acks; 1815 size_t handle_len; 1816 1817 TAILQ_INIT(&acks); 1818 1819 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1820 error("Couldn't open local file \"%s\" for reading: %s", 1821 local_path, strerror(errno)); 1822 return(-1); 1823 } 1824 if (fstat(local_fd, &sb) == -1) { 1825 error("Couldn't fstat local file \"%s\": %s", 1826 local_path, strerror(errno)); 1827 close(local_fd); 1828 return(-1); 1829 } 1830 if (!S_ISREG(sb.st_mode)) { 1831 error("%s is not a regular file", local_path); 1832 close(local_fd); 1833 return(-1); 1834 } 1835 stat_to_attrib(&sb, &a); 1836 1837 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1838 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1839 a.perm &= 0777; 1840 if (!preserve_flag) 1841 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1842 1843 if (resume) { 1844 /* Get remote file size if it exists */ 1845 if ((c = do_stat(conn, remote_path, 0)) == NULL) { 1846 close(local_fd); 1847 return -1; 1848 } 1849 1850 if ((off_t)c->size >= sb.st_size) { 1851 error("destination file bigger or same size as " 1852 "source file"); 1853 close(local_fd); 1854 return -1; 1855 } 1856 1857 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { 1858 close(local_fd); 1859 return -1; 1860 } 1861 } 1862 1863 /* Send open request */ 1864 if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT| 1865 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC), 1866 &a, &handle, &handle_len) != 0) { 1867 close(local_fd); 1868 return -1; 1869 } 1870 1871 id = conn->msg_id; 1872 startid = ackid = id + 1; 1873 data = xmalloc(conn->upload_buflen); 1874 1875 /* Read from local and write to remote */ 1876 offset = progress_counter = (resume ? c->size : 0); 1877 if (showprogress) { 1878 start_progress_meter(progress_meter_path(local_path), 1879 sb.st_size, &progress_counter); 1880 } 1881 1882 if ((msg = sshbuf_new()) == NULL) 1883 fatal_f("sshbuf_new failed"); 1884 for (;;) { 1885 int len; 1886 1887 /* 1888 * Can't use atomicio here because it returns 0 on EOF, 1889 * thus losing the last block of the file. 1890 * Simulate an EOF on interrupt, allowing ACKs from the 1891 * server to drain. 1892 */ 1893 if (interrupted || status != SSH2_FX_OK) 1894 len = 0; 1895 else do 1896 len = read(local_fd, data, conn->upload_buflen); 1897 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1898 1899 if (len == -1) 1900 fatal("Couldn't read from \"%s\": %s", local_path, 1901 strerror(errno)); 1902 1903 if (len != 0) { 1904 ack = request_enqueue(&acks, ++id, len, offset); 1905 sshbuf_reset(msg); 1906 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 1907 (r = sshbuf_put_u32(msg, ack->id)) != 0 || 1908 (r = sshbuf_put_string(msg, handle, 1909 handle_len)) != 0 || 1910 (r = sshbuf_put_u64(msg, offset)) != 0 || 1911 (r = sshbuf_put_string(msg, data, len)) != 0) 1912 fatal_fr(r, "compose"); 1913 send_msg(conn, msg); 1914 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1915 id, (unsigned long long)offset, len); 1916 } else if (TAILQ_FIRST(&acks) == NULL) 1917 break; 1918 1919 if (ack == NULL) 1920 fatal("Unexpected ACK %u", id); 1921 1922 if (id == startid || len == 0 || 1923 id - ackid >= conn->num_requests) { 1924 u_int rid; 1925 1926 sshbuf_reset(msg); 1927 get_msg(conn, msg); 1928 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1929 (r = sshbuf_get_u32(msg, &rid)) != 0) 1930 fatal_fr(r, "parse"); 1931 1932 if (type != SSH2_FXP_STATUS) 1933 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1934 "got %d", SSH2_FXP_STATUS, type); 1935 1936 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1937 fatal_fr(r, "parse status"); 1938 debug3("SSH2_FXP_STATUS %u", status); 1939 1940 /* Find the request in our queue */ 1941 if ((ack = request_find(&acks, rid)) == NULL) 1942 fatal("Can't find request for ID %u", rid); 1943 TAILQ_REMOVE(&acks, ack, tq); 1944 debug3("In write loop, ack for %u %zu bytes at %lld", 1945 ack->id, ack->len, (unsigned long long)ack->offset); 1946 ++ackid; 1947 progress_counter += ack->len; 1948 free(ack); 1949 } 1950 offset += len; 1951 if (offset < 0) 1952 fatal_f("offset < 0"); 1953 } 1954 sshbuf_free(msg); 1955 1956 if (showprogress) 1957 stop_progress_meter(); 1958 free(data); 1959 1960 if (status != SSH2_FX_OK) { 1961 error("Couldn't write to remote file \"%s\": %s", 1962 remote_path, fx2txt(status)); 1963 status = SSH2_FX_FAILURE; 1964 } 1965 1966 if (close(local_fd) == -1) { 1967 error("Couldn't close local file \"%s\": %s", local_path, 1968 strerror(errno)); 1969 status = SSH2_FX_FAILURE; 1970 } 1971 1972 /* Override umask and utimes if asked */ 1973 if (preserve_flag) 1974 do_fsetstat(conn, handle, handle_len, &a); 1975 1976 if (fsync_flag) 1977 (void)do_fsync(conn, handle, handle_len); 1978 1979 if (do_close(conn, handle, handle_len) != 0) 1980 status = SSH2_FX_FAILURE; 1981 1982 free(handle); 1983 1984 return status == SSH2_FX_OK ? 0 : -1; 1985 } 1986 1987 static int 1988 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1989 int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, 1990 int follow_link_flag) 1991 { 1992 int ret = 0; 1993 DIR *dirp; 1994 struct dirent *dp; 1995 char *filename, *new_src = NULL, *new_dst = NULL; 1996 struct stat sb; 1997 Attrib a, *dirattrib; 1998 u_int32_t saved_perm; 1999 2000 if (depth >= MAX_DIR_DEPTH) { 2001 error("Maximum directory depth exceeded: %d levels", depth); 2002 return -1; 2003 } 2004 2005 if (stat(src, &sb) == -1) { 2006 error("Couldn't stat directory \"%s\": %s", 2007 src, strerror(errno)); 2008 return -1; 2009 } 2010 if (!S_ISDIR(sb.st_mode)) { 2011 error("\"%s\" is not a directory", src); 2012 return -1; 2013 } 2014 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2015 mprintf("Entering %s\n", src); 2016 2017 stat_to_attrib(&sb, &a); 2018 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2019 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2020 a.perm &= 01777; 2021 if (!preserve_flag) 2022 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2023 2024 /* 2025 * sftp lacks a portable status value to match errno EEXIST, 2026 * so if we get a failure back then we must check whether 2027 * the path already existed and is a directory. Ensure we can 2028 * write to the directory we create for the duration of the transfer. 2029 */ 2030 saved_perm = a.perm; 2031 a.perm |= (S_IWUSR|S_IXUSR); 2032 if (do_mkdir(conn, dst, &a, 0) != 0) { 2033 if ((dirattrib = do_stat(conn, dst, 0)) == NULL) 2034 return -1; 2035 if (!S_ISDIR(dirattrib->perm)) { 2036 error("\"%s\" exists but is not a directory", dst); 2037 return -1; 2038 } 2039 } 2040 a.perm = saved_perm; 2041 2042 if ((dirp = opendir(src)) == NULL) { 2043 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 2044 return -1; 2045 } 2046 2047 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 2048 if (dp->d_ino == 0) 2049 continue; 2050 free(new_dst); 2051 free(new_src); 2052 filename = dp->d_name; 2053 new_dst = path_append(dst, filename); 2054 new_src = path_append(src, filename); 2055 2056 if (lstat(new_src, &sb) == -1) { 2057 logit("%s: lstat failed: %s", filename, 2058 strerror(errno)); 2059 ret = -1; 2060 } else if (S_ISDIR(sb.st_mode)) { 2061 if (strcmp(filename, ".") == 0 || 2062 strcmp(filename, "..") == 0) 2063 continue; 2064 2065 if (upload_dir_internal(conn, new_src, new_dst, 2066 depth + 1, preserve_flag, print_flag, resume, 2067 fsync_flag, follow_link_flag) == -1) 2068 ret = -1; 2069 } else if (S_ISREG(sb.st_mode) || 2070 (follow_link_flag && S_ISLNK(sb.st_mode))) { 2071 if (do_upload(conn, new_src, new_dst, 2072 preserve_flag, resume, fsync_flag) == -1) { 2073 error("Uploading of file %s to %s failed!", 2074 new_src, new_dst); 2075 ret = -1; 2076 } 2077 } else 2078 logit("%s: not a regular file\n", filename); 2079 } 2080 free(new_dst); 2081 free(new_src); 2082 2083 do_setstat(conn, dst, &a); 2084 2085 (void) closedir(dirp); 2086 return ret; 2087 } 2088 2089 int 2090 upload_dir(struct sftp_conn *conn, const char *src, const char *dst, 2091 int preserve_flag, int print_flag, int resume, int fsync_flag, 2092 int follow_link_flag) 2093 { 2094 char *dst_canon; 2095 int ret; 2096 2097 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 2098 error("Unable to canonicalize path \"%s\"", dst); 2099 return -1; 2100 } 2101 2102 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 2103 print_flag, resume, fsync_flag, follow_link_flag); 2104 2105 free(dst_canon); 2106 return ret; 2107 } 2108 2109 static void 2110 handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, 2111 u_int *nreqsp, u_int *write_errorp) 2112 { 2113 struct sshbuf *msg; 2114 u_char type; 2115 u_int id, status; 2116 int r; 2117 struct pollfd pfd; 2118 2119 if ((msg = sshbuf_new()) == NULL) 2120 fatal_f("sshbuf_new failed"); 2121 2122 /* Try to eat replies from the upload side */ 2123 while (*nreqsp > 0) { 2124 debug3_f("%u outstanding replies", *nreqsp); 2125 if (!synchronous) { 2126 /* Bail out if no data is ready to be read */ 2127 pfd.fd = to->fd_in; 2128 pfd.events = POLLIN; 2129 if ((r = poll(&pfd, 1, 0)) == -1) { 2130 if (errno == EINTR) 2131 break; 2132 fatal_f("poll: %s", strerror(errno)); 2133 } else if (r == 0) 2134 break; /* fd not ready */ 2135 } 2136 sshbuf_reset(msg); 2137 get_msg(to, msg); 2138 2139 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2140 (r = sshbuf_get_u32(msg, &id)) != 0) 2141 fatal_fr(r, "dest parse"); 2142 debug3("Received dest reply T:%u I:%u R:%u", type, id, *nreqsp); 2143 if (type != SSH2_FXP_STATUS) { 2144 fatal_f("Expected SSH2_FXP_STATUS(%d) packet, got %d", 2145 SSH2_FXP_STATUS, type); 2146 } 2147 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2148 fatal_fr(r, "parse dest status"); 2149 debug3("dest SSH2_FXP_STATUS %u", status); 2150 if (status != SSH2_FX_OK) { 2151 /* record first error */ 2152 if (*write_errorp == 0) 2153 *write_errorp = status; 2154 } 2155 /* 2156 * XXX this doesn't do full reply matching like do_upload and 2157 * so cannot gracefully truncate terminated uploads at a 2158 * high-water mark. ATM the only caller of this function (scp) 2159 * doesn't support transfer resumption, so this doesn't matter 2160 * a whole lot. 2161 * 2162 * To be safe, do_crossload truncates the destination file to 2163 * zero length on upload failure, since we can't trust the 2164 * server not to have reordered replies that could have 2165 * inserted holes where none existed in the source file. 2166 * 2167 * XXX we could get a more accutate progress bar if we updated 2168 * the counter based on the reply from the destination... 2169 */ 2170 (*nreqsp)--; 2171 } 2172 debug3_f("done: %u outstanding replies", *nreqsp); 2173 } 2174 2175 int 2176 do_crossload(struct sftp_conn *from, struct sftp_conn *to, 2177 const char *from_path, const char *to_path, 2178 Attrib *a, int preserve_flag) 2179 { 2180 struct sshbuf *msg; 2181 int write_error, read_error, r; 2182 u_int64_t offset = 0, size; 2183 u_int id, buflen, num_req, max_req, status = SSH2_FX_OK; 2184 u_int num_upload_req; 2185 off_t progress_counter; 2186 u_char *from_handle, *to_handle; 2187 size_t from_handle_len, to_handle_len; 2188 struct requests requests; 2189 struct request *req; 2190 u_char type; 2191 2192 TAILQ_INIT(&requests); 2193 2194 if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL) 2195 return -1; 2196 2197 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 2198 (!S_ISREG(a->perm))) { 2199 error("Cannot download non-regular file: %s", from_path); 2200 return(-1); 2201 } 2202 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 2203 size = a->size; 2204 else 2205 size = 0; 2206 2207 buflen = from->download_buflen; 2208 if (buflen > to->upload_buflen) 2209 buflen = to->upload_buflen; 2210 2211 /* Send open request to read side */ 2212 if (send_open(from, from_path, "origin", SSH2_FXF_READ, NULL, 2213 &from_handle, &from_handle_len) != 0) 2214 return -1; 2215 2216 /* Send open request to write side */ 2217 a->flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2218 a->flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2219 a->perm &= 0777; 2220 if (!preserve_flag) 2221 a->flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2222 if (send_open(to, to_path, "dest", 2223 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2224 &to_handle, &to_handle_len) != 0) { 2225 do_close(from, from_handle, from_handle_len); 2226 return -1; 2227 } 2228 2229 /* Read from remote "from" and write to remote "to" */ 2230 offset = 0; 2231 write_error = read_error = num_req = num_upload_req = 0; 2232 max_req = 1; 2233 progress_counter = 0; 2234 2235 if (showprogress && size != 0) { 2236 start_progress_meter(progress_meter_path(from_path), 2237 size, &progress_counter); 2238 } 2239 if ((msg = sshbuf_new()) == NULL) 2240 fatal_f("sshbuf_new failed"); 2241 while (num_req > 0 || max_req > 0) { 2242 u_char *data; 2243 size_t len; 2244 2245 /* 2246 * Simulate EOF on interrupt: stop sending new requests and 2247 * allow outstanding requests to drain gracefully 2248 */ 2249 if (interrupted) { 2250 if (num_req == 0) /* If we haven't started yet... */ 2251 break; 2252 max_req = 0; 2253 } 2254 2255 /* Send some more requests */ 2256 while (num_req < max_req) { 2257 debug3("Request range %llu -> %llu (%d/%d)", 2258 (unsigned long long)offset, 2259 (unsigned long long)offset + buflen - 1, 2260 num_req, max_req); 2261 req = request_enqueue(&requests, from->msg_id++, 2262 buflen, offset); 2263 offset += buflen; 2264 num_req++; 2265 send_read_request(from, req->id, req->offset, 2266 req->len, from_handle, from_handle_len); 2267 } 2268 2269 /* Try to eat replies from the upload side (nonblocking) */ 2270 handle_dest_replies(to, to_path, 0, 2271 &num_upload_req, &write_error); 2272 2273 sshbuf_reset(msg); 2274 get_msg(from, msg); 2275 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2276 (r = sshbuf_get_u32(msg, &id)) != 0) 2277 fatal_fr(r, "parse"); 2278 debug3("Received origin reply T:%u I:%u R:%d", 2279 type, id, max_req); 2280 2281 /* Find the request in our queue */ 2282 if ((req = request_find(&requests, id)) == NULL) 2283 fatal("Unexpected reply %u", id); 2284 2285 switch (type) { 2286 case SSH2_FXP_STATUS: 2287 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2288 fatal_fr(r, "parse status"); 2289 if (status != SSH2_FX_EOF) 2290 read_error = 1; 2291 max_req = 0; 2292 TAILQ_REMOVE(&requests, req, tq); 2293 free(req); 2294 num_req--; 2295 break; 2296 case SSH2_FXP_DATA: 2297 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 2298 fatal_fr(r, "parse data"); 2299 debug3("Received data %llu -> %llu", 2300 (unsigned long long)req->offset, 2301 (unsigned long long)req->offset + len - 1); 2302 if (len > req->len) 2303 fatal("Received more data than asked for " 2304 "%zu > %zu", len, req->len); 2305 2306 /* Write this chunk out to the destination */ 2307 sshbuf_reset(msg); 2308 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 2309 (r = sshbuf_put_u32(msg, to->msg_id++)) != 0 || 2310 (r = sshbuf_put_string(msg, to_handle, 2311 to_handle_len)) != 0 || 2312 (r = sshbuf_put_u64(msg, req->offset)) != 0 || 2313 (r = sshbuf_put_string(msg, data, len)) != 0) 2314 fatal_fr(r, "compose write"); 2315 send_msg(to, msg); 2316 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%zu", 2317 id, (unsigned long long)offset, len); 2318 num_upload_req++; 2319 progress_counter += len; 2320 free(data); 2321 2322 if (len == req->len) { 2323 TAILQ_REMOVE(&requests, req, tq); 2324 free(req); 2325 num_req--; 2326 } else { 2327 /* Resend the request for the missing data */ 2328 debug3("Short data block, re-requesting " 2329 "%llu -> %llu (%2d)", 2330 (unsigned long long)req->offset + len, 2331 (unsigned long long)req->offset + 2332 req->len - 1, num_req); 2333 req->id = from->msg_id++; 2334 req->len -= len; 2335 req->offset += len; 2336 send_read_request(from, req->id, 2337 req->offset, req->len, 2338 from_handle, from_handle_len); 2339 /* Reduce the request size */ 2340 if (len < buflen) 2341 buflen = MAXIMUM(MIN_READ_SIZE, len); 2342 } 2343 if (max_req > 0) { /* max_req = 0 iff EOF received */ 2344 if (size > 0 && offset > size) { 2345 /* Only one request at a time 2346 * after the expected EOF */ 2347 debug3("Finish at %llu (%2d)", 2348 (unsigned long long)offset, 2349 num_req); 2350 max_req = 1; 2351 } else if (max_req < from->num_requests) { 2352 ++max_req; 2353 } 2354 } 2355 break; 2356 default: 2357 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 2358 SSH2_FXP_DATA, type); 2359 } 2360 } 2361 2362 if (showprogress && size) 2363 stop_progress_meter(); 2364 2365 /* Drain replies from the server (blocking) */ 2366 debug3_f("waiting for %u replies from destination", num_upload_req); 2367 handle_dest_replies(to, to_path, 1, &num_upload_req, &write_error); 2368 2369 /* Sanity check */ 2370 if (TAILQ_FIRST(&requests) != NULL) 2371 fatal("Transfer complete, but requests still in queue"); 2372 /* Truncate at 0 length on interrupt or error to avoid holes at dest */ 2373 if (read_error || write_error || interrupted) { 2374 debug("truncating \"%s\" at 0", to_path); 2375 do_close(to, to_handle, to_handle_len); 2376 free(to_handle); 2377 if (send_open(to, to_path, "dest", 2378 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2379 &to_handle, &to_handle_len) != 0) { 2380 error("truncation failed for \"%s\"", to_path); 2381 to_handle = NULL; 2382 } 2383 } 2384 if (read_error) { 2385 error("Couldn't read from origin file \"%s\" : %s", 2386 from_path, fx2txt(status)); 2387 status = -1; 2388 do_close(from, from_handle, from_handle_len); 2389 if (to_handle != NULL) 2390 do_close(to, to_handle, to_handle_len); 2391 } else if (write_error) { 2392 error("Couldn't write to \"%s\": %s", 2393 to_path, fx2txt(write_error)); 2394 status = SSH2_FX_FAILURE; 2395 do_close(from, from_handle, from_handle_len); 2396 if (to_handle != NULL) 2397 do_close(to, to_handle, to_handle_len); 2398 } else { 2399 if (do_close(from, from_handle, from_handle_len) != 0 || 2400 interrupted) 2401 status = -1; 2402 else 2403 status = SSH2_FX_OK; 2404 if (to_handle != NULL) { 2405 /* Need to resend utimes after write */ 2406 if (preserve_flag) 2407 do_fsetstat(to, to_handle, to_handle_len, a); 2408 do_close(to, to_handle, to_handle_len); 2409 } 2410 } 2411 sshbuf_free(msg); 2412 free(from_handle); 2413 free(to_handle); 2414 2415 return status == SSH2_FX_OK ? 0 : -1; 2416 } 2417 2418 static int 2419 crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, 2420 const char *from_path, const char *to_path, 2421 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 2422 int follow_link_flag) 2423 { 2424 int i, ret = 0; 2425 SFTP_DIRENT **dir_entries; 2426 char *filename, *new_from_path = NULL, *new_to_path = NULL; 2427 mode_t mode = 0777; 2428 Attrib curdir; 2429 2430 if (depth >= MAX_DIR_DEPTH) { 2431 error("Maximum directory depth exceeded: %d levels", depth); 2432 return -1; 2433 } 2434 2435 if (dirattrib == NULL && 2436 (dirattrib = do_stat(from, from_path, 1)) == NULL) { 2437 error("Unable to stat remote directory \"%s\"", from_path); 2438 return -1; 2439 } 2440 if (!S_ISDIR(dirattrib->perm)) { 2441 error("\"%s\" is not a directory", from_path); 2442 return -1; 2443 } 2444 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2445 mprintf("Retrieving %s\n", from_path); 2446 2447 curdir = *dirattrib; /* dirattrib will be clobbered */ 2448 curdir.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2449 curdir.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2450 if ((curdir.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) == 0) { 2451 debug("Origin did not send permissions for " 2452 "directory \"%s\"", to_path); 2453 curdir.perm = S_IWUSR|S_IXUSR; 2454 curdir.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 2455 } 2456 /* We need to be able to write to the directory while we transfer it */ 2457 mode = curdir.perm & 01777; 2458 curdir.perm = mode | (S_IWUSR|S_IXUSR); 2459 2460 /* 2461 * sftp lacks a portable status value to match errno EEXIST, 2462 * so if we get a failure back then we must check whether 2463 * the path already existed and is a directory. Ensure we can 2464 * write to the directory we create for the duration of the transfer. 2465 */ 2466 if (do_mkdir(to, to_path, &curdir, 0) != 0) { 2467 if ((dirattrib = do_stat(to, to_path, 0)) == NULL) 2468 return -1; 2469 if (!S_ISDIR(dirattrib->perm)) { 2470 error("\"%s\" exists but is not a directory", to_path); 2471 return -1; 2472 } 2473 } 2474 curdir.perm = mode; 2475 2476 if (do_readdir(from, from_path, &dir_entries) == -1) { 2477 error("%s: Failed to get directory contents", from_path); 2478 return -1; 2479 } 2480 2481 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 2482 free(new_from_path); 2483 free(new_to_path); 2484 2485 filename = dir_entries[i]->filename; 2486 new_from_path = path_append(from_path, filename); 2487 new_to_path = path_append(to_path, filename); 2488 2489 if (S_ISDIR(dir_entries[i]->a.perm)) { 2490 if (strcmp(filename, ".") == 0 || 2491 strcmp(filename, "..") == 0) 2492 continue; 2493 if (crossload_dir_internal(from, to, 2494 new_from_path, new_to_path, 2495 depth + 1, &(dir_entries[i]->a), preserve_flag, 2496 print_flag, follow_link_flag) == -1) 2497 ret = -1; 2498 } else if (S_ISREG(dir_entries[i]->a.perm) || 2499 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 2500 /* 2501 * If this is a symlink then don't send the link's 2502 * Attrib. do_download() will do a FXP_STAT operation 2503 * and get the link target's attributes. 2504 */ 2505 if (do_crossload(from, to, new_from_path, new_to_path, 2506 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 2507 &(dir_entries[i]->a), preserve_flag) == -1) { 2508 error("Transfer of file %s to %s failed", 2509 new_from_path, new_to_path); 2510 ret = -1; 2511 } 2512 } else 2513 logit("%s: not a regular file\n", new_from_path); 2514 2515 } 2516 free(new_to_path); 2517 free(new_from_path); 2518 2519 do_setstat(to, to_path, &curdir); 2520 2521 free_sftp_dirents(dir_entries); 2522 2523 return ret; 2524 } 2525 2526 int 2527 crossload_dir(struct sftp_conn *from, struct sftp_conn *to, 2528 const char *from_path, const char *to_path, 2529 Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) 2530 { 2531 char *from_path_canon; 2532 int ret; 2533 2534 if ((from_path_canon = do_realpath(from, from_path)) == NULL) { 2535 error("Unable to canonicalize path \"%s\"", from_path); 2536 return -1; 2537 } 2538 2539 ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0, 2540 dirattrib, preserve_flag, print_flag, follow_link_flag); 2541 free(from_path_canon); 2542 return ret; 2543 } 2544 2545 char * 2546 path_append(const char *p1, const char *p2) 2547 { 2548 char *ret; 2549 size_t len = strlen(p1) + strlen(p2) + 2; 2550 2551 ret = xmalloc(len); 2552 strlcpy(ret, p1, len); 2553 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 2554 strlcat(ret, "/", len); 2555 strlcat(ret, p2, len); 2556 2557 return(ret); 2558 } 2559 2560 char * 2561 make_absolute(char *p, const char *pwd) 2562 { 2563 char *abs_str; 2564 2565 /* Derelativise */ 2566 if (p && !path_absolute(p)) { 2567 abs_str = path_append(pwd, p); 2568 free(p); 2569 return(abs_str); 2570 } else 2571 return(p); 2572 } 2573 2574 int 2575 remote_is_dir(struct sftp_conn *conn, const char *path) 2576 { 2577 Attrib *a; 2578 2579 /* XXX: report errors? */ 2580 if ((a = do_stat(conn, path, 1)) == NULL) 2581 return(0); 2582 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 2583 return(0); 2584 return(S_ISDIR(a->perm)); 2585 } 2586 2587 2588 int 2589 local_is_dir(const char *path) 2590 { 2591 struct stat sb; 2592 2593 /* XXX: report errors? */ 2594 if (stat(path, &sb) == -1) 2595 return(0); 2596 2597 return(S_ISDIR(sb.st_mode)); 2598 } 2599 2600 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 2601 int 2602 globpath_is_dir(const char *pathname) 2603 { 2604 size_t l = strlen(pathname); 2605 2606 return l > 0 && pathname[l - 1] == '/'; 2607 } 2608 2609