diff options
author | Damien Miller <djm@mindrot.org> | 2002-02-13 14:10:32 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2002-02-13 14:10:32 +1100 |
commit | 3db5f530d0fdf8044d6014ab12940efe0bbecca7 (patch) | |
tree | 578c5ea0091f934c13d40264b033bbd2532d2e9a /sftp-client.c | |
parent | 3606ee29388781894e6374030d0e40fa46da4cf9 (diff) |
- djm@cvs.openbsd.org 2002/02/13 00:59:23
[sftp-client.c sftp-client.h sftp-glob.c sftp-glob.h sftp.h]
[sftp-int.c sftp-int.h]
API cleanup and backwards compat for filexfer v.0 servers; ok markus@
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 302 |
1 files changed, 176 insertions, 126 deletions
diff --git a/sftp-client.c b/sftp-client.c index cb11fd581..481341c66 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001-2002 Damien Miller. All rights reserved. | 2 | * Copyright (c) 2001,2002 Damien Miller. All rights reserved. |
3 | * | 3 | * |
4 | * Redistribution and use in source and binary forms, with or without | 4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 5 | * modification, are permitted provided that the following conditions |
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | /* XXX: memleaks */ | 25 | /* XXX: memleaks */ |
26 | /* XXX: signed vs unsigned */ | 26 | /* XXX: signed vs unsigned */ |
27 | /* XXX: we use fatal too much, error may be more appropriate in places */ | 27 | /* XXX: remove all logging, only return status codes */ |
28 | /* XXX: copy between two remote sites */ | 28 | /* XXX: copy between two remote sites */ |
29 | 29 | ||
30 | #include "includes.h" | 30 | #include "includes.h" |
31 | RCSID("$OpenBSD: sftp-client.c,v 1.22 2002/02/12 12:44:46 djm Exp $"); | 31 | RCSID("$OpenBSD: sftp-client.c,v 1.23 2002/02/13 00:59:23 djm Exp $"); |
32 | 32 | ||
33 | #if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) | 33 | #if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) |
34 | #include <sys/queue.h> | 34 | #include <sys/queue.h> |
@@ -50,8 +50,14 @@ RCSID("$OpenBSD: sftp-client.c,v 1.22 2002/02/12 12:44:46 djm Exp $"); | |||
50 | /* Minimum amount of data to read at at time */ | 50 | /* Minimum amount of data to read at at time */ |
51 | #define MIN_READ_SIZE 512 | 51 | #define MIN_READ_SIZE 512 |
52 | 52 | ||
53 | /* Message ID */ | 53 | struct sftp_conn { |
54 | static u_int msg_id = 1; | 54 | int fd_in; |
55 | int fd_out; | ||
56 | u_int transfer_buflen; | ||
57 | u_int num_requests; | ||
58 | u_int version; | ||
59 | u_int msg_id; | ||
60 | }; | ||
55 | 61 | ||
56 | static void | 62 | static void |
57 | send_msg(int fd, Buffer *m) | 63 | send_msg(int fd, Buffer *m) |
@@ -219,11 +225,12 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
219 | return(a); | 225 | return(a); |
220 | } | 226 | } |
221 | 227 | ||
222 | int | 228 | struct sftp_conn * |
223 | do_init(int fd_in, int fd_out) | 229 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) |
224 | { | 230 | { |
225 | int type, version; | 231 | int type, version; |
226 | Buffer msg; | 232 | Buffer msg; |
233 | struct sftp_conn *ret; | ||
227 | 234 | ||
228 | buffer_init(&msg); | 235 | buffer_init(&msg); |
229 | buffer_put_char(&msg, SSH2_FXP_INIT); | 236 | buffer_put_char(&msg, SSH2_FXP_INIT); |
@@ -239,7 +246,7 @@ do_init(int fd_in, int fd_out) | |||
239 | error("Invalid packet back from SSH2_FXP_INIT (type %d)", | 246 | error("Invalid packet back from SSH2_FXP_INIT (type %d)", |
240 | type); | 247 | type); |
241 | buffer_free(&msg); | 248 | buffer_free(&msg); |
242 | return(-1); | 249 | return(NULL); |
243 | } | 250 | } |
244 | version = buffer_get_int(&msg); | 251 | version = buffer_get_int(&msg); |
245 | 252 | ||
@@ -257,25 +264,43 @@ do_init(int fd_in, int fd_out) | |||
257 | 264 | ||
258 | buffer_free(&msg); | 265 | buffer_free(&msg); |
259 | 266 | ||
260 | return(version); | 267 | ret = xmalloc(sizeof(*ret)); |
268 | ret->fd_in = fd_in; | ||
269 | ret->fd_out = fd_out; | ||
270 | ret->transfer_buflen = transfer_buflen; | ||
271 | ret->num_requests = num_requests; | ||
272 | ret->version = version; | ||
273 | ret->msg_id = 1; | ||
274 | |||
275 | /* Some filexfer v.0 servers don't support large packets */ | ||
276 | if (version == 0) | ||
277 | ret->transfer_buflen = MAX(ret->transfer_buflen, 20480); | ||
278 | |||
279 | return(ret); | ||
280 | } | ||
281 | |||
282 | u_int | ||
283 | sftp_proto_version(struct sftp_conn *conn) | ||
284 | { | ||
285 | return(conn->version); | ||
261 | } | 286 | } |
262 | 287 | ||
263 | int | 288 | int |
264 | do_close(int fd_in, int fd_out, char *handle, u_int handle_len) | 289 | do_close(struct sftp_conn *conn, char *handle, u_int handle_len) |
265 | { | 290 | { |
266 | u_int id, status; | 291 | u_int id, status; |
267 | Buffer msg; | 292 | Buffer msg; |
268 | 293 | ||
269 | buffer_init(&msg); | 294 | buffer_init(&msg); |
270 | 295 | ||
271 | id = msg_id++; | 296 | id = conn->msg_id++; |
272 | buffer_put_char(&msg, SSH2_FXP_CLOSE); | 297 | buffer_put_char(&msg, SSH2_FXP_CLOSE); |
273 | buffer_put_int(&msg, id); | 298 | buffer_put_int(&msg, id); |
274 | buffer_put_string(&msg, handle, handle_len); | 299 | buffer_put_string(&msg, handle, handle_len); |
275 | send_msg(fd_out, &msg); | 300 | send_msg(conn->fd_out, &msg); |
276 | debug3("Sent message SSH2_FXP_CLOSE I:%d", id); | 301 | debug3("Sent message SSH2_FXP_CLOSE I:%d", id); |
277 | 302 | ||
278 | status = get_status(fd_in, id); | 303 | status = get_status(conn->fd_in, id); |
279 | if (status != SSH2_FX_OK) | 304 | if (status != SSH2_FX_OK) |
280 | error("Couldn't close file: %s", fx2txt(status)); | 305 | error("Couldn't close file: %s", fx2txt(status)); |
281 | 306 | ||
@@ -286,24 +311,24 @@ do_close(int fd_in, int fd_out, char *handle, u_int handle_len) | |||
286 | 311 | ||
287 | 312 | ||
288 | static int | 313 | static int |
289 | do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, | 314 | do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, |
290 | SFTP_DIRENT ***dir) | 315 | SFTP_DIRENT ***dir) |
291 | { | 316 | { |
292 | Buffer msg; | 317 | Buffer msg; |
293 | u_int type, id, handle_len, i, expected_id, ents = 0; | 318 | u_int type, id, handle_len, i, expected_id, ents = 0; |
294 | char *handle; | 319 | char *handle; |
295 | 320 | ||
296 | id = msg_id++; | 321 | id = conn->msg_id++; |
297 | 322 | ||
298 | buffer_init(&msg); | 323 | buffer_init(&msg); |
299 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); | 324 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); |
300 | buffer_put_int(&msg, id); | 325 | buffer_put_int(&msg, id); |
301 | buffer_put_cstring(&msg, path); | 326 | buffer_put_cstring(&msg, path); |
302 | send_msg(fd_out, &msg); | 327 | send_msg(conn->fd_out, &msg); |
303 | 328 | ||
304 | buffer_clear(&msg); | 329 | buffer_clear(&msg); |
305 | 330 | ||
306 | handle = get_handle(fd_in, id, &handle_len); | 331 | handle = get_handle(conn->fd_in, id, &handle_len); |
307 | if (handle == NULL) | 332 | if (handle == NULL) |
308 | return(-1); | 333 | return(-1); |
309 | 334 | ||
@@ -316,7 +341,7 @@ do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, | |||
316 | for (;;) { | 341 | for (;;) { |
317 | int count; | 342 | int count; |
318 | 343 | ||
319 | id = expected_id = msg_id++; | 344 | id = expected_id = conn->msg_id++; |
320 | 345 | ||
321 | debug3("Sending SSH2_FXP_READDIR I:%d", id); | 346 | debug3("Sending SSH2_FXP_READDIR I:%d", id); |
322 | 347 | ||
@@ -324,11 +349,11 @@ do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, | |||
324 | buffer_put_char(&msg, SSH2_FXP_READDIR); | 349 | buffer_put_char(&msg, SSH2_FXP_READDIR); |
325 | buffer_put_int(&msg, id); | 350 | buffer_put_int(&msg, id); |
326 | buffer_put_string(&msg, handle, handle_len); | 351 | buffer_put_string(&msg, handle, handle_len); |
327 | send_msg(fd_out, &msg); | 352 | send_msg(conn->fd_out, &msg); |
328 | 353 | ||
329 | buffer_clear(&msg); | 354 | buffer_clear(&msg); |
330 | 355 | ||
331 | get_msg(fd_in, &msg); | 356 | get_msg(conn->fd_in, &msg); |
332 | 357 | ||
333 | type = buffer_get_char(&msg); | 358 | type = buffer_get_char(&msg); |
334 | id = buffer_get_int(&msg); | 359 | id = buffer_get_int(&msg); |
@@ -348,7 +373,7 @@ do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, | |||
348 | } else { | 373 | } else { |
349 | error("Couldn't read directory: %s", | 374 | error("Couldn't read directory: %s", |
350 | fx2txt(status)); | 375 | fx2txt(status)); |
351 | do_close(fd_in, fd_out, handle, handle_len); | 376 | do_close(conn, handle, handle_len); |
352 | return(status); | 377 | return(status); |
353 | } | 378 | } |
354 | } else if (type != SSH2_FXP_NAME) | 379 | } else if (type != SSH2_FXP_NAME) |
@@ -386,22 +411,22 @@ do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, | |||
386 | } | 411 | } |
387 | 412 | ||
388 | buffer_free(&msg); | 413 | buffer_free(&msg); |
389 | do_close(fd_in, fd_out, handle, handle_len); | 414 | do_close(conn, handle, handle_len); |
390 | xfree(handle); | 415 | xfree(handle); |
391 | 416 | ||
392 | return(0); | 417 | return(0); |
393 | } | 418 | } |
394 | 419 | ||
395 | int | 420 | int |
396 | do_ls(int fd_in, int fd_out, char *path) | 421 | do_ls(struct sftp_conn *conn, char *path) |
397 | { | 422 | { |
398 | return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); | 423 | return(do_lsreaddir(conn, path, 1, NULL)); |
399 | } | 424 | } |
400 | 425 | ||
401 | int | 426 | int |
402 | do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) | 427 | do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) |
403 | { | 428 | { |
404 | return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); | 429 | return(do_lsreaddir(conn, path, 0, dir)); |
405 | } | 430 | } |
406 | 431 | ||
407 | void free_sftp_dirents(SFTP_DIRENT **s) | 432 | void free_sftp_dirents(SFTP_DIRENT **s) |
@@ -417,30 +442,31 @@ void free_sftp_dirents(SFTP_DIRENT **s) | |||
417 | } | 442 | } |
418 | 443 | ||
419 | int | 444 | int |
420 | do_rm(int fd_in, int fd_out, char *path) | 445 | do_rm(struct sftp_conn *conn, char *path) |
421 | { | 446 | { |
422 | u_int status, id; | 447 | u_int status, id; |
423 | 448 | ||
424 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); | 449 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
425 | 450 | ||
426 | id = msg_id++; | 451 | id = conn->msg_id++; |
427 | send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path)); | 452 | send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, |
428 | status = get_status(fd_in, id); | 453 | strlen(path)); |
454 | status = get_status(conn->fd_in, id); | ||
429 | if (status != SSH2_FX_OK) | 455 | if (status != SSH2_FX_OK) |
430 | error("Couldn't delete file: %s", fx2txt(status)); | 456 | error("Couldn't delete file: %s", fx2txt(status)); |
431 | return(status); | 457 | return(status); |
432 | } | 458 | } |
433 | 459 | ||
434 | int | 460 | int |
435 | do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) | 461 | do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) |
436 | { | 462 | { |
437 | u_int status, id; | 463 | u_int status, id; |
438 | 464 | ||
439 | id = msg_id++; | 465 | id = conn->msg_id++; |
440 | send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path, | 466 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, |
441 | strlen(path), a); | 467 | strlen(path), a); |
442 | 468 | ||
443 | status = get_status(fd_in, id); | 469 | status = get_status(conn->fd_in, id); |
444 | if (status != SSH2_FX_OK) | 470 | if (status != SSH2_FX_OK) |
445 | error("Couldn't create directory: %s", fx2txt(status)); | 471 | error("Couldn't create directory: %s", fx2txt(status)); |
446 | 472 | ||
@@ -448,14 +474,15 @@ do_mkdir(int fd_in, int fd_out, char *path, Attrib *a) | |||
448 | } | 474 | } |
449 | 475 | ||
450 | int | 476 | int |
451 | do_rmdir(int fd_in, int fd_out, char *path) | 477 | do_rmdir(struct sftp_conn *conn, char *path) |
452 | { | 478 | { |
453 | u_int status, id; | 479 | u_int status, id; |
454 | 480 | ||
455 | id = msg_id++; | 481 | id = conn->msg_id++; |
456 | send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path)); | 482 | send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, |
483 | strlen(path)); | ||
457 | 484 | ||
458 | status = get_status(fd_in, id); | 485 | status = get_status(conn->fd_in, id); |
459 | if (status != SSH2_FX_OK) | 486 | if (status != SSH2_FX_OK) |
460 | error("Couldn't remove directory: %s", fx2txt(status)); | 487 | error("Couldn't remove directory: %s", fx2txt(status)); |
461 | 488 | ||
@@ -463,45 +490,61 @@ do_rmdir(int fd_in, int fd_out, char *path) | |||
463 | } | 490 | } |
464 | 491 | ||
465 | Attrib * | 492 | Attrib * |
466 | do_stat(int fd_in, int fd_out, char *path, int quiet) | 493 | do_stat(struct sftp_conn *conn, char *path, int quiet) |
467 | { | 494 | { |
468 | u_int id; | 495 | u_int id; |
469 | 496 | ||
470 | id = msg_id++; | 497 | id = conn->msg_id++; |
471 | send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); | 498 | |
472 | return(get_decode_stat(fd_in, id, quiet)); | 499 | send_string_request(conn->fd_out, id, |
500 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, | ||
501 | path, strlen(path)); | ||
502 | |||
503 | return(get_decode_stat(conn->fd_in, id, quiet)); | ||
473 | } | 504 | } |
474 | 505 | ||
475 | Attrib * | 506 | Attrib * |
476 | do_lstat(int fd_in, int fd_out, char *path, int quiet) | 507 | do_lstat(struct sftp_conn *conn, char *path, int quiet) |
477 | { | 508 | { |
478 | u_int id; | 509 | u_int id; |
479 | 510 | ||
480 | id = msg_id++; | 511 | if (conn->version == 0) { |
481 | send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); | 512 | if (quiet) |
482 | return(get_decode_stat(fd_in, id, quiet)); | 513 | debug("Server version does not support lstat operation"); |
514 | else | ||
515 | error("Server version does not support lstat operation"); | ||
516 | return(NULL); | ||
517 | } | ||
518 | |||
519 | id = conn->msg_id++; | ||
520 | send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, | ||
521 | strlen(path)); | ||
522 | |||
523 | return(get_decode_stat(conn->fd_in, id, quiet)); | ||
483 | } | 524 | } |
484 | 525 | ||
485 | Attrib * | 526 | Attrib * |
486 | do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet) | 527 | do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) |
487 | { | 528 | { |
488 | u_int id; | 529 | u_int id; |
489 | 530 | ||
490 | id = msg_id++; | 531 | id = conn->msg_id++; |
491 | send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); | 532 | send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, |
492 | return(get_decode_stat(fd_in, id, quiet)); | 533 | handle_len); |
534 | |||
535 | return(get_decode_stat(conn->fd_in, id, quiet)); | ||
493 | } | 536 | } |
494 | 537 | ||
495 | int | 538 | int |
496 | do_setstat(int fd_in, int fd_out, char *path, Attrib *a) | 539 | do_setstat(struct sftp_conn *conn, char *path, Attrib *a) |
497 | { | 540 | { |
498 | u_int status, id; | 541 | u_int status, id; |
499 | 542 | ||
500 | id = msg_id++; | 543 | id = conn->msg_id++; |
501 | send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path, | 544 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, |
502 | strlen(path), a); | 545 | strlen(path), a); |
503 | 546 | ||
504 | status = get_status(fd_in, id); | 547 | status = get_status(conn->fd_in, id); |
505 | if (status != SSH2_FX_OK) | 548 | if (status != SSH2_FX_OK) |
506 | error("Couldn't setstat on \"%s\": %s", path, | 549 | error("Couldn't setstat on \"%s\": %s", path, |
507 | fx2txt(status)); | 550 | fx2txt(status)); |
@@ -510,16 +553,16 @@ do_setstat(int fd_in, int fd_out, char *path, Attrib *a) | |||
510 | } | 553 | } |
511 | 554 | ||
512 | int | 555 | int |
513 | do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, | 556 | do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, |
514 | Attrib *a) | 557 | Attrib *a) |
515 | { | 558 | { |
516 | u_int status, id; | 559 | u_int status, id; |
517 | 560 | ||
518 | id = msg_id++; | 561 | id = conn->msg_id++; |
519 | send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle, | 562 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, |
520 | handle_len, a); | 563 | handle_len, a); |
521 | 564 | ||
522 | status = get_status(fd_in, id); | 565 | status = get_status(conn->fd_in, id); |
523 | if (status != SSH2_FX_OK) | 566 | if (status != SSH2_FX_OK) |
524 | error("Couldn't fsetstat: %s", fx2txt(status)); | 567 | error("Couldn't fsetstat: %s", fx2txt(status)); |
525 | 568 | ||
@@ -527,19 +570,20 @@ do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len, | |||
527 | } | 570 | } |
528 | 571 | ||
529 | char * | 572 | char * |
530 | do_realpath(int fd_in, int fd_out, char *path) | 573 | do_realpath(struct sftp_conn *conn, char *path) |
531 | { | 574 | { |
532 | Buffer msg; | 575 | Buffer msg; |
533 | u_int type, expected_id, count, id; | 576 | u_int type, expected_id, count, id; |
534 | char *filename, *longname; | 577 | char *filename, *longname; |
535 | Attrib *a; | 578 | Attrib *a; |
536 | 579 | ||
537 | expected_id = id = msg_id++; | 580 | expected_id = id = conn->msg_id++; |
538 | send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path)); | 581 | send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, |
582 | strlen(path)); | ||
539 | 583 | ||
540 | buffer_init(&msg); | 584 | buffer_init(&msg); |
541 | 585 | ||
542 | get_msg(fd_in, &msg); | 586 | get_msg(conn->fd_in, &msg); |
543 | type = buffer_get_char(&msg); | 587 | type = buffer_get_char(&msg); |
544 | id = buffer_get_int(&msg); | 588 | id = buffer_get_int(&msg); |
545 | 589 | ||
@@ -573,7 +617,7 @@ do_realpath(int fd_in, int fd_out, char *path) | |||
573 | } | 617 | } |
574 | 618 | ||
575 | int | 619 | int |
576 | do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) | 620 | do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) |
577 | { | 621 | { |
578 | Buffer msg; | 622 | Buffer msg; |
579 | u_int status, id; | 623 | u_int status, id; |
@@ -581,65 +625,71 @@ do_rename(int fd_in, int fd_out, char *oldpath, char *newpath) | |||
581 | buffer_init(&msg); | 625 | buffer_init(&msg); |
582 | 626 | ||
583 | /* Send rename request */ | 627 | /* Send rename request */ |
584 | id = msg_id++; | 628 | id = conn->msg_id++; |
585 | buffer_put_char(&msg, SSH2_FXP_RENAME); | 629 | buffer_put_char(&msg, SSH2_FXP_RENAME); |
586 | buffer_put_int(&msg, id); | 630 | buffer_put_int(&msg, id); |
587 | buffer_put_cstring(&msg, oldpath); | 631 | buffer_put_cstring(&msg, oldpath); |
588 | buffer_put_cstring(&msg, newpath); | 632 | buffer_put_cstring(&msg, newpath); |
589 | send_msg(fd_out, &msg); | 633 | send_msg(conn->fd_out, &msg); |
590 | debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, | 634 | debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, |
591 | newpath); | 635 | newpath); |
592 | buffer_free(&msg); | 636 | buffer_free(&msg); |
593 | 637 | ||
594 | status = get_status(fd_in, id); | 638 | status = get_status(conn->fd_in, id); |
595 | if (status != SSH2_FX_OK) | 639 | if (status != SSH2_FX_OK) |
596 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, | 640 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, |
597 | fx2txt(status)); | 641 | newpath, fx2txt(status)); |
598 | 642 | ||
599 | return(status); | 643 | return(status); |
600 | } | 644 | } |
601 | 645 | ||
602 | int | 646 | int |
603 | do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath) | 647 | do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) |
604 | { | 648 | { |
605 | Buffer msg; | 649 | Buffer msg; |
606 | u_int status, id; | 650 | u_int status, id; |
607 | 651 | ||
652 | if (conn->version < 3) { | ||
653 | error("This server does not support the symlink operation"); | ||
654 | return(SSH2_FX_OP_UNSUPPORTED); | ||
655 | } | ||
656 | |||
608 | buffer_init(&msg); | 657 | buffer_init(&msg); |
609 | 658 | ||
610 | /* Send rename request */ | 659 | /* Send rename request */ |
611 | id = msg_id++; | 660 | id = conn->msg_id++; |
612 | buffer_put_char(&msg, SSH2_FXP_SYMLINK); | 661 | buffer_put_char(&msg, SSH2_FXP_SYMLINK); |
613 | buffer_put_int(&msg, id); | 662 | buffer_put_int(&msg, id); |
614 | buffer_put_cstring(&msg, oldpath); | 663 | buffer_put_cstring(&msg, oldpath); |
615 | buffer_put_cstring(&msg, newpath); | 664 | buffer_put_cstring(&msg, newpath); |
616 | send_msg(fd_out, &msg); | 665 | send_msg(conn->fd_out, &msg); |
617 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, | 666 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, |
618 | newpath); | 667 | newpath); |
619 | buffer_free(&msg); | 668 | buffer_free(&msg); |
620 | 669 | ||
621 | status = get_status(fd_in, id); | 670 | status = get_status(conn->fd_in, id); |
622 | if (status != SSH2_FX_OK) | 671 | if (status != SSH2_FX_OK) |
623 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, | 672 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, |
624 | fx2txt(status)); | 673 | newpath, fx2txt(status)); |
625 | 674 | ||
626 | return(status); | 675 | return(status); |
627 | } | 676 | } |
628 | 677 | ||
629 | char * | 678 | char * |
630 | do_readlink(int fd_in, int fd_out, char *path) | 679 | do_readlink(struct sftp_conn *conn, char *path) |
631 | { | 680 | { |
632 | Buffer msg; | 681 | Buffer msg; |
633 | u_int type, expected_id, count, id; | 682 | u_int type, expected_id, count, id; |
634 | char *filename, *longname; | 683 | char *filename, *longname; |
635 | Attrib *a; | 684 | Attrib *a; |
636 | 685 | ||
637 | expected_id = id = msg_id++; | 686 | expected_id = id = conn->msg_id++; |
638 | send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path)); | 687 | send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, |
688 | strlen(path)); | ||
639 | 689 | ||
640 | buffer_init(&msg); | 690 | buffer_init(&msg); |
641 | 691 | ||
642 | get_msg(fd_in, &msg); | 692 | get_msg(conn->fd_in, &msg); |
643 | type = buffer_get_char(&msg); | 693 | type = buffer_get_char(&msg); |
644 | id = buffer_get_int(&msg); | 694 | id = buffer_get_int(&msg); |
645 | 695 | ||
@@ -690,8 +740,8 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | |||
690 | } | 740 | } |
691 | 741 | ||
692 | int | 742 | int |
693 | do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | 743 | do_download(struct sftp_conn *conn, char *remote_path, char *local_path, |
694 | int pflag, size_t buflen, int num_requests) | 744 | int pflag) |
695 | { | 745 | { |
696 | Attrib junk, *a; | 746 | Attrib junk, *a; |
697 | Buffer msg; | 747 | Buffer msg; |
@@ -699,7 +749,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
699 | int local_fd, status, num_req, max_req, write_error; | 749 | int local_fd, status, num_req, max_req, write_error; |
700 | int read_error, write_errno; | 750 | int read_error, write_errno; |
701 | u_int64_t offset, size; | 751 | u_int64_t offset, size; |
702 | u_int handle_len, mode, type, id; | 752 | u_int handle_len, mode, type, id, buflen; |
703 | struct request { | 753 | struct request { |
704 | u_int id; | 754 | u_int id; |
705 | u_int len; | 755 | u_int len; |
@@ -711,7 +761,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
711 | 761 | ||
712 | TAILQ_INIT(&requests); | 762 | TAILQ_INIT(&requests); |
713 | 763 | ||
714 | a = do_stat(fd_in, fd_out, remote_path, 0); | 764 | a = do_stat(conn, remote_path, 0); |
715 | if (a == NULL) | 765 | if (a == NULL) |
716 | return(-1); | 766 | return(-1); |
717 | 767 | ||
@@ -732,33 +782,34 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
732 | else | 782 | else |
733 | size = 0; | 783 | size = 0; |
734 | 784 | ||
735 | local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); | 785 | buflen = conn->transfer_buflen; |
736 | if (local_fd == -1) { | ||
737 | error("Couldn't open local file \"%s\" for writing: %s", | ||
738 | local_path, strerror(errno)); | ||
739 | return(-1); | ||
740 | } | ||
741 | |||
742 | buffer_init(&msg); | 786 | buffer_init(&msg); |
743 | 787 | ||
744 | /* Send open request */ | 788 | /* Send open request */ |
745 | id = msg_id++; | 789 | id = conn->msg_id++; |
746 | buffer_put_char(&msg, SSH2_FXP_OPEN); | 790 | buffer_put_char(&msg, SSH2_FXP_OPEN); |
747 | buffer_put_int(&msg, id); | 791 | buffer_put_int(&msg, id); |
748 | buffer_put_cstring(&msg, remote_path); | 792 | buffer_put_cstring(&msg, remote_path); |
749 | buffer_put_int(&msg, SSH2_FXF_READ); | 793 | buffer_put_int(&msg, SSH2_FXF_READ); |
750 | attrib_clear(&junk); /* Send empty attributes */ | 794 | attrib_clear(&junk); /* Send empty attributes */ |
751 | encode_attrib(&msg, &junk); | 795 | encode_attrib(&msg, &junk); |
752 | send_msg(fd_out, &msg); | 796 | send_msg(conn->fd_out, &msg); |
753 | debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); | 797 | debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); |
754 | 798 | ||
755 | handle = get_handle(fd_in, id, &handle_len); | 799 | handle = get_handle(conn->fd_in, id, &handle_len); |
756 | if (handle == NULL) { | 800 | if (handle == NULL) { |
757 | buffer_free(&msg); | 801 | buffer_free(&msg); |
758 | close(local_fd); | 802 | close(local_fd); |
759 | return(-1); | 803 | return(-1); |
760 | } | 804 | } |
761 | 805 | ||
806 | local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); | ||
807 | if (local_fd == -1) { | ||
808 | error("Couldn't open local file \"%s\" for writing: %s", | ||
809 | local_path, strerror(errno)); | ||
810 | return(-1); | ||
811 | } | ||
812 | |||
762 | /* Read from remote and write to local */ | 813 | /* Read from remote and write to local */ |
763 | write_error = read_error = write_errno = num_req = offset = 0; | 814 | write_error = read_error = write_errno = num_req = offset = 0; |
764 | max_req = 1; | 815 | max_req = 1; |
@@ -771,18 +822,18 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
771 | debug3("Request range %llu -> %llu (%d/%d)", | 822 | debug3("Request range %llu -> %llu (%d/%d)", |
772 | offset, offset + buflen - 1, num_req, max_req); | 823 | offset, offset + buflen - 1, num_req, max_req); |
773 | req = xmalloc(sizeof(*req)); | 824 | req = xmalloc(sizeof(*req)); |
774 | req->id = msg_id++; | 825 | req->id = conn->msg_id++; |
775 | req->len = buflen; | 826 | req->len = buflen; |
776 | req->offset = offset; | 827 | req->offset = offset; |
777 | offset += buflen; | 828 | offset += buflen; |
778 | num_req++; | 829 | num_req++; |
779 | TAILQ_INSERT_TAIL(&requests, req, tq); | 830 | TAILQ_INSERT_TAIL(&requests, req, tq); |
780 | send_read_request(fd_out, req->id, req->offset, | 831 | send_read_request(conn->fd_out, req->id, req->offset, |
781 | req->len, handle, handle_len); | 832 | req->len, handle, handle_len); |
782 | } | 833 | } |
783 | 834 | ||
784 | buffer_clear(&msg); | 835 | buffer_clear(&msg); |
785 | get_msg(fd_in, &msg); | 836 | get_msg(conn->fd_in, &msg); |
786 | type = buffer_get_char(&msg); | 837 | type = buffer_get_char(&msg); |
787 | id = buffer_get_int(&msg); | 838 | id = buffer_get_int(&msg); |
788 | debug3("Received reply T:%d I:%d R:%d", type, id, max_req); | 839 | debug3("Received reply T:%d I:%d R:%d", type, id, max_req); |
@@ -830,12 +881,11 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
830 | debug3("Short data block, re-requesting " | 881 | debug3("Short data block, re-requesting " |
831 | "%llu -> %llu (%2d)", req->offset + len, | 882 | "%llu -> %llu (%2d)", req->offset + len, |
832 | req->offset + req->len - 1, num_req); | 883 | req->offset + req->len - 1, num_req); |
833 | req->id = msg_id++; | 884 | req->id = conn->msg_id++; |
834 | req->len -= len; | 885 | req->len -= len; |
835 | req->offset += len; | 886 | req->offset += len; |
836 | send_read_request(fd_out, req->id, | 887 | send_read_request(conn->fd_out, req->id, |
837 | req->offset, req->len, handle, | 888 | req->offset, req->len, handle, handle_len); |
838 | handle_len); | ||
839 | /* Reduce the request size */ | 889 | /* Reduce the request size */ |
840 | if (len < buflen) | 890 | if (len < buflen) |
841 | buflen = MAX(MIN_READ_SIZE, len); | 891 | buflen = MAX(MIN_READ_SIZE, len); |
@@ -848,7 +898,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
848 | offset, num_req); | 898 | offset, num_req); |
849 | max_req = 1; | 899 | max_req = 1; |
850 | } | 900 | } |
851 | else if (max_req < num_requests + 1) { | 901 | else if (max_req < conn->num_requests + 1) { |
852 | ++max_req; | 902 | ++max_req; |
853 | } | 903 | } |
854 | } | 904 | } |
@@ -864,17 +914,16 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
864 | fatal("Transfer complete, but requests still in queue"); | 914 | fatal("Transfer complete, but requests still in queue"); |
865 | 915 | ||
866 | if (read_error) { | 916 | if (read_error) { |
867 | error("Couldn't read from remote " | 917 | error("Couldn't read from remote file \"%s\" : %s", |
868 | "file \"%s\" : %s", remote_path, | 918 | remote_path, fx2txt(status)); |
869 | fx2txt(status)); | 919 | do_close(conn, handle, handle_len); |
870 | do_close(fd_in, fd_out, handle, handle_len); | ||
871 | } else if (write_error) { | 920 | } else if (write_error) { |
872 | error("Couldn't write to \"%s\": %s", local_path, | 921 | error("Couldn't write to \"%s\": %s", local_path, |
873 | strerror(write_errno)); | 922 | strerror(write_errno)); |
874 | status = -1; | 923 | status = -1; |
875 | do_close(fd_in, fd_out, handle, handle_len); | 924 | do_close(conn, handle, handle_len); |
876 | } else { | 925 | } else { |
877 | status = do_close(fd_in, fd_out, handle, handle_len); | 926 | status = do_close(conn, handle, handle_len); |
878 | 927 | ||
879 | /* Override umask and utimes if asked */ | 928 | /* Override umask and utimes if asked */ |
880 | #ifdef HAVE_FCHMOD | 929 | #ifdef HAVE_FCHMOD |
@@ -897,12 +946,13 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
897 | close(local_fd); | 946 | close(local_fd); |
898 | buffer_free(&msg); | 947 | buffer_free(&msg); |
899 | xfree(handle); | 948 | xfree(handle); |
900 | return status; | 949 | |
950 | return(status); | ||
901 | } | 951 | } |
902 | 952 | ||
903 | int | 953 | int |
904 | do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | 954 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, |
905 | int pflag, size_t buflen, int num_requests) | 955 | int pflag) |
906 | { | 956 | { |
907 | int local_fd, status; | 957 | int local_fd, status; |
908 | u_int handle_len, id, type; | 958 | u_int handle_len, id, type; |
@@ -946,18 +996,18 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
946 | buffer_init(&msg); | 996 | buffer_init(&msg); |
947 | 997 | ||
948 | /* Send open request */ | 998 | /* Send open request */ |
949 | id = msg_id++; | 999 | id = conn->msg_id++; |
950 | buffer_put_char(&msg, SSH2_FXP_OPEN); | 1000 | buffer_put_char(&msg, SSH2_FXP_OPEN); |
951 | buffer_put_int(&msg, id); | 1001 | buffer_put_int(&msg, id); |
952 | buffer_put_cstring(&msg, remote_path); | 1002 | buffer_put_cstring(&msg, remote_path); |
953 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); | 1003 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); |
954 | encode_attrib(&msg, &a); | 1004 | encode_attrib(&msg, &a); |
955 | send_msg(fd_out, &msg); | 1005 | send_msg(conn->fd_out, &msg); |
956 | debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); | 1006 | debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path); |
957 | 1007 | ||
958 | buffer_clear(&msg); | 1008 | buffer_clear(&msg); |
959 | 1009 | ||
960 | handle = get_handle(fd_in, id, &handle_len); | 1010 | handle = get_handle(conn->fd_in, id, &handle_len); |
961 | if (handle == NULL) { | 1011 | if (handle == NULL) { |
962 | close(local_fd); | 1012 | close(local_fd); |
963 | buffer_free(&msg); | 1013 | buffer_free(&msg); |
@@ -965,7 +1015,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
965 | } | 1015 | } |
966 | 1016 | ||
967 | startid = ackid = id + 1; | 1017 | startid = ackid = id + 1; |
968 | data = xmalloc(buflen); | 1018 | data = xmalloc(conn->transfer_buflen); |
969 | 1019 | ||
970 | /* Read from local and write to remote */ | 1020 | /* Read from local and write to remote */ |
971 | offset = 0; | 1021 | offset = 0; |
@@ -977,7 +1027,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
977 | * the last block of the file | 1027 | * the last block of the file |
978 | */ | 1028 | */ |
979 | do | 1029 | do |
980 | len = read(local_fd, data, buflen); | 1030 | len = read(local_fd, data, conn->transfer_buflen); |
981 | while ((len == -1) && (errno == EINTR || errno == EAGAIN)); | 1031 | while ((len == -1) && (errno == EINTR || errno == EAGAIN)); |
982 | 1032 | ||
983 | if (len == -1) | 1033 | if (len == -1) |
@@ -997,7 +1047,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
997 | buffer_put_string(&msg, handle, handle_len); | 1047 | buffer_put_string(&msg, handle, handle_len); |
998 | buffer_put_int64(&msg, offset); | 1048 | buffer_put_int64(&msg, offset); |
999 | buffer_put_string(&msg, data, len); | 1049 | buffer_put_string(&msg, data, len); |
1000 | send_msg(fd_out, &msg); | 1050 | send_msg(conn->fd_out, &msg); |
1001 | debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", | 1051 | debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", |
1002 | id, (u_int64_t)offset, len); | 1052 | id, (u_int64_t)offset, len); |
1003 | } else if (TAILQ_FIRST(&acks) == NULL) | 1053 | } else if (TAILQ_FIRST(&acks) == NULL) |
@@ -1006,9 +1056,10 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
1006 | if (ack == NULL) | 1056 | if (ack == NULL) |
1007 | fatal("Unexpected ACK %u", id); | 1057 | fatal("Unexpected ACK %u", id); |
1008 | 1058 | ||
1009 | if (id == startid || len == 0 || id - ackid >= num_requests) { | 1059 | if (id == startid || len == 0 || |
1060 | id - ackid >= conn->num_requests) { | ||
1010 | buffer_clear(&msg); | 1061 | buffer_clear(&msg); |
1011 | get_msg(fd_in, &msg); | 1062 | get_msg(conn->fd_in, &msg); |
1012 | type = buffer_get_char(&msg); | 1063 | type = buffer_get_char(&msg); |
1013 | id = buffer_get_int(&msg); | 1064 | id = buffer_get_int(&msg); |
1014 | 1065 | ||
@@ -1031,7 +1082,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
1031 | if (status != SSH2_FX_OK) { | 1082 | if (status != SSH2_FX_OK) { |
1032 | error("Couldn't write to remote file \"%s\": %s", | 1083 | error("Couldn't write to remote file \"%s\": %s", |
1033 | remote_path, fx2txt(status)); | 1084 | remote_path, fx2txt(status)); |
1034 | do_close(fd_in, fd_out, handle, handle_len); | 1085 | do_close(conn, handle, handle_len); |
1035 | close(local_fd); | 1086 | close(local_fd); |
1036 | goto done; | 1087 | goto done; |
1037 | } | 1088 | } |
@@ -1040,7 +1091,6 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
1040 | ++ackid; | 1091 | ++ackid; |
1041 | free(ack); | 1092 | free(ack); |
1042 | } | 1093 | } |
1043 | |||
1044 | offset += len; | 1094 | offset += len; |
1045 | } | 1095 | } |
1046 | xfree(data); | 1096 | xfree(data); |
@@ -1048,19 +1098,19 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
1048 | if (close(local_fd) == -1) { | 1098 | if (close(local_fd) == -1) { |
1049 | error("Couldn't close local file \"%s\": %s", local_path, | 1099 | error("Couldn't close local file \"%s\": %s", local_path, |
1050 | strerror(errno)); | 1100 | strerror(errno)); |
1051 | do_close(fd_in, fd_out, handle, handle_len); | 1101 | do_close(conn, handle, handle_len); |
1052 | status = -1; | 1102 | status = -1; |
1053 | goto done; | 1103 | goto done; |
1054 | } | 1104 | } |
1055 | 1105 | ||
1056 | /* Override umask and utimes if asked */ | 1106 | /* Override umask and utimes if asked */ |
1057 | if (pflag) | 1107 | if (pflag) |
1058 | do_fsetstat(fd_in, fd_out, handle, handle_len, &a); | 1108 | do_fsetstat(conn, handle, handle_len, &a); |
1059 | 1109 | ||
1060 | status = do_close(fd_in, fd_out, handle, handle_len); | 1110 | status = do_close(conn, handle, handle_len); |
1061 | 1111 | ||
1062 | done: | 1112 | done: |
1063 | xfree(handle); | 1113 | xfree(handle); |
1064 | buffer_free(&msg); | 1114 | buffer_free(&msg); |
1065 | return status; | 1115 | return(status); |
1066 | } | 1116 | } |