fetch.c (63235) | fetch.c (63345) |
---|---|
1/*- 2 * Copyright (c) 2000 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 --- 11 unchanged lines hidden (view full) --- 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 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 * | 1/*- 2 * Copyright (c) 2000 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 --- 11 unchanged lines hidden (view full) --- 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 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 * $FreeBSD: head/usr.bin/fetch/fetch.c 63235 2000-07-16 00:47:00Z des $ | 28 * $FreeBSD: head/usr.bin/fetch/fetch.c 63345 2000-07-17 21:49:01Z des $ |
29 */ 30 31#include <sys/param.h> 32#include <sys/stat.h> 33#include <sys/socket.h> 34 35#include <ctype.h> 36#include <err.h> --- 154 unchanged lines hidden (view full) --- 191 /* parse URL */ 192 if ((url = fetchParseURL(URL)) == NULL) { 193 warnx("%s: parse error", URL); 194 goto failure; 195 } 196 197 timeout = 0; 198 *flags = 0; | 29 */ 30 31#include <sys/param.h> 32#include <sys/stat.h> 33#include <sys/socket.h> 34 35#include <ctype.h> 36#include <err.h> --- 154 unchanged lines hidden (view full) --- 191 /* parse URL */ 192 if ((url = fetchParseURL(URL)) == NULL) { 193 warnx("%s: parse error", URL); 194 goto failure; 195 } 196 197 timeout = 0; 198 *flags = 0; |
199 count = 0; |
|
199 200 /* common flags */ 201 if (v_level > 2) 202 strcat(flags, "v"); 203 switch (family) { 204 case PF_INET: 205 strcat(flags, "4"); 206 break; --- 20 unchanged lines hidden (view full) --- 227 if (A_flag) 228 strcat(flags, "A"); 229 timeout = T_secs ? T_secs : http_timeout; 230 } 231 232 /* set the protocol timeout. */ 233 fetchTimeout = timeout; 234 | 200 201 /* common flags */ 202 if (v_level > 2) 203 strcat(flags, "v"); 204 switch (family) { 205 case PF_INET: 206 strcat(flags, "4"); 207 break; --- 20 unchanged lines hidden (view full) --- 228 if (A_flag) 229 strcat(flags, "A"); 230 timeout = T_secs ? T_secs : http_timeout; 231 } 232 233 /* set the protocol timeout. */ 234 fetchTimeout = timeout; 235 |
235 /* stat remote file */ 236 if (fetchStat(url, &us, flags) == -1) 237 goto failure; 238 | |
239 /* just print size */ 240 if (s_flag) { | 236 /* just print size */ 237 if (s_flag) { |
238 if (fetchStat(url, &us, flags) == -1) 239 goto failure; |
|
241 if (us.size == -1) 242 printf("Unknown\n"); 243 else 244 printf("%lld\n", us.size); 245 goto success; 246 } 247 | 240 if (us.size == -1) 241 printf("Unknown\n"); 242 else 243 printf("%lld\n", us.size); 244 goto success; 245 } 246 |
248 /* check that size is as expected */ 249 if (S_size && us.size != -1 && us.size != S_size) { 250 warnx("%s: size mismatch: expected %lld, actual %lld", 251 path, S_size, us.size); | 247 /* 248 * If the -r flag was specified, we have to compare the local and 249 * remote files, so we should really do a fetchStat() first, but I 250 * know of at least one HTTP server that only sends the content 251 * size in response to GET requests, and leaves it out of replies 252 * to HEAD requests. Also, in the (frequent) case that the local 253 * and remote files match but the local file is truncated, we have 254 * sufficient information *before* the compare to issue a correct 255 * request. Therefore, we always issue a GET request as if we were 256 * sure the local file was a truncated copy of the remote file; we 257 * can drop the connection later if we change our minds. 258 */ 259 if (r_flag && !o_stdout && stat(path, &sb) != -1) 260 url->offset = sb.st_size; 261 262 /* start the transfer */ 263 if ((f = fetchXGet(url, &us, flags)) == NULL) { 264 warnx("%s: %s", path, fetchLastErrString); |
252 goto failure; 253 } | 265 goto failure; 266 } |
267 if (sigint) 268 goto signal; |
|
254 | 269 |
270 /* check that size is as expected */ 271 if (S_size) { 272 if (us.size == -1) { 273 warnx("%s: size unknown", path); 274 goto failure; 275 } else if (us.size != S_size) { 276 warnx("%s: size mismatch: expected %lld, actual %lld", 277 path, S_size, us.size); 278 goto failure; 279 } 280 } 281 |
|
255 /* symlink instead of copy */ 256 if (l_flag && strcmp(url->scheme, "file") == 0 && !o_stdout) { 257 if (symlink(url->doc, path) == -1) { 258 warn("%s: symlink()", path); 259 goto failure; 260 } 261 goto success; 262 } 263 | 282 /* symlink instead of copy */ 283 if (l_flag && strcmp(url->scheme, "file") == 0 && !o_stdout) { 284 if (symlink(url->doc, path) == -1) { 285 warn("%s: symlink()", path); 286 goto failure; 287 } 288 goto success; 289 } 290 |
291 /* open output file */ |
|
264 if (o_stdout) { 265 /* output to stdout */ 266 of = stdout; | 292 if (o_stdout) { 293 /* output to stdout */ 294 of = stdout; |
267 } else if (r_flag && us.size != -1 && stat(path, &sb) != -1 268 && (F_flag || (us.mtime && sb.st_mtime == us.mtime))) { 269 /* output to file, restart aborted transfer */ | 295 } else if (url->offset) { 296 /* resume mode, local file exists */ 297 if (!F_flag && us.mtime && sb.st_mtime != us.mtime) { 298 /* no match! have to refetch */ 299 fclose(f); 300 url->offset = 0; 301 if ((f = fetchXGet(url, &us, flags)) == NULL) { 302 warnx("%s: %s", path, fetchLastErrString); 303 goto failure; 304 } 305 if (sigint) 306 goto signal; 307 } else { 308 us.size += url->offset; 309 } |
270 if (us.size == sb.st_size) | 310 if (us.size == sb.st_size) |
311 /* nothing to do */ |
|
271 goto success; | 312 goto success; |
272 else if (sb.st_size > us.size && truncate(path, us.size) == -1) { 273 warn("%s: truncate()", path); | 313 if (sb.st_size > us.size) { 314 /* local file too long! */ 315 warnx("%s: local file (%lld bytes) is longer " 316 "than remote file (%lld bytes)", 317 path, sb.st_size, us.size); |
274 goto failure; 275 } | 318 goto failure; 319 } |
320 /* we got through, open local file in append mode */ 321 /* 322 * XXX there's a race condition here - the file we open is not 323 * necessarily the same as the one we stat()'ed earlier... 324 */ |
|
276 if ((of = fopen(path, "a")) == NULL) { 277 warn("%s: open()", path); 278 goto failure; 279 } | 325 if ((of = fopen(path, "a")) == NULL) { 326 warn("%s: open()", path); 327 goto failure; 328 } |
280 url->offset = sb.st_size; 281 } else if (m_flag && us.size != -1 && stat(path, &sb) != -1) { 282 /* output to file, mirror mode */ | 329 } 330 if (m_flag && stat(path, &sb) != -1) { 331 /* mirror mode, local file exists */ |
283 if (sb.st_size == us.size && sb.st_mtime == us.mtime) | 332 if (sb.st_size == us.size && sb.st_mtime == us.mtime) |
284 return 0; | 333 goto success; 334 } 335 if (!of) { 336 /* 337 * We don't yet have an output file; either this is a vanilla 338 * run with no special flags, or the local and remote files 339 * didn't match. 340 */ |
285 if ((of = fopen(path, "w")) == NULL) { 286 warn("%s: open()", path); 287 goto failure; 288 } | 341 if ((of = fopen(path, "w")) == NULL) { 342 warn("%s: open()", path); 343 goto failure; 344 } |
289 } else { 290 /* output to file, all other cases */ 291 if ((of = fopen(path, "w")) == NULL) { 292 warn("%s: open()", path); 293 goto failure; 294 } | |
295 } 296 count = url->offset; 297 | 345 } 346 count = url->offset; 347 |
298 /* start the transfer */ 299 if ((f = fetchGet(url, flags)) == NULL) { 300 warnx("%s", fetchLastErrString); 301 if (!R_flag && !r_flag && !o_stdout) 302 unlink(path); 303 goto failure; 304 } 305 | |
306 /* start the counter */ 307 stat_start(&xs, path, us.size, count); 308 309 sigint = sigalrm = 0; 310 311 /* suck in the data */ 312 for (n = 0; !sigint && !sigalrm; ++n) { 313 if (us.size != -1 && us.size - count < B_size) --- 22 unchanged lines hidden (view full) --- 336 tv[0].tv_sec = (long)(us.atime ? us.atime : us.mtime); 337 tv[1].tv_sec = (long)us.mtime; 338 tv[0].tv_usec = tv[1].tv_usec = 0; 339 if (utimes(path, tv)) 340 warn("%s: utimes()", path); 341 } 342 343 /* timed out or interrupted? */ | 348 /* start the counter */ 349 stat_start(&xs, path, us.size, count); 350 351 sigint = sigalrm = 0; 352 353 /* suck in the data */ 354 for (n = 0; !sigint && !sigalrm; ++n) { 355 if (us.size != -1 && us.size - count < B_size) --- 22 unchanged lines hidden (view full) --- 378 tv[0].tv_sec = (long)(us.atime ? us.atime : us.mtime); 379 tv[1].tv_sec = (long)us.mtime; 380 tv[0].tv_usec = tv[1].tv_usec = 0; 381 if (utimes(path, tv)) 382 warn("%s: utimes()", path); 383 } 384 385 /* timed out or interrupted? */ |
386 signal: |
|
344 if (sigalrm) 345 warnx("transfer timed out"); 346 if (sigint) 347 warnx("transfer interrupted"); 348 349 if (!sigalrm && !sigint) { 350 /* check the status of our files */ 351 if (ferror(f)) --- 115 unchanged lines hidden (view full) --- 467 l_flag = 1; 468 break; 469 case 'o': 470 o_flag = 1; 471 o_filename = optarg; 472 break; 473 case 'M': 474 case 'm': | 387 if (sigalrm) 388 warnx("transfer timed out"); 389 if (sigint) 390 warnx("transfer interrupted"); 391 392 if (!sigalrm && !sigint) { 393 /* check the status of our files */ 394 if (ferror(f)) --- 115 unchanged lines hidden (view full) --- 510 l_flag = 1; 511 break; 512 case 'o': 513 o_flag = 1; 514 o_filename = optarg; 515 break; 516 case 'M': 517 case 'm': |
518 if (r_flag) 519 errx(1, "the -m and -r flags are mutually exclusive"); |
|
475 m_flag = 1; 476 break; 477 case 'n': 478 n_flag = 1; 479 break; 480 case 'P': 481 case 'p': 482 p_flag = 1; 483 break; 484 case 'q': 485 v_level = 0; 486 break; 487 case 'R': 488 R_flag = 1; 489 break; 490 case 'r': | 520 m_flag = 1; 521 break; 522 case 'n': 523 n_flag = 1; 524 break; 525 case 'P': 526 case 'p': 527 p_flag = 1; 528 break; 529 case 'q': 530 v_level = 0; 531 break; 532 case 'R': 533 R_flag = 1; 534 break; 535 case 'r': |
536 if (m_flag) 537 errx(1, "the -m and -r flags are mutually exclusive"); |
|
491 r_flag = 1; 492 break; 493 case 'S': 494 if (parseoff(optarg, &S_size) == -1) 495 errx(1, "invalid size"); 496 break; 497 case 's': 498 s_flag = 1; --- 30 unchanged lines hidden (view full) --- 529 /* XXX this is a hack. */ 530 if (strcspn(h_hostname, "@:/") != strlen(h_hostname)) 531 errx(1, "invalid hostname"); 532 if (asprintf(argv, "ftp://%s/%s/%s", h_hostname, 533 c_dirname ? c_dirname : "", f_filename) == -1) 534 errx(1, strerror(ENOMEM)); 535 argc++; 536 } | 538 r_flag = 1; 539 break; 540 case 'S': 541 if (parseoff(optarg, &S_size) == -1) 542 errx(1, "invalid size"); 543 break; 544 case 's': 545 s_flag = 1; --- 30 unchanged lines hidden (view full) --- 576 /* XXX this is a hack. */ 577 if (strcspn(h_hostname, "@:/") != strlen(h_hostname)) 578 errx(1, "invalid hostname"); 579 if (asprintf(argv, "ftp://%s/%s/%s", h_hostname, 580 c_dirname ? c_dirname : "", f_filename) == -1) 581 errx(1, strerror(ENOMEM)); 582 argc++; 583 } |
537 | 584 |
538 if (!argc) { 539 usage(); 540 exit(EX_USAGE); 541 } 542 543 /* allocate buffer */ 544 if (B_size < MINBUFSIZE) 545 B_size = MINBUFSIZE; --- 13 unchanged lines hidden (view full) --- 559 http_timeout = 0; 560 } 561 } 562 563 /* signal handling */ 564 sa.sa_flags = 0; 565 sa.sa_handler = sig_handler; 566 sigemptyset(&sa.sa_mask); | 585 if (!argc) { 586 usage(); 587 exit(EX_USAGE); 588 } 589 590 /* allocate buffer */ 591 if (B_size < MINBUFSIZE) 592 B_size = MINBUFSIZE; --- 13 unchanged lines hidden (view full) --- 606 http_timeout = 0; 607 } 608 } 609 610 /* signal handling */ 611 sa.sa_flags = 0; 612 sa.sa_handler = sig_handler; 613 sigemptyset(&sa.sa_mask); |
567 (void)sigaction(SIGALRM, &sa, NULL); 568 (void)sigaction(SIGINT, &sa, NULL); | 614 sigaction(SIGALRM, &sa, NULL); 615 sa.sa_flags = SA_RESETHAND; 616 sigaction(SIGINT, &sa, NULL); 617 fetchRestartCalls = 0; |
569 570 /* output file */ 571 if (o_flag) { 572 if (strcmp(o_filename, "-") == 0) { 573 o_stdout = 1; 574 } else if (stat(o_filename, &sb) == -1) { 575 if (errno == ENOENT) { 576 if (argc > 1) --- 32 unchanged lines hidden (view full) --- 609 } else { 610 e = fetch(*argv, o_filename); 611 } 612 } else { 613 e = fetch(*argv, p); 614 } 615 616 if (sigint) | 618 619 /* output file */ 620 if (o_flag) { 621 if (strcmp(o_filename, "-") == 0) { 622 o_stdout = 1; 623 } else if (stat(o_filename, &sb) == -1) { 624 if (errno == ENOENT) { 625 if (argc > 1) --- 32 unchanged lines hidden (view full) --- 658 } else { 659 e = fetch(*argv, o_filename); 660 } 661 } else { 662 e = fetch(*argv, p); 663 } 664 665 if (sigint) |
617 exit(1); | 666 kill(getpid(), SIGINT); |
618 619 if (e == 0 && once_flag) 620 exit(0); 621 622 if (e) { 623 r = 1; 624 if ((fetchLastErrCode 625 && fetchLastErrCode != FETCH_UNAVAIL --- 20 unchanged lines hidden --- | 667 668 if (e == 0 && once_flag) 669 exit(0); 670 671 if (e) { 672 r = 1; 673 if ((fetchLastErrCode 674 && fetchLastErrCode != FETCH_UNAVAIL --- 20 unchanged lines hidden --- |