diff options
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 259 |
1 files changed, 160 insertions, 99 deletions
diff --git a/sftp-client.c b/sftp-client.c index 9dab47780..caa384b4e 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.92 2010/07/19 03:16:33 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -75,15 +75,28 @@ struct sftp_conn { | |||
75 | #define SFTP_EXT_POSIX_RENAME 0x00000001 | 75 | #define SFTP_EXT_POSIX_RENAME 0x00000001 |
76 | #define SFTP_EXT_STATVFS 0x00000002 | 76 | #define SFTP_EXT_STATVFS 0x00000002 |
77 | #define SFTP_EXT_FSTATVFS 0x00000004 | 77 | #define SFTP_EXT_FSTATVFS 0x00000004 |
78 | #define SFTP_EXT_HARDLINK 0x00000008 | ||
78 | u_int exts; | 79 | u_int exts; |
80 | u_int64_t limit_kbps; | ||
81 | struct bwlimit bwlimit_in, bwlimit_out; | ||
79 | }; | 82 | }; |
80 | 83 | ||
81 | static char * | 84 | static char * |
82 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 85 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
83 | __attribute__((format(printf, 4, 5))); | 86 | const char *errfmt, ...) __attribute__((format(printf, 4, 5))); |
87 | |||
88 | /* ARGSUSED */ | ||
89 | static int | ||
90 | sftpio(void *_bwlimit, size_t amount) | ||
91 | { | ||
92 | struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; | ||
93 | |||
94 | bandwidth_limit(bwlimit, amount); | ||
95 | return 0; | ||
96 | } | ||
84 | 97 | ||
85 | static void | 98 | static void |
86 | send_msg(int fd, Buffer *m) | 99 | send_msg(struct sftp_conn *conn, Buffer *m) |
87 | { | 100 | { |
88 | u_char mlen[4]; | 101 | u_char mlen[4]; |
89 | struct iovec iov[2]; | 102 | struct iovec iov[2]; |
@@ -98,19 +111,22 @@ send_msg(int fd, Buffer *m) | |||
98 | iov[1].iov_base = buffer_ptr(m); | 111 | iov[1].iov_base = buffer_ptr(m); |
99 | iov[1].iov_len = buffer_len(m); | 112 | iov[1].iov_len = buffer_len(m); |
100 | 113 | ||
101 | if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen)) | 114 | if (atomiciov6(writev, conn->fd_out, iov, 2, |
115 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != | ||
116 | buffer_len(m) + sizeof(mlen)) | ||
102 | fatal("Couldn't send packet: %s", strerror(errno)); | 117 | fatal("Couldn't send packet: %s", strerror(errno)); |
103 | 118 | ||
104 | buffer_clear(m); | 119 | buffer_clear(m); |
105 | } | 120 | } |
106 | 121 | ||
107 | static void | 122 | static void |
108 | get_msg(int fd, Buffer *m) | 123 | get_msg(struct sftp_conn *conn, Buffer *m) |
109 | { | 124 | { |
110 | u_int msg_len; | 125 | u_int msg_len; |
111 | 126 | ||
112 | buffer_append_space(m, 4); | 127 | buffer_append_space(m, 4); |
113 | if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { | 128 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, |
129 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { | ||
114 | if (errno == EPIPE) | 130 | if (errno == EPIPE) |
115 | fatal("Connection closed"); | 131 | fatal("Connection closed"); |
116 | else | 132 | else |
@@ -122,7 +138,9 @@ get_msg(int fd, Buffer *m) | |||
122 | fatal("Received message too long %u", msg_len); | 138 | fatal("Received message too long %u", msg_len); |
123 | 139 | ||
124 | buffer_append_space(m, msg_len); | 140 | buffer_append_space(m, msg_len); |
125 | if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { | 141 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, |
142 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) | ||
143 | != msg_len) { | ||
126 | if (errno == EPIPE) | 144 | if (errno == EPIPE) |
127 | fatal("Connection closed"); | 145 | fatal("Connection closed"); |
128 | else | 146 | else |
@@ -131,7 +149,7 @@ get_msg(int fd, Buffer *m) | |||
131 | } | 149 | } |
132 | 150 | ||
133 | static void | 151 | static void |
134 | send_string_request(int fd, u_int id, u_int code, char *s, | 152 | send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, |
135 | u_int len) | 153 | u_int len) |
136 | { | 154 | { |
137 | Buffer msg; | 155 | Buffer msg; |
@@ -140,14 +158,14 @@ send_string_request(int fd, u_int id, u_int code, char *s, | |||
140 | buffer_put_char(&msg, code); | 158 | buffer_put_char(&msg, code); |
141 | buffer_put_int(&msg, id); | 159 | buffer_put_int(&msg, id); |
142 | buffer_put_string(&msg, s, len); | 160 | buffer_put_string(&msg, s, len); |
143 | send_msg(fd, &msg); | 161 | send_msg(conn, &msg); |
144 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 162 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
145 | buffer_free(&msg); | 163 | buffer_free(&msg); |
146 | } | 164 | } |
147 | 165 | ||
148 | static void | 166 | static void |
149 | send_string_attrs_request(int fd, u_int id, u_int code, char *s, | 167 | send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, |
150 | u_int len, Attrib *a) | 168 | char *s, u_int len, Attrib *a) |
151 | { | 169 | { |
152 | Buffer msg; | 170 | Buffer msg; |
153 | 171 | ||
@@ -156,19 +174,19 @@ send_string_attrs_request(int fd, u_int id, u_int code, char *s, | |||
156 | buffer_put_int(&msg, id); | 174 | buffer_put_int(&msg, id); |
157 | buffer_put_string(&msg, s, len); | 175 | buffer_put_string(&msg, s, len); |
158 | encode_attrib(&msg, a); | 176 | encode_attrib(&msg, a); |
159 | send_msg(fd, &msg); | 177 | send_msg(conn, &msg); |
160 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 178 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
161 | buffer_free(&msg); | 179 | buffer_free(&msg); |
162 | } | 180 | } |
163 | 181 | ||
164 | static u_int | 182 | static u_int |
165 | get_status(int fd, u_int expected_id) | 183 | get_status(struct sftp_conn *conn, u_int expected_id) |
166 | { | 184 | { |
167 | Buffer msg; | 185 | Buffer msg; |
168 | u_int type, id, status; | 186 | u_int type, id, status; |
169 | 187 | ||
170 | buffer_init(&msg); | 188 | buffer_init(&msg); |
171 | get_msg(fd, &msg); | 189 | get_msg(conn, &msg); |
172 | type = buffer_get_char(&msg); | 190 | type = buffer_get_char(&msg); |
173 | id = buffer_get_int(&msg); | 191 | id = buffer_get_int(&msg); |
174 | 192 | ||
@@ -183,11 +201,12 @@ get_status(int fd, u_int expected_id) | |||
183 | 201 | ||
184 | debug3("SSH2_FXP_STATUS %u", status); | 202 | debug3("SSH2_FXP_STATUS %u", status); |
185 | 203 | ||
186 | return(status); | 204 | return status; |
187 | } | 205 | } |
188 | 206 | ||
189 | static char * | 207 | static char * |
190 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 208 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
209 | const char *errfmt, ...) | ||
191 | { | 210 | { |
192 | Buffer msg; | 211 | Buffer msg; |
193 | u_int type, id; | 212 | u_int type, id; |
@@ -201,7 +220,7 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
201 | va_end(args); | 220 | va_end(args); |
202 | 221 | ||
203 | buffer_init(&msg); | 222 | buffer_init(&msg); |
204 | get_msg(fd, &msg); | 223 | get_msg(conn, &msg); |
205 | type = buffer_get_char(&msg); | 224 | type = buffer_get_char(&msg); |
206 | id = buffer_get_int(&msg); | 225 | id = buffer_get_int(&msg); |
207 | 226 | ||
@@ -225,14 +244,14 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
225 | } | 244 | } |
226 | 245 | ||
227 | static Attrib * | 246 | static Attrib * |
228 | get_decode_stat(int fd, u_int expected_id, int quiet) | 247 | get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) |
229 | { | 248 | { |
230 | Buffer msg; | 249 | Buffer msg; |
231 | u_int type, id; | 250 | u_int type, id; |
232 | Attrib *a; | 251 | Attrib *a; |
233 | 252 | ||
234 | buffer_init(&msg); | 253 | buffer_init(&msg); |
235 | get_msg(fd, &msg); | 254 | get_msg(conn, &msg); |
236 | 255 | ||
237 | type = buffer_get_char(&msg); | 256 | type = buffer_get_char(&msg); |
238 | id = buffer_get_int(&msg); | 257 | id = buffer_get_int(&msg); |
@@ -260,14 +279,14 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
260 | } | 279 | } |
261 | 280 | ||
262 | static int | 281 | static int |
263 | get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | 282 | get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, |
264 | int quiet) | 283 | u_int expected_id, int quiet) |
265 | { | 284 | { |
266 | Buffer msg; | 285 | Buffer msg; |
267 | u_int type, id, flag; | 286 | u_int type, id, flag; |
268 | 287 | ||
269 | buffer_init(&msg); | 288 | buffer_init(&msg); |
270 | get_msg(fd, &msg); | 289 | get_msg(conn, &msg); |
271 | 290 | ||
272 | type = buffer_get_char(&msg); | 291 | type = buffer_get_char(&msg); |
273 | id = buffer_get_int(&msg); | 292 | id = buffer_get_int(&msg); |
@@ -311,21 +330,29 @@ get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | |||
311 | } | 330 | } |
312 | 331 | ||
313 | struct sftp_conn * | 332 | struct sftp_conn * |
314 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | 333 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, |
334 | u_int64_t limit_kbps) | ||
315 | { | 335 | { |
316 | u_int type, exts = 0; | 336 | u_int type; |
317 | int version; | ||
318 | Buffer msg; | 337 | Buffer msg; |
319 | struct sftp_conn *ret; | 338 | struct sftp_conn *ret; |
320 | 339 | ||
340 | ret = xmalloc(sizeof(*ret)); | ||
341 | ret->fd_in = fd_in; | ||
342 | ret->fd_out = fd_out; | ||
343 | ret->transfer_buflen = transfer_buflen; | ||
344 | ret->num_requests = num_requests; | ||
345 | ret->exts = 0; | ||
346 | ret->limit_kbps = 0; | ||
347 | |||
321 | buffer_init(&msg); | 348 | buffer_init(&msg); |
322 | buffer_put_char(&msg, SSH2_FXP_INIT); | 349 | buffer_put_char(&msg, SSH2_FXP_INIT); |
323 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); | 350 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); |
324 | send_msg(fd_out, &msg); | 351 | send_msg(ret, &msg); |
325 | 352 | ||
326 | buffer_clear(&msg); | 353 | buffer_clear(&msg); |
327 | 354 | ||
328 | get_msg(fd_in, &msg); | 355 | get_msg(ret, &msg); |
329 | 356 | ||
330 | /* Expecting a VERSION reply */ | 357 | /* Expecting a VERSION reply */ |
331 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { | 358 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { |
@@ -334,9 +361,9 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
334 | buffer_free(&msg); | 361 | buffer_free(&msg); |
335 | return(NULL); | 362 | return(NULL); |
336 | } | 363 | } |
337 | version = buffer_get_int(&msg); | 364 | ret->version = buffer_get_int(&msg); |
338 | 365 | ||
339 | debug2("Remote version: %d", version); | 366 | debug2("Remote version: %u", ret->version); |
340 | 367 | ||
341 | /* Check for extensions */ | 368 | /* Check for extensions */ |
342 | while (buffer_len(&msg) > 0) { | 369 | while (buffer_len(&msg) > 0) { |
@@ -346,15 +373,19 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
346 | 373 | ||
347 | if (strcmp(name, "posix-rename@openssh.com") == 0 && | 374 | if (strcmp(name, "posix-rename@openssh.com") == 0 && |
348 | strcmp(value, "1") == 0) { | 375 | strcmp(value, "1") == 0) { |
349 | exts |= SFTP_EXT_POSIX_RENAME; | 376 | ret->exts |= SFTP_EXT_POSIX_RENAME; |
350 | known = 1; | 377 | known = 1; |
351 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && | 378 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && |
352 | strcmp(value, "2") == 0) { | 379 | strcmp(value, "2") == 0) { |
353 | exts |= SFTP_EXT_STATVFS; | 380 | ret->exts |= SFTP_EXT_STATVFS; |
354 | known = 1; | 381 | known = 1; |
355 | } if (strcmp(name, "fstatvfs@openssh.com") == 0 && | 382 | } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && |
356 | strcmp(value, "2") == 0) { | 383 | strcmp(value, "2") == 0) { |
357 | exts |= SFTP_EXT_FSTATVFS; | 384 | ret->exts |= SFTP_EXT_FSTATVFS; |
385 | known = 1; | ||
386 | } else if (strcmp(name, "hardlink@openssh.com") == 0 && | ||
387 | strcmp(value, "1") == 0) { | ||
388 | ret->exts |= SFTP_EXT_HARDLINK; | ||
358 | known = 1; | 389 | known = 1; |
359 | } | 390 | } |
360 | if (known) { | 391 | if (known) { |
@@ -369,26 +400,25 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
369 | 400 | ||
370 | buffer_free(&msg); | 401 | buffer_free(&msg); |
371 | 402 | ||
372 | ret = xmalloc(sizeof(*ret)); | ||
373 | ret->fd_in = fd_in; | ||
374 | ret->fd_out = fd_out; | ||
375 | ret->transfer_buflen = transfer_buflen; | ||
376 | ret->num_requests = num_requests; | ||
377 | ret->version = version; | ||
378 | ret->msg_id = 1; | ||
379 | ret->exts = exts; | ||
380 | |||
381 | /* Some filexfer v.0 servers don't support large packets */ | 403 | /* Some filexfer v.0 servers don't support large packets */ |
382 | if (version == 0) | 404 | if (ret->version == 0) |
383 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); | 405 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); |
384 | 406 | ||
385 | return(ret); | 407 | ret->limit_kbps = limit_kbps; |
408 | if (ret->limit_kbps > 0) { | ||
409 | bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, | ||
410 | ret->transfer_buflen); | ||
411 | bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, | ||
412 | ret->transfer_buflen); | ||
413 | } | ||
414 | |||
415 | return ret; | ||
386 | } | 416 | } |
387 | 417 | ||
388 | u_int | 418 | u_int |
389 | sftp_proto_version(struct sftp_conn *conn) | 419 | sftp_proto_version(struct sftp_conn *conn) |
390 | { | 420 | { |
391 | return(conn->version); | 421 | return conn->version; |
392 | } | 422 | } |
393 | 423 | ||
394 | int | 424 | int |
@@ -403,16 +433,16 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len) | |||
403 | buffer_put_char(&msg, SSH2_FXP_CLOSE); | 433 | buffer_put_char(&msg, SSH2_FXP_CLOSE); |
404 | buffer_put_int(&msg, id); | 434 | buffer_put_int(&msg, id); |
405 | buffer_put_string(&msg, handle, handle_len); | 435 | buffer_put_string(&msg, handle, handle_len); |
406 | send_msg(conn->fd_out, &msg); | 436 | send_msg(conn, &msg); |
407 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); | 437 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); |
408 | 438 | ||
409 | status = get_status(conn->fd_in, id); | 439 | status = get_status(conn, id); |
410 | if (status != SSH2_FX_OK) | 440 | if (status != SSH2_FX_OK) |
411 | error("Couldn't close file: %s", fx2txt(status)); | 441 | error("Couldn't close file: %s", fx2txt(status)); |
412 | 442 | ||
413 | buffer_free(&msg); | 443 | buffer_free(&msg); |
414 | 444 | ||
415 | return(status); | 445 | return status; |
416 | } | 446 | } |
417 | 447 | ||
418 | 448 | ||
@@ -430,14 +460,14 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
430 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); | 460 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); |
431 | buffer_put_int(&msg, id); | 461 | buffer_put_int(&msg, id); |
432 | buffer_put_cstring(&msg, path); | 462 | buffer_put_cstring(&msg, path); |
433 | send_msg(conn->fd_out, &msg); | 463 | send_msg(conn, &msg); |
434 | 464 | ||
435 | buffer_clear(&msg); | 465 | buffer_clear(&msg); |
436 | 466 | ||
437 | handle = get_handle(conn->fd_in, id, &handle_len, | 467 | handle = get_handle(conn, id, &handle_len, |
438 | "remote readdir(\"%s\")", path); | 468 | "remote readdir(\"%s\")", path); |
439 | if (handle == NULL) | 469 | if (handle == NULL) |
440 | return(-1); | 470 | return -1; |
441 | 471 | ||
442 | if (dir) { | 472 | if (dir) { |
443 | ents = 0; | 473 | ents = 0; |
@@ -454,11 +484,11 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
454 | buffer_put_char(&msg, SSH2_FXP_READDIR); | 484 | buffer_put_char(&msg, SSH2_FXP_READDIR); |
455 | buffer_put_int(&msg, id); | 485 | buffer_put_int(&msg, id); |
456 | buffer_put_string(&msg, handle, handle_len); | 486 | buffer_put_string(&msg, handle, handle_len); |
457 | send_msg(conn->fd_out, &msg); | 487 | send_msg(conn, &msg); |
458 | 488 | ||
459 | buffer_clear(&msg); | 489 | buffer_clear(&msg); |
460 | 490 | ||
461 | get_msg(conn->fd_in, &msg); | 491 | get_msg(conn, &msg); |
462 | 492 | ||
463 | type = buffer_get_char(&msg); | 493 | type = buffer_get_char(&msg); |
464 | id = buffer_get_int(&msg); | 494 | id = buffer_get_int(&msg); |
@@ -537,7 +567,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
537 | **dir = NULL; | 567 | **dir = NULL; |
538 | } | 568 | } |
539 | 569 | ||
540 | return(0); | 570 | return 0; |
541 | } | 571 | } |
542 | 572 | ||
543 | int | 573 | int |
@@ -566,9 +596,8 @@ do_rm(struct sftp_conn *conn, char *path) | |||
566 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); | 596 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
567 | 597 | ||
568 | id = conn->msg_id++; | 598 | id = conn->msg_id++; |
569 | send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, | 599 | send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); |
570 | strlen(path)); | 600 | status = get_status(conn, id); |
571 | status = get_status(conn->fd_in, id); | ||
572 | if (status != SSH2_FX_OK) | 601 | if (status != SSH2_FX_OK) |
573 | error("Couldn't delete file: %s", fx2txt(status)); | 602 | error("Couldn't delete file: %s", fx2txt(status)); |
574 | return(status); | 603 | return(status); |
@@ -580,10 +609,10 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) | |||
580 | u_int status, id; | 609 | u_int status, id; |
581 | 610 | ||
582 | id = conn->msg_id++; | 611 | id = conn->msg_id++; |
583 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, | 612 | send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, |
584 | strlen(path), a); | 613 | strlen(path), a); |
585 | 614 | ||
586 | status = get_status(conn->fd_in, id); | 615 | status = get_status(conn, id); |
587 | if (status != SSH2_FX_OK && printflag) | 616 | if (status != SSH2_FX_OK && printflag) |
588 | error("Couldn't create directory: %s", fx2txt(status)); | 617 | error("Couldn't create directory: %s", fx2txt(status)); |
589 | 618 | ||
@@ -596,10 +625,10 @@ do_rmdir(struct sftp_conn *conn, char *path) | |||
596 | u_int status, id; | 625 | u_int status, id; |
597 | 626 | ||
598 | id = conn->msg_id++; | 627 | id = conn->msg_id++; |
599 | send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, | 628 | send_string_request(conn, id, SSH2_FXP_RMDIR, path, |
600 | strlen(path)); | 629 | strlen(path)); |
601 | 630 | ||
602 | status = get_status(conn->fd_in, id); | 631 | status = get_status(conn, id); |
603 | if (status != SSH2_FX_OK) | 632 | if (status != SSH2_FX_OK) |
604 | error("Couldn't remove directory: %s", fx2txt(status)); | 633 | error("Couldn't remove directory: %s", fx2txt(status)); |
605 | 634 | ||
@@ -613,11 +642,11 @@ do_stat(struct sftp_conn *conn, char *path, int quiet) | |||
613 | 642 | ||
614 | id = conn->msg_id++; | 643 | id = conn->msg_id++; |
615 | 644 | ||
616 | send_string_request(conn->fd_out, id, | 645 | send_string_request(conn, id, |
617 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, | 646 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, |
618 | path, strlen(path)); | 647 | path, strlen(path)); |
619 | 648 | ||
620 | return(get_decode_stat(conn->fd_in, id, quiet)); | 649 | return(get_decode_stat(conn, id, quiet)); |
621 | } | 650 | } |
622 | 651 | ||
623 | Attrib * | 652 | Attrib * |
@@ -634,10 +663,10 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) | |||
634 | } | 663 | } |
635 | 664 | ||
636 | id = conn->msg_id++; | 665 | id = conn->msg_id++; |
637 | send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, | 666 | send_string_request(conn, id, SSH2_FXP_LSTAT, path, |
638 | strlen(path)); | 667 | strlen(path)); |
639 | 668 | ||
640 | return(get_decode_stat(conn->fd_in, id, quiet)); | 669 | return(get_decode_stat(conn, id, quiet)); |
641 | } | 670 | } |
642 | 671 | ||
643 | #ifdef notyet | 672 | #ifdef notyet |
@@ -647,10 +676,10 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) | |||
647 | u_int id; | 676 | u_int id; |
648 | 677 | ||
649 | id = conn->msg_id++; | 678 | id = conn->msg_id++; |
650 | send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, | 679 | send_string_request(conn, id, SSH2_FXP_FSTAT, handle, |
651 | handle_len); | 680 | handle_len); |
652 | 681 | ||
653 | return(get_decode_stat(conn->fd_in, id, quiet)); | 682 | return(get_decode_stat(conn, id, quiet)); |
654 | } | 683 | } |
655 | #endif | 684 | #endif |
656 | 685 | ||
@@ -660,10 +689,10 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a) | |||
660 | u_int status, id; | 689 | u_int status, id; |
661 | 690 | ||
662 | id = conn->msg_id++; | 691 | id = conn->msg_id++; |
663 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, | 692 | send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, |
664 | strlen(path), a); | 693 | strlen(path), a); |
665 | 694 | ||
666 | status = get_status(conn->fd_in, id); | 695 | status = get_status(conn, id); |
667 | if (status != SSH2_FX_OK) | 696 | if (status != SSH2_FX_OK) |
668 | error("Couldn't setstat on \"%s\": %s", path, | 697 | error("Couldn't setstat on \"%s\": %s", path, |
669 | fx2txt(status)); | 698 | fx2txt(status)); |
@@ -678,10 +707,10 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, | |||
678 | u_int status, id; | 707 | u_int status, id; |
679 | 708 | ||
680 | id = conn->msg_id++; | 709 | id = conn->msg_id++; |
681 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, | 710 | send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, |
682 | handle_len, a); | 711 | handle_len, a); |
683 | 712 | ||
684 | status = get_status(conn->fd_in, id); | 713 | status = get_status(conn, id); |
685 | if (status != SSH2_FX_OK) | 714 | if (status != SSH2_FX_OK) |
686 | error("Couldn't fsetstat: %s", fx2txt(status)); | 715 | error("Couldn't fsetstat: %s", fx2txt(status)); |
687 | 716 | ||
@@ -697,12 +726,12 @@ do_realpath(struct sftp_conn *conn, char *path) | |||
697 | Attrib *a; | 726 | Attrib *a; |
698 | 727 | ||
699 | expected_id = id = conn->msg_id++; | 728 | expected_id = id = conn->msg_id++; |
700 | send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, | 729 | send_string_request(conn, id, SSH2_FXP_REALPATH, path, |
701 | strlen(path)); | 730 | strlen(path)); |
702 | 731 | ||
703 | buffer_init(&msg); | 732 | buffer_init(&msg); |
704 | 733 | ||
705 | get_msg(conn->fd_in, &msg); | 734 | get_msg(conn, &msg); |
706 | type = buffer_get_char(&msg); | 735 | type = buffer_get_char(&msg); |
707 | id = buffer_get_int(&msg); | 736 | id = buffer_get_int(&msg); |
708 | 737 | ||
@@ -756,13 +785,13 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
756 | } | 785 | } |
757 | buffer_put_cstring(&msg, oldpath); | 786 | buffer_put_cstring(&msg, oldpath); |
758 | buffer_put_cstring(&msg, newpath); | 787 | buffer_put_cstring(&msg, newpath); |
759 | send_msg(conn->fd_out, &msg); | 788 | send_msg(conn, &msg); |
760 | debug3("Sent message %s \"%s\" -> \"%s\"", | 789 | debug3("Sent message %s \"%s\" -> \"%s\"", |
761 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : | 790 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : |
762 | "SSH2_FXP_RENAME", oldpath, newpath); | 791 | "SSH2_FXP_RENAME", oldpath, newpath); |
763 | buffer_free(&msg); | 792 | buffer_free(&msg); |
764 | 793 | ||
765 | status = get_status(conn->fd_in, id); | 794 | status = get_status(conn, id); |
766 | if (status != SSH2_FX_OK) | 795 | if (status != SSH2_FX_OK) |
767 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, | 796 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, |
768 | newpath, fx2txt(status)); | 797 | newpath, fx2txt(status)); |
@@ -771,6 +800,39 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
771 | } | 800 | } |
772 | 801 | ||
773 | int | 802 | int |
803 | do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) | ||
804 | { | ||
805 | Buffer msg; | ||
806 | u_int status, id; | ||
807 | |||
808 | buffer_init(&msg); | ||
809 | |||
810 | /* Send link request */ | ||
811 | id = conn->msg_id++; | ||
812 | if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { | ||
813 | error("Server does not support hardlink@openssh.com extension"); | ||
814 | return -1; | ||
815 | } | ||
816 | |||
817 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
818 | buffer_put_int(&msg, id); | ||
819 | buffer_put_cstring(&msg, "hardlink@openssh.com"); | ||
820 | buffer_put_cstring(&msg, oldpath); | ||
821 | buffer_put_cstring(&msg, newpath); | ||
822 | send_msg(conn, &msg); | ||
823 | debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", | ||
824 | oldpath, newpath); | ||
825 | buffer_free(&msg); | ||
826 | |||
827 | status = get_status(conn, id); | ||
828 | if (status != SSH2_FX_OK) | ||
829 | error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, | ||
830 | newpath, fx2txt(status)); | ||
831 | |||
832 | return(status); | ||
833 | } | ||
834 | |||
835 | int | ||
774 | do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | 836 | do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) |
775 | { | 837 | { |
776 | Buffer msg; | 838 | Buffer msg; |
@@ -789,12 +851,12 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
789 | buffer_put_int(&msg, id); | 851 | buffer_put_int(&msg, id); |
790 | buffer_put_cstring(&msg, oldpath); | 852 | buffer_put_cstring(&msg, oldpath); |
791 | buffer_put_cstring(&msg, newpath); | 853 | buffer_put_cstring(&msg, newpath); |
792 | send_msg(conn->fd_out, &msg); | 854 | send_msg(conn, &msg); |
793 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, | 855 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, |
794 | newpath); | 856 | newpath); |
795 | buffer_free(&msg); | 857 | buffer_free(&msg); |
796 | 858 | ||
797 | status = get_status(conn->fd_in, id); | 859 | status = get_status(conn, id); |
798 | if (status != SSH2_FX_OK) | 860 | if (status != SSH2_FX_OK) |
799 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, | 861 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, |
800 | newpath, fx2txt(status)); | 862 | newpath, fx2txt(status)); |
@@ -812,12 +874,11 @@ do_readlink(struct sftp_conn *conn, char *path) | |||
812 | Attrib *a; | 874 | Attrib *a; |
813 | 875 | ||
814 | expected_id = id = conn->msg_id++; | 876 | expected_id = id = conn->msg_id++; |
815 | send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, | 877 | send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); |
816 | strlen(path)); | ||
817 | 878 | ||
818 | buffer_init(&msg); | 879 | buffer_init(&msg); |
819 | 880 | ||
820 | get_msg(conn->fd_in, &msg); | 881 | get_msg(conn, &msg); |
821 | type = buffer_get_char(&msg); | 882 | type = buffer_get_char(&msg); |
822 | id = buffer_get_int(&msg); | 883 | id = buffer_get_int(&msg); |
823 | 884 | ||
@@ -871,10 +932,10 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, | |||
871 | buffer_put_int(&msg, id); | 932 | buffer_put_int(&msg, id); |
872 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | 933 | buffer_put_cstring(&msg, "statvfs@openssh.com"); |
873 | buffer_put_cstring(&msg, path); | 934 | buffer_put_cstring(&msg, path); |
874 | send_msg(conn->fd_out, &msg); | 935 | send_msg(conn, &msg); |
875 | buffer_free(&msg); | 936 | buffer_free(&msg); |
876 | 937 | ||
877 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 938 | return get_decode_statvfs(conn, st, id, quiet); |
878 | } | 939 | } |
879 | 940 | ||
880 | #ifdef notyet | 941 | #ifdef notyet |
@@ -898,16 +959,16 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, | |||
898 | buffer_put_int(&msg, id); | 959 | buffer_put_int(&msg, id); |
899 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | 960 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); |
900 | buffer_put_string(&msg, handle, handle_len); | 961 | buffer_put_string(&msg, handle, handle_len); |
901 | send_msg(conn->fd_out, &msg); | 962 | send_msg(conn, &msg); |
902 | buffer_free(&msg); | 963 | buffer_free(&msg); |
903 | 964 | ||
904 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 965 | return get_decode_statvfs(conn, st, id, quiet); |
905 | } | 966 | } |
906 | #endif | 967 | #endif |
907 | 968 | ||
908 | static void | 969 | static void |
909 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | 970 | send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, |
910 | char *handle, u_int handle_len) | 971 | u_int len, char *handle, u_int handle_len) |
911 | { | 972 | { |
912 | Buffer msg; | 973 | Buffer msg; |
913 | 974 | ||
@@ -918,7 +979,7 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | |||
918 | buffer_put_string(&msg, handle, handle_len); | 979 | buffer_put_string(&msg, handle, handle_len); |
919 | buffer_put_int64(&msg, offset); | 980 | buffer_put_int64(&msg, offset); |
920 | buffer_put_int(&msg, len); | 981 | buffer_put_int(&msg, len); |
921 | send_msg(fd_out, &msg); | 982 | send_msg(conn, &msg); |
922 | buffer_free(&msg); | 983 | buffer_free(&msg); |
923 | } | 984 | } |
924 | 985 | ||
@@ -976,10 +1037,10 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
976 | buffer_put_int(&msg, SSH2_FXF_READ); | 1037 | buffer_put_int(&msg, SSH2_FXF_READ); |
977 | attrib_clear(&junk); /* Send empty attributes */ | 1038 | attrib_clear(&junk); /* Send empty attributes */ |
978 | encode_attrib(&msg, &junk); | 1039 | encode_attrib(&msg, &junk); |
979 | send_msg(conn->fd_out, &msg); | 1040 | send_msg(conn, &msg); |
980 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1041 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
981 | 1042 | ||
982 | handle = get_handle(conn->fd_in, id, &handle_len, | 1043 | handle = get_handle(conn, id, &handle_len, |
983 | "remote open(\"%s\")", remote_path); | 1044 | "remote open(\"%s\")", remote_path); |
984 | if (handle == NULL) { | 1045 | if (handle == NULL) { |
985 | buffer_free(&msg); | 1046 | buffer_free(&msg); |
@@ -1032,12 +1093,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1032 | offset += buflen; | 1093 | offset += buflen; |
1033 | num_req++; | 1094 | num_req++; |
1034 | TAILQ_INSERT_TAIL(&requests, req, tq); | 1095 | TAILQ_INSERT_TAIL(&requests, req, tq); |
1035 | send_read_request(conn->fd_out, req->id, req->offset, | 1096 | send_read_request(conn, req->id, req->offset, |
1036 | req->len, handle, handle_len); | 1097 | req->len, handle, handle_len); |
1037 | } | 1098 | } |
1038 | 1099 | ||
1039 | buffer_clear(&msg); | 1100 | buffer_clear(&msg); |
1040 | get_msg(conn->fd_in, &msg); | 1101 | get_msg(conn, &msg); |
1041 | type = buffer_get_char(&msg); | 1102 | type = buffer_get_char(&msg); |
1042 | id = buffer_get_int(&msg); | 1103 | id = buffer_get_int(&msg); |
1043 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); | 1104 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); |
@@ -1092,7 +1153,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1092 | req->id = conn->msg_id++; | 1153 | req->id = conn->msg_id++; |
1093 | req->len -= len; | 1154 | req->len -= len; |
1094 | req->offset += len; | 1155 | req->offset += len; |
1095 | send_read_request(conn->fd_out, req->id, | 1156 | send_read_request(conn, req->id, |
1096 | req->offset, req->len, handle, handle_len); | 1157 | req->offset, req->len, handle, handle_len); |
1097 | /* Reduce the request size */ | 1158 | /* Reduce the request size */ |
1098 | if (len < buflen) | 1159 | if (len < buflen) |
@@ -1327,12 +1388,12 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1327 | buffer_put_cstring(&msg, remote_path); | 1388 | buffer_put_cstring(&msg, remote_path); |
1328 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); | 1389 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); |
1329 | encode_attrib(&msg, &a); | 1390 | encode_attrib(&msg, &a); |
1330 | send_msg(conn->fd_out, &msg); | 1391 | send_msg(conn, &msg); |
1331 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1392 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
1332 | 1393 | ||
1333 | buffer_clear(&msg); | 1394 | buffer_clear(&msg); |
1334 | 1395 | ||
1335 | handle = get_handle(conn->fd_in, id, &handle_len, | 1396 | handle = get_handle(conn, id, &handle_len, |
1336 | "remote open(\"%s\")", remote_path); | 1397 | "remote open(\"%s\")", remote_path); |
1337 | if (handle == NULL) { | 1398 | if (handle == NULL) { |
1338 | close(local_fd); | 1399 | close(local_fd); |
@@ -1381,7 +1442,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1381 | buffer_put_string(&msg, handle, handle_len); | 1442 | buffer_put_string(&msg, handle, handle_len); |
1382 | buffer_put_int64(&msg, offset); | 1443 | buffer_put_int64(&msg, offset); |
1383 | buffer_put_string(&msg, data, len); | 1444 | buffer_put_string(&msg, data, len); |
1384 | send_msg(conn->fd_out, &msg); | 1445 | send_msg(conn, &msg); |
1385 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", | 1446 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", |
1386 | id, (unsigned long long)offset, len); | 1447 | id, (unsigned long long)offset, len); |
1387 | } else if (TAILQ_FIRST(&acks) == NULL) | 1448 | } else if (TAILQ_FIRST(&acks) == NULL) |
@@ -1395,7 +1456,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1395 | u_int r_id; | 1456 | u_int r_id; |
1396 | 1457 | ||
1397 | buffer_clear(&msg); | 1458 | buffer_clear(&msg); |
1398 | get_msg(conn->fd_in, &msg); | 1459 | get_msg(conn, &msg); |
1399 | type = buffer_get_char(&msg); | 1460 | type = buffer_get_char(&msg); |
1400 | r_id = buffer_get_int(&msg); | 1461 | r_id = buffer_get_int(&msg); |
1401 | 1462 | ||