ftp.c (135546) | ftp.c (148986) |
---|---|
1/*- 2 * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/lib/libfetch/ftp.c 135546 2004-09-21 18:35:21Z des $"); | 30__FBSDID("$FreeBSD: head/lib/libfetch/ftp.c 148986 2005-08-12 12:48:50Z des $"); |
31 32/* 33 * Portions of this code were taken from or based on ftpio.c: 34 * 35 * ---------------------------------------------------------------------------- 36 * "THE BEER-WARE LICENSE" (Revision 42): 37 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 38 * can do whatever you want with this stuff. If we meet some day, and you think --- 46 unchanged lines hidden (view full) --- 85#define FTP_FILE_STATUS 213 86#define FTP_SERVICE_READY 220 87#define FTP_TRANSFER_COMPLETE 226 88#define FTP_PASSIVE_MODE 227 89#define FTP_LPASSIVE_MODE 228 90#define FTP_EPASSIVE_MODE 229 91#define FTP_LOGGED_IN 230 92#define FTP_FILE_ACTION_OK 250 | 31 32/* 33 * Portions of this code were taken from or based on ftpio.c: 34 * 35 * ---------------------------------------------------------------------------- 36 * "THE BEER-WARE LICENSE" (Revision 42): 37 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 38 * can do whatever you want with this stuff. If we meet some day, and you think --- 46 unchanged lines hidden (view full) --- 85#define FTP_FILE_STATUS 213 86#define FTP_SERVICE_READY 220 87#define FTP_TRANSFER_COMPLETE 226 88#define FTP_PASSIVE_MODE 227 89#define FTP_LPASSIVE_MODE 228 90#define FTP_EPASSIVE_MODE 229 91#define FTP_LOGGED_IN 230 92#define FTP_FILE_ACTION_OK 250 |
93#define FTP_DIRECTORY_CREATED 257 /* multiple meanings */ 94#define FTP_FILE_CREATED 257 /* multiple meanings */ 95#define FTP_WORKING_DIRECTORY 257 /* multiple meanings */ |
|
93#define FTP_NEED_PASSWORD 331 94#define FTP_NEED_ACCOUNT 332 95#define FTP_FILE_OK 350 96#define FTP_SYNTAX_ERROR 500 97#define FTP_PROTOCOL_ERROR 999 98 99static struct url cached_host; 100static conn_t *cached_connection; --- 93 unchanged lines hidden (view full) --- 194 195 return (_ftp_chkerr(conn)); 196} 197 198/* 199 * Return a pointer to the filename part of a path 200 */ 201static const char * | 96#define FTP_NEED_PASSWORD 331 97#define FTP_NEED_ACCOUNT 332 98#define FTP_FILE_OK 350 99#define FTP_SYNTAX_ERROR 500 100#define FTP_PROTOCOL_ERROR 999 101 102static struct url cached_host; 103static conn_t *cached_connection; --- 93 unchanged lines hidden (view full) --- 197 198 return (_ftp_chkerr(conn)); 199} 200 201/* 202 * Return a pointer to the filename part of a path 203 */ 204static const char * |
202_ftp_filename(const char *file) | 205_ftp_filename(const char *file, int *len, int *type) |
203{ | 206{ |
204 char *s; | 207 const char *s; |
205 206 if ((s = strrchr(file, '/')) == NULL) | 208 209 if ((s = strrchr(file, '/')) == NULL) |
207 return (file); | 210 s = file; |
208 else | 211 else |
209 return (s + 1); | 212 s = s + 1; 213 *len = strlen(s); 214 if (*len > 7 && strncmp(s + *len - 7, ";type=", 6) == 0) { 215 *type = s[*len - 1]; 216 *len -= 7; 217 } else { 218 *type = '\0'; 219 } 220 return (s); |
210} 211 212/* | 221} 222 223/* |
224 * Get current working directory from the reply to a CWD, PWD or CDUP 225 * command. 226 */ 227static int 228_ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen) 229{ 230 char *src, *dst, *end; 231 int q; 232 233 if (conn->err != FTP_WORKING_DIRECTORY && 234 conn->err != FTP_FILE_ACTION_OK) 235 return (FTP_PROTOCOL_ERROR); 236 end = conn->buf + conn->buflen; 237 src = conn->buf + 4; 238 if (src >= end || *src++ != '"') 239 return (FTP_PROTOCOL_ERROR); 240 for (q = 0, dst = pwd; src < end && pwdlen--; ++src) { 241 if (!q && *src == '"') 242 q = 1; 243 else if (q && *src != '"') 244 break; 245 else if (q) 246 *dst++ = '"', q = 0; 247 else 248 *dst++ = *src; 249 } 250 if (!pwdlen) 251 return (FTP_PROTOCOL_ERROR); 252 *dst = '\0'; 253#if 0 254 DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd)); 255#endif 256 return (FTP_OK); 257} 258 259/* |
|
213 * Change working directory to the directory that contains the specified 214 * file. 215 */ 216static int 217_ftp_cwd(conn_t *conn, const char *file) 218{ | 260 * Change working directory to the directory that contains the specified 261 * file. 262 */ 263static int 264_ftp_cwd(conn_t *conn, const char *file) 265{ |
219 char *s; 220 int e; | 266 const char *beg, *end; 267 char pwd[PATH_MAX]; 268 int e, i, len; |
221 | 269 |
222 if ((s = strrchr(file, '/')) == NULL || s == file) { 223 e = _ftp_cmd(conn, "CWD /"); 224 } else { 225 e = _ftp_cmd(conn, "CWD %.*s", s - file, file); 226 } 227 if (e != FTP_FILE_ACTION_OK) { | 270 if ((end = strrchr(file, '/')) == NULL) 271 return (0); 272 if ((e = _ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY || 273 (e = _ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) { |
228 _ftp_seterr(e); 229 return (-1); 230 } | 274 _ftp_seterr(e); 275 return (-1); 276 } |
277 for (;;) { 278 len = strlen(pwd); 279 /* look for a common prefix */ 280 for (i = 0; i <= len && i <= end - file; ++i) 281 if (pwd[i] != file[i]) 282 break; 283#if 0 284 DEBUG(fprintf(stderr, "have: [%.*s|%s]\n", i, pwd, pwd + i)); 285 DEBUG(fprintf(stderr, "want: [%.*s|%s]\n", i, file, file + i)); 286#endif 287 if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/')) 288 break; 289 if ((e = _ftp_cmd(conn, "CDUP")) != FTP_FILE_ACTION_OK || 290 (e = _ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY || 291 (e = _ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) { 292 _ftp_seterr(e); 293 return (-1); 294 } 295 } 296 for (beg = file + i; beg < end; beg = file + i + 1) { 297 for (++i; file + i < end && file[i] != '/'; ++i) 298 /* nothing */ ; 299 e = _ftp_cmd(conn, "CWD %.*s", file + i - beg, beg); 300 if (e != FTP_FILE_ACTION_OK) { 301 _ftp_seterr(e); 302 return (-1); 303 } 304 } |
|
231 return (0); 232} 233 234/* | 305 return (0); 306} 307 308/* |
309 * Set transfer mode and data type 310 */ 311static int 312_ftp_mode_type(conn_t *conn, int mode, int type) 313{ 314 int e; 315 316 switch (mode) { 317 case 0: 318 case 's': 319 mode = 'S'; 320 case 'S': 321 break; 322 default: 323 return (FTP_PROTOCOL_ERROR); 324 } 325 if ((e = _ftp_cmd(conn, "MODE %c", mode)) != FTP_OK) 326 return (e); 327 328 switch (type) { 329 case 0: 330 case 'i': 331 type = 'I'; 332 case 'I': 333 break; 334 case 'a': 335 type = 'A'; 336 case 'A': 337 break; 338 case 'd': 339 type = 'D'; 340 case 'D': 341 /* can't handle yet */ 342 default: 343 return (FTP_PROTOCOL_ERROR); 344 } 345 if ((e = _ftp_cmd(conn, "TYPE %c", type)) != FTP_OK) 346 return (e); 347 348 return (FTP_OK); 349} 350 351/* |
|
235 * Request and parse file stats 236 */ 237static int 238_ftp_stat(conn_t *conn, const char *file, struct url_stat *us) 239{ 240 char *ln; | 352 * Request and parse file stats 353 */ 354static int 355_ftp_stat(conn_t *conn, const char *file, struct url_stat *us) 356{ 357 char *ln; |
241 const char *s; | 358 const char *filename; 359 int filenamelen, type; |
242 struct tm tm; 243 time_t t; 244 int e; 245 246 us->size = -1; 247 us->atime = us->mtime = 0; 248 | 360 struct tm tm; 361 time_t t; 362 int e; 363 364 us->size = -1; 365 us->atime = us->mtime = 0; 366 |
249 if ((s = strrchr(file, '/')) == NULL) 250 s = file; 251 else 252 ++s; | 367 filename = _ftp_filename(file, &filenamelen, &type); |
253 | 368 |
254 if ((e = _ftp_cmd(conn, "SIZE %s", s)) != FTP_FILE_STATUS) { | 369 if ((e = _ftp_mode_type(conn, 0, type)) != FTP_OK) { |
255 _ftp_seterr(e); 256 return (-1); 257 } | 370 _ftp_seterr(e); 371 return (-1); 372 } |
373 374 e = _ftp_cmd(conn, "SIZE %.*s", filenamelen, filename); 375 if (e != FTP_FILE_STATUS) { 376 _ftp_seterr(e); 377 return (-1); 378 } |
|
258 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++) 259 /* nothing */ ; 260 for (us->size = 0; *ln && isdigit(*ln); ln++) 261 us->size = us->size * 10 + *ln - '0'; 262 if (*ln && !isspace(*ln)) { 263 _ftp_seterr(FTP_PROTOCOL_ERROR); 264 us->size = -1; 265 return (-1); 266 } 267 if (us->size == 0) 268 us->size = -1; 269 DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size)); 270 | 379 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++) 380 /* nothing */ ; 381 for (us->size = 0; *ln && isdigit(*ln); ln++) 382 us->size = us->size * 10 + *ln - '0'; 383 if (*ln && !isspace(*ln)) { 384 _ftp_seterr(FTP_PROTOCOL_ERROR); 385 us->size = -1; 386 return (-1); 387 } 388 if (us->size == 0) 389 us->size = -1; 390 DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size)); 391 |
271 if ((e = _ftp_cmd(conn, "MDTM %s", s)) != FTP_FILE_STATUS) { | 392 e = _ftp_cmd(conn, "MDTM %.*s", filenamelen, filename); 393 if (e != FTP_FILE_STATUS) { |
272 _ftp_seterr(e); 273 return (-1); 274 } 275 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++) 276 /* nothing */ ; 277 switch (strspn(ln, "0123456789")) { 278 case 14: 279 break; --- 171 unchanged lines hidden (view full) --- 451 */ 452static FILE * 453_ftp_transfer(conn_t *conn, const char *oper, const char *file, 454 int mode, off_t offset, const char *flags) 455{ 456 struct sockaddr_storage sa; 457 struct sockaddr_in6 *sin6; 458 struct sockaddr_in *sin4; | 394 _ftp_seterr(e); 395 return (-1); 396 } 397 for (ln = conn->buf + 4; *ln && isspace(*ln); ln++) 398 /* nothing */ ; 399 switch (strspn(ln, "0123456789")) { 400 case 14: 401 break; --- 171 unchanged lines hidden (view full) --- 573 */ 574static FILE * 575_ftp_transfer(conn_t *conn, const char *oper, const char *file, 576 int mode, off_t offset, const char *flags) 577{ 578 struct sockaddr_storage sa; 579 struct sockaddr_in6 *sin6; 580 struct sockaddr_in *sin4; |
581 const char *filename; 582 int filenamelen, type; |
|
459 int low, pasv, verbose; 460 int e, sd = -1; 461 socklen_t l; 462 char *s; 463 FILE *df; 464 465 /* check flags */ 466 low = CHECK_FLAG('l'); 467 pasv = CHECK_FLAG('p'); 468 verbose = CHECK_FLAG('v'); 469 470 /* passive mode */ 471 if (!pasv) 472 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL && 473 strncasecmp(s, "no", 2) != 0); 474 | 583 int low, pasv, verbose; 584 int e, sd = -1; 585 socklen_t l; 586 char *s; 587 FILE *df; 588 589 /* check flags */ 590 low = CHECK_FLAG('l'); 591 pasv = CHECK_FLAG('p'); 592 verbose = CHECK_FLAG('v'); 593 594 /* passive mode */ 595 if (!pasv) 596 pasv = ((s = getenv("FTP_PASSIVE_MODE")) != NULL && 597 strncasecmp(s, "no", 2) != 0); 598 |
599 /* isolate filename */ 600 filename = _ftp_filename(file, &filenamelen, &type); 601 602 /* set transfer mode and data type */ 603 if ((e = _ftp_mode_type(conn, 0, type)) != FTP_OK) 604 goto ouch; 605 |
|
475 /* find our own address, bind, and listen */ 476 l = sizeof(sa); 477 if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1) 478 goto sysouch; 479 if (sa.ss_family == AF_INET6) 480 unmappedaddr((struct sockaddr_in6 *)&sa); 481 482 /* open data socket */ --- 109 unchanged lines hidden (view full) --- 592 if (verbose) 593 _fetch_info("opening data connection"); 594 if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1) 595 goto sysouch; 596 597 /* make the server initiate the transfer */ 598 if (verbose) 599 _fetch_info("initiating transfer"); | 606 /* find our own address, bind, and listen */ 607 l = sizeof(sa); 608 if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1) 609 goto sysouch; 610 if (sa.ss_family == AF_INET6) 611 unmappedaddr((struct sockaddr_in6 *)&sa); 612 613 /* open data socket */ --- 109 unchanged lines hidden (view full) --- 723 if (verbose) 724 _fetch_info("opening data connection"); 725 if (connect(sd, (struct sockaddr *)&sa, sa.ss_len) == -1) 726 goto sysouch; 727 728 /* make the server initiate the transfer */ 729 if (verbose) 730 _fetch_info("initiating transfer"); |
600 e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file)); | 731 e = _ftp_cmd(conn, "%s %.*s", oper, filenamelen, filename); |
601 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 602 goto ouch; 603 604 } else { 605 u_int32_t a; 606 u_short p; 607 int arg, d; 608 char *ap; --- 74 unchanged lines hidden (view full) --- 683 /* seek to required offset */ 684 if (offset) 685 if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK) 686 goto sysouch; 687 688 /* make the server initiate the transfer */ 689 if (verbose) 690 _fetch_info("initiating transfer"); | 732 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 733 goto ouch; 734 735 } else { 736 u_int32_t a; 737 u_short p; 738 int arg, d; 739 char *ap; --- 74 unchanged lines hidden (view full) --- 814 /* seek to required offset */ 815 if (offset) 816 if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK) 817 goto sysouch; 818 819 /* make the server initiate the transfer */ 820 if (verbose) 821 _fetch_info("initiating transfer"); |
691 e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file)); | 822 e = _ftp_cmd(conn, "%s %.*s", oper, filenamelen, filename); |
692 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 693 goto ouch; 694 695 /* accept the incoming connection and go to town */ 696 if ((d = accept(sd, NULL, NULL)) == -1) 697 goto sysouch; 698 close(sd); 699 sd = d; --- 107 unchanged lines hidden (view full) --- 807 /* expect welcome message */ 808 if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY) 809 goto fouch; 810 811 /* authenticate */ 812 if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN) 813 goto fouch; 814 | 823 if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 824 goto ouch; 825 826 /* accept the incoming connection and go to town */ 827 if ((d = accept(sd, NULL, NULL)) == -1) 828 goto sysouch; 829 close(sd); 830 sd = d; --- 107 unchanged lines hidden (view full) --- 938 /* expect welcome message */ 939 if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY) 940 goto fouch; 941 942 /* authenticate */ 943 if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN) 944 goto fouch; 945 |
815 /* might as well select mode and type at once */ 816#ifdef FTP_FORCE_STREAM_MODE 817 if ((e = _ftp_cmd(conn, "MODE S")) != FTP_OK) /* default is S */ 818 goto fouch; 819#endif 820 if ((e = _ftp_cmd(conn, "TYPE I")) != FTP_OK) /* default is A */ 821 goto fouch; 822 | |
823 /* done */ 824 return (conn); 825 826fouch: 827 if (e != -1) 828 _ftp_seterr(e); 829 _fetch_close(conn); 830 return (NULL); --- 190 unchanged lines hidden --- | 946 /* done */ 947 return (conn); 948 949fouch: 950 if (e != -1) 951 _ftp_seterr(e); 952 _fetch_close(conn); 953 return (NULL); --- 190 unchanged lines hidden --- |