aboutsummaryrefslogtreecommitdiff
path: root/lib/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/file.c')
-rw-r--r--lib/file.c89
1 files changed, 84 insertions, 5 deletions
diff --git a/lib/file.c b/lib/file.c
index 858226416..cbc9f4ce8 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2008, 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
@@ -70,6 +70,7 @@
#endif
+#include "strtoofft.h"
#include "urldata.h"
#include <curl/curl.h>
#include "progress.h"
@@ -119,6 +120,61 @@ const struct Curl_handler Curl_handler_file = {
PROT_FILE /* protocol */
};
+
+ /*
+ Check if this is a range download, and if so, set the internal variables
+ properly. This code is copied from the FTP implementation and might as
+ well be factored out.
+ */
+static CURLcode file_range(struct connectdata *conn)
+{
+ curl_off_t from, to;
+ curl_off_t totalsize=-1;
+ char *ptr;
+ char *ptr2;
+ struct SessionHandle *data = conn->data;
+
+ if(data->state.use_range && data->state.range) {
+ from=curlx_strtoofft(data->state.range, &ptr, 0);
+ while(ptr && *ptr && (isspace((int)*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)) {
+ /* X - */
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n",
+ from));
+ }
+ else if(from < 0) {
+ /* -Y */
+ totalsize = -from;
+ data->req.maxdownload = -from;
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n",
+ totalsize));
+ }
+ else {
+ /* X-Y */
+ totalsize = to-from;
+ 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",
+ from, data->req.maxdownload));
+ }
+ DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T
+ " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+ from, to, data->req.maxdownload));
+ }
+ else
+ data->req.maxdownload = -1;
+ return CURLE_OK;
+}
+
/*
* file_connect() gets called from Curl_protocol_connect() to allow us to
* do protocol-specific actions at connect-time. We emulate a
@@ -287,8 +343,8 @@ static CURLcode file_upload(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* treat the negative resume offset value as the case of "-" */
- if(data->state.resume_from < 0){
- if(stat(file->path, &file_stat)){
+ if(data->state.resume_from < 0) {
+ if(stat(file->path, &file_stat)) {
fclose(fp);
failf(data, "Can't get the size of %s", file->path);
return CURLE_WRITE_ERROR;
@@ -434,6 +490,20 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
return result;
}
+ /* Check whether file range has been specified */
+ file_range(conn);
+
+ /* Adjust the start offset in case we want to get the N last bytes
+ * of the stream iff the filesize could be determined */
+ if(data->state.resume_from < 0) {
+ if(!fstated) {
+ failf(data, "Can't get the size of file.");
+ return CURLE_READ_ERROR;
+ }
+ else
+ data->state.resume_from += (curl_off_t)statbuf.st_size;
+ }
+
if(data->state.resume_from <= expected_size)
expected_size -= data->state.resume_from;
else {
@@ -441,6 +511,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
return CURLE_BAD_DOWNLOAD_RESUME;
}
+ /* A high water mark has been specified so we obey... */
+ if (data->req.maxdownload > 0)
+ expected_size = data->req.maxdownload;
+
if(fstated && (expected_size == 0))
return CURLE_OK;
@@ -460,15 +534,20 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
while(res == CURLE_OK) {
- nread = read(fd, buf, BUFSIZE-1);
+ /* Don't fill a whole buffer if we want less than all data */
+ if (expected_size < BUFSIZE-1)
+ nread = read(fd, buf, expected_size);
+ else
+ nread = read(fd, buf, BUFSIZE-1);
if( nread > 0)
buf[nread] = 0;
- if(nread <= 0)
+ if (nread <= 0 || expected_size == 0)
break;
bytecount += nread;
+ expected_size -= nread;
res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
if(res)