Commit fa775b56 authored by Yang Tse's avatar Yang Tse
Browse files

curl tool: fix some OOM handling issues

parent fb3845a4
Loading
Loading
Loading
Loading
+126 −111
Original line number Diff line number Diff line
@@ -4042,11 +4042,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
      /* Here's looping around each globbed URL */
      for(i = 0 ;; i++) {

        int infd = STDIN_FILENO;
        int infd;
        bool infdopen;
        char *outfile;
        struct timeval retrystart;

        outfile = NULL;
        infdopen = FALSE;
        infd = STDIN_FILENO;

        if(urls)
          url = glob_next_url(urls);
        else if(!i)
@@ -4056,7 +4060,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
        if(!url)
          break;

        outfile = outfiles?strdup(outfiles):NULL;
        if(outfiles) {
          outfile = strdup(outfiles);
          if(!outfile) {
            res = CURLE_OUT_OF_MEMORY;
            goto show_error;
          }
        }

        if((urlnode->flags&GETOUT_USEREMOTE) ||
           (outfile && !curlx_strequal("-", outfile)) ) {
@@ -4071,19 +4081,16 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
            outfile = get_url_file_name(url);
            if((!outfile || !*outfile) && !config->content_disposition) {
              helpf(config->errors, "Remote file name has no length!\n");
              Curl_safefree(url);
              res = CURLE_WRITE_ERROR;
              break;
              goto quit_urls;
            }
#if defined(MSDOS) || defined(WIN32)
            /* For DOS and WIN32, we do some major replacing of
               bad characters in the file name before using it */
            outfile = sanitize_dos_name(outfile);
            if(!outfile) {
              warnf(config, "out of memory\n");
              Curl_safefree(url);
              res = CURLE_OUT_OF_MEMORY;
              break;
              goto show_error;
            }
#endif /* MSDOS || WIN32 */
          }
@@ -4095,9 +4102,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
            if(!outfile) {
              /* bad globbing */
              warnf(config, "bad output glob!\n");
              Curl_safefree(url);
              res = CURLE_FAILED_INIT;
              break;
              goto quit_urls;
            }
          }

@@ -4107,11 +4113,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          if(config->create_dirs) {
            res = create_dir_hierarchy(outfile, config->errors);
            /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
            if(res == CURLE_OUT_OF_MEMORY)
              warnf(config, "out of memory\n");
            if(res == CURLE_WRITE_ERROR)
              goto quit_urls;
            if(res) {
              Curl_safefree(url);
              break;
              goto show_error;
            }
          }

@@ -4136,12 +4141,11 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          if(config->resume_from) {
            outs.init = config->resume_from;
            /* open file for output: */
            outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
            outs.stream = fopen(outfile, config->resume_from?"ab":"wb");
            if(!outs.stream) {
              helpf(config->errors, "Can't open '%s'!\n", outfile);
              Curl_safefree(url);
              res = CURLE_WRITE_ERROR;
              break;
              goto quit_urls;
            }
          }
          else {
@@ -4149,7 +4153,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
            outs.bytes = 0;     /* reset byte counter */
          }
        }
        infdopen=FALSE;

        if(uploadfile && !stdin_upload(uploadfile)) {
          /*
           * We have specified a file to upload and it isn't "-".
@@ -4158,9 +4162,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])

          url = add_file_name_to_url(curl, url, uploadfile);
          if(!url) {
            helpf(config->errors, "out of memory\n");
            res = CURLE_OUT_OF_MEMORY;
            break;
            goto show_error;
          }
          /* VMS Note:
           *
@@ -4180,21 +4183,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          infd = open(uploadfile, O_RDONLY | O_BINARY);
          if((infd == -1) || fstat(infd, &fileinfo)) {
            helpf(config->errors, "Can't open '%s'!\n", uploadfile);
            if(infd != -1)
            if(infd != -1) {
              close(infd);

            /* Free the list of remaining URLs and globbed upload files
             * to force curl to exit immediately
             */
            if(urls) {
              glob_cleanup(urls);
              urls = NULL;
            }
            if(inglob) {
              glob_cleanup(inglob);
              inglob = NULL;
              infd = STDIN_FILENO;
            }

            res = CURLE_READ_ERROR;
            goto quit_urls;
          }
@@ -4231,8 +4223,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
                  " file or a fixed auth type instead!\n");
          }

          DEBUGASSERT(infdopen == FALSE);
          DEBUGASSERT(infd == STDIN_FILENO);

          SET_BINMODE(stdin);
          infd = STDIN_FILENO;
          if(curlx_strequal(uploadfile, ".")) {
            if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
              warnf(config,
@@ -4280,22 +4274,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
           */
          urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
          if(!urlbuffer) {
            helpf(config->errors, "out of memory\n");

            /* Free the list of remaining URLs and globbed upload files
             * to force curl to exit immediately
             */
            if(urls) {
              glob_cleanup(urls);
              urls = NULL;
            }
            if(inglob) {
              glob_cleanup(inglob);
              inglob = NULL;
            }

            res = CURLE_OUT_OF_MEMORY;
            goto quit_urls;
            goto show_error;
          }
          if(pc)
            sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
@@ -4534,19 +4514,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
              }
              free(home);
            }
            if(res) {
              /* Free the list of remaining URLs and globbed upload files
               * to force curl to exit immediately */
              if(urls) {
                glob_cleanup(urls);
                urls = NULL;
              }
              if(inglob) {
                glob_cleanup(inglob);
                inglob = NULL;
              }
              goto quit_urls;
            }
            if(res)
              goto show_error;
          }
        }

