diff options
-rw-r--r-- | src/main.c | 180 |
1 files changed, 105 insertions, 75 deletions
diff --git a/src/main.c b/src/main.c index 8acf032fe..a0096b790 100644 --- a/src/main.c +++ b/src/main.c @@ -168,6 +168,7 @@ static int vms_show = 0; static const char *msdosify(const char *); static char *rename_if_dos_device_name(char *); +static char *sanitize_dos_name(char *); #ifndef S_ISCHR # ifdef S_IFCHR @@ -4091,6 +4092,83 @@ static bool stdin_upload(const char *uploadfile) curlx_strequal(uploadfile, ".")); } +/* Adds the file name to the URL if it doesn't already have one. + * url will be freed before return if the returned pointer is different + */ +static char *add_file_name_to_url(CURL *curl, char *url, const char *filename) +{ + /* If no file name part is given in the URL, we add this file name */ + char *ptr=strstr(url, "://"); + if(ptr) + ptr+=3; + else + ptr=url; + ptr = strrchr(ptr, '/'); + if(!ptr || !strlen(++ptr)) { + /* The URL has no file name part, add the local file name. In order + to be able to do so, we have to create a new URL in another + buffer.*/ + + /* We only want the part of the local path that is on the right + side of the rightmost slash and backslash. */ + const char *filep = strrchr(filename, '/'); + char *file2 = strrchr(filep?filep:filename, '\\'); + char *encfile; + + if(file2) + filep = file2+1; + else if(filep) + filep++; + else + filep = filename; + + /* URL encode the file name */ + encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); + if(encfile) { + char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3); + if(!urlbuffer) { + free(url); + return NULL; + } + if(ptr) + /* there is a trailing slash on the URL */ + sprintf(urlbuffer, "%s%s", url, encfile); + else + /* there is no trailing slash on the URL */ + sprintf(urlbuffer, "%s/%s", url, encfile); + + curl_free(encfile); + + free(url); + url = urlbuffer; /* use our new URL instead! */ + } + } + return url; +} + +/* Extracts the name portion of the URL. + * Returns a heap-allocated string, or NULL if no name part + */ +static char *get_url_file_name(const char *url) +{ + char *fn = NULL; + + /* Find and get the remote file name */ + const char * pc =strstr(url, "://"); + if(pc) + pc+=3; + else + pc=url; + pc = strrchr(pc, '/'); + + if(pc) { + /* duplicate the string beyond the slash */ + pc++; + fn = *pc ? strdup(pc): NULL; + } + return fn; +} + static char* parse_filename(char *ptr, int len) { @@ -4539,19 +4617,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) */ if(!outfile) { - /* Find and get the remote file name */ - char * pc =strstr(url, "://"); - if(pc) - pc+=3; - else - pc=url; - pc = strrchr(pc, '/'); - - if(pc) { - /* duplicate the string beyond the slash */ - pc++; - outfile = *pc ? strdup(pc): NULL; - } + /* extract the file name from the URL */ + outfile = get_url_file_name(url); if((!outfile || !*outfile) && !config->content_disposition) { helpf(config->errors, "Remote file name has no length!\n"); res = CURLE_WRITE_ERROR; @@ -4559,20 +4626,12 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) break; } #if defined(MSDOS) || defined(WIN32) - { - /* For DOS and WIN32, we do some major replacing of - bad characters in the file name before using it */ - char file1[PATH_MAX]; - if(strlen(outfile) >= PATH_MAX) - outfile[PATH_MAX-1]=0; /* cut it */ - strcpy(file1, msdosify(outfile)); - free(outfile); - - outfile = strdup(rename_if_dos_device_name(file1)); - if(!outfile) { - res = CURLE_OUT_OF_MEMORY; - break; - } + /* 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) { + res = CURLE_OUT_OF_MEMORY; + break; } #endif /* MSDOS || WIN32 */ } @@ -4639,53 +4698,11 @@ operate(struct Configurable *config, int argc, argv_item_t argv[]) */ struct_stat fileinfo; - /* If no file name part is given in the URL, we add this file name */ - char *ptr=strstr(url, "://"); - if(ptr) - ptr+=3; - else - ptr=url; - ptr = strrchr(ptr, '/'); - if(!ptr || !strlen(++ptr)) { - /* The URL has no file name part, add the local file name. In order - to be able to do so, we have to create a new URL in another - buffer.*/ - - /* We only want the part of the local path that is on the right - side of the rightmost slash and backslash. */ - char *filep = strrchr(uploadfile, '/'); - char *file2 = strrchr(filep?filep:uploadfile, '\\'); - - if(file2) - filep = file2+1; - else if(filep) - filep++; - else - filep = uploadfile; - - /* URL encode the file name */ - filep = curl_easy_escape(curl, filep, 0 /* use strlen */); - - if(filep) { - char *urlbuffer = malloc(strlen(url) + strlen(filep) + 3); - if(!urlbuffer) { - helpf(config->errors, "out of memory\n"); - free(url); - res = CURLE_OUT_OF_MEMORY; - break; - } - if(ptr) - /* there is a trailing slash on the URL */ - sprintf(urlbuffer, "%s%s", url, filep); - else - /* there is no trailing slash on the URL */ - sprintf(urlbuffer, "%s/%s", url, filep); - - curl_free(filep); - - free(url); - url = urlbuffer; /* use our new URL instead! */ - } + url = add_file_name_to_url(curl, url, uploadfile); + if(!url) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + break; } /* VMS Note: * @@ -5782,7 +5799,7 @@ rename_if_dos_device_name (char *file_name) strncpy(fname, file_name, PATH_MAX-1); fname[PATH_MAX-1] = 0; - base = basename (fname); + base = basename(fname); if (((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { size_t blen = strlen (base); @@ -5798,4 +5815,17 @@ rename_if_dos_device_name (char *file_name) } return file_name; } + +/* Replace bad characters in the file name before using it. + * fn will always be freed before return + * The returned pointer must be freed by the caller if not NULL + */ +static char *sanitize_dos_name(char *fn) +{ + char tmpfn[PATH_MAX]; + fn[PATH_MAX-1]=0; /* ensure fn is not too long by possibly truncating it */ + strcpy(tmpfn, msdosify(fn)); + free(fn); + return strdup(rename_if_dos_device_name(tmpfn)); +} #endif /* MSDOS || WIN32 */ |