Annotation of embedaddon/curl/src/tool_operate.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
        !             9:  *
        !            10:  * This software is licensed as described in the file COPYING, which
        !            11:  * you should have received as part of this distribution. The terms
        !            12:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            13:  *
        !            14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            15:  * copies of the Software, and permit persons to whom the Software is
        !            16:  * furnished to do so, under the terms of the COPYING file.
        !            17:  *
        !            18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            19:  * KIND, either express or implied.
        !            20:  *
        !            21:  ***************************************************************************/
        !            22: #include "tool_setup.h"
        !            23: 
        !            24: #ifdef HAVE_FCNTL_H
        !            25: #  include <fcntl.h>
        !            26: #endif
        !            27: 
        !            28: #ifdef HAVE_LOCALE_H
        !            29: #  include <locale.h>
        !            30: #endif
        !            31: 
        !            32: #ifdef HAVE_SYS_SELECT_H
        !            33: #  include <sys/select.h>
        !            34: #elif defined(HAVE_UNISTD_H)
        !            35: #  include <unistd.h>
        !            36: #endif
        !            37: 
        !            38: #ifdef __VMS
        !            39: #  include <fabdef.h>
        !            40: #endif
        !            41: 
        !            42: #ifdef __AMIGA__
        !            43: #  include <proto/dos.h>
        !            44: #endif
        !            45: 
        !            46: #include "strcase.h"
        !            47: 
        !            48: #define ENABLE_CURLX_PRINTF
        !            49: /* use our own printf() functions */
        !            50: #include "curlx.h"
        !            51: 
        !            52: #include "tool_binmode.h"
        !            53: #include "tool_cfgable.h"
        !            54: #include "tool_cb_dbg.h"
        !            55: #include "tool_cb_hdr.h"
        !            56: #include "tool_cb_prg.h"
        !            57: #include "tool_cb_rea.h"
        !            58: #include "tool_cb_see.h"
        !            59: #include "tool_cb_wrt.h"
        !            60: #include "tool_dirhie.h"
        !            61: #include "tool_doswin.h"
        !            62: #include "tool_easysrc.h"
        !            63: #include "tool_filetime.h"
        !            64: #include "tool_getparam.h"
        !            65: #include "tool_helpers.h"
        !            66: #include "tool_homedir.h"
        !            67: #include "tool_libinfo.h"
        !            68: #include "tool_main.h"
        !            69: #include "tool_metalink.h"
        !            70: #include "tool_msgs.h"
        !            71: #include "tool_operate.h"
        !            72: #include "tool_operhlp.h"
        !            73: #include "tool_paramhlp.h"
        !            74: #include "tool_parsecfg.h"
        !            75: #include "tool_setopt.h"
        !            76: #include "tool_sleep.h"
        !            77: #include "tool_urlglob.h"
        !            78: #include "tool_util.h"
        !            79: #include "tool_writeout.h"
        !            80: #include "tool_xattr.h"
        !            81: #include "tool_vms.h"
        !            82: #include "tool_help.h"
        !            83: #include "tool_hugehelp.h"
        !            84: #include "tool_progress.h"
        !            85: 
        !            86: #include "memdebug.h" /* keep this as LAST include */
        !            87: 
        !            88: #ifdef CURLDEBUG
        !            89: /* libcurl's debug builds provide an extra function */
        !            90: CURLcode curl_easy_perform_ev(CURL *easy);
        !            91: #endif
        !            92: 
        !            93: #define CURLseparator  "--_curl_--"
        !            94: 
        !            95: #ifndef O_BINARY
        !            96: /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
        !            97:    source code but yet it doesn't ruin anything */
        !            98: #  define O_BINARY 0
        !            99: #endif
        !           100: 
        !           101: #define CURL_CA_CERT_ERRORMSG                                               \
        !           102:   "More details here: https://curl.haxx.se/docs/sslcerts.html\n\n"          \
        !           103:   "curl failed to verify the legitimacy of the server and therefore "       \
        !           104:   "could not\nestablish a secure connection to it. To learn more about "    \
        !           105:   "this situation and\nhow to fix it, please visit the web page mentioned " \
        !           106:   "above.\n"
        !           107: 
        !           108: static CURLcode single_transfer(struct GlobalConfig *global,
        !           109:                                 struct OperationConfig *config,
        !           110:                                 CURLSH *share,
        !           111:                                 bool capath_from_env,
        !           112:                                 bool *added);
        !           113: static CURLcode create_transfer(struct GlobalConfig *global,
        !           114:                                 CURLSH *share,
        !           115:                                 bool *added);
        !           116: 
        !           117: static bool is_fatal_error(CURLcode code)
        !           118: {
        !           119:   switch(code) {
        !           120:   case CURLE_FAILED_INIT:
        !           121:   case CURLE_OUT_OF_MEMORY:
        !           122:   case CURLE_UNKNOWN_OPTION:
        !           123:   case CURLE_FUNCTION_NOT_FOUND:
        !           124:   case CURLE_BAD_FUNCTION_ARGUMENT:
        !           125:     /* critical error */
        !           126:     return TRUE;
        !           127:   default:
        !           128:     break;
        !           129:   }
        !           130: 
        !           131:   /* no error or not critical */
        !           132:   return FALSE;
        !           133: }
        !           134: 
        !           135: /*
        !           136:  * Check if a given string is a PKCS#11 URI
        !           137:  */
        !           138: static bool is_pkcs11_uri(const char *string)
        !           139: {
        !           140:   if(curl_strnequal(string, "pkcs11:", 7)) {
        !           141:     return TRUE;
        !           142:   }
        !           143:   else {
        !           144:     return FALSE;
        !           145:   }
        !           146: }
        !           147: 
        !           148: #ifdef __VMS
        !           149: /*
        !           150:  * get_vms_file_size does what it takes to get the real size of the file
        !           151:  *
        !           152:  * For fixed files, find out the size of the EOF block and adjust.
        !           153:  *
        !           154:  * For all others, have to read the entire file in, discarding the contents.
        !           155:  * Most posted text files will be small, and binary files like zlib archives
        !           156:  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
        !           157:  *
        !           158:  */
        !           159: static curl_off_t vms_realfilesize(const char *name,
        !           160:                                    const struct_stat *stat_buf)
        !           161: {
        !           162:   char buffer[8192];
        !           163:   curl_off_t count;
        !           164:   int ret_stat;
        !           165:   FILE * file;
        !           166: 
        !           167:   /* !checksrc! disable FOPENMODE 1 */
        !           168:   file = fopen(name, "r"); /* VMS */
        !           169:   if(file == NULL) {
        !           170:     return 0;
        !           171:   }
        !           172:   count = 0;
        !           173:   ret_stat = 1;
        !           174:   while(ret_stat > 0) {
        !           175:     ret_stat = fread(buffer, 1, sizeof(buffer), file);
        !           176:     if(ret_stat != 0)
        !           177:       count += ret_stat;
        !           178:   }
        !           179:   fclose(file);
        !           180: 
        !           181:   return count;
        !           182: }
        !           183: 
        !           184: /*
        !           185:  *
        !           186:  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
        !           187:  *  if not to call a routine to get the correct size.
        !           188:  *
        !           189:  */
        !           190: static curl_off_t VmsSpecialSize(const char *name,
        !           191:                                  const struct_stat *stat_buf)
        !           192: {
        !           193:   switch(stat_buf->st_fab_rfm) {
        !           194:   case FAB$C_VAR:
        !           195:   case FAB$C_VFC:
        !           196:     return vms_realfilesize(name, stat_buf);
        !           197:     break;
        !           198:   default:
        !           199:     return stat_buf->st_size;
        !           200:   }
        !           201: }
        !           202: #endif /* __VMS */
        !           203: 
        !           204: #define BUFFER_SIZE (100*1024)
        !           205: 
        !           206: struct per_transfer *transfers; /* first node */
        !           207: static struct per_transfer *transfersl; /* last node */
        !           208: 
        !           209: /* add_per_transfer creates a new 'per_transfer' node in the linked
        !           210:    list of transfers */
        !           211: static CURLcode add_per_transfer(struct per_transfer **per)
        !           212: {
        !           213:   struct per_transfer *p;
        !           214:   p = calloc(sizeof(struct per_transfer), 1);
        !           215:   if(!p)
        !           216:     return CURLE_OUT_OF_MEMORY;
        !           217:   if(!transfers)
        !           218:     /* first entry */
        !           219:     transfersl = transfers = p;
        !           220:   else {
        !           221:     /* make the last node point to the new node */
        !           222:     transfersl->next = p;
        !           223:     /* make the new node point back to the formerly last node */
        !           224:     p->prev = transfersl;
        !           225:     /* move the last node pointer to the new entry */
        !           226:     transfersl = p;
        !           227:   }
        !           228:   *per = p;
        !           229:   all_xfers++; /* count total number of transfers added */
        !           230:   return CURLE_OK;
        !           231: }
        !           232: 
        !           233: /* Remove the specified transfer from the list (and free it), return the next
        !           234:    in line */
        !           235: static struct per_transfer *del_per_transfer(struct per_transfer *per)
        !           236: {
        !           237:   struct per_transfer *n;
        !           238:   struct per_transfer *p;
        !           239:   DEBUGASSERT(transfers);
        !           240:   DEBUGASSERT(transfersl);
        !           241:   DEBUGASSERT(per);
        !           242: 
        !           243:   n = per->next;
        !           244:   p = per->prev;
        !           245: 
        !           246:   if(p)
        !           247:     p->next = n;
        !           248:   else
        !           249:     transfers = n;
        !           250: 
        !           251:   if(n)
        !           252:     n->prev = p;
        !           253:   else
        !           254:     transfersl = p;
        !           255: 
        !           256:   free(per);
        !           257: 
        !           258:   return n;
        !           259: }
        !           260: 
        !           261: static CURLcode pre_transfer(struct GlobalConfig *global,
        !           262:                              struct per_transfer *per)
        !           263: {
        !           264:   curl_off_t uploadfilesize = -1;
        !           265:   struct_stat fileinfo;
        !           266:   CURLcode result = CURLE_OK;
        !           267: 
        !           268:   if(per->separator_err)
        !           269:     fprintf(global->errors, "%s\n", per->separator_err);
        !           270:   if(per->separator)
        !           271:     printf("%s\n", per->separator);
        !           272: 
        !           273:   if(per->uploadfile && !stdin_upload(per->uploadfile)) {
        !           274:     /* VMS Note:
        !           275:      *
        !           276:      * Reading binary from files can be a problem...  Only FIXED, VAR
        !           277:      * etc WITHOUT implied CC will work Others need a \n appended to a
        !           278:      * line
        !           279:      *
        !           280:      * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
        !           281:      * fixed file with implied CC needs to have a byte added for every
        !           282:      * record processed, this can by derived from Filesize & recordsize
        !           283:      * for VARiable record files the records need to be counted!  for
        !           284:      * every record add 1 for linefeed and subtract 2 for the record
        !           285:      * header for VARIABLE header files only the bare record data needs
        !           286:      * to be considered with one appended if implied CC
        !           287:      */
        !           288: #ifdef __VMS
        !           289:     /* Calculate the real upload size for VMS */
        !           290:     per->infd = -1;
        !           291:     if(stat(per->uploadfile, &fileinfo) == 0) {
        !           292:       fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
        !           293:       switch(fileinfo.st_fab_rfm) {
        !           294:       case FAB$C_VAR:
        !           295:       case FAB$C_VFC:
        !           296:       case FAB$C_STMCR:
        !           297:         per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
        !           298:         break;
        !           299:       default:
        !           300:         per->infd = open(per->uploadfile, O_RDONLY | O_BINARY,
        !           301:                         "rfm=stmlf", "ctx=stm");
        !           302:       }
        !           303:     }
        !           304:     if(per->infd == -1)
        !           305: #else
        !           306:       per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
        !           307:     if((per->infd == -1) || fstat(per->infd, &fileinfo))
        !           308: #endif
        !           309:     {
        !           310:       helpf(global->errors, "Can't open '%s'!\n", per->uploadfile);
        !           311:       if(per->infd != -1) {
        !           312:         close(per->infd);
        !           313:         per->infd = STDIN_FILENO;
        !           314:       }
        !           315:       return CURLE_READ_ERROR;
        !           316:     }
        !           317:     per->infdopen = TRUE;
        !           318: 
        !           319:     /* we ignore file size for char/block devices, sockets, etc. */
        !           320:     if(S_ISREG(fileinfo.st_mode))
        !           321:       uploadfilesize = fileinfo.st_size;
        !           322: 
        !           323:     if(uploadfilesize != -1)
        !           324:       my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
        !           325:     per->input.fd = per->infd;
        !           326:   }
        !           327:   return result;
        !           328: }
        !           329: 
        !           330: /*
        !           331:  * Call this after a transfer has completed.
        !           332:  */
        !           333: static CURLcode post_per_transfer(struct GlobalConfig *global,
        !           334:                                   struct per_transfer *per,
        !           335:                                   CURLcode result,
        !           336:                                   bool *retryp)
        !           337: {
        !           338:   struct OutStruct *outs = &per->outs;
        !           339:   CURL *curl = per->curl;
        !           340:   struct OperationConfig *config = per->config;
        !           341: 
        !           342:   if(!curl || !config)
        !           343:     return result;
        !           344: 
        !           345:   *retryp = FALSE;
        !           346: 
        !           347:   if(per->infdopen)
        !           348:     close(per->infd);
        !           349: 
        !           350: #ifdef __VMS
        !           351:   if(is_vms_shell()) {
        !           352:     /* VMS DCL shell behavior */
        !           353:     if(!global->showerror)
        !           354:       vms_show = VMSSTS_HIDE;
        !           355:   }
        !           356:   else
        !           357: #endif
        !           358:     if(config->synthetic_error) {
        !           359:       ;
        !           360:     }
        !           361:     else if(result && global->showerror) {
        !           362:       fprintf(global->errors, "curl: (%d) %s\n", result,
        !           363:               (per->errorbuffer[0]) ? per->errorbuffer :
        !           364:               curl_easy_strerror(result));
        !           365:       if(result == CURLE_PEER_FAILED_VERIFICATION)
        !           366:         fputs(CURL_CA_CERT_ERRORMSG, global->errors);
        !           367:     }
        !           368: 
        !           369:   /* Set file extended attributes */
        !           370:   if(!result && config->xattr && outs->fopened && outs->stream) {
        !           371:     int rc = fwrite_xattr(curl, fileno(outs->stream));
        !           372:     if(rc)
        !           373:       warnf(config->global, "Error setting extended attributes: %s\n",
        !           374:             strerror(errno));
        !           375:   }
        !           376: 
        !           377:   if(!result && !outs->stream && !outs->bytes) {
        !           378:     /* we have received no data despite the transfer was successful
        !           379:        ==> force cration of an empty output file (if an output file
        !           380:        was specified) */
        !           381:     long cond_unmet = 0L;
        !           382:     /* do not create (or even overwrite) the file in case we get no
        !           383:        data because of unmet condition */
        !           384:     curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
        !           385:     if(!cond_unmet && !tool_create_output_file(outs, config))
        !           386:       result = CURLE_WRITE_ERROR;
        !           387:   }
        !           388: 
        !           389:   if(!outs->s_isreg && outs->stream) {
        !           390:     /* Dump standard stream buffered data */
        !           391:     int rc = fflush(outs->stream);
        !           392:     if(!result && rc) {
        !           393:       /* something went wrong in the writing process */
        !           394:       result = CURLE_WRITE_ERROR;
        !           395:       fprintf(global->errors, "(%d) Failed writing body\n", result);
        !           396:     }
        !           397:   }
        !           398: 
        !           399: #ifdef USE_METALINK
        !           400:   if(per->metalink && !per->metalink_next_res)
        !           401:     fprintf(global->errors, "Metalink: fetching (%s) from (%s) OK\n",
        !           402:             per->mlfile->filename, per->this_url);
        !           403: 
        !           404:   if(!per->metalink && config->use_metalink && result == CURLE_OK) {
        !           405:     int rv = parse_metalink(config, outs, per->this_url);
        !           406:     if(!rv) {
        !           407:       fprintf(config->global->errors, "Metalink: parsing (%s) OK\n",
        !           408:               per->this_url);
        !           409:     }
        !           410:     else if(rv == -1)
        !           411:       fprintf(config->global->errors, "Metalink: parsing (%s) FAILED\n",
        !           412:               per->this_url);
        !           413:   }
        !           414:   else if(per->metalink && result == CURLE_OK && !per->metalink_next_res) {
        !           415:     int rv;
        !           416:     (void)fflush(outs->stream);
        !           417:     rv = metalink_check_hash(global, per->mlfile, outs->filename);
        !           418:     if(!rv)
        !           419:       per->metalink_next_res = 1;
        !           420:   }
        !           421: #endif /* USE_METALINK */
        !           422: 
        !           423: #ifdef USE_METALINK
        !           424:   if(outs->metalink_parser)
        !           425:     metalink_parser_context_delete(outs->metalink_parser);
        !           426: #endif /* USE_METALINK */
        !           427: 
        !           428:   if(outs->is_cd_filename && outs->stream && !global->mute &&
        !           429:      outs->filename)
        !           430:     printf("curl: Saved to filename '%s'\n", outs->filename);
        !           431: 
        !           432:   /* if retry-max-time is non-zero, make sure we haven't exceeded the
        !           433:      time */
        !           434:   if(per->retry_numretries &&
        !           435:      (!config->retry_maxtime ||
        !           436:       (tvdiff(tvnow(), per->retrystart) <
        !           437:        config->retry_maxtime*1000L)) ) {
        !           438:     enum {
        !           439:       RETRY_NO,
        !           440:       RETRY_TIMEOUT,
        !           441:       RETRY_CONNREFUSED,
        !           442:       RETRY_HTTP,
        !           443:       RETRY_FTP,
        !           444:       RETRY_LAST /* not used */
        !           445:     } retry = RETRY_NO;
        !           446:     long response;
        !           447:     if((CURLE_OPERATION_TIMEDOUT == result) ||
        !           448:        (CURLE_COULDNT_RESOLVE_HOST == result) ||
        !           449:        (CURLE_COULDNT_RESOLVE_PROXY == result) ||
        !           450:        (CURLE_FTP_ACCEPT_TIMEOUT == result))
        !           451:       /* retry timeout always */
        !           452:       retry = RETRY_TIMEOUT;
        !           453:     else if(config->retry_connrefused &&
        !           454:             (CURLE_COULDNT_CONNECT == result)) {
        !           455:       long oserrno;
        !           456:       curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
        !           457:       if(ECONNREFUSED == oserrno)
        !           458:         retry = RETRY_CONNREFUSED;
        !           459:     }
        !           460:     else if((CURLE_OK == result) ||
        !           461:             (config->failonerror &&
        !           462:              (CURLE_HTTP_RETURNED_ERROR == result))) {
        !           463:       /* If it returned OK. _or_ failonerror was enabled and it
        !           464:          returned due to such an error, check for HTTP transient
        !           465:          errors to retry on. */
        !           466:       long protocol;
        !           467:       curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
        !           468:       if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) {
        !           469:         /* This was HTTP(S) */
        !           470:         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
        !           471: 
        !           472:         switch(response) {
        !           473:         case 429: /* Too Many Requests (RFC6585) */
        !           474:         case 500: /* Internal Server Error */
        !           475:         case 502: /* Bad Gateway */
        !           476:         case 503: /* Service Unavailable */
        !           477:         case 504: /* Gateway Timeout */
        !           478:           retry = RETRY_HTTP;
        !           479:           /*
        !           480:            * At this point, we have already written data to the output
        !           481:            * file (or terminal). If we write to a file, we must rewind
        !           482:            * or close/re-open the file so that the next attempt starts
        !           483:            * over from the beginning.
        !           484:            *
        !           485:            * TODO: similar action for the upload case. We might need
        !           486:            * to start over reading from a previous point if we have
        !           487:            * uploaded something when this was returned.
        !           488:            */
        !           489:           break;
        !           490:         }
        !           491:       }
        !           492:     } /* if CURLE_OK */
        !           493:     else if(result) {
        !           494:       long protocol;
        !           495: 
        !           496:       curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
        !           497:       curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
        !           498: 
        !           499:       if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) &&
        !           500:          response / 100 == 4)
        !           501:         /*
        !           502:          * This is typically when the FTP server only allows a certain
        !           503:          * amount of users and we are not one of them.  All 4xx codes
        !           504:          * are transient.
        !           505:          */
        !           506:         retry = RETRY_FTP;
        !           507:     }
        !           508: 
        !           509:     if(retry) {
        !           510:       long sleeptime = 0;
        !           511:       curl_off_t retry_after = 0;
        !           512:       static const char * const m[]={
        !           513:         NULL,
        !           514:         "timeout",
        !           515:         "connection refused",
        !           516:         "HTTP error",
        !           517:         "FTP error"
        !           518:       };
        !           519: 
        !           520:       sleeptime = per->retry_sleep;
        !           521:       if(RETRY_HTTP == retry) {
        !           522:         curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
        !           523:         if(retry_after) {
        !           524:           /* store in a 'long', make sure it doesn't overflow */
        !           525:           if(retry_after > LONG_MAX/1000)
        !           526:             sleeptime = LONG_MAX;
        !           527:           else
        !           528:             sleeptime = (long)retry_after * 1000; /* milliseconds */
        !           529:         }
        !           530:       }
        !           531:       warnf(config->global, "Transient problem: %s "
        !           532:             "Will retry in %ld seconds. "
        !           533:             "%ld retries left.\n",
        !           534:             m[retry], sleeptime/1000L, per->retry_numretries);
        !           535: 
        !           536:       per->retry_numretries--;
        !           537:       tool_go_sleep(sleeptime);
        !           538:       if(!config->retry_delay) {
        !           539:         per->retry_sleep *= 2;
        !           540:         if(per->retry_sleep > RETRY_SLEEP_MAX)
        !           541:           per->retry_sleep = RETRY_SLEEP_MAX;
        !           542:       }
        !           543:       if(outs->bytes && outs->filename && outs->stream) {
        !           544:         int rc;
        !           545:         /* We have written data to a output file, we truncate file
        !           546:          */
        !           547:         if(!global->mute)
        !           548:           fprintf(global->errors, "Throwing away %"
        !           549:                   CURL_FORMAT_CURL_OFF_T " bytes\n",
        !           550:                   outs->bytes);
        !           551:         fflush(outs->stream);
        !           552:         /* truncate file at the position where we started appending */
        !           553: #ifdef HAVE_FTRUNCATE
        !           554:         if(ftruncate(fileno(outs->stream), outs->init)) {
        !           555:           /* when truncate fails, we can't just append as then we'll
        !           556:              create something strange, bail out */
        !           557:           if(!global->mute)
        !           558:             fprintf(global->errors,
        !           559:                     "failed to truncate, exiting\n");
        !           560:           return CURLE_WRITE_ERROR;
        !           561:         }
        !           562:         /* now seek to the end of the file, the position where we
        !           563:            just truncated the file in a large file-safe way */
        !           564:         rc = fseek(outs->stream, 0, SEEK_END);
        !           565: #else
        !           566:         /* ftruncate is not available, so just reposition the file
        !           567:            to the location we would have truncated it. This won't
        !           568:            work properly with large files on 32-bit systems, but
        !           569:            most of those will have ftruncate. */
        !           570:         rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
        !           571: #endif
        !           572:         if(rc) {
        !           573:           if(!global->mute)
        !           574:             fprintf(global->errors,
        !           575:                     "failed seeking to end of file, exiting\n");
        !           576:           return CURLE_WRITE_ERROR;
        !           577:         }
        !           578:         outs->bytes = 0; /* clear for next round */
        !           579:       }
        !           580:       *retryp = TRUE; /* curl_easy_perform loop */
        !           581:       return CURLE_OK;
        !           582:     }
        !           583:   } /* if retry_numretries */
        !           584:   else if(per->metalink) {
        !           585:     /* Metalink: Decide to try the next resource or not. Try the next resource
        !           586:        if download was not successful. */
        !           587:     long response;
        !           588:     if(CURLE_OK == result) {
        !           589:       /* TODO We want to try next resource when download was
        !           590:          not successful. How to know that? */
        !           591:       char *effective_url = NULL;
        !           592:       curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
        !           593:       if(effective_url &&
        !           594:          curl_strnequal(effective_url, "http", 4)) {
        !           595:         /* This was HTTP(S) */
        !           596:         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
        !           597:         if(response != 200 && response != 206) {
        !           598:           per->metalink_next_res = 1;
        !           599:           fprintf(global->errors,
        !           600:                   "Metalink: fetching (%s) from (%s) FAILED "
        !           601:                   "(HTTP status code %ld)\n",
        !           602:                   per->mlfile->filename, per->this_url, response);
        !           603:         }
        !           604:       }
        !           605:     }
        !           606:     else {
        !           607:       per->metalink_next_res = 1;
        !           608:       fprintf(global->errors,
        !           609:               "Metalink: fetching (%s) from (%s) FAILED (%s)\n",
        !           610:               per->mlfile->filename, per->this_url,
        !           611:               curl_easy_strerror(result));
        !           612:     }
        !           613:   }
        !           614: 
        !           615:   if((global->progressmode == CURL_PROGRESS_BAR) &&
        !           616:      per->progressbar.calls)
        !           617:     /* if the custom progress bar has been displayed, we output a
        !           618:        newline here */
        !           619:     fputs("\n", per->progressbar.out);
        !           620: 
        !           621:   if(config->writeout)
        !           622:     ourWriteOut(per->curl, &per->outs, config->writeout);
        !           623: 
        !           624:   /* Close the outs file */
        !           625:   if(outs->fopened && outs->stream) {
        !           626:     int rc = fclose(outs->stream);
        !           627:     if(!result && rc) {
        !           628:       /* something went wrong in the writing process */
        !           629:       result = CURLE_WRITE_ERROR;
        !           630:       fprintf(global->errors, "(%d) Failed writing body\n", result);
        !           631:     }
        !           632:   }
        !           633: 
        !           634:   /* File time can only be set _after_ the file has been closed */
        !           635:   if(!result && config->remote_time && outs->s_isreg && outs->filename) {
        !           636:     /* Ask libcurl if we got a remote file time */
        !           637:     curl_off_t filetime = -1;
        !           638:     curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime);
        !           639:     setfiletime(filetime, outs->filename, config->global->errors);
        !           640:   }
        !           641: 
        !           642:   /* Close function-local opened file descriptors */
        !           643:   if(per->heads.fopened && per->heads.stream)
        !           644:     fclose(per->heads.stream);
        !           645: 
        !           646:   if(per->heads.alloc_filename)
        !           647:     Curl_safefree(per->heads.filename);
        !           648: 
        !           649:   if(per->etag_save.fopened && per->etag_save.stream)
        !           650:     fclose(per->etag_save.stream);
        !           651: 
        !           652:   if(per->etag_save.alloc_filename)
        !           653:     Curl_safefree(per->etag_save.filename);
        !           654: 
        !           655:   curl_easy_cleanup(per->curl);
        !           656:   if(outs->alloc_filename)
        !           657:     free(outs->filename);
        !           658:   free(per->this_url);
        !           659:   free(per->separator_err);
        !           660:   free(per->separator);
        !           661:   free(per->outfile);
        !           662:   free(per->uploadfile);
        !           663: 
        !           664:   return CURLE_OK;
        !           665: }
        !           666: 
        !           667: static void single_transfer_cleanup(struct OperationConfig *config)
        !           668: {
        !           669:   if(config) {
        !           670:     struct State *state = &config->state;
        !           671:     if(state->urls) {
        !           672:       /* Free list of remaining URLs */
        !           673:       glob_cleanup(state->urls);
        !           674:       state->urls = NULL;
        !           675:     }
        !           676:     Curl_safefree(state->outfiles);
        !           677:     Curl_safefree(state->httpgetfields);
        !           678:     Curl_safefree(state->uploadfile);
        !           679:     if(state->inglob) {
        !           680:       /* Free list of globbed upload files */
        !           681:       glob_cleanup(state->inglob);
        !           682:       state->inglob = NULL;
        !           683:     }
        !           684:   }
        !           685: }
        !           686: 
        !           687: /* create the next (singular) transfer */
        !           688: 
        !           689: static CURLcode single_transfer(struct GlobalConfig *global,
        !           690:                                 struct OperationConfig *config,
        !           691:                                 CURLSH *share,
        !           692:                                 bool capath_from_env,
        !           693:                                 bool *added)
        !           694: {
        !           695:   CURLcode result = CURLE_OK;
        !           696:   struct getout *urlnode;
        !           697:   metalinkfile *mlfile_last = NULL;
        !           698:   bool orig_noprogress = global->noprogress;
        !           699:   bool orig_isatty = global->isatty;
        !           700:   struct State *state = &config->state;
        !           701:   char *httpgetfields = state->httpgetfields;
        !           702:   *added = FALSE; /* not yet */
        !           703: 
        !           704:   if(config->postfields) {
        !           705:     if(config->use_httpget) {
        !           706:       if(!httpgetfields) {
        !           707:         /* Use the postfields data for a http get */
        !           708:         httpgetfields = state->httpgetfields = strdup(config->postfields);
        !           709:         Curl_safefree(config->postfields);
        !           710:         if(!httpgetfields) {
        !           711:           errorf(global, "out of memory\n");
        !           712:           result = CURLE_OUT_OF_MEMORY;
        !           713:         }
        !           714:         else if(SetHTTPrequest(config,
        !           715:                                (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
        !           716:                                &config->httpreq)) {
        !           717:           result = CURLE_FAILED_INIT;
        !           718:         }
        !           719:       }
        !           720:     }
        !           721:     else {
        !           722:       if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
        !           723:         result = CURLE_FAILED_INIT;
        !           724:     }
        !           725:     if(result) {
        !           726:       single_transfer_cleanup(config);
        !           727:       return result;
        !           728:     }
        !           729:   }
        !           730:   if(!state->urlnode) {
        !           731:     /* first time caller, setup things */
        !           732:     state->urlnode = config->url_list;
        !           733:     state->infilenum = 1;
        !           734:   }
        !           735: 
        !           736:   while(config->state.urlnode) {
        !           737:     char *infiles; /* might be a glob pattern */
        !           738:     URLGlob *inglob = state->inglob;
        !           739:     bool metalink = FALSE; /* metalink download? */
        !           740:     metalinkfile *mlfile;
        !           741:     metalink_resource *mlres;
        !           742: 
        !           743:     urlnode = config->state.urlnode;
        !           744:     if(urlnode->flags & GETOUT_METALINK) {
        !           745:       metalink = 1;
        !           746:       if(mlfile_last == NULL) {
        !           747:         mlfile_last = config->metalinkfile_list;
        !           748:       }
        !           749:       mlfile = mlfile_last;
        !           750:       mlfile_last = mlfile_last->next;
        !           751:       mlres = mlfile->resource;
        !           752:     }
        !           753:     else {
        !           754:       mlfile = NULL;
        !           755:       mlres = NULL;
        !           756:     }
        !           757: 
        !           758:     /* urlnode->url is the full URL (it might be NULL) */
        !           759: 
        !           760:     if(!urlnode->url) {
        !           761:       /* This node has no URL. Free node data without destroying the
        !           762:          node itself nor modifying next pointer and continue to next */
        !           763:       Curl_safefree(urlnode->outfile);
        !           764:       Curl_safefree(urlnode->infile);
        !           765:       urlnode->flags = 0;
        !           766:       config->state.urlnode = urlnode->next;
        !           767:       state->up = 0;
        !           768:       continue; /* next URL please */
        !           769:     }
        !           770: 
        !           771:     /* save outfile pattern before expansion */
        !           772:     if(urlnode->outfile && !state->outfiles) {
        !           773:       state->outfiles = strdup(urlnode->outfile);
        !           774:       if(!state->outfiles) {
        !           775:         errorf(global, "out of memory\n");
        !           776:         result = CURLE_OUT_OF_MEMORY;
        !           777:         break;
        !           778:       }
        !           779:     }
        !           780: 
        !           781:     infiles = urlnode->infile;
        !           782: 
        !           783:     if(!config->globoff && infiles && !inglob) {
        !           784:       /* Unless explicitly shut off */
        !           785:       result = glob_url(&inglob, infiles, &state->infilenum,
        !           786:                         global->showerror?global->errors:NULL);
        !           787:       if(result)
        !           788:         break;
        !           789:       config->state.inglob = inglob;
        !           790:     }
        !           791: 
        !           792:     {
        !           793:       int separator;
        !           794:       unsigned long urlnum;
        !           795: 
        !           796:       if(!state->up && !infiles)
        !           797:         Curl_nop_stmt;
        !           798:       else {
        !           799:         if(!state->uploadfile) {
        !           800:           if(inglob) {
        !           801:             result = glob_next_url(&state->uploadfile, inglob);
        !           802:             if(result == CURLE_OUT_OF_MEMORY)
        !           803:               errorf(global, "out of memory\n");
        !           804:           }
        !           805:           else if(!state->up) {
        !           806:             state->uploadfile = strdup(infiles);
        !           807:             if(!state->uploadfile) {
        !           808:               errorf(global, "out of memory\n");
        !           809:               result = CURLE_OUT_OF_MEMORY;
        !           810:             }
        !           811:           }
        !           812:         }
        !           813:         if(result)
        !           814:           break;
        !           815:       }
        !           816: 
        !           817:       if(!state->urlnum) {
        !           818:         if(metalink) {
        !           819:           /* For Metalink download, we don't use glob. Instead we use
        !           820:              the number of resources as urlnum. */
        !           821:           urlnum = count_next_metalink_resource(mlfile);
        !           822:         }
        !           823:         else if(!config->globoff) {
        !           824:           /* Unless explicitly shut off, we expand '{...}' and '[...]'
        !           825:              expressions and return total number of URLs in pattern set */
        !           826:           result = glob_url(&state->urls, urlnode->url, &state->urlnum,
        !           827:                             global->showerror?global->errors:NULL);
        !           828:           if(result)
        !           829:             break;
        !           830:           urlnum = state->urlnum;
        !           831:         }
        !           832:         else
        !           833:           urlnum = 1; /* without globbing, this is a single URL */
        !           834:       }
        !           835:       else
        !           836:         urlnum = state->urlnum;
        !           837: 
        !           838:       /* if multiple files extracted to stdout, insert separators! */
        !           839:       separator = ((!state->outfiles ||
        !           840:                     !strcmp(state->outfiles, "-")) && urlnum > 1);
        !           841: 
        !           842:       if(state->up < state->infilenum) {
        !           843:         struct per_transfer *per;
        !           844:         struct OutStruct *outs;
        !           845:         struct InStruct *input;
        !           846:         struct OutStruct *heads;
        !           847:         struct OutStruct *etag_save;
        !           848:         struct HdrCbData *hdrcbdata = NULL;
        !           849:         CURL *curl = curl_easy_init();
        !           850:         result = add_per_transfer(&per);
        !           851:         if(result || !curl) {
        !           852:           curl_easy_cleanup(curl);
        !           853:           result = CURLE_OUT_OF_MEMORY;
        !           854:           break;
        !           855:         }
        !           856:         if(state->uploadfile) {
        !           857:           per->uploadfile = strdup(state->uploadfile);
        !           858:           if(!per->uploadfile) {
        !           859:             curl_easy_cleanup(curl);
        !           860:             result = CURLE_OUT_OF_MEMORY;
        !           861:             break;
        !           862:           }
        !           863:         }
        !           864:         *added = TRUE;
        !           865:         per->config = config;
        !           866:         per->curl = curl;
        !           867: 
        !           868:         /* default headers output stream is stdout */
        !           869:         heads = &per->heads;
        !           870:         heads->stream = stdout;
        !           871: 
        !           872:         /* Single header file for all URLs */
        !           873:         if(config->headerfile) {
        !           874:           /* open file for output: */
        !           875:           if(strcmp(config->headerfile, "-")) {
        !           876:             FILE *newfile;
        !           877:             newfile = fopen(config->headerfile, per->prev == NULL?"wb":"ab");
        !           878:             if(!newfile) {
        !           879:               warnf(config->global, "Failed to open %s\n", config->headerfile);
        !           880:               result = CURLE_WRITE_ERROR;
        !           881:               break;
        !           882:             }
        !           883:             else {
        !           884:               heads->filename = config->headerfile;
        !           885:               heads->s_isreg = TRUE;
        !           886:               heads->fopened = TRUE;
        !           887:               heads->stream = newfile;
        !           888:             }
        !           889:           }
        !           890:           else {
        !           891:             /* always use binary mode for protocol header output */
        !           892:             set_binmode(heads->stream);
        !           893:           }
        !           894:         }
        !           895: 
        !           896:         hdrcbdata = &per->hdrcbdata;
        !           897: 
        !           898:         outs = &per->outs;
        !           899:         input = &per->input;
        !           900: 
        !           901:         per->outfile = NULL;
        !           902:         per->infdopen = FALSE;
        !           903:         per->infd = STDIN_FILENO;
        !           904: 
        !           905:         /* default output stream is stdout */
        !           906:         outs->stream = stdout;
        !           907: 
        !           908:         /* --etag-compare */
        !           909:         if(config->etag_compare_file) {
        !           910:           char *etag_from_file = NULL;
        !           911:           char *header = NULL;
        !           912: 
        !           913:           /* open file for reading: */
        !           914:           FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT);
        !           915:           if(!file && !config->etag_save_file) {
        !           916:             errorf(config->global,
        !           917:                    "Failed to open %s\n", config->etag_compare_file);
        !           918:             result = CURLE_READ_ERROR;
        !           919:             break;
        !           920:           }
        !           921: 
        !           922:           if((PARAM_OK == file2string(&etag_from_file, file)) &&
        !           923:              etag_from_file) {
        !           924:             header = aprintf("If-None-Match: \"%s\"", etag_from_file);
        !           925:             Curl_safefree(etag_from_file);
        !           926:           }
        !           927:           else
        !           928:             header = aprintf("If-None-Match: \"\"");
        !           929: 
        !           930:           if(!header) {
        !           931:             if(file)
        !           932:               fclose(file);
        !           933:             errorf(config->global,
        !           934:                    "Failed to allocate memory for custom etag header\n");
        !           935:             result = CURLE_OUT_OF_MEMORY;
        !           936:             break;
        !           937:           }
        !           938: 
        !           939:           /* add Etag from file to list of custom headers */
        !           940:           add2list(&config->headers, header);
        !           941: 
        !           942:           Curl_safefree(header);
        !           943: 
        !           944:           if(file) {
        !           945:             fclose(file);
        !           946:           }
        !           947:         }
        !           948: 
        !           949:         /* --etag-save */
        !           950:         etag_save = &per->etag_save;
        !           951:         etag_save->stream = stdout;
        !           952: 
        !           953:         if(config->etag_save_file) {
        !           954:           /* open file for output: */
        !           955:           if(strcmp(config->etag_save_file, "-")) {
        !           956:             FILE *newfile = fopen(config->etag_save_file, "wb");
        !           957:             if(!newfile) {
        !           958:               warnf(
        !           959:                 config->global,
        !           960:                 "Failed to open %s\n", config->etag_save_file);
        !           961: 
        !           962:               result = CURLE_WRITE_ERROR;
        !           963:               break;
        !           964:             }
        !           965:             else {
        !           966:               etag_save->filename = config->etag_save_file;
        !           967:               etag_save->s_isreg = TRUE;
        !           968:               etag_save->fopened = TRUE;
        !           969:               etag_save->stream = newfile;
        !           970:             }
        !           971:           }
        !           972:           else {
        !           973:             /* always use binary mode for protocol header output */
        !           974:             set_binmode(etag_save->stream);
        !           975:           }
        !           976:         }
        !           977: 
        !           978:         if(metalink) {
        !           979:           /* For Metalink download, use name in Metalink file as
        !           980:              filename. */
        !           981:           per->outfile = strdup(mlfile->filename);
        !           982:           if(!per->outfile) {
        !           983:             result = CURLE_OUT_OF_MEMORY;
        !           984:             break;
        !           985:           }
        !           986:           per->this_url = strdup(mlres->url);
        !           987:           if(!per->this_url) {
        !           988:             result = CURLE_OUT_OF_MEMORY;
        !           989:             break;
        !           990:           }
        !           991:           per->mlfile = mlfile;
        !           992:         }
        !           993:         else {
        !           994:           if(state->urls) {
        !           995:             result = glob_next_url(&per->this_url, state->urls);
        !           996:             if(result)
        !           997:               break;
        !           998:           }
        !           999:           else if(!state->li) {
        !          1000:             per->this_url = strdup(urlnode->url);
        !          1001:             if(!per->this_url) {
        !          1002:               result = CURLE_OUT_OF_MEMORY;
        !          1003:               break;
        !          1004:             }
        !          1005:           }
        !          1006:           else
        !          1007:             per->this_url = NULL;
        !          1008:           if(!per->this_url)
        !          1009:             break;
        !          1010: 
        !          1011:           if(state->outfiles) {
        !          1012:             per->outfile = strdup(state->outfiles);
        !          1013:             if(!per->outfile) {
        !          1014:               result = CURLE_OUT_OF_MEMORY;
        !          1015:               break;
        !          1016:             }
        !          1017:           }
        !          1018:         }
        !          1019: 
        !          1020:         if(((urlnode->flags&GETOUT_USEREMOTE) ||
        !          1021:             (per->outfile && strcmp("-", per->outfile))) &&
        !          1022:            (metalink || !config->use_metalink)) {
        !          1023: 
        !          1024:           /*
        !          1025:            * We have specified a file name to store the result in, or we have
        !          1026:            * decided we want to use the remote file name.
        !          1027:            */
        !          1028: 
        !          1029:           if(!per->outfile) {
        !          1030:             /* extract the file name from the URL */
        !          1031:             result = get_url_file_name(&per->outfile, per->this_url);
        !          1032:             if(result)
        !          1033:               break;
        !          1034:             if(!*per->outfile && !config->content_disposition) {
        !          1035:               errorf(global, "Remote file name has no length!\n");
        !          1036:               result = CURLE_WRITE_ERROR;
        !          1037:               break;
        !          1038:             }
        !          1039:           }
        !          1040:           else if(state->urls) {
        !          1041:             /* fill '#1' ... '#9' terms from URL pattern */
        !          1042:             char *storefile = per->outfile;
        !          1043:             result = glob_match_url(&per->outfile, storefile, state->urls);
        !          1044:             Curl_safefree(storefile);
        !          1045:             if(result) {
        !          1046:               /* bad globbing */
        !          1047:               warnf(config->global, "bad output glob!\n");
        !          1048:               break;
        !          1049:             }
        !          1050:           }
        !          1051: 
        !          1052:           /* Create the directory hierarchy, if not pre-existent to a multiple
        !          1053:              file output call */
        !          1054: 
        !          1055:           if(config->create_dirs || metalink) {
        !          1056:             result = create_dir_hierarchy(per->outfile, global->errors);
        !          1057:             /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
        !          1058:             if(result)
        !          1059:               break;
        !          1060:           }
        !          1061: 
        !          1062:           if((urlnode->flags & GETOUT_USEREMOTE)
        !          1063:              && config->content_disposition) {
        !          1064:             /* Our header callback MIGHT set the filename */
        !          1065:             DEBUGASSERT(!outs->filename);
        !          1066:           }
        !          1067: 
        !          1068:           if(config->resume_from || config->resume_from_current) {
        !          1069: #ifdef __VMS
        !          1070:             /* open file for output, forcing VMS output format into stream
        !          1071:                mode which is needed for stat() call above to always work. */
        !          1072:             FILE *file = fopen(outfile, "ab",
        !          1073:                                "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
        !          1074: #else
        !          1075:             /* open file for output: */
        !          1076:             FILE *file = fopen(per->outfile, "ab");
        !          1077: #endif
        !          1078:             if(!file) {
        !          1079:               errorf(global, "Can't open '%s'!\n", per->outfile);
        !          1080:               result = CURLE_WRITE_ERROR;
        !          1081:               break;
        !          1082:             }
        !          1083:             outs->fopened = TRUE;
        !          1084:             outs->stream = file;
        !          1085: 
        !          1086:             if(config->resume_from_current) {
        !          1087:               /* We're told to continue from where we are now. Get the size
        !          1088:                  of the file as it is now */
        !          1089:               struct_stat fileinfo;
        !          1090:               if(0 == fstat(fileno(outs->stream), &fileinfo))
        !          1091:                 /* set offset to current file size: */
        !          1092:                 config->resume_from = fileinfo.st_size;
        !          1093:               else
        !          1094:                 /* let offset be 0 */
        !          1095:                 config->resume_from = 0;
        !          1096:             }
        !          1097: 
        !          1098:             outs->init = config->resume_from;
        !          1099:           }
        !          1100:           else {
        !          1101:             outs->stream = NULL; /* open when needed */
        !          1102:           }
        !          1103:           outs->filename = per->outfile;
        !          1104:           outs->s_isreg = TRUE;
        !          1105:         }
        !          1106: 
        !          1107:         if(per->uploadfile && !stdin_upload(per->uploadfile)) {
        !          1108:           /*
        !          1109:            * We have specified a file to upload and it isn't "-".
        !          1110:            */
        !          1111:           char *nurl = add_file_name_to_url(per->this_url, per->uploadfile);
        !          1112:           if(!nurl) {
        !          1113:             result = CURLE_OUT_OF_MEMORY;
        !          1114:             break;
        !          1115:           }
        !          1116:           per->this_url = nurl;
        !          1117:         }
        !          1118:         else if(per->uploadfile && stdin_upload(per->uploadfile)) {
        !          1119:           /* count to see if there are more than one auth bit set
        !          1120:              in the authtype field */
        !          1121:           int authbits = 0;
        !          1122:           int bitcheck = 0;
        !          1123:           while(bitcheck < 32) {
        !          1124:             if(config->authtype & (1UL << bitcheck++)) {
        !          1125:               authbits++;
        !          1126:               if(authbits > 1) {
        !          1127:                 /* more than one, we're done! */
        !          1128:                 break;
        !          1129:               }
        !          1130:             }
        !          1131:           }
        !          1132: 
        !          1133:           /*
        !          1134:            * If the user has also selected --anyauth or --proxy-anyauth
        !          1135:            * we should warn him/her.
        !          1136:            */
        !          1137:           if(config->proxyanyauth || (authbits>1)) {
        !          1138:             warnf(config->global,
        !          1139:                   "Using --anyauth or --proxy-anyauth with upload from stdin"
        !          1140:                   " involves a big risk of it not working. Use a temporary"
        !          1141:                   " file or a fixed auth type instead!\n");
        !          1142:           }
        !          1143: 
        !          1144:           DEBUGASSERT(per->infdopen == FALSE);
        !          1145:           DEBUGASSERT(per->infd == STDIN_FILENO);
        !          1146: 
        !          1147:           set_binmode(stdin);
        !          1148:           if(!strcmp(per->uploadfile, ".")) {
        !          1149:             if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0)
        !          1150:               warnf(config->global,
        !          1151:                     "fcntl failed on fd=%d: %s\n", per->infd, strerror(errno));
        !          1152:           }
        !          1153:         }
        !          1154: 
        !          1155:         if(per->uploadfile && config->resume_from_current)
        !          1156:           config->resume_from = -1; /* -1 will then force get-it-yourself */
        !          1157: 
        !          1158:         if(output_expected(per->this_url, per->uploadfile) && outs->stream &&
        !          1159:            isatty(fileno(outs->stream)))
        !          1160:           /* we send the output to a tty, therefore we switch off the progress
        !          1161:              meter */
        !          1162:           per->noprogress = global->noprogress = global->isatty = TRUE;
        !          1163:         else {
        !          1164:           /* progress meter is per download, so restore config
        !          1165:              values */
        !          1166:           per->noprogress = global->noprogress = orig_noprogress;
        !          1167:           global->isatty = orig_isatty;
        !          1168:         }
        !          1169: 
        !          1170:         if(urlnum > 1 && !global->mute) {
        !          1171:           per->separator_err =
        !          1172:             aprintf("\n[%lu/%lu]: %s --> %s",
        !          1173:                     state->li + 1, urlnum, per->this_url,
        !          1174:                     per->outfile ? per->outfile : "<stdout>");
        !          1175:           if(separator)
        !          1176:             per->separator = aprintf("%s%s", CURLseparator, per->this_url);
        !          1177:         }
        !          1178:         if(httpgetfields) {
        !          1179:           char *urlbuffer;
        !          1180:           /* Find out whether the url contains a file name */
        !          1181:           const char *pc = strstr(per->this_url, "://");
        !          1182:           char sep = '?';
        !          1183:           if(pc)
        !          1184:             pc += 3;
        !          1185:           else
        !          1186:             pc = per->this_url;
        !          1187: 
        !          1188:           pc = strrchr(pc, '/'); /* check for a slash */
        !          1189: 
        !          1190:           if(pc) {
        !          1191:             /* there is a slash present in the URL */
        !          1192: 
        !          1193:             if(strchr(pc, '?'))
        !          1194:               /* Ouch, there's already a question mark in the URL string, we
        !          1195:                  then append the data with an ampersand separator instead! */
        !          1196:               sep = '&';
        !          1197:           }
        !          1198:           /*
        !          1199:            * Then append ? followed by the get fields to the url.
        !          1200:            */
        !          1201:           if(pc)
        !          1202:             urlbuffer = aprintf("%s%c%s", per->this_url, sep, httpgetfields);
        !          1203:           else
        !          1204:             /* Append  / before the ? to create a well-formed url
        !          1205:                if the url contains a hostname only
        !          1206:             */
        !          1207:             urlbuffer = aprintf("%s/?%s", per->this_url, httpgetfields);
        !          1208: 
        !          1209:           if(!urlbuffer) {
        !          1210:             result = CURLE_OUT_OF_MEMORY;
        !          1211:             break;
        !          1212:           }
        !          1213: 
        !          1214:           Curl_safefree(per->this_url); /* free previous URL */
        !          1215:           per->this_url = urlbuffer; /* use our new URL instead! */
        !          1216:         }
        !          1217: 
        !          1218:         if(!global->errors)
        !          1219:           global->errors = stderr;
        !          1220: 
        !          1221:         if((!per->outfile || !strcmp(per->outfile, "-")) &&
        !          1222:            !config->use_ascii) {
        !          1223:           /* We get the output to stdout and we have not got the ASCII/text
        !          1224:              flag, then set stdout to be binary */
        !          1225:           set_binmode(stdout);
        !          1226:         }
        !          1227: 
        !          1228:         /* explicitly passed to stdout means okaying binary gunk */
        !          1229:         config->terminal_binary_ok =
        !          1230:           (per->outfile && !strcmp(per->outfile, "-"));
        !          1231: 
        !          1232:         /* Avoid having this setopt added to the --libcurl source output. */
        !          1233:         result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
        !          1234:         if(result)
        !          1235:           break;
        !          1236: 
        !          1237:         if(!config->tcp_nodelay)
        !          1238:           my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
        !          1239: 
        !          1240:         if(config->tcp_fastopen)
        !          1241:           my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
        !          1242: 
        !          1243:         /* where to store */
        !          1244:         my_setopt(curl, CURLOPT_WRITEDATA, per);
        !          1245:         my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
        !          1246: 
        !          1247:         if(metalink || !config->use_metalink)
        !          1248:           /* what call to write */
        !          1249:           my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
        !          1250: #ifdef USE_METALINK
        !          1251:         else
        !          1252:           /* Set Metalink specific write callback function to parse
        !          1253:              XML data progressively. */
        !          1254:           my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
        !          1255: #endif /* USE_METALINK */
        !          1256: 
        !          1257:         /* for uploads */
        !          1258:         input->config = config;
        !          1259:         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
        !          1260:          * lib/telnet.c will Curl_poll() on the input file descriptor
        !          1261:          * rather then calling the READFUNCTION at regular intervals.
        !          1262:          * The circumstances in which it is preferable to enable this
        !          1263:          * behaviour, by omitting to set the READFUNCTION & READDATA options,
        !          1264:          * have not been determined.
        !          1265:          */
        !          1266:         my_setopt(curl, CURLOPT_READDATA, input);
        !          1267:         /* what call to read */
        !          1268:         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
        !          1269: 
        !          1270:         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
        !          1271:            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
        !          1272:         my_setopt(curl, CURLOPT_SEEKDATA, input);
        !          1273:         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
        !          1274: 
        !          1275:         if(config->recvpersecond &&
        !          1276:            (config->recvpersecond < BUFFER_SIZE))
        !          1277:           /* use a smaller sized buffer for better sleeps */
        !          1278:           my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
        !          1279:         else
        !          1280:           my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE);
        !          1281: 
        !          1282:         my_setopt_str(curl, CURLOPT_URL, per->this_url);
        !          1283:         my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L);
        !          1284:         if(config->no_body)
        !          1285:           my_setopt(curl, CURLOPT_NOBODY, 1L);
        !          1286: 
        !          1287:         if(config->oauth_bearer)
        !          1288:           my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
        !          1289: 
        !          1290:         {
        !          1291:           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
        !          1292:           /* new in libcurl 7.5 */
        !          1293:           if(config->proxy)
        !          1294:             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
        !          1295: 
        !          1296:           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
        !          1297: 
        !          1298:           /* new in libcurl 7.3 */
        !          1299:           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
        !          1300: 
        !          1301:           /* new in libcurl 7.52.0 */
        !          1302:           if(config->preproxy)
        !          1303:             my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
        !          1304: 
        !          1305:           /* new in libcurl 7.10.6 */
        !          1306:           if(config->proxyanyauth)
        !          1307:             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
        !          1308:                               (long)CURLAUTH_ANY);
        !          1309:           else if(config->proxynegotiate)
        !          1310:             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
        !          1311:                               (long)CURLAUTH_GSSNEGOTIATE);
        !          1312:           else if(config->proxyntlm)
        !          1313:             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
        !          1314:                               (long)CURLAUTH_NTLM);
        !          1315:           else if(config->proxydigest)
        !          1316:             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
        !          1317:                               (long)CURLAUTH_DIGEST);
        !          1318:           else if(config->proxybasic)
        !          1319:             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
        !          1320:                               (long)CURLAUTH_BASIC);
        !          1321: 
        !          1322:           /* new in libcurl 7.19.4 */
        !          1323:           my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
        !          1324: 
        !          1325:           my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS,
        !          1326:                     config->suppress_connect_headers?1L:0L);
        !          1327:         }
        !          1328: 
        !          1329:         my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L);
        !          1330:         my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target);
        !          1331:         my_setopt(curl, CURLOPT_UPLOAD, per->uploadfile?1L:0L);
        !          1332:         my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L);
        !          1333:         my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L);
        !          1334: 
        !          1335:         if(config->netrc_opt)
        !          1336:           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
        !          1337:         else if(config->netrc || config->netrc_file)
        !          1338:           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
        !          1339:         else
        !          1340:           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED);
        !          1341: 
        !          1342:         if(config->netrc_file)
        !          1343:           my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
        !          1344: 
        !          1345:         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L);
        !          1346:         if(config->login_options)
        !          1347:           my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
        !          1348:         my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
        !          1349:         my_setopt_str(curl, CURLOPT_RANGE, config->range);
        !          1350:         my_setopt(curl, CURLOPT_ERRORBUFFER, per->errorbuffer);
        !          1351:         my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000));
        !          1352: 
        !          1353:         switch(config->httpreq) {
        !          1354:         case HTTPREQ_SIMPLEPOST:
        !          1355:           my_setopt_str(curl, CURLOPT_POSTFIELDS,
        !          1356:                         config->postfields);
        !          1357:           my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
        !          1358:                     config->postfieldsize);
        !          1359:           break;
        !          1360:         case HTTPREQ_MIMEPOST:
        !          1361:           /* free previous remainders */
        !          1362:           curl_mime_free(config->mimepost);
        !          1363:           config->mimepost = NULL;
        !          1364:           result = tool2curlmime(curl, config->mimeroot, &config->mimepost);
        !          1365:           if(result)
        !          1366:             break;
        !          1367:           my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
        !          1368:           break;
        !          1369:         default:
        !          1370:           break;
        !          1371:         }
        !          1372:         if(result)
        !          1373:           break;
        !          1374: 
        !          1375:         /* new in libcurl 7.10.6 (default is Basic) */
        !          1376:         if(config->authtype)
        !          1377:           my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);
        !          1378: 
        !          1379:         my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
        !          1380: 
        !          1381:         if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) {
        !          1382:           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
        !          1383:           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
        !          1384:         }
        !          1385: 
        !          1386:         if(built_in_protos & CURLPROTO_HTTP) {
        !          1387: 
        !          1388:           long postRedir = 0;
        !          1389: 
        !          1390:           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
        !          1391:                     config->followlocation?1L:0L);
        !          1392:           my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
        !          1393:                     config->unrestricted_auth?1L:0L);
        !          1394: 
        !          1395:           my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L);
        !          1396: 
        !          1397:           /* new in libcurl 7.36.0 */
        !          1398:           if(config->proxyheaders) {
        !          1399:             my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
        !          1400:             my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
        !          1401:           }
        !          1402: 
        !          1403:           /* new in libcurl 7.5 */
        !          1404:           my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
        !          1405: 
        !          1406:           if(config->httpversion)
        !          1407:             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
        !          1408:           else if(curlinfo->features & CURL_VERSION_HTTP2) {
        !          1409:             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
        !          1410:           }
        !          1411: 
        !          1412:           /* curl 7.19.1 (the 301 version existed in 7.18.2),
        !          1413:              303 was added in 7.26.0 */
        !          1414:           if(config->post301)
        !          1415:             postRedir |= CURL_REDIR_POST_301;
        !          1416:           if(config->post302)
        !          1417:             postRedir |= CURL_REDIR_POST_302;
        !          1418:           if(config->post303)
        !          1419:             postRedir |= CURL_REDIR_POST_303;
        !          1420:           my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
        !          1421: 
        !          1422:           /* new in libcurl 7.21.6 */
        !          1423:           if(config->encoding)
        !          1424:             my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
        !          1425: 
        !          1426:           /* new in libcurl 7.21.6 */
        !          1427:           if(config->tr_encoding)
        !          1428:             my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
        !          1429:           /* new in libcurl 7.64.0 */
        !          1430:           my_setopt(curl, CURLOPT_HTTP09_ALLOWED,
        !          1431:                     config->http09_allowed ? 1L : 0L);
        !          1432: 
        !          1433:         } /* (built_in_protos & CURLPROTO_HTTP) */
        !          1434: 
        !          1435:         my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
        !          1436:         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
        !          1437:                   config->low_speed_limit);
        !          1438:         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
        !          1439:         my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
        !          1440:                   config->sendpersecond);
        !          1441:         my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
        !          1442:                   config->recvpersecond);
        !          1443: 
        !          1444:         if(config->use_resume)
        !          1445:           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
        !          1446:         else
        !          1447:           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
        !          1448: 
        !          1449:         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
        !          1450:         my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
        !          1451: 
        !          1452:         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
        !          1453: 
        !          1454:           /* SSH and SSL private key uses same command-line option */
        !          1455:           /* new in libcurl 7.16.1 */
        !          1456:           my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
        !          1457:           /* new in libcurl 7.16.1 */
        !          1458:           my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
        !          1459: 
        !          1460:           /* new in libcurl 7.17.1: SSH host key md5 checking allows us
        !          1461:              to fail if we are not talking to who we think we should */
        !          1462:           my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
        !          1463:                         config->hostpubmd5);
        !          1464: 
        !          1465:           /* new in libcurl 7.56.0 */
        !          1466:           if(config->ssh_compression)
        !          1467:             my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
        !          1468:         }
        !          1469: 
        !          1470:         if(config->cacert)
        !          1471:           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
        !          1472:         if(config->proxy_cacert)
        !          1473:           my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
        !          1474: 
        !          1475:         if(config->capath) {
        !          1476:           result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
        !          1477:           if(result == CURLE_NOT_BUILT_IN) {
        !          1478:             warnf(config->global, "ignoring %s, not supported by libcurl\n",
        !          1479:                   capath_from_env?
        !          1480:                   "SSL_CERT_DIR environment variable":"--capath");
        !          1481:           }
        !          1482:           else if(result)
        !          1483:             break;
        !          1484:         }
        !          1485:         /* For the time being if --proxy-capath is not set then we use the
        !          1486:            --capath value for it, if any. See #1257 */
        !          1487:         if((config->proxy_capath || config->capath) &&
        !          1488:            !tool_setopt_skip(CURLOPT_PROXY_CAPATH)) {
        !          1489:           result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH,
        !          1490:                                   (config->proxy_capath ?
        !          1491:                                    config->proxy_capath :
        !          1492:                                    config->capath));
        !          1493:           if(result == CURLE_NOT_BUILT_IN) {
        !          1494:             if(config->proxy_capath) {
        !          1495:               warnf(config->global,
        !          1496:                     "ignoring --proxy-capath, not supported by libcurl\n");
        !          1497:             }
        !          1498:           }
        !          1499:           else if(result)
        !          1500:             break;
        !          1501:         }
        !          1502: 
        !          1503:         if(config->crlfile)
        !          1504:           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
        !          1505:         if(config->proxy_crlfile)
        !          1506:           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
        !          1507:         else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
        !          1508:           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
        !          1509: 
        !          1510:         if(config->pinnedpubkey)
        !          1511:           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
        !          1512: 
        !          1513:         if(curlinfo->features & CURL_VERSION_SSL) {
        !          1514:           /* Check if config->cert is a PKCS#11 URI and set the
        !          1515:            * config->cert_type if necessary */
        !          1516:           if(config->cert) {
        !          1517:             if(!config->cert_type) {
        !          1518:               if(is_pkcs11_uri(config->cert)) {
        !          1519:                 config->cert_type = strdup("ENG");
        !          1520:               }
        !          1521:             }
        !          1522:           }
        !          1523: 
        !          1524:           /* Check if config->key is a PKCS#11 URI and set the
        !          1525:            * config->key_type if necessary */
        !          1526:           if(config->key) {
        !          1527:             if(!config->key_type) {
        !          1528:               if(is_pkcs11_uri(config->key)) {
        !          1529:                 config->key_type = strdup("ENG");
        !          1530:               }
        !          1531:             }
        !          1532:           }
        !          1533: 
        !          1534:           /* Check if config->proxy_cert is a PKCS#11 URI and set the
        !          1535:            * config->proxy_type if necessary */
        !          1536:           if(config->proxy_cert) {
        !          1537:             if(!config->proxy_cert_type) {
        !          1538:               if(is_pkcs11_uri(config->proxy_cert)) {
        !          1539:                 config->proxy_cert_type = strdup("ENG");
        !          1540:               }
        !          1541:             }
        !          1542:           }
        !          1543: 
        !          1544:           /* Check if config->proxy_key is a PKCS#11 URI and set the
        !          1545:            * config->proxy_key_type if necessary */
        !          1546:           if(config->proxy_key) {
        !          1547:             if(!config->proxy_key_type) {
        !          1548:               if(is_pkcs11_uri(config->proxy_key)) {
        !          1549:                 config->proxy_key_type = strdup("ENG");
        !          1550:               }
        !          1551:             }
        !          1552:           }
        !          1553: 
        !          1554:           my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
        !          1555:           my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
        !          1556:           my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
        !          1557:           my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
        !          1558:                         config->proxy_cert_type);
        !          1559:           my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
        !          1560:           my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
        !          1561:           my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
        !          1562:           my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
        !          1563:                         config->proxy_key_type);
        !          1564: 
        !          1565:           if(config->insecure_ok) {
        !          1566:             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        !          1567:             my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        !          1568:           }
        !          1569:           else {
        !          1570:             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
        !          1571:             /* libcurl default is strict verifyhost -> 2L   */
        !          1572:             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
        !          1573:           }
        !          1574:           if(config->proxy_insecure_ok) {
        !          1575:             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
        !          1576:             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
        !          1577:           }
        !          1578:           else {
        !          1579:             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
        !          1580:           }
        !          1581: 
        !          1582:           if(config->verifystatus)
        !          1583:             my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
        !          1584: 
        !          1585:           if(config->falsestart)
        !          1586:             my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
        !          1587: 
        !          1588:           my_setopt_enum(curl, CURLOPT_SSLVERSION,
        !          1589:                          config->ssl_version | config->ssl_version_max);
        !          1590:           my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
        !          1591:                          config->proxy_ssl_version);
        !          1592:         }
        !          1593:         if(config->path_as_is)
        !          1594:           my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
        !          1595: 
        !          1596:         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
        !          1597:           if(!config->insecure_ok) {
        !          1598:             char *home;
        !          1599:             char *file;
        !          1600:             result = CURLE_FAILED_INIT;
        !          1601:             home = homedir();
        !          1602:             if(home) {
        !          1603:               file = aprintf("%s/.ssh/known_hosts", home);
        !          1604:               if(file) {
        !          1605:                 /* new in curl 7.19.6 */
        !          1606:                 result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
        !          1607:                 curl_free(file);
        !          1608:                 if(result == CURLE_UNKNOWN_OPTION)
        !          1609:                   /* libssh2 version older than 1.1.1 */
        !          1610:                   result = CURLE_OK;
        !          1611:               }
        !          1612:               Curl_safefree(home);
        !          1613:             }
        !          1614:             else {
        !          1615:               errorf(global, "Failed to figure out user's home dir!");
        !          1616:             }
        !          1617:             if(result)
        !          1618:               break;
        !          1619:           }
        !          1620:         }
        !          1621: 
        !          1622:         if(config->no_body || config->remote_time) {
        !          1623:           /* no body or use remote time */
        !          1624:           my_setopt(curl, CURLOPT_FILETIME, 1L);
        !          1625:         }
        !          1626: 
        !          1627:         my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L);
        !          1628:         my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
        !          1629:         my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
        !          1630:         my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
        !          1631: 
        !          1632:         if(config->cookie)
        !          1633:           my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
        !          1634: 
        !          1635:         if(config->cookiefile)
        !          1636:           my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
        !          1637: 
        !          1638:         /* new in libcurl 7.9 */
        !          1639:         if(config->cookiejar)
        !          1640:           my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
        !          1641: 
        !          1642:         /* new in libcurl 7.9.7 */
        !          1643:         my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L);
        !          1644: 
        !          1645:         my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
        !          1646:         my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
        !          1647:         my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
        !          1648:         customrequest_helper(config, config->httpreq, config->customrequest);
        !          1649:         my_setopt(curl, CURLOPT_STDERR, global->errors);
        !          1650: 
        !          1651:         /* three new ones in libcurl 7.3: */
        !          1652:         my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
        !          1653:         my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
        !          1654:         progressbarinit(&per->progressbar, config);
        !          1655: 
        !          1656:         if((global->progressmode == CURL_PROGRESS_BAR) &&
        !          1657:            !global->noprogress && !global->mute) {
        !          1658:           /* we want the alternative style, then we have to implement it
        !          1659:              ourselves! */
        !          1660:           my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
        !          1661:           my_setopt(curl, CURLOPT_XFERINFODATA, per);
        !          1662:         }
        !          1663:         else if(per->uploadfile && !strcmp(per->uploadfile, ".")) {
        !          1664:           /* when reading from stdin in non-blocking mode, we use the progress
        !          1665:              function to unpause a busy read */
        !          1666:           my_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        !          1667:           my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb);
        !          1668:           my_setopt(curl, CURLOPT_XFERINFODATA, per);
        !          1669:         }
        !          1670: 
        !          1671:         /* new in libcurl 7.24.0: */
        !          1672:         if(config->dns_servers)
        !          1673:           my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
        !          1674: 
        !          1675:         /* new in libcurl 7.33.0: */
        !          1676:         if(config->dns_interface)
        !          1677:           my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
        !          1678:         if(config->dns_ipv4_addr)
        !          1679:           my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
        !          1680:         if(config->dns_ipv6_addr)
        !          1681:         my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
        !          1682: 
        !          1683:         /* new in libcurl 7.6.2: */
        !          1684:         my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
        !          1685: 
        !          1686:         /* new in libcurl 7.7: */
        !          1687:         my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
        !          1688:         my_setopt_str(curl, CURLOPT_EGDSOCKET, config->egd_file);
        !          1689:         my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS,
        !          1690:                   (long)(config->connecttimeout * 1000));
        !          1691: 
        !          1692:         if(config->doh_url)
        !          1693:           my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url);
        !          1694: 
        !          1695:         if(config->cipher_list)
        !          1696:           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
        !          1697: 
        !          1698:         if(config->proxy_cipher_list)
        !          1699:           my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
        !          1700:                         config->proxy_cipher_list);
        !          1701: 
        !          1702:         if(config->cipher13_list)
        !          1703:           my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list);
        !          1704: 
        !          1705:         if(config->proxy_cipher13_list)
        !          1706:           my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
        !          1707:                         config->proxy_cipher13_list);
        !          1708: 
        !          1709:         /* new in libcurl 7.9.2: */
        !          1710:         if(config->disable_epsv)
        !          1711:           /* disable it */
        !          1712:           my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
        !          1713: 
        !          1714:         /* new in libcurl 7.10.5 */
        !          1715:         if(config->disable_eprt)
        !          1716:           /* disable it */
        !          1717:           my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L);
        !          1718: 
        !          1719:         if(global->tracetype != TRACE_NONE) {
        !          1720:           my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
        !          1721:           my_setopt(curl, CURLOPT_DEBUGDATA, config);
        !          1722:           my_setopt(curl, CURLOPT_VERBOSE, 1L);
        !          1723:         }
        !          1724: 
        !          1725:         /* new in curl 7.9.3 */
        !          1726:         if(config->engine) {
        !          1727:           result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
        !          1728:           if(result)
        !          1729:             break;
        !          1730:         }
        !          1731: 
        !          1732:         /* new in curl 7.10.7, extended in 7.19.4. Modified to use
        !          1733:            CREATE_DIR_RETRY in 7.49.0 */
        !          1734:         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
        !          1735:                   (long)(config->ftp_create_dirs?
        !          1736:                          CURLFTP_CREATE_DIR_RETRY:
        !          1737:                          CURLFTP_CREATE_DIR_NONE));
        !          1738: 
        !          1739:         /* new in curl 7.10.8 */
        !          1740:         if(config->max_filesize)
        !          1741:           my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
        !          1742:                     config->max_filesize);
        !          1743: 
        !          1744:         if(4 == config->ip_version)
        !          1745:           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        !          1746:         else if(6 == config->ip_version)
        !          1747:           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
        !          1748:         else
        !          1749:           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
        !          1750: 
        !          1751:         /* new in curl 7.15.5 */
        !          1752:         if(config->ftp_ssl_reqd)
        !          1753:           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
        !          1754: 
        !          1755:         /* new in curl 7.11.0 */
        !          1756:         else if(config->ftp_ssl)
        !          1757:           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
        !          1758: 
        !          1759:         /* new in curl 7.16.0 */
        !          1760:         else if(config->ftp_ssl_control)
        !          1761:           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL);
        !          1762: 
        !          1763:         /* new in curl 7.16.1 */
        !          1764:         if(config->ftp_ssl_ccc)
        !          1765:           my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC,
        !          1766:                          (long)config->ftp_ssl_ccc_mode);
        !          1767: 
        !          1768:         /* new in curl 7.19.4 */
        !          1769:         if(config->socks5_gssapi_nec)
        !          1770:           my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
        !          1771:                         config->socks5_gssapi_nec);
        !          1772: 
        !          1773:         /* new in curl 7.55.0 */
        !          1774:         if(config->socks5_auth)
        !          1775:           my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH,
        !          1776:                             (long)config->socks5_auth);
        !          1777: 
        !          1778:         /* new in curl 7.43.0 */
        !          1779:         if(config->proxy_service_name)
        !          1780:           my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
        !          1781:                         config->proxy_service_name);
        !          1782: 
        !          1783:         /* new in curl 7.43.0 */
        !          1784:         if(config->service_name)
        !          1785:           my_setopt_str(curl, CURLOPT_SERVICE_NAME,
        !          1786:                         config->service_name);
        !          1787: 
        !          1788:         /* curl 7.13.0 */
        !          1789:         my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
        !          1790:         my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L);
        !          1791: 
        !          1792:         /* curl 7.14.2 */
        !          1793:         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
        !          1794: 
        !          1795:         /* curl 7.15.1 */
        !          1796:         my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod);
        !          1797: 
        !          1798:         /* curl 7.15.2 */
        !          1799:         if(config->localport) {
        !          1800:           my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
        !          1801:           my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, config->localportrange);
        !          1802:         }
        !          1803: 
        !          1804:         /* curl 7.15.5 */
        !          1805:         my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
        !          1806:                       config->ftp_alternative_to_user);
        !          1807: 
        !          1808:         /* curl 7.16.0 */
        !          1809:         if(config->disable_sessionid)
        !          1810:           /* disable it */
        !          1811:           my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
        !          1812: 
        !          1813:         /* curl 7.16.2 */
        !          1814:         if(config->raw) {
        !          1815:           my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
        !          1816:           my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
        !          1817:         }
        !          1818: 
        !          1819:         /* curl 7.17.1 */
        !          1820:         if(!config->nokeepalive) {
        !          1821:           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
        !          1822:           if(config->alivetime != 0) {
        !          1823:             my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
        !          1824:             my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
        !          1825:           }
        !          1826:         }
        !          1827:         else
        !          1828:           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
        !          1829: 
        !          1830:         /* curl 7.20.0 */
        !          1831:         if(config->tftp_blksize)
        !          1832:           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
        !          1833: 
        !          1834:         if(config->mail_from)
        !          1835:           my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
        !          1836: 
        !          1837:         if(config->mail_rcpt)
        !          1838:           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
        !          1839: 
        !          1840:         /* curl 7.69.x */
        !          1841:         my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS,
        !          1842:           config->mail_rcpt_allowfails ? 1L : 0L);
        !          1843: 
        !          1844:         /* curl 7.20.x */
        !          1845:         if(config->ftp_pret)
        !          1846:           my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
        !          1847: 
        !          1848:         if(config->proto_present)
        !          1849:           my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
        !          1850:         if(config->proto_redir_present)
        !          1851:           my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
        !          1852: 
        !          1853:         if(config->content_disposition
        !          1854:            && (urlnode->flags & GETOUT_USEREMOTE))
        !          1855:           hdrcbdata->honor_cd_filename = TRUE;
        !          1856:         else
        !          1857:           hdrcbdata->honor_cd_filename = FALSE;
        !          1858: 
        !          1859:         hdrcbdata->outs = outs;
        !          1860:         hdrcbdata->heads = heads;
        !          1861:         hdrcbdata->etag_save = etag_save;
        !          1862:         hdrcbdata->global = global;
        !          1863:         hdrcbdata->config = config;
        !          1864: 
        !          1865:         my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
        !          1866:         my_setopt(curl, CURLOPT_HEADERDATA, per);
        !          1867: 
        !          1868:         if(config->resolve)
        !          1869:           /* new in 7.21.3 */
        !          1870:           my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
        !          1871: 
        !          1872:         if(config->connect_to)
        !          1873:           /* new in 7.49.0 */
        !          1874:           my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
        !          1875: 
        !          1876:         /* new in 7.21.4 */
        !          1877:         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
        !          1878:           if(config->tls_username)
        !          1879:             my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
        !          1880:                           config->tls_username);
        !          1881:           if(config->tls_password)
        !          1882:             my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
        !          1883:                           config->tls_password);
        !          1884:           if(config->tls_authtype)
        !          1885:             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
        !          1886:                           config->tls_authtype);
        !          1887:           if(config->proxy_tls_username)
        !          1888:             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
        !          1889:                           config->proxy_tls_username);
        !          1890:           if(config->proxy_tls_password)
        !          1891:             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
        !          1892:                           config->proxy_tls_password);
        !          1893:           if(config->proxy_tls_authtype)
        !          1894:             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
        !          1895:                           config->proxy_tls_authtype);
        !          1896:         }
        !          1897: 
        !          1898:         /* new in 7.22.0 */
        !          1899:         if(config->gssapi_delegation)
        !          1900:           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
        !          1901:                         config->gssapi_delegation);
        !          1902: 
        !          1903:         /* new in 7.25.0, 7.44.0 and 7.70.0 */
        !          1904:         {
        !          1905:           long mask = (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
        !          1906:                       (config->ssl_revoke_best_effort ?
        !          1907:                        CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
        !          1908:                       (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0);
        !          1909:           if(mask)
        !          1910:             my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
        !          1911:         }
        !          1912: 
        !          1913:         if(config->proxy_ssl_allow_beast)
        !          1914:           my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
        !          1915:                     (long)CURLSSLOPT_ALLOW_BEAST);
        !          1916: 
        !          1917:         if(config->mail_auth)
        !          1918:           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
        !          1919: 
        !          1920:         /* new in 7.66.0 */
        !          1921:         if(config->sasl_authzid)
        !          1922:           my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid);
        !          1923: 
        !          1924:         /* new in 7.31.0 */
        !          1925:         if(config->sasl_ir)
        !          1926:           my_setopt(curl, CURLOPT_SASL_IR, 1L);
        !          1927: 
        !          1928:         if(config->nonpn) {
        !          1929:           my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L);
        !          1930:         }
        !          1931: 
        !          1932:         if(config->noalpn) {
        !          1933:           my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
        !          1934:         }
        !          1935: 
        !          1936:         /* new in 7.40.0, abstract support added in 7.53.0 */
        !          1937:         if(config->unix_socket_path) {
        !          1938:           if(config->abstract_unix_socket) {
        !          1939:             my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
        !          1940:                           config->unix_socket_path);
        !          1941:           }
        !          1942:           else {
        !          1943:             my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
        !          1944:                           config->unix_socket_path);
        !          1945:           }
        !          1946:         }
        !          1947: 
        !          1948:         /* new in 7.45.0 */
        !          1949:         if(config->proto_default)
        !          1950:           my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
        !          1951: 
        !          1952:         /* new in 7.47.0 */
        !          1953:         if(config->expect100timeout > 0)
        !          1954:           my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
        !          1955:                         (long)(config->expect100timeout*1000));
        !          1956: 
        !          1957:         /* new in 7.48.0 */
        !          1958:         if(config->tftp_no_options)
        !          1959:           my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
        !          1960: 
        !          1961:         /* new in 7.59.0 */
        !          1962:         if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT)
        !          1963:           my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
        !          1964:                     config->happy_eyeballs_timeout_ms);
        !          1965: 
        !          1966:         /* new in 7.60.0 */
        !          1967:         if(config->haproxy_protocol)
        !          1968:           my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
        !          1969: 
        !          1970:         if(config->disallow_username_in_url)
        !          1971:           my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L);
        !          1972: 
        !          1973:         if(config->altsvc)
        !          1974:           my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc);
        !          1975: 
        !          1976: #ifdef USE_METALINK
        !          1977:         if(!metalink && config->use_metalink) {
        !          1978:           outs->metalink_parser = metalink_parser_context_new();
        !          1979:           if(outs->metalink_parser == NULL) {
        !          1980:             result = CURLE_OUT_OF_MEMORY;
        !          1981:             break;
        !          1982:           }
        !          1983:           fprintf(config->global->errors,
        !          1984:                   "Metalink: parsing (%s) metalink/XML...\n", per->this_url);
        !          1985:         }
        !          1986:         else if(metalink)
        !          1987:           fprintf(config->global->errors,
        !          1988:                   "Metalink: fetching (%s) from (%s)...\n",
        !          1989:                   mlfile->filename, per->this_url);
        !          1990: #endif /* USE_METALINK */
        !          1991: 
        !          1992:         per->metalink = metalink;
        !          1993:         /* initialize retry vars for loop below */
        !          1994:         per->retry_sleep_default = (config->retry_delay) ?
        !          1995:           config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
        !          1996:         per->retry_numretries = config->req_retry;
        !          1997:         per->retry_sleep = per->retry_sleep_default; /* ms */
        !          1998:         per->retrystart = tvnow();
        !          1999: 
        !          2000:         state->li++;
        !          2001:         /* Here's looping around each globbed URL */
        !          2002:         if(state->li >= urlnum) {
        !          2003:           state->li = 0;
        !          2004:           state->urlnum = 0; /* forced reglob of URLs */
        !          2005:           glob_cleanup(state->urls);
        !          2006:           state->urls = NULL;
        !          2007:           state->up++;
        !          2008:           Curl_safefree(state->uploadfile); /* clear it to get the next */
        !          2009:         }
        !          2010:       }
        !          2011:       else {
        !          2012:         /* Free this URL node data without destroying the
        !          2013:            the node itself nor modifying next pointer. */
        !          2014:         Curl_safefree(urlnode->outfile);
        !          2015:         Curl_safefree(urlnode->infile);
        !          2016:         urlnode->flags = 0;
        !          2017:         glob_cleanup(state->urls);
        !          2018:         state->urls = NULL;
        !          2019:         state->urlnum = 0;
        !          2020: 
        !          2021:         Curl_safefree(state->outfiles);
        !          2022:         Curl_safefree(state->uploadfile);
        !          2023:         if(state->inglob) {
        !          2024:           /* Free list of globbed upload files */
        !          2025:           glob_cleanup(state->inglob);
        !          2026:           state->inglob = NULL;
        !          2027:         }
        !          2028:         config->state.urlnode = urlnode->next;
        !          2029:         state->up = 0;
        !          2030:         continue;
        !          2031:       }
        !          2032:     }
        !          2033:     break;
        !          2034:   }
        !          2035: 
        !          2036:   if(!*added || result) {
        !          2037:     *added = FALSE;
        !          2038:     single_transfer_cleanup(config);
        !          2039:   }
        !          2040:   return result;
        !          2041: }
        !          2042: 
        !          2043: static long all_added; /* number of easy handles currently added */
        !          2044: 
        !          2045: /*
        !          2046:  * add_parallel_transfers() sets 'morep' to TRUE if there are more transfers
        !          2047:  * to add even after this call returns. sets 'addedp' to TRUE if one or more
        !          2048:  * transfers were added.
        !          2049:  */
        !          2050: static CURLcode add_parallel_transfers(struct GlobalConfig *global,
        !          2051:                                        CURLM *multi,
        !          2052:                                        CURLSH *share,
        !          2053:                                        bool *morep,
        !          2054:                                        bool *addedp)
        !          2055: {
        !          2056:   struct per_transfer *per;
        !          2057:   CURLcode result = CURLE_OK;
        !          2058:   CURLMcode mcode;
        !          2059:   *addedp = FALSE;
        !          2060:   *morep = FALSE;
        !          2061:   result = create_transfer(global, share, addedp);
        !          2062:   if(result)
        !          2063:     return result;
        !          2064:   for(per = transfers; per && (all_added < global->parallel_max);
        !          2065:       per = per->next) {
        !          2066:     bool getadded = FALSE;
        !          2067:     if(per->added)
        !          2068:       /* already added */
        !          2069:       continue;
        !          2070: 
        !          2071:     result = pre_transfer(global, per);
        !          2072:     if(result)
        !          2073:       break;
        !          2074: 
        !          2075:     /* parallel connect means that we don't set PIPEWAIT since pipewait
        !          2076:        will make libcurl prefer multiplexing */
        !          2077:     (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
        !          2078:                            global->parallel_connect ? 0L : 1L);
        !          2079:     (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
        !          2080:     (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
        !          2081:     (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
        !          2082: 
        !          2083:     mcode = curl_multi_add_handle(multi, per->curl);
        !          2084:     if(mcode)
        !          2085:       return CURLE_OUT_OF_MEMORY;
        !          2086: 
        !          2087:     result = create_transfer(global, share, &getadded);
        !          2088:     if(result)
        !          2089:       return result;
        !          2090:     per->added = TRUE;
        !          2091:     all_added++;
        !          2092:     *addedp = TRUE;
        !          2093:   }
        !          2094:   *morep = per ? TRUE : FALSE;
        !          2095:   return CURLE_OK;
        !          2096: }
        !          2097: 
        !          2098: static CURLcode parallel_transfers(struct GlobalConfig *global,
        !          2099:                                    CURLSH *share)
        !          2100: {
        !          2101:   CURLM *multi;
        !          2102:   CURLMcode mcode = CURLM_OK;
        !          2103:   CURLcode result = CURLE_OK;
        !          2104:   int still_running = 1;
        !          2105:   struct timeval start = tvnow();
        !          2106:   bool more_transfers;
        !          2107:   bool added_transfers;
        !          2108: 
        !          2109:   multi = curl_multi_init();
        !          2110:   if(!multi)
        !          2111:     return CURLE_OUT_OF_MEMORY;
        !          2112: 
        !          2113:   result = add_parallel_transfers(global, multi, share,
        !          2114:                                   &more_transfers, &added_transfers);
        !          2115:   if(result) {
        !          2116:     curl_multi_cleanup(multi);
        !          2117:     return result;
        !          2118:   }
        !          2119: 
        !          2120:   while(!mcode && (still_running || more_transfers)) {
        !          2121:     mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
        !          2122:     if(!mcode)
        !          2123:       mcode = curl_multi_perform(multi, &still_running);
        !          2124: 
        !          2125:     progress_meter(global, &start, FALSE);
        !          2126: 
        !          2127:     if(!mcode) {
        !          2128:       int rc;
        !          2129:       CURLMsg *msg;
        !          2130:       bool removed = FALSE;
        !          2131:       do {
        !          2132:         msg = curl_multi_info_read(multi, &rc);
        !          2133:         if(msg) {
        !          2134:           bool retry;
        !          2135:           struct per_transfer *ended;
        !          2136:           CURL *easy = msg->easy_handle;
        !          2137:           result = msg->data.result;
        !          2138:           curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended);
        !          2139:           curl_multi_remove_handle(multi, easy);
        !          2140: 
        !          2141:           result = post_per_transfer(global, ended, result, &retry);
        !          2142:           if(retry)
        !          2143:             continue;
        !          2144:           progress_finalize(ended); /* before it goes away */
        !          2145:           all_added--; /* one fewer added */
        !          2146:           removed = TRUE;
        !          2147:           (void)del_per_transfer(ended);
        !          2148:         }
        !          2149:       } while(msg);
        !          2150:       if(removed) {
        !          2151:         /* one or more transfers completed, add more! */
        !          2152:         (void)add_parallel_transfers(global, multi, share,
        !          2153:                                      &more_transfers,
        !          2154:                                      &added_transfers);
        !          2155:         if(added_transfers)
        !          2156:           /* we added new ones, make sure the loop doesn't exit yet */
        !          2157:           still_running = 1;
        !          2158:       }
        !          2159:     }
        !          2160:   }
        !          2161: 
        !          2162:   (void)progress_meter(global, &start, TRUE);
        !          2163: 
        !          2164:   /* Make sure to return some kind of error if there was a multi problem */
        !          2165:   if(mcode) {
        !          2166:     result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
        !          2167:       /* The other multi errors should never happen, so return
        !          2168:          something suitably generic */
        !          2169:       CURLE_BAD_FUNCTION_ARGUMENT;
        !          2170:   }
        !          2171: 
        !          2172:   curl_multi_cleanup(multi);
        !          2173: 
        !          2174:   return result;
        !          2175: }
        !          2176: 
        !          2177: static CURLcode serial_transfers(struct GlobalConfig *global,
        !          2178:                                  CURLSH *share)
        !          2179: {
        !          2180:   CURLcode returncode = CURLE_OK;
        !          2181:   CURLcode result = CURLE_OK;
        !          2182:   struct per_transfer *per;
        !          2183:   bool added = FALSE;
        !          2184: 
        !          2185:   result = create_transfer(global, share, &added);
        !          2186:   if(result || !added)
        !          2187:     return result;
        !          2188:   for(per = transfers; per;) {
        !          2189:     bool retry;
        !          2190:     bool bailout = FALSE;
        !          2191:     result = pre_transfer(global, per);
        !          2192:     if(result)
        !          2193:       break;
        !          2194: 
        !          2195: #ifndef CURL_DISABLE_LIBCURL_OPTION
        !          2196:     if(global->libcurl) {
        !          2197:       result = easysrc_perform();
        !          2198:       if(result)
        !          2199:         break;
        !          2200:     }
        !          2201: #endif
        !          2202: #ifdef CURLDEBUG
        !          2203:     if(global->test_event_based)
        !          2204:       result = curl_easy_perform_ev(per->curl);
        !          2205:     else
        !          2206: #endif
        !          2207:       result = curl_easy_perform(per->curl);
        !          2208: 
        !          2209:     /* store the result of the actual transfer */
        !          2210:     returncode = result;
        !          2211: 
        !          2212:     result = post_per_transfer(global, per, result, &retry);
        !          2213:     if(retry)
        !          2214:       continue;
        !          2215: 
        !          2216:     /* Bail out upon critical errors or --fail-early */
        !          2217:     if(result || is_fatal_error(returncode) ||
        !          2218:        (returncode && global->fail_early))
        !          2219:       bailout = TRUE;
        !          2220:     else {
        !          2221:       /* setup the next one just before we delete this */
        !          2222:       result = create_transfer(global, share, &added);
        !          2223:       if(result)
        !          2224:         bailout = TRUE;
        !          2225:     }
        !          2226: 
        !          2227:     /* Release metalink related resources here */
        !          2228:     delete_metalinkfile(per->mlfile);
        !          2229: 
        !          2230:     per = del_per_transfer(per);
        !          2231: 
        !          2232:     if(bailout)
        !          2233:       break;
        !          2234:   }
        !          2235:   if(returncode)
        !          2236:     /* returncode errors have priority */
        !          2237:     result = returncode;
        !          2238: 
        !          2239:   if(result)
        !          2240:     single_transfer_cleanup(global->current);
        !          2241: 
        !          2242:   return result;
        !          2243: }
        !          2244: 
        !          2245: /* setup a transfer for the given config */
        !          2246: static CURLcode transfer_per_config(struct GlobalConfig *global,
        !          2247:                                     struct OperationConfig *config,
        !          2248:                                     CURLSH *share,
        !          2249:                                     bool *added)
        !          2250: {
        !          2251:   CURLcode result = CURLE_OK;
        !          2252:   bool capath_from_env;
        !          2253:   *added = FALSE;
        !          2254: 
        !          2255:   /* Check we have a url */
        !          2256:   if(!config->url_list || !config->url_list->url) {
        !          2257:     helpf(global->errors, "no URL specified!\n");
        !          2258:     return CURLE_FAILED_INIT;
        !          2259:   }
        !          2260: 
        !          2261:   /* On WIN32 we can't set the path to curl-ca-bundle.crt
        !          2262:    * at compile time. So we look here for the file in two ways:
        !          2263:    * 1: look at the environment variable CURL_CA_BUNDLE for a path
        !          2264:    * 2: if #1 isn't found, use the windows API function SearchPath()
        !          2265:    *    to find it along the app's path (includes app's dir and CWD)
        !          2266:    *
        !          2267:    * We support the environment variable thing for non-Windows platforms
        !          2268:    * too. Just for the sake of it.
        !          2269:    */
        !          2270:   capath_from_env = false;
        !          2271:   if(!config->cacert &&
        !          2272:      !config->capath &&
        !          2273:      !config->insecure_ok) {
        !          2274:     CURL *curltls = curl_easy_init();
        !          2275:     struct curl_tlssessioninfo *tls_backend_info = NULL;
        !          2276: 
        !          2277:     /* With the addition of CAINFO support for Schannel, this search could find
        !          2278:      * a certificate bundle that was previously ignored. To maintain backward
        !          2279:      * compatibility, only perform this search if not using Schannel.
        !          2280:      */
        !          2281:     result = curl_easy_getinfo(curltls, CURLINFO_TLS_SSL_PTR,
        !          2282:                                &tls_backend_info);
        !          2283:     if(result)
        !          2284:       return result;
        !          2285: 
        !          2286:     /* Set the CA cert locations specified in the environment. For Windows if
        !          2287:      * no environment-specified filename is found then check for CA bundle
        !          2288:      * default filename curl-ca-bundle.crt in the user's PATH.
        !          2289:      *
        !          2290:      * If Schannel is the selected SSL backend then these locations are
        !          2291:      * ignored. We allow setting CA location for schannel only when explicitly
        !          2292:      * specified by the user via CURLOPT_CAINFO / --cacert.
        !          2293:      */
        !          2294:     if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {
        !          2295:       char *env;
        !          2296:       env = curlx_getenv("CURL_CA_BUNDLE");
        !          2297:       if(env) {
        !          2298:         config->cacert = strdup(env);
        !          2299:         if(!config->cacert) {
        !          2300:           curl_free(env);
        !          2301:           errorf(global, "out of memory\n");
        !          2302:           return CURLE_OUT_OF_MEMORY;
        !          2303:         }
        !          2304:       }
        !          2305:       else {
        !          2306:         env = curlx_getenv("SSL_CERT_DIR");
        !          2307:         if(env) {
        !          2308:           config->capath = strdup(env);
        !          2309:           if(!config->capath) {
        !          2310:             curl_free(env);
        !          2311:             helpf(global->errors, "out of memory\n");
        !          2312:             return CURLE_OUT_OF_MEMORY;
        !          2313:           }
        !          2314:           capath_from_env = true;
        !          2315:         }
        !          2316:         else {
        !          2317:           env = curlx_getenv("SSL_CERT_FILE");
        !          2318:           if(env) {
        !          2319:             config->cacert = strdup(env);
        !          2320:             if(!config->cacert) {
        !          2321:               curl_free(env);
        !          2322:               errorf(global, "out of memory\n");
        !          2323:               return CURLE_OUT_OF_MEMORY;
        !          2324:             }
        !          2325:           }
        !          2326:         }
        !          2327:       }
        !          2328: 
        !          2329:       if(env)
        !          2330:         curl_free(env);
        !          2331: #ifdef WIN32
        !          2332:       else {
        !          2333:         result = FindWin32CACert(config, tls_backend_info->backend,
        !          2334:                                  "curl-ca-bundle.crt");
        !          2335:       }
        !          2336: #endif
        !          2337:     }
        !          2338:     curl_easy_cleanup(curltls);
        !          2339:   }
        !          2340: 
        !          2341:   if(!result)
        !          2342:     result = single_transfer(global, config, share, capath_from_env, added);
        !          2343: 
        !          2344:   return result;
        !          2345: }
        !          2346: 
        !          2347: /*
        !          2348:  * 'create_transfer' gets the details and sets up a new transfer if 'added'
        !          2349:  * returns TRUE.
        !          2350:  */
        !          2351: static CURLcode create_transfer(struct GlobalConfig *global,
        !          2352:                                 CURLSH *share,
        !          2353:                                 bool *added)
        !          2354: {
        !          2355:   CURLcode result = CURLE_OK;
        !          2356:   *added = FALSE;
        !          2357:   while(global->current) {
        !          2358:     result = transfer_per_config(global, global->current, share, added);
        !          2359:     if(!result && !*added) {
        !          2360:       /* when one set is drained, continue to next */
        !          2361:       global->current = global->current->next;
        !          2362:       continue;
        !          2363:     }
        !          2364:     break;
        !          2365:   }
        !          2366:   return result;
        !          2367: }
        !          2368: 
        !          2369: static CURLcode run_all_transfers(struct GlobalConfig *global,
        !          2370:                                   CURLSH *share,
        !          2371:                                   CURLcode result)
        !          2372: {
        !          2373:   /* Save the values of noprogress and isatty to restore them later on */
        !          2374:   bool orig_noprogress = global->noprogress;
        !          2375:   bool orig_isatty = global->isatty;
        !          2376:   struct per_transfer *per;
        !          2377: 
        !          2378:   /* Time to actually do the transfers */
        !          2379:   if(!result) {
        !          2380:     if(global->parallel)
        !          2381:       result = parallel_transfers(global, share);
        !          2382:     else
        !          2383:       result = serial_transfers(global, share);
        !          2384:   }
        !          2385: 
        !          2386:   /* cleanup if there are any left */
        !          2387:   for(per = transfers; per;) {
        !          2388:     bool retry;
        !          2389:     CURLcode result2 = post_per_transfer(global, per, result, &retry);
        !          2390:     if(!result)
        !          2391:       /* don't overwrite the original error */
        !          2392:       result = result2;
        !          2393: 
        !          2394:     /* Free list of given URLs */
        !          2395:     clean_getout(per->config);
        !          2396: 
        !          2397:     /* Release metalink related resources here */
        !          2398:     clean_metalink(per->config);
        !          2399:     per = del_per_transfer(per);
        !          2400:   }
        !          2401: 
        !          2402:   /* Reset the global config variables */
        !          2403:   global->noprogress = orig_noprogress;
        !          2404:   global->isatty = orig_isatty;
        !          2405: 
        !          2406: 
        !          2407:   return result;
        !          2408: }
        !          2409: 
        !          2410: CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
        !          2411: {
        !          2412:   CURLcode result = CURLE_OK;
        !          2413: 
        !          2414:   /* Setup proper locale from environment */
        !          2415: #ifdef HAVE_SETLOCALE
        !          2416:   setlocale(LC_ALL, "");
        !          2417: #endif
        !          2418: 
        !          2419:   /* Parse .curlrc if necessary */
        !          2420:   if((argc == 1) ||
        !          2421:      (!curl_strequal(argv[1], "-q") &&
        !          2422:       !curl_strequal(argv[1], "--disable"))) {
        !          2423:     parseconfig(NULL, global); /* ignore possible failure */
        !          2424: 
        !          2425:     /* If we had no arguments then make sure a url was specified in .curlrc */
        !          2426:     if((argc < 2) && (!global->first->url_list)) {
        !          2427:       helpf(global->errors, NULL);
        !          2428:       result = CURLE_FAILED_INIT;
        !          2429:     }
        !          2430:   }
        !          2431: 
        !          2432:   if(!result) {
        !          2433:     /* Parse the command line arguments */
        !          2434:     ParameterError res = parse_args(global, argc, argv);
        !          2435:     if(res) {
        !          2436:       result = CURLE_OK;
        !          2437: 
        !          2438:       /* Check if we were asked for the help */
        !          2439:       if(res == PARAM_HELP_REQUESTED)
        !          2440:         tool_help();
        !          2441:       /* Check if we were asked for the manual */
        !          2442:       else if(res == PARAM_MANUAL_REQUESTED)
        !          2443:         hugehelp();
        !          2444:       /* Check if we were asked for the version information */
        !          2445:       else if(res == PARAM_VERSION_INFO_REQUESTED)
        !          2446:         tool_version_info();
        !          2447:       /* Check if we were asked to list the SSL engines */
        !          2448:       else if(res == PARAM_ENGINES_REQUESTED)
        !          2449:         tool_list_engines();
        !          2450:       else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
        !          2451:         result = CURLE_UNSUPPORTED_PROTOCOL;
        !          2452:       else
        !          2453:         result = CURLE_FAILED_INIT;
        !          2454:     }
        !          2455:     else {
        !          2456: #ifndef CURL_DISABLE_LIBCURL_OPTION
        !          2457:       if(global->libcurl) {
        !          2458:         /* Initialise the libcurl source output */
        !          2459:         result = easysrc_init();
        !          2460:       }
        !          2461: #endif
        !          2462: 
        !          2463:       /* Perform the main operations */
        !          2464:       if(!result) {
        !          2465:         size_t count = 0;
        !          2466:         struct OperationConfig *operation = global->first;
        !          2467:         CURLSH *share = curl_share_init();
        !          2468:         if(!share) {
        !          2469: #ifndef CURL_DISABLE_LIBCURL_OPTION
        !          2470:           if(global->libcurl) {
        !          2471:             /* Cleanup the libcurl source output */
        !          2472:             easysrc_cleanup();
        !          2473:           }
        !          2474: #endif
        !          2475:           return CURLE_OUT_OF_MEMORY;
        !          2476:         }
        !          2477: 
        !          2478:         curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
        !          2479:         curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
        !          2480:         curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
        !          2481:         curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
        !          2482:         curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
        !          2483: 
        !          2484:         /* Get the required arguments for each operation */
        !          2485:         do {
        !          2486:           result = get_args(operation, count++);
        !          2487: 
        !          2488:           operation = operation->next;
        !          2489:         } while(!result && operation);
        !          2490: 
        !          2491:         /* Set the current operation pointer */
        !          2492:         global->current = global->first;
        !          2493: 
        !          2494:         /* now run! */
        !          2495:         result = run_all_transfers(global, share, result);
        !          2496: 
        !          2497:         curl_share_cleanup(share);
        !          2498: #ifndef CURL_DISABLE_LIBCURL_OPTION
        !          2499:         if(global->libcurl) {
        !          2500:           /* Cleanup the libcurl source output */
        !          2501:           easysrc_cleanup();
        !          2502: 
        !          2503:           /* Dump the libcurl code if previously enabled */
        !          2504:           dumpeasysrc(global);
        !          2505:         }
        !          2506: #endif
        !          2507:       }
        !          2508:       else
        !          2509:         errorf(global, "out of memory\n");
        !          2510:     }
        !          2511:   }
        !          2512: 
        !          2513:   return result;
        !          2514: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>