@@ -4780,7 +4749,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          res = curl_easy_perform(curl);
          if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) {
            res = CURLE_OUT_OF_MEMORY;
            break;
            goto show_error;
          }

          if(config->content_disposition && outs.stream && !config->mute &&
@@ -4881,7 +4850,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
                  if(!config->mute)
                    fprintf(config->errors,
                            "failed to truncate, exiting\n");
                  break;
                  res = CURLE_WRITE_ERROR;
                  goto quit_urls;
                }
                /* now seek to the end of the file, the position where we
                   just truncated the file in a large file-safe way */
@@ -4895,13 +4865,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
#endif
                outs.bytes = 0; /* clear for next round */
              }
              continue;
              continue; /* curl_easy_perform loop */
            }
          } /* if retry_numretries */

          /* In all ordinary cases, just break out of loop here */
          retry_sleep = retry_sleep_default;
          break;
          break; /* curl_easy_perform loop */

        }

@@ -4918,55 +4888,82 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          ourWriteEnv(curl);
#endif

        /*
        ** Code within this loop may jump directly here to label 'show_error'
        ** in order to display an error message for CURLcode stored in 'res'
        ** variable and exit loop once that necessary writing and cleanup
        ** in label 'quit_urls' has been done.
        */

        show_error:

#ifdef __VMS
        if(is_vms_shell()) {
          /* VMS DCL shell behavior */
          if(!config->showerror) {
          if(!config->showerror)
            vms_show = VMSSTS_HIDE;
        }
        }
        else
#endif
        {
          if((res!=CURLE_OK) && config->showerror) {
        if(res && config->showerror) {
          fprintf(config->errors, "curl: (%d) %s\n", res,
                    errorbuffer[0]? errorbuffer:
                    curl_easy_strerror((CURLcode)res));
            if(CURLE_SSL_CACERT == res) {
                  (errorbuffer[0]) ? errorbuffer: curl_easy_strerror(res));
          if(res == CURLE_SSL_CACERT)
            fprintf(config->errors, "%s%s",
                      CURL_CA_CERT_ERRORMSG1,
                      CURL_CA_CERT_ERRORMSG2 );
            }
          }
                    CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
        }
        if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
          int rc;

          if(config->xattr) {
            rc = fwrite_xattr(curl, fileno(outs.stream) );
        /* Fall through comment to 'quit_urls' label */

        /*
        ** Upon error condition and always that a message has already been
        ** displayed, code within this loop may jump directly here to label
        ** 'quit_urls' otherwise it should jump to 'show_error' label above.
        **
        ** When 'res' variable is _not_ CURLE_OK loop will exit once that
        ** all code following 'quit_urls' has been executed. Otherwise it
        ** will loop to the beginning from where it may exit if there are
        ** no more urls left.
        */

        quit_urls:

        /* Set file extended attributes */
        if(!res && config->xattr &&
           outfile && !curlx_strequal(outfile, "-") && outs.stream) {
          int rc = fwrite_xattr(curl, fileno(outs.stream));
          if(rc)
            warnf(config, "Error setting extended attributes: %s\n",
                  strerror(errno));
        }
          if(outs.alloc_filename)
            Curl_safefree(outs.filename);

          rc = fclose(outs.stream);
        /* Close the file */
        if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
          int rc = fclose(outs.stream);
          if(!res && rc) {
            /* something went wrong in the writing process */
            res = CURLE_WRITE_ERROR;
            fprintf(config->errors, "(%d) Failed writing body\n", res);
          }
          if(outs.alloc_filename)
            Curl_safefree(outs.filename);
        }

#ifdef __AMIGA__
        if(!res) {
          /* Set the url (up to 80 chars) as comment for the file */
          if(strlen(url) > 78)
            url[79] = '\0';
          SetComment( outs.filename, url);
        }
#endif

#ifdef HAVE_UTIME
        /* Important that we set the time _after_ the file has been
           closed, as is done above here */
        if(config->remote_time && outs.filename) {
          /* ask libcurl if we got a time. Pretty please */
          long filetime;
        /* File time can only be set _after_ the file has been closed */
        if(!res && config->remote_time &&
           outs.filename && !curlx_strequal("-", outs.filename)) {
          /* Ask libcurl if we got a remote file time */
          long filetime = -1;
          curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
          if(filetime >= 0) {
            struct utimbuf times;
@@ -4976,22 +4973,36 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
          }
        }
#endif
#ifdef __AMIGA__
        /* Set the url as comment for the file. (up to 80 chars are allowed)
         */
        if(strlen(url) > 78)
          url[79] = '\0';

        SetComment( outs.filename, url);
#endif
        /* Cleanup loop-local variables for next loop iteration or exit */

        if(infdopen) {
          close(infd);
          infdopen = FALSE;    /* not needed */
          infd = STDIN_FILENO; /* not needed */
        }
        Curl_safefree(outfile);

        /* ... */

        quit_urls:
        Curl_safefree(url);

        Curl_safefree(outfile);
        if(res) {
          /* Free list of remaining URLs */
          if(urls) {
            glob_cleanup(urls);
            urls = NULL;
          }
          /* Free list of globbed upload files */
          if(inglob) {
            glob_cleanup(inglob);
            inglob = NULL;
          }
        }

        if(infdopen)
          close(infd);
        /* upon error exit loop */
        if(res)
          break;

      } /* loop to the next URL */

@@ -5003,6 +5014,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])

      Curl_safefree(uploadfile);

      /* upon error exit loop */
      if(res)
        break;

    } /* loop to the next globbed upload file */

    if(inglob) {