summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/file.c')
-rw-r--r--libs/libcurl/src/file.c226
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