diff options
Diffstat (limited to 'libs/libcurl/src/file.c')
-rw-r--r-- | libs/libcurl/src/file.c | 226 |
1 files changed, 122 insertions, 104 deletions
diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c index e658ada0aa..0bbc0e1800 100644 --- a/libs/libcurl/src/file.c +++ b/libs/libcurl/src/file.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -59,14 +59,11 @@ #include "getinfo.h" #include "transfer.h" #include "url.h" -#include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" #include "memdebug.h" #if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ @@ -111,6 +108,7 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* perform_getsock */ file_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ 0, /* defport */ CURLPROTO_FILE, /* protocol */ PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ @@ -135,44 +133,50 @@ static CURLcode file_setup_connection(struct connectdata *conn) static CURLcode file_range(struct connectdata *conn) { curl_off_t from, to; - curl_off_t totalsize=-1; + curl_off_t totalsize = -1; char *ptr; char *ptr2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->state.use_range && data->state.range) { - from=curlx_strtoofft(data->state.range, &ptr, 0); - while(*ptr && (ISSPACE(*ptr) || (*ptr=='-'))) + CURLofft from_t; + CURLofft to_t; + from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); + if(from_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; - to=curlx_strtoofft(ptr, &ptr2, 0); - if(ptr == ptr2) { - /* we didn't get any digit */ - to=-1; - } - if((-1 == to) && (from>=0)) { + to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); + if(to_t == CURL_OFFT_FLOW) + return CURLE_RANGE_ERROR; + if((to_t == CURL_OFFT_INVAL) && !from_t) { /* X - */ data->state.resume_from = from; - DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n", + DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", from)); } - else if(from < 0) { + else if((from_t == CURL_OFFT_INVAL) && !to_t) { /* -Y */ - data->req.maxdownload = -from; - data->state.resume_from = from; - DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n", - -from)); + data->req.maxdownload = to; + data->state.resume_from = -to; + DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n", + to)); } else { /* X-Y */ totalsize = to-from; - data->req.maxdownload = totalsize+1; /* include last byte */ + if(totalsize == CURL_OFF_T_MAX) + /* this is too big to increase, so bail out */ + return CURLE_RANGE_ERROR; + data->req.maxdownload = totalsize + 1; /* include last byte */ data->state.resume_from = from; - DEBUGF(infof(data, "RANGE from %" FORMAT_OFF_T - " getting %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T + " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, data->req.maxdownload)); } - DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T - " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n", + DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T + " to %" CURL_FORMAT_CURL_OFF_T ", totally %" + CURL_FORMAT_CURL_OFF_T " bytes\n", from, to, data->req.maxdownload)); } else @@ -187,18 +191,20 @@ static CURLcode file_range(struct connectdata *conn) */ static CURLcode file_connect(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; int fd; #ifdef DOS_FILESYSTEM - int i; + size_t i; char *actual_path; #endif + size_t real_path_len; - real_path = curl_easy_unescape(data, data->state.path, 0, NULL); - if(!real_path) - return CURLE_OUT_OF_MEMORY; + CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, + &real_path_len, FALSE); + if(result) + return result; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's @@ -221,16 +227,27 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) (actual_path[2] == ':' || actual_path[2] == '|')) { actual_path[2] = ':'; actual_path++; + real_path_len--; } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for(i=0; actual_path[i] != '\0'; ++i) + for(i = 0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; + else if(!actual_path[i]) { /* binary zero */ + Curl_safefree(real_path); + return CURLE_URL_MALFORMAT; + } fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else + if(memchr(real_path, 0, real_path_len)) { + /* binary zeroes indicate foul play */ + Curl_safefree(real_path); + return CURLE_URL_MALFORMAT; + } + fd = open_readonly(real_path, O_RDONLY); file->path = real_path; #endif @@ -294,22 +311,19 @@ static CURLcode file_upload(struct connectdata *conn) const char *dir = strchr(file->path, DIRSEP); int fd; int mode; - CURLcode res=CURLE_OK; - struct SessionHandle *data = conn->data; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; size_t nread; size_t nwrite; curl_off_t bytecount = 0; - struct timeval now = Curl_tvnow(); struct_stat file_stat; - const char* buf2; + const char *buf2; /* * Since FILE: doesn't do the full init, we need to provide some extra * assignments here. */ - conn->fread_func = data->set.fread_func; - conn->fread_in = data->set.in; conn->data->req.upload_fromhere = buf; if(!dir) @@ -335,9 +349,9 @@ static CURLcode file_upload(struct connectdata *conn) return CURLE_WRITE_ERROR; } - if(-1 != data->set.infilesize) + if(-1 != data->state.infilesize) /* known size of data to "upload" */ - Curl_pgrsSetUploadSize(data, data->set.infilesize); + Curl_pgrsSetUploadSize(data, data->state.infilesize); /* treat the negative resume offset value as the case of "-" */ if(data->state.resume_from < 0) { @@ -346,14 +360,13 @@ static CURLcode file_upload(struct connectdata *conn) failf(data, "Can't get the size of %s", file->path); return CURLE_WRITE_ERROR; } - else - data->state.resume_from = (curl_off_t)file_stat.st_size; + data->state.resume_from = (curl_off_t)file_stat.st_size; } - while(res == CURLE_OK) { + while(!result) { int readcount; - res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); - if(res) + result = Curl_fillreadbuffer(conn, (int)data->set.buffer_size, &readcount); + if(result) break; if(readcount <= 0) /* fix questionable compare error. curlvms */ @@ -363,7 +376,7 @@ static CURLcode file_upload(struct connectdata *conn) /*skip bytes before resume point*/ if(data->state.resume_from) { - if((curl_off_t)nread <= data->state.resume_from ) { + if((curl_off_t)nread <= data->state.resume_from) { data->state.resume_from -= nread; nread = 0; buf2 = buf; @@ -380,7 +393,7 @@ static CURLcode file_upload(struct connectdata *conn) /* write the data to the target */ nwrite = write(fd, buf2, nread); if(nwrite != nread) { - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; break; } @@ -389,16 +402,16 @@ static CURLcode file_upload(struct connectdata *conn) Curl_pgrsSetUploadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, Curl_now()); } - if(!res && Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + if(!result && Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; close(fd); - return res; + return result; } /* @@ -416,18 +429,18 @@ static CURLcode file_do(struct connectdata *conn, bool *done) are supported. This means that files on remotely mounted directories (via NFS, Samba, NT sharing) can be accessed through a file:// URL */ - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct_stat statbuf; /* struct_stat instead of struct stat just to allow the Windows version to have a different struct without having to redefine the simple word 'stat' */ - curl_off_t expected_size=0; - bool fstated=FALSE; + curl_off_t expected_size = 0; + bool size_known; + bool fstated = FALSE; ssize_t nread; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; int fd; - struct timeval now = Curl_tvnow(); struct FILEPROTO *file; *done = TRUE; /* unconditionally */ @@ -463,10 +476,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) information. Which for FILE can't be much more than the file size and date. */ if(data->set.opt_no_body && data->set.include_header && fstated) { - CURLcode result; - snprintf(buf, sizeof(data->state.buffer), - "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + time_t filetime; + struct tm buffer; + const struct tm *tm = &buffer; + char header[80]; + snprintf(header, sizeof(header), + "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0); if(result) return result; @@ -475,29 +491,24 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(result) return result; - if(fstated) { - time_t filetime = (time_t)statbuf.st_mtime; - struct tm buffer; - const struct tm *tm = &buffer; - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; - - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(buf, BUFSIZE-1, - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - } - /* if we fstat()ed the file, set the file size to make it available post- - transfer */ - if(fstated) + filetime = (time_t)statbuf.st_mtime; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + snprintf(header, sizeof(header), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0); + if(!result) + /* set the file size to make it available post transfer */ Curl_pgrsSetDownloadSize(data, expected_size); return result; } @@ -512,8 +523,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) failf(data, "Can't get the size of file."); return CURLE_READ_ERROR; } - else - data->state.resume_from += (curl_off_t)statbuf.st_size; + data->state.resume_from += (curl_off_t)statbuf.st_size; } if(data->state.resume_from <= expected_size) @@ -527,8 +537,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(data->req.maxdownload > 0) expected_size = data->req.maxdownload; - if(fstated && (expected_size == 0)) - return CURLE_OK; + if(!fstated || (expected_size == 0)) + size_known = FALSE; + else + size_known = TRUE; /* The following is a shortcut implementation of file reading this is both more efficient than the former call to download() and @@ -545,38 +557,44 @@ static CURLcode file_do(struct connectdata *conn, bool *done) Curl_pgrsTime(data, TIMER_STARTTRANSFER); - while(res == CURLE_OK) { + while(!result) { /* Don't fill a whole buffer if we want less than all data */ - size_t bytestoread = - (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? - curlx_sotouz(expected_size) : BUFSIZE - 1; + size_t bytestoread; + + if(size_known) { + bytestoread = (expected_size < data->set.buffer_size) ? + curlx_sotouz(expected_size) : (size_t)data->set.buffer_size; + } + else + bytestoread = data->set.buffer_size-1; nread = read(fd, buf, bytestoread); if(nread > 0) buf[nread] = 0; - if(nread <= 0 || expected_size == 0) + if(nread <= 0 || (size_known && (expected_size == 0))) break; bytecount += nread; - expected_size -= nread; + if(size_known) + expected_size -= nread; - res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(res) - return res; + result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); + if(result) + return result; Curl_pgrsSetDownloadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, Curl_now()); } if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; - return res; + return result; } #endif